diff --git a/code/espurna/board.cpp b/code/espurna/board.cpp index 320d191a..de4f21c9 100644 --- a/code/espurna/board.cpp +++ b/code/espurna/board.cpp @@ -17,9 +17,6 @@ PROGMEM const char espurna_modules[] = #if API_SUPPORT "API " #endif - #if BROKER_SUPPORT - "BROKER " - #endif #if BUTTON_SUPPORT "BUTTON " #endif diff --git a/code/espurna/broker.h b/code/espurna/broker.h deleted file mode 100644 index 9f9c6100..00000000 --- a/code/espurna/broker.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - -BROKER MODULE - -Copyright (C) 2017-2019 by Xose Pérez - -*/ - -#pragma once - -#include -#include -#include -#include - -// Example usage: -// -// module.h -// BrokerDeclare(CustomBroker, void(int)); -// -// module.cpp -// BrokerBind(CustomBroker); -// -// other.cpp -// #include "module.h" -// void func() { -// CustomBroker::Register([](int arg) { Serial.println(arg); } -// CustomBroker::Publish(12345); -// } - -template -struct TBroker {}; - -template -struct TBroker { - - using TArgs = typename std::tuple; - using TCallback = std::function; - using TCallbacks = std::vector; - - TBroker(const TBroker&) = delete; - TBroker& operator=(const TBroker&) = delete; - - TBroker() = default; - - // TODO: https://source.chromium.org/chromium/chromium/src/+/master:base/callback_list.h - // Consider giving out 'subscription' / 'token', so that the caller can remove callback later - - void Register(TCallback callback) { - callbacks.push_back(callback); - } - - void Publish(Args... args) { - for (auto& callback : callbacks) { - callback(args...); - } - } - - protected: - - TCallbacks callbacks; - -}; - -// TODO: since 1.14.0 we intoduced static syntax for Brokers, ::Register & ::Publish. -// Preserve it (up to a point) when creating module-level objects. -// Provide a helper namespace with Register & Publish, instance and -// To help out VS Code with argument discovery, put TArgs as the first template parameter. - -#define BrokerDeclare(Name, Signature) \ -namespace Name { \ -using type = TBroker; \ -extern type Instance; \ -template \ -inline void Register(Args&&... args) { \ - Instance.Register(std::forward(args)...); \ -}\ -\ -template \ -inline void Publish(Args&&... args) { \ - Instance.Publish(std::forward(args)...); \ -}\ -} - -#define BrokerBind(Name) \ -namespace Name { \ -Name::type Instance; \ -} - diff --git a/code/espurna/config/arduino.h b/code/espurna/config/arduino.h index 18be561d..14d3c070 100644 --- a/code/espurna/config/arduino.h +++ b/code/espurna/config/arduino.h @@ -191,7 +191,6 @@ //#define ALEXA_SUPPORT 0 //#define API_SUPPORT 0 -//#define BROKER_SUPPORT 0 //#define BUTTON_SUPPORT 0 //#define DEBUG_SERIAL_SUPPORT 0 //#define DEBUG_TELNET_SUPPORT 0 diff --git a/code/espurna/config/dependencies.h b/code/espurna/config/dependencies.h index 43319e0a..0088e949 100644 --- a/code/espurna/config/dependencies.h +++ b/code/espurna/config/dependencies.h @@ -36,32 +36,16 @@ #endif #if ALEXA_SUPPORT -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // If Alexa enabled enable BROKER #undef RELAY_SUPPORT #define RELAY_SUPPORT 1 // and switches #endif #if RPN_RULES_SUPPORT -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // If RPN Rules enabled enable BROKER #undef MQTT_SUPPORT #define MQTT_SUPPORT 1 #endif -#if LED_SUPPORT -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // If LED is enabled enable BROKER to supply status changes -#endif - -#if INFLUXDB_SUPPORT -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // If InfluxDB enabled enable BROKER -#endif - #if DOMOTICZ_SUPPORT -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // If Domoticz enabled enable BROKER #undef MQTT_SUPPORT #define MQTT_SUPPORT 1 // If Domoticz enabled enable MQTT #endif @@ -71,11 +55,6 @@ #define MQTT_SUPPORT 1 // If Home Assistant enabled enable MQTT #endif -#if THINGSPEAK_SUPPORT -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // If Thingspeak enabled enable BROKER -#endif - #if THERMOSTAT_SUPPORT #undef MQTT_USE_JSON #define MQTT_USE_JSON 1 // Thermostat depends on group messages in a JSON body @@ -86,8 +65,6 @@ #if SCHEDULER_SUPPORT #undef NTP_SUPPORT #define NTP_SUPPORT 1 // Scheduler needs NTP to work -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // Scheduler needs Broker to trigger every minute #undef RELAY_SUPPORT #define RELAY_SUPPORT 1 // Scheduler needs relays #endif @@ -102,8 +79,6 @@ #endif #if TUYA_SUPPORT -#undef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // Broker is required to process relay & lights events #undef RELAY_SUPPORT #define RELAY_SUPPORT 1 // Most of the time we require it #endif diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 39ba6df6..6c024e17 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -1234,14 +1234,6 @@ #define MQTT_SETTER "/set" #endif -// ----------------------------------------------------------------------------- -// BROKER -// ----------------------------------------------------------------------------- - -#ifndef BROKER_SUPPORT -#define BROKER_SUPPORT 1 // The broker is a poor-man's pubsub manager -#endif - // ----------------------------------------------------------------------------- // SETTINGS // ----------------------------------------------------------------------------- diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h index 0147e7aa..acfcee1a 100644 --- a/code/espurna/config/hardware.h +++ b/code/espurna/config/hardware.h @@ -60,7 +60,6 @@ // Disable non-core modules #define ALEXA_SUPPORT 0 #define API_SUPPORT 0 - #define BROKER_SUPPORT 0 #define DEBUG_SERIAL_SUPPORT 0 #define DEBUG_TELNET_SUPPORT 0 #define DEBUG_WEB_SUPPORT 0 @@ -99,7 +98,6 @@ // Disable non-core modules #define ALEXA_SUPPORT 0 #define API_SUPPORT 0 - #define BROKER_SUPPORT 0 #define DOMOTICZ_SUPPORT 0 #define DEBUG_SERIAL_SUPPORT 0 //#define DEBUG_TELNET_SUPPORT 0 diff --git a/code/espurna/influxdb.cpp b/code/espurna/influxdb.cpp index 96516cba..004d1e11 100644 --- a/code/espurna/influxdb.cpp +++ b/code/espurna/influxdb.cpp @@ -13,9 +13,9 @@ Copyright (C) 2017-2019 by Xose Pérez #include #include -#include "broker.h" #include "mqtt.h" #include "rpc.h" +#include "relay.h" #include "sensor.h" #include "terminal.h" #include "ws.h" @@ -157,7 +157,7 @@ void _idbConfigure() { if (_idb_enabled && !_idb_client) _idbInitClient(); } -void _idbBrokerSensor(const String& topic, unsigned char id, double, const char* value) { +void _idbSendSensor(const String& topic, unsigned char id, double, const char* value) { idbSend(topic.c_str(), id, value); } @@ -297,7 +297,7 @@ void idbSetup() { #endif #if SENSOR_SUPPORT - SensorReportBroker::Register(_idbBrokerSensor); + sensorSetMagnitudeReport(_idbSendSensor); #endif espurnaRegisterReload(_idbConfigure); diff --git a/code/espurna/light.h b/code/espurna/light.h index 7d49bb6b..c4b54ccd 100644 --- a/code/espurna/light.h +++ b/code/espurna/light.h @@ -41,8 +41,7 @@ enum class Report { None = 0, Web = 1 << 0, Mqtt = 1 << 1, - MqttGroup = 1 << 2, - Broker = 1 << 3 + MqttGroup = 1 << 2 }; constexpr int operator|(Report lhs, int rhs) { @@ -66,7 +65,7 @@ constexpr int operator&(Report lhs, int rhs) { } constexpr int DefaultReport { - Report::Web | Report::Mqtt | Report::MqttGroup | Report::Broker + Report::Web | Report::Mqtt | Report::MqttGroup }; struct Hsv { diff --git a/code/espurna/main.h b/code/espurna/main.h index 314ff3c0..3d2cac26 100644 --- a/code/espurna/main.h +++ b/code/espurna/main.h @@ -22,7 +22,6 @@ along with this program. If not, see . #include "alexa.h" #include "api.h" -#include "broker.h" #include "button.h" #include "crash.h" #include "curtain_kingart.h" diff --git a/code/espurna/rfbridge.cpp b/code/espurna/rfbridge.cpp index 110984ea..b451d136 100644 --- a/code/espurna/rfbridge.cpp +++ b/code/espurna/rfbridge.cpp @@ -17,8 +17,6 @@ Copyright (C) 2016-2019 by Xose Pérez #include "ws.h" #include "utils.h" -BrokerBind(RfbridgeBroker); - #include #include #include @@ -45,6 +43,12 @@ constexpr bool _rfb_transmit { true }; #endif +std::forward_list _rfb_code_handlers; + +void rfbSetCodeHandler(RfbCodeHandler handler) { + _rfb_code_handlers.push_front(handler); +} + // ----------------------------------------------------------------------------- // MATCH RECEIVED CODE WITH THE SPECIFIC RELAY ID // ----------------------------------------------------------------------------- @@ -531,7 +535,7 @@ void _rfbLearnStartFromPayload(const char* payload) { std::copy(payload, sep, relay); size_t id; - if (!tryParseId(relay, relayCount(), id)) { + if (!tryParseId(relay, relayCount, id)) { DEBUG_MSG_P(PSTR("[RF] Invalid relay ID (%u)\n"), id); return; } @@ -645,9 +649,9 @@ void _rfbParse(uint8_t code, const std::vector& payload) { mqttSend(MQTT_TOPIC_RFIN, buffer, false, false); #endif -#if BROKER_SUPPORT - RfbridgeBroker::Publish(RfbDefaultProtocol, buffer + 12); -#endif + for (auto& handler : _rfb_code_handlers) { + handler(RfbDefaultProtocol, buffer + 12); + } } break; } @@ -665,10 +669,10 @@ void _rfbParse(uint8_t code, const std::vector& payload) { mqttSend(MQTT_TOPIC_RFIN, buffer, false, false); #endif -#if BROKER_SUPPORT // ref. https://github.com/Portisch/RF-Bridge-EFM8BB1/wiki/0xA6#example-of-a-received-decoded-protocol - RfbridgeBroker::Publish(payload[0], buffer + 2); -#endif + for (auto& handler : _rfb_code_handlers) { + handler(payload[0], buffer + 2); + } } else { DEBUG_MSG_P(PSTR("[RF] Received 0x%02X (%u bytes)\n"), code, payload.size()); } @@ -882,9 +886,9 @@ void _rfbReceiveImpl() { mqttSend(MQTT_TOPIC_RFIN, buffer, false, false); #endif -#if BROKER_SUPPORT - RfbridgeBroker::Publish(message[1], buffer + 10); -#endif + for (auto& handler : _rfb_code_handlers) { + handler(message[1], buffer + 10); + } } _rfb_modem->resetAvailable(); diff --git a/code/espurna/rfbridge.h b/code/espurna/rfbridge.h index a6eed9e1..ec4a1cec 100644 --- a/code/espurna/rfbridge.h +++ b/code/espurna/rfbridge.h @@ -12,9 +12,8 @@ Copyright (C) 2016-2019 by Xose Pérez #if RFB_SUPPORT -#include "broker.h" - -BrokerDeclare(RfbridgeBroker, void(unsigned char protocol, const char* code)); +using RfbCodeHandler = void(*)(unsigned char protocol, const char* code); +void rfbSetCodeHandler(RfbCodeHandler); void rfbSend(const char* code); void rfbSend(const String& code); diff --git a/code/espurna/rpnrules.cpp b/code/espurna/rpnrules.cpp index f4ac86c6..2a70cc41 100644 --- a/code/espurna/rpnrules.cpp +++ b/code/espurna/rpnrules.cpp @@ -158,7 +158,7 @@ void _rpnRelayStatus(size_t id, bool status) { char name[32] = {0}; snprintf(name, sizeof(name), "relay%u", id); - rpn_variable_set(_rpn_ctxt, name, rpn_value(std::forward(value))); + rpn_variable_set(_rpn_ctxt, name, rpn_value(status)); _rpn_run = true; } @@ -167,13 +167,30 @@ void _rpnLightStatus() { char name[32] = {0}; for (decltype(channels) channel = 0; channel < channels; ++channel) { + auto value = rpn_value(static_cast(lightChannel(channel))); snprintf(name, sizeof(name), "channel%u", channel); - rpn_variable_set(_rpn_ctxt, name, rpn_value(lightChannel(channel))); + rpn_variable_set(_rpn_ctxt, name, std::move(value)); } _rpn_run = true; } +#if SENSOR_SUPPORT + +void _rpnSensorMagnitudeRead(const String& topic, unsigned char index, double reading, const char*) { + static_assert(sizeof(double) == sizeof(rpn_float), ""); + + String name; + name.reserve(topic.length() + 3); + + name += topic; + name += index; + + rpn_variable_set(_rpn_ctxt, name, rpn_value(static_cast(reading))); +} + +#endif + #if NTP_SUPPORT namespace { @@ -494,7 +511,7 @@ rpn_error _rpnRfbMatcher(rpn_context& ctxt) { return rpn_operator_error::CannotContinue; } -void _rpnBrokerRfbridgeCallback(unsigned char protocol, const char* raw_code) { +void _rpnRfbridgeCodeHandler(unsigned char protocol, const char* raw_code) { // remove really old codes that we have not seen in a while to avoid memory exhaustion auto ts = millis(); @@ -525,7 +542,7 @@ void _rpnRfbSetup() { // - Repeat window is an arbitrary time, just about 3-4 more times it takes for // a code to be sent again when holding a generic remote button // Code counter is reset to 0 when outside of the window. - // - Stale delay allows broker callback to remove really old codes. + // - Stale delay allows the handler to remove really old codes. // (TODO: can this happen in loop() cb instead?) _rfb_code_repeat_window = getSetting("rfbRepeatWindow", 2000ul); _rfb_code_match_window = getSetting("rfbMatchWindow", 2000ul); @@ -548,23 +565,27 @@ void _rpnRfbSetup() { #endif // Main bulk of the processing goes on in here - RfbridgeBroker::Register(_rpnBrokerRfbridgeCallback); + rfbSetCodeHandler(_rpnRfbridgeCodeHandler); } #endif // RFB_SUPPORT void _rpnDeepSleep(uint64_t duration, RFMode mode); +void _rpnDeepSleepSchedule(uint64_t duration, RFMode mode) { + schedule_function([duration, mode]() { + _rpnDeepSleep(duration, mode); + }); +} + void _rpnDeepSleep(uint64_t duration, RFMode mode) { if (WiFi.getMode() != WIFI_OFF) { wifiTurnOff(); - schedule_function([duration, mode]() { - _rpnDeepSleep(duration, mode); - }); + _rpnDeepSleepSchedule(duration, mode); return; } - deepSleep(duration, mode); + ESP.deepSleep(duration, mode); } void _rpnShowStack(Print& print) { @@ -1015,13 +1036,13 @@ void rpnSetup() { lightSetReportListener(_rpnLightStatus); #endif - #if RFB_SUPPORT - _rpnRfbSetup(); - #endif +#if RFB_SUPPORT + _rpnRfbSetup(); +#endif - #if SENSOR_SUPPORT - SensorReadBroker::Register(_rpnBrokerCallback); - #endif +#if SENSOR_SUPPORT + sensorSetMagnitudeRead(_rpnSensorMagnitudeRead); +#endif espurnaRegisterReload(_rpnConfigure); espurnaRegisterLoop(_rpnLoop); diff --git a/code/espurna/scheduler.cpp b/code/espurna/scheduler.cpp index b2de9649..1a66e62c 100644 --- a/code/espurna/scheduler.cpp +++ b/code/espurna/scheduler.cpp @@ -11,7 +11,6 @@ Adapted by Xose Pérez #if SCHEDULER_SUPPORT -#include "broker.h" #include "light.h" #include "ntp.h" #include "ntp_timelib.h" diff --git a/code/espurna/sensor.cpp b/code/espurna/sensor.cpp index c7a7f662..307120e6 100644 --- a/code/espurna/sensor.cpp +++ b/code/espurna/sensor.cpp @@ -11,7 +11,6 @@ Copyright (C) 2016-2019 by Xose Pérez #if SENSOR_SUPPORT #include "api.h" -#include "broker.h" #include "domoticz.h" #include "i2c.h" #include "mqtt.h" @@ -528,9 +527,6 @@ void _magnitudeSaveEnergyTotal(sensor_magnitude_t& magnitude, bool persistent) { // --------------------------------------------------------------------------- -BrokerBind(SensorReadBroker); -BrokerBind(SensorReportBroker); - std::vector _sensors; std::vector _magnitudes; bool _sensors_ready = false; @@ -539,6 +535,22 @@ bool _sensor_realtime = API_REAL_TIME_VALUES; unsigned long _sensor_read_interval = 1000 * SENSOR_READ_INTERVAL; unsigned char _sensor_report_every = SENSOR_REPORT_EVERY; +// --------------------------------------------------------------------------- + +using MagnitudeReadHandlers = std::forward_list; + +MagnitudeReadHandlers _magnitude_read_handlers; + +void sensorSetMagnitudeRead(MagnitudeReadHandler handler) { + _magnitude_read_handlers.push_front(handler); +} + +MagnitudeReadHandlers _magnitude_report_handlers; + +void sensorSetMagnitudeReport(MagnitudeReadHandler handler) { + _magnitude_report_handlers.push_front(handler); +} + // ----------------------------------------------------------------------------- // Private // ----------------------------------------------------------------------------- @@ -2258,9 +2270,9 @@ void _sensorReport(unsigned char index, const sensor_magnitude_t& magnitude) { char buffer[64]; dtostrf(magnitude.reported, 1, magnitude.decimals, buffer); -#if BROKER_SUPPORT - SensorReportBroker::Publish(magnitudeTopic(magnitude.type), magnitude.index_global, magnitude.reported, buffer); -#endif + for (auto& handler : _magnitude_report_handlers) { + handler(magnitudeTopic(magnitude.type), magnitude.index_global, magnitude.reported, buffer); + } #if MQTT_SUPPORT { @@ -2364,7 +2376,7 @@ namespace settings { namespace internal { template <> -sensor::Unit convert(const String& string) { +sensor::Unit convert(const String& value) { auto len = value.length(); if (len && isNumber(value)) { constexpr int Min { static_cast(sensor::Unit::Min_) }; @@ -2811,13 +2823,13 @@ void sensorLoop() { // ------------------------------------------------------------- value_show = _magnitudeProcess(magnitude, value_raw); -#if BROKER_SUPPORT { char buffer[64]; dtostrf(value_show, 1, magnitude.decimals, buffer); - SensorReadBroker::Publish(magnitudeTopic(magnitude.type), magnitude.index_global, value_show, buffer); + for (auto& handler : _magnitude_read_handlers) { + handler(magnitudeTopic(magnitude.type), magnitude.index_global, value_show, buffer); + } } -#endif // ------------------------------------------------------------- // Debug diff --git a/code/espurna/sensor.h b/code/espurna/sensor.h index cdf278bb..1e888555 100644 --- a/code/espurna/sensor.h +++ b/code/espurna/sensor.h @@ -11,8 +11,6 @@ Copyright (C) 2020 by Maxim Prokhorov #include "espurna.h" -#include "broker.h" - //-------------------------------------------------------------------------------- namespace sensor { @@ -137,8 +135,9 @@ struct Value { } -BrokerDeclare(SensorReadBroker, void(const String&, unsigned char, double, const char*)); -BrokerDeclare(SensorReportBroker, void(const String&, unsigned char, double, const char*)); +using MagnitudeReadHandler = void(*)(const String&, unsigned char, double, const char*); +void sensorSetMagnitudeRead(MagnitudeReadHandler handler); +void sensorSetMagnitudeReport(MagnitudeReadHandler handler); String magnitudeUnits(unsigned char index); String magnitudeDescription(unsigned char index); diff --git a/code/espurna/terminal.cpp b/code/espurna/terminal.cpp index b999c7c4..326d4712 100644 --- a/code/espurna/terminal.cpp +++ b/code/espurna/terminal.cpp @@ -351,7 +351,7 @@ void _terminalInitCommands() { auto count = 1; if (ctx.argc == 2) { count = ctx.argv[1].toInt(); - if (arg < SYSTEM_CHECK_MAX) { + if (count < SYSTEM_CHECK_MAX) { systemStabilityCounter(count); } } diff --git a/code/espurna/tuya.cpp b/code/espurna/tuya.cpp index 2168917d..4990153f 100644 --- a/code/espurna/tuya.cpp +++ b/code/espurna/tuya.cpp @@ -12,7 +12,6 @@ Copyright (C) 2019-2021 by Maxim Prokhorov