Browse Source

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
mcspr-patch-1
Max Prokhorov 4 years ago
committed by GitHub
parent
commit
84b51cf680
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 124 additions and 64 deletions
  1. +2
    -5
      code/espurna/alexa.cpp
  2. +61
    -26
      code/espurna/broker.h
  3. +6
    -0
      code/espurna/button.cpp
  4. +4
    -0
      code/espurna/button.h
  5. +3
    -8
      code/espurna/domoticz.cpp
  6. +1
    -0
      code/espurna/espurna.h
  7. +6
    -7
      code/espurna/influxdb.cpp
  8. +1
    -6
      code/espurna/led.cpp
  9. +1
    -0
      code/espurna/light.cpp
  10. +2
    -0
      code/espurna/ntp.cpp
  11. +1
    -1
      code/espurna/ntp.h
  12. +2
    -0
      code/espurna/ntp_legacy.cpp
  13. +4
    -1
      code/espurna/rpc.cpp
  14. +5
    -2
      code/espurna/rpc.h
  15. +6
    -1
      code/espurna/rpnrules.cpp
  16. +3
    -0
      code/espurna/sensor.cpp
  17. +5
    -0
      code/espurna/sensor.h
  18. +4
    -0
      code/espurna/settings.cpp
  19. +3
    -0
      code/espurna/settings.h
  20. +2
    -6
      code/espurna/thingspeak.cpp
  21. +2
    -1
      code/espurna/tuya.cpp

+ 2
- 5
code/espurna/alexa.cpp View File

@ -15,6 +15,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "broker.h" #include "broker.h"
#include "light.h" #include "light.h"
#include "relay.h" #include "relay.h"
#include "rpc.h"
#include "web.h" #include "web.h"
#include "ws.h" #include "ws.h"
@ -56,7 +57,6 @@ void _alexaConfigure() {
} }
#endif #endif
#if BROKER_SUPPORT
void _alexaBrokerCallback(const String& topic, unsigned char id, unsigned int value) { void _alexaBrokerCallback(const String& topic, unsigned char id, unsigned int value) {
// Only process status messages for switches and channels // 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 // Register main callbacks
#if BROKER_SUPPORT
StatusBroker::Register(_alexaBrokerCallback);
#endif
StatusBroker::Register(_alexaBrokerCallback);
espurnaRegisterReload(_alexaConfigure); espurnaRegisterReload(_alexaConfigure);
espurnaRegisterLoop(alexaLoop); espurnaRegisterLoop(alexaLoop);


+ 61
- 26
code/espurna/broker.h View File

@ -8,47 +8,82 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#pragma once #pragma once
#include "espurna.h"
#include <functional> #include <functional>
#include <vector>
#include <utility> #include <utility>
#include <vector>
#include <tuple>
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 <typename Func>
struct TBroker {};
template <typename R, typename ...Args>
struct TBroker<R(Args...)> {
template <typename... TArgs>
using TBrokerCallback = std::function<void(TArgs...)>;
using TArgs = typename std::tuple<Args...>;
using TCallback = std::function<R(Args...)>;
using TCallbacks = std::vector<TCallback>;
template <typename... TArgs>
using TBrokerCallbacks = std::vector<TBrokerCallback<TArgs...>>;
TBroker(const TBroker&) = delete;
TBroker& operator=(const TBroker&) = delete;
template <TBrokerType type, typename... TArgs>
struct TBroker {
static TBrokerCallbacks<TArgs...> callbacks;
TBroker() = default;
static void Register(TBrokerCallback<TArgs...> 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); callbacks.push_back(callback);
} }
static void Publish(TArgs... args) {
void Publish(Args... args) {
for (auto& callback : callbacks) { for (auto& callback : callbacks) {
callback(args...); callback(args...);
} }
} }
protected:
TCallbacks callbacks;
}; };
template <TBrokerType type, typename... TArgs>
TBrokerCallbacks<TArgs...> TBroker<type, TArgs...>::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<TBrokerType::Status, const String&, unsigned char, unsigned int>;
#define BrokerDeclare(Name, Signature) \
namespace Name { \
using type = TBroker<Signature>; \
extern type Instance; \
template<typename S = type::TArgs, typename ...Args> \
inline void Register(Args&&... args) { \
Instance.Register(std::forward<Args>(args)...); \
}\
\
template<typename S = type::TArgs, typename ...Args> \
inline void Publish(Args&&... args) { \
Instance.Publish(std::forward<Args>(args)...); \
}\
}
using SensorReadBroker = TBroker<TBrokerType::SensorRead, const String&, unsigned char, double, const char*>;
using SensorReportBroker = TBroker<TBrokerType::SensorReport, const String&, unsigned char, double, const char*>;
#define BrokerBind(Name) \
namespace Name { \
Name::type Instance; \
}
using ConfigBroker = TBroker<TBrokerType::Config, const String&, const String&>;

