Configurable MQTT Topic #428

This commit is contained in:
fvanroie 2023-02-15 20:09:13 +01:00
parent 59bc01be04
commit c296a5e568
3 changed files with 264 additions and 134 deletions

View File

@ -22,16 +22,21 @@ bool nvs_user_begin(Preferences& preferences, const char* key, bool readonly)
bool nvs_clear_user_config() bool nvs_clear_user_config()
{ {
const char* name[8] = {FP_TIME, FP_OTA, FP_HTTP, FP_FTP, FP_MQTT, FP_WIFI}; const char* name[] = {FP_TIME, FP_OTA, FP_HTTP, FP_FTP, FP_MQTT, FP_WIFI};
Preferences preferences; Preferences preferences;
bool state = true;
for(int i = 0; i < 6; i++) { for(int i = 0; i < sizeof(name) / sizeof(name[0]); i++) {
if(!preferences.begin(name[i], false)) return false; if(preferences.begin(name[i], false) && !preferences.clear()) state = false;
if(!preferences.clear()) return false;
preferences.end(); preferences.end();
} }
return true; for(int i = 0; i < sizeof(name) / sizeof(name[0]); i++) {
if(preferences.begin(name[i], false, "config") && !preferences.clear()) state = false;
preferences.end();
}
return state;
} }
bool nvsUpdateString(Preferences& preferences, const char* key, JsonVariant value) bool nvsUpdateString(Preferences& preferences, const char* key, JsonVariant value)

View File

