add connect wifi mqtt auto.

This commit is contained in:
amass 2024-06-05 22:59:04 +08:00
parent 7f3491094f
commit 8413ce1fa9
8 changed files with 193 additions and 21 deletions

View File

@ -65,3 +65,12 @@ void Application::initializeWifi() {
ESP_ERROR_CHECK(esp_wifi_start()); ESP_ERROR_CHECK(esp_wifi_start());
initialized = true; 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;
}

View File

@ -26,11 +26,12 @@ public:
if (error != ESP_OK) { if (error != ESP_OK) {
ESP_LOGI("App", "nvs_open() failed."); ESP_LOGI("App", "nvs_open() failed.");
} }
if constexpr (std::is_same_v<char *, std::decay_t<T>>) {
if (std::is_same_v<char *, std::decay_t<T>>) {
error = nvs_set_str(hanlde, key.c_str(), value); error = nvs_set_str(hanlde, key.c_str(), value);
} else if constexpr (std::is_same_v<std::string, T>) { } else if constexpr (std::is_same_v<std::string, T>) {
error = nvs_set_str(hanlde, key.c_str(), value.c_str()); error = nvs_set_str(hanlde, key.c_str(), value.c_str());
} else if constexpr (std::is_same_v<int32_t, T> || std::is_same_v<int, T>) {
error = nvs_set_i32(hanlde, key.c_str(), value);
} else { } else {
ESP_LOGW("App", "unknown data"); ESP_LOGW("App", "unknown data");
} }
@ -43,7 +44,24 @@ public:
template <typename T> template <typename T>
T field(const std::string &key) { T field(const std::string &key) {
T ret{};
nvs_handle_t hanlde;
nvs_open(Namespace, NVS_READWRITE, &hanlde);
if constexpr (std::is_same_v<char *, std::decay_t<T>> || std::is_same_v<std::string, T>) {
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<int, T>) {
ret = field<int32_t>(key);
} else if constexpr (std::is_same_v<int32_t, T>) {
nvs_get_i32(hanlde, key.c_str(), &ret);
} }
nvs_close(hanlde);
return ret;
}
bool contains(const std::string &key);
protected: protected:
static void eventHandler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data); static void eventHandler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);

View File

@ -1,4 +1,5 @@
#include "MqttClient.h" #include "MqttClient.h"
#include "Application.h"
#include "LedController.h" #include "LedController.h"
#include <cJSON.h> #include <cJSON.h>
#include <esp_log.h> #include <esp_log.h>
@ -17,7 +18,7 @@ void MqttClient::onConnected(struct esp_mqtt_client *client) {
cJSON_AddStringToObject(root, "cmd_t", "~/set"); cJSON_AddStringToObject(root, "cmd_t", "~/set");
cJSON_AddStringToObject(root, "stat_t", "~/state"); cJSON_AddStringToObject(root, "stat_t", "~/state");
cJSON_AddStringToObject(root, "schema", "json"); cJSON_AddStringToObject(root, "schema", "json");
cJSON_AddNumberToObject(root, "brightness_scale", 100); cJSON_AddNumberToObject(root, "brightness_scale", LedController::Resolution);
const char *modes[] = { const char *modes[] = {
"color_temp", "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); ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
m_setStatusTopic = "homeassistant/light/bedroom/set"; m_setStatusTopic = "homeassistant/light/bedroom/set";
m_statusTopic = "homeassistant/light/bedroom/state";
msg_id = esp_mqtt_client_subscribe(client, m_setStatusTopic.c_str(), 0); msg_id = esp_mqtt_client_subscribe(client, m_setStatusTopic.c_str(), 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
reportLedState();
} }
void MqttClient::onSetStatus(const char *data, int size) { 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 *root = cJSON_Parse(data);
cJSON *brightness = cJSON_GetObjectItem(root, "brightness"); cJSON *brightness = cJSON_GetObjectItem(root, "brightness");
if (brightness != nullptr) { if (brightness != nullptr) {
ESP_LOGI(TAG, "brightness: %d", brightness->valueint); 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); 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) { 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); ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
auto event = reinterpret_cast<esp_mqtt_event_handle_t>(event_data); auto event = reinterpret_cast<esp_mqtt_event_handle_t>(event_data);
esp_mqtt_client_handle_t client = event->client; esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch ((esp_mqtt_event_id_t)event_id) { switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED: case MQTT_EVENT_CONNECTED:
self->onConnected(client); self->onConnected(client);
@ -71,8 +113,6 @@ void MqttClient::eventHandler(void *handler_args, esp_event_base_t base, int32_t
case MQTT_EVENT_SUBSCRIBED: case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); 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; break;
case MQTT_EVENT_UNSUBSCRIBED: case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); 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.username = username.c_str();
config.credentials.authentication.password = password.c_str(); config.credentials.authentication.password = password.c_str();
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&config); m_client = esp_mqtt_client_init(&config);
esp_mqtt_client_register_event(client, static_cast<esp_mqtt_event_id_t>(ESP_EVENT_ANY_ID), esp_mqtt_client_register_event(m_client, static_cast<esp_mqtt_event_id_t>(ESP_EVENT_ANY_ID),
&MqttClient::eventHandler, this); &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, ESP_LOGI(TAG, "connect to %s, username: %s, password: %s", config.broker.address.uri, config.credentials.username,
config.credentials.authentication.password); config.credentials.authentication.password);
return true; return true;

View File

@ -9,6 +9,9 @@ public:
static MqttClient *instance(); static MqttClient *instance();
bool initialize(const std::string &username, const std::string &password); bool initialize(const std::string &username, const std::string &password);
void reportLedState();
~MqttClient();
protected: protected:
static void eventHandler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); 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); void onConnected(struct esp_mqtt_client *client);
@ -17,5 +20,7 @@ protected:
private: private:
std::string m_setStatusTopic; std::string m_setStatusTopic;
std::string m_statusTopic;
esp_mqtt_client_handle_t m_client = nullptr;
}; };
#endif // __MQTTCLIENT_H__ #endif // __MQTTCLIENT_H__

