From 84b51cf680d9b3b3733da2741d95b025d5dbcf2d Mon Sep 17 00:00:00 2001 From: Max Prokhorov Date: Mon, 18 May 2020 02:29:17 +0300 Subject: [PATCH] broker: declare and define per module (#2253) * broker: declare and define per module We no longer need to specify each Broker type in broker.h But, we exchange that bit for explicit initialization of the instance Define helper macros to generate boilerplate code - namespace with Instance, Register(), Publish() - forward Register(...) -> Instance.Register(...), Publish(...) -> Instance.Publish(...) * don't check for broker when deps enable it --- code/espurna/alexa.cpp | 7 +-- code/espurna/broker.h | 87 ++++++++++++++++++++++++++----------- code/espurna/button.cpp | 6 +++ code/espurna/button.h | 4 ++ code/espurna/domoticz.cpp | 11 ++--- code/espurna/espurna.h | 1 + code/espurna/influxdb.cpp | 13 +++--- code/espurna/led.cpp | 7 +-- code/espurna/light.cpp | 1 + code/espurna/ntp.cpp | 2 + code/espurna/ntp.h | 2 +- code/espurna/ntp_legacy.cpp | 2 + code/espurna/rpc.cpp | 5 ++- code/espurna/rpc.h | 7 ++- code/espurna/rpnrules.cpp | 7 ++- code/espurna/sensor.cpp | 3 ++ code/espurna/sensor.h | 5 +++ code/espurna/settings.cpp | 4 ++ code/espurna/settings.h | 3 ++ code/espurna/thingspeak.cpp | 8 +--- code/espurna/tuya.cpp | 3 +- 21 files changed, 124 insertions(+), 64 deletions(-) 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