mirror of
https://github.com/binary-kitchen/doorlockd
synced 2024-12-22 10:24:26 +01:00
Reimplement doorlockd in python
Signed-off-by: Ralf Ramsauer <ralf@binary-kitchen.de>
This commit is contained in:
parent
020ac1b38b
commit
eeafa6350f
280
doorlockd-new/doorlockd.py
Executable file
280
doorlockd-new/doorlockd.py
Executable file
@ -0,0 +1,280 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from enum import Enum
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
from random import sample
|
||||
from serial import Serial
|
||||
|
||||
from flask import Flask, render_template, request, Markup
|
||||
from flask_bootstrap import Bootstrap
|
||||
from flask_socketio import SocketIO
|
||||
from flask_wtf import FlaskForm
|
||||
|
||||
from wtforms import PasswordField, StringField, SubmitField
|
||||
from wtforms.validators import DataRequired, Length
|
||||
|
||||
__author__ = 'Ralf Ramsauer'
|
||||
__copyright = 'Copyright (c) Ralf Ramsauer, 2018'
|
||||
__license__ = 'GPLv2'
|
||||
__email__ = 'ralf@binary-kitchen.de'
|
||||
__status__ = 'Development'
|
||||
__maintainer__ = 'Ralf Ramsauer'
|
||||
__version__ = '0.01a'
|
||||
|
||||
log_level = logging.DEBUG
|
||||
date_fmt = '%Y-%m-%d %H:%M:%S'
|
||||
log_fmt = '%(asctime)-15s %(levelname)-8s %(message)s'
|
||||
log = logging.getLogger()
|
||||
|
||||
default_serial = '/dev/ttyS0'
|
||||
default_ldap_uri = 'ldaps://ldap1.binary.kitchen/ ' \
|
||||
'ldaps://ldap2.binary.kitchen/ ' \
|
||||
'ldaps://ldapm.binary.kitchen/'
|
||||
default_binddn = 'cn=%s,ou=people,dc=binary-kitchen,dc=de'
|
||||
|
||||
html_title = 'Binary Kitchen Doorlock (%s - v%s)' % (__status__, __version__)
|
||||
|
||||
webapp = Flask(__name__)
|
||||
webapp.config['SECRET_KEY'] = 'foobar'
|
||||
socketio = SocketIO(webapp, async_mode=None)
|
||||
Bootstrap(webapp)
|
||||
|
||||
# copied from sudo
|
||||
eperm_insults = {
|
||||
'Wrong! You cheating scum!',
|
||||
'And you call yourself a Rocket Scientist!',
|
||||
'No soap, honkie-lips.',
|
||||
'Where did you learn to type?',
|
||||
'Are you on drugs?',
|
||||
'My pet ferret can type better than you!',
|
||||
'You type like i drive.',
|
||||
'Do you think like you type?',
|
||||
'Your mind just hasn\'t been the same since the electro-shock, has it?',
|
||||
'Maybe if you used more than just two fingers...',
|
||||
'BOB says: You seem to have forgotten your passwd, enter another!',
|
||||
'stty: unknown mode: doofus',
|
||||
'I can\'t hear you -- I\'m using the scrambler.',
|
||||
'The more you drive -- the dumber you get.',
|
||||
'Listen, broccoli brains, I don\'t have time to listen to this trash.',
|
||||
'I\'ve seen penguins that can type better than that.',
|
||||
'Have you considered trying to match wits with a rutabaga?',
|
||||
'You speak an infinite deal of nothing',
|
||||
}
|
||||
|
||||
|
||||
def choose_insult():
|
||||
return(sample(eperm_insults, 1)[0])
|
||||
|
||||
|
||||
class AuthMethod(Enum):
|
||||
LDAP_USER_PW = 1
|
||||
|
||||
|
||||
class DoorState(Enum):
|
||||
Close = 1
|
||||
Open = 2
|
||||
|
||||
def to_img(self):
|
||||
led = 'red'
|
||||
if self == DoorState.Open:
|
||||
led = 'green'
|
||||
return '<img src="static/led-%s.png">' % led
|
||||
|
||||
def to_html(self):
|
||||
if self == DoorState.Open:
|
||||
return 'Offen'
|
||||
return 'Zu'
|
||||
|
||||
|
||||
class LogicResponse(Enum):
|
||||
Success = 0
|
||||
Perm = 1
|
||||
AlreadyLocked = 2
|
||||
AlreadyOpen = 3
|
||||
Inval = 4
|
||||
LDAP = 5
|
||||
|
||||
def to_html(self):
|
||||
if self == LogicResponse.Success:
|
||||
return 'Yo, passt.'
|
||||
elif self == LogicResponse.Perm:
|
||||
return choose_insult()
|
||||
elif self == LogicResponse.AlreadyLocked:
|
||||
return 'Narf. Schon zu.'
|
||||
elif self == LogicResponse.AlreadyOpen:
|
||||
return 'Schon offen, treten Sie ein!'
|
||||
elif self == LogicResponse.Inval:
|
||||
return 'Das was du willst geht nicht.'
|
||||
elif self == LogicResponse.LDAP:
|
||||
return 'Moep! Geh LDAP fixen!'
|
||||
|
||||
return 'Bitte spezifizieren Sie.'
|
||||
|
||||
|
||||
class DoorHandler:
|
||||
state = DoorState.Close
|
||||
|
||||
def __init__(self, device):
|
||||
self.serial = Serial(device, baudrate=9600, bytesize=8, parity='N',
|
||||
stopbits=1, timeout=1)
|
||||
self.thread = Thread(target=self.thread_worker)
|
||||
self.thread.start()
|
||||
|
||||
def send_command(self, cmd):
|
||||
print('sending cmd %c' % cmd)
|
||||
|
||||
def clear_buffer(self):
|
||||
print('clearing buffer...')
|
||||
|
||||
def thread_worker(self):
|
||||
while True:
|
||||
self.clear_buffer()
|
||||
|
||||
if self.state == DoorState.Open:
|
||||
self.send_command('u')
|
||||
elif self.state == DoorState.Close:
|
||||
self.send_command('l')
|
||||
sleep(1)
|
||||
|
||||
def open(self):
|
||||
if self.state == DoorState.Open:
|
||||
return LogicResponse.AlreadyOpen
|
||||
|
||||
self.state = DoorState.Open
|
||||
return LogicResponse.Success
|
||||
|
||||
def close(self):
|
||||
if self.state == DoorState.Close:
|
||||
return LogicResponse.AlreadyLocked
|
||||
|
||||
self.state = DoorState.Close
|
||||
return LogicResponse.Success
|
||||
|
||||
def request(self, state):
|
||||
if state == DoorState.Close:
|
||||
return self.close()
|
||||
elif state == DoorState.Open:
|
||||
return self.open()
|
||||
|
||||
|
||||
class Logic:
|
||||
def __init__(self, device):
|
||||
self.door_handler = DoorHandler(device)
|
||||
|
||||
def _try_auth_ldap(self, user, password):
|
||||
log.info('Trying to LDAP auth (user, password) as user %s', user)
|
||||
return LogicResponse.Success
|
||||
return LogicResponse.LDAP
|
||||
|
||||
def try_auth(self, credentials):
|
||||
method = credentials[0]
|
||||
if method == AuthMethod.LDAP_USER_PW:
|
||||
return self._try_auth_ldap(credentials[1], credentials[2])
|
||||
|
||||
return LogicResponse.Inval
|
||||
|
||||
def _request(self, state, credentials):
|
||||
err = self.try_auth(credentials)
|
||||
if err != LogicResponse.Success:
|
||||
return err
|
||||
return self.door_handler.request(state)
|
||||
|
||||
def request(self, state, credentials):
|
||||
err = self._request(state, credentials)
|
||||
return err
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
return self.door_handler.state
|
||||
|
||||
|
||||
class AuthenticationForm(FlaskForm):
|
||||
username = StringField('Username', [Length(min=4, max=25)])
|
||||
password = PasswordField('Password', [DataRequired()])
|
||||
open = SubmitField('Open')
|
||||
close = SubmitField('Close')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
FlaskForm.__init__(self, *args, **kwargs)
|
||||
self.desired_state = DoorState.Close
|
||||
|
||||
def validate(self):
|
||||
if not FlaskForm.validate(self):
|
||||
return False
|
||||
|
||||
if self.open.data:
|
||||
self.desired_state = DoorState.Open
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def emit_status(message=None):
|
||||
led = logic.state.to_img()
|
||||
if message is None:
|
||||
message = logic.state.to_html()
|
||||
else:
|
||||
message = message.to_html()
|
||||
|
||||
socketio.emit('status', {'led': led, 'message': message})
|
||||
|
||||
|
||||
@socketio.on('connect')
|
||||
def on_connect():
|
||||
emit_status()
|
||||
|
||||
|
||||
@webapp.route('/display')
|
||||
def display():
|
||||
return render_template('display.html')
|
||||
|
||||
|
||||
@webapp.route('/', methods=['GET', 'POST'])
|
||||
def home():
|
||||
authentication_form = AuthenticationForm()
|
||||
response = None
|
||||
|
||||
if request.method == 'POST' and authentication_form.validate():
|
||||
user = authentication_form.username.data
|
||||
password = authentication_form.password.data
|
||||
credentials = AuthMethod.LDAP_USER_PW, user, password
|
||||
|
||||
log.info('Incoming request from %s' % user)
|
||||
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)
|
||||
|
||||
# Don't trust python, zero credentials
|
||||
user = password = credentials = None
|
||||
|
||||
emit_status(response)
|
||||
|
||||
return render_template('index.html',
|
||||
authentication_form=authentication_form,
|
||||
response=response,
|
||||
state_text=logic.state.to_html(),
|
||||
state_img=Markup(logic.state.to_img()),
|
||||
title=html_title)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser('doorlockd', 'Binary Kitchen doorlockd')
|
||||
parser.add_argument('-s', '--serial', default=default_serial, type=str)
|
||||
args = parser.parse_args()
|
||||
|
||||
logging.basicConfig(level=log_level, stream=sys.stdout,
|
||||
format=log_fmt, datefmt=date_fmt)
|
||||
log.info('Starting doorlockd')
|
||||
log.info('Using serial port: %s' % args.serial)
|
||||
|
||||
logic = Logic(args.serial)
|
||||
|
||||
socketio.run(webapp, port=8080)
|
||||
|
||||
sys.exit(0)
|
BIN
doorlockd-new/static/led-green.png
Normal file
BIN
doorlockd-new/static/led-green.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
doorlockd-new/static/led-red.png
Normal file
BIN
doorlockd-new/static/led-red.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
81
doorlockd-new/static/logo.svg
Normal file
81
doorlockd-new/static/logo.svg
Normal file
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="200"
|
||||
height="180"
|
||||
id="svg4662"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="New document 4">
|
||||
<defs
|
||||
id="defs4664" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8"
|
||||
inkscape:cx="150.41655"
|
||||
inkscape:cy="115.14291"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1031"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="25"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata4667">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-872.36218)">
|
||||
<g
|
||||
id="g5022"
|
||||
transform="matrix(1.2255371,0,0,1.2255371,-230.84023,1130.0139)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3021"
|
||||
d="m 244.28546,-205.07285 c -13.55524,0.0103 -24.54012,7.56438 -24.53305,16.88361 0.006,7.85919 7.80317,14.5031 18.40741,16.23346 2.21111,0.3608 3.4598,0.3416 4.77455,0.40635 0.27656,0.0138 0.50974,0.29954 0.49777,0.54856 -0.012,0.24902 -0.272,0.52169 -0.54857,0.50793 -1.96704,-0.0979 -2.21207,-0.0854 -3.67741,-0.22349 l 0,4.96757 -2.48886,0.0101 c -0.96509,0.004 -1.80211,0.7736 -1.74729,1.73712 l 2.05204,36.06308 c 0.0548,0.96352 0.78464,1.66853 1.74728,1.73712 16.97546,1.20947 34.16131,1.28134 51.56512,-0.0406 0.96231,-0.0731 1.68392,-0.7735 1.73713,-1.73712 l 1.99108,-36.06307 c 0.0532,-0.96362 -0.77204,-1.73713 -1.73712,-1.73713 l -1.99109,0 -0.0101,-6.41008 c -0.59278,0.0685 -1.30174,0.1021 -2.28569,0.10158 -0.28484,-1.4e-4 -0.55101,-0.28356 -0.54856,-0.5384 0.003,-0.25484 0.27393,-0.52379 0.55872,-0.51809 1.08555,0.0217 1.80456,0.0155 2.37712,-0.1219 7.72295,-1.8535 13.20034,-6.75436 13.19604,-12.43415 -0.006,-7.34241 -9.17359,-13.28587 -20.46961,-13.2773 -5.9236,0.004 -11.26017,1.64843 -14.99411,4.26661 0.71202,0.9635 1.31636,1.69784 1.99109,2.19426 0.68758,0.50589 1.45609,0.794 2.65139,0.85333 0.27658,0.0137 0.50975,0.29955 0.49778,0.54856 -0.012,0.24902 -0.272,0.52167 -0.54857,0.50793 -1.35281,-0.0672 -2.42214,-0.38317 -3.23044,-1.05649 -0.98588,-0.82125 -1.47763,-1.14899 -2.34664,-2.6514 -3.62458,-6.26641 -12.45917,-10.76586 -22.88737,-10.75795 z m 9.38656,47.75563 3.62662,0.0406 c 0.8264,0.01 1.48105,0.67707 1.473,1.50347 l -0.21333,22.39974 c -0.008,0.82641 -0.68724,1.49312 -1.51363,1.48316 l -3.61647,-0.0406 c -0.82639,-0.01 -1.48104,-0.67707 -1.473,-1.50348 l 0.21334,-22.39974 c 0.008,-0.82641 0.67708,-1.49311 1.50347,-1.48316 z m 19.08803,0.19302 c 4.59464,0.0456 8.26648,5.6641 8.198,12.55604 -0.0685,6.89195 -3.83701,12.43916 -8.43164,12.39351 -4.59463,-0.0456 -8.26648,-5.6641 -8.19801,-12.55604 0.0685,-6.89195 3.83702,-12.43916 8.43165,-12.39351 z"
|
||||
style="fill:#ccbbbb;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="use3078"
|
||||
d="m 200.30883,-134.33843 c -1.39853,0.0404 -3.12049,0.56027 -3.67742,1.91997 l -3.37266,8.22848 c -0.84129,2.05396 1.37784,4.43092 2.53965,4.90661 l 35.56531,14.55729 c 0.38962,-0.3884 0.93039,-0.63562 1.52379,-0.65015 1.22875,-0.0301 2.2556,0.96549 2.28569,2.19426 0.15008,0.0661 0.30962,0.14098 0.43682,0.19302 1.16194,0.47535 2.48075,-0.0876 2.95615,-1.24951 l 1.43237,-3.50473 16.57885,6.78596 4.97772,-2.1841 -20.06326,-8.21832 1.43237,-3.50472 c 0.4754,-1.16193 -0.0761,-2.49428 -1.23935,-2.96632 l -0.43682,-0.17269 c -0.39626,0.46577 -0.98624,0.76607 -1.6457,0.78221 -1.22876,0.0301 -2.29115,-1.05984 -2.26537,-2.39743 -12.25687,-5.07793 -24.37983,-9.98145 -35.46372,-14.5065 -0.36093,-0.14735 -0.92873,-0.23168 -1.56442,-0.21333 z m -0.0813,4.15487 c 0.68786,-0.0126 1.39645,0.0653 1.94029,0.28444 11.52178,4.64268 22.39838,9.14152 33.89929,13.83603 0.33307,0.14692 0.49168,0.61064 0.36571,0.91428 -0.12597,0.30363 -0.56708,0.52359 -0.90411,0.38602 l -33.76723,-13.77508 -0.0101,0 c -1.42005,-0.57618 -2.57387,-0.25535 -3.23044,0.57905 -0.2481,0.31529 -0.77308,0.39811 -1.04634,0.17269 -0.27326,-0.22541 -0.2957,-0.76564 -0.0305,-1.06665 0.83707,-0.94999 1.88567,-1.31433 2.78346,-1.33078 z m -1.09713,6.70468 c 0.0935,-0.006 0.18575,0.0105 0.28444,0.0508 11.49444,4.69486 22.39412,9.17072 33.88913,13.87666 0.34309,0.14046 0.52212,0.61406 0.39619,0.92444 -0.12594,0.31037 -0.58137,0.52653 -0.92444,0.38602 l -33.82818,-13.85635 c -0.38694,-0.15848 -0.54846,-0.61414 -0.42666,-0.93459 0.087,-0.22894 0.32917,-0.42985 0.60952,-0.44698 z m 82.01048,28.36285 -5.31296,2.041882 32.64979,13.368734 c 0.25004,1.079745 3.14683,3.021327 5.22152,3.972018 1.30859,0.599644 2.67177,1.086854 4.0025,1.635536 0.91278,-2.256918 1.83518,-4.51491 2.76314,-6.765636 -1.33528,-0.537581 -2.63001,-1.16066 -3.99234,-1.625378 -1.73375,-0.59141 -5.10658,-1.391879 -6.52183,-0.833006 l -28.80982,-11.79415 z"
|
||||
style="fill:#ccbbbb;fill-opacity:1;fill-rule:nonzero;stroke:none" />
|
||||
<g
|
||||
transform="matrix(0.32303566,-0.14109669,0.14109669,0.32303566,99.129267,-226.69717)"
|
||||
id="use3083">
|
||||
<path
|
||||
style="fill:#ccbbbb;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 900.1875,443.75 -10.0625,0.0312 c -2.06742,0.006 -3.71875,1.65132 -3.71875,3.71875 l 0,6.25 -14.875,9.1875 C 822.66476,464.22979 769.15433,465.92087 718,467.4687 c -3.86018,0.1168 -6.954,3.13809 -6.9375,7 l 0.0312,7.3125 c -4.39379,0.1562 -8.77864,0.31969 -13.125,0.40625 0.97303,-5.55653 -0.58392,-11.07117 -3.84375,-15.125 -3.90015,-4.85012 -9.63745,-7.59553 -16.6875,-8.375 -1.77081,-0.19579 -3.69096,-0.27617 -5.65625,-0.15625 -1.96529,0.11992 -3.96613,0.45055 -5.90625,1.0625 -3.88023,1.22388 -7.73646,3.96623 -9.0625,8.53125 -1.13246,3.89857 -1.08251,8.27896 1.21875,12 2.30126,3.72104 6.66466,6.31703 12.8125,7.25 5.20014,0.78916 10.38378,1.20262 15.5625,1.375 -0.42767,0.29707 -0.71554,0.66894 -1.1875,0.9375 -3.16064,1.79846 -7.2586,2.82575 -11.21875,3 -16.17998,0.71196 -33.27007,1.52537 -49.75,0.90625 l -0.21875,6.5 c 16.86139,0.63344 34.08845,-0.19511 50.25,-0.90625 4.85233,-0.21352 9.86708,-1.40312 14.15625,-3.84375 2.80877,-1.59825 5.26565,-3.83995 7.0625,-6.625 5.2263,-0.0543 10.41482,-0.22176 15.59375,-0.40625 l 0.0312,4.875 c 0.0248,3.86187 3.07592,6.91592 6.9375,6.96875 50.79894,0.69498 105.04842,1.35105 153.5625,3.96875 l 14.875,9.125 0.0312,6.25 c 0.0103,2.06745 1.65133,3.72517 3.71875,3.71875 l 10.0625,-0.0312 c 2.06742,-0.006 3.75283,-1.65128 3.75,-3.71875 l -0.0312,-22.84375 127.21875,-0.25 c 2.4965,-0.005 4.5,-2.00347 4.5,-4.5 l 0,-4.78125 31.7188,-0.0625 c 2.1455,-0.004 8.1914,-1.72948 8.1874,-3.875 0,-2.14552 -6.0732,-3.84798 -8.2187,-3.84375 l -31.7187,0.0625 0,-4.78125 c 0,-2.49653 -2.0348,-4.50429 -4.5313,-4.5 L 904,470.3125 903.9375,447.46875 c -0.006,-2.06743 -1.68258,-3.72517 -3.75,-3.71875 z M 674.5,465.03125 c 0.76399,0.0155 1.53642,0.0461 2.25,0.125 5.62398,0.62179 9.55318,2.43804 12.375,6.0625 2.29548,2.94841 3.4456,6.73828 2.3125,10.96875 -6.61366,-0.0371 -13.17428,-0.27106 -19.625,-1.25 -4.90375,-0.74418 -7.17641,-2.43226 -8.28125,-4.21875 -1.10484,-1.78649 -1.24006,-4.12594 -0.46875,-6.78125 0.62042,-2.13582 2.1484,-3.33567 4.75,-4.15625 1.3008,-0.41029 2.83201,-0.6234 4.375,-0.71875 0.77149,-0.0477 1.54851,-0.0468 2.3125,-0.0312 z"
|
||||
transform="matrix(0.92218368,0.00169429,-0.00169429,0.92218368,-452.50678,78.944729)"
|
||||
id="path3858"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssccssccasssssscssccssccssccsssscsscscscsscssssacssssss" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.2 KiB |
25
doorlockd-new/templates/display.html
Normal file
25
doorlockd-new/templates/display.html
Normal file
@ -0,0 +1,25 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.min.js"></script>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
$(document).ready(function() {
|
||||
var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port)
|
||||
socket.on('connect', function() {
|
||||
socket.emit('connected');
|
||||
});
|
||||
socket.on('status', function(status) {
|
||||
$('#led').html(status.led)
|
||||
$('#message').html(status.message)
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Willkommen in der Binary Kitchen!</h1>
|
||||
<div id="led"></div>
|
||||
<div id="message"></div>
|
||||
{{ super() }}
|
||||
{% endblock %}
|
12
doorlockd-new/templates/formhelpers.html
Normal file
12
doorlockd-new/templates/formhelpers.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% macro render_field(field) %}
|
||||
<dt>{{ field.label }}
|
||||
<dd>{{ field(**kwargs)|safe }}
|
||||
{% if field.errors %}
|
||||
<ul class=errors>
|
||||
{% for error in field.errors %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</dd>
|
||||
{% endmacro %}
|
55
doorlockd-new/templates/index.html
Normal file
55
doorlockd-new/templates/index.html
Normal file
@ -0,0 +1,55 @@
|
||||
{% from "formhelpers.html" import render_field %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<style>
|
||||
* {
|
||||
font: normal 30px Arial,sans-serif;
|
||||
}
|
||||
body {
|
||||
background-color: #037;
|
||||
color: white;
|
||||
background-image: url('static/logo.svg');
|
||||
background-repeat: repeat;
|
||||
background-size: 100%;
|
||||
background-position: -0px -0px;
|
||||
}
|
||||
form {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
}
|
||||
input {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: auto;
|
||||
width: 100%;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
margin-top: 40px;
|
||||
}
|
||||
</style>
|
||||
<form name="login" method="POST" action="{{ url_for('home') }}">
|
||||
{{ render_field(authentication_form.username) }}
|
||||
{{ render_field(authentication_form.password) }}
|
||||
{{ render_field(authentication_form.open) }}
|
||||
{{ render_field(authentication_form.close) }}
|
||||
{{ authentication_form.csrf_token }}
|
||||
</form>
|
||||
{% if response %}
|
||||
<hr/>
|
||||
<h1>{{ response.to_html() }}</h1>
|
||||
{% endif %}
|
||||
<hr/>
|
||||
Die Kitchen ist: {{ state_text }}
|
||||
{{ state_img }}
|
||||
</body>
|
||||
</html>
|
11
doorlockd-new/templates/layout.html
Normal file
11
doorlockd-new/templates/layout.html
Normal file
@ -0,0 +1,11 @@
|
||||
{%extends "bootstrap/base.html" %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{%- block content %}
|
||||
{{super()}}
|
||||
{%- block footer %}
|
||||
<br><br><br>
|
||||
<footer>Ralf Ramsauer © 2018 Binary Kitchen e.V.</footer>
|
||||
{%- endblock footer %}
|
||||
{%- endblock content %}
|
Loading…
Reference in New Issue
Block a user