Compare commits

..

No commits in common. "master" and "v3.0.4" have entirely different histories.

10 changed files with 290 additions and 333 deletions

View File

@ -18,7 +18,7 @@ Falls `/etc/foodoord.conf` nicht vorhanden ist:
### Dateiliste
Der Daemon besteht aus folgenden Dateien.
Der Deamon 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 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 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,7 +88,8 @@ Es ist zu beachten, dass Putty den PrivateKey im Putty-Format benötigt! Das hei
5. Speichern
## Hardware
##Hardware
### Input:
@ -96,6 +97,7 @@ Es ist zu beachten, dass Putty den PrivateKey im Putty-Format benötigt! Das hei
* Klingel
* Statustaster
### Output:
* Status LEDs

View File

@ -1,3 +1,3 @@
#!/bin/bash
VERSION=3.2.0
dpkg-deb --root-owner-group -b debian "foodoord_${VERSION}_all.deb"
VERSION=3.0.4
dpkg-deb --root-owner-group -b debian foodoord_${VERSION}_all.deb

View File

@ -1,5 +1,5 @@
Package: foodoord
Version: 3.2.0
Version: 3.0.4
Maintainer: Bandie <bandie@chaospott.de>
Architecture: all
Description: Control the doors of the club, ja!

View File

@ -1,5 +1,4 @@
#!/bin/bash
echo "Creating group and users.."
groupadd foodoor
useradd -M -d /var/lib/foodoor/close -G foodoor -s /bin/sh close
@ -8,8 +7,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"
@ -21,8 +20,8 @@ chown root:foodoor /state
chmod 664 /state
echo "##################"
while [ "$prompt" != "oben" ] && [ "$prompt" != "unten" ]; do
read -r -p "Sind wir oben oder unten? (oben, unten): " prompt
while [ "$prompt" != "oben" -a "$prompt" != "unten" ]; do
read -p "Sind wir oben oder unten? (oben, unten): " prompt
done
echo "##################"
@ -31,6 +30,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

View File

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

View File

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

View File

@ -1,34 +1,37 @@
#!/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

View File

@ -4,51 +4,60 @@ 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..."
git -C "$dest" 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..."
( cd /var/run && git clone --quiet --single-branch --depth=1 ssh://git.chaospott.de/Keyverwaltung/foodoor-keys.git "${dest}" )
else
#echo "Repo exists, updating..."
git -C "$dest" fetch --quiet && git -C "$dest" merge --quiet origin/master master
#echo "Repo exists, updating..."
( cd "${dest}" && git fetch --quiet && git merge --quiet origin/master master )
fi
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)
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)
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 [ "${crypto}" == "RSA" ]; then
echo "command=\"/usr/sbin/foodoor \$action \",no-port-forwarding,no-X11-forwarding,no-agent-forwarding $(sed 's/\r//g' "$keyfile") $keyfile" >> $temp_outfile
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
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
envsubst < "$temp_outfile" > "$outfile"
outfile="${dest}/authorized_keys.${appendix}"
cat ${temp_outfile} |envsubst > ${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

View File

@ -1,165 +1,143 @@
#!/usr/bin/env python3
# vim: ts=2 sw=2 et
import grp
import json
import os
import signal
import stat
import subprocess
import sys
import time
from configparser import ConfigParser
from dataclasses import dataclass
import pifacedigitalio
import signal
import sys
import grp
from configparser import ConfigParser
# 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
#Read config
parser = ConfigParser()
parser.read('/etc/foodoord.conf')
@dataclass
class API:
api_url: str
consumer_key: str
consumer_secret: str
doorapi = parser.get('doorstatus', 'status_url')
consumerkey = parser.get('doorstatus', 'key')
consumersecret = parser.get('doorstatus', 'secret')
APIv1 = API(
parser.get('doorstatus', 'status_url'),
parser.get('doorstatus', 'key'),
parser.get('doorstatus', 'secret'),
)
APIv2 = API(
parser.get('doorstatusv2', 'status_url'),
parser.get('doorstatusv2', 'key'),
parser.get('doorstatusv2', '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
def update_api(locked):
try:
# API v1
subprocess.check_call([
"/usr/bin/curl", "-XPOST",
"--header", "Content-Type: application/json",
"--data",
json.dumps({"consumer_key": APIv1.consumer_key, "consumer_secret": APIv1.consumer_secret, "aerie": locked}),
APIv1.api_url
])
os.system("/usr/bin/curl -XPOST --header 'Content-Type: application/json' --data '{ \"consumer_key\": \"" + consumerkey + "\", \"consumer_secret\": \"" + consumersecret + "\", \"aerie\": " + str(locked).lower() + " }' '" + doorapi + "' ")
except:
pass
try:
# API v2
subprocess.check_call([
"/usr/bin/curl", "-XPOST",
"--header", "Content-Type: application/json",
"--data",
json.dumps({"consumer_key": APIv2.consumer_key, "consumer_secret": APIv2.consumer_secret, "aerie": locked}),
APIv2.api_url
])
except:
pass
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()
class Foodoord:
def __init__(self):
self.status_open = False
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)
def signal_handler(self, _signal, _frame):
self.listener.deactivate()
os.remove("/var/run/foodoord.pipe")
update_api(True)
set_led(RED)
sys.exit(0)
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)
def main(self):
self.listener.activate()
pifacedigital = pifacedigitalio.PiFaceDigital()
signal.signal(signal.SIGTERM, self.signal_handler)
# 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
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:
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()
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,128 +1,97 @@
#!/usr/bin/env python3
#! /usr/bin/python3
# vim: ts=2 sw=2 et
import grp
import json
import os
import stat
import subprocess
import time
from configparser import ConfigParser
from dataclasses import dataclass
import signal
import sys
import RPi.GPIO as gpio
import grp
from configparser import ConfigParser
# 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
#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')
@dataclass
class API:
api_url: str
consumer_key: str
consumer_secret: str
#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
APIv1 = API(
parser.get('doorstatus', 'status_url'),
parser.get('doorstatus', 'key'),
parser.get('doorstatus', 'secret'),
)
APIv2 = API(
parser.get('doorstatusv2', 'status_url'),
parser.get('doorstatusv2', 'key'),
parser.get('doorstatusv2', 'secret'),
)
def write_state(state):
try:
with open("/tmp/door_state", "w") as handle:
handle.write(state)
except:
pass
try:
handle = open("/tmp/door_state", "w")
handle.write(state)
handle.close()
except:
pass
def update_api(locked):
try:
# API v1
subprocess.check_call([
"/usr/bin/curl", "-XPOST",
"--header", "Content-Type: application/json",
"--data",
json.dumps({"consumer_key": APIv1.consumer_key, "consumer_secret": APIv1.consumer_secret, "cellar": locked}),
APIv1.api_url
])
except:
pass
try:
# API v2
subprocess.check_call([
"/usr/bin/curl", "-XPOST",
"--header", "Content-Type: application/json",
"--data",
json.dumps({"consumer_key": APIv2.consumer_key, "consumer_secret": APIv2.consumer_secret, "cellar": locked}),
APIv2.api_url
])
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)
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
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)