dcz: flash strings and our own namespace

This commit is contained in:
Maxim Prokhorov
2022-05-25 02:57:26 +03:00
parent d2c7f7ea28
commit b23137f414

View File

@@ -22,32 +22,31 @@ Copyright (C) 2019-2021 by Maxim Prokhorov <prokhorov dot max at outlook dot com
#include <ArduinoJson.h>
#include <bitset>
namespace espurna {
namespace domoticz {
namespace {
struct Idx {
constexpr static size_t Default { 0 };
Idx() = default;
Idx(const Idx&) = default;
Idx(Idx&&) = default;
explicit Idx(size_t value) :
constexpr Idx() = default;
constexpr explicit Idx(size_t value) :
_value(value)
{}
explicit operator bool() const {
constexpr explicit operator bool() const {
return _value != Default;
}
bool operator==(size_t other) const {
constexpr bool operator==(size_t other) const {
return _value == other;
}
bool operator==(const Idx& other) {
constexpr bool operator==(const Idx& other) {
return _value == other._value;
}
size_t value() const {
constexpr size_t value() const {
return _value;
}
@@ -55,27 +54,33 @@ private:
size_t _value { Default };
};
} // namespace
} // namespace domoticz
} // namespace espurna
namespace settings {
namespace internal {
template <>
domoticz::Idx convert(const String& value) {
return domoticz::Idx(convert<size_t>(value));
espurna::domoticz::Idx convert(const String& value) {
return espurna::domoticz::Idx(convert<size_t>(value));
}
} // namespace internal
} // namespace settings
namespace espurna {
namespace domoticz {
namespace {
namespace internal {
namespace {
bool enabled { false };
} // namespace
} // namespace internal
namespace {
bool enabled() {
return internal::enabled;
}
@@ -88,9 +93,12 @@ void disable() {
internal::enabled = false;
}
namespace build {
} // namespace
constexpr Idx DefaultIdx{};
namespace build {
namespace {
static constexpr ::espurna::domoticz::Idx DefaultIdx;
const __FlashStringHelper* topicOut() {
return F(DOMOTICZ_OUT_TOPIC);
@@ -104,50 +112,77 @@ constexpr bool enabled() {
return 1 == DOMOTICZ_ENABLED;
}
} // namespace
} // namespace build
namespace settings {
namespace keys {
alignas(4) static constexpr char Enabled[] PROGMEM = "dczEnabled";
alignas(4) static constexpr char TopicOut[] PROGMEM = "dczTopicOut";
alignas(4) static constexpr char TopicIn[] PROGMEM = "dczTopicIn";
#if RELAY_SUPPORT
alignas(4) static constexpr char RelayIdx[] PROGMEM = "dczTopicIn";
#endif
#if SENSOR_SUPPORT
alignas(4) static constexpr char MagnitudeIdx[] PROGMEM = "dczTopicIn";
#endif
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
alignas(4) static constexpr char LightIdx[] PROGMEM = "dczLightIdx";
#endif
} // namespace keys
namespace {
bool enabled() {
return getSetting("dczEnabled", build::enabled());
return getSetting(FPSTR(keys::Enabled), build::enabled());
}
String topicOut() {
return getSetting("dczTopicOut", build::topicOut());
return getSetting(FPSTR(keys::TopicOut), build::topicOut());
}
String topicIn() {
return getSetting("dczTopicIn", build::topicIn());
return getSetting(FPSTR(keys::TopicIn), build::topicIn());
}
#if RELAY_SUPPORT
Idx relayIdx(size_t id) {
return getSetting({"dczRelayIdx", id}, build::DefaultIdx);
return getSetting({FPSTR(keys::RelayIdx), id}, build::DefaultIdx);
}
#endif
#if SENSOR_SUPPORT
Idx magnitudeIdx(size_t id) {
return getSetting({"dczMagnitude", id}, build::DefaultIdx);
return getSetting({FPSTR(keys::MagnitudeIdx), id}, build::DefaultIdx);
}
#endif
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
Idx lightIdx() {
return getSetting("dczLightIdx", build::DefaultIdx);
return getSetting(FPSTR(keys::LightIdx), build::DefaultIdx);
}
#endif
} // namespace
} // namespace settings
#if RELAY_SUPPORT
namespace relay {
namespace internal {
namespace {
std::bitset<RelaysMax> status;
} // namespace
} // namespace internal
namespace {
void send(Idx, bool);
void send();
@@ -177,14 +212,20 @@ void callback(size_t id, bool value) {
}
}
void setup() {
::relayOnStatusChange(callback);
}
} // namespace
} // namespace relay
#endif
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
namespace light {
namespace {
void status(const JsonObject& root, unsigned char nvalue) {
JsonObject& color = root["Color"];
JsonObject& color = root[F("Color")];
if (color.success()) {
// for ColorMode... see:
@@ -199,7 +240,7 @@ void status(const JsonObject& root, unsigned char nvalue) {
auto ww = color["ww"].as<long>();
DEBUG_MSG_P(PSTR("[DOMOTICZ] Dimmer nvalue:%hhu rgb:%ld,%ld,%ld ww:%ld,cw:%ld t:%ld brightness:%ld\n"),
nvalue, r, g, b, ww, cw, color["t"].as<long>(), color["Level"].as<long>());
nvalue, r, g, b, ww, cw, color["t"].as<long>(), color[F("Level")].as<long>());
// m field contains information about color mode (enum ColorMode from domoticz ColorSwitch.h):
switch (color["m"].as<int>()) {
@@ -223,15 +264,17 @@ void status(const JsonObject& root, unsigned char nvalue) {
}
// domoticz uses 100 as maximum value while we're using a custom scale
lightBrightnessPercent(root["Level"].as<long>());
lightBrightnessPercent(root[F("Level")].as<long>());
lightState(nvalue > 0);
lightUpdate();
}
} // namespace
} // namespace light
#endif
namespace mqtt {
namespace {
void subscribe() {
mqttSubscribeRaw(settings::topicOut().c_str());
@@ -264,19 +307,19 @@ void callback(unsigned int type, const char* topic, char* payload) {
return;
}
unsigned char nvalue = root["nvalue"];
Idx idx(root["idx"].as<size_t>());
unsigned char nvalue = root[F("nvalue")];
Idx idx(root[F("idx")].as<size_t>());
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
String stype = root["stype"];
String switchType = root["switchType"];
if ((idx == settings::lightIdx()) && (stype.startsWith("RGB") || (switchType.equals("Dimmer")))) {
domoticz::light::status(root, nvalue);
String stype = root[F("stype")];
String switchType = root[F("switchType")];
if ((idx == settings::lightIdx()) && (stype.startsWith(F("RGB")) || (switchType.equals(F("Dimmer"))))) {
espurna::domoticz::light::status(root, nvalue);
return;
}
#endif
domoticz::relay::status(idx, nvalue > 0);
espurna::domoticz::relay::status(idx, nvalue > 0);
return;
}
}
@@ -293,9 +336,9 @@ void send(Idx idx, int nvalue, const char* svalue) {
StaticJsonBuffer<JSON_OBJECT_SIZE(3)> json;
JsonObject& root = json.createObject();
root["idx"] = idx.value();
root["nvalue"] = nvalue;
root["svalue"] = svalue;
root[F("idx")] = idx.value();
root[F("nvalue")] = nvalue;
root[F("svalue")] = svalue;
char payload[128] = {0};
root.printTo(payload);
@@ -307,10 +350,16 @@ void send(Idx idx, int nvalue) {
send(idx, nvalue, "");
}
void setup() {
::mqttRegister(callback);
}
} // namespace
} // namespace mqtt
#if RELAY_SUPPORT
namespace relay {
namespace {
void send(Idx idx, bool value) {
mqtt::send(idx, value ? 1 : 0);
@@ -323,11 +372,13 @@ void send() {
}
}
} // namespace
} // namespace relay
#endif
#if SENSOR_SUPPORT
namespace sensor {
namespace {
void send(unsigned char index, const ::sensor::Value& value) {
if (!enabled()) {
@@ -373,50 +424,64 @@ void send(unsigned char index, const ::sensor::Value& value) {
}
}
} // namespace
} // namespace sensor
#endif // SENSOR_SUPPORT
#if WEB_SUPPORT
namespace web {
namespace {
alignas(4) static constexpr char Prefix[] PROGMEM = "dcz";
bool onKeyCheck(const char* key, JsonVariant& value) {
return (strncmp(key, "dcz", 3) == 0);
return (strncmp_P(key, Prefix, 3) == 0);
}
void onVisible(JsonObject& root) {
if (haveRelaysOrSensors()) {
wsPayloadModule(root, "dcz");
wsPayloadModule(root, Prefix);
}
}
void onConnected(JsonObject& root) {
root["dczEnabled"] = settings::enabled();
root["dczTopicIn"] = settings::topicIn();
root["dczTopicOut"] = settings::topicOut();
root[FPSTR(settings::keys::Enabled)] = settings::enabled();
root[FPSTR(settings::keys::TopicIn)] = settings::topicIn();
root[FPSTR(settings::keys::TopicOut)] = settings::topicOut();
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
root["dczLightIdx"] = settings::lightIdx().value();
root[FPSTR(settings::keys::LightIdx)] = settings::lightIdx().value();
#endif
const size_t Relays { relayCount() };
JsonArray& relays = root.createNestedArray("dczRelays");
JsonArray& relays = root.createNestedArray(F("dczRelays"));
for (size_t id = 0; id < Relays; ++id) {
relays.add(settings::relayIdx(id).value());
}
#if SENSOR_SUPPORT
sensorWebSocketMagnitudes(root, PSTR("dcz"), [](JsonArray& out, size_t index) {
out.add(getSetting({"dczMagnitude", index}, "0"));
out.add(settings::magnitudeIdx(index).value());
});
#endif
}
void setup() {
wsRegister()
.onVisible(onVisible)
.onConnected(onConnected)
.onKeyCheck(onKeyCheck);
}
} // namespace
} // namespace web
#endif // WEB_SUPPORT
//------------------------------------------------------------------------------
namespace {
void configure() {
auto enabled_in_cfg = settings::enabled();
if (enabled_in_cfg != enabled()) {
@@ -447,46 +512,46 @@ void migrate(int version) {
return;
}
moveSetting("dczRelayIdx0", "dczLightIdx");
moveSetting(F("dczRelayIdx0"), FPSTR(settings::keys::LightIdx));
}
}
#endif
} // namespace
} // namespace domoticz
#if SENSOR_SUPPORT
void domoticzSendMagnitude(unsigned char index, const sensor::Value& value) {
domoticz::sensor::send(index, value);
}
#endif
void domoticzSetup() {
void setup() {
#if RELAY_SUPPORT && (LIGHT_PROVIDER != LIGHT_PROVIDER_NONE)
migrateVersion(domoticz::migrate);
migrateVersion(migrate);
#endif
#if WEB_SUPPORT
wsRegister()
.onVisible(domoticz::web::onVisible)
.onConnected(domoticz::web::onConnected)
.onKeyCheck(domoticz::web::onKeyCheck);
web::setup();
#endif
#if RELAY_SUPPORT
relayOnStatusChange(domoticz::relay::callback);
relay::setup();
#endif
mqttRegister(domoticz::mqtt::callback);
espurnaRegisterReload(domoticz::configure);
mqtt::setup();
domoticz::configure();
::espurnaRegisterReload(configure);
configure();
}
} // namespace
} // namespace domoticz
} // namespace espurna
#if SENSOR_SUPPORT
void domoticzSendMagnitude(unsigned char index, const sensor::Value& value) {
espurna::domoticz::sensor::send(index, value);
}
#endif
bool domoticzEnabled() {
return domoticz::enabled();
return espurna::domoticz::enabled();
}
void domoticzSetup() {
espurna::domoticz::setup();
}
#endif