@ -1,4 +1,4 @@
/* MIT License - Copyright (c) 2019-2022 Francis Van Roie /* MIT License - Copyright (c) 2019-2023 Francis Van Roie
For full license information read the LICENSE file in the project folder */ For full license information read the LICENSE file in the project folder */
#include "hasp_conf.h" #include "hasp_conf.h"
@ -22,6 +22,14 @@
#include "../hasp/hasp_dispatch.h" #include "../hasp/hasp_dispatch.h"
#include "freertos/queue.h" #include "freertos/queue.h"
#include "esp_http_server.h"
#include "esp_tls.h"
#define MQTT_DEFAULT_NODE_TOPIC MQTT_PREFIX "/%hostname%/%topic%"
#define MQTT_DEFAULT_GROUP_TOPIC MQTT_PREFIX "/plates/%topic%"
#define MQTT_DEFAULT_BROADCAST_TOPIC MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/%topic%"
#define MQTT_DEFAULT_HASS_TOPIC "homeassistant/status"
QueueHandle_t queue; QueueHandle_t queue;
typedef struct typedef struct
{ {
@ -29,22 +37,30 @@ typedef struct
char* payload; //[512]; char* payload; //[512];
} mqtt_message_t; } mqtt_message_t;
char mqttLwtTopic[28];
char mqttNodeTopic[24];
char mqttClientId[64]; char mqttClientId[64];
char mqttGroupTopic[24]; String mqttNodeLwtTopic;
String mqttHassLwtTopic;
String mqttNodeStateTopic;
String mqttNodeCommandTopic;
String mqttGroupCommandTopic;
String mqttBroadcastCommandTopic;
bool mqttEnabled = false; bool mqttEnabled = false;
bool mqttHAautodiscover = true; bool mqttHAautodiscover = true;
uint32_t mqttPublishCount; uint32_t mqttPublishCount;
uint32_t mqttReceiveCount; uint32_t mqttReceiveCount;
uint32_t mqttFailedCount; uint32_t mqttFailedCount;
char mqttServer[MAX_HOSTNAME_LENGTH] = MQTT_HOSTNAME; String mqttServer = MQTT_HOSTNAME;
char mqttUsername[MAX_USERNAME_LENGTH] = MQTT_USERNAME; String mqttUsername = MQTT_USERNAME;
char mqttPassword[MAX_PASSWORD_LENGTH] = MQTT_PASSWORD; String mqttPassword = MQTT_PASSWORD;
// char mqttServer[MAX_HOSTNAME_LENGTH] = MQTT_HOSTNAME;
// char mqttUsername[MAX_USERNAME_LENGTH] = MQTT_USERNAME;
// char mqttPassword[MAX_PASSWORD_LENGTH] = MQTT_PASSWORD;
// char mqttNodeName[16] = MQTT_NODENAME; // char mqttNodeName[16] = MQTT_NODENAME;
char mqttGroupName[16] = MQTT_GROUPNAME; // char mqttGroupName[16] = MQTT_GROUPNAME;
uint16_t mqttPort = MQTT_PORT; uint16_t mqttPort = MQTT_PORT;
int mqttQos = 0;
esp_mqtt_client_handle_t mqttClient; esp_mqtt_client_handle_t mqttClient;
static esp_mqtt_client_config_t mqtt_cfg; static esp_mqtt_client_config_t mqtt_cfg;
@ -107,7 +123,7 @@ int mqttPublish(const char* topic, const char* payload, size_t len, bool retain)
if(!mqttEnabled) return MQTT_ERR_DISABLED; if(!mqttEnabled) return MQTT_ERR_DISABLED;
// Write directly to the client, don't use the buffer // Write directly to the client, don't use the buffer
if(current_mqtt_state && esp_mqtt_client_publish(mqttClient, topic, payload, len, 0, retain) != ESP_FAIL) { if(current_mqtt_state && esp_mqtt_client_publish(mqttClient, topic, payload, len, mqttQos, retain) != ESP_FAIL) {
// Enqueue a message to the outbox, to be sent later // Enqueue a message to the outbox, to be sent later
// if(current_mqtt_state && esp_mqtt_client_enqueue(mqttClient, topic, payload, len, 0, retain, true) != // if(current_mqtt_state && esp_mqtt_client_enqueue(mqttClient, topic, payload, len, 0, retain, true) !=
@ -136,29 +152,29 @@ bool mqttIsConnected()
bool mqtt_send_lwt(bool online) bool mqtt_send_lwt(bool online)
{ {
char tmp_payload[8]; char tmp_payload[8];
// char tmp_topic[strlen(mqttNodeTopic) + 4];
// strncpy(tmp_topic, mqttNodeTopic, sizeof(tmp_topic));
// strncat_P(tmp_topic, PSTR(MQTT_TOPIC_LWT), sizeof(tmp_topic));
size_t len = snprintf_P(tmp_payload, sizeof(tmp_payload), online ? PSTR("online") : PSTR("offline")); size_t len = snprintf_P(tmp_payload, sizeof(tmp_payload), online ? PSTR("online") : PSTR("offline"));
bool res = mqttPublish(mqttLwtTopic, tmp_payload, len, true); bool res = mqttPublish(mqttNodeLwtTopic.c_str(), tmp_payload, len, true);
return res; return res;
} }
int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload) // int mqtt_send_object_state(uint8_t pageid, uint8_t btnid, const char* payload)
{ // {
char tmp_topic[strlen(mqttNodeTopic) + 16]; // char tmp_topic[strlen(mqttNodeTopic) + 16];
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/" HASP_OBJECT_NOTATION), mqttNodeTopic, // snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/" HASP_OBJECT_NOTATION), mqttNodeTopic,
pageid, btnid); // pageid, btnid);
return mqttPublish(tmp_topic, payload, false); // return mqttPublish(tmp_topic, payload, false);
} // }
int mqtt_send_state(const char* subtopic, const char* payload) int mqtt_send_state(const char* subtopic, const char* payload)
{ {
char tmp_topic[strlen(mqttNodeTopic) + strlen(subtopic) + 16]; String tmp_topic((char*)0);
snprintf_P(tmp_topic, sizeof(tmp_topic), PSTR("%s" MQTT_TOPIC_STATE "/%s"), mqttNodeTopic, subtopic); tmp_topic.reserve(128);
return mqttPublish(tmp_topic, payload, false); tmp_topic = mqttNodeStateTopic;
// tmp_topic += MQTT_TOPIC_STATE;
// tmp_topic += "/";
tmp_topic += subtopic;
return mqttPublish(tmp_topic.c_str(), payload, false);
} }
int mqtt_send_discovery(const char* payload, size_t len) int mqtt_send_discovery(const char* payload, size_t len)
@ -216,21 +232,15 @@ static void mqtt_message_cb(const char* topic, byte* payload, unsigned int lengt
mqttReceiveCount++; mqttReceiveCount++;
// LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload); // LOG_TRACE(TAG_MQTT_RCV, F("%s = %s"), topic, (char*)payload);
if(topic == strstr(topic, mqttNodeTopic)) { // startsWith mqttNodeTopic if(topic == strstr(topic, mqttNodeCommandTopic.c_str())) { // startsWith mqttNodeCommandTopic
topic += strlen(mqttNodeCommandTopic.c_str()); // shorten Node topic
// Node topic } else if(topic == strstr(topic, mqttGroupCommandTopic.c_str())) { // startsWith mqttGroupCommandTopic
topic += strlen(mqttNodeTopic); // shorten topic topic += strlen(mqttGroupCommandTopic.c_str()); // shorten Group topic
} else if(topic == strstr(topic, mqttGroupTopic)) { // startsWith mqttGroupTopic
// Group topic
topic += strlen(mqttGroupTopic); // shorten topic
#ifdef HASP_USE_BROADCAST #ifdef HASP_USE_BROADCAST
} else if(topic == strstr_P(topic, PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/"))) { // broadcast topic } else if(topic == strstr_P(topic, mqttBroadcastCommandTopic.c_str())) { // broadcast topic
topic += strlen_P(mqttBroadcastCommandTopic.c_str()); // shorten Broadcast topic
// Broadcast topic
topic += strlen_P(PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/")); // shorten topic
#endif #endif
#ifdef HASP_USE_HA #ifdef HASP_USE_HA
@ -241,10 +251,14 @@ static void mqtt_message_cb(const char* topic, byte* payload, unsigned int lengt
} }
return; return;
#endif #endif
} else if(topic == strstr(topic, mqttHassLwtTopic.c_str())) { // startsWith mqttGroupCommandTopic
String state = String((const char*)payload);
state.toLowerCase();
LOG_VERBOSE(TAG_MQTT, "Home Automation System: %s", state);
return;
} else { } else {
// Other topic LOG_ERROR(TAG_MQTT, F(D_MQTT_INVALID_TOPIC ": %s"), topic); // Other topic
LOG_ERROR(TAG_MQTT, F(D_MQTT_INVALID_TOPIC));
return; return;
} }
@ -270,6 +284,7 @@ static void mqtt_message_cb(const char* topic, byte* payload, unsigned int lengt
else */ else */
{ {
if(topic[0] == '/') topic++;
mqtt_process_topic_payload(topic, (const char*)payload, length); mqtt_process_topic_payload(topic, (const char*)payload, length);
} }
@ -286,41 +301,58 @@ static void mqtt_message_cb(const char* topic, byte* payload, unsigned int lengt
} */ } */
} }
static void mqttSubscribeTo(const char* topic) static int mqttSubscribeTo(String topic)
{ {
if(esp_mqtt_client_subscribe(mqttClient, topic, 0) == ESP_FAIL) { int err = esp_mqtt_client_subscribe(mqttClient, topic.c_str(), mqttQos);
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_SUBSCRIBED), topic); if(err == ESP_FAIL) {
LOG_ERROR(TAG_MQTT, F(D_MQTT_NOT_SUBSCRIBED), topic.c_str());
mqttFailedCount++; mqttFailedCount++;
} else { } else {
LOG_VERBOSE(TAG_MQTT, F(D_BULLET D_MQTT_SUBSCRIBED), topic); LOG_VERBOSE(TAG_MQTT, F(D_BULLET D_MQTT_SUBSCRIBED), topic.c_str());
} }
return err;
}
String mqttGetTopic(Preferences preferences, String subtopic, String key, String value, bool add_slash)
{
String topic = preferences.getString(key.c_str(), value);
topic.replace(F("%hostname%"), haspDevice.get_hostname());
topic.replace(F("%hwid%"), haspDevice.get_hardware_id());
topic.replace(F("%topic%"), subtopic);
topic.replace(F("%prefix%"), MQTT_PREFIX);
if(add_slash && !topic.endsWith("/")) {
topic += "/";
}
return topic;
} }
void onMqttConnect(esp_mqtt_client_handle_t client) void onMqttConnect(esp_mqtt_client_handle_t client)
{ {
LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTED), mqttServer, mqttClientId); LOG_INFO(TAG_MQTT, F(D_MQTT_CONNECTED), mqttServer, mqttClientId);
// Subscribe to our incoming topics LOG_DEBUG(TAG_MQTT, F(D_BULLET "%s"), mqttNodeCommandTopic.c_str());
char topic[64]; LOG_DEBUG(TAG_MQTT, F(D_BULLET "%s"), mqttGroupCommandTopic.c_str());
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_COMMAND "/#"), mqttGroupTopic); LOG_DEBUG(TAG_MQTT, F(D_BULLET "%s"), mqttBroadcastCommandTopic.c_str());
mqttSubscribeTo(topic); LOG_DEBUG(TAG_MQTT, F(D_BULLET "%s"), mqttHassLwtTopic.c_str());
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_COMMAND "/#"), mqttNodeTopic);
mqttSubscribeTo(topic);
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_CONFIG "/#"), mqttGroupTopic);
mqttSubscribeTo(topic);
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_CONFIG "/#"), mqttNodeTopic);
mqttSubscribeTo(topic);
#if defined(HASP_USE_CUSTOM) // Subscribe to our incoming topics
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_CUSTOM "/#"), mqttGroupTopic); mqttSubscribeTo(mqttGroupCommandTopic + "/#");
mqttSubscribeTo(topic); mqttSubscribeTo(mqttNodeCommandTopic + "/#");
snprintf_P(topic, sizeof(topic), PSTR("%s" MQTT_TOPIC_CUSTOM "/#"), mqttNodeTopic);
mqttSubscribeTo(topic);
#endif
#ifdef HASP_USE_BROADCAST #ifdef HASP_USE_BROADCAST
snprintf_P(topic, sizeof(topic), PSTR(MQTT_PREFIX "/" MQTT_TOPIC_BROADCAST "/" MQTT_TOPIC_COMMAND "/#")); mqttSubscribeTo(mqttBroadcastCommandTopic + "/#");
mqttSubscribeTo(topic); #endif
// subtopic = F(MQTT_TOPIC_CONFIG "/#");
// mqttSubscribeTo(mqttGroupTopic + subtopic);
// mqttSubscribeTo(mqttNodeTopic + subtopic);
#if defined(HASP_USE_CUSTOM)
subtopic = F(MQTT_TOPIC_CUSTOM "/#");
mqttSubscribeTo(mqttGroupTopic + subtopic);
mqttSubscribeTo(mqttNodeTopic + subtopic);
#endif #endif
/* Home Assistant auto-configuration */ /* Home Assistant auto-configuration */
@ -334,6 +366,8 @@ void onMqttConnect(esp_mqtt_client_handle_t client)
} }
#endif #endif
mqttSubscribeTo(mqttHassLwtTopic);
// Force any subscribed clients to toggle offline/online when we first connect to // Force any subscribed clients to toggle offline/online when we first connect to
// make sure we get a full panel refresh at power on. Sending offline, // make sure we get a full panel refresh at power on. Sending offline,
// "online" will be sent by the mqttStatusTopic subscription action. // "online" will be sent by the mqttStatusTopic subscription action.
@ -358,10 +392,10 @@ static void onMqttData(esp_mqtt_event_handle_t event)
static void onMqttSubscribed(esp_mqtt_event_handle_t event) static void onMqttSubscribed(esp_mqtt_event_handle_t event)
{ {
String topic = String(event->topic).substring(0, event->topic_len); // String topic = String(event->topic).substring(0, event->topic_len);
String msg = String(event->data).substring(0, event->data_len); String msg = String(event->data).substring(0, event->data_len);
LOG_VERBOSE(TAG_MQTT, F(D_BULLET D_MQTT_SUBSCRIBED " %d %s %d"), topic.c_str(), event->topic_len, msg.c_str(), const char* topic = "topic";
event->data_len); LOG_VERBOSE(TAG_MQTT, F(D_BULLET D_MQTT_SUBSCRIBED "(%d)"), topic, event->msg_id);
} }
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
@ -410,8 +444,8 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
case MQTT_CONNECTION_REFUSE_BAD_USERNAME: /*!< MQTT connection refused reason: Wrong user */ case MQTT_CONNECTION_REFUSE_BAD_USERNAME: /*!< MQTT connection refused reason: Wrong user */
LOG_WARNING(TAG_MQTT, "Connection refused: Wrong user"); LOG_WARNING(TAG_MQTT, "Connection refused: Wrong user");
break; break;
case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED: /*!< MQTT connection refused reason: Wrong username case MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED: /*!< MQTT connection refused reason: Wrong
or password */ username or password */
LOG_WARNING(TAG_MQTT, "Connection refused: Authentication error"); LOG_WARNING(TAG_MQTT, "Connection refused: Authentication error");
break; break;
default:; default:;
@ -430,12 +464,6 @@ static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
void mqttSetup() void mqttSetup()
{ {
Preferences preferences;
preferences.begin("mqtt", true);
String password = preferences.getString(FP_CONFIG_PASS, MQTT_PASSWORD);
strncpy(mqttPassword, password.c_str(), sizeof(mqttPassword));
LOG_DEBUG(TAG_MQTT, F(D_BULLET "Read %s => %s (%d bytes)"), FP_CONFIG_PASS, password.c_str(), password.length());
queue = xQueueCreate(64, sizeof(mqtt_message_t)); queue = xQueueCreate(64, sizeof(mqtt_message_t));
esp_crt_bundle_set(rootca_crt_bundle_start); esp_crt_bundle_set(rootca_crt_bundle_start);
mqttStart(); mqttStart();
@ -468,10 +496,45 @@ void mqttEvery5Seconds(bool networkIsConnected)
void mqttStart() void mqttStart()
{ {
char buffer[64]; {
char lastWillPayload[8]; Preferences preferences;
nvs_user_begin(preferences, FP_MQTT, true);
mqttServer = preferences.getString(FP_CONFIG_HOST, mqttServer); // Update from NVS if it exists
mqttUsername = preferences.getString(FP_CONFIG_USER, mqttUsername); // Update from NVS if it exists
mqttPassword = preferences.getString(FP_CONFIG_PASS, mqttPassword); // Update from NVS if it exists
mqttPort = preferences.getUShort(FP_CONFIG_PORT, mqttPort); // Update from NVS if it exists
mqttEnabled = strlen(mqttServer) > 0 && mqttPort > 0; String subtopic((char*)0);
subtopic.reserve(64);
String nvsOldGroup = MQTT_PREFIX "/"; // recover group setting
nvsOldGroup += preferences.getString(FP_CONFIG_GROUP, "plates");
nvsOldGroup += "/%topic%";
subtopic = F(MQTT_TOPIC_COMMAND);
mqttNodeCommandTopic =
mqttGetTopic(preferences, subtopic, FP_CONFIG_NODE_TOPIC, MQTT_DEFAULT_NODE_TOPIC, false);
mqttGroupCommandTopic = mqttGetTopic(preferences, subtopic, FP_CONFIG_GROUP_TOPIC, nvsOldGroup.c_str(), false);
#ifdef HASP_USE_BROADCAST
mqttBroadcastCommandTopic =
mqttGetTopic(preferences, subtopic, FP_CONFIG_BROADCAST_TOPIC, MQTT_DEFAULT_BROADCAST_TOPIC, false);
#endif
subtopic = F(MQTT_TOPIC_STATE);
mqttNodeStateTopic = mqttGetTopic(preferences, subtopic, FP_CONFIG_NODE_TOPIC, MQTT_DEFAULT_NODE_TOPIC, true);
subtopic = F(MQTT_TOPIC_LWT);
mqttNodeLwtTopic = mqttGetTopic(preferences, subtopic, FP_CONFIG_NODE_TOPIC, MQTT_DEFAULT_NODE_TOPIC, false);
LOG_WARNING(TAG_MQTT, mqttNodeLwtTopic.c_str());
subtopic = F(MQTT_TOPIC_LWT);
mqttHassLwtTopic = mqttGetTopic(preferences, subtopic, FP_CONFIG_HASS_TOPIC, MQTT_DEFAULT_HASS_TOPIC, false);
LOG_WARNING(TAG_MQTT, mqttNodeLwtTopic.c_str());
preferences.end();
}
mqttEnabled = mqttServer.length() > 0 && mqttPort > 0;
if(!mqttEnabled) { if(!mqttEnabled) {
LOG_WARNING(TAG_MQTT, F(D_MQTT_NOT_CONFIGURED)); LOG_WARNING(TAG_MQTT, F(D_MQTT_NOT_CONFIGURED));
return; return;
@ -488,10 +551,6 @@ void mqttStart()
LOG_INFO(TAG_MQTT, mqttClientId); LOG_INFO(TAG_MQTT, mqttClientId);
} }
strncpy(mqttLwtTopic, mqttNodeTopic, sizeof(mqttLwtTopic));
strncat_P(mqttLwtTopic, PSTR(MQTT_TOPIC_LWT), sizeof(mqttLwtTopic));
LOG_WARNING(TAG_MQTT, mqttLwtTopic);
mqtt_cfg.event_handle = mqtt_event_handler; mqtt_cfg.event_handle = mqtt_event_handler;
mqtt_cfg.buffer_size = MQTT_MAX_PACKET_SIZE; mqtt_cfg.buffer_size = MQTT_MAX_PACKET_SIZE;
mqtt_cfg.out_buffer_size = 512; mqtt_cfg.out_buffer_size = 512;
@ -502,15 +561,15 @@ void mqttStart()
mqtt_cfg.protocol_ver = MQTT_PROTOCOL_V_3_1_1; mqtt_cfg.protocol_ver = MQTT_PROTOCOL_V_3_1_1;
mqtt_cfg.transport = MQTT_TRANSPORT_OVER_TCP; mqtt_cfg.transport = MQTT_TRANSPORT_OVER_TCP;
mqtt_cfg.host = mqttServer; mqtt_cfg.host = mqttServer.c_str();
mqtt_cfg.port = mqttPort; mqtt_cfg.port = mqttPort;
mqtt_cfg.username = mqttUsername; mqtt_cfg.username = mqttUsername.c_str();
mqtt_cfg.password = mqttPassword; mqtt_cfg.password = mqttPassword.c_str();
mqtt_cfg.client_id = mqttClientId; mqtt_cfg.client_id = mqttClientId;
mqtt_cfg.lwt_msg = "offline"; mqtt_cfg.lwt_msg = "offline";
mqtt_cfg.lwt_retain = true; mqtt_cfg.lwt_retain = true;
mqtt_cfg.lwt_topic = mqttLwtTopic; mqtt_cfg.lwt_topic = mqttNodeLwtTopic.c_str();
mqtt_cfg.lwt_qos = 1; mqtt_cfg.lwt_qos = 1;
mqtt_cfg.task_prio = 1; mqtt_cfg.task_prio = 1;
@ -610,27 +669,73 @@ void mqtt_get_info(JsonDocument& doc)
bool mqttGetConfig(const JsonObject& settings) bool mqttGetConfig(const JsonObject& settings)
{ {
bool changed = false; bool changed = false;
Preferences preferences;
nvs_user_begin(preferences, FP_MQTT, false);
if(strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)].as<String>().c_str()) != 0) changed = true; {
settings[FPSTR(FP_CONFIG_NAME)] = haspDevice.get_hostname(); String nvsServer = preferences.getString(FP_CONFIG_HOST, mqttServer); // Read from NVS if it exists
if(strcmp(nvsServer.c_str(), settings[FP_CONFIG_HOST].as<String>().c_str()) != 0) changed = true;
settings[FP_CONFIG_HOST] = nvsServer;
}
if(strcmp(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)].as<String>().c_str()) != 0) changed = true; {
settings[FPSTR(FP_CONFIG_GROUP)] = mqttGroupName; String nvsUsername = preferences.getString(FP_CONFIG_USER, mqttUsername); // Read from NVS if it exists
if(strcmp(nvsUsername.c_str(), settings[FP_CONFIG_USER].as<String>().c_str()) != 0) changed = true;
settings[FP_CONFIG_USER] = nvsUsername;
}
if(strcmp(mqttServer, settings[FPSTR(FP_CONFIG_HOST)].as<String>().c_str()) != 0) changed = true; {
settings[FPSTR(FP_CONFIG_HOST)] = mqttServer; String nvsPassword = preferences.getString(FP_CONFIG_PASS, mqttPassword); // Read from NVS if it exists
if(strcmp(D_PASSWORD_MASK, settings[FP_CONFIG_PASS].as<String>().c_str()) != 0) changed = true;
settings[FP_CONFIG_PASS] = D_PASSWORD_MASK;
}
if(mqttPort != settings[FPSTR(FP_CONFIG_PORT)].as<uint16_t>()) changed = true; {
settings[FPSTR(FP_CONFIG_PORT)] = mqttPort; String nvsNodeTopic =
preferences.getString(FP_CONFIG_NODE_TOPIC, MQTT_DEFAULT_NODE_TOPIC); // Read from NVS if it exists
if(strcmp(nvsNodeTopic.c_str(), settings["topic"][FP_CONFIG_NODE].as<String>().c_str()) != 0) changed = true;
settings["topic"][FP_CONFIG_NODE] = nvsNodeTopic;
}
if(strcmp(mqttUsername, settings[FPSTR(FP_CONFIG_USER)].as<String>().c_str()) != 0) changed = true; {
settings[FPSTR(FP_CONFIG_USER)] = mqttUsername; String nvsOldGroup = MQTT_PREFIX "/"; // recover group setting
nvsOldGroup += preferences.getString(FP_CONFIG_GROUP, "plates");
nvsOldGroup += "/%topic%";
String nvsGroupTopic =
preferences.getString(FP_CONFIG_GROUP_TOPIC, nvsOldGroup.c_str()); // Read from NVS if it exists
if(strcmp(nvsGroupTopic.c_str(), settings["topic"][FP_CONFIG_GROUP].as<String>().c_str()) != 0) changed = true;
settings["topic"][FP_CONFIG_GROUP] = nvsGroupTopic;
}
// if(strcmp(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)].as<String>().c_str()) != 0) changed = true; {
// settings[FPSTR(FP_CONFIG_PASS)] = mqttPassword; String nvsBroadcastTopic = preferences.getString(FP_CONFIG_BROADCAST_TOPIC,
if(strcmp(D_PASSWORD_MASK, settings[FPSTR(FP_CONFIG_PASS)].as<String>().c_str()) != 0) changed = true; MQTT_DEFAULT_BROADCAST_TOPIC); // Read from NVS if it exists
settings[FPSTR(FP_CONFIG_PASS)] = D_PASSWORD_MASK; if(strcmp(nvsBroadcastTopic.c_str(), settings["topic"][FP_CONFIG_BROADCAST].as<String>().c_str()) != 0)
changed = true;
settings["topic"][FP_CONFIG_BROADCAST] = nvsBroadcastTopic;
}
{
String nvsHassTopic =
preferences.getString(FP_CONFIG_HASS_TOPIC, MQTT_DEFAULT_HASS_TOPIC); // Read from NVS if it exists
if(strcmp(nvsHassTopic.c_str(), settings["topic"][FP_CONFIG_HASS].as<String>().c_str()) != 0) changed = true;
settings["topic"][FP_CONFIG_HASS] = nvsHassTopic;
}
{
uint16_t nvsPort = preferences.getUShort(FP_CONFIG_PORT, mqttPort); // Read from NVS if it exists
if(nvsPort != settings[FP_CONFIG_PORT].as<uint16_t>()) changed = true;
settings[FP_CONFIG_PORT] = nvsPort;
}
if(strcmp(haspDevice.get_hostname(), settings[FP_CONFIG_NAME].as<String>().c_str()) != 0) changed = true;
settings[FP_CONFIG_NAME] = haspDevice.get_hostname();
// if(strcmp(mqttGroupName, settings[FP_CONFIG_GROUP].as<String>().c_str()) != 0) changed = true;
// settings[FP_CONFIG_GROUP] = mqttGroupName;
preferences.end();
if(changed) configOutput(settings, TAG_MQTT); if(changed) configOutput(settings, TAG_MQTT);
return changed; return changed;
} }
@ -646,17 +751,20 @@ bool mqttGetConfig(const JsonObject& settings)
bool mqttSetConfig(const JsonObject& settings) bool mqttSetConfig(const JsonObject& settings)
{ {
Preferences preferences; Preferences preferences;
preferences.begin("mqtt", false); nvs_user_begin(preferences, FP_MQTT, false);
configOutput(settings, TAG_MQTT); configOutput(settings, TAG_MQTT);
bool changed = false; bool changed = false;
changed |= configSet(mqttPort, settings[FPSTR(FP_CONFIG_PORT)], F("mqttPort")); if(!settings[FP_CONFIG_PORT].isNull()) {
// changed |= configSet(mqttPort, settings[FP_CONFIG_PORT], F("mqttPort"));
changed |= nvsUpdateString(preferences, FP_CONFIG_PORT, settings[FP_CONFIG_PORT]);
}
if(!settings[FPSTR(FP_CONFIG_NAME)].isNull()) { if(!settings[FP_CONFIG_NAME].isNull()) {
changed |= strcmp(haspDevice.get_hostname(), settings[FPSTR(FP_CONFIG_NAME)]) != 0; changed |= strcmp(haspDevice.get_hostname(), settings[FP_CONFIG_NAME]) != 0;
// strncpy(mqttNodeName, settings[FPSTR(FP_CONFIG_NAME)], sizeof(mqttNodeName)); // strncpy(mqttNodeName, settings[FP_CONFIG_NAME], sizeof(mqttNodeName));
haspDevice.set_hostname(settings[FPSTR(FP_CONFIG_NAME)].as<const char*>()); haspDevice.set_hostname(settings[FP_CONFIG_NAME].as<const char*>());
} }
// Prefill node name // Prefill node name
if(strlen(haspDevice.get_hostname()) == 0) { if(strlen(haspDevice.get_hostname()) == 0) {
@ -668,36 +776,57 @@ bool mqttSetConfig(const JsonObject& settings)
changed = true; changed = true;
} }
if(!settings[FPSTR(FP_CONFIG_GROUP)].isNull()) { if(!settings[FP_CONFIG_GROUP].isNull()) {
changed |= strcmp(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)]) != 0; // changed |= strcmp(mqttGroupName, settings[FP_CONFIG_GROUP]) != 0;
strncpy(mqttGroupName, settings[FPSTR(FP_CONFIG_GROUP)], sizeof(mqttGroupName)); // strncpy(mqttGroupName, settings[FP_CONFIG_GROUP], sizeof(mqttGroupName));
changed |= nvsUpdateString(preferences, FP_CONFIG_GROUP, settings[FP_CONFIG_GROUP]);
} }
if(strlen(mqttGroupName) == 0) { // if(strlen(mqttGroupName) == 0) {
strcpy_P(mqttGroupName, PSTR("plates")); // strcpy_P(mqttGroupName, PSTR("plates"));
changed = true; // changed = true;
// }
if(!settings[FP_CONFIG_HOST].isNull()) {
// changed |= strcmp(mqttServer, settings[FP_CONFIG_HOST]) != 0;
// strncpy(mqttServer, settings[FP_CONFIG_HOST], sizeof(mqttServer));
changed |= nvsUpdateString(preferences, FP_CONFIG_HOST, settings[FP_CONFIG_HOST]);
} }
if(!settings[FPSTR(FP_CONFIG_HOST)].isNull()) { if(!settings[FP_CONFIG_USER].isNull()) {
changed |= strcmp(mqttServer, settings[FPSTR(FP_CONFIG_HOST)]) != 0; // changed |= strcmp(mqttUsername, settings[FP_CONFIG_USER]) != 0;
strncpy(mqttServer, settings[FPSTR(FP_CONFIG_HOST)], sizeof(mqttServer)); // strncpy(mqttUsername, settings[FP_CONFIG_USER], sizeof(mqttUsername));
changed |= nvsUpdateString(preferences, FP_CONFIG_USER, settings[FP_CONFIG_USER]);
} }
if(!settings[FPSTR(FP_CONFIG_USER)].isNull()) { if(!settings[FP_CONFIG_PASS].isNull() && settings[FP_CONFIG_PASS].as<String>() != String(D_PASSWORD_MASK)) {
changed |= strcmp(mqttUsername, settings[FPSTR(FP_CONFIG_USER)]) != 0; // changed |= strcmp(mqttPassword, settings[FP_CONFIG_PASS]) != 0;
strncpy(mqttUsername, settings[FPSTR(FP_CONFIG_USER)], sizeof(mqttUsername)); // strncpy(mqttPassword, settings[FP_CONFIG_PASS], sizeof(mqttPassword));
changed |= nvsUpdateString(preferences, FP_CONFIG_PASS, settings[FP_CONFIG_PASS]);
} }
if(!settings[FPSTR(FP_CONFIG_PASS)].isNull() && JsonVariant topic;
settings[FPSTR(FP_CONFIG_PASS)].as<String>() != String(FPSTR(D_PASSWORD_MASK))) { topic = settings["topic"][FP_CONFIG_NODE];
changed |= strcmp(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)]) != 0; if(topic.is<const char*>()) {
strncpy(mqttPassword, settings[FPSTR(FP_CONFIG_PASS)], sizeof(mqttPassword)); changed |= nvsUpdateString(preferences, FP_CONFIG_NODE_TOPIC, topic);
nvsUpdateString(preferences, FP_CONFIG_PASS, settings[FPSTR(FP_CONFIG_PASS)]); }
topic = settings["topic"][FP_CONFIG_GROUP];
if(topic.is<const char*>()) {
changed |= nvsUpdateString(preferences, FP_CONFIG_GROUP_TOPIC, topic);
}
topic = settings["topic"][FP_CONFIG_BROADCAST];
if(topic.is<const char*>()) {
changed |= nvsUpdateString(preferences, FP_CONFIG_BROADCAST_TOPIC, topic);
}
topic = settings["topic"][FP_CONFIG_HASS];
if(topic.is<const char*>()) {
changed |= nvsUpdateString(preferences, FP_CONFIG_HASS_TOPIC, topic);
} }
snprintf_P(mqttNodeTopic, sizeof(mqttNodeTopic), PSTR(MQTT_PREFIX "/%s/"), haspDevice.get_hostname()); // snprintf_P(mqttNodeTopic, sizeof(mqttNodeTopic), PSTR(MQTT_PREFIX "/%s/"), haspDevice.get_hostname());
snprintf_P(mqttGroupTopic, sizeof(mqttGroupTopic), PSTR(MQTT_PREFIX "/%s/"), mqttGroupName); // snprintf_P(mqttGroupTopic, sizeof(mqttGroupTopic), PSTR(MQTT_PREFIX "/%s/"), mqttGroupName);
preferences.end();
return changed; return changed;
} }
#endif // HASP_USE_CONFIG #endif // HASP_USE_CONFIG

