Merge pull request #11 from arendst/development

Update fork
This commit is contained in:
Adrian 2018-03-22 11:35:38 -03:00 committed by GitHub
commit a64b839729
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 530 additions and 104 deletions

View File

@ -62,7 +62,7 @@ There is **NO CONFLICT** with MQTT, Home Assistant, Web, etc. Tests show fast re
## 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

View File

@ -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.

View File

@ -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",

View File

@ -1,8 +1,8 @@
name=TasmotaSerial
version=1.0
version=1.2.0
author=Theo Arends
maintainer=Theo Arends <theo@arends.com>
sentence=Implementation of software serial for ESP8266 at 9600 baud.
sentence=Implementation of software serial for ESP8266.
paragraph=
category=Signal Input/Output
url=

View File

@ -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;

View File

@ -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 <core_version.h> // 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;

View File

@ -1,5 +1,15 @@
/* 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 optional Arduino OTA support to be enabled in user_config.h (#1998)
* 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)
* Add support for Zengge WF017 PWM Led strip controller (#2202)
* Add PWM status to command State if PWM enabled (#2203)
* Add command HSBColor Hue,Sat,Bri (#1642, #2203)
* Add command Channel 0..100 to control dimmer value for individual color channels (#2111, #2203)
* Add Channel status information (#2211)
* Add all FriendlyNames to Status information (#2208)
* Change status display of Ssid and SetOption
* Change default option SetOption15 from 0 to 1 providing better initial PWM experience
*
* 5.12.0f
* Add compile time support for WS2812 BRG and RBG led configurations to be defined in user_config.h (#1690)

View File

@ -63,6 +63,7 @@
#define D_JSON_GATEWAY "Gateway"
#define D_JSON_HEAPSIZE "Heap"
#define D_JSON_HIGH "High"
#define D_JSON_HSBCOLOR "HSBColor"
#define D_JSON_HUMIDITY "Humidity"
#define D_JSON_I2CSCAN_DEVICES_FOUND_AT "Device(s) found at"
#define D_JSON_I2CSCAN_UNKNOWN_ERROR_AT "Unknown error at"
@ -242,13 +243,16 @@
#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"
// Commands xdrv_01_light.ino
#define D_CMND_CHANNEL "Channel"
#define D_CMND_COLOR "Color"
#define D_CMND_COLORTEMPERATURE "CT"
#define D_CMND_DIMMER "Dimmer"
#define D_CMND_HSBCOLOR "HSBColor"
#define D_CMND_LED "Led"
#define D_CMND_LEDTABLE "LedTable"
#define D_CMND_FADE "Fade"
@ -340,6 +344,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
@ -477,4 +486,4 @@ const char S_INFORMATION[] PROGMEM = D_INFORMATION;
const char S_RESTART[] PROGMEM = D_RESTART;
#endif // USE_WEBSERVER
#endif // _I18N_H_
#endif // _I18N_H_

View File

@ -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"

View File

@ -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"

View File

@ -427,6 +427,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"

View File

@ -427,6 +427,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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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 "А"

View File

@ -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 "安"

View File

@ -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 "安"

View File

@ -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

View File

@ -450,6 +450,7 @@ void SettingsDefaultSet2()
Settings.flag.mqtt_power_retain = MQTT_POWER_RETAIN;
Settings.flag.mqtt_button_retain = MQTT_BUTTON_RETAIN;
Settings.flag.mqtt_switch_retain = MQTT_SWITCH_RETAIN;
Settings.flag.pwm_control = 1;
Settings.flag.hass_discovery = HOME_ASSISTANT_DISCOVERY_ENABLE;
Settings.flag2.emulation = EMULATION;
@ -458,6 +459,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;
@ -523,14 +526,14 @@ void SettingsDefaultSet2()
// Settings.energy_max_voltage = 0;
// Settings.energy_min_current = 0;
// Settings.energy_max_current = 0;
// Settings.energy_max_power_limit = 0; // MaxPowerLimit
// Settings.energy_max_power_limit = 0; // MaxPowerLimit
Settings.energy_max_power_limit_hold = MAX_POWER_HOLD;
Settings.energy_max_power_limit_window = MAX_POWER_WINDOW;
// Settings.energy_max_power_safe_limit = 0; // MaxSafePowerLimit
// Settings.energy_max_power_safe_limit = 0; // MaxSafePowerLimit
Settings.energy_max_power_safe_limit_hold = SAFE_POWER_HOLD;
Settings.energy_max_power_safe_limit_window = SAFE_POWER_WINDOW;
// Settings.energy_max_energy = 0; // MaxEnergy
// Settings.energy_max_energy_start = 0; // MaxEnergyStart
// Settings.energy_max_energy = 0; // MaxEnergy
// Settings.energy_max_energy_start = 0; // MaxEnergyStart
SettingsDefaultSet_3_2_4();
@ -903,6 +906,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);

View File

@ -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

View File

@ -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 <core_version.h> // Arduino_Esp8266 version information (ARDUINO_ESP8266_RELEASE and ARDUINO_ESP8266_RELEASE_2_3_0)
@ -54,8 +54,14 @@
#include <ESP8266WebServer.h> // WifiManager, Webserver
#include <DNSServer.h> // WifiManager
#endif // USE_WEBSERVER
#ifdef USE_ARDUINO_OTA
#include <ArduinoOTA.h> // Arduino OTA
#ifndef USE_DISCOVERY
#define USE_DISCOVERY
#endif
#endif // USE_ARDUINO_OTA
#ifdef USE_DISCOVERY
#include <ESP8266mDNS.h> // MQTT, Webserver
#include <ESP8266mDNS.h> // MQTT, Webserver, Arduino OTA
#endif // USE_DISCOVERY
#ifdef USE_I2C
#include <Wire.h> // I2C support library
@ -76,7 +82,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 +92,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
@ -176,7 +182,6 @@ uint8_t i2c_flg = 0; // I2C configured
uint8_t spi_flg = 0; // SPI configured
uint8_t light_type = 0; // Light types
bool pwm_present = false; // Any PWM channel configured with SetOption15 0
boolean mdns_begun = false;
char my_version[33]; // Composed version string
@ -737,15 +742,9 @@ void MqttDataHandler(char* topic, byte* data, unsigned int data_len)
Settings.pwm_value[index -1] = payload;
analogWrite(pin[GPIO_PWM1 + index -1], bitRead(pwm_inverted, index -1) ? Settings.pwm_range - payload : payload);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_PWM "\":{"));
bool first = true;
for (byte i = 0; i < MAX_PWMS; i++) {
if (pin[GPIO_PWM1 + i] < 99) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_PWM "%d\":%d"), mqtt_data, first ? "" : ",", i+1, Settings.pwm_value[i]);
first = false;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}}"),mqtt_data);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{"));
MqttShowPWMState(); // Render the PWM status to MQTT
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
}
else if (CMND_PWMFREQUENCY == command_code) {
if ((1 == payload) || ((payload >= 100) && (payload <= 4000))) {
@ -821,15 +820,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;
@ -1229,6 +1248,7 @@ void ExecuteCommand(char *cmnd)
void PublishStatus(uint8_t payload)
{
uint8_t option = 1;
char stemp[MAX_FRIENDLYNAMES * (sizeof(Settings.friendlyname[0]) +4)];
// Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX
if (!strcmp(Settings.mqtt_prefix[0],Settings.mqtt_prefix[1]) && (!payload)) option++;
@ -1237,8 +1257,13 @@ void PublishStatus(uint8_t payload)
if (!energy_flg && (9 == payload)) payload = 99;
if ((0 == payload) || (99 == payload)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":\"%s\",\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
Settings.module +1, Settings.friendlyname[0], mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_power_retain);
uint8_t maxfn = (devices_present > MAX_FRIENDLYNAMES) ? MAX_FRIENDLYNAMES : devices_present;
stemp[0] = '\0';
for (byte i = 0; i < maxfn; i++) {
snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), Settings.friendlyname[i]);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" D_CMND_BUTTONTOPIC "\":\"%s\",\"" D_CMND_POWER "\":%d,\"" D_CMND_POWERONSTATE "\":%d,\"" D_CMND_LEDSTATE "\":%d,\"" D_CMND_SAVEDATA "\":%d,\"" D_JSON_SAVESTATE "\":%d,\"" D_CMND_BUTTONRETAIN "\":%d,\"" D_CMND_POWERRETAIN "\":%d}}"),
Settings.module +1, stemp, mqtt_topic, Settings.button_topic, power, Settings.poweronstate, Settings.ledstate, Settings.save_data, Settings.flag.save_state, Settings.flag.mqtt_button_retain, Settings.flag.mqtt_power_retain);
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS));
}
@ -1255,8 +1280,8 @@ void PublishStatus(uint8_t payload)
}
if ((0 == payload) || (3 == payload)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\"" D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "1\":\"%s\",\"" D_CMND_SSID "2\":\"%s\",\"" D_CMND_TELEPERIOD "\":%d,\"" D_CMND_SETOPTION "\":\"%08X\"}}"),
Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.sta_ssid[0], Settings.sta_ssid[1], Settings.tele_period, Settings.flag.data);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_STATUS D_STATUS3_LOGGING "\":{\"" D_CMND_SERIALLOG "\":%d,\"" D_CMND_WEBLOG "\":%d,\"" D_CMND_SYSLOG "\":%d,\"" D_CMND_LOGHOST "\":\"%s\",\"" D_CMND_LOGPORT "\":%d,\"" D_CMND_SSID "\":[\"%s\",\"%s\"],\"" D_CMND_TELEPERIOD "\":%d,\"" D_CMND_SETOPTION "\":[\"%08X\",\"%08X\"]}}"),
Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.sta_ssid[0], Settings.sta_ssid[1], Settings.tele_period, Settings.flag.data, Settings.flag2.data);
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "3"));
}
@ -1313,6 +1338,19 @@ void PublishStatus(uint8_t payload)
}
void MqttShowPWMState()
{
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s\"" D_CMND_PWM "\":{"), mqtt_data);
bool first = true;
for (byte i = 0; i < MAX_PWMS; i++) {
if (pin[GPIO_PWM1 + i] < 99) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"" D_CMND_PWM "%d\":%d"), mqtt_data, first ? "" : ",", i+1, Settings.pwm_value[i]);
first = false;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data);
}
void MqttShowState()
{
char stemp1[33];
@ -1331,6 +1369,11 @@ void MqttShowState()
}
}
if (pwm_present) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
MqttShowPWMState();
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_RSSI "\":%d,\"" D_JSON_APMAC_ADDRESS "\":\"%s\"}}"),
mqtt_data, Settings.sta_active +1, Settings.sta_ssid[Settings.sta_active], WifiGetRssiAsQuality(WiFi.RSSI()), WiFi.BSSIDstr().c_str());
}
@ -1871,6 +1914,86 @@ void StateLoop()
}
}
#ifdef USE_ARDUINO_OTA
/*********************************************************************************************\
* Allow updating via the Arduino OTA-protocol.
*
* - Once started disables current wifi clients and udp
* - Perform restart when done to re-init wifi clients
\*********************************************************************************************/
bool arduino_ota_triggered = false;
uint16_t arduino_ota_progress_dot_count = 0;
void ArduinoOTAInit()
{
ArduinoOTA.setPort(8266);
ArduinoOTA.setHostname(Settings.hostname);
if (Settings.web_password[0] !=0) ArduinoOTA.setPassword(Settings.web_password);
ArduinoOTA.onStart([]()
{
SettingsSave(1); // Free flash for OTA update
#ifdef USE_WEBSERVER
if (Settings.webserver) StopWebserver();
#endif // USE_WEBSERVER
#ifdef USE_ARILUX_RF
AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine
#endif // USE_ARILUX_RF
if (Settings.flag.mqtt_enabled) MqttDisconnect();
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_UPLOAD_STARTED));
AddLog(LOG_LEVEL_INFO);
arduino_ota_triggered = true;
arduino_ota_progress_dot_count = 0;
delay(100); // Allow time for message xfer
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total)
{
if ((LOG_LEVEL_DEBUG <= seriallog_level)) {
arduino_ota_progress_dot_count++;
Serial.printf(".");
if (!(arduino_ota_progress_dot_count % 80)) Serial.println();
}
});
ArduinoOTA.onError([](ota_error_t error)
{
/*
From ArduinoOTA.h:
typedef enum { OTA_AUTH_ERROR, OTA_BEGIN_ERROR, OTA_CONNECT_ERROR, OTA_RECEIVE_ERROR, OTA_END_ERROR } ota_error_t;
*/
char error_str[100];
if ((LOG_LEVEL_DEBUG <= seriallog_level) && arduino_ota_progress_dot_count) Serial.println();
switch (error) {
case OTA_BEGIN_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_2), sizeof(error_str)); break;
case OTA_RECEIVE_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_5), sizeof(error_str)); break;
case OTA_END_ERROR: strncpy_P(error_str, PSTR(D_UPLOAD_ERR_7), sizeof(error_str)); break;
default:
snprintf_P(error_str, sizeof(error_str), PSTR(D_UPLOAD_ERROR_CODE " %d"), error);
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA %s. " D_RESTARTING), error_str);
AddLog(LOG_LEVEL_INFO);
delay(100); // Allow time for message xfer
ESP.restart();
});
ArduinoOTA.onEnd([]()
{
if ((LOG_LEVEL_DEBUG <= seriallog_level)) Serial.println();
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_SUCCESSFUL ". " D_RESTARTING));
AddLog(LOG_LEVEL_INFO);
delay(100); // Allow time for message xfer
ESP.restart();
});
ArduinoOTA.begin();
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_UPLOAD "Arduino OTA " D_ENABLED " " D_PORT " 8266"));
AddLog(LOG_LEVEL_INFO);
}
#endif // USE_ARDUINO_OTA
/********************************************************************************************/
void SerialInput()
@ -1927,17 +2050,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;
}
}
}
@ -1955,24 +2087,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;
@ -1991,8 +2106,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();
}
}
@ -2289,6 +2402,11 @@ void setup()
#endif // BE_MINIMAL
RtcInit();
#ifdef USE_ARDUINO_OTA
ArduinoOTAInit();
#endif // USE_ARDUINO_OTA
XsnsCall(FUNC_INIT);
}
@ -2310,6 +2428,12 @@ void loop()
SerialInput();
#ifdef USE_ARDUINO_OTA
ArduinoOTA.handle();
// Once OTA is triggered, only handle that and dont do other stuff. (otherwise it fails)
while (arduino_ota_triggered) ArduinoOTA.handle();
#endif // USE_ARDUINO_OTA
// yield(); // yield == delay(0), delay contains yield, auto yield in loop
delay(sleep); // https://github.com/esp8266/Arduino/issues/2021
}

