#!/usr/bin/env python3 from flask import Flask, request, json, jsonify, abort, make_response import logging import argparse import time import dataset import sys CONFIG_FILE = 'config.json' DB_FILE = 'db.sqlite' LIMIT=100 PORT = 5000 # TIMEOUT_CLIENT = 10 core = None # sensors NUM_VALUES = 1000 def setup(): # arguments parser = argparse.ArgumentParser(description='homecontrol') parser.add_argument('-p', '--port', dest='port', type=int, help='listening port') parser.add_argument('-c', '--config', dest='config', type=str, help='config file', default=CONFIG_FILE) parser.add_argument('-f', '--dbfile', dest='dbfile', type=str, help='database file', default=DB_FILE) 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') # parse arguments args = parser.parse_args() # initialize config config = {} try: config_file = open(args.config, 'r') config = json.load(config_file) except: pass # fill new keys with defaults if not config.get('port'): config['port'] = PORT if not config.get('dbfile'): config['dbfile'] = DB_FILE # overwrite with arguments if args.port: config['port'] = args.port if args.dbfile: config['dbfile'] = args.dbfile # save to file with open(args.config, 'w') as config_file: json.dump(config, config_file) return args, config 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 class Core: def __init__(self, dbfile, debug): self.logger = Logger("Core", debug).getLogger() self.logger.info("initialization starting...") self.actor_queue = {} self.db = dataset.connect('sqlite:///db.sqlite') self.logger.info("initialization complete.") def actor_add_level(self, actorId, actorType, maxLevel, level): ret = {} 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}) return ret def actor_add_queue(self, actorId, command, data): self.actor_queue[actorId] = {"command": command, "data": data} def actor_get_actors(self): ret = {} for s in self.db["actors"]: actorId = s["actorId"] ret[actorId] = self.actor_get_info(actorId) return ret def actor_get_info(self, actorId): ret = {} 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"] return ret def actor_get_levels(self, actorId, limit=None): ret = self.actor_get_info(actorId) levels = {} if limit: query = self.db["actor_levels"].find(actorId=actorId, _limit=limit) else: query = self.db["actor_levels"].find(actorId=actorId) k = query.keys for q in query: levels[q["ts"]] = "0x%x" % q["level"] ret["levels"] = levels return ret def actor_get_queue(self, actorId): ret = {} if actorId in self.actor_queue: ret = self.actor_queue.pop(actorId) return ret def sensor_get_info(self, sensorId): ret = {} 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"] return ret def sensor_get_values(self, sensorId, limit=None): ret = self.sensor_get_info(sensorId) values = {} if limit: query = self.db["sensor_values"].find(sensorId=sensorId, _limit=limit) else: query = self.db["sensor_values"].find(sensorId=sensorId) k = query.keys for q in query: values[q["ts"]] = q["value"] ret["values"] = values return ret def sensor_get_sensors(self): ret = {} for s in self.db["sensors"]: sensorId = s["sensorId"] ret[sensorId] = self.sensor_get_info(sensorId) return ret def sensor_add_value(self, sensorId, sensorType, value): ret = {} 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}) return ret app = Flask(__name__) @app.route("/actor/command", methods=['POST']) def actor_command(): ret = {} try: content = request.json actorId = content.get("id") command = content.get("command") data = content.get("data") if core.db["actors"].find_one(actorId=actorId): 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) @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/", methods=['GET']) def actor_get_level(actorId): ret = {} if request.args.get("limit"): limit=int(request.args.get("limit")) else: limit=None logger.debug("actor/get_levels/%s, limit: %s" % (actorId, limit)) if actorId == "all": for q in core.db["actors"]: s = q["actorId"] ret[s] = core.actor_get_levels(s, limit=limit) elif core.db["actors"].find_one(actorId=actorId): ret[actorId] = core.actor_get_levels(actorId, limit=limit) else: abort(404) 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) @app.route("/sensor/get", methods=['GET']) def sensor_get_sensors(): ret = core.sensor_get_sensors() return make_response(jsonify(ret), 200) @app.route("/sensor/get_values/", methods=['GET']) def sensor_get_values(sensorId): ret = {} if request.args.get("limit"): limit=int(request.args.get("limit")) else: limit=None logger.debug("sensor/get_values/%s, limit: %s" % (sensorId, limit)) if sensorId == "all": for q in core.db["sensors"]: s = q["sensorId"] ret[s] = core.sensor_get_values(s, limit=limit) elif core.db["sensors"].find_one(sensorId=sensorId): ret[sensorId] = core.sensor_get_values(sensorId, limit=limit) else: abort(404) return make_response(jsonify(ret), 200) @app.route("/sensor/update", methods=['POST']) def sensor_add_value(): ret = {} try: content = request.json sensorId = content.get("id") sensorType = content.get("type") value = content.get("value") 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) if __name__ == "__main__": args, config = setup() 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)