瀏覽代碼

Make blinky service-ready

New features include:
 - General robustness
 - Configurable config path
 - MQTT retry
master
Nathaniel Walizer 3 年之前
父節點
當前提交
3c9dd7b1d6
共有 1 個文件被更改,包括 70 次插入25 次删除
  1. +70
    -25
      blinky.py

+ 70
- 25
blinky.py 查看文件

@@ -5,7 +5,9 @@ import board
import neopixel
import json
import os
import sys
import time
from pathlib import Path

import pyinotify, threading
import paho.mqtt.subscribe as subscribe
@@ -16,22 +18,34 @@ from pattern import Pattern
lock_reload = threading.Lock()
cond_reload = threading.Condition(lock_reload)
reload = False
config = None
ignore_file = False
config = {}
new_config = None


# Monitor config from file

config_file = "blinky.json"
if len(sys.argv) > 1:
config_file = sys.argv[1]
else:
config_file = "blinky.json"

if not Path(config_file).is_file():
print("WARNING: Config file does not exist:", config_file)

def file_thread(file):
class EventHandler(pyinotify.ProcessEvent):
def process_IN_CLOSE_WRITE(self, event):
global reload, config
global reload, new_config, ignore_file
with lock_reload:
print("Triggering file reload")
config = None
reload = True
cond_reload.notify_all()
if ignore_file:
print("Ignoring file change")
ignore_file = False
else:
print("Triggering file reload")
new_config = None
reload = True
cond_reload.notify_all()

wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm, EventHandler())
@@ -52,17 +66,37 @@ class mqtt:

def mqtt_thread():
def on_message(client, userdata, message):
global reload, config
global reload, new_config
with lock_reload:
print("Triggering MQTT reload")
try:
config = json.loads(message.payload)
new_config = json.loads(message.payload)
reload = True
cond_reload.notify_all()
except:
print("Invalid MQTT config")

subscribe.callback(on_message, mqtt.topic, hostname=mqtt.hostname, auth=mqtt.auth, port=8883, tls=mqtt.tls)
global reload, new_config
while True:
print(f"Subscribing to MQTT topic {mqtt.topic}")
try:
message = subscribe.simple(mqtt.topic, hostname=mqtt.hostname, auth=mqtt.auth, port=8883, tls=mqtt.tls)
except Exception as e:
print("MQTT subscription error:", e)
message = None
if not message:
print("Subscription failed - retrying")
time.sleep(1)
else:
with lock_reload:
print("Triggering MQTT reload")
try:
new_config = json.loads(message.payload)
reload = True
cond_reload.notify_all()
except:
print("Invalid MQTT config")


threading.Thread(target=mqtt_thread).start()

@@ -81,27 +115,37 @@ with lock_reload:
reload = False

try:
config = config or json.load(open(config_file))

new_length = config['length']

if length != new_length:
print("New string config")
length = new_length
pixels = neopixel.NeoPixel(board.D18, length, pixel_order=neopixel.RGB, auto_write=False)
#pixels = TermLEDs(length)

patterns = [(pattern['length'], Pattern.from_dict(pattern)) for pattern in config['patterns']]
# If it wasn't delivered, load from file
new_config = new_config or json.load(open(config_file, 'r'))

if 'length' in new_config:
new_length = new_config['length']
if length != new_length:
length = new_length
config['length'] = length
pixels = neopixel.NeoPixel(board.D18, length, pixel_order=neopixel.RGB, auto_write=False)
#pixels = TermLEDs(length)
print("String configured")

patterns = [(pattern.get('length', length), Pattern.from_dict(pattern)) for pattern in new_config['patterns']]
config['patterns'] = new_config['patterns']
print("Pattern configured")

except Exception as e:
print("Failed to load config:", e)

if not pixels or not patterns:
finally:
print("Saving config")
ignore_file = True
json.dump(config, open(config_file, 'w'))

if not length or not pixels or not patterns:
print("Waiting for valid config")
while not reload:
cond_reload.wait()
else:
target = time.time()
print("Starting animation")
last = target = time.time()
while not reload:
lock_reload.release()

@@ -112,7 +156,8 @@ with lock_reload:
# Go ahead and sleep, maintaining maximum framerate
target += (1 / framerate)
now = time.time()
if target > now:
time.sleep(target - now)
sleeptime = target - now
if sleeptime > 0:
time.sleep(sleeptime)

lock_reload.acquire()

Loading…
取消
儲存