Skip to content

Commit 3a8d67b

Browse files
committed
v5.12.0g - Add hardware serial mqtt bridge
5.12.0g * Add support for MQTT to hardware serial bridge using commands Baudrate and SerialSend. Currently supports 8N1 and text only (arendst#2182)
1 parent 1f78bd1 commit 3a8d67b

File tree

8 files changed

+98
-35
lines changed

8 files changed

+98
-35
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
## Sonoff-Tasmota
22
Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE.
33

4-
Current version is **5.12.0f** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
4+
Current version is **5.12.0g** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information.
55

66
### ATTENTION All versions
77

sonoff/_releasenotes.ino

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
/* 5.12.0f
1+
/* 5.12.0g
2+
* Add support for MQTT to hardware serial bridge using commands Baudrate and SerialSend. Currently supports 8N1 and text only (#2182)
3+
*
4+
* 5.12.0f
25
* Add compile time support for WS2812 BRG and RBG led configurations to be defined in user_config.h (#1690)
36
*
47
* 5.12.0e

sonoff/i18n.h

+3
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
#define D_JSON_SAVESTATE "SaveState"
9797
#define D_JSON_SDKVERSION "SDK"
9898
#define D_JSON_SELECTED "selected"
99+
#define D_JSON_SERIALRECEIVED "SerialReceived"
99100
#define D_JSON_SSID "SSId"
100101
#define D_JSON_STARTDST "StartDST" // Start Daylight Savings Time
101102
#define D_JSON_STARTED "Started"
@@ -240,6 +241,8 @@
240241
#define D_CMND_LEDSTATE "LedState"
241242
#define D_CMND_CFGDUMP "CfgDump"
242243
#define D_CMND_I2CSCAN "I2CScan"
244+
#define D_CMND_SERIALSEND "SerialSend"
245+
#define D_CMND_BAUDRATE "Baudrate"
243246
#define D_CMND_EXCEPTION "Exception"
244247

245248
// Commands xdrv_01_light.ino

sonoff/settings.h

+3-15
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
4747
uint32_t hass_discovery : 1; // bit 19 (v5.11.1a)
4848
uint32_t not_power_linked : 1; // bit 20 (v5.11.1f)
4949
uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i)
50-
uint32_t spare22 : 1;
50+
uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f)
5151
uint32_t spare23 : 1;
5252
uint32_t spare24 : 1;
5353
uint32_t spare25 : 1;
@@ -99,9 +99,7 @@ struct SYSCFG {
9999
int8_t timezone; // 016
100100
char ota_url[101]; // 017
101101
char mqtt_prefix[3][11]; // 07C
102-
103-
byte free_09D[1]; // 09D
104-
102+
uint8_t baudrate; // 09D
105103
byte seriallog_level; // 09E
106104
uint8_t sta_config; // 09F
107105
byte sta_active; // 0A0
@@ -128,7 +126,6 @@ struct SYSCFG {
128126
char mqtt_topic[33]; // 26F
129127
char button_topic[33]; // 290
130128
char mqtt_grptopic[33]; // 2B1
131-
132129
uint8_t display_model; // 2D2
133130
uint8_t display_mode; // 2D3
134131
uint8_t display_refresh; // 2D4
@@ -137,12 +134,12 @@ struct SYSCFG {
137134
uint8_t display_address[8]; // 2D8
138135
uint8_t display_dimmer; // 2E0
139136
uint8_t display_size; // 2E1
137+
140138
uint8_t free_2E2[4]; // 2E2
141139

142140
uint16_t pwm_frequency; // 2E6
143141
power_t power; // 2E8
144142
uint16_t pwm_value[MAX_PWMS]; // 2EC
145-
146143
int16_t altitude; // 2F6 Add since 5.8.0i
147144
uint16_t tele_period; // 2F8
148145
uint8_t ex_power; // 2FA Not used since 5.8.0j
@@ -152,10 +149,8 @@ struct SYSCFG {
152149
uint8_t energy_power_delta; // 33F
153150
uint16_t domoticz_update_timer; // 340
154151
uint16_t pwm_range; // 342
155-
156152
unsigned long domoticz_relay_idx[MAX_DOMOTICZ_IDX]; // 344
157153
unsigned long domoticz_key_idx[MAX_DOMOTICZ_IDX]; // 354
158-
159154
unsigned long energy_power_calibration; // 364
160155
unsigned long energy_voltage_calibration; // 368
161156
unsigned long energy_current_calibration; // 36C
@@ -179,7 +174,6 @@ struct SYSCFG {
179174
uint16_t mqtt_retry; // 396
180175
uint8_t poweronstate; // 398
181176
uint8_t last_module; // 399
182-
183177
uint16_t blinktime; // 39A
184178
uint16_t blinkcount; // 39C
185179
uint16_t light_rotation; // 39E
@@ -205,10 +199,8 @@ struct SYSCFG {
205199
uint16_t domoticz_switch_idx[MAX_DOMOTICZ_IDX]; // 454
206200
uint16_t domoticz_sensor_idx[MAX_DOMOTICZ_SNS_IDX]; // 45C
207201
uint8_t module; // 474
208-
209202
uint8_t ws_color[4][3]; // 475
210203
uint8_t ws_width[3]; // 481
211-
212204
myio my_gp; // 484
213205
uint16_t light_pixels; // 496
214206
uint8_t light_color[5]; // 498
@@ -231,19 +223,15 @@ struct SYSCFG {
231223
char web_password[33]; // 4A9
232224
uint8_t switchmode[MAX_SWITCHES]; // 4CA
233225
char ntp_server[3][33]; // 4CE
234-
235226
byte ina219_mode; // 531
236-
237227
uint16_t pulse_timer[MAX_PULSETIMERS]; // 532
238228

239229
byte free_542[2]; // 542
240230

241231
uint32_t ip_address[4]; // 544
242232
unsigned long energy_kWhtotal; // 554
243233
char mqtt_fulltopic[100]; // 558
244-
245234
SysBitfield2 flag2; // 5BC Add flag2 since 5.9.2
246-
247235
unsigned long pulse_counter[MAX_COUNTERS]; // 5C0
248236
uint16_t pulse_counter_type; // 5D0
249237
uint16_t pulse_counter_debounce; // 5D2

sonoff/settings.ino

+4
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ void SettingsDefaultSet2()
457457
Settings.save_data = SAVE_DATA;
458458
Settings.timezone = APP_TIMEZONE;
459459
strlcpy(Settings.ota_url, OTA_URL, sizeof(Settings.ota_url));
460+
Settings.baudrate = APP_BAUDRATE / 1200;
460461

461462
Settings.seriallog_level = SERIAL_LOG_LEVEL;
462463
// Settings.sta_active = 0;
@@ -899,6 +900,9 @@ void SettingsDelta()
899900
Settings.mqtt_fingerprint[1][i] = Settings.mqtt_fingerprint[0][i];
900901
}
901902
}
903+
if (Settings.version < 0x050C0007) {
904+
Settings.baudrate = APP_BAUDRATE / 1200;
905+
}
902906

903907
Settings.version = VERSION;
904908
SettingsSave(1);

sonoff/sonoff.h

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ typedef unsigned long power_t; // Power (Relay) type
9999
#define MIN_BACKLOG_DELAY 2 // Minimal backlog delay in 0.1 seconds
100100

101101
#define APP_BAUDRATE 115200 // Default serial baudrate
102+
#define SERIAL_POLLING 100 // Serial receive polling in ms
102103
#define MAX_STATUS 11 // Max number of status lines
103104

104105
/*

sonoff/sonoff.ino

+74-18
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
- Select IDE Tools - Flash Size: "1M (no SPIFFS)"
2626
====================================================*/
2727

28-
#define VERSION 0x050C0006 // 5.12.0f
28+
#define VERSION 0x050C0007 // 5.12.0g
2929

3030
// Location specific includes
3131
#include <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
@@ -76,7 +76,7 @@ enum TasmotaCommands {
7676
CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME,
7777
CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_EMULATION,
7878
CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE,
79-
CMND_CFGDUMP, CMND_I2CSCAN, CMND_EXCEPTION };
79+
CMND_CFGDUMP, CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_EXCEPTION };
8080
const char kTasmotaCommands[] PROGMEM =
8181
D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|"
8282
D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_SENSOR "|" D_CMND_SAVEDATA "|" D_CMND_SETOPTION "|" D_CMND_TEMPERATURE_RESOLUTION "|" D_CMND_HUMIDITY_RESOLUTION "|"
@@ -86,7 +86,7 @@ const char kTasmotaCommands[] PROGMEM =
8686
D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|"
8787
D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_EMULATION "|"
8888
D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|"
89-
D_CMND_CFGDUMP "|" D_CMND_I2CSCAN
89+
D_CMND_CFGDUMP "|" D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE
9090
#ifdef DEBUG_THEO
9191
"|" D_CMND_EXCEPTION
9292
#endif
@@ -102,6 +102,7 @@ const char kOptionBlinkOff[] PROGMEM = "BLINKOFF|" D_BLINKOFF ;
102102
int baudrate = APP_BAUDRATE; // Serial interface baud rate
103103
SerialConfig serial_config = SERIAL_8N1; // Serial interface configuration 8 data bits, No parity, 1 stop bit
104104
byte serial_in_byte; // Received byte
105+
unsigned long serial_polling_window = 0; // Serial polling window
105106
int serial_in_byte_counter = 0; // Index in receive buffer
106107
byte dual_hex_code = 0; // Sonoff dual input flag
107108
uint16_t dual_button_code = 0; // Sonoff dual received code
@@ -422,10 +423,12 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
422423
if (!strcmp(dataBuf,"?")) data_len = 0;
423424
int16_t payload = -99; // No payload
424425
uint16_t payload16 = 0;
425-
long lnum = strtol(dataBuf, &p, 10);
426+
long payload32 = strtol(dataBuf, &p, 10);
426427
if (p != dataBuf) {
427-
payload = (int16_t) lnum; // -32766 - 32767
428-
payload16 = (uint16_t) lnum; // 0 - 65535
428+
payload = (int16_t) payload32; // -32766 - 32767
429+
payload16 = (uint16_t) payload32; // 0 - 65535
430+
} else {
431+
payload32 = 0;
429432
}
430433
backlog_delay = MIN_BACKLOG_DELAY; // Reset backlog delay
431434

@@ -810,11 +813,27 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
810813
strlcpy(Settings.ota_url, (1 == payload) ? OTA_URL : dataBuf, sizeof(Settings.ota_url));
811814
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.ota_url);
812815
}
816+
else if (CMND_BAUDRATE == command_code) {
817+
if (payload32 > 0) {
818+
payload32 /= 1200; // Make it a valid baudrate
819+
baudrate = (1 == payload) ? APP_BAUDRATE : payload32 * 1200;
820+
SetSerialBaudrate(baudrate);
821+
}
822+
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.baudrate * 1200);
823+
}
824+
else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 2)) {
825+
SetSeriallog(LOG_LEVEL_NONE);
826+
Settings.flag.mqtt_serial = 1;
827+
if (data_len > 0) {
828+
if (1 == index) Serial.printf("%s\n", dataBuf);
829+
if (2 == index) Serial.printf("%s", dataBuf);
830+
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
831+
}
832+
}
813833
else if (CMND_SERIALLOG == command_code) {
814834
if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) {
815-
Settings.seriallog_level = payload;
816-
seriallog_level = payload;
817-
seriallog_timer = 0;
835+
Settings.flag.mqtt_serial = 0;
836+
SetSeriallog(payload);
818837
}
819838
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, command, Settings.seriallog_level, seriallog_level);
820839
}
@@ -1016,7 +1035,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
10161035
}
10171036
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(bitRead(Settings.ledstate, 3)));
10181037
}
1019-
else if (CMND_LEDSTATE ==command_code) {
1038+
else if (CMND_LEDSTATE == command_code) {
10201039
if ((payload >= 0) && (payload < MAX_LED_OPTION)) {
10211040
Settings.ledstate = payload;
10221041
if (!Settings.ledstate) SetLedPower(0);
@@ -1902,41 +1921,73 @@ void SerialInput()
19021921

19031922
if (serial_in_byte > 127) { // binary data...
19041923
serial_in_byte_counter = 0;
1924+
serial_polling_window = 0;
19051925
Serial.flush();
19061926
return;
19071927
}
19081928
if (isprint(serial_in_byte)) {
1909-
if (serial_in_byte_counter < INPUT_BUFFER_SIZE) { // add char to string if it still fits
1929+
if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits
19101930
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
1931+
serial_polling_window = millis();
19111932
} else {
19121933
serial_in_byte_counter = 0;
1934+
serial_polling_window = 0;
19131935
}
19141936
}
19151937

19161938
/*-------------------------------------------------------------------------------------------*\
19171939
* Sonoff SC 19200 baud serial interface
19181940
\*-------------------------------------------------------------------------------------------*/
1919-
if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P
1941+
if (SONOFF_SC == Settings.module) {
1942+
if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P
1943+
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
1944+
SonoffScSerialInput(serial_in_buffer);
1945+
serial_in_byte_counter = 0;
1946+
Serial.flush();
1947+
return;
1948+
}
1949+
}
1950+
1951+
/*-------------------------------------------------------------------------------------------*/
1952+
/*
1953+
else if (serial_in_byte == '\n') {
19201954
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
1921-
SonoffScSerialInput(serial_in_buffer);
1955+
if (!Settings.flag.mqtt_serial) {
1956+
seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (byte)LOG_LEVEL_INFO : Settings.seriallog_level;
1957+
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), serial_in_buffer);
1958+
AddLog(LOG_LEVEL_INFO);
1959+
ExecuteCommand(serial_in_buffer);
1960+
} else {
1961+
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer);
1962+
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
1963+
}
19221964
serial_in_byte_counter = 0;
1965+
serial_polling_window = 0;
19231966
Serial.flush();
19241967
return;
19251968
}
1926-
1927-
/*-------------------------------------------------------------------------------------------*/
1928-
1929-
else if (serial_in_byte == '\n') {
1969+
*/
1970+
else if (!Settings.flag.mqtt_serial && (serial_in_byte == '\n')) {
19301971
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
19311972
seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (byte)LOG_LEVEL_INFO : Settings.seriallog_level;
19321973
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), serial_in_buffer);
19331974
AddLog(LOG_LEVEL_INFO);
19341975
ExecuteCommand(serial_in_buffer);
19351976
serial_in_byte_counter = 0;
1977+
serial_polling_window = 0;
19361978
Serial.flush();
19371979
return;
19381980
}
19391981
}
1982+
1983+
if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) {
1984+
serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed
1985+
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer);
1986+
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED));
1987+
serial_in_byte_counter = 0;
1988+
serial_polling_window = 0;
1989+
Serial.flush();
1990+
}
19401991
}
19411992

