#include "sdkconfig.h" // system includes #include #include // esp-idf includes #include #include #if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT) #include #include #endif #ifdef CONFIG_APP_ROLLBACK_ENABLE #include #endif #include #include #include #include // Arduino includes #include #include // 3rdparty lib includes #include #include #include #include // local includes #include "espwifistack.h" #include "tickchrono.h" #include "wrappers/mqtt_client.h" using namespace std::chrono_literals; namespace { constexpr const char * const TAG = "MAIN"; constexpr const int pins_sda = 16; constexpr const int pins_scl = 17; constexpr const std::string_view topic_lamp_availability = "dahoam/wohnzimmer/deckenlicht1/available"; constexpr const std::string_view topic_lamp_status = "dahoam/wohnzimmer/deckenlicht1/status"; constexpr const std::string_view topic_lamp_set = "dahoam/wohnzimmer/deckenlicht1/set"; constexpr const std::string_view topic_switch_availability = "dahoam/wohnzimmer/lichtschalter1/available"; constexpr const std::string_view topic_switch_status = "dahoam/wohnzimmer/lichtschalter1/status"; constexpr const std::string_view topic_lux_availability = "dahoam/wohnzimmer/lux1/available"; constexpr const std::string_view topic_lux_value = "dahoam/wohnzimmer/lux1/value"; constexpr const std::string_view topic_bmp085_availability = "dahoam/wohnzimmer/bmp085_1/available"; constexpr const std::string_view topic_bmp085_pressure = "dahoam/wohnzimmer/bmp085_1/pressure"; constexpr const std::string_view topic_bmp085_temperature = "dahoam/wohnzimmer/bmp085_1/temperature"; constexpr const std::string_view topic_bmp085_altitude = "dahoam/wohnzimmer/bmp085_1/altitude"; std::atomic mqttConnected; espcpputils::mqtt_client mqttClient; std::atomic lampState; std::atomic switchState; //espchrono::millis_clock::time_point lastLampToggle; //espchrono::millis_clock::time_point lastSwitchToggle; Adafruit_TSL2561_Unified tsl{TSL2561_ADDR_FLOAT, 12345}; Adafruit_BMP085_Unified bmp{10085}; bool tslInitialized{}; bool bmpInitialized{}; std::optional lastTslValue; struct BmpValue { float pressure; float temperature; float altitude; }; std::optional lastBmpValue; esp_err_t webserver_root_handler(httpd_req_t *req); esp_err_t webserver_on_handler(httpd_req_t *req); esp_err_t webserver_off_handler(httpd_req_t *req); esp_err_t webserver_toggle_handler(httpd_req_t *req); esp_err_t webserver_reboot_handler(httpd_req_t *req); void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data); int mqttVerbosePub(std::string_view topic, std::string_view value, int qos, int retain); } // namespace extern "C" void app_main() { #if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT) { const auto taskHandle = xTaskGetCurrentTaskHandle(); if (!taskHandle) { ESP_LOGE(TAG, "could not get handle to current main task!"); } else if (const auto result = esp_task_wdt_add(taskHandle); result != ESP_OK) { ESP_LOGE(TAG, "could not add main task to watchdog: %s", esp_err_to_name(result)); } } #endif #ifdef CONFIG_APP_ROLLBACK_ENABLE esp_ota_img_states_t ota_state; if (const esp_partition_t * const running = esp_ota_get_running_partition()) { if (const auto result = esp_ota_get_state_partition(running, &ota_state); result == ESP_ERR_NOT_FOUND) ota_state = ESP_OTA_IMG_VALID; else if (result != ESP_OK) { ESP_LOGE(TAG, "esp_ota_get_state_partition() failed with %s", esp_err_to_name(result)); ota_state = ESP_OTA_IMG_UNDEFINED; } } else { ESP_LOGE(TAG, "esp_ota_get_running_partition() returned nullptr"); ota_state = ESP_OTA_IMG_UNDEFINED; } #endif { const auto result = nvs_flash_init(); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_flash_init(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } nvs_handle_t nvsHandle; { const auto result = nvs_open("deckenlampe", NVS_READWRITE, &nvsHandle); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "nvs_open(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } wifi_stack::config wifiConfig { .wifiEnabled = true, .hostname = "deckenlampe1", .wifis = std::array { wifi_stack::wifi_entry { .ssid = "McDonalds Free WiFi", .key = "Passwort_123" }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} }, wifi_stack::wifi_entry { .ssid = {}, .key = {} } }, .sta_ip = { .dhcpEnabled = true, // .staticIp = {}, // .staticGateway = {}, // .staticSubnet = {}, // .staticDns1 = {}, // .staticDns2 = {} }, .ap = { { .ssid = "deckenlampe1", .key = "Passwort_123" }, .channel = 1, .authmode = WIFI_AUTH_WPA2_PSK, .ssid_hidden = false, .max_connection = 4, .beacon_interval = 100, .ip{192, 168, 4, 1}, .subnet{255, 255, 255, 0} }, .min_rssi = -90 }; wifi_stack::init(wifiConfig); httpd_handle_t httpdHandle{}; { httpd_config_t httpConfig HTTPD_DEFAULT_CONFIG(); const auto result = httpd_start(&httpdHandle, &httpConfig); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_start(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { httpd_uri_t uri { .uri = "/", .method = HTTP_GET, .handler = webserver_root_handler, .user_ctx = NULL}; const auto result = httpd_register_uri_handler(httpdHandle, &uri); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { httpd_uri_t uri { .uri = "/on", .method = HTTP_GET, .handler = webserver_on_handler, .user_ctx = NULL}; const auto result = httpd_register_uri_handler(httpdHandle, &uri); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/on", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { httpd_uri_t uri { .uri = "/off", .method = HTTP_GET, .handler = webserver_off_handler, .user_ctx = NULL}; const auto result = httpd_register_uri_handler(httpdHandle, &uri); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/off", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { httpd_uri_t uri { .uri = "/toggle", .method = HTTP_GET, .handler = webserver_toggle_handler, .user_ctx = NULL}; const auto result = httpd_register_uri_handler(httpdHandle, &uri); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/toggle", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { httpd_uri_t uri { .uri = "/reboot", .method = HTTP_GET, .handler = webserver_reboot_handler, .user_ctx = NULL}; const auto result = httpd_register_uri_handler(httpdHandle, &uri); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "httpd_register_uri_handler() for %s: %s", "/reboot", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { const auto result = mdns_init(); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_init(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { const auto result = mdns_hostname_set(wifiConfig.hostname.c_str()); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_hostname_set(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { const auto result = mdns_instance_name_set(wifiConfig.hostname.c_str()); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_instance_name_set(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { const auto result = mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "mdns_service_add(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } { esp_mqtt_client_config_t mqtt_cfg = { .uri = "mqtt://192.168.0.2/", }; mqttClient = espcpputils::mqtt_client{&mqtt_cfg}; if (!mqttClient) { ESP_LOGE(TAG, "error while initializing mqtt client!"); return; } else { { const auto result = mqttClient.register_event(MQTT_EVENT_ANY, mqttEventHandler, NULL); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_mqtt_client_register_event(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } const auto result = mqttClient.start(); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_mqtt_client_start(): %s", esp_err_to_name(result)); //if (result != ESP_OK) // return result; } } { ESP_LOGI(TAG, "calling Wire.begin()..."); const auto result = Wire.begin(pins_sda, pins_scl); ESP_LOGI(TAG, "finished with %s", result ? "true" : "false"); } { ESP_LOGI(TAG, "calling tsl.begin()..."); tslInitialized = tsl.begin(true); ESP_LOGI(TAG, "finished with %s", tslInitialized ? "true" : "false"); if (tslInitialized) { sensor_t sensor = tsl.getSensor(); ESP_LOGI(TAG, "------------------------------------"); ESP_LOGI(TAG, "Sensor: %s", sensor.name); ESP_LOGI(TAG, "Driver Ver: %i", sensor.version); ESP_LOGI(TAG, "Unique ID: %i", sensor.sensor_id); ESP_LOGI(TAG, "Max Value: %.1f lux", sensor.max_value); ESP_LOGI(TAG, "Min Value: %.1f lux", sensor.min_value); ESP_LOGI(TAG, "Resolution: %.1f lux", sensor.resolution); ESP_LOGI(TAG, "------------------------------------"); ESP_LOGI(TAG, ""); /* You can also manually set the gain or enable auto-gain support */ // tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */ // tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */ tsl.enableAutoRange(true); /* Auto-gain ... switches automatically between 1x and 16x */ /* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */ tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */ // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */ // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */ /* Update these values depending on what you've set above! */ ESP_LOGI(TAG, "------------------------------------"); ESP_LOGI(TAG, "Gain: Auto"); ESP_LOGI(TAG, "Timing: 13 ms"); ESP_LOGI(TAG, "------------------------------------"); } } { ESP_LOGI(TAG, "calling bmp.begin()..."); bmpInitialized = bmp.begin(); ESP_LOGI(TAG, "finished with %s", bmpInitialized ? "true" : "false"); if (bmpInitialized) { sensor_t sensor = bmp.getSensor(); ESP_LOGI(TAG, "------------------------------------"); ESP_LOGI(TAG, "Sensor: %s", sensor.name); ESP_LOGI(TAG, "Driver Ver: %i", sensor.version); ESP_LOGI(TAG, "Unique ID: %i", sensor.sensor_id); ESP_LOGI(TAG, "Max Value: %.1f hPa", sensor.max_value); ESP_LOGI(TAG, "Min Value: %.1f hPa", sensor.min_value); ESP_LOGI(TAG, "Resolution: %.1f hPa", sensor.resolution); ESP_LOGI(TAG, "------------------------------------"); ESP_LOGI(TAG, ""); } } while (true) { wifi_stack::update(wifiConfig); // if (espchrono::ago(lastLampToggle) >= 10s) // { // lastLampToggle = espchrono::millis_clock::now(); // lampState = !lampState; // if (mqttClient && mqttConnected) // mqttVerbosePub(topic_lamp_status, lampState ? "ON" : "OFF", 0, 1); // } // if (espchrono::ago(lastSwitchToggle) >= 30s) // { // lastSwitchToggle = espchrono::millis_clock::now(); // switchState = !switchState; // if (mqttClient && mqttConnected) // mqttVerbosePub(topic_switch_status, switchState ? "ON" : "OFF", 0, 1); // } if (tslInitialized) { if (std::optional event = tsl.getEvent()) { /* Display the results (light is measured in lux) */ if (event->light) { const float tslValue = event->light; ESP_LOGI(TAG, "read tsl: %.1f lux", tslValue); if (mqttClient && mqttConnected) { if (!lastTslValue) mqttVerbosePub(topic_lux_availability, "online", 0, 1); if (!lastTslValue || fmt::format("{:.1f}", *lastTslValue) != fmt::format("{:.1f}", tslValue)) mqttVerbosePub(topic_lux_value, fmt::format("{:.1f}", tslValue), 0, 1); } lastTslValue = tslValue; } else { /* If event.light = 0 lux the sensor is probably saturated * and no reliable data could be generated! */ ESP_LOGD(TAG, "tsl sensor overload %f", event->light); } } else { ESP_LOGW(TAG, "tsl failed"); goto tslOffline; } } else { tslOffline: if (lastTslValue) { if (mqttClient && mqttConnected) mqttVerbosePub(topic_lux_availability, "offline", 0, 1); lastTslValue = std::nullopt; } } if (bmpInitialized) { if (std::optional event = bmp.getEvent()) { if (event->pressure) { BmpValue bmpValue { .pressure = event->pressure }; ESP_LOGI(TAG, "read bmp Pressure: %.1f hPa", bmpValue.pressure); bmp.getTemperature(&bmpValue.temperature); ESP_LOGI(TAG, "read bmp Temperature: %.1f C", bmpValue.temperature); /* Then convert the atmospheric pressure, and SLP to altitude */ /* Update this next line with the current SLP for better results */ constexpr const float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA; bmpValue.altitude = bmp.pressureToAltitude(seaLevelPressure, event->pressure); ESP_LOGI(TAG, "read bmp Altitude: %.1f m", bmpValue.altitude); if (mqttClient && mqttConnected) { if (!lastBmpValue) mqttVerbosePub(topic_bmp085_availability, "online", 0, 1); if (!lastBmpValue || fmt::format("{:.1f}", lastBmpValue->pressure) != fmt::format("{:.1f}", bmpValue.pressure)) mqttVerbosePub(topic_bmp085_pressure, fmt::format("{:.1f}", bmpValue.pressure), 0, 1); if (!lastBmpValue || fmt::format("{:.1f}", lastBmpValue->temperature) != fmt::format("{:.1f}", bmpValue.temperature)) mqttVerbosePub(topic_bmp085_temperature, fmt::format("{:.1f}", bmpValue.temperature), 0, 1); if (!lastBmpValue || fmt::format("{:.1f}", lastBmpValue->altitude) != fmt::format("{:.1f}", bmpValue.altitude)) mqttVerbosePub(topic_bmp085_altitude, fmt::format("{:.1f}", bmpValue.altitude), 0, 1); } lastBmpValue = bmpValue; } else { ESP_LOGW(TAG, "bmp sensor error"); goto bmpOffline; } } else { ESP_LOGW(TAG, "bmp failed"); goto bmpOffline; } } else { bmpOffline: if (lastBmpValue) { if (mqttClient && mqttConnected) mqttVerbosePub(topic_bmp085_availability, "offline", 0, 1); lastBmpValue = std::nullopt; } } #if defined(CONFIG_ESP_TASK_WDT_PANIC) || defined(CONFIG_ESP_TASK_WDT) if (const auto result = esp_task_wdt_reset(); result != ESP_OK) ESP_LOGE(TAG, "esp_task_wdt_reset() failed with %s", esp_err_to_name(result)); #endif #ifdef CONFIG_APP_ROLLBACK_ENABLE if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) { const auto result = esp_ota_mark_app_valid_cancel_rollback(); ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_ota_mark_app_valid_cancel_rollback() returned: %s", esp_err_to_name(result)); ota_state = ESP_OTA_IMG_VALID; } #endif vPortYield(); vTaskDelay(std::chrono::ceil(2000ms).count()); } } #define CALL_AND_EXIT_ON_ERROR(METHOD, ...) \ if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \ { \ ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \ return result; \ } #define CALL_AND_EXIT(METHOD, ...) \ if (const auto result = METHOD(__VA_ARGS__); result != ESP_OK) \ { \ ESP_LOGE(TAG, "%s() failed with %s", #METHOD, esp_err_to_name(result)); \ return result; \ } \ else \ return result; namespace { esp_err_t webserver_root_handler(httpd_req_t *req) { std::string body = "this is work in progress...
\n" "on
\n" "off
\n" "toggle
\n" "reboot
\n" "
\n"; body += fmt::format("Lamp: {}
\n", lampState ? "ON" : "OFF"); body += fmt::format("Switch: {}
\n", switchState ? "ON" : "OFF"); if (lastTslValue) { body += fmt::format("Brightness: {:.1f} lux
\n", *lastTslValue); } if (lastBmpValue) { body += fmt::format("BMP085 Pressure: {:.1f} lux
\n", lastBmpValue->pressure); body += fmt::format("BMP085 Temperature: {:.1f} C
\n", lastBmpValue->temperature); body += fmt::format("BMP085 Altitude: {:.1f} m
\n", lastBmpValue->altitude); } CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html") CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size()) return ESP_OK; } esp_err_t webserver_on_handler(httpd_req_t *req) { const bool state = (lampState = true); if (mqttClient && mqttConnected) mqttVerbosePub(topic_lamp_status, state ? "ON" : "OFF", 0, 1); std::string_view body{"ON called..."}; CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html") CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size()) return ESP_OK; } esp_err_t webserver_off_handler(httpd_req_t *req) { const bool state = (lampState = false); if (mqttClient && mqttConnected) mqttVerbosePub(topic_lamp_status, state ? "ON" : "OFF", 0, 1); std::string_view body{"OFF called..."}; CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html") CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size()) return ESP_OK; } esp_err_t webserver_toggle_handler(httpd_req_t *req) { const bool state = (lampState = !lampState); if (mqttClient && mqttConnected) mqttVerbosePub(topic_lamp_status, state ? "ON" : "OFF", 0, 1); std::string_view body{"TOGGLE called..."}; CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html") CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size()) return ESP_OK; } esp_err_t webserver_reboot_handler(httpd_req_t *req) { std::string_view body{"REBOOT called..."}; CALL_AND_EXIT_ON_ERROR(httpd_resp_set_type, req, "text/html") CALL_AND_EXIT_ON_ERROR(httpd_resp_send, req, body.data(), body.size()) esp_restart(); return ESP_OK; } void mqttEventHandler(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { CPP_UNUSED(event_handler_arg) const esp_mqtt_event_t *data = reinterpret_cast(event_data); switch (esp_mqtt_event_id_t(event_id)) { case MQTT_EVENT_ERROR: ESP_LOGE(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_ERROR"); // ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); // if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { // log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err); // log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err); // log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno); // ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno)); // } break; case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_CONNECTED"); mqttConnected = true; mqttVerbosePub(topic_lamp_availability, "online", 0, 1); mqttVerbosePub(topic_lamp_status, lampState.load() ? "ON" : "OFF", 0, 1); mqttVerbosePub(topic_switch_availability, "online", 0, 1); mqttVerbosePub(topic_switch_status, switchState.load() ? "ON" : "OFF", 0, 1); mqttVerbosePub(topic_lux_availability, lastTslValue ? "online" : "offline", 0, 1); if (lastTslValue) mqttVerbosePub(topic_lux_value, fmt::format("{:.1f}", *lastTslValue), 0, 1); mqttVerbosePub(topic_bmp085_availability, lastBmpValue ? "online" : "offline", 0, 1); if (lastBmpValue) { mqttVerbosePub(topic_bmp085_pressure, fmt::format("{:.1f}", lastBmpValue->pressure), 0, 1); mqttVerbosePub(topic_bmp085_temperature, fmt::format("{:.1f}", lastBmpValue->temperature), 0, 1); mqttVerbosePub(topic_bmp085_altitude, fmt::format("{:.1f}", lastBmpValue->altitude), 0, 1); } mqttClient.subscribe(topic_lamp_set, 0); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_DISCONNECTED"); mqttConnected = false; break; case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_SUBSCRIBED"); break; case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_UNSUBSCRIBED"); break; case MQTT_EVENT_PUBLISHED: ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_PUBLISHED"); break; case MQTT_EVENT_DATA: { std::string_view topic{data->topic, (size_t)data->topic_len}; std::string_view value{data->data, (size_t)data->data_len}; ESP_LOGI(TAG, "%s event_id=%s topic=%.*s data=%.*s", event_base, "MQTT_EVENT_DATA", topic.size(), topic.data(), value.size(), value.data()); if (topic == topic_lamp_set) { bool newState = (lampState = (value == "ON")); if (mqttClient && mqttConnected) mqttVerbosePub(topic_lamp_status, newState ? "ON" : "OFF", 0, 1); } break; } case MQTT_EVENT_BEFORE_CONNECT: ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_BEFORE_CONNECT"); break; case MQTT_EVENT_DELETED: ESP_LOGI(TAG, "%s event_id=%s", event_base, "MQTT_EVENT_DELETED"); break; default: ESP_LOGW(TAG, "%s unknown event_id %i", event_base, event_id); break; } } int mqttVerbosePub(std::string_view topic, std::string_view value, int qos, int retain) { ESP_LOGI(TAG, "topic=\"%.*s\" value=\"%.*s\"", topic.size(), topic.data(), value.size(), value.data()); return mqttClient.publish(topic, value, qos, retain); } } // namespace