View File

@ -10,7 +10,7 @@ bool LedController::initialize() {
ledc_timer_config_t ledc_timer; ledc_timer_config_t ledc_timer;
memset(&ledc_timer, 0, sizeof(ledc_timer)); memset(&ledc_timer, 0, sizeof(ledc_timer));
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; 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.timer_num = LEDC_TIMER_0;
ledc_timer.freq_hz = 4000; ledc_timer.freq_hz = 4000;
ledc_timer.clk_cfg = LEDC_AUTO_CLK; ledc_timer.clk_cfg = LEDC_AUTO_CLK;
@ -41,18 +41,60 @@ bool LedController::initialize() {
std::cout << "ledc_timer_config() failed." << std::endl; 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); ledc_update_duty(m_channels[i].speed_mode, m_channels[i].channel);
} }
std::cout << "led controller initialize finished." << std::endl;
return true; return true;
} }
void LedController::setDuty(int32_t channel, int32_t duty) { int32_t LedController::brightness() const {
duty = static_cast<float>(0x1FFF * duty) / 100; 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<float>(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; if ((channel < 0) || (channel >= sizeof(m_channels) / sizeof(m_channels[0]))) return;
std::cout<<"set channle "<<channel<<" duty: "<<duty<<std::endl; std::cout << "set channle " << channel << " duty: " << duty << std::endl;
ledc_set_duty(m_channels[channel].speed_mode, m_channels[channel].channel, duty); ledc_set_duty(m_channels[channel].speed_mode, m_channels[channel].channel, duty);
ledc_update_duty(m_channels[channel].speed_mode, m_channels[channel].channel); ledc_update_duty(m_channels[channel].speed_mode, m_channels[channel].channel);
} }

View File

@ -5,12 +5,38 @@
class LedController { class LedController {
public: public:
constexpr static ledc_timer_bit_t TimerBit = LEDC_TIMER_12_BIT;
constexpr static int32_t Resolution = 1 << LEDC_TIMER_12_BIT;
constexpr static int32_t MinimumColorTemp = 153;
constexpr static int32_t MaximumColorTemp = 500;
enum Channel {
Warm = 0,
Cold = 1,
};
static LedController *instance(); static LedController *instance();
bool initialize(); bool initialize();
void setDuty(int32_t channel, int32_t duty);
int32_t brightness() const;
void setBrightness(int32_t brightness);
int32_t colorTemperature() const;
void setColorTemperature(int32_t temp);
bool enabled() const;
void setEnabled(bool enabled);
void setDuty(Channel channel, int32_t duty);
protected: protected:
LedController(); LedController();
void update();
ledc_channel_config_t m_channels[2]; ledc_channel_config_t m_channels[2];
private:
bool m_enabled = false;
int32_t m_brightness = 0;
int32_t m_colorTemp = 0;
}; };
#endif // __LEDCONTROLLER_H__ #endif // __LEDCONTROLLER_H__

View File

@ -16,13 +16,14 @@ static int led_command(int argc, char **argv) {
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
std::cout << i << " " << argv[i] << std::endl; std::cout << i << " " << argv[i] << std::endl;
} }
LedController::instance()->setDuty(atoi(argv[1]), atoi(argv[2])); LedController::instance()->setDuty(static_cast<LedController::Channel>(atoi(argv[1])), atoi(argv[2]));
return 0; return 0;
} }
static int mqtt_command(int argc, char **argv) { static int mqtt_command(int argc, char **argv) {
MqttClient::instance()->initialize(argv[1], argv[2]); 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; return 0;
} }
@ -52,6 +53,8 @@ static int wifi_connect(int argc, char **argv) {
ESP_LOGW(__func__, "Connection timed out"); ESP_LOGW(__func__, "Connection timed out");
return 1; 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"); ESP_LOGI(__func__, "Connected");
return 0; return 0;
} }

View File

@ -1,6 +1,7 @@
#include "Application.h" #include "Application.h"
#include "CustomCommand.h" #include "CustomCommand.h"
#include "LedController.h" #include "LedController.h"
#include "MqttClient.h"
#include "cmd_nvs.h" #include "cmd_nvs.h"
#include "cmd_system.h" #include "cmd_system.h"
#include "driver/uart.h" #include "driver/uart.h"
@ -31,7 +32,7 @@ extern "C" void app_main() {
initialize_filesystem(); initialize_filesystem();
initialize_console(); initialize_console();
Application::instance()->initialize(); Application::instance()->initialize();
Application::instance()->setField("author", "amass");
esp_console_register_help_command(); esp_console_register_help_command();
register_system_common(); register_system_common();
register_system_sleep(); register_system_sleep();
@ -39,6 +40,34 @@ extern "C" void app_main() {
register_nvs(); register_nvs();
LedController::instance()->initialize(); LedController::instance()->initialize();
if (Application::instance()->contains("brightness")) {
int brightness = Application::instance()->field<int>("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<int>("color_temp");
LedController::instance()->setColorTemperature(Application::instance()->field<int>("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<std::string>("ssid");
auto psk = Application::instance()->field<std::string>("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<std::string>("mqtt_username");
auto password = Application::instance()->field<std::string>("mqtt_password");
MqttClient::instance()->initialize(username, password);
} else {
ESP_LOGI("main", "please connect mqtt use command.\n");
}
}
while (true) { while (true) {
char *line = linenoise(prompt); char *line = linenoise(prompt);