19421993
/********************************************************************************************/
@@ -2033,18 +2084,22 @@ void GpioInit()
20332084
}
20342085

20352086
if (SONOFF_BRIDGE == Settings.module) {
2087+
Settings.flag.mqtt_serial = 0;
20362088
baudrate = 19200;
20372089
}
20382090

20392091
if (SONOFF_DUAL == Settings.module) {
2092+
Settings.flag.mqtt_serial = 0;
20402093
devices_present = 2;
20412094
baudrate = 19200;
20422095
}
20432096
else if (CH4 == Settings.module) {
2097+
Settings.flag.mqtt_serial = 0;
20442098
devices_present = 4;
20452099
baudrate = 19200;
20462100
}
20472101
else if (SONOFF_SC == Settings.module) {
2102+
Settings.flag.mqtt_serial = 0;
20482103
devices_present = 0;
20492104
baudrate = 19200;
20502105
}
@@ -2141,6 +2196,7 @@ void setup()
21412196

21422197
OsWatchInit();
21432198

2199+
baudrate = Settings.baudrate * 1200;
21442200
seriallog_level = Settings.seriallog_level;
21452201
seriallog_timer = SERIALLOG_TIMER;
21462202
#ifndef USE_EMULATION
@@ -2246,7 +2302,7 @@ void loop()
22462302

