homecontrol/homecontrol.py

318 lines
10 KiB
Python
Raw Normal View History

2019-10-22 23:55:00 +02:00
#!/usr/bin/env python3
from flask import Flask, request, json, jsonify, abort, make_response
import logging
2019-10-22 23:55:00 +02:00
import argparse
import time
2019-11-05 01:18:25 +01:00
import dataset
import sys
from math import inf
2019-10-22 23:55:00 +02:00
CONFIG_FILE = 'config.json'
2019-11-05 01:18:25 +01:00
DB_FILE = 'db.sqlite'
LIMIT=100
2019-10-22 23:55:00 +02:00
PORT = 5000
2019-11-05 01:18:25 +01:00
# TIMEOUT_CLIENT = 10
core = None
# sensors
NUM_VALUES = 1000
2019-10-22 23:55:00 +02:00
def setup():
# arguments
parser = argparse.ArgumentParser(description='homecontrol')
parser.add_argument('-p', '--port', dest='port', type=int,
help='listening port')
2019-10-22 23:55:00 +02:00
parser.add_argument('-c', '--config', dest='config', type=str,
help='config file', default=CONFIG_FILE)
2019-11-05 01:18:25 +01:00
parser.add_argument('-f', '--dbfile', dest='dbfile', type=str,
help='database file', default=DB_FILE)
2019-10-22 23:55:00 +02:00
parser.add_argument('-d', '--debug', dest='debug', action='store_true',
help='debug mode')
parser.add_argument('-D', '--debugflask', dest='debugflask', action='store_true',
help='flask debug mode')
2019-10-22 23:55:00 +02:00
# parse arguments
args = parser.parse_args()
# initialize config
config = {}
try:
config_file = open(args.config, 'r')
2019-10-22 23:55:00 +02:00
config = json.load(config_file)
2019-11-05 01:18:25 +01:00
except:
pass
2019-10-22 23:55:00 +02:00
# fill new keys with defaults
if not config.get('port'):
config['port'] = PORT
2019-11-05 01:18:25 +01:00
if not config.get('dbfile'):
config['dbfile'] = DB_FILE
2019-10-22 23:55:00 +02:00
# overwrite with arguments
if args.port:
config['port'] = args.port
2019-11-05 01:18:25 +01:00
if args.dbfile:
config['dbfile'] = args.dbfile
2019-10-22 23:55:00 +02:00
# save to file
with open(args.config, 'w') as config_file:
json.dump(config, config_file)
return args, config
2019-11-05 01:18:25 +01:00
class Logger:
def __init__(self, name, debug):
FORMAT='%(asctime)-8s %(name)12s::%(levelname)-7s %(message)s'
DATEFMT='%H:%M:%S'
logging.basicConfig(level=logging.INFO, format=FORMAT, datefmt=DATEFMT)
self.logger = logging.getLogger(name)
if debug:
self.logger.setLevel(logging.DEBUG)
def getLogger(self):
return self.logger
2019-10-22 23:55:00 +02:00
class Core:
2019-11-05 01:18:25 +01:00
def __init__(self, dbfile, debug):
self.logger = Logger("Core", debug).getLogger()
self.logger.info("initialization starting...")
self.actor_queue = {}
self.db = dataset.connect("sqlite:///%s?check_same_thread=False" % dbfile)
2019-11-05 01:18:25 +01:00
self.logger.info("initialization complete.")
def actor_add_level(self, actorId, actorType, maxLevel, level):
ret = {}
try:
if not self.db["actors"].find_one(actorId=actorId):
self.db['actors'].insert({"actorId": actorId, "actorType": actorType,
"maxLevel": maxLevel})
self.db['actor_levels'].insert({"actorId": actorId, "ts": time.time(), "level":
level})
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
return ret
def actor_add_queue(self, actorId, command, data):
try:
if self.db["actors"].find_one(actorId=actorId):
self.actor_queue[actorId] = {"command": command, "data": data}
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
def actor_get_actors(self):
ret = {}
try:
for s in self.db["actors"]:
actorId = s["actorId"]
ret[actorId] = self.actor_get_info(actorId)
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
return ret
def actor_get_info(self, actorId):
ret = {}
try:
q = self.db["actors"].find_one(actorId=actorId)
ret["actorId"] = actorId
ret["maxLevel"] = "0x%x" % q["maxLevel"]
ret["actorType"] = q["actorType"]
q = self.db["actor_levels"].find_one(actorId=actorId, order_by="-ts")
ret["ts"] = q["ts"]
ret["level"] = "0x%x" % q["level"]
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
return ret
def actor_get_levels(self, actorId, limit=None):
ret = {}
try:
if self.db["actors"].find_one(actorId=actorId):
ret = self.actor_get_info(actorId)
if limit:
query = self.db["actor_levels"].find(actorId=actorId, _limit=limit)
else:
query = self.db["actor_levels"].find(actorId=actorId)
levels = []
for q in query:
levels.append({"ts": q["ts"], "value": "0x%x" % q["level"]})
ret["levels"] = levels
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
return ret
2019-11-05 01:18:25 +01:00
def actor_get_queue(self, actorId):
ret = {}
try:
if actorId in self.actor_queue:
ret = self.actor_queue.pop(actorId)
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
return ret
2019-11-05 01:18:25 +01:00
def sensor_get_info(self, sensorId):
ret = {}
try:
q = self.db["sensors"].find_one(sensorId=sensorId)
ret["sensorId"] = sensorId
ret["sensorType"] = q["sensorType"]
q = self.db["sensor_values"].find_one(sensorId=sensorId, order_by="-ts")
ret["ts"] = q["ts"]
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
return ret
2019-10-22 23:55:00 +02:00
def sensor_get_values(self, sensorId, min_ts, max_ts, limit=None):
ret = {}
try:
if self.db["sensors"].find_one(sensorId=sensorId):
ret = self.sensor_get_info(sensorId)
if limit:
query = self.db["sensor_values"].find(sensorId=sensorId,
ts={"between": [min_ts, max_ts]}, _limit=limit)
else:
query = self.db["sensor_values"].find(sensorId=sensorId,
ts={"between": [min_ts, max_ts]})
values = []
for q in query:
values.append({"ts": float(q["ts"]), "value": float(q["value"])})
ret["values"] = values
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
return ret
2019-10-22 23:55:00 +02:00
2019-11-05 01:18:25 +01:00
def sensor_get_sensors(self):
ret = {}
try:
for s in self.db["sensors"]:
sensorId = s["sensorId"]
ret[sensorId] = self.sensor_get_info(sensorId)
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
return ret
2019-10-22 23:55:00 +02:00
2019-11-05 01:18:25 +01:00
def sensor_add_value(self, sensorId, sensorType, value):
ret = {}
try:
if not self.db["sensors"].find_one(sensorId=sensorId):
self.db['sensors'].insert({"sensorId": sensorId, "sensorType": sensorType})
self.db['sensor_values'].insert({"sensorId": sensorId, "ts": time.time(), "value":
value})
except Exception as ex:
self.logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
2019-11-05 01:18:25 +01:00
return ret
2019-11-05 01:18:25 +01:00
app = Flask(__name__)
2019-11-05 01:18:25 +01:00
@app.route("/actor/command", methods=['POST'])
def actor_command():
ret = {}
try:
content = request.json
2019-11-05 01:18:25 +01:00
actorId = content.get("id")
command = content.get("command")
data = content.get("data")
core.actor_add_queue(actorId, command, data)
except Exception as ex:
logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
abort(400)
return make_response(jsonify(ret), 200)
2019-11-05 01:18:25 +01:00
@app.route("/actor/get", methods=['GET'])
def actor_get():
ret = core.actor_get_actors()
return make_response(jsonify(ret), 200)
@app.route("/actor/get_levels/<actorId>", methods=['GET'])
def actor_get_level(actorId):
ret = {}
2019-11-05 01:18:25 +01:00
if request.args.get("limit"):
limit=int(request.args.get("limit"))
else:
2019-11-05 01:18:25 +01:00
limit=None
logger.debug("actor/get_levels/%s, limit: %s" % (actorId, limit))
ret[actorId] = core.actor_get_levels(actorId, limit=limit)
2019-11-05 01:18:25 +01:00
return make_response(jsonify(ret), 200)
@app.route("/actor/update", methods=['POST'])
def actor_update():
ret = {}
try:
content = request.json
actorId = content.get("id")
actorType = content.get("type")
level = content.get("level")
maxLevel = content.get("maxLevel")
core.actor_add_level(actorId, actorType, maxLevel, level)
ret = core.actor_get_queue(actorId)
except Exception as ex:
logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
abort(400)
return make_response(jsonify(ret), 200)
2019-11-05 01:18:25 +01:00
@app.route("/sensor/get", methods=['GET'])
def sensor_get_sensors():
ret = core.sensor_get_sensors()
return make_response(jsonify(ret), 200)
2019-11-05 01:18:25 +01:00
@app.route("/sensor/get_values/<sensorId>", methods=['GET'])
def sensor_get_values(sensorId):
ret = {}
min_ts = 0
if request.args.get("min_ts"):
min_ts=int(request.args.get("min_ts"))
max_ts = inf
limit=None
2019-11-05 01:18:25 +01:00
if request.args.get("limit"):
limit=int(request.args.get("limit"))
if request.args.get("max_ts"):
max_ts=int(request.args.get("max_ts"))
logger.debug("sensor/get_values/%s, [%f, %f], limit: %s" % (sensorId, min_ts, max_ts, limit))
ret[sensorId] = core.sensor_get_values(sensorId, min_ts=min_ts, max_ts=max_ts, limit=limit)
return make_response(jsonify(ret), 200)
2019-11-05 01:18:25 +01:00
@app.route("/sensor/update", methods=['POST'])
def sensor_add_value():
ret = {}
try:
content = request.json
2019-11-05 01:18:25 +01:00
sensorId = content.get("id")
sensorType = content.get("type")
value = content.get("value")
2019-11-05 01:18:25 +01:00
ret = core.sensor_add_value(sensorId, sensorType, value)
except Exception as ex:
logger.error('Exception Type:%s, args:\n%s' % (type(ex).__name__, ex.args))
abort(400)
return make_response(jsonify(ret), 200)
2019-10-22 23:55:00 +02:00
if __name__ == "__main__":
args, config = setup()
2019-11-05 01:18:25 +01:00
core = Core(config['dbfile'], args.debug)
logger = Logger("main", args.debug).getLogger()
app.run(host='0.0.0.0', port=config['port'], debug=args.debugflask)