Move to go for secondary services we have built specifically for piframe
This commit is contained in:
parent
292fa5888a
commit
926435f924
|
@ -6,9 +6,9 @@ Can be used for setup and/or re-configuring WiFi if something changes.
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
|
|
||||||
git clone https://git.kemonine.info/PiFrame/piframe.git /opt/piframe
|
DL_URL=$(curl https://git.kemonine.info/api/v1/repos/PiFrame/piframe-go/releases | jq -r '.[0].assets[] | select(.name == "wifi") | .browser_download_url')
|
||||||
cp /opt/piframe/wifi_setup.py /usr/local/bin
|
wget $DL_URL -O /usr/local/bin/pf-wifi
|
||||||
chmod a+x /usr/local/bin/wifi_setup.py
|
chmod a+x /usr/local/bin/pf-wifi
|
||||||
|
|
||||||
cat > /etc/systemd/system/wifi_setup.service <<EOF
|
cat > /etc/systemd/system/wifi_setup.service <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
|
@ -17,7 +17,7 @@ Description=Automatic configuration of WiFi on boot
|
||||||
[Service]
|
[Service]
|
||||||
User=root
|
User=root
|
||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
ExecStart=/usr/local/bin/wifi_setup.py
|
ExecStart=/usr/local/bin/pf-wifi
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
# LCD Control
|
|
||||||
|
|
||||||
The below will setup an Adafruit mini LCD with 2 buttons as a controller for selecting which photo albums are displayed on a PiFrame. This setup also includes the Adafruit stemma/qwiic LUX sensor setup which will be integrated further in the future.
|
|
||||||
|
|
||||||
Please note:
|
|
||||||
- Single button presses need about 1/4 of a second to register
|
|
||||||
- Holding 'Up' for at least 3 seconds will trigger a prompt to reboot
|
|
||||||
- Holding 'Down' for at least 3 seconds will trigger a prompt to power off
|
|
||||||
- If you hold 'Down' on the reboot or power off prompts a debug menu will be displayed
|
|
||||||
|
|
||||||
``` sh
|
|
||||||
|
|
||||||
apt install -y python3-pip ttf-dejavu python3-pil python3-numpy
|
|
||||||
|
|
||||||
pip3 install adafruit-circuitpython-rgb-display adafruit-circuitpython-bh1750 RPI.GPIO
|
|
||||||
pip3 install --upgrade --force-reinstall spidev
|
|
||||||
|
|
||||||
git clone https://git.kemonine.info/kemonine/piframe.git /opt/piframe
|
|
||||||
cp /opt/piframe/lcd_control.py /usr/local/bin/
|
|
||||||
chmod a+x /usr/local/bin/lcd_control.py
|
|
||||||
cat > /etc/systemd/system/lcd_control.service <<EOF
|
|
||||||
[Unit]
|
|
||||||
Description=Control which album is shown as a slideshow
|
|
||||||
After=fim.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
ExecStart=/usr/local/bin/lcd_control.py
|
|
||||||
TimeoutSec=15
|
|
||||||
Restart=always
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable --now lcd_control
|
|
||||||
|
|
||||||
```
|
|
|
@ -225,9 +225,10 @@ EOF
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl enable --now no-cursor-tty1
|
systemctl enable --now no-cursor-tty1
|
||||||
systemctl enable --now fim
|
systemctl enable --now fim
|
||||||
git clone https://git.kemonine.info/kemonine/piframe.git /opt/piframe
|
|
||||||
cp /opt/piframe/inotify-pictures.py /usr/local/bin/
|
DL_URL=$(curl https://git.kemonine.info/api/v1/repos/PiFrame/piframe-go/releases | jq -r '.[0].assets[] | select(.name == "inotify") | .browser_download_url')
|
||||||
chmod a+x /usr/local/bin/inotify-pictures.py
|
wget $DL_URL -O /usr/local/bin/pf-inotify
|
||||||
|
chmod a+x /usr/local/bin/pf-inotify
|
||||||
cat > /etc/systemd/system/inotify-pictures.service <<EOF
|
cat > /etc/systemd/system/inotify-pictures.service <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Watch for picture folder changes and restart slideshow
|
Description=Watch for picture folder changes and restart slideshow
|
||||||
|
@ -236,7 +237,7 @@ After=fim.service
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=root
|
User=root
|
||||||
ExecStart=/usr/local/bin/inotify-pictures.py
|
ExecStart=/usr/local/bin/pf-inotify
|
||||||
TimeoutSec=15
|
TimeoutSec=15
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Inspiration / Further Reading
|
|
||||||
####################
|
|
||||||
# https://github.com/chrisjbillington/inotify_simple
|
|
||||||
# https://stackoverflow.com/questions/16148735/how-to-implement-a-watchdog-timer-in-python
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Dependencies
|
|
||||||
####################
|
|
||||||
# apt install python3 python3-pip python3-dbus
|
|
||||||
# pip3 install inotify_simple
|
|
||||||
|
|
||||||
from inotify_simple import INotify, flags
|
|
||||||
import os
|
|
||||||
from threading import Timer
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Simple watchdog timer class
|
|
||||||
####################
|
|
||||||
class Watchdog:
|
|
||||||
def __init__(self, timeout, userHandler=None): # timeout in seconds
|
|
||||||
self.timeout = timeout
|
|
||||||
self.handler = userHandler if userHandler is not None else self.defaultHandler
|
|
||||||
self.timer = Timer(self.timeout, self.handler)
|
|
||||||
# Do NOT start timer by default ; we want this triggered by reset events that come through
|
|
||||||
# via the inotify filesystem watcher
|
|
||||||
#self.timer.start()
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.timer.cancel()
|
|
||||||
self.timer = Timer(self.timeout, self.handler)
|
|
||||||
self.timer.start()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.timer.cancel()
|
|
||||||
|
|
||||||
def defaultHandler(self):
|
|
||||||
raise self
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Setup inotify on folder(s)
|
|
||||||
####################
|
|
||||||
inotify = INotify()
|
|
||||||
watch_flags = flags.CREATE | flags.DELETE
|
|
||||||
wd = inotify.add_watch('/tank/pictures', watch_flags)
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Restart fim slideshow once inotify storm is over (3s timeout)
|
|
||||||
####################
|
|
||||||
def inotify_handler():
|
|
||||||
print('restarting fim slideshow')
|
|
||||||
import dbus
|
|
||||||
sysbus = dbus.SystemBus()
|
|
||||||
systemd1 = sysbus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
|
|
||||||
manager = dbus.Interface(systemd1, 'org.freedesktop.systemd1.Manager')
|
|
||||||
job = manager.RestartUnit('fim.service', 'fail')
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Watch for inotify events in an infinate loop
|
|
||||||
# This will BLOCK waiting for events within inotify.read(None)
|
|
||||||
# This makes it pretty safe for an infinate loop scenario
|
|
||||||
####################
|
|
||||||
watchdog = Watchdog(3.0, inotify_handler)
|
|
||||||
while True:
|
|
||||||
for event in inotify.read(None):
|
|
||||||
print(event)
|
|
||||||
watchdog.reset()
|
|
||||||
for flag in flags.from_mask(event.mask):
|
|
||||||
print(' ' + str(flag))
|
|
486
lcd_control.py
486
lcd_control.py
|
@ -1,486 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
# IMPORTANT CONSIDERATIONS
|
|
||||||
# - Button presses may be missed if you push/release too fast
|
|
||||||
# - Button presses read most reliably after about 0.25 seconds being held down
|
|
||||||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Inspiration / Further Reading
|
|
||||||
########################################
|
|
||||||
# https://circuitpython.readthedocs.io/projects/bh1750/en/latest/
|
|
||||||
# https://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3
|
|
||||||
# https://stackoverflow.com/questions/16148735/how-to-implement-a-watchdog-timer-in-python
|
|
||||||
# https://learn.adafruit.com/adafruit-bh1750-ambient-light-sensor
|
|
||||||
# https://learn.adafruit.com/adafruit-mini-pitft-135x240-color-tft-add-on-for-raspberry-pi/overview
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Imports and whatnot
|
|
||||||
########################################
|
|
||||||
import adafruit_bh1750
|
|
||||||
import adafruit_rgb_display.st7789 as st7789
|
|
||||||
import board
|
|
||||||
import busio
|
|
||||||
import dbus
|
|
||||||
import digitalio
|
|
||||||
import os
|
|
||||||
import RPi.GPIO as GPIO
|
|
||||||
import time
|
|
||||||
from datetime import datetime
|
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
|
||||||
from threading import Timer
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Generic watchdog timer class
|
|
||||||
########################################
|
|
||||||
class Watchdog:
|
|
||||||
def __init__(self, timeout, userHandler=None): # timeout in seconds
|
|
||||||
self.timeout = timeout
|
|
||||||
self.handler = userHandler if userHandler is not None else self.defaultHandler
|
|
||||||
self.timer = Timer(self.timeout, self.handler)
|
|
||||||
# Do NOT start timer by default ; we want this triggered by reset events that come through
|
|
||||||
# via the inotify filesystem watcher
|
|
||||||
#self.timer.start()
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.timer.cancel()
|
|
||||||
self.timer = Timer(self.timeout, self.handler)
|
|
||||||
self.timer.start()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.timer.cancel()
|
|
||||||
|
|
||||||
def defaultHandler(self):
|
|
||||||
raise self
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Cheat for walking only one level deep via os.walk (faster than other options)
|
|
||||||
########################################
|
|
||||||
def walklevel(some_dir, level=1):
|
|
||||||
some_dir = some_dir.rstrip(os.path.sep)
|
|
||||||
assert os.path.isdir(some_dir)
|
|
||||||
num_sep = some_dir.count(os.path.sep)
|
|
||||||
for root, dirs, files in os.walk(some_dir):
|
|
||||||
yield root, dirs, files
|
|
||||||
num_sep_this = root.count(os.path.sep)
|
|
||||||
if num_sep + level <= num_sep_this:
|
|
||||||
del dirs[:]
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# bh1740 lux sensor
|
|
||||||
########################################
|
|
||||||
i2c = busio.I2C(board.SCL, board.SDA)
|
|
||||||
sensor = adafruit_bh1750.BH1750(i2c)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Configuration for CS and DC pins (these are FeatherWing defaults on M0/M4):
|
|
||||||
########################################
|
|
||||||
cs_pin = digitalio.DigitalInOut(board.CE0)
|
|
||||||
dc_pin = digitalio.DigitalInOut(board.D25)
|
|
||||||
reset_pin = None
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Setup button pins as inputs
|
|
||||||
########################################
|
|
||||||
GPIO.setup(23, GPIO.IN)
|
|
||||||
GPIO.setup(24, GPIO.IN)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Config for display baudrate (default max is 24mhz)
|
|
||||||
########################################
|
|
||||||
BAUDRATE = 64000000
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Setup SPI bus using hardware SPI
|
|
||||||
########################################
|
|
||||||
spi = board.SPI()
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Create the ST7789 display
|
|
||||||
########################################
|
|
||||||
disp = st7789.ST7789(
|
|
||||||
spi,
|
|
||||||
cs=cs_pin,
|
|
||||||
dc=dc_pin,
|
|
||||||
rst=reset_pin,
|
|
||||||
baudrate=BAUDRATE,
|
|
||||||
width=135,
|
|
||||||
height=240,
|
|
||||||
x_offset=53,
|
|
||||||
y_offset=40,
|
|
||||||
)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Create blank image for drawing.
|
|
||||||
# Make sure to create image with mode 'RGB' for full color.
|
|
||||||
########################################
|
|
||||||
height = disp.width # we swap height/width to rotate it to landscape!
|
|
||||||
width = disp.height
|
|
||||||
image = Image.new('RGB', (width, height))
|
|
||||||
rotation = 90
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Get drawing object to draw on image.
|
|
||||||
########################################
|
|
||||||
draw = ImageDraw.Draw(image)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw a black filled box to clear the image
|
|
||||||
########################################
|
|
||||||
draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0))
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw some shapes
|
|
||||||
# First define some constants to allow easy resizing of shapes.
|
|
||||||
########################################
|
|
||||||
padding = -2
|
|
||||||
top = padding
|
|
||||||
bottom = height - padding
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Move left to right keeping track of the current x position for drawing shapes.
|
|
||||||
########################################
|
|
||||||
x = 0
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Load fonts used for output on screen
|
|
||||||
########################################
|
|
||||||
font_small = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf', 24)
|
|
||||||
font_medium = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf', 36)
|
|
||||||
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf', 48)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Turn on the backlight
|
|
||||||
########################################
|
|
||||||
backlight = digitalio.DigitalInOut(board.D22)
|
|
||||||
backlight.switch_to_output()
|
|
||||||
backlight.value = True
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Watchdog timer for screen on/off control based on button presses
|
|
||||||
# Turns off screen 10s after last button press
|
|
||||||
# Turns on screen for 10s when starting up
|
|
||||||
# Restart fim slideshow when the screen blanks so there is an indicator when it's going to change the selection
|
|
||||||
########################################
|
|
||||||
def backlight_callback():
|
|
||||||
global backlight
|
|
||||||
backlight.value = False
|
|
||||||
sysbus = dbus.SystemBus()
|
|
||||||
systemd1 = sysbus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
|
|
||||||
manager = dbus.Interface(systemd1, 'org.freedesktop.systemd1.Manager')
|
|
||||||
job = manager.RestartUnit('fim.service', 'fail')
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Setup screen off watchdog
|
|
||||||
########################################
|
|
||||||
watchdog = Watchdog(10.0, backlight_callback)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Figure out which albums are present as well as the special 'All' album
|
|
||||||
########################################
|
|
||||||
albums = [ 'All' ]
|
|
||||||
selected_album = 0
|
|
||||||
try:
|
|
||||||
with open('/etc/default/fim_album_index', 'r') as f:
|
|
||||||
selected_album = int(f.readline())
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
for root, dirs, files in walklevel('/tank/pictures'):
|
|
||||||
for folder in dirs:
|
|
||||||
if folder == '.stfolder':
|
|
||||||
continue
|
|
||||||
albums.append(folder)
|
|
||||||
albums.sort()
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Track which UI screen is shown
|
|
||||||
########################################
|
|
||||||
current_ui = 'main'
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw main UI
|
|
||||||
########################################
|
|
||||||
def draw_main_ui():
|
|
||||||
global width, height, x, y, top, draw, selected_album, albums, font, current_ui
|
|
||||||
current_ui = 'main'
|
|
||||||
|
|
||||||
# Split the line on spaces and then add a blank line if needed to avoid crashes
|
|
||||||
text_lines = albums[selected_album].split(' ')
|
|
||||||
if len(text_lines) < 2:
|
|
||||||
text_lines.append('')
|
|
||||||
|
|
||||||
# Write some text
|
|
||||||
y = top
|
|
||||||
draw.text((x, y), text_lines[0], font=font, fill='#DCDCDC')
|
|
||||||
y += font.getsize('0')[1]
|
|
||||||
draw.text((x, y), text_lines[1], font=font, fill='#DCDCDC')
|
|
||||||
pos = 'Position: %d/%d' % (selected_album + 1, len(albums))
|
|
||||||
y = height - font_small.getsize(pos)[1]
|
|
||||||
draw.text((x, y), pos, font=font_small, fill='#DCDCDC')
|
|
||||||
|
|
||||||
# Display image.
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw yes/no labels
|
|
||||||
########################################
|
|
||||||
def draw_yes_no_labels():
|
|
||||||
global width, height, x, y, top, draw, font_medium
|
|
||||||
# Yes
|
|
||||||
draw.text((x, top+15), 'Yes', font=font_medium, fill='#DCDCDC')
|
|
||||||
|
|
||||||
# No
|
|
||||||
y = height - font_medium.getsize('No')[1]
|
|
||||||
draw.text((x, y-15), 'No', font=font_medium, fill='#DCDCDC')
|
|
||||||
|
|
||||||
# Display image.
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw rebootING UI
|
|
||||||
########################################
|
|
||||||
def draw_rebooting_ui():
|
|
||||||
global width, height, x, y, top, draw, font_medium, current_ui
|
|
||||||
current_ui = 'rebooting'
|
|
||||||
|
|
||||||
font_size = font_medium.getsize('0')
|
|
||||||
left = x + font_size[0]
|
|
||||||
y = (height / 2) - (font_size[1] / 2)
|
|
||||||
|
|
||||||
draw.text((left, y), 'Rebooting', font=font_medium, fill='#DCDCDC')
|
|
||||||
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw reboot UI
|
|
||||||
########################################
|
|
||||||
def draw_reboot_ui():
|
|
||||||
global width, height, x, y, top, draw, font_medium, current_ui
|
|
||||||
current_ui = 'reboot'
|
|
||||||
draw_yes_no_labels()
|
|
||||||
|
|
||||||
font_size = font_medium.getsize('Yes ')
|
|
||||||
left = x + font_size[0]
|
|
||||||
y = (height / 2) - (font_size[1] / 2)
|
|
||||||
|
|
||||||
draw.text((left, y), 'Reboot', font=font_medium, fill='#DCDCDC')
|
|
||||||
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw powerING off UI
|
|
||||||
########################################
|
|
||||||
def draw_poweringoff_ui():
|
|
||||||
global width, height, x, y, top, draw, font_medium, current_ui
|
|
||||||
current_ui = 'poweringoff'
|
|
||||||
|
|
||||||
font_size = font_medium.getsize('0')
|
|
||||||
left = x + font_size[0]
|
|
||||||
y = (height / 2) - font_size[1]
|
|
||||||
draw.text((left, y), 'Powering', font=font_medium, fill='#DCDCDC')
|
|
||||||
y += font_size[1]
|
|
||||||
left += font_medium.getsize('00')[0]
|
|
||||||
draw.text((left, y), 'Off', font=font_medium, fill='#DCDCDC')
|
|
||||||
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw poweroff UI
|
|
||||||
########################################
|
|
||||||
def draw_poweroff_ui():
|
|
||||||
global width, height, x, y, top, draw, font_medium, current_ui
|
|
||||||
current_ui = 'poweroff'
|
|
||||||
draw_yes_no_labels()
|
|
||||||
|
|
||||||
font_size = font_medium.getsize('Yes ')
|
|
||||||
left = x + font_size[0]
|
|
||||||
y = (height / 2) - font_size[1]
|
|
||||||
draw.text((left, y), 'Power', font=font_medium, fill='#DCDCDC')
|
|
||||||
y += font_size[1]
|
|
||||||
left += font_medium.getsize('0')[0]
|
|
||||||
draw.text((left, y), 'Off', font=font_medium, fill='#DCDCDC')
|
|
||||||
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw debug UI
|
|
||||||
########################################
|
|
||||||
def draw_debug_ui():
|
|
||||||
global width, height, x, y, top, draw, font_small, current_ui
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
current_ui = 'debug'
|
|
||||||
ip_cmd = '/usr/sbin/ip'
|
|
||||||
|
|
||||||
process = subprocess.run([ip_cmd, '-o', 'link', 'show'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
|
||||||
addresses = []
|
|
||||||
for line in process.stdout.split('\n'):
|
|
||||||
if line == '':
|
|
||||||
continue
|
|
||||||
values = line.split(':')
|
|
||||||
adapter = values[1].strip()
|
|
||||||
if adapter != 'lo' and not 'wg' in adapter:
|
|
||||||
addr = subprocess.run([ip_cmd, '-f', 'inet', '-o', 'addr', 'show', adapter], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
|
||||||
addr = addr.stdout.split()
|
|
||||||
if len(addr) >=4:
|
|
||||||
addresses.append(addr[3].split('/')[0])
|
|
||||||
|
|
||||||
# Write some text
|
|
||||||
lux = 'Light: %.2f Lux' % sensor.lux
|
|
||||||
y = top
|
|
||||||
draw.text((x, y), lux, font=font_small, fill='#DCDCDC')
|
|
||||||
for addr in addresses:
|
|
||||||
y += font_small.getsize('0')[1]
|
|
||||||
draw.text((x, y), addr, font=font_small, fill='#DCDCDC')
|
|
||||||
|
|
||||||
# Display image.
|
|
||||||
disp.image(image, rotation)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Method for drawing on the screen
|
|
||||||
# Called by the button handlers since we don't need anything more than a basic while(1) main for this setup
|
|
||||||
########################################
|
|
||||||
def refresh_screen(screen):
|
|
||||||
global draw, width, height
|
|
||||||
# Draw a black filled box to clear the image.
|
|
||||||
draw.rectangle((0, 0, width, height), outline=0, fill=0)
|
|
||||||
|
|
||||||
if screen == 'main':
|
|
||||||
draw_main_ui()
|
|
||||||
elif screen == 'debug':
|
|
||||||
draw_debug_ui()
|
|
||||||
elif screen == 'reboot':
|
|
||||||
draw_reboot_ui()
|
|
||||||
elif screen == 'poweroff':
|
|
||||||
draw_poweroff_ui()
|
|
||||||
elif screen == 'rebooting':
|
|
||||||
draw_rebooting_ui()
|
|
||||||
elif screen == 'poweringoff':
|
|
||||||
draw_poweringoff_ui()
|
|
||||||
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Write current album when restarting the slideshow
|
|
||||||
########################################
|
|
||||||
def write_selected_album():
|
|
||||||
with open('/etc/default/fim_album_index', 'w') as f:
|
|
||||||
f.write(str(selected_album))
|
|
||||||
with open('/etc/default/fim_album', 'w') as f:
|
|
||||||
if not selected_album == 0:
|
|
||||||
f.write('/tank/pictures/' + albums[selected_album])
|
|
||||||
else:
|
|
||||||
f.write('/tank/pictures')
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Button held tracking date/times
|
|
||||||
########################################
|
|
||||||
up_held_rising = None
|
|
||||||
dn_held_rising = None
|
|
||||||
btn_is_prompting = False
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Interrupt callback for changing albums (up)
|
|
||||||
########################################
|
|
||||||
def up_button(channel):
|
|
||||||
global selected_album, albums, backlight, up_held_rising, btn_is_prompting, current_ui
|
|
||||||
backlight.value = True
|
|
||||||
# Pull ups on the LCD flip the standard logic you're expecting
|
|
||||||
# Button Released
|
|
||||||
if not GPIO.input(channel):
|
|
||||||
up_held_rising = datetime.now()
|
|
||||||
# Button pressed
|
|
||||||
else:
|
|
||||||
if btn_is_prompting:
|
|
||||||
if current_ui == 'debug':
|
|
||||||
btn_is_prompting = False
|
|
||||||
up_held_rising = None
|
|
||||||
refresh_screen('main')
|
|
||||||
return
|
|
||||||
if current_ui == 'reboot':
|
|
||||||
refresh_screen('rebooting')
|
|
||||||
os.system('/usr/bin/systemctl reboot')
|
|
||||||
elif current_ui == 'poweroff':
|
|
||||||
refresh_screen('poweringoff')
|
|
||||||
os.system('/usr/bin/systemctl poweroff')
|
|
||||||
btn_is_prompting = False
|
|
||||||
return
|
|
||||||
if up_held_rising is not None:
|
|
||||||
now = datetime.now()
|
|
||||||
diff = (now - up_held_rising).total_seconds()
|
|
||||||
if diff >= 3:
|
|
||||||
up_held_rising = None
|
|
||||||
btn_is_prompting = True
|
|
||||||
refresh_screen('reboot')
|
|
||||||
return
|
|
||||||
selected_album += 1
|
|
||||||
if selected_album >= len(albums):
|
|
||||||
selected_album = 0
|
|
||||||
refresh_screen('main')
|
|
||||||
write_selected_album()
|
|
||||||
watchdog.reset()
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Interrupt callback for changing albums (dn)
|
|
||||||
########################################
|
|
||||||
def dn_button(channel):
|
|
||||||
global selected_album, albums, backlight, dn_held_rising, btn_is_prompting
|
|
||||||
backlight.value = True
|
|
||||||
# Pull ups on the LCD flip the standard logic you're expecting
|
|
||||||
# Button released
|
|
||||||
if not GPIO.input(channel):
|
|
||||||
dn_held_rising = datetime.now()
|
|
||||||
# Button pressed
|
|
||||||
else:
|
|
||||||
if btn_is_prompting:
|
|
||||||
# Show debug menu if long pressed dn on reboot/shutdown screens
|
|
||||||
if dn_held_rising is not None:
|
|
||||||
now = datetime.now()
|
|
||||||
diff = (now - dn_held_rising).total_seconds()
|
|
||||||
if diff >= 3:
|
|
||||||
dn_held_rising = None
|
|
||||||
btn_is_prompting = True
|
|
||||||
refresh_screen('debug')
|
|
||||||
return
|
|
||||||
btn_is_prompting = False
|
|
||||||
refresh_screen('main')
|
|
||||||
if dn_held_rising is not None:
|
|
||||||
now = datetime.now()
|
|
||||||
diff = (now - dn_held_rising).total_seconds()
|
|
||||||
if diff >= 3:
|
|
||||||
dn_held_rising = None
|
|
||||||
btn_is_prompting = True
|
|
||||||
refresh_screen('poweroff')
|
|
||||||
return
|
|
||||||
selected_album -= 1
|
|
||||||
if selected_album < 0:
|
|
||||||
selected_album = len(albums) - 1
|
|
||||||
refresh_screen('main')
|
|
||||||
write_selected_album()
|
|
||||||
watchdog.reset()
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Setup button interrupts
|
|
||||||
########################################
|
|
||||||
GPIO.add_event_detect(23, GPIO.BOTH, callback=up_button, bouncetime=250)
|
|
||||||
GPIO.add_event_detect(24, GPIO.BOTH, callback=dn_button, bouncetime=250)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Draw initial screen state
|
|
||||||
########################################
|
|
||||||
refresh_screen(current_ui)
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# Kick off watchdog to start the 10s initial 'on' status
|
|
||||||
########################################
|
|
||||||
watchdog.reset()
|
|
||||||
|
|
||||||
########################################
|
|
||||||
# We use watchdogs/interrupts for ALL operations, no need for anything in a main loop other than keeping the app alive
|
|
||||||
########################################
|
|
||||||
while True:
|
|
||||||
time.sleep(300)
|
|
|
@ -1,56 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
# Make sure mount point exists
|
|
||||||
if not os.path.isdir('/var/wifi'):
|
|
||||||
os.mkdir('/var/wifi')
|
|
||||||
|
|
||||||
# Scan unmounted disks/partitions to see if we need to reconfig wifi
|
|
||||||
blkids = subprocess.run(['/usr/sbin/blkid', '-o', 'device'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
|
||||||
for blkid in blkids.stdout.split('\n'):
|
|
||||||
blkid = blkid.strip()
|
|
||||||
if not blkid:
|
|
||||||
continue
|
|
||||||
# Verify the disk/partition isn't mounted
|
|
||||||
findmnt = subprocess.run(['/usr/bin/findmnt', '-n', '-o', 'TARGET', blkid], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
|
||||||
mnt = findmnt.stdout.strip()
|
|
||||||
if not mnt and not 'zram' in blkid:
|
|
||||||
print('checking ' + blkid)
|
|
||||||
try:
|
|
||||||
# Mount the disk
|
|
||||||
subprocess.run(['/usr/bin/mount', blkid, '/var/wifi/'], universal_newlines=True)
|
|
||||||
# Check if the wifi.txt confg file is present (line 1 is essid, line 2 is PSK)
|
|
||||||
if os.path.exists('/var/wifi/wifi.txt'):
|
|
||||||
# Get wifi config
|
|
||||||
essid = ''
|
|
||||||
password = ''
|
|
||||||
with open('/var/wifi/wifi.txt', 'r') as f:
|
|
||||||
essid = f.readline().strip()
|
|
||||||
password = f.readline().strip()
|
|
||||||
if essid and password:
|
|
||||||
print('Found wifi config (' + essid + ' / ' + password + ')')
|
|
||||||
# Look for existing wifi connections that should be cleaned up
|
|
||||||
nmcli = subprocess.run(['/usr/bin/nmcli', '-t', 'connection', 'show'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
|
||||||
for connection in nmcli.stdout.split('\n'):
|
|
||||||
# Ignore empty lines in output
|
|
||||||
if not connection:
|
|
||||||
continue
|
|
||||||
connection_details = connection.split(':')
|
|
||||||
if connection_details[2] == '802-11-wireless':
|
|
||||||
# If we cannot clean up a wifi connection assume it's a non-issue
|
|
||||||
try:
|
|
||||||
# Cleanup existing wifi connection
|
|
||||||
print('cleaning up wifi connection ' + connection_details[0])
|
|
||||||
subprocess.run(['/usr/bin/nmcli', 'connection', 'del', connection_details[1]], universal_newlines=True)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
print('Connecting to ' + essid + ' with password ' + password)
|
|
||||||
subprocess.run(['/usr/bin/nmcli', 'd', 'wifi', 'connect', essid, 'password', password], universal_newlines=True)
|
|
||||||
# Unmount disk so it's safe to remove
|
|
||||||
subprocess.run(['/usr/bin/umount', '/var/wifi/'], universal_newlines=True)
|
|
||||||
except:
|
|
||||||
# Unmount disk so it's safe to remove
|
|
||||||
subprocess.run(['/usr/bin/umount', '/var/wifi/'], universal_newlines=True)
|
|
Loading…
Reference in a new issue