Featureful Python controller code for WS2811/WS2812/NeoPixels
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

115 Zeilen
2.9KB

  1. #!/usr/bin/python3
  2. from pixels import TermLEDs
  3. import board
  4. import neopixel
  5. import json
  6. import os
  7. import time
  8. import pyinotify, threading
  9. import paho.mqtt.subscribe as subscribe
  10. from pattern import Pattern
  11. lock_reload = threading.Lock()
  12. cond_reload = threading.Condition(lock_reload)
  13. reload = False
  14. config = None
  15. # Monitor config from file
  16. config_file = "blinky.json"
  17. def file_thread(file):
  18. class EventHandler(pyinotify.ProcessEvent):
  19. def process_IN_CLOSE_WRITE(self, event):
  20. global reload, config
  21. with lock_reload:
  22. print("Triggering reload")
  23. config = None
  24. reload = True
  25. cond_reload.notify_all()
  26. wm = pyinotify.WatchManager()
  27. notifier = pyinotify.Notifier(wm, EventHandler())
  28. wdd = wm.add_watch(file, pyinotify.IN_CLOSE_WRITE)
  29. notifier.loop()
  30. threading.Thread(target=file_thread, args=[config_file]).start()
  31. # Monitor config from MQTT
  32. class mqtt:
  33. topic = "blinky/config"
  34. hostname = "mqtt.jrhoffa.com"
  35. auth = {'username':"blinky", 'password':"rainbow"}
  36. tls = {'ca_certs':"/etc/ssl/certs/ca-certificates.crt"}
  37. def mqtt_thread():
  38. def on_message(client, userdata, message):
  39. global reload, config
  40. with lock_reload:
  41. config = json.loads(message.payload)
  42. reload = True
  43. cond_reload.notify_all()
  44. subscribe.callback(on_message, mqtt.topic, hostname=mqtt.hostname, auth=mqtt.auth, port=8883, tls=mqtt.tls)
  45. threading.Thread(target=mqtt_thread).start()
  46. ### Entry Point ##
  47. framerate = 30
  48. length = None
  49. patterns = None
  50. pixels = None
  51. with lock_reload:
  52. while True:
  53. print("Loading config")
  54. reload = False
  55. try:
  56. config = config or json.load(open(config_file))
  57. new_length = config['length']
  58. if length != new_length:
  59. print("New string config")
  60. length = new_length
  61. pixels = neopixel.NeoPixel(board.D18, length, pixel_order=neopixel.RGB, auto_write=False)
  62. #pixels = TermLEDs(length)
  63. patterns = [(pattern['length'], Pattern.from_dict(pattern)) for pattern in config['patterns']]
  64. except Exception as e:
  65. print("Failed to load config:", e)
  66. if not pixels or not patterns:
  67. print("Waiting for valid config")
  68. while not reload:
  69. cond_reload.wait()
  70. else:
  71. target = time.time()
  72. while not reload:
  73. lock_reload.release()
  74. # Generate and show new light pattern
  75. pixels[:] = [x for y in (pattern.step(length) for (length, pattern) in patterns) for x in y]
  76. pixels.show()
  77. # Go ahead and sleep, maintaining maximum framerate
  78. target += (1 / framerate)
  79. now = time.time()
  80. if target > now:
  81. time.sleep(target - now)
  82. lock_reload.acquire()