From 78b4007f01e8df9334d16e9550a03443527176f2 Mon Sep 17 00:00:00 2001 From: Maxim Prokhorov Date: Tue, 9 Mar 2021 12:37:16 +0300 Subject: [PATCH] system: use direct status updates instead of broker Get rid of status & config brokers, register status callbacks directly with the module. --- code/espurna/alexa.cpp | 180 ++++++++++++++++++++++-------------- code/espurna/domoticz.cpp | 41 +++----- code/espurna/influxdb.cpp | 10 +- code/espurna/led.cpp | 16 +--- code/espurna/light.cpp | 29 +----- code/espurna/relay.cpp | 105 ++++++++++----------- code/espurna/relay.h | 4 +- code/espurna/rpc.cpp | 2 - code/espurna/rpc.h | 4 - code/espurna/rpnrules.cpp | 42 +++++---- code/espurna/settings.cpp | 2 - code/espurna/settings.h | 3 - code/espurna/thingspeak.cpp | 16 +--- code/espurna/utils.cpp | 55 +++++++---- code/espurna/utils.h | 2 +- 15 files changed, 259 insertions(+), 252 deletions(-) diff --git a/code/espurna/alexa.cpp b/code/espurna/alexa.cpp index 82f0f4b5..afde4d21 100644 --- a/code/espurna/alexa.cpp +++ b/code/espurna/alexa.cpp @@ -13,7 +13,6 @@ Copyright (C) 2016-2019 by Xose Pérez #include #include "api.h" -#include "broker.h" #include "light.h" #include "mqtt.h" #include "relay.h" @@ -24,16 +23,40 @@ Copyright (C) 2016-2019 by Xose Pérez #include #include -struct alexa_queue_element_t { - unsigned char device_id; - bool state; - unsigned char value; +namespace { + +struct AlexaEvent { + AlexaEvent() = delete; + AlexaEvent(unsigned char id, bool state, unsigned char value) : + _id(id), + _state(state), + _value(value) + {} + + unsigned char id() const { + return _id; + } + + unsigned char value() const { + return _value; + } + + bool state() const { + return _state; + } + +private: + unsigned char _id; + bool _state; + unsigned char _value; }; -static std::queue _alexa_queue; +std::queue _alexa_events; fauxmoESP _alexa; +} // namespace + // ----------------------------------------------------------------------------- // ALEXA // ----------------------------------------------------------------------------- @@ -62,25 +85,27 @@ void _alexaConfigure() { } #endif -void _alexaBrokerCallback(const String& topic, unsigned char id, unsigned int value) { - - // Only process status messages for switches and channels - if (!topic.equals(MQTT_TOPIC_CHANNEL) - && !topic.equals(MQTT_TOPIC_RELAY)) { - return; - } +#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - if (topic.equals(MQTT_TOPIC_CHANNEL)) { - _alexa.setState(id + 1, value > 0, value); - } +void _alexaUpdateLights() { + _alexa.setState(static_cast(0u), lightState(), lightState() ? 255u : 0u); - if (topic.equals(MQTT_TOPIC_RELAY)) { - if (id > 0) return; - _alexa.setState(id, value, value > 0 ? 255 : 0); + auto channels = lightChannels(); + for (decltype(channels) channel = 0; channel < channels; ++channel) { + auto value = lightChannel(channel); + _alexa.setState(channel + 1, value > 0, value); } +} + +#endif +#if RELAY_SUPPORT + +void _alexaUpdateRelay(size_t id, bool status) { + _alexa.setState(id, status, status ? 255 : 0); } +#endif // ----------------------------------------------------------------------------- bool alexaEnabled() { @@ -91,67 +116,83 @@ void alexaLoop() { _alexa.handle(); - while (!_alexa_queue.empty()) { + while (!_alexa_events.empty()) { + auto& event = _alexa_events.front(); + DEBUG_MSG_P(PSTR("[ALEXA] Device #%hhu state=#%s value=%hhu\n"), + event.id(), event.state() ? 't' : 'f', event.value()); - alexa_queue_element_t element = _alexa_queue.front(); - DEBUG_MSG_P(PSTR("[ALEXA] Device #%u state: %s value: %d\n"), element.device_id, element.state ? "ON" : "OFF", element.value); - - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - if (0 == element.device_id) { - lightState(element.state); - } else { - lightState(element.device_id - 1, element.state); - lightChannel(element.device_id - 1, element.value); - lightUpdate(); - } - #else - relayStatus(element.device_id, element.state); - #endif +#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + if (0 == event.id()) { + lightState(event.state()); + } else { + lightState(event.id() - 1, event.state()); + lightChannel(event.id() - 1, event.value()); + lightUpdate(); + } +#else + relayStatus(event.id(), event.state()); +#endif - _alexa_queue.pop(); + _alexa_events.pop(); } } -void alexaSetup() { +constexpr bool _alexaCreateServer() { + return !WEB_SUPPORT; +} + +constexpr const char* _alexaHostname() { + return ALEXA_HOSTNAME; +} + +void _alexaSettingsMigrate(int version) { + if (version && (version < 3)) { + moveSetting("fauxmoEnabled", "alexaEnabled"); + } +} + +void alexaSetup() { // Backwards compatibility - moveSetting("fauxmoEnabled", "alexaEnabled"); + _alexaSettingsMigrate(migrateVersion()); // Basic fauxmoESP configuration - _alexa.createServer(!WEB_SUPPORT); + _alexa.createServer(_alexaCreateServer()); _alexa.setPort(80); // Use custom alexa hostname if defined, device hostname otherwise - String hostname = getSetting("alexaName", ALEXA_HOSTNAME); - if (hostname.length() == 0) { - hostname = getSetting("hostname"); + String hostname = getSetting("alexaName", _alexaHostname()); + if (!hostname.length()) { + hostname = getSetting("hostname", getIdentifier()); } - // Lights - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - - // Global switch - _alexa.addDevice(hostname.c_str()); - - // For each channel - for (unsigned char i = 1; i <= lightChannels(); i++) { - _alexa.addDevice((hostname + " " + i).c_str()); - } - - // Relays - #else + auto deviceName = [&](size_t index) { + auto name = hostname; + name += ' '; + name += index; + return name; + }; + +#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + // 1st is the global state, the rest are mapped to channel values + _alexa.addDevice(hostname.c_str()); + for (size_t channel = 1; channel <= lightChannels(); ++channel) { + _alexa.addDevice(deviceName(channel).c_str()); + } - unsigned int relays = relayCount(); - if (relays == 1) { - _alexa.addDevice(hostname.c_str()); - } else { - for (unsigned int i=1; i<=relays; i++) { - _alexa.addDevice((hostname + " " + i).c_str()); - } + // Relays are mapped 1-to-1 +#elif RELAY_SUPPORT + auto relays = relayCount(); + if (relays > 1) { + for (decltype(relays) id = 1; id <= relays; ++id) { + _alexa.addDevice(deviceName(id).c_str()); } + } else { + _alexa.addDevice(hostname.c_str()); + } - #endif +#endif // Load & cache settings _alexaConfigure(); @@ -174,16 +215,17 @@ void alexaSetup() { }); // Callback - _alexa.onSetState([&](unsigned char device_id, const char * name, bool state, unsigned char value) { - alexa_queue_element_t element; - element.device_id = device_id; - element.state = state; - element.value = value; - _alexa_queue.push(element); + _alexa.onSetState([&](unsigned char device_id, const char*, bool state, unsigned char value) { + _alexa_events.emplace(device_id, state, value); }); // Register main callbacks - StatusBroker::Register(_alexaBrokerCallback); +#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + lightSetReportListener(_alexaUpdateLights); +#else + relaySetStatusChange(_alexaUpdateRelay); +#endif + espurnaRegisterReload(_alexaConfigure); espurnaRegisterLoop(alexaLoop); diff --git a/code/espurna/domoticz.cpp b/code/espurna/domoticz.cpp index 2f3e53f3..4f2c548c 100644 --- a/code/espurna/domoticz.cpp +++ b/code/espurna/domoticz.cpp @@ -10,7 +10,6 @@ Copyright (C) 2016-2019 by Xose Pérez #if DOMOTICZ_SUPPORT -#include "broker.h" #include "light.h" #include "mqtt.h" #include "relay.h" @@ -173,43 +172,26 @@ void _domoticzMqtt(unsigned int type, const char * topic, char * payload) { } -}; - -void _domoticzRelayConfigure(size_t size) { - for (size_t n = 0; n < size; ++n) { - _dcz_relay_state[n] = relayStatus(n); - } } void _domoticzConfigure() { const bool enabled = getSetting("dczEnabled", 1 == DOMOTICZ_ENABLED); if (enabled != _dcz_enabled) _domoticzMqttSubscribe(enabled); - #if RELAY_SUPPORT - _domoticzRelayConfigure(relayCount()); - #endif +#if RELAY_SUPPORT + for (size_t id = 0; id < relayCount(); ++id) { + _dcz_relay_state[id] = relayStatus(id); + } +#endif _dcz_enabled = enabled; } -void _domoticzConfigCallback(const String& key, const String& value) { - if (key.equals("relayDummy")) { - _domoticzRelayConfigure(value.toInt()); - return; - } -} - -void _domoticzBrokerCallback(const String& topic, unsigned char id, unsigned int value) { - - // Only process status messages for switches - if (!topic.equals(MQTT_TOPIC_RELAY)) { - return; +void _domoticzRelayCallback(size_t id, bool status) { + if (_domoticzStatus(id) != status) { + _dcz_relay_state[id] = status; + domoticzSendRelay(id, status); } - - if (_domoticzStatus(id) == value) return; - _dcz_relay_state[id] = value; - domoticzSendRelay(id, value); - } #if SENSOR_SUPPORT @@ -330,8 +312,9 @@ void domoticzSetup() { .onKeyCheck(_domoticzWebSocketOnKeyCheck); #endif - StatusBroker::Register(_domoticzBrokerCallback); - ConfigBroker::Register(_domoticzConfigCallback); + #if RELAY_SUPPORT + relaySetStatusChange(_domoticzRelayCallback); + #endif // Callbacks mqttRegister(_domoticzMqtt); diff --git a/code/espurna/influxdb.cpp b/code/espurna/influxdb.cpp index 0569e751..96516cba 100644 --- a/code/espurna/influxdb.cpp +++ b/code/espurna/influxdb.cpp @@ -161,8 +161,8 @@ void _idbBrokerSensor(const String& topic, unsigned char id, double, const char* idbSend(topic.c_str(), id, value); } -void _idbBrokerStatus(const String& topic, unsigned char id, unsigned int value) { - idbSend(topic.c_str(), id, String(int(value)).c_str()); +void _idbSendStatus(size_t id, bool status) { + idbSend(MQTT_TOPIC_RELAY, id, status ? "1" : "0"); // "status" ? } // ----------------------------------------------------------------------------- @@ -219,7 +219,7 @@ void _idbFlush() { _idb_client->payload = ""; for (auto& pair : _idb_client->values) { - if (!isNumber(pair.second.c_str())) { + if (!isNumber(pair.second)) { String quoted; quoted.reserve(pair.second.length() + 2); quoted += '"'; @@ -292,7 +292,9 @@ void idbSetup() { .onKeyCheck(_idbWebSocketOnKeyCheck); #endif - StatusBroker::Register(_idbBrokerStatus); + #if RELAY_SUPPORT + relaySetStatusChange(_idbSendStatus); + #endif #if SENSOR_SUPPORT SensorReportBroker::Register(_idbBrokerSensor); diff --git a/code/espurna/led.cpp b/code/espurna/led.cpp index 3811ba07..1f116ac7 100644 --- a/code/espurna/led.cpp +++ b/code/espurna/led.cpp @@ -12,7 +12,6 @@ Copyright (C) 2016-2019 by Xose Pérez #include -#include "broker.h" #include "mqtt.h" #include "relay.h" #include "rpc.h" @@ -232,15 +231,6 @@ void _ledWebSocketOnConnected(JsonObject& root) { #endif -void _ledBrokerCallback(const String& topic, unsigned char, unsigned int) { - - // Only process status messages for switches - if (topic.equals(MQTT_TOPIC_RELAY)) { - ledUpdate(true); - } - -} - #if MQTT_SUPPORT void _ledMQTTCallback(unsigned int type, const char * topic, const char * payload) { @@ -497,7 +487,11 @@ void ledSetup() { .onKeyCheck(_ledWebSocketOnKeyCheck); #endif - StatusBroker::Register(_ledBrokerCallback); + #if RELAY_SUPPORT + relaySetStatusNotify([](size_t, bool) { + ledUpdate(true); + }); + #endif DEBUG_MSG_P(PSTR("[LED] Number of leds: %d\n"), _leds.size()); diff --git a/code/espurna/light.cpp b/code/espurna/light.cpp index 13af9662..fab1dfd0 100644 --- a/code/espurna/light.cpp +++ b/code/espurna/light.cpp @@ -12,7 +12,6 @@ Copyright (C) 2019-2021 by Maxim Prokhorov _light_report; bool _light_has_controls = false; bool _light_has_color = false; @@ -1553,20 +1552,6 @@ void lightMQTTGroup() { #endif -// ----------------------------------------------------------------------------- -// Broker -// ----------------------------------------------------------------------------- - -#if BROKER_SUPPORT - -void lightBroker() { - for (unsigned int id = 0; id < _light_channels.size(); ++id) { - StatusBroker::Publish(MQTT_TOPIC_CHANNEL, id, _light_channels[id].value); - } -} - -#endif - // ----------------------------------------------------------------------------- // API // ----------------------------------------------------------------------------- @@ -2037,7 +2022,7 @@ void lightHs(long hue, long saturation) { // ----------------------------------------------------------------------------- void lightSetReportListener(LightReportListener func) { - _light_report = func; + _light_report.push_front(func); } void _lightReport(int report) { @@ -2057,14 +2042,8 @@ void _lightReport(int report) { } #endif -#if BROKER_SUPPORT - if (report & Light::Report::Broker) { - lightBroker(); - } -#endif - - if (_light_report) { - _light_report(); + for (auto& report : _light_report) { + report(); } } diff --git a/code/espurna/relay.cpp b/code/espurna/relay.cpp index ef3bbec1..df6ed2e8 100644 --- a/code/espurna/relay.cpp +++ b/code/espurna/relay.cpp @@ -12,16 +12,17 @@ Copyright (C) 2016-2019 by Xose Pérez #include #include -#include -#include #include +#include +#include +#include #include "api.h" -#include "broker.h" #include "mqtt.h" #include "rpc.h" #include "rtcmem.h" #include "settings.h" +#include "terminal.h" #include "storage_eeprom.h" #include "utils.h" #include "ws.h" @@ -286,8 +287,8 @@ bool _relay_sync_locked = false; Ticker _relay_save_timer; Ticker _relay_sync_timer; -RelayStatusCallback _relay_status_notify { nullptr }; -RelayStatusCallback _relay_status_change { nullptr }; +std::forward_list _relay_status_notify; +std::forward_list _relay_status_change; #if WEB_SUPPORT @@ -332,11 +333,11 @@ void RelayProviderBase::notify(bool) { // Direct status notifications void relaySetStatusNotify(RelayStatusCallback callback) { - _relay_status_notify = callback; + _relay_status_notify.push_front(callback); } void relaySetStatusChange(RelayStatusCallback callback) { - _relay_status_change = callback; + _relay_status_change.push_front(callback); } // No-op provider, available for purely virtual relays that are controlled only via API @@ -418,7 +419,7 @@ struct GpioProvider : public RelayProviderBase { } private: - unsigned char _id { RELAY_NONE }; + unsigned char _id { RelaysMax }; RelayType _type { RelayType::Normal }; std::unique_ptr _pin; std::unique_ptr _reset_pin; @@ -620,16 +621,16 @@ bool _relayTryParseIdFromPath(const String& endpoint, unsigned char& relayID) { return _relayTryParseId(p, relayID); } -void _relayHandleStatus(unsigned char relayID, PayloadStatus status) { +void _relayHandleStatus(unsigned char id, PayloadStatus status) { switch (status) { case PayloadStatus::Off: - relayStatus(relayID, false); + relayStatus(id, false); break; case PayloadStatus::On: - relayStatus(relayID, true); + relayStatus(id, true); break; case PayloadStatus::Toggle: - relayToggle(relayID); + relayToggle(id); break; case PayloadStatus::Unknown: break; @@ -832,7 +833,7 @@ void relayPulse(unsigned char id) { } if ((mode == RelayPulse::On) != relay.current_status) { - DEBUG_MSG_P(PSTR("[RELAY] Scheduling relay #%d back in %lums (pulse)\n"), id, ms); + DEBUG_MSG_P(PSTR("[RELAY] Scheduling relay #%u back in %lums (pulse)\n"), id, ms); relay.pulseTicker->once_ms(ms, relayToggle, id); // Reconfigure after dynamic pulse relay.pulse = getSetting({"relayPulse", id}, _relayPulseMode(id)); @@ -845,11 +846,12 @@ void relayPulse(unsigned char id) { bool relayStatus(unsigned char id, bool status, bool report, bool group_report) { - if (id == RELAY_NONE) return false; - if (id >= _relays.size()) return false; + if ((id >= RelaysMax) || (id >= _relays.size())) { + return false; + } if (!_relayStatusLock(id, status)) { - DEBUG_MSG_P(PSTR("[RELAY] #%d is locked to %s\n"), id, _relays[id].current_status ? "ON" : "OFF"); + DEBUG_MSG_P(PSTR("[RELAY] #%u is locked to %s\n"), id, _relays[id].current_status ? "ON" : "OFF"); _relays[id].report = true; _relays[id].group_report = true; return false; @@ -860,7 +862,7 @@ bool relayStatus(unsigned char id, bool status, bool report, bool group_report) if (_relays[id].current_status == status) { if (_relays[id].target_status != status) { - DEBUG_MSG_P(PSTR("[RELAY] #%d scheduled change cancelled\n"), id); + DEBUG_MSG_P(PSTR("[RELAY] #%u scheduled change cancelled\n"), id); _relays[id].target_status = status; _relays[id].report = false; _relays[id].group_report = false; @@ -869,8 +871,8 @@ bool relayStatus(unsigned char id, bool status, bool report, bool group_report) } _relays[id].provider->notify(status); - if (_relay_status_notify) { - _relay_status_notify(id, status); + for (auto& notify : _relay_status_notify) { + notify(id, status); } // Update the pulse counter if the relay is already in the non-normal state (#454) @@ -911,7 +913,7 @@ bool relayStatus(unsigned char id, bool status, bool report, bool group_report) relaySync(id); - DEBUG_MSG_P(PSTR("[RELAY] #%d scheduled %s in %u ms\n"), + DEBUG_MSG_P(PSTR("[RELAY] #%u scheduled %s in %u ms\n"), id, status ? "ON" : "OFF", _relays[id].change_delay ); @@ -1407,16 +1409,17 @@ const String& relayPayloadToggle() { const char* relayPayload(PayloadStatus status) { switch (status) { - case PayloadStatus::Off: - return _relay_rpc_payload_off.c_str(); - case PayloadStatus::On: - return _relay_rpc_payload_on.c_str(); - case PayloadStatus::Toggle: - return _relay_rpc_payload_toggle.c_str(); - case PayloadStatus::Unknown: - default: - return ""; + case PayloadStatus::Off: + return _relay_rpc_payload_off.c_str(); + case PayloadStatus::On: + return _relay_rpc_payload_on.c_str(); + case PayloadStatus::Toggle: + return _relay_rpc_payload_toggle.c_str(); + case PayloadStatus::Unknown: + break; } + + return ""; } #endif // MQTT_SUPPORT || API_SUPPORT @@ -1480,6 +1483,7 @@ private: String _value; RelayMqttTopicMode _mode; }; + struct RelayCustomTopic { RelayCustomTopic() = delete; RelayCustomTopic(const RelayCustomTopic&) = delete; @@ -1836,9 +1840,9 @@ void _relayInitCommands() { //------------------------------------------------------------------------------ void _relayReport(unsigned char id [[gnu::unused]], bool status [[gnu::unused]]) { -#if BROKER_SUPPORT - StatusBroker::Publish(MQTT_TOPIC_RELAY, id, status); -#endif + for (auto& change : _relay_status_change) { + change(id, status); + } #if MQTT_SUPPORT _relayMqttReport(id); #endif @@ -1873,15 +1877,11 @@ void _relayProcess(bool mode) { _relays[id].change_delay = 0; changed = true; - DEBUG_MSG_P(PSTR("[RELAY] #%d set to %s\n"), id, target ? "ON" : "OFF"); + DEBUG_MSG_P(PSTR("[RELAY] #%u set to %s\n"), id, target ? "ON" : "OFF"); // Call the provider to perform the action _relays[id].current_status = target; _relays[id].provider->change(target); - if (_relay_status_change) { - _relay_status_change(id, target); - } - _relayReport(id, target); if (!_relayRecursive) { @@ -1926,11 +1926,14 @@ void _relayLoop() { // Dummy relays for virtual light switches (hardware-less), Sonoff Dual, Sonoff RF Bridge and Tuya void relaySetupDummy(size_t size, bool reconfigure) { - - if (size == _relayDummy) return; + if (size == _relayDummy) { + return; + } const size_t new_size = ((_relays.size() - _relayDummy) + size); - if (new_size > RelaysMax) return; + if (new_size > RelaysMax) { + return; + } _relayDummy = size; _relays.resize(new_size); @@ -1938,11 +1941,6 @@ void relaySetupDummy(size_t size, bool reconfigure) { if (reconfigure) { _relayConfigure(); } - - #if BROKER_SUPPORT - ConfigBroker::Publish("relayDummy", String(int(size))); - #endif - } constexpr size_t _relayAdhocPins() { @@ -1976,8 +1974,8 @@ constexpr size_t _relayAdhocPins() { struct RelayGpioProviderCfg { GpioBase* base; - unsigned char main; - unsigned char reset; + uint8_t main; + uint8_t reset; }; RelayGpioProviderCfg _relayGpioProviderCfg(unsigned char index) { @@ -1987,8 +1985,6 @@ RelayGpioProviderCfg _relayGpioProviderCfg(unsigned char index) { getSetting({"relayResetGPIO", index}, _relayResetPin(index))}; } -using GpioCheck = bool(*)(unsigned char); - std::unique_ptr _relayGpioProvider(unsigned char index, RelayType type) { auto cfg = _relayGpioProviderCfg(index); if (!cfg.base) { @@ -1996,14 +1992,13 @@ std::unique_ptr _relayGpioProvider(unsigned char index, RelayType } auto main = gpioRegister(*cfg.base, cfg.main); - if (!main) { - return nullptr; + if (main) { + auto reset = gpioRegister(*cfg.base, cfg.reset); + return std::make_unique( + index, type, std::move(main), std::move(reset)); } - auto reset = gpioRegister(*cfg.base, cfg.reset); - return std::make_unique( - index, type, std::move(main), std::move(reset) - ); + return nullptr; } RelayProviderBasePtr _relaySetupProvider(unsigned char index) { diff --git a/code/espurna/relay.h b/code/espurna/relay.h index d368f111..27b6120e 100644 --- a/code/espurna/relay.h +++ b/code/espurna/relay.h @@ -11,7 +11,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include "espurna.h" #include "rpc.h" -constexpr size_t RelaysMax = 32; +constexpr size_t RelaysMax { 32ul }; enum class RelayPulse : uint8_t { None, @@ -94,7 +94,7 @@ void relayPulse(unsigned char id); void relaySync(unsigned char id); void relaySave(bool persist); -using RelayStatusCallback = void(*)(unsigned char id, bool status); +using RelayStatusCallback = void(*)(size_t id, bool status); using RelayProviderBasePtr = std::unique_ptr; bool relayAdd(RelayProviderBasePtr&& provider); diff --git a/code/espurna/rpc.cpp b/code/espurna/rpc.cpp index 0e8a2ecc..768c23f4 100644 --- a/code/espurna/rpc.cpp +++ b/code/espurna/rpc.cpp @@ -14,8 +14,6 @@ Copyright (C) 2020 by Maxim Prokhorov #include "system.h" #include "utils.h" -BrokerBind(StatusBroker); - bool rpcHandleAction(const String& action) { bool result = false; if (action.equals("reboot")) { diff --git a/code/espurna/rpc.h b/code/espurna/rpc.h index 08370b6e..4316e899 100644 --- a/code/espurna/rpc.h +++ b/code/espurna/rpc.h @@ -8,10 +8,6 @@ Part of MQTT and API modules #include "espurna.h" -#include "broker.h" - -BrokerDeclare(StatusBroker, void(const String& topic, unsigned char id, unsigned int status)); - // -------------------------------------------------------------------------- enum class PayloadStatus { diff --git a/code/espurna/rpnrules.cpp b/code/espurna/rpnrules.cpp index 29daf75c..fb407111 100644 --- a/code/espurna/rpnrules.cpp +++ b/code/espurna/rpnrules.cpp @@ -12,7 +12,6 @@ Copyright (C) 2019 by Xose Pérez #include -#include "broker.h" #include "light.h" #include "mqtt.h" #include "ntp.h" @@ -147,29 +146,32 @@ void _rpnMQTTCallback(unsigned int type, const char * topic, const char * payloa #endif // MQTT_SUPPORT void _rpnConfigure() { - #if MQTT_SUPPORT - if (mqttConnected()) _rpnMQTTSubscribe(); - #endif +#if MQTT_SUPPORT + if (mqttConnected()) { + _rpnMQTTSubscribe(); + } +#endif _rpn_delay = getSetting("rpnDelay", RPN_DELAY); } -void _rpnBrokerCallback(const String& topic, unsigned char id, double value, const char*) { - +void _rpnRelayStatus(size_t id, bool status) { char name[32] = {0}; - snprintf(name, sizeof(name), "%s%u", topic.c_str(), id); - - if (topic == MQTT_TOPIC_RELAY) { - rpn_variable_set(_rpn_ctxt, name, rpn_value(static_cast(value))); - } else { - rpn_variable_set(_rpn_ctxt, name, rpn_value(value)); - } + snprintf(name, sizeof(name), "relay%u", id); + rpn_variable_set(_rpn_ctxt, name, rpn_value(std::forward(value))); _rpn_run = true; - } -void _rpnBrokerStatus(const String& topic, unsigned char id, unsigned int value) { - _rpnBrokerCallback(topic, id, double(value), nullptr); +void _rpnLightStatus() { + auto channels = lightChannels(); + + char name[32] = {0}; + for (decltype(channels) channel = 0; channel < channels; ++channel) { + snprintf(name, sizeof(name), "channel%u", channel); + rpn_variable_set(_rpn_ctxt, name, rpn_value(lightChannel(channel))); + } + + _rpn_run = true; } #if NTP_SUPPORT @@ -1019,7 +1021,13 @@ void rpnSetup() { }); #endif - StatusBroker::Register(_rpnBrokerStatus); +#if RELAY_SUPPORT + relaySetStatusChange(_rpnRelayStatus); +#endif + +#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + lightSetReportListener(_rpnLightStatus); +#endif #if RFB_SUPPORT _rpnRfbSetup(); diff --git a/code/espurna/settings.cpp b/code/espurna/settings.cpp index 7c6f9b95..16aba1d4 100644 --- a/code/espurna/settings.cpp +++ b/code/espurna/settings.cpp @@ -18,8 +18,6 @@ Copyright (C) 2016-2019 by Xose Pérez #include -BrokerBind(ConfigBroker); - // ----------------------------------------------------------------------------- namespace settings { diff --git a/code/espurna/settings.h b/code/espurna/settings.h index c4c3c16d..58966148 100644 --- a/code/espurna/settings.h +++ b/code/espurna/settings.h @@ -17,12 +17,9 @@ Copyright (C) 2016-2019 by Xose Pérez #include -#include "broker.h" #include "storage_eeprom.h" #include "settings_embedis.h" -BrokerDeclare(ConfigBroker, void(const String& key, const String& value)); - // -------------------------------------------------------------------------- void resetSettings(); diff --git a/code/espurna/thingspeak.cpp b/code/espurna/thingspeak.cpp index d183ccb9..203502bb 100644 --- a/code/espurna/thingspeak.cpp +++ b/code/espurna/thingspeak.cpp @@ -12,7 +12,6 @@ Copyright (C) 2019 by Xose Pérez #include -#include "broker.h" #include "mqtt.h" #include "relay.h" #include "rpc.h" @@ -87,16 +86,9 @@ AsyncClientState _tspk_state = AsyncClientState::Disconnected; // ----------------------------------------------------------------------------- -void _tspkBrokerCallback(const String& topic, unsigned char id, unsigned int value) { - - // Only process status messages for switches - if (!topic.equals(MQTT_TOPIC_RELAY)) { - return; - } - - tspkEnqueueRelay(id, value > 0); +void _tspkRelayStatus(size_t id, bool status) { + tspkEnqueueRelay(id, status); tspkFlush(); - } #if WEB_SUPPORT @@ -464,7 +456,9 @@ void tspkSetup() { .onKeyCheck(_tspkWebSocketOnKeyCheck); #endif - StatusBroker::Register(_tspkBrokerCallback); + #if RELAY_SUPPORT + relaySetStatusChange(_tspkRelayStatus); + #endif DEBUG_MSG_P(PSTR("[THINGSPEAK] Async %s, SSL %s\n"), THINGSPEAK_USE_ASYNC ? "ENABLED" : "DISABLED", diff --git a/code/espurna/utils.cpp b/code/espurna/utils.cpp index c28861af..cd5b6f09 100644 --- a/code/espurna/utils.cpp +++ b/code/espurna/utils.cpp @@ -404,25 +404,46 @@ void nice_delay(unsigned long ms) { while (millis() - start < ms) delay(1); } -bool isNumber(const char * s) { - unsigned char len = strlen(s); - if (0 == len) return false; - bool decimal = false; - bool digit = false; - for (unsigned char i=0; i0) return false; - } else if (s[i] == '.') { - if (!digit) return false; - if (decimal) return false; - decimal = true; - } else if (!isdigit(s[i])) { - return false; - } else { - digit = true; +bool isNumber(const String& value) { + if (value.length()) { + const char* begin { value.c_str() }; + const char* end { value.c_str() + value.length() }; + + bool dot { false }; + bool digit { false }; + const char* ptr { begin }; + + while (ptr != end) { + switch (*ptr) { + case '\0': + break; + case '-': + case '+': + if (ptr != begin) { + return false; + } + break; + case '.': + if (dot) { + return false; + } + dot = true; + break; + case '0' ... '9': + digit = true; + break; + case 'a' ... 'z': + case 'A' ... 'Z': + return false; + } + + ++ptr; } + + return digit; } - return digit; + + return false; } // ref: lwip2 lwip_strnstr with strnlen diff --git a/code/espurna/utils.h b/code/espurna/utils.h index d534392e..dc485033 100644 --- a/code/espurna/utils.h +++ b/code/espurna/utils.h @@ -44,7 +44,7 @@ bool sslFingerPrintChar(const char * fingerprint, char * destination); char* ltrim(char* s); char* strnstr(const char* buffer, const char* token, size_t n); -bool isNumber(const char* s); +bool isNumber(const String&); void nice_delay(unsigned long ms);