diff --git a/README.md b/README.md index 91c14f661..2f4d7ed1c 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.0g** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. +Current version is **5.12.0h** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. ### ATTENTION All versions diff --git a/lib/TasmotaSerial-1.1.0/README.md b/lib/TasmotaSerial-1.2.0/README.md similarity index 79% rename from lib/TasmotaSerial-1.1.0/README.md rename to lib/TasmotaSerial-1.2.0/README.md index 5c7a24721..205a9597c 100644 --- a/lib/TasmotaSerial-1.1.0/README.md +++ b/lib/TasmotaSerial-1.2.0/README.md @@ -1,6 +1,6 @@ # TasmotaSerial -Implementation of software serial library for the ESP8266 at 9600 baud +Implementation of software serial library for the ESP8266 Allows for several instances to be active at the same time. diff --git a/lib/TasmotaSerial-1.1.0/examples/swsertest/swsertest.ino b/lib/TasmotaSerial-1.2.0/examples/swsertest/swsertest.ino similarity index 100% rename from lib/TasmotaSerial-1.1.0/examples/swsertest/swsertest.ino rename to lib/TasmotaSerial-1.2.0/examples/swsertest/swsertest.ino diff --git a/lib/TasmotaSerial-1.1.0/keywords.txt b/lib/TasmotaSerial-1.2.0/keywords.txt similarity index 100% rename from lib/TasmotaSerial-1.1.0/keywords.txt rename to lib/TasmotaSerial-1.2.0/keywords.txt diff --git a/lib/TasmotaSerial-1.1.0/library.json b/lib/TasmotaSerial-1.2.0/library.json similarity index 89% rename from lib/TasmotaSerial-1.1.0/library.json rename to lib/TasmotaSerial-1.2.0/library.json index 986c6d7ac..e4b2ba8a3 100644 --- a/lib/TasmotaSerial-1.1.0/library.json +++ b/lib/TasmotaSerial-1.2.0/library.json @@ -1,10 +1,10 @@ { "name": "TasmotaSerial", - "version": "1.0.0", + "version": "1.2.0", "keywords": [ "serial", "io", "TasmotaSerial" ], - "description": "Implementation of software serial for ESP8266 at 9600 baud.", + "description": "Implementation of software serial for ESP8266.", "repository": { "type": "git", diff --git a/lib/TasmotaSerial-1.1.0/library.properties b/lib/TasmotaSerial-1.2.0/library.properties similarity index 64% rename from lib/TasmotaSerial-1.1.0/library.properties rename to lib/TasmotaSerial-1.2.0/library.properties index 703b613ee..d427d0fb3 100644 --- a/lib/TasmotaSerial-1.1.0/library.properties +++ b/lib/TasmotaSerial-1.2.0/library.properties @@ -1,8 +1,8 @@ name=TasmotaSerial -version=1.0 +version=1.2.0 author=Theo Arends maintainer=Theo Arends -sentence=Implementation of software serial for ESP8266 at 9600 baud. +sentence=Implementation of software serial for ESP8266. paragraph= category=Signal Input/Output url= diff --git a/lib/TasmotaSerial-1.1.0/src/TasmotaSerial.cpp b/lib/TasmotaSerial-1.2.0/src/TasmotaSerial.cpp similarity index 91% rename from lib/TasmotaSerial-1.1.0/src/TasmotaSerial.cpp rename to lib/TasmotaSerial-1.2.0/src/TasmotaSerial.cpp index 35881dfb3..c189442e6 100644 --- a/lib/TasmotaSerial-1.1.0/src/TasmotaSerial.cpp +++ b/lib/TasmotaSerial-1.2.0/src/TasmotaSerial.cpp @@ -87,9 +87,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin) m_in_pos = m_out_pos = 0; if (m_rx_pin > -1) { m_buffer = (uint8_t*)malloc(TM_SERIAL_BUFFER_SIZE); - if (m_buffer == NULL) { - return; - } + if (m_buffer == NULL) return; // Use getCycleCount() loop to get as exact timing as possible m_bit_time = ESP.getCpuFreqMHz() *1000000 /TM_SERIAL_BAUDRATE; pinMode(m_rx_pin, INPUT); @@ -111,7 +109,8 @@ bool TasmotaSerial::isValidGPIOpin(int pin) bool TasmotaSerial::begin(long speed) { // Use getCycleCount() loop to get as exact timing as possible m_bit_time = ESP.getCpuFreqMHz() *1000000 /speed; - return m_valid && (speed <= TM_SERIAL_BAUDRATE); + m_high_speed = (speed > 9600); + return m_valid; } bool TasmotaSerial::begin() { @@ -123,17 +122,13 @@ void TasmotaSerial::flush() { } int TasmotaSerial::peek() { - if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) { - return -1; - } + if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; return m_buffer[m_out_pos]; } int TasmotaSerial::read() { - if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) { - return -1; - } + if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1; uint8_t ch = m_buffer[m_out_pos]; m_out_pos = (m_out_pos +1) % TM_SERIAL_BUFFER_SIZE; return ch; @@ -142,23 +137,20 @@ int TasmotaSerial::read() int TasmotaSerial::available() { int avail = m_in_pos - m_out_pos; - if (avail < 0) { - avail += TM_SERIAL_BUFFER_SIZE; - } + if (avail < 0) avail += TM_SERIAL_BUFFER_SIZE; return avail; } #ifdef TM_SERIAL_USE_IRAM -#define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts +#define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait) if (!m_high_speed) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts #else #define TM_SERIAL_WAIT { while (ESP.getCycleCount()-start < wait); wait += m_bit_time; } #endif size_t TasmotaSerial::write(uint8_t b) { - if (-1 == m_tx_pin) { - return 0; - } + if (-1 == m_tx_pin) return 0; + if (m_high_speed) cli(); // Disable interrupts in order to get a clean transmit unsigned long wait = m_bit_time; digitalWrite(m_tx_pin, HIGH); unsigned long start = ESP.getCycleCount(); @@ -173,6 +165,7 @@ size_t TasmotaSerial::write(uint8_t b) // Stop bit digitalWrite(m_tx_pin, HIGH); TM_SERIAL_WAIT; + if (m_high_speed) sei(); return 1; } @@ -191,9 +184,7 @@ void TasmotaSerial::rxRead() for (int i = 0; i < 8; i++) { TM_SERIAL_WAIT; rec >>= 1; - if (digitalRead(m_rx_pin)) { - rec |= 0x80; - } + if (digitalRead(m_rx_pin)) rec |= 0x80; } // Stop bit TM_SERIAL_WAIT; diff --git a/lib/TasmotaSerial-1.1.0/src/TasmotaSerial.h b/lib/TasmotaSerial-1.2.0/src/TasmotaSerial.h similarity index 91% rename from lib/TasmotaSerial-1.1.0/src/TasmotaSerial.h rename to lib/TasmotaSerial-1.2.0/src/TasmotaSerial.h index d18dd335f..0876590fe 100644 --- a/lib/TasmotaSerial-1.1.0/src/TasmotaSerial.h +++ b/lib/TasmotaSerial-1.2.0/src/TasmotaSerial.h @@ -20,12 +20,12 @@ #ifndef TasmotaSerial_h #define TasmotaSerial_h /*********************************************************************************************\ - * TasmotaSerial supports up to 9600 baud with fixed buffer size of 64 bytes using optional no iram + * TasmotaSerial supports up to 115200 baud with fixed buffer size of 64 bytes using optional no iram * * Based on EspSoftwareSerial v3.3.1 by Peter Lerup (https://github.com/plerup/espsoftwareserial) \*********************************************************************************************/ -#define TM_SERIAL_BAUDRATE 9600 // Max supported baudrate +#define TM_SERIAL_BAUDRATE 9600 // Default baudrate #define TM_SERIAL_BUFFER_SIZE 64 // Receive buffer size #include // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0) @@ -57,6 +57,7 @@ class TasmotaSerial : public Stream { // Member variables bool m_valid; + bool m_high_speed; int m_rx_pin; int m_tx_pin; unsigned long m_bit_time; diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index ca3d6c7a7..7dd12439a 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,5 +1,6 @@ -/* 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.0h + * Add support for Software Serial bridge using commands SerialDelimiter, SBaudrate and SSerialSend. Supports 8N1 and text only (#2190) + * Add support for Hardware Serial bridge using commands SerialDelimiter, Baudrate and SerialSend. 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) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index d59143209..ce785243d 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -242,6 +242,7 @@ #define D_CMND_CFGDUMP "CfgDump" #define D_CMND_I2CSCAN "I2CScan" #define D_CMND_SERIALSEND "SerialSend" +#define D_CMND_SERIALDELIMITER "SerialDelimiter" #define D_CMND_BAUDRATE "Baudrate" #define D_CMND_EXCEPTION "Exception" @@ -340,6 +341,11 @@ #define D_CMND_DISP_SIZE "Size" #define D_CMND_DISP_TEXT "Text" +// Commands xdrv_08_serial_bridge.ino +#define D_CMND_SSERIALSEND "SSerialSend" +#define D_CMND_SBAUDRATE "SBaudrate" + #define D_JSON_SSERIALRECEIVED "SSerialReceived" + /********************************************************************************************/ #ifndef MY_LANGUAGE diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 5f60ae8c1..e78d0a8e0 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 4ba502af3..b0ea8033a 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 99faed325..5fb862b5e 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 531f78d26..dbe241731 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 4690bab6e..7b9c0137f 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 613008ae0..82dde4c38 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "Háttérvil" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 67752fd81..4e16869a4 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 3a02ded56..53bdb7f67 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 6acc8a7f6..90a69afb5 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 180d316d7..7d8f0512c 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "Luz negra" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index d2626ae5f..640b8bef7 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index eb0351508..0cd86bcc8 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index cab33a14b..c3efc118b 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -412,6 +412,8 @@ #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" #define D_SENSOR_SDS0X1 "SDS0X1" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/settings.h b/sonoff/settings.h index 3c3caf9da..936e54963 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -192,9 +192,8 @@ struct SYSCFG { uint16_t ws_wakeup; // 3AA Not used since 5.8.0 char friendlyname[MAX_FRIENDLYNAMES][33]; // 3AC char switch_topic[33]; // 430 - - byte free_451[2]; // 451 - + char serial_delimiter; // 451 + uint8_t sbaudrate; // 452 uint8_t sleep; // 453 uint16_t domoticz_switch_idx[MAX_DOMOTICZ_IDX]; // 454 uint16_t domoticz_sensor_idx[MAX_DOMOTICZ_SNS_IDX]; // 45C diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 84f68ba08..8b8123741 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -458,6 +458,8 @@ void SettingsDefaultSet2() Settings.timezone = APP_TIMEZONE; strlcpy(Settings.ota_url, OTA_URL, sizeof(Settings.ota_url)); Settings.baudrate = APP_BAUDRATE / 1200; + Settings.sbaudrate = SOFT_BAUDRATE / 1200; + Settings.serial_delimiter = 0xff; Settings.seriallog_level = SERIAL_LOG_LEVEL; // Settings.sta_active = 0; @@ -903,6 +905,10 @@ void SettingsDelta() if (Settings.version < 0x050C0007) { Settings.baudrate = APP_BAUDRATE / 1200; } + if (Settings.version < 0x050C0008) { + Settings.sbaudrate = SOFT_BAUDRATE / 1200; + Settings.serial_delimiter = 0xff; + } Settings.version = VERSION; SettingsSave(1); diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 0b90213bd..58079e2df 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -98,6 +98,7 @@ typedef unsigned long power_t; // Power (Relay) type #define MAX_BACKLOG 16 // Max number of commands in backlog (chk backlog_index and backlog_pointer code) #define MIN_BACKLOG_DELAY 2 // Minimal backlog delay in 0.1 seconds +#define SOFT_BAUDRATE 9600 // Default software serial baudrate #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 dfd322bae..941ec36c6 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x050C0007 // 5.12.0g +#define VERSION 0x050C0008 // 5.12.0h // 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_SERIALSEND, CMND_BAUDRATE, CMND_EXCEPTION }; + CMND_CFGDUMP, CMND_I2CSCAN, CMND_SERIALSEND, CMND_BAUDRATE, CMND_SERIALDELIMITER, 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_SERIALSEND "|" D_CMND_BAUDRATE + D_CMND_CFGDUMP "|" D_CMND_I2CSCAN "|" D_CMND_SERIALSEND "|" D_CMND_BAUDRATE "|" D_CMND_SERIALDELIMITER #ifdef DEBUG_THEO "|" D_CMND_EXCEPTION #endif @@ -821,15 +821,35 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len) } 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)) { + else if ((CMND_SERIALSEND == command_code) && (index > 0) && (index <= 3)) { 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); + if (1 == index) { + Serial.printf("%s\n", dataBuf); + } + else if (2 == index) { + Serial.printf("%s", dataBuf); + } + else if (3 == index) { + uint16_t dat_len = data_len; + Serial.printf("%s", Unescape(dataBuf, &dat_len)); + } snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); } } + else if (CMND_SERIALDELIMITER == command_code) { + if ((data_len > 0) && (payload < 256)) { + if (payload > 0) { + Settings.serial_delimiter = payload; + } else { + uint16_t dat_len = data_len; + Unescape(dataBuf, &dat_len); + Settings.serial_delimiter = dataBuf[0]; + } + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_NVALUE, command, Settings.serial_delimiter); + } else if (CMND_SERIALLOG == command_code) { if ((payload >= LOG_LEVEL_NONE) && (payload <= LOG_LEVEL_ALL)) { Settings.flag.mqtt_serial = 0; @@ -1921,17 +1941,26 @@ 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 -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; + if (!Settings.flag.mqtt_serial) { + if (isprint(serial_in_byte)) { + 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; + } else { + serial_in_byte_counter = 0; + } + } + } else { + if (serial_in_byte) { + if ((serial_in_byte_counter < INPUT_BUFFER_SIZE -1) && (serial_in_byte != Settings.serial_delimiter)) { // add char to string if it still fits + serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; + serial_polling_window = millis(); + } else { + serial_polling_window = 0; + break; + } } } @@ -1949,24 +1978,7 @@ void SerialInput() } /*-------------------------------------------------------------------------------------------*/ -/* - 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; @@ -1985,8 +1997,6 @@ void SerialInput() 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(); } } diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 026cc9465..09b4836ba 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -63,6 +63,7 @@ void WifiWpsStatusCallback(wps_cb_status status); #define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) #define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) +#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram) #define USE_IR_HVAC // Support for HVAC system using IR (+2k code) #define USE_IR_RECEIVE // Support for IR receiver (+5k5 code, 264 iram) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 6a0e2cd97..f5a68bbfa 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -89,6 +89,8 @@ enum UserSelectablePins { GPIO_BACKLIGHT, // Display backlight control GPIO_PMS5003, // Plantower PMS5003 Serial interface GPIO_SDS0X1, // Nova Fitness SDS011 Serial interface + GPIO_SBR_TX, // Serial Bridge Serial interface + GPIO_SBR_RX, // Serial Bridge Serial interface GPIO_SENSOR_END }; // Programmer selectable GPIO functionality offset by user selectable GPIOs @@ -130,7 +132,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_PZEM_TX "|" D_SENSOR_PZEM_RX "|" D_SENSOR_SAIR_TX "|" D_SENSOR_SAIR_RX "|" D_SENSOR_SPI_CS "|" D_SENSOR_SPI_DC "|" D_SENSOR_BACKLIGHT "|" - D_SENSOR_PMS5003 "|" D_SENSOR_SDS0X1; + D_SENSOR_PMS5003 "|" D_SENSOR_SDS0X1 "|" + D_SENSOR_SBR_TX "|" D_SENSOR_SBR_RX; /********************************************************************************************/ diff --git a/sonoff/support.ino b/sonoff/support.ino index 62312bd7b..4689ae707 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -197,6 +197,50 @@ char* dtostrfd(double number, unsigned char prec, char *s) return dtostrf(number, 1, prec, s); } +char* Unescape(char* buffer, uint16_t* size) +{ + uint8_t* read = (uint8_t*)buffer; + uint8_t* write = (uint8_t*)buffer; + uint16_t start_size = *size; + uint16_t end_size = *size; + uint8_t che = 0; + + while (start_size > 0) { + uint8_t ch = *read++; + start_size--; + if (ch != '\\') { + *write++ = ch; + } else { + if (start_size > 0) { + uint8_t chi = *read++; + start_size--; + end_size--; + switch (chi) { + case '\\': che = '\\'; break; // 5C Backslash + case 'a': che = '\a'; break; // 07 Bell (Alert) + case 'b': che = '\b'; break; // 08 Backspace + case 'e': che = '\e'; break; // 1B Escape + case 'f': che = '\f'; break; // 0C Formfeed + case 'n': che = '\n'; break; // 0A Linefeed (Newline) + case 'r': che = '\r'; break; // 0D Carriage return +// case 's': che = ' '; break; // 20 Space + case 't': che = '\t'; break; // 09 Horizontal tab + case 'v': che = '\v'; break; // 0B Vertical tab +// case '?': che = '\?'; break; // 3F Question mark + default : { + che = chi; + *write++ = ch; + end_size++; + } + } + *write++ = che; + } + } + } + *size = end_size; + return buffer; +} + boolean ParseIp(uint32_t* addr, const char* str) { uint8_t *part = (uint8_t*)addr; diff --git a/sonoff/user_config.h b/sonoff/user_config.h index caf686d6b..a93e386ae 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -220,6 +220,7 @@ #define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) #define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) +#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) // -- Low level interface devices ----------------- #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram) diff --git a/sonoff/xdrv_08_serial_bridge.ino b/sonoff/xdrv_08_serial_bridge.ino new file mode 100644 index 000000000..428dc5e35 --- /dev/null +++ b/sonoff/xdrv_08_serial_bridge.ino @@ -0,0 +1,149 @@ +/* + xdrv_08_serial_bridge.ino - serial bridge support for Sonoff-Tasmota + + Copyright (C) 2018 Theo Arends and Dániel Zoltán Tolnai + + This program 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. + + This program 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 . +*/ + +#ifdef USE_SERIAL_BRIDGE +/*********************************************************************************************\ + * Serial Bridge using Software Serial library (TasmotaSerial) +\*********************************************************************************************/ +#define SERIAL_BRIDGE_BUFFER_SIZE 130 + +#include + +enum SerialBridgeCommands { CMND_SSERIALSEND, CMND_SBAUDRATE }; +const char kSerialBridgeCommands[] PROGMEM = D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE; + +TasmotaSerial *SerialBridgeSerial; + +uint8_t serial_bridge_active = 1; +uint8_t serial_bridge_in_byte_counter = 0; +unsigned long serial_bridge_polling_window = 0; +char serial_bridge_buffer[SERIAL_BRIDGE_BUFFER_SIZE]; + +void SerialBridgeInput() +{ + while (SerialBridgeSerial->available()) { + yield(); + uint8_t serial_in_byte = SerialBridgeSerial->read(); + + if (serial_in_byte > 127) { // binary data... + serial_bridge_in_byte_counter = 0; + SerialBridgeSerial->flush(); + return; + } + if (serial_in_byte) { + if ((serial_in_byte_counter < sizeof(serial_bridge_buffer) -1) && (serial_in_byte != Settings.serial_delimiter)) { // add char to string if it still fits + serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte; + serial_bridge_polling_window = millis(); // Wait for more data + } else { + serial_bridge_polling_window = 0; // Publish now + break; + } + } + } + + if (serial_bridge_in_byte_counter && (millis() > (serial_bridge_polling_window + SERIAL_POLLING))) { + serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // serial data completed + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_SSERIALRECEIVED "\":\"%s\"}"), serial_bridge_buffer); + MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED)); + serial_bridge_in_byte_counter = 0; + } +} + +/********************************************************************************************/ + +void SerialBridgeInit(void) +{ + serial_bridge_active = 0; + if ((pin[GPIO_SBR_RX] < 99) && (pin[GPIO_SBR_TX] < 99)) { + SerialBridgeSerial = new TasmotaSerial(pin[GPIO_SBR_RX], pin[GPIO_SBR_TX]); + if (SerialBridgeSerial->begin(Settings.sbaudrate * 1200)) { // Baud rate is stored div 1200 so it fits into one byte + serial_bridge_active = 1; + SerialBridgeSerial->flush(); + } + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +boolean SerialBridgeCommand() +{ + char command [CMDSZ]; + boolean serviced = true; + + int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kSerialBridgeCommands); + if ((CMND_SSERIALSEND == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 3)) { + if (XdrvMailbox.data_len > 0) { + if (1 == XdrvMailbox.index) { + SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); + SerialBridgeSerial->write("\n"); + } + else if (2 == XdrvMailbox.index) { + SerialBridgeSerial->write(XdrvMailbox.data, XdrvMailbox.data_len); + } + else if (3 == XdrvMailbox.index) { + SerialBridgeSerial->write(Unescape(XdrvMailbox.data, &XdrvMailbox.data_len), XdrvMailbox.data_len); + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_SVALUE, command, D_JSON_DONE); + } + } + else if (CMND_SBAUDRATE == command_code) { + char *p; + int baud = strtol(XdrvMailbox.data, &p, 10); + if (baud > 0) { + baud /= 1200; // Make it a valid baudrate + Settings.sbaudrate = (1 == XdrvMailbox.payload) ? SOFT_BAUDRATE / 1200 : baud; + SerialBridgeSerial->begin(Settings.sbaudrate * 1200); // Reinitialize serial port with new baud rate + } + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_LVALUE, command, Settings.sbaudrate * 1200); + } + else { + serviced = false; // Unknown command + } + return serviced; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XDRV_08 + +boolean Xdrv08(byte function) +{ + boolean result = false; + + if (serial_bridge_active) { + switch (function) { + case FUNC_INIT: + SerialBridgeInit(); + break; + case FUNC_LOOP: + SerialBridgeInput(); + break; + case FUNC_COMMAND: + result = SerialBridgeCommand(); + break; + } + } + return result; +} + +#endif // USE_SERIAL_BRIDGE