#Einbinden der Bibliotheken
import paho.mqtt.client as mqtt  #Bibliothek zur Verwendung von MQTT
import RPi.GPIO as GPIO          #Bibliothek zur Verwendung der GPIO-Pins
import time                      #Bibliothek zur Verwendung der Zeitfunktion
import threading                 #Bibliothek um das gleichzeitige Ausführen von Funktionen zu ermöglichen
import influxdb_client           #Bibliothek für die Influx Datenbank
from influxdb_client.client.write_api import SYNCHRONOUS  #Bilbiothek zum synchronen Schreiben der Daten in die Datenbank

#GPIO-Einstellungen
GPIO.setmode(GPIO.BCM)           #setzt die Pin-Nummerierung auf die Broadcom-Nummerierung
GPIO.setwarnings(False)          #ignoriert fälschliche Warnungen durch die GPIO-Pins

#Deklarierung notwendiger Variablen
TASTER_GPIO = 27      #Pin zur Erfassung der Tasterbetätigung
LED_GPIO = 22         #Pin zum Ansteuern der LED des Quittierungstasters
RELAIS_1_GPIO = 14    #Pin zum Ansteuern des 1. Relais (für die grüne Stufe der Warnleuchte)
RELAIS_2_GPIO = 15    #Pin zum Ansteuern des 2. Relais (für die gelbe Stufe der Warnleuchte)
RELAIS_3_GPIO = 18    #Pin zum Ansteuern des 3. Relais (für die rote Stufe der Warnleuchte)
RELAIS_4_GPIO = 23    #Pin zum Ansteuern des 3. Relais (aktuell nicht benötigt)
tasterStatus = False  #Status ob der Quittierungstaster betätigt wurde
temp = 0              #Variable zum Speichern der Temperatur
humidity = 0          #Variable zum Speichern der Luftfeuchtigkeit
eco2 = 0              #Variable zum Speichern des CO2-Wertes
pirState = 0          #Variable zum Speichern des Anwesenheitsstatus
temp1, temp2 = 24.5, 26.0
humid1, humid2 = 60.0, 70.0
eco21, eco22 = 900.0, 1500.0

#Datenbank setup
bucket = "climatecube"                #Speicherort der Daten
org = "bbs2wob"                       #Organisation
token = "FenscDPTy6RmzdE4Kp5T3Y-DM0XJ1Wk3esXY8d6p7F6A9HRgX_yw0MMUIc_PVQG6sdtMBbzVPcaYKuMZ_ji0Xg==" #Zugriffsschlüssel
url = "https://influx.xplore-dna.de"  #URL der datenbank
#Erstellung eines Objektes zum Hochladen der Daten
client = influxdb_client.InfluxDBClient(
    url = url,
    token = token,
    org = org
)

write_api = client.write_api(write_options=SYNCHRONOUS)
#Kofiguration der Pins
#Setzen der Pins für das Ansteuern der Relais und LED auf OUTPUT
GPIO.setup(RELAIS_1_GPIO, GPIO.OUT)
GPIO.setup(RELAIS_2_GPIO, GPIO.OUT)
GPIO.setup(RELAIS_3_GPIO, GPIO.OUT)
GPIO.setup(RELAIS_4_GPIO, GPIO.OUT)
GPIO.setup(LED_GPIO, GPIO.OUT)
#Definieren des Tasterpins als Pullup
GPIO.setup(TASTER_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)

#alle Relais standardmäßig ausschschalten
GPIO.output(RELAIS_1_GPIO, GPIO.HIGH)
GPIO.output(RELAIS_2_GPIO, GPIO.HIGH)
GPIO.output(RELAIS_3_GPIO, GPIO.HIGH)
GPIO.output(RELAIS_4_GPIO, GPIO.HIGH)

#Funktion wird beim Verbindungsaufbau mit dem ESP32 aufgerufen
def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
    client.subscribe("esp32/data")    #erhalte nur Nachrichten mit dem Thema: "esp32/data"

#Funktion wird beim Erhalt einer Nachricht aufgerufen
def on_message(client, userdata, msg):
    #print(msg.topic+" "+str(msg.payload.decode("utf-8"))) #direkte Ausgabe der empfangenen Daten
    receivedData = str(msg.payload.decode("utf-8"))  #speichert die empfangenen Werte in der Variable receivedData
    dataArray = receivedData.split(",")              #trennt die Werte aus dem Array
    #Verwendung der globalen Variablen
    global temp
    global humidity
    global eco2
    global pirState
    #Speichern der Werte aus dem Array in den einzelnen Variablen
    temp = float(dataArray[0])
    humidity = float(dataArray[1])
    eco2 = float(dataArray[2])
    pirState = float(dataArray[3])
    #Sensorwerte in die Datenbank schreiben
    p = influxdb_client.Point("Sensordaten").measurement("measurement").tag("Raum", "C007").field("temperature", temp)
    write_api.write(bucket=bucket,org=org,record=p)
    p = influxdb_client.Point("Sensordaten").measurement("measurement").tag("Raum", "C007").field("humidity", humidity)
    write_api.write(bucket=bucket,org=org,record=p)
    p = influxdb_client.Point("Sensordaten").measurement("measurement").tag("Raum", "C007").field("CO2", eco2)
    write_api.write(bucket=bucket,org=org,record=p)
    p = influxdb_client.Point("Sensordaten").measurement("measurement").tag("Raum", "C007").field("motion", pirState)
    write_api.write(bucket=bucket,org=org,record=p)
    #Ausgabe der empfangenen Sensordaten auf dem seriellen Monitor
    print("temp:", temp, "humidity:", humidity, "eco2:", eco2, "Motion:", pirState)
    

