viri-leds-dmx-sacn/dmx_queue.py

159 lines
5.6 KiB
Python
Raw Normal View History

2023-08-07 11:39:15 +00:00
import logging
2023-08-07 12:45:01 +00:00
from colorsys import hsv_to_rgb
2023-08-07 11:39:15 +00:00
from queue import Empty
from threading import Thread
from time import sleep
from sacn import sACNsender
LOG = logging.getLogger('DMXQueue')
2023-08-07 12:48:18 +00:00
2023-08-07 11:39:15 +00:00
class DMXQueue:
2023-08-07 18:05:20 +00:00
def __init__(self, config, queue, lights):
self.config = config
2023-08-07 11:39:15 +00:00
self.queue = queue
self.lights = lights
self.worker = Thread(target=self._worker)
self.worker_should_be_running = False
self.sacn = sACNsender(
fps=40,
)
2023-08-07 11:39:15 +00:00
def start(self):
self.sacn.start()
self.sacn.activate_output(self.config.sacn.universe)
2023-08-07 11:39:15 +00:00
self.sacn[self.config.sacn.universe].multicast = self.config.sacn.multicast
if not self.config.sacn.multicast:
self.sacn[self.config.sacn.universe].destination = self.config.sacn.target
2023-08-07 11:39:15 +00:00
2023-08-07 12:48:18 +00:00
self.dmx_data = 512 * [0]
2023-08-07 11:39:15 +00:00
self.worker_should_be_running = True
self.worker.start()
def stop(self):
LOG.info('Waiting for worker to terminate ...')
self.worker_should_be_running = False
self.worker.join()
self.sacn.stop()
def _dmx(self, addr, data):
2023-08-07 12:48:18 +00:00
self.dmx_data[addr - 1] = data
self.sacn[self.config.sacn.universe].dmx_data = tuple(self.dmx_data)
2023-08-07 11:39:15 +00:00
def _bulk(self, start_addr, values):
for idx, value in enumerate(values):
2023-08-07 12:48:18 +00:00
self._dmx(start_addr + idx, value)
2023-08-07 11:39:15 +00:00
2023-08-16 20:13:18 +00:00
def _update_all(self, intensity, red, green, blue, white=50):
2023-08-07 11:39:15 +00:00
for light in self.lights:
light.intensity = intensity
light.red = red
light.green = green
light.blue = blue
light.white = white
self._bulk(*light.dump())
def _worker(self):
LOG.info('Worker startup')
2023-08-07 12:45:01 +00:00
rotation = 0
2023-08-07 11:39:15 +00:00
while self.worker_should_be_running:
try:
level, component, text = self.queue.get_nowait()
LOG.info(f'Got queue item: {level} {component} : {text}')
2023-08-08 04:40:54 +00:00
# effect duration should be between 1s and 1.5s
2023-08-07 11:39:15 +00:00
if level == 'error':
2023-08-13 21:28:14 +00:00
self._update_all(0, 0, 0, 0)
sleep(0.2)
2023-08-07 11:39:15 +00:00
# three instances of two flashes each
for i in range(3):
2023-08-08 04:40:54 +00:00
for j in range(2):
2023-08-16 20:13:18 +00:00
self._update_all(self.config.alerts.brightness, 255, 0, 0)
2023-08-07 11:39:15 +00:00
sleep(0.1)
self._update_all(0, 255, 0, 0)
sleep(0.1)
sleep(0.2)
elif level == 'warn':
2023-08-13 21:28:14 +00:00
self._update_all(0, 0, 0, 0)
sleep(0.2)
2023-08-07 11:39:15 +00:00
# warning: blink alternate, but slow
for i in range(6):
for idx, light in enumerate(self.lights):
light.red = 255
light.green = 150
light.blue = 0
light.white = 0
if (idx + i) % 2:
light.intensity = self.config.alerts.brightness
2023-08-07 11:39:15 +00:00
else:
light.intensity = 0
self._bulk(*light.dump())
2023-08-08 04:40:54 +00:00
sleep(0.2)
2023-08-07 11:39:15 +00:00
self._update_all(0, 0, 0, 0)
elif level == 'info':
2023-08-08 04:40:54 +00:00
forward = list(range(15))
reverse = list(range(15))
reverse.reverse()
2023-08-13 21:28:14 +00:00
if self.config.rainbow.enable:
diff = (
self.config.alerts.brightness
- self.config.rainbow.brightness
)
LOG.debug(diff)
if diff >= 50:
for idx in forward + reverse:
LOG.debug(idx)
LOG.debug(diff * idx)
self._update_all(
int(
self.config.rainbow.brightness
+ ((diff / len(forward + reverse)) * idx)
),
0,
50,
255,
)
sleep(0.025)
2023-08-07 11:39:15 +00:00
self.queue.task_done()
except Empty:
if self.config.rainbow.enable:
2023-08-07 18:05:20 +00:00
degrees_per_step = 360 / len(self.lights)
for idx, light in enumerate(self.lights):
light_degrees_dec = (
(rotation + (idx * degrees_per_step)) % 360 / 360
)
r, g, b = hsv_to_rgb(
light_degrees_dec,
1,
self.config.rainbow.intensity / 100,
2023-08-07 18:05:20 +00:00
)
light.red = int(r * 255)
light.green = int(g * 255)
light.blue = int(b * 200)
light.intensity = self.config.rainbow.brightness
2023-08-07 18:05:20 +00:00
self._bulk(*light.dump())
if self.config.rainbow.speed >= 25:
2023-08-07 18:05:20 +00:00
rotation = rotation + 1
if rotation >= 360:
rotation = 0
sleep(self.config.rainbow.speed / 1000)
2023-08-07 18:05:20 +00:00
else:
sleep(0.2)
else:
sleep(0.2)
2023-08-07 11:39:15 +00:00
LOG.info('Worker shutdown')