5.5.0 20170730
* Reduce code space by removing the following commands as they are
replaced by SetOption alternatives:
*   SaveState = SetOption0
*   ButtonRestrict = SetOption1
*   Units = SetOption2
*   MQTT = SetOption3
*   MQTTResponse = SetOption4
*   TempUnit = SetOption8
* Smoothing WS2812 animation poll, invert fade speed and max allowed
wakeup time down to 3000 seconds
* Fix initial button press detection
* Add support for Sonoff RF Bridge 433 using command RfKey
* Fix regression from 5.0.7 by increasing message buffer size from 360
to 368 to accomodate 4 x DS18x20 sensors (#637)
* Add GroupTopic to Topic test when using ButtonTopic/SwitchTopic to
send either ON/OFF or TOGGLE (#642)
* Adjust HLW calibration limits to accomodate HuaFan device and add
commands HlwPSet, HlwUSet and HlwISet (#654)
This commit is contained in:
arendst 2017-07-30 17:55:37 +02:00
parent 22ef93a2c4
commit 0a9ec10b0a
13 changed files with 351 additions and 166 deletions

View File

@ -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.4.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
Current version is **5.5.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
### **** ATTENTION Version 5.x.x specific information ****
@ -41,17 +41,15 @@ The following devices are supported:
- [iTead Sonoff SC](http://sonoff.itead.cc/en/products/residential/sonoff-sc)
- [iTead Sonoff Led](http://sonoff.itead.cc/en/products/appliances/sonoff-led)
- [iTead Sonoff BN-SZ01 Ceiling Led](http://sonoff.itead.cc/en/products/appliances/bn-sz01)
- [iTead Sonoff RF Bridge 433](http://sonoff.itead.cc/en/products/appliances/sonoff-rf-bridge-433)
- [iTead Sonoff Dev](https://www.itead.cc/sonoff-dev.html)
- [iTead 1 Channel Switch 5V / 12V](https://www.itead.cc/smart-home/inching-self-locking-wifi-wireless-switch.html)
- [iTead Motor Clockwise/Anticlockwise](https://www.itead.cc/smart-home/motor-reversing-wifi-wireless-switch.html)
- [Electrodragon IoT Relay Board](http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/)
Planned support:
- [iTead Sonoff T1](https://www.itead.cc/smart-home/sonoff-t1.html)
- [iTead Sonoff B1](https://www.itead.cc/smart-home/sonoff-b1.html)
Optional future support:
- iTead RF Bridge
- [iTead Sonoff T1](http://sonoff.itead.cc/en/products/residential/sonoff-t1)
- [iTead Sonoff B1](http://sonoff.itead.cc/en/products/residential/sonoff-b1)
<img src="https://github.com/arendst/arendst.github.io/blob/master/media/sonofftoucheu.jpg" height="280" align="left" />
<img src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoff4ch.jpg" height="250" align="right" />

View File

@ -1,4 +1,19 @@
/* 5.4.0 20170725
/* 5.5.0 20170730
* Reduce code space by removing the following commands as they are replaced by SetOption alternatives:
* SaveState = SetOption0
* ButtonRestrict = SetOption1
* Units = SetOption2
* MQTT = SetOption3
* MQTTResponse = SetOption4
* TempUnit = SetOption8
* Smoothing WS2812 animation poll, invert fade speed and max allowed wakeup time down to 3000 seconds
* Fix initial button press detection
* Add support for Sonoff RF Bridge 433 using command RfKey
* Fix regression from 5.0.7 by increasing message buffer size from 360 to 368 to accomodate 4 x DS18x20 sensors (#637)
* Add GroupTopic to Topic test when using ButtonTopic/SwitchTopic to send either ON/OFF or TOGGLE (#642)
* Adjust HLW calibration limits to accomodate HuaFan device and add commands HlwPSet, HlwUSet and HlwISet (#654)
*
* 5.4.0 20170725
* Fix command reset regression introduced in 5.2.0
* Increase polling from 0.1 second to 0.05 second
* Add multipress to all buttons

View File

@ -203,6 +203,9 @@ struct SYSCFG {
uint16_t pCounterType;
uint16_t pCounterDebounce;
// 5.4.1
uint8_t sfb_code[17][9];
} sysCfg;
struct RTCMEM {

View File

@ -17,6 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const uint8_t sfb_codeDefault[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
/*********************************************************************************************\
* RTC memory
\*********************************************************************************************/
@ -269,30 +271,7 @@ void CFG_Load()
}
snprintf_P(log, sizeof(log), PSTR("Cnfg: Load from flash at %X and count %d"), _cfgLocation, sysCfg.saveFlag);
addLog(LOG_LEVEL_DEBUG, log);
/*
if (sysCfg.cfg_holder != CFG_HOLDER) {
CFG_Default();
}
*/
if (sysCfg.cfg_holder != CFG_HOLDER) {
/*
// Auto upgrade
if ((sysCfg.version < 0x04020000) || (sysCfg.version > VERSION)) {
noInterrupts();
spi_flash_read((CFG_LOCATION_3) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG));
spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH));
if (sysCfg.saveFlag < _sysCfgH.saveFlag)
spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG));
interrupts();
if (sysCfg.cfg_holder != CFG_HOLDER) {
CFG_Default();
} else {
sysCfg.saveFlag = 0;
}
} else {
CFG_Default();
}
*/
// Auto upgrade
noInterrupts();
spi_flash_read((CFG_LOCATION_3) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG));
@ -339,7 +318,7 @@ void CFG_Erase()
}
}
void CFG_Dump(uint16_t srow, uint16_t mrow)
void CFG_Dump(char* parms)
{
#define CFG_COLS 16
@ -348,18 +327,25 @@ void CFG_Dump(uint16_t srow, uint16_t mrow)
uint16_t maxrow;
uint16_t row;
uint16_t col;
char *p;
uint8_t *buffer = (uint8_t *) &sysCfg;
row = 0;
maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS);
if ((srow > 0) && (srow < maxrow)) {
row = srow;
uint16_t srow = strtol(parms, &p, 16) / CFG_COLS;
uint16_t mrow = strtol(p, &p, 10);
// snprintf_P(log, sizeof(log), PSTR("Cnfg: Parms %s, Start row %d, rows %d"), parms, srow, mrow);
// addLog(LOG_LEVEL_DEBUG, log);
if (0 == mrow) { // Default only 8 lines
mrow = 8;
}
if (0 == mrow) { // Default only four lines
mrow = 4;
if (srow > maxrow) {
srow = maxrow - mrow;
}
if ((mrow > 0) && (mrow < (maxrow - row))) {
maxrow = row + mrow;
if (mrow < (maxrow - srow)) {
maxrow = srow + mrow;
}
for (row = srow; row < maxrow; row++) {
@ -525,6 +511,9 @@ void CFG_DefaultSet2()
// 5.2.0
sysCfg.param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY;
// 5.4.1
memcpy_P(sysCfg.sfb_code[0], sfb_codeDefault, 9);
}
/********************************************************************************************/
@ -727,6 +716,12 @@ void CFG_Delta()
if (sysCfg.version < 0x05020000) {
sysCfg.param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY;
}
if (sysCfg.version < 0x05050000) {
for (byte i = 0; i < 17; i++) {
sysCfg.sfb_code[i][0] = 0;
}
memcpy_P(sysCfg.sfb_code[0], sfb_codeDefault, 9);
}
sysCfg.version = VERSION;
CFG_Save(1);

View File

@ -25,7 +25,7 @@
- Select IDE Tools - Flash Size: "1M (no SPIFFS)"
====================================================*/
#define VERSION 0x05040000 // 5.4.0
#define VERSION 0x05050000 // 5.5.0
enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL};
enum week_t {Last, First, Second, Third, Fourth};
@ -159,7 +159,7 @@ enum opt_t {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8}; // Index in sysCf
#include <PubSubClient.h> // MQTT
#ifndef MESSZ
#define MESSZ 360 // Max number of characters in JSON message string (4 x DS18x20 sensors)
#define MESSZ 368 // Max number of characters in JSON message string (4 x DS18x20 sensors)
#endif
#if (MQTT_MAX_PACKET_SIZE -TOPSZ -7) < MESSZ // If the max message size is too small, throw an error at compile time
// See pubsubclient.c line 359
@ -1111,47 +1111,6 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SetOption%d\":\"%s\"}"), (ptype) ? index +32 : index, (ptype) ? stemp1 : getStateText(bitRead(sysCfg.flag.data, index)));
}
// To be removed in near future
else if (!strcmp_P(type,PSTR("SAVESTATE"))) {
if ((payload >= 0) && (payload <= 1)) {
sysCfg.flag.savestate = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveState\":\"%s\"}"), getStateText(sysCfg.flag.savestate));
}
else if (!strcmp_P(type,PSTR("BUTTONRESTRICT"))) {
if ((payload >= 0) && (payload <= 1)) {
sysCfg.flag.button_restrict = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"ButtonRestrict\":\"%s\"}"), getStateText(sysCfg.flag.button_restrict));
}
else if (!strcmp_P(type,PSTR("UNITS"))) {
if ((payload >= 0) && (payload <= 1)) {
sysCfg.flag.value_units = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Units\":\"%s\"}"), getStateText(sysCfg.flag.value_units));
}
else if (!strcmp_P(type,PSTR("TEMPUNIT"))) {
if ((payload >= 0) && (payload <= 1)) {
sysCfg.flag.temperature_conversion = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"TempUnit\":\"%s\"}"), (sysCfg.flag.temperature_conversion) ? "Fahrenheit" : "Celsius");
}
else if (!strcmp_P(type,PSTR("MQTT"))) {
if ((payload >= 0) && (payload <= 1)) {
sysCfg.flag.mqtt_enabled = payload;
restartflag = 2;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Mqtt\":\"%s\"}"), getStateText(sysCfg.flag.mqtt_enabled));
}
else if (!strcmp_P(type,PSTR("MQTTRESPONSE"))) {
if ((payload >= 0) && (payload <= 1)) {
sysCfg.flag.mqtt_response = payload;
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"MqttResponse\":\"%s\"}"), getStateText(sysCfg.flag.mqtt_response));
}
// Until here
else if (!strcmp_P(type,PSTR("TEMPRES"))) {
if ((payload >= 0) && (payload <= 3)) {
sysCfg.flag.temperature_resolution = payload;
@ -1567,23 +1526,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
snprintf_P(svalue, sizeof(svalue), PSTR("{\"LedState\":%d}"), sysCfg.ledstate);
}
else if (!strcmp_P(type,PSTR("CFGDUMP"))) {
uint16_t srow = 0;
uint16_t mrow = 0;
if (data_len > 0) {
srow = payload16;
byte i = 0;
while (isdigit(dataBuf[i])) {
i++;
}
if (i < strlen(dataBuf)) {
mrow = atoi(dataBuf +i);
}
if (0 == mrow) {
mrow = payload16;
srow = 0;
}
}
CFG_Dump(srow, mrow);
CFG_Dump(dataBuf);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"CfgDump\":\"Done\"}"));
}
else if (sysCfg.flag.mqtt_enabled && mqtt_command(grpflg, type, index, dataBuf, data_len, payload, svalue, sizeof(svalue))) {
@ -1592,6 +1535,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
else if (hlw_flg && hlw_command(type, index, dataBuf, data_len, payload, svalue, sizeof(svalue))) {
// Serviced
}
else if ((SONOFF_BRIDGE == sysCfg.module) && sb_command(type, index, dataBuf, data_len, payload, svalue, sizeof(svalue))) {
// Serviced
}
#ifdef USE_I2C
else if (i2c_flg && !strcmp_P(type,PSTR("I2CSCAN"))) {
i2c_scan(svalue, sizeof(svalue));
@ -1661,7 +1607,7 @@ boolean send_button_power(byte key, byte device, byte state)
if (9 == state) {
svalue[0] = '\0';
} else {
if (!strcmp(sysCfg.mqtt_topic, key_topic) && (2 == state)) {
if ((!strcmp(sysCfg.mqtt_topic, key_topic) || !strcmp(sysCfg.mqtt_grptopic, key_topic)) && (2 == state)) {
state = ~(power >> (device -1)) & 0x01;
}
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), getStateText(state));
@ -1816,8 +1762,8 @@ void publish_status(uint8_t payload)
}
if ((0 == payload) || (3 == payload)) {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusLOG\":{\"Seriallog\":%d, \"Weblog\":%d, \"Syslog\":%d, \"LogHost\":\"%s\", \"SSId1\":\"%s\", \"SSId2\":\"%s\", \"TelePeriod\":%d}}"),
sysCfg.seriallog_level, sysCfg.weblog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid[0], sysCfg.sta_ssid[1], sysCfg.tele_period);
snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusLOG\":{\"Seriallog\":%d, \"Weblog\":%d, \"Syslog\":%d, \"LogHost\":\"%s\", \"SSId1\":\"%s\", \"SSId2\":\"%s\", \"TelePeriod\":%d, \"Option\":\"%X\"}}"),
sysCfg.seriallog_level, sysCfg.weblog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid[0], sysCfg.sta_ssid[1], sysCfg.tele_period, sysCfg.flag.data);
mqtt_publish_topic_P(option, PSTR("STATUS3"), svalue);
}
@ -2083,6 +2029,7 @@ void button_handler()
char log[LOGSZ];
for (byte i = 0; i < Maxdevice; i++) {
button = NOT_PRESSED;
butt_present = 0;
if (!i && ((SONOFF_DUAL == sysCfg.module) || (CH4 == sysCfg.module))) {
@ -2095,8 +2042,6 @@ void button_handler()
holdbutton[i] = (sysCfg.param[P_HOLD_TIME] * (STATES / 10)) -1;
}
ButtonCode = 0;
} else {
button = NOT_PRESSED;
}
} else {
if ((pin[GPIO_KEY1 +i] < 99) && !blockgpio0) {
@ -2203,8 +2148,8 @@ void button_handler()
}
}
}
lastbutton[i] = button;
}
lastbutton[i] = button;
}
}
@ -2308,7 +2253,6 @@ void stateloop()
* Every 0.1 second
\*-------------------------------------------------------------------------------------------*/
// if (0 == (state & 1)) {
if (!(state % (STATES/10))) {
if (mqtt_cmnd_publish) {
@ -2346,16 +2290,6 @@ void stateloop()
}
}
if (sfl_flg) { // Sonoff BN-SZ01 or Sonoff Led
sl_animate();
}
#ifdef USE_WS2812
if (pin[GPIO_WS2812] < 99) {
ws2812_animate();
}
#endif // USE_WS2812
// Backlog
if (blogdelay) {
blogdelay--;
@ -2381,6 +2315,16 @@ void stateloop()
button_handler();
switch_handler();
if (sfl_flg) { // Sonoff BN-SZ01 or Sonoff Led
sl_animate();
}
#ifdef USE_WS2812
if (pin[GPIO_WS2812] < 99) {
ws2812_animate();
}
#endif // USE_WS2812
/*-------------------------------------------------------------------------------------------*\
* Every 0.2 second
\*-------------------------------------------------------------------------------------------*/
@ -2533,7 +2477,10 @@ void serial()
yield();
SerialInByte = Serial.read();
// Sonoff dual 19200 baud serial interface
/*-------------------------------------------------------------------------------------------*\
* Sonoff dual 19200 baud serial interface
\*-------------------------------------------------------------------------------------------*/
if (Hexcode) {
Hexcode--;
if (Hexcode) {
@ -2541,17 +2488,29 @@ void serial()
SerialInByte = 0;
} else {
if (SerialInByte != 0xA1) {
ButtonCode = 0; // 0xA1 - End of Sonoff dual button code
ButtonCode = 0; // 0xA1 - End of Sonoff dual button code
}
}
}
if (0xA0 == SerialInByte) { // 0xA0 - Start of Sonoff dual button code
if (0xA0 == SerialInByte) { // 0xA0 - Start of Sonoff dual button code
SerialInByte = 0;
ButtonCode = 0;
Hexcode = 3;
}
if (SerialInByte > 127) { // binary data...
/*-------------------------------------------------------------------------------------------*\
* Sonoff bridge 19200 baud serial interface
\*-------------------------------------------------------------------------------------------*/
if (sb_serial()) {
SerialInByteCounter = 0;
Serial.flush();
return;
}
/*-------------------------------------------------------------------------------------------*/
if (SerialInByte > 127) { // binary data...
SerialInByteCounter = 0;
Serial.flush();
return;
@ -2564,7 +2523,7 @@ void serial()
}
}
if (SerialInByte == '\x1B') { // Sonoff SC status from ATMEGA328P
if (SerialInByte == '\x1B') { // Sonoff SC status from ATMEGA328P
serialInBuf[SerialInByteCounter] = 0; // serial data completed
sc_rcvstat(serialInBuf);
SerialInByteCounter = 0;
@ -2650,6 +2609,9 @@ void GPIO_init()
analogWriteFreq(PWM_FREQ); // Default is 1000 (core_esp8266_wiring_pwm.c)
Maxdevice = 1;
if (SONOFF_BRIDGE == sysCfg.module) {
Baudrate = 19200;
}
if (SONOFF_DUAL == sysCfg.module) {
Maxdevice = 2;
Baudrate = 19200;
@ -2675,12 +2637,15 @@ void GPIO_init()
pinMode(pin[GPIO_REL1 +i], OUTPUT);
Maxdevice++;
}
if (pin[GPIO_KEY1 +i] < 99) {
pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP);
}
// if (pin[GPIO_KEY1 +i] < 99) {
// pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP);
// }
}
}
for (byte i = 0; i < 4; i++) {
if (pin[GPIO_KEY1 +i] < 99) {
pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP);
}
if (pin[GPIO_LED1 +i] < 99) {
pinMode(pin[GPIO_LED1 +i], OUTPUT);
digitalWrite(pin[GPIO_LED1 +i], led_inverted[i]);

View File

@ -148,6 +148,7 @@ enum module_t {
SONOFF_BN,
SONOFF_4CHPRO,
HUAFAN_SS,
SONOFF_BRIDGE,
MAXMODULE };
/********************************************************************************************/
@ -475,6 +476,19 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
GPIO_HLW_SEL, // GPIO13 HLW8012 Sel output
GPIO_HLW_CF, // GPIO14 HLW8012 CF power
0, 0, 0
},
{ "Sonoff Bridge", // Sonoff RF Bridge 433 (ESP8285)
GPIO_KEY1, // GPIO00 Button
GPIO_TXD, // GPIO01 RF bridge control
GPIO_USER, // GPIO02 Optional sensor
GPIO_RXD, // GPIO03 RF bridge control
0, 0,
0, 0, 0, // Flash connection
0, 0,
0, // Flash connection
0,
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
0, 0, 0, 0
}
};

