diff options
author | Florian Baumann <derflob@derflob.de> | 2020-06-09 18:04:20 +0200 |
---|---|---|
committer | Florian Baumann <derflob@derflob.de> | 2020-06-09 18:06:21 +0200 |
commit | 2c3dc2b448ab917123af7a4f15b5fb1d8e0e2351 (patch) | |
tree | 7b95eba97ce9135579cb81917887e91b10ac3cf8 | |
parent | d36c70f712a0851a53cc5d26516a9e2439305d38 (diff) | |
download | ULPSoilMonitor-2c3dc2b448ab917123af7a4f15b5fb1d8e0e2351.tar.gz ULPSoilMonitor-2c3dc2b448ab917123af7a4f15b5fb1d8e0e2351.tar.bz2 |
publish data via mqtt, homeassistant-autodiscovery-compatiblestatic-wifi
-rw-r--r-- | ULPSoilMonitor.ino | 194 |
1 files changed, 176 insertions, 18 deletions
diff --git a/ULPSoilMonitor.ino b/ULPSoilMonitor.ino index 1f63925..b401398 100644 --- a/ULPSoilMonitor.ino +++ b/ULPSoilMonitor.ino @@ -7,12 +7,28 @@ #include "config.h" #include <math.h> +#include <WiFi.h> +#include <PubSubClient.h> +#include <ArduinoJson.h> + #define ADC_FACTOR (3.5f) #define ADC_VCC_PIN (ADC2_CHANNEL_9) extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); +volatile enum ulpsm_states { + ULPSM_RESETTING, + ULPSM_CONNECTING_WIFI, + ULPSM_CONNECTING_MQTT, + ULPSM_PUBLISHING_DATA, + ULPSM_PUBLISHED_DATA, + ULPSM_DISCONNECTING_MQTT, + ULPSM_DISCONNECTING_WIFI, + ULPSM_DONE, +} state; + + struct { float soil0; float soil1; @@ -33,10 +49,10 @@ struct soil_data { bool valid = false; } soil; -/* To be called once after power-on reset, to load ULP program into - RTC memory and configure the ADC. - */ -static void init_ulp_program(); +WiFiClient wifi_client; +PubSubClient mqtt(wifi_client); + +static void init_ulp_periphery(); /* To be called every time before going into deep sleep. It starts the ULP program and resets measurement counter. @@ -53,41 +69,123 @@ static float soil_moisture(uint16_t adc_value, float vcc, float offset, float gr /* fills soil_data struct */ static void calculate_soil_data(); -/* logs current soil_data */ +/* logs current soil_data to Serial */ static void print_soil_data(); +/* publish current soil_data via MQTT */ +static void publish_soil_data(); + void setup() { Serial.begin(115200); esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); if (cause == ESP_SLEEP_WAKEUP_ULP) { - Serial.printf("Deep sleep wakeup\n"); Serial.printf("max_diff:%d\n", (uint16_t)ulp_max_diff); + if ((uint16_t)ulp_max_diff == 4095) { + Serial.printf("Skip first measurement after reset\n"); + state = ULPSM_DONE; + return; + } + measure_vcc(); + + WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info) { + Serial.printf("WiFi connected & got IP\n"); + mqtt.connect(HOSTNAME); + state = ULPSM_CONNECTING_MQTT; + }, WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); + + WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info) { + if (state == ULPSM_DISCONNECTING_WIFI) { + state = ULPSM_DONE; + } else { + state = ULPSM_RESETTING; + } + }, WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); + + WiFi.begin(STA_SSID, STA_PASSWD); + + state = ULPSM_CONNECTING_WIFI; + + mqtt.setServer(MQTT_HOST, 1883); + calculate_soil_data(); print_soil_data(); + } - } else { +} + +void loop() { + mqtt.loop(); + + if (state == ULPSM_RESETTING) { + Serial.printf("Loading ULP...\n"); esp_err_t err = ulptool_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t)); ESP_ERROR_CHECK(err); + /* Set ULP wake up period */ + ulp_set_wakeup_period(0, ULP_PERIOD_MS * 1000); + + state = ULPSM_DONE; } - Serial.printf("Entering deep sleep\n\n"); - start_ulp_program(); - ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup()); - esp_deep_sleep_start(); -} + if (state == ULPSM_CONNECTING_MQTT) { + auto mqtt_state = mqtt.state(); + if (mqtt_state == MQTT_CONNECTED) { + Serial.printf("MQTT connected.\n"); + state = ULPSM_PUBLISHING_DATA; -void loop() { + } else if (mqtt_state == MQTT_CONNECTION_TIMEOUT || mqtt_state == MQTT_CONNECT_FAILED) { + Serial.printf("MQTT connection failed.\n"); + state = ULPSM_DONE; + } else if (mqtt_state > MQTT_CONNECTED) { + Serial.printf("MQTT failed after connection: %d\n", mqtt_state); + state = ULPSM_DONE; + + } else { + Serial.printf("MQTT unkown error: %d\n", mqtt_state); + state = ULPSM_DONE; + } + } + + if (state == ULPSM_PUBLISHING_DATA) { + Serial.printf("Publishing data...\n"); + publish_soil_data(); + state = ULPSM_PUBLISHED_DATA; + } + + if (state == ULPSM_PUBLISHED_DATA) { + wifi_client.flush(); + mqtt.loop(); + wifi_client.flush(); + + mqtt.disconnect(); + state = ULPSM_DISCONNECTING_MQTT; + } + + if (state == ULPSM_DISCONNECTING_MQTT) { + auto mqtt_state = mqtt.state(); + if (mqtt_state != MQTT_CONNECTED) { + WiFi.disconnect(); + state = ULPSM_DISCONNECTING_WIFI; + } + } + + if (state == ULPSM_DONE) { + Serial.printf("Starting ULP & entering deep sleep\n\n"); + start_ulp_program(); + + ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup()); + esp_deep_sleep_start(); + } } -static void init_ulp_program() +static void init_ulp_periphery() { /* Configure ADC channel */ adc1_ulp_enable(); @@ -108,9 +206,6 @@ static void init_ulp_program() rtc_gpio_set_level(GPIO_NUM_25, 1); rtc_gpio_hold_en(GPIO_NUM_25); - /* Set ULP wake up period */ - ulp_set_wakeup_period(0, ULP_PERIOD_MS * 1000); - /* Disable pullup on GPIO15, in case it is connected to ground to suppress boot messages. */ @@ -120,7 +215,8 @@ static void init_ulp_program() static void start_ulp_program() { - init_ulp_program(); + + init_ulp_periphery(); /* Start the program */ esp_err_t err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)); @@ -214,3 +310,65 @@ static void print_soil_data() Serial.printf("Soil4:%d -> %f\n", (uint16_t)ulp_soil4, soil.soil4); Serial.printf("Soil5:%d -> %f\n", (uint16_t)ulp_soil5, soil.soil5); } + +static void publish_vcc() +{ + String topic = String("homeassistant/sensor/") + String(HOSTNAME) + String("/vcc/"); + String id = String(HOSTNAME) + String("_vcc"); + + StaticJsonDocument<512> config; + config["name"] = id; + config["state_topic"] = topic + "state"; + config["unit_of_measurement"] = "V"; + config["unique_id"] = id; + + JsonObject dev = config.createNestedObject("device"); + dev["name"] = HOSTNAME; + dev["identifiers"] = HOSTNAME; + dev["manufacturer"] = "Flobs"; + dev["model"] = "ULPSoilMonitor v2.0"; + + size_t message_size = measureJson(config); + mqtt.beginPublish((topic + "config").c_str(), message_size, true); + serializeJson(config, mqtt); + mqtt.endPublish(); + + String vcc = String(soil.vcc); + mqtt.publish((topic + "state").c_str(), vcc.c_str(), true); +} + +static void publish_soil(uint8_t index, float value) +{ + String topic = String("homeassistant/sensor/") + String(HOSTNAME) + String("/soil") + String(index) + String("/"); + String id = String(HOSTNAME) + String("_soil") + String(index); + + StaticJsonDocument<512> config; + config["name"] = id; + config["state_topic"] = topic + "state"; + config["unit_of_measurement"] = "%"; + config["unique_id"] = id; + + JsonObject dev = config.createNestedObject("device"); + dev["name"] = HOSTNAME; + dev["identifiers"] = HOSTNAME; + dev["manufacturer"] = "Flobs"; + dev["model"] = "ULPSoilMonitor v2.0"; + + size_t message_size = measureJson(config); + mqtt.beginPublish((topic + "config").c_str(), message_size, true); + serializeJson(config, mqtt); + mqtt.endPublish(); + + mqtt.publish((topic + "state").c_str(), String(value).c_str(), true); +} + +static void publish_soil_data() +{ + publish_vcc(); + publish_soil(0, soil.soil0); + publish_soil(1, soil.soil1); + publish_soil(2, soil.soil2); + publish_soil(3, soil.soil3); + publish_soil(4, soil.soil4); + publish_soil(5, soil.soil5); +} |