#include // #include #include #include extern "C" { #include "freertos/FreeRTOS.h" #include "freertos/timers.h" } // #define MQTT_VALVE_COMMAND(device_id) (MQTT_TOPIC_BASE_SUB "/" device_id "/valve") // #define MQTT_SOIL_PROPERTIES(device_id) (MQTT_TOPIC_BASE_SUB "/" device_id "/soil") // #define MQTT_LIGHT_PROPERTIES(device_id) (MQTT_TOPIC_BASE_SUB "/" device_id "/light") // #define MQTT_AUTO_PROPERTIES(device_id) (MQTT_TOPIC_BASE_SUB "/" device_id "/automatic") char MQTT_VALVE_COMMAND[72]; char MQTT_SOIL_PROPERTIES[72]; char MQTT_LIGHT_PROPERTIES[72]; char MQTT_AUTO_PROPERTIES[72]; TimerHandle_t mqttReconnectTimer; TimerHandle_t wifiReconnectTimer; TaskHandle_t mqttTask; WebServer Server; AutoConnect Portal(Server); WiFiClient client; AutoConnectConfig Config; PubSubClient mqttClient(client); void connectWiFi() { yield(); Serial.println("Start WiFi..."); if (Portal.begin()) { digitalWrite(PIN_LED_G, HIGH); } } void mqttLoop(void *parameter) { do { yield(); mqttClient.loop(); delay(100); } while (mqttClient.connected()); Serial.println("Disconnected from MQTT."); if (!mqttClient.connected()) { Serial.println("Checking WiFi Connection."); if (WiFi.isConnected()) { Serial.println("WiFi OK. Starting reconnect timer for MQTT."); xTimerStart(mqttReconnectTimer, 0); } } vTaskDelete(NULL); } void connectMQTT() { yield(); if (mqttClient.connected()) return; Serial.println("Connecting to MQTT..."); // mqttClient.begin(MQTT_HOST, MQTT_PORT, client); mqttClient.setServer(MQTT_HOST, MQTT_PORT); mqttClient.disconnect(); mqttClient.connect(getDeviceIDcharArr()); if (mqttClient.connected()) { Serial.println("Connected!"); } else { Serial.println("NOT Connected!"); } mqttClient.subscribe(MQTT_PATH_SUB); Serial.print("subscribed to: "); Serial.println(MQTT_PATH_SUB); xTaskCreatePinnedToCore( mqttLoop, "mqttLoop", 8192, NULL, 2, &mqttTask, 1); // xTaskCreate( // mqttLoop, /* Task function. */ // "mqttLoop", /* String with name of task. */ // 8192, /* Stack size in bytes. */ // NULL, /* Parameter passed as input of the task */ // 1, /* Priority of the task. */ // &mqttTask); /* Task handle. */ } void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { Serial.printf("[WiFi-event] event: %d\n", event); switch (event) { case SYSTEM_EVENT_STA_GOT_IP: Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); connectMQTT(); break; case SYSTEM_EVENT_STA_DISCONNECTED: digitalWrite(PIN_LED_G, LOW); // workaround for 202 auth failed bug: https://github.com/espressif/arduino-esp32/issues/2501 if (info.disconnected.reason == 202) { Serial.println("weirdbehaviour"); Serial.println(info.disconnected.reason); ESP.restart(); } xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi xTimerStart(wifiReconnectTimer, 0); break; } } void onMqttMessage(char *topic, byte *payload, unsigned int payload_length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < payload_length; i++) { Serial.print((char)payload[i]); } Serial.println(); if (strcmp(topic, MQTT_LIGHT_PROPERTIES) == 0) { Serial.println("receiving light treshold..."); Serial.println(topic); StaticJsonDocument<1024> doc; DeserializationError err = deserializeJson(doc, payload); if (err == DeserializationError::Ok) { int nm = doc["nm"]; int minLX = doc["minLX"]; setLightProperties(nm, minLX); } else { Serial.println(err.c_str()); } } if (strcmp(topic, MQTT_VALVE_COMMAND) == 0) { Serial.println("toggling valve..."); Serial.println(topic); toggleValve(false); } if (strcmp(topic, MQTT_SOIL_PROPERTIES) == 0) { Serial.println("receiving soil thresholds..."); Serial.println(topic); StaticJsonDocument<1024> doc; DeserializationError err = deserializeJson(doc, payload); if (err == DeserializationError::Ok) { int fc = doc["fc"]; int pwp = doc["pwp"]; int sat = doc["sat"]; setSoilProperties(fc, pwp, sat); } else { Serial.println(err.c_str()); } } if (strcmp(topic, MQTT_AUTO_PROPERTIES) == 0) { Serial.println("receiving auto settings..."); Serial.println(topic); StaticJsonDocument<1024> doc; DeserializationError err = deserializeJson(doc, payload); if (err == DeserializationError::Ok) { bool ir = doc["irrigation"]; bool li = doc["light"]; setAutoProperties(li, ir); } else { Serial.println(err.c_str()); } } } void constructMQTTpaths() { strcpy(MQTT_VALVE_COMMAND, MQTT_TOPIC_BASE_SUB "/"); strcat(MQTT_VALVE_COMMAND, getDeviceIDcharArr()); strcat(MQTT_VALVE_COMMAND, "/valve"); strcpy(MQTT_SOIL_PROPERTIES, MQTT_TOPIC_BASE_SUB "/"); strcat(MQTT_SOIL_PROPERTIES, getDeviceIDcharArr()); strcat(MQTT_SOIL_PROPERTIES, "/soil"); strcpy(MQTT_LIGHT_PROPERTIES, MQTT_TOPIC_BASE_SUB "/"); strcat(MQTT_LIGHT_PROPERTIES, getDeviceIDcharArr()); strcat(MQTT_LIGHT_PROPERTIES, "/light"); strcpy(MQTT_AUTO_PROPERTIES, MQTT_TOPIC_BASE_SUB "/"); strcat(MQTT_AUTO_PROPERTIES, getDeviceIDcharArr()); strcat(MQTT_AUTO_PROPERTIES, "/automatic"); Serial.println("MQTT_COMMANDS:"); Serial.println(MQTT_VALVE_COMMAND); Serial.println(MQTT_SOIL_PROPERTIES); Serial.println(MQTT_LIGHT_PROPERTIES); Serial.println(MQTT_AUTO_PROPERTIES); } void setupConnections() { constructMQTTpaths(); Serial.println(); Serial.println(); disableCore0WDT(); // disableCore1WDT(); Config.autoReconnect = true; // Config.autoReset = true; Portal.config(Config); mqttReconnectTimer = xTimerCreate( "mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast(connectMQTT)); wifiReconnectTimer = xTimerCreate( "wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void *)0, reinterpret_cast(connectWiFi)); WiFi.onEvent(WiFiEvent); connectWiFi(); connectMQTT(); mqttClient.setCallback(onMqttMessage); } void publishMessage(const char *topic, const char *msg) { if(mqttClient.connected()) { mqttClient.publish(topic, msg); Serial.print(topic); Serial.println(" successfully sent."); } else { Serial.println("couldn't send message. waiting for reconnect."); } }