Stuff
This commit is contained in:
parent
5212cd45d6
commit
e48f0f6338
154
door.py
154
door.py
|
@ -1,3 +1,4 @@
|
||||||
|
#!/usr/bin/python
|
||||||
import os, serial, socket, subprocess, select, datetime, sys
|
import os, serial, socket, subprocess, select, datetime, sys
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ config = parser.parse_args()
|
||||||
|
|
||||||
# Log data to stdout and the log file
|
# Log data to stdout and the log file
|
||||||
def log(*args):
|
def log(*args):
|
||||||
data = "%s %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), " ".join(i for i in args))
|
data = "%s %s" % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), " ".join(str(i) for i in args))
|
||||||
lgf.write(data + "\n")
|
lgf.write(data + "\n")
|
||||||
lgf.flush()
|
lgf.flush()
|
||||||
print(data)
|
print(data)
|
||||||
|
@ -59,10 +60,23 @@ def read_valid_tokens():
|
||||||
global config
|
global config
|
||||||
|
|
||||||
try:
|
try:
|
||||||
valid = [ s.strip() for s in open(config.valid_tokens, "r").readlines() ]
|
log("Loading tokens")
|
||||||
|
valid = {}
|
||||||
|
lines =[ s.strip() for s in open(config.valid_tokens, "r").readlines() ]
|
||||||
|
for l in lines:
|
||||||
|
l = l.split(' ', 1)
|
||||||
|
if len(l) > 1:
|
||||||
|
if l[0] in valid:
|
||||||
|
log("Warning: Overwriting token %s" % (l[0],))
|
||||||
|
log("Got token: %s (%s)" % (l[0], l[1]))
|
||||||
|
valid[l[0]] = l[1]
|
||||||
|
else:
|
||||||
|
log("Got unnamed token: %s" % (l[0],))
|
||||||
|
valid[l[0]] = None
|
||||||
except:
|
except:
|
||||||
valid = []
|
valid = {}
|
||||||
log("No valid tokens")
|
log("Error reading token file")
|
||||||
|
raise
|
||||||
|
|
||||||
# Opens the log file for writing
|
# Opens the log file for writing
|
||||||
def open_logfile():
|
def open_logfile():
|
||||||
|
@ -73,43 +87,51 @@ def open_logfile():
|
||||||
|
|
||||||
# Actions
|
# Actions
|
||||||
IDLE, CLOSE, OPEN_THEN_CLOSE, OPEN, CLOSE_THEN_OPEN = range(5)
|
IDLE, CLOSE, OPEN_THEN_CLOSE, OPEN, CLOSE_THEN_OPEN = range(5)
|
||||||
|
state_names = {
|
||||||
|
OPEN: "open",
|
||||||
|
CLOSE: "close"
|
||||||
|
}
|
||||||
|
action_names = {
|
||||||
|
IDLE: "idling",
|
||||||
|
OPEN: "waiting for open door",
|
||||||
|
CLOSE: "waiting for closed door",
|
||||||
|
OPEN_THEN_CLOSE: "waiting for open door, then closing again",
|
||||||
|
CLOSE_THEN_OPEN: "waiting for closed door, then opening again"
|
||||||
|
}
|
||||||
# Current door state
|
# Current door state
|
||||||
state = None
|
state = None
|
||||||
|
state_pos = 0
|
||||||
# Current target action
|
# Current target action
|
||||||
action = CLOSE
|
action = CLOSE
|
||||||
# Start time of the current action
|
# Start time of the current action
|
||||||
start_time = datetime.datetime.now()
|
start_time = None
|
||||||
# How often the action was repeated
|
# How often the action was repeated
|
||||||
repeats = 0
|
repeats = 0
|
||||||
|
|
||||||
# Read the state of the door from the serial port
|
# Read the state of the door from the serial port
|
||||||
def poll_door_state():
|
def poll_door_state():
|
||||||
global state
|
global state
|
||||||
|
global state_pos
|
||||||
global serial_port
|
global serial_port
|
||||||
serial_port.reset_input_buffer()
|
serial_port.reset_input_buffer()
|
||||||
serial_port.write(b"R")
|
serial_port.write(b"R")
|
||||||
data = serial_port.readline().strip().split()
|
data = serial_port.readline().strip().split()
|
||||||
if data[0] == b'pos:':
|
if data[0] == b'pos:':
|
||||||
data = int(data[1])
|
data = int(data[1])
|
||||||
|
state_pos = data
|
||||||
changed = False
|
changed = False
|
||||||
if data < 80 and door_state != OPEN:
|
if data < 80 and state != OPEN:
|
||||||
door_state = OPEN
|
state = OPEN
|
||||||
changed = True
|
changed = True
|
||||||
elif data > 100 and door_state != CLOSE:
|
elif data > 100 and state != CLOSE:
|
||||||
door_state = CLOSE
|
state = CLOSE
|
||||||
changed = True
|
changed = True
|
||||||
else:
|
return state
|
||||||
print(data)
|
|
||||||
return door_state
|
|
||||||
|
|
||||||
# Check the door state and send commands through a state machine
|
# Check the door state and send commands through a state machine
|
||||||
def handle_door_state():
|
def handle_door_state():
|
||||||
global action, target, serial_port, start_time, repeats
|
global action, target, serial_port, start_time, repeats
|
||||||
|
|
||||||
state_names = {
|
|
||||||
OPEN: "open",
|
|
||||||
CLOSE: "close"
|
|
||||||
}
|
|
||||||
# Commands associated with each target state
|
# Commands associated with each target state
|
||||||
target_state_cmd = {
|
target_state_cmd = {
|
||||||
OPEN: b'O',
|
OPEN: b'O',
|
||||||
|
@ -129,7 +151,7 @@ def handle_door_state():
|
||||||
poll_door_state()
|
poll_door_state()
|
||||||
|
|
||||||
# Idle + change = key?
|
# Idle + change = key?
|
||||||
if target == IDLE:
|
if action == IDLE:
|
||||||
if state != old_state:
|
if state != old_state:
|
||||||
log("Door changed unexpectedly:", state_names[state])
|
log("Door changed unexpectedly:", state_names[state])
|
||||||
return
|
return
|
||||||
|
@ -142,6 +164,10 @@ def handle_door_state():
|
||||||
CLOSE_THEN_OPEN: (CLOSE, OPEN, OPEN )
|
CLOSE_THEN_OPEN: (CLOSE, OPEN, OPEN )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if start_time == None:
|
||||||
|
start_time = datetime.datetime.now()
|
||||||
|
serial_port.write(target_state_cmd[actions[action][0]])
|
||||||
|
|
||||||
# Target state reached
|
# Target state reached
|
||||||
if state == actions[action][0]:
|
if state == actions[action][0]:
|
||||||
# Select next action, reset start time and repetitions
|
# Select next action, reset start time and repetitions
|
||||||
|
@ -154,13 +180,13 @@ def handle_door_state():
|
||||||
return
|
return
|
||||||
|
|
||||||
# Execution time
|
# Execution time
|
||||||
t = (datetime.datetime.now() - start_time)
|
t = (datetime.datetime.now() - start_time).total_seconds()
|
||||||
if t >= config.state_timeout:
|
if t >= config.state_timeout:
|
||||||
# Timeout -> switch to timeout action
|
# Timeout -> switch to timeout action
|
||||||
action = actions[action][2]
|
action = actions[action][2]
|
||||||
start_time = datetime.datetime.now()
|
start_time = None
|
||||||
repeats = 0
|
repeats = 0
|
||||||
log("Timeout. Switching to", action)
|
log("Timeout. Switching to", action_names[action])
|
||||||
elif t >= (1 + repeats) * config.repeat_time:
|
elif t >= (1 + repeats) * config.repeat_time:
|
||||||
# Repeat every couple of seconds
|
# Repeat every couple of seconds
|
||||||
repeats += 1
|
repeats += 1
|
||||||
|
@ -169,13 +195,19 @@ def handle_door_state():
|
||||||
|
|
||||||
def open_door():
|
def open_door():
|
||||||
global action
|
global action
|
||||||
|
global start_time
|
||||||
log("Opening the door")
|
log("Opening the door")
|
||||||
action = OPEN
|
action = OPEN
|
||||||
|
start_time = None
|
||||||
|
handle_door_state()
|
||||||
|
|
||||||
def close_door():
|
def close_door():
|
||||||
global action
|
global action
|
||||||
|
global start_time
|
||||||
log("Closing the door")
|
log("Closing the door")
|
||||||
action = CLOSE
|
action = CLOSE
|
||||||
|
start_time = None
|
||||||
|
handle_door_state()
|
||||||
|
|
||||||
def toggle_door_state():
|
def toggle_door_state():
|
||||||
global state, action
|
global state, action
|
||||||
|
@ -184,17 +216,22 @@ def toggle_door_state():
|
||||||
else:
|
else:
|
||||||
close_door()
|
close_door()
|
||||||
|
|
||||||
def handle_nfc_token():
|
def handle_nfc_token(token = None):
|
||||||
global valid
|
global valid
|
||||||
|
|
||||||
token = nfc_fifo.readline()
|
if not token:
|
||||||
|
token = nfc_fifo.readline()
|
||||||
if token == "":
|
if token == "":
|
||||||
open_nfc_fifo()
|
open_nfc_fifo()
|
||||||
|
|
||||||
token = token.strip()
|
token = token.strip()
|
||||||
if token in valid:
|
if token in valid:
|
||||||
log("Valid token:", token)
|
name = valid[token]
|
||||||
|
if name:
|
||||||
|
name = "%s (%s)" % (token, name)
|
||||||
|
else:
|
||||||
|
name = token
|
||||||
|
log("Valid token: %s" % name)
|
||||||
toggle_door_state()
|
toggle_door_state()
|
||||||
else:
|
else:
|
||||||
log("Invalid token:", token)
|
log("Invalid token:", token)
|
||||||
|
@ -205,18 +242,69 @@ open_nfc_fifo()
|
||||||
open_serial_port()
|
open_serial_port()
|
||||||
open_control_socket()
|
open_control_socket()
|
||||||
|
|
||||||
|
class LineBuffer(object):
|
||||||
|
def __init__(self, f, handler):
|
||||||
|
self.data = b''
|
||||||
|
self.f = f
|
||||||
|
self.handler = handler
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
data = self.f.recv(1024)
|
||||||
|
if not data:
|
||||||
|
return False
|
||||||
|
self.data += data
|
||||||
|
d = self.data.split(b'\n')
|
||||||
|
d, self.data = d[:-1], d[-1]
|
||||||
|
for i in d:
|
||||||
|
self.handler(self.f, i)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def handle_cmd(comm, data):
|
||||||
|
cmd = data.decode('utf8').split()
|
||||||
|
cmd, args = cmd[0], cmd[1:]
|
||||||
|
log("Got command:", data)
|
||||||
|
|
||||||
|
send = lambda x: comm.send(x.encode('utf8'))
|
||||||
|
|
||||||
|
if cmd == 'fake':
|
||||||
|
log("Faking token", args[0])
|
||||||
|
send("Handling token\n")
|
||||||
|
handle_nfc_token(args[0])
|
||||||
|
elif cmd == 'open':
|
||||||
|
log("Control socket opening door")
|
||||||
|
send("Opening door")
|
||||||
|
open_door()
|
||||||
|
elif cmd == 'close':
|
||||||
|
log("Control socket closing door")
|
||||||
|
send("Closing door")
|
||||||
|
close_door()
|
||||||
|
elif cmd == 'rld':
|
||||||
|
log("Reloading tokens")
|
||||||
|
send("Reloading tokens")
|
||||||
|
read_valid_tokens()
|
||||||
|
elif cmd == 'stat':
|
||||||
|
send("Door status is %s, position is %d. Current action: %s (%g seconds ago)\n" % (
|
||||||
|
state_names.get(state, "None"),
|
||||||
|
state_pos,
|
||||||
|
action_names[action],
|
||||||
|
(datetime.datetime.now() - start_time).total_seconds()))
|
||||||
|
|
||||||
|
buffers = {}
|
||||||
while True:
|
while True:
|
||||||
readable = select.select([ nfc_fifo, control_socket ] + comm_channels, [], [], 0.5)[0]
|
readable = select.select([ nfc_fifo, control_socket ] + comm_channels, [], [], 1)[0]
|
||||||
|
|
||||||
for c in readable:
|
for c in readable:
|
||||||
if c == nfc_fifo:
|
if c == nfc_fifo:
|
||||||
handle_nfc_token()
|
handle_nfc_token()
|
||||||
elif c == control_socket:
|
elif c == control_socket:
|
||||||
comm_channels.append(control_socket.accept()[0])
|
log("Got connection")
|
||||||
|
sock = control_socket.accept()[0]
|
||||||
|
buffers[sock] = LineBuffer(sock, handle_cmd)
|
||||||
|
comm_channels += [sock]
|
||||||
else:
|
else:
|
||||||
data = c.recv(1024)
|
if not buffers[c].update():
|
||||||
if len(data) == 0:
|
log("Lost connection")
|
||||||
|
del buffers[c]
|
||||||
comm_channels.remove(c)
|
comm_channels.remove(c)
|
||||||
else:
|
handle_door_state()
|
||||||
print("Got comms data: ", str(c.recv(1024)))
|
|
||||||
c.sendall(b':)\n')
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user