#!/usr/bin/python import os import sys import logging import json import bottle import gevent import geventwebsocket from gevent.pywsgi import WSGIServer from geventwebsocket.handler import WebSocketHandler from geventwebsocket import WebSocketError try: sys.dont_write_bytecode = True import config sys.dont_write_bytecode = False except: print("Could not import config file.") print("Copy config.py.EXAMPLE to config.py and adapt it for your setup.") exit(1) logging.basicConfig(level=config.log_level, format=config.log_format) log = logging.getLogger("kilncontrollerd") log.info("Starting kilncontrollerd") script_dir = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, script_dir + '/lib/') profile_path = os.path.join(script_dir, "storage", "profiles") from oven import Oven, Profile from ovenWatcher import OvenWatcher app = bottle.Bottle() oven = Oven() ovenWatcher = OvenWatcher(oven) @app.route('/') def index(): return bottle.redirect('/kilncontroller/index.html') @app.route('/kilncontroller/:filename#.*#') def send_static(filename): log.debug("serving %s" % filename) return bottle.static_file(filename, root=os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), "public")) def get_websocket_from_request(): env = bottle.request.environ wsock = env.get('wsgi.websocket') if not wsock: abort(400, 'Expected WebSocket request.') return wsock @app.route('/control') def handle_control(): wsock = get_websocket_from_request() log.info("websocket (control) opened") while True: try: message = wsock.receive() log.info("Received (control): %s" % message) msgdict = json.loads(message) if msgdict.get("cmd") == "RUN": log.info("RUN command received") profile_obj = msgdict.get('profile') if profile_obj: profile_json = json.dumps(profile_obj) profile = Profile(profile_json) oven.run_profile(profile) ovenWatcher.record(profile) elif msgdict.get("cmd") == "SIMULATE": log.info("SIMULATE command received") profile_obj = msgdict.get('profile') if profile_obj: profile_json = json.dumps(profile_obj) profile = Profile(profile_json) simulated_oven = Oven(simulate=True, time_step=0.05) simulation_watcher = OvenWatcher(simulated_oven) simulation_watcher.add_observer(wsock) # simulated_oven.run_profile(profile) # simulation_watcher.record(profile) elif msgdict.get("cmd") == "STOP": log.info("Stop command received") oven.abort_run() except WebSocketHandler.WebSocketError: break log.info("websocket (control) closed") @app.route('/storage') def handle_storage(): wsock = get_websocket_from_request() log.info("websocket (storage) opened") while True: try: message = wsock.receive() if not message: break log.debug("websocket (storage) received: %s" % message) try: msgdict = json.loads(message) except: msgdict = {} if message == "GET": log.info("GET command recived") wsock.send(get_profiles()) elif msgdict.get("cmd") == "DELETE": log.info("DELETE command received") profile_obj = msgdict.get('profile') if delete_profile(profile_obj): msgdict["resp"] = "OK" wsock.send(json.dumps(msgdict)) #wsock.send(get_profiles()) elif msgdict.get("cmd") == "PUT": log.info("PUT command received") profile_obj = msgdict.get('profile') force = msgdict.get('force', False) if profile_obj: #del msgdict["cmd"] if save_profile(profile_obj, force): msgdict["resp"] = "OK" else: msgdict["resp"] = "FAIL" log.debug("websocket (storage) sent: %s" % message) wsock.send(json.dumps(msgdict)) wsock.send(get_profiles()) except WebSocketHandler.WebSocketError: break log.info("websocket (storage) closed") @app.route('/config') def handle_config(): wsock = get_websocket_from_request() log.info("websocket (config) opened") while True: try: message = wsock.receive() wsock.send(get_config()) except WebSocketHandler.WebSocketError: break log.info("websocket (config) closed") @app.route('/status') def handle_status(): wsock = get_websocket_from_request() ovenWatcher.add_observer(wsock) log.info("websocket (status) opened") while True: try: message = wsock.receive() wsock.send("Your message was: %r" % message) except WebSocketHandler.WebSocketError: break log.info("websocket (status) closed") def get_profiles(): try: profile_files = os.listdir(profile_path) except: profile_files = [] profiles = [] for filename in profile_files: with open(os.path.join(profile_path, filename), 'r') as f: profiles.append(json.load(f)) return json.dumps(profiles) def save_profile(profile, force=False): profile_json = json.dumps(profile) filename = profile['name'] + ".json" filepath = os.path.join(profile_path, filename) if not force and os.path.exists(filepath): log.error("Could not write, %s already exists" % filepath) return False with open(filepath, 'w+') as f: f.write(profile_json) f.close() log.info("Wrote %s" % filepath) return True def delete_profile(profile): # profile_json = json.dumps(profile) filename = profile['name'] + ".json" filepath = os.path.join(profile_path, filename) os.remove(filepath) log.info("Deleted %s" % filepath) return True def get_config(): return json.dumps({"temp_scale": config.temp_scale, "time_scale_slope": config.time_scale_slope, "time_scale_profile": config.time_scale_profile, "kwh_rate": config.kwh_rate, "currency_type": config.currency_type}) def main(): ip = config.listening_ip port = config.listening_port log.info("listening on %s:%d" % (ip, port)) server = WSGIServer((ip, port), app, handler_class=WebSocketHandler) server.serve_forever() if __name__ == "__main__": main()