diff --git a/default.nix b/default.nix index ea1a0e0..549da4e 100644 --- a/default.nix +++ b/default.nix @@ -6,10 +6,7 @@ pkgs.python3Packages.buildPythonPackage { src = ./.; - propagatedBuildInputs = with pkgs; [ - python3Packages.gunicorn - python3Packages.flask - python3Packages.paho-mqtt - python3Packages.pyyaml + propagatedBuildInputs = with pkgs.python3Packages; [ + gunicorn flask paho-mqtt pyyaml setuptools ]; } diff --git a/lights_web/__init__.py b/lights_web/__init__.py index 69aec11..9c38add 100644 --- a/lights_web/__init__.py +++ b/lights_web/__init__.py @@ -16,107 +16,105 @@ import atexit # remove temporary files created by resource_filename atexit.register(cleanup_resources, force=True) -secrets_path = Path(os.environ.get("LIGHTS_WEB_SECRETS", 'secrets.yaml')) -config_path = Path(os.environ.get("LIGHTS_WEB_CONFIG", 'config.yaml')) -config = yaml.safe_load(config_path.read_text()) -config.update(yaml.safe_load(secrets_path.read_text())) - -c = threading.Condition() -application = flask.Flask(__name__) -application.msg="ab" -application.lights = { lid: False for lid in config['lights'] } - -application.logger.removeHandler(flask.logging.default_handler) -logging.basicConfig(level=logging.DEBUG) - - -def on_message(client,userdata,message): - c.acquire() - for lid, cfg in config['lights'].items(): - if cfg['mqtt_path'] == message.topic: - if message.payload == b'true': - application.lights[lid] = True - elif message.payload == b'false': - application.lights[lid] = False - - c.release() - - -def on_connect(client, userdata, rc, l): - logging.info(f"connected") - for lid, cfg in config['lights'].items(): - logging.info(f"subscribing: {cfg}") - client.subscribe(cfg['mqtt_path']) - - -mc = mqtt.client.Client() -mc.username_pw_set(config['mqtt_rw_username'], config['mqtt_rw_password']) -mc.on_connect = on_connect -mc.on_message = on_message -mc.connect_async(config["mqtt_server"]) -mc.enable_logger() -mc.loop_start() - - -@application.route("/") -def main(): - return flask.send_file(resource_filename(__name__, 'static/index.html')) - -@application.route("/status") -def status(): - print("Main Thread: " + str(threading.current_thread())) - c.acquire() - st = {"lights" : application.lights} - c.release() - return json.dumps(st) - - -@application.route("/config") -def get_config(): - return flask.jsonify({ - "mqtt_server": config["mqtt_server"], - "mqtt_port": config["mqtt_port"], - "mqtt_username": config["mqtt_ro_username"], - "mqtt_password": config["mqtt_ro_password"], - "lights": config['lights'] - }) - -def publish(path, payload): - mc.publish(path, payload, qos=1) - -@application.route('/light//on/set', methods=['POST']) -def set_light(lid): - try: - path = config["lights"][lid]["mqtt_path"] - except KeyError: - return flask.jsonify({"ok": False}) - - publish(path + '/set', "true") - return flask.jsonify({"ok": True}) - - -@application.route('/light//on/toggle', methods=['POST']) -def toggle_light(lid): - try: - cfg = config["lights"][lid] - toggle = cfg.get('toggle', False) - path = cfg["mqtt_path"] - except KeyError: - print(config["lights"]) - logging.exception("toggle exception") - return flask.jsonify({"ok": False}) - - if toggle: - publish(path + '/toggle', "true") - elif application.lights[lid]: - publish(path + '/set', "false") - else: +def app(): + secrets_path = Path(os.environ.get("LIGHTS_WEB_SECRETS", 'secrets.yaml')) + config_path = Path(os.environ.get("LIGHTS_WEB_CONFIG", 'config.yaml')) + config = yaml.safe_load(config_path.read_text()) + config.update(yaml.safe_load(secrets_path.read_text())) + + c = threading.Condition() + application = flask.Flask(__name__) + application.msg="ab" + application.lights = { lid: False for lid in config['lights'] } + + def on_message(client,userdata,message): + c.acquire() + for lid, cfg in config['lights'].items(): + if cfg['mqtt_path'] == message.topic: + if message.payload == b'true': + application.lights[lid] = True + elif message.payload == b'false': + application.lights[lid] = False + + c.release() + + + def on_connect(client, userdata, rc, l): + logging.info(f"connected") + for lid, cfg in config['lights'].items(): + logging.info(f"subscribing: {cfg}") + client.subscribe(cfg['mqtt_path']) + + + mc = mqtt.client.Client() + mc.username_pw_set(config['mqtt_rw_username'], config['mqtt_rw_password']) + mc.on_connect = on_connect + mc.on_message = on_message + mc.connect_async(config["mqtt_server"]) + mc.enable_logger() + mc.loop_start() + + + @application.route("/") + def main(): + return flask.send_file(resource_filename(__name__, 'static/index.html')) + + @application.route("/status") + def status(): + print("Main Thread: " + str(threading.current_thread())) + c.acquire() + st = {"lights" : application.lights} + c.release() + return json.dumps(st) + + + @application.route("/config") + def get_config(): + return flask.jsonify({ + "mqtt_server": config["mqtt_server"], + "mqtt_port": config["mqtt_ws_port"], + "mqtt_username": config["mqtt_ro_username"], + "mqtt_password": config["mqtt_ro_password"], + "lights": config['lights'] + }) + + def publish(path, payload): + mc.publish(path, payload, qos=1) + + @application.route('/light//on/set', methods=['POST']) + def set_light(lid): + try: + path = config["lights"][lid]["mqtt_path"] + except KeyError: + return flask.jsonify({"ok": False}) + publish(path + '/set', "true") - return flask.jsonify({"ok": True}) + return flask.jsonify({"ok": True}) + + + @application.route('/light//on/toggle', methods=['POST']) + def toggle_light(lid): + try: + cfg = config["lights"][lid] + toggle = cfg.get('toggle', False) + path = cfg["mqtt_path"] + except KeyError: + print(config["lights"]) + logging.exception("toggle exception") + return flask.jsonify({"ok": False}) + + if toggle: + publish(path + '/toggle', "true") + elif application.lights[lid]: + publish(path + '/set', "false") + else: + publish(path + '/set', "true") + return flask.jsonify({"ok": True}) + + return application def run_development(): - application.run(host='127.0.0.1',port=8000,debug=True) - + app().run(host='127.0.0.1',port=8000,debug=True) if __name__ == "__main__": run_development()