6 Commits

Author SHA1 Message Date
T
ba2946706b Fix update-keydb 2025-02-13 16:44:08 +01:00
T
80573055d9 Resend last known state on reconnect 2025-01-27 23:50:22 +01:00
T
1941698a52 Bug Fix 2025-01-14 19:04:13 +01:00
T
bd7532a080 Add MQTT 2025-01-10 01:10:31 +01:00
T
e2e5878630 Add API v2 2024-07-04 23:03:35 +02:00
T
5724fcad2a Code style and shellcheck 2024-06-07 22:17:06 +02:00
10 changed files with 417 additions and 300 deletions

View File

@ -18,7 +18,7 @@ Falls `/etc/foodoord.conf` nicht vorhanden ist:
### Dateiliste ### Dateiliste
Der Deamon besteht aus folgenden Dateien. Der Daemon besteht aus folgenden Dateien.
* foodoor * foodoor
* foodoord * foodoord
@ -31,9 +31,9 @@ Zusätzlich sollte für das git-repo eine Config angelegt werden:
/root/.ssh/config /root/.ssh/config
``` ```
Host git.chaospott.de Host git.chaospott.de
User git User git
Port 2222 Port 2222
IdentityFile ~/.ssh/id_chaospott IdentityFile ~/.ssh/id_chaospott
``` ```
Das IdentityFile ist der Deploy-SSH-Key, der im [Repo](https://git.chaospott.de/Chaospott/foodoor-keys) hinterlegt ist. Das IdentityFile ist der Deploy-SSH-Key, der im [Repo](https://git.chaospott.de/Chaospott/foodoor-keys) hinterlegt ist.
@ -44,7 +44,7 @@ Das IdentityFile ist der Deploy-SSH-Key, der im [Repo](https://git.chaospott.de/
### Schlüsselupdate ### Schlüsselupdate
`foodoor-update-keydb` `foodoor-update-keydb`
Aktualisiert die die Schlüssel auf der Tür und baut die *Authorized_Keys* für die User *open* und *close*. Keys die nicht dem OpenSSH-Format mit 4096 bit entsprechen, werden ignoriert. Wenn das Script von Hand aufgerufen wird, werden die betroffenen Keys angezeigt. Über einen Cronjob werden die Keys alle **5 Min aktualisiert**. Aktualisiert die Schlüssel auf der Tür und baut die *Authorized_Keys* für die User *open* und *close*. Keys die nicht dem OpenSSH-Format mit 4096 bit entsprechen, werden ignoriert. Wenn das Script von Hand aufgerufen wird, werden die betroffenen Keys angezeigt. Über einen Cronjob werden die Keys alle **5 Min aktualisiert**.
### Schlüsselformate ### Schlüsselformate
@ -56,30 +56,30 @@ Der foodoord akzeptiert nur Pub-Keys im *OpenSSH2-Format*. Keys lassen sich unte
* Mit `ssh-keygen -b 4096` lassen sich Keys generieren. * Mit `ssh-keygen -b 4096` lassen sich Keys generieren.
* `ssh-add $Pfad_zum_Key` fügt den Key dem ssh-Agent hinzu. Die Option `ssh-add -l` zeigt geladene Keys an. * `ssh-add $Pfad_zum_Key` fügt den Key dem ssh-Agent hinzu. Die Option `ssh-add -l` zeigt geladene Keys an.
* `ssh-kegen -l -f $Pfad_zum_Key ` gibt den Fingerprint und andere Informationen zurück. * `ssh-kegen -l -f $Pfad_zum_Key` gibt den Fingerprint und andere Informationen zurück.
####Keys konvertieren(PuTTy>OpenSSH):#### #### Keys konvertieren (PuTTy > OpenSSH):
* `ssh-keygen -i $Pfad_zum_Key > $Pfad_neuer_Pfad.pub<` liest ssh2-kompatible Keys(RFC 4716) ein und speichert diese im OpenSSH-Format. * `ssh-keygen -i $Pfad_zum_Key > $Pfad_neuer_Pfad.pub<` liest ssh2-kompatible Keys (RFC 4716) ein und speichert diese im OpenSSH-Format.
###PuTTy### ### PuTTy
Da die Tür nur Keys im OpenSSH-Format verträgt, dürfen auch mit Putty nur OpenSSH-Keys genutzt werden. Da die Tür nur Keys im OpenSSH-Format verträgt, dürfen auch mit Putty nur OpenSSH-Keys genutzt werden.
###Keys generieren (OpenSSH-Format mit PuttyGen):### #### Keys generieren (OpenSSH-Format mit PuttyGen):
1. PuTTYgen öffnen 1. PuTTYgen öffnen
2. Unten "Number of Bits in a generated Key:" 4096 eintippen 2. Unten "Number of Bits in a generated Key:" 4096 eintippen
3. "Generate" klicken um Key zu generieren 3. "Generate" klicken um Key zu generieren
4. Nach dem generieren oben im Menu "Conversions" > "Export OpenSSH-Key" 4. Nach dem Generieren oben im Menu "Conversions" > "Export OpenSSH-Key"
5. Speichern 5. Speichern
Es ist zu beachten, dass Putty den PrivateKey im Putty-Format benötigt! Das heißt, falls der generierte Key vor dem Export nicht gespeichert wurde, muss der private Key noch konvertiert werden, siehe nächster Punkt! Es ist zu beachten, dass Putty den PrivateKey im Putty-Format benötigt! Das heißt, falls der generierte Key vor dem Export nicht gespeichert wurde, muss der private Key noch konvertiert werden, siehe nächster Punkt!
###Keys konvertieren(OpenSSH>PuTTy):### #### Keys konvertieren (OpenSSH > PuTTy):
1. PuTTYgen öffnen 1. PuTTYgen öffnen
2. "Load" drücken 2. "Load" drücken
@ -88,8 +88,7 @@ Es ist zu beachten, dass Putty den PrivateKey im Putty-Format benötigt! Das hei
5. Speichern 5. Speichern
## Hardware
##Hardware
### Input: ### Input:
@ -97,7 +96,6 @@ Es ist zu beachten, dass Putty den PrivateKey im Putty-Format benötigt! Das hei
* Klingel * Klingel
* Statustaster * Statustaster
### Output: ### Output:
* Status LEDs * Status LEDs

View File

@ -1,3 +1,3 @@
#!/bin/bash #!/bin/bash
VERSION=3.0.4 VERSION=$(grep -oP '(?<=Version: ).*$' debian/DEBIAN/control)
dpkg-deb --root-owner-group -b debian foodoord_${VERSION}_all.deb dpkg-deb --root-owner-group -b debian "foodoord_${VERSION}_all.deb"

View File

@ -1,6 +1,6 @@
Package: foodoord Package: foodoord
Version: 3.0.4 Version: 3.3.3
Maintainer: Bandie <bandie@chaospott.de> Maintainer: Tobi <tobi@chaospott.de>
Architecture: all Architecture: all
Description: Control the doors of the club, ja! Description: Control the doors of the club, ja!
Depends: dash, git, python3, pip, tmux Depends: dash, git, python3, pip, tmux

View File

@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
echo "Creating group and users.." echo "Creating group and users.."
groupadd foodoor groupadd foodoor
useradd -M -d /var/lib/foodoor/close -G foodoor -s /bin/sh close useradd -M -d /var/lib/foodoor/close -G foodoor -s /bin/sh close
@ -7,8 +8,8 @@ useradd -M -d /var/lib/foodoor/door -G foodoor -s /bin/sh door
echo "Chown homes" echo "Chown homes"
for u in close open door; do for u in close open door; do
groupadd ${u} groupadd ${u}
chown ${u}:${u} /var/lib/foodoor/${u} chown ${u}:${u} /var/lib/foodoor/${u}
done done
echo "Chmod foodoor" echo "Chmod foodoor"
@ -20,16 +21,17 @@ chown root:foodoor /state
chmod 664 /state chmod 664 /state
echo "##################" echo "##################"
while [ "$prompt" != "oben" -a "$prompt" != "unten" ]; do while [ "$prompt" != "oben" ] && [ "$prompt" != "unten" ]; do
read -p "Sind wir oben oder unten? (oben, unten): " prompt read -r -p "Sind wir oben oder unten? (oben, unten): " prompt
done done
echo "##################" echo "##################"
echo "Installing dependencies via pip: pifacecommon pifacedigitalio" PIP_DEP=(pifacecommon pifacedigitalio paho-mqtt)
pip install pifacecommon pifacedigitalio echo "Installing dependencies via pip: ${PIP_DEP[*]}"
pip install "${PIP_DEP[@]}"
echo "Enabling and starting systemd-Services" echo "Enabling and starting systemd-Services"
systemctl daemon-reload systemctl daemon-reload
systemctl enable foodoord@$prompt systemctl enable "foodoord@$prompt"
systemctl restart foodoord@$prompt systemctl restart "foodoord@$prompt"
systemctl status foodoord@$prompt systemctl status "foodoord@$prompt"

View File

@ -2,3 +2,8 @@
status_url = status_url =
key = key =
secret = secret =
[doorstatusv2]
status_url =
key =
secret =

View File

@ -9,7 +9,5 @@ ExecStart=/usr/sbin/foodoord_%i
Restart=on-failure Restart=on-failure
RestartSec=5s RestartSec=5s
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -1,37 +1,34 @@
#!/bin/sh #!/bin/sh
set -e set -e
PIPE_PATH=/var/run/foodoord.pipe PIPE_PATH=/var/run/foodoord.pipe
if [ ! -e $PIPE_PATH ] if [ ! -e $PIPE_PATH ]; then
then echo "Pipe missing. Check daemon status."
echo "Pipe missing. Check daemon status." exit 1
exit 1 fi
fi
action="$1" action=$1
isTriggerActivated="0" isTriggerActivated=0
if [ -z "$action" ] if [ -z "$action" ]; then
then action=$SSH_ORIGINAL_COMMAND
action="$SSH_ORIGINAL_COMMAND" isTriggerActivated=1
isTriggerActivated="1" fi
fi
case $action in case $action in
close|open) close | open)
echo $action | tee $PIPE_PATH |sed 's/open/UNLOCKED/;s/close/LOCKED/' > /state echo "$action" | tee "$PIPE_PATH" | sed 's/open/UNLOCKED/;s/close/LOCKED/' > /state
;; ;;
status) status) ;;
;; *)
*) echo "Usage: $(basename "$0") { close, open, status }"
echo "Usage: $(basename $0) { close, open, status }"
exit 1 exit 1
;; ;;
esac esac
if [ $isTriggerActivated -eq 1 ] if [ $isTriggerActivated -eq 1 ]; then
then cat /state
cat /state sleep 2
sleep 2
fi fi

