diff --git a/events.py b/events.py index 7695dba..89b4b39 100644 --- a/events.py +++ b/events.py @@ -239,6 +239,35 @@ async def neopixel(request, ws, data): # websocket response is handled under LightStrip.mqtt_callback +async def lixie_clock(request, ws, data): + """Changes the state of a Lixie Clock.""" + device_id = data.get('device_id') + + device = network.find(device_id) + if not device: + data['ok'] = False + data['error'] = "device_id not found" + await ws.send_json(data) + return + + mqtt_msg = [device.mqtt_root] + payload = '' + if data.get('change_mode') == 'time': + mqtt_msg.append('time') + payload = '' + elif data.get('change_mode') == 'number': + mqtt_msg.append('number') + payload = data.get('display_number') + elif data.get('change_mode') == 'color': + mqtt_msg.append('color') + payload = tools.from_html_color(data.get('color')) + payload = str(payload)[1:-1].replace(' ', '') + mqtt_msg = '/'.join(mqtt_msg) + + request.app['mqtt'].publish(mqtt_msg, payload) + # websocket response is handled under LixieClock.mqtt_callback + + events = {} for obj in dir(): if type(locals()[obj]) == types.FunctionType: diff --git a/models.py b/models.py index 1726c4b..c0b8e79 100644 --- a/models.py +++ b/models.py @@ -68,6 +68,9 @@ class Device: elif sub_device_dict.get('type') == 'NeoPixel': sub_device = NeoPixel().from_dict(sub_device_dict) self.sub_devices.append(sub_device) + elif sub_device_dict.get('type') == 'LixieDisplay': + sub_device = LixieDisplay().from_dict(sub_device_dict) + self.sub_devices.append(sub_device) else: typ = sub_device_dict.get('type') raise ValueError(f"Unknown sub_device type {typ}") @@ -246,6 +249,56 @@ class NeoPixel(SubDevice): self.color = [0,0,0] # JSON doesn't have tuples +class LixieClock(Device): + """ + Represents a clock made of Lixie displays. + """ + def __init__(self): + super().__init__() + self.type = "LixieClock" + self.color = [0,0,0] + self.display_mode = 'time' + self.time_offset = -5 + self.display_number = 0 + + async def mqtt_callback(self, app, msg): + topic = msg.topic.split('/') + payload = msg.payload.decode('utf8') + + data = {} + data['ok'] = True + data['device_id'] = self.id + + if topic[1] == 'time': + data['change_mode'] = 'time' + self.display_mode = 'time' + elif topic[1] == 'number': + payload = int(payload) + data['change_mode'] = 'number' + data['display_number'] = payload + self.display_mode = 'number' + self.display_number = payload + elif topic[1] == 'color': + payload = payload.split(',') + payload = [int(num) for num in payload] + data['change_mode'] = 'color' + data['color'] = tools.to_html_color(payload) + self.color = payload + save_network(network) + + res = {'event': 'lixie_clock', 'data': data} + await app.send_json_all(res) + + +class LixieDisplay(SubDevice): + """ + Represents a single Lixie display. + """ + def __init__(self): + self.id = "" + self.type = "LixieDisplay" + + class DeviceEncoder(json.JSONEncoder): """ A custom json encoder for dumping devices to file. @@ -269,6 +322,9 @@ def init_network(filepath="devices.json"): elif device_dict.get('type') == 'LightStrip': device = LightStrip().from_dict(device_dict) network.append(device) + elif device_dict.get('type') == 'LixieClock': + device = LixieClock().from_dict(device_dict) + network.append(device) else: raise ValueError(f"Unknown device type {device_dict.get('type')}") return network diff --git a/static/juice.js b/static/juice.js index d42cab7..ce293dc 100644 --- a/static/juice.js +++ b/static/juice.js @@ -44,6 +44,7 @@ function init_websocket() { socket.events['lock_device'] = lock_device_recv; socket.events['delete_device'] = delete_device_recv; socket.events['neopixel'] = neopixel_recv; + socket.events['lixie_clock'] = lixie_clock_recv; return socket; } @@ -227,7 +228,22 @@ function neopixel_recv(data) { } } } +} +function lixie_clock_recv(data) { + let device = document.querySelector('#' + data.device_id); + if (data.change_mode === 'time') { + let radio = device.querySelector('#display_mode_time_' + device.id); + radio.checked = true; + lixie_display_mode(radio, false); + } else if (data.change_mode === 'number') { + let radio = device.querySelector('#display_mode_number_' + device.id); + radio.checked = true; + lixie_display_mode(radio, false); + device.querySelector('#lixie_number_' + device.id).value = data.display_number; + } else if (data.change_mode === 'color') { + device.querySelector('#display_color_' + device.id).value = data.color; + } } /* Websocket send */ @@ -364,6 +380,23 @@ function neopixel_animation(device) { socket.send('neopixel', data); } +function lixie_clock(input) { + let device = input.closest('.device'); + data = { + device_id: device.id + } + if (input.className === 'time') { + data['change_mode'] = 'time'; + } else if (input.className === 'number') { + data['change_mode'] = 'number'; + data['display_number'] = device.querySelector('#lixie_number_' + device.id).value; + } else if (input.className === 'color') { + data['change_mode'] = 'color'; + data['color'] = input.value + } + socket.send('lixie_clock', data); +} + /* DOM */ function edit_field(field) { let value = field.firstElementChild.innerText; @@ -379,7 +412,7 @@ function edit_field(field) { } function state_solid_amount(radio) { - let device = radio.parentElement.parentElement.parentElement.parentElement; + let device = radio.closest('.device'); let sub_devices = device.querySelector('.sub_devices'); for (let sub_device of sub_devices.children) { let input = sub_device.firstElementChild.firstElementChild; @@ -435,6 +468,18 @@ function animation_select(select, send_socket_event = true) { } } +function lixie_display_mode(radio, send_socket_event = true) { + let device = radio.closest('.device'); + if (radio.value === 'time') { + device.querySelector('.lixie_number').style.display = 'none'; + } else if (radio.value === 'number') { + device.querySelector('.lixie_number').style.display = 'block'; + } + if (send_socket_event) { + lixie_clock(radio); + } +} + /* Misc */ function get_object_from_svg(svg) { let all_objects = document.getElementsByTagName("object"); diff --git a/templates/index.html b/templates/index.html index 436d1a7..78a22c1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -131,18 +131,34 @@ + {% elif device.type == 'LixieClock' %} +
{{ device.mqtt_root }}{% if not device.locked %}{% endif %}
+
+ +
+ +
+
+ + +
+ + +
{% endif %}
{% for sub_device in device.sub_devices %}
- {% if device.type == 'RelayDevice' %} + {% if sub_device.type == 'RelayOutlet' %}
{{ sub_device.id }}
{{ sub_device.description }}{% if not device.locked %}{% endif %}
- {% elif device.type == 'LightStrip' %} + {% elif sub_device.type == 'NeoPixel' %} + {% elif sub_device.type == 'LixieDisplay' %} + LixieDisplay {% endif %}
{% endfor %}