diff --git a/arch/PKGBUILD b/arch/PKGBUILD index f6b40f7..4b94ae9 100644 --- a/arch/PKGBUILD +++ b/arch/PKGBUILD @@ -16,7 +16,6 @@ depends=('python3' 'mosquitto' 'mpg123' 'python-flask-wtf' - 'python-flask-socketio' 'python-paho-mqtt' 'chromium' 'xf86-video-fbdev' diff --git a/pydoorlock/Doorlock.py b/pydoorlock/Doorlock.py index 17be03f..3f2a8ad 100644 --- a/pydoorlock/Doorlock.py +++ b/pydoorlock/Doorlock.py @@ -24,7 +24,7 @@ from serial import Serial from threading import Thread from time import sleep from os.path import join - +import gevent from .Door import DoorState from .Protocol import Protocol diff --git a/pydoorlock/EventClient.py b/pydoorlock/EventClient.py new file mode 100644 index 0000000..5ad257d --- /dev/null +++ b/pydoorlock/EventClient.py @@ -0,0 +1,34 @@ +import requests +import threading +import json + +class EventClient: + def __init__(self,url): + self.r = requests.get(url,stream=True) + print("connected") + if self.r.encoding is None: + self.r.encoding = 'utf8' + + def parseEvent(self,line_buf): + ret = dict() + for line in line_buf: + if line: + k,v = line.decode().split(':',1) + ret[k] = v + return ret + + def events(self): + lines = self.r.iter_lines() + line_buf = [] + while True: + line_buf.append(next(lines)) + if line_buf: + if not line_buf[-1].decode(): + yield self.parseEvent(line_buf) + line_buf = [] + +if __name__ == "__main__": + e = EventClient("http://localhost:8080/push") + for evt in e.events(): + print(json.loads(evt['data'])) + diff --git a/pydoorlock/WebApp.py b/pydoorlock/WebApp.py index b1c3046..c5748c0 100644 --- a/pydoorlock/WebApp.py +++ b/pydoorlock/WebApp.py @@ -16,9 +16,11 @@ details. """ import logging +import json +import gevent +import threading -from flask import abort, Flask, jsonify, render_template, request -from flask_socketio import SocketIO +from flask import abort, Flask, jsonify, render_template, request, Response from flask_wtf import FlaskForm from wtforms import PasswordField, StringField, SubmitField from wtforms.validators import DataRequired, Length @@ -28,19 +30,46 @@ from .Doorlock import DoorlockResponse from .Authenticator import AuthMethod log = logging.getLogger() - webapp = Flask(__name__) -socketio = SocketIO(webapp, async_mode='threading') +evt = threading.Event() +json_push_state = "" def emit_doorstate(response=None): - state = logic.state + global json_push_state + json_dict = dict() + if response: message = str(response) else: - message = str(state) - socketio.emit('status', {'led': state.to_img(), 'message': message}) + message = str(logic.state) + json_dict['message'] = message + json_dict['status'] = logic.state.value + json_push_state = json.dumps(json_dict) + + #Notify push clients + evt.set() + evt.clear() + +def event_str(): + return "data: {}\n\n".format(json_push_state) + +def push_state(): + try: + yield event_str() + while True: + evt.wait() + yield event_str() + except GeneratorExit: + return + +def push_refresh(): + while True: + sleep(10) + emit_doorstate() + evt.set() + evt.clear() class AuthenticationForm(FlaskForm): username = StringField('Username', [Length(min=3, max=25)]) @@ -64,13 +93,6 @@ class AuthenticationForm(FlaskForm): return True - -@socketio.on('request_status') -@socketio.on('connect') -def on_connect(): - emit_doorstate() - - @webapp.route('/display') def display(): return render_template('display.html', @@ -78,19 +100,25 @@ def display(): title=title, welcome=welcome) +@webapp.route('/push') +def push(): + if not json_push_state: + emit_doorstate() + return Response(push_state(),mimetype="text/event-stream") + @webapp.route('/api', methods=['POST']) def api(): def json_response(response, msg=None): - json = dict() - json['err'] = response.value - json['msg'] = str(response) if msg is None else msg + json_dict = dict() + json_dict['err'] = response.value + json_dict['msg'] = str(response) if msg is None else msg if response == DoorlockResponse.Success or \ response == DoorlockResponse.AlreadyActive: # TBD: Remove 'open'. No more users. Still used in App Version 2.1.1! - json['open'] = logic.state.is_open() - json['status'] = logic.state.value - return jsonify(json) + json_dict['open'] = logic.state.is_open() + json_dict['status'] = logic.state.value + return jsonify(json_dict) user = request.form.get('user') password = request.form.get('pass') @@ -137,6 +165,7 @@ def home(): desired_state = authentication_form.desired_state log.info(' desired state: %s' % desired_state) log.info(' current state: %s' % logic.state) + response = logic.request(desired_state, credentials) log.info(' response: %s' % response) @@ -154,6 +183,7 @@ def home(): def webapp_run(cfg, my_logic, status, version, template_folder, static_folder): global logic logic = my_logic + state = logic.state debug = cfg.boolean('DEBUG') @@ -176,4 +206,5 @@ def webapp_run(cfg, my_logic, status, version, template_folder, static_folder): webapp.config['SECRET_KEY'] = cfg.str('SECRET_KEY') webapp.template_folder = template_folder webapp.static_folder = static_folder - socketio.run(webapp, host=host, port=8080, use_reloader=False, debug=debug) + webapp.debug = debug + webapp.run() diff --git a/share/doorlockd/templates/display.html b/share/doorlockd/templates/display.html index cfb34f7..f1d12a6 100644 --- a/share/doorlockd/templates/display.html +++ b/share/doorlockd/templates/display.html @@ -13,23 +13,27 @@ {% endblock %}