Skip to content

Commit

Permalink
v4.1.3
Browse files Browse the repository at this point in the history
4.1.3 20170410
* Add user configuarble GPIO to module S20 Socket and Slampher
* Add support for Sonoff SC (arendst#112)
* Set PWM frequency from 1000Hz to 910Hz as used on iTead Sonoff Led
firmware (arendst#122)
* Set Sonoff Led unconfigured floating outputs to 0 to reduce exceptions
due to power supply instabilities (arendst#122)
* Add Access Point Mac Address to Status 11 and Telemetry (arendst#329)
* Fix DS18B20 negative temperature readings (arendst#334)
  • Loading branch information
arendst committed Apr 10, 2017
1 parent a0b9d17 commit 1a3455a
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 14 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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```.
Expand All @@ -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)
Expand Down
Binary file modified api/arduino/sonoff.ino.bin
Binary file not shown.
10 changes: 9 additions & 1 deletion sonoff/_releasenotes.ino
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
44 changes: 37 additions & 7 deletions sonoff/sonoff.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -1524,7 +1525,8 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
snprintf_P(svalue, ssvalue, PSTR("%s, \"AnalogInput0\":%d"), svalue, analogRead(A0));
*djson = 1;
}
#endif
#endif
if (sysCfg.module == SONOFF_SC) sc_mqttPresent(svalue, ssvalue, djson);
if (pin[GPIO_DSB] < 99) {
#ifdef USE_DS18B20
dsb_mqttPresent(svalue, ssvalue, djson);
Expand Down Expand Up @@ -1915,6 +1917,8 @@ void stateloop()
}
}

/********************************************************************************************/

void serial()
{
char log[LOGSZ];
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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"),
Expand Down
22 changes: 20 additions & 2 deletions sonoff/sonoff_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ enum module_t {
WEMOS,
SONOFF_DEV,
H801,
SONOFF_SC,
MAXMODULE };

/********************************************************************************************/
Expand Down Expand Up @@ -240,15 +241,21 @@ 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)
0, 0, 0, 0
},
{ "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)
Expand Down Expand Up @@ -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
}
};

7 changes: 7 additions & 0 deletions sonoff/webserver.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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>"
Expand Down Expand Up @@ -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
Expand Down
149 changes: 149 additions & 0 deletions sonoff/xdrv_snfsc.ino
Original file line number Diff line number Diff line change
@@ -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

8 changes: 6 additions & 2 deletions sonoff/xsns_ds18b20.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion sonoff/xsns_ds18x20.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit 1a3455a

Please sign in to comment.