Juice/events.py

292 lines
7.6 KiB
Python
Raw Normal View History

2019-11-15 10:35:56 -05:00
#!/usr/bin/env python3
"""Websocket events."""
2019-11-15 12:21:35 -05:00
import re
2019-11-15 10:35:56 -05:00
import types
2019-11-18 13:05:37 -05:00
import tools
2019-11-15 10:35:56 -05:00
import models
from models import network
async def toggle_outlet(request, ws, data):
2019-11-15 10:35:56 -05:00
"""Toggles the state of a RelayDevice."""
device_id = data.get('device_id')
sub_device_id = data.get('sub_device_id')
2019-11-15 12:21:35 -05:00
data = {}
data['device_id'] = device_id
data['sub_device_id'] = sub_device_id
2019-11-15 10:35:56 -05:00
device = network.find(device_id)
if not device:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "device_id not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
state = device.toggle(sub_device_id)
if state is None:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "sub_device_id not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
models.save_network(network)
data['ok'] = True
data['state'] = state
res = {'event': 'toggle_outlet', 'data': data}
await request.app.send_json_all(res)
2019-11-15 10:35:56 -05:00
async def edit_field(request, ws, data):
2019-11-15 10:35:56 -05:00
"""Edits the text of a particular field."""
device_id = data.get('device_id')
sub_device_id = data.get('sub_device_id')
field = data.get('field')
value = data.get('value')
2019-11-15 12:21:35 -05:00
data = {}
data['device_id'] = device_id
if sub_device_id:
data['sub_device_id'] = sub_device_id
data['field'] = field
data['value'] = value
2019-11-15 10:35:56 -05:00
device = network.find(device_id)
if not device:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "device_id not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
if device.locked:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "device is locked for editing"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
if sub_device_id:
sub_device = device.find(sub_device_id)
if not sub_device:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "sub_device_id not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
if hasattr(sub_device, field):
setattr(sub_device, field, value)
else:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "sub_device field not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
else:
if hasattr(device, field):
setattr(device, field, value)
else:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "device field not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
models.save_network(network)
2019-11-15 12:21:35 -05:00
data['ok'] = True
res = {'event': 'edit_field', 'data': data}
await request.app.send_json_all(res)
2019-11-15 10:35:56 -05:00
async def new_device(request, ws, data):
2019-11-15 10:35:56 -05:00
"""
Allows adding a new device. Accepts device_type parameter, returns
the device_id.
"""
2020-12-11 14:03:44 -05:00
device_id = data.get('device_id', '')
2019-11-15 10:35:56 -05:00
device_type = data.get('device_type')
2020-12-11 14:03:44 -05:00
num_sub_devices = data.get('num_sub_devices')
2019-11-15 10:35:56 -05:00
2020-12-11 14:03:44 -05:00
try:
num_sub_devices = int(num_sub_devices)
except (TypeError, ValueError):
data['ok'] = False
data['error'] = "num_sub_devices value error"
await ws.send_json(data)
return
2019-11-15 12:21:35 -05:00
2020-12-11 14:03:44 -05:00
data = {}
if device_type == 'relay_device':
2019-11-15 10:35:56 -05:00
device = models.RelayDevice()
2020-12-11 14:03:44 -05:00
for n in [0,2]:
sub_device = models.RelayOutlet()
sub_device.id = 'OUT' + str(n)
sub_device.gpio = str(n)
device.sub_devices.append(sub_device)
device.update()
2020-12-11 14:03:44 -05:00
elif device_type == 'light_strip':
device = models.LightStrip()
for n in range(num_sub_devices):
sub_device = models.NeoPixel()
sub_device.id = 'LED' + str(n)
device.sub_devices.append(sub_device)
elif device_type == 'lixie_clock':
device = models.LixieClock()
for n in range(num_sub_devices):
sub_device = models.LixieDisplay()
sub_device.id = 'LixieDisplay' + str(n)
device.sub_devices.append(sub_device)
2019-11-15 10:35:56 -05:00
else:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "unknown device type"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
2020-12-11 14:03:44 -05:00
while network.find(device_id):
device_id += '0'
device.id = device_id
2019-11-15 10:35:56 -05:00
network.append(device)
models.save_network(network)
2019-11-15 12:21:35 -05:00
data['ok'] = True
data['device_id'] = device.id
2020-12-11 14:03:44 -05:00
data['device_type'] = device_type
data['sub_device_ids'] = [sub_dev.id for sub_dev in device.sub_devices]
2019-11-15 12:21:35 -05:00
res = {'event': 'new_device', 'data': data}
await request.app.send_json_all(res)
2019-11-15 10:35:56 -05:00
async def lock_device(request, ws, data):
2019-11-15 10:35:56 -05:00
"""Locks or unlocks a device to prevent or allow editing it's fields."""
device_id = data.get('device_id')
2019-11-15 12:21:35 -05:00
locked = bool(data.get('locked'))
data = {}
data['device_id'] = device_id
data['locked'] = locked
2019-11-15 10:35:56 -05:00
device = network.find(device_id)
if not device:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "device_id not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
2019-11-15 12:21:35 -05:00
device.locked = locked
2019-11-15 10:35:56 -05:00
models.save_network(network)
2019-11-15 12:21:35 -05:00
data['ok'] = True
res = {'event': 'lock_device', 'data': data}
await request.app.send_json_all(res)
2019-11-15 10:35:56 -05:00
async def delete_device(request, ws, data):
2019-11-15 10:35:56 -05:00
"""Deletes a device."""
device_id = data.get('device_id')
2019-11-15 12:21:35 -05:00
data = {}
data['device_id'] = device_id
2019-11-15 10:35:56 -05:00
device = network.find(device_id)
if not device:
2019-11-15 12:21:35 -05:00
data['ok'] = False
data['error'] = "device_id not found"
await ws.send_json(data)
2019-11-15 10:35:56 -05:00
return
network.remove(device)
models.save_network(network)
2019-11-15 12:21:35 -05:00
data['ok'] = True
res = {'event': 'delete_device', 'data': data}
await request.app.send_json_all(res)
2019-11-15 10:35:56 -05:00
2019-11-18 13:05:37 -05:00
async def neopixel(request, ws, data):
"""Changes the state of a NeoPixel strip."""
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]
2019-11-21 20:39:47 -05:00
if data.get('change_mode') == 'state':
mqtt_msg.append(data.get('change_mode'))
if data.get('type') == 'solid':
mqtt_msg.append(data.get('type'))
if data.get('amount') == 'single':
mqtt_msg.append(data.get('amount'))
mqtt_msg.append(data.get('sub_device_id').replace('led', ''))
elif data.get('amount') == 'all':
mqtt_msg.append(data.get('amount'))
else:
error = "invalid amount"
payload = tools.from_html_color(data.get('color'))
payload = str(payload)[1:-1].replace(' ', '')
elif data.get('type') == 'rainbow':
mqtt_msg.append(data.get('type'))
payload = ','.join(data.get('rainbow_params'))
elif data.get('type') == 'america':
mqtt_msg.append(data.get('type'))
payload = ','.join(data.get('america_params'))
else:
error = "invalid state type"
elif data.get('change_mode') == 'animation':
mqtt_msg.append(data.get('change_mode'))
if data.get('property_type') == 'mode':
mqtt_msg.append(data.get('property_type'))
if data.get('type') == 'static':
mqtt_msg.append(data.get('type'))
payload = ''
elif data.get('type') == 'rotate_left':
mqtt_msg.append(data.get('type'))
payload = data.get('rotate_count')
elif data.get('type') == 'rotate_right':
mqtt_msg.append(data.get('type'))
payload = data.get('rotate_count')
elif data.get('property_type') == 'delay':
mqtt_msg.append(data.get('property_type'))
payload = data.get('delay')
2019-11-18 13:05:37 -05:00
mqtt_msg = '/'.join(mqtt_msg)
2019-11-20 12:59:42 -05:00
2019-11-18 13:05:37 -05:00
request.app['mqtt'].publish(mqtt_msg, payload)
# websocket response is handled under LightStrip.mqtt_callback
2019-11-25 08:39:42 -05:00
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(' ', '')
2020-03-18 13:07:07 -04:00
elif data.get('change_mode') == 'time_offset':
mqtt_msg.append('time_offset')
payload = data.get('time_offset')
2019-11-25 08:39:42 -05:00
mqtt_msg = '/'.join(mqtt_msg)
request.app['mqtt'].publish(mqtt_msg, payload)
# websocket response is handled under LixieClock.mqtt_callback
2019-11-15 10:35:56 -05:00
events = {}
for obj in dir():
if type(locals()[obj]) == types.FunctionType:
events[locals()[obj].__name__] = locals()[obj]