+ 6
- 0
code/espurna/button.cpp View File

@ -26,6 +26,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "libs/DebounceEvent.h" #include "libs/DebounceEvent.h"
BrokerBind(ButtonBroker);
// TODO: if we are using such conversion helpers across the codebase, should convert() be in internal ns? // TODO: if we are using such conversion helpers across the codebase, should convert() be in internal ns?
namespace settings { namespace settings {
@ -455,6 +457,10 @@ void buttonEvent(unsigned char id, button_event_t event) {
auto& button = _buttons[id]; auto& button = _buttons[id];
auto action = _buttonDecodeEventAction(button.actions, event); auto action = _buttonDecodeEventAction(button.actions, event);
#if BROKER_SUPPORT
ButtonBroker::Publish(id, event);
#endif
#if MQTT_SUPPORT #if MQTT_SUPPORT
if (action || _buttons_mqtt_send_all[id]) { if (action || _buttons_mqtt_send_all[id]) {
buttonMQTT(id, event); buttonMQTT(id, event);


+ 4
- 0
code/espurna/button.h View File

@ -10,6 +10,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "espurna.h" #include "espurna.h"
#include "broker.h"
#include "libs/BasePin.h" #include "libs/BasePin.h"
#include "libs/DebounceEvent.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); bool buttonState(unsigned char id);
button_action_t buttonAction(unsigned char id, const button_event_t event); button_action_t buttonAction(unsigned char id, const button_event_t event);


+ 3
- 8
code/espurna/domoticz.cpp View File

@ -14,6 +14,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "light.h" #include "light.h"
#include "mqtt.h" #include "mqtt.h"
#include "relay.h" #include "relay.h"
#include "rpc.h"
#include "sensor.h" #include "sensor.h"
#include "ws.h" #include "ws.h"
@ -191,8 +192,6 @@ void _domoticzConfigure() {
_dcz_enabled = enabled; _dcz_enabled = enabled;
} }
#if BROKER_SUPPORT
void _domoticzConfigCallback(const String& key, const String& value) { void _domoticzConfigCallback(const String& key, const String& value) {
if (key.equals("relayDummy")) { if (key.equals("relayDummy")) {
_domoticzRelayConfigure(value.toInt()); _domoticzRelayConfigure(value.toInt());
@ -213,8 +212,6 @@ void _domoticzBrokerCallback(const String& topic, unsigned char id, unsigned int
} }
#endif // BROKER_SUPPORT
#if SENSOR_SUPPORT #if SENSOR_SUPPORT
void domoticzSendMagnitude(unsigned char type, unsigned char index, double value, const char* buffer) { void domoticzSendMagnitude(unsigned char type, unsigned char index, double value, const char* buffer) {
@ -328,10 +325,8 @@ void domoticzSetup() {
.onKeyCheck(_domoticzWebSocketOnKeyCheck); .onKeyCheck(_domoticzWebSocketOnKeyCheck);
#endif #endif
#if BROKER_SUPPORT
StatusBroker::Register(_domoticzBrokerCallback);
ConfigBroker::Register(_domoticzConfigCallback);
#endif
StatusBroker::Register(_domoticzBrokerCallback);
ConfigBroker::Register(_domoticzConfigCallback);
// Callbacks // Callbacks
mqttRegister(_domoticzMqtt); mqttRegister(_domoticzMqtt);


+ 1
- 0
code/espurna/espurna.h View File

@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "config/all.h" #include "config/all.h"
#include "board.h" #include "board.h"
#include "broker.h"
#include "debug.h" #include "debug.h"
#include "compat.h" #include "compat.h"
#include "wifi.h" #include "wifi.h"


+ 6
- 7
code/espurna/influxdb.cpp View File

@ -14,8 +14,10 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <memory> #include <memory>
#include "broker.h" #include "broker.h"
#include "ws.h"
#include "rpc.h"
#include "sensor.h"
#include "terminal.h" #include "terminal.h"
#include "ws.h"
#include "libs/AsyncClientHelpers.h" #include "libs/AsyncClientHelpers.h"
const char InfluxDb_http_success[] = "HTTP/1.1 204"; const char InfluxDb_http_success[] = "HTTP/1.1 204";
@ -152,8 +154,6 @@ void _idbConfigure() {
if (_idb_enabled && !_idb_client) _idbInitClient(); if (_idb_enabled && !_idb_client) _idbInitClient();
} }
#if BROKER_SUPPORT
void _idbBrokerSensor(const String& topic, unsigned char id, double, const char* value) { void _idbBrokerSensor(const String& topic, unsigned char id, double, const char* value) {
idbSend(topic.c_str(), id, 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()); idbSend(topic.c_str(), id, String(int(value)).c_str());
} }
#endif // BROKER_SUPPORT
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
bool idbSend(const char * topic, const char * payload) { bool idbSend(const char * topic, const char * payload) {
@ -260,8 +258,9 @@ void idbSetup() {
.onKeyCheck(_idbWebSocketOnKeyCheck); .onKeyCheck(_idbWebSocketOnKeyCheck);
#endif #endif
#if BROKER_SUPPORT
StatusBroker::Register(_idbBrokerStatus);
StatusBroker::Register(_idbBrokerStatus);
#if SENSOR_SUPPORT
SensorReportBroker::Register(_idbBrokerSensor); SensorReportBroker::Register(_idbBrokerSensor);
#endif #endif


+ 1
- 6
code/espurna/led.cpp View File

@ -234,7 +234,6 @@ void _ledWebSocketOnConnected(JsonObject& root) {
#endif #endif
#if BROKER_SUPPORT
void _ledBrokerCallback(const String& topic, unsigned char, unsigned int) { void _ledBrokerCallback(const String& topic, unsigned char, unsigned int) {
// Only process status messages for switches // 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 #if MQTT_SUPPORT
void _ledMQTTCallback(unsigned int type, const char * topic, const char * payload) { void _ledMQTTCallback(unsigned int type, const char * topic, const char * payload) {
@ -488,10 +486,7 @@ void ledSetup() {
.onKeyCheck(_ledWebSocketOnKeyCheck); .onKeyCheck(_ledWebSocketOnKeyCheck);
#endif #endif
#if BROKER_SUPPORT
StatusBroker::Register(_ledBrokerCallback);
#endif
StatusBroker::Register(_ledBrokerCallback);
DEBUG_MSG_P(PSTR("[LED] Number of leds: %d\n"), _leds.size()); DEBUG_MSG_P(PSTR("[LED] Number of leds: %d\n"), _leds.size());


+ 1
- 0
code/espurna/light.cpp View File

@ -13,6 +13,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "api.h" #include "api.h"
#include "broker.h" #include "broker.h"
#include "mqtt.h" #include "mqtt.h"
#include "rpc.h"
#include "rtcmem.h" #include "rtcmem.h"
#include "tuya.h" #include "tuya.h"
#include "ws.h" #include "ws.h"


+ 2
- 0
code/espurna/ntp.cpp View File

@ -29,6 +29,8 @@ static_assert(
#include "broker.h" #include "broker.h"
#include "ws.h" #include "ws.h"
BrokerBind(NtpBroker);
// Arduino/esp8266 lwip2 custom functions that can be redefined // Arduino/esp8266 lwip2 custom functions that can be redefined
// Must return time in milliseconds, legacy settings are in seconds. // Must return time in milliseconds, legacy settings are in seconds.


+ 1
- 1
code/espurna/ntp.h View File

@ -44,7 +44,7 @@ struct NtpCalendarWeekday {
int utc_minute; int utc_minute;
}; };
using NtpBroker = TBroker<TBrokerType::Datetime, const NtpTick, time_t, const String&>;
BrokerDeclare(NtpBroker, void(const NtpTick, time_t, const String&));
String ntpDateTime(tm* timestruct); String ntpDateTime(tm* timestruct);
String ntpDateTime(time_t ts); String ntpDateTime(time_t ts);


+ 2
- 0
code/espurna/ntp_legacy.cpp View File

@ -16,6 +16,8 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "broker.h" #include "broker.h"
#include "ws.h" #include "ws.h"
BrokerBind(NtpBroker);
Ticker _ntp_defer; Ticker _ntp_defer;
bool _ntp_report = false; bool _ntp_report = false;


+ 4
- 1
code/espurna/rpc.cpp View File

@ -6,12 +6,15 @@ Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
*/ */
#include "rpc.h"
#include <Schedule.h> #include <Schedule.h>
#include <cstring> #include <cstring>
#include "system.h" #include "system.h"
#include "utils.h" #include "utils.h"
#include "rpc.h"
BrokerBind(StatusBroker);
bool rpcHandleAction(const String& action) { bool rpcHandleAction(const String& action) {
bool result = false; bool result = false;


+ 5
- 2
code/espurna/rpc.h View File

@ -8,8 +8,11 @@ Part of MQTT and API modules
#include "espurna.h" #include "espurna.h"
#include <vector>
#include <utility>
#include "broker.h"
BrokerDeclare(StatusBroker, void(const String& topic, unsigned char id, unsigned int status));
// --------------------------------------------------------------------------
enum class PayloadStatus { enum class PayloadStatus {
Off = 0, Off = 0,


+ 6
- 1
code/espurna/rpnrules.cpp View File

@ -14,6 +14,8 @@ Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "mqtt.h" #include "mqtt.h"
#include "ntp.h" #include "ntp.h"
#include "relay.h" #include "relay.h"
#include "rpc.h"
#include "sensor.h"
#include "terminal.h" #include "terminal.h"
#include "ws.h" #include "ws.h"
@ -391,7 +393,10 @@ void rpnSetup() {
#endif #endif
StatusBroker::Register(_rpnBrokerStatus); StatusBroker::Register(_rpnBrokerStatus);
SensorReadBroker::Register(_rpnBrokerCallback);
#if SENSOR_SUPPORT
SensorReadBroker::Register(_rpnBrokerCallback);
#endif
espurnaRegisterReload(_rpnConfigure); espurnaRegisterReload(_rpnConfigure);
espurnaRegisterLoop(_rpnLoop); espurnaRegisterLoop(_rpnLoop);


+ 3
- 0
code/espurna/sensor.cpp View File

@ -436,6 +436,9 @@ void _magnitudeSaveEnergyTotal(sensor_magnitude_t& magnitude, bool persistent) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
BrokerBind(SensorReadBroker);
BrokerBind(SensorReportBroker);
std::vector<BaseSensor *> _sensors; std::vector<BaseSensor *> _sensors;
std::vector<sensor_magnitude_t> _magnitudes; std::vector<sensor_magnitude_t> _magnitudes;
bool _sensors_ready = false; bool _sensors_ready = false;


+ 5
- 0
code/espurna/sensor.h View File

@ -11,6 +11,8 @@ Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#include "espurna.h" #include "espurna.h"
#include "broker.h"
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
namespace sensor { 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 magnitudeName(unsigned char index);
String magnitudeUnits(unsigned char index); String magnitudeUnits(unsigned char index);
unsigned char magnitudeType(unsigned char index); unsigned char magnitudeType(unsigned char index);


+ 4
- 0
code/espurna/settings.cpp View File

@ -13,6 +13,10 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <cstdlib> #include <cstdlib>
// -----------------------------------------------------------------------------
BrokerBind(ConfigBroker);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// (HACK) Embedis storage format, reverse engineered // (HACK) Embedis storage format, reverse engineered
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------


+ 3
- 0
code/espurna/settings.h View File

@ -16,8 +16,11 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include "espurna.h" #include "espurna.h"
#include "broker.h"
#include "libs/EmbedisWrap.h" #include "libs/EmbedisWrap.h"
BrokerDeclare(ConfigBroker, void(const String& key, const String& value));
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
class settings_key_t { class settings_key_t {


+ 2
- 6
code/espurna/thingspeak.cpp View File

@ -14,6 +14,7 @@ Copyright (C) 2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "broker.h" #include "broker.h"
#include "relay.h" #include "relay.h"
#include "rpc.h"
#include "sensor.h" #include "sensor.h"
#include "ws.h" #include "ws.h"
#include "libs/URL.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) { void _tspkBrokerCallback(const String& topic, unsigned char id, unsigned int value) {
// Only process status messages for switches // Only process status messages for switches
@ -90,8 +90,6 @@ void _tspkBrokerCallback(const String& topic, unsigned char id, unsigned int val
tspkFlush(); tspkFlush();
} }
#endif // BROKER_SUPPORT
#if WEB_SUPPORT #if WEB_SUPPORT
@ -458,9 +456,7 @@ void tspkSetup() {
.onKeyCheck(_tspkWebSocketOnKeyCheck); .onKeyCheck(_tspkWebSocketOnKeyCheck);
#endif #endif
#if BROKER_SUPPORT
StatusBroker::Register(_tspkBrokerCallback);
#endif
StatusBroker::Register(_tspkBrokerCallback);
DEBUG_MSG_P(PSTR("[THINGSPEAK] Async %s, SSL %s\n"), DEBUG_MSG_P(PSTR("[THINGSPEAK] Async %s, SSL %s\n"),
THINGSPEAK_USE_ASYNC ? "ENABLED" : "DISABLED", THINGSPEAK_USE_ASYNC ? "ENABLED" : "DISABLED",


+ 2
- 1
code/espurna/tuya.cpp View File

@ -13,8 +13,9 @@ Copyright (C) 2019 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#if TUYA_SUPPORT #if TUYA_SUPPORT
#include "broker.h" #include "broker.h"
#include "relay.h"
#include "light.h" #include "light.h"
#include "relay.h"
#include "rpc.h"
#include <functional> #include <functional>
#include <queue> #include <queue>


Loading…
Cancel
Save