From ba41a2ada59c5789aeed926a0d3c32a7a9a5cc0a Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 18 May 2019 09:45:04 +0200 Subject: [PATCH 01/31] update scripter --- platformio.ini | 10 +- sonoff/my_user_config.h | 3 + sonoff/scripter.md | 621 ++++++++++ sonoff/sonoff.ino | 12 +- sonoff/support_features.ino | 2 +- sonoff/xdrv_09_timers.ino | 12 +- sonoff/xdrv_10_scripter.ino | 2235 +++++++++++++++++++++++++++++++++++ 7 files changed, 2882 insertions(+), 13 deletions(-) create mode 100644 sonoff/scripter.md create mode 100644 sonoff/xdrv_10_scripter.ino diff --git a/platformio.ini b/platformio.ini index f721a496a..1d80293cb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ src_dir = sonoff ;env_default = sonoff-BR ;env_default = sonoff-CN ;env_default = sonoff-CZ -;env_default = sonoff-DE +env_default = sonoff-DE ;env_default = sonoff-ES ;env_default = sonoff-FR ;env_default = sonoff-GR @@ -70,14 +70,14 @@ build_flags = ${esp82xx_defaults.build_flags} platform = espressif8266@~2.1.1 build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 -O2 -DBEARSSL_SSL_BASIC ; nonos-sdk 22x -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x ; nonos-sdk-pre-v3 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -; lwIP 1.4 +; lwIP 1.4 ; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH ; lwIP 2 - Low Memory ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY @@ -96,13 +96,13 @@ build_flags = ${esp82xx_defaults.build_flags} platform = https://github.com/platformio/platform-espressif8266.git#feature/stage build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 -O2 -DBEARSSL_SSL_BASIC ; nonos-sdk 22x -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x ; nonos-sdk-pre-v3 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 +; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 ; lwIP 1.4 ; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH ; lwIP 2 - Low Memory diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 945261e1c..a7d7a3602 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -290,6 +290,9 @@ // -- Rules --------------------------------------- #define USE_RULES // Add support for rules (+4k4 code) +#undef USE_RULES +#define USE_SCRIPT + // #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem) // #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) diff --git a/sonoff/scripter.md b/sonoff/scripter.md new file mode 100644 index 000000000..5b9ac7840 --- /dev/null +++ b/sonoff/scripter.md @@ -0,0 +1,621 @@ +**Script Language for Tasmota** + +As an alternative to rules. (about 14,2k flash size, variable ram size) + +In submenu Configuration =\> edit script +1535 bytes max script size (uses rules buffer) + +to enable: +\#define USE_SCRIPT +\#undef USE_RULES + + +Up to 50 variables (45 numeric and 5 strings, maybe changed by #define) +Freely definable variable names (all names are intentionally case sensitive) +Nested if,then,else up to a level of 8 +Math operators **+,-,\*,/,%,&,|,^** +all operators may be used in the op= form e.g. **+=** +Left right evaluation with optional brackets +all numbers are float +e.g. temp=hum\*(100/37.5)+temp-(timer\*hum%10) +no spaces allowed between math operations +Comparison operators **==,!=,\>,\>=,<,<=** +**and** , **or** support + +strings support **+** and **+=** operators +string comparison **==,!=** +max string size = 19 chars (default, can be increased or decreased by optional >D parameter) + +**Comments** start with **;** + +**Sections** defined: + +>**\>D ssize** +ssize = optional max stringsize (default=19) +define and init variables here, must be the first section, no other code allowed +**p:**vname specifies permanent vars (the number of permanent vars is limited by tasmota rules space (50 bytes) +numeric var=4 bytes, string var=lenght of string+1) +**t:**vname specifies countdown timers, if >0 they are decremented in seconds until zero is reached. see example below +**i:**vname specifies auto increment counters if >=0 (in seconds) +**m:**vname specifies a median filter variable with 5 entries (for elimination of outliers) +**M:**vname specifies a moving average filter variable with 8 entries (for smoothing data) +(max 5 filters in total m+M) + +>all variable names length taken together may not exceed 256 characters, so keep variable names as short as possible. +memory is dynamically allocated as a result of the D section. +copying a string to a number or reverse is supported + +>**\>B** +executed on BOOT time + +>**\>T** +executed on teleperiod time (**SENSOR** and **STATE**), get tele vars only in this section + +>**\>S** +executed every second + +>**\>E** +executed e.g. on power change and mqtt **RESULT** + +>**\>R** +executed on restart, p vars are saved automatically after this call + + +special variables (read only): + +>**upsecs** = seconds since start +**uptime** = minutes since start +**time** = minutes since midnight +**sunrise** = sunrise minutes since midnight +**sunset** = sunset minutes since midnight +**tper** = teleperiod (may be set also) +**tstamp** = timestamp (local date and time) +**topic** = mqtt topic +**gtopic** = mqtt group topic +**prefixn** = prefix n = 1-3 +**pwr[x]** = tasmota power state (x = 1-N) +**sw[x]** = tasmota switch state (x = 1-N) +>**pin[x]** = gpio pin level (x = 0-16) +**pn[x]** = pin number for sensor code x, 99 if none +**pd[x]** = defined sensor for gpio pin nr x none=999 +**gtmp** = global temperature +**ghum** = global humidity +**gprs** = global pressure +**pow(x y)** = calculates the power of x^y +**med(n x)** = calculates a 5 value median filter of x (2 filters possible n=0,1) +**int(x)** = gets the integer part of x (like floor) +**hn(x)** = converts x (0..255) zu a hex nibble string +**mqtts** = state of mqtt disconnected=0, connected>0 +**wifis** = state of wifi disconnected=0, connected>0 + +>**hours** = hours +**mins** = mins +**secs** = seconds +**day** = day of month +**wday** = day of week +**month** = month +**year** = year + +these variables are cleared after reading true +>**chg[var]** = true if a variables value was changed (numeric vars only) +**upd[var]** = true if a variable was updated +**boot** = true on BOOT +**tinit** = true on time init +**tset** = true on time set +**mqttc** = true on mqtt connect +**mqttd** = true on mqtt disconnect +**wific** = true on wifi connect +**wifid** = true on wifi disconnect + +system vars (for debugging) +>**stack** = stack size +**heap** = heap size +**ram** = used ram size +**slen** = script length +**micros** = running microseconds +**millis** = running milliseconds +**loglvl** = loglevel of script cmds, may be set also + +remarks: +if you define a variable with the same name as a special +variable that special variable is discarded + + +**Tasmota** cmds start with **=\>** +within cmds you can replace text with variables with **%varname%** +a single percent sign must be given as **%%** + +**special** cmds: + +>**=\> print** prints to info log for debugging + +to save code space nearly no error messages are provided. However it is taken care of that at least it should not crash on syntax errors. +if a variable does not exist a **???** is given on commands +if a **SENSOR** or **STATUS** or **RESULT** message or a var does not exist the destination variable is NOT updated. + +2 possibilities for conditionals: +>**if** a==b +**and** x==y +**or** k==i +**then** => do this +**else** => do that +**endif** + +OR + +>**if** a==b +**and** x==y +**or** k==i **{** + => do this +**} else {** + => do that +**}** + +you may NOT mix both methods + +also possible e.g. + +>if var1-var2==var3*var4 +then + +remarks: +the last closing bracket must be on a single line +the condition may not be enclosed in brackets + +>**break** exits a section or terminates a for next loop +**dprecx** sets decimal precision to x (0-9) +**svars** save permanent vars +**delay(x)** pauses x milliseconds (should be as short as possible) +**spin(x m)** set gpio pin x (0-16) to value m (0,1) only the last bit is used, so even values set the pin to zero and uneven values set the pin to 1 +**spinm(x m)** set pin mode gpio pin x (0-16) to mode m (input=0,output=1) + +>**#name** names a subroutine, subroutines are called with **=#name** +**#name(param)** names a subroutines with a parameter is called with **=#name(param)** +subroutines end with the next '#' or '>' line or break, may be nested +params can be numbers or strings and on mismatch are converted + +>**for var from to inc** +**next** +specifies a for next loop, (loop count must not be less then 1) + +>**switch x** +**case a** +**case b** +**ends** +specifies a switch case selector + +**konsole script cmds** +>**script 1 or 0** switch script on or off +**script >cmdline** executes the script cmdline +can be used e.g. to set variables e.g. **script >mintmp=15** +more then one line may be executed seperated by a semicolon e.g. **script >mintmp=15;maxtemp=40** +script itself cant be set because the size would not fit the mqtt buffers + +***example script*** +meant to show some of the possibilities +(actually this code ist too large) + +**\>D** +; define all vars here +p:mintmp=10 (p:means permanent) +p:maxtmp=30 +t:timer1=30 (t:means countdown timer) +t:mt=0 +i:count=0 (i:means auto counter) +hello="hello world" +string="xxx" +url="[192.168.178.86]" +hum=0 +temp=0 +timer=0 +dimmer=0 +sw=0 +rssi=0 +param=0 + +col="" +ocol="" +chan1=0 +chan2=0 +chan3=0 + +ahum=0 +atemp=0 +tcnt=0 +hour=0 +state=1 +m:med5=0 +M:movav=0 + +**\>B** + +string=hello+"how are you?" +=\>print BOOT executed +=\>print %hello% +=\>mp3track 1 + +; list gpio pin definitions +for cnt 0 16 1 +tmp=pd[cnt] +=>print %cnt% = %tmp% +next + +; get gpio pin for relais 1 +tmp=pn[21] +=>print relais 1 is on pin %tmp% + +; pulse relais over raw gpio +spin(tmp 1) +delay(100) +spin(tmp 0) + +; raw pin level +=>print level of gpio1 %pin[1]% + +; pulse over tasmota cmd +=>power 1 +delay(100) +=>power 0 + +**\>T** + +hum=BME280#Humidity +temp=BME280#Temperature +rssi=Wifi#RSSI +string=SleepMode + +; add to median filter +median=temp +; add to moving average filter +movav=hum + +; show filtered results +=>print %median% %movav% + +if chg[rssi]>0 +then =>print rssi changed to %rssi% +endif + +if temp\>30 +and hum\>70 +then =\>print damn hot! +endif + +**\>S** + +; every second but not completely reliable time here +; use upsecs and uptime or best t: for reliable timers + +; call subrountines with parameters +=#sub1("hallo") +=#sub2(999) + +; stop timer after expired +if timer1==0 +then timer1=-1 +=>print timer1 expired +endif + +; auto counter with restart +if count>=10 +then =>print 10 seconds over +count=0 +endif + +if upsecs%5==0 +then =\>print %upsecs% (every 5 seconds) +endif + +; not recommended for reliable timers +timer+=1 +if timer\>=5 +then =\>print 5 seconds over (may be) +timer=0 +endif + +dimmer+=1 +if dimmer\>100 +then dimmer=0 +endif + +=\>dimmer %dimmer% +=\>WebSend %url% dimmer %dimmer% + +; show on display +dprec0 +=\>displaytext [c1l1f1s2p20] dimmer=%dimmer% + +=\>print %upsecs% %uptime% %time% %sunrise% %sunset% %tstamp% + +if time\>sunset +and time< sunrise +then +; night time +if pwr[1]==0 +then =\>power1 1 +endif +else +; day time +if pwr[1]\>0 +then =\>power1 0 +endif +endif + +; clr display on boot +if boot\>0 +then =\>displaytext [z] +endif + +; frost warning +if temp<0 +and mt<=0 +then =#sendmail("frost alert") +; alarm only every 5 minutes +mt=300 +=>mp3track 2 +endif + +; var has been updated +if upd[hello]>0 +then =>print %hello% +endif + +; send to Thingspeak every 60 seconds +; average data in between +if upsecs%60==0 +then +ahum/=tcnt +atemp/=tcnt +=>Websend [184.106.153.149:80]/update?key=PYUZMVWCICBW492&field1=%atemp%&field2=%ahum% +tcnt=0 +atemp=0 +ahum=0 +else +ahum+=hum +atemp+=temp +tcnt+=1 +endif + +hour=int(time/60) +if chg[hour]>0 +then +; exactly every hour +=>print full hour reached +endif + +if time>5 { +=>print more then 5 minutes after midnight +} else { +=>print less then 5 minutes after midnight +} + + +; publish abs hum every teleperiod time +if mqtts>0 +and upsecs%tper==0 +then +; calc abs humidity +tmp=pow(2.718281828 (17.67\*temp)/(temp+243.5)) +tmp=(6.112\*tmp\*hum\*18.01534)/((273.15+temp)\*8.31447215) +; publish median filtered value +=>Publish tele/%topic%/SENSOR {"Script":{"abshum":%med(0 tmp)%}} +endif + +;switch case state machine +switch state +case 1 +=>print state=%state% , start +state+=1 +case 2 +=>print state=%state% +state+=1 +case 3 +=>print state=%state% , reset +state=1 +ends + + +; subroutines +\#sub1(string) +=>print sub1: %string% +\#sub2(param) +=>print sub2: %param% + +\#sendmail(string) +=>sendmail [smtp.gmail.com:465:user:passwd:::alarm] %string% + +**\>E** +=\>print event executed! + + +; check if switch changed state +sw=sw[1] +if chg[sw]>0 +then =\>power1 %sw% +endif + +hello="event occured" + +; check for Color change (Color is a string) +col=Color +; color change needs 2 string vars +if col!=ocol +then ocol=col +=>print color changed %col% +endif + +; or check change of color channels +chan1=Channel[1] +chan2=Channel[2] +chan3=Channel[3] + +if chg[chan1]>0 +or chg[chan2]>0 +or chg[chan3]>0 +then => color has changed +endif + +; compose color string for red +col=hn(255)+hn(0)+hn(0) +=>color %col% + +**\>R** +=\>print restarting now + +**a real example** +epaper 29 with sgp30 and bme280 +some vars are set from iobroker +DisplayText substituted to save script space +\>D +hum=0 +temp=0 +press=0 +ahum=0 +tvoc=0 +eco2=0 +zwz=0 +wr1=0 +wr2=0 +wr3=0 +otmp=0 +pwl=0 +tmp=0 +DT="DisplayText" +; preset units in case they are not available +punit="hPa" +tunit="C" + +\>B +;reset auto draw +=>%DT% [zD0] +;clr display and draw a frame +=>%DT% [x0y20h296x0y40h296] + +\>T +; get tele vars +temp=BME280#Temperature +hum=BME280#Humidity +press=BME280#Pressure +tvoc=SGP30#TVOC +eco2=SGP30#eCO2 +ahum=SGP30#aHumidity +tunit=TempUnit +punit=PressureUnit + +\>S +// update display every teleperiod time +if upsecs%tper==0 +then +dprec2 +=>%DT% [f1p7x0y5]%temp% %tunit% +=>%DT% [p5x70y5]%hum% %%[x250y5t] +=>%DT% [p11x140y5]%press% %punit% +=>%DT% [p10x30y25]TVOC: %tvoc% ppb +=>%DT% [p10x160y25]eCO2: %eco2% ppm +=>%DT% [p10c26l5]ahum: %ahum% g^m3 + +dprec0 +=>%DT% [p25c1l5]WR 1 (Dach) : %wr1% W +=>%DT% [p25c1l6]WR 2 (Garage): %-wr3% W +=>%DT% [p25c1l7]WR 3 (Garten): %-wr2% W +=>%DT% [p25c1l8]Aussentemperatur: %otmp% C +=>%DT% [x170y95r120:30f2p6x185y100] %pwl% %% +; now update screen +=>%DT% [d] +endif + + +\>E + +\>R + +**another real example** +ILI 9488 color LCD Display shows various energy graphs +display switches on and off with proximity sensor +BMP280 and vl5310x +some vars are set from iobroker + +**>D** +temp=0 +press=0 +zwz=0 +wr1=0 +wr2=0 +wr3=0 +otmp=0 +pwl=0 +tmp=0 +dist=0 +DT="DisplayText" +punit="hPa" +tunit="C" +hour=0 + +**>B** +=>%DT% [z] + +// define 2 graphs, 2. has 3 tracks +=>%DT% [zCi1G2656:5:20:400:80:1440:-5000:5000:3Ci7f3x410y20]+5000 W[x410y95]-5000 W [Ci7f1x70y3] Zweirichtungsz~80hler - 24 Stunden +=>%DT% [Ci1G2657:5:120:400:80:1440:0:5000:3Ci7f3x410y120]+5000 W[x410y195]0 W [Ci7f1x70y103] Wechselrichter 1-3 - 24 Stunden +=>%DT% [Ci1G2658:5:120:400:80:1440:0:5000:16][Ci1G2659:5:120:400:80:1440:0:5000:5] +=>%DT% [f1s1b0:260:260:100:50:2:11:4:2:Rel 1:b1:370:260:100:50:2:11:4:2:Dsp off:] +=>mp3volume 100 +=>mp3track 4 + +**>T** +; get some tele vars +temp=BMP280#Temperature +press=BMP280#Pressure +tunit=TempUnit +punit=PressureUnit +dist=VL53L0X#Distance + +; check proximity sensor to switch display on/off +; to prevent burn in +if dist>300 +then +if pwr[2]>0 +then +=>power2 0 +endif +else +if pwr[2]==0 +then +=>power2 1 +endif +endif + + +**>S** +; update graph every teleperiod +if upsecs%tper==0 +then +dprec2 +=>%DT% [f1Ci3x40y260w30Ci1] +=>%DT% [Ci7x120y220t] +=>%DT% [Ci7x180y220T] +=>%DT% [Ci7p8x120y240]%temp% %tunit% +=>%DT% [Ci7x120y260]%press% %punit% +=>%DT% [Ci7x120y280]%dist% mm +dprec0 +=>%DT% [g0:%zwz%g1:%wr1%g2:%-wr2%g3:%-wr3%] +if zwz>0 +then +=>%DT% [p-8x410y55Ci2Bi0]%zwz% W +else +=>%DT% [p-8x410y55Ci3Bi0]%zwz% W +endif +=>%DT% [p-8x410y140Ci3Bi0]%wr1% W +=>%DT% [p-8x410y155Ci16Bi0]%-wr2% W +=>%DT% [p-8x410y170Ci5Bi0]%-wr3% W +endif + +; chime every full hour +hour=int(time/60) +if chg[hour]>0 +then =>mp3track 4 +endif + +**>E** + +**>R** diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 6e1260c78..9517755ee 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -1468,7 +1468,12 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_UNKNOWN "\"}")); type = (char*)topicBuf; } - if (mqtt_data[0] != '\0') { MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); } + if (mqtt_data[0] != '\0') { + MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); +#ifdef USE_SCRIPT + XdrvRulesProcess(); +#endif + } fallback_topic_flag = false; } @@ -1835,6 +1840,9 @@ void MqttPublishTeleState(void) mqtt_data[0] = '\0'; MqttShowState(); MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_STATE), MQTT_TELE_RETAIN); +#ifdef USE_SCRIPT + RulesTeleperiod(); // Allow rule based HA messages +#endif // USE_SCRIPT } bool MqttShowSensor(void) @@ -1919,7 +1927,7 @@ void PerformEverySecond(void) mqtt_data[0] = '\0'; if (MqttShowSensor()) { MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); -#ifdef USE_RULES +#if defined(USE_RULES) || defined(USE_SCRIPT) RulesTeleperiod(); // Allow rule based HA messages #endif // USE_RULES } diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index c97f77c9d..1802f93b4 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -103,7 +103,7 @@ void GetFeatures(void) #ifdef USE_TIMERS_WEB feature_drv1 |= 0x04000000; // xdrv_09_timers.ino #endif -#ifdef USE_RULES +#if defined(USE_RULES) || defined(USE_SCRIPT) feature_drv1 |= 0x08000000; // xdrv_10_rules.ino #endif #ifdef USE_KNX diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index dcd18c6f1..3f838ed7a 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -285,7 +285,7 @@ void TimerEverySecond(void) if (time == set_time) { if (xtimer.days & days) { Settings.timer[i].arm = xtimer.repeat; -#ifdef USE_RULES +#if defined(USE_RULES) || defined(USE_SCRIPT) if (3 == xtimer.power) { // Blink becomes Rule disregarding device and allowing use of Backlog commands Response_P(PSTR("{\"Clock\":{\"Timer\":%d}}"), i +1); XdrvRulesProcess(); @@ -359,7 +359,8 @@ bool TimerCommand(void) Settings.timer[index -1].data = Settings.timer[XdrvMailbox.payload -1].data; // Copy timer } } else { -#ifndef USE_RULES +//#ifndef USE_RULES +#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0 if (devices_present) { #endif StaticJsonBuffer<256> jsonBuffer; @@ -437,7 +438,8 @@ bool TimerCommand(void) index++; } -#ifndef USE_RULES +//#ifndef USE_RULES +#if defined(USE_RULES)==0 && defined(USE_SCRIPT)==0 } else { Response_P(PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_TIMER_NO_DEVICE "\"}"), index); // No outputs defined so nothing to control error = 1; @@ -630,7 +632,7 @@ const char HTTP_TIMER_SCRIPT5[] PROGMEM = "if(%d>0){" // Create Output and Action drop down boxes "eb('oa').innerHTML=\"" D_TIMER_OUTPUT " " D_TIMER_ACTION " \";" "o=qs('#p1');ce('" D_OFF "',o);ce('" D_ON "',o);ce('" D_TOGGLE "',o);" // Create offset direction select options -#ifdef USE_RULES +#if defined(USE_RULES) || defined(USE_SCRIPT) "ce('" D_RULE "',o);" #else "ce('" D_BLINK "',o);" @@ -768,7 +770,7 @@ bool Xdrv09(uint8_t function) #ifdef USE_WEBSERVER #ifdef USE_TIMERS_WEB case FUNC_WEB_ADD_BUTTON: -#ifdef USE_RULES +#if defined(USE_RULES) || defined(USE_SCRIPT) WSContentSend_P(HTTP_BTN_MENU_TIMER); #else if (devices_present) { WSContentSend_P(HTTP_BTN_MENU_TIMER); } diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino new file mode 100644 index 000000000..72e6b6190 --- /dev/null +++ b/sonoff/xdrv_10_scripter.ino @@ -0,0 +1,2235 @@ +/* + xdrv_10_scripter.ino - script support for Sonoff-Tasmota + + Copyright (C) 2019 Gerhard Mutz and 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 . +*/ + +// for doku see up to date doku in file scripter.md + +// uses about 14,2 k of flash +// more stack could be needed for sendmail => -D CONT_STACKSIZE=4800 = +0.8k stack -0.8k heap +// + +/* to doo +optimize code for space + +// remarks +goal is fast execution time, minimal use of ram and intuitive syntax +therefore => +case sensitive cmds and vars (lowercase uses time and code) +no math hierarchy (costs ram and execution time, better group with brackets, anyhow better readable for beginners) +(will probably make math hierarchy an ifdefed option) +keywords if then else endif, or, and are better readable for beginners (others may use {}) +*/ +#ifdef USE_SCRIPT +#ifndef USE_RULES + +#define XDRV_10 10 + +#define SCRIPT_DEBUG 0 + +#define MAXVARS 50 +#define MAXNVARS 45 +#define MAXSVARS 5 +#define MAXFILT 5 +#define SCRIPT_SVARSIZE 20 +#define SCRIPT_MAXSSIZE 48 +#define SCRIPT_EOL '\n' +#define SCRIPT_FLOAT_PRECISION 2 +#define SCRIPT_MAXPERM (MAX_RULE_MEMS*10)-4/sizeof(float) + + +enum {OPER_EQU=1,OPER_PLS,OPER_MIN,OPER_MUL,OPER_DIV,OPER_PLSEQU,OPER_MINEQU,OPER_MULEQU,OPER_DIVEQU,OPER_EQUEQU,OPER_NOTEQU,OPER_GRTEQU,OPER_LOWEQU,OPER_GRT,OPER_LOW,OPER_PERC,OPER_XOR,OPER_AND,OPER_OR,OPER_ANDEQU,OPER_OREQU,OPER_XOREQU,OPER_PERCEQU}; +enum {SCRIPT_LOGLEVEL=1,SCRIPT_TELEPERIOD}; + +typedef union { + uint8_t data; + struct { + uint8_t is_string : 1; // string or number + uint8_t is_permanent : 1; + uint8_t is_timer : 1; + uint8_t is_autoinc : 1; + uint8_t changed : 1; + uint8_t settable : 1; + uint8_t is_filter : 1; + uint8_t constant : 1; + }; +} SCRIPT_TYPE; + +struct T_INDEX { + uint8_t index; + SCRIPT_TYPE bits; +}; + +struct M_FILT { + uint8_t numvals; + uint8_t index; + float maccu; + float rbuff[1]; +}; + +// global memory +struct SCRIPT_MEM { + float *fvars; // number var pointer + float *s_fvars; // shadow var pointer + struct T_INDEX *type; // type and index pointer + struct M_FILT *mfilt; + char *glob_vnp; // var name pointer + uint8_t *vnp_offset; + char *glob_snp; // string vars pointer + char *scriptptr; + uint8_t numvars; + void *script_mem; + uint16_t script_mem_size; + uint8_t script_dprec; + uint8_t var_not_found; + uint8_t glob_error; + uint8_t max_ssize; + uint8_t script_loglevel; +} glob_script_mem; + +uint8_t tasm_cmd_activ=0; + +uint32_t script_lastmillis; + +char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo); + +void ScriptEverySecond(void) { + + if (bitRead(Settings.rule_enabled, 0)) { + struct T_INDEX *vtp=glob_script_mem.type; + float delta=(millis()-script_lastmillis)/1000; + script_lastmillis=millis(); + for (uint8_t count=0; count0) { + // decrement + *fp-=delta; + if (*fp<0) *fp=0; + } + } + if (vtp[count].bits.is_autoinc) { + // increments timers + float *fp=&glob_script_mem.fvars[vtp[count].index]; + if (*fp>=0) { + *fp+=delta; + } + } + } + Run_Scripter(">S",2,0); + } +} + +void RulesTeleperiod(void) { + if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">T",2, mqtt_data); +} + +#define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++; +#define SCRIPT_SKIP_EOL while (*lp==SCRIPT_EOL) lp++; + +// allocates all variable and presets them +int16_t Init_Scripter(char *script) { + // scan lines for >DEF + uint16_t lines=0,nvars=0,svars=0,vars=0; + char *lp=script; + char vnames[MAXVARS*10]; + char *vnames_p=vnames; + char *vnp[MAXVARS]; + char **vnp_p=vnp; + char strings[MAXSVARS*SCRIPT_MAXSSIZE]; + struct M_FILT mfilt[MAXFILT]; + + char *strings_p=strings; + char *snp[MAXSVARS]; + char **snp_p=snp; + uint8_t numperm=0,numflt=0,count; + + glob_script_mem.max_ssize=SCRIPT_SVARSIZE; + glob_script_mem.scriptptr=0; + if (!*script) return -999; + + float fvalues[MAXVARS]; + struct T_INDEX vtypes[MAXVARS]; + char init=0; + while (1) { + // check line + // skip leading spaces + SCRIPT_SKIP_SPACES + // skip empty line + if (*lp=='\n' || *lp=='\r') goto next_line; + // skip comment + if (*lp==';') goto next_line; + if (init) { + // init section + if (*lp=='>') { + init=0; + break; + } + char *op=strchr(lp,'='); + if (op) { + vtypes[vars].bits.data=0; + // found variable definition + if (*lp=='p' && *(lp+1)==':') { + lp+=2; + if (numpermMAXFILT) { + return -6; + } + } else { + vtypes[vars].bits.is_filter=0; + } + *vnp_p++=vnames_p; + while (lpMAXNVARS) { + return -1; + } + } else { + // string vars + op++; + *snp_p++=strings_p; + while (*op!='\"') { + if (*op==SCRIPT_EOL) break; + *strings_p++=*op++; + } + *strings_p++=0; + vtypes[vars].bits.is_string=1; + vtypes[vars].index=svars; + svars++; + if (svars>MAXSVARS) { + return -2; + } + } + vars++; + if (vars>MAXVARS) { + return -3; + } + } + } else { + if (!strncmp(lp,">D",2)) { + lp+=2; + SCRIPT_SKIP_SPACES + if (isdigit(*lp)) { + uint8_t ssize=atoi(lp)+1; + if (ssize<10 || ssize>SCRIPT_MAXSSIZE) ssize=SCRIPT_MAXSSIZE; + glob_script_mem.max_ssize=ssize; + } + init=1; + } + } + // next line + next_line: + lp = strchr(lp, SCRIPT_EOL); + if (!lp) break; + lp++; + } + + uint16_t fsize=0; + for (count=0; countnumvals=mfilt[count].numvals; + mp+=sizeof(struct M_FILT)+((mfilt[count].numvals&0x7f)-1)*sizeof(float); + } + + glob_script_mem.numvars=vars; + glob_script_mem.script_dprec=SCRIPT_FLOAT_PRECISION; + glob_script_mem.script_loglevel=LOG_LEVEL_INFO; + + +#if SCRIPT_DEBUG>2 + struct T_INDEX *dvtp=glob_script_mem.type; + for (uint8_t count=0; count0 + ClaimSerial(); + SetSerialBaudrate(9600); +#endif + + // store start of actual program here + glob_script_mem.scriptptr=lp-1; + return 0; + +} + +#define NUM_RES 0xfe +#define STR_RES 0xfd +#define VAR_NV 0xff + +#define NTYPE 0 +#define STYPE 0x80 + + +//Settings.seriallog_level +//Settings.weblog_level + +float Get_MFilter(uint8_t index) { + uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; + for (uint8_t count=0; countnumvals&0x80) { + // moving average + return mflp->maccu/(mflp->numvals&0x7f); + } else { + // median, sort array + float tbuff[mflp->numvals],tmp; + uint8_t flag; + memmove(tbuff,mflp->rbuff,sizeof(tbuff)); + for (uint8_t ocnt=0; ocntnumvals; ocnt++) { + flag=0; + for (uint8_t count=0; countnumvals-1; count++) { + if (tbuff[count]>tbuff[count+1]) { + tmp=tbuff[count]; + tbuff[count]=tbuff[count+1]; + tbuff[count+1]=tmp; + flag=1; + } + } + if (!flag) break; + } + return mflp->rbuff[mflp->numvals/2]; + } + } + mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + } + return 0; +} + +void Set_MFilter(uint8_t index, float invar) { + uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; + for (uint8_t count=0; countnumvals&0x80) { + // moving average + mflp->maccu-=mflp->rbuff[mflp->index]; + mflp->maccu+=invar; + mflp->rbuff[mflp->index]=invar; + mflp->index++; + if (mflp->index>=(mflp->numvals&0x7f)) mflp->index=0; + } else { + // median + mflp->rbuff[mflp->index]=invar; + mflp->index++; + if (mflp->index>=mflp->numvals) mflp->index=0; + } + break; + } + mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + } +} + +#define MEDIAN_SIZE 5 +#define MEDIAN_FILTER_NUM 2 + +struct MEDIAN_FILTER { +float buffer[MEDIAN_SIZE]; +int8_t index; +} script_mf[MEDIAN_FILTER_NUM]; + +float DoMedian5(uint8_t index, float in) { + + if (index>=MEDIAN_FILTER_NUM) index=0; + + struct MEDIAN_FILTER* mf=&script_mf[index]; + + float tbuff[MEDIAN_SIZE],tmp; + uint8_t flag; + mf->buffer[mf->index]=in; + mf->index++; + if (mf->index>=MEDIAN_SIZE) mf->index=0; + // sort list and take median + memmove(tbuff,mf->buffer,sizeof(tbuff)); + for (uint8_t ocnt=0; ocnttbuff[count+1]) { + tmp=tbuff[count]; + tbuff[count]=tbuff[count+1]; + tbuff[count+1]=tmp; + flag=1; + } + } + if (!flag) break; + } + return tbuff[MEDIAN_SIZE/2]; +} + + +// vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number +// no flash strings here for performance reasons!!! +char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,JsonObject *jo) { + uint16_t count,len=0; + uint8_t nres=0; + char vname[32]; + float fvar=0; + tind->index=0; + tind->bits.data=0; + + if (isdigit(*lp) || (*lp=='-' && isdigit(*(lp+1))) || *lp=='.') { + // isnumber + if (fp) *fp=CharToDouble(lp); + if (*lp=='-') lp++; + while (isdigit(*lp) || *lp=='.') { + if (*lp==0 || *lp==SCRIPT_EOL) break; + lp++; + } + tind->bits.constant=1; + tind->bits.is_string=0; + *vtype=NUM_RES; + return lp; + } + if (*lp=='"') { + lp++; + while (*lp!='"') { + if (*lp==0 || *lp==SCRIPT_EOL) break; + if (sp) *sp++=*lp; + lp++; + } + if (sp) *sp=0; + *vtype=STR_RES; + tind->bits.constant=1; + tind->bits.is_string=1; + return lp+1; + } + + if (*lp=='-') { + // inverted var + nres=1; + lp++; + } + + const char *term="\n\r ])=+-/*%>index=VAR_NV; + glob_script_mem.var_not_found=1; + return lp; + } + + struct T_INDEX *vtp=glob_script_mem.type; + for (count=0; countindex=count; // overwrite with global var index + if (vtp[count].bits.is_string==0) { + *vtype=NTYPE|index; + if (vtp[count].bits.is_filter) { + fvar=Get_MFilter(index); + } else { + fvar=glob_script_mem.fvars[index]; + } + if (nres) fvar=-fvar; + if (fp) *fp=fvar; + } else { + *vtype=STYPE|index; + if (sp) strlcpy(sp,glob_script_mem.glob_snp+(index*glob_script_mem.max_ssize),SCRIPT_MAXSSIZE); + } + return lp+len; + } + } + } + + if (jo) { + // look for json input + const char* str_value; + uint8_t aindex; + String vn; + char *ja=strchr(vname,'['); + if (ja) { + // json array + *ja=0; + ja++; + // fetch array index + float fvar; + GetNumericResult(ja,OPER_EQU,&fvar,0); + aindex=fvar; + if (aindex<1 || aindex>6) aindex=1; + aindex--; + } + if (jo->success()) { + char *subtype=strchr(vname,'#'); + if (subtype) { + *subtype=0; + subtype++; + } + vn=vname; + str_value = (*jo)[vn]; + if ((*jo)[vn].success()) { + if (subtype) { + JsonObject &jobj1=(*jo)[vn]; + if (jobj1.success()) { + vn=subtype; + jo=&jobj1; + str_value = (*jo)[vn]; + if ((*jo)[vn].success()) { + goto skip; + } + } else { + goto chknext; + } + } + skip: + if (ja) { + // json array + str_value = (*jo)[vn][aindex]; + } + if (str_value && *str_value) { + if ((*jo).is(vn)) { + if (!strncmp(str_value,"ON",2)) { + if (fp) *fp=1; + } else if (!strncmp(str_value,"OFF",3)) { + if (fp) *fp=0; + } else { + *vtype=STR_RES; + tind->bits.constant=1; + tind->bits.is_string=1; + if (sp) strlcpy(sp,str_value,SCRIPT_MAXSSIZE); + return lp+len; + } + } else { + if (fp) *fp=CharToDouble((char*)str_value); + *vtype=NUM_RES; + tind->bits.constant=1; + tind->bits.is_string=0; + return lp+len; + } + } + } + } + } + +chknext: + switch (vname[0]) { + case 'b': + if (!strncmp(vname,"boot",4)) { + if (rules_flag.system_boot) { + rules_flag.system_boot=0; + fvar=1; + } + goto exit; + } + break; + case 'c': + if (!strncmp(vname,"chg[",4)) { + // var changed + struct T_INDEX ind; + uint8_t vtype; + isvar(vname+4,&vtype,&ind,0,0,0); + if (!ind.bits.constant) { + uint8_t index=glob_script_mem.type[ind.index].index; + if (glob_script_mem.fvars[index]!=glob_script_mem.s_fvars[index]) { + // var has changed + glob_script_mem.s_fvars[index]=glob_script_mem.fvars[index]; + fvar=1; + len++; + goto exit; + } else { + fvar=0; + len++; + goto exit; + } + } + } + break; + case 'd': + if (!strncmp(vname,"day",3)) { + fvar=RtcTime.day_of_month; + goto exit; + } + break; + case 'g': + if (!strncmp(vname,"gtmp",4)) { + fvar=global_temperature; + goto exit; + } + if (!strncmp(vname,"ghum",4)) { + fvar=global_humidity; + goto exit; + } + if (!strncmp(vname,"gprs",4)) { + fvar=global_pressure; + goto exit; + } + if (!strncmp(vname,"gtopic",6)) { + if (sp) strlcpy(sp,Settings.mqtt_grptopic,glob_script_mem.max_ssize); + goto strexit; + } + break; + case 'h': + if (!strncmp(vname,"hours",5)) { + fvar=RtcTime.hour; + goto exit; + } + if (!strncmp(vname,"heap",4)) { + fvar=ESP.getFreeHeap(); + goto exit; + } + if (!strncmp(vname,"hn(",3)) { + lp=GetNumericResult(lp+3,OPER_EQU,&fvar,0); + if (fvar<0 || fvar>255) fvar=0; + lp++; + len=0; + if (sp) { + sprintf(sp,"%02x",(uint8_t)fvar); + } + goto strexit; + } + break; + case 'i': + if (!strncmp(vname,"int(",4)) { + lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0); + fvar=floor(fvar); + lp++; + len=0; + goto exit; + } + break; + case 'l': + if (!strncmp(vname,"loglvl",6)) { + fvar=glob_script_mem.script_loglevel; + tind->index=SCRIPT_LOGLEVEL; + exit_settable: + if (fp) *fp=fvar; + *vtype=NTYPE; + tind->bits.settable=1; + tind->bits.is_string=0; + return lp+len; + } + break; + case 'm': + if (!strncmp(vname,"med(",4)) { + float fvar1; + lp=GetNumericResult(lp+4,OPER_EQU,&fvar1,0); + SCRIPT_SKIP_SPACES + // arg2 + float fvar2; + lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); + fvar=DoMedian5(fvar1,fvar2); + lp++; + len=0; + goto exit; + } + if (!strncmp(vname,"micros",6)) { + fvar=micros(); + goto exit; + } + if (!strncmp(vname,"millis",6)) { + fvar=millis(); + goto exit; + } + if (!strncmp(vname,"mins",4)) { + fvar=RtcTime.minute; + goto exit; + } + if (!strncmp(vname,"month",5)) { + fvar=RtcTime.month; + goto exit; + } + if (!strncmp(vname,"mqttc",5)) { + if (rules_flag.mqtt_connected) { + rules_flag.mqtt_connected=0; + fvar=1; + } + goto exit; + } + if (!strncmp(vname,"mqttd",5)) { + if (rules_flag.mqtt_disconnected) { + rules_flag.mqtt_disconnected=0; + fvar=1; + } + goto exit; + } + if (!strncmp(vname,"mqtts",5)) { + fvar=!global_state.mqtt_down; + goto exit; + } + break; + case 'p': + if (!strncmp(vname,"pin[",4)) { + // raw pin level + GetNumericResult(vname+4,OPER_EQU,&fvar,0); + fvar=digitalRead((uint8_t)fvar); + // skip ] bracket + len++; + goto exit; + } + if (!strncmp(vname,"pn[",3)) { + GetNumericResult(vname+3,OPER_EQU,&fvar,0); + fvar=pin[(uint8_t)fvar]; + // skip ] bracket + len++; + goto exit; + } + if (!strncmp(vname,"pd[",3)) { + GetNumericResult(vname+3,OPER_EQU,&fvar,0); + uint8_t gpiopin=fvar; + for (uint8_t i=0;iindex=SCRIPT_TELEPERIOD; + goto exit_settable; + } + if (!strncmp(vname,"tinit",5)) { + if (rules_flag.time_init) { + rules_flag.time_init=0; + fvar=1; + } + goto exit; + } + if (!strncmp(vname,"tset",4)) { + if (rules_flag.time_set) { + rules_flag.time_set=0; + fvar=1; + } + goto exit; + } + if (!strncmp(vname,"tstamp",6)) { + if (sp) strlcpy(sp,GetDateAndTime(DT_LOCAL).c_str(),glob_script_mem.max_ssize); + goto strexit; + } + if (!strncmp(vname,"topic",5)) { + if (sp) strlcpy(sp,Settings.mqtt_topic,glob_script_mem.max_ssize); + goto strexit; + } + break; + case 'u': + if (!strncmp(vname,"uptime",6)) { + fvar=MinutesUptime(); + goto exit; + } + if (!strncmp(vname,"upsecs",6)) { + fvar=uptime; + goto exit; + } + if (!strncmp(vname,"upd[",4)) { + // var was updated + struct T_INDEX ind; + uint8_t vtype; + isvar(vname+4,&vtype,&ind,0,0,0); + if (!ind.bits.constant) { + if (!ind.bits.changed) { + fvar=0; + len++; + goto exit; + } else { + glob_script_mem.type[ind.index].bits.changed=0; + fvar=1; + len++; + goto exit; + } + } + goto notfound; + } + break; + case 'w': + if (!strncmp(vname,"wday",4)) { + fvar=RtcTime.day_of_week; + goto exit; + } + if (!strncmp(vname,"wific",5)) { + if (rules_flag.wifi_connected) { + rules_flag.wifi_connected=0; + fvar=1; + } + goto exit; + } + if (!strncmp(vname,"wifid",5)) { + if (rules_flag.wifi_disconnected) { + rules_flag.wifi_disconnected=0; + fvar=1; + } + goto exit; + } + if (!strncmp(vname,"wifis",5)) { + fvar=!global_state.wifi_down; + goto exit; + } + break; + case 'y': + if (!strncmp(vname,"year",4)) { + fvar=RtcTime.year; + goto exit; + } + break; + default: + break; + } + // nothing valid found +notfound: + if (fp) *fp=0; + *vtype=VAR_NV; + tind->index=VAR_NV; + glob_script_mem.var_not_found=1; + return lp; + // return constant numbers +exit: + if (fp) *fp=fvar; + *vtype=NUM_RES; + tind->bits.constant=1; + tind->bits.is_string=0; + return lp+len; + // return constant strings +strexit: + *vtype=STYPE; + tind->bits.constant=1; + tind->bits.is_string=1; + return lp+len; +} + + + +char *getop(char *lp, uint8_t *operand) { + switch (*lp) { + case '=': + if (*(lp+1)=='=') { + *operand=OPER_EQUEQU; + return lp+2; + } else { + *operand=OPER_EQU; + return lp+1; + } + break; + case '+': + if (*(lp+1)=='=') { + *operand=OPER_PLSEQU; + return lp+2; + } else { + *operand=OPER_PLS; + return lp+1; + } + break; + case '-': + if (*(lp+1)=='=') { + *operand=OPER_MINEQU; + return lp+2; + } else { + *operand=OPER_MIN; + return lp+1; + } + break; + case '*': + if (*(lp+1)=='=') { + *operand=OPER_MULEQU; + return lp+2; + } else { + *operand=OPER_MUL; + return lp+1; + } + break; + case '/': + if (*(lp+1)=='=') { + *operand=OPER_DIVEQU; + return lp+2; + } else { + *operand=OPER_DIV; + return lp+1; + } + break; + case '!': + if (*(lp+1)=='=') { + *operand=OPER_NOTEQU; + return lp+2; + } + break; + case '>': + if (*(lp+1)=='=') { + *operand=OPER_GRTEQU; + return lp+2; + } else { + *operand=OPER_GRT; + return lp+1; + + } + break; + case '<': + if (*(lp+1)=='=') { + *operand=OPER_LOWEQU; + return lp+2; + } else { + *operand=OPER_LOW; + return lp+1; + } + break; + case '%': + if (*(lp+1)=='=') { + *operand=OPER_PERCEQU; + return lp+2; + } else { + *operand=OPER_PERC; + return lp+1; + } + break; + case '^': + if (*(lp+1)=='=') { + *operand=OPER_XOREQU; + return lp+2; + } else { + *operand=OPER_XOR; + return lp+1; + } + break; + case '&': + if (*(lp+1)=='=') { + *operand=OPER_ANDEQU; + return lp+2; + } else { + *operand=OPER_AND; + return lp+1; + } + break; + case '|': + if (*(lp+1)=='=') { + *operand=OPER_OREQU; + return lp+2; + } else { + *operand=OPER_OR; + return lp+1; + } + break; + } + *operand=0; + return lp; +} + + +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_1) +// All version before core 2.4.2 +// https://github.com/esp8266/Arduino/issues/2557 +extern "C" { +#include + extern cont_t g_cont; +} +uint16_t GetStack(void) { + register uint32_t *sp asm("a1"); + return (4 * (sp - g_pcont.stack)); +} + +#else +extern "C" { +#include + extern cont_t* g_pcont; +} +uint16_t GetStack(void) { + register uint32_t *sp asm("a1"); + return (4 * (sp - g_pcont->stack)); +} +#endif + +char *GetStringResult(char *lp,uint8_t lastop,char *cp,JsonObject *jo) { + uint8_t operand=0; + uint8_t vtype; + char *slp; + struct T_INDEX ind; + char str[SCRIPT_MAXSSIZE],str1[SCRIPT_MAXSSIZE]; + while (1) { + lp=isvar(lp,&vtype,&ind,0,str1,jo); + switch (lastop) { + case OPER_EQU: + strlcpy(str,str1,sizeof(str)); + break; + case OPER_PLS: + strlcat(str,str1,sizeof(str)); + break; + } + slp=lp; + lp=getop(lp,&operand); + switch (operand) { + case OPER_EQUEQU: + case OPER_NOTEQU: + case OPER_LOW: + case OPER_LOWEQU: + case OPER_GRT: + case OPER_GRTEQU: + lp=slp; + strcpy(cp,str); + return lp; + break; + default: + break; + } + lastop=operand; + if (!operand) { + strcpy(cp,str); + return lp; + } + } +} + +char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo) { +uint8_t operand=0; +float fvar1,fvar; +char *slp; +uint8_t vtype; +struct T_INDEX ind; + while (1) { + // get 1. value + if (*lp=='(') { + lp++; + lp=GetNumericResult(lp,OPER_EQU,&fvar1,jo); + lp++; + //if (*lp==')') lp++; + } else { + lp=isvar(lp,&vtype,&ind,&fvar1,0,jo); + if (vtype!=NUM_RES && vtype&STYPE) { + // string type + glob_script_mem.glob_error=1; + } + } + switch (lastop) { + case OPER_EQU: + fvar=fvar1; + break; + case OPER_PLS: + fvar+=fvar1; + break; + case OPER_MIN: + fvar-=fvar1; + break; + case OPER_MUL: + fvar*=fvar1; + break; + case OPER_DIV: + fvar/=fvar1; + break; + case OPER_PERC: + fvar=fmod(fvar,fvar1); + break; + case OPER_XOR: + fvar=(uint32_t)fvar^(uint32_t)fvar1; + break; + case OPER_AND: + fvar=(uint32_t)fvar&(uint32_t)fvar1; + break; + case OPER_OR: + fvar=(uint32_t)fvar|(uint32_t)fvar1; + break; + default: + break; + } + slp=lp; + lp=getop(lp,&operand); + switch (operand) { + case OPER_EQUEQU: + case OPER_NOTEQU: + case OPER_LOW: + case OPER_LOWEQU: + case OPER_GRT: + case OPER_GRTEQU: + lp=slp; + *fp=fvar; + return lp; + break; + default: + break; + } + lastop=operand; + if (!operand) { + *fp=fvar; + return lp; + } + } +} + + +// replace vars in cmd %var% +void Replace_Cmd_Vars(char *srcbuf,char *dstbuf,uint16_t dstsize) { + char *cp; + uint16_t count; + uint8_t vtype; + float fvar; + cp=srcbuf; + struct T_INDEX ind; + char string[SCRIPT_MAXSSIZE]; + for (count=0;count=sizeof(str)) len=len>=sizeof(str); + strlcpy(str,cp,len); + toSLog(str); +} + +void toLogEOL(const char *s1,const char *str) { + if (!str) return; + uint8_t index=0; + char *cp=log_data; + strcpy(cp,s1); + cp+=strlen(s1); + while (*str) { + if (*str==SCRIPT_EOL) break; + *cp++=*str++; + } + *cp=0; + AddLog(LOG_LEVEL_INFO); +} + + +void toSLog(const char *str) { + if (!str) return; +#if SCRIPT_DEBUG>0 + while (*str) { + Serial.write(*str); + str++; + } +#endif +} + +#define IF_NEST 8 +// execute section of scripter +int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { + uint8_t vtype=0,sindex,xflg,floop=0,globvindex; + struct T_INDEX ind; + uint8_t operand,lastop,numeric=1,if_state[IF_NEST],if_result[IF_NEST],and_or,ifstck=0,s_ifstck=0; + if_state[ifstck]=0; + if_result[ifstck]=0; + char cmpstr[SCRIPT_MAXSSIZE]; + + if (tasm_cmd_activ) return 0; + + + float *dfvar,*cv_count,cv_max,cv_inc; + char *cv_ptr; + float fvar=0,fvar1,sysvar,swvar; + uint8_t section=0,sysv_type=0,swflg=0; + + if (!glob_script_mem.scriptptr) { + return -99; + } + + DynamicJsonBuffer jsonBuffer; // on heap + JsonObject &jobj=jsonBuffer.parseObject(js); + JsonObject *jo; + if (js) jo=&jobj; + else jo=0; + + char *lp=glob_script_mem.scriptptr; + + while (1) { + // check line + // skip leading spaces + startline: + SCRIPT_SKIP_SPACES + // skip empty line + SCRIPT_SKIP_EOL + // skip comment + if (*lp==';') goto next_line; + if (!*lp) break; + + if (section) { + // we are in section + if (*lp=='>') { + section=0; + break; + } + if (*lp=='#') { + section=0; + break; + } + glob_script_mem.var_not_found=0; + +#if SCRIPT_DEBUG>0 + char tbuff[128]; + sprintf(tbuff,"stack=%d,state=%d,cmpres=%d line: ",ifstck,if_state[ifstck],if_result[ifstck]); + toLogEOL(tbuff,lp); +#endif + + if (!strncmp(lp,"if",2)) { + lp+=2; + if (if_state[ifstck]>0) { + if (ifstck=2) { + lp+=5; + if_state[ifstck]=0; + if (ifstck>0) { + ifstck--; + } + s_ifstck=ifstck; // >>>>> + goto next_line; + } else if (!strncmp(lp,"or",2) && if_state[ifstck]==1) { + lp+=2; + and_or=1; + } else if (!strncmp(lp,"and",3) && if_state[ifstck]==1) { + lp+=3; + and_or=2; + } + + if (*lp=='{' && if_state[ifstck]==1) { + lp+=1; // then + if_state[ifstck]=2; + } else if (*lp=='{' && if_state[ifstck]==3) { + lp+=1; // after else + //if_state[ifstck]=3; + } else if (*lp=='}' && if_state[ifstck]>=2) { + lp++; // must check for else + char *slp=lp; + uint8_t iselse=0; + for (uint8_t count=0; count<8;count++) { + if (*lp=='}') { + // must be endif + break; + } + if (!strncmp(lp,"else",4)) { + // is before else, no endif + if_state[ifstck]=3; + lp+=4; + iselse=1; + break; + } + lp++; + } + if (!iselse) { + lp=slp; + // endif + if_state[ifstck]=0; + if (ifstck>0) { + ifstck--; + } + s_ifstck=ifstck; // >>>>> + } + } + + if (!strncmp(lp,"for",3)) { + // start for next loop, fetch 3 params + // simple implementation, zero loop count not supported + lp+=3; + SCRIPT_SKIP_SPACES + lp=isvar(lp,&vtype,&ind,0,0,0); + if ((vtype!=VAR_NV) && (vtype&STYPE)==0) { + // numeric var + uint8_t index=glob_script_mem.type[ind.index].index; + cv_count=&glob_script_mem.fvars[index]; + SCRIPT_SKIP_SPACES + lp=GetNumericResult(lp,OPER_EQU,cv_count,0); + SCRIPT_SKIP_SPACES + lp=GetNumericResult(lp,OPER_EQU,&cv_max,0); + SCRIPT_SKIP_SPACES + lp=GetNumericResult(lp,OPER_EQU,&cv_inc,0); + SCRIPT_SKIP_EOL + cv_ptr=lp; + floop=1; + } else { + // error + toLogEOL("for error",lp); + } + } else if (!strncmp(lp,"next",4) && floop>0) { + // for next loop + *cv_count+=cv_inc; + if (*cv_count<=cv_max) { + lp=cv_ptr; + } else { + lp+=4; + floop=0; + } + } + + if (!strncmp(lp,"switch",6)) { + lp+=6; + SCRIPT_SKIP_SPACES + lp=GetNumericResult(lp,OPER_EQU,&swvar,0); + swflg=1; + } else if (!strncmp(lp,"case",4) && swflg>0) { + lp+=4; + SCRIPT_SKIP_SPACES + float cvar; + lp=GetNumericResult(lp,OPER_EQU,&cvar,0); + if (swvar!=cvar) { + swflg=2; + } else { + swflg=1; + } + } else if (!strncmp(lp,"ends",4) && swflg>0) { + lp+=4; + swflg=0; + } + + if (swflg==2) goto next_line; + + + SCRIPT_SKIP_SPACES + //SCRIPT_SKIP_EOL + if (*lp==SCRIPT_EOL) { + goto next_line; + } + //toLogN(lp,16); + if (if_state[s_ifstck]==3 && if_result[s_ifstck]) goto next_line; + if (if_state[s_ifstck]==2 && !if_result[s_ifstck]) goto next_line; + + s_ifstck=ifstck; + + if (!strncmp(lp,"break",5)) { + if (floop) { + // should break loop + floop=0; + } else { + section=0; + } + break; + } else if (!strncmp(lp,"dprec",5)) { + lp+=5; + // number precision + glob_script_mem.script_dprec=atoi(lp); + goto next_line; + } else if (!strncmp(lp,"delay(",6)) { + lp+=5; + // delay + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + delay(fvar); + goto next_line; + } else if (!strncmp(lp,"spinm(",6)) { + lp+=6; + // set pin mode + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + int8_t pinnr=fvar; + SCRIPT_SKIP_SPACES + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + int8_t mode=fvar; + pinMode(pinnr,mode&1); + goto next_line; + } else if (!strncmp(lp,"spin(",5)) { + lp+=5; + // set pin mode + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + int8_t pinnr=fvar; + SCRIPT_SKIP_SPACES + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + int8_t mode=fvar; + digitalWrite(pinnr,mode&1); + goto next_line; + } else if (!strncmp(lp,"svars(",5)) { + lp+=5; + // save vars + Scripter_save_pvars(); + goto next_line; + } + + else if (!strncmp(lp,"=>",2)) { + // execute cmd + lp+=2; + SCRIPT_SKIP_SPACES + #define SCRIPT_CMDMEM 512 + char *cmdmem=(char*)malloc(SCRIPT_CMDMEM); + if (cmdmem) { + char *cmd=cmdmem; + short count; + for (count=0; countfvar1); + break; + case OPER_GRTEQU: + res=(*dfvar>=fvar1); + break; + default: + // error + break; + } + + if (!and_or) { + if_result[s_ifstck]=res; + } else if (and_or==1) { + if_result[s_ifstck]|=res; + } else { + if_result[s_ifstck]&=res; + } +#if SCRIPT_DEBUG>0 + char tbuff[128]; + sprintf(tbuff,"p1=%d,p2=%d,cmpres=%d line: ",(int32_t)*dfvar,(int32_t)fvar1,if_result[s_ifstck]); + toLogEOL(tbuff,lp); +#endif + + } else { + // compare string + char str[SCRIPT_MAXSSIZE]; + lp=GetStringResult(lp,OPER_EQU,str,0); + if (lastop==OPER_EQUEQU || lastop==OPER_NOTEQU) { + uint8_t res=0; + res=strcmp(cmpstr,str); + if (lastop==OPER_EQUEQU) res=!res; + if (!and_or) { + if_result[s_ifstck]=res; + } else if (and_or==1) { + if_result[s_ifstck]|=res; + } else { + if_result[s_ifstck]&=res; + } + } + } + SCRIPT_SKIP_SPACES + if (*lp=='{' && if_state[ifstck]==1) { + lp+=1; // then + if_state[ifstck]=2; + } + goto next_line; + } else { + if (numeric) { + char *slp=lp; + glob_script_mem.glob_error=0; + lp=GetNumericResult(lp,OPER_EQU,&fvar,jo); + if (glob_script_mem.glob_error==1) { + // mismatch was string, not number + // get the string and convert to number + lp=isvar(slp,&vtype,&ind,0,cmpstr,jo); + fvar=CharToDouble(cmpstr); + } + switch (lastop) { + case OPER_EQU: + if (glob_script_mem.var_not_found) { + if (!js) toLog("var not found\n"); + goto next_line; + } + *dfvar=fvar; + break; + case OPER_PLSEQU: + *dfvar+=fvar; + break; + case OPER_MINEQU: + *dfvar-=fvar; + break; + case OPER_MULEQU: + *dfvar*=fvar; + break; + case OPER_DIVEQU: + *dfvar/=fvar; + break; + case OPER_PERCEQU: + *dfvar=fmod(*dfvar,fvar); + break; + case OPER_ANDEQU: + *dfvar=(uint32_t)*dfvar&(uint32_t)fvar; + break; + case OPER_OREQU: + *dfvar=(uint32_t)*dfvar|(uint32_t)fvar; + break; + case OPER_XOREQU: + *dfvar=(uint32_t)*dfvar^(uint32_t)fvar; + break; + default: + // error + break; + } + // var was changed + glob_script_mem.type[globvindex].bits.changed=1; + if (glob_script_mem.type[globvindex].bits.is_filter) { + Set_MFilter(glob_script_mem.type[globvindex].index,*dfvar); + } + + if (sysv_type) { + switch (sysv_type) { + case SCRIPT_LOGLEVEL: + glob_script_mem.script_loglevel=*dfvar; + break; + case SCRIPT_TELEPERIOD: + if (*dfvar<10) *dfvar=10; + if (*dfvar>300) *dfvar=300; + Settings.tele_period=*dfvar; + break; + } + sysv_type=0; + } + + } else { + // string result + char str[SCRIPT_MAXSSIZE]; + char *slp=lp; + lp=GetStringResult(lp,OPER_EQU,str,jo); + if (!js && glob_script_mem.var_not_found) { + // mismatch + lp=GetNumericResult(slp,OPER_EQU,&fvar,0); + dtostrfd(fvar,6,str); + glob_script_mem.var_not_found=0; + } + + if (!glob_script_mem.var_not_found) { + // var was changed + glob_script_mem.type[globvindex].bits.changed=1; + if (lastop==OPER_EQU) { + strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize); + } else if (lastop==OPER_PLSEQU) { + strlcat(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize); + } + } + } + SCRIPT_SKIP_SPACES + if (*lp=='{' && if_state[ifstck]==3) { + lp+=1; // else + //if_state[ifstck]=3; + } + goto next_line; + } + } else { + // decode line + if (*lp=='>' && tlen==1) { + // called from cmdline + lp++; + section=1; + goto startline; + } + if (!strncmp(lp,type,tlen)) { + // found section + section=1; + // check for subroutine + if (*type=='#') { + // check for parameter + type+=tlen; + if (*type=='(') { + float fparam; + numeric=1; + glob_script_mem.glob_error=0; + GetNumericResult((char*)type,OPER_EQU,&fparam,0); + if (glob_script_mem.glob_error==1) { + // was string, not number + numeric=0; + // get the string + GetStringResult((char*)type+1,OPER_EQU,cmpstr,0); + } + lp+=tlen; + if (*lp=='(') { + // fetch destination + lp++; + lp=isvar(lp,&vtype,&ind,0,0,0); + if (vtype!=VAR_NV) { + // found variable as result + uint8_t index=glob_script_mem.type[ind.index].index; + if ((vtype&STYPE)==0) { + // numeric result + dfvar=&glob_script_mem.fvars[index]; + if (numeric) { + *dfvar=fparam; + } else { + // mismatch + *dfvar=CharToDouble(cmpstr); + } + } else { + // string result + sindex=index; + if (!numeric) { + strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),cmpstr,glob_script_mem.max_ssize); + } else { + // mismatch + dtostrfd(fparam,6,glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize)); + } + } + } + } + } + } + } + } + // next line + next_line: + if (*lp==SCRIPT_EOL) { + lp++; + } else { + lp = strchr(lp, SCRIPT_EOL); + if (!lp) break; + lp++; + } + } +} + +uint8_t script_xsns_index = 0; + + +void ScripterEvery100ms(void) +{ + if (Settings.rule_enabled && (uptime > 4)) { + mqtt_data[0] = '\0'; + uint16_t script_tele_period_save = tele_period; + tele_period = 2; + XsnsNextCall(FUNC_JSON_APPEND, script_xsns_index); + tele_period = script_tele_period_save; + if (strlen(mqtt_data)) { + mqtt_data[0] = '{'; + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + Run_Scripter(">T",2, mqtt_data); + } + } +} + +//mems[MAX_RULE_MEMS] is 50 bytes in 6.5 +// can hold 11 floats or floats + strings +// should report overflow later +void Scripter_save_pvars(void) { + uint32_t lptr=(uint32_t)Settings.mems[0]; + int16_t mlen=0; + lptr&=0xfffffffc; + float *fp=(float*)lptr; + fp++; + mlen+=sizeof(float); + struct T_INDEX *vtp=glob_script_mem.type; + for (uint8_t count=0; countMAX_RULE_MEMS*10) { + vtp[count].bits.is_permanent=0; + return; + } + *fp++=glob_script_mem.fvars[index]; + } + } + char *cp=(char*)fp; + for (uint8_t count=0; countMAX_RULE_MEMS*10) { + vtp[count].bits.is_permanent=0; + return; + } + strcpy(cp,sp); + cp+=slen+1; + } + } +} + +// works only with webserver +#ifdef USE_WEBSERVER + +#define WEB_HANDLE_SCRIPT "s10" +#define D_CONFIGURE_SCRIPT "Edit script" +#define D_RULEVARS "edit script" + +const char S_CONFIGURE_SCRIPT[] PROGMEM = D_CONFIGURE_SCRIPT; + +const char HTTP_BTN_MENU_RULES[] PROGMEM = + "

