add option for MQTT retain flag - #507

This commit is contained in:
proddy
2020-09-17 21:12:30 +02:00
parent 7ed41147d3
commit 0d66d97fd2
11 changed files with 71 additions and 21 deletions

View File

@@ -12,12 +12,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- add boiler wWType - add boiler wWType
- support for uploading compressed firmware binaries - support for uploading compressed firmware binaries
- add wWType to MQTT publish - add wWType to MQTT publish
- option to set the MQTT retain flag
### Fixed ### Fixed
- fix wwontime readback - fix wwontime readback
- fixed support for RC300 via MQTT commands (#505)
### Changed ### Changed
- renamed wWCircPumpType to wWChargeType - renamed wWCircPumpType to wWChargeType
- Installation doc moved to wiki
### Removed ### Removed
- -

View File

@@ -149,6 +149,16 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
<MenuItem value={1}>1</MenuItem> <MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem> <MenuItem value={2}>2</MenuItem>
</SelectValidator> </SelectValidator>
<BlockFormControlLabel
control={
<Checkbox
checked={data.mqtt_retain}
onChange={handleValueChange('mqtt_retain')}
value="mqtt_retain"
/>
}
label="Retain Flag"
/>
<Typography variant="h6" color="primary" > <Typography variant="h6" color="primary" >
Publish Intervals Publish Intervals
</Typography> </Typography>

View File

@@ -35,5 +35,6 @@ export interface MqttSettings {
publish_time_sensor: number; publish_time_sensor: number;
mqtt_format: number; mqtt_format: number;
mqtt_qos: number; mqtt_qos: number;
mqtt_retain: boolean;
system_heartbeat: boolean; system_heartbeat: boolean;
} }

View File

@@ -193,6 +193,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
root["publish_time_sensor"] = settings.publish_time_sensor; root["publish_time_sensor"] = settings.publish_time_sensor;
root["mqtt_format"] = settings.mqtt_format; root["mqtt_format"] = settings.mqtt_format;
root["mqtt_qos"] = settings.mqtt_qos; root["mqtt_qos"] = settings.mqtt_qos;
root["mqtt_retain"] = settings.mqtt_retain;
} }
StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) { StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) {
@@ -217,6 +218,7 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME; newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.mqtt_format = root["mqtt_format"] | EMSESP_DEFAULT_MQTT_FORMAT; newSettings.mqtt_format = root["mqtt_format"] | EMSESP_DEFAULT_MQTT_FORMAT;
newSettings.mqtt_qos = root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS; newSettings.mqtt_qos = root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS;
newSettings.mqtt_retain = root["mqtt_retain"] | EMSESP_DEFAULT_MQTT_RETAIN;
if (newSettings.system_heartbeat != settings.system_heartbeat) { if (newSettings.system_heartbeat != settings.system_heartbeat) {
emsesp::EMSESP::system_.set_heartbeat(newSettings.system_heartbeat); emsesp::EMSESP::system_.set_heartbeat(newSettings.system_heartbeat);
@@ -226,6 +228,10 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos); emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
} }
if (newSettings.mqtt_retain != settings.mqtt_retain) {
emsesp::EMSESP::mqtt_.set_retain(newSettings.mqtt_retain);
}
if (newSettings.publish_time_boiler != settings.publish_time_boiler) { if (newSettings.publish_time_boiler != settings.publish_time_boiler) {
emsesp::EMSESP::mqtt_.set_publish_time_boiler(newSettings.publish_time_boiler); emsesp::EMSESP::mqtt_.set_publish_time_boiler(newSettings.publish_time_boiler);
} }

View File

