diff --git a/components/Communication/Application.cpp b/components/Communication/Application.cpp index ff29db3..6058e63 100644 --- a/components/Communication/Application.cpp +++ b/components/Communication/Application.cpp @@ -64,4 +64,13 @@ void Application::initializeWifi() { ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); ESP_ERROR_CHECK(esp_wifi_start()); initialized = true; +} + +bool Application::contains(const std::string &key) { + nvs_handle_t hanlde; + esp_err_t error = nvs_open(Namespace, NVS_READWRITE, &hanlde); + nvs_type_t type; + error = nvs_find_key(hanlde, key.c_str(), &type); + nvs_close(hanlde); + return error == ESP_OK; } \ No newline at end of file diff --git a/components/Communication/Application.h b/components/Communication/Application.h index 68f936d..309ed4b 100644 --- a/components/Communication/Application.h +++ b/components/Communication/Application.h @@ -26,11 +26,12 @@ public: if (error != ESP_OK) { ESP_LOGI("App", "nvs_open() failed."); } - - if (std::is_same_v>) { + if constexpr (std::is_same_v>) { error = nvs_set_str(hanlde, key.c_str(), value); } else if constexpr (std::is_same_v) { error = nvs_set_str(hanlde, key.c_str(), value.c_str()); + } else if constexpr (std::is_same_v || std::is_same_v) { + error = nvs_set_i32(hanlde, key.c_str(), value); } else { ESP_LOGW("App", "unknown data"); } @@ -43,8 +44,25 @@ public: template T field(const std::string &key) { + T ret{}; + nvs_handle_t hanlde; + nvs_open(Namespace, NVS_READWRITE, &hanlde); + if constexpr (std::is_same_v> || std::is_same_v) { + size_t requiredSize; + nvs_get_str(hanlde, key.c_str(), nullptr, &requiredSize); + ret.resize(requiredSize); + nvs_get_str(hanlde, key.c_str(), ret.data(), &requiredSize); + } else if constexpr (std::is_same_v) { + ret = field(key); + } else if constexpr (std::is_same_v) { + nvs_get_i32(hanlde, key.c_str(), &ret); + } + nvs_close(hanlde); + return ret; } + bool contains(const std::string &key); + protected: static void eventHandler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); void initializeWifi(); diff --git a/components/Communication/MqttClient.cpp b/components/Communication/MqttClient.cpp index cfe5074..ab63a1d 100644 --- a/components/Communication/MqttClient.cpp +++ b/components/Communication/MqttClient.cpp @@ -1,4 +1,5 @@ #include "MqttClient.h" +#include "Application.h" #include "LedController.h" #include #include @@ -17,7 +18,7 @@ void MqttClient::onConnected(struct esp_mqtt_client *client) { cJSON_AddStringToObject(root, "cmd_t", "~/set"); cJSON_AddStringToObject(root, "stat_t", "~/state"); cJSON_AddStringToObject(root, "schema", "json"); - cJSON_AddNumberToObject(root, "brightness_scale", 100); + cJSON_AddNumberToObject(root, "brightness_scale", LedController::Resolution); const char *modes[] = { "color_temp", @@ -33,20 +34,62 @@ void MqttClient::onConnected(struct esp_mqtt_client *client) { ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); m_setStatusTopic = "homeassistant/light/bedroom/set"; + m_statusTopic = "homeassistant/light/bedroom/state"; msg_id = esp_mqtt_client_subscribe(client, m_setStatusTopic.c_str(), 0); ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + reportLedState(); } void MqttClient::onSetStatus(const char *data, int size) { - ESP_LOGI(TAG, "set: %s", data); + ESP_LOGI(TAG, "set: %.*s", size, data); cJSON *root = cJSON_Parse(data); cJSON *brightness = cJSON_GetObjectItem(root, "brightness"); if (brightness != nullptr) { ESP_LOGI(TAG, "brightness: %d", brightness->valueint); - LedController::instance()->setDuty(1, brightness->valueint); + LedController::instance()->setBrightness(brightness->valueint); + Application::instance()->setField("brightness", brightness->valueint); + } + + cJSON *color_temp = cJSON_GetObjectItem(root, "color_temp"); + if (color_temp != nullptr) { + ESP_LOGI(TAG, "color_temp: %d", color_temp->valueint); + LedController::instance()->setColorTemperature(color_temp->valueint); + Application::instance()->setField("color_temp", color_temp->valueint); + } + + cJSON *state = cJSON_GetObjectItem(root, "state"); + if (state != nullptr) { + if (std::string_view(state->valuestring) == "ON") { + LedController::instance()->setEnabled(true); + } else { + LedController::instance()->setEnabled(false); + } } cJSON_Delete(root); + reportLedState(); +} + +void MqttClient::reportLedState() { + cJSON *root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "state", LedController::instance()->enabled() ? "ON" : "OFF"); + cJSON_AddNumberToObject(root, "brightness", LedController::instance()->brightness()); + cJSON_AddNumberToObject(root, "color_temp", LedController::instance()->colorTemperature()); + + auto text = cJSON_PrintUnformatted(root); + if (text != nullptr) { + auto messageId = esp_mqtt_client_publish(m_client, m_statusTopic.c_str(), text, strlen(text), 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", messageId); + free(text); + } + cJSON_Delete(root); +} + +MqttClient::~MqttClient() { + if (m_client != nullptr) { + esp_mqtt_client_destroy(m_client); + } } static void log_error_if_nonzero(const char *message, int error_code) { @@ -60,7 +103,6 @@ void MqttClient::eventHandler(void *handler_args, esp_event_base_t base, int32_t ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id); auto event = reinterpret_cast(event_data); esp_mqtt_client_handle_t client = event->client; - int msg_id; switch ((esp_mqtt_event_id_t)event_id) { case MQTT_EVENT_CONNECTED: self->onConnected(client); @@ -71,8 +113,6 @@ void MqttClient::eventHandler(void *handler_args, esp_event_base_t base, int32_t case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); - ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); @@ -111,10 +151,10 @@ bool MqttClient::initialize(const std::string &username, const std::string &pass config.credentials.username = username.c_str(); config.credentials.authentication.password = password.c_str(); - esp_mqtt_client_handle_t client = esp_mqtt_client_init(&config); - esp_mqtt_client_register_event(client, static_cast(ESP_EVENT_ANY_ID), + m_client = esp_mqtt_client_init(&config); + esp_mqtt_client_register_event(m_client, static_cast(ESP_EVENT_ANY_ID), &MqttClient::eventHandler, this); - esp_mqtt_client_start(client); + esp_mqtt_client_start(m_client); ESP_LOGI(TAG, "connect to %s, username: %s, password: %s", config.broker.address.uri, config.credentials.username, config.credentials.authentication.password); return true; diff --git a/components/Communication/MqttClient.h b/components/Communication/MqttClient.h index 3640bb0..50f9708 100644 --- a/components/Communication/MqttClient.h +++ b/components/Communication/MqttClient.h @@ -9,6 +9,9 @@ public: static MqttClient *instance(); bool initialize(const std::string &username, const std::string &password); + void reportLedState(); + ~MqttClient(); + protected: static void eventHandler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); void onConnected(struct esp_mqtt_client *client); @@ -17,5 +20,7 @@ protected: private: std::string m_setStatusTopic; + std::string m_statusTopic; + esp_mqtt_client_handle_t m_client = nullptr; }; #endif // __MQTTCLIENT_H__ \ No newline at end of file diff --git a/components/LedController/LedController.cpp b/components/LedController/LedController.cpp index 315725d..efd5a88 100644 --- a/components/LedController/LedController.cpp +++ b/components/LedController/LedController.cpp @@ -10,7 +10,7 @@ bool LedController::initialize() { ledc_timer_config_t ledc_timer; memset(&ledc_timer, 0, sizeof(ledc_timer)); ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; - ledc_timer.duty_resolution = LEDC_TIMER_13_BIT; + ledc_timer.duty_resolution = TimerBit; ledc_timer.timer_num = LEDC_TIMER_0; ledc_timer.freq_hz = 4000; ledc_timer.clk_cfg = LEDC_AUTO_CLK; @@ -41,18 +41,60 @@ bool LedController::initialize() { std::cout << "ledc_timer_config() failed." << std::endl; } - ledc_set_duty(m_channels[i].speed_mode, m_channels[i].channel, 4096); + ledc_set_duty(m_channels[i].speed_mode, m_channels[i].channel, 0); ledc_update_duty(m_channels[i].speed_mode, m_channels[i].channel); } - std::cout << "led controller initialize finished." << std::endl; return true; } -void LedController::setDuty(int32_t channel, int32_t duty) { - duty = static_cast(0x1FFF * duty) / 100; +int32_t LedController::brightness() const { + return m_brightness; +} +void LedController::setBrightness(int32_t brightness) { + if (m_brightness != brightness) { + m_brightness = brightness; + update(); + } +} + +int32_t LedController::colorTemperature() const { + return m_colorTemp; +} + +void LedController::setColorTemperature(int32_t temp) { + if (m_colorTemp != temp) { + m_colorTemp = temp; + update(); + } +} + +bool LedController::enabled() const { + return m_enabled; +} + +void LedController::setEnabled(bool enabled) { + if (m_enabled != enabled) { + m_enabled = enabled; + update(); + } +} + +void LedController::update() { + if (!m_enabled) { + setDuty(Warm, 0); + setDuty(Cold, 0); + return; + } + auto warm = static_cast(m_colorTemp - MinimumColorTemp) / (MaximumColorTemp - MinimumColorTemp); + auto wamDuty = m_brightness * warm; + setDuty(Warm, wamDuty); + setDuty(Cold, m_brightness - wamDuty); +} + +void LedController::setDuty(Channel channel, int32_t duty) { if ((channel < 0) || (channel >= sizeof(m_channels) / sizeof(m_channels[0]))) return; - std::cout<<"set channle "<setDuty(atoi(argv[1]), atoi(argv[2])); - + LedController::instance()->setDuty(static_cast(atoi(argv[1])), atoi(argv[2])); return 0; } static int mqtt_command(int argc, char **argv) { MqttClient::instance()->initialize(argv[1], argv[2]); + Application::instance()->setField("mqtt_username", std::string(argv[1])); + Application::instance()->setField("mqtt_password", std::string(argv[2])); return 0; } @@ -52,6 +53,8 @@ static int wifi_connect(int argc, char **argv) { ESP_LOGW(__func__, "Connection timed out"); return 1; } + Application::instance()->setField("ssid", std::string(join_args.ssid->sval[0])); + Application::instance()->setField("psk", std::string(join_args.password->sval[0])); ESP_LOGI(__func__, "Connected"); return 0; } diff --git a/main/main.cpp b/main/main.cpp index 9cc2443..83c4e9d 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,6 +1,7 @@ #include "Application.h" #include "CustomCommand.h" #include "LedController.h" +#include "MqttClient.h" #include "cmd_nvs.h" #include "cmd_system.h" #include "driver/uart.h" @@ -31,7 +32,7 @@ extern "C" void app_main() { initialize_filesystem(); initialize_console(); Application::instance()->initialize(); - Application::instance()->setField("author", "amass"); + esp_console_register_help_command(); register_system_common(); register_system_sleep(); @@ -39,6 +40,34 @@ extern "C" void app_main() { register_nvs(); LedController::instance()->initialize(); + if (Application::instance()->contains("brightness")) { + int brightness = Application::instance()->field("brightness"); + LedController::instance()->setBrightness(brightness); + ESP_LOGI("main", "last brightness: %d \n", brightness); + } + if (Application::instance()->contains("color_temp")) { + int color_temp = Application::instance()->field("color_temp"); + LedController::instance()->setColorTemperature(Application::instance()->field("color_temp")); + ESP_LOGI("main", "last color_temp: %d \n", color_temp); + } + + bool connected = false; + if (Application::instance()->contains("ssid")) { + auto ssid = Application::instance()->field("ssid"); + auto psk = Application::instance()->field("psk"); + connected = Application::instance()->wifiConnect(ssid, psk); + } else { + ESP_LOGI("main", "please connect wifi use command.\n"); + } + if (connected) { + if (Application::instance()->contains("mqtt_username")) { + auto username = Application::instance()->field("mqtt_username"); + auto password = Application::instance()->field("mqtt_password"); + MqttClient::instance()->initialize(username, password); + } else { + ESP_LOGI("main", "please connect mqtt use command.\n"); + } + } while (true) { char *line = linenoise(prompt);