diff --git a/README.md b/README.md index f0a505f..386a782 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Falls `/etc/foodoord.conf` nicht vorhanden ist: ### Dateiliste -Der Deamon besteht aus folgenden Dateien. +Der Daemon besteht aus folgenden Dateien. * foodoor * foodoord @@ -31,9 +31,9 @@ Zusätzlich sollte für das git-repo eine Config angelegt werden: /root/.ssh/config ``` Host git.chaospott.de - User git - Port 2222 - IdentityFile ~/.ssh/id_chaospott + User git + Port 2222 + IdentityFile ~/.ssh/id_chaospott ``` 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 `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 @@ -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. * `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. -###Keys generieren (OpenSSH-Format mit PuttyGen):### +#### Keys generieren (OpenSSH-Format mit PuttyGen): 1. PuTTYgen öffnen 2. Unten "Number of Bits in a generated Key:" 4096 eintippen 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 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 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 - -##Hardware +## Hardware ### Input: @@ -97,7 +96,6 @@ Es ist zu beachten, dass Putty den PrivateKey im Putty-Format benötigt! Das hei * Klingel * Statustaster - ### Output: * Status LEDs diff --git a/build-package b/build-package index ad26c6d..0ed3a3f 100755 --- a/build-package +++ b/build-package @@ -1,3 +1,3 @@ #!/bin/bash -VERSION=3.0.4 -dpkg-deb --root-owner-group -b debian foodoord_${VERSION}_all.deb +VERSION=3.1.0 +dpkg-deb --root-owner-group -b debian "foodoord_${VERSION}_all.deb" diff --git a/debian/DEBIAN/postinst b/debian/DEBIAN/postinst index f3f7675..47017bf 100755 --- a/debian/DEBIAN/postinst +++ b/debian/DEBIAN/postinst @@ -1,4 +1,5 @@ #!/bin/bash + echo "Creating group and users.." groupadd foodoor 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" for u in close open door; do - groupadd ${u} - chown ${u}:${u} /var/lib/foodoor/${u} + groupadd ${u} + chown ${u}:${u} /var/lib/foodoor/${u} done echo "Chmod foodoor" @@ -20,8 +21,8 @@ chown root:foodoor /state chmod 664 /state echo "##################" -while [ "$prompt" != "oben" -a "$prompt" != "unten" ]; do - read -p "Sind wir oben oder unten? (oben, unten): " prompt +while [ "$prompt" != "oben" ] && [ "$prompt" != "unten" ]; do + read -r -p "Sind wir oben oder unten? (oben, unten): " prompt done echo "##################" @@ -30,6 +31,6 @@ pip install pifacecommon pifacedigitalio echo "Enabling and starting systemd-Services" systemctl daemon-reload -systemctl enable foodoord@$prompt -systemctl restart foodoord@$prompt -systemctl status foodoord@$prompt +systemctl enable "foodoord@$prompt" +systemctl restart "foodoord@$prompt" +systemctl status "foodoord@$prompt" diff --git a/debian/etc/systemd/system/foodoord@.service b/debian/etc/systemd/system/foodoord@.service index cf1ba2d..d9539f2 100755 --- a/debian/etc/systemd/system/foodoord@.service +++ b/debian/etc/systemd/system/foodoord@.service @@ -9,7 +9,5 @@ ExecStart=/usr/sbin/foodoord_%i Restart=on-failure RestartSec=5s - [Install] WantedBy=multi-user.target - diff --git a/debian/usr/sbin/foodoor b/debian/usr/sbin/foodoor index b050583..bdfdc64 100755 --- a/debian/usr/sbin/foodoor +++ b/debian/usr/sbin/foodoor @@ -1,37 +1,34 @@ #!/bin/sh + set -e PIPE_PATH=/var/run/foodoord.pipe -if [ ! -e $PIPE_PATH ] - then - echo "Pipe missing. Check daemon status." - exit 1 -fi +if [ ! -e $PIPE_PATH ]; then + echo "Pipe missing. Check daemon status." + exit 1 +fi -action="$1" -isTriggerActivated="0" +action=$1 +isTriggerActivated=0 -if [ -z "$action" ] - then - action="$SSH_ORIGINAL_COMMAND" - isTriggerActivated="1" -fi +if [ -z "$action" ]; then + action=$SSH_ORIGINAL_COMMAND + isTriggerActivated=1 +fi case $action in - close|open) - echo $action | tee $PIPE_PATH |sed 's/open/UNLOCKED/;s/close/LOCKED/' > /state - ;; - status) - ;; - *) - echo "Usage: $(basename $0) { close, open, status }" +close | open) + echo "$action" | tee "$PIPE_PATH" | sed 's/open/UNLOCKED/;s/close/LOCKED/' > /state + ;; +status) ;; +*) + echo "Usage: $(basename "$0") { close, open, status }" exit 1 - ;; + ;; esac -if [ $isTriggerActivated -eq 1 ] -then - cat /state - sleep 2 +if [ $isTriggerActivated -eq 1 ]; then + cat /state + sleep 2 fi diff --git a/debian/usr/sbin/foodoor-update-keydb b/debian/usr/sbin/foodoor-update-keydb index f4e2084..adbfd06 100755 --- a/debian/usr/sbin/foodoor-update-keydb +++ b/debian/usr/sbin/foodoor-update-keydb @@ -4,60 +4,51 @@ set -e export PATH="/usr/bin:/bin:/usr/sbin:/sbin" dest=/var/run/foodoor-keys -temp_outfile="$dest.tmp" +temp_outfile=$dest.tmp - -if [ ! -e "${dest}/.git/config" ] -then - #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}" ) +if [ ! -e "$dest/.git/config" ]; then + #echo "Repo does not exist, trying to clone..." + git -C "$dest" clone --quiet --single-branch --depth=1 ssh://git.chaospott.de/Keyverwaltung/foodoor-keys.git "$dest" else - #echo "Repo exists, updating..." - ( cd "${dest}" && git fetch --quiet && git merge --quiet origin/master master ) + #echo "Repo exists, updating..." + git -C "$dest" fetch --quiet && git -C "$dest" merge --quiet origin/master master fi -rm -f ${temp_outfile} - find "${dest}/keys" -name '*.pub' | sort | \ - while read keyfile - do - ssh-keygen -l -f ${keyfile} &> /dev/null - if [ $? -eq 0 ]; then - valid=false - 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) +rm -f "$temp_outfile" +find "$dest/keys" -type f -name '*.pub' | sort | + while read -r keyfile; do + if ssh-keygen -l -f "$keyfile" &> /dev/null; then + 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 "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 + echo "command=\"/usr/sbin/foodoor \$action \",no-port-forwarding,no-X11-forwarding,no-agent-forwarding $(sed 's/\r//g' "$keyfile") $keyfile" >> $temp_outfile 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 -for appendix in open close door -do - action="$appendix" +for appendix in open close door; do + action=$appendix if [ "$appendix" = "door" ]; then - action="" + action="" fi export action - outfile="${dest}/authorized_keys.${appendix}" - cat ${temp_outfile} |envsubst > ${outfile} - + outfile=$dest/authorized_keys.$appendix + envsubst < "$temp_outfile" > "$outfile" + # Oben und unten - 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 -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" done diff --git a/debian/usr/sbin/foodoord_oben b/debian/usr/sbin/foodoord_oben index 3859efa..3e2adb5 100755 --- a/debian/usr/sbin/foodoord_oben +++ b/debian/usr/sbin/foodoord_oben @@ -1,143 +1,136 @@ #!/usr/bin/env python3 # vim: ts=2 sw=2 et -import os -import stat -import time -import pifacedigitalio -import signal -import sys import grp +import json +import os +import signal +import stat +import subprocess +import sys +import time from configparser import ConfigParser -#Read config +import pifacedigitalio + +# Definitions for output +LED_RED = 6 +LED_GREEN = 7 +RELAYS_LOCK = 0 +RELAYS_UNLOCK = 1 + +# Definitions for input +DOOR_BELL = 0 +REED_RELAYS = 1 # not implemented yet + +# Definitions for LED color +RED = 1 +GREEN = 2 +ORANGE = 3 + +# Read config parser = ConfigParser() parser.read('/etc/foodoord.conf') -doorapi = parser.get('doorstatus', 'status_url') -consumerkey = parser.get('doorstatus', 'key') -consumersecret = parser.get('doorstatus', 'secret') - - -#Definitions for output -LED_RED=6 -LED_GREEN=7 -RELAYS_LOCK=0 -RELAYS_UNLOCK=1 - -#Definitions for input -DOOR_BELL=0 -REED_RELAYS=1 #not implementet yet - -#Definitions for LEDcolor -RED=1 -GREEN=2 -ORANGE=3 +DOORAPI = parser.get('doorstatus', 'status_url') +CONSUMERKEY = parser.get('doorstatus', 'key') +CONSUMERSECRET = parser.get('doorstatus', 'secret') def update_api(locked): try: - os.system("/usr/bin/curl -XPOST --header 'Content-Type: application/json' --data '{ \"consumer_key\": \"" + consumerkey + "\", \"consumer_secret\": \"" + consumersecret + "\", \"aerie\": " + str(locked).lower() + " }' '" + doorapi + "' ") + subprocess.check_call([ + "/usr/bin/curl", "-XPOST", + "--header", "Content-Type: application/json", + "--data", + json.dumps({"consumer_key": CONSUMERKEY, "consumer_secret": CONSUMERSECRET, "aerie": locked}) + ]) except: pass -if __name__ == "__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) +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() - 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() +class Foodoord: + def __init__(self): + self.status_open = False - def signal_handler(signal, frame): - listener.deactivate() - os.remove("/var/run/foodoord.pipe") + self.listener = pifacedigitalio.InputEventListener() + self.listener.register(0, pifacedigitalio.IODIR_RISING_EDGE, self.doorbell, settle_time=10) + self.listener.register(1, pifacedigitalio.IODIR_RISING_EDGE, self.close_button, settle_time=5) - try: - update_api(True) - except: - pass + def signal_handler(self, _signal, _frame): + self.listener.deactivate() + os.remove("/var/run/foodoord.pipe") - set_led(RED) - sys.exit(0) + update_api(True) + 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 + def doorbell(self, event): + if self.status_open: + pifacedigital.relays[RELAYS_UNLOCK].toggle() + time.sleep(2) + pifacedigital.relays[RELAYS_UNLOCK].toggle() + def close_button(self, _event): + self.status_open = False + update_api(True) set_led(RED) - elif (Pipe == "open"): - pifacedigital.relays[RELAYS_UNLOCK].toggle() - time.sleep(2) - pifacedigital.relays[RELAYS_UNLOCK].toggle() + def main(self): + self.listener.activate() - if (STATUS==False): + pifacedigital = pifacedigitalio.PiFaceDigital() + signal.signal(signal.SIGTERM, self.signal_handler) - try: - update_api(False) - except: + # Start settings + 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 - STATUS = True + ssh_input = open("/var/run/foodoord.pipe", "r") + while True: + # Read sshd-output from pipe + pipe_cmd = ssh_input.readline().strip() - set_led(GREEN) - time.sleep(0.1) + if pipe_cmd == "close" and self.status_open: + pifacedigital.relays[RELAYS_LOCK].toggle() + time.sleep(1) + pifacedigital.relays[RELAYS_LOCK].toggle() + + self.status_open = False + update_api(True) + set_led(RED) + + elif pipe_cmd == "open": + pifacedigital.relays[RELAYS_UNLOCK].toggle() + time.sleep(2) + pifacedigital.relays[RELAYS_UNLOCK].toggle() + + if not self.status_open: + update_api(False) + self.status_open = True + set_led(GREEN) + + time.sleep(0.1) + + +if __name__ == "__main__": + Foodoord().main() diff --git a/debian/usr/sbin/foodoord_unten b/debian/usr/sbin/foodoord_unten index a6d02e2..93fb72e 100755 --- a/debian/usr/sbin/foodoord_unten +++ b/debian/usr/sbin/foodoord_unten @@ -1,97 +1,100 @@ -#! /usr/bin/python3 +#!/usr/bin/env python3 # vim: ts=2 sw=2 et +import grp +import json import os import stat +import subprocess import time -import signal -import sys -import RPi.GPIO as gpio -import grp from configparser import ConfigParser -#Read config +import RPi.GPIO as gpio + +# Definitions for output +LED_RED = 6 +LED_GREEN = 7 +RELAYS_LOCK = 0 +RELAYS_UNLOCK = 1 +PIN_OPEN = 24 +PIN_CLOSE = 27 +# Definitions for input +DOOR_BELL = 0 +REED_RELAYS = 1 # not implemented yet + +# Definitions for LED color +RED = 1 +GREEN = 2 +ORANGE = 3 + +# Read config parser = ConfigParser() parser.read('/etc/foodoord.conf') -doorapi = parser.get('doorstatus', 'status_url') -consumerkey = parser.get('doorstatus', 'key') -consumersecret = parser.get('doorstatus', 'secret') - -#Definitions for output -LED_RED=6 -LED_GREEN=7 -RELAYS_LOCK=0 -RELAYS_UNLOCK=1 -PIN_OPEN=24 -PIN_CLOSE=27 -#Definitions for input -DOOR_BELL=0 -REED_RELAYS=1 #not implementet yet - -#Definitions for LEDcolor -RED=1 -GREEN=2 -ORANGE=3 - +DOORAPI = parser.get('doorstatus', 'status_url') +CONSUMERKEY = parser.get('doorstatus', 'key') +CONSUMERSECRET = parser.get('doorstatus', 'secret') def write_state(state): - try: - handle = open("/tmp/door_state", "w") - handle.write(state) - handle.close() - except: - pass + try: + with open("/tmp/door_state", "w") as handle: + handle.write(state) + except: + pass def update_api(locked): - try: - os.system("/usr/bin/curl -XPOST --header 'Content-Type: application/json' --data '{ \"consumer_key\": \"" + consumerkey + "\", \"consumer_secret\": \"" + consumersecret + "\", \"cellar\": " + str(locked).lower() + " }' '" + doorapi + "' ") - except: - pass + try: + subprocess.check_call([ + "/usr/bin/curl", "-XPOST", + "--header", "Content-Type: application/json", + "--data", + json.dumps({"consumer_key": CONSUMERKEY, "consumer_secret": CONSUMERSECRET, "cellar": locked}), + DOORAPI + ]) + 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 + + 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__": - - #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) - + main()