#Funktion zum Ausführen des MQTT-Clients
def mqtt_thread():
    global client
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect("192.168.178.10", 1883, 60)
    client.loop_forever()

#Funktion zum Steuern der Relais und LED des Leuchtdrucktasters anhand der empfangenen Sensordaten
def blink():
    while True:
        global tasterStatus
        if (temp>=temp2) or (humidity>=humid2) or (eco2>=eco22):  #wenn sehr kritischer Zustand
            #Relais 1 und 2 ausschalten
            GPIO.output(RELAIS_1_GPIO, GPIO.HIGH)
            GPIO.output(RELAIS_2_GPIO, GPIO.HIGH)
            #wenn der Quittierungstaster noch nicht betätigt wurde soll Relais 3 und die LED des Tasters blinken
            if tasterStatus == False:
                GPIO.output(LED_GPIO, GPIO.HIGH)              
                GPIO.output(RELAIS_2_GPIO, GPIO.HIGH)
                GPIO.output(RELAIS_3_GPIO, GPIO.LOW)
                time.sleep(0.5)
                GPIO.output(RELAIS_3_GPIO, GPIO.HIGH)
                GPIO.output(LED_GPIO, GPIO.LOW)
                time.sleep(0.5)
            #wenn der Quittierungstaster betätigt wurde soll die LED und das Relais 3 dauerhaft an sein
            else:
                GPIO.output(LED_GPIO, GPIO.HIGH)
                GPIO.output(RELAIS_3_GPIO, GPIO.LOW)
                
        elif (temp>=temp1 and temp<temp2) or (humidity>=humid1 and humidity<humid2) or (eco2>=eco21 and eco2<eco22): #wenn kritischer Zustand
            #Relais 1 und 3 ausschalten
            GPIO.output(RELAIS_1_GPIO, GPIO.HIGH)
            GPIO.output(RELAIS_3_GPIO, GPIO.HIGH)
            #wenn der Quittierungstaster noch nicht betätigt wurde soll Relais 2 und die LED des Tasters blinken
            if tasterStatus == False:
                GPIO.output(LED_GPIO, GPIO.HIGH)              
                GPIO.output(RELAIS_1_GPIO, GPIO.HIGH)
                GPIO.output(RELAIS_3_GPIO, GPIO.HIGH)
                GPIO.output(RELAIS_2_GPIO, GPIO.LOW)
                time.sleep(0.5)
                GPIO.output(RELAIS_2_GPIO, GPIO.HIGH)
                GPIO.output(LED_GPIO, GPIO.LOW)
                time.sleep(0.5)
            #wenn der Quittierungstaster betätigt wurde soll die LED und das Relais 2 dauerhaft an sein
            else:
                GPIO.output(LED_GPIO, GPIO.HIGH)
                GPIO.output(RELAIS_2_GPIO, GPIO.LOW)      
        elif (temp<temp1) and (humidity<humid1) and (eco2<eco21): #wenn normaler Zustand
            #Relais 2 und 3 ausschalten
            GPIO.output(RELAIS_2_GPIO, GPIO.HIGH)
            GPIO.output(RELAIS_3_GPIO, GPIO.HIGH)
            #Rücksetzen des Tasterstatus durch den normalen Zustand
            tasterStatus = False
            #Relais 1 einschalten
            GPIO.output(RELAIS_1_GPIO, GPIO.LOW)           

#Funktion zum Abfragen des Tasters
def taster():
    while True:
        input_state = GPIO.input(TASTER_GPIO)  #Abfrage ob der Taster gedrückt wurde
        if input_state == False:
            global tasterStatus
            tasterStatus = True                #Taster wurde gedrückt
            print(tasterStatus)
            global client
            client.publish("esp32/receive", "Quittierungstaster betätigt") #Teilt dem ESP32 mit, dass der Taster gedrückt wurde
            time.sleep(0.3)
        
#Ausführung des MQTT-Clients in einem seperaten Thread
mqtt_t = threading.Thread(target=mqtt_thread)
mqtt_t.start()
#Ausführung der Tasterabfrage in einem seperaten Thread
taster_t = threading.Thread(target=taster)
taster_t.start()
#Ausführung der Funktion blink
blink()


    



