mirror of
https://github.com/1technophile/OpenMQTTGateway.git
synced 2026-02-19 16:21:44 +01:00
[SERIAL][BREAKING] RS232 change to SERIAL GATEWAY (#2008)
Make the RS232 more generic by converting it to a Serial Gateway Add the capability to decode BLE data coming through Serial
This commit is contained in:
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
- "nodemcuv2-fastled-test"
|
||||
- "nodemcuv2-2g"
|
||||
- "nodemcuv2-ir"
|
||||
- "nodemcuv2-rs232"
|
||||
- "nodemcuv2-serial"
|
||||
- "avatto-bakeey-ir"
|
||||
- "nodemcuv2-rf"
|
||||
- "nodemcuv2-rf-cc1101"
|
||||
|
||||
@@ -35,7 +35,7 @@ module.exports = {
|
||||
'setitup/ir',
|
||||
'setitup/lora',
|
||||
'setitup/gsm',
|
||||
'setitup/rs232',
|
||||
'setitup/serial',
|
||||
'setitup/sensors',
|
||||
'setitup/actuators'
|
||||
]
|
||||
@@ -62,7 +62,7 @@ module.exports = {
|
||||
'use/ir',
|
||||
'use/lora',
|
||||
'use/gsm',
|
||||
'use/rs232',
|
||||
'use/serial',
|
||||
'use/rfm69',
|
||||
'use/sensors',
|
||||
'use/actuators',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# RS232 gateway
|
||||
# Serial/RS232 gateway
|
||||
## Compatible parts
|
||||
|Module|Purpose|Where to Buy|
|
||||
|-|-|-|
|
||||
@@ -1,32 +1,32 @@
|
||||
# RS232 gateway
|
||||
# RS232/Serial gateway
|
||||
|
||||
The RS232 gateway can be used to send and receive data from the serial connection to and from MQTT. Both softwareSerial as hardwareSerial are supported. HardwareSerial can be used for higher baud rates, but is limited to specific pins on most platforms.
|
||||
The SERIAL gateway can be used to send and receive data from the serial connection to and from MQTT. Both softwareSerial as hardwareSerial are supported. HardwareSerial can be used for higher baud rates, but is limited to specific pins on most platforms.
|
||||
|
||||
## Sending an RS232 message
|
||||
## Sending an SERIAL message
|
||||
|
||||
Simply publish the message you wish to transmit, minus the prefix and postfix. For example, to send the "Turn On" signal for a Mitsubishi XD221U projector, the code is simply '!' so you would use the command
|
||||
|
||||
`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoRS232 -m '{"value": "!"}'`
|
||||
`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoSERIAL -m '{"value": "!"}'`
|
||||
|
||||
It will automatically add the prefix and postfix you set in [config_RS232.h](https://github.com/1technophile/OpenMQTTGateway/blob/master/main/config_RS232.h).
|
||||
It will automatically add the prefix and postfix you set in [config_SERIAL.h](https://github.com/1technophile/OpenMQTTGateway/blob/master/main/config_SERIAL.h).
|
||||
|
||||
|
||||
## Receiving an RS232 message
|
||||
## Receiving an SERIAL message
|
||||
|
||||
Two modes are available for receiving RS232 messages.
|
||||
Two modes are available for receiving SERIAL messages.
|
||||
|
||||
### Single MQTT message mode (default)
|
||||
To receive a message, subscribe to all with `mosquitto_sub -t +/# -v`
|
||||
and perform an action that should get a response from the device. For example, If I were to send the "Turn On" signal from earlier, I would receive back
|
||||
|
||||
```json
|
||||
home/OpenMQTTGateway/RS232toMQTT {"value":"1"}
|
||||
home/OpenMQTTGateway/SERIALtoMQTT {"value":"1"}
|
||||
```
|
||||
|
||||
Because this projector echoes back a received command to acknowledge. Some devices will send a NACK, or Negative Acknowledge, to confirm that they received your message but could not comply. That would look like
|
||||
|
||||
```json
|
||||
home/OpenMQTTGateway/RStoMQTT {"value":"!:N"}
|
||||
home/OpenMQTTGateway/SERIALtoMQTT {"value":"!:N"}
|
||||
```
|
||||
|
||||
### JSON mode
|
||||
@@ -42,15 +42,15 @@ input received at serial link:
|
||||
|
||||
output in case of max nesting level 1:
|
||||
```json
|
||||
home/OpenMQTTGateway/RS232toMQTT/temperature "{sens1: 22, sens2: 23}"
|
||||
home/OpenMQTTGateway/RS232toMQTT/humidity "{sens1: 80, sens2: 60}"
|
||||
home/OpenMQTTGateway/SERIALtoMQTT/temperature "{sens1: 22, sens2: 23}"
|
||||
home/OpenMQTTGateway/SERIALtoMQTT/humidity "{sens1: 80, sens2: 60}"
|
||||
```
|
||||
|
||||
output in case of max nesting level 2 (or higher):
|
||||
```json
|
||||
home/OpenMQTTGateway/RS232toMQTT/temperature/sens1 22
|
||||
home/OpenMQTTGateway/RS232toMQTT/temperature/sens2 23
|
||||
home/OpenMQTTGateway/RS232toMQTT/humidity/sens1 80
|
||||
home/OpenMQTTGateway/RS232toMQTT/humidity/sens2 60
|
||||
home/OpenMQTTGateway/SERIALtoMQTT/temperature/sens1 22
|
||||
home/OpenMQTTGateway/SERIALtoMQTT/temperature/sens2 23
|
||||
home/OpenMQTTGateway/SERIALtoMQTT/humidity/sens1 80
|
||||
home/OpenMQTTGateway/SERIALtoMQTT/humidity/sens2 60
|
||||
```
|
||||
|
||||
@@ -1325,7 +1325,7 @@ build_flags =
|
||||
board_build.flash_mode = dout
|
||||
custom_description = Infrared gateway using IRremoteESP8266
|
||||
|
||||
[env:nodemcuv2-rs232]
|
||||
[env:nodemcuv2-serial]
|
||||
platform = ${com.esp8266_platform}
|
||||
board = nodemcuv2
|
||||
lib_deps =
|
||||
@@ -1334,10 +1334,10 @@ lib_deps =
|
||||
${libraries.esp8266_mdns}
|
||||
build_flags =
|
||||
${com-esp.build_flags}
|
||||
'-DZgatewayRS232="RS232"'
|
||||
'-DGateway_Name="OMG_ESP8266_RS232"'
|
||||
'-DZgatewaySERIAL="SERIAL"'
|
||||
'-DGateway_Name="OMG_ESP8266_SERIAL"'
|
||||
board_build.flash_mode = dout
|
||||
custom_description = RS232 gateway
|
||||
custom_description = SERIAL gateway
|
||||
|
||||
[env:avatto-bakeey-ir]
|
||||
platform = ${com.esp8266_platform}
|
||||
|
||||
@@ -373,7 +373,7 @@ int lowpowermode = DEFAULT_LOW_POWER_MODE;
|
||||
//#define ZactuatorPWM "PWM" //ESP8266, ESP32
|
||||
//#define ZsensorSHTC3 "SHTC3" //ESP8266, Arduino, ESP32, Sonoff RF Bridge
|
||||
//#define ZactuatorSomfy "Somfy" //ESP8266, Arduino, ESP32
|
||||
//#define ZgatewayRS232 "RS232" //ESP8266, Arduino, ESP32
|
||||
//#define ZgatewaySERIAL "SERIAL" //ESP8266, Arduino, ESP32
|
||||
|
||||
/*-------------DEFINE YOUR MQTT ADVANCED PARAMETERS BELOW----------------*/
|
||||
#ifndef will_Topic
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
Theengs OpenMQTTGateway - We Unite Sensors in One Open-Source Interface
|
||||
|
||||
Act as a wifi or ethernet gateway between your RS232 device and a MQTT broker
|
||||
Send and receiving command by MQTT
|
||||
|
||||
This gateway enables to:
|
||||
- receive MQTT data from a topic and send RS232 signal corresponding to the received MQTT data
|
||||
- publish MQTT data to a different topic related to received RS232 signal
|
||||
|
||||
Copyright: (c)Florian ROBERT
|
||||
|
||||
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/>.
|
||||
*/
|
||||
#include "User_config.h"
|
||||
|
||||
#ifdef ZgatewayRS232
|
||||
|
||||
# ifndef RS232_UART // software serial mode
|
||||
# include <SoftwareSerial.h>
|
||||
SoftwareSerial RS232SoftSerial(RS232_RX_GPIO, RS232_TX_GPIO); // RX, TX
|
||||
# endif
|
||||
|
||||
// use pointer to stream class for serial communication to make code
|
||||
// compatible with both softwareSerial as hardwareSerial.
|
||||
Stream* RS232Stream = NULL;
|
||||
|
||||
void setupRS232() {
|
||||
//Initalize serial port
|
||||
# ifdef RS232_UART // Hardware serial
|
||||
# if RS232_UART == 0 // init UART0
|
||||
Serial.end(); // stop if already initialized
|
||||
# ifdef ESP32
|
||||
Serial.begin(RS232Baud, SERIAL_8N1, RS232_RX_GPIO, RS232_TX_GPIO);
|
||||
# else
|
||||
Serial.begin(RS232Baud, SERIAL_8N1);
|
||||
# endif
|
||||
# if defined(ESP8266) && defined(RS232_UART0_SWAP)
|
||||
Serial.swap(); // swap UART0 ports from (GPIO1,GPIO3) to (GPIO15,GPIO13)
|
||||
# endif
|
||||
RS232Stream = &Serial;
|
||||
Log.notice(F("RS232 HW UART0" CR));
|
||||
|
||||
# elif RS232_UART == 1 // init UART1
|
||||
Serial1.end(); // stop if already initialized
|
||||
# ifdef ESP32
|
||||
Serial1.begin(RS232Baud, SERIAL_8N1, RS232_RX_GPIO, RS232_TX_GPIO);
|
||||
# else
|
||||
Serial1.begin(RS232Baud, SERIAL_8N1);
|
||||
# endif
|
||||
RS232Stream = &Serial1;
|
||||
Log.notice(F("RS232 HW UART1" CR));
|
||||
|
||||
# elif RS232_UART == 2 // init UART2
|
||||
Serial2.end(); // stop if already initialized
|
||||
# ifdef ESP32
|
||||
Serial2.begin(RS232Baud, SERIAL_8N1, RS232_RX_GPIO, RS232_TX_GPIO);
|
||||
# else
|
||||
Serial2.begin(RS232Baud, SERIAL_8N1);
|
||||
# endif
|
||||
RS232Stream = &Serial2;
|
||||
Log.notice(F("RS232 HW UART2" CR));
|
||||
|
||||
# elif RS232_UART == 3 // init UART3
|
||||
Serial3.end(); // stop if already initialized
|
||||
Serial3.begin(RS232Baud, SERIAL_8N1);
|
||||
RS232Stream = &Serial3;
|
||||
Log.notice(F("RS232 HW UART3" CR));
|
||||
# endif
|
||||
|
||||
# else // Software serial
|
||||
// define pin modes for RX, TX:
|
||||
pinMode(RS232_RX_GPIO, INPUT);
|
||||
pinMode(RS232_TX_GPIO, OUTPUT);
|
||||
RS232SoftSerial.begin(RS232Baud);
|
||||
RS232Stream = &RS232SoftSerial; // get stream of serial
|
||||
|
||||
Log.notice(F("RS232_RX_GPIO: %d" CR), RS232_RX_GPIO);
|
||||
Log.notice(F("RS232_TX_GPIO: %d" CR), RS232_TX_GPIO);
|
||||
# endif
|
||||
|
||||
// Flush all bytes in the "link" serial port buffer
|
||||
while (RS232Stream->available() > 0)
|
||||
RS232Stream->read();
|
||||
|
||||
Log.notice(F("RS232Baud: %d" CR), RS232Baud);
|
||||
Log.trace(F("ZgatewayRS232 setup done" CR));
|
||||
}
|
||||
|
||||
# if RS232toMQTTmode == 0 // Convert received data to single MQTT topic
|
||||
void RS232toMQTT() {
|
||||
// Send all RS232 output (up to RS232InPost char revieved) as MQTT message
|
||||
//This function is Blocking, but there should only ever be a few bytes, usually an ACK or a NACK.
|
||||
if (RS232Stream->available()) {
|
||||
Log.trace(F("RS232toMQTT" CR));
|
||||
static char RS232data[MAX_INPUT];
|
||||
static unsigned int input_pos = 0;
|
||||
static char inChar;
|
||||
do {
|
||||
if (RS232Stream->available()) {
|
||||
inChar = RS232Stream->read();
|
||||
RS232data[input_pos] = inChar;
|
||||
input_pos++;
|
||||
Log.trace(F("Received %c" CR), inChar);
|
||||
}
|
||||
} while (inChar != RS232InPost && input_pos < MAX_INPUT);
|
||||
RS232data[input_pos] = 0;
|
||||
input_pos = 0;
|
||||
Log.trace(F("Publish %s" CR), RS232data);
|
||||
char* output = RS232data + sizeof(RS232Pre) - 1;
|
||||
pub(subjectRS232toMQTT, output);
|
||||
}
|
||||
}
|
||||
|
||||
# elif RS232toMQTTmode == 1 // Convert recievee JSON data to multiple MQTT topics based (nested) keys
|
||||
void RS232toMQTT() {
|
||||
// Assumes valid JSON data at RS232 interface. Use (nested) keys to split JSON data in separate
|
||||
// sub-MQTT-topics up to the defined nesting level.
|
||||
if (RS232Stream->available()) {
|
||||
Log.trace(F("RS232toMQTT" CR));
|
||||
|
||||
// Allocate the JSON document
|
||||
StaticJsonDocument<RS232JSONDocSize> doc;
|
||||
|
||||
// Read the JSON document from the "link" serial port
|
||||
DeserializationError err = deserializeJson(doc, *RS232Stream);
|
||||
|
||||
if (err == DeserializationError::Ok) {
|
||||
// JSON received, send as MQTT topics
|
||||
char topic[mqtt_topic_max_size + 1] = subjectRS232toMQTT;
|
||||
sendMQTTfromNestedJson(doc.as<JsonVariant>(), topic, 0, RS232maxJSONlevel);
|
||||
} else {
|
||||
// Print error to serial log
|
||||
Log.error(F("Error in RS232JSONtoMQTT, deserializeJson() returned %s"), err.c_str());
|
||||
|
||||
// Flush all bytes in the "link" serial port buffer
|
||||
while (RS232Stream->available() > 0)
|
||||
RS232Stream->read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sendMQTTfromNestedJson(JsonVariant obj, char* topic, int level, int maxLevel) {
|
||||
// recursively step through JSON data and send MQTT messages
|
||||
if (level < maxLevel && obj.is<JsonObject>()) {
|
||||
int topicLength = strlen(topic);
|
||||
// loop over fields
|
||||
for (JsonPair pair : obj.as<JsonObject>()) {
|
||||
// check if new key still fits in topic cstring
|
||||
const char* key = pair.key().c_str();
|
||||
Log.trace(F("level=%d, key='%s'" CR), level, pair.key().c_str());
|
||||
if (topicLength + 2 + strlen(key) <= mqtt_topic_max_size) {
|
||||
// add new level to existing topic cstring
|
||||
topic[topicLength] = '/'; // add slash
|
||||
topic[topicLength + 1] = '\0'; // terminate
|
||||
strncat(topic + topicLength, key, mqtt_topic_max_size - topicLength - 2);
|
||||
|
||||
// step recursively into next level
|
||||
sendMQTTfromNestedJson(pair.value(), topic, level + 1, maxLevel);
|
||||
|
||||
// restore topic
|
||||
topic[topicLength] = '\0';
|
||||
} else {
|
||||
Log.error(F("Nested key '%s' at level %d does not fit within max topic length of %d, skipping"),
|
||||
key, level, mqtt_topic_max_size);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// output value at current json level
|
||||
char output[MAX_INPUT + 1];
|
||||
serializeJson(obj, output, MAX_INPUT);
|
||||
Log.notice(F("level=%d, topic=%s, value: %s\n"), level, topic, output);
|
||||
|
||||
// send MQTT message
|
||||
pub(topic, &output[0]);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
void MQTTtoRS232(char* topicOri, JsonObject& RS232data) {
|
||||
Log.trace(F("json" CR));
|
||||
if (cmpToMainTopic(topicOri, subjectMQTTtoRS232)) {
|
||||
Log.trace(F("MQTTtoRS232 json" CR));
|
||||
const char* data = RS232data["value"];
|
||||
const char* prefix = RS232data["prefix"] | RS232Pre;
|
||||
const char* postfix = RS232data["postfix"] | RS232Post;
|
||||
Log.trace(F("Value set: %s" CR), data);
|
||||
Log.trace(F("Prefix set: %s" CR), prefix);
|
||||
Log.trace(F("Postfix set: %s" CR), postfix);
|
||||
RS232Stream->print(prefix);
|
||||
RS232Stream->print(data);
|
||||
RS232Stream->print(postfix);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
246
main/ZgatewaySERIAL.ino
Normal file
246
main/ZgatewaySERIAL.ino
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
Theengs OpenMQTTGateway - We Unite Sensors in One Open-Source Interface
|
||||
|
||||
Act as a wifi or ethernet gateway between your SERIAL device and a MQTT broker
|
||||
Send and receiving command by MQTT
|
||||
|
||||
This gateway enables to:
|
||||
- receive MQTT data from a topic and send SERIAL signal corresponding to the received MQTT data
|
||||
- publish MQTT data to a different topic related to received SERIAL signal
|
||||
|
||||
Copyright: (c)Florian ROBERT
|
||||
|
||||
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/>.
|
||||
*/
|
||||
#include "User_config.h"
|
||||
|
||||
#ifdef ZgatewaySERIAL
|
||||
|
||||
# ifndef SERIAL_UART // software serial mode
|
||||
# include <SoftwareSerial.h>
|
||||
SoftwareSerial SERIALSoftSerial(SERIAL_RX_GPIO, SERIAL_TX_GPIO); // RX, TX
|
||||
# endif
|
||||
|
||||
// use pointer to stream class for serial communication to make code
|
||||
// compatible with both softwareSerial as hardwareSerial.
|
||||
Stream* SERIALStream = NULL;
|
||||
|
||||
void setupSERIAL() {
|
||||
//Initalize serial port
|
||||
# ifdef SERIAL_UART // Hardware serial
|
||||
# if SERIAL_UART == 0 // init UART0
|
||||
Serial.end(); // stop if already initialized
|
||||
# ifdef ESP32
|
||||
Serial.begin(SERIALBaud, SERIAL_8N1, SERIAL_RX_GPIO, SERIAL_TX_GPIO);
|
||||
# else
|
||||
Serial.begin(SERIALBaud, SERIAL_8N1);
|
||||
# endif
|
||||
# if defined(ESP8266) && defined(SERIAL_UART0_SWAP)
|
||||
Serial.swap(); // swap UART0 ports from (GPIO1,GPIO3) to (GPIO15,GPIO13)
|
||||
# endif
|
||||
SERIALStream = &Serial;
|
||||
Log.notice(F("SERIAL HW UART0" CR));
|
||||
|
||||
# elif SERIAL_UART == 1 // init UART1
|
||||
Serial1.end(); // stop if already initialized
|
||||
# ifdef ESP32
|
||||
Serial1.begin(SERIALBaud, SERIAL_8N1, SERIAL_RX_GPIO, SERIAL_TX_GPIO);
|
||||
# else
|
||||
Serial1.begin(SERIALBaud, SERIAL_8N1);
|
||||
# endif
|
||||
SERIALStream = &Serial1;
|
||||
Log.notice(F("SERIAL HW UART1" CR));
|
||||
|
||||
# elif SERIAL_UART == 2 // init UART2
|
||||
Serial2.end(); // stop if already initialized
|
||||
# ifdef ESP32
|
||||
Serial2.begin(SERIALBaud, SERIAL_8N1, SERIAL_RX_GPIO, SERIAL_TX_GPIO);
|
||||
# else
|
||||
Serial2.begin(SERIALBaud, SERIAL_8N1);
|
||||
# endif
|
||||
SERIALStream = &Serial2;
|
||||
Log.notice(F("SERIAL HW UART2" CR));
|
||||
|
||||
# elif SERIAL_UART == 3 // init UART3
|
||||
Serial3.end(); // stop if already initialized
|
||||
Serial3.begin(SERIALBaud, SERIAL_8N1);
|
||||
SERIALStream = &Serial3;
|
||||
Log.notice(F("SERIAL HW UART3" CR));
|
||||
# endif
|
||||
|
||||
# else // Software serial
|
||||
// define pin modes for RX, TX:
|
||||
pinMode(SERIAL_RX_GPIO, INPUT);
|
||||
pinMode(SERIAL_TX_GPIO, OUTPUT);
|
||||
SERIALSoftSerial.begin(SERIALBaud);
|
||||
SERIALStream = &SERIALSoftSerial; // get stream of serial
|
||||
|
||||
Log.notice(F("SERIAL_RX_GPIO: %d" CR), SERIAL_RX_GPIO);
|
||||
Log.notice(F("SERIAL_TX_GPIO: %d" CR), SERIAL_TX_GPIO);
|
||||
# endif
|
||||
|
||||
// Flush all bytes in the "link" serial port buffer
|
||||
while (SERIALStream->available() > 0)
|
||||
SERIALStream->read();
|
||||
|
||||
Log.notice(F("SERIALBaud: %d" CR), SERIALBaud);
|
||||
Log.trace(F("ZgatewaySERIAL setup done" CR));
|
||||
}
|
||||
|
||||
# if SERIALtoMQTTmode == 0 // Convert received data to single MQTT topic
|
||||
void SERIALtoMQTT() {
|
||||
// Send all SERIAL output (up to SERIALInPost char revieved) as MQTT message
|
||||
//This function is Blocking, but there should only ever be a few bytes, usually an ACK or a NACK.
|
||||
if (SERIALStream->available()) {
|
||||
Log.trace(F("SERIALtoMQTT" CR));
|
||||
static char SERIALdata[MAX_INPUT];
|
||||
static unsigned int input_pos = 0;
|
||||
static char inChar;
|
||||
do {
|
||||
if (SERIALStream->available()) {
|
||||
inChar = SERIALStream->read();
|
||||
SERIALdata[input_pos] = inChar;
|
||||
input_pos++;
|
||||
}
|
||||
} while (inChar != SERIALInPost && input_pos < MAX_INPUT);
|
||||
SERIALdata[input_pos] = 0;
|
||||
input_pos = 0;
|
||||
|
||||
char* output = SERIALdata + sizeof(SERIALPre) - 1;
|
||||
Log.notice(F("SERIAL data: %s" CR), output);
|
||||
pub(subjectSERIALtoMQTT, output);
|
||||
}
|
||||
}
|
||||
|
||||
# elif SERIALtoMQTTmode == 1 // Convert recievee JSON data to multiple MQTT topics based (nested) keys
|
||||
void SERIALtoMQTT() {
|
||||
// Assumes valid JSON data at SERIAL interface. Use (nested) keys to split JSON data in separate
|
||||
// sub-MQTT-topics up to the defined nesting level.
|
||||
if (SERIALStream->available()) {
|
||||
Log.trace(F("SERIALtoMQTT" CR));
|
||||
|
||||
// Allocate the JSON document
|
||||
StaticJsonDocument<JSON_MSG_BUFFER> SERIALBuffer;
|
||||
JsonObject SERIALdata = SERIALBuffer.to<JsonObject>();
|
||||
|
||||
// JSON validation
|
||||
StaticJsonDocument<0> emptyDoc;
|
||||
StaticJsonDocument<0> filter;
|
||||
DeserializationError validationError = deserializeJson(emptyDoc, *SERIALStream, DeserializationOption::Filter(filter));
|
||||
if (validationError == DeserializationError::Ok) {
|
||||
Log.trace(F("SERIAL data is valid JSON" CR));
|
||||
} else {
|
||||
Log.error(F("SERIAL data is not valid JSON" CR));
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the JSON document from the "link" serial port
|
||||
DeserializationError err = deserializeJson(SERIALBuffer, *SERIALStream);
|
||||
|
||||
// Check if the JSON object is empty
|
||||
if (SERIALBuffer.isNull() || SERIALBuffer.size() == 0) {
|
||||
Log.error(F("SERIAL data is empty JSON object" CR));
|
||||
return;
|
||||
}
|
||||
|
||||
if (err == DeserializationError::Ok) {
|
||||
// JSON received
|
||||
# if jsonPublishing
|
||||
// send as json
|
||||
if (SERIALdata.containsKey("origin")) {
|
||||
if (SERIALdata["origin"] == "BT") {
|
||||
//Decode the BT data
|
||||
# ifdef ZgatewayBT
|
||||
SERIALdata.remove("origin");
|
||||
PublishDeviceData(SERIALdata);
|
||||
# endif
|
||||
}
|
||||
} else {
|
||||
SERIALdata["origin"] = subjectSERIALtoMQTT;
|
||||
handleJsonEnqueue(SERIALdata);
|
||||
}
|
||||
|
||||
# endif
|
||||
# if simplePublishing
|
||||
// send as MQTT topics
|
||||
char topic[mqtt_topic_max_size + 1] = subjectSERIALtoMQTT;
|
||||
sendMQTTfromNestedJson(SERIALBuffer.as<JsonVariant>(), topic, 0, SERIALmaxJSONlevel);
|
||||
# endif
|
||||
} else {
|
||||
// Print error to serial log
|
||||
Log.error(F("Error in SERIALJSONtoMQTT, deserializeJson() returned %s" CR), err.c_str());
|
||||
|
||||
// Flush all bytes in the "link" serial port buffer
|
||||
while (SERIALStream->available() > 0)
|
||||
SERIALStream->read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sendMQTTfromNestedJson(JsonVariant obj, char* topic, int level, int maxLevel) {
|
||||
// recursively step through JSON data and send MQTT messages
|
||||
if (level < maxLevel && obj.is<JsonObject>()) {
|
||||
int topicLength = strlen(topic);
|
||||
// loop over fields
|
||||
for (JsonPair pair : obj.as<JsonObject>()) {
|
||||
// check if new key still fits in topic cstring
|
||||
const char* key = pair.key().c_str();
|
||||
Log.trace(F("level=%d, key='%s'" CR), level, pair.key().c_str());
|
||||
if (topicLength + 2 + strlen(key) <= mqtt_topic_max_size) {
|
||||
// add new level to existing topic cstring
|
||||
topic[topicLength] = '/'; // add slash
|
||||
topic[topicLength + 1] = '\0'; // terminate
|
||||
strncat(topic + topicLength, key, mqtt_topic_max_size - topicLength - 2);
|
||||
|
||||
// step recursively into next level
|
||||
sendMQTTfromNestedJson(pair.value(), topic, level + 1, maxLevel);
|
||||
|
||||
// restore topic
|
||||
topic[topicLength] = '\0';
|
||||
} else {
|
||||
Log.error(F("Nested key '%s' at level %d does not fit within max topic length of %d, skipping"),
|
||||
key, level, mqtt_topic_max_size);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// output value at current json level
|
||||
char output[MAX_INPUT + 1];
|
||||
serializeJson(obj, output, MAX_INPUT);
|
||||
Log.notice(F("level=%d, topic=%s, value: %s\n"), level, topic, output);
|
||||
|
||||
// send MQTT message
|
||||
pub(topic, &output[0]);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
void MQTTtoSERIAL(char* topicOri, JsonObject& SERIALdata) {
|
||||
Log.trace(F("json" CR));
|
||||
if (cmpToMainTopic(topicOri, subjectMQTTtoSERIAL)) {
|
||||
Log.trace(F("MQTTtoSERIAL json" CR));
|
||||
const char* data = SERIALdata["value"];
|
||||
const char* prefix = SERIALdata["prefix"] | SERIALPre;
|
||||
const char* postfix = SERIALdata["postfix"] | SERIALPost;
|
||||
Log.trace(F("Value set: %s" CR), data);
|
||||
Log.trace(F("Prefix set: %s" CR), prefix);
|
||||
Log.trace(F("Postfix set: %s" CR), postfix);
|
||||
SERIALStream->print(prefix);
|
||||
SERIALStream->print(data);
|
||||
SERIALStream->print(postfix);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
Theengs OpenMQTTGateway - We Unite Sensors in One Open-Source Interface
|
||||
|
||||
Act as a wifi or ethernet gateway between your RS232 device and a MQTT broker
|
||||
Send and receiving command by MQTT
|
||||
|
||||
This files enables to set your parameter for the RS232 gateway
|
||||
|
||||
Copyright: (c)Florian ROBERT
|
||||
|
||||
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/>.
|
||||
*/
|
||||
#ifndef config_RS232_h
|
||||
#define config_RS232_h
|
||||
|
||||
extern void setupRS232();
|
||||
extern void RS232toMQTT();
|
||||
extern void MQTTtoRS232(char* topicOri, JsonObject& RS232data);
|
||||
|
||||
/*-------------------RS232 topics & parameters----------------------*/
|
||||
|
||||
// Settings RS232 to MQTT topic
|
||||
#define subjectRS232toMQTT "/RS232toMQTT"
|
||||
|
||||
// setting to specify mode used for sending MQTT messages:
|
||||
// 0: RAW: all recieved input at RS232 interface is collected in single MQTT message
|
||||
// defined by RS232toMQTTsubject
|
||||
//
|
||||
// 1: JSON: Assumes input at RS232 interface to be valid JSON. JSON keys are used to
|
||||
// split the JSON data in separate MQTT sub-topics. This will be repeated for
|
||||
// sub-keys up to the specified nesting level (RS232maxJSONlevel).
|
||||
//
|
||||
// EXAMPLE: "{temperature: {sens1: 22, sens2: 23}, humidity: {sens1: 80, sens2: 60}}"
|
||||
// - with RS232maxJSONlevel=1:
|
||||
// ./RS232toMQTT/temperature ==> "{sens1: 22, sens2: 23}"
|
||||
// ./RS232toMQTT/humidity ==> "{sens1: 80, sens2: 60}"
|
||||
//
|
||||
// - with RS232maxJSONlevel=2 (or higher):
|
||||
// ./RS232toMQTT/temperature/sens1 ==> 22
|
||||
// ./RS232toMQTT/temperature/sens2 ==> 23
|
||||
// ./RS232toMQTT/humidity/sens1 ==> 80
|
||||
// ./RS232toMQTT/humidity/sens2 ==> 60
|
||||
//
|
||||
#ifndef RS232toMQTTmode
|
||||
# define RS232toMQTTmode 0
|
||||
#endif
|
||||
|
||||
// settings for RS232TopicMode 0 (RAW)
|
||||
#define RS232InPost '\n' // Hacky way to get last character of postfix for incoming
|
||||
#define MAX_INPUT 200 // how much serial data we expect
|
||||
|
||||
// settings for RS232TopicMode 1 (JSON)
|
||||
#define RS232maxJSONlevel 2 // Max nested level in which JSON keys are converted to seperate sub-topics
|
||||
#define RS232JSONDocSize 1024 // bytes to reserve for the JSON doc
|
||||
|
||||
// settings for MQTT to RS232
|
||||
#define subjectMQTTtoRS232 "/commands/MQTTtoRS232"
|
||||
#define RS232Pre "00" // The prefix for the RS232 message
|
||||
#define RS232Post "\r" // The postfix for the RS232 message
|
||||
|
||||
//Setup for RS232
|
||||
#ifndef RS232Baud
|
||||
# define RS232Baud 9600 // The serial connection Baud
|
||||
#endif
|
||||
|
||||
/*-------------------PIN DEFINITIONS----------------------*/
|
||||
#ifndef RS232_UART
|
||||
// set hardware serial UART to be used for device communication or
|
||||
// use software emulaton if not defined
|
||||
//
|
||||
// VALUES:
|
||||
// - not defined: use software emulation (pins set by RS232_RX_GPIO & RS232_TX_GPIO)
|
||||
//
|
||||
// - 0: use HW UART0 (serial), warning: default used for logging & usb
|
||||
// ESP8266: (TX0 GPIO1, RX0 GPIO3)
|
||||
// (TX0 GPIO15, RX0 GPIO13) with UART0 swap enabled
|
||||
// ESP32: (TX0 by RS232_TX_GPIO, RX0 by RS232_RX_GPIO)
|
||||
//
|
||||
// - 1: use HW UART1 (serial1)
|
||||
// ESP8266: (TX1 GPIO2, RX none) only transmit available
|
||||
// ESP32: (TX1 by RS232_TX_GPIO, RX1 by RS232_RX_GPIO)
|
||||
//
|
||||
// - 2: use HW UART2 (serial2)
|
||||
// ESP8266: N/A
|
||||
// ESP32: (TX2 by RS232_TX_GPIO, RX2 by RS232_RX_GPIO)
|
||||
//
|
||||
// - 3: use HW UART3 (serial3)
|
||||
// ESP8266: N/A
|
||||
// ESP32: N/A
|
||||
//
|
||||
// defaults
|
||||
# ifdef ESP32
|
||||
# define RS232_UART 1 // use HW UART ESP32
|
||||
# else
|
||||
# undef RS232_UART // default use software serial
|
||||
//# define RS232_UART 1 // define to use HW UART
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef RS232_UART0_SWAP
|
||||
// option for ESP8266 only to swap UART0 ports from (GPIO1,GPIO3) to (GPIO15,GPIO13)
|
||||
# define RS232_UART0_SWAP
|
||||
#endif
|
||||
|
||||
#ifndef RS232_RX_GPIO
|
||||
// define receive pin (for software serial or ESP32 with configurable HW UART)
|
||||
# if defined(ESP8266) && !defined(RS232_UART)
|
||||
# define RS232_RX_GPIO 4 //D2
|
||||
# elif defined(ESP32)
|
||||
# define RS232_RX_GPIO 26
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef RS232_TX_GPIO
|
||||
// define transmit pin (for software serial and/or ESP32)
|
||||
# if defined(ESP8266) && !defined(RS232_UART)
|
||||
# define RS232_TX_GPIO 2 //D4
|
||||
# elif ESP32
|
||||
# define RS232_TX_GPIO 14
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
139
main/config_SERIAL.h
Normal file
139
main/config_SERIAL.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
Theengs OpenMQTTGateway - We Unite Sensors in One Open-Source Interface
|
||||
|
||||
Act as a wifi or ethernet gateway between your SERIAL device and a MQTT broker
|
||||
Send and receiving command by MQTT
|
||||
|
||||
This files enables to set your parameter for the SERIAL gateway
|
||||
|
||||
Copyright: (c)Florian ROBERT
|
||||
|
||||
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/>.
|
||||
*/
|
||||
#ifndef config_SERIAL_h
|
||||
#define config_SERIAL_h
|
||||
|
||||
extern void setupSERIAL();
|
||||
extern void SERIALtoMQTT();
|
||||
extern void MQTTtoSERIAL(char* topicOri, JsonObject& SERIALdata);
|
||||
|
||||
/*-------------------SERIAL topics & parameters----------------------*/
|
||||
|
||||
// Settings SERIAL to MQTT topic
|
||||
#define subjectSERIALtoMQTT "/SERIALtoMQTT"
|
||||
|
||||
// setting to specify mode used for sending MQTT messages:
|
||||
// 0: RAW: all recieved input at SERIAL interface is collected in single MQTT message
|
||||
// defined by SERIALtoMQTTsubject
|
||||
//
|
||||
// 1: JSON: Assumes input at SERIAL interface to be valid JSON. JSON keys are used to
|
||||
// split the JSON data in separate MQTT sub-topics. This will be repeated for
|
||||
// sub-keys up to the specified nesting level (SERIALmaxJSONlevel).
|
||||
//
|
||||
// EXAMPLE: "{temperature: {sens1: 22, sens2: 23}, humidity: {sens1: 80, sens2: 60}}"
|
||||
// - with SERIALmaxJSONlevel=1:
|
||||
// ./SERIALtoMQTT/temperature ==> "{sens1: 22, sens2: 23}"
|
||||
// ./SERIALtoMQTT/humidity ==> "{sens1: 80, sens2: 60}"
|
||||
//
|
||||
// - with SERIALmaxJSONlevel=2 (or higher):
|
||||
// ./SERIALtoMQTT/temperature/sens1 ==> 22
|
||||
// ./SERIALtoMQTT/temperature/sens2 ==> 23
|
||||
// ./SERIALtoMQTT/humidity/sens1 ==> 80
|
||||
// ./SERIALtoMQTT/humidity/sens2 ==> 60
|
||||
//
|
||||
#ifndef SERIALtoMQTTmode
|
||||
# define SERIALtoMQTTmode 0
|
||||
#endif
|
||||
|
||||
// settings for SERIALTopicMode 0 (RAW)
|
||||
#define SERIALInPost '\n' // Hacky way to get last character of postfix for incoming
|
||||
#define MAX_INPUT JSON_MSG_BUFFER // how much serial data we expect
|
||||
|
||||
// settings for SERIALTopicMode 1 (JSON)
|
||||
#define SERIALmaxJSONlevel 2 // Max nested level in which JSON keys are converted to seperate sub-topics
|
||||
|
||||
// settings for MQTT to SERIAL
|
||||
#define subjectMQTTtoSERIAL "/commands/MQTTtoSERIAL"
|
||||
#ifndef SERIALPre
|
||||
# define SERIALPre "00" // The prefix for the SERIAL message
|
||||
#endif
|
||||
#ifndef SERIALPost
|
||||
# define SERIALPost "\r" // The postfix for the SERIAL message
|
||||
#endif
|
||||
|
||||
//Setup for SERIAL
|
||||
#ifndef SERIALBaud
|
||||
# define SERIALBaud 9600 // The serial connection Baud
|
||||
#endif
|
||||
|
||||
/*-------------------PIN DEFINITIONS----------------------*/
|
||||
#ifndef SERIAL_UART
|
||||
// set hardware serial UART to be used for device communication or
|
||||
// use software emulaton if not defined
|
||||
//
|
||||
// VALUES:
|
||||
// - not defined: use software emulation (pins set by SERIAL_RX_GPIO & SERIAL_TX_GPIO)
|
||||
//
|
||||
// - 0: use HW UART0 (serial), warning: default used for logging & usb
|
||||
// ESP8266: (TX0 GPIO1, RX0 GPIO3)
|
||||
// (TX0 GPIO15, RX0 GPIO13) with UART0 swap enabled
|
||||
// ESP32: (TX0 by SERIAL_TX_GPIO, RX0 by SERIAL_RX_GPIO)
|
||||
//
|
||||
// - 1: use HW UART1 (serial1)
|
||||
// ESP8266: (TX1 GPIO2, RX none) only transmit available
|
||||
// ESP32: (TX1 by SERIAL_TX_GPIO, RX1 by SERIAL_RX_GPIO)
|
||||
//
|
||||
// - 2: use HW UART2 (serial2)
|
||||
// ESP8266: N/A
|
||||
// ESP32: (TX2 by SERIAL_TX_GPIO, RX2 by SERIAL_RX_GPIO)
|
||||
//
|
||||
// - 3: use HW UART3 (serial3)
|
||||
// ESP8266: N/A
|
||||
// ESP32: N/A
|
||||
//
|
||||
// defaults
|
||||
# ifdef ESP32
|
||||
# define SERIAL_UART 1 // use HW UART ESP32
|
||||
# else
|
||||
# undef SERIAL_UART // default use software serial
|
||||
//# define SERIAL_UART 1 // define to use HW UART
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SERIAL_UART0_SWAP
|
||||
// option for ESP8266 only to swap UART0 ports from (GPIO1,GPIO3) to (GPIO15,GPIO13)
|
||||
# define SERIAL_UART0_SWAP
|
||||
#endif
|
||||
|
||||
#ifndef SERIAL_RX_GPIO
|
||||
// define receive pin (for software serial or ESP32 with configurable HW UART)
|
||||
# if defined(ESP8266) && !defined(SERIAL_UART)
|
||||
# define SERIAL_RX_GPIO 4 //D2
|
||||
# elif defined(ESP32)
|
||||
# define SERIAL_RX_GPIO 26
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SERIAL_TX_GPIO
|
||||
// define transmit pin (for software serial and/or ESP32)
|
||||
# if defined(ESP8266) && !defined(SERIAL_UART)
|
||||
# define SERIAL_TX_GPIO 2 //D4
|
||||
# elif ESP32
|
||||
# define SERIAL_TX_GPIO 14
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -216,8 +216,8 @@ struct GfSun2000Data {};
|
||||
#if defined(ZdisplaySSD1306)
|
||||
# include "config_SSD1306.h"
|
||||
#endif
|
||||
#if defined(ZgatewayRS232)
|
||||
# include "config_RS232.h"
|
||||
#if defined(ZgatewaySERIAL)
|
||||
# include "config_SERIAL.h"
|
||||
#endif
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
@@ -1490,9 +1490,9 @@ void setup() {
|
||||
setupDHT();
|
||||
modules.add(ZsensorDHT);
|
||||
#endif
|
||||
#ifdef ZgatewayRS232
|
||||
setupRS232();
|
||||
modules.add(ZgatewayRS232);
|
||||
#ifdef ZgatewaySERIAL
|
||||
setupSERIAL();
|
||||
modules.add(ZgatewaySERIAL);
|
||||
#endif
|
||||
#ifdef ZsensorSHTC3
|
||||
setupSHTC3();
|
||||
@@ -2520,8 +2520,8 @@ void loop() {
|
||||
if (RFM69toMQTT())
|
||||
Log.trace(F("RFM69toMQTT OK" CR));
|
||||
#endif
|
||||
#ifdef ZgatewayRS232
|
||||
RS232toMQTT();
|
||||
#ifdef ZgatewaySERIAL
|
||||
SERIALtoMQTT();
|
||||
#endif
|
||||
#ifdef ZactuatorFASTLED
|
||||
FASTLEDLoop();
|
||||
@@ -2898,8 +2898,8 @@ void receivingMQTT(char* topicOri, char* datacallback) {
|
||||
# ifdef ZactuatorSomfy
|
||||
MQTTtoSomfy(topicOri, jsondata);
|
||||
# endif
|
||||
# ifdef ZgatewayRS232
|
||||
MQTTtoRS232(topicOri, jsondata);
|
||||
# ifdef ZgatewaySERIAL
|
||||
MQTTtoSERIAL(topicOri, jsondata);
|
||||
# endif
|
||||
# ifdef MQTT_HTTPS_FW_UPDATE
|
||||
MQTTHttpsFWUpdate(topicOri, jsondata);
|
||||
|
||||
@@ -78,7 +78,7 @@ extra_configs =
|
||||
;default_envs = nodemcuv2-fastled-test
|
||||
;default_envs = nodemcuv2-2g
|
||||
;default_envs = nodemcuv2-ir
|
||||
;default_envs = nodemcuv2-rs232
|
||||
;default_envs = nodemcuv2-serial
|
||||
;default_envs = avatto-bakeey-ir
|
||||
;default_envs = nodemcuv2-rf
|
||||
;default_envs = nodemcuv2-rf-cc1101
|
||||
|
||||
Reference in New Issue
Block a user