add support for lixie clock
This commit is contained in:
parent
dafd952a05
commit
e389a91ebd
29
events.py
29
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:
|
||||
|
|
56
models.py
56
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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -131,18 +131,34 @@
|
|||
<label for="animation_delay{{ device.id }}">ms</label>
|
||||
</div>
|
||||
</div>
|
||||
{% elif device.type == 'LixieClock' %}
|
||||
<div class="mqtt_root editable"><span class="field_value">{{ device.mqtt_root }}</span>{% if not device.locked %}<span class="edit font-awesome" onclick="edit_field(this.parentElement)"></span>{% endif %}</div>
|
||||
<div class="lixie_controls">
|
||||
<input type="radio" id="display_mode_time_{{ device.id }}" class="time" name="display_mode_{{ device.id }}" value="time" onchange="lixie_display_mode(this)"{% if device.display_mode == 'time' %} checked{% endif %}>
|
||||
<label for="display_mode_time_{{ device.id }}">Time</label><br>
|
||||
<input type="radio" id="display_mode_number_{{ device.id }}" class="number" name="display_mode_{{ device.id }}" value="number" onchange="lixie_display_mode(this)"{% if device.display_mode == 'number' %} checked{% endif %}>
|
||||
<label for="display_mode_number_{{ device.id }}">Number</label><br>
|
||||
<div class='lixie_number' style="display: {% if device.display_mode == 'number' %}block{% else %}none{% endif %}">
|
||||
<label for="lixie_number_{{ device.id }}">Number:</label>
|
||||
<input type="number" id="lixie_number_{{ device.id }}" class="number" min="0" max="9999" value="{{ device.display_number }}" onchange="lixie_clock(this)">
|
||||
</div>
|
||||
<label for="display_color_{{ device.id }}">Color:</label>
|
||||
<input type="color" id="display_color_{{ device.id }}" class="color" value="{{ device.color|html_color }}" onchange="lixie_clock(this)">
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="sub_devices">
|
||||
{% for sub_device in device.sub_devices %}
|
||||
<div class="sub_device {{ sub_device.type }} {{ sub_device.id }}">
|
||||
{% if device.type == 'RelayDevice' %}
|
||||
{% if sub_device.type == 'RelayOutlet' %}
|
||||
<div class="id">{{ sub_device.id }}</div>
|
||||
<object class="outlet_image" aria-label="Outlet Image" data="/static/outlet.svg"></object>
|
||||
<div class="description editable"><span class="field_value">{{ sub_device.description }}</span>{% if not device.locked %}<span class="edit font-awesome" onclick="edit_field(this.parentElement)"></span>{% endif %}</div>
|
||||
{% elif device.type == 'LightStrip' %}
|
||||
{% elif sub_device.type == 'NeoPixel' %}
|
||||
<label class="NeoPixel_color" style="background-color: {{ sub_device.color|html_color }}">
|
||||
<input class="NeoPixel_color_input" type="color" value="{{ sub_device.color|html_color }}" onchange="neopixel_state(this.closest('.sub_device'))" disabled>
|
||||
</label>
|
||||
{% elif sub_device.type == 'LixieDisplay' %}
|
||||
LixieDisplay
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
Loading…
Reference in New Issue
Block a user