View File

@ -1413,14 +1413,10 @@ static void http_handle_mqtt()
<h2 v-t="'mqtt.title'"></h2> <h2 v-t="'mqtt.title'"></h2>
<div class="container" v-cloak v-if="config.mqtt"> <div class="container" v-cloak v-if="config.mqtt">
<form @submit.prevent="submitOldConfig('mqtt') "> <form @submit.prevent="submitOldConfig('mqtt') ">
<div class="row"> <div class="row gap">
<div class="col-25"><label class="required" for="name" v-t="'mqtt.name'"></label></div> <div class="col-25"><label class="required" for="name" v-t="'mqtt.name'"></label></div>
<div class="col-75"><input required="" type="text" id="name" maxlength="63" pattern="[a-z0-9_]*" placeholder="Plate Name" v-model="config.mqtt.name"></div> <div class="col-75"><input required="" type="text" id="name" maxlength="63" pattern="[a-z0-9_]*" placeholder="Plate Name" v-model="config.mqtt.name"></div>
</div> </div>
<div class="row gap">
<div class="col-25"><label for="group" v-t="'mqtt.group'"></label></div>
<div class="col-75"><input type="text" id="group" maxlength="15" pattern="[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]" placeholder="Group Name" v-model="config.mqtt.group"></div>
</div>
<div class="row"> <div class="row">
<div class="col-25"><label for="host" v-t="'mqtt.host'"></label></div> <div class="col-25"><label for="host" v-t="'mqtt.host'"></label></div>
<div class="col-75"><input type="text" id="host" maxlength="127" placeholder="Server Name" v-model="config.mqtt.host"></div> <div class="col-75"><input type="text" id="host" maxlength="127" placeholder="Server Name" v-model="config.mqtt.host"></div>