diff --git a/code/espurna/alexa.cpp b/code/espurna/alexa.cpp index 2e747473..93c8e8a7 100644 --- a/code/espurna/alexa.cpp +++ b/code/espurna/alexa.cpp @@ -15,6 +15,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include "broker.h" #include "light.h" #include "relay.h" +#include "rpc.h" #include "web.h" #include "ws.h" @@ -56,7 +57,6 @@ void _alexaConfigure() { } #endif -#if BROKER_SUPPORT void _alexaBrokerCallback(const String& topic, unsigned char id, unsigned int value) { // Only process status messages for switches and channels @@ -77,7 +77,6 @@ void _alexaBrokerCallback(const String& topic, unsigned char id, unsigned int va } } -#endif // BROKER_SUPPORT // ----------------------------------------------------------------------------- @@ -181,9 +180,7 @@ void alexaSetup() { }); // Register main callbacks - #if BROKER_SUPPORT - StatusBroker::Register(_alexaBrokerCallback); - #endif + StatusBroker::Register(_alexaBrokerCallback); espurnaRegisterReload(_alexaConfigure); espurnaRegisterLoop(alexaLoop); diff --git a/code/espurna/broker.h b/code/espurna/broker.h index 8f221d1c..8fd9361c 100644 --- a/code/espurna/broker.h +++ b/code/espurna/broker.h @@ -8,47 +8,82 @@ Copyright (C) 2017-2019 by Xose Pérez #pragma once -#include "espurna.h" - #include -#include #include +#include +#include -enum class TBrokerType { - System, - Status, - SensorRead, - SensorReport, - Datetime, - Config -}; +// 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 { -template -using TBrokerCallback = std::function; + using TArgs = typename std::tuple; + using TCallback = std::function; + using TCallbacks = std::vector; -template -using TBrokerCallbacks = std::vector>; + TBroker(const TBroker&) = delete; + TBroker& operator=(const TBroker&) = delete; -template -struct TBroker { - static TBrokerCallbacks callbacks; + TBroker() = default; - static void Register(TBrokerCallback callback) { + // 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); } - static void Publish(TArgs... args) { + + void Publish(Args... args) { for (auto& callback : callbacks) { callback(args...); } } + + protected: + + TCallbacks callbacks; + }; -template -TBrokerCallbacks TBroker::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. -using StatusBroker = TBroker; +#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)...); \ +}\ +} -using SensorReadBroker = TBroker; -using SensorReportBroker = TBroker; +#define BrokerBind(Name) \ +namespace Name { \ +Name::type Instance; \ +} -using ConfigBroker = TBroker; diff --git a/code/espurna/button.cpp b/code/espurna/button.cpp index 84ed6956..3d81acb6 100644 --- a/code/espurna/button.cpp +++ b/code/espurna/button.cpp @@ -26,6 +26,8 @@ Copyright (C) 2016-2019 by Xose Pérez #include "libs/DebounceEvent.h" +BrokerBind(ButtonBroker); + // TODO: if we are using such conversion helpers across the codebase, should convert() be in internal ns? namespace settings { @@ -455,6 +457,10 @@ void buttonEvent(unsigned char id, button_event_t event) { auto& button = _buttons[id]; auto action = _buttonDecodeEventAction(button.actions, event); + #if BROKER_SUPPORT + ButtonBroker::Publish(id, event); + #endif + #if MQTT_SUPPORT if (action || _buttons_mqtt_send_all[id]) { buttonMQTT(id, event); diff --git a/code/espurna/button.h b/code/espurna/button.h index eaf648a8..c673468e 100644 --- a/code/espurna/button.h +++ b/code/espurna/button.h @@ -10,6 +10,8 @@ Copyright (C) 2016-2019 by Xose Pérez #include "espurna.h" +#include "broker.h" + #include "libs/BasePin.h" #include "libs/DebounceEvent.h" @@ -67,6 +69,8 @@ struct button_t { }; +BrokerDeclare(ButtonBroker, void(unsigned char id, button_event_t event)); + bool buttonState(unsigned char id); button_action_t buttonAction(unsigned char id, const button_event_t event); diff --git a/code/espurna/domoticz.cpp b/code/espurna/domoticz.cpp index 68dff106..b0691899 100644 --- a/code/espurna/domoticz.cpp +++ b/code/espurna/domoticz.cpp @@ -14,6 +14,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include "light.h" #include "mqtt.h" #include "relay.h" +#include "rpc.h" #include "sensor.h" #include "ws.h" @@ -191,8 +192,6 @@ void _domoticzConfigure() { _dcz_enabled = enabled; } -#if BROKER_SUPPORT - void _domoticzConfigCallback(const String& key, const String& value) { if (key.equals("relayDummy")) { _domoticzRelayConfigure(value.toInt()); @@ -213,8 +212,6 @@ void _domoticzBrokerCallback(const String& topic, unsigned char id, unsigned int } -#endif // BROKER_SUPPORT - #if SENSOR_SUPPORT void domoticzSendMagnitude(unsigned char type, unsigned char index, double value, const char* buffer) { @@ -328,10 +325,8 @@ void domoticzSetup() { .onKeyCheck(_domoticzWebSocketOnKeyCheck); #endif - #if BROKER_SUPPORT - StatusBroker::Register(_domoticzBrokerCallback); - ConfigBroker::Register(_domoticzConfigCallback); - #endif + StatusBroker::Register(_domoticzBrokerCallback); + ConfigBroker::Register(_domoticzConfigCallback); // Callbacks mqttRegister(_domoticzMqtt); diff --git a/code/espurna/espurna.h b/code/espurna/espurna.h index c8509383..9fe0c8a2 100644 --- a/code/espurna/espurna.h +++ b/code/espurna/espurna.h @@ -24,6 +24,7 @@ along with this program. If not, see . #include "config/all.h" #include "board.h" +#include "broker.h" #include "debug.h" #include "compat.h" #include "wifi.h" diff --git a/code/espurna/influxdb.cpp b/code/espurna/influxdb.cpp index 5c4eb1de..e2ebca2b 100644 --- a/code/espurna/influxdb.cpp +++ b/code/espurna/influxdb.cpp @@ -14,8 +14,10 @@ Copyright (C) 2017-2019 by Xose Pérez #include #include "broker.h" -#include "ws.h" +#include "rpc.h" +#include "sensor.h" #include "terminal.h" +#include "ws.h" #include "libs/AsyncClientHelpers.h" const char InfluxDb_http_success[] = "HTTP/1.1 204"; @@ -152,8 +154,6 @@ void _idbConfigure() { if (_idb_enabled && !_idb_client) _idbInitClient(); } -#if BROKER_SUPPORT - void _idbBrokerSensor(const String& topic, unsigned char id, double, const char* value) { idbSend(topic.c_str(), id, value); } @@ -162,8 +162,6 @@ void _idbBrokerStatus(const String& topic, unsigned char id, unsigned int value) idbSend(topic.c_str(), id, String(int(value)).c_str()); } -#endif // BROKER_SUPPORT - // ----------------------------------------------------------------------------- bool idbSend(const char * topic, const char * payload) { @@ -260,8 +258,9 @@ void idbSetup() { .onKeyCheck(_idbWebSocketOnKeyCheck); #endif - #if BROKER_SUPPORT - StatusBroker::Register(_idbBrokerStatus); + StatusBroker::Register(_idbBrokerStatus); + + #if SENSOR_SUPPORT SensorReportBroker::Register(_idbBrokerSensor); #endif diff --git a/code/espurna/led.cpp b/code/espurna/led.cpp index 3bc26abf..5787de4f 100644 --- a/code/espurna/led.cpp +++ b/code/espurna/led.cpp @@ -234,7 +234,6 @@ void _ledWebSocketOnConnected(JsonObject& root) { #endif -#if BROKER_SUPPORT void _ledBrokerCallback(const String& topic, unsigned char, unsigned int) { // Only process status messages for switches @@ -243,7 +242,6 @@ void _ledBrokerCallback(const String& topic, unsigned char, unsigned int) { } } -#endif // BROKER_SUPPORT #if MQTT_SUPPORT void _ledMQTTCallback(unsigned int type, const char * topic, const char * payload) { @@ -488,10 +486,7 @@ void ledSetup() { .onKeyCheck(_ledWebSocketOnKeyCheck); #endif - #if BROKER_SUPPORT - StatusBroker::Register(_ledBrokerCallback); - #endif - + StatusBroker::Register(_ledBrokerCallback); 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 393c3106..078e918c 100644 --- a/code/espurna/light.cpp +++ b/code/espurna/light.cpp @@ -13,6 +13,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include "api.h" #include "broker.h" #include "mqtt.h" +#include "rpc.h" #include "rtcmem.h" #include "tuya.h" #include "ws.h" diff --git a/code/espurna/ntp.cpp b/code/espurna/ntp.cpp index dd86047d..f2e7e3c3 100644 --- a/code/espurna/ntp.cpp +++ b/code/espurna/ntp.cpp @@ -29,6 +29,8 @@ static_assert( #include "broker.h" #include "ws.h" +BrokerBind(NtpBroker); + // Arduino/esp8266 lwip2 custom functions that can be redefined // Must return time in milliseconds, legacy settings are in seconds. diff --git a/code/espurna/ntp.h b/code/espurna/ntp.h index 7deed613..9f024b5f 100644 --- a/code/espurna/ntp.h +++ b/code/espurna/ntp.h @@ -44,7 +44,7 @@ struct NtpCalendarWeekday { int utc_minute; }; -using NtpBroker = TBroker; +BrokerDeclare(NtpBroker, void(const NtpTick, time_t, const String&)); String ntpDateTime(tm* timestruct); String ntpDateTime(time_t ts); diff --git a/code/espurna/ntp_legacy.cpp b/code/espurna/ntp_legacy.cpp index 98b58a1e..1386b7ba 100644 --- a/code/espurna/ntp_legacy.cpp +++ b/code/espurna/ntp_legacy.cpp @@ -16,6 +16,8 @@ Copyright (C) 2016-2019 by Xose Pérez #include "broker.h" #include "ws.h" +BrokerBind(NtpBroker); + Ticker _ntp_defer; bool _ntp_report = false; diff --git a/code/espurna/rpc.cpp b/code/espurna/rpc.cpp index 58bed101..970027b5 100644 --- a/code/espurna/rpc.cpp +++ b/code/espurna/rpc.cpp @@ -6,12 +6,15 @@ Copyright (C) 2020 by Maxim Prokhorov */ +#include "rpc.h" + #include #include #include "system.h" #include "utils.h" -#include "rpc.h" + +BrokerBind(StatusBroker); bool rpcHandleAction(const String& action) { bool result = false; diff --git a/code/espurna/rpc.h b/code/espurna/rpc.h index aa88c6e6..08370b6e 100644 --- a/code/espurna/rpc.h +++ b/code/espurna/rpc.h @@ -8,8 +8,11 @@ Part of MQTT and API modules #include "espurna.h" -#include -#include +#include "broker.h" + +BrokerDeclare(StatusBroker, void(const String& topic, unsigned char id, unsigned int status)); + +// -------------------------------------------------------------------------- enum class PayloadStatus { Off = 0, diff --git a/code/espurna/rpnrules.cpp b/code/espurna/rpnrules.cpp index e405079f..d54f0c4d 100644 --- a/code/espurna/rpnrules.cpp +++ b/code/espurna/rpnrules.cpp @@ -14,6 +14,8 @@ Copyright (C) 2019 by Xose Pérez #include "mqtt.h" #include "ntp.h" #include "relay.h" +#include "rpc.h" +#include "sensor.h" #include "terminal.h" #include "ws.h" @@ -391,7 +393,10 @@ void rpnSetup() { #endif StatusBroker::Register(_rpnBrokerStatus); - SensorReadBroker::Register(_rpnBrokerCallback); + + #if SENSOR_SUPPORT + SensorReadBroker::Register(_rpnBrokerCallback); + #endif espurnaRegisterReload(_rpnConfigure); espurnaRegisterLoop(_rpnLoop); diff --git a/code/espurna/sensor.cpp b/code/espurna/sensor.cpp index f80f1232..0e90b369 100644 --- a/code/espurna/sensor.cpp +++ b/code/espurna/sensor.cpp @@ -436,6 +436,9 @@ void _magnitudeSaveEnergyTotal(sensor_magnitude_t& magnitude, bool persistent) { // --------------------------------------------------------------------------- +BrokerBind(SensorReadBroker); +BrokerBind(SensorReportBroker); + std::vector _sensors; std::vector _magnitudes; bool _sensors_ready = false; diff --git a/code/espurna/sensor.h b/code/espurna/sensor.h index bc0276b9..38cb75ea 100644 --- a/code/espurna/sensor.h +++ b/code/espurna/sensor.h @@ -11,6 +11,8 @@ Copyright (C) 2020 by Maxim Prokhorov #include "espurna.h" +#include "broker.h" + //-------------------------------------------------------------------------------- namespace sensor { @@ -125,6 +127,9 @@ struct Energy { } +BrokerDeclare(SensorReadBroker, void(const String&, unsigned char, double, const char*)); +BrokerDeclare(SensorReportBroker, void(const String&, unsigned char, double, const char*)); + String magnitudeName(unsigned char index); String magnitudeUnits(unsigned char index); unsigned char magnitudeType(unsigned char index); diff --git a/code/espurna/settings.cpp b/code/espurna/settings.cpp index b6024d52..aeef61ee 100644 --- a/code/espurna/settings.cpp +++ b/code/espurna/settings.cpp @@ -13,6 +13,10 @@ Copyright (C) 2016-2019 by Xose Pérez #include +// ----------------------------------------------------------------------------- + +BrokerBind(ConfigBroker); + // ----------------------------------------------------------------------------- // (HACK) Embedis storage format, reverse engineered // ----------------------------------------------------------------------------- diff --git a/code/espurna/settings.h b/code/espurna/settings.h index c168fc6c..8b5db050 100644 --- a/code/espurna/settings.h +++ b/code/espurna/settings.h @@ -16,8 +16,11 @@ Copyright (C) 2016-2019 by Xose Pérez #include #include "espurna.h" +#include "broker.h" #include "libs/EmbedisWrap.h" +BrokerDeclare(ConfigBroker, void(const String& key, const String& value)); + // -------------------------------------------------------------------------- class settings_key_t { diff --git a/code/espurna/thingspeak.cpp b/code/espurna/thingspeak.cpp index f9047437..e5f6da9f 100644 --- a/code/espurna/thingspeak.cpp +++ b/code/espurna/thingspeak.cpp @@ -14,6 +14,7 @@ Copyright (C) 2019 by Xose Pérez #include "broker.h" #include "relay.h" +#include "rpc.h" #include "sensor.h" #include "ws.h" #include "libs/URL.h" @@ -78,7 +79,6 @@ AsyncClientState _tspk_state = AsyncClientState::Disconnected; // ----------------------------------------------------------------------------- -#if BROKER_SUPPORT void _tspkBrokerCallback(const String& topic, unsigned char id, unsigned int value) { // Only process status messages for switches @@ -90,8 +90,6 @@ void _tspkBrokerCallback(const String& topic, unsigned char id, unsigned int val tspkFlush(); } -#endif // BROKER_SUPPORT - #if WEB_SUPPORT @@ -458,9 +456,7 @@ void tspkSetup() { .onKeyCheck(_tspkWebSocketOnKeyCheck); #endif - #if BROKER_SUPPORT - StatusBroker::Register(_tspkBrokerCallback); - #endif + StatusBroker::Register(_tspkBrokerCallback); DEBUG_MSG_P(PSTR("[THINGSPEAK] Async %s, SSL %s\n"), THINGSPEAK_USE_ASYNC ? "ENABLED" : "DISABLED", diff --git a/code/espurna/tuya.cpp b/code/espurna/tuya.cpp index e42878dd..3336584c 100644 --- a/code/espurna/tuya.cpp +++ b/code/espurna/tuya.cpp @@ -13,8 +13,9 @@ Copyright (C) 2019 by Maxim Prokhorov #if TUYA_SUPPORT #include "broker.h" -#include "relay.h" #include "light.h" +#include "relay.h" +#include "rpc.h" #include #include