from machine import Pin, ADC
from umqtt.robust import MQTTClient
import ujson
import network
from utime import ticks_ms
import dht

# Setups do sistema

DEVICE_ID = "922"

WIFI_SSID     = "Wokwi-GUEST"
WIFI_PASSWORD = ""

MQTT_BROKER          = "broker.mqttdashboard.com"
MQTT_CLIENT          = DEVICE_ID
MQTT_TELEMETRY_TOPIC = "IFRS/ESP32_IoT/telemetry"
MQTT_CONTROL_TOPIC   = "IFRS/ESP32_IoT/control"


button     = Pin(14, Pin.IN, Pin.PULL_DOWN)
blueLED    = Pin(4, Pin.OUT)
greenLED   = Pin(18, Pin.OUT)
ogDHT      = dht.DHT22(Pin(15))
luz        = ADC(Pin(33))


buttonHistory = 0

connectDelay  = ticks_ms() + 200

global lockDelay
lockDelay = ticks_ms()


##########################################################################################################################

# Funções

def receivedCallback(topic, message):
    print('\n\nData Recieved! \ntopic = {0}, message = {1}'.format(topic, message))

    if topic == MQTT_CONTROL_TOPIC.encode():
        if message == ('{\"ID:\": \"922\", \"LED\": \"ON\"}').encode():
            greenLED.on()
            lockDelay     = ticks_ms() + 5000

            if ticks_ms() >= lockDelay:
                greenLED.off()

        elif message == ('{\"ID:\": \"922\", \"LED\": \"OFF\"}').encode():
            greenLED.off()

        jsonLedStatus()

def mqttConnect():
    print("Connecting to MQTT broker... ", end="")
    mqttClient = MQTTClient(MQTT_CLIENT, MQTT_BROKER, user="ESP32_IFRS", password="ifrsrgautomacao")
    mqttClient.set_callback(receivedCallback)
    mqttClient.connect()
    print("Connected!")
    mqttClient.subscribe(MQTT_CONTROL_TOPIC)
    return mqttClient

def mqttPublish(topic, data):
    print("\nUpdating MQTT Broker...")
    mqttClient.publish(topic, data)

def createJsonData(lumens, temp, hum):
    data = {
            "ID": DEVICE_ID,
            "Luminosidade": lumens,
            "Temperatura": f'{temp:.2f}ºC',
            "Umidade": f'{hum}%'
            }
    return ujson.dumps(data)

def createJsonButton(x):
    data = ujson.dumps(
        {"ID:": "922", "LED": "ON" if x == 1 else "OFF"})
        
    return data

def jsonLedStatus():
    data = ujson.dumps(
        {"CONTROLLED LED": "ON" if greenLED.value() == 1 else "OFF"})
    print(data)

##########################################################################################################################

# Programa principal

wifiClient = network.WLAN(network.STA_IF)
wifiClient.active(True)
print("Connecting device to WiFi", end="")
wifiClient.connect(WIFI_SSID, WIFI_PASSWORD)

while not wifiClient.isconnected():
    if ticks_ms() >= connectDelay:
        print(".", end="")
        connectDelay = ticks_ms() + 200
print("Wifi connected!\n")
print(wifiClient.ifconfig())


mqttClient = mqttConnect()

oldButtonTelemetryData  = ""
oldTelemetryData        = ""

antiBouncing  = ticks_ms() + 100
publishTimer     = ticks_ms() + 5000
printLoop     = ticks_ms() + 200
timerLux      = ticks_ms() + 4000



while True:

    mqttClient.check_msg()

    ogDHT.measure()
    

    if ticks_ms() >= printLoop:
        print(". ", end="")
        printLoop = ticks_ms() + 200

 

    if ticks_ms() >= antiBouncing:
        buttonStatus = button.value()
        if buttonStatus != buttonHistory:
            if buttonStatus == 1:
                blueLED.value(not blueLED())

            buttonHistory = buttonStatus
            antiBouncing = ticks_ms() + 100


    
    newButtonTelemetryData = createJsonButton(blueLED.value())

    if newButtonTelemetryData != oldButtonTelemetryData:
        mqttPublish(MQTT_CONTROL_TOPIC, newButtonTelemetryData.encode())  
        print(newButtonTelemetryData)
        oldButtonTelemetryData = newButtonTelemetryData



    newTelemetryData = createJsonData(luz.read(), ogDHT.temperature(), ogDHT.humidity())

    if ticks_ms() >= publishTimer and newTelemetryData != oldTelemetryData:
        mqttPublish(MQTT_CONTROL_TOPIC, newTelemetryData.encode())  
        print(newTelemetryData)
        oldTelemetryData = newTelemetryData
        publishTimer = ticks_ms() + 5000

    if ticks_ms() >= lockDelay and greenLED:
        greenLED.off()
        lockDelay = ticks_ms() + 5000