@@ -63,9 +63,9 @@ static String generateClientId() {
#define EMSESP_DEFAULT_SYSTEM_HEARTBEAT true #define EMSESP_DEFAULT_SYSTEM_HEARTBEAT true
#define EMSESP_DEFAULT_MQTT_FORMAT 2 // nested #define EMSESP_DEFAULT_MQTT_FORMAT 2 // nested
#define EMSESP_DEFAULT_MQTT_QOS 0 #define EMSESP_DEFAULT_MQTT_QOS 0
#define EMSESP_DEFAULT_MQTT_RETAIN false
#define EMSESP_DEFAULT_PUBLISH_TIME 10 #define EMSESP_DEFAULT_PUBLISH_TIME 10
class MqttSettings { class MqttSettings {
public: public:
// host and port - if enabled // host and port - if enabled
@@ -95,6 +95,7 @@ class MqttSettings {
uint8_t mqtt_format; // 1=single, 2=nested, 3=ha, 4=custom uint8_t mqtt_format; // 1=single, 2=nested, 3=ha, 4=custom
uint8_t mqtt_qos; uint8_t mqtt_qos;
bool system_heartbeat; bool system_heartbeat;
bool mqtt_retain;
static void read(MqttSettings & settings, JsonObject & root); static void read(MqttSettings & settings, JsonObject & root);
static StateUpdateResult update(JsonObject & root, MqttSettings & settings); static StateUpdateResult update(JsonObject & root, MqttSettings & settings);

View File

@@ -26,6 +26,7 @@ class DummySettings {
uint16_t publish_time = 10; // seconds uint16_t publish_time = 10; // seconds
uint8_t mqtt_format = 3; // 1=single, 2=nested, 3=ha, 4=custom uint8_t mqtt_format = 3; // 1=single, 2=nested, 3=ha, 4=custom
uint8_t mqtt_qos = 0; uint8_t mqtt_qos = 0;
bool mqtt_retain = false;
String hostname = "ems-esp"; String hostname = "ems-esp";
String jwtSecret = "ems-esp"; String jwtSecret = "ems-esp";
String ssid = "ems-esp"; String ssid = "ems-esp";

View File

@@ -600,7 +600,7 @@ void Thermostat::register_mqtt_ha_config(uint8_t hc_num) {
std::string topic(100, '\0'); // e.g homeassistant/climate/hc1/thermostat/config std::string topic(100, '\0'); // e.g homeassistant/climate/hc1/thermostat/config
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/config"), hc_num); snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/config"), hc_num);
// Mqtt::publish(topic); // empty payload, this remove any previous config sent to HA // Mqtt::publish(topic); // empty payload, this remove any previous config sent to HA
Mqtt::publish(topic, doc, true); // publish the config payload with retain flag Mqtt::publish_retain(topic, doc, true); // publish the config payload with retain flag
// subscribe to the temp and mode commands // subscribe to the temp and mode commands
snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/cmd_temp"), hc_num); snprintf_P(&topic[0], topic.capacity() + 1, PSTR("homeassistant/climate/ems-esp/hc%d/cmd_temp"), hc_num);

View File

@@ -27,6 +27,7 @@ AsyncMqttClient * Mqtt::mqttClient_;
// static parameters we make global // static parameters we make global
std::string Mqtt::hostname_; std::string Mqtt::hostname_;
uint8_t Mqtt::mqtt_qos_; uint8_t Mqtt::mqtt_qos_;
bool Mqtt::mqtt_retain_;
uint8_t Mqtt::bus_id_; uint8_t Mqtt::bus_id_;
uint32_t Mqtt::publish_time_boiler_; uint32_t Mqtt::publish_time_boiler_;
uint32_t Mqtt::publish_time_thermostat_; uint32_t Mqtt::publish_time_thermostat_;
@@ -373,6 +374,7 @@ void Mqtt::start() {
publish_time_other_ = mqttSettings.publish_time_other * 1000; publish_time_other_ = mqttSettings.publish_time_other * 1000;
publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000; publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000;
mqtt_qos_ = mqttSettings.mqtt_qos; mqtt_qos_ = mqttSettings.mqtt_qos;
mqtt_retain_ = mqttSettings.mqtt_retain;
}); });
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { bus_id_ = settings.ems_bus_id; }); EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { bus_id_ = settings.ems_bus_id; });
@@ -470,6 +472,10 @@ void Mqtt::set_qos(uint8_t mqtt_qos) {
mqtt_qos_ = mqtt_qos; mqtt_qos_ = mqtt_qos;
} }
void Mqtt::set_retain(bool mqtt_retain) {
mqtt_retain_ = mqtt_retain;
}
// MQTT onConnect - when a connect is established // MQTT onConnect - when a connect is established
void Mqtt::on_connect() { void Mqtt::on_connect() {
// send info topic appended with the version information as JSON // send info topic appended with the version information as JSON
@@ -479,9 +485,9 @@ void Mqtt::on_connect() {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
doc["ip"] = WiFi.localIP().toString(); doc["ip"] = WiFi.localIP().toString();
#endif #endif
publish(F("info"), doc, false); // send with retain off publish(F("info"), doc);
publish(F("status"), "online", true); // say we're alive to the Last Will topic, with retain on publish_retain(F("status"), "online", true); // say we're alive to the Last Will topic, with retain on
reset_publish_fails(); // reset fail count to 0 reset_publish_fails(); // reset fail count to 0
@@ -533,30 +539,46 @@ std::shared_ptr<const MqttMessage> Mqtt::queue_subscribe_message(const std::stri
return queue_message(Operation::SUBSCRIBE, topic, "", false); // no payload return queue_message(Operation::SUBSCRIBE, topic, "", false); // no payload
} }
// MQTT Publish, using a specific retain flag // MQTT Publish, using a user's retain flag
void Mqtt::publish(const std::string & topic, const std::string & payload, bool retain) { void Mqtt::publish(const std::string & topic, const std::string & payload) {
queue_publish_message(topic, payload, retain); queue_publish_message(topic, payload, mqtt_retain_);
} }
// MQTT Publish, using a specific retain flag, topic is a flash string // MQTT Publish, using a specific retain flag, topic is a flash string
void Mqtt::publish(const __FlashStringHelper * topic, const std::string & payload, bool retain) { void Mqtt::publish(const __FlashStringHelper * topic, const std::string & payload) {
queue_publish_message(uuid::read_flash_string(topic), payload, mqtt_retain_);
}
void Mqtt::publish(const __FlashStringHelper * topic, const JsonDocument & payload) {
publish(uuid::read_flash_string(topic), payload);
}
// MQTT Publish, using a specific retain flag, topic is a flash string, forcing retain flag
void Mqtt::publish_retain(const __FlashStringHelper * topic, const std::string & payload, bool retain) {
queue_publish_message(uuid::read_flash_string(topic), payload, retain); queue_publish_message(uuid::read_flash_string(topic), payload, retain);
} }
void Mqtt::publish(const __FlashStringHelper * topic, const JsonDocument & payload, bool retain) { void Mqtt::publish_retain(const std::string & topic, const JsonDocument & payload, bool retain) {
publish(uuid::read_flash_string(topic), payload, retain);
}
void Mqtt::publish(const std::string & topic, const JsonDocument & payload, bool retain) {
std::string payload_text; std::string payload_text;
serializeJson(payload, payload_text); // convert json to string serializeJson(payload, payload_text); // convert json to string
queue_publish_message(topic, payload_text, retain); queue_publish_message(topic, payload_text, retain);
} }
void Mqtt::publish_retain(const __FlashStringHelper * topic, const JsonDocument & payload, bool retain) {
publish_retain(uuid::read_flash_string(topic), payload, retain);
}
void Mqtt::publish(const std::string & topic, const JsonDocument & payload) {
std::string payload_text;
serializeJson(payload, payload_text); // convert json to string
queue_publish_message(topic, payload_text, mqtt_retain_);
}
// for booleans, which get converted to string values 1 and 0 // for booleans, which get converted to string values 1 and 0
void Mqtt::publish(const std::string & topic, const bool value) { void Mqtt::publish(const std::string & topic, const bool value) {
queue_publish_message(topic, value ? "1" : "0", false); queue_publish_message(topic, value ? "1" : "0", false);
} }
void Mqtt::publish(const __FlashStringHelper * topic, const bool value) { void Mqtt::publish(const __FlashStringHelper * topic, const bool value) {
queue_publish_message(uuid::read_flash_string(topic), value ? "1" : "0", false); queue_publish_message(uuid::read_flash_string(topic), value ? "1" : "0", false);
} }

View File

@@ -74,6 +74,7 @@ class Mqtt {
void set_publish_time_other(uint16_t publish_time); void set_publish_time_other(uint16_t publish_time);
void set_publish_time_sensor(uint16_t publish_time); void set_publish_time_sensor(uint16_t publish_time);
void set_qos(uint8_t mqtt_qos); void set_qos(uint8_t mqtt_qos);
void set_retain(bool mqtt_retain);
bool get_publish_onchange(uint8_t device_type); bool get_publish_onchange(uint8_t device_type);
enum Operation { PUBLISH, SUBSCRIBE }; enum Operation { PUBLISH, SUBSCRIBE };
@@ -86,14 +87,18 @@ class Mqtt {
static void add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb); static void add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb);
static void publish(const std::string & topic, const std::string & payload, bool retain = false); static void publish(const std::string & topic, const std::string & payload);
static void publish(const std::string & topic, const JsonDocument & payload, bool retain = false); static void publish(const std::string & topic, const JsonDocument & payload);
static void publish(const __FlashStringHelper * topic, const JsonDocument & payload, bool retain = false); static void publish(const __FlashStringHelper * topic, const JsonDocument & payload);
static void publish(const __FlashStringHelper * topic, const std::string & payload, bool retain = false); static void publish(const __FlashStringHelper * topic, const std::string & payload);
static void publish(const std::string & topic, const bool value); static void publish(const std::string & topic, const bool value);
static void publish(const __FlashStringHelper * topi, const bool value); static void publish(const __FlashStringHelper * topi, const bool value);
static void publish(const std::string & topic); static void publish(const std::string & topic);
static void publish_retain(const std::string & topic, const JsonDocument & payload, bool retain);
static void publish_retain(const __FlashStringHelper * topic, const std::string & payload, bool retain);
static void publish_retain(const __FlashStringHelper * topic, const JsonDocument & payload, bool retain);
static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type); static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type);
static void show_mqtt(uuid::console::Shell & shell); static void show_mqtt(uuid::console::Shell & shell);
@@ -163,7 +168,6 @@ class Mqtt {
static size_t maximum_mqtt_messages_; static size_t maximum_mqtt_messages_;
static uint16_t mqtt_message_id_; static uint16_t mqtt_message_id_;
static bool mqtt_retain_;
static constexpr size_t MAX_MQTT_MESSAGES = 20; // size of queue static constexpr size_t MAX_MQTT_MESSAGES = 20; // size of queue
static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads static constexpr uint32_t MQTT_PUBLISH_WAIT = 200; // delay between sending publishes, to account for large payloads
@@ -208,6 +212,7 @@ class Mqtt {
// settings, copied over // settings, copied over
static std::string hostname_; static std::string hostname_;
static uint8_t mqtt_qos_; static uint8_t mqtt_qos_;
static bool mqtt_retain_;
static uint32_t publish_time_; static uint32_t publish_time_;
static uint8_t bus_id_; static uint8_t bus_id_;
static uint32_t publish_time_boiler_; static uint32_t publish_time_boiler_;

View File

@@ -342,7 +342,7 @@ void Sensors::publish_values() {
config["uniq_id"] = str; config["uniq_id"] = str;
snprintf_P(&topic[0], 50, PSTR("homeassistant/sensor/ems-esp/sensor%d/config"), i); snprintf_P(&topic[0], 50, PSTR("homeassistant/sensor/ems-esp/sensor%d/config"), i);
Mqtt::publish(topic, config, false); // publish the config payload with no retain flag Mqtt::publish_retain(topic, config, false); // publish the config payload with no retain flag
registered_ha_[i] = true; registered_ha_[i] = true;
} }

View File

@@ -237,7 +237,7 @@ void System::send_heartbeat() {
doc["rxfails"] = EMSESP::rxservice_.telegram_error_count(); doc["rxfails"] = EMSESP::rxservice_.telegram_error_count();
doc["adc"] = analog_; //analogRead(A0); doc["adc"] = analog_; //analogRead(A0);
Mqtt::publish(F("heartbeat"), doc, false); // send to MQTT with retain off. This will add to MQTT queue. Mqtt::publish_retain(F("heartbeat"), doc, false); // send to MQTT with retain off. This will add to MQTT queue.
} }
// measure and moving average adc // measure and moving average adc
@@ -726,6 +726,7 @@ bool System::check_upgrade() {
mqttSettings.host = mqtt["ip"] | FACTORY_MQTT_HOST; mqttSettings.host = mqtt["ip"] | FACTORY_MQTT_HOST;
mqttSettings.mqtt_format = (mqtt["nestedjson"] ? MQTT_format::NESTED : MQTT_format::SINGLE); mqttSettings.mqtt_format = (mqtt["nestedjson"] ? MQTT_format::NESTED : MQTT_format::SINGLE);
mqttSettings.mqtt_qos = mqtt["qos"] | 0; mqttSettings.mqtt_qos = mqtt["qos"] | 0;
mqttSettings.mqtt_retain = mqtt["retain"];
mqttSettings.username = mqtt["user"] | ""; mqttSettings.username = mqtt["user"] | "";
mqttSettings.password = mqtt["password"] | ""; mqttSettings.password = mqtt["password"] | "";
mqttSettings.port = mqtt["port"] | FACTORY_MQTT_PORT; mqttSettings.port = mqtt["port"] | FACTORY_MQTT_PORT;