因为有了之前(树莓派:Adafruit的I2C SSD1306 OLED驱动)那篇的基础,想干脆让它开机自动显示IP地址。
首先当然找获取IP的代码。记得前几年抄过一段,所以又找了出来:
def get_ip_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915,
struct.pack('256s', ifname[:15]))[20:24])
当时调用很简单,因为我是用无线的,所以历史代码调用用了这一句: ip = get_ip_address('wlan0')
然而今天再拿出来试居然报错了。解决起来倒是非常简单,加个“b”类型前缀即可:
ip = get_ip_address(b'wlan0')
结合示例中的代码,另存了一份代码,命名为s.py,完整代码如下:
import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
#import subprocess
import socket
import fcntl
import struct
#import commands
def get_ip_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915,
struct.pack('256s', ifname[:15]))[20:24])
ip = get_ip_address(b'wlan0')
RST = None # on the PiOLED this pin isnt used
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)
disp.begin()
disp.clear()
disp.display()
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
draw = ImageDraw.Draw(image)
draw.rectangle((0,0,width,height), outline=0, fill=0)
padding = -2
top = padding
bottom = height-padding
x = 0
font = ImageFont.truetype('/usr/share/fonts/truetype/noto/NotoMono-Regular.ttf', 14)
draw.rectangle((0,0,width,height), outline=0, fill=0)
#cmd = "hostname -I"
#IP = subprocess.check_output(cmd, shell = True )
draw.text((x, top), ip, font=font, fill=255)
disp.image(image)
disp.display()
然后就是设置开机自动执行了。意外的,并没有想象中顺利,无论是使用/etc/rc.local还是crontab -e。没有深究,感觉是要么python相关的库调取不到,要么bash环境有问题。
最终使用systemd解决。
在/usr/lib/systemd/system下新建一个后缀为.service的文件(我用了showip-oled.service),内容如下:
[Unit]
Description=Show IP on OLED
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 -u /home/pi/Adafruit_Python_SSD1306/examples/s.py
Restart=on-failure
RestartSec=6
User=pi
[Install]
WantedBy=multi-user.target
具体含义可以参考:Systemd的使用指南 - 简书 (jianshu.com)https://www.jianshu.com/p/7fd8b6ea336e
?因为获取IP并展示在OLED屏幕上只需要在开机时执行,因此Type用了oneshot。一开始没有加Restart和RestartSec,结果测试时发现脚本运行到获取ip相关的地方会报错,因此最终还是加上了这两项。
Service文件保存(含新建、修改等)后可以执行sudo systemctl daemon-reload让系统重刷一下。然后尝试?sudo systemctl start showip-oled.service 看看是否能正常运行,并用sudo systemctl status showip-oled.service 确认。最后运行下?sudo systemctl enable showip-oled.service 使能自动运行。
最后就可以正式测试了。由于我发现树莓派关机后只要不撤电源线,OLED仍可继续显示,因此建议关机后先把电源也断开,确保OLED无任何显示,之后再给树莓派通电。正常情况下应该能显示IP地址了。如果还是不行,可以再用?sudo systemctl status showip-oled.service 看看还有啥错。
|