View File

@ -1,63 +1,54 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -e
export PATH="/usr/bin:/bin:/usr/sbin:/sbin" export PATH="/usr/bin:/bin:/usr/sbin:/sbin"
dest=/var/run/foodoor-keys dest=/var/run/foodoor-keys
temp_outfile="$dest.tmp" temp_outfile=$dest.tmp
if [ ! -e "$dest/.git/config" ]; then
if [ ! -e "${dest}/.git/config" ] #echo "Repo does not exist, trying to clone..."
then git clone --quiet --single-branch --depth=1 ssh://git.chaospott.de/Keyverwaltung/foodoor-keys.git "$dest"
#echo "Repo does not exist, trying to clone..."
( cd /var/run && git clone --quiet --single-branch --depth=1 ssh://git.chaospott.de/Keyverwaltung/foodoor-keys.git "${dest}" )
else else
#echo "Repo exists, updating..." #echo "Repo exists, updating..."
( cd "${dest}" && git fetch --quiet && git merge --quiet origin/master master ) git -C "$dest" fetch --quiet && git -C "$dest" merge --quiet origin/master master
fi fi
rm -f ${temp_outfile} rm -f "$temp_outfile"
find "${dest}/keys" -name '*.pub' | sort | \ find "$dest/keys" -type f -name '*.pub' | sort |
while read keyfile while read -r keyfile; do
do if ssh-keygen -l -f "$keyfile" &> /dev/null; then
ssh-keygen -l -f ${keyfile} &> /dev/null keyinfo=$(ssh-keygen -l -f "$keyfile") # The whole key information
if [ $? -eq 0 ]; then crypto=$(echo "$keyinfo" | sed 's/.*(\(.*\))/\1/') # Looks like "RSA" or "ED25519"
valid=false key_length=$(echo "$keyinfo" | cut -d" " -f1)
keyinfo=$(ssh-keygen -l -f ${keyfile}) # The whole key information
crypto=$(echo "${keyinfo}" | sed 's/.*(\(.*\))/\1/') # Looks like "RSA" or "ED25519"
key_length=$(echo "${keyinfo}" | cut -d" " -f1)
if [ "${crypto}" == "RSA" ]; then if [ "$crypto" == "RSA" ]; then
if [ "$key_length" -lt 4096 ]; then
echo "Key size of key $keyfile less than 4096. Not adding it to key database." >&2
continue
fi
# valid
elif [ "$crypto" == "ED25519" ]; then
: # valid
else
continue
fi
if [ ${key_length} -lt 4096 ]; then echo "command=\"/usr/sbin/foodoor \$action \",no-port-forwarding,no-X11-forwarding,no-agent-forwarding $(sed 's/\r//g' "$keyfile") $keyfile" >> $temp_outfile
echo "Key size of key ${keyfile} not equal to 4096. Not adding it to key database." >&2
continue
else
valid=true
fi
elif [ "${crypto}" == "ED25519" ]; then
valid=true
fi fi
if [ "$valid" = true ]; then
echo "command=\"/usr/sbin/foodoor \$action \",no-port-forwarding,no-X11-forwarding,no-agent-forwarding $(cat ${keyfile} | sed 's/\r//g') ${keyfile}" >> ${temp_outfile}
fi
fi
done done
for appendix in open close door for appendix in open close door; do
do action=$appendix
action="$appendix"
if [ "$appendix" = "door" ]; then if [ "$appendix" = "door" ]; then
action="" action=""
fi fi
export action export action
outfile="${dest}/authorized_keys.${appendix}" outfile=$dest/authorized_keys.$appendix
cat ${temp_outfile} |envsubst > ${outfile} envsubst < "$temp_outfile" > "$outfile"
# Oben und unten # Oben und unten
install -d -o ${appendix} -g nogroup -m 0700 /var/lib/foodoor/${appendix}/.ssh install -d -o "$appendix" -g nogroup -m 0700 "/var/lib/foodoor/$appendix/.ssh"
install -b -S .last -o ${appendix} -g nogroup -m 0600 ${outfile} /var/lib/foodoor/${appendix}/.ssh/authorized_keys install -b -S .last -o "$appendix" -g nogroup -m 0600 "$outfile" "/var/lib/foodoor/$appendix/.ssh/authorized_keys"
done done

View File

@ -1,143 +1,205 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# vim: ts=2 sw=2 et # vim: ts=2 sw=2 et
import os
import stat
import time
import pifacedigitalio
import signal
import sys
import grp import grp
import json
import os
import signal
import stat
import subprocess
import sys
import threading
import time
from configparser import ConfigParser from configparser import ConfigParser
from dataclasses import dataclass
#Read config import paho.mqtt.client as mqtt
import pifacedigitalio
class FoodoorMQTT:
def __init__(self, area):
self.area = area
self.client = mqtt.Client()
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message
self._last_state = None
self._connect_lock = threading.Condition()
def connect(self):
try:
self.client.connect("mqtt.chaospott.de")
self.client.loop_start()
with self._connect_lock:
self._connect_lock.wait()
except Exception as e:
print(f"Verbindungsfehler zu MQTT-Server: {e}")
def disconnect(self):
self.client.loop_stop()
def on_connect(self, client, userdata, flags, rc):
if self._last_state is not None:
self.send_state(self._last_state)
with self._connect_lock:
self._connect_lock.notify()
def on_message(self, client, userdata, msg):
print(f"MQTT-Server Message: {msg.topic} {msg.payload}")
def send_state(self, locked: bool):
self._last_state = locked
self.client.publish(f"foobar/{self.area}/foodoor/status", {
False: "open",
True: "closed",
}[locked], qos=0, retain=True)
# Read config
parser = ConfigParser() parser = ConfigParser()
parser.read('/etc/foodoord.conf') parser.read('/etc/foodoord.conf')
doorapi = parser.get('doorstatus', 'status_url')
consumerkey = parser.get('doorstatus', 'key') @dataclass
consumersecret = parser.get('doorstatus', 'secret') class API:
location: str
api_url: str
consumer_key: str
consumer_secret: str
def update_state(self, locked):
subprocess.check_call([
"/usr/bin/curl", "-XPOST",
"--header", "Content-Type: application/json",
"--data",
json.dumps({"consumer_key": self.consumer_key, "consumer_secret": self.consumer_secret, self.location: locked}),
self.api_url
])
#Definitions for output APIv1 = API("aerie",
LED_RED=6 parser.get('doorstatus', 'status_url'),
LED_GREEN=7 parser.get('doorstatus', 'key'),
RELAYS_LOCK=0 parser.get('doorstatus', 'secret'),
RELAYS_UNLOCK=1 )
APIv2 = API("aerie",
#Definitions for input parser.get('doorstatusv2', 'status_url'),
DOOR_BELL=0 parser.get('doorstatusv2', 'key'),
REED_RELAYS=1 #not implementet yet parser.get('doorstatusv2', 'secret'),
)
#Definitions for LEDcolor
RED=1
GREEN=2
ORANGE=3
def update_api(locked): class Foodoord:
try: # Definitions for LED color
os.system("/usr/bin/curl -XPOST --header 'Content-Type: application/json' --data '{ \"consumer_key\": \"" + consumerkey + "\", \"consumer_secret\": \"" + consumersecret + "\", \"aerie\": " + str(locked).lower() + " }' '" + doorapi + "' ") RED = 0b1
except: GREEN = 0b10
pass ORANGE = RED | GREEN
# Definitions for output
LEDS = {
RED: 6,
GREEN: 7,
}
RELAYS_LOCK = 0
RELAYS_UNLOCK = 1
# Definitions for input
DOOR_BELL = 0
CLOSE_BUTTON = 1
def __init__(self):
self.status_open = False
self.mqtt = FoodoorMQTT("oben")
self.pifacedigital = pifacedigitalio.PiFaceDigital()
self.listener = pifacedigitalio.InputEventListener()
self.listener.register(self.DOOR_BELL, pifacedigitalio.IODIR_RISING_EDGE, self.doorbell, settle_time=10)
self.listener.register(self.CLOSE_BUTTON, pifacedigitalio.IODIR_RISING_EDGE, self.close_button, settle_time=5)
def signal_handler(self, _signal, _frame):
self.listener.deactivate()
os.remove("/var/run/foodoord.pipe")
self.update_api(True)
self.set_led(self.RED)
sys.exit(0)
def update_api(self, locked):
try:
self.mqtt.send_state(locked)
except:
pass
try:
APIv1.update_state(locked)
except:
pass
try:
APIv2.update_state(locked)
except:
pass
def set_led(self, color):
for led, gpio in self.LEDS.items():
if color & led:
self.pifacedigital.leds[gpio].turn_on()
else:
self.pifacedigital.leds[gpio].turn_off()
def doorbell(self, event):
if self.status_open:
self.pifacedigital.relays[self.RELAYS_UNLOCK].toggle()
time.sleep(2)
self.pifacedigital.relays[self.RELAYS_UNLOCK].toggle()
def close_button(self, _event):
self.status_open = False
self.update_api(True)
self.set_led(self.RED)
def main(self):
self.mqtt.connect()
self.listener.activate()
signal.signal(signal.SIGTERM, self.signal_handler)
# Start settings
self.set_led(self.RED)
# Setting up FiFo to get sshd-output
try:
os.mkfifo("/var/run/foodoord.pipe")
os.chown("/var/run/foodoord.pipe", -1, grp.getgrnam('foodoor')[2])
os.chmod("/var/run/foodoord.pipe", stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP)
except OSError:
pass
ssh_input = open("/var/run/foodoord.pipe", "r")
while True:
# Read sshd-output from pipe
pipe_cmd = ssh_input.readline().strip()
if pipe_cmd == "close" and self.status_open:
self.pifacedigital.relays[self.RELAYS_LOCK].toggle()
time.sleep(1)
self.pifacedigital.relays[self.RELAYS_LOCK].toggle()
self.status_open = False
self.update_api(True)
self.set_led(self.RED)
elif pipe_cmd == "open":
self.pifacedigital.relays[self.RELAYS_UNLOCK].toggle()
time.sleep(2)
self.pifacedigital.relays[self.RELAYS_UNLOCK].toggle()
if not self.status_open:
self.update_api(False)
self.status_open = True
self.set_led(self.GREEN)
time.sleep(0.1)
if __name__ == "__main__": if __name__ == "__main__":
Foodoord().main()
def doorbell(event):
if (STATUS):
pifacedigital.relays[RELAYS_UNLOCK].toggle()
time.sleep(2)
pifacedigital.relays[RELAYS_UNLOCK].toggle()
#print 'got doorbell'
def close_button(event):
global STATUS
STATUS = False
try:
update_api(True)
except:
pass
set_led(RED)
listener = pifacedigitalio.InputEventListener()
listener.register(0, pifacedigitalio.IODIR_RISING_EDGE, doorbell, settle_time=10)
listener.register(1, pifacedigitalio.IODIR_RISING_EDGE, close_button, settle_time=5)
listener.activate()
def signal_handler(signal, frame):
listener.deactivate()
os.remove("/var/run/foodoord.pipe")
try:
update_api(True)
except:
pass
set_led(RED)
sys.exit(0)
def set_led(color):
if (color==RED):
pifacedigital.leds[LED_RED].turn_on()
pifacedigital.leds[LED_GREEN].turn_off()
elif (color==GREEN):
pifacedigital.leds[LED_GREEN].turn_on()
pifacedigital.leds[LED_RED].turn_off()
elif (color==ORANGE):
pifacedigital.leds[LED_RED].turn_on()
pifacedigital.leds[LED_GREEN].turn_on()
pifacedigital = pifacedigitalio.PiFaceDigital()
signal.signal(signal.SIGTERM, signal_handler)
#Startsettings
STATUS = False
pifacedigital.leds[LED_RED].turn_on()
#Setting up FiFo to get sshd-output
try:
os.mkfifo("/var/run/foodoord.pipe")
os.chown("/var/run/foodoord.pipe", -1, grp.getgrnam('foodoor')[2])
os.chmod("/var/run/foodoord.pipe", stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP)
except OSError:
pass
with open("/var/run/foodoord.pipe", "r") as ssh_input:
while 1:
#Read sshd-output from pipe
Pipe = ssh_input.readline()[:-1]
if (Pipe == "close" and STATUS):
pifacedigital.relays[RELAYS_LOCK].toggle()
time.sleep(1)
pifacedigital.relays[RELAYS_LOCK].toggle()
STATUS = False
try:
update_api(True)
except:
pass
set_led(RED)
elif (Pipe == "open"):
pifacedigital.relays[RELAYS_UNLOCK].toggle()
time.sleep(2)
pifacedigital.relays[RELAYS_UNLOCK].toggle()
if (STATUS==False):
try:
update_api(False)
except:
pass
STATUS = True
set_led(GREEN)
time.sleep(0.1)

