fixed climate card mqtt crash bug

This commit is contained in:
Siwat Sirichai 2023-12-31 23:29:40 +07:00
parent 9cd5b7132b
commit 4c77474a94
8 changed files with 128 additions and 50 deletions

View file

@ -3,7 +3,7 @@
ESPMegaIoT::ESPMegaIoT() : mqtt(tcpClient)
{
tcpClient.setTimeout(1);
tcpClient.setTimeout(TCP_TIMEOUT_SEC);
// Initialize the components array
for (int i = 0; i < 255; i++)
{
@ -11,9 +11,6 @@ ESPMegaIoT::ESPMegaIoT() : mqtt(tcpClient)
}
active = false;
mqtt_connected = false;
this->user_mqtt_callback = nullptr;
this->user_relative_mqtt_callback = nullptr;
this->user_subscribe_callback = nullptr;
}
ESPMegaIoT::~ESPMegaIoT()
@ -26,14 +23,14 @@ void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length)
memcpy(payload_buffer, payload, length);
payload_buffer[length] = '\0';
// Remove the base topic from the topic
char *topic_without_base = topic + strlen(base_topic) + 1;
if (user_relative_mqtt_callback != NULL)
char *topic_without_base = topic + strlen(this->mqtt_config.base_topic) + 1;
for (const auto &callback : mqtt_relative_callbacks)
{
user_relative_mqtt_callback(topic_without_base + 3, payload_buffer);
callback.second(topic_without_base + 3, payload_buffer);
}
if (user_mqtt_callback != NULL)
for (const auto &callback : mqtt_callbacks)
{
user_mqtt_callback(topic, payload_buffer);
callback.second(topic, payload_buffer);
}
// Call the respective card's mqtt callback
// Note that after the base topic, there should be the card id
@ -51,8 +48,8 @@ void ESPMegaIoT::mqttCallback(char *topic, byte *payload, unsigned int length)
void ESPMegaIoT::setBaseTopic(char *base_topic)
{
strcpy(this->base_topic, base_topic);
base_topic_length = strlen(base_topic);
strcpy(this->mqtt_config.base_topic, base_topic);
base_topic_length = strlen(this->mqtt_config.base_topic);
}
void ESPMegaIoT::intr_begin(ExpansionCard *cards[])
@ -91,7 +88,7 @@ void ESPMegaIoT::registerCard(uint8_t card_id)
{
case CARD_TYPE_ANALOG:
components[card_id] = new AnalogIoT();
components[card_id]->begin(card_id, cards[card_id], &mqtt, base_topic);
components[card_id]->begin(card_id, cards[card_id], &mqtt, this->mqtt_config.base_topic);
if (mqtt_connected)
{
components[card_id]->subscribe();
@ -100,16 +97,22 @@ void ESPMegaIoT::registerCard(uint8_t card_id)
break;
case CARD_TYPE_DIGITAL_INPUT:
components[card_id] = new DigitalInputIoT();
components[card_id]->begin(card_id, cards[card_id], &mqtt, base_topic);
components[card_id]->begin(card_id, cards[card_id], &mqtt, this->mqtt_config.base_topic);
if (mqtt_connected)
{
Serial.println("Subscribing to Input Topics");
components[card_id]->subscribe();
mqtt.loop();
Serial.println(mqtt.connected()? "MQTT Connected" : "MQTT Not Connected");
Serial.println("Publishing Input report");
components[card_id]->publishReport();
mqtt.loop();
Serial.println(mqtt.connected()? "MQTT Connected" : "MQTT Not Connected");
}
break;
case CARD_TYPE_DIGITAL_OUTPUT:
components[card_id] = new DigitalOutputIoT();
components[card_id]->begin(card_id, cards[card_id], &mqtt, base_topic);
components[card_id]->begin(card_id, cards[card_id], &mqtt, this->mqtt_config.base_topic);
if (mqtt_connected)
{
components[card_id]->subscribe();
@ -118,7 +121,7 @@ void ESPMegaIoT::registerCard(uint8_t card_id)
break;
case CARD_TYPE_CLIMATE:
components[card_id] = new ClimateIoT();
components[card_id]->begin(card_id, cards[card_id], &mqtt, base_topic);
components[card_id]->begin(card_id, cards[card_id], &mqtt, this->mqtt_config.base_topic);
if (mqtt_connected)
{
components[card_id]->subscribe();
@ -238,27 +241,33 @@ void ESPMegaIoT::disconnectFromMqtt()
{
mqtt.disconnect();
}
void ESPMegaIoT::publishToTopic(char *topic, char *payload)
void ESPMegaIoT::publish(const char *topic, const char *payload)
{
mqtt.publish(topic, payload);
}
void ESPMegaIoT::registerMqttCallback(void (*callback)(char *, char *))
uint8_t ESPMegaIoT::registerMqttCallback(std::function<void(char *, char *)> callback)
{
user_mqtt_callback = callback;
mqtt_callbacks[mqtt_callbacks_handler_index] = callback;
return mqtt_callbacks_handler_index++;
}
void ESPMegaIoT::unregisterMqttCallback(uint8_t handler)
{
mqtt_callbacks.erase(handler);
}
void ESPMegaIoT::mqttSubscribe()
{
ESP_LOGD("ESPMegaIoT", "Begin MQTT Subscription");
if (user_subscribe_callback != nullptr)
for (const auto &callback : subscribe_callbacks)
{
ESP_LOGD("ESPMegaIoT", "Subscribing user callback");
user_subscribe_callback();
callback.second();
mqtt.loop();
}
// Subscribe to all topics
for (int i = 0; i < 255; i++)
{
ESP_LOGV("ESPMegaIoT","Scanning component %d", i);
if (components[i] != NULL)
{
ESP_LOGD("ESPMegaIoT","Subscribing component %d", i);
@ -271,7 +280,7 @@ void ESPMegaIoT::mqttSubscribe()
void ESPMegaIoT::publishRelative(uint8_t card_id, char *topic, char *payload)
{
char absolute_topic[100];
sprintf(absolute_topic, "%s/%d/%s", base_topic, card_id, topic);
sprintf(absolute_topic, "%s/%d/%s", this->mqtt_config.base_topic, card_id, topic);
mqtt.publish(absolute_topic, payload);
}
@ -289,28 +298,45 @@ bool ESPMegaIoT::mqttReconnect()
void ESPMegaIoT::sessionKeepAlive()
{
// This reconnect the MQTT if it disconnect.
// If a disconnect happens, this will reconnect the MQTT within 1 second.
// A connection attempt will be made at most once every MQTT_RECONNECT_INTERVAL
// This have the effect of reconnecting to the server immediately if the connection is lost
// and the connection was previously stable for at least MQTT_RECONNECT_INTERVAL
// But will not reconnect if the connection was unstable and the connection was lost
static unsigned long lastSessionKeepAlive = 0;
if (millis() - lastSessionKeepAlive > 30000)
static unsigned long lastConnectionAttempt = 0;
if (millis() - lastSessionKeepAlive > 1000)
{
lastSessionKeepAlive = millis();
// Check if mqtt is connected
if (!mqtt.connected())
{
// Try to reconnect
mqtt_connected = mqttReconnect();
// Try to reconnect if lastConnectionAttempt exceed MQTT_RECONNECT_INTERVAL
if (millis() - lastConnectionAttempt > MQTT_RECONNECT_INTERVAL)
{
lastConnectionAttempt = millis();
mqtt_connected = mqttReconnect();
}
}
}
}
void ESPMegaIoT::registerRelativeMqttCallback(void (*callback)(char *, char *))
uint8_t ESPMegaIoT::registerRelativeMqttCallback(std::function<void(char *, char *)> callback)
{
user_relative_mqtt_callback = callback;
mqtt_relative_callbacks[mqtt_relative_callbacks_handler_index] = callback;
return mqtt_relative_callbacks_handler_index++;
}
void ESPMegaIoT::unregisterRelativeMqttCallback(uint8_t handler)
{
mqtt_relative_callbacks.erase(handler);
}
void ESPMegaIoT::publishRelative(char *topic, char *payload)
{
char absolute_topic[100];
sprintf(absolute_topic, "%s/%s", base_topic, topic);
sprintf(absolute_topic, "%s/%s", this->mqtt_config.base_topic, topic);
mqtt.publish(absolute_topic, payload);
mqtt.loop();
}
@ -318,14 +344,20 @@ void ESPMegaIoT::publishRelative(char *topic, char *payload)
void ESPMegaIoT::subscribeRelative(char *topic)
{
char absolute_topic[100];
sprintf(absolute_topic, "%s/%s", base_topic, topic);
sprintf(absolute_topic, "%s/%s", this->mqtt_config.base_topic, topic);
mqtt.subscribe(absolute_topic);
mqtt.loop();
}
void ESPMegaIoT::registerSubscribeCallback(void (*callback)(void))
uint8_t ESPMegaIoT::registerSubscribeCallback(std::function<void(void)> callback)
{
user_subscribe_callback = callback;
subscribe_callbacks[subscribe_callbacks_handler_index] = callback;
return subscribe_callbacks_handler_index++;
}
void ESPMegaIoT::unregisterSubscribeCallback(uint8_t handler)
{
subscribe_callbacks.erase(handler);
}
void ESPMegaIoT::setNetworkConfig(NetworkConfig network_config)
@ -380,6 +412,7 @@ void ESPMegaIoT::loadMqttConfig()
fram->read(IOT_FRAM_ADDRESS + 194, (uint8_t *)mqtt_config.mqtt_password, 32);
mqtt_config.mqtt_useauth = fram->read8(IOT_FRAM_ADDRESS + 226);
fram->read(IOT_FRAM_ADDRESS + 227, (uint8_t *)mqtt_config.base_topic, 32);
this->base_topic_length = strlen(mqtt_config.base_topic);
}
void ESPMegaIoT::saveMqttConfig()
@ -430,6 +463,7 @@ void ESPMegaIoT::connectNetwork()
void ESPMegaIoT::setMqttConfig(MqttConfig mqtt_config)
{
this->mqtt_config = mqtt_config;
this->base_topic_length = strlen(mqtt_config.base_topic);
}
void ESPMegaIoT::bindEthernetInterface(ETHClass *ethernetIface)