Juice/juice.py

184 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""
A hub for controlling IOT devices.
"""
import os
import re
import copy
import json
from aiohttp import web
import jinja2
import aiohttp_jinja2
from aiohttp_jinja2 import render_template
#import uvloop
import requests
import config
import models
import buckler_aiohttp
from tools import make_error
#uvloop.install()
network = models.init_network()
routes = web.RouteTableDef()
@routes.get('/', name='index')
async def index(request):
"""The index page."""
global network
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
d = {'network': network, 'init_state': init_state}
return render_template('index.html', request, d)
@routes.get('/toggle', name='toggle')
async def toggle(request):
"""Toggles the state of a RelayDevice."""
global network
device_id = request.query.get('device_id')
sub_dev_id = request.query.get('sub_dev_id')
for device in network:
if device.id == device_id:
break
else:
return make_error(404, "device_id not found")
res = device.toggle(sub_dev_id)
if not res:
return make_error(404, "sub_dev_id not found")
models.save_network(network)
return web.json_response(res)
@routes.get('/edit', name='edit')
async def edit(request):
"""Edits the text of a particular field."""
global network
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')
for device in network:
if device.id == device_id:
break
else:
return make_error(404, "device_id not found")
if device.locked:
return make_error(400, "device is locked for editing")
if sub_dev_id:
for sub_dev in device.sub_devices:
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
}
models.save_network(network)
return web.json_response(data)
@routes.get('/new_device', name='new_device')
async def new_device(request):
"""
Allows adding a new device. Accepts device_type parameter, returns
the device_id.
"""
global network
device_type = request.query.get('device_type')
if device_type == 'RelayDevice':
device = models.RelayDevice()
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)
models.save_network(network)
data = {'device_id': device.id}
return web.json_response(data)
@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."""
global network
device_id = request.query.get('device_id')
locked = request.query.get('locked') == 'true'
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
models.save_network(network)
return web.json_response({'device_id': device.id, 'locked': device.locked})
@routes.get('/delete', name='delete')
async def delete(request):
"""Deletes a device."""
global network
device_id = request.query.get('device_id')
for device in network:
if device.id == device_id:
break
else:
return make_error(404, "device_id not found")
network.remove(device)
models.save_network(network)
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)
app.router.add_routes(routes)
app_wrap = web.Application()
app_wrap.add_subapp(config.url_prefix, app)
return app_wrap