From d3ef9caa347c7894daee3aadcd5cb5a9359c5fd6 Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Sun, 18 Mar 2018 13:47:30 +0100 Subject: [PATCH] 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 (#2182) --- README.md | 2 +- sonoff/_releasenotes.ino | 5 ++- sonoff/i18n.h | 3 ++ sonoff/settings.h | 18 ++------ sonoff/settings.ino | 4 ++ sonoff/sonoff.h | 1 + sonoff/sonoff.ino | 94 ++++++++++++++++++++++++++++++++-------- sonoff/support.ino | 8 ++++ 8 files changed, 99 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 6b30d05d0..91c14f661 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota 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. -Current version is **5.12.0f** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. +Current version is **5.12.0g** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. ### ATTENTION All versions diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 97fb87e7f..ca3d6c7a7 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,7 @@ -/* 5.12.0f +/* 5.12.0g + * Add support for MQTT to hardware serial bridge using commands Baudrate and SerialSend. Currently supports 8N1 and text only (#2182) + * + * 5.12.0f * Add compile time support for WS2812 BRG and RBG led configurations to be defined in user_config.h (#1690) * * 5.12.0e diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 4bfa45866..d59143209 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -96,6 +96,7 @@ #define D_JSON_SAVESTATE "SaveState" #define D_JSON_SDKVERSION "SDK" #define D_JSON_SELECTED "selected" +#define D_JSON_SERIALRECEIVED "SerialReceived" #define D_JSON_SSID "SSId" #define D_JSON_STARTDST "StartDST" // Start Daylight Savings Time #define D_JSON_STARTED "Started" @@ -240,6 +241,8 @@ #define D_CMND_LEDSTATE "LedState" #define D_CMND_CFGDUMP "CfgDump" #define D_CMND_I2CSCAN "I2CScan" +#define D_CMND_SERIALSEND "SerialSend" +#define D_CMND_BAUDRATE "Baudrate" #define D_CMND_EXCEPTION "Exception" // Commands xdrv_01_light.ino diff --git a/sonoff/settings.h b/sonoff/settings.h index 54c5116ab..3c3caf9da 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -47,7 +47,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t hass_discovery : 1; // bit 19 (v5.11.1a) uint32_t not_power_linked : 1; // bit 20 (v5.11.1f) uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i) - uint32_t spare22 : 1; + uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f) uint32_t spare23 : 1; uint32_t spare24 : 1; uint32_t spare25 : 1; @@ -99,9 +99,7 @@ struct SYSCFG { int8_t timezone; // 016 char ota_url[101]; // 017 char mqtt_prefix[3][11]; // 07C - - byte free_09D[1]; // 09D - + uint8_t baudrate; // 09D byte seriallog_level; // 09E uint8_t sta_config; // 09F byte sta_active; // 0A0 @@ -128,7 +126,6 @@ struct SYSCFG { char mqtt_topic[33]; // 26F char button_topic[33]; // 290 char mqtt_grptopic[33]; // 2B1 - uint8_t display_model; // 2D2 uint8_t display_mode; // 2D3 uint8_t display_refresh; // 2D4 @@ -137,12 +134,12 @@ struct SYSCFG { uint8_t display_address[8]; // 2D8 uint8_t display_dimmer; // 2E0 uint8_t display_size; // 2E1 + uint8_t free_2E2[4]; // 2E2 uint16_t pwm_frequency; // 2E6 power_t power; // 2E8 uint16_t pwm_value[MAX_PWMS]; // 2EC - int16_t altitude; // 2F6 Add since 5.8.0i uint16_t tele_period; // 2F8 uint8_t ex_power; // 2FA Not used since 5.8.0j @@ -152,10 +149,8 @@ struct SYSCFG { uint8_t energy_power_delta; // 33F uint16_t domoticz_update_timer; // 340 uint16_t pwm_range; // 342 - unsigned long domoticz_relay_idx[MAX_DOMOTICZ_IDX]; // 344 unsigned long domoticz_key_idx[MAX_DOMOTICZ_IDX]; // 354 - unsigned long energy_power_calibration; // 364 unsigned long energy_voltage_calibration; // 368 unsigned long energy_current_calibration; // 36C @@ -179,7 +174,6 @@ struct SYSCFG { uint16_t mqtt_retry; // 396 uint8_t poweronstate; // 398 uint8_t last_module; // 399 - uint16_t blinktime; // 39A uint16_t blinkcount; // 39C uint16_t light_rotation; // 39E @@ -205,10 +199,8 @@ struct SYSCFG { uint16_t domoticz_switch_idx[MAX_DOMOTICZ_IDX]; // 454 uint16_t domoticz_sensor_idx[MAX_DOMOTICZ_SNS_IDX]; // 45C uint8_t module; // 474 - uint8_t ws_color[4][3]; // 475 uint8_t ws_width[3]; // 481 - myio my_gp; // 484 uint16_t light_pixels; // 496 uint8_t light_color[5]; // 498 @@ -231,9 +223,7 @@ struct SYSCFG { char web_password[33]; // 4A9 uint8_t switchmode[MAX_SWITCHES]; // 4CA char ntp_server[3][33]; // 4CE - byte ina219_mode; // 531 - uint16_t pulse_timer[MAX_PULSETIMERS]; // 532 byte free_542[2]; // 542 @@ -241,9 +231,7 @@ struct SYSCFG { uint32_t ip_address[4]; // 544 unsigned long energy_kWhtotal; // 554 char mqtt_fulltopic[100]; // 558 - SysBitfield2 flag2; // 5BC Add flag2 since 5.9.2 - unsigned long pulse_counter[MAX_COUNTERS]; // 5C0 uint16_t pulse_counter_type; // 5D0 uint16_t pulse_counter_debounce; // 5D2 diff --git a/sonoff/settings.ino b/sonoff/settings.ino index cc2d1c955..84f68ba08 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -457,6 +457,7 @@ void SettingsDefaultSet2() Settings.save_data = SAVE_DATA; Settings.timezone = APP_TIMEZONE; strlcpy(Settings.ota_url, OTA_URL, sizeof(Settings.ota_url)); + Settings.baudrate = APP_BAUDRATE / 1200; Settings.seriallog_level = SERIAL_LOG_LEVEL; // Settings.sta_active = 0; @@ -899,6 +900,9 @@ void SettingsDelta() Settings.mqtt_fingerprint[1][i] = Settings.mqtt_fingerprint[0][i]; } } + if (Settings.version < 0x050C0007) { + Settings.baudrate = APP_BAUDRATE / 1200; + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index fa3649ad1..0b90213bd 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -99,6 +99,7 @@ typedef unsigned long power_t; // Power (Relay) type #define MIN_BACKLOG_DELAY 2 // Minimal backlog delay in 0.1 seconds #define APP_BAUDRATE 115200 // Default serial baudrate +#define SERIAL_POLLING 100 // Serial receive polling in ms #define MAX_STATUS 11 // Max number of status lines /* diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index e4a8c0b2a..dfd322bae 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x050C0006 // 5.12.0f +#define VERSION 0x050C0007 // 5.12.0g // Location specific includes #include // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0) @@ -76,7 +76,7 @@ enum TasmotaCommands { CMND_LOGHOST, CMND_LOGPORT, CMND_IPADDRESS, CMND_NTPSERVER, CMND_AP, CMND_SSID, CMND_PASSWORD, CMND_HOSTNAME, CMND_WIFICONFIG, CMND_FRIENDLYNAME, CMND_SWITCHMODE, CMND_WEBSERVER, CMND_WEBPASSWORD, CMND_WEBLOG, CMND_EMULATION, CMND_TELEPERIOD, CMND_RESTART, CMND_RESET, CMND_TIMEZONE, CMND_ALTITUDE, CMND_LEDPOWER, CMND_LEDSTATE, - CMND_CFGDUMP, CMND_I2CSCAN, CMND_EXCEPTION }; + CMND_CFGDUMP, CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_EXCEPTION }; const char kTasmotaCommands[] PROGMEM = D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|" 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 = D_CMND_LOGHOST "|" D_CMND_LOGPORT "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_WEBSERVER "|" D_CMND_WEBPASSWORD "|" D_CMND_WEBLOG "|" D_CMND_EMULATION "|" D_CMND_TELEPERIOD "|" D_CMND_RESTART "|" D_CMND_RESET "|" D_CMND_TIMEZONE "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" - D_CMND_CFGDUMP "|" D_CMND_I2CSCAN + D_CMND_CFGDUMP "|" D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE #ifdef DEBUG_THEO "|" D_CMND_EXCEPTION #endif @@ -102,6 +102,7 @@ const char kOptionBlinkOff[] PROGMEM = "BLINKOFF|" D_BLINKOFF ; int baudrate = APP_BAUDRATE; // Serial interface baud rate SerialConfig serial_config = SERIAL_8N1; // Serial interface configuration 8 data bits, No parity, 1 stop bit byte serial_in_byte; // Received byte +unsigned long serial_polling_window = 0; // Serial polling window int serial_in_byte_counter = 0; // Index in receive buffer byte dual_hex_code = 0; // Sonoff dual input flag uint16_t dual_button_code = 0; // Sonoff dual received code @@ -422,10 +423,12 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) if (!strcmp(dataBuf,"?")) data_len = 0; int16_t payload = -99; // No payload uint16_t payload16 = 0; - long lnum = strtol(dataBuf, &p, 10); + long payload32 = strtol(dataBuf, &p, 10); if (p != dataBuf) { - payload = (int16_t) lnum; // -32766 - 32767 - payload16 = (uint16_t) lnum; // 0 - 65535 + payload = (int16_t) payload32; // -32766 - 32767 + payload16 = (uint16_t) payload32; // 0 - 65535 + } else { + payload32 = 0; } backlog_delay = MIN_BACKLOG_DELAY; // Reset backlog delay @@ -810,11 +813,27 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) strlcpy(Settings.ota_url, (1 == payload) ? OTA_URL : dataBuf, sizeof(Settings.ota_url)); snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, Settings.ota_url); } + else if (CMND_BAUDRATE == command_code) { + if (payload32 > 0) { + payload32 /= 1200; // Make it a valid baudrate + baudrate = (1 == payload) ? APP_BAUDRATE : payload32 * 1200; + SetSerialBaudrate(baudrate); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.baudrate * 1200); + } + else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 2)) { + SetSeriallog(LOG_LEVEL_NONE); + Settings.flag.mqtt_serial = 1; + if (data_len > 0) { + if (1 == index) Serial.printf("%s\n", dataBuf); + if (2 == index) Serial.printf("%s", dataBuf); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); + } + } else if (CMND_SERIALLOG == command_code) { if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) { - Settings.seriallog_level = payload; - seriallog_level = payload; - seriallog_timer = 0; + Settings.flag.mqtt_serial = 0; + SetSeriallog(payload); } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE_ACTIVE_NVALUE, command, Settings.seriallog_level, seriallog_level); } @@ -1016,7 +1035,7 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, GetStateText(bitRead(Settings.ledstate, 3))); } - else if (CMND_LEDSTATE ==command_code) { + else if (CMND_LEDSTATE == command_code) { if ((payload >= 0) && (payload < MAX_LED_OPTION)) { Settings.ledstate = payload; if (!Settings.ledstate) SetLedPower(0); @@ -1902,41 +1921,73 @@ void SerialInput() if (serial_in_byte > 127) { // binary data... serial_in_byte_counter = 0; + serial_polling_window = 0; Serial.flush(); return; } if (isprint(serial_in_byte)) { - if (serial_in_byte_counter < INPUT_BUFFER_SIZE) { // add char to string if it still fits + if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // add char to string if it still fits serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; + serial_polling_window = millis(); } else { serial_in_byte_counter = 0; + serial_polling_window = 0; } } /*-------------------------------------------------------------------------------------------*\ * Sonoff SC 19200 baud serial interface \*-------------------------------------------------------------------------------------------*/ - if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P - serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed - SonoffScSerialInput(serial_in_buffer); - serial_in_byte_counter = 0; - Serial.flush(); - return; + if (SONOFF_SC == Settings.module) { + if (serial_in_byte == '\x1B') { // Sonoff SC status from ATMEGA328P + serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed + SonoffScSerialInput(serial_in_buffer); + serial_in_byte_counter = 0; + Serial.flush(); + return; + } } /*-------------------------------------------------------------------------------------------*/ - +/* else if (serial_in_byte == '\n') { + serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed + if (!Settings.flag.mqtt_serial) { + seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (byte)LOG_LEVEL_INFO : Settings.seriallog_level; + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), serial_in_buffer); + AddLog(LOG_LEVEL_INFO); + ExecuteCommand(serial_in_buffer); + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer); + MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED)); + } + serial_in_byte_counter = 0; + serial_polling_window = 0; + Serial.flush(); + return; + } +*/ + else if (!Settings.flag.mqtt_serial && (serial_in_byte == '\n')) { serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (byte)LOG_LEVEL_INFO : Settings.seriallog_level; snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_COMMAND "%s"), serial_in_buffer); AddLog(LOG_LEVEL_INFO); ExecuteCommand(serial_in_buffer); serial_in_byte_counter = 0; + serial_polling_window = 0; Serial.flush(); return; } } + + if (Settings.flag.mqtt_serial && serial_in_byte_counter && (millis() > (serial_polling_window + SERIAL_POLLING))) { + serial_in_buffer[serial_in_byte_counter] = 0; // serial data completed + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SERIALRECEIVED "\":\"%s\"}"), serial_in_buffer); + MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED)); + serial_in_byte_counter = 0; + serial_polling_window = 0; + Serial.flush(); + } } /********************************************************************************************/ @@ -2033,18 +2084,22 @@ void GpioInit() } if (SONOFF_BRIDGE == Settings.module) { + Settings.flag.mqtt_serial = 0; baudrate = 19200; } if (SONOFF_DUAL == Settings.module) { + Settings.flag.mqtt_serial = 0; devices_present = 2; baudrate = 19200; } else if (CH4 == Settings.module) { + Settings.flag.mqtt_serial = 0; devices_present = 4; baudrate = 19200; } else if (SONOFF_SC == Settings.module) { + Settings.flag.mqtt_serial = 0; devices_present = 0; baudrate = 19200; } @@ -2141,6 +2196,7 @@ void setup() OsWatchInit(); + baudrate = Settings.baudrate * 1200; seriallog_level = Settings.seriallog_level; seriallog_timer = SERIALLOG_TIMER; #ifndef USE_EMULATION @@ -2246,7 +2302,7 @@ void loop() if (millis() >= state_loop_timer) StateLoop(); - if (Serial.available()) SerialInput(); + SerialInput(); // yield(); // yield == delay(0), delay contains yield, auto yield in loop delay(sleep); // https://github.com/esp8266/Arduino/issues/2021 diff --git a/sonoff/support.ino b/sonoff/support.ino index 1033d7e1b..62312bd7b 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -401,6 +401,7 @@ int GetCommandCode(char* destination, size_t destination_size, const char* needl void SetSerialBaudrate(int baudrate) { + Settings.baudrate = baudrate / 1200; if (Serial.baudRate() != baudrate) { if (seriallog_level) { 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) * \*********************************************************************************************/ +void SetSeriallog(byte loglevel) +{ + Settings.seriallog_level = loglevel; + seriallog_level = loglevel; + seriallog_timer = 0; +} + #ifdef USE_WEBSERVER void GetLog(byte idx, char** entry_pp, size_t* len_p) {