mirror of
https://github.com/1technophile/OpenMQTTGateway.git
synced 2026-02-19 16:21:44 +01:00
- Introduced RFConfiguration class to encapsulate RF settings and operations. - Replaced direct usage of RFConfig structure with iRFConfig instance across multiple files. - Updated frequency handling in actuatorSomfy, gatewayPilight, gatewayRF, and gatewayRF2 to use iRFConfig. - Modified webUI to interact with iRFConfig for RF settings management. - Removed deprecated RFConfig structure and related functions. - Enhanced JSON handling for RF configuration loading and saving. - Improved logging for RF configuration operations.
346 lines
12 KiB
C++
346 lines
12 KiB
C++
/*
|
|
Theengs OpenMQTTGateway - We Unite Sensors in One Open-Source Interface
|
|
|
|
Act as a gateway between your 433mhz, infrared IR, BLE, LoRa signal and one interface like an MQTT broker
|
|
Send and receiving command by MQTT
|
|
|
|
This gateway enables to:
|
|
- publish MQTT data to a different topic related to received 433Mhz signal DIO/new kaku protocol
|
|
|
|
Copyright: (c)Florian ROBERT
|
|
Copyright: (c)Randy Simons http://randysimons.nl/
|
|
|
|
This file is part of OpenMQTTGateway.
|
|
|
|
OpenMQTTGateway is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
OpenMQTTGateway is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*Command example for switching off:
|
|
sudo mosquitto_pub -t home/commands/MQTTtoRF2/CODE_8233372/UNIT_0/PERIOD_272 -m 0
|
|
Command example for switching on:
|
|
sudo mosquitto_pub -t home/commands/MQTTtoRF2/CODE_8233372/UNIT_0/PERIOD_272 -m 1
|
|
Command example for dimming:
|
|
sudo mosquitto_pub -t home/commands/MQTTtoRF2/CODE_8233372/UNIT_0/PERIOD_272 -m/DIM 8
|
|
*/
|
|
#include "User_config.h"
|
|
|
|
#ifdef ZgatewayRF2
|
|
# include "TheengsCommon.h"
|
|
# include "TheengsUtils.h"
|
|
# include "config_RF.h"
|
|
|
|
# ifdef ZradioCC1101
|
|
# include <ELECHOUSE_CC1101_SRC_DRV.h>
|
|
extern void initCC1101();
|
|
# endif
|
|
|
|
# include <NewRemoteReceiver.h>
|
|
# include <NewRemoteTransmitter.h>
|
|
|
|
void disableCurrentReceiver();
|
|
void enableActiveReceiver();
|
|
|
|
struct RF2rxd {
|
|
unsigned int period;
|
|
unsigned long address;
|
|
unsigned long groupBit;
|
|
unsigned long unit;
|
|
unsigned long switchType;
|
|
bool hasNewData;
|
|
};
|
|
|
|
RF2rxd rf2rd;
|
|
|
|
# ifdef ZmqttDiscovery
|
|
# include "config_mqttDiscovery.h"
|
|
extern String getUniqueId(String name, String sufix);
|
|
|
|
//Register for autodiscover in Home Assistant
|
|
void RF2toMQTTdiscovery(JsonObject& data) {
|
|
THEENGS_LOG_TRACE(F("switchRF2Discovery" CR));
|
|
String payloadonstr;
|
|
String payloadoffstr;
|
|
|
|
int org_switchtype = data["switchType"]; // Store original switchvalue
|
|
data["switchType"] = 1; // switchtype = 1 turns switch on.
|
|
serializeJson(data, payloadonstr);
|
|
data["switchType"] = 0; // switchtype = 0 turns switch off.
|
|
serializeJson(data, payloadoffstr);
|
|
data["switchType"] = org_switchtype; // Restore original switchvalue
|
|
|
|
String switchname;
|
|
switchname = "RF2_" + String((int)data["unit"]) + "_" +
|
|
String((int)data["groupbit"]) + "_" +
|
|
String((unsigned long)data["address"]);
|
|
|
|
char* switchRF[8] = {"switch",
|
|
(char*)switchname.c_str(),
|
|
"",
|
|
"",
|
|
"",
|
|
(char*)payloadonstr.c_str(),
|
|
(char*)payloadoffstr.c_str(),
|
|
""};
|
|
// component type,name,availability topic,device class,value template,payload
|
|
// on, payload off, unit of measurement
|
|
|
|
THEENGS_LOG_TRACE(F("CreateDiscoverySwitch: %s" CR), switchRF[1]);
|
|
|
|
// As RF2 433Mhz switches do not render their state, no state topic should be
|
|
// provided in the discovery. This will cause the switch to be in optimistic
|
|
// mode in HA with separate on and off icons.
|
|
// The two separate on/off icons allow for subsequent on commands to support
|
|
// the dimming feature of KAKU switches like ACM-300.
|
|
createDiscovery(switchRF[0], "", switchRF[1],
|
|
(char*)getUniqueId(switchRF[1], "").c_str(), will_Topic,
|
|
switchRF[3], switchRF[4], switchRF[5], switchRF[6],
|
|
switchRF[7], 0, "", "", true, subjectMQTTtoRF2,
|
|
"", "", "", "", false,
|
|
stateClassNone);
|
|
}
|
|
# endif
|
|
|
|
void RF2toX() {
|
|
if (rf2rd.hasNewData) {
|
|
StaticJsonDocument<JSON_MSG_BUFFER> RF2dataBuffer;
|
|
JsonObject RF2data = RF2dataBuffer.to<JsonObject>();
|
|
rf2rd.hasNewData = false;
|
|
|
|
THEENGS_LOG_TRACE(F("Rcv. RF2" CR));
|
|
RF2data["unit"] = (int)rf2rd.unit;
|
|
RF2data["groupBit"] = (int)rf2rd.groupBit;
|
|
RF2data["period"] = (int)rf2rd.period;
|
|
RF2data["address"] = (unsigned long)rf2rd.address;
|
|
RF2data["switchType"] = (int)rf2rd.switchType;
|
|
# ifdef ZmqttDiscovery //component creation for HA
|
|
if (SYSConfig.discovery)
|
|
RF2toMQTTdiscovery(RF2data);
|
|
# endif
|
|
RF2data["origin"] = subjectRF2toMQTT;
|
|
enqueueJsonObject(RF2data);
|
|
}
|
|
}
|
|
|
|
void rf2Callback(unsigned int period, unsigned long address, unsigned long groupBit, unsigned long unit, unsigned long switchType) {
|
|
rf2rd.period = period;
|
|
rf2rd.address = address;
|
|
rf2rd.groupBit = groupBit;
|
|
rf2rd.unit = unit;
|
|
rf2rd.switchType = switchType;
|
|
rf2rd.hasNewData = true;
|
|
}
|
|
|
|
# if simpleReceiving
|
|
void XtoRF2(const char* topicOri, const char* datacallback) {
|
|
disableCurrentReceiver();
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
# ifdef ZradioCC1101
|
|
initCC1101();
|
|
int txPower = RF_CC1101_TXPOWER;
|
|
ELECHOUSE_cc1101.setPA((int)txPower);
|
|
THEENGS_LOG_NOTICE(F("[RF] CC1101 TX Power: %d" CR), txPower);
|
|
float txFrequency = iRFConfig.getFrequency();
|
|
ELECHOUSE_cc1101.SetTx(txFrequency);
|
|
THEENGS_LOG_NOTICE(F("[RF] Transmit frequency: %F" CR), txFrequency);
|
|
# endif
|
|
|
|
// RF DATA ANALYSIS
|
|
//We look into the subject to see if a special RF protocol is defined
|
|
String topic = topicOri;
|
|
bool boolSWITCHTYPE;
|
|
boolSWITCHTYPE = TheengsUtils::to_bool(datacallback);
|
|
bool isDimCommand = false;
|
|
|
|
long valueCODE = 0;
|
|
int valueUNIT = -1;
|
|
int valuePERIOD = 0;
|
|
int valueGROUP = 0;
|
|
int valueDIM = -1;
|
|
|
|
int pos = topic.lastIndexOf(RF2codeKey);
|
|
if (pos != -1) {
|
|
pos = pos + +strlen(RF2codeKey);
|
|
valueCODE = (topic.substring(pos, pos + 8)).toInt();
|
|
THEENGS_LOG_NOTICE(F("RF2 code: %l" CR), valueCODE);
|
|
}
|
|
int pos2 = topic.lastIndexOf(RF2periodKey);
|
|
if (pos2 != -1) {
|
|
pos2 = pos2 + strlen(RF2periodKey);
|
|
valuePERIOD = (topic.substring(pos2, pos2 + 3)).toInt();
|
|
THEENGS_LOG_NOTICE(F("RF2 Period: %d" CR), valuePERIOD);
|
|
}
|
|
int pos3 = topic.lastIndexOf(RF2unitKey);
|
|
if (pos3 != -1) {
|
|
pos3 = pos3 + strlen(RF2unitKey);
|
|
valueUNIT = (topic.substring(pos3, topic.indexOf("/", pos3))).toInt();
|
|
THEENGS_LOG_NOTICE(F("Unit: %d" CR), valueUNIT);
|
|
}
|
|
int pos4 = topic.lastIndexOf(RF2groupKey);
|
|
if (pos4 != -1) {
|
|
pos4 = pos4 + strlen(RF2groupKey);
|
|
valueGROUP = (topic.substring(pos4, pos4 + 1)).toInt();
|
|
THEENGS_LOG_NOTICE(F("RF2 Group: %d" CR), valueGROUP);
|
|
}
|
|
int pos5 = topic.lastIndexOf(RF2dimKey);
|
|
if (pos5 != -1) {
|
|
isDimCommand = true;
|
|
valueDIM = atoi(datacallback);
|
|
THEENGS_LOG_NOTICE(F("RF2 Dim: %d" CR), valueDIM);
|
|
}
|
|
|
|
if ((topic == subjectMQTTtoRF2) || (valueCODE != 0) || (valueUNIT != -1) || (valuePERIOD != 0)) {
|
|
THEENGS_LOG_TRACE(F("MQTTtoRF2" CR));
|
|
if (valueCODE == 0)
|
|
valueCODE = 8233378;
|
|
if (valueUNIT == -1)
|
|
valueUNIT = 0;
|
|
if (valuePERIOD == 0)
|
|
valuePERIOD = 272;
|
|
NewRemoteReceiver::disable();
|
|
THEENGS_LOG_TRACE(F("Creating transmitter" CR));
|
|
NewRemoteTransmitter transmitter(valueCODE, RF_EMITTER_GPIO, valuePERIOD, RF2_EMITTER_REPEAT);
|
|
THEENGS_LOG_TRACE(F("Sending data" CR));
|
|
if (valueGROUP) {
|
|
if (isDimCommand) {
|
|
transmitter.sendGroupDim(valueDIM);
|
|
} else {
|
|
transmitter.sendGroup(boolSWITCHTYPE);
|
|
}
|
|
} else {
|
|
if (isDimCommand) {
|
|
transmitter.sendDim(valueUNIT, valueDIM);
|
|
} else {
|
|
transmitter.sendUnit(valueUNIT, boolSWITCHTYPE);
|
|
}
|
|
}
|
|
THEENGS_LOG_TRACE(F("Data sent" CR));
|
|
NewRemoteReceiver::enable();
|
|
|
|
// Publish state change back to MQTT
|
|
String MQTTAddress;
|
|
String MQTTperiod;
|
|
String MQTTunit;
|
|
String MQTTgroupBit;
|
|
String MQTTswitchType;
|
|
String MQTTdimLevel;
|
|
|
|
MQTTAddress = String(valueCODE);
|
|
MQTTperiod = String(valuePERIOD);
|
|
MQTTunit = String(valueUNIT);
|
|
MQTTgroupBit = String(rf2rd.groupBit);
|
|
MQTTswitchType = String(boolSWITCHTYPE);
|
|
MQTTdimLevel = String(valueDIM);
|
|
String MQTTRF2string;
|
|
THEENGS_LOG_TRACE(F("Adv data XtoRF2 push state via RF2toMQTT" CR));
|
|
if (isDimCommand) {
|
|
MQTTRF2string = subjectRF2toMQTT + String("/") + RF2codeKey + MQTTAddress + String("/") + RF2unitKey + MQTTunit + String("/") + RF2groupKey + MQTTgroupBit + String("/") + RF2dimKey + String("/") + RF2periodKey + MQTTperiod;
|
|
pub((char*)MQTTRF2string.c_str(), (char*)MQTTdimLevel.c_str());
|
|
} else {
|
|
MQTTRF2string = subjectRF2toMQTT + String("/") + RF2codeKey + MQTTAddress + String("/") + RF2unitKey + MQTTunit + String("/") + RF2groupKey + MQTTgroupBit + String("/") + RF2periodKey + MQTTperiod;
|
|
pub((char*)MQTTRF2string.c_str(), (char*)MQTTswitchType.c_str());
|
|
}
|
|
}
|
|
# ifdef ZradioCC1101
|
|
ELECHOUSE_cc1101.SetRx(iRFConfig.getFrequency()); // set Receive on
|
|
# endif
|
|
enableActiveReceiver();
|
|
}
|
|
# endif
|
|
|
|
# if jsonReceiving
|
|
void XtoRF2(const char* topicOri, JsonObject& RF2data) { // json object decoding
|
|
|
|
if (cmpToMainTopic(topicOri, subjectMQTTtoRF2)) {
|
|
THEENGS_LOG_TRACE(F("MQTTtoRF2 json" CR));
|
|
int boolSWITCHTYPE = RF2data["switchType"] | 99;
|
|
bool success = false;
|
|
if (boolSWITCHTYPE != 99) {
|
|
disableCurrentReceiver();
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
# ifdef ZradioCC1101
|
|
initCC1101();
|
|
int txPower = RF2data["txpower"] | RF_CC1101_TXPOWER;
|
|
ELECHOUSE_cc1101.setPA((int)txPower);
|
|
THEENGS_LOG_NOTICE(F("[RF] CC1101 TX Power: %d" CR), txPower);
|
|
float txFrequency = RF2data["frequency"] | iRFConfig.getFrequency();
|
|
ELECHOUSE_cc1101.SetTx(txFrequency);
|
|
THEENGS_LOG_NOTICE(F("[RF] Transmit frequency: %F" CR), txFrequency);
|
|
# endif
|
|
THEENGS_LOG_TRACE(F("MQTTtoRF2 switch type ok" CR));
|
|
bool isDimCommand = boolSWITCHTYPE == 2;
|
|
unsigned long valueCODE = RF2data["address"];
|
|
int valueUNIT = RF2data["unit"] | -1;
|
|
int valuePERIOD = RF2data["period"];
|
|
int valueGROUP = RF2data["group"];
|
|
int valueDIM = RF2data["dim"] | -1;
|
|
if ((valueCODE != 0) || (valueUNIT != -1) || (valuePERIOD != 0)) {
|
|
THEENGS_LOG_TRACE(F("MQTTtoRF2" CR));
|
|
if (valueCODE == 0)
|
|
valueCODE = 8233378;
|
|
if (valueUNIT == -1)
|
|
valueUNIT = 0;
|
|
if (valuePERIOD == 0)
|
|
valuePERIOD = 272;
|
|
NewRemoteTransmitter transmitter(valueCODE, RF_EMITTER_GPIO, valuePERIOD, RF2_EMITTER_REPEAT);
|
|
THEENGS_LOG_TRACE(F("Sending" CR));
|
|
if (valueGROUP) {
|
|
if (isDimCommand) {
|
|
transmitter.sendGroupDim(valueDIM);
|
|
} else {
|
|
transmitter.sendGroup(boolSWITCHTYPE);
|
|
}
|
|
} else {
|
|
if (isDimCommand) {
|
|
transmitter.sendDim(valueUNIT, valueDIM);
|
|
} else {
|
|
transmitter.sendUnit(valueUNIT, boolSWITCHTYPE);
|
|
}
|
|
}
|
|
THEENGS_LOG_NOTICE(F("MQTTtoRF2 OK" CR));
|
|
|
|
success = true;
|
|
}
|
|
}
|
|
if (success) {
|
|
// we acknowledge the sending by publishing the value to an acknowledgement topic, for the moment even if it is a signal repetition we acknowledge also
|
|
RF2data["origin"] = subjectRF2toMQTT;
|
|
enqueueJsonObject(RF2data);
|
|
} else {
|
|
pub(subjectGTWRF2toMQTT, "{\"Status\": \"Error\"}"); // Fail feedback
|
|
THEENGS_LOG_ERROR(F("MQTTtoRF2 failed json read" CR));
|
|
}
|
|
enableActiveReceiver();
|
|
}
|
|
}
|
|
# endif
|
|
|
|
void disableRF2Receive() {
|
|
THEENGS_LOG_TRACE(F("disableRF2Receive" CR));
|
|
NewRemoteReceiver::disable();
|
|
}
|
|
|
|
void enableRF2Receive() {
|
|
THEENGS_LOG_TRACE(F("enableRF2Receive" CR));
|
|
NewRemoteReceiver::init(RF_RECEIVER_GPIO, 2, rf2Callback);
|
|
|
|
THEENGS_LOG_NOTICE(F("RF_EMITTER_GPIO: %d " CR), RF_EMITTER_GPIO);
|
|
THEENGS_LOG_NOTICE(F("RF_RECEIVER_GPIO: %d " CR), RF_RECEIVER_GPIO);
|
|
THEENGS_LOG_TRACE(F("gatewayRF2 command topic: %s%s%s" CR), mqtt_topic, gateway_name, subjectMQTTtoRF2);
|
|
pinMode(RF_EMITTER_GPIO, OUTPUT);
|
|
digitalWrite(RF_EMITTER_GPIO, LOW);
|
|
THEENGS_LOG_TRACE(F("gatewayRF2 setup done " CR));
|
|
}
|
|
|
|
#endif
|