"; + + +const char HTTP_FORM_SCRIPT[] PROGMEM = + "
 " D_RULEVARS " " + "
"; + +const char HTTP_FORM_SCRIPT1[] PROGMEM = + "
script enable
" + "
"; + +void HandleScriptConfiguration(void) +{ + if (!HttpCheckPriviledgedAccess()) { return; } + + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_SCRIPT); + + if (WebServer->hasArg("save")) { + ScriptSaveSettings(); + HandleConfiguration(); + return; + } + + WSContentStart_P(S_CONFIGURE_SCRIPT); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_SCRIPT); + WSContentSend_P(HTTP_FORM_SCRIPT1,1,1,bitRead(Settings.rule_enabled,0) ? " checked" : "",1,1,MAX_RULE_SIZE*3); + + // script is to larg for WSContentSend_P + if (Settings.rules[0][0]) { + _WSContentSend(Settings.rules[0]); + } + WSContentSend_P(HTTP_FORM_SCRIPT1b); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentStop(); + } + + +void strrepl_inplace(char *str, const char *a, const char *b) { + for (char *cursor=str; (cursor=strstr(cursor,a)) != NULL;) { + memmove(cursor+strlen(b),cursor+strlen(a),strlen(cursor)-strlen(a)+1); + for (int i=0; b[i]!='\0'; i++) { + cursor[i] = b[i]; + } + cursor += strlen(b); + } +} + +#define MAX_SCRIPT_SIZE MAX_RULE_SIZE*3 + +void ScriptSaveSettings(void) { + + if (WebServer->hasArg("c1")) { + bitWrite(Settings.rule_enabled,0,1); + } else { + bitWrite(Settings.rule_enabled,0,0); + } + + String str = WebServer->arg("t1"); + + if (*str.c_str()) { +#if 1 + strrepl_inplace((char*)str.c_str(),"\r\n","\n"); + strrepl_inplace((char*)str.c_str(),"\r","\n"); +#else + str.replace("\r\n","\n"); + str.replace("\r","\n"); +#endif + strlcpy(Settings.rules[0],str.c_str(), MAX_RULE_SIZE*3); + } + + if (glob_script_mem.script_mem) { + Scripter_save_pvars(); + free(glob_script_mem.script_mem); + glob_script_mem.script_mem=0; + glob_script_mem.script_mem_size=0; + } + + if (bitRead(Settings.rule_enabled, 0)) { + int16_t res=Init_Scripter(Settings.rules[0]); + if (res) { + snprintf_P(log_data, sizeof(log_data), PSTR("script init error: %d"),res); + AddLog(LOG_LEVEL_INFO); + return; + } + Run_Scripter(">B",2,0); + } +} + +#endif + +void execute_script(char *script) { +char *svd_sp=glob_script_mem.scriptptr; + strcat(script,"\n#"); + glob_script_mem.scriptptr=script; + Run_Scripter(">",1,0); + glob_script_mem.scriptptr=svd_sp; + Scripter_save_pvars(); +} + +enum ScriptCommands { CMND_SCRIPT }; +const char kScriptCommands[] PROGMEM = "Script"; + +bool ScriptCommand(void) { + char command[CMDSZ]; + bool serviced = true; + uint8_t index = XdrvMailbox.index; + + int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kScriptCommands); + if (-1 == command_code) { + serviced = false; // Unknown command + } + else if ((CMND_SCRIPT == command_code) && (index > 0)) { + + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 2)) { + switch (XdrvMailbox.payload) { + case 0: // Off + case 1: // On + bitWrite(Settings.rule_enabled, index -1, XdrvMailbox.payload); + } + } else { + if ('>' == XdrvMailbox.data[0]) { + // execute script + for (uint8_t count=0; countB",2,0); + break; + case FUNC_EVERY_100_MSECOND: + ScripterEvery100ms(); + break; + case FUNC_EVERY_SECOND: + ScriptEverySecond(); + break; + case FUNC_COMMAND: + result = ScriptCommand(); + break; + case FUNC_SET_POWER: + case FUNC_RULES_PROCESS: + if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">E",2,mqtt_data); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_ADD_BUTTON: + WSContentSend_P(HTTP_BTN_MENU_RULES); + break; + case FUNC_WEB_ADD_HANDLER: + WebServer->on("/" WEB_HANDLE_SCRIPT, HandleScriptConfiguration); + break; +#endif // USE_WEBSERVER + case FUNC_SAVE_BEFORE_RESTART: + if (bitRead(Settings.rule_enabled, 0)) { + Run_Scripter(">R",2,0); + Scripter_save_pvars(); + } + break; + } + return result; +} + +#endif // not use RULES +#endif // USE_SCRIPT From 8ab60add17b1fe94340348ec4970d261c66092cd Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 18 May 2019 09:47:49 +0200 Subject: [PATCH 02/31] scripter.md moved --- sonoff/scripter.md => scripter.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename sonoff/scripter.md => scripter.md (100%) diff --git a/sonoff/scripter.md b/scripter.md similarity index 100% rename from sonoff/scripter.md rename to scripter.md From 6ed2f06193385861cdc6e9c044c4b8924ff71c2b Mon Sep 17 00:00:00 2001 From: gemu Date: Sat, 18 May 2019 10:50:18 +0200 Subject: [PATCH 03/31] Delete platformio.ini --- platformio.ini | 571 ------------------------------------------------- 1 file changed, 571 deletions(-) delete mode 100644 platformio.ini diff --git a/platformio.ini b/platformio.ini deleted file mode 100644 index 1d80293cb..000000000 --- a/platformio.ini +++ /dev/null @@ -1,571 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter, extra scripting -; Upload options: custom port, speed and extra flags -; Library options: dependencies, extra library storages -; -; Please visit documentation for the other options and examples -; http://docs.platformio.org/en/stable/projectconf.html - -[platformio] -src_dir = sonoff - -; *** Uncomment one of the lines below to build/upload only one environment -;env_default = sonoff -;env_default = sonoff-minimal -;env_default = sonoff-basic -;env_default = sonoff-classic -;env_default = sonoff-knx -;env_default = sonoff-sensors -;env_default = sonoff-display -;env_default = sonoff-BG -;env_default = sonoff-BR -;env_default = sonoff-CN -;env_default = sonoff-CZ -env_default = sonoff-DE -;env_default = sonoff-ES -;env_default = sonoff-FR -;env_default = sonoff-GR -;env_default = sonoff-HE -;env_default = sonoff-HU -;env_default = sonoff-IT -;env_default = sonoff-KO -;env_default = sonoff-NL -;env_default = sonoff-PL -;env_default = sonoff-PT -;env_default = sonoff-RU -;env_default = sonoff-SE -;env_default = sonoff-SK -;env_default = sonoff-TR -;env_default = sonoff-TW -;env_default = sonoff-UK - -[esp82xx_defaults] -build_flags = -D NDEBUG - -mtarget-align - -Wl,-Map,firmware.map - -[core_2_3_0] -; *** Esp8266 core for Arduino version 2.3.0 -platform = espressif8266@1.5.0 -build_flags = ${esp82xx_defaults.build_flags} - -Wl,-Tesp8266.flash.1m0.ld - -[core_2_4_2] -; *** Esp8266 core for Arduino version 2.4.2 -platform = espressif8266@1.8.0 -build_flags = ${esp82xx_defaults.build_flags} - -Wl,-Teagle.flash.1m0.ld - -lstdc++ -lsupc++ -; lwIP 1.4 -; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH -; lwIP 2 - Low Memory -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -; lwIP 2 - Higher Bandwidth (Tasmota default) - -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH - -DVTABLES_IN_FLASH - -[core_2_5_1] -; *** Esp8266 core for Arduino version 2.5.1 -platform = espressif8266@~2.1.1 -build_flags = ${esp82xx_defaults.build_flags} - -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 - -O2 - -DBEARSSL_SSL_BASIC -; nonos-sdk 22x - -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x -; nonos-sdk-pre-v3 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -; lwIP 1.4 -; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH -; lwIP 2 - Low Memory -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -; lwIP 2 - Higher Bandwidth -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -; lwIP 2 - Higher Bandwidth Low Memory no Features -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY_LOW_FLASH -; lwIP 2 - Higher Bandwidth no Features (Tasmota default) - -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH - -DVTABLES_IN_FLASH - -fno-exceptions - -lstdc++ - -[core_stage] -; *** Esp8266 core for Arduino version latest beta -platform = https://github.com/platformio/platform-espressif8266.git#feature/stage -build_flags = ${esp82xx_defaults.build_flags} - -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 - -O2 - -DBEARSSL_SSL_BASIC -; nonos-sdk 22x - -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x -; nonos-sdk-pre-v3 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -; lwIP 1.4 -; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH -; lwIP 2 - Low Memory -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY -; lwIP 2 - Higher Bandwidth -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -; lwIP 2 - Higher Bandwitdh Low Memory no Features -; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY_LOW_FLASH -; lwIP 2 - Higher Bandwitdh no Features - -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH -; VTABLES in Flash (default) - -DVTABLES_IN_FLASH -; VTABLES in Heap -; -DVTABLES_IN_DRAM -; VTABLES in IRAM -; -DVTABLES_IN_IRAM -; enable one option set -> No exception recommended -; No exception code in firmware - -fno-exceptions - -lstdc++ -; Exception code in firmware /needs much space! 90k -; -fexceptions -; -lstdc++-exc - -[core_active] -; Select one core set for platform and build_flags -;platform = ${core_2_3_0.platform} -;build_flags = ${core_2_3_0.build_flags} -;platform = ${core_2_4_2.platform} -;build_flags = ${core_2_4_2.build_flags} -platform = ${core_2_5_1.platform} -build_flags = ${core_2_5_1.build_flags} -;platform = ${core_stage.platform} -;build_flags = ${core_stage.build_flags} - -[common] -framework = arduino -board = esp01_1m -board_build.flash_mode = dout - -platform = ${core_active.platform} -build_flags = ${core_active.build_flags} -; -DFIRMWARE_CLASSIC -; -DFIRMWARE_MINIMAL -; -DFIRMWARE_SENSORS -; -DFIRMWARE_BASIC -; -DFIRMWARE_KNX_NO_EMULATION -; -DFIRMWARE_DISPLAYS -; -DUSE_CONFIG_OVERRIDE - -; *** Fix espressif8266@1.7.0 induced undesired all warnings -build_unflags = -Wall - -; set CPU frequency to 80MHz (default) or 160MHz -board_build.f_cpu = 80000000L -;board_build.f_cpu = 160000000L - -monitor_speed = 115200 -upload_speed = 115200 -upload_resetmethod = nodemcu - -; *** Upload Serial reset method for Wemos and NodeMCU -upload_port = COM5 -extra_scripts = pio/strip-floats.py - -; *** Upload file to OTA server using SCP -;upload_port = user@host:/path -;extra_scripts = pio/strip-floats.py, pio/sftp-uploader.py - -; *** Upload file to OTA server in folder api/arduino using HTTP -;upload_port = domus1:80/api/upload-arduino.php -;extra_scripts = pio/strip-floats.py, pio/http-uploader.py - -; ********************************************************************* - -[env:sonoff] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-minimal] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DFIRMWARE_MINIMAL -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-basic] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DFIRMWARE_BASIC -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-classic] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DFIRMWARE_CLASSIC -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-knx] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DFIRMWARE_KNX_NO_EMULATION -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-sensors] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DFIRMWARE_SENSORS -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-display] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DFIRMWARE_DISPLAYS -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-BG] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=bg-BG -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-BR] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=pt-BR -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-CN] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=zh-CN -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-CZ] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=cs-CZ -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-DE] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=de-DE -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-ES] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=es-ES -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-FR] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=fr-FR -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-GR] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=el-GR -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-HE] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=he-HE -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-HU] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=hu-HU -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-IT] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=it-IT -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-KO] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=ko-KO -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-NL] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=nl-NL -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-PL] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=pl-PL -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-PT] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=pt-PT -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-RU] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=ru-RU -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-SE] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=sv-SE -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-SK] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=sk-SK -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-TR] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=tr-TR -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-TW] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=zh-TW -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} - -[env:sonoff-UK] -platform = ${common.platform} -framework = ${common.framework} -board = ${common.board} -board_build.flash_mode = ${common.board_build.flash_mode} -board_build.f_cpu = ${common.board_build.f_cpu} -build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} -DMY_LANGUAGE=uk-UK -monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} -upload_resetmethod = ${common.upload_resetmethod} -upload_speed = ${common.upload_speed} -extra_scripts = ${common.extra_scripts} From 520643d17eef8ca0f016c9c3096ddb290e956bd1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 18 May 2019 12:21:09 +0200 Subject: [PATCH 04/31] Update my_user_config.h Default disable script for legacy reason --- sonoff/my_user_config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index a7d7a3602..3250573a4 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -288,10 +288,10 @@ #define USE_SUNRISE // Add support for Sunrise and sunset tools (+16k) #define SUNRISE_DAWN_ANGLE DAWN_NORMAL // Select desired Dawn Angle from (DAWN_NORMAL, DAWN_CIVIL, DAWN_NAUTIC, DAWN_ASTRONOMIC) -// -- Rules --------------------------------------- +// -- Rules or Scripts ---------------------------- +// Select none or only one of the below defines #define USE_RULES // Add support for rules (+4k4 code) -#undef USE_RULES -#define USE_SCRIPT +//#define USE_SCRIPT // Add support for script // #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem) // #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) From cb662637ebc7da2f692817e8d8c699553f69616a Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 18 May 2019 12:59:42 +0200 Subject: [PATCH 05/31] Create platformio.ini --- platformio.ini | 571 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100755 platformio.ini diff --git a/platformio.ini b/platformio.ini new file mode 100755 index 000000000..f721a496a --- /dev/null +++ b/platformio.ini @@ -0,0 +1,571 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter, extra scripting +; Upload options: custom port, speed and extra flags +; Library options: dependencies, extra library storages +; +; Please visit documentation for the other options and examples +; http://docs.platformio.org/en/stable/projectconf.html + +[platformio] +src_dir = sonoff + +; *** Uncomment one of the lines below to build/upload only one environment +;env_default = sonoff +;env_default = sonoff-minimal +;env_default = sonoff-basic +;env_default = sonoff-classic +;env_default = sonoff-knx +;env_default = sonoff-sensors +;env_default = sonoff-display +;env_default = sonoff-BG +;env_default = sonoff-BR +;env_default = sonoff-CN +;env_default = sonoff-CZ +;env_default = sonoff-DE +;env_default = sonoff-ES +;env_default = sonoff-FR +;env_default = sonoff-GR +;env_default = sonoff-HE +;env_default = sonoff-HU +;env_default = sonoff-IT +;env_default = sonoff-KO +;env_default = sonoff-NL +;env_default = sonoff-PL +;env_default = sonoff-PT +;env_default = sonoff-RU +;env_default = sonoff-SE +;env_default = sonoff-SK +;env_default = sonoff-TR +;env_default = sonoff-TW +;env_default = sonoff-UK + +[esp82xx_defaults] +build_flags = -D NDEBUG + -mtarget-align + -Wl,-Map,firmware.map + +[core_2_3_0] +; *** Esp8266 core for Arduino version 2.3.0 +platform = espressif8266@1.5.0 +build_flags = ${esp82xx_defaults.build_flags} + -Wl,-Tesp8266.flash.1m0.ld + +[core_2_4_2] +; *** Esp8266 core for Arduino version 2.4.2 +platform = espressif8266@1.8.0 +build_flags = ${esp82xx_defaults.build_flags} + -Wl,-Teagle.flash.1m0.ld + -lstdc++ -lsupc++ +; lwIP 1.4 +; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH +; lwIP 2 - Low Memory +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +; lwIP 2 - Higher Bandwidth (Tasmota default) + -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH + -DVTABLES_IN_FLASH + +[core_2_5_1] +; *** Esp8266 core for Arduino version 2.5.1 +platform = espressif8266@~2.1.1 +build_flags = ${esp82xx_defaults.build_flags} + -Wl,-Teagle.flash.1m.ld +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 + -O2 + -DBEARSSL_SSL_BASIC +; nonos-sdk 22x + -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x +; nonos-sdk-pre-v3 +; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 +; lwIP 1.4 +; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH +; lwIP 2 - Low Memory +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +; lwIP 2 - Higher Bandwidth +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH +; lwIP 2 - Higher Bandwidth Low Memory no Features +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY_LOW_FLASH +; lwIP 2 - Higher Bandwidth no Features (Tasmota default) + -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH + -DVTABLES_IN_FLASH + -fno-exceptions + -lstdc++ + +[core_stage] +; *** Esp8266 core for Arduino version latest beta +platform = https://github.com/platformio/platform-espressif8266.git#feature/stage +build_flags = ${esp82xx_defaults.build_flags} + -Wl,-Teagle.flash.1m.ld +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 + -O2 + -DBEARSSL_SSL_BASIC +; nonos-sdk 22x + -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x +; nonos-sdk-pre-v3 +; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 +; lwIP 1.4 +; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH +; lwIP 2 - Low Memory +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +; lwIP 2 - Higher Bandwidth +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH +; lwIP 2 - Higher Bandwitdh Low Memory no Features +; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY_LOW_FLASH +; lwIP 2 - Higher Bandwitdh no Features + -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH +; VTABLES in Flash (default) + -DVTABLES_IN_FLASH +; VTABLES in Heap +; -DVTABLES_IN_DRAM +; VTABLES in IRAM +; -DVTABLES_IN_IRAM +; enable one option set -> No exception recommended +; No exception code in firmware + -fno-exceptions + -lstdc++ +; Exception code in firmware /needs much space! 90k +; -fexceptions +; -lstdc++-exc + +[core_active] +; Select one core set for platform and build_flags +;platform = ${core_2_3_0.platform} +;build_flags = ${core_2_3_0.build_flags} +;platform = ${core_2_4_2.platform} +;build_flags = ${core_2_4_2.build_flags} +platform = ${core_2_5_1.platform} +build_flags = ${core_2_5_1.build_flags} +;platform = ${core_stage.platform} +;build_flags = ${core_stage.build_flags} + +[common] +framework = arduino +board = esp01_1m +board_build.flash_mode = dout + +platform = ${core_active.platform} +build_flags = ${core_active.build_flags} +; -DFIRMWARE_CLASSIC +; -DFIRMWARE_MINIMAL +; -DFIRMWARE_SENSORS +; -DFIRMWARE_BASIC +; -DFIRMWARE_KNX_NO_EMULATION +; -DFIRMWARE_DISPLAYS +; -DUSE_CONFIG_OVERRIDE + +; *** Fix espressif8266@1.7.0 induced undesired all warnings +build_unflags = -Wall + +; set CPU frequency to 80MHz (default) or 160MHz +board_build.f_cpu = 80000000L +;board_build.f_cpu = 160000000L + +monitor_speed = 115200 +upload_speed = 115200 +upload_resetmethod = nodemcu + +; *** Upload Serial reset method for Wemos and NodeMCU +upload_port = COM5 +extra_scripts = pio/strip-floats.py + +; *** Upload file to OTA server using SCP +;upload_port = user@host:/path +;extra_scripts = pio/strip-floats.py, pio/sftp-uploader.py + +; *** Upload file to OTA server in folder api/arduino using HTTP +;upload_port = domus1:80/api/upload-arduino.php +;extra_scripts = pio/strip-floats.py, pio/http-uploader.py + +; ********************************************************************* + +[env:sonoff] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-minimal] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DFIRMWARE_MINIMAL +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-basic] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DFIRMWARE_BASIC +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-classic] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DFIRMWARE_CLASSIC +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-knx] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DFIRMWARE_KNX_NO_EMULATION +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-sensors] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DFIRMWARE_SENSORS +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-display] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DFIRMWARE_DISPLAYS +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-BG] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=bg-BG +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-BR] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=pt-BR +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-CN] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=zh-CN +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-CZ] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=cs-CZ +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-DE] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=de-DE +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-ES] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=es-ES +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-FR] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=fr-FR +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-GR] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=el-GR +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-HE] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=he-HE +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-HU] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=hu-HU +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-IT] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=it-IT +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-KO] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=ko-KO +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-NL] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=nl-NL +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-PL] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=pl-PL +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-PT] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=pt-PT +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-RU] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=ru-RU +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-SE] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=sv-SE +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-SK] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=sk-SK +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-TR] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=tr-TR +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-TW] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=zh-TW +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} + +[env:sonoff-UK] +platform = ${common.platform} +framework = ${common.framework} +board = ${common.board} +board_build.flash_mode = ${common.board_build.flash_mode} +board_build.f_cpu = ${common.board_build.f_cpu} +build_unflags = ${common.build_unflags} +build_flags = ${common.build_flags} -DMY_LANGUAGE=uk-UK +monitor_speed = ${common.monitor_speed} +upload_port = ${common.upload_port} +upload_resetmethod = ${common.upload_resetmethod} +upload_speed = ${common.upload_speed} +extra_scripts = ${common.extra_scripts} From 1ff821d8866f6c2c95ad2dcfd4a97a97d1886eaa Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 18 May 2019 13:23:55 +0200 Subject: [PATCH 06/31] Update xsns_21_sgp30.ino --- sonoff/xsns_21_sgp30.ino | 105 +++++++++++++++++++++++++++++++-------- 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/sonoff/xsns_21_sgp30.ino b/sonoff/xsns_21_sgp30.ino index d8241f1d6..16c4657ad 100644 --- a/sonoff/xsns_21_sgp30.ino +++ b/sonoff/xsns_21_sgp30.ino @@ -34,65 +34,130 @@ Adafruit_SGP30 sgp; uint8_t sgp30_type = 0; uint8_t sgp30_ready = 0; -uint8_t sgp30_counter = 0; +float sgp30_abshum; /********************************************************************************************/ +void sgp30_Init(void) { + if (sgp.begin()) { + sgp30_type = 1; +// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Serialnumber 0x%04X-0x%04X-0x%04X"), sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]); +// AddLog(LOG_LEVEL_DEBUG); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "SGP30", 0x58); + AddLog(LOG_LEVEL_DEBUG); + } +} + +float sgp30_AbsoluteHumidity(float temperature, float humidity,char tempUnit) { + //taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ + //precision is about 0.1°C in range -30 to 35°C + //August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04) + //Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97) + //reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html + float temp = NAN; + const float mw = 18.01534; // molar mass of water g/mol + const float r = 8.31447215; // Universal gas constant J/mol/K + + if (isnan(temperature) || isnan(humidity) ) { + return NAN; + } + + if (tempUnit != 'C') { + temperature = (temperature - 32.0) * (5.0 / 9.0); /*conversion to [°C]*/ + } + + temp = pow(2.718281828, (17.67 * temperature) / (temperature + 243.5)); + + //return (6.112 * temp * humidity * 2.1674) / (273.15 + temperature); //simplified version + return (6.112 * temp * humidity * mw) / ((273.15 + temperature) * r); //long version +} + +#define SAVE_PERIOD 30 + void Sgp30Update(void) // Perform every second to ensure proper operation of the baseline compensation algorithm { sgp30_ready = 0; - if (!sgp30_type) { - if (sgp.begin()) { - sgp30_type = 1; -// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SGP: Serialnumber 0x%04X-0x%04X-0x%04X"), sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]); - AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "SGP30", 0x58); + if (!sgp.IAQmeasure() || !sgp30_type) { + // retry to init every 100 seconds + if (21 == (uptime %100)) { + sgp30_Init(); } - } else { - if (!sgp.IAQmeasure()) return; // Measurement failed - sgp30_counter++; - if (30 == sgp30_counter) { - sgp30_counter = 0; + return; // Measurement failed + } + if (global_update) { + // abs hum in mg/m3 + sgp30_abshum=sgp30_AbsoluteHumidity(global_temperature,global_humidity,TempUnit()); + sgp.setHumidity(sgp30_abshum*1000); + } + sgp30_ready = 1; - uint16_t TVOC_base; - uint16_t eCO2_base; + // these should normally be stored permanently and used for fast restart + if (!(uptime%SAVE_PERIOD)) { + // store settings every N seconds + uint16_t TVOC_base; + uint16_t eCO2_base; + + if (!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) return; // Failed to get baseline readings +// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Baseline values eCO2 0x%04X, TVOC 0x%04X"), eCO2_base, TVOC_base); +// AddLog(LOG_LEVEL_DEBUG); - if (!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) return; // Failed to get baseline readings -// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SGP: Baseline values eCO2 0x%04X, TVOC 0x%04X"), eCO2_base, TVOC_base); - } - sgp30_ready = 1; } } + +#ifdef USE_WEBSERVER const char HTTP_SNS_SGP30[] PROGMEM = "{s}SGP30 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" // {s} = , {m} = , {e} = "{s}SGP30 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; +const char HTTP_SNS_AHUM[] PROGMEM = "{s}SGP30 " "Abs Humidity" "{m}%s g/m3{e}"; +#endif + +#define D_JSON_AHUM "aHumidity" void Sgp30Show(bool json) { if (sgp30_ready) { + char abs_hum[33]; + + if (global_update) { + // has humidity + temperature + dtostrfd(sgp30_abshum,4,abs_hum); + } + if (json) { - ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), sgp.eCO2, sgp.TVOC); + ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d"), sgp.eCO2, sgp.TVOC); + if (global_update) { + ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum); + } + ResponseAppend_P(PSTR("}")); #ifdef USE_DOMOTICZ if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, sgp.eCO2); #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { WSContentSend_PD(HTTP_SNS_SGP30, sgp.eCO2, sgp.TVOC); + if (global_update) { + WSContentSend_PD(HTTP_SNS_AHUM, abs_hum); + } #endif } } } + /*********************************************************************************************\ * Interface \*********************************************************************************************/ -bool Xsns21(uint8_t function) +bool Xsns21(byte function) { bool result = false; if (i2c_flg) { switch (function) { + case FUNC_INIT: + sgp30_Init(); + break; case FUNC_EVERY_SECOND: Sgp30Update(); break; @@ -110,4 +175,4 @@ bool Xsns21(uint8_t function) } #endif // USE_SGP30 -#endif // USE_I2C \ No newline at end of file +#endif // USE_I2C From d40a9b96d702a2613cdaccf1059c088ebe088d9e Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 18 May 2019 13:27:46 +0200 Subject: [PATCH 07/31] Update xsns_21_sgp30.ino --- sonoff/xsns_21_sgp30.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_21_sgp30.ino b/sonoff/xsns_21_sgp30.ino index 16c4657ad..53b9a27db 100644 --- a/sonoff/xsns_21_sgp30.ino +++ b/sonoff/xsns_21_sgp30.ino @@ -149,7 +149,7 @@ void Sgp30Show(bool json) * Interface \*********************************************************************************************/ -bool Xsns21(byte function) +bool Xsns21(uint8_t function) { bool result = false; From dc3d0aea9447f4501d33bd08be7dd8c72e7e13a3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 18 May 2019 13:34:52 +0200 Subject: [PATCH 08/31] Add initial support for Scripts Add initial support for Scripts as replacement for Rules. Default disabled but can be enabled in my_user_config.h (#5689) --- sonoff/_changelog.ino | 1 + sonoff/my_user_config.h | 6 +++--- sonoff/support_features.ino | 6 ++++-- sonoff/xdrv_10_rules.ino | 2 ++ sonoff/xdrv_10_scripter.ino | 27 +++++++++++++++------------ 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 0071e38d1..4b394dc79 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,5 +1,6 @@ /* 6.5.0.11 20190517 * Add command SetOption64 0/1 to switch between "-" or "_" as sensor index separator impacting DS18X20, DHT, BMP and SHT3X sensor names (#5689) + * Add initial support for Scripts as replacement for Rules. Default disabled but can be enabled in my_user_config.h (#5689) * * 6.5.0.10 20190513 * Enable ADC0 by default in my_user_config.h (#5671) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 3250573a4..8da668960 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -288,10 +288,10 @@ #define USE_SUNRISE // Add support for Sunrise and sunset tools (+16k) #define SUNRISE_DAWN_ANGLE DAWN_NORMAL // Select desired Dawn Angle from (DAWN_NORMAL, DAWN_CIVIL, DAWN_NAUTIC, DAWN_ASTRONOMIC) -// -- Rules or Scripts ---------------------------- +// -- Rules or Script ---------------------------- // Select none or only one of the below defines -#define USE_RULES // Add support for rules (+4k4 code) -//#define USE_SCRIPT // Add support for script +#define USE_RULES // Add support for rules (+8k code) +//#define USE_SCRIPT // Add support for script (+15k code) // #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem) // #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index 1802f93b4..fef9766ea 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -103,7 +103,7 @@ void GetFeatures(void) #ifdef USE_TIMERS_WEB feature_drv1 |= 0x04000000; // xdrv_09_timers.ino #endif -#if defined(USE_RULES) || defined(USE_SCRIPT) +#ifdef USE_RULES feature_drv1 |= 0x08000000; // xdrv_10_rules.ino #endif #ifdef USE_KNX @@ -180,8 +180,10 @@ void GetFeatures(void) #ifdef USE_SM16716 feature_drv2 |= 0x00040000; // xdrv_04_light.ino #endif +#ifdef USE_SCRIPT + feature_drv2 |= 0x00080000; // xdrv_10_scripter.ino +#endif -// feature_drv2 |= 0x00080000; // feature_drv2 |= 0x00100000; // feature_drv2 |= 0x00200000; // feature_drv2 |= 0x00400000; diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 3c0d05d4a..142f3f234 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -18,6 +18,7 @@ */ #ifdef USE_RULES +#ifndef USE_SCRIPT /*********************************************************************************************\ * Rules based heavily on ESP Easy implementation * @@ -1287,4 +1288,5 @@ bool Xdrv10(uint8_t function) return result; } +#endif // Do not USE_SCRIPT #endif // USE_RULES \ No newline at end of file diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino index 72e6b6190..9edd27a9f 100644 --- a/sonoff/xdrv_10_scripter.ino +++ b/sonoff/xdrv_10_scripter.ino @@ -17,25 +17,28 @@ along with this program. If not, see . */ -// for doku see up to date doku in file scripter.md +#ifdef USE_SCRIPT +#ifndef USE_RULES +/*********************************************************************************************\ -// uses about 14,2 k of flash -// more stack could be needed for sendmail => -D CONT_STACKSIZE=4800 = +0.8k stack -0.8k heap -// +for documentation see up to date docs in file SCRIPTER.md -/* to doo +uses about 14,2 k of flash +more stack could be needed for sendmail => -D CONT_STACKSIZE=4800 = +0.8k stack -0.8k heap + + +to do optimize code for space -// remarks +remarks goal is fast execution time, minimal use of ram and intuitive syntax therefore => case sensitive cmds and vars (lowercase uses time and code) no math hierarchy (costs ram and execution time, better group with brackets, anyhow better readable for beginners) (will probably make math hierarchy an ifdefed option) keywords if then else endif, or, and are better readable for beginners (others may use {}) -*/ -#ifdef USE_SCRIPT -#ifndef USE_RULES + +\*********************************************************************************************/ #define XDRV_10 10 @@ -896,8 +899,8 @@ chknext: float fvar2; lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); lp++; - fvar=pow(fvar1,fvar2); - //fvar=FastPrecisePow(fvar1,fvar2); + //fvar=pow(fvar1,fvar2); + fvar=FastPrecisePow(fvar1,fvar2); len=0; goto exit; } @@ -2231,5 +2234,5 @@ bool Xdrv10(byte function) return result; } -#endif // not use RULES +#endif // Do not USE_RULES #endif // USE_SCRIPT From 22a4410280c9d00f7e1ee112ea403b5b8e642169 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 18 May 2019 14:16:29 +0200 Subject: [PATCH 09/31] update adafruit sgp30 lib --- .../.github/ISSUE_TEMPLATE.md | 0 .../.github/PULL_REQUEST_TEMPLATE.md | 0 .../.gitignore | 0 .../.travis.yml | 0 .../Adafruit_SGP30.cpp | 58 +++++++++++++------ .../Adafruit_SGP30.h | 1 + .../README.md | 0 .../examples/sgp30test/sgp30test.ino | 16 +++++ .../library.properties | 2 +- .../license.txt | 0 10 files changed, 59 insertions(+), 18 deletions(-) rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/.github/ISSUE_TEMPLATE.md (100%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/.github/PULL_REQUEST_TEMPLATE.md (100%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/.gitignore (100%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/.travis.yml (100%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/Adafruit_SGP30.cpp (83%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/Adafruit_SGP30.h (97%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/README.md (100%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/examples/sgp30test/sgp30test.ino (58%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/library.properties (95%) mode change 100644 => 100755 rename lib/{Adafruit_SGP30-1.0.0.13 => Adafruit_SGP30-1.0.3}/license.txt (100%) mode change 100644 => 100755 diff --git a/lib/Adafruit_SGP30-1.0.0.13/.github/ISSUE_TEMPLATE.md b/lib/Adafruit_SGP30-1.0.3/.github/ISSUE_TEMPLATE.md old mode 100644 new mode 100755 similarity index 100% rename from lib/Adafruit_SGP30-1.0.0.13/.github/ISSUE_TEMPLATE.md rename to lib/Adafruit_SGP30-1.0.3/.github/ISSUE_TEMPLATE.md diff --git a/lib/Adafruit_SGP30-1.0.0.13/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit_SGP30-1.0.3/.github/PULL_REQUEST_TEMPLATE.md old mode 100644 new mode 100755 similarity index 100% rename from lib/Adafruit_SGP30-1.0.0.13/.github/PULL_REQUEST_TEMPLATE.md rename to lib/Adafruit_SGP30-1.0.3/.github/PULL_REQUEST_TEMPLATE.md diff --git a/lib/Adafruit_SGP30-1.0.0.13/.gitignore b/lib/Adafruit_SGP30-1.0.3/.gitignore old mode 100644 new mode 100755 similarity index 100% rename from lib/Adafruit_SGP30-1.0.0.13/.gitignore rename to lib/Adafruit_SGP30-1.0.3/.gitignore diff --git a/lib/Adafruit_SGP30-1.0.0.13/.travis.yml b/lib/Adafruit_SGP30-1.0.3/.travis.yml old mode 100644 new mode 100755 similarity index 100% rename from lib/Adafruit_SGP30-1.0.0.13/.travis.yml rename to lib/Adafruit_SGP30-1.0.3/.travis.yml diff --git a/lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.cpp b/lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.cpp old mode 100644 new mode 100755 similarity index 83% rename from lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.cpp rename to lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.cpp index b2ccbe8da..ce6116863 --- a/lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.cpp +++ b/lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.cpp @@ -37,7 +37,7 @@ //#define I2C_DEBUG /**************************************************************************/ -/*! +/*! @brief Instantiates a new SGP30 class */ /**************************************************************************/ @@ -45,7 +45,7 @@ Adafruit_SGP30::Adafruit_SGP30() { } /**************************************************************************/ -/*! +/*! @brief Setups the hardware and detects a valid SGP30. Initializes I2C then reads the serialnumber and checks that we are talking to an SGP30 @param theWire Optional pointer to I2C interface, otherwise use Wire @@ -60,31 +60,32 @@ boolean Adafruit_SGP30::begin(TwoWire *theWire) { _i2c = theWire; } - _i2c->begin(); +// assume i2c initialized already to avoid resetting clock stretching +// _i2c->begin(); + - uint8_t command[2]; command[0] = 0x36; command[1] = 0x82; - if (! readWordFromCommand(command, 2, 10, serialnumber, 3)) + if (! readWordFromCommand(command, 2, 10, serialnumber, 3)) return false; uint16_t featureset; command[0] = 0x20; command[1] = 0x2F; - if (! readWordFromCommand(command, 2, 10, &featureset, 1)) + if (! readWordFromCommand(command, 2, 10, &featureset, 1)) return false; //Serial.print("Featureset 0x"); Serial.println(featureset, HEX); - if (featureset != SGP30_FEATURESET) + if (featureset != SGP30_FEATURESET) return false; - if (! IAQinit()) + if (! IAQinit()) return false; return true; } /**************************************************************************/ -/*! +/*! @brief Commands the sensor to begin the IAQ algorithm. Must be called after startup. @returns True if command completed successfully, false if something went wrong! */ @@ -97,7 +98,7 @@ boolean Adafruit_SGP30::IAQinit(void) { } /**************************************************************************/ -/*! +/*! @brief Commands the sensor to take a single eCO2/VOC measurement. Places results in {@link TVOC} and {@link eCO2} @returns True if command completed successfully, false if something went wrong! */ @@ -113,9 +114,9 @@ boolean Adafruit_SGP30::IAQmeasure(void) { eCO2 = reply[0]; return true; } - + /**************************************************************************/ -/*! +/*! @brief Request baseline calibration values for both CO2 and TVOC IAQ calculations. Places results in parameter memory locaitons. @param eco2_base A pointer to a uint16_t which we will save the calibration value to @param tvoc_base A pointer to a uint16_t which we will save the calibration value to @@ -135,7 +136,7 @@ boolean Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base) } /**************************************************************************/ -/*! +/*! @brief Assign baseline calibration values for both CO2 and TVOC IAQ calculations. @param eco2_base A uint16_t which we will save the calibration value from @param tvoc_base A uint16_t which we will save the calibration value from @@ -157,7 +158,30 @@ boolean Adafruit_SGP30::setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base) { } /**************************************************************************/ -/*! +/*! + @brief Set the absolute humidity value [mg/m^3] for compensation to increase precision of TVOC and eCO2. + @param absolute_humidity A uint32_t [mg/m^3] which we will be used for compensation. If the absolute humidity is set to zero, humidity compensation will be disabled. + @returns True if command completed successfully, false if something went wrong! +*/ +/**************************************************************************/ +boolean Adafruit_SGP30::setHumidity(uint32_t absolute_humidity) { + if (absolute_humidity > 256000) { + return false; + } + + uint16_t ah_scaled = (uint16_t)(((uint64_t)absolute_humidity * 256 * 16777) >> 24); + uint8_t command[5]; + command[0] = 0x20; + command[1] = 0x61; + command[2] = ah_scaled >> 8; + command[3] = ah_scaled & 0xFF; + command[4] = generateCRC(command+2, 2); + + return readWordFromCommand(command, 5, 10); +} + +/**************************************************************************/ +/*! @brief I2C low level interfacing */ /**************************************************************************/ @@ -186,16 +210,16 @@ boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLe delay(delayms); - if (readlen == 0) + if (readlen == 0) return true; uint8_t replylen = readlen * (SGP30_WORD_LEN +1); - if (_i2c->requestFrom(_i2caddr, replylen) != replylen) + if (_i2c->requestFrom(_i2caddr, replylen) != replylen) return false; uint8_t replybuffer[replylen]; #ifdef I2C_DEBUG Serial.print("\t\t<- "); -#endif +#endif for (uint8_t i=0; iread(); #ifdef I2C_DEBUG diff --git a/lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.h b/lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.h old mode 100644 new mode 100755 similarity index 97% rename from lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.h rename to lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.h index cc95fa54b..6f27aad04 --- a/lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.h +++ b/lib/Adafruit_SGP30-1.0.3/Adafruit_SGP30.h @@ -42,6 +42,7 @@ class Adafruit_SGP30 { boolean getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base); boolean setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base); + boolean setHumidity(uint32_t absolute_humidity); /** * The last measurement of the IAQ-calculated Total Volatile Organic Compounds in ppb. This value is set when you call {@link IAQmeasure()} diff --git a/lib/Adafruit_SGP30-1.0.0.13/README.md b/lib/Adafruit_SGP30-1.0.3/README.md old mode 100644 new mode 100755 similarity index 100% rename from lib/Adafruit_SGP30-1.0.0.13/README.md rename to lib/Adafruit_SGP30-1.0.3/README.md diff --git a/lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino b/lib/Adafruit_SGP30-1.0.3/examples/sgp30test/sgp30test.ino old mode 100644 new mode 100755 similarity index 58% rename from lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino rename to lib/Adafruit_SGP30-1.0.3/examples/sgp30test/sgp30test.ino index 6b9b3ea05..b7ff8a70c --- a/lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino +++ b/lib/Adafruit_SGP30-1.0.3/examples/sgp30test/sgp30test.ino @@ -3,6 +3,17 @@ Adafruit_SGP30 sgp; +/* return absolute humidity [mg/m^3] with approximation formula +* @param temperature [°C] +* @param humidity [%RH] +*/ +uint32_t getAbsoluteHumidity(float temperature, float humidity) { + // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15 + const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3] + const uint32_t absoluteHumidityScaled = static_cast(1000.0f * absoluteHumidity); // [mg/m^3] + return absoluteHumidityScaled; +} + void setup() { Serial.begin(9600); Serial.println("SGP30 test"); @@ -22,6 +33,11 @@ void setup() { int counter = 0; void loop() { + // If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humditiy compensation for the air quality signals + //float temperature = 22.1; // [°C] + //float humidity = 45.2; // [%RH] + //sgp.setHumidity(getAbsoluteHumidity(temperature, humidity)); + if (! sgp.IAQmeasure()) { Serial.println("Measurement failed"); return; diff --git a/lib/Adafruit_SGP30-1.0.0.13/library.properties b/lib/Adafruit_SGP30-1.0.3/library.properties old mode 100644 new mode 100755 similarity index 95% rename from lib/Adafruit_SGP30-1.0.0.13/library.properties rename to lib/Adafruit_SGP30-1.0.3/library.properties index 3520b4d38..6c86464d1 --- a/lib/Adafruit_SGP30-1.0.0.13/library.properties +++ b/lib/Adafruit_SGP30-1.0.3/library.properties @@ -1,5 +1,5 @@ name=Adafruit SGP30 Sensor -version=1.0.2 +version=1.0.3 author=Adafruit maintainer=Adafruit sentence=This is an Arduino library for the Adafruit SGP30 Gas / Air Quality Sensor diff --git a/lib/Adafruit_SGP30-1.0.0.13/license.txt b/lib/Adafruit_SGP30-1.0.3/license.txt old mode 100644 new mode 100755 similarity index 100% rename from lib/Adafruit_SGP30-1.0.0.13/license.txt rename to lib/Adafruit_SGP30-1.0.3/license.txt From a866e610bd68f512c42a5a793be0836097c4fd91 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sat, 18 May 2019 14:21:43 +0200 Subject: [PATCH 10/31] select pow function --- sonoff/xsns_21_sgp30.ino | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sonoff/xsns_21_sgp30.ino b/sonoff/xsns_21_sgp30.ino index 53b9a27db..27d1a43f9 100644 --- a/sonoff/xsns_21_sgp30.ino +++ b/sonoff/xsns_21_sgp30.ino @@ -48,6 +48,9 @@ void sgp30_Init(void) { } } +//#define POW_FUNC pow +#define POW_FUNC FastPrecisePow + float sgp30_AbsoluteHumidity(float temperature, float humidity,char tempUnit) { //taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ //precision is about 0.1°C in range -30 to 35°C @@ -66,7 +69,9 @@ float sgp30_AbsoluteHumidity(float temperature, float humidity,char tempUnit) { temperature = (temperature - 32.0) * (5.0 / 9.0); /*conversion to [°C]*/ } - temp = pow(2.718281828, (17.67 * temperature) / (temperature + 243.5)); + temp = POW_FUNC(2.718281828, (17.67 * temperature) / (temperature + 243.5)); + + //return (6.112 * temp * humidity * 2.1674) / (273.15 + temperature); //simplified version return (6.112 * temp * humidity * mw) / ((273.15 + temperature) * r); //long version From 3c13310664e7088233a8db66674fb5de11265879 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 18 May 2019 15:59:40 +0200 Subject: [PATCH 11/31] Replace powf() with FastPrecisePow(), saves 4KB of code --- sonoff/my_user_config.h | 2 +- sonoff/xdrv_04_light.ino | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 8da668960..164dbca0c 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -275,7 +275,7 @@ #define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem) #define WEB_PORT 80 // Web server Port for User and Admin mode #define WEB_USERNAME "admin" // Web server Admin mode user name - #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+22k code, +2k mem) + #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+18k code, +2k mem) // -- mDNS ---------------------------------------- #define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index c9bce585e..391702b52 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -716,6 +716,12 @@ void LightStateClass::HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t * if (r_b) *r_b = b; } +#define POW FastPrecisePowf + +float FastPrecisePowf(float a, float b) { + return (float) FastPrecisePow(a,b); +} + void LightStateClass::RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y) { float x = 0.31271f; // default medium white float y = 0.32902f; @@ -726,9 +732,9 @@ void LightStateClass::RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float b = (float)i_b / 255.0f; // https://gist.github.com/popcorn245/30afa0f98eea1c2fd34d // Gamma correction - r = (r > 0.04045f) ? powf((r + 0.055f) / (1.0f + 0.055f), 2.4f) : (r / 12.92f); - g = (g > 0.04045f) ? powf((g + 0.055f) / (1.0f + 0.055f), 2.4f) : (g / 12.92f); - b = (b > 0.04045f) ? powf((b + 0.055f) / (1.0f + 0.055f), 2.4f) : (b / 12.92f); + r = (r > 0.04045f) ? POW((r + 0.055f) / (1.0f + 0.055f), 2.4f) : (r / 12.92f); + g = (g > 0.04045f) ? POW((g + 0.055f) / (1.0f + 0.055f), 2.4f) : (g / 12.92f); + b = (b > 0.04045f) ? POW((b + 0.055f) / (1.0f + 0.055f), 2.4f) : (b / 12.92f); // conversion to X, Y, Z // Y is also the Luminance @@ -762,9 +768,9 @@ void LightStateClass::XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_ r = r / max; // normalize to max == 1.0 g = g / max; b = b / max; - r = (r <= 0.0031308f) ? 12.92f * r : 1.055f * powf(r, (1.0f / 2.4f)) - 0.055f; - g = (g <= 0.0031308f) ? 12.92f * g : 1.055f * powf(g, (1.0f / 2.4f)) - 0.055f; - b = (b <= 0.0031308f) ? 12.92f * b : 1.055f * powf(b, (1.0f / 2.4f)) - 0.055f; + r = (r <= 0.0031308f) ? 12.92f * r : 1.055f * POW(r, (1.0f / 2.4f)) - 0.055f; + g = (g <= 0.0031308f) ? 12.92f * g : 1.055f * POW(g, (1.0f / 2.4f)) - 0.055f; + b = (b <= 0.0031308f) ? 12.92f * b : 1.055f * POW(b, (1.0f / 2.4f)) - 0.055f; // // AddLog_P2(LOG_LEVEL_DEBUG_MORE, "XyToRgb XZ (%s %s) rgb (%s %s %s)", // String(X,5).c_str(), String(Z,5).c_str(), From 866c9c4b1f7dbc6d8af6a45fd87627ac2faafc9d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 18 May 2019 16:17:05 +0200 Subject: [PATCH 12/31] Clean up code and functionality Clean up code and functionality --- sonoff/xnrg_01_hlw8012.ino | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sonoff/xnrg_01_hlw8012.ino b/sonoff/xnrg_01_hlw8012.ino index 67eab0fee..d2da0e3a7 100644 --- a/sonoff/xnrg_01_hlw8012.ino +++ b/sonoff/xnrg_01_hlw8012.ino @@ -233,26 +233,27 @@ void HlwSnsInit(void) void HlwDrvInit(void) { if (!energy_flg) { - hlw_model_type = 0; // HLW8012 + hlw_model_type = 0; // HLW8012 if (pin[GPIO_HJL_CF] < 99) { pin[GPIO_HLW_CF] = pin[GPIO_HJL_CF]; pin[GPIO_HJL_CF] = 99; - hlw_model_type = 1; // HJL-01/BL0937 + hlw_model_type = 1; // HJL-01/BL0937 } - if (pin[GPIO_HLW_CF] < 99) { // HLW8012 or HJL-01 based device + if (pin[GPIO_HLW_CF] < 99) { // HLW8012 or HJL-01 based device Power monitor - hlw_ui_flag = 1; // Voltage on high + hlw_ui_flag = 1; // Voltage on high if (pin[GPIO_NRG_SEL_INV] < 99) { pin[GPIO_NRG_SEL] = pin[GPIO_NRG_SEL_INV]; pin[GPIO_NRG_SEL_INV] = 99; - hlw_ui_flag = 0; // Voltage on low + hlw_ui_flag = 0; // Voltage on low } - if (99 == pin[GPIO_NRG_SEL]) { - energy_current_available = false; - } - if (99 == pin[GPIO_NRG_CF1]) { + if (pin[GPIO_NRG_CF1] < 99) { // Voltage and/or Current monitor + if (99 == pin[GPIO_NRG_SEL]) { // Voltage and/or Current selector + energy_current_available = false; // Assume Voltage + } + } else { energy_current_available = false; energy_voltage_available = false; } From 5515a97be6586c0a318dd012c2277d985b74371e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 18 May 2019 16:54:29 +0200 Subject: [PATCH 13/31] Provide function FastPrecisePowf Provide function FastPrecisePowf --- sonoff/support.ino | 6 ++++++ sonoff/xdrv_04_light.ino | 4 ---- sonoff/xsns_27_apds9960.ino | 12 +----------- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/sonoff/support.ino b/sonoff/support.ino index 317d25065..c10c81eb0 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -674,6 +674,12 @@ double FastPrecisePow(double a, double b) return r * u.d; } +float FastPrecisePowf(const float x, const float y) +{ +// return (float)(pow((double)x, (double)y)); + return (float)FastPrecisePow(x, y); +} + uint32_t SqrtInt(uint32_t num) { if (num <= 1) { diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index 391702b52..a25b63d0e 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -718,10 +718,6 @@ void LightStateClass::HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t * #define POW FastPrecisePowf -float FastPrecisePowf(float a, float b) { - return (float) FastPrecisePow(a,b); -} - void LightStateClass::RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y) { float x = 0.31271f; // default medium white float y = 0.32902f; diff --git a/sonoff/xsns_27_apds9960.ino b/sonoff/xsns_27_apds9960.ino index 7594a5322..909bb607e 100644 --- a/sonoff/xsns_27_apds9960.ino +++ b/sonoff/xsns_27_apds9960.ino @@ -374,21 +374,11 @@ void calculateColorTemperature(void) n = (xc - 0.3320F) / (0.1858F - yc); /* Calculate the final CCT */ - color_data.cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F; + color_data.cct = (449.0F * FastPrecisePowf(n, 3)) + (3525.0F * FastPrecisePowf(n, 2)) + (6823.3F * n) + 5520.33F; return; } -/** -* Taken from the Adafruit-Library -* @brief Implements missing powf function -*/ - -float powf(const float x, const float y) -{ - return (float)(pow((double)x, (double)y)); -} - /******************************************************************************* * Getters and setters for register values ******************************************************************************/ From 052cfbc11de1fc6d2fc0d6723a6ec2643770ff6d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 18 May 2019 18:24:17 +0200 Subject: [PATCH 14/31] Save 1k code space by using TaylorSeries log function Save 1k code space by using TaylorSeries log function --- sonoff/support.ino | 18 ++++++++++++++++++ sonoff/xsns_02_analog.ino | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/sonoff/support.ino b/sonoff/support.ino index c10c81eb0..7c0bbb1a2 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -680,6 +680,24 @@ float FastPrecisePowf(const float x, const float y) return (float)FastPrecisePow(x, y); } +double TaylorLog(double x) +{ + // https://stackoverflow.com/questions/46879166/finding-the-natural-logarithm-of-a-number-using-taylor-series-in-c + + double z = (x + 1) / (x - 1); // We start from power -1, to make sure we get the right power in each iteration; + double step = ((x - 1) * (x - 1)) / ((x + 1) * (x + 1)); // Store step to not have to calculate it each time + double totalValue = 0; + double powe = 1; + double y; + for (int count = 0; count < 10; count++) { + z *= step; + y = (1 / powe) * z; + totalValue = totalValue + y; + powe = powe + 2; + } + return 2 * totalValue; +} + uint32_t SqrtInt(uint32_t num) { if (num <= 1) { diff --git a/sonoff/xsns_02_analog.ino b/sonoff/xsns_02_analog.ino index e93377165..85560e3d3 100644 --- a/sonoff/xsns_02_analog.ino +++ b/sonoff/xsns_02_analog.ino @@ -100,7 +100,7 @@ void AdcEverySecond(void) int adc = AdcRead(2); // Steinhart-Hart equation for thermistor as temperature sensor double Rt = (adc * ANALOG_NTC_BRIDGE_RESISTANCE) / (1024.0 * ANALOG_V33 - (double)adc); - double T = ANALOG_NTC_B_COEFFICIENT / (ANALOG_NTC_B_COEFFICIENT / ANALOG_T0 + log(Rt / ANALOG_NTC_RESISTANCE)); + double T = ANALOG_NTC_B_COEFFICIENT / (ANALOG_NTC_B_COEFFICIENT / ANALOG_T0 + TaylorLog(Rt / ANALOG_NTC_RESISTANCE)); adc_temp = ConvertTemp(TO_CELSIUS(T)); } } From d6d56618dc4b964c7556244e794706b9414cd88c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 18 May 2019 18:40:13 +0200 Subject: [PATCH 15/31] Add range test Add range test --- sonoff/support.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonoff/support.ino b/sonoff/support.ino index 7c0bbb1a2..65ca62d7e 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -684,12 +684,13 @@ double TaylorLog(double x) { // https://stackoverflow.com/questions/46879166/finding-the-natural-logarithm-of-a-number-using-taylor-series-in-c + if (x <= 0.0) { return NAN; } double z = (x + 1) / (x - 1); // We start from power -1, to make sure we get the right power in each iteration; double step = ((x - 1) * (x - 1)) / ((x + 1) * (x + 1)); // Store step to not have to calculate it each time double totalValue = 0; double powe = 1; double y; - for (int count = 0; count < 10; count++) { + for (int count = 0; count < 10; count++) { // Experimental number of 10 iterations z *= step; y = (1 / powe) * z; totalValue = totalValue + y; From 292efcc358f8f8f6093a87dfbd632855be70073e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 18 May 2019 19:43:04 +0200 Subject: [PATCH 16/31] Update support.ino Add optional debug info --- sonoff/support.ino | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sonoff/support.ino b/sonoff/support.ino index 65ca62d7e..da79be0e0 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -696,7 +696,18 @@ double TaylorLog(double x) totalValue = totalValue + y; powe = powe + 2; } - return 2 * totalValue; + totalValue *= 2; +/* + char logxs[33]; + dtostrfd(x, 8, logxs); + double log1 = log(x); + char log1s[33]; + dtostrfd(log1, 8, log1s); + char log2s[33]; + dtostrfd(totalValue, 8, log2s); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("input %s, log %s, taylor %s"), logxs, log1s, log2s); +*/ + return totalValue; } uint32_t SqrtInt(uint32_t num) From ef9f0f64537cdc6098659f5435f6ea23b1cdd0dd Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 19 May 2019 12:07:20 +0200 Subject: [PATCH 17/31] Fix exception 28 due to regression from 6.5.0.1 (#5822) Fix exception 28 due to regression from 6.5.0.1 (#5822) --- sonoff/xsns_17_senseair.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/xsns_17_senseair.ino b/sonoff/xsns_17_senseair.ino index 1cf69d23d..ebc440ec1 100644 --- a/sonoff/xsns_17_senseair.ino +++ b/sonoff/xsns_17_senseair.ino @@ -149,9 +149,9 @@ void SenseairShow(bool json) GetTextIndexed(senseair_types, sizeof(senseair_types), senseair_type -1, kSenseairTypes); if (json) { - ResponseAppend_P(PSTR("%s,\"%s\":{\"" D_JSON_CO2 "\":%d"), senseair_types, senseair_co2); + ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_CO2 "\":%d"), senseair_types, senseair_co2); if (senseair_type != 2) { - ResponseAppend_P(PSTR("%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s"), temperature, humidity); + ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s"), temperature, humidity); } ResponseJsonEnd(); #ifdef USE_DOMOTICZ From 8c132bd0ff26e062894d3488c1f76742c2f232d1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 19 May 2019 12:42:10 +0200 Subject: [PATCH 18/31] Add rule System#Save executed just before a planned restart Add rule System#Save executed just before a planned restart --- sonoff/_changelog.ino | 1 + sonoff/xdrv_10_rules.ino | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 4b394dc79..bdc84b6ea 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.5.0.11 20190517 * Add command SetOption64 0/1 to switch between "-" or "_" as sensor index separator impacting DS18X20, DHT, BMP and SHT3X sensor names (#5689) * Add initial support for Scripts as replacement for Rules. Default disabled but can be enabled in my_user_config.h (#5689) + * Add rule System#Save executed just before a planned restart * * 6.5.0.10 20190513 * Enable ADC0 by default in my_user_config.h (#5671) diff --git a/sonoff/xdrv_10_rules.ino b/sonoff/xdrv_10_rules.ino index 142f3f234..7b3e4d316 100644 --- a/sonoff/xdrv_10_rules.ino +++ b/sonoff/xdrv_10_rules.ino @@ -587,6 +587,16 @@ void RulesEverySecond(void) } } +void RulesSaveBeforeRestart(void) +{ + if (Settings.rule_enabled) { // Any rule enabled + char json_event[32]; + + strncpy_P(json_event, PSTR("{\"System\":{\"Save\":1}}"), sizeof(json_event)); + RulesProcessEvent(json_event); + } +} + void RulesSetPower(void) { rules_new_power = XdrvMailbox.index; @@ -1279,6 +1289,9 @@ bool Xdrv10(uint8_t function) case FUNC_RULES_PROCESS: result = RulesProcess(); break; + case FUNC_SAVE_BEFORE_RESTART: + RulesSaveBeforeRestart(); + break; #ifdef SUPPORT_MQTT_EVENT case FUNC_MQTT_DATA: result = RulesMqttData(); From 25feabb92116a6a7e421aafa1750bb2e669d3356 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 19 May 2019 14:59:07 +0200 Subject: [PATCH 19/31] Fix Script and Rule System#Save Fix Script and Rule System#Save --- sonoff/settings.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 4fee5e8cc..a8445b232 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -444,6 +444,7 @@ void SettingsSaveAll(void) Settings.power = 0; } XsnsCall(FUNC_SAVE_BEFORE_RESTART); + XdrvCall(FUNC_SAVE_BEFORE_RESTART); #ifdef USE_EEPROM EepromCommit(); #endif From 9c0bd2a6653e510b6aeb3bc2bfa7d87302ded5f7 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 19 May 2019 17:49:00 +0200 Subject: [PATCH 20/31] Add HX711 weight restore after controlled restart or after power restore just before executing command Sensor34 7 (#5367, #5786) Add HX711 weight restore after controlled restart or after power restore just before executing command Sensor34 7 (#5367, #5786) --- sonoff/_changelog.ino | 1 + sonoff/settings.h | 2 +- sonoff/xsns_34_hx711.ino | 40 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index bdc84b6ea..815fc3374 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -2,6 +2,7 @@ * Add command SetOption64 0/1 to switch between "-" or "_" as sensor index separator impacting DS18X20, DHT, BMP and SHT3X sensor names (#5689) * Add initial support for Scripts as replacement for Rules. Default disabled but can be enabled in my_user_config.h (#5689) * Add rule System#Save executed just before a planned restart + * Add HX711 weight restore after controlled restart or after power restore just before executing command Sensor34 7 (#5367, #5786) * * 6.5.0.10 20190513 * Enable ADC0 by default in my_user_config.h (#5671) diff --git a/sonoff/settings.h b/sonoff/settings.h index c08c3e041..199c85f62 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -345,7 +345,7 @@ struct SYSCFG { uint16_t weight_max; // 7BE Total max weight in kilogram unsigned long weight_reference; // 7C0 Reference weight in gram unsigned long weight_calibration; // 7C4 - unsigned long energy_frequency_calibration; // 7C8 + unsigned long energy_frequency_calibration; // 7C8 also used by HX711 to save last weight uint16_t web_refresh; // 7CC char mems[MAX_RULE_MEMS][10]; // 7CE char rules[MAX_RULE_SETS][MAX_RULE_SIZE]; // 800 uses 512 bytes in v5.12.0m, 3 x 512 bytes in v5.14.0b diff --git a/sonoff/xsns_34_hx711.ino b/sonoff/xsns_34_hx711.ino index c1fd9c20e..4f1742943 100644 --- a/sonoff/xsns_34_hx711.ino +++ b/sonoff/xsns_34_hx711.ino @@ -62,6 +62,7 @@ enum HxCalibrationSteps { HX_CAL_END, HX_CAL_LIMBO, HX_CAL_FINISH, HX_CAL_FAIL, const char kHxCalibrationStates[] PROGMEM = D_HX_CAL_FAIL "|" D_HX_CAL_DONE "|" D_HX_CAL_REFERENCE "|" D_HX_CAL_REMOVE; long hx_weight = 0; +long hx_last_weight = 0; long hx_sum_weight = 0; long hx_offset = 0; long hx_scale = 1; @@ -116,11 +117,18 @@ long HxRead() /*********************************************************************************************/ -void HxReset(void) +void HxResetPart(void) { hx_tare_flg = true; hx_sum_weight = 0; hx_sample_count = 0; + hx_last_weight = 0; +} + +void HxReset(void) +{ + HxResetPart(); + Settings.energy_frequency_calibration = 0; } void HxCalibrationStateTextJson(uint8_t msg_id) @@ -147,6 +155,7 @@ void HxCalibrationStateTextJson(uint8_t msg_id) * Sensor34 5 - Set max weight * Sensor34 6 - Show item weigth in decigram * Sensor34 6 - Set item weight + * Sensor34 7 - Save current weight to be used as start weight on restart \*********************************************************************************************/ bool HxCommand(void) @@ -199,6 +208,10 @@ bool HxCommand(void) } show_parms = true; break; + case 7: // WeightSave + Settings.energy_frequency_calibration = hx_weight; + Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_34, D_JSON_DONE); + break; default: serviced = false; } @@ -238,8 +251,7 @@ void HxInit(void) if (!Settings.weight_reference) { Settings.weight_reference = HX_REFERENCE; } hx_scale = Settings.weight_calibration; HxRead(); - HxReset(); - + HxResetPart(); hx_type = 1; } } @@ -254,7 +266,16 @@ void HxEvery100mSecond(void) long average = hx_sum_weight / hx_sample_count; // grams long value = average - hx_offset; // grams hx_weight = value / hx_scale; // grams - if (hx_weight < 0) { hx_weight = 0; } + if (hx_weight < 0) { + if (Settings.energy_frequency_calibration) { + long difference = Settings.energy_frequency_calibration + hx_weight; + hx_last_weight = difference; + if (difference < 0) { HxReset(); } // Cancel last weight as there seems to be no more weight on the scale + } + hx_weight = 0; + } else { + hx_last_weight = Settings.energy_frequency_calibration; + } if (hx_tare_flg) { hx_tare_flg = false; @@ -313,6 +334,8 @@ void HxEvery100mSecond(void) if (!hx_calibrate_timer) { hx_calibrate_step = HX_CAL_END; // End of calibration } + } else { + hx_weight += hx_last_weight; // grams } hx_sum_weight = 0; @@ -320,6 +343,12 @@ void HxEvery100mSecond(void) } } +void HxSaveBeforeRestart() +{ + Settings.energy_frequency_calibration = hx_weight; + hx_sample_count = HX_SAMPLES +1; // Stop updating hx_weight +} + #ifdef USE_WEBSERVER const char HTTP_HX711_WEIGHT[] PROGMEM = "{s}HX711 " D_WEIGHT "{m}%s " D_UNIT_KILOGRAM "{e}"; // {s} = , {m} = , {e} = @@ -484,6 +513,9 @@ bool Xsns34(uint8_t function) case FUNC_JSON_APPEND: HxShow(1); break; + case FUNC_SAVE_BEFORE_RESTART: + HxSaveBeforeRestart(); + break; #ifdef USE_WEBSERVER case FUNC_WEB_SENSOR: HxShow(0); From 0e518084d7a57df3bb8cf72dc31800a505e5e03e Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Mon, 20 May 2019 08:52:05 +0200 Subject: [PATCH 21/31] Fix CSE7766 Sensor invalid energy load steps prevention fixes PR #5793 solution which can async (load overflow) forever until device restart --- sonoff/xnrg_02_cse7766.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/xnrg_02_cse7766.ino b/sonoff/xnrg_02_cse7766.ino index 078ff3d6e..55d87a163 100644 --- a/sonoff/xnrg_02_cse7766.ino +++ b/sonoff/xnrg_02_cse7766.ino @@ -189,6 +189,7 @@ void CseEverySecond(void) } else { AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Load overflow")); + cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; } EnergyUpdateToday(); } From 1a6acf50781f53b1854b1ff3f6b75acf615e19dc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 20 May 2019 10:25:49 +0200 Subject: [PATCH 22/31] Remove redundant call Remove redundant call --- sonoff/sonoff.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 9517755ee..f58fc8947 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -2181,7 +2181,9 @@ void Every250mSeconds(void) SettingsDefault(); restart_flag = 2; } - SettingsSaveAll(); + if (2 == restart_flag) { + SettingsSaveAll(); + } restart_flag--; if (restart_flag <= 0) { AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_RESTARTING)); From d599f21758afc47155f8bb6ca7fd74d2630bca7f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 20 May 2019 15:09:42 +0200 Subject: [PATCH 23/31] Add defines USE_EMULATION_WEMO and USE_EMULATION_HUE * Remove define USE_EMULATION from my_user_config.h (#5826) * Add defines USE_EMULATION_WEMO and USE_EMULATION_HUE to my_user_config.h to control emulation features at compile time (#5826) --- sonoff/_changelog.ino | 2 + sonoff/my_user_config.h | 3 +- sonoff/sonoff.ino | 7 + sonoff/sonoff_post.h | 7 + sonoff/support_features.ino | 8 +- sonoff/support_udp.ino | 136 +++++++ sonoff/support_wifi.ino | 8 +- sonoff/xdrv_01_webserver.ino | 34 +- sonoff/xdrv_02_mqtt.ino | 2 +- sonoff/{xplg_wemohue.ino => xdrv_20_hue.ino} | 368 +------------------ sonoff/xdrv_21_wemo.ino | 271 ++++++++++++++ tools/decode-status.py | 10 +- 12 files changed, 486 insertions(+), 370 deletions(-) create mode 100644 sonoff/support_udp.ino rename sonoff/{xplg_wemohue.ino => xdrv_20_hue.ino} (64%) create mode 100644 sonoff/xdrv_21_wemo.ino diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 815fc3374..4e4ef94e6 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -3,6 +3,8 @@ * Add initial support for Scripts as replacement for Rules. Default disabled but can be enabled in my_user_config.h (#5689) * Add rule System#Save executed just before a planned restart * Add HX711 weight restore after controlled restart or after power restore just before executing command Sensor34 7 (#5367, #5786) + * Remove define USE_EMULATION from my_user_config.h (#5826) + * Add defines USE_EMULATION_WEMO and USE_EMULATION_HUE to my_user_config.h to control emulation features at compile time (#5826) * * 6.5.0.10 20190513 * Enable ADC0 by default in my_user_config.h (#5671) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 164dbca0c..2453d2ce5 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -275,7 +275,8 @@ #define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem) #define WEB_PORT 80 // Web server Port for User and Admin mode #define WEB_USERNAME "admin" // Web server Admin mode user name - #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+18k code, +2k mem) + #define USE_EMULATION_HUE // Enable Hue Bridge emulation for Alexa (+14k code, +2k mem common) + #define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem common) // -- mDNS ---------------------------------------- #define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index f58fc8947..e04619fdf 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -2652,6 +2652,13 @@ void setup(void) sleep = Settings.sleep; #ifndef USE_EMULATION Settings.flag2.emulation = 0; +#else +#ifndef USE_EMULATION_WEMO + if (EMUL_WEMO == Settings.flag2.emulation) { Settings.flag2.emulation = 0; } +#endif +#ifndef USE_EMULATION_HUE + if (EMUL_HUE == Settings.flag2.emulation) { Settings.flag2.emulation = 0; } +#endif #endif // USE_EMULATION if (Settings.param[P_BOOT_LOOP_OFFSET]) { diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 10a466981..6089adfa5 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -46,6 +46,13 @@ void KNX_CB_Action(message_t const &msg, void *arg); * Default global defines \*********************************************************************************************/ +#ifdef USE_EMULATION_HUE +#define USE_EMULATION +#endif +#ifdef USE_EMULATION_WEMO +#define USE_EMULATION +#endif + #ifndef MODULE #define MODULE SONOFF_BASIC // [Module] Select default model #endif diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index fef9766ea..9ae3df3b2 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -49,8 +49,8 @@ void GetFeatures(void) #ifdef WEBSERVER_ADVERTISE feature_drv1 |= 0x00000100; // xdrv_02_webserver.ino #endif -#ifdef USE_EMULATION - feature_drv1 |= 0x00000200; // xplg_wemohue.ino +#ifdef USE_EMULATION_HUE + feature_drv1 |= 0x00000200; // xdrv_20_hue.ino #endif #if (MQTT_LIBRARY_TYPE == MQTT_PUBSUBCLIENT) feature_drv1 |= 0x00000400; // xdrv_01_mqtt.ino @@ -183,8 +183,10 @@ void GetFeatures(void) #ifdef USE_SCRIPT feature_drv2 |= 0x00080000; // xdrv_10_scripter.ino #endif +#ifdef USE_EMULATION_WEMO + feature_drv2 |= 0x00100000; // xdrv_21_wemo.ino +#endif -// feature_drv2 |= 0x00100000; // feature_drv2 |= 0x00200000; // feature_drv2 |= 0x00400000; diff --git a/sonoff/support_udp.ino b/sonoff/support_udp.ino new file mode 100644 index 000000000..eccc4681d --- /dev/null +++ b/sonoff/support_udp.ino @@ -0,0 +1,136 @@ +/* + support_udp.ino - Udp support for Sonoff-Tasmota + + Copyright (C) 2019 Heiko Krupp and 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 . +*/ + +#ifdef USE_EMULATION + +#define UDP_BUFFER_SIZE 200 // Max UDP buffer size needed for M-SEARCH message +#define UDP_MSEARCH_SEND_DELAY 1500 // Delay in ms before M-Search response is send + +#include +Ticker TickerMSearch; + +IPAddress udp_remote_ip; // M-Search remote IP address +uint16_t udp_remote_port; // M-Search remote port + +bool udp_connected = false; +bool udp_response_mutex = false; // M-Search response mutex to control re-entry + +/*********************************************************************************************\ + * UPNP/SSDP search targets +\*********************************************************************************************/ + +const char URN_BELKIN_DEVICE[] PROGMEM = "urn:belkin:device:**"; +const char UPNP_ROOTDEVICE[] PROGMEM = "upnp:rootdevice"; +const char SSDPSEARCH_ALL[] PROGMEM = "ssdpsearch:all"; +const char SSDP_ALL[] PROGMEM = "ssdp:all"; + +/*********************************************************************************************\ + * UDP support routines +\*********************************************************************************************/ + +bool UdpDisconnect(void) +{ + if (udp_connected) { + PortUdp.flush(); + WiFiUDP::stopAll(); + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_MULTICAST_DISABLED)); + udp_connected = false; + } + return udp_connected; +} + +bool UdpConnect(void) +{ + if (!udp_connected) { + // Simple Service Discovery Protocol (SSDP) + if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) { + AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED)); + udp_response_mutex = false; + udp_connected = true; + } else { + AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_JOIN_FAILED)); + udp_connected = false; + } + } + return udp_connected; +} + +void PollUdp(void) +{ + if (udp_connected) { + if (PortUdp.parsePacket()) { + char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet + + int len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1); + packet_buffer[len] = 0; + + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len); +// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer); + + // Simple Service Discovery Protocol (SSDP) + if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) { + udp_response_mutex = true; + + udp_remote_ip = PortUdp.remoteIP(); + udp_remote_port = PortUdp.remotePort(); + +// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet from %s:%d\n%s"), +// udp_remote_ip.toString().c_str(), udp_remote_port, packet_buffer); + + uint32_t response_delay = UDP_MSEARCH_SEND_DELAY + ((millis() &0x7) * 100); // 1500 - 2200 msec + + LowerCase(packet_buffer, packet_buffer); + RemoveSpace(packet_buffer); + +#ifdef USE_EMULATION_WEMO + if (EMUL_WEMO == Settings.flag2.emulation) { + if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { // type1 echo dot 2g, echo 1g's + TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 1); + return; + } + else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || // type2 Echo 2g (echo & echo plus) + (strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) || + (strstr_P(packet_buffer, SSDP_ALL) != nullptr)) { + TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 2); + return; + } + } +#endif // USE_EMULATION_WEMO + +#ifdef USE_EMULATION_HUE + if (EMUL_HUE == Settings.flag2.emulation) { + if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) || + (strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || + (strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) || + (strstr_P(packet_buffer, SSDP_ALL) != nullptr)) { + TickerMSearch.attach_ms(response_delay, HueRespondToMSearch); + return; + } + } +#endif // USE_EMULATION_HUE + + udp_response_mutex = false; + } + + } + delay(1); + } +} + +#endif // USE_EMULATION diff --git a/sonoff/support_wifi.ino b/sonoff/support_wifi.ino index 44efdac0f..8c406fad5 100644 --- a/sonoff/support_wifi.ino +++ b/sonoff/support_wifi.ino @@ -131,7 +131,7 @@ void WifiConfig(uint8_t type) { if (!wifi_config_type) { if ((WIFI_RETRY == type) || (WIFI_WAIT == type)) { return; } -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) +#ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION WiFi.disconnect(); // Solve possible Wifi hangs @@ -159,7 +159,7 @@ void WifiConfig(uint8_t type) #ifdef USE_SMARTCONFIG else if (WIFI_SMARTCONFIG == wifi_config_type) { AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_WCFG_1_SMARTCONFIG " " D_ACTIVE_FOR_3_MINUTES)); - WiFi.mode(WIFI_STA); // Disable AP mode + WiFi.mode(WIFI_STA); // Disable AP mode WiFi.beginSmartConfig(); } #endif // USE_SMARTCONFIG @@ -211,7 +211,7 @@ void WifiBegin(uint8_t flag, uint8_t channel) { const char kWifiPhyMode[] = " BGN"; -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) +#ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION @@ -565,7 +565,7 @@ void WifiCheck(uint8_t param) } else { WifiSetState(0); -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) +#ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION mdns_begun = 0; diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index dfbce53ba..fc5ffa467 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -493,9 +493,6 @@ void StartWebserver(int type, IPAddress ipweb) WebServer->on("/rs", HandleRestoreConfiguration); WebServer->on("/rt", HandleResetConfiguration); WebServer->on("/in", HandleInformation); -#ifdef USE_EMULATION - HueWemoAddHandlers(); -#endif // USE_EMULATION XdrvCall(FUNC_WEB_ADD_HANDLER); XsnsCall(FUNC_WEB_ADD_HANDLER); #endif // Not FIRMWARE_MINIMAL @@ -1529,11 +1526,19 @@ void HandleOtherConfiguration(void) #ifdef USE_EMULATION WSContentSend_P(PSTR("

 " D_EMULATION " 

