diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..379e402 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cquery.cacheDirectory": "${workspaceFolder}/.vscode/cquery_cached_index/" +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index fe810f5..346cfd9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -19,6 +19,9 @@ lib_deps = 19 #DHT sensor library 31 #Adafruit Unified Sensor AutoConnect@^1.1.7 - ; ESPRandom@^1.3.3 AsyncMqttClient@^0.8.2 - ; PubSubClient@^2.8 \ No newline at end of file + ArduinoJson@^6.15.2 + ; MQTT@^2.4.7 + PubSubClient@^2.8 + ArduinoNvs@^2.5 + ; ESPRandom@^1.3.3 \ No newline at end of file diff --git a/src/connections.cpp b/src/connections.cpp index 9971b25..3830f28 100644 --- a/src/connections.cpp +++ b/src/connections.cpp @@ -1,15 +1,22 @@ +#include +// #include +#include #include -extern "C" -{ +extern "C" { #include "freertos/FreeRTOS.h" #include "freertos/timers.h" } -AsyncMqttClient mqttClient; +#define MQTT_VALVE_COMMAND MQTT_TOPIC_BASE_SUB "/" MQTT_DEVICE_ID "/valve" +#define MQTT_SOIL_PROPERTIES MQTT_TOPIC_BASE_SUB "/" MQTT_DEVICE_ID "/soil" + TimerHandle_t mqttReconnectTimer; TimerHandle_t wifiReconnectTimer; +// TimerHandle_t mqttProcessingTimer; +TaskHandle_t mqttTask; + WebServer Server; AutoConnect Portal(Server); WiFiClient client; @@ -17,122 +24,127 @@ WiFiClient client; AutoConnectConfig Config; // Config.autoReconnect = true; // WiFi.config(Config); +// MQTTClient mqttClient; +PubSubClient mqttClient(client); -void connectWiFi() -{ +void connectWiFi() { Serial.println("Start WiFi..."); - if (Portal.begin()) - { + if (Portal.begin()) { digitalWrite(PIN_LED_G, HIGH); } } -void connectMQTT() -{ - Serial.println("Connecting to MQTT..."); - mqttClient.setClientId(MQTT_DEVICE_ID); - mqttClient.connect(); -} - -void WiFiEvent(WiFiEvent_t event) -{ - 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); - Serial.println("WiFi lost connection"); - xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi - xTimerStart(wifiReconnectTimer, 0); - break; +void mqttLoop(void *parameter) { + do { + mqttClient.loop(); + delay(50); + } while (mqttClient.connected()); + Serial.println("Disconnected from MQTT."); + if (!mqttClient.connected()) { + Serial.println("Checking WiFi Connection."); + if (WiFi.isConnected()) { + Serial.println("Starting reconnect timer for MQTT."); + xTimerStart(mqttReconnectTimer, 0); + } } + vTaskDelete(NULL); } -void onMqttConnect(bool sessionPresent) -{ - Serial.println("Connected to MQTT."); - - Serial.print("Session present: "); - Serial.println(sessionPresent); - - uint16_t packetIdSub = mqttClient.subscribe(MQTT_PATH_SUB, 2); +void connectMQTT() { + Serial.println("Connecting to MQTT..."); + // mqttClient.begin(MQTT_HOST, MQTT_PORT, client); + mqttClient.setServer(MQTT_HOST, MQTT_PORT); + mqttClient.connect(MQTT_DEVICE_ID); + 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); + 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. */ + //xTimerStart(mqttProcessingTimer, 0); } -void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) -{ - Serial.println("Disconnected from MQTT."); - - if (WiFi.isConnected()) - { - xTimerStart(mqttReconnectTimer, 0); +void WiFiEvent(WiFiEvent_t event) { + 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); + xTimerStop(mqttReconnectTimer, 0); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi + // xTimerStop(mqttProcessingTimer, 0); + xTimerStart(wifiReconnectTimer, 0); + break; } } -void onMqttSubscribe(uint16_t packetId, uint8_t qos) -{ - Serial.print("Subscribe acknowledged:"); - Serial.print(" packetId: "); - Serial.print(packetId); - Serial.print(" qos: "); - Serial.println(qos); -} +// void onMqttMessage(MQTTClient *client, char topic[], char payload[], int payload_length) { +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(); -void onMqttUnsubscribe(uint16_t packetId) -{ - Serial.println("Unsubscribe acknowledged."); - Serial.print(" packetId: "); - Serial.println(packetId); -} - -void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) -{ - Serial.print("Publish received: "); - Serial.print(" topic: "); - Serial.println(topic); - - if (strcmp(topic, "smartgarden/commands") == 0 ) { - Serial.println("executing command..."); + if (strcmp(topic, MQTT_VALVE_COMMAND) == 0) { + Serial.println("toggling valve..."); Serial.println(topic); toggleValve(); } + if (strcmp(topic, MQTT_SOIL_PROPERTIES) == 0) { + Serial.println("receiving soil thresholds..."); + Serial.println(topic); + //Serial.println(reinterpret_cast(payload)); + // Serial.println(payload); + // const int capacity = JSON_OBJECT_SIZE(3) + 2 * JSON_OBJECT_SIZE(1); + 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()); + } + } } -void onMqttPublish(uint16_t packetId) -{ - Serial.print("Publish acknowledged: "); - Serial.print(" packetId: "); - Serial.println(packetId); -} - -void setupConnections() -{ +void setupConnections() { Serial.println(); Serial.println(); - 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)); + 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)); + // mqttProcessingTimer = xTimerCreate( + // "messageTimer", pdMS_TO_TICKS(50), pdTRUE, (void *)0, reinterpret_cast(mqttLoop)); WiFi.onEvent(WiFiEvent); - mqttClient.onConnect(onMqttConnect); - mqttClient.onDisconnect(onMqttDisconnect); - mqttClient.onSubscribe(onMqttSubscribe); - mqttClient.onUnsubscribe(onMqttUnsubscribe); - mqttClient.onMessage(onMqttMessage); - mqttClient.onPublish(onMqttPublish); - mqttClient.setServer(MQTT_HOST, MQTT_PORT); + // mqttClient.onMessageAdvanced(onMqttMessage); + mqttClient.setCallback(onMqttMessage); connectWiFi(); } void publishMessage(const char *topic, const char *msg) { - mqttClient.publish(topic, 1, true, msg); + mqttClient.publish(topic, msg); + // mqttClient.publish(topic, msg, true, 1); } diff --git a/src/header.h b/src/header.h index 4b91a52..7955c34 100644 --- a/src/header.h +++ b/src/header.h @@ -15,7 +15,10 @@ #include #include #include -#include + +// fix for core panic during wifi initialization +// #define configMINIMAL_STACK_SIZE 2048 +// #define CONFIG_TIMER_TASK_STACK_SIZE 8192 // DHT11 #define PIN_DHT11 14 @@ -70,4 +73,6 @@ extern void publishMessage(const char *topic, const char *msg); // sensors void readSensors(); -void toggleValve(); \ No newline at end of file +void toggleValve(); +void setSoilProperties(int FC, int PWP, int SAT); +void setupStore(); \ No newline at end of file diff --git a/src/lightSensor.cpp b/src/lightSensor.cpp index 1dca49b..776a3fd 100644 --- a/src/lightSensor.cpp +++ b/src/lightSensor.cpp @@ -3,13 +3,12 @@ BH1750 lightMeter; void setupLightSensor() { - Wire.begin(); - lightMeter.begin(); - Serial.println("Sensor started..."); + Wire.begin(); + lightMeter.begin(); + Serial.println("Sensor started..."); } -float readLightSensorValue() -{ - float intensity = lightMeter.readLightLevel(); - return intensity; +float readLightSensorValue() { + float intensity = lightMeter.readLightLevel(); + return intensity; } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 2e450c8..3a609ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,13 +3,13 @@ */ #include + #include unsigned long sensorReadTimer = 0; bool valveOpen = false; -void setup() -{ +void setup() { Serial.begin(115200); sensorReadTimer = millis(); @@ -20,6 +20,7 @@ void setup() digitalWrite(PIN_VALVE, LOW); + setupStore(); setupConnections(); setupLightSensor(); setupTemperatureSensor(); @@ -29,17 +30,13 @@ void setup() Serial.println(); } -void loop() -{ +void loop() { // read sensors - if (millis() - sensorReadTimer >= FREQUENCY) - { + if (millis() - sensorReadTimer >= FREQUENCY) { readSensors(); sensorReadTimer = millis(); } // toggle valve if (valveOpen) { - } } - diff --git a/src/peripherals.cpp b/src/peripherals.cpp index f7d68d2..6d93cf9 100644 --- a/src/peripherals.cpp +++ b/src/peripherals.cpp @@ -1,46 +1,58 @@ +#include +#include #include + #include //using namespace std; -extern "C" -{ +extern "C" { #include "freertos/FreeRTOS.h" #include "freertos/task.h" } -#define MQTT_MOISTURE MQTT_PATH_PUB "moisture" -#define MQTT_TEMPERATURE MQTT_PATH_PUB "temperature" -#define MQTT_HUMIDITY MQTT_PATH_PUB "humidity" -#define MQTT_BRIGHTNESS MQTT_PATH_PUB "brightness" +#define MQTT_SENSOR_DATA MQTT_PATH_PUB "data" -char buffer[16]; +char buffer[128]; -void readSensors() -{ +// Feldkapazität des Bodens in Prozent: Standard ist Humus +int fieldCapacity = 44; +// PWP des Bodens in Prozent: Standard ist Humus +int permanentWiltingPoint = 25; +// Boden vollständig gesättigt bei (Prozent): Standard ist Humus +int soilSaturation = 69; + +void readSensors() { + StaticJsonDocument<128> doc; float lxValue = readLightSensorValue(); Serial.print("Light intensity: "); Serial.print(lxValue); Serial.println(" lx"); - sprintf(buffer, "%f", lxValue); - publishMessage(MQTT_BRIGHTNESS, buffer); + doc["brightness"] = lxValue; + //sprintf(buffer, "%f", lxValue); + //publishMessage(MQTT_BRIGHTNESS, buffer); int mstValue = readCapacitiveSoilMoistureSensor(); Serial.print("Soil moisture: "); Serial.println(mstValue); - sprintf(buffer, "%i", mstValue); - publishMessage(MQTT_MOISTURE, buffer); + // sprintf(buffer, "%i", mstValue); + // publishMessage(MQTT_MOISTURE, buffer); + doc["moisture"] = mstValue; float humidityValue = readHumidity(); Serial.print("Humidity: "); Serial.println(humidityValue); - sprintf(buffer, "%f", humidityValue); - publishMessage(MQTT_HUMIDITY, buffer); + // sprintf(buffer, "%f", humidityValue); + // publishMessage(MQTT_HUMIDITY, buffer); + doc["humidity"] = humidityValue; float temperatureValue = readTemperature(); Serial.print("Temperature: "); Serial.println(temperatureValue); - sprintf(buffer, "%f", temperatureValue); - publishMessage(MQTT_TEMPERATURE, buffer); + // sprintf(buffer, "%f", temperatureValue); + // publishMessage(MQTT_TEMPERATURE, buffer); + doc["temperature"] = temperatureValue; Serial.print("\n"); + serializeJson(doc, buffer); + publishMessage(MQTT_SENSOR_DATA, buffer); } bool openValve() { @@ -57,18 +69,15 @@ bool closeValve() { return false; } -void valveTask(void *parameter) -{ +void valveTask(void *parameter) { unsigned long valveTimeoutTimer = millis(); bool valveOpen = openValve(); - while (valveOpen) - { + while (valveOpen) { delay(500); int mstValue = readCapacitiveSoilMoistureSensor(); - if (millis() - valveTimeoutTimer >= MAX_VALVE_TIMEOUT) - { + if (millis() - valveTimeoutTimer >= MAX_VALVE_TIMEOUT) { valveOpen = closeValve(); } // if (mstValue > 80) { @@ -78,13 +87,64 @@ void valveTask(void *parameter) vTaskDelete(NULL); } -void toggleValve() -{ +void toggleValve() { xTaskCreate( valveTask, /* Task function. */ "valveTask", /* String with name of task. */ - 10000, /* Stack size in bytes. */ + 2048, /* Stack size in bytes. */ NULL, /* Parameter passed as input of the task */ 1, /* Priority of the task. */ NULL); /* Task handle. */ } + +void persistSoilProps(int FC, int PWP, int SAT) { + Serial.println("persistSoilProps"); + bool f = NVS.setInt("fieldCapacity", FC); + bool p = NVS.setInt("permanentWilt", PWP); + bool s = NVS.setInt("soilSaturation", SAT); + if (f && p && s) { + Serial.println("Soil properties sucessfully stored."); + NVS.commit(); + } + else { + Serial.println("error occured while trying to persist soil properties"); + } +} + +void restoreSoilProps() { + Serial.println("restoreSoilProps"); + int fc = NVS.getInt("fieldCapacity"); + int pwp = NVS.getInt("permanentWilt"); + int sat = NVS.getInt("soilSaturation"); + if (fc != 0) { + fieldCapacity = fc; + } + if (pwp != 0) { + permanentWiltingPoint = pwp; + } + if (sat != 0) { + soilSaturation = sat; + } + Serial.print(fieldCapacity); + Serial.print(permanentWiltingPoint); + Serial.print(soilSaturation); +} + +void setupStore() { + NVS.begin("store"); + restoreSoilProps(); +} + +void setSoilProperties(int FC, int PWP, int SAT) { + fieldCapacity = FC; + permanentWiltingPoint = PWP; + soilSaturation = SAT; + persistSoilProps(FC, PWP, SAT); + Serial.print("new fieldCapacity: "); + Serial.println(fieldCapacity); + Serial.print("new permanentWiltingPoint: "); + Serial.println(permanentWiltingPoint); + Serial.print("new soilSaturation: "); + Serial.println(soilSaturation); +} +