diff --git a/datenbank.py b/datenbank.py new file mode 100755 index 0000000..1fdef79 --- /dev/null +++ b/datenbank.py @@ -0,0 +1,193 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +# Import der notwendigen Bibliotheken +import json +import MySQLdb + +# Zugangsdaten importieren +with open('/home/pi/.credentials/datenbank.json') as creds: + credentials = json.load(creds) + +# Setzen der Datenbank Daten +datenbankserver = credentials['datenbankserver'] +datenbankbenutzername = credentials['datenbankbenutzername'] +datenbankpasswort = credentials['datenbankpasswort'] +datenbankname = credentials['datenbankname'] + +# Tabellen erstellen für die Devices +def CreateTables(tabelle): + mysql = MySQLdb.connect(datenbankserver, datenbankbenutzername, datenbankpasswort, datenbankname) + zeiger = mysql.cursor() + datenbankquery = """CREATE TABLE IF NOT EXISTS %s (id INT AUTO_INCREMENT PRIMARY KEY, running TINYINT, starttimestamp TIMESTAMP NULL, endtimestamp TIMESTAMP NULL);""" + zeiger.execute(datenbankquery %(tabelle)) + datenbankquery = """INSERT INTO %s (running) VALUES (0);""" + zeiger.execute(datenbankquery %(tabelle)) + datenbankquery = """ALTER TABLE failure ADD COLUMN IF NOT EXISTS %s TINYINT;""" + zeiger.execute(datenbankquery %(tabelle)) + datenbankquery = """GRANT ALL ON *.* TO 'root'@'localhost' IDENTIFIED BY '%s'; FLUSH PRIVILEGES;""" + zeiger.execute(datenbankquery %(credentials['datenbankpasswort'])) + +# Funktion Datenbank auslesen +def lesen(tabelle, feld, start=None): + mysql = None + try: + mysql = MySQLdb.connect(datenbankserver, datenbankbenutzername, datenbankpasswort, datenbankname) + zeiger = mysql.cursor() + if "running" in feld: + datenbankquery = """SELECT %s FROM %s ORDER BY id DESC LIMIT 1;""" + zeiger.execute(datenbankquery %(feld, tabelle)) + datenraw = zeiger.fetchall() + wert = datenraw[0] + wert = wert[0] + return wert + elif "timestamp" in feld: + if start == None: + datenbankquery = """SELECT UNIX_TIMESTAMP(%s) FROM %s WHERE running = 2 ORDER BY id LIMIT 1 ;""" + zeiger.execute(datenbankquery %(feld, tabelle)) + datenraw = zeiger.fetchall() + wert = datenraw[0] + wert = wert[0] + return wert + elif start == 1: + datenbankquery = """SELECT UNIX_TIMESTAMP(%s) FROM %s ORDER BY id DESC LIMIT 1;""" + zeiger.execute(datenbankquery %(feld, tabelle)) + datenraw = zeiger.fetchall() + wert = datenraw[0] + wert = wert[0] + return wert + else: + datenbankquery = """SELECT %s FROM %s WHERE id = 1;""" + zeiger.execute(datenbankquery %(feld,tabelle)) + datenraw = zeiger.fetchall() + wert = datenraw[0] + if "," not in feld: + wert = wert[0] + return wert + except: + wert = None + return wert + finally: + if mysql: + mysql.close() + +# Funktion Datenbank schreiben +def schreiben(tabelle, feld1, wert1, feld2=None, wert2=None, feld3=None, wert3=None): + mysql = None + if wert1 == None: + wert1 = "NULL" + if wert2 == None: + wert2 = "NULL" + if wert3 == None: + wert3 = "NULL" + if feld3 != None: + query = """INSERT INTO %s (%s, %s, %s) VALUES (%s,%s,%s);""" + datenbankquery = query %(tabelle, feld1, feld2, feld3, wert1, wert2, wert3) + elif feld2 !=None: + query = """INSERT INTO %s (%s, %s) VALUES (%s,%s);""" + datenbankquery = query %(tabelle, feld1, feld2, wert1, wert2) + else: + query = """INSERT INTO %s (%s) VALUES (%s);""" + datenbankquery = query %(tabelle, feld1, wert1) + try: + mysql = MySQLdb.connect(datenbankserver, datenbankbenutzername, datenbankpasswort, datenbankname) + zeiger = mysql.cursor() + zeiger.execute(datenbankquery) + mysql.commit() + fehler = 0 + return fehler + except: + fehler = 1 + return fehler + finally: + if mysql: + mysql.close() + + +# Funktion Datenbankupdate +def update(tabelle, feld1, wert1, feld2=None, wert2=None, feld3=None, wert3=None): + mysql = None + if wert1 == None: + wert1 = "NULL" + if wert2 == None: + wert2 = "NULL" + if wert3 == None: + wert3 = "NULL" + if feld3 !=None: + query = """UPDATE %s SET %s = %s, %s = %s, %s = %s ORDER BY id DESC LIMIT 1;""" + datenbankquery = query %(tabelle, feld1, wert1, feld2, wert2, feld3, wert3) + if feld2 != None: + query = """UPDATE %s SET %s = %s, %s = %s ORDER BY id DESC LIMIT 1;""" + datenbankquery = query %(tabelle, feld1, wert1, feld2, wert2) + else: + query = """UPDATE %s SET %s = %s ORDER BY id DESC LIMIT 1;""" + datenbankquery = query %(tabelle, feld1, wert1) + try: + mysql = MySQLdb.connect(datenbankserver, datenbankbenutzername, datenbankpasswort, datenbankname) + zeiger = mysql.cursor() + zeiger.execute(datenbankquery) + mysql.commit() + fehler = 0 + return fehler + except: + fehler = 1 + return fehler + finally: + if mysql: + mysql.close() + +# Funktion Datenbank löschen +def loeschen(tabelle): + mysql = None + query = """DELETE FROM %s ORDER BY id DESC LIMIT 1;""" + datenbankquery = query %(tabelle) + try: + mysql = MySQLdb.connect(datenbankserver, datenbankbenutzername, datenbankpasswort, datenbankname) + zeiger = mysql.cursor() + zeiger.execute(datenbankquery) + mysql.commit() + fehler = 0 + return fehler + except: + fehler = 1 + return fehler + finally: + if mysql: + mysql.close() + +# Funktion temporäre Datenbank exportieren +def exporttemp(): + mysql = None + query = """SELECT * FROM temp INTO OUTFILE '/tmp/aufzeichnung.txt' LINES TERMINATED BY '\n';""" + datenbankquery = query + try: + mysql = MySQLdb.connect(datenbankserver, datenbankbenutzername, datenbankpasswort, datenbankname) + zeiger = mysql.cursor() + zeiger.execute(datenbankquery) + mysql.commit() + fehler = 0 + return fehler + except: + fehler = 1 + return fehler + finally: + if mysql: + mysql.close() + +# Funktion temporäre Datenbank löschen +def loeschetemp(): + mysql = None + query = """TRUNCATE TABLE temp;""" + datenbankquery = query + try: + mysql = MySQLdb.connect(datenbankserver, datenbankbenutzername, datenbankpasswort, datenbankname) + zeiger = mysql.cursor() + zeiger.execute(datenbankquery) + fehler = 0 + return fehler + except: + fehler = 1 + return fehler + finally: + if mysql: + mysql.close() diff --git a/haushalt.py b/haushalt.py new file mode 100755 index 0000000..fb0a430 --- /dev/null +++ b/haushalt.py @@ -0,0 +1,265 @@ +#!/usr/bin/python3 + +# Import der notwendigen Bibliotheken +import time +import json +import datenbank +import zeitdauer +import subprocess as sub +import PyDect200 + +# PyDect200 initialisieren +p = PyDect200.PyDect200 + +# AVM Daten importieren +with open('./settings/settings.json') as content: + settings = json.load(content) + +fritzboxbenutzername = settings['fritz']['user'] +fritzboxpasswort = settings['fritz']['password'] + +# Telegram Daten +try: + Bot = settings['telegram']['bot'] + groupid = settings['telegram']['groupid'] +except: + print("No Telegramm bot configured") + Bot = None + groupid = None + exit(1) + +# Allgemeine Hilfsvariablen anlegen +verbindungsversuch = 0 +endzeitzaehler = 3 +verbindung = None + +# Funktion om Telegram Nachricht zu versenden +def sendMessage(Bot, Groupid, Name, Text): + parse_mode = "HTML" #MarkdownV2 + now = time.strftime("%H:%M") + message = """%s %s: +%s""" %(now, Name, Text) + + uri = "https://api.telegram.org/bot%s/sendMessage?chat_id=%s&parse_mode=%s" %(Bot, Groupid, parse_mode) + print("%s \n%s" %(uri, message)) + try: + sub.call (["curl --data 'text=%s' -X POST '%s'" %(message, uri)], shell=True) + except: + print("Error sending message:\n%s" %(message)) + +# Funktion um eine Verbindung zur Fritzbox herzustellen +def verbinden(AIN): + global verbindungsversuch + global verbindung + while verbindungsversuch == 0: + try: + verbindung = p(fritzboxpasswort,fritzboxbenutzername) + except: + print('Failed to connect to fritzbox') + time.sleep(5) + continue + if not verbindung.login_ok(): + print('Failed to connect to fritzbox. Next try.') + time.sleep(5) + continue + else: + test = verbindung.get_device_name(AIN) + test = test.encode('ascii', 'ignore') + if test == "inval": + time.sleep(5) + continue + else: + print("Verbindung zur FritzBox hergestellt.") + print("") + verbindungsversuch = 1 + verbindungsversuch = 0 + +# Funktion um zu testen ob die Verbindung zur Fritzbox noch besteht +def verbindungstest(AIN): + global verbindung + if not verbindung.login_ok(): + verbinden(AIN) + print("Call function verbinden\n") + else: + test = None + test = verbindung.get_device_name(AIN) + if test == "inval" or test == "" or test == None: + verbinden(AIN) + print("Funktion Verbinden aufgerufen, da die Fritzbox nicht mehr erreichbar ist.") + else: + print("Verbindungstest erfolgreich.") + pass + +# Funktion zum ermitteln des aktuellen Schaltstatus +def ermittlestatus(device): + status = "NULL" + cb = 0 + while status == "NULL": + status = verbindung.get_state(device) + status = status.encode('ascii', 'ignore') + if status == "inval" or status == "": + status = "NULL" + elif status == "0": + return 0 + else: + try: + status = int(status) + return status + except: + status = "NULL" + + cb += 1 + if cb > 10: + return "NULL" + else: + time.sleep(60) + +# Funktion zum ermitteln des aktuellen Verbrauches in Milliwatt +def ermittlestrom(device): + strom = "NULL" + cb = 0 + while strom == "NULL": + strom = verbindung.get_power_single(device) + strom = strom.encode('ascii', 'ignore') + if strom == "inval" or strom == "": + strom = "NULL" + elif strom == "0": + return 0 + else: + try: + strom = int(strom) + return strom + except: + strom = "NULL" + + cb += 1 + if cb > 10: + return "NULL" + else: + time.sleep(60) + +# Funktion zum ermitteln der aktuellen Temperatur +def ermittletemp(device): + try: + temp = verbindung.get_temperature_single(device) + return temp + except: + return -99 + +def startdatenbanklesen(device): + datenbank.CreateTables(("dev_%s" %(device['AIN']))) + device['runningAIN'] = datenbank.lesen(("dev_%s" %(device['AIN'])), "running") + if device['runningAIN'] == None: + device['runningAIN'] = 0 + elif device['runningAIN'] == 0 or device['runningAIN'] == 2: + device['runningAIN'] = 0 + elif device['runningAIN'] == 1: + device['runningAIN'] = 1 + device['startzeitAIN'] = datenbank.lesen(("dev_%s" %(device['AIN'])), "starttimestamp", 1) + +# Hauptprogramm +for device in settings['devices']: + startdatenbanklesen(device) + verbinden(device['AIN']) + +sendMessage(Bot, groupid, "Service", "Service gestartet") +try: + while True: + for device in settings['devices']: + verbindungstest(device['AIN']) + now = time.strftime("%H:%M") + device['statusAIN'] = ermittlestatus(device['AIN']) + device['stromAIN'] = ermittlestrom(device['AIN']) + temp = ermittletemp(device['AIN']) + if temp < 4: + text = "Temperaturwarnung: %s Grad Celcius" %(temp) + sendMessage(Bot, groupid, "Raum", text) + + device['datenbankfehlerAIN'] = datenbank.lesen('failure', ("dev_%s" %(device['AIN']))) + if device['statusAIN'] == "NULL" or device['stromAIN'] == "NULL": + device['runningAIN'] = 0 + datenbankrunningAIN = datenbank.lesen(("dev_%s" %(device['AIN'])), 'running') + if datenbankrunningAIN == 1: + datenbank.update(("dev_%s" %(device['AIN'])), 'running', 2, "endtimestamp", "CURRENT_TIMESTAMP") + + if device['datenbankfehlerAIN'] == 0: + datenbank.update('failure', ("dev_%s" %(device['AIN'])), 1) + text = 'Es ist ein Fehler aufgetreten. Die Steckdose ist nicht mehr erreichbar. Das Programn wurde reinitialisiert' + sendMessage(Bot, groupid, device['Name'], text) + + print("Es ist ein Fehler aufgetreten. Die Steckdose '%s' ist nicht mehr erreichbar. Das Programn wurde zuruckgesetzt." %(device['Name'])) + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + elif device['statusAIN'] == 0 and device['runningAIN'] == 0: + if device['datenbankfehlerAIN'] == 1: + datenbank.update('failure', ("dev_%s" %(device['AIN'])), 0) + text = 'Der Fehler ist behoben. Die Steckdose ist wieder erreichbar' + sendMessage(Bot, groupid, device['Name'], text) + + print("Die Steckdose '%s' ist ausgeschaltet. Es kann kein Vorgang gestartet werden." %(device['Name'])) + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + elif device['runningAIN'] == 0: + if device['datenbankfehlerAIN'] == 1: + datenbank.update('failure', ("dev_%s" %(device['AIN'])), 0) + text = 'Der Fehler ist behoben. Die Steckdose ist wieder erreichbar' + sendMessage(Bot, groupid, device['Name'], text) + + if device['statusAIN'] == 1 and device['stromAIN'] > device['ThresholdStart']: + device['startzeitAIN'] = time.time() + sendMessage(Bot, groupid, device['Name'], "Wurde gestartet") + print("'%s' wurde um %s gestartet." %(device['Name'], now)) + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + device['runningAIN'] = 1 + datenbank.schreiben(("dev_%s" %(device['AIN'])),'running',1,'starttimestamp','CURRENT_TIMESTAMP') + else: + print("Das Programm wartet bis ein Vorgang von '%s' gemacht wird." %(device['Name'])) + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + elif device['runningAIN'] == 1: + if device['datenbankfehlerAIN'] == 1: + datenbank.update('failure', ("dev_%s" %(device['AIN'])), 0) + text = 'Der Fehler ist behoben. Die Steckdose ist wieder erreichbar' + sendMessage(Bot, groupid, device['Name'], text) + + if device['statusAIN'] == 0: + device['zaehlerAIN'] = 0 + device['runningAIN'] = 0 + datenbank.update(("dev_%s" %(device['AIN'])), "running", 2, "endtimestamp", "CURRENT_TIMESTAMP") + text = "Die Steckdose wurde ausgeschaltet." + sendMessage(Bot, groupid, device['Name'], text) + print("Die Steckdose wurde ausgeschaltet.") + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + elif device['stromAIN'] < device['ThresholdStop']: + if device['zaehlerAIN'] < endzeitzaehler: + device['zaehlerAIN'] = device['zaehlerAIN'] + 1 + print("Aktueller Endzeitzaehlerstand von '%s': %s" %(device['Name'], device['zaehlerAIN'])) + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + + if device['zaehlerAIN'] == endzeitzaehler: + stopzeitAIN = time.time() + dauerAIN = stopzeitAIN - device['startzeitAIN'] + dauerAIN = int(dauerAIN) + dauerstringAIN = zeitdauer.ermittlerzeitdauer(dauerAIN) + text = "Ist fertig. Die Vorgangsdauer betrug %s" %(dauerstringAIN) + sendMessage(Bot, groupid, device['Name'], text) + print("'%s' ist seit %s fertig. Die Vorgangsdauer betrug %s." %(device['Name'], now, dauerstringAIN)) + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + device['zaehlerAIN'] = 0 + device['runningAIN'] = 0 + datenbank.update(("dev_%s" %(device['AIN'])), "running", 2, "endtimestamp", "CURRENT_TIMESTAMP") + else: + print("'%s' ist am laufen." %(device['Name'])) + print("Der aktuelle Status der Steckdose '%s': %s" %(device['Name'], device['statusAIN'])) + print("Der aktuelle Stromverbrauch der Steckdose '%s': %s" %(device['Name'], device['stromAIN'])) + device['zaehlerAIN'] = 0 + + time.sleep(60) + +finally: + print("Service will be stoped") + sendMessage(Bot, groupid, "Service", "Service wird gestoppt") diff --git a/settings/settings.json b/settings/settings.json new file mode 100644 index 0000000..a0e1cd0 --- /dev/null +++ b/settings/settings.json @@ -0,0 +1,25 @@ +{ + "fritz" : { + "user" : "username", + "password" : "TopSecret;)" + }, + "telegram" : { + "bot" : "123456789:abcdefhtzuj-fhgj76h", + "groupid" : "-123456"" + }, + "count": 2, + "devices": [ + { + "Name" : "Waschmaschine", + "AIN" : 116300231942, + "ThresholdStart" : 5500, + "ThresholdStop" : 3500 + + }, { + "Name" : "Trockner", + "AIN" : 116300231936, + "ThresholdStart" : 5500, + "ThresholdStop" : 4000 + } + ] +}