")); // Keep close to Friendlynames so do not use
for (uint8_t i = 0; i < EMUL_MAX; i++) { - WSContentSend_P(PSTR("%s %s
"), // Different id only used for labels - i, i, - (i == Settings.flag2.emulation) ? " checked" : "", - GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions), - (i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE); +#ifndef USE_EMULATION_WEMO + if (i == EMUL_WEMO) { i++; } +#endif +#ifndef USE_EMULATION_HUE + if (i == EMUL_HUE) { i++; } +#endif + if (i < EMUL_MAX) { + WSContentSend_P(PSTR("%s %s
"), // Different id only used for labels + i, i, + (i == Settings.flag2.emulation) ? " checked" : "", + GetTextIndexed(stemp, sizeof(stemp), i, kEmulationOptions), + (i == EMUL_NONE) ? "" : (i == EMUL_WEMO) ? D_SINGLE_DEVICE : D_MULTI_DEVICE); + } } WSContentSend_P(PSTR("

")); #endif // USE_EMULATION @@ -2186,11 +2191,13 @@ void HandleNotFound(void) if (CaptivePortal()) { return; } // If captive portal redirect instead of displaying the error page. #ifdef USE_EMULATION +#ifdef USE_EMULATION_HUE String path = WebServer->uri(); if ((EMUL_HUE == Settings.flag2.emulation) && (path.startsWith("/api"))) { HandleHueApi(&path); } else -#endif // USE_EMULATION +#endif // USE_EMULATION_HUE +#endif // USE_EMULATION { WSContentBegin(404, CT_PLAIN); WSContentSend_P(PSTR(D_FILE_NOT_FOUND "\n\nURI: %s\nMethod: %s\nArguments: %d\n"), WebServer->uri().c_str(), (WebServer->method() == HTTP_GET) ? "GET" : "POST", WebServer->args()); @@ -2427,7 +2434,16 @@ bool WebCommand(void) } #ifdef USE_EMULATION else if (CMND_EMULATION == command_code) { +#if defined(USE_EMULATION_WEMO) && defined(USE_EMULATION_HUE) if ((XdrvMailbox.payload >= EMUL_NONE) && (XdrvMailbox.payload < EMUL_MAX)) { +#else +#ifndef USE_EMULATION_WEMO + if ((EMUL_NONE == XdrvMailbox.payload) || (EMUL_HUE == XdrvMailbox.payload)) { +#endif +#ifndef USE_EMULATION_HUE + if ((EMUL_NONE == XdrvMailbox.payload) || (EMUL_WEMO == XdrvMailbox.payload)) { +#endif +#endif Settings.flag2.emulation = XdrvMailbox.payload; restart_flag = 2; } diff --git a/sonoff/xdrv_02_mqtt.ino b/sonoff/xdrv_02_mqtt.ino index cc510b20c..4d60e157b 100644 --- a/sonoff/xdrv_02_mqtt.ino +++ b/sonoff/xdrv_02_mqtt.ino @@ -423,7 +423,7 @@ void MqttReconnect(void) return; } -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) +#ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION diff --git a/sonoff/xplg_wemohue.ino b/sonoff/xdrv_20_hue.ino similarity index 64% rename from sonoff/xplg_wemohue.ino rename to sonoff/xdrv_20_hue.ino index b4ca72124..d54becd66 100644 --- a/sonoff/xplg_wemohue.ino +++ b/sonoff/xdrv_20_hue.ino @@ -1,5 +1,5 @@ /* - xplg_wemohue.ino - wemo and hue support for Sonoff-Tasmota + xdrv_20_hue.ino - Philips Hue support for Sonoff-Tasmota Copyright (C) 2019 Heiko Krupp and Theo Arends @@ -17,93 +17,10 @@ along with this program. If not, see . */ -#if defined(USE_WEBSERVER) && defined(USE_EMULATION) -/*********************************************************************************************\ - * Belkin WeMo and Philips Hue bridge emulation -\*********************************************************************************************/ - -#define UDP_BUFFER_SIZE 200 // Max UDP buffer size needed for M-SEARCH message -#define UDP_MSEARCH_SEND_DELAY 1500 // Delay in ms before M-Search response is send - -#include -Ticker TickerMSearch; - -IPAddress udp_remote_ip; // M-Search remote IP address -uint16_t udp_remote_port; // M-Search remote port - -bool udp_connected = false; -bool udp_response_mutex = false; // M-Search response mutex to control re-entry - -/*********************************************************************************************\ - * UPNP search targets -\*********************************************************************************************/ - -const char URN_BELKIN_DEVICE[] PROGMEM = "urn:belkin:device:**"; -const char UPNP_ROOTDEVICE[] PROGMEM = "upnp:rootdevice"; -const char SSDPSEARCH_ALL[] PROGMEM = "ssdpsearch:all"; -const char SSDP_ALL[] PROGMEM = "ssdp:all"; - -/*********************************************************************************************\ - * WeMo UPNP support routines -\*********************************************************************************************/ - -const char WEMO_MSEARCH[] PROGMEM = - "HTTP/1.1 200 OK\r\n" - "CACHE-CONTROL: max-age=86400\r\n" - "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n" - "EXT:\r\n" - "LOCATION: http://%s:80/setup.xml\r\n" - "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" - "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n" - "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" - "ST: %s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice - "USN: uuid:%s::%s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice - "X-User-Agent: redsonic\r\n" - "\r\n"; - -String WemoSerialnumber(void) -{ - char serial[16]; - - snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP.getChipId()); - return String(serial); -} - -String WemoUuid(void) -{ - char uuid[27]; - - snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), WemoSerialnumber().c_str()); - return String(uuid); -} - -void WemoRespondToMSearch(int echo_type) -{ - char message[TOPSZ]; - - TickerMSearch.detach(); - if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) { - char type[24]; - if (1 == echo_type) { // type1 echo 1g & dot 2g - strcpy_P(type, URN_BELKIN_DEVICE); - } else { // type2 echo 2g (echo, plus, show) - strcpy_P(type, UPNP_ROOTDEVICE); - } - char response[400]; - snprintf_P(response, sizeof(response), WEMO_MSEARCH, WiFi.localIP().toString().c_str(), type, WemoUuid().c_str(), type); - PortUdp.write(response); - PortUdp.endPacket(); - snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT)); - } else { - snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"), - echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port); - - udp_response_mutex = false; -} - +#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) /*********************************************************************************************\ + * Philips Hue bridge emulation + * * Hue Bridge UPNP support routines * Need to send 3 response packets with varying ST and USN * @@ -111,6 +28,8 @@ void WemoRespondToMSearch(int echo_type) * Philips Lighting is 00:17:88:00:00:00 \*********************************************************************************************/ +#define XDRV_20 20 + const char HUE_RESPONSE[] PROGMEM = "HTTP/1.1 200 OK\r\n" "HOST: 239.255.255.250:1900\r\n" @@ -187,256 +106,6 @@ void HueRespondToMSearch(void) udp_response_mutex = false; } -/*********************************************************************************************\ - * Belkin WeMo and Philips Hue bridge UDP multicast support -\*********************************************************************************************/ - -bool UdpDisconnect(void) -{ - if (udp_connected) { - PortUdp.flush(); - WiFiUDP::stopAll(); - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_MULTICAST_DISABLED)); - udp_connected = false; - } - return udp_connected; -} - -bool UdpConnect(void) -{ - if (!udp_connected) { - // Simple Service Discovery Protocol (SSDP) - if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), 1900)) { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_REJOINED)); - udp_response_mutex = false; - udp_connected = true; - } else { - AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_UPNP D_MULTICAST_JOIN_FAILED)); - udp_connected = false; - } - } - return udp_connected; -} - -void PollUdp(void) -{ - if (udp_connected) { - if (PortUdp.parsePacket()) { - char packet_buffer[UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet - - int len = PortUdp.read(packet_buffer, UDP_BUFFER_SIZE -1); - packet_buffer[len] = 0; - - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet (%d)"), len); -// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), packet_buffer); - - if (devices_present && !udp_response_mutex && (strstr_P(packet_buffer, PSTR("M-SEARCH")) != nullptr)) { - udp_response_mutex = true; - - udp_remote_ip = PortUdp.remoteIP(); - udp_remote_port = PortUdp.remotePort(); - -// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: M-SEARCH Packet from %s:%d\n%s"), -// udp_remote_ip.toString().c_str(), udp_remote_port, packet_buffer); - - uint32_t response_delay = UDP_MSEARCH_SEND_DELAY + ((millis() &0x7) * 100); // 1500 - 2200 msec - - LowerCase(packet_buffer, packet_buffer); - RemoveSpace(packet_buffer); - if (EMUL_WEMO == Settings.flag2.emulation) { - if (strstr_P(packet_buffer, URN_BELKIN_DEVICE) != nullptr) { // type1 echo dot 2g, echo 1g's - TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 1); - return; - } - else if ((strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || // type2 Echo 2g (echo & echo plus) - (strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) || - (strstr_P(packet_buffer, SSDP_ALL) != nullptr)) { - TickerMSearch.attach_ms(response_delay, WemoRespondToMSearch, 2); - return; - } - } else { - if ((strstr_P(packet_buffer, PSTR(":device:basic:1")) != nullptr) || - (strstr_P(packet_buffer, UPNP_ROOTDEVICE) != nullptr) || - (strstr_P(packet_buffer, SSDPSEARCH_ALL) != nullptr) || - (strstr_P(packet_buffer, SSDP_ALL) != nullptr)) { - TickerMSearch.attach_ms(response_delay, HueRespondToMSearch); - return; - } - } - udp_response_mutex = false; - } - } - delay(1); - } -} - -/*********************************************************************************************\ - * Wemo web server additions -\*********************************************************************************************/ - -const char WEMO_EVENTSERVICE_XML[] PROGMEM = - "" - "" - "" - "SetBinaryState" - "" - "" - "" - "BinaryState" - "BinaryState" - "in" - "" - "" - "" - "" - "GetBinaryState" - "" - "" - "" - "BinaryState" - "BinaryState" - "out" - "" - "" - "" - "" - "" - "" - "BinaryState" - "bool" - "0" - "" - "" - "level" - "string" - "0" - "" - "" - "\r\n\r\n"; - -const char WEMO_METASERVICE_XML[] PROGMEM = - "" - "" - "1" - "0" - "" - "" - "" - "GetMetaInfo" - "" - "" - "GetMetaInfo" - "MetaInfo" - "in" - "" - "" - "" - "" - "" - "MetaInfo" - "string" - "0" - "" - "" - "\r\n\r\n"; - -const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM = - "" - "" - "" - "%d" - "" - "" - "\r\n"; - -const char WEMO_SETUP_XML[] PROGMEM = - "" - "" - "" - "urn:Belkin:device:controllee:1" - "{x1" - "Belkin International Inc." - "Socket" - "3.1415" - "uuid:{x2" - "{x3" - "0" - "" - "" - "urn:Belkin:service:basicevent:1" - "urn:Belkin:serviceId:basicevent1" - "/upnp/control/basicevent1" - "/upnp/event/basicevent1" - "/eventservice.xml" - "" - "" - "urn:Belkin:service:metainfo:1" - "urn:Belkin:serviceId:metainfo1" - "/upnp/control/metainfo1" - "/upnp/event/metainfo1" - "/metainfoservice.xml" - "" - "" - "" - "\r\n"; - -/********************************************************************************************/ - -void HandleUpnpEvent(void) -{ - AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT)); - - char event[500]; - strlcpy(event, WebServer->arg(0).c_str(), sizeof(event)); - -// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event); - - //differentiate get and set state - char state = 'G'; - if (strstr_P(event, PSTR("SetBinaryState")) != nullptr) { - state = 'S'; - uint8_t power = POWER_TOGGLE; - if (strstr_P(event, PSTR("State>10on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); - WebServer->on("/eventservice.xml", HandleUpnpService); - WebServer->on("/metainfoservice.xml", HandleUpnpMetaService); - WebServer->on("/setup.xml", HandleUpnpSetupWemo); - } - if (EMUL_HUE == Settings.flag2.emulation) { - WebServer->on("/description.xml", HandleUpnpSetupHue); + bool result = false; + + if (devices_present && (EMUL_HUE == Settings.flag2.emulation)) { + switch (function) { + case FUNC_WEB_ADD_HANDLER: + WebServer->on("/description.xml", HandleUpnpSetupHue); + break; } } + return result; } -#endif // USE_WEBSERVER && USE_EMULATION +#endif // USE_WEBSERVER && USE_EMULATION && USE_EMULATION_HUE diff --git a/sonoff/xdrv_21_wemo.ino b/sonoff/xdrv_21_wemo.ino new file mode 100644 index 000000000..6d5a41715 --- /dev/null +++ b/sonoff/xdrv_21_wemo.ino @@ -0,0 +1,271 @@ +/* + xdrv_21_wemo.ino - wemo support for Sonoff-Tasmota + + Copyright (C) 2019 Heiko Krupp and 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 . +*/ + +#if defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined (USE_EMULATION_WEMO) +/*********************************************************************************************\ + * Belkin WeMo emulation +\*********************************************************************************************/ + +#define XDRV_21 21 + +const char WEMO_MSEARCH[] PROGMEM = + "HTTP/1.1 200 OK\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n" + "EXT:\r\n" + "LOCATION: http://%s:80/setup.xml\r\n" + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" + "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n" + "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" + "ST: %s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice + "USN: uuid:%s::%s\r\n" // type1 = urn:Belkin:device:**, type2 = upnp:rootdevice + "X-User-Agent: redsonic\r\n" + "\r\n"; + +String WemoSerialnumber(void) +{ + char serial[16]; + + snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP.getChipId()); + return String(serial); +} + +String WemoUuid(void) +{ + char uuid[27]; + + snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), WemoSerialnumber().c_str()); + return String(uuid); +} + +void WemoRespondToMSearch(int echo_type) +{ + char message[TOPSZ]; + + TickerMSearch.detach(); + if (PortUdp.beginPacket(udp_remote_ip, udp_remote_port)) { + char type[24]; + if (1 == echo_type) { // type1 echo 1g & dot 2g + strcpy_P(type, URN_BELKIN_DEVICE); + } else { // type2 echo 2g (echo, plus, show) + strcpy_P(type, UPNP_ROOTDEVICE); + } + char response[400]; + snprintf_P(response, sizeof(response), WEMO_MSEARCH, WiFi.localIP().toString().c_str(), type, WemoUuid().c_str(), type); + PortUdp.write(response); + PortUdp.endPacket(); + snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT)); + } else { + snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"), + echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port); + + udp_response_mutex = false; +} + +/*********************************************************************************************\ + * Wemo web server additions +\*********************************************************************************************/ + +const char WEMO_EVENTSERVICE_XML[] PROGMEM = + "" + "" + "" + "SetBinaryState" + "" + "" + "" + "BinaryState" + "BinaryState" + "in" + "" + "" + "" + "" + "GetBinaryState" + "" + "" + "" + "BinaryState" + "BinaryState" + "out" + "" + "" + "" + "" + "" + "" + "BinaryState" + "bool" + "0" + "" + "" + "level" + "string" + "0" + "" + "" + "\r\n\r\n"; + +const char WEMO_METASERVICE_XML[] PROGMEM = + "" + "" + "1" + "0" + "" + "" + "" + "GetMetaInfo" + "" + "" + "GetMetaInfo" + "MetaInfo" + "in" + "" + "" + "" + "" + "" + "MetaInfo" + "string" + "0" + "" + "" + "\r\n\r\n"; + +const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM = + "" + "" + "" + "%d" + "" + "" + "\r\n"; + +const char WEMO_SETUP_XML[] PROGMEM = + "" + "" + "" + "urn:Belkin:device:controllee:1" + "{x1" + "Belkin International Inc." + "Socket" + "3.1415" + "uuid:{x2" + "{x3" + "0" + "" + "" + "urn:Belkin:service:basicevent:1" + "urn:Belkin:serviceId:basicevent1" + "/upnp/control/basicevent1" + "/upnp/event/basicevent1" + "/eventservice.xml" + "" + "" + "urn:Belkin:service:metainfo:1" + "urn:Belkin:serviceId:metainfo1" + "/upnp/control/metainfo1" + "/upnp/event/metainfo1" + "/metainfoservice.xml" + "" + "" + "" + "\r\n"; + +/********************************************************************************************/ + +void HandleUpnpEvent(void) +{ + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_BASIC_EVENT)); + + char event[500]; + strlcpy(event, WebServer->arg(0).c_str(), sizeof(event)); + +// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("\n%s"), event); + + //differentiate get and set state + char state = 'G'; + if (strstr_P(event, PSTR("SetBinaryState")) != nullptr) { + state = 'S'; + uint8_t power = POWER_TOGGLE; + if (strstr_P(event, PSTR("State>10on("/upnp/control/basicevent1", HTTP_POST, HandleUpnpEvent); + WebServer->on("/eventservice.xml", HandleUpnpService); + WebServer->on("/metainfoservice.xml", HandleUpnpMetaService); + WebServer->on("/setup.xml", HandleUpnpSetupWemo); + break; + } + } + return result; +} + +#endif // USE_WEBSERVER && USE_EMULATION && USE_EMULATION_WEMO diff --git a/tools/decode-status.py b/tools/decode-status.py index 5b8f60923..43ba0c6fb 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -106,7 +106,9 @@ a_setoption = [[ "Enable normal sleep instead of dynamic sleep", "Force local operation when button/switch topic is set", "Do not use retain flag on HOLD messages", - "","","", + "Do not scan relay power state at restart", + "Use _ instead of - as sensor index separator", + "", "","","","", "","","","", "","","","", @@ -116,7 +118,7 @@ a_setoption = [[ a_features = [[ "","","USE_I2C","USE_SPI", "USE_DISCOVERY","USE_ARDUINO_OTA","USE_MQTT_TLS","USE_WEBSERVER", - "WEBSERVER_ADVERTISE","USE_EMULATION","MQTT_PUBSUBCLIENT","MQTT_TASMOTAMQTT", + "WEBSERVER_ADVERTISE","USE_EMULATION_HUE","MQTT_PUBSUBCLIENT","MQTT_TASMOTAMQTT", "MQTT_ESPMQTTARDUINO","MQTT_HOST_DISCOVERY","USE_ARILUX_RF","USE_WS2812", "USE_WS2812_DMA","USE_IR_REMOTE","USE_IR_HVAC","USE_IR_RECEIVE", "USE_DOMOTICZ","USE_DISPLAY","USE_HOME_ASSISTANT","USE_SERIAL_BRIDGE", @@ -127,8 +129,8 @@ a_features = [[ "FIRMWARE_KNX_NO_EMULATION","USE_DISPLAY_MODES1TO5","USE_DISPLAY_GRAPH","USE_DISPLAY_LCD", "USE_DISPLAY_SSD1306","USE_DISPLAY_MATRIX","USE_DISPLAY_ILI9341","USE_DISPLAY_EPAPER", "USE_DISPLAY_SH1106","USE_MP3_PLAYER","USE_PCA9685","USE_TUYA_DIMMER", - "USE_RC_SWITCH","USE_ARMTRONIX_DIMMERS","","", - "","","","NO_EXTRA_4K_HEAP", + "USE_RC_SWITCH","USE_ARMTRONIX_DIMMERS","USE_SM16716","USE_SCRIPT", + "USE_EMULATION_WEMO","","","NO_EXTRA_4K_HEAP", "VTABLES_IN_IRAM","VTABLES_IN_DRAM","VTABLES_IN_FLASH","PIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH", "PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY","PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH","DEBUG_THEO","USE_DEBUG_DRIVER" ],[ From e26509f0debc12b5f4c7ff96c751260485b38418 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 20 May 2019 20:12:34 +0200 Subject: [PATCH 24/31] Create xsns_44_sps30.ino --- sonoff/xsns_44_sps30.ino | 307 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 sonoff/xsns_44_sps30.ino diff --git a/sonoff/xsns_44_sps30.ino b/sonoff/xsns_44_sps30.ino new file mode 100644 index 000000000..38a09f151 --- /dev/null +++ b/sonoff/xsns_44_sps30.ino @@ -0,0 +1,307 @@ +/* + xsns_96_sps30.ino - Sensirion SPS30 + + Copyright (C) 2019 Gerhard Mutz and 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_SPS30 + +#define XSNS_44 44 + +#define SPS30_ADDR 0x69 + +#include +#include + +uint8_t sps30_ready = 0; +struct SPS30 { + float PM1_0; + float PM2_5; + float PM4_0; + float PM10; + float NCPM0_5; + float NCPM1_0; + float NCPM2_5; + float NCPM4_0; + float NCPM10; + float TYPSIZ; +} sps30_result; + +#define SPS_CMD_START_MEASUREMENT 0x0010 +#define SPS_CMD_START_MEASUREMENT_ARG 0x0300 +#define SPS_CMD_STOP_MEASUREMENT 0x0104 +#define SPS_CMD_READ_MEASUREMENT 0x0300 +#define SPS_CMD_GET_DATA_READY 0x0202 +#define SPS_CMD_AUTOCLEAN_INTERVAL 0x8004 +#define SPS_CMD_CLEAN 0x5607 +#define SPS_CMD_GET_ACODE 0xd025 +#define SPS_CMD_GET_SERIAL 0xd033 +#define SPS_CMD_RESET 0xd304 +#define SPS_WRITE_DELAY_US 20000 +#define SPS_MAX_SERIAL_LEN 32 + +uint8_t sps30_calc_CRC(uint8_t *data) { + uint8_t crc = 0xFF; + for (uint8_t i = 0; i < 2; i++) { + crc ^= data[i]; + for(uint8_t bit = 8; bit > 0; --bit) { + if(crc & 0x80) { + crc = (crc << 1) ^ 0x31u; + } else { + crc = (crc << 1); + } + } + } + return crc; +} + + +unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop); + +void sps30_get_data(uint16_t cmd, uint8_t *data, uint8_t dlen) { +unsigned char cmdb[2]; +uint8_t tmp[3]; +uint8_t index=0; +memset(data,0,dlen); +uint8_t twi_buff[64]; + + Wire.beginTransmission(SPS30_ADDR); + cmdb[0]=cmd>>8; + cmdb[1]=cmd; + Wire.write(cmdb,2); + Wire.endTransmission(); + + // need 60 bytes max + dlen/=2; + dlen*=3; + + twi_readFrom(SPS30_ADDR,twi_buff,dlen,1); + + uint8_t bind=0; + while (bind>8; + cmdb[1]=cmd; + + if (cmd==SPS_CMD_START_MEASUREMENT) { + cmdb[2]=SPS_CMD_START_MEASUREMENT_ARG>>8; + cmdb[3]=SPS_CMD_START_MEASUREMENT_ARG&0xff; + cmdb[4]=sps30_calc_CRC(&cmdb[2]); + Wire.write(cmdb,5); + } else { + Wire.write(cmdb,2); + } + Wire.endTransmission(); +} + +void SPS30_Detect() { + + if (!I2cDevice(SPS30_ADDR)) { + return; + } + uint8_t dcode[32]; + sps30_get_data(SPS_CMD_GET_SERIAL,dcode,sizeof(dcode)); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("sps30 found with serial: %s"),dcode); + sps30_cmd(SPS_CMD_START_MEASUREMENT); + sps30_ready = 1; +} + +#define D_UNIT_PM "ug/m3" +#define D_UNIT_NCPM "#/m3" + +#ifdef USE_WEBSERVER +const char HTTP_SNS_SPS30_a[] PROGMEM ="{s}SPS30 " "PM 1.0" "{m}%s " D_UNIT_PM "{e}"; +const char HTTP_SNS_SPS30_b[] PROGMEM ="{s}SPS30 " "PM 2.5" "{m}%s " D_UNIT_PM "{e}"; +const char HTTP_SNS_SPS30_c[] PROGMEM ="{s}SPS30 " "PM 4.0" "{m}%s " D_UNIT_PM "{e}"; +const char HTTP_SNS_SPS30_d[] PROGMEM ="{s}SPS30 " "PM 10" "{m}%s " D_UNIT_PM "{e}"; +const char HTTP_SNS_SPS30_e[] PROGMEM ="{s}SPS30 " "NCPM 0.5" "{m}%s " D_UNIT_NCPM "{e}"; +const char HTTP_SNS_SPS30_f[] PROGMEM ="{s}SPS30 " "NCPM 1.0" "{m}%s " D_UNIT_NCPM "{e}"; +const char HTTP_SNS_SPS30_g[] PROGMEM ="{s}SPS30 " "NCPM 2.5" "{m}%s " D_UNIT_NCPM "{e}"; +const char HTTP_SNS_SPS30_h[] PROGMEM ="{s}SPS30 " "NCPM 4.0" "{m}%s " D_UNIT_NCPM "{e}"; +const char HTTP_SNS_SPS30_i[] PROGMEM ="{s}SPS30 " "NCPM 10" "{m}%s " D_UNIT_NCPM "{e}"; +const char HTTP_SNS_SPS30_j[] PROGMEM ="{s}SPS30 " "TYPSIZ" "{m}%s " "um" "{e}"; + +#endif // USE_WEBSERVER + +#define PMDP 2 + +//#define SPS30_HOURS Settings.sps30_inuse_hours +#define SPS30_HOURS sps30_inuse_hours +uint8_t sps30_inuse_hours; + +void SPS30_Every_Second() { + + if (!sps30_ready) return; + + if (uptime%10==0) { + uint8_t vars[sizeof(float)*10]; + sps30_get_data(SPS_CMD_READ_MEASUREMENT,vars,sizeof(vars)); + float *fp=&sps30_result.PM1_0; + + typedef union { + uint8_t array[4]; + float value; + } ByteToFloat; + + ByteToFloat conv; + + for (uint8_t count=0; count<10; count++) { + for (uint8_t i = 0; i < 4; i++){ + conv.array[3-i] = vars[count*sizeof(float)+i]; + } + *fp++=conv.value; + } + } + + if (uptime%3600==0 && uptime>60) { + // should auto clean once per week runtime + // so count hours, should be in Settings + SPS30_HOURS++; + if (SPS30_HOURS>(7*24)) { + sps30_cmd(SPS_CMD_CLEAN); + SPS30_HOURS=0; + } + } + +} + +void SPS30_Show(bool json) { + char str[64]; + if (!sps30_ready) { + return; + } + + if (json) { + dtostrfd(sps30_result.PM1_0,PMDP,str); + ResponseAppend_P(PSTR(",\"SPS30\":{\"" "PM1_0" "\":%s"), str); + dtostrfd(sps30_result.PM2_5,PMDP,str); + ResponseAppend_P(PSTR(",\"" "PM2_5" "\":%s"), str); + dtostrfd(sps30_result.PM4_0,PMDP,str); + ResponseAppend_P(PSTR(",\"" "PM4_0" "\":%s"), str); + dtostrfd(sps30_result.PM10,PMDP,str); + ResponseAppend_P(PSTR(",\"" "PM10" "\":%s"), str); + dtostrfd(sps30_result.NCPM0_5,PMDP,str); + ResponseAppend_P(PSTR(",\"" "NCPM0_5" "\":%s"), str); + dtostrfd(sps30_result.NCPM1_0,PMDP,str); + ResponseAppend_P(PSTR(",\"" "NCPM1_0" "\":%s"), str); + dtostrfd(sps30_result.NCPM2_5,PMDP,str); + ResponseAppend_P(PSTR(",\"" "NCPM2_5" "\":%s"), str); + dtostrfd(sps30_result.NCPM4_0,PMDP,str); + ResponseAppend_P(PSTR(",\"" "NCPM4_0" "\":%s"), str); + dtostrfd(sps30_result.NCPM10,PMDP,str); + ResponseAppend_P(PSTR(",\"" "NCPM10" "\":%s"), str); + dtostrfd(sps30_result.TYPSIZ,PMDP,str); + ResponseAppend_P(PSTR(",\"" "TYPSIZ" "\":%s}"), str); + +#ifdef USE_WEBSERVER + } else { + dtostrfd(sps30_result.PM1_0,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_a,str); + dtostrfd(sps30_result.PM2_5,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_b,str); + dtostrfd(sps30_result.PM4_0,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_c,str); + dtostrfd(sps30_result.PM10,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_d,str); + dtostrfd(sps30_result.NCPM0_5,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_e,str); + dtostrfd(sps30_result.NCPM1_0,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_f,str); + dtostrfd(sps30_result.NCPM2_5,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_g,str); + dtostrfd(sps30_result.NCPM4_0,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_h,str); + dtostrfd(sps30_result.NCPM10,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_i,str); + dtostrfd(sps30_result.TYPSIZ,PMDP,str); + WSContentSend_PD(HTTP_SNS_SPS30_j,str); +#endif + } + +} + + +bool XSNS_44_cmd(void) { + boolean serviced = true; + const char S_JSON_SPS30[] = "{\"" D_CMND_SENSOR "%d\":%s}"; + + if (XdrvMailbox.data_len > 0) { + char *cp=XdrvMailbox.data; + if (*cp=='c') { + // clean cmd + sps30_cmd(SPS_CMD_CLEAN); + cp++; + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SPS30, XSNS_96,"clean_fan"); + } else { + serviced=false; + } + } + return serviced; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + + +bool Xsns44(byte function) +{ + bool result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_INIT: + SPS30_Detect(); + break; + case FUNC_EVERY_SECOND: + SPS30_Every_Second(); + break; + case FUNC_JSON_APPEND: + SPS30_Show(1); + break; + case FUNC_COMMAND_SENSOR: + if (XSNS_44 == XdrvMailbox.index) { + result = XSNS_44_cmd(); + } + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + SPS30_Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_SPS30 +#endif // USE_I2C From c3fd4b4cab3edd07ee49f08f134f8353e3b59e33 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Tue, 21 May 2019 06:44:44 +0200 Subject: [PATCH 25/31] update sps30 --- sonoff/my_user_config.h | 1 + sonoff/xsns_44_sps30.ino | 34 +++++++++++++--------------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 2453d2ce5..846a0973b 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -346,6 +346,7 @@ // #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) // #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) // #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) +// #define USE_SPS30 // Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+3k3 code) #define USE_ADE7953 // Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) // #define USE_DISPLAY // Add I2C Display Support (+2k code) diff --git a/sonoff/xsns_44_sps30.ino b/sonoff/xsns_44_sps30.ino index 38a09f151..df0cce440 100644 --- a/sonoff/xsns_44_sps30.ino +++ b/sonoff/xsns_44_sps30.ino @@ -139,17 +139,9 @@ void SPS30_Detect() { #define D_UNIT_NCPM "#/m3" #ifdef USE_WEBSERVER -const char HTTP_SNS_SPS30_a[] PROGMEM ="{s}SPS30 " "PM 1.0" "{m}%s " D_UNIT_PM "{e}"; -const char HTTP_SNS_SPS30_b[] PROGMEM ="{s}SPS30 " "PM 2.5" "{m}%s " D_UNIT_PM "{e}"; -const char HTTP_SNS_SPS30_c[] PROGMEM ="{s}SPS30 " "PM 4.0" "{m}%s " D_UNIT_PM "{e}"; -const char HTTP_SNS_SPS30_d[] PROGMEM ="{s}SPS30 " "PM 10" "{m}%s " D_UNIT_PM "{e}"; -const char HTTP_SNS_SPS30_e[] PROGMEM ="{s}SPS30 " "NCPM 0.5" "{m}%s " D_UNIT_NCPM "{e}"; -const char HTTP_SNS_SPS30_f[] PROGMEM ="{s}SPS30 " "NCPM 1.0" "{m}%s " D_UNIT_NCPM "{e}"; -const char HTTP_SNS_SPS30_g[] PROGMEM ="{s}SPS30 " "NCPM 2.5" "{m}%s " D_UNIT_NCPM "{e}"; -const char HTTP_SNS_SPS30_h[] PROGMEM ="{s}SPS30 " "NCPM 4.0" "{m}%s " D_UNIT_NCPM "{e}"; -const char HTTP_SNS_SPS30_i[] PROGMEM ="{s}SPS30 " "NCPM 10" "{m}%s " D_UNIT_NCPM "{e}"; -const char HTTP_SNS_SPS30_j[] PROGMEM ="{s}SPS30 " "TYPSIZ" "{m}%s " "um" "{e}"; - +const char HTTP_SNS_SPS30_a[] PROGMEM ="{s}SPS30 " "%s" "{m}%s " D_UNIT_PM "{e}"; +const char HTTP_SNS_SPS30_b[] PROGMEM ="{s}SPS30 " "%s" "{m}%s " D_UNIT_NCPM "{e}"; +const char HTTP_SNS_SPS30_c[] PROGMEM ="{s}SPS30 " "TYPSIZ" "{m}%s " "um" "{e}"; #endif // USE_WEBSERVER #define PMDP 2 @@ -225,25 +217,25 @@ void SPS30_Show(bool json) { #ifdef USE_WEBSERVER } else { dtostrfd(sps30_result.PM1_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_a,str); + WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 1.0",str); dtostrfd(sps30_result.PM2_5,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_b,str); + WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 2.5",str); dtostrfd(sps30_result.PM4_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_c,str); + WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 4.0",str); dtostrfd(sps30_result.PM10,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_d,str); + WSContentSend_PD(HTTP_SNS_SPS30_a,"PM 10",str); dtostrfd(sps30_result.NCPM0_5,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_e,str); + WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 0.5",str); dtostrfd(sps30_result.NCPM1_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_f,str); + WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 1.0",str); dtostrfd(sps30_result.NCPM2_5,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_g,str); + WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 2.5",str); dtostrfd(sps30_result.NCPM4_0,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_h,str); + WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 4.0",str); dtostrfd(sps30_result.NCPM10,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_i,str); + WSContentSend_PD(HTTP_SNS_SPS30_b,"NCPM 10",str); dtostrfd(sps30_result.TYPSIZ,PMDP,str); - WSContentSend_PD(HTTP_SNS_SPS30_j,str); + WSContentSend_PD(HTTP_SNS_SPS30_c,str); #endif } From 720eeef0ebe0c29b86313dcb26d7160c24c3d501 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Tue, 21 May 2019 06:52:01 +0200 Subject: [PATCH 26/31] some fixes --- platformio.ini | 8 ++++---- sonoff/my_user_config.h | 2 +- sonoff/xsns_44_sps30.ino | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index f721a496a..d92fad447 100755 --- a/platformio.ini +++ b/platformio.ini @@ -70,14 +70,14 @@ build_flags = ${esp82xx_defaults.build_flags} platform = espressif8266@~2.1.1 build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 -O2 -DBEARSSL_SSL_BASIC ; nonos-sdk 22x -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x ; nonos-sdk-pre-v3 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -; lwIP 1.4 +; lwIP 1.4 ; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH ; lwIP 2 - Low Memory ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY @@ -96,13 +96,13 @@ build_flags = ${esp82xx_defaults.build_flags} platform = https://github.com/platformio/platform-espressif8266.git#feature/stage build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 -O2 -DBEARSSL_SSL_BASIC ; nonos-sdk 22x -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x ; nonos-sdk-pre-v3 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 +; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 ; lwIP 1.4 ; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH ; lwIP 2 - Low Memory diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index 846a0973b..6786f755b 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -346,7 +346,7 @@ // #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) // #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) // #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) -// #define USE_SPS30 // Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+3k3 code) + #define USE_SPS30 // Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code) #define USE_ADE7953 // Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) // #define USE_DISPLAY // Add I2C Display Support (+2k code) diff --git a/sonoff/xsns_44_sps30.ino b/sonoff/xsns_44_sps30.ino index df0cce440..1cc4267b9 100644 --- a/sonoff/xsns_44_sps30.ino +++ b/sonoff/xsns_44_sps30.ino @@ -1,5 +1,5 @@ /* - xsns_96_sps30.ino - Sensirion SPS30 + xsns_44_sps30.ino - Sensirion SPS30 Copyright (C) 2019 Gerhard Mutz and Theo Arends @@ -252,7 +252,7 @@ bool XSNS_44_cmd(void) { // clean cmd sps30_cmd(SPS_CMD_CLEAN); cp++; - snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SPS30, XSNS_96,"clean_fan"); + snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_SPS30, XSNS_44,"clean_fan"); } else { serviced=false; } From 44b471d84bf91af2f26f56a3edcf652c66cb3f91 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Tue, 21 May 2019 06:53:31 +0200 Subject: [PATCH 27/31] Update platformio.ini --- platformio.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index d92fad447..f721a496a 100755 --- a/platformio.ini +++ b/platformio.ini @@ -70,14 +70,14 @@ build_flags = ${esp82xx_defaults.build_flags} platform = espressif8266@~2.1.1 build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 -O2 -DBEARSSL_SSL_BASIC ; nonos-sdk 22x -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x ; nonos-sdk-pre-v3 ; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 -; lwIP 1.4 +; lwIP 1.4 ; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH ; lwIP 2 - Low Memory ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY @@ -96,13 +96,13 @@ build_flags = ${esp82xx_defaults.build_flags} platform = https://github.com/platformio/platform-espressif8266.git#feature/stage build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld -; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 +; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 -O2 -DBEARSSL_SSL_BASIC ; nonos-sdk 22x -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x ; nonos-sdk-pre-v3 -; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 +; -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK3 ; lwIP 1.4 ; -DPIO_FRAMEWORK_ARDUINO_LWIP_HIGHER_BANDWIDTH ; lwIP 2 - Low Memory From 7204f85a3afe58b2833e11382f477e67eaddbcba Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 21 May 2019 10:39:54 +0200 Subject: [PATCH 28/31] Add support for SPS30 Particle sensor thanks to Gerhard Mutz (#5830) Add support for SPS30 Particle sensor thanks to Gerhard Mutz (#5830) --- sonoff/_changelog.ino | 1 + sonoff/settings.h | 3 ++- sonoff/xsns_44_sps30.ino | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 4e4ef94e6..15556b72d 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -5,6 +5,7 @@ * Add HX711 weight restore after controlled restart or after power restore just before executing command Sensor34 7 (#5367, #5786) * Remove define USE_EMULATION from my_user_config.h (#5826) * Add defines USE_EMULATION_WEMO and USE_EMULATION_HUE to my_user_config.h to control emulation features at compile time (#5826) + * Add support for SPS30 Particle sensor thanks to Gerhard Mutz (#5830) * * 6.5.0.10 20190513 * Enable ADC0 by default in my_user_config.h (#5671) diff --git a/sonoff/settings.h b/sonoff/settings.h index 199c85f62..03529e8fa 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -211,8 +211,9 @@ struct SYSCFG { uint8_t weblog_level; // 1AC uint8_t mqtt_fingerprint[2][20]; // 1AD - uint8_t free_1D5[20]; // 1D5 Free since 5.12.0e + uint8_t free_1D5[19]; // 1D5 Free since 5.12.0e + uint8_t sps30_inuse_hours; // 1E8 char mqtt_host[33]; // 1E9 - Keep together with below as being copied as one chunck with reset 6 uint16_t mqtt_port; // 20A - Keep together char mqtt_client[33]; // 20C - Keep together diff --git a/sonoff/xsns_44_sps30.ino b/sonoff/xsns_44_sps30.ino index 1cc4267b9..dfb96b912 100644 --- a/sonoff/xsns_44_sps30.ino +++ b/sonoff/xsns_44_sps30.ino @@ -146,9 +146,9 @@ const char HTTP_SNS_SPS30_c[] PROGMEM ="{s}SPS30 " "TYPSIZ" "{m}%s " "um" "{e}"; #define PMDP 2 -//#define SPS30_HOURS Settings.sps30_inuse_hours -#define SPS30_HOURS sps30_inuse_hours -uint8_t sps30_inuse_hours; +#define SPS30_HOURS Settings.sps30_inuse_hours +//#define SPS30_HOURS sps30_inuse_hours +//uint8_t sps30_inuse_hours; void SPS30_Every_Second() { From 10a9ca6c5e03dce77898fc7a00d247d2ee8ce14a Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Tue, 21 May 2019 11:13:35 +0200 Subject: [PATCH 29/31] decode-config.py: adapt settings - fix some -g groupsnames not accepted --- tools/decode-config.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/decode-config.py b/tools/decode-config.py index d05b8ff49..f3e2b526b 100755 --- a/tools/decode-config.py +++ b/tools/decode-config.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -VER = '2.2.0025' +VER = '2.2.0026' """ decode-config.py - Backup/Restore Sonoff-Tasmota configuration data @@ -903,7 +903,13 @@ Setting_6_5_0_9['flag3'][0].update ({ 'no_power_feedback': (' 0: - groups.add(group) + groups.add(group.title()) if isinstance(format_, dict): subgroups = GetGroupList(format_) if subgroups is not None and len(subgroups) > 0: for group in subgroups: - groups.add(group) + groups.add(group.title()) groups=list(groups) groups.sort() From 119f124a1d74f851e05459f6fab7532daea15f89 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Tue, 21 May 2019 11:36:00 +0200 Subject: [PATCH 30/31] Bugfix Core 2.5.2 release --- platformio.ini | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platformio.ini b/platformio.ini index f721a496a..351d1ba02 100755 --- a/platformio.ini +++ b/platformio.ini @@ -65,9 +65,9 @@ build_flags = ${esp82xx_defaults.build_flags} -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -DVTABLES_IN_FLASH -[core_2_5_1] -; *** Esp8266 core for Arduino version 2.5.1 -platform = espressif8266@~2.1.1 +[core_2_5_2] +; *** Esp8266 core for Arduino version 2.5.2 +platform = espressif8266@~2.2.0 build_flags = ${esp82xx_defaults.build_flags} -Wl,-Teagle.flash.1m.ld ; Code optimization see https://github.com/esp8266/Arduino/issues/5790#issuecomment-475672473 @@ -133,8 +133,8 @@ build_flags = ${esp82xx_defaults.build_flags} ;build_flags = ${core_2_3_0.build_flags} ;platform = ${core_2_4_2.platform} ;build_flags = ${core_2_4_2.build_flags} -platform = ${core_2_5_1.platform} -build_flags = ${core_2_5_1.build_flags} +platform = ${core_2_5_2.platform} +build_flags = ${core_2_5_2.build_flags} ;platform = ${core_stage.platform} ;build_flags = ${core_stage.build_flags} From 763118b6265b25d317eabfd60234fb558fded1b2 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 21 May 2019 18:11:39 +0200 Subject: [PATCH 31/31] 6.5.0.12 Add support for link LED and four power LEDs 6.5.0.12 20190521 * Add AriLux RF control GPIO option "ALux IrSel" (159) replacing "Led4i" (59) for full LED control (#5709) * Add LED GPIO option "LedLink" (157) and "LedLinki" (158) to select dedicated link status LED (#5709) * Add support for up to four LEDs related to four power outputs. Enabled when "LedLink(i)" is configured too (#5709) * Add extended LED power control using command LedPowerX where X is 1 to 4. Enabled when "LedLink(i)" is configured too (#5709) --- sonoff/_changelog.ino | 8 +- sonoff/language/bg-BG.h | 2 + sonoff/language/cs-CZ.h | 2 + sonoff/language/de-DE.h | 2 + sonoff/language/el-GR.h | 2 + sonoff/language/en-GB.h | 2 + sonoff/language/es-ES.h | 2 + sonoff/language/fr-FR.h | 2 + sonoff/language/he-HE.h | 2 + sonoff/language/hu-HU.h | 2 + sonoff/language/it-IT.h | 2 + sonoff/language/ko-KO.h | 2 + sonoff/language/nl-NL.h | 2 + sonoff/language/pl-PL.h | 2 + sonoff/language/pt-BR.h | 2 + sonoff/language/pt-PT.h | 2 + sonoff/language/ru-RU.h | 2 + sonoff/language/sk-SK.h | 2 + sonoff/language/sv-SE.h | 2 + sonoff/language/tr-TR.h | 2 + sonoff/language/uk-UK.h | 2 + sonoff/language/zh-CN.h | 2 + sonoff/language/zh-TW.h | 2 + sonoff/sonoff.ino | 153 +++++++++++++++++++++++++++++++++++---- sonoff/sonoff_template.h | 56 ++++++++------ sonoff/sonoff_version.h | 2 +- sonoff/xdrv_04_light.ino | 14 ++-- 27 files changed, 231 insertions(+), 46 deletions(-) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index 15556b72d..5b2497eb5 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,10 @@ -/* 6.5.0.11 20190517 +/* 6.5.0.12 20190521 + * Add AriLux RF control GPIO option "ALux IrSel" (159) replacing "Led4i" (59) for full LED control (#5709) + * Add LED GPIO option "LedLink" (157) and "LedLinki" (158) to select dedicated link status LED (#5709) + * Add support for up to four LEDs related to four power outputs. Enabled when "LedLink(i)" is configured too (#5709) + * Add extended LED power control using command LedPowerX where X is 1 to 4. Enabled when "LedLink(i)" is configured too (#5709) + * + * 6.5.0.11 20190517 * Add command SetOption64 0/1 to switch between "-" or "_" as sensor index separator impacting DS18X20, DHT, BMP and SHT3X sensor names (#5689) * Add initial support for Scripts as replacement for Rules. Default disabled but can be enabled in my_user_config.h (#5689) * Add rule System#Save executed just before a planned restart diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index a1913c612..3209cc101 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -513,6 +513,7 @@ #define D_SENSOR_BUTTON "Бутон" // Suffix "1" #define D_SENSOR_RELAY "Реле" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Брояч" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -578,6 +579,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index fcf9b7ec5..8a919715a 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Tlačítko" // Suffix "1" #define D_SENSOR_RELAY "Relé" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1", #define D_SENSOR_COUNTER "Počítadlo" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 171256aa8..efc1b737a 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index 238ad7050..155bf2f4f 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index d8a78cec0..8d300a711 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/es-ES.h b/sonoff/language/es-ES.h index caddf2f06..24200b752 100644 --- a/sonoff/language/es-ES.h +++ b/sonoff/language/es-ES.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Botón" // Suffix "1" #define D_SENSOR_RELAY "Relé" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Contador" // Suffix "1" #define D_SENSOR_IRRECV "IR Rx" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index ac60a779e..493e8b395 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Bouton" // Suffix "1" #define D_SENSOR_RELAY "Relais" // Suffix "1i" #define D_SENSOR_LED "LED" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Compteur" // Suffix "1" #define D_SENSOR_IRRECV "RécptIR" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index 86811cae7..c36f050a7 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "לחצן" // Suffix "1" #define D_SENSOR_RELAY "ממסר" // Suffix "1i" #define D_SENSOR_LED "לד" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "מונה" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 50e266aa5..3b3ef7821 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Gomb" // Suffix "1" #define D_SENSOR_RELAY "Relé" // Suffix "1i" #define D_SENSOR_LED "LED" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Számláló" // Suffix "1" #define D_SENSOR_IRRECV "IR vevő" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 082526cb8..9078bc81e 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/ko-KO.h b/sonoff/language/ko-KO.h index be7c36b64..37c289963 100644 --- a/sonoff/language/ko-KO.h +++ b/sonoff/language/ko-KO.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 565ff2164..4525ce5cb 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relais" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Teller" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 6605e6867..a2ed0721c 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Przyci" // Suffix "1" #define D_SENSOR_RELAY "Przek" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Liczni" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index 953fbe979..c66867178 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Botão" // Suffix "1" #define D_SENSOR_RELAY "Relé" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Contador" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 880471f69..334844a72 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Botão" // Suffix "1" #define D_SENSOR_RELAY "Relé" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Contador" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index 2f56eb44f..071be1394 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Кнопка" // Suffix "1" #define D_SENSOR_RELAY "Реле" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Счетчик" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/sk-SK.h b/sonoff/language/sk-SK.h index 92b551488..7cdea4177 100644 --- a/sonoff/language/sk-SK.h +++ b/sonoff/language/sk-SK.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Tlačidlo" // Suffix "1" #define D_SENSOR_RELAY "Relé" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1", #define D_SENSOR_COUNTER "Počítadlo" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/sv-SE.h b/sonoff/language/sv-SE.h index e34847480..f6b0638bd 100644 --- a/sonoff/language/sv-SE.h +++ b/sonoff/language/sv-SE.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Knapp" // Suffix "1" #define D_SENSOR_RELAY "Relä" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Räknare" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index f6a7ba233..dc764d006 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 54b2bfa39..6f4d6208c 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Кнопка" // Suffix "1" #define D_SENSOR_RELAY "Реле" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Лічильник" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index be8e1c91c..a1bca5a88 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 07d63e30a..9b87d03f3 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -512,6 +512,7 @@ #define D_SENSOR_BUTTON "Button" // Suffix "1" #define D_SENSOR_RELAY "Relay" // Suffix "1i" #define D_SENSOR_LED "Led" // Suffix "1i" +#define D_SENSOR_LED_LINK "LedLink" // Suffix "i" #define D_SENSOR_PWM "PWM" // Suffix "1" #define D_SENSOR_COUNTER "Counter" // Suffix "1" #define D_SENSOR_IRRECV "IRrecv" @@ -577,6 +578,7 @@ #define D_SENSOR_MY92X1_DI "MY92x1 DI" #define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" +#define D_SENSOR_ARIRFSEL "ALux IrSel" #define D_SENSOR_TXD "Serial Tx" #define D_SENSOR_RXD "Serial Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index e04619fdf..ef9845c81 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -142,7 +142,10 @@ uint8_t backlog_pointer = 0; // Command backlog pointer uint8_t sleep; // Current copy of Settings.sleep uint8_t blinkspeed = 1; // LED blink rate uint8_t pin[GPIO_MAX]; // Possible pin configurations +uint8_t leds_present = 0; // Max number of LED supported uint8_t led_inverted = 0; // LED inverted flag (1 = (0 = On, 1 = Off)) +uint8_t led_power = 0; // LED power state +uint8_t ledlnk_inverted = 0; // Link LED inverted flag (1 = (0 = On, 1 = Off)) uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted) uint8_t counter_no_pullup = 0; // Counter input pullup flag (1 = No pullup) uint8_t energy_flg = 0; // Energy monitor configured @@ -369,19 +372,56 @@ void SetDevicePower(power_t rpower, int source) } } +void SetLedPowerIdx(uint8_t led, uint8_t state) +{ + if ((99 == pin[GPIO_LEDLNK]) && (0 == led)) { // Legacy - LED1 is link led only if LED2 is present + if (pin[GPIO_LED2] < 99) { led = 1; } + } + if (pin[GPIO_LED1 + led] < 99) { + uint8_t mask = 1 << led; + if (state) { + state = 1; + led_power |= mask; + } else { + led_power &= (0xFF ^ mask); + } + digitalWrite(pin[GPIO_LED1 + led], bitRead(led_inverted, led) ? !state : state); + } +} + void SetLedPower(uint8_t state) { - if (state) { state = 1; } + if (99 == pin[GPIO_LEDLNK]) { // Legacy - Only use LED1 and/or LED2 + SetLedPowerIdx(0, state); + } else { + power_t mask = 1; + for (uint8_t i = 0; i < leds_present; i++) { // Map leds to power + bool tstate = (power & mask); + SetLedPowerIdx(i, tstate); + mask <<= 1; + } + } +} - uint8_t led_pin = 0; - if (pin[GPIO_LED2] < 99) { led_pin = 1; } - digitalWrite(pin[GPIO_LED1 + led_pin], (bitRead(led_inverted, led_pin)) ? !state : state); +void SetLedPowerAll(uint8_t state) +{ + for (uint8_t i = 0; i < leds_present; i++) { + SetLedPowerIdx(i, state); + } } void SetLedLink(uint8_t state) { - if (state) { state = 1; } - digitalWrite(pin[GPIO_LED1], (bitRead(led_inverted, 0)) ? !state : state); + uint8_t led_pin = pin[GPIO_LEDLNK]; + uint8_t led_inv = ledlnk_inverted; + if (99 == led_pin) { // Legacy - LED1 is status + led_pin = pin[GPIO_LED1]; + led_inv = bitRead(led_inverted, 0); + } + if (led_pin < 99) { + if (state) { state = 1; } + digitalWrite(led_pin, (led_inv) ? !state : state); + } } uint8_t GetFanspeed(void) @@ -1421,7 +1461,8 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) } Response_P(S_JSON_COMMAND_NVALUE, command, Settings.altitude); } - else if (CMND_LEDPOWER == command_code) { + else if ((CMND_LEDPOWER == command_code) && (index > 0) && (index <= MAX_LEDS)) { +/* if ((payload >= 0) && (payload <= 2)) { Settings.ledstate &= 8; switch (payload) { @@ -1434,15 +1475,83 @@ void MqttDataHandler(char* topic, uint8_t* data, unsigned int data_len) break; } blinks = 0; - SetLedPower(Settings.ledstate &8); + SetLedPowerIdx(index -1, Settings.ledstate &8); } - Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(bitRead(Settings.ledstate, 3))); + Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(bitRead(Settings.ledstate, 3))); +*/ +/* + if (99 == pin[GPIO_LEDLNK]) { + if ((payload >= 0) && (payload <= 2)) { + Settings.ledstate &= 8; + switch (payload) { + case 0: // Off + case 1: // On + Settings.ledstate = payload << 3; + break; + case 2: // Toggle + Settings.ledstate ^= 8; + break; + } + blinks = 0; + SetLedPower(Settings.ledstate &8); + } + Response_P(S_JSON_COMMAND_SVALUE, command, GetStateText(bitRead(Settings.ledstate, 3))); + } else { + if ((payload >= 0) && (payload <= 2)) { + Settings.ledstate &= 8; // Disable power control + uint8_t mask = 1 << (index -1); // Led to control + switch (payload) { + case 0: // Off + led_power &= (0xFF ^ mask); + case 1: // On + led_power |= mask; + break; + case 2: // Toggle + led_power ^= mask; + break; + } + blinks = 0; + SetLedPowerIdx(index -1, (led_power & mask)); + } + Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(bitRead(led_power, index -1))); + } +*/ + if (99 == pin[GPIO_LEDLNK]) { index = 1; } + if ((payload >= 0) && (payload <= 2)) { + Settings.ledstate &= 8; // Disable power control + uint8_t mask = 1 << (index -1); // Led to control + switch (payload) { + case 0: // Off + led_power &= (0xFF ^ mask); + Settings.ledstate = 0; + break; + case 1: // On + led_power |= mask; + Settings.ledstate = 8; + break; + case 2: // Toggle + led_power ^= mask; + Settings.ledstate ^= 8; + break; + } + blinks = 0; + if (99 == pin[GPIO_LEDLNK]) { + SetLedPower(Settings.ledstate &8); + } else { + SetLedPowerIdx(index -1, (led_power & mask)); + } + } + uint8_t state = bitRead(led_power, index -1); + if (99 == pin[GPIO_LEDLNK]) { + state = bitRead(Settings.ledstate, 3); + } + Response_P(S_JSON_COMMAND_INDEX_SVALUE, command, index, GetStateText(state)); } else if (CMND_LEDSTATE == command_code) { if ((payload >= 0) && (payload < MAX_LED_OPTION)) { Settings.ledstate = payload; if (!Settings.ledstate) { - SetLedPower(0); + SetLedPowerAll(0); SetLedLink(0); } } @@ -2030,8 +2139,6 @@ void Every250mSeconds(void) } } if ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) { -// if ( (!Settings.flag.global_state && global_state.data) || ((!(Settings.ledstate &0x08)) && ((Settings.ledstate &0x06) || (blinks > 200) || (blinkstate))) ) { -// SetLedPower(blinkstate); // Set led on or off SetLedLink(blinkstate); // Set led on or off } if (!blinkstate) { @@ -2456,6 +2563,10 @@ void GpioInit(void) bitSet(led_inverted, mpin - GPIO_LED1_INV); mpin -= (GPIO_LED1_INV - GPIO_LED1); } + else if (mpin == GPIO_LEDLNK_INV) { + ledlnk_inverted = 1; + mpin -= (GPIO_LEDLNK_INV - GPIO_LEDLNK); + } else if ((mpin >= GPIO_PWM1_INV) && (mpin < (GPIO_PWM1_INV + MAX_PWMS))) { bitSet(pwm_inverted, mpin - GPIO_PWM1_INV); mpin -= (GPIO_PWM1_INV - GPIO_PWM1); @@ -2567,10 +2678,24 @@ void GpioInit(void) for (uint8_t i = 0; i < MAX_LEDS; i++) { if (pin[GPIO_LED1 +i] < 99) { - pinMode(pin[GPIO_LED1 +i], OUTPUT); - digitalWrite(pin[GPIO_LED1 +i], bitRead(led_inverted, i)); +#ifdef USE_ARILUX_RF + if ((3 == i) && (leds_present < 2) && (99 == pin[GPIO_ARIRFSEL])) { + pin[GPIO_ARIRFSEL] = pin[GPIO_LED4]; // Legacy support where LED4 was Arilux RF enable + pin[GPIO_LED4] = 99; + } else { +#endif + pinMode(pin[GPIO_LED1 +i], OUTPUT); + leds_present++; + digitalWrite(pin[GPIO_LED1 +i], bitRead(led_inverted, i)); +#ifdef USE_ARILUX_RF + } +#endif } } + if (pin[GPIO_LEDLNK] < 99) { + pinMode(pin[GPIO_LEDLNK], OUTPUT); + digitalWrite(pin[GPIO_LEDLNK], ledlnk_inverted); + } ButtonInit(); SwitchInit(); diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 071c1f420..2cf4404f6 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -171,7 +171,7 @@ enum UserSelectablePins { GPIO_DCKI, // my92x1 CLK input GPIO_CSE7766_TX, // CSE7766 Serial interface (S31 and Pow R2) GPIO_CSE7766_RX, // CSE7766 Serial interface (S31 and Pow R2) - GPIO_ARIRFRCV, // AliLux RF Receive input + GPIO_ARIRFRCV, // AriLux RF Receive input GPIO_TXD, // Serial interface GPIO_RXD, // Serial interface GPIO_ROT1A, // Rotary switch1 A Pin @@ -181,6 +181,9 @@ enum UserSelectablePins { GPIO_HRE_CLOCK, // Clock/Power line for HR-E Water Meter GPIO_HRE_DATA, // Data line for HR-E Water Meter GPIO_ADE7953_IRQ, // ADE7953 IRQ + GPIO_LEDLNK, // Link led + GPIO_LEDLNK_INV, // Inverted link led + GPIO_ARIRFSEL, // Arilux RF Receive input selected GPIO_SENSOR_END }; // Programmer selectable GPIO functionality @@ -246,6 +249,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_ROTARY "1a|" D_SENSOR_ROTARY "1b|" D_SENSOR_ROTARY "2a|" D_SENSOR_ROTARY "2b|" D_SENSOR_HRE_CLOCK "|" D_SENSOR_HRE_DATA "|" D_SENSOR_ADE7953_IRQ "|" + D_SENSOR_LED_LINK "|" D_SENSOR_LED_LINK "i|" + D_SENSOR_ARIRFSEL "|" ; // User selectable ADC0 functionality @@ -448,6 +453,8 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_LED3_INV, GPIO_LED4, GPIO_LED4_INV, + GPIO_LEDLNK, // Link led + GPIO_LEDLNK_INV, // Inverted link led GPIO_PWM1, // RGB Red or C Cold White GPIO_PWM1_INV, GPIO_PWM2, // RGB Green or CW Warm White @@ -616,7 +623,8 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_ROT2B, // Rotary switch2 B Pin #endif #ifdef USE_ARILUX_RF - GPIO_ARIRFRCV, // AliLux RF Receive input + GPIO_ARIRFRCV, // AriLux RF Receive input + GPIO_ARIRFSEL, // Arilux RF Receive input selected #endif #ifdef USE_HRE GPIO_HRE_CLOCK, @@ -1109,9 +1117,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0 }, { "Huafan SS", // Hua Fan Smart Socket (ESP8266) - like Sonoff Pow - GPIO_LED1_INV, // GPIO00 Blue Led (0 = On, 1 = Off) - Link status + GPIO_LEDLNK_INV, // GPIO00 Blue Led (0 = On, 1 = Off) - Link status 0, 0, - GPIO_LED2_INV, // GPIO03 Red Led (0 = On, 1 = Off) - Power status + GPIO_LED1_INV, // GPIO03 Red Led (0 = On, 1 = Off) - Power status GPIO_KEY1, // GPIO04 Button GPIO_REL1_INV, // GPIO05 Relay (0 = On, 1 = Off) // GPIO06 (SD_CLK Flash) @@ -1304,7 +1312,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_PWM3, // GPIO12 RGB LED Blue GPIO_USER, // GPIO13 RGBW LED White (optional - set to PWM4 for Cold White or Warm White as used on Arilux LC10) GPIO_PWM1, // GPIO14 RGB LED Red - GPIO_LED4_INV, // GPIO15 RF receiver control (Arilux LC10) + GPIO_ARIRFSEL, // GPIO15 RF receiver control (Arilux LC10) 0, 0 }, { "Luani HVIO", // ESP8266_HVIO @@ -1350,7 +1358,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // (PwmFrequency 1111Hz) GPIO_KEY1, // GPIO00 Optional Button GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED4_INV, // GPIO02 RF receiver control + GPIO_ARIRFSEL, // GPIO02 RF receiver control GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_ARIRFRCV, // GPIO04 IR or RF receiver (optional) GPIO_PWM1, // GPIO05 RGB LED Red @@ -1370,7 +1378,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // (PwmFrequency 540Hz) GPIO_KEY1, // GPIO00 Optional Button GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED4_INV, // GPIO02 RF receiver control + GPIO_ARIRFSEL, // GPIO02 RF receiver control GPIO_USER, // GPIO03 Serial TXD and Optional sensor GPIO_PWM2, // GPIO04 RGB LED Green GPIO_PWM1, // GPIO05 RGB LED Red @@ -1498,9 +1506,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { // https://www.amazon.de/Steckdose-Homecube-intelligente-Verbrauchsanzeige-funktioniert/dp/B076Q2LKHG/ref=sr_1_fkmr0_1 // https://www.amazon.de/Intelligente-Stromverbrauch-Fernsteurung-Schaltbare-Energieklasse/dp/B076WZQS4S/ref=sr_1_1 // https://www.aliexpress.com/store/product/BlitzWolf-BW-SHP6-EU-Plug-Metering-Version-WIFI-Smart-Socket-220V-240V-10A-Work-with-Amazon/1965360_32945504669.html - GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status + GPIO_LED1_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status GPIO_USER, // GPIO01 Serial RXD and Optional sensor - GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status + GPIO_LEDLNK_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status GPIO_USER, // GPIO03 Serial TXD and Optional sensor 0, GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power @@ -1624,7 +1632,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, GPIO_KEY1, // GPIO01 Serial TXD and Button 0, - GPIO_LED2_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) - Power status + GPIO_LED1_INV, // GPIO03 Serial RXD and Red Led (0 = On, 1 = Off) - Power status GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power GPIO_NRG_CF1, // GPIO05 BL0937 or HJL-01 CF1 current / voltage // GPIO06 (SD_CLK Flash) @@ -1634,7 +1642,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) - GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link status + GPIO_LEDLNK_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link status GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On) 0, 0, 0 }, @@ -1678,7 +1686,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { }, { "Gosund SP1 v23", // https://www.amazon.de/gp/product/B0777BWS1P 0, - GPIO_LED1_INV, // GPIO01 Serial RXD and LED1 (blue) inv - Link status + GPIO_LEDLNK_INV, // GPIO01 Serial RXD and LED1 (blue) inv - Link status 0, GPIO_KEY1, // GPIO03 Serial TXD and Button GPIO_HJL_CF, // GPIO04 BL0937 or HJL-01 CF power @@ -1690,7 +1698,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 BL0937 or HJL-01 Sel output (0 = Voltage) - GPIO_LED2_INV, // GPIO13 LED2 (red) inv - Power status + GPIO_LED1_INV, // GPIO13 LED2 (red) inv - Power status GPIO_REL1, // GPIO14 Relay (0 = Off, 1 = On) 0, 0, 0 }, @@ -1728,8 +1736,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 HLW8012 CF Sel output (0 = Voltage) - GPIO_LED2_INV, // GPIO13 Red Led (0 = On, 1 = Off) - Power status - GPIO_LED1_INV, // GPIO14 Blue Led (0 = On, 1 = Off) - Link status + GPIO_LED1_INV, // GPIO13 Red Led (0 = On, 1 = Off) - Power status + GPIO_LEDLNK_INV, // GPIO14 Blue Led (0 = On, 1 = Off) - Link status GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On) 0, 0 }, @@ -1757,9 +1765,9 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { { "Teckin US", // Teckin SP20 US with Energy Monitoring // https://www.amazon.com/Outlet-Compatible-Monitoring-Function-Required/dp/B079Q5W22B // https://www.amazon.com/Outlet-ZOOZEE-Monitoring-Function-Compatible/dp/B07J2LR5KN - GPIO_LED2_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status + GPIO_LED1_INV, // GPIO00 Red Led (1 = On, 0 = Off) - Power status 0, - GPIO_LED1_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status + GPIO_LEDLNK_INV, // GPIO02 Blue Led (1 = On, 0 = Off) - Link status 0, GPIO_REL1, // GPIO04 Relay (0 = Off, 1 = On) GPIO_HJL_CF, // GPIO05 BL0937 or HJL-01 CF power @@ -1809,8 +1817,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO09 (SD_DATA2 Flash QIO or ESP8285) 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) // GPIO11 (SD_CMD Flash) - GPIO_LED1_INV, // GPIO12 Green LED - Link status - GPIO_LED2, // GPIO13 Red LED - Power status + GPIO_LEDLNK_INV, // GPIO12 Green LED - Link status + GPIO_LED1, // GPIO13 Red LED - Power status 0, 0, 0, 0 }, { "YTF IR Bridge", // https://www.aliexpress.com/item/Tuya-universal-Smart-IR-Hub-remote-control-Voice-Control-AC-TV-Work-With-Alexa-Google-Home/32951202513.html @@ -1854,7 +1862,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { }, { "KA10", // SMANERGY KA10 (ESP8285 - BL0937 Energy Monitoring) - https://www.amazon.es/dp/B07MBTCH2Y 0, // GPIO00 - GPIO_LED1_INV, // GPIO01 Blue LED - Link status + GPIO_LEDLNK_INV, // GPIO01 Blue LED - Link status 0, // GPIO02 GPIO_KEY1, // GPIO03 Button GPIO_HJL_CF, // GPIO04 BL0937 CF power @@ -1866,7 +1874,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO10 (SD_DATA3 Flash QIO or ESP8285) // GPIO11 (SD_CMD Flash) GPIO_NRG_SEL_INV, // GPIO12 BL0937 Sel output (1 = Voltage) - GPIO_LED2, // GPIO13 Red LED - Power status + GPIO_LED1, // GPIO13 Red LED - Power status GPIO_REL1, // GPIO14 Relay 1 0, 0, 0 }, @@ -1923,7 +1931,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { }, { "WAGA CHCZ02MB", // WAGA life CHCZ02MB (HJL-01 Energy Monitoring) // https://www.ebay.com/itm/332595697006 - GPIO_LED2_INV, // GPIO00 Red LED + GPIO_LED1_INV, // GPIO00 Red LED 0, // GPIO01 Serial RXD 0, // GPIO02 GPIO_NRG_SEL_INV, // GPIO03 HJL-01 Sel output (1 = Voltage) @@ -1938,7 +1946,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_REL1, // GPIO12 Relay GPIO_KEY1, // GPIO13 Button GPIO_NRG_CF1, // GPIO14 HJL-01 CF1 voltage / current - GPIO_LED1_INV, // GPIO15 Blue LED - Link status + GPIO_LEDLNK_INV, // GPIO15 Blue LED - Link status 0, 0 }, { "SYF05", // Sunyesmart SYF05 (a.k.a. Fcmila) = TYWE3S + SM16726 @@ -2070,7 +2078,7 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_PWM3, // GPIO12 RGB LED Blue GPIO_PWM4, // GPIO13 RGBW LED White GPIO_PWM1, // GPIO14 RGB LED Red - GPIO_LED4_INV, // GPIO15 RF receiver control + GPIO_ARIRFSEL, // GPIO15 RF receiver control 0, 0 } diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index ce4413124..e06fab8d0 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,6 +20,6 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -const uint32_t VERSION = 0x0605000B; +const uint32_t VERSION = 0x0605000C; #endif // _SONOFF_VERSION_H_ diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index a25b63d0e..90b4f872e 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -1107,23 +1107,24 @@ void AriluxRfHandler(void) void AriluxRfInit(void) { - if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED4] < 99)) { + if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_ARIRFSEL] < 99)) { if (Settings.last_module != Settings.module) { Settings.rf_code[1][6] = 0; Settings.rf_code[1][7] = 0; Settings.last_module = Settings.module; } arilux_rf_received_value = 0; - digitalWrite(pin[GPIO_LED4], !bitRead(led_inverted, 3)); // Turn on RF + + digitalWrite(pin[GPIO_ARIRFSEL], 0); // Turn on RF attachInterrupt(pin[GPIO_ARIRFRCV], AriluxRfInterrupt, CHANGE); } } void AriluxRfDisable(void) { - if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_LED4] < 99)) { + if ((pin[GPIO_ARIRFRCV] < 99) && (pin[GPIO_ARIRFSEL] < 99)) { detachInterrupt(pin[GPIO_ARIRFRCV]); - digitalWrite(pin[GPIO_LED4], bitRead(led_inverted, 3)); // Turn off RF + digitalWrite(pin[GPIO_ARIRFSEL], 1); // Turn off RF } } #endif // USE_ARILUX_RF @@ -1353,8 +1354,9 @@ void LightInit(void) } } if (pin[GPIO_ARIRFRCV] < 99) { - if (pin[GPIO_LED4] < 99) { - digitalWrite(pin[GPIO_LED4], bitRead(led_inverted, 3)); // Turn off RF + if (pin[GPIO_ARIRFSEL] < 99) { + pinMode(pin[GPIO_ARIRFSEL], OUTPUT); + digitalWrite(pin[GPIO_ARIRFSEL], 1); // Turn off RF } } }