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());
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) {
ESP_LOGI("App", "nvs_open() failed.");
}
if (std::is_same_v<char *, std::decay_t<T>>) {
if constexpr (std::is_same_v<char *, std::decay_t<T>>) {
error = nvs_set_str(hanlde, key.c_str(), value);
} else if constexpr (std::is_same_v<std::string, T>) {
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 {
ESP_LOGW("App", "unknown data");
}
@ -43,7 +44,24 @@ public:
template <typename T>
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:
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 "Application.h"
#include "LedController.h"
#include <cJSON.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, "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<esp_mqtt_event_handle_t>(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_mqtt_event_id_t>(ESP_EVENT_ANY_ID),
m_client = esp_mqtt_client_init(&config);
esp_mqtt_client_register_event(m_client, static_cast<esp_mqtt_event_id_t>(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;

View File

@ -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__

View File

@ -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,16 +41,58 @@ 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<float>(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<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;
std::cout << "set channle " << channel << " duty: " << duty << std::endl;
ledc_set_duty(m_channels[channel].speed_mode, m_channels[channel].channel, duty);

View File

@ -5,12 +5,38 @@
class LedController {
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();
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:
LedController();
void update();
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__

View File

@ -16,13 +16,14 @@ static int led_command(int argc, char **argv) {
for (int i = 0; i < argc; i++) {
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;
}
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;
}

View File

@ -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<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) {
char *line = linenoise(prompt);