Featureful Python controller code for WS2811/WS2812/NeoPixels
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

115 linhas
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()