22472303
if (millis() >= state_loop_timer) StateLoop();
22482304

2249-
if (Serial.available()) SerialInput();
2305+
SerialInput();
22502306

22512307
// yield(); // yield == delay(0), delay contains yield, auto yield in loop
22522308
delay(sleep); // https://github.com/esp8266/Arduino/issues/2021

sonoff/support.ino

+8
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ int GetCommandCode(char* destination, size_t destination_size, const char* needl
401401

402402
void SetSerialBaudrate(int baudrate)
403403
{
404+
Settings.baudrate = baudrate / 1200;
404405
if (Serial.baudRate() != baudrate) {
405406
if (seriallog_level) {
406407
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION D_SET_BAUDRATE_TO " %d"), baudrate);
@@ -1378,6 +1379,13 @@ boolean Xsns02(byte function)
13781379
*
13791380
\*********************************************************************************************/
13801381

1382+
void SetSeriallog(byte loglevel)
1383+
{
1384+
Settings.seriallog_level = loglevel;
1385+
seriallog_level = loglevel;
1386+
seriallog_timer = 0;
1387+
}
1388+
13811389
#ifdef USE_WEBSERVER
13821390
void GetLog(byte idx, char** entry_pp, size_t* len_p)
13831391
{

0 commit comments

Comments
 (0)