View File

@ -1,97 +1,161 @@
#! /usr/bin/python3 #!/usr/bin/env python3
# vim: ts=2 sw=2 et # vim: ts=2 sw=2 et
import grp
import json
import os import os
import stat import stat
import subprocess
import threading
import time import time
import signal
import sys
import RPi.GPIO as gpio
import grp
from configparser import ConfigParser from configparser import ConfigParser
from dataclasses import dataclass
#Read config import RPi.GPIO as gpio
import paho.mqtt.client as mqtt
class FoodoorMQTT:
def __init__(self, area):
self.area = area
self.client = mqtt.Client()
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message
self._last_state = None
self._connect_lock = threading.Condition()
def connect(self):
try:
self.client.connect("mqtt.chaospott.de")
self.client.loop_start()
with self._connect_lock:
self._connect_lock.wait()
except Exception as e:
print(f"Verbindungsfehler zu MQTT-Server: {e}")
def disconnect(self):
self.client.loop_stop()
def on_connect(self, client, userdata, flags, rc):
if self._last_state is not None:
self.send_state(self._last_state)
with self._connect_lock:
self._connect_lock.notify()
def on_message(self, client, userdata, msg):
print(f"MQTT-Server Message: {msg.topic} {msg.payload}")
def send_state(self, locked: bool):
self._last_state = locked
self.client.publish(f"foobar/{self.area}/foodoor/status", {
False: "open",
True: "closed",
}[locked], qos=0, retain=True)
# Definitions for output
PIN_OPEN = 24
PIN_CLOSE = 27
# Read config
parser = ConfigParser() parser = ConfigParser()
parser.read('/etc/foodoord.conf') parser.read('/etc/foodoord.conf')
doorapi = parser.get('doorstatus', 'status_url')
consumerkey = parser.get('doorstatus', 'key')
consumersecret = parser.get('doorstatus', 'secret')
#Definitions for output @dataclass
LED_RED=6 class API:
LED_GREEN=7 location: str
RELAYS_LOCK=0 api_url: str
RELAYS_UNLOCK=1 consumer_key: str
PIN_OPEN=24 consumer_secret: str
PIN_CLOSE=27
#Definitions for input
DOOR_BELL=0
REED_RELAYS=1 #not implementet yet
#Definitions for LEDcolor def update_state(self, locked):
RED=1 subprocess.check_call([
GREEN=2 "/usr/bin/curl", "-XPOST",
ORANGE=3 "--header", "Content-Type: application/json",
"--data",
json.dumps({"consumer_key": self.consumer_key, "consumer_secret": self.consumer_secret, self.location: locked}),
self.api_url
])
MQTT = FoodoorMQTT("unten")
APIv1 = API("cellar",
parser.get('doorstatus', 'status_url'),
parser.get('doorstatus', 'key'),
parser.get('doorstatus', 'secret'),
)
APIv2 = API("cellar",
parser.get('doorstatusv2', 'status_url'),
parser.get('doorstatusv2', 'key'),
parser.get('doorstatusv2', 'secret'),
)
def write_state(state): def write_state(state):
try: try:
handle = open("/tmp/door_state", "w") with open("/tmp/door_state", "w") as f:
handle.write(state) f.write(state)
handle.close() except:
except: pass
pass
def update_api(locked): def update_api(locked):
try: try:
os.system("/usr/bin/curl -XPOST --header 'Content-Type: application/json' --data '{ \"consumer_key\": \"" + consumerkey + "\", \"consumer_secret\": \"" + consumersecret + "\", \"cellar\": " + str(locked).lower() + " }' '" + doorapi + "' ") MQTT.send_state(locked)
except: except:
pass pass
try:
APIv1.update_state(locked)
except:
pass
try:
APIv2.update_state(locked)
except:
pass
def main():
# Start settings
gpio.setmode(gpio.BCM)
gpio.setup(PIN_OPEN, gpio.OUT)
gpio.setup(PIN_CLOSE, gpio.OUT)
# Setting up FiFo to get sshd-output
try:
os.mkfifo("/var/run/foodoord.pipe")
os.chown("/var/run/foodoord.pipe", -1, grp.getgrnam('foodoor')[2])
os.chmod("/var/run/foodoord.pipe", stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP)
except OSError:
pass
MQTT.connect()
ssh_input = open("/var/run/foodoord.pipe", "r")
while True:
# Read sshd output from pipe
pipe_cmd = ssh_input.readline().strip()
if pipe_cmd == "close":
gpio.output(PIN_CLOSE, 1)
time.sleep(1)
gpio.output(PIN_CLOSE, 0)
write_state("closed")
update_api(True)
elif pipe_cmd == "open":
# Locking
gpio.output(PIN_OPEN, 1)
time.sleep(1)
gpio.output(PIN_OPEN, 0)
write_state("open") # Save State
update_api(False) # Status Update
time.sleep(0.2)
if __name__ == "__main__": if __name__ == "__main__":
main()
#Startsettings
STATUS=False
gpio.setmode(gpio.BCM)
gpio.setup(PIN_OPEN, gpio.OUT)
gpio.setup(PIN_CLOSE, gpio.OUT)
#Setting up FiFo to get sshd-output
try:
os.mkfifo("/var/run/foodoord.pipe")
os.chown("/var/run/foodoord.pipe", -1, grp.getgrnam('foodoor')[2])
os.chmod("/var/run/foodoord.pipe", stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP)
except OSError:
pass
with open("/var/run/foodoord.pipe", "r") as ssh_input:
while 1:
#Read sshd-output from pipe
Pipe = ssh_input.readline()[:-1]
if (Pipe == "close"):
gpio.output(PIN_CLOSE,1)
time.sleep(1)
gpio.output(PIN_CLOSE,0)
write_state("closed")
update_api(True)
elif (Pipe == "open"):
#Locking
gpio.output(PIN_OPEN,1)
time.sleep(1)
gpio.output(PIN_OPEN,0)
#Save State
write_state("open")
#Status Update
update_api(False)
time.sleep(0.2)