View File

@ -31,7 +31,7 @@
#define CFG_HOLDER 0x20161209 // [Reset 1] Change this value to load following default configuration parameters
#define SAVE_DATA 1 // [SaveData] Save changed parameters to Flash (0 = disable, 1 - 3600 seconds)
#define SAVE_STATE 1 // [SaveState] Save changed power state to Flash (0 = disable, 1 = enable)
#define SAVE_STATE 1 // [SetOption0] Save changed power state to Flash (0 = disable, 1 = enable)
// -- Wifi ----------------------------------------
#define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress1] Set to 0.0.0.0 for using DHCP or IP address
@ -57,7 +57,7 @@
#define OTA_URL "http://domus1:80/api/arduino/" PROJECT ".ino.bin" // [OtaUrl]
// -- MQTT ----------------------------------------
#define MQTT_USE 1 // [Mqtt] Select default MQTT use (0 = Off, 1 = On)
#define MQTT_USE 1 // [SetOption3] Select default MQTT use (0 = Off, 1 = On)
// !!! TLS uses a LOT OF MEMORY (20k) so be careful to enable other options at the same time !!!
//#define USE_MQTT_TLS // EXPERIMENTAL Use TLS for MQTT connection (+53k code, +20k mem) - Disable by //
// Needs Fingerprint, TLS Port, UserId and Password
@ -145,7 +145,7 @@
#define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD or PUSHBUTTONHOLD_INV (the wall switch state)
#define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with
#define TEMP_CONVERSION 0 // [TempUnit] Return temperature in (0 = Celsius or 1 = Fahrenheit)
#define TEMP_CONVERSION 0 // [SetOption8] Return temperature in (0 = Celsius or 1 = Fahrenheit)
#define TEMP_RESOLUTION 1 // [TempRes] Maximum number of decimals (0 - 3) showing sensor Temperature
#define HUMIDITY_RESOLUTION 1 // [HumRes] Maximum number of decimals (0 - 3) showing sensor Humidity
#define PRESSURE_RESOLUTION 1 // [PressRes] Maximum number of decimals (0 - 3) showing sensor Pressure

View File

@ -437,6 +437,23 @@ void handleRoot()
}
page += F("</tr></table>");
}
if (SONOFF_BRIDGE == sysCfg.module) {
page += FPSTR(HTTP_TABLE100);
page += F("<tr>");
byte idx = 0;
for (byte i = 0; i < 4; i++) {
if (idx > 0) {
page += F("</tr><tr>");
}
for (byte j = 0; j < 4; j++) {
idx++;
snprintf_P(line, sizeof(line), PSTR("<td style='width:25%'><button onclick='la(\"?k=%d\");'>%d</button></td>"),
idx, idx);
page += line;
}
}
page += F("</tr></table>");
}
if (HTTP_ADMIN == _httpflag) {
page += FPSTR(HTTP_BTN_MENU1);
@ -457,6 +474,10 @@ void handleAjax2()
snprintf_P(svalue, sizeof(svalue), PSTR("dimmer %s"), webServer->arg("d").c_str());
do_cmnd(svalue);
}
if (strlen(webServer->arg("k").c_str())) {
snprintf_P(svalue, sizeof(svalue), PSTR("rfkey%s"), webServer->arg("k").c_str());
do_cmnd(svalue);
}
String tpage = "";
tpage += counter_webPresent();

160
sonoff/xdrv_snfbridge.ino Normal file
View File

@ -0,0 +1,160 @@
/*
xdrv_snfbridge.ino - sonoff RF bridge 433 support for Sonoff-Tasmota
Copyright (C) 2017 Theo Arends
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/>.
*/
/*********************************************************************************************\
Sonoff RF Bridge 433
\*********************************************************************************************/
uint8_t sfb_rcvflg = 0; // Sonoff RF Bridge communication
uint8_t sfb_learnKey = 1;
uint8_t sfb_learnFlg = 0;
void sb_received()
{
char svalue[60];
char log[LOGSZ];
svalue[0] = '\0';
for (byte i = 0; i < SerialInByteCounter; i++) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%02X "), svalue, serialInBuf[i]);
}
snprintf_P(log, sizeof(log), PSTR("BRDG: Received %s"), svalue);
addLog(LOG_LEVEL_DEBUG, log);
if (0xA2 == serialInBuf[0]) { // Learn failed
sfb_learnFlg = 0;
snprintf_P(svalue, sizeof(svalue), PSTR("{\"RfKey%d\":\"Learn failed\"}"), sfb_learnKey);
mqtt_publish_topic_P(5, PSTR("RFKEY"), svalue);
}
if (0xA3 == serialInBuf[0]) { // Learn
sfb_learnFlg = 0;
for (uint8_t i = 0; i < 9; i++) {
sysCfg.sfb_code[sfb_learnKey][i] = serialInBuf[i +1];
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"RfKey%d\":\"Learned\"}"), sfb_learnKey);
mqtt_publish_topic_P(5, PSTR("RFKEY"), svalue);
}
}
boolean sb_serial()
{
if (sfb_rcvflg) {
if (SerialInByte > 0) {
serialInBuf[SerialInByteCounter++] = SerialInByte;
if (0x55 == SerialInByte) {
// serialInBuf[SerialInByteCounter] = 0x55;
sb_received();
sfb_rcvflg = 0; // 0x55 - End of text
return 1;
}
}
SerialInByte = 0;
}
if (0xAA == SerialInByte) { // 0xAA - Start of text
SerialInByteCounter = 0;
SerialInByte = 0;
sfb_rcvflg = 1;
}
return 0;
}
void sb_sendAck()
{
Serial.write(0xAA); // Start of Text
Serial.write(0xA0); // Acknowledge
Serial.write(0x55); // End of Text
}
void sb_send(uint8_t idx, uint8_t key)
{
uint8_t code;
key--; // Support 1 to 16
Serial.write(0xAA); // Start of Text
Serial.write(0xA5); // Send following code
for (uint8_t i = 0; i < 8; i++) {
Serial.write(sysCfg.sfb_code[idx][i]);
}
if (0 == idx) {
code = (0x10 << (key >> 2)) | (0x01 << (key & 3)); // 11,12,14,18,21,22,24,28,41,42,44,48,81,82,84,88
} else {
code = sysCfg.sfb_code[idx][8];
}
Serial.write(code);
Serial.write(0x55); // End of Text
Serial.flush();
}
void sb_learn(uint8_t key)
{
sfb_learnKey = key;
sfb_learnFlg = 1;
Serial.write(0xAA); // Start of Text
Serial.write(0xA1); // Start learning
Serial.write(0x55); // End of Text
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
boolean sb_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
{
boolean serviced = true;
char *p;
if (!strcmp_P(type, PSTR("RFDEFAULT"))) {
if (4 == data_len) {
uint16_t hexcode = strtol(dataBuf, &p, 16);
uint8_t msb = hexcode >> 8;
uint8_t lsb = hexcode & 0xFF;
if ((hexcode > 0) && (hexcode < 0x7FFF) && (msb != 0x55) && (lsb != 0x55)) {
sysCfg.sfb_code[0][6] = msb;
sysCfg.sfb_code[0][7] = lsb;
}
}
snprintf_P(svalue, ssvalue, PSTR("{\"RfDefault\":\"%0X%0X\"}"), sysCfg.sfb_code[0][6], sysCfg.sfb_code[0][7]);
}
else if (!strcmp_P(type, PSTR("RFKEY")) && (index > 0) && (index <= 16)) {
if (!sfb_learnFlg) {
if (2 == payload) {
sb_learn(index);
snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Start learning\"}"), index);
}
else if (3 == payload) {
sysCfg.sfb_code[index][0] = 0;
snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Set to default\"}"), index);
} else {
if ((1 == payload) || (0 == sysCfg.sfb_code[index][0])) {
sb_send(0, index);
snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Default sent\"}"), index);
} else {
sb_send(index, 0);
snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Learned sent\"}"), index);
}
}
} else {
snprintf_P(svalue, ssvalue, PSTR("{\"RfKey%d\":\"Learning active\"}"), sfb_learnKey);
}
}
else {
serviced = false; // Unknown command
}
return serviced;
}

View File

@ -290,7 +290,7 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le
snprintf_P(svalue, ssvalue, PSTR("{\"Speed\":%d}"), sysCfg.led_speed);
}
else if (!strcmp_P(type,PSTR("WAKEUPDURATION"))) {
if ((payload > 0) && (payload < 3601)) {
if ((payload > 0) && (payload < 3001)) {
sysCfg.led_wakeup = payload;
sl_wakeupActive = 0;
}

View File

@ -1,7 +1,7 @@
/*
xdrv_snfsc.ino - sonoff SC support for Sonoff-Tasmota
Copyright (C) 2017 Heiko Krupp and Theo Arends
Copyright (C) 2017 Theo Arends
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

View File

@ -76,31 +76,13 @@ uint8_t repeatValues[5] = {
2, // Largest
1 }; // All
uint8_t speedValues[6] = {
0, // None
18, // Slowest
14, // Slower
10, // Slow
6, // Fast
2 }; // Fastest
/*
uint8_t ledTable[] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4,
4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8,
8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14,
14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22,
22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32,
33, 33, 34, 35, 36, 36, 37, 38, 39, 40, 40, 41, 42, 43, 44, 45,
46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78,
80, 81, 82, 83, 85, 86, 87, 89, 90, 91, 93, 94, 95, 97, 98, 99,
101,102,104,105,107,108,110,111,113,114,116,117,119,121,122,124,
125,127,129,130,132,134,135,137,139,141,142,144,146,148,150,151,
153,155,157,159,161,163,165,166,168,170,172,174,176,178,180,182,
184,186,189,191,193,195,197,199,201,204,206,208,210,212,215,217,
219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 };
*/
0, // None
9 * (STATES / 10), // Slowest
7 * (STATES / 10), // Slower
5 * (STATES / 10), // Slow
3 * (STATES / 10), // Fast
1 * (STATES / 10) }; // Fastest
uint8_t lany = 0;
RgbColor dcolor;
RgbColor tcolor;
@ -409,23 +391,24 @@ void ws2812_animate()
tcolor = dcolor;
} else {
if (tcolor != dcolor) {
uint8_t ws_speed = speedValues[sysCfg.ws_speed];
if (tcolor.R < dcolor.R) {
tcolor.R += ((dcolor.R - tcolor.R) >> sysCfg.ws_speed) +1;
tcolor.R += ((dcolor.R - tcolor.R) / ws_speed) +1;
}
if (tcolor.G < dcolor.G) {
tcolor.G += ((dcolor.G - tcolor.G) >> sysCfg.ws_speed) +1;
tcolor.G += ((dcolor.G - tcolor.G) / ws_speed) +1;
}
if (tcolor.B < dcolor.B) {
tcolor.B += ((dcolor.B - tcolor.B) >> sysCfg.ws_speed) +1;
tcolor.B += ((dcolor.B - tcolor.B) / ws_speed) +1;
}
if (tcolor.R > dcolor.R) {
tcolor.R -= ((tcolor.R - dcolor.R) >> sysCfg.ws_speed) +1;
tcolor.R -= ((tcolor.R - dcolor.R) / ws_speed) +1;
}
if (tcolor.G > dcolor.G) {
tcolor.G -= ((tcolor.G - dcolor.G) >> sysCfg.ws_speed) +1;
tcolor.G -= ((tcolor.G - dcolor.G) / ws_speed) +1;
}
if (tcolor.B > dcolor.B) {
tcolor.B -= ((tcolor.B - dcolor.B) >> sysCfg.ws_speed) +1;
tcolor.B -= ((tcolor.B - dcolor.B) / ws_speed) +1;
}
}
}
@ -443,8 +426,9 @@ void ws2812_animate()
if (wakeupDimmer <= sysCfg.ws_dimmer) {
ws2812_setDim(wakeupDimmer);
tcolor = dcolor;
} else
} else {
sysCfg.ws_scheme = 0;
}
}
}
break;
@ -599,7 +583,7 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_
snprintf_P(svalue, ssvalue, PSTR("{\"Width\":%d}"), sysCfg.ws_width);
}
else if (!strcmp_P(type,PSTR("WAKEUP"))) {
if ((payload > 0) && (payload < 3601)) {
if ((payload > 0) && (payload < 3001)) {
sysCfg.ws_wakeup = payload;
if (1 == sysCfg.ws_scheme) {
sysCfg.ws_scheme = 0;

View File

@ -437,6 +437,7 @@ void hlw_margin_chk()
boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue)
{
boolean serviced = true;
uint8_t caltext = 0;
if (!strcmp_P(type,PSTR("POWERLOW"))) {
if ((payload >= 0) && (payload < 3601)) {
@ -501,21 +502,39 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len
}
else if (!strcmp_P(type,PSTR("HLWPCAL"))) {
if ((payload > 0) && (payload < 32001)) {
sysCfg.hlw_pcal = (payload > 9999) ? payload : HLW_PREF_PULSE; // 12530
sysCfg.hlw_pcal = (payload > 4000) ? payload : HLW_PREF_PULSE; // 12530
}
snprintf_P(svalue, ssvalue, PSTR("(\"HlwPcal\":\"%d%s\"}"), sysCfg.hlw_pcal, (sysCfg.flag.value_units) ? " uS" : "");
caltext = 1;
}
else if (!strcmp_P(type,PSTR("HLWPSET"))) {
if ((payload > 0) && (payload < 3601) && hlw_cf_plen) {
sysCfg.hlw_pcal = (payload * 10 * hlw_cf_plen) / HLW_PREF;
}
caltext = 1;
}
else if (!strcmp_P(type,PSTR("HLWUCAL"))) {
if ((payload > 0) && (payload < 32001)) {
sysCfg.hlw_ucal = (payload > 999) ? payload : HLW_UREF_PULSE; // 1950
}
snprintf_P(svalue, ssvalue, PSTR("{\"HlwUcal\":\"%d%s\"}"), sysCfg.hlw_ucal, (sysCfg.flag.value_units) ? " uS" : "");
caltext = 2;
}
else if (!strcmp_P(type,PSTR("HLWUSET"))) {
if ((payload > 0) && (payload < 501) && hlw_cf1u_plen) {
sysCfg.hlw_ucal = (payload * 10 * hlw_cf1u_plen) / HLW_UREF;
}
caltext = 2;
}
else if (!strcmp_P(type,PSTR("HLWICAL"))) {
if ((payload > 0) && (payload < 32001)) {
sysCfg.hlw_ical = (payload > 2499) ? payload : HLW_IREF_PULSE; // 3500
sysCfg.hlw_ical = (payload > 1100) ? payload : HLW_IREF_PULSE; // 3500
}
snprintf_P(svalue, ssvalue, PSTR("{\"HlwIcal\":\"%d%s\"}"), sysCfg.hlw_ical, (sysCfg.flag.value_units) ? " uS" : "");
caltext = 3;
}
else if (!strcmp_P(type,PSTR("HLWISET"))) {
if ((payload > 0) && (payload < 16001) && hlw_cf1i_plen) {
sysCfg.hlw_ical = (payload * hlw_cf1i_plen) / HLW_IREF;
}
caltext = 3;
}
#if FEATURE_POWER_LIMIT
else if (!strcmp_P(type,PSTR("MAXPOWER"))) {
@ -571,6 +590,17 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len
else {
serviced = false;
}
switch (caltext) {
case 1:
snprintf_P(svalue, ssvalue, PSTR("(\"HlwPcal\":\"%d%s\"}"), sysCfg.hlw_pcal, (sysCfg.flag.value_units) ? " uS" : "");
break;
case 2:
snprintf_P(svalue, ssvalue, PSTR("{\"HlwUcal\":\"%d%s\"}"), sysCfg.hlw_ucal, (sysCfg.flag.value_units) ? " uS" : "");
break;
case 3:
snprintf_P(svalue, ssvalue, PSTR("(\"HlwIcal\":\"%d%s\"}"), sysCfg.hlw_ical, (sysCfg.flag.value_units) ? " uS" : "");
break;
}
return serviced;
}