2019-06-05 13:32:10 -04:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
"""
|
|
|
|
A hub for controlling IOT devices.
|
|
|
|
"""
|
2019-06-13 20:28:47 -04:00
|
|
|
import os
|
2019-06-05 13:32:10 -04:00
|
|
|
import re
|
2019-06-08 03:56:30 -04:00
|
|
|
import copy
|
2019-06-05 13:32:10 -04:00
|
|
|
import json
|
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
from aiohttp import web
|
|
|
|
import jinja2
|
|
|
|
import aiohttp_jinja2
|
|
|
|
from aiohttp_jinja2 import render_template
|
|
|
|
#import uvloop
|
|
|
|
import requests
|
2019-06-13 20:28:47 -04:00
|
|
|
|
2019-06-22 18:37:16 -04:00
|
|
|
import config
|
2019-07-02 08:56:17 -04:00
|
|
|
import models
|
2019-11-08 13:11:57 -05:00
|
|
|
import buckler_aiohttp
|
2019-06-22 18:37:16 -04:00
|
|
|
from tools import make_error
|
2019-06-05 13:32:10 -04:00
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
#uvloop.install()
|
|
|
|
network = models.init_network()
|
|
|
|
routes = web.RouteTableDef()
|
2019-06-08 03:56:30 -04:00
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
@routes.get('/', name='index')
|
|
|
|
async def index(request):
|
|
|
|
"""The index page."""
|
2019-07-02 08:56:17 -04:00
|
|
|
global network
|
2019-06-19 10:15:08 -04:00
|
|
|
init_state = {}
|
|
|
|
for device in network:
|
|
|
|
device_state = {}
|
|
|
|
for sub_dev in device.sub_devices:
|
|
|
|
device_state[sub_dev.id] = sub_dev.state
|
|
|
|
init_state[device.id] = device_state
|
2019-11-08 13:11:57 -05:00
|
|
|
d = {'network': network, 'init_state': init_state}
|
|
|
|
return render_template('index.html', request, d)
|
2019-06-05 13:32:10 -04:00
|
|
|
|
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
@routes.get('/toggle', name='toggle')
|
|
|
|
async def toggle(request):
|
|
|
|
"""Toggles the state of a RelayDevice."""
|
2019-07-02 08:56:17 -04:00
|
|
|
global network
|
2019-11-08 13:11:57 -05:00
|
|
|
device_id = request.query.get('device_id')
|
|
|
|
sub_dev_id = request.query.get('sub_dev_id')
|
2019-06-06 13:16:59 -04:00
|
|
|
|
2019-06-18 13:44:35 -04:00
|
|
|
for device in network:
|
2019-06-06 13:16:59 -04:00
|
|
|
if device.id == device_id:
|
|
|
|
break
|
|
|
|
else:
|
2019-06-13 10:46:59 -04:00
|
|
|
return make_error(404, "device_id not found")
|
2019-06-06 13:16:59 -04:00
|
|
|
res = device.toggle(sub_dev_id)
|
|
|
|
if not res:
|
2019-06-13 10:46:59 -04:00
|
|
|
return make_error(404, "sub_dev_id not found")
|
2019-07-02 08:56:17 -04:00
|
|
|
models.save_network(network)
|
2019-11-08 13:11:57 -05:00
|
|
|
return web.json_response(res)
|
2019-06-06 13:16:59 -04:00
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
@routes.get('/edit', name='edit')
|
|
|
|
async def edit(request):
|
|
|
|
"""Edits the text of a particular field."""
|
2019-07-02 08:56:17 -04:00
|
|
|
global network
|
2019-11-08 13:11:57 -05:00
|
|
|
device_id = request.query.get('device_id')
|
|
|
|
sub_dev_id = request.query.get('sub_dev_id')
|
|
|
|
field = request.query.get('field')
|
|
|
|
value = request.query.get('value')
|
2019-06-13 10:46:59 -04:00
|
|
|
|
2019-06-18 13:44:35 -04:00
|
|
|
for device in network:
|
2019-06-13 10:46:59 -04:00
|
|
|
if device.id == device_id:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
return make_error(404, "device_id not found")
|
|
|
|
|
2019-06-20 12:36:19 -04:00
|
|
|
if device.locked:
|
|
|
|
return make_error(400, "device is locked for editing")
|
|
|
|
|
2019-06-13 10:46:59 -04:00
|
|
|
if sub_dev_id:
|
2019-06-18 13:44:35 -04:00
|
|
|
for sub_dev in device.sub_devices:
|
2019-06-13 10:46:59 -04:00
|
|
|
if sub_dev.id == sub_dev_id:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
return make_error(404, "sub_dev_id not found")
|
|
|
|
if hasattr(sub_dev, field):
|
|
|
|
setattr(sub_dev, field, value)
|
|
|
|
else:
|
|
|
|
return make_error(404, "sub_device field not found")
|
|
|
|
else:
|
|
|
|
if hasattr(device, field):
|
|
|
|
setattr(device, field, value)
|
|
|
|
else:
|
|
|
|
return make_error(404, "device field not found")
|
|
|
|
|
|
|
|
data = {
|
|
|
|
'ok': True,
|
|
|
|
'field': field,
|
|
|
|
'value': value
|
|
|
|
}
|
2019-07-02 08:56:17 -04:00
|
|
|
models.save_network(network)
|
2019-11-08 13:11:57 -05:00
|
|
|
return web.json_response(data)
|
2019-06-13 10:46:59 -04:00
|
|
|
|
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
@routes.get('/new_device', name='new_device')
|
|
|
|
async def new_device(request):
|
2019-06-20 07:49:29 -04:00
|
|
|
"""
|
|
|
|
Allows adding a new device. Accepts device_type parameter, returns
|
|
|
|
the device_id.
|
|
|
|
"""
|
2019-07-02 08:56:17 -04:00
|
|
|
global network
|
2019-11-08 13:11:57 -05:00
|
|
|
device_type = request.query.get('device_type')
|
2019-06-20 07:49:29 -04:00
|
|
|
|
|
|
|
if device_type == 'RelayDevice':
|
2019-09-25 19:57:54 -04:00
|
|
|
device = models.RelayDevice()
|
2019-06-20 07:49:29 -04:00
|
|
|
else:
|
|
|
|
return make_error(400, "Unknown device type")
|
|
|
|
|
|
|
|
devices = [dev for dev in network if dev.type == device_type]
|
|
|
|
devices.sort(key=lambda dev: dev.type)
|
|
|
|
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)
|
2019-07-02 08:56:17 -04:00
|
|
|
models.save_network(network)
|
2019-06-20 07:49:29 -04:00
|
|
|
data = {'device_id': device.id}
|
2019-11-08 13:11:57 -05:00
|
|
|
return web.json_response(data)
|
2019-06-20 07:49:29 -04:00
|
|
|
|
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
@routes.get('/lock_device', name='lock_device')
|
|
|
|
async def lock_device(request):
|
|
|
|
"""Locks or unlocks a device to prevent or allow editing it's fields."""
|
2019-07-02 08:56:17 -04:00
|
|
|
global network
|
2019-11-08 13:11:57 -05:00
|
|
|
device_id = request.query.get('device_id')
|
|
|
|
locked = request.query.get('locked') == 'true'
|
2019-06-20 12:36:19 -04:00
|
|
|
|
|
|
|
for device in network:
|
|
|
|
if device.id == device_id:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
return make_error(404, "device_id not found")
|
|
|
|
|
|
|
|
if locked:
|
|
|
|
device.locked = True
|
|
|
|
else:
|
|
|
|
device.locked = False
|
2019-07-02 08:56:17 -04:00
|
|
|
models.save_network(network)
|
2019-06-20 12:36:19 -04:00
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
return web.json_response({'device_id': device.id, 'locked': device.locked})
|
2019-06-20 12:36:19 -04:00
|
|
|
|
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
@routes.get('/delete', name='delete')
|
|
|
|
async def delete(request):
|
|
|
|
"""Deletes a device."""
|
2019-07-02 08:56:17 -04:00
|
|
|
global network
|
2019-11-08 13:11:57 -05:00
|
|
|
device_id = request.query.get('device_id')
|
2019-06-20 14:51:00 -04:00
|
|
|
|
|
|
|
for device in network:
|
|
|
|
if device.id == device_id:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
return make_error(404, "device_id not found")
|
|
|
|
|
|
|
|
network.remove(device)
|
2019-07-02 08:56:17 -04:00
|
|
|
models.save_network(network)
|
2019-06-20 14:51:00 -04:00
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
return web.json_response(True)
|
|
|
|
|
|
|
|
|
|
|
|
async def init_app():
|
|
|
|
"""Initializes the application."""
|
|
|
|
app = web.Application(middlewares=[buckler_aiohttp.buckler_session])
|
|
|
|
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('templates'))
|
|
|
|
#app.on_startup.append(start_background_tasks)
|
|
|
|
#app.on_cleanup.append(cleanup_background_tasks)
|
2019-06-13 20:28:47 -04:00
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
app.router.add_routes(routes)
|
2019-06-13 20:28:47 -04:00
|
|
|
|
2019-11-08 13:11:57 -05:00
|
|
|
app_wrap = web.Application()
|
|
|
|
app_wrap.add_subapp(config.url_prefix, app)
|
|
|
|
return app_wrap
|