From 13c1a193280652358e678ab92e13b20266ee00be Mon Sep 17 00:00:00 2001 From: Max Prokhorov Date: Tue, 3 Sep 2019 06:34:11 +0300 Subject: [PATCH] Home Assistant updates (#1885) - remove "platform" key, see #1440. this implicitly sets schema to "basic". pending some other clean-up regarding json and mqtt queueing, other schema can be added down the line - updated ws module queue elem to capture callbacks list, allows to pass more than one callback (for example, when they are generated on the fly as lambdas, see ha wsPost usage) - modified method to send ha config to use global ws queue, fix #1762 problem with empty topics and ensure json allocation is consistent. - use existing defines to set mqtt payload options. amend #1085, #1188, #1883 to use the set payload value. drop HOMEASSISTANT_PAYLOAD... defines. - update MQTT_STATUS_ONLINE/OFFLINE and RELAY_MQTT_ON/OFF with runtime configuration - filter payload strings so that the resulting yaml value is not interpreted as bool (python True, False) - helper method for settings to streamline string values manipulation --- code/espurna/config/deprecated.h | 19 ++- code/espurna/config/general.h | 22 +-- code/espurna/config/prototypes.h | 89 +++++++++--- code/espurna/homeassistant.ino | 232 +++++++++++++++++-------------- code/espurna/mqtt.ino | 34 ++++- code/espurna/relay.ino | 32 ++++- code/espurna/settings.ino | 11 ++ code/espurna/utils.ino | 4 +- code/espurna/ws.ino | 12 ++ 9 files changed, 297 insertions(+), 158 deletions(-) diff --git a/code/espurna/config/deprecated.h b/code/espurna/config/deprecated.h index 563540d3..9480a0cf 100644 --- a/code/espurna/config/deprecated.h +++ b/code/espurna/config/deprecated.h @@ -24,4 +24,21 @@ #ifdef EVENTS_PIN #warning EVENTS_PIN is deprecated! Please use EVENTS1_PIN instead #define EVENTS1_PIN EVENTS_PIN -#endif \ No newline at end of file +#endif + +// 1.13.6 unifies mqtt payload options +#ifdef HOMEASSISTANT_PAYLOAD_ON +#warning HOMEASSISTANT_PAYLOAD_ON is deprecated! Global RELAY_MQTT_ON is used instead +#endif + +#ifdef HOMEASSISTANT_PAYLOAD_OFF +#warning HOMEASSISTANT_PAYLOAD_OFF is deprecated! Global RELAY_MQTT_OFF is used instead +#endif + +#ifdef HOMEASSISTANT_PAYLOAD_AVAILABLE +#warning HOMEASSISTANT_PAYLOAD_AVAILABLE is deprecated! Global MQTT_STATUS_ONLINE is used instead +#endif + +#ifdef HOMEASSISTANT_PAYLOAD_NOT_AVAILABLE +#warning HOMEASSISTANT_PAYLOAD_NOT_AVAILABLE is deprecated! Global MQTT_STATUS_OFFLINE is used instead +#endif diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 475594be..df05143b 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -408,6 +408,7 @@ #ifndef RELAY_MQTT_ON #define RELAY_MQTT_ON "1" #endif + #ifndef RELAY_MQTT_OFF #define RELAY_MQTT_OFF "0" #endif @@ -1076,15 +1077,16 @@ #define MQTT_TOPIC_NOTIFY_TEMP_RANGE_MAX "notify_temp_range_max" +#ifndef MQTT_STATUS_ONLINE #define MQTT_STATUS_ONLINE "1" // Value for the device ON message +#endif + #ifndef MQTT_STATUS_OFFLINE #define MQTT_STATUS_OFFLINE "0" // Value for the device OFF message (will) #endif #define MQTT_ACTION_RESET "reboot" // RESET MQTT topic particle -#define MQTT_MESSAGE_ID_SHIFT 1000 // Store MQTT message id into EEPROM every these many - // Custom get and set postfixes // Use something like "/status" or "/set", with leading slash // Since 1.9.0 the default value is "" for getter and "/set" for setter @@ -1286,22 +1288,6 @@ #define HOMEASSISTANT_PREFIX "homeassistant" // Default MQTT prefix #endif -#ifndef HOMEASSISTANT_PAYLOAD_ON -#define HOMEASSISTANT_PAYLOAD_ON "1" // Payload for ON and available messages -#endif - -#ifndef HOMEASSISTANT_PAYLOAD_OFF -#define HOMEASSISTANT_PAYLOAD_OFF "0" // Payload for OFF and unavailable messages -#endif - -#ifndef HOMEASSISTANT_PAYLOAD_AVAILABLE -#define HOMEASSISTANT_PAYLOAD_AVAILABLE "1" // Payload for available messages -#endif - -#ifndef HOMEASSISTANT_PAYLOAD_NOT_AVAILABLE -#define HOMEASSISTANT_PAYLOAD_NOT_AVAILABLE "0" // Payload for available messages -#endif - // ----------------------------------------------------------------------------- // INFLUXDB // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index 7c53b3cb..72b68ddf 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -194,10 +194,28 @@ void lightChannel(unsigned char id, unsigned char value); using mqtt_callback_f = std::function; -#if MQTT_SUPPORT - void mqttRegister(mqtt_callback_f callback); - String mqttMagnitude(char * topic); -#endif +void mqttRegister(mqtt_callback_f callback); + +String mqttTopic(const char * magnitude, bool is_set); +String mqttTopic(const char * magnitude, unsigned int index, bool is_set); + +String mqttMagnitude(char * topic); + +void mqttSendRaw(const char * topic, const char * message, bool retain); +void mqttSendRaw(const char * topic, const char * message); + +void mqttSend(const char * topic, const char * message, bool force, bool retain); +void mqttSend(const char * topic, const char * message, bool force); +void mqttSend(const char * topic, const char * message); + +void mqttSend(const char * topic, unsigned int index, const char * message, bool force); +void mqttSend(const char * topic, unsigned int index, const char * message); + +const String& mqttPayloadOnline(); +const String& mqttPayloadOffline(); +const char* mqttPayloadStatus(bool status); + +void mqttSendStatus(); // ----------------------------------------------------------------------------- // OTA @@ -236,10 +254,25 @@ typedef struct { // ----------------------------------------------------------------------------- #include +bool relayStatus(unsigned char id, bool status, bool report, bool group_report); +bool relayStatus(unsigned char id, bool status); +bool relayStatus(unsigned char id); + +void relayToggle(unsigned char id, bool report, bool group_report); +void relayToggle(unsigned char id); + +unsigned char relayCount(); +unsigned char relayParsePayload(const char * payload); + +const String& relayPayloadOn(); +const String& relayPayloadOff(); +const char* relayPayload(bool status); + // ----------------------------------------------------------------------------- // Settings // ----------------------------------------------------------------------------- #include + template bool setSetting(const String& key, T value); template bool setSetting(const String& key, unsigned int index, T value); template String getSetting(const String& key, T defaultValue); @@ -247,6 +280,17 @@ template String getSetting(const String& key, unsigned int index, T void settingsGetJson(JsonObject& data); bool settingsRestoreJson(JsonObject& data); +struct settings_cfg_t { + String& setting; + const char* key; + const char* default_value; +}; + +using settings_filter_t = std::function; +using settings_cfg_list_t = std::initializer_list; + +void settingsProcessConfig(const settings_cfg_list_t& config, settings_filter_t filter = nullptr); + // ----------------------------------------------------------------------------- // Terminal // ----------------------------------------------------------------------------- @@ -302,9 +346,9 @@ struct ws_data_t; struct ws_debug_t; struct ws_callbacks_t; -using ws_on_send_callback_f = std::function; -using ws_on_action_callback_f = std::function; -using ws_on_keycheck_callback_f = std::function; +using ws_on_send_callback_f = std::function; +using ws_on_action_callback_f = std::function; +using ws_on_keycheck_callback_f = std::function; using ws_on_send_callback_list_t = std::vector; using ws_on_action_callback_list_t = std::vector; @@ -329,27 +373,28 @@ using ws_on_keycheck_callback_list_t = std::vector; ws_callbacks_t& wsRegister(); void wsSetup(); - void wsSend(uint32_t, const char*); - void wsSend(uint32_t, JsonObject&); - void wsSend(JsonObject&); - void wsSend(ws_on_send_callback_f); + void wsSend(uint32_t client_id, const char* data); + void wsSend(uint32_t client_id, JsonObject& root); + void wsSend(JsonObject& root); + void wsSend(ws_on_send_callback_f callback); - void wsSend_P(PGM_P); - void wsSend_P(uint32_t, PGM_P); + void wsSend_P(PGM_P data); + void wsSend_P(uint32_t client_id, PGM_P data); - void wsPost(const ws_on_send_callback_f&); - void wsPost(const ws_on_send_callback_list_t&); - void wsPost(uint32_t, const ws_on_send_callback_list_t&); + void wsPost(const ws_on_send_callback_f& callback); + void wsPost(const ws_on_send_callback_list_t& callbacks); + void wsPost(uint32_t client_id, const ws_on_send_callback_list_t& callbacks); - void wsPostAll(uint32_t, const ws_on_send_callback_list_t&); - void wsPostAll(const ws_on_send_callback_list_t&); + void wsPostAll(uint32_t client_id, const ws_on_send_callback_list_t& callbacks); + void wsPostAll(const ws_on_send_callback_list_t& callbacks); - void wsPostSequence(uint32_t, const ws_on_send_callback_list_t&); - void wsPostSequence(const ws_on_send_callback_list_t&); + void wsPostSequence(uint32_t client_id, const ws_on_send_callback_list_t& callbacks); + void wsPostSequence(uint32_t client_id, ws_on_send_callback_list_t&& callbacks); + void wsPostSequence(const ws_on_send_callback_list_t& callbacks); bool wsConnected(); - bool wsConnected(uint32_t); - bool wsDebugSend(const char*, const char*); + bool wsConnected(uint32_t client_id); + bool wsDebugSend(const char* prefix, const char* message); #endif // ----------------------------------------------------------------------------- diff --git a/code/espurna/homeassistant.ino b/code/espurna/homeassistant.ino index a3f2f691..d1f3bf45 100644 --- a/code/espurna/homeassistant.ino +++ b/code/espurna/homeassistant.ino @@ -9,7 +9,6 @@ Copyright (C) 2017-2019 by Xose PĂ©rez #if HOMEASSISTANT_SUPPORT #include -#include bool _haEnabled = false; bool _haSendFlag = false; @@ -18,7 +17,29 @@ bool _haSendFlag = false; // UTILS // ----------------------------------------------------------------------------- -String _haFixName(String name) { +// per yaml 1.1 spec, following scalars are converted to bool. we want the string, so quoting the output +// y|Y|yes|Yes|YES|n|N|no|No|NO |true|True|TRUE|false|False|FALSE |on|On|ON|off|Off|OFF +String _haFixPayload(const String& value) { + if (value.equalsIgnoreCase("y") + || value.equalsIgnoreCase("n") + || value.equalsIgnoreCase("yes") + || value.equalsIgnoreCase("no") + || value.equalsIgnoreCase("true") + || value.equalsIgnoreCase("false") + || value.equalsIgnoreCase("on") + || value.equalsIgnoreCase("off") + ) { + String temp; + temp.reserve(value.length() + 2); + temp = "\""; + temp += value; + temp += "\""; + return temp; + } + return value; +} + +String& _haFixName(String& name) { for (unsigned char i=0; i printer, bool wrapJson = false) { +constexpr const size_t HA_YAML_BUFFER_SIZE = 1024; - constexpr const size_t BUFFER_SIZE = 1024; +void _haSwitchYaml(unsigned char index, JsonObject& root) { String output; - output.reserve(BUFFER_SIZE + 64); - DynamicJsonBuffer jsonBuffer(BUFFER_SIZE); + output.reserve(HA_YAML_BUFFER_SIZE); - for (unsigned char i=0; i()); + } else { output += kv.value.as(); - output += "\n"; - } - output += " "; - - if (wrapJson) { - output += "\"}"; } - - jsonBuffer.clear(); - printer(output); - output = ""; - + output += "\n"; } + output += " "; - #if SENSOR_SUPPORT - - for (unsigned char i=0; i(); - value.replace("%", "'%'"); - output += kv.key; - output += ": "; - output += value; - output += "\n"; - } - output += " "; + String output; + output.reserve(HA_YAML_BUFFER_SIZE); - if (wrapJson) { - output += "\"}"; - } + JsonObject& config = root.createNestedObject("config"); + _haSendMagnitude(index, config); - jsonBuffer.clear(); - printer(output); - output = ""; + if (index == 0) output += "\n\nsensor:"; + output += "\n"; + bool first = true; + for (auto kv : config) { + if (first) { + output += " - "; + first = false; + } else { + output += " "; } + String value = kv.value.as(); + value.replace("%", "'%'"); + output += kv.key; + output += ": "; + output += value; + output += "\n"; + } + output += " "; + + root.remove("config"); + root["haConfig"] = output; - #endif } +#endif // SENSOR_SUPPORT + void _haGetDeviceConfig(JsonObject& config) { - String identifier = getIdentifier(); - - config.createNestedArray("identifiers").add(identifier); + config.createNestedArray("identifiers").add(getIdentifier()); config["name"] = getSetting("desc", getSetting("hostname")); - config["manufacturer"] = String(MANUFACTURER); - config["model"] = String(DEVICE); - config["sw_version"] = String(APP_NAME) + " " + String(APP_VERSION) + " (" + getCoreVersion() + ")"; + config["manufacturer"] = MANUFACTURER; + config["model"] = DEVICE; + config["sw_version"] = String(APP_NAME) + " " + APP_VERSION + " (" + getCoreVersion() + ")"; } void _haSend() { @@ -315,8 +318,6 @@ void _haConfigure() { #if WEB_SUPPORT -std::queue _ha_send_config; - bool _haWebSocketOnKeyCheck(const char * key, JsonVariant& value) { return (strncmp(key, "ha", 2) == 0); } @@ -332,20 +333,53 @@ void _haWebSocketOnConnected(JsonObject& root) { void _haWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) { if (strcmp(action, "haconfig") == 0) { - _ha_send_config.push(client_id); + ws_on_send_callback_list_t callbacks; + #if SENSOR_SUPPORT + callbacks.reserve(magnitudeCount() + relayCount()); + #else + callbacks.reserve(relayCount()); + #endif // SENSOR_SUPPORT + { + for (unsigned char idx=0; idx().c_str()); + } + #if SENSOR_SUPPORT + for (unsigned char idx=0; idx().c_str()); + } + #endif // SENSOR_SUPPORT DEBUG_MSG("\n"); terminalOK(); }); @@ -374,23 +408,6 @@ void _haInitCommands() { // ----------------------------------------------------------------------------- -#if WEB_SUPPORT -void _haLoop() { - if (_ha_send_config.empty()) return; - - uint32_t client_id = _ha_send_config.front(); - _ha_send_config.pop(); - - if (!wsConnected(client_id)) return; - - // TODO check wsConnected after each "printer" call? - _haDumpConfig([client_id](String& output) { - wsSend(client_id, output.c_str()); - yield(); - }, true); -} -#endif - void haSetup() { _haConfigure(); @@ -401,7 +418,6 @@ void haSetup() { .onConnected(_haWebSocketOnConnected) .onAction(_haWebSocketOnAction) .onKeyCheck(_haWebSocketOnKeyCheck); - espurnaRegisterLoop(_haLoop); #endif #if TERMINAL_SUPPORT diff --git a/code/espurna/mqtt.ino b/code/espurna/mqtt.ino index 9025d6e4..4f876581 100644 --- a/code/espurna/mqtt.ino +++ b/code/espurna/mqtt.ino @@ -74,6 +74,9 @@ String _mqtt_server; uint16_t _mqtt_port; String _mqtt_clientid; +String _mqtt_payload_online; +String _mqtt_payload_offline; + std::vector _mqtt_callbacks; struct mqtt_message_t { @@ -133,7 +136,7 @@ void _mqttSetupAsyncClient(bool secure = false) { _mqtt.setClientId(_mqtt_clientid.c_str()); _mqtt.setKeepAlive(_mqtt_keepalive); _mqtt.setCleanSession(false); - _mqtt.setWill(_mqtt_will.c_str(), _mqtt_qos, _mqtt_retain, MQTT_STATUS_OFFLINE); + _mqtt.setWill(_mqtt_will.c_str(), _mqtt_qos, _mqtt_retain, _mqtt_payload_offline.c_str()); if (_mqtt_user.length() && _mqtt_pass.length()) { DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user.c_str()); @@ -172,7 +175,7 @@ bool _mqttConnectSyncClient(bool secure = false) { #if MQTT_LIBRARY == MQTT_LIBRARY_ARDUINOMQTT _mqtt.begin(_mqtt_server.c_str(), _mqtt_port, (secure ? _mqtt_client_secure->get() : _mqtt_client)); - _mqtt.setWill(_mqtt_will.c_str(), MQTT_STATUS_OFFLINE, _mqtt_qos, _mqtt_retain); + _mqtt.setWill(_mqtt_will.c_str(), _mqtt_payload_offline.c_str(), _mqtt_qos, _mqtt_retain); result = _mqtt.connect(_mqtt_clientid.c_str(), _mqtt_user.c_str(), _mqtt_pass.c_str()); #elif MQTT_LIBRARY == MQTT_LIBRARY_PUBSUBCLIENT _mqtt.setClient(secure ? _mqtt_client_secure->get() : _mqtt_client); @@ -180,9 +183,9 @@ bool _mqttConnectSyncClient(bool secure = false) { if (_mqtt_user.length() && _mqtt_pass.length()) { DEBUG_MSG_P(PSTR("[MQTT] Connecting as user %s\n"), _mqtt_user.c_str()); - result = _mqtt.connect(_mqtt_clientid.c_str(), _mqtt_user.c_str(), _mqtt_pass.c_str(), _mqtt_will.c_str(), _mqtt_qos, _mqtt_retain, MQTT_STATUS_OFFLINE); + result = _mqtt.connect(_mqtt_clientid.c_str(), _mqtt_user.c_str(), _mqtt_pass.c_str(), _mqtt_will.c_str(), _mqtt_qos, _mqtt_retain, _mqtt_payload_offline.c_str()); } else { - result = _mqtt.connect(_mqtt_clientid.c_str(), _mqtt_will.c_str(), _mqtt_qos, _mqtt_retain, MQTT_STATUS_OFFLINE); + result = _mqtt.connect(_mqtt_clientid.c_str(), _mqtt_will.c_str(), _mqtt_qos, _mqtt_retain, _mqtt_payload_offline.c_str()); } #endif @@ -357,6 +360,13 @@ void _mqttConfigure() { _mqttApplyTopic(_mqtt_topic_json, MQTT_TOPIC_JSON); } + // Custom payload strings + settingsProcessConfig({ + {_mqtt_payload_online, "mqttPayloadOnline", MQTT_STATUS_ONLINE}, + {_mqtt_payload_offline, "mqttPayloadOffline", MQTT_STATUS_OFFLINE} + }); + + // Reset reconnect delay to reconnect sooner _mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN; } @@ -868,6 +878,22 @@ void mqttSetBrokerIfNone(IPAddress ip, unsigned int port) { if (getSetting("mqttServer", MQTT_SERVER).length() == 0) mqttSetBroker(ip, port); } +const String& mqttPayloadOnline() { + return _mqtt_payload_online; +} + +const String& mqttPayloadOffline() { + return _mqtt_payload_offline; +} + +const char* mqttPayloadStatus(bool status) { + return status ? _mqtt_payload_online.c_str() : _mqtt_payload_offline.c_str(); +} + +void mqttSendStatus() { + mqttSend(MQTT_TOPIC_STATUS, _mqtt_payload_online.c_str(), true); +} + // ----------------------------------------------------------------------------- // Initialization // ----------------------------------------------------------------------------- diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino index be477f0c..675f898e 100644 --- a/code/espurna/relay.ino +++ b/code/espurna/relay.ino @@ -44,6 +44,13 @@ std::vector _relays; bool _relayRecursive = false; Ticker _relaySaveTicker; +#if MQTT_SUPPORT + +String _relay_mqtt_payload_on; +String _relay_mqtt_payload_off; + +#endif // MQTT_SUPPORT + // ----------------------------------------------------------------------------- // RELAY PROVIDERS // ----------------------------------------------------------------------------- @@ -616,6 +623,13 @@ void _relayConfigure() { digitalWrite(_relays[i].pin, HIGH); } } + + #if MQTT_SUPPORT + settingsProcessConfig({ + {_relay_mqtt_payload_on, "relayPayloadON", RELAY_MQTT_ON}, + {_relay_mqtt_payload_off, "relayPayloadOFF", RELAY_MQTT_OFF} + }); + #endif // MQTT_SUPPORT } //------------------------------------------------------------------------------ @@ -857,6 +871,18 @@ void relaySetupAPI() { #if MQTT_SUPPORT +const String& relayPayloadOn() { + return _relay_mqtt_payload_on; +} + +const String& relayPayloadOff() { + return _relay_mqtt_payload_off; +} + +const char* relayPayload(bool status) { + return status ? _relay_mqtt_payload_on.c_str() : _relay_mqtt_payload_off.c_str(); +} + void _relayMQTTGroup(unsigned char id) { String topic = getSetting("mqttGroup", id, ""); if (!topic.length()) return; @@ -866,7 +892,7 @@ void _relayMQTTGroup(unsigned char id) { bool status = relayStatus(id); if (mode == RELAY_GROUP_SYNC_INVERSE) status = !status; - mqttSendRaw(topic.c_str(), status ? RELAY_MQTT_ON : RELAY_MQTT_OFF); + mqttSendRaw(topic.c_str(), relayPayload(status)); } void relayMQTT(unsigned char id) { @@ -876,7 +902,7 @@ void relayMQTT(unsigned char id) { // Send state topic if (_relays[id].report) { _relays[id].report = false; - mqttSend(MQTT_TOPIC_RELAY, id, _relays[id].current_status ? RELAY_MQTT_ON : RELAY_MQTT_OFF); + mqttSend(MQTT_TOPIC_RELAY, id, relayPayload(_relays[id].current_status)); } // Check group topic @@ -896,7 +922,7 @@ void relayMQTT(unsigned char id) { void relayMQTT() { for (unsigned int id=0; id < _relays.size(); id++) { - mqttSend(MQTT_TOPIC_RELAY, id, _relays[id].current_status ? RELAY_MQTT_ON : RELAY_MQTT_OFF); + mqttSend(MQTT_TOPIC_RELAY, id, relayPayload(_relays[id].current_status)); } } diff --git a/code/espurna/settings.ino b/code/espurna/settings.ino index 4cbbc5e0..0e82b4d0 100644 --- a/code/espurna/settings.ino +++ b/code/espurna/settings.ino @@ -245,6 +245,17 @@ void settingsGetJson(JsonObject& root) { } +void settingsProcessConfig(const settings_cfg_list_t& config, settings_filter_t filter) { + for (auto& entry : config) { + String value = getSetting(entry.key, entry.default_value); + if (filter) { + value = filter(value); + } + if (value.equals(entry.setting)) continue; + entry.setting = std::move(value); + } +} + // ----------------------------------------------------------------------------- // Initialization // ----------------------------------------------------------------------------- diff --git a/code/espurna/utils.ino b/code/espurna/utils.ino index efbe9ce9..e95d7d75 100644 --- a/code/espurna/utils.ino +++ b/code/espurna/utils.ino @@ -272,7 +272,7 @@ void heartbeat() { mqttSend(MQTT_TOPIC_VCC, String(ESP.getVcc()).c_str()); if (hb_cfg & Heartbeat::Status) - mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); + mqttSendStatus(); if (hb_cfg & Heartbeat::Loadavg) mqttSend(MQTT_TOPIC_LOADAVG, String(systemLoadAverage()).c_str()); @@ -291,7 +291,7 @@ void heartbeat() { #endif } else if (!serial && _heartbeat_mode == HEARTBEAT_REPEAT_STATUS) { - mqttSend(MQTT_TOPIC_STATUS, MQTT_STATUS_ONLINE, true); + mqttSendStatus(); } #endif diff --git a/code/espurna/ws.ino b/code/espurna/ws.ino index 790ed31a..b9780c80 100644 --- a/code/espurna/ws.ino +++ b/code/espurna/ws.ino @@ -91,6 +91,14 @@ struct ws_data_t { counter(0, 1) {} + ws_data_t(const uint32_t client_id, ws_on_send_callback_list_t&& callbacks, mode_t mode = SEQUENCE) : + storage(new ws_on_send_callback_list_t(std::move(callbacks))), + client_id(client_id), + mode(mode), + callbacks(*storage.get()), + counter(0, (storage.get())->size()) + {} + ws_data_t(const uint32_t client_id, const ws_on_send_callback_list_t& callbacks, mode_t mode = SEQUENCE) : client_id(client_id), mode(mode), @@ -764,6 +772,10 @@ void wsPostSequence(uint32_t client_id, const ws_on_send_callback_list_t& cbs) { _ws_client_data.emplace(client_id, cbs, ws_data_t::SEQUENCE); } +void wsPostSequence(uint32_t client_id, ws_on_send_callback_list_t&& cbs) { + _ws_client_data.emplace(client_id, std::forward(cbs), ws_data_t::SEQUENCE); +} + void wsPostSequence(const ws_on_send_callback_list_t& cbs) { _ws_client_data.emplace(0, cbs, ws_data_t::SEQUENCE); }