View File

@ -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)

View File

@ -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;
/********************************************************************************************/
@ -177,6 +180,7 @@ enum SupportedModules {
SONOFF_DUAL_R2,
ARILUX_LC06,
SONOFF_S31,
ZENGGE_ZF_WF017,
MAXMODULE };
/********************************************************************************************/
@ -231,6 +235,7 @@ const uint8_t kNiceList[MAXMODULE] PROGMEM = {
ARILUX_LC01,
ARILUX_LC06,
ARILUX_LC11,
ZENGGE_ZF_WF017,
HUAFAN_SS,
KMC_70011,
AILIGHT,
@ -786,6 +791,19 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
0, 0, 0, 0
},
{ "Zengge WF017", // Zenggee ZJ-WF017-A (ESP12S)) - https://www.ebay.com/p/Smartphone-Android-IOS-WiFi-Music-Controller-for-RGB-5050-3528-LED-Strip-Light/534446632?_trksid=p2047675.l2644
GPIO_KEY1, // GPIO00 Optional Button
0,
GPIO_USER, // GPIO02 Empty pad
0,
GPIO_USER, // GPIO04 W2 - PWM5
0,
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_PWM2, // GPIO12 RGB LED Green
GPIO_PWM1, // GPIO13 RGB LED Red
GPIO_PWM3, // GPIO14 RGB LED Blue
0, 0, 0
}
};
@ -816,20 +834,6 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
0, 0
}
{ "Zengge WF017", // Zenggee ZJ-WF017-A (ESP12S)) - https://www.ebay.com/p/Smartphone-Android-IOS-WiFi-Music-Controller-for-RGB-5050-3528-LED-Strip-Light/534446632?_trksid=p2047675.l2644
GPIO_KEY1, // GPIO00 Optional Button
0,
GPIO_USER, // GPIO02 Empty pad
0,
GPIO_USER, // GPIO04 W2 - PWM5
0,
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_PWM2, // GPIO12 RGB LED Green
GPIO_PWM1, // GPIO13 RGB LED Red
GPIO_PWM3, // GPIO14 RGB LED Blue
0, 0, 0
}
{ "SMPW701E", // SM-PW701E WLAN Socket (#1190)
0, 0, 0, 0,
GPIO_LED1_INV, // GPIO04 Blue Led (0 = On, 1 = Off)

View File

@ -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;

View File

@ -73,6 +73,7 @@
// -- Ota -----------------------------------------
#define OTA_URL "http://sonoff.maddox.co.uk/tasmota/sonoff.ino.bin" // [OtaUrl]
//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+4k5 code)
/*********************************************************************************************\
* Select ONE of possible MQTT library types below
@ -223,6 +224,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)

View File

@ -55,10 +55,12 @@
enum LightCommands {
CMND_COLOR, CMND_COLORTEMPERATURE, CMND_DIMMER, CMND_LED, CMND_LEDTABLE, CMND_FADE,
CMND_PIXELS, CMND_ROTATION, CMND_SCHEME, CMND_SPEED, CMND_WAKEUP, CMND_WAKEUPDURATION, CMND_WIDTH, CMND_UNDOCA };
CMND_PIXELS, CMND_ROTATION, CMND_SCHEME, CMND_SPEED, CMND_WAKEUP, CMND_WAKEUPDURATION,
CMND_WIDTH, CMND_CHANNEL, CMND_HSBCOLOR, CMND_UNDOCA };
const char kLightCommands[] PROGMEM =
D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_LED "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|"
D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|" D_CMND_WIDTH "|UNDOCA" ;
D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
D_CMND_WIDTH "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR "|UNDOCA" ;
struct LRgbColor {
uint8_t R, G, B;
@ -535,6 +537,8 @@ void LightState(uint8_t append)
{
char scolor[25];
char scommand[33];
float hsb[3];
int16_t h,s,b;
if (append) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data);
@ -546,6 +550,19 @@ void LightState(uint8_t append)
mqtt_data, scommand, GetStateText(light_power), Settings.light_dimmer);
if (light_subtype > LST_SINGLE) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_COLOR "\":\"%s\""), mqtt_data, LightGetColor(0, scolor));
// Add status for HSB
LightGetHsb(&hsb[0],&hsb[1],&hsb[2]);
// Scale these percentages up to the numbers expected byt he client
h = round(hsb[0] * 360);
s = round(hsb[1] * 100);
b = round(hsb[2] * 100);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_HSBCOLOR "\":\"%d,%d,%d\""), mqtt_data, h,s,b);
// Add status for each channel
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_CHANNEL "\":[" ), mqtt_data);
for (byte i = 0; i < light_subtype; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s%d" ), mqtt_data, (i > 0 ? "," : ""), round(light_current_color[i]/2.55));
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s]" ), mqtt_data);
}
if ((LST_COLDWARM == light_subtype) || (LST_RGBWC == light_subtype)) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_CMND_COLORTEMPERATURE "\":%d"), mqtt_data, LightGetColorTemp());
@ -1053,6 +1070,47 @@ boolean LightCommand()
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_SVALUE, command, XdrvMailbox.index, scolor);
}
}
else if ((CMND_CHANNEL == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= light_subtype ) ) {
// Set "Channel" directly - this allows Color and Direct PWM control to coexist
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
uint8_t level = XdrvMailbox.payload;
light_current_color[XdrvMailbox.index-1] = round(level * 2.55);
LightSetColor();
coldim = true;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, round(light_current_color[XdrvMailbox.index -1] / 2.55));
}
else if ((CMND_HSBCOLOR == command_code) && ( light_subtype >= LST_RGB)) {
// Implement method to "direct set" color by HSB (HSB is passed comma separated, 0<H<360 0<S<100 0<B<100 )
uint16_t HSB[3];
bool validHSB = true;
for (int i = 0; i < 3; i++) {
char *substr;
if (0 == i) {
substr = strtok(XdrvMailbox.data, ",");
} else {
substr = strtok(NULL, ",");
}
if (substr != NULL) {
HSB[i] = atoi(substr);
} else {
validHSB = false;
}
}
if (validHSB) {
// Translate to fractional elements as required by LightHsbToRgb
// Keep the results <=1 in the event someone passes something
// out of range.
LightSetHsb(( (HSB[0]>360) ? (HSB[0] % 360) : HSB[0] ) /360.0,
( (HSB[1]>100) ? (HSB[1] % 100) : HSB[1] ) /100.0,
( (HSB[2]>100) ? (HSB[2] % 100) : HSB[2] ) /100.0,
0);
} else {
LightState(0);
}
}
#ifdef USE_WS2812 // ***********************************************************************
else if ((CMND_LED == command_code) && (LT_WS2812 == light_type) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= Settings.light_pixels)) {
if (XdrvMailbox.data_len > 0) {

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifdef USE_SERIAL_BRIDGE
/*********************************************************************************************\
* Serial Bridge using Software Serial library (TasmotaSerial)
\*********************************************************************************************/
#define SERIAL_BRIDGE_BUFFER_SIZE 130
#include <TasmotaSerial.h>
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