### Einbinden der Pakete ###
# generelle Pakete 
from cProfile import run
from wsgiref.simple_server import demo_app
import paho.mqtt.client as mqtt
import json
import time
### Initialisieren der Fariablen ###

# Host Name des Thingsboard
THINGSBOARD_HOST = 'thingsboard.cloud'
# Access token für Phillis Vesorgungswagen 
ACCESS_TOKEN = 'sCdIh0TLguO5gvSRZcL8' 

gpio_state = {1: True, 2: False}
run_status = ""
drive_status = False
demo_mode = False
debug_mode = True

### Definieren der Funktionen ###


def on_connect(client, userdata, rc, test):
    """Der Callback für den Fall, dass der Client eine CONNACK-Antwort vom Server erhält

    Parameters
    ----------
    client : class
        mqtt client
    userdata : str
        userdata
    rc : str
        response from connetction
    """
    if debug_mode: print('Connected with result code ' + str(rc))
    # Abonnieren des Empfangs von RPC-Anfragen
    client.subscribe('v1/devices/me/rpc/request/+')
    # Senden des aktuellen GPIO-Status
    client.publish('v1/devices/me/attributes', get_gpio_status(), 1)

def on_message(client, userdata, msg):
    """Callback, wenn eine PUBLISH-Nachricht vom Server empfangen wird.

    Parameters
    ----------
    client : class
        mqtt client
    userdata : str
        userdata
    msg : str
        Nachricht 
    """
    if debug_mode: print( 'Topic: ' + msg.topic + '\nMessage: ' + str(msg.payload))
    # JSON-Anfrage dekodieren
    data = json.loads(msg.payload)
    # Anforderungsmethode prüfen
    if data['method'] == 'getGpioStatus':
        # Antwort mit GPIO-Status
        client.publish(msg.topic.replace('request', 'response'), get_gpio_status(), 1)
    elif data['method'] == 'setGpioStatus':
        # GPIO-Status und Antwort aktualisieren
        set_gpio_status(data['params']['pin'], data['params']['enabled'])
        # Überdabe der daten zum setzten der Variablen
        switch_on_off(data)
        client.publish(msg.topic.replace('request', 'response'), get_gpio_status(), 1)
        client.publish('v1/devices/me/attributes', get_gpio_status(), 1)

def switch_on_off(data):
    """Diese Funktion leißt die erhaltenen Daten aus und setzt "drive_status" und "demo_mode" entsprechend.

    Parameters
    ----------
    data : dict
        Vom Thingsboard erhaltene Daten
    """
    global drive_status
    global demo_mode
    if data['params']['enabled'] and data['params']['pin'] == 1:
        drive_status = True
        if debug_mode: print("Staus von Pin 1 im TB auf True gesetzt")
    elif not data['params']['enabled'] and data['params']['pin'] == 1:
        drive_status = False
        if debug_mode: print("Staus von Pin 1 im TB auf False gesetzt")
    elif data['params']['enabled'] and data['params']['pin'] == 2:
        demo_mode = True
        if debug_mode: print("Staus von Pin 2 im TB auf True gesetzt")
    elif not data['params']['enabled'] and data['params']['pin'] == 2:
        demo_mode = False
        if debug_mode: print("Staus von Pin 2 im TB auf False gesetzt")
    else:
        drive_status = False
        demo_mode = False
        if debug_mode: print("run status error" + str(data))

def get_gpio_status():
    """Gibt den aktuellen Zustand der Pins als json zurück

    Returns
    -------
    json
        Aktueller zustand der Pins
    """
    # GPIOs-Status in json kodieren
    return json.dumps(gpio_state)

def set_gpio_status(pin, status):
    """Setzt den Status von gpio_status

    Parameters
    ----------
    pin : int
        Bezeichnung des Pins welcher verändert werden soll
    status : bool
        Zustand des Pins
    """
    # GPIOs-Status aktualisieren
    gpio_state[pin] = status
    
def run_demo_mode():
    """Diese Funktion stelle eine Verbingung per MQTT zum Thingsboard her und prüft auf Statusänderungen. 
    """
    client = mqtt.Client()
    # Callback zum Verbinden registrieren
    if debug_mode: print(str(client))
    client.on_connect = on_connect
    # Callback zur Veröffentlichung von Nachrichten registrieren
    client.on_message = on_message
    # Setzte access token
    client.username_pw_set(ACCESS_TOKEN)
    # Verbindung zum Thingsboard über den Standard-MQTT-Port und 60 Sekunden Keepalive-Intervall
    client.connect(THINGSBOARD_HOST, 1883, 60)
    try:
        client.loop_forever()
        
    except KeyboardInterrupt:
        print("erros detected")