mirror of https://github.com/arendst/Tasmota.git
v4.1.3
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:
parent
d32cb04b1a
commit
824368125b
|
@ -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 **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.
|
||||
- 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 Slampher](http://sonoff.itead.cc/en/products/residential/slampher-rf)
|
||||
- [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 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)
|
||||
|
|
Binary file not shown.
|
@ -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
|
||||
* Remove all command lists
|
||||
* Remove command SmartConfig (superseded by WifiConfig)
|
||||
|
|
|
@ -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 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 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_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, \"Wifi\":{\"AP\":%d, \"SSID\":\"%s\", \"RSSI\":%d}}"),
|
||||
svalue, sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], WIFI_getRSSIasQuality(WiFi.RSSI()));
|
||||
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()), WiFi.BSSIDstr().c_str());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
if (sysCfg.module == SONOFF_SC) sc_mqttPresent(svalue, ssvalue, djson);
|
||||
if (pin[GPIO_DSB] < 99) {
|
||||
#ifdef USE_DS18B20
|
||||
dsb_mqttPresent(svalue, ssvalue, djson);
|
||||
|
@ -1915,6 +1917,8 @@ void stateloop()
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************/
|
||||
|
||||
void serial()
|
||||
{
|
||||
char log[LOGSZ];
|
||||
|
@ -1951,7 +1955,15 @@ void serial()
|
|||
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
|
||||
seriallog_level = (sysCfg.seriallog_level < LOG_LEVEL_INFO) ? LOG_LEVEL_INFO : sysCfg.seriallog_level;
|
||||
snprintf_P(log, sizeof(log), PSTR("CMND: %s"), serialInBuf);
|
||||
|
@ -2024,9 +2036,25 @@ void GPIO_init()
|
|||
Maxdevice = 4;
|
||||
Baudrate = 19200;
|
||||
}
|
||||
else if (sysCfg.module == SONOFF_SC) {
|
||||
Maxdevice = 0;
|
||||
Baudrate = 19200;
|
||||
}
|
||||
else if (sysCfg.module == SONOFF_LED) {
|
||||
pwm_idxoffset = 2;
|
||||
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();
|
||||
}
|
||||
else {
|
||||
|
@ -2128,7 +2156,7 @@ void setup()
|
|||
|
||||
if (Serial.baudRate() != Baudrate) {
|
||||
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);
|
||||
}
|
||||
delay(100);
|
||||
|
@ -2172,6 +2200,8 @@ void setup()
|
|||
}
|
||||
blink_powersave = power;
|
||||
|
||||
if (sysCfg.module == SONOFF_SC) sc_init();
|
||||
|
||||
rtc_init();
|
||||
|
||||
snprintf_P(log, sizeof(log), PSTR("APP: Project %s %s (Topic %s, Fallback %s, GroupTopic %s) Version %s"),
|
||||
|
|
|
@ -121,6 +121,7 @@ enum module_t {
|
|||
WEMOS,
|
||||
SONOFF_DEV,
|
||||
H801,
|
||||
SONOFF_SC,
|
||||
MAXMODULE };
|
||||
|
||||
/********************************************************************************************/
|
||||
|
@ -240,7 +241,10 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
},
|
||||
{ "S20 Socket", // S20 Smart Socket (ESP8266)
|
||||
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
|
||||
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||
|
@ -248,7 +252,10 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
},
|
||||
{ "Slampher", // Slampher (ESP8266)
|
||||
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
|
||||
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
|
||||
|
@ -391,6 +398,17 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
|
|||
GPIO_PWM1, // GPIO14 W1
|
||||
GPIO_PWM5, // GPIO15 Red
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -267,6 +267,12 @@ const char HTTP_SNS_HUM[] PROGMEM =
|
|||
"<tr><th>%s Humidity</th><td>%s%</td></tr>";
|
||||
const char HTTP_SNS_PRESSURE[] PROGMEM =
|
||||
"<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 =
|
||||
"</div>"
|
||||
"</body>"
|
||||
|
@ -452,6 +458,7 @@ void handleAjax2()
|
|||
|
||||
String tpage = "";
|
||||
if (hlw_flg) tpage += hlw_webPresent();
|
||||
if (sysCfg.module == SONOFF_SC) tpage += sc_webPresent();
|
||||
#ifdef USE_DS18B20
|
||||
if (pin[GPIO_DSB] < 99) tpage += dsb_webPresent();
|
||||
#endif // USE_DS18B20
|
||||
|
|
|
@ -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
|
||||
|
|
@ -131,7 +131,7 @@ float dsb_convertCtoF(float c)
|
|||
boolean dsb_readTemp(bool S, float &t)
|
||||
{
|
||||
int16_t DSTemp;
|
||||
byte msb, lsb, crc;
|
||||
byte msb, lsb, crc, sign = 1;
|
||||
|
||||
if (!dsb_mt) {
|
||||
t = NAN;
|
||||
|
@ -168,7 +168,11 @@ boolean dsb_readTemp(bool S, float &t)
|
|||
addLog_P(LOG_LEVEL_DEBUG, PSTR("DSB: Sensor CRC error"));
|
||||
} else {
|
||||
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 (!isnan(t)) dsb_mt = t;
|
||||
|
|
|
@ -154,7 +154,12 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t)
|
|||
break;
|
||||
case DS18B20_CHIPID: // DS18B20
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue