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
|
|
|
|
|
2019-11-15 12:54:41 -05:00
|
|
|
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}
|
2019-11-15 12:54:41 -05:00
|
|
|
await request.app.send_json_all(res)
|
2019-11-15 10:35:56 -05:00
|
|
|
|
|
|
|
|
2019-11-15 12:54:41 -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}
|
2019-11-15 12:54:41 -05:00
|
|
|
await request.app.send_json_all(res)
|
2019-11-15 10:35:56 -05:00
|
|
|
|
|
|
|
|
2019-11-15 12:54:41 -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.
|
|
|
|
"""
|
|
|
|
device_type = data.get('device_type')
|
|
|
|
|
2019-11-15 12:21:35 -05:00
|
|
|
data = {}
|
|
|
|
data['device_type'] = device_type
|
|
|
|
|
2019-11-15 10:35:56 -05:00
|
|
|
if device_type == 'RelayDevice':
|
|
|
|
device = models.RelayDevice()
|
2019-11-17 19:46:57 -05:00
|
|
|
device.sub_devices.append(models.RelayOutlet())
|
|
|
|
device.sub_devices.append(models.RelayOutlet())
|
|
|
|
device.sub_devices[0].id = 'OUT0'
|
|
|
|
device.sub_devices[0].gpio = '0'
|
|
|
|
device.sub_devices[1].id = 'OUT2'
|
|
|
|
device.sub_devices[1].gpio = '2'
|
|
|
|
device.update()
|
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
|
|
|
|
|
|
|
|
devices = [dev for dev in network if dev.type == device_type]
|
|
|
|
devices.sort(key=lambda dev: dev.id)
|
|
|
|
if not devices:
|
|
|
|
device.id = device_type + '01'
|
|
|
|
else:
|
|
|
|
num = re.search(r'(\d*)$', devices[-1].id).groups()
|
|
|
|
if not num:
|
|
|
|
device.id = device_type + '01'
|
|
|
|
else:
|
|
|
|
num = str(int(num[0]) + 1).zfill(2)
|
|
|
|
device.id = device_type + num
|
|
|
|
network.append(device)
|
|
|
|
models.save_network(network)
|
2019-11-15 12:21:35 -05:00
|
|
|
|
|
|
|
data['ok'] = True
|
|
|
|
data['device_id'] = device.id
|
|
|
|
res = {'event': 'new_device', 'data': data}
|
2019-11-15 12:54:41 -05:00
|
|
|
await request.app.send_json_all(res)
|
2019-11-15 10:35:56 -05:00
|
|
|
|
|
|
|
|
2019-11-15 12:54:41 -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}
|
2019-11-15 12:54:41 -05:00
|
|
|
await request.app.send_json_all(res)
|
2019-11-15 10:35:56 -05:00
|
|
|
|
|
|
|
|
2019-11-15 12:54:41 -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}
|
2019-11-15 12:54:41 -05:00
|
|
|
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-15 10:35:56 -05:00
|
|
|
events = {}
|
|
|
|
for obj in dir():
|
|
|
|
if type(locals()[obj]) == types.FunctionType:
|
|
|
|
events[locals()[obj].__name__] = locals()[obj]
|