Juice/juice.py

199 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""
A hub for controlling IOT devices.
"""
import os
import re
import copy
import json
from flask import Flask, render_template, request, abort, jsonify
from flask import Blueprint
import auth
import config
import models
from auth import auth_required
from tools import make_error
app_views = Blueprint('app_views', __name__)
@app_views.route('/')
@auth_required
def index():
"""
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
return render_template('index.html', network=network,init_state=init_state)
@app_views.route('/toggle')
@auth_required
def toggle():
"""
Toggles the state of a RelayDevice.
"""
global network
device_id = request.args.get('device_id')
sub_dev_id = request.args.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 res
@app_views.route('/edit')
@auth_required
def edit():
"""
Edits the text of a particular field.
"""
global network
device_id = request.args.get('device_id')
sub_dev_id = request.args.get('sub_dev_id')
field = request.args.get('field')
value = request.args.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 json.dumps(data)
@app_views.route('/new_device')
@auth_required
def new_device():
"""
Allows adding a new device. Accepts device_type parameter, returns
the device_id.
"""
global network
device_type = request.args.get('device_type')
if device_type == 'RelayDevice':
device = 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 json.dumps(data)
@app_views.route('/lock_device')
@auth_required
def lock_device():
"""
Locks or unlocks a device to prevent or allow editing it's fields.
"""
global network
device_id = request.args.get('device_id')
locked = request.args.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 jsonify(device_id=device.id, locked=device.locked)
@app_views.route('/delete')
@auth_required
def delete():
"""
Deletes a device.
"""
global network
device_id = request.args.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 jsonify(True)
app = Flask(__name__)
app.register_blueprint(app_views, url_prefix=config.url_prefix)
app.register_blueprint(auth.auth_views, url_prefix=config.url_prefix)
app.jinja_env.undefined = "StrictUndefined"
if os.path.isfile('secret_key'):
with open('secret_key', 'rb') as file:
app.secret_key = file.read()
else:
secret_key = os.urandom(32)
app.secret_key = secret_key
with open('secret_key', 'wb') as file:
file.write(secret_key)
network = models.init_network()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5300, debug=True)