Skip to content

Commit

Permalink
refactor relaystatus into generic payloadstatus
Browse files Browse the repository at this point in the history
  • Loading branch information
mcspr committed Mar 5, 2020
1 parent 6d2f0cd commit 32bc78a
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 94 deletions.
6 changes: 4 additions & 2 deletions code/espurna/homeassistant.ino
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>

#include "homeassistant.h"
#include "mqtt.h"
#include "relay.h"
#include "rpc.h"
#include "ws.h"

bool _ha_enabled = false;
Expand Down Expand Up @@ -253,8 +255,8 @@ void _haSendSwitch(unsigned char i, JsonObject& config) {
if (relayCount()) {
config["state_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, false);
config["command_topic"] = mqttTopic(MQTT_TOPIC_RELAY, i, true);
config["payload_on"] = relayPayload(RelayStatus::ON);
config["payload_off"] = relayPayload(RelayStatus::OFF);
config["payload_on"] = relayPayload(PayloadStatus::On);
config["payload_off"] = relayPayload(PayloadStatus::Off);
config["availability_topic"] = mqttTopic(MQTT_TOPIC_STATUS, false);
config["payload_available"] = mqttPayloadStatus(true);
config["payload_not_available"] = mqttPayloadStatus(false);
Expand Down
16 changes: 8 additions & 8 deletions code/espurna/led.ino
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>

#include "broker.h"
#include "relay.h"
#include "rpc.h"

#include "led.h"
#include "led_pattern.h"
Expand Down Expand Up @@ -261,18 +262,17 @@ void _ledMQTTCallback(unsigned int type, const char * topic, const char * payloa
// Check if LED is managed
if (_leds[ledID].mode != LED_MODE_MANUAL) return;

// Get value based on relays payload logic (see relay.ino)
// XXX: we will also 'match' custom relay MQTT payload strings
const auto value = relayParsePayload(payload);
// Get value based on rpc payload logic (see rpc.ino)
const auto value = rpcParsePayload(payload);
switch (value) {
case RelayStatus::ON:
case RelayStatus::OFF:
_ledStatus(_leds[ledID], (value == RelayStatus::ON));
case PayloadStatus::On:
case PayloadStatus::Off:
_ledStatus(_leds[ledID], (value == PayloadStatus::On));
break;
case RelayStatus::TOGGLE:
case PayloadStatus::Toggle:
_ledToggle(_leds[ledID]);
break;
case RelayStatus::UNKNOWN:
case PayloadStatus::Unknown:
default:
_ledLoadPattern(_leds[ledID], payload);
_ledStatus(_leds[ledID], true);
Expand Down
12 changes: 3 additions & 9 deletions code/espurna/relay.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,11 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#pragma once

#include <bitset>
#include "rpc.h"
#include "utils.h"

constexpr size_t RELAYS_MAX = 32;

enum class RelayStatus : unsigned char {
OFF = 0,
ON = 1,
TOGGLE = 2,
UNKNOWN = 0xFF
};

struct RelayMask {

explicit RelayMask(const String& string) :
Expand Down Expand Up @@ -51,7 +45,7 @@ struct RelayMask {

};

RelayStatus relayParsePayload(const char * payload);
PayloadStatus relayParsePayload(const char * payload);

bool relayStatus(unsigned char id, bool status, bool report, bool group_report);
bool relayStatus(unsigned char id, bool status);
Expand All @@ -66,7 +60,7 @@ const String& relayPayloadOn();
const String& relayPayloadOff();
const String& relayPayloadToggle();

const char* relayPayload(RelayStatus status);
const char* relayPayload(PayloadStatus status);

void relaySetupDummy(size_t size, bool reconfigure = false);

133 changes: 58 additions & 75 deletions code/espurna/relay.ino
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "settings.h"
#include "mqtt.h"
#include "relay.h"
#include "rpc.h"
#include "tuya.h"
#include "ws.h"

Expand Down Expand Up @@ -103,42 +104,42 @@ bool _relay_report_ws = false;

#endif // WEB_SUPPORT

#if MQTT_SUPPORT
#if MQTT_SUPPORT || API_SUPPORT

String _relay_mqtt_payload_on;
String _relay_mqtt_payload_off;
String _relay_mqtt_payload_toggle;
String _relay_rpc_payload_on;
String _relay_rpc_payload_off;
String _relay_rpc_payload_toggle;

#endif // MQTT_SUPPORT
#endif // MQTT_SUPPORT || API_SUPPORT

// -----------------------------------------------------------------------------
// UTILITY
// -----------------------------------------------------------------------------

bool _relayHandlePayload(unsigned char relayID, const char* payload) {
auto value = relayParsePayload(payload);
if (value == RelayStatus::UNKNOWN) return false;
if (value == PayloadStatus::Unknown) return false;

if (value == RelayStatus::OFF) {
if (value == PayloadStatus::Off) {
relayStatus(relayID, false);
} else if (value == RelayStatus::ON) {
} else if (value == PayloadStatus::On) {
relayStatus(relayID, true);
} else if (value == RelayStatus::TOGGLE) {
} else if (value == PayloadStatus::Toggle) {
relayToggle(relayID);
}

return true;
}

RelayStatus _relayStatusInvert(RelayStatus status) {
return (status == RelayStatus::ON) ? RelayStatus::OFF : status;
PayloadStatus _relayStatusInvert(PayloadStatus status) {
return (status == PayloadStatus::On) ? PayloadStatus::Off : status;
}

RelayStatus _relayStatusTyped(unsigned char id) {
if (id >= _relays.size()) return RelayStatus::OFF;
PayloadStatus _relayStatusTyped(unsigned char id) {
if (id >= _relays.size()) return PayloadStatus::Off;

const bool status = _relays[id].current_status;
return (status) ? RelayStatus::ON : RelayStatus::OFF;
return (status) ? PayloadStatus::On : PayloadStatus::Off;
}

void _relayLockAll() {
Expand Down Expand Up @@ -676,41 +677,17 @@ unsigned char relayCount() {
return _relays.size();
}

RelayStatus relayParsePayload(const char * payload) {

// Don't parse empty strings
const auto len = strlen(payload);
if (!len) return RelayStatus::UNKNOWN;

// Check most commonly used payloads
if (len == 1) {
if (payload[0] == '0') return RelayStatus::OFF;
if (payload[0] == '1') return RelayStatus::ON;
if (payload[0] == '2') return RelayStatus::TOGGLE;
return RelayStatus::UNKNOWN;
}

// If possible, compare to locally configured payload strings
#if MQTT_SUPPORT
if (_relay_mqtt_payload_off.equals(payload)) return RelayStatus::OFF;
if (_relay_mqtt_payload_on.equals(payload)) return RelayStatus::ON;
if (_relay_mqtt_payload_toggle.equals(payload)) return RelayStatus::TOGGLE;
#endif // MQTT_SUPPORT

// Finally, check for "OFF", "ON", "TOGGLE" (both lower and upper cases)
String temp(payload);
temp.trim();

if (temp.equalsIgnoreCase("off")) {
return RelayStatus::OFF;
} else if (temp.equalsIgnoreCase("on")) {
return RelayStatus::ON;
} else if (temp.equalsIgnoreCase("toggle")) {
return RelayStatus::TOGGLE;
}

return RelayStatus::UNKNOWN;

PayloadStatus relayParsePayload(const char * payload) {
#if MQTT_SUPPORT || API_SUPPORT
return rpcParsePayload(payload, [](const char* payload) {
if (_relay_rpc_payload_off.equals(payload)) return PayloadStatus::Off;
if (_relay_rpc_payload_on.equals(payload)) return PayloadStatus::On;
if (_relay_rpc_payload_toggle.equals(payload)) return PayloadStatus::Toggle;
return PayloadStatus::Unknown;
});
#else
return rpcParsePayload(payload);
#endif
}

// BACKWARDS COMPATIBILITY
Expand Down Expand Up @@ -835,9 +812,9 @@ void _relayConfigure() {

#if MQTT_SUPPORT
settingsProcessConfig({
{_relay_mqtt_payload_on, "relayPayloadOn", RELAY_MQTT_ON},
{_relay_mqtt_payload_off, "relayPayloadOff", RELAY_MQTT_OFF},
{_relay_mqtt_payload_toggle, "relayPayloadToggle", RELAY_MQTT_TOGGLE},
{_relay_rpc_payload_on, "relayPayloadOn", RELAY_MQTT_ON},
{_relay_rpc_payload_off, "relayPayloadOff", RELAY_MQTT_OFF},
{_relay_rpc_payload_toggle, "relayPayloadToggle", RELAY_MQTT_TOGGLE},
});
#endif // MQTT_SUPPORT
}
Expand Down Expand Up @@ -1059,33 +1036,38 @@ void relaySetupAPI() {
// MQTT
//------------------------------------------------------------------------------

#if MQTT_SUPPORT
#if MQTT_SUPPORT || API_SUPPORT

const String& relayPayloadOn() {
return _relay_mqtt_payload_on;
return _relay_rpc_payload_on;
}

const String& relayPayloadOff() {
return _relay_mqtt_payload_off;
return _relay_rpc_payload_off;
}

const String& relayPayloadToggle() {
return _relay_mqtt_payload_toggle;
return _relay_rpc_payload_toggle;
}

const char* relayPayload(RelayStatus status) {

if (status == RelayStatus::OFF) {
return _relay_mqtt_payload_off.c_str();
} else if (status == RelayStatus::ON) {
return _relay_mqtt_payload_on.c_str();
} else if (status == RelayStatus::TOGGLE) {
return _relay_mqtt_payload_toggle.c_str();
const char* relayPayload(PayloadStatus status) {
switch (status) {
case PayloadStatus::Off:
return _relay_rpc_payload_off.c_str();
case PayloadStatus::On:
return _relay_rpc_payload_on.c_str();
case PayloadStatus::Toggle:
return _relay_rpc_payload_toggle.c_str();
case PayloadStatus::Unknown:
default:
return "";
}

return "";
}

#endif // MQTT_SUPPORT || API_SUPPORT

#if MQTT_SUPPORT

void _relayMQTTGroup(unsigned char id) {
const String topic = getSetting({"mqttGroup", id});
if (!topic.length()) return;
Expand Down Expand Up @@ -1129,17 +1111,18 @@ void relayMQTT() {
}
}

void relayStatusWrap(unsigned char id, RelayStatus value, bool is_group_topic) {
void relayStatusWrap(unsigned char id, PayloadStatus value, bool is_group_topic) {
switch (value) {
case RelayStatus::OFF:
case PayloadStatus::Off:
relayStatus(id, false, mqttForward(), !is_group_topic);
break;
case RelayStatus::ON:
case PayloadStatus::On:
relayStatus(id, true, mqttForward(), !is_group_topic);
break;
case RelayStatus::TOGGLE:
case PayloadStatus::Toggle:
relayToggle(id, true, true);
break;
case PayloadStatus::Unknown:
default:
_relays[id].report = true;
relayMQTT(id);
Expand Down Expand Up @@ -1219,7 +1202,7 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo

// Get value
auto value = relayParsePayload(payload);
if (value == RelayStatus::UNKNOWN) return;
if (value == PayloadStatus::Unknown) return;

relayStatusWrap(id, value, false);

Expand All @@ -1235,9 +1218,9 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo
if ((t.length() > 0) && t.equals(topic)) {

auto value = relayParsePayload(payload);
if (value == RelayStatus::UNKNOWN) return;
if (value == PayloadStatus::Unknown) return;

if ((value == RelayStatus::ON) || (value == RelayStatus::OFF)) {
if ((value == PayloadStatus::On) || (value == PayloadStatus::Off)) {
if (getSetting({"mqttGroupSync", i}, RELAY_GROUP_SYNC_NORMAL) == RELAY_GROUP_SYNC_INVERSE) {
value = _relayStatusInvert(value);
}
Expand All @@ -1263,10 +1246,10 @@ void relayMQTTCallback(unsigned int type, const char * topic, const char * paylo
const auto reaction = getSetting({"relayOnDisc", i}, 0);
if (1 == reaction) { // switch relay OFF
DEBUG_MSG_P(PSTR("[RELAY] Reset relay (%d) due to MQTT disconnection\n"), i);
relayStatusWrap(i, RelayStatus::OFF, false);
relayStatusWrap(i, PayloadStatus::Off, false);
} else if(2 == reaction) { // switch relay ON
DEBUG_MSG_P(PSTR("[RELAY] Set relay (%d) due to MQTT disconnection\n"), i);
relayStatusWrap(i, RelayStatus::ON, false);
relayStatusWrap(i, PayloadStatus::On, false);
}
}

Expand Down
13 changes: 13 additions & 0 deletions code/espurna/rpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,17 @@ Part of MQTT and API modules

#pragma once

#include <vector>
#include <utility>

enum class PayloadStatus {
Off = 0,
On = 1,
Toggle = 2,
Unknown = 0xFF
};

using rpc_payload_check_t = PayloadStatus(*)(const char*);

bool rpcHandleAction(const String& action);
PayloadStatus rpcParsePayload(const char* payload, const rpc_payload_check_t ext_check = nullptr);
38 changes: 38 additions & 0 deletions code/espurna/rpc.ino
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,42 @@ bool rpcHandleAction(const String& action) {
return result;
}

PayloadStatus rpcParsePayload(const char* payload, const rpc_payload_check_t ext_check) {

// Don't parse empty strings
const auto len = strlen(payload);
if (!len) return PayloadStatus::Unknown;

// Check most commonly used payloads
if (len == 1) {
if (payload[0] == '0') return PayloadStatus::Off;
if (payload[0] == '1') return PayloadStatus::On;
if (payload[0] == '2') return PayloadStatus::Toggle;
return PayloadStatus::Unknown;
}

// If possible, use externally provided payload checker
if (ext_check) {
const PayloadStatus result = ext_check(payload);
if (result != PayloadStatus::Unknown) {
return result;
}
}

// Finally, check for "OFF", "ON", "TOGGLE" (both lower and upper cases)
String temp(payload);
temp.trim();

if (temp.equalsIgnoreCase("off")) {
return PayloadStatus::Off;
} else if (temp.equalsIgnoreCase("on")) {
return PayloadStatus::On;
} else if (temp.equalsIgnoreCase("toggle")) {
return PayloadStatus::Toggle;
}

return PayloadStatus::Unknown;

}

#endif // MQTT_SUPPORT || API_SUPPORT

0 comments on commit 32bc78a

Please sign in to comment.