# HG changeset patch # User Michiel Broek # Date 1680188705 -7200 # Node ID b1f38105ca7e51071967f719c4e0a85d3a7ac16f # Parent d0155c16e9927e8bb8ab6621e5bd1ae10376b53a Added task MQTT and some utilities. Added more power measurement variables and code. INA219 measurements are saved in the State record. diff -r d0155c16e992 -r b1f38105ca7e main/CMakeLists.txt --- a/main/CMakeLists.txt Wed Mar 29 21:39:07 2023 +0200 +++ b/main/CMakeLists.txt Thu Mar 30 17:05:05 2023 +0200 @@ -1,2 +1,2 @@ -idf_component_register(SRCS config.c iotbalkon.c task_bmp280.c task_ina219.c task_wifi.c +idf_component_register(SRCS config.c iotbalkon.c task_bmp280.c task_ina219.c task_wifi.c task_mqtt.c xutil.c INCLUDE_DIRS ".") diff -r d0155c16e992 -r b1f38105ca7e main/Kconfig.projbuild --- a/main/Kconfig.projbuild Wed Mar 29 21:39:07 2023 +0200 +++ b/main/Kconfig.projbuild Thu Mar 30 17:05:05 2023 +0200 @@ -40,17 +40,48 @@ endmenu - config ESP_WIFI_SSID - string "WiFi SSID" - default "myssid" - help - SSID (network name) to connect to. + menu "WiFi settings" + + config ESP_WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) to connect to. + + config ESP_WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) to use. + + endmenu + + menu "MQTT server" - config ESP_WIFI_PASSWORD - string "WiFi Password" - default "mypassword" - help - WiFi password (WPA or WPA2) to use. + config MQTT_SERVER + string "MQTT server" + default "mqtt.eclipseprojects.io" + help + The MQTT server to connect to + + config MQTT_PORT + int "MQTT port number" + default 1883 + help + The MQTT server port + config MQTT_USER + string "MQTT username" + default "" + help + The optional MQTT username. + + config MQTT_PASS + string "MQTT password" + default "letmein" + help + The optional MQTT password for the username. + + endmenu endmenu diff -r d0155c16e992 -r b1f38105ca7e main/config.h --- a/main/config.h Wed Mar 29 21:39:07 2023 +0200 +++ b/main/config.h Thu Mar 30 17:05:05 2023 +0200 @@ -22,27 +22,22 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/event_groups.h" -//#include "freertos/queue.h" +#include "freertos/queue.h" #include "driver/gpio.h" #include "driver/i2c.h" //#include "driver/rtc_io.h" //#include "soc/sens_periph.h" //#include "soc/rtc.h" #include "esp_log.h" -//#include "esp_spiffs.h" -//#include "esp_vfs.h" #include "esp_system.h" +#include "esp_app_desc.h" #include "esp_wifi.h" -//#include "esp_wifi_types.h" -//#include "esp_wpa2.h" #include "esp_event.h" +#include "esp_netif.h" #include "nvs_flash.h" #include "lwip/err.h" #include "lwip/sys.h" -//#include "lwip/sockets.h" -//#include "lwip/dns.h" -//#include "lwip/netdb.h" -//#include "mqtt_client.h" +#include "mqtt_client.h" /* * esp-idf-lib @@ -57,10 +52,8 @@ #include "task_bmp280.h" #include "task_ina219.h" #include "task_wifi.h" -//#include "task_mqtt.h" -//#include "task_user.h" -//#include "xutil.h" - +#include "task_mqtt.h" +#include "xutil.h" diff -r d0155c16e992 -r b1f38105ca7e main/iotbalkon.c --- a/main/iotbalkon.c Wed Mar 29 21:39:07 2023 +0200 +++ b/main/iotbalkon.c Thu Mar 30 17:05:05 2023 +0200 @@ -19,8 +19,24 @@ static TaskHandle_t xTaskBMP280 = NULL; static TaskHandle_t xTaskINA219 = NULL; +static TaskHandle_t xTaskMQTT = NULL; static TaskHandle_t xTaskWifi = NULL; +#define MAX_LOOPS 32 + +RTC_DATA_ATTR float solarVolts, solarCurrent, solarPower; +RTC_DATA_ATTR float batteryVolts, batteryCurrent, batteryPower; +RTC_DATA_ATTR int batteryState; +RTC_DATA_ATTR float s_Volts[MAX_LOOPS + 1]; +RTC_DATA_ATTR float s_Current[MAX_LOOPS + 1]; +RTC_DATA_ATTR float b_Volts[MAX_LOOPS + 1]; +RTC_DATA_ATTR float b_Current[MAX_LOOPS + 1]; +RTC_DATA_ATTR bool m_Valid[MAX_LOOPS + 1]; +RTC_DATA_ATTR unsigned long m_Time[MAX_LOOPS + 1]; +RTC_DATA_ATTR unsigned long gLastTime; // millis() +RTC_DATA_ATTR uint8_t loopno; +RTC_DATA_ATTR uint8_t loops; + extern BMP280_State *bmp280_state; ///< I2C state extern SemaphoreHandle_t xSemaphoreBMP280; ///< I2C lock semaphore extern bmp280_params_t bmp280_params; @@ -31,6 +47,122 @@ extern SemaphoreHandle_t xSemaphoreWiFi; extern WIFI_State *wifi_state; ///< WiFi state +uint32_t Alarm = 0; + +/* + Alarm bits +*/ +#define AL_ACCULOW 0x01 +#define AL_NOWIFI 0x02 + + +#define ST_INTERVAL 10000 +#define MAX_LOOPS 32 + + + +// 0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100% +float Charge_C_5[11] = { 12.40, 12.60, 12.75, 12.95, 13.20, 13.35, 13.55, 13.67, 14.00, 15.25, 15.94 }; +float Charge_C_10[11] = { 12.20, 12.38, 12.60, 12.80, 13.05, 13.20, 13.28, 13.39, 13.60, 14.20, 15.25 }; +float Charge_C_20[11] = { 12.00, 12.07, 12.42, 12.70, 12.85, 13.02, 13.11, 13.15, 13.25, 13.60, 14.15 }; +float Charge_C_40[11] = { 11.55, 11.80, 12.25, 12.57, 12.70, 12.80, 12.90, 12.95, 13.00, 13.20, 13.50 }; +float Rest[11] = { 11.50, 11.70, 11.88, 12.10, 12.22, 12.30, 12.40, 12.50, 12.57, 12.64, 12.72 }; +float Load_C_20[11] = { 11.45, 11.70, 11.80, 12.05, 12.20, 12.28, 12.37, 12.48, 12.55, 12.57, 12.60 }; +float Load_C_10[11] = { 10.98, 11.27, 11.50, 11.65, 11.85, 12.00, 12.10, 12.20, 12.30, 12.40, 12.50 }; +float Load_C_5[11] = { 10.20, 10.65, 10.90, 11.15, 11.35, 11.55, 11.63, 11.75, 11.90, 12.00, 12.08 }; + + +/* + * Calculate the load state of the battery. + */ +void BatteryState(float Voltage, float Current) { + int i; + + batteryState = 0; + ESP_LOGI(TAG, "Batt %.4fV %.4fmA", Voltage, Current); + + if (Current < -750) { + // Load current > C/5, 1A + for (i = 0; i < 10; i++) { + if (Load_C_5[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Load C/5 %d%%", batteryState); + + } else if (Current < -375) { + // Load current > C/10, 500mA + for (i = 0; i < 10; i++) { + if (Load_C_10[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Load C/10 %d%%", batteryState); + + } else if (Current < -125) { + // Load current > C/20, 250mA + for (i = 0; i < 10; i++) { + if (Load_C_20[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Load C/20 %d%%", batteryState); + + } else if (Current > 750) { + // Charge > C/5, 1A + for (i = 0; i < 10; i++) { + if (Charge_C_5[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Charge C/5 %d%%", batteryState); + + } else if (Current > 375) { + // Charge > C/10, 500mA + for (i = 0; i < 10; i++) { + if (Charge_C_10[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Charge C/10 %d%%", batteryState); + + } else if (Current > 187.5) { + // Charge > C/20, 250 mA + for (i = 0; i < 10; i++) { + if (Charge_C_20[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Charge C/20 %d%%", batteryState); + + } else if (Current > 62.5) { + // Charge > C/40, 125 mA + for (i = 0; i < 10; i++) { + if (Charge_C_40[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Charge C/40 %d%%", batteryState); + + } else { + // Rest + for (i = 0; i < 10; i++) { + if (Rest[i + 1] >= Voltage) { + break; + } + } + batteryState = i * 10; + ESP_LOGI(TAG, "Rest %d%%", batteryState); + } +} + void app_main(void) @@ -93,6 +225,9 @@ xTaskCreate(&task_bmp280, "task_bmp280", 2560, NULL, 8, &xTaskBMP280); xTaskCreate(&task_ina219, "task_ina219", 2560, NULL, 8, &xTaskINA219); + // esp_log_level_set("MQTT_CLIENT", ESP_LOG_ERROR); + xTaskCreate(&task_mqtt, "task_mqtt", 4096, NULL, 5, &xTaskMQTT); + // esp_log_level_set("wifi", ESP_LOG_ERROR); xTaskCreate(&task_wifi, "task_wifi", 4096, NULL, 3, &xTaskWifi); vTaskDelay(10 / portTICK_PERIOD_MS); @@ -137,7 +272,7 @@ // // Measure // getVoltsCurrent(); - // solarVolts = solarCurrent = batteryVolts = batteryCurrent = 0; + solarVolts = solarCurrent = solarPower = batteryVolts = batteryCurrent = batteryPower = 0; // loops = 0; // totalTime = 0; // for (int i = 0; i < loopno; i++) { @@ -182,34 +317,17 @@ // batteryVolts = batteryVolts / loops; // batteryCurrent = batteryCurrent / totalTime; // batteryPower = batteryVolts * batteryCurrent; - // BatteryState(batteryVolts, (0 - batteryCurrent) + solarCurrent); - - // //#if Debug == true - // Serial.print(F(" Solar Volts: ")); - // Serial.print(solarVolts, 4); - // Serial.print(F("V Current: ")); - // Serial.print(solarCurrent, 4); - // Serial.print(F("mA Power: ")); - // Serial.print(solarPower, 4); - // Serial.println(F("mW")); + BatteryState(batteryVolts, (0 - batteryCurrent) + solarCurrent); - // Serial.print(F("Battery Volts: ")); - // Serial.print(batteryVolts, 4); - // Serial.print(F("V Current: ")); - // Serial.print(batteryCurrent, 4); - // Serial.print(F("mA Power: ")); - // Serial.print(batteryPower, 4); - // Serial.print(F("mW Capacity ")); - // Serial.print(batteryState); - // Serial.println(F("%")); - // //#endif + ESP_LOGI(TAG, " Solar Volts: %.4fV Current %.4fmA Power %.4fmW", solarVolts, solarCurrent, solarPower); + ESP_LOGI(TAG, "Battery Volts: %.4fV Current %.4fmA Power %.4fmW", batteryVolts, batteryCurrent, batteryPower); /* Check alarm conditions */ - // if (batteryState <= 10) { - // Alarm |= AL_ACCULOW; - // } else { - // Alarm &= ~AL_ACCULOW; - // } + if (batteryState <= 10) { + Alarm |= AL_ACCULOW; + } else { + Alarm &= ~AL_ACCULOW; + } // } // getTempHumi(); // Publish(); diff -r d0155c16e992 -r b1f38105ca7e main/task_ina219.c --- a/main/task_ina219.c Wed Mar 29 21:39:07 2023 +0200 +++ b/main/task_ina219.c Thu Mar 30 17:05:05 2023 +0200 @@ -15,6 +15,11 @@ extern ina219_t ina219_b_dev; extern ina219_t ina219_s_dev; +extern float s_Volts[I_MAX_LOOPS + 1]; +extern float s_Current[I_MAX_LOOPS + 1]; +extern float b_Volts[I_MAX_LOOPS + 1]; +extern float b_Current[I_MAX_LOOPS + 1]; +extern uint8_t loopno; const int TASK_INA219_REQUEST_DONE = BIT0; ///< All requests are done. const int TASK_INA219_REQUEST_POWER = BIT1; ///< Request power readings @@ -43,7 +48,6 @@ */ void task_ina219(void *pvParameter) { - int error = 0; float bus_voltage, shunt_voltage, current, power; ESP_LOGI(TAG, "Starting task INA219 sda=%d scl=%d", CONFIG_I2C_MASTER_SDA, CONFIG_I2C_MASTER_SCL); @@ -104,6 +108,25 @@ ESP_LOGI(TAG, "Battery VBUS: %.04f V, VSHUNT: %.04f mV, IBUS: %.04f mA, PBUS: %.04f mW", bus_voltage, shunt_voltage * 1000, current * 1000, power * 1000); } + if (xSemaphoreTake(xSemaphoreINA219, 25) == pdTRUE) { + if (ina219_state->Battery.fake) { + ina219_state->Battery.volts = 13.21; + if (ready_WiFi()) { + ina219_state->Battery.shunt = 0.00785; + ina219_state->Battery.current = 78.5; + } else { + ina219_state->Battery.shunt = 0.00182; + ina219_state->Battery.current = 18.2; + } + } else { + ina219_state->Battery.volts = bus_voltage; + ina219_state->Battery.shunt = shunt_voltage; + ina219_state->Battery.current = current; + } + ina219_state->Battery.valid = true; + xSemaphoreGive(xSemaphoreINA219); + } + if (! ina219_state->Solar.fake) { ESP_ERROR_CHECK(ina219_get_bus_voltage(&ina219_s_dev, &bus_voltage)); ESP_ERROR_CHECK(ina219_get_shunt_voltage(&ina219_s_dev, &shunt_voltage)); @@ -112,42 +135,26 @@ ESP_LOGI(TAG, " Solar VBUS: %.04f V, VSHUNT: %.04f mV, IBUS: %.04f mA, PBUS: %.04f mW", bus_voltage, shunt_voltage * 1000, current * 1000, power * 1000); } - - /* - error = ina219_read_float(&ina219_dev, &temperature, &pressure, &humidity); - if (xSemaphoreTake(xSemaphoreINA219, 25) == pdTRUE) { - if (error == ESP_OK) { - ina219_state->error = INA219_ERR_NONE; - ina219_state->valid = true; - ina219_state->temperature = temperature; - ina219_state->pressure = pressure; - ina219_state->humidity = humidity; - } else { - ina219_state->error = INA219_ERR_READ; - ina219_state->valid = false; - ina219_state->temperature = 0; - ina219_state->pressure = 0; - ina219_state->humidity = 0; - } - xSemaphoreGive(xSemaphoreINA219); + if (xSemaphoreTake(xSemaphoreINA219, 25) == pdTRUE) { + if (! ina219_state->Solar.fake && ! ina219_state->Battery.fake) { + ina219_state->Solar.volts = bus_voltage; + ina219_state->Solar.shunt = shunt_voltage; + ina219_state->Solar.current = current; + } else if (ina219_state->Solar.fake && ! ina219_state->Battery.fake) { + ina219_state->Solar.volts = ina219_state->Battery.volts + 0.78; + ina219_state->Solar.shunt = 0.02341; + ina219_state->Solar.current = 234.1; + } else { + ina219_state->Solar.volts = 13.98; + ina219_state->Solar.shunt = 0.02341; + ina219_state->Solar.current = 234.1; } - } else { - if (xSemaphoreTake(xSemaphoreINA219, 25) == pdTRUE) { - ina219_state->error = INA219_ERR_NONE; - ina219_state->valid = true; - ina219_state->temperature = 21.23; - ina219_state->pressure = 101360; - ina219_state->humidity = 0; - xSemaphoreGive(xSemaphoreINA219); - } + ina219_state->Solar.valid = true; + xSemaphoreGive(xSemaphoreINA219); } - */ xEventGroupClearBits(xEventGroupINA219, TASK_INA219_REQUEST_POWER); xEventGroupSetBits(xEventGroupINA219, TASK_INA219_REQUEST_DONE); -#if 0 - ESP_LOGI(TAG, " TB: %.3f C, %.1f hPa, error: %d", ina219_state->temperature, ina219_state->pressure / 100, ina219_state->error); -#endif } } } diff -r d0155c16e992 -r b1f38105ca7e main/task_ina219.h --- a/main/task_ina219.h Wed Mar 29 21:39:07 2023 +0200 +++ b/main/task_ina219.h Thu Mar 30 17:05:05 2023 +0200 @@ -38,15 +38,6 @@ bool fake; ///< Fake measurement INA219_tt Battery; ///< Battery measurement INA219_tt Solar; ///< Solar measurement - float s_Volts[I_MAX_LOOPS]; - float s_Current[I_MAX_LOOPS]; - float b_Volts[I_MAX_LOOPS]; - float b_Current[I_MAX_LOOPS]; - bool m_Valid[I_MAX_LOOPS]; - time_t m_Time[I_MAX_LOOPS]; - time_t gLastTime; - uint8_t loopno; - uint8_t loops; uint8_t tries; int error; ///< Error result } INA219_State; diff -r d0155c16e992 -r b1f38105ca7e main/task_mqtt.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/task_mqtt.c Thu Mar 30 17:05:05 2023 +0200 @@ -0,0 +1,313 @@ +/** + * @file task_mqtt.c + * @brief The FreeRTOS task to maintain MQTT connections. + */ + + +#include "config.h" + + +static const char *TAG = "task_mqtt"; + +EventGroupHandle_t xEventGroupMQTT; ///< Events MQTT task +SemaphoreHandle_t xSemaphorePcounter; ///< Publish counter semaphore. +int count_pub = 0; ///< Outstanding published messages. +esp_mqtt_client_handle_t client; ///< MQTT client handle + +const int TASK_MQTT_CONNECT = BIT0; ///< Request MQTT connection +const int TASK_MQTT_DISCONNECT = BIT1; ///< Request MQTT disconnect +const int TASK_MQTT_CONNECTED = BIT2; ///< MQTT is connected + +const char *sensState[] = { "OK", "ERROR" }; ///< Sensor state strings +const char *unitMode[] = { "OFF", "ON" }; ///< Units state strings + +extern BMP280_State *bmp280_state; ///< BMP280 state +extern SemaphoreHandle_t xSemaphoreBMP280; ///< BMP280 lock semaphore +extern INA219_State *ina219_state; ///< INA219 state +extern SemaphoreHandle_t xSemaphoreINA219; ///< INA219 lock semaphore +extern WIFI_State *wifi_state; ///< WiFi state +extern SemaphoreHandle_t xSemaphoreWiFi; ///< WiFi lock semaphore +extern const esp_app_desc_t *app_desc; + +extern uint32_t Alarm; +extern float batteryState; +extern float batteryVolts; +extern float batteryCurrent; +extern float batteryPower; +extern float solarVolts; +extern float solarCurrent; +extern float solarPower; + + +void connect_mqtt(bool state) +{ + if (state) + xEventGroupSetBits(xEventGroupMQTT, TASK_MQTT_CONNECT); + else + xEventGroupSetBits(xEventGroupMQTT, TASK_MQTT_DISCONNECT); +} + + + +bool ready_mqtt(void) +{ + if (xEventGroupGetBits(xEventGroupMQTT) & TASK_MQTT_CONNECTED) + return true; + return false; +} + + + +/** + * @brief Generate the mqtt payload header. + * @return Allocated character string with the header. + */ +char *payload_header(void) +{ + char *tmp; + + tmp = xstrcpy((char *)"{\"metric\":"); + return tmp; +} + + + +/** + * @brief Generate the mqtt topic base part. + * @return The topic string allocated in memory. + */ +char *topic_base(void) +{ + char *tmp; + +#ifdef CONFIG_CODE_PRODUCTION + tmp = xstrcpy((char *)"balkon/"); +#endif +#ifdef CONFIG_CODE_TESTING + tmp = xstrcpy((char *)"wemos/"); +#endif + + return tmp; +} + + + +/** + * @brief The mqtt generic publish function. + * @param topic The topic of the mqtt message. + * @param payload The payload of the mqtt message. + */ +void publisher(char *topic, char *payload) +{ + /* + * First count, then sent the data. + */ + if (xSemaphoreTake(xSemaphorePcounter, 10) == pdTRUE) { + count_pub++; + xSemaphoreGive(xSemaphorePcounter); + } else { + ESP_LOGE(TAG, "publisher() counter lock"); + } + + if (payload) + esp_mqtt_client_publish(client, topic, payload, strlen(payload), 1, 0); + else + esp_mqtt_client_publish(client, topic, NULL, 0, 1, 0); +} + + + +void publish(void) +{ + char *topic = NULL, *payload = NULL, buf[64]; + + // {"system":{"battery":70,"alarm":0,"version":"0.2.6","rssi":-56,"wifi":88,"light":{"lux":12.34,"gain":2}},"solar":{"voltage":13.98,"current":234.1,"power":3.272718},"battery":{"voltage":13.21,"current":4.942289,"power":0.065288},"real":{"current":229.1577},"TH":{"temperature":20.2,"humidity":48.3},"output":{"relay1":0,"relay2":0,"dimmer3":0,"dimmer4":0}} + // + payload = payload_header(); + payload = xstrcat(payload, (char *)"{\"system\":{\"battery\":"); + sprintf(buf, "%.0f", batteryState); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"alarm\":"); + sprintf(buf, "%ld", Alarm); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"version\":\""); + payload = xstrcat(payload, (char *)app_desc->version); + payload = xstrcat(payload, (char *)",\"rssi\":"); + + payload = xstrcat(payload, (char *)",\"light\":{\"lux\":"); + + payload = xstrcat(payload, (char *)",\"gain\":"); + + payload = xstrcat(payload, (char *)"}},\"solar\":{\"voltage\":"); + sprintf(buf, "%.2f", solarVolts); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"current\":"); + sprintf(buf, "%.1f", solarCurrent); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"power\":"); + sprintf(buf, "%.3f", solarPower / 1000.0); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"},\"battery\":{\"voltage\":"); + sprintf(buf, "%.2f", batteryVolts); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"current\":"); + sprintf(buf, "%.1f", batteryCurrent); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"power\":"); + sprintf(buf, "%.3f", batteryPower / 1000.0); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"},\"real\":{\"current\":"); + payload = xstrcat(payload, (char *)"},\"TB\":{\"temperature\":"); + if (xSemaphoreTake(xSemaphoreBMP280, 25) == pdTRUE) { + sprintf(buf, "%.2f", bmp280_state->temperature); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)",\"pressure\":"); + sprintf(buf, "%.1f", bmp280_state->pressure / 100.0); + payload = xstrcat(payload, buf); + xSemaphoreGive(xSemaphoreBMP280); + } + payload = xstrcat(payload, (char *)"},\"output\":{\"relay1\":"); + + payload = xstrcat(payload, (char *)",\"relay2\":"); + + payload = xstrcat(payload, (char *)",\"dimmer3\":"); + + payload = xstrcat(payload, (char *)",\"dimmer4\":"); + + payload = xstrcat(payload, (char *)"}}"); + topic = topic_base(); + topic = xstrcat(topic, (char *)"status"); + publisher(topic, payload); + free(topic); + topic = NULL; + free(payload); + payload = NULL; +} + + + +static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) +{ + switch (event->event_id) { + + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + xEventGroupSetBits(xEventGroupMQTT, TASK_MQTT_CONNECTED); + break; + + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + xEventGroupClearBits(xEventGroupMQTT, TASK_MQTT_CONNECTED); + break; + + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + break; + + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + if (xSemaphoreTake(xSemaphorePcounter, 10) == pdTRUE) { + if (count_pub) { + count_pub--; + } + xSemaphoreGive(xSemaphorePcounter); + } else { + ESP_LOGE(TAG, "mqtt_event_handler_cb(() lock error event"); + } + break; + + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + break; + + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + break; + + case MQTT_EVENT_BEFORE_CONNECT: + ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT"); + // Configure connection can be here. + break; + + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } + return ESP_OK; +} + + + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { + mqtt_event_handler_cb(event_data); +} + + + +/* + * Task to read temperature sensors on request. + */ +void task_mqtt(void *pvParameter) +{ + esp_err_t err; + char *uri = NULL, port[11]; + + ESP_LOGI(TAG, "Starting MQTT task"); + xSemaphorePcounter = xSemaphoreCreateMutex(); + + /* event handler and event group for the wifi driver */ + xEventGroupMQTT = xEventGroupCreate(); + EventBits_t uxBits; + + esp_mqtt_client_config_t mqtt_cfg = { + .broker.address.uri = "mqtt://localhost", + }; + client = esp_mqtt_client_init(&mqtt_cfg); + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client); + + /* + * Task loop forever. + */ + while (1) { + + uxBits = xEventGroupWaitBits(xEventGroupMQTT, TASK_MQTT_CONNECT | TASK_MQTT_DISCONNECT, pdFALSE, pdFALSE, portMAX_DELAY ); + + if (uxBits & TASK_MQTT_CONNECT) { + uri = xstrcpy((char *)"mqtt://"); + if (strlen(CONFIG_MQTT_USER) && strlen(CONFIG_MQTT_PASS)) { + uri = xstrcat(uri, CONFIG_MQTT_USER); + uri = xstrcat(uri, (char *)":"); + uri = xstrcat(uri, CONFIG_MQTT_PASS); + uri = xstrcat(uri, (char *)"@"); + } + uri = xstrcat(uri, CONFIG_MQTT_SERVER); + if (CONFIG_MQTT_PORT != 1883) { + uri = xstrcat(uri, (char *)":"); + sprintf(port, "%d", CONFIG_MQTT_PORT); + uri = xstrcat(uri, port); + } + + ESP_LOGI(TAG, "Request MQTT connect %s", uri); + err = esp_mqtt_client_set_uri(client, uri); + if (err != ESP_OK) + ESP_LOGE(TAG, "Set uri %s", esp_err_to_name(err)); + err = esp_mqtt_client_start(client); + if (err != ESP_OK) + ESP_LOGE(TAG, "Result %s", esp_err_to_name(err)); + xEventGroupClearBits(xEventGroupMQTT, TASK_MQTT_CONNECT); + + } else if (uxBits & TASK_MQTT_DISCONNECT) { + ESP_LOGI(TAG, "Request MQTT disconnect"); + esp_mqtt_client_stop(client); + xEventGroupClearBits(xEventGroupMQTT, TASK_MQTT_DISCONNECT); + xEventGroupClearBits(xEventGroupMQTT, TASK_MQTT_CONNECTED); + } + } +} + diff -r d0155c16e992 -r b1f38105ca7e main/task_mqtt.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/task_mqtt.h Thu Mar 30 17:05:05 2023 +0200 @@ -0,0 +1,38 @@ +/** + * @file task_mqtt.h + * @brief The FreeRTOS task to maintain MQTT connections. + */ + +#ifndef _TASK_MQTT_H +#define _TASK_MQTT_H + + + +/** + * @brief Request a MQTT connection + * @param state Request of disconnect a connection. + */ +void connect_mqtt(bool state); + + +/** + * @brief Check if MQTT is connected + * @return Returns true if MQTT is connected + */ +bool ready_mqtt(void); + + +/** + * @brief Publish + */ +void publish(void); + + +/** + * @brief The FreeRTOS task to run MQTT connections. + * @param pvParameters Parameters for the task. + */ +void task_mqtt(void *pvParameters); + + +#endif diff -r d0155c16e992 -r b1f38105ca7e main/task_wifi.c --- a/main/task_wifi.c Wed Mar 29 21:39:07 2023 +0200 +++ b/main/task_wifi.c Thu Mar 30 17:05:05 2023 +0200 @@ -104,7 +104,7 @@ } else { ESP_LOGE(TAG, "wifi_event_handler() lock error WIFI_EVENT_STA_DISCONNECTED"); } -// connect_mqtt(false); + connect_mqtt(false); xEventGroupClearBits(xEventGroupWifi, TASK_WIFI_STA_CONNECTED); xEventGroupSetBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED); break; @@ -135,7 +135,7 @@ } else { ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_GOT_IP"); } -// connect_mqtt(true); + connect_mqtt(true); break; case IP_EVENT_STA_LOST_IP: @@ -150,7 +150,7 @@ } else { ESP_LOGE(TAG, "got_ip_event_handler() lock error IP_EVENT_STA_LOST_IP"); } -// connect_mqtt(false); + connect_mqtt(false); break; case IP_EVENT_AP_STAIPASSIGNED: @@ -227,7 +227,7 @@ /* * user requested a disconnect, this will in effect disconnect the wifi */ -// connect_mqtt(false); + connect_mqtt(false); ESP_LOGI(TAG, "Request STA disconnect"); ESP_ERROR_CHECK(esp_wifi_disconnect()); xEventGroupWaitBits(xEventGroupWifi, TASK_WIFI_STA_DISCONNECTED, pdFALSE, pdTRUE, portMAX_DELAY ); diff -r d0155c16e992 -r b1f38105ca7e main/xutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/xutil.c Thu Mar 30 17:05:05 2023 +0200 @@ -0,0 +1,72 @@ +/***************************************************************************** + * Copyright (C) 2008-2019 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * mbsePi-apps is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ThermFerm; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "config.h" + + +char *xmalloc(size_t size) +{ + char *tmp; + + tmp = malloc(size); + if (!tmp) + abort(); + + return tmp; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = xmalloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = xmalloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + diff -r d0155c16e992 -r b1f38105ca7e main/xutil.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/xutil.h Thu Mar 30 17:05:05 2023 +0200 @@ -0,0 +1,32 @@ +/** + * @file xutil.h + * @brief In memory string manipulation. + */ + + +#ifndef XUTIL_H +#define XUTIL_H + +/** + * @brief Safe memory allocation. Abort if not enough. + * @param size The amount of memory to allocate. + * @return A pointer to the allocated memory. + */ +char *xmalloc(size_t size); + +/** + * @brief Copy string in memory. + * @param src The source string to copy. + * @return A pointer to the string with the copied string. + */ +char *xstrcpy(char *src); + +/** + * @brief Add data to a string in memory. + * @param src The original string. + * @param add The string to append to src. + * @return A pointer to the combined string. + */ +char *xstrcat(char *src, char *add); + +#endif