4.1.3 20170410
* Add user configuarble GPIO to module S20 Socket and Slampher
* Add support for Sonoff SC (#112)
* Set PWM frequency from 1000Hz to 910Hz as used on iTead Sonoff Led
firmware (#122)
* Set Sonoff Led unconfigured floating outputs to 0 to reduce exceptions
due to power supply instabilities (#122)
* Add Access Point Mac Address to Status 11 and Telemetry (#329)
* Fix DS18B20 negative temperature readings (#334)
This commit is contained in:
arendst 2017-04-10 17:25:31 +02:00
parent d32cb04b1a
commit 824368125b
9 changed files with 236 additions and 14 deletions

View File

@ -1,7 +1,7 @@
## Sonoff-Tasmota ## 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. 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 **4.1.2** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. Current version is **4.1.3** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
- This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic.
- Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.
@ -23,6 +23,7 @@ The following devices are supported:
- [iTead S20 Smart Socket](http://sonoff.itead.cc/en/products/residential/s20-socket) - [iTead S20 Smart Socket](http://sonoff.itead.cc/en/products/residential/s20-socket)
- [iTead Slampher](http://sonoff.itead.cc/en/products/residential/slampher-rf) - [iTead Slampher](http://sonoff.itead.cc/en/products/residential/slampher-rf)
- [iTead Sonoff Touch](http://sonoff.itead.cc/en/products/residential/sonoff-touch) - [iTead Sonoff Touch](http://sonoff.itead.cc/en/products/residential/sonoff-touch)
- [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 Led](http://sonoff.itead.cc/en/products/appliances/sonoff-led)
- [iTead Sonoff Dev](https://www.itead.cc/sonoff-dev.html) - [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 1 Channel Switch 5V / 12V](https://www.itead.cc/smart-home/inching-self-locking-wifi-wireless-switch.html)

Binary file not shown.

View File

@ -1,4 +1,12 @@
/* 4.1.2 20170403 /* 4.1.3 20170410
* Add user configuarble GPIO to module S20 Socket and Slampher
* Add support for Sonoff SC (#112)
* Set PWM frequency from 1000Hz to 910Hz as used on iTead Sonoff Led firmware (#122)
* Set Sonoff Led unconfigured floating outputs to 0 to reduce exceptions due to power supply instabilities (#122)
* Add Access Point Mac Address to Status 11 and Telemetry (#329)
* Fix DS18B20 negative temperature readings (#334)
*
* 4.1.2 20170403
* Rename Unrecognised command to Unknown command * Rename Unrecognised command to Unknown command
* Remove all command lists * Remove all command lists
* Remove command SmartConfig (superseded by WifiConfig) * Remove command SmartConfig (superseded by WifiConfig)

View File

@ -10,7 +10,7 @@
* ==================================================== * ====================================================
*/ */
#define VERSION 0x04010200 // 4.1.2 #define VERSION 0x04010300 // 4.1.3
enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; 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}; enum week_t {Last, First, Second, Third, Fourth};
@ -104,7 +104,8 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#define WS2812_MAX_LEDS 256 // Max number of LEDs #define WS2812_MAX_LEDS 256 // Max number of LEDs
#define PWM_RANGE 1023 // 255..1023 needs to be devisible by 256 #define PWM_RANGE 1023 // 255..1023 needs to be devisible by 256
#define PWM_FREQ 1000 // 100..1000 Hz led refresh //#define PWM_FREQ 1000 // 100..1000 Hz led refresh
#define PWM_FREQ 910 // 100..1000 Hz led refresh (iTead value)
#define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power (Pow) #define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power (Pow)
#define MAX_POWER_WINDOW 30 // Time in SECONDS to disable allow max agreed power (Pow) #define MAX_POWER_WINDOW 30 // Time in SECONDS to disable allow max agreed power (Pow)
@ -1505,8 +1506,8 @@ void state_mqttPresent(char* svalue, uint16_t ssvalue)
} }
snprintf_P(svalue, ssvalue, PSTR("%s\"%s\""), svalue, getStateText(bitRead(power, i))); snprintf_P(svalue, ssvalue, PSTR("%s\"%s\""), svalue, getStateText(bitRead(power, i)));
} }
snprintf_P(svalue, ssvalue, PSTR("%s, \"Wifi\":{\"AP\":%d, \"SSID\":\"%s\", \"RSSI\":%d}}"), snprintf_P(svalue, ssvalue, PSTR("%s, \"Wifi\":{\"AP\":%d, \"SSID\":\"%s\", \"RSSI\":%d, \"APMac\":\"%s\"}}"),
svalue, sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], WIFI_getRSSIasQuality(WiFi.RSSI())); svalue, sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], WIFI_getRSSIasQuality(WiFi.RSSI()), WiFi.BSSIDstr().c_str());
} }
void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
@ -1525,6 +1526,7 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
*djson = 1; *djson = 1;
} }
#endif #endif
if (sysCfg.module == SONOFF_SC) sc_mqttPresent(svalue, ssvalue, djson);
if (pin[GPIO_DSB] < 99) { if (pin[GPIO_DSB] < 99) {
#ifdef USE_DS18B20 #ifdef USE_DS18B20
dsb_mqttPresent(svalue, ssvalue, djson); dsb_mqttPresent(svalue, ssvalue, djson);
@ -1915,6 +1917,8 @@ void stateloop()
} }
} }
/********************************************************************************************/
void serial() void serial()
{ {
char log[LOGSZ]; char log[LOGSZ];
@ -1951,7 +1955,15 @@ void serial()
SerialInByteCounter = 0; SerialInByteCounter = 0;
} }
} }
if (SerialInByte == '\n') {
if (SerialInByte == '\x1B') { // Sonoff SC status from ATMEGA328P
serialInBuf[SerialInByteCounter] = 0; // serial data completed
sc_rcvstat(serialInBuf);
SerialInByteCounter = 0;
Serial.flush();
return;
}
else if (SerialInByte == '\n') {
serialInBuf[SerialInByteCounter] = 0; // serial data completed serialInBuf[SerialInByteCounter] = 0; // serial data completed
seriallog_level = (sysCfg.seriallog_level < LOG_LEVEL_INFO) ? LOG_LEVEL_INFO : sysCfg.seriallog_level; seriallog_level = (sysCfg.seriallog_level < LOG_LEVEL_INFO) ? LOG_LEVEL_INFO : sysCfg.seriallog_level;
snprintf_P(log, sizeof(log), PSTR("CMND: %s"), serialInBuf); snprintf_P(log, sizeof(log), PSTR("CMND: %s"), serialInBuf);
@ -2024,9 +2036,25 @@ void GPIO_init()
Maxdevice = 4; Maxdevice = 4;
Baudrate = 19200; Baudrate = 19200;
} }
else if (sysCfg.module == SONOFF_SC) {
Maxdevice = 0;
Baudrate = 19200;
}
else if (sysCfg.module == SONOFF_LED) { else if (sysCfg.module == SONOFF_LED) {
pwm_idxoffset = 2; pwm_idxoffset = 2;
pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led
if (!my_module.gp.io[4]) {
pinMode(4, OUTPUT); // Stop floating outputs
digitalWrite(4, LOW);
}
if (!my_module.gp.io[5]) {
pinMode(5, OUTPUT); // Stop floating outputs
digitalWrite(5, LOW);
}
if (!my_module.gp.io[14]) {
pinMode(14, OUTPUT); // Stop floating outputs
digitalWrite(14, LOW);
}
sl_init(); sl_init();
} }
else { else {
@ -2128,7 +2156,7 @@ void setup()
if (Serial.baudRate() != Baudrate) { if (Serial.baudRate() != Baudrate) {
if (seriallog_level) { if (seriallog_level) {
snprintf_P(log, sizeof(log), PSTR("APP: Change your baudrate to %d"), Baudrate); snprintf_P(log, sizeof(log), PSTR("APP: Set baudrate to %d"), Baudrate);
addLog(LOG_LEVEL_INFO, log); addLog(LOG_LEVEL_INFO, log);
} }
delay(100); delay(100);
@ -2172,6 +2200,8 @@ void setup()
} }
blink_powersave = power; blink_powersave = power;
if (sysCfg.module == SONOFF_SC) sc_init();
rtc_init(); rtc_init();
snprintf_P(log, sizeof(log), PSTR("APP: Project %s %s (Topic %s, Fallback %s, GroupTopic %s) Version %s"), snprintf_P(log, sizeof(log), PSTR("APP: Project %s %s (Topic %s, Fallback %s, GroupTopic %s) Version %s"),

View File

@ -121,6 +121,7 @@ enum module_t {
WEMOS, WEMOS,
SONOFF_DEV, SONOFF_DEV,
H801, H801,
SONOFF_SC,
MAXMODULE }; MAXMODULE };
/********************************************************************************************/ /********************************************************************************************/
@ -240,7 +241,10 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
}, },
{ "S20 Socket", // S20 Smart Socket (ESP8266) { "S20 Socket", // S20 Smart Socket (ESP8266)
GPIO_KEY1, // GPIO00 Button GPIO_KEY1, // GPIO00 Button
0, 0, 0, 0, 0, GPIO_USER, // GPIO01 Serial RXD and Optional sensor
0,
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
0, 0,
0, 0, 0, 0, 0, 0, // Flash connection 0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off) GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
@ -248,7 +252,10 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
}, },
{ "Slampher", // Slampher (ESP8266) { "Slampher", // Slampher (ESP8266)
GPIO_KEY1, // GPIO00 Button GPIO_KEY1, // GPIO00 Button
0, 0, 0, 0, 0, GPIO_USER, // GPIO01 Serial RXD and Optional sensor
0,
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
0, 0,
0, 0, 0, 0, 0, 0, // Flash connection 0, 0, 0, 0, 0, 0, // Flash connection
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
@ -391,6 +398,17 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
GPIO_PWM1, // GPIO14 W1 GPIO_PWM1, // GPIO14 W1
GPIO_PWM5, // GPIO15 Red GPIO_PWM5, // GPIO15 Red
0, 0 0, 0
},
{ "Sonoff SC", // Sonoff SC (ESP8266)
GPIO_KEY1, // GPIO00 Button
GPIO_TXD, // GPIO01 RXD to ATMEGA328P
GPIO_USER, // GPIO02 Optional sensor
GPIO_RXD, // GPIO03 TXD to ATMEGA328P
0, 0,
0, 0, 0, 0, 0, 0, // Flash connection
0,
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
0, 0, 0, 0
} }
}; };

View File

@ -267,6 +267,12 @@ const char HTTP_SNS_HUM[] PROGMEM =
"<tr><th>%s Humidity</th><td>%s%</td></tr>"; "<tr><th>%s Humidity</th><td>%s%</td></tr>";
const char HTTP_SNS_PRESSURE[] PROGMEM = const char HTTP_SNS_PRESSURE[] PROGMEM =
"<tr><th>%s Pressure</th><td>%s hPa</td></tr>"; "<tr><th>%s Pressure</th><td>%s hPa</td></tr>";
const char HTTP_SNS_LIGHT[] PROGMEM =
"<tr><th>%s Light</th><td>%d of 10</td></tr>";
const char HTTP_SNS_NOISE[] PROGMEM =
"<tr><th>%s Noise</th><td>%d of 10</td></tr>";
const char HTTP_SNS_DUST[] PROGMEM =
"<tr><th>%s Air quality</th><td>%d of 10</td></tr>";
const char HTTP_END[] PROGMEM = const char HTTP_END[] PROGMEM =
"</div>" "</div>"
"</body>" "</body>"
@ -452,6 +458,7 @@ void handleAjax2()
String tpage = ""; String tpage = "";
if (hlw_flg) tpage += hlw_webPresent(); if (hlw_flg) tpage += hlw_webPresent();
if (sysCfg.module == SONOFF_SC) tpage += sc_webPresent();
#ifdef USE_DS18B20 #ifdef USE_DS18B20
if (pin[GPIO_DSB] < 99) tpage += dsb_webPresent(); if (pin[GPIO_DSB] < 99) tpage += dsb_webPresent();
#endif // USE_DS18B20 #endif // USE_DS18B20

149
sonoff/xdrv_snfsc.ino Normal file
View File

@ -0,0 +1,149 @@
/*
Copyright (c) 2017 Theo Arends. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*********************************************************************************************\
* Sonoff Sc
*
* sc_value[0] DHT11 Humidity
* sc_value[1] DHT11 Temperature in Celsius
* sc_value[2] Light level from 1 (Dark) to 10 (Bright) - inverted from original
* sc_value[3] Noise level from 1 (Quiet) to 10 (Loud)
* sc_value[4] Air Quality level from 1 (Bad) to 10 (Good) - inverted from original
*
* To ATMEGA328P:
* AT+DEVCONFIG="uploadFreq":1800,"humiThreshold":2,"tempThreshold":1[1B]
* AT+NOTIFY="uploadFreq":1800,"humiThreshold":2,"tempThreshold":1[1B]
* response: AT+NOTIFY=ok[1B]
* AT+SEND=fail[1B]
* AT+SEND=ok[1B]
* AT+STATUS=4[1B]
* AT+STATUS[1B]
* AT+START[1B]
*
* From ATMEGA328P:
* AT+UPDATE="humidity":42,"temperature":20,"light":7,"noise":3,"dusty":1[1B]
* response: AT+SEND=ok[1B] or AT+SEND=fail[1B]
* AT+STATUS?[1B]
* response: AT+STATUS=4[1B]
*
* Sequence:
* SC sends: ATMEGA328P sends:
* AT+START[1B]
* AT+UPDATE="humidity":42,"temperature":20,"light":7,"noise":3,"dusty":1[1B]
* AT+SEND=ok[1B]
*
* AT+STATUS?[1B]
* AT+STATUS=4[1B]
*
\*********************************************************************************************/
uint16_t sc_value[5] = { 0 };
void sc_init()
{
// Serial.write("AT+DEVCONFIG=\"uploadFreq\":1800\e");
Serial.write("AT+START\e");
// Serial.write("AT+STATUS\e");
}
void sc_rcvstat(char *rcvstat)
{
char *p, *str;
uint16_t value[5] = { 0 };
if (!strncmp(rcvstat,"AT+UPDATE=",10)) {
int8_t i = -1;
for (str = strtok_r(rcvstat, ":", &p); str && i < 5; str = strtok_r(NULL, ":", &p)) value[i++] = atoi(str);
if (value[0] > 0) {
for (byte i = 0; i < 5; i++) sc_value[i] = value[i];
sc_value[2] = 11 - sc_value[2]; // Invert light level
sc_value[4] = 11 - sc_value[4]; // Invert dust level
Serial.write("AT+SEND=ok\e");
} else {
Serial.write("AT+SEND=fail\e");
}
}
else if (!strcmp(rcvstat,"AT+STATUS?")) {
Serial.write("AT+STATUS=4\e");
}
}
/*********************************************************************************************\
* Presentation
\*********************************************************************************************/
float sc_convertCtoF(float c)
{
return c * 1.8 + 32;
}
void sc_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
{
if (sc_value[0] > 0) {
char stemp1[10], stemp2[10];
float t = sc_value[1];
if (TEMP_CONVERSION) t = sc_convertCtoF(t);
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1);
float h = sc_value[0];
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp2);
snprintf_P(svalue, ssvalue, PSTR("%s, \"SC\":{\"Temperature\":%s, \"Humidity\":%s, \"Light\":%d, \"Noise\":%d, \"AirQuality\":%d}"),
svalue, stemp1, stemp2, sc_value[2], sc_value[3], sc_value[4]);
*djson = 1;
#ifdef USE_DOMOTICZ
domoticz_sensor2(stemp1, stemp2);
domoticz_sensor5(sc_value[2]);
#endif // USE_DOMOTICZ
}
}
#ifdef USE_WEBSERVER
String sc_webPresent()
{
String page = "";
if (sc_value[0] > 0) {
char stemp[10], sensor[80], scstype[] = "SC";
float t = sc_value[1];
if (TEMP_CONVERSION) t = sc_convertCtoF(t);
dtostrf(t, 1, TEMP_RESOLUTION &3, stemp);
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, scstype, stemp, (TEMP_CONVERSION) ? 'F' : 'C');
page += sensor;
float h = sc_value[0];
dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp);
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_HUM, scstype, stemp);
page += sensor;
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_LIGHT, scstype, sc_value[2]);
page += sensor;
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_NOISE, scstype, sc_value[3]);
page += sensor;
snprintf_P(sensor, sizeof(sensor), HTTP_SNS_DUST, scstype, sc_value[4]);
page += sensor;
}
return page;
}
#endif // USE_WEBSERVER

View File

@ -131,7 +131,7 @@ float dsb_convertCtoF(float c)
boolean dsb_readTemp(bool S, float &t) boolean dsb_readTemp(bool S, float &t)
{ {
int16_t DSTemp; int16_t DSTemp;
byte msb, lsb, crc; byte msb, lsb, crc, sign = 1;
if (!dsb_mt) { if (!dsb_mt) {
t = NAN; t = NAN;
@ -168,7 +168,11 @@ boolean dsb_readTemp(bool S, float &t)
addLog_P(LOG_LEVEL_DEBUG, PSTR("DSB: Sensor CRC error")); addLog_P(LOG_LEVEL_DEBUG, PSTR("DSB: Sensor CRC error"));
} else { } else {
DSTemp = (msb << 8) + lsb; DSTemp = (msb << 8) + lsb;
t = (float(DSTemp) * 0.0625); if (DSTemp > 2047) {
DSTemp = (~DSTemp) +1;
sign = -1;
}
t = (float)sign * DSTemp * 0.0625;
if(S) t = dsb_convertCtoF(t); if(S) t = dsb_convertCtoF(t);
} }
if (!isnan(t)) dsb_mt = t; if (!isnan(t)) dsb_mt = t;

View File

@ -154,7 +154,12 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t)
break; break;
case DS18B20_CHIPID: // DS18B20 case DS18B20_CHIPID: // DS18B20
case MAX31850_CHIPID: // MAX31850 case MAX31850_CHIPID: // MAX31850
t = ((data[1] << 8) + data[0]) * 0.0625; uint16_t temp12 = (data[1] << 8) + data[0];
if (temp12 > 2047) {
temp12 = (~temp12) +1;
sign = -1;
}
t = sign * temp12 * 0.0625;
if(S) t = ds18x20_convertCtoF(t); if(S) t = ds18x20_convertCtoF(t);
break; break;
} }