From ecc6bb5fdc199a2fc52aa4c14423e4f500546fe8 Mon Sep 17 00:00:00 2001 From: arendst Date: Tue, 25 Apr 2017 18:24:42 +0200 Subject: [PATCH] v5.0.0 5.0.0 20170425 * Memory status message update * Fix setting migration to better preserve settings during move (#382) * Best practice is first doing a Backup Configuration before installing version 5.0.0 * Reset save count after setting move * Start using new linker script without SPIFFS --- README.md | 16 +- api/arduino/sonoff-minimal.ino.bin | Bin 422400 -> 422368 bytes api/arduino/sonoff.ino.bin | Bin 478720 -> 478736 bytes sonoff/_releasenotes.ino | 9 +- sonoff/settings.ino | 89 +++- sonoff/sonoff.ino | 784 +++++++++++++++++++---------- sonoff/support.ino | 241 +++++---- sonoff/webserver.ino | 335 ++++++++---- sonoff/xdrv_domoticz.ino | 60 ++- sonoff/xdrv_ir_send.ino | 42 +- sonoff/xdrv_snfled.ino | 90 ++-- sonoff/xdrv_snfsc.ino | 28 +- sonoff/xdrv_wemohue.ino | 64 ++- sonoff/xdrv_ws2812.ino | 110 ++-- sonoff/xsns_bh1750.ino | 11 +- sonoff/xsns_bmp.ino | 76 ++- sonoff/xsns_dht.ino | 58 ++- sonoff/xsns_ds18b20.ino | 22 +- sonoff/xsns_ds18x20.ino | 39 +- sonoff/xsns_hlw8012.ino | 119 +++-- sonoff/xsns_htu21.ino | 75 ++- sonoff/xsns_sht1x.ino | 66 ++- 22 files changed, 1575 insertions(+), 759 deletions(-) diff --git a/README.md b/README.md index 4e4d333e7..b7ae6c322 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,21 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **4.2.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **5.0.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. + +### **** ATTENTION Version 5.0.0 specific information ******* + +This version uses a new linker script to free flash memory for future code additions. It moves the settings from Spiffs to Eeprom. If you compile your own download the new linker to your IDE or Platformio base folder. + +Best practice to implement is: +- Open the webpage to your device +- Perform option ``Backup Configuration`` +- Upgrade new firmware using ``Firmware upgrade`` +- If configuration conversion failed keep the webpage open and perform ``Restore Configuration`` + +You should now have a device with 32k more code memory to play with. + +### ********************************************************* - This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. diff --git a/api/arduino/sonoff-minimal.ino.bin b/api/arduino/sonoff-minimal.ino.bin index 120748e404fea341d34d64d0625c9fa7b1539db6..92e33feb9d8d575047be3749bd1e377e41ff8e78 100644 GIT binary patch delta 50608 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 diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index ae6873b938f5ba6f296b82a39ed5dccaee64adf9..9b072715c272d46f2fdb0f7d969ef3db85567c38 100644 GIT binary patch delta 71429 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%0D@FS|l^}H}@s)@EPGC8TxUTYZm6CtQ6`x`d zTciX{;DbS6N}pm5pW<0eY>pfeCTxiE%d46-zUKduR}Lr64+l8ge#co>uFqoPBH7^- zM+NI=&If_??)Z8P&po^ef^>#tb$T18O~eahAXi5hAq8t7DX5jvSVvaAzK;kaI z!iFi(2X1@th(>*3pq5!9`u+sH(UBd(NH9FvEcCf`ZNrprD`(Zm5tK zbQBd0+}DCaMMcFOw?K4U(J-xJYK2RssfFv+v|oUZVWOc~qM>4%X)fU|ip>9eF4(X4 z|GxA2eCIjmInP<|+1H8}4=q2wL?GL_7`AbTU9IlicSJCRCy(tsSrpnTeSER|*)L!IzI709jAC7}Ypc3G z_$c0LlQ#ihAk5GlpA84{)xun|HRHz;e#L_Ao<7P|%^CeLbAwITc4it*@CLy}+|FRT z$lc*p0orVP1y2a>%kOCDD)hc>bqGMo)|4NQS%zGWFj(DOEQ9$&S4fD3FHu7O)FaEd z^3Cq=xJ0AnRZEO%X@c?feG&8T|>=p!Of?5G?dW)%;sC zoU|bQnQ;VZN^C4<1Zl4;#~gkUMnvn`oDrl`cEM8%z061dHF^tyBG`6LkHH)Udgt_f zDQA z@dbM6_y1b4cUN6Mz^&L0==q=wiW7RvUkdlt{$EKcj!RnisgCc}?QxQ^M)FrLerZ;i z2q+Bp?F|9ijsTs)br^oOARe9%^?2~*!}{RhMGL*0+)%MwIU!|t-RaymK z?RgEpT7T7J2OGj@{X}o+pde72{*m^Bv~>lfr4@S1(<^Y=`m-9et@lmMZt!ra|2$kv z_0ImU1D1|pjRKMoG(S)SoB9@((NdqEQfvv}K8{18*nDd_ceeijc(~xP0o%KP^}t>1$5;$H z2xt?EzsD|Epaj+f%YY0Z5oixoV;AsxAP>;Eu>ZVGnr3@8=JQLqekt*(?bSWgw5qc^ zzD2rQ_Whumb}19EFKG6^4x)cr)Lg4^0(v(|95)qz{2H{ zhwvi@7veNAj}m#W9q%vlJ*-_U(q_FW_d43HvT4N&ujBryAs#9vV(WBo!+0kdru*254v>qtF6 z1S8lEx=kNtz}6naHsm%{1Y7byLQ>g>>3d$qExuiGvZ2J(C0pIJ9nH6Ksr8aI z5%rR-Q*A?CwF`?g!;s145x9r~v=m1q)Y{43yKcx{9i|&`0hi^eB>~yc&xSJ8>o=68 zw1!go?my-1Dtwlbd8tg&TM{9Iqe3W@{C4=IuZ8TDJb3+ih0$McVTbv&<=c8Z@(8PM zzZSAyf{-l{Le@mR`pBan>KMx_w0(Zkhseo(wlS!7{j7an*JXmBM$G;OA|_pZ_3uj9 z7F(BH=4qezx@JzK4Y8AA)VjA8v9kp|wRrH@+2`vm?g+Vch~Dy?zil^I-!PSGJ&Q0| zyYpJ4yWSFA!vm40H>Dj`y8zhh$+rWjtCZ(?FzqXNFr|_AP1T2^vI{6KSAd0Xufu!S z5hBk(Qjh9_0tA{5EbffcFu;1KZ*{^>r)aFDK^+NN09pk**kEf)I80L;m!$fhOZE9Z z)f@Y5k@0Z*wB%pcbE|;+^)O}X`_yvzlDRls%0%*ALY?7l?X9=m;H4@7iHw`kVQ4+h zW7HAh^p-m6@e~Mnwrrl>Nc^6tDbb>P+pVZ;@W3sXFXp0F+=)e`c6z=cfJi;`mit`H z)?JT21tcM7{|}e5NAhnNsXzOZ@*w+1yu*s=@0Q_oiJyS|0$eH!{j5q}({j%R$JeEM*rf@-97>`nz z-X!hA9=cZHW~yu1F4mI0lgG_IRgc#q;6SwA@?fud+n~sp{8sIvyii-iEo5BC)JMX; zmpf(;<}nD?Uwae2Vg%Je-?R+uSObLn|KqX5dmi4BnTOD%Z;?oQ+8qzpI7$ix^&PWt z+XOvN|5!JhMYV6__K|V%4dRQ{DDHv-=xwTA2I~7Y!p*3}YH+c%MfumW7T$J{T)Y( zQM4!C)*H`LM@rGFZ174~FUV8OWzHr+py=9P^ z*`OH66{x3pC|je5hTGiHxUhHYa8F0&7!s8&U3xX-oPTi+I+l^qhNxq*6s|XA?^V|$ z@YI0`T^humM=cUdSu^#Q`AV3xK5qdS*0wb#hNv6<&{6Z}`5FB)YfpVtI2L>1l(nV$ z>{c)$jSnZ)XX#+%QSA5s)iLZLT8)7&gR%7v*6i_m%LUbbJd6#v9p44pL*Q<2{WWZH zDGtVP+$QV!86d$@bdZ;2PkpqZpDSv$k2GrE2ep{xy}zYoc4aKK4%%yVsMBh7kZgKc zs@3tUNDcOxE-iOc{%CQ(L#Ip?*buF^^gV>Yxu6spBs>c1YM+C3G^vJLey+1vRWX|m z9XW_ex_`v1vms`C3NhISW_LBr@x`rK%kd<`MUPOS6y4CB z-NZf}Pdc~}Fzi+J!IUPkYvV~Xw`Z4-YFFxcwn@x&0x=VbMNUBH_auyL=jx5@Z=pp! zAJ6y4;dr1~>W47%(-Tr9U)(coC{#~HZ8zc&WRPIL=ODNC79l5ge-JHVXQ(u|)@&Hyn=69=JI80}}$tV;!fH4&*(SF`Y~x>)3_qWFeWshR+}} z*046rAfFN!)_Eq`Ph6GzGs$=o_U2b`r6<~7bAh*Yr;hJU4i}WF(am=b6wu-;!H$04eC zZY`F5y_f{H?xY$J0mp^nen5F#YC_FjJdX6-2@6BaXlllx*@-%CL?S+2O!^1z-U@?o zN-AnW&8CicJ%H!$8WVV5uv8nlNM5q8OGqgBoTV*61Vh;;OOUw+vhSA=8;N4prQ{0~jpE+egwz?sW1*;2*wmXXe=9!@MH_q{&a9UZqa&f3|rDIS@H49hj$Vm~Y= zfzpf>Cb>Pky`22!vz>=BEGEWFw{a2<5v~q$NRa z{bMybrCYYrB&Pt+mBa6owFDPm^jkw_6N6%3L)sFro;y`vKd)=>b&F{|)2=0DWF|Ym zmJB2*EOZ?iO?oR!){zsG+h*h^;->_zCtJm^P3fpZff+y=FbGHhqJdDr8F)Odg?xkE z-bmKERzO(>90&F*%Qumq#jx#A=YLWE_VXsF^MLt4CXf!a2MRyO`A)@FK$=jphZSr= zVt=We+(JGiUU57dLhUe)D&RbD2-w6tz9e1AWu@Pjq&*?|EO$Hky7Mxa%m7k=1RxR!05rg3MD8w737iLF znwjM!_#zax#Q}oxJ4j#T>jOJTf3j53d_{7J;n{IxP?376f+?7Nu#<$iHrawlIqaJ? z{6&t&?D$SHln@rMi)2!p%vSFrOUZkR?{4Cd4EBwPC^ih3^rVED_92WN*pPiB#&!5^ z7+{(b%L=y6?6ZAjceeK=#1W{?Kq!G*Kq+t(*ad6?mH{(>3?Kza0(tP(ukyGK!* zy0M7w$Slw5PZ0~e{ey>#utnV*PVOoPz9T)5pQDtQ-;*|4vQBCB11WJrQMz}Uv?1v% z;0#i00Gn}!boQ`2{upBRTQVA!1!MvuEB`q|#t>pvg3HNo)TQl5aK7RwYRhn@|CvlC z9?G1bi6%trS zv`!c%RmW=r8}Z|4-fUY1E^_P7-N#{qvfx-Z(wCjBAaA&JRe1yIdC@HJBI)ZE!g*zT zIj<3Jrf0;PQ4YvLY zsUTmosaKH$HnT6TqH-Cj#8#325F)VJYverniJkqO{7E*k!`IPvrLy1~XvwCr5jRLP z=;qwOc>OK*dWHog=8gr`6oIVk6G+3veGT#p!Gss!`RnkRerrivXPjvZ0KJ& zvTX0eR{ll4qV{&I(;X5;Cb0>3P*FZ)d3R75-eKGCpj=zo**j<#SFAwDa8I=MeNeMO zgA2iJ4J^tU-zC9hE{nNKB7MC$*BXBv)80{AZ;=eHCAXB^yX13GyJ#cIo27=esYcz~ zp0R3@mObxdNLb$ZjQBAqur%q07Ea}L{*2${#~*jZX>&4F<+c9|85F#Gxa0wur+gFC zUwC@p*d4m(q>O8EWBW}{Tnf(_rJV7~aMP2#YIwhs9OtZGe;06)+?5n>%7!l1^&?ep zAm4GrST|$L)`&*r2-jF%EDytTQRD#Evp9%iyUSRP8qE-v94 z@67iHkR4oecP~6K)T^Tjsp6I{Qb^EX*F8lg&V|!eg*b`GvywV^Wxk=?au{h&f zuZGQY+@|H?ax|c7v_IrB;FqcV9S$<_AQ$+;L4M#IHDITgCwMsT3Dbm{YJy8QSFE|U z@cGm*Y{!dqtuC70Lbf& z6fD))b%=sg^pFH*kLOIBS?2d1<2uLn&|Rj)E1z=*U?E*3FE|h96kW+%Ty_%0TbOR| zqzWXY-oSLhL56Y@$QX!`Gy74~IS0O3Z;#$4lJt+6KQ~Lqxiiy`j+Bl@(q~gqGj5Gn zDxM9F9e0o(|5$Kkb03j}_NzXP(2yFQRY(obvzFzb;w%z8d#v&vtGvbF5d`vYmG?J$ z`UpkmnG*e&3?`%_Tm1y3B8(M3Axk66vd}C6yMXmT4v-0?0KL%2S!ppWCg1RmZEfylieurg=m{*O!wPN#`F~3nl*h#9q=RAJe>uOgRnJL`VcdT?Cpo7ntA36pBkQE=xSV~I z&7Vco5TmDk!u2xTf6uqUo5LkcIZN#A8e%p|>DMa5+ot$ySCS8If z5aE)QZLT35sZGx=a#w6A_0sbnb}57JTJ(A7WQ`6qZ2!Qpqc+rYI{9&R9-w8 zn1_&?!!_@y1*V_dXji)zTl4~lz-__T8)_s05@xBs!z~TGUfYzo;+@`!*Mb+fU~gy7-c;Ra8aJ2azC`~k zk)3>rT04c^eu-*q3G=K)E7MF_Sc}cIsLMZng~rU@gWbR-ljyQV)Zy}1BuO2~M8B~d z$C}A!%Aa*4jgX-qCeqJI*@q92os06UV;!jnUnQ@xS>9*igtpY%zOjgZ8QbNUWHy@6 z4mf$Xme4NbLw1JHjb5+59$*rTGm0{M8CwNi>M+NHoMQ7S4MvvROsO~djvb_QEQwPB zMcN$ABa7A0w~U!zr%&sH$1`MWQIQksy4nFak8J(VwNOJs+vw)W>FkJx&O&L7lIRum zVLhB^DC*xXPP7x+ziCdiHyO!}I>EtcR_R1rk~W+)WzDrXi+hkIX=yfkqvc$;f)Qsb zlS3@tnRamRvlt&OG#u?IJs}C?G+XLS3y91@b&!$Rcpc_muzIDVZFScBRXq1vAG6PN z@IhkFIFVU%J)MlNwpvdUFh;tdr@gfH@~Q|zidl#Y4b|FDbIk!Z$OUP2ldW)}f#eF? z?m`El>3ZctXOnl>OamQ964+$}jd8QJ_#GD$VrYePnD!9X(iQFwVVSOU7_)i7$(AL+B(n(hU*^*fuvh22HNM5k1{##!^JF@Q=6OU`+z9iFXJKu)rSTThZ#m2t&~(d?0WTw*P*D%e z1;Z%>yX}R{hdD_-a$=n$8uj)VZUf3y5DPVp1Y8Z_L5<`QyX-+D-<002dRgf1fKqXywv}L zH~RnJ4P&FQH9Om$c`bNrT{lyWBd*Q?XGa~=S!`3Toh~cuHVAwSbuXU9B%4O};N&&_ zrsO@%E0OG64Sy}q93+O<@|M4!kv@FvN;)s&|6P{g|1|Y|N5o`!`L%wAQ^{!M8rj-h zJ7sAVE_J(xRtt0dc)ANIQR_+5h&xO5qJjDji(nDg!4x-T%e*L`nc3+@n_?*cgBKk_ z?dw=`Z=~LR_J%hNHrfVUYlt~QebRKAnyMD-ETr54H#V7ZU2m>8ou!-aWtL@M+{(d- z4>kIkdC;P^95hh!lnYvqR@sgUrf*nhAKI2oR>u3#?i!4ccl*<3p1Ab5dv6*glDuPM z*FHFL%ONP2{pq{T%_|qcYTQo?l7Cu2u5f2=dWud1QC1rLx>qorVQ-tM4>`eRnrWA2 zMXK!n1k6{RUNZ^@8M8EIEjNim9RMAev8l zvW3AA>d17qtm=EJ}BCbh?-BbV5K5R{xUwk(8NJ^Z*?LfmNH8`2Cn5rtg|p`9B^ zoUJn5!2F!GXhA!9Jf7FUMAJDSm6Ek=atqql{RU_E;|^fQr-m$IyIasL9t!8Cr!JuA zhd9kiM$S!XNfSIab9PqpC!DSQ*o1EV;g(cO$Oxr4ls+PzggKZ@0uJHGvkaO9M2~ex z>sWo#Lr3t*o;dE#CzE-+O^+M_YjL*2hm2=;TG39?qg3uS2c~gV_Rt2s{gi-1rudog zj>lulpfz+{p86#<^RDdWKv3`*>3sW;EBI#SCnuS+&J#RE9V}< z@Zc6c5vJNYOKn~JmbMs^kao0}&Nvstz&e}&Wy$Sm3%@X)R89_uZHH!4l<8uf8LI zNh&#)N^e_q{4UVHI-;H(!IC=BDAJuR>V#x&#`big!+p)%4bu)s+&hkFg2N_*s6j&l zm@yjdgcnPQrXfVfCP&i_o-g?adF|UR2j&IXfoQY@Ta}2;w3~=eJ1GX0`X%LH480(d zkJ)M&rKD169!DkWk%@ri0FS@IP~S~RF(@6n)1kyjXTw!ID^mQ0!=ORUQ#%X#2m{g; z!xta)4R`gR`$(CRVx_gjwMS>OT(k@4Q{v2WH5=cH{y-WtO9J)sd^CH2G-2~ehajCz zDp3a?;B}3>2LiQ-5hw+N6 zw~{}S&LJ4C>POSjWW0jQr7H<3XV$mrHOytUOre`dE9H0!6)C#9rSH(6NH1mmyC_L0 zE@#tdH`i(eP?(1k9QW$F^v`xM8V@8;vs%{8PjCVf90L)#kmax?1z z;Y5wYon0J5=b<>Cv*5O3-;Jl4$SG|m(2c}9=6_3UVV5V;FC#MH+%4pg z9MF8A06?vzBeyLlJuad#IZGYa7XDp}K@hUWo($CI57`eH)JlG5u9IkEOjU>dy8Kjrl^<~^B)lR_3Z8BGm3E0byCuv~7# z2{#>_P73oN*<5Fi@ZyEt_AkpGB#Z5tOy4Cr%x4NcFfNMAA!Lya{>6uT4oftLdzB9^ z8ex{rMWo$-EkmpY7h8hyg)<3muxYNRQ3d1GuMo(!r5+WgTb9=a4H5DXLd3MeLGH5anKUlgeZHDvCq0U*Ug?N)nc%AN&D5LAlE^Qr*OLt;N}gUs-JL{ zX=^P~)ok`6TgO4$@Kroe>|$micPFu#v(S!?R(8&!zY{{)>MUwPeO8!774*^5=g=y2 zAA8TGFZvJSX&XvnrmG=O;<|rAE?5S=#6>_F*=!6u#-s6kvKiOh3Buwmvz#&q>bYk5 zE+Ee{%hA)!awS_c58ZSNJ2{VzXx)T6W-6`4J|2{y#;VTE!5>G{5HD3X;T1pgq(O(N z|9m>f<54;+m`zSm1)bE;+-DW@X&?W(+8799 z4MywPre#NW!$9-7XXcWRNd{;46omN?8?q0%hxat~W(+7k$fYGA%iv=supWp+lT-kj z4^#uCKsivv<}AXM%l5-sOhG za@CO#M@H6bqP{FwyEwyCZCu8a`8TFMQo63?&%q63;~CvTS~0_Vnn$$C$Lrw{+5hE@ zkKw&>0cOtu!!ulPv=c2Q)Jd#n1C`N5>#~tvFqwGpP4?TC6St8zq^YVczKyZ~E!sUl z7PSdgWY{Nk9Mx=OAACYTFmK=yF?qZ&xYPJBoU9`2RYnU3tgHELtYO zPD1Fyz7|6oX~wlXEe(cExh}%syry)sIx!Zy5Edcj^FO3KSmrMDZZvG`E*gZzr5|=- z%$lS8v5U5JCf>~T0R2)bz;`HOhY!%tuv9txAe}1NVlOc^iVs zL{T#u1^3I>9ZqQ}s{&(YIwa3UYg(A|IlM zNob!DdmFoK!7h$*+QP4L);HdBeJG0mGM%u@y>J9pYy3B2rGiB%kYc390*oAX^S-&$_ zO*yR$IYUPgt(=UoShCpRpJ-6yvxDGmsFe9n4K1B5xUy%A^5`d2R_H(-JBwD%rffb( zorq?B^1{n(=g;sWla>CADUMLZ=R6%sb$5@NWnAbN*MiOb6(!A`?fDh0b|HK4D_XF0 z=5>KaHXk$q-lAuQ&0iYwCfBGXIKp7?DYc-Aedhu#(Ji}bmP1jIWU+_}+PaY|7c)I{ zV2d#<>Dagm8t0!^VV2w1VIl23EdOy-qFn>cWW^P|tybo;uP)IxQsi%DIfGrk zL=Pb!eDoU)_U_2VtXGN2A0xhIs;q^b`3;}k$b2ekTYqmZV8RTrCs$CD(9osGVWTV2 ziqx>eN;)IBG6{z1{mTv_Nv_r*sK0UsU!%ZfzV$80IhJr46K5yc2bb|VzhQW*)qx(s z^DA_lPb`-{p%D@!mgW+DKn+GT+jA8Sc|N;+l}^_cAW2R?M18D`slo&pIi#GwhG@D^ zNQBM4;ZY_JWcGHL4{mauJ|sno>kZmYBUQl`y5hI!1Kovw5JcDQ7uM}Io#}FjYx`EB zUwnXlf15UO->sUvzOIMAVz+P8Xt&S%K+LlHY2S!&4OXAp{zc!?=Wn}P|Kj^hgGJEq5eM2A5^?XXbo5JqU(<18TF@MvDK$!>MVts*p zqaj_n=D!1|X!gzDG_GHmDiTpI68t|!OkBI&&ZRnuuSY*t_G5vimgtz@8E$!R~>9obh6L3~7T%&~Y})9WMSHX#k_nQo7G zJ(I%<9@9aAw|Io{q3=G2+4XwO>vXG9Jf6^F6w{x-JVW!>m_=2~u10B$oUVeU+JP-AfD~ zyR%WX=zK)8k89D9f6iXj((WjEaj(!yx+|tSK5HuAK{q4o=RiA#{*Hrw5U5Y654_t` z1YWAwybe75aH$we79X&SpE;p69-|d!VUnm)E9MhVJdY=S6?@fMZ~OWq*uGS+d2Raw z*Z#N5kD=G^B5MAS*7tEUK|eQAp$yWA(@BfzT&|&?9-3I1Y%cL5lQ_>gP93lbNeFZ# zyQdd}W8da{>tjblC-AvGNX~?*I^9#8bIMZd2u;)xN@X~5w+dkzz%7I(ayJLC{w|`w z2~Sm_t@9F|Cb{FGWQbTf0~?&2+yoR&Or$Pz5mS(Uw_U{K5MOSHZ>w-g53cEZ8W}@X zfsL6X4Q3DDMo$dwb*@3QL_F&OAuMpf^n6eC`#$2F(&UQNh6usr1ni-2beB~b#3kfs zWt^+1BY}m8O0^oDDqY;g)RW1VQ8dgr^juO+a@i_3aSEBtUb%@s>)dmYBtVjKv60x7 zpeFS35Z}WVopl~!6^UVCUSa@S<0&!>uAshxxg}?B5%={gq26K#qG=R2HIt?Kh|LI9 za(u*aBIU!iLbk_OY)NLbi@stoysGmRzmZ8>JbJx>6v!*f`#RQbXGA{( zvg-Dx;wW9@LUb+x^l1XbFw&fL3J`~)A$UJP48Wx1t^hFx;lCXqK0$x@YM}TLMdLHe zD7N*`#KOVX`9lzdMeLwa+)vK2i6$h+G4`cNl+j1OWr9QQOfrk@$Y-pxS!6onA`A?+ z;U-6R(Jao28Xg0O%*Dp&V#DI7V}4|Cy*{*F?@p4rz9+UE7Q06m$D6!JKejMP#10V_ z7L3o4#6Aud!+mPIs;>A-{HBd&h8|JHGjKENrC_nz^;>QfP5Oo>9>;9yg%EKO`XwV< zh`R|%QgoqWF(KcwQ(qFfCSP;0Z@7lEQR-TY zet1QgHI5Jq$q`l>Ax2>{z{?0RwDq>m5IwXe??|kRxhxLLe+8W3yl~jUT^Pan-t{z> zy&G?85-ae*L>sXuS;jtWBX)?M%f&(i!$p4LQR|4_96-iGW`sTl15H`6juYP}K1pMPWC7;xV}j%isLRrW zODt}l*dG1FS@TfbtCU~niGMqFa9@rPBj!~| zg$&;iIqi^Hc4k5H{M;Zptue0S1-;2r2y!x)1$rnoxnf@tU3Tjdaiz3~p6#Ksrz(G~6EBG<^7i!zu`UblX96?W@(p5_rnh;!o43Vu-$ClO zLW#S5A{s@fqLIA8u51wfF&X%LgSdcyiH+i~7`*k{gbI3rGHsK1QzH4w@GasZ4IIDx zg}6Y%P;ulgG0+tQ)H#R6?ouKADOZXQi>;}L`)Yg(Y^Gb*Ll9y>jmoPdVkez03H(eT zQi-*TTSZ+C)I~sna=TRY()e#L3zDmVZRJ67f;~vS0s6QUxm@u%Euwo<&My8Weor#k z$K|MhtJp8);!rBQ&)S?7=c4Dl<1Er&Rszq710`2Uf86LChikbL1)Gj7xFEK1wK*L( zVg@783A@oH<Su8Q8usH-Agf=_`yM_GPHoZ^B4UGr3Y(^-K!Tm*d%kfMxF)J#-6Z2dLue5$~5UxS1Jk^tipWPBy?O$`>IGL?`d%~swG zJejOHf-Gwrpy?_VL8^+`2WYzMgb!dDK;9mx$(B-}%wZo6)C`php)6+)25KI45Y|En z@B@s1un4_+&?F!Q$ON*09AFp%>NiIa3Kajrntde9eI4upMj#Z31fl^MD2IGCAV6KD zJQ<=nCWfUzoevZMg`5wR0~J6OAbbe_K$DbfBQ!sVk`a1Y+5ML0C*ofObrp~TAQXrMl7LJg2UrH=1BJ@PDViThb`jL2K;*|rJwOH$fFxiTkOSlc>wyBG2&e*t z4Tv#d1R{ZGKn7BPLYSAs&1%3MY9qG;bqc6wapCW&E)P=;C8=6nYO&IMng(6NOxVf+ z$^l^`YydJ)h4|+KcY!461&yOy3TP&f11tjyVJBZHo~t?K?3xdK0Z;@~DIYJ=Oc6T^ zn-B`X2t)!&KqgQC6anQxHQ@dUWPnIO1`?FGr5Z0CYL>zInvp~ouqIgE1*EXUYcxC2 zu8sLXGmetu%IS5QQ;pHn`goUSBbK;2?AE+Xbnd%?<;24%UdraLHLWS;6HXUuIuVkl zNP9ICwNlQ`U`$WXJgj*{b}8e()pW;{gtGgH=4TDo+7=dRvPI&pkmH)6?&Q2O{JiF+ z237}O)I5?%fYSS_=DLK9ei46YnmUnSrS~1pKte_-pWM|1X`~ql{5-{8t(hXhjSf#W zV|B!?Y;tINQEDwx{vc9&5sW4hjvRo7Yo*47T1POevviE~U^<;NkvJ#8gbZcPpORZA_DwUV0Od$Cr&oirBd52J9nY%;Bj|-YFN8x} z?+^rU(DROL!Jz7^1r2EBlP5y$H0(gW;SdU;7x23a{pmXnVLO+Dz6$!^Tdxo*KwGu? z9A{x$$V(4h5sE+yK7Cu*4=TXj?V!!ZpUV~sph(Jg2>GD*K1>r9gH~cWa6V{^ccm}` zlm{psbR|3(#VHhtpe{=e2{P!89Xo{fph6lt(GB_l(22@-f;;F+0Tw{pP8=*eo(j1< zhj0tDEGqkBp^7sga2|B-N4JIJpzj}jU)T@2GB!cj2KwfkZH09WbTR1JGuROU`m?Z3 z$N*jI?GREx9p4MWFwpVi#|udfvkOL~z&KEL4Pa}kBpf@Xa z3&TKja;k+yP=}*RXb*bs#S0-6^yi;{76L%?@8=8d4SEe|@j-|1dK8%|r~?K$ z++4^JGNAwJ^jIMU^fdBD66nu^zZGQAip;e_BGY0J`A?wqs7lw?CU8 z+?|YpzRl+cp%RQte}ADI^o8Sza2)g+a`_?91E9M=cVBS`S^N{gqixXNeDX@jR6j+I zupauL)f0tuuK(O2d5FRYZ z0rP`!d<8x5c|qvzZgx1ercw^f^VwOVeH$H53)RkZEd-|=r~;~$!&KXnbP!f>o|9k% z-FhKi$OO#?zUd$c`;Tjc0;mgtB4GH?75*}4isGZu{wY#TN2N}yoj{tDgNevyBB}ls zu;Zl~dUrk|TdCygv>S+PBs679g5=Uxf_zsAbI~H^)k>hN_5wl7pSWomm2UkJEJw37 z9@>dmUU=o9eN*ajI~YCVWKV5NDGkka23z2%&GvEE;9Poju@`O#`g$@n;u@; z?nF9zF<4&AhI?yUQ;mr&@z%D&X^uVK+O|&RXCb+s-SpPBA<>GDkG8Q>U^$+HYCBU9 zw)-JF;JK_cZ1XKVZj_I9G|E{@@1|N8EhaSwo3*XUV`ZUPdqnh)@eGpxjcVvsu)!^~ zT?4%b;PIJv@s*Q8=$A^BgE_peH~t19yOh=n&;K zpgZXBf9W$C)N?_TtAgcK4cKzEUVXhwi0m5^BL4=w1m?xotBXKez7c}F!hc4kZ7b~> z(aq8&vK`mQWll3jbx_VkXuojvpOIpc=K{IFGGH~Z4%om}b=7wFDDyST+|KJ?8N1e1 z+tyMs*CgKpvOLXlXj8LFUyE>B1v3FB|1|SWvLC3-;$pPTvtt6V_h6MtUW~(QX{$~0 zFzC~vH#kgkDAbRao8)aAFssNj$$8)%1vHRJ019F6-`?DXnRB379<~PZ`6jsv__uj5 z%tF`VAk7B|LZG>eoCd~X;I)Utm`M%?B0n<8Hz1U_4uSg+;RbbwoB;JY&>74>Ry)Nt zb(2XR4kQD;*qT^v^U!~LSFs*J0G^f7Muqi1Y`jP!0QNYcw~}K z0-ph20DBaVcZ;&}yIz2moH&t9_10*RZd9Xqyanerb}Y%o_VTGy?y~ zs$Ed7evQ|5Ukk3oSM(Fia+=XBS3tcB$b?#zQv$8pjm`-bv+?B@!f!%G8_Af3@d)vNir6XKAsRwfm{;D1J@}YKl6G_YuCY(CT z{w$|RJ(Zg_{b3(NSY_F!RB>cClXmfDb;Igd_1ScRaGO3#-)TzH)SHD?y~-fMA$>uw zVktq<&&cWuM-myJe(DfHl{b>b(GNIyS^d-D>aIM0v(l4!U1a1<;!P}TITEhtB%2{YY;^C|3t(_9QKvresR2SvitiI{zepGRa|9j;e1sv&>4}^_+V3PiHc#xztu? zU+^Vnv4kvE`wUnREk`E{hjoQbDq^$49ee@m|9F5Hx}8TI2#xCR10Eo!H@R+JKuDeX z3JHV`oWim}>db+4QJ=@?Ijf%Q%=r!RhlpF$34^|l`YKA#*@a&fh`jjpKPUbdSBGoc$rmRaqVuIR3DS0V+w zwlLYjXA|X6QZUO%FLjn@*g5s$;D@9c5g>yK9za}&_))|s5U0h0al{#jFCorE9P)f; z&H(kbA$R)PAi6aCQUE<3@m9n$5WkQ3VZ4$@iT~DL0pP>H{wQwZAeF< zS$hyW5!WFehxjz&62vRs@634(aSMLeBW_2`MuUsxoz9#zB$_iBX1$qVRv;a}yfbGb zVmsnm#A%4nBhEw|3yHqCsqEGTEH@j;`_zQn4)-vN`-6Cs)BPdjfj{X7JvFPl&`Xzw zb!5b<2|2?_f_hhu)xM0N@FNsj#r+%*JUyJAWT&U6(_?pfggm0Ynv+I$sXyez`F_C{ z`MJW5uh1xT=%JF+f49@kL`K;)+u&Vpp3Ot|75zkx8Ej>BbYU%JuyuZ?EDR2jqAMcJ zjrkDqZqSIXsN3$XXxBsMIe2Ag>?~)ngJkncdaQ6s51EJWy3HG1VK+Da3fO9d8U&$9 z4@139Kf`)W+E40Txw$@Vc~VWQzEj9H%VkMUp5xa!i1K_=HrXj??<6^hHX|w9yi-u# zMPabp-yPjVc{WhInik)MVzGi(-bQ&himWL{Dfe%baz#m?98nO?bILDBa?_GRnzq&N ztvOL~X=8LnuDQ`ijyD%kx4v9$*!qj~|)g?28ZU)a^4W9s454K6$Jt2M5T-L))Gb5=wu6Vy_7 zJcjanZs}I#rXCI+netdP$H8x_H<}WXl#;vGtmiPfFXvverR1JK*o#n&Fr_=XzS5cV zsv0$HK%|n|L#&A81|Cbr1k1iWnq}+U&yTJNY~#w248iyy@;2^9(g9l zwO7Z`G#Bx6B4nY5@Q3dDUEMS+b();qqp_|;+Np~sCiS*=r7&FxZ);}#4%6TYB`sFI zxyPW20v5H6tk8tm4gI68h)%zMh$scMMK6aSn{_+- zzCQuqqale-Dw-)NWFur%7G05PZe+HBQtvJHTuE$4kL1}2WK`F(tOLl~j%vRE4= zvL9J%&1q(I6W90c^4r#l&3s-a!#%89D_N-?14n7HNp(7g1=nQTDHRY5#|P2%m4mjO zf_%^>{YAf|mYO8dFDN7a6G$h_+*zCShYq+iwgSR)J0(XrH_Zxh{S7>y_LohnHsG{> zY|<})lmEE}r%VBywwKc1Ym>GaVDd?uR0S~Yguw*Qf!rj3$$tQh`@@!Ic9rW+|F-gJ zc15=a$1_ZtSqqAzJq}aXcRGeJchn|*OBKbVi9%@&HtFGZ z5N_ydtyTmW?N`7kzuLrbCdJ8C{jBGGt^Pf-A1i08A)^NP){&Il5)1)h;pOOx4NkF! z^~O|sqpex2SZfm5sC^g>7Cw$^js5Lzzo6uG3cu-m zufeP%d{C6DRu7IeI=d_}W|x8_ z>E}zkS*Iz4OYR|D*0-}5s>c#;oI;pw?$zo&1rD-CRSRz7pPqZzROn7X^bHfjY3 zzJ%~1g0%b+&pLnO#Bn{uammspT^z=A{cknW#(#6;GZsB(0Jx?_`CD|5|7nhItNL48TMeg0Nv|O73$A zlM$-pB6FpF7?~?7y@|EngxxIbwP}jFa7+*10?HL>qW}5WqM+i6v2t0v>x4edGy{gO)p}TP>(V`fc2;?1e#Nqk_6#Ap*}g*=93GP#EK-%3wl_x z=G$&q-kFRWsQv+}T+Vf>T0vluoBMyLh8Q^I+v~x}_Di8n+N}YcjA7tpRDhEQuh)`i z%y2>N2K$xXU|?-VO|@Pwv${kcl<2yQR?IOwh|?dbEh_BeQ{J{o z7wG~s(^m6#8&&W)OUzCe{Z#THI$IaoFpC%3q_cE&DYl6f@z4PyV|EJ8ig@Mi!~m$W zpHBXF093idCLN*lrUyV3P@|yQTV0^sUjXGs15~@+Ci(uRtI@PBvR$y;DgzduQ~ndc z@<;%4BW+R*V7aLjJs2}T?fmlZw0s0DA7KmGxUFpOD*?r!q^(cx7j!s1bO}pIU>#9< zCqh>=6pj@14LK`GC{FIkCflI+q$%TVt`-b2PemHmKkY#)@~}U9$73Ba=@Q)t?G#vV z7zDw`VjP<2x+ch{bg7jth1wV!RV9(L6RgPDHX*;mwIBM#&O%CTmK7`yRogtG@0Csr zk!)6Yv6H+^ll6mJ53mgfO=5T%S#Fe>$@4U}yX|85nvsM&)0MlF#vQB}?yoqh6JJ;E zQ#2-KI;=4RqDqy@A&J&^;L5t z08x_Y;M^%iy6oB;$l z?r(Q>cBWw#kH>(J`(t#)D?zq57QaVg)#VfU9@8&|&fD%i=?e7A-KN|lcCJd7;%M($ zqi&k$Ci&{ci9^DFI7fS=y(F7YC!|QdZBiVWq)wdFC;qVx6kuRI(m@u|UvQDO{s?(tM1(u#LthGK$JXEIUoMcEN#$@p+=o zrez_L!@Nz{8+Civ?g)Ht7b+?!r$!a?x~g!}DtIUP>?%Q%GPjLiLq6&HO$;4nH#^ir z-d7h-xnue}7ofk`GlM{8{ZjBlA`B*J`-prmMO}WCR168BWkcuZg))S@4yMg)6a6l- zxC@TTt@A8p!$bb1I;NJyc`xv$eD}au))~zSQ!cn`P0sN{r77w+Q&Y(pwQg#B|F_x! zFE#4qO`3R4$akfOOqPNPBfNDk-DJHdL^!1nV&|}e`@*iZ(yeOhopxW=g<^4^(Et2M zmwna}LAo$SviDhXpFqabx@Qa7tRt8d()45rh&655917DZ+g*jD3?|o-d>ZGw#PQ5B zhH;K(gwzXzSnOp4+XXjju%5T~UP5vLzz0||l%~XKJ_hUoei|c)fM35wOk#G;7q(u8 zt)^RXPk{&WU&1#!Ma~Q$pJ9oErce#TvxA5@ju9*r_b_nRuN3qaxA=E%?+v+PqhE{~ zB@&TBcd%r%A)fbjGKwaEF5Gdh5Nfh`H)EY1WW6cK+F=5T%`2-9`0M&Fajrdq1c|2D zbqAudS=dTQ1pVdo&rID!940c*pg5qN+(Hvo3`h=9U!Qg>sZndErTN}!br$b)e(;X7 z_%CS{(tk_4T6i|yB%RP*GcO|E-IANzg7~P8f4gXEH~qJR{@Y3a-AxO=psBA~JTc6O z*I2O^sraEq`n;w7dt{4z8gE8dsl9_y`lIuvIl~#!kMbz;>67_h@=eH0$D+sgCN*^A zihN(bmzIItzS0ie?PtkOnk}qr;bUNN6Y_LE_&!#6y`}JHy%@jWZNUUqYb5ws8vm#( zuc0) z;5AXaGuQBL6I?B>pL8I4EVltS+w2IRH}rz{Gd-`7foTA^8?V*b5Cvq^D3%3wVL5_R zy?uI;Z|ybed;S|BSLog1dOtut_bT4qnxe2w#9P^mg_BA zWwgju#WT|D6zf?7s~K2dU$IX9f)QT6hUXSST3jy$>U3YNlfB?ws4x2p^T%_>=5is$ zZ?6m+>QZ#=^GX}S)BLgDYQC`9Lz(mj$_7e2VSbu9}uSiI+N@psmBm+tBF_f`IOw0Lv% zyr&px3T<7E(Ylpr-NRHS4_^CP!-Vql*S_*tLngy~!B6R6pnxJuM*XO0IWMK*UOkG}FbUof7E}GkD0K_h5_nNar#; zXmq1A>aWp=zOuTv5FThicj5l?d{*Uzk#rK7ah*terz3o<$1-x>oh{xyop}*326Tc* zH6=n#7q@^H=E}g>?ie&l^9{?zD53DYtFhA}K!1+9CPo#<4mpP z52!77-_awhb+pOBLtl{Zhj!Qrr9T7Z@WSdDJHS!+WC;!m4xFJe3L+MdIyFz0V$v6!-kw+FuznV0W z6e9_MUficwoIC?qw?9Pww#|Ol9so|h4s4@Is7>KiZ8|{=y=k>o%-w*%2aOa*#PEYz zsZCe+++$&ta`m5k@`o=oGkx#y1Tk){Iybju#8<+@vKMTk_RCe9GMd&!%K0 z1rK2${GUHU*$~M+4C<^6M#hpqo#o3es*lV{Pp(R17)a*(_-v!(IaECxHlAVUGPxi;ww zHFLJ;qu&4%*L^OML+xPXNBSS<5QTenGMWmDaCAYfINEf8t=w-S+o&Qcj$S87m+`H# zDD-UC0jgE?r)lI>8olVp0GuC#BfYC&vr+JMprFhVPI_G~w-_j286_J7C2NH5)uXdB zGhd5$lNb+)EhZLh({~EwB4uQ!#IxAAhu~m|o-i;>CiabK2=S_XU$2>O=wUafv1qf$ z8>(GMbT#RdU$Ix0*teC~>mEshJw~fY494or2=8=lqLtS>g~?Z7?5bs%N|rRRtkWNh zz0^;M%z>!IyP|f?8T7QP9y3K`p}lU_V(o{-z_zFEKJMn_O*b4}Veb>V(aEmm`3|;b zo?hRoZ&k;qndRU0JhT!*b1*n|QvOjB@6RSj)XDcdeKVRuoA%Y5thl@pq80fMr06!W zvLjR6(98y1?9b-SV#K5|@)8Bi_j(9dOjywS zC?OaJeN4JY7)qFcscs@+MOTP)w$n{QJW(bQi}&y-Os->x+vTll@`F81RXV5UKG?JG zsm9Aq0ZUS?H_EWtd?5Y%N13C`~>}JPZj5b4f-c%B2OZyNPI8M-l>`O0Zla zaWr{`<%6mc={!b8zDuHv(r^+<<2kIzv-iDBc>K7RZeqh|ZV_^sDZYR;2${h&lf2f1 z|F9X&ei=h=W#9+#^zSydkDa^}_{rwKd+RRSaH!;e4tOPPI$D-$eCYBLK0MgMq>Wkc zkw&U7&#{EQcLBt(-F{2`bWXDHWT!ZW&5yuG4Y!?DK1r;rYmshl6=TMv-d3jkr1yw0 z2EfXPVto&EI$aDphtq|9OB#Q*Gs~YP)<4>4h7nj8ciNxg)=&xCg=}n zr}%GlJ>ewH-E8EJzM5Mo9HF^i8@YKjw>Ei+9nSqbQ7UMh zJP+IYY|buHN+h3BS;U`Vv&~`RV_s4apti`M=F4r#4su}fmj9gya`|4n{Sl0lW)~$F zlux+V6Bl7cbA$si=SIYJ|*;+}?KCm-zp2n2)i_J)Wq& zq`DrAxn(R49{nM38Nq?!YQ)my&ghErG}FGCn)xl;>qDF9ENc_7#WXXn3wp)$i~Bz> z+@#(%FT=5_V^%LVZ#+{q1%q;(9N+2Y--F+bbl0U_!-GdM`17!g+r*5puvPz3-4 zsORPSWc7~ugUH?Lv-6Wf6s}WvQVzPs#^6CU$V=d)t9}XgWvT*d=S(SXEYqXvTm6`V-mD1zr}+S)5qTuh~lR2swE96Ar& zq?x&ax-dfLV=CQDrJGc`S)oNGCAMJ)aik=KoO70;x^6Ilh@&H6<*K|~yO!CP;V_fG zsm@nmP9F+QuH*#L!hv?)v>mfsB$-QplONUTCH-Mhd%5IRGE&`HGJxc*e8iFRMK@cY z^rV5YCC|Q^?B>Xv(D}hk>DCc%aPD9NYfHab!EL&AraJDC+<0qR((DX;mP|9hQ>8kdReH{Y0>+lPLfdRfay$-T+w#Aco3h&Dp850Zr(JQ9V|{x zD*b&BSDIC1TGpYbbJQ}Eo>aPKU$h$hXa*S!)_SO8AB`ussP{d31t-{TQ2nF3zaYw+ z)wv53Bjoqn>`pt+rp9!8p_f*!u3FfWRW_>ME*!@y>(uZ?*=$szI`4@o>idgimMc@w zESjCbz1qeKVUbaV5LRMy zo(5|x=ZdS6u)uvmi_5!;n}rv;inUR3!F?ex=~Er5CHaN|Ol)R^r7hLIY&#{O+2X1M zM*4u_Z=l5>{;#XV#W=b+!cstyKQfS6B9zd1fa1zy;;N!i{w75(qs9B9g$KKkd5e}B z7aT?_UuodKY2c&snFf9=<=zoj#WGHzx9bJEf!E$uKlxWCE6-IA{A(O57vt+>`Fb*8 zqBxqrJ%jrrAuVazCXrfNxr{KE!>gM00~iRr zjn=E4cp}xuO~;2smDo@Q2Hhw3WDv9TdCWd?bZhDnue~GU(&5^ z6Vw!fqd&8DPG4W_2!~G=;hxo3e{LXirTVT)2cNM;c|o68+m;7Ar6U|&oAdmSo~OR_ zWJuP*#(+~6PR{IOOET+9avMwd>}>Edg=jTa>fk6>ShFM0?aHk435gJE8)k~`XO^ePCKnIQPN!y#V{$qSc}+p_aIULVp9Ze8*;U;tdoUo?s&AV zDj2iGrbefi+gzCDVrC;g-M&49I4tPHXD7D&P|PIDPKPqiI+U2RF&REhv#;K$7S}%dF z=k!0vwd*xssB4yd7-NF>Af2oN`EsLPqiiZ#I+5J=Q73gPY(aj3iF;Acz~pn;0J^AM z(WPMB-p7@1!k%HsaOvI7-0@3_RR)Q%(}ej*l&MY6SbEy@OsDX0*5Y}ucg~Mv9?n`a zZ&hbzj%)rK%-Bgw=Dn=;QBwH5htUMXZI1k|PEs<=VMd$Uj}&gzNsziiiH)4o3Dz-2 zoc=4?X7u+Hd~Wf*Gat)$EZ6D^5sVg zkLzSRO=B=I!sa8=_v(ww2KMaJ3HKwY{8ZofMmBpR3?^H-zjV>d31#ZxWqrw;YWTCW ziBDbl>?>rN8v5Lx*wiD1B|7PUja;uIlBhO4XCt?(=I7G~M;?(Pk6iOHdjhJ)q8DMs zg@?sT{|f0pr(nHl@Y-2#uQP0=SFH64&EB5!u{an`=RTjnaxbXMpHK2}1aMSJG3as5kfsPIxYck3h*4H zC_?)_9^;(IVe!;)BijrBIBB#|kZSm1P!Q!?1B45WXN6wi(Ggy$_F3L%*2Xh%J%YuY zPF^ND?9N!QkLTqxmg>xs#aU6%%I&@Eq?&dBm+xZXImno%2}3s^Arh4o9Gd#@2YNw`*v z(|;6TXfZFhp*hmyhbOY#;XQiBjBl^qaXCO%X{2NiS>AUFbTZ!yNK7qA%70p_t6S_2 zJ2X%5@`nY=Gp1T?X@_+0;o~bOihkDa$VAJ@G`h(ne-EUQ>o2|VZ=K9GBvo{{aGy>d zFeKHJ9w*j}ZG_5!ok#-xm2Ey29Vv}h(@JmgWt=(b8f~Jxbv|_7zQW5AcLEJK4BkIR z1Gv+)0og_a8ubpN0Xba_fFJ-+ZJFi7io$Kb&i}Um;(x0J(<0@+q(ka=xOL?udgLP- zockNgbHMrE2Imfg^O2pD^Gt*Dqjb{&C1(8{zym#9=W;!?yH5(y5VS3woYCYs3+$Nc$ywb zZA8*(-37OUVGNELoogmLJ&Xtc%c$%0Bk{b5QO7c@Fc)=I3J=u^bKZ(FH||H}b-toXs{D@I~QDUij*j zPoLK3MV)k=#;HA;S!ABW*DX@HqId|y$Z;Km`yutUcKZ7}%-reAuEV;`V@PBUuS`{g zRt(78VYIhyUt!JCQY?Q@pLB)JgDOB~QB{Bc5)3w|bi}33UNM}@2ZKY^ zjVlu3YK|9}zA6ZD@)qHup6OmHRt!xtX`|Kp6|rF}P7Rqy{ZF3IMy-4$X?!e@+S5~V zccaD@#DQt2)@#Ac1KqY}?&;D}Y`nHQO?2I_^b^;4y$DVtx%^sLjz>x1CnvrV;nR>S zoYTX0;iI@tt8>fZe8QUJ7?raY_nQ?7HzQX(9HQX7>z13KFvL{~)>^?5T`>d3$5-JX zxC&u8LMg(B(9-<~M{wH!ZY+Z7+>PtczIGO~DXj#+G z`mC5(r=NA+0V}=^k|+_UGw8UUo{ZRIoZI}4Mtj6wK6YAK zy!0V<2EzW$7fSt4X3+W9=lo&J5lSaL2$gN&pZyJm$4^>??t7b zX*d`p3{vk>;}YMxFl0a;!|ce$l2n%!g^Ln$`X$@0SsA+wTa%A&-CWDhLUnLLksQvr zo;z!|2Z_TO;kmOoq2cPNE_YRtB=^@r-nL!U zHLmjV66qcF;a7Y6PN3`7A?!t{Mz{n6#!L*>XOPatwDtsz5e6ZwgQn3NaT3BF!0kuZ zUx$vjvMkb2J96u{9%H@3D!uMnudCUcBOZinyT{rPQd4-cV);qeQE0U*=I}-4p<5C~ zEhHWt(C30aydqI_;ymXo-F5K4AcEs7Zaw2faTeC3D`vW=nq7bB-hZ70PJoIMgmv2h z;4V>s%Vs!mdVi&4x&YW~02e7ht63Y_RO*FKGVg6L}Wj)t_eaPt$=@eWv6}1QtA0qqJM9qDDMsz{kxnrnV2O{ zwYt94y=@)yg)C5_!#z^D5(faZw|kuQS%9YY5geN$EB$+RRQmAMwLw>4d#0cNUg#{V ziy;fqzpZaC>CxkSgwoyW5pLm=V0t$4H`{wH)^5Jy5wiH6uD2;2R3x{=S$|?g|7L)o zoC}I8T@4cW)wh>yiZc-R^zEgvaoCyS;t$%Tl<5rzSy5f_`heILc(zv~tVh7afmx$s zl)CqIF|O?tCW?Vh7Gr~t!8Ik3EeZRrK1_{zqjzfVv8z603B~(OIHK@m)D#C}bsB9_ zj$l#ECY-7Z4eGQv5<}$%BSTrC`rdGpNVW2fZ1Ua8Rq=8NPENi-uiA|8Gs2}SeR6jp zK7x2J;ysA#Xc^)Yh`&JGh&Tc+_Un+og!HRw(JF^;!ZGyi(+xQH3>%8`7q~PxJ#%{C zfT$bJ*xi-W$7mZmz?vB+OrD-&s$OPrJ%W1G=TYp5Zq_Z3)klOKN2w!O^q3LOn0zv8 zW^h{6AVE9Ro)%>s-7xUWN*qQdtjP`6{i4&W*OlAh4Kfo4_QJjDh&OxlJ&f{NSZ;*^b>W-IiKXZHSobhY zeQUpR5U}3rqi??n!M8Hf za--%Zx@kJ?F(gwcsOfK|gdL$-`)hGtY*DAaCC2WfzuVo0{9FNVgKp}IxB3s?MhocK z^3Z(Jbm^agv3j>VM-Y@EF}tB!w<@1>N*31^SP|9K3?1QxcylE!3Epu6o@09`?9o@*LKz>mW)Q*}~*KysO+MXS;9hQ$G^ZbfLSoX@cBLMOa+np(p&@=dGfUKr#ba`NpCD24uyNel&|Z4Dfxl z&yW*OQjMH&x1aDgEB|RNuCRNeZUL8Q63$JFy-CW0abncX#X&;SynOY*JH3*X`{F=d zI&+rvq2@ReK`HRD#TEHQLCS|}^1Grh5?qHMtn@cx9jo*Xsq}A4%wWB@Do#waPS+(p z8{J91J1#LpTVTy51w0?E!F&5WRm^bb7CrM;;8qGls1D9BmsFT{@X@ZuEO+{{`WY^AiB7v#m*2}dAShu+)@awp` zp)9`N9_S#u5Pm_ZMW{x=sW`pLxxI|q53vQstW)}#kgc9C%j~(i4W}uS_}C{dme0zZ zF(K09#?2e2m*LKK4kCr=s(a0d)VmJb&#n-YiL_h)>o>88sp^ZHhYw0`w?RM6TwqTv z&G2s1C9}F=jReQyhBbY<*LUVcGP8ya5}sD0)+UleYR1}83w>p!?2&dIEYx|Pbk#JHyaO~xKZpM?(vmI4zIjwzc7!@I`R(9M?dF_{B0o$fM`E&D$-UjR+l;=p3b_nVNH#3VA(Ym{h518s*V-*xp)T;Vyj z^F4tys`mF|C)HnB-9PLWm(mU`W8i=g>B!0A3FEL^am~W*uyJ%e%PrQbUf}Rwl-MCk zjGoW1%X%~Ug&=7!k-yS~KTh&7uBkd!Op3xasV}^rlEB@61p`4^cM`jcI!{#J3HAvq z+-s_ZJJcQT_Z-CiW94HoDGS3I>f4Vs*9JKw-kEs*(z0VXMst|{%VRu^b|Qp92zVLb zgImcrs`rCwFK~vS|mO|g1czha2vfeaf)7=I9hL9 zn(z^&s6uKND6Nbj8rRQ-=3PVS%Uu<|Uh zrtA%X!ayjk4uEPW0E#ao!%|m<4P;_gq|2_{O@V*!0{-1%qrU$T?4M3Hc#STWZI*VP z!u})LD)`Edr?Gi=6Gpn1UX3^cD;}oR94k~5qSRQdpHAVQaqx{fcCN$bcc{6jia?Cib|8ErjRDH&50sswKk2x z4}8{aUxc>bXsf&*+-~mrh(MsXh?VVKE!b|6?D!JgUxDA*xVWgDqwsDJ8IBJkD&qs6 zL#YBauF4_}3RJ-TX_0OL+pwGl$R}o@mxv0s)kNE35p#^rwZ$S$Kb~gdvg1VWqLgSh zxHoQ{M5afHWh-1$j;9Mks?J9Y3Q8wp*@l9MMDemDkBf8)4+`Ve|9ouoi5*yW%Qm2w z{$Rls6WBE6&)Qm7vQ^0p4m4wQW$vZc=t!K#F1_Rw7TI%_V);pl>52Uv6k~agj_dOV zy0#X-lRUtF!NT=r>eq1BiY%C>n^`EkFcy?L(B%VgI2;s_3flTZ^P2iCpEI0G`qO;fX$4Bi_I; z5Z()r*Vb7iIE5L|hCs6M+2Bj@%MCR`YN!c!hm0D_x@s)5@I9sV5DTZaS=~|6M^r-V zsf5xD34MK%qy!|iK=Px8&51ryK46hvGt#1b+#*Dt< zl+XshX_4;klF-M2EJH$6%5+q?0Thr>?=F5{M+ueC>lUB%SXYG~SR@~kR7CFw5O1ha z=&Df-kk?jPq`6(dYiU-Ogy{FVT4O*$J-TXq86~vFm#KtiQ3*ZWW?dO2`R=A7daL~a zOX`l(PBiZ%IY<*&GvM_S=tMg$QbAYpcZ)O{Nh+b$0g{l=zXR3Yz^}E7-{(+5CG@OC zvUN#lRUpfd(0?qx>kJ1(6y3$}GXd)IGZsnes_-?7G#E)Lp;!OE8Y8-De7dW~#TF^G z3;30;8qMfK^!r?ukQkY@*cUl`u@Xk>#PCy|L@CH~Pg<5S46}N!Frn`1!Vo433!K7y zw@@Pc+dxB#>qNWIuZJE>!|~V&56EJlF+p1!8T<&u2Z%^O$m=bx0mssUmR-~#T)q=C z*K>hM_#)1s9KuRj=qAGhl7wi4eMbVf z5Qm(Uj@8|G3lYoelCGxGl@*M1U~*OFb~SLWMH*mG@rjzxa>IQ@zAkVdQF-dWuoWDg z5$%Bhw)}ua>T?n`JQ4Vfn~9NEz@0m=zCtV)X#o}JY@o@rEke*WId(Uiq1|#NZ=)`C zJBIHMfolsb72h>riRHP4|5Y#7ObN^k)T7;Pk#?Lg5R?++qu!GLg2rrzHhKfloYx|i z2cWfi$fplP&FccE*1ZBEpSCz|ADtL@TWM2>TI2 z@VgxGHwfL44o2`Jy#nE3gxLsV5pofFBP1cLEVE-nE4_S)^^U0Y=BaON%q@QDO8u}S zHOmh{(X7ZiW{tLsN!hy^M8~0BD@8}$F1MKEwpJ!fnWscyARkWdrL!NoyAJ-q-aJ>5G)UHo~9sPwn;$)KLMddRT)A2CwxUss`Yi3~i*x&Lvr;XixXO%|76zGP*cxwkAogE>oL%vArvFFZ>!etKbOy==Bh>2Ncm#Xod-l15rBVNKNs-NK-T z2&VlZVaGuyi|zlY)EKs^55q^hdg_H8b>bK%z?>WkZ5p=TAd3I3K|arhR?bR(K)V0l zla3&_H{0VKO5UbZH(7NE|2@J`94)(r>`BgiUIZma5LtW-1$bKN=3U{4#<=&a~6Ay&JdkfZq!kBuTy$#)h6Zly}yF-pH28ST{lSb6L zrq&C?>#GN-r0F2I+yD8jj07Q5?fX?m-vC9uR=T=@nXc|5zj_E z6Y)&?8)0Z_3X7Lx3ctS9^*U``I~#@@5_l@6et#W3)!AEztGz>2$k*)`v?p7I4M*rx zF{02rJHqv|9{f0D1Vfp$MJLPD-CsLW-?^duOKefOs(+!kQ;Dl0-wtF) z^qmD~HZb5368g=`^WuC~NSwIEL@6!P$*@2bS6i_ht*}bZ2U>yN?H9QFT7{w;n0#Ch zPBqwg>{gv*QS6CgkoXI|-{$o9tbYOoQlzKrpf8gQS}JWkSXwMCyh<@6mYdlsj8w;b zn=rGdfz1Y8t^9ricaDJ@Z{WU7aqqbScY3RE^HpYClkogkQFw3+p>3IyG-5nZBI)CnYD$@3nwu6jcI!jgBY>vKAEQcrC<6Pts( z8k3qe0p4^MrnNlrXa&hY2B@b^EcHUT5Q)gkz zp{frkPqdnIo#b8hzVCDMa}Bm%q=byi=hDGLApAW2Ek)2T_vayFGzfnl!kb68!a__( zK}~1jZ-e|>@`17Gqz{0h#Px42Js|wO9~bdz z-RGCV!Gms@>t9hn+$@k^)g7C~DZ{#0ex;M#YS3{9Ti-Dmbh3oyhoonz@RZb6>uyH) z9)yBw-G#xJzxX7GmLBW*O}1U!bNZ}lXMbwP@VTfLe88{eyvzB8txd-g~!*=TXg^n8EmriD@MES?JP_?F19a2 z%S%UNBydg(EA(6G-%u&^trgN6gtTTMbw$+T#gN%8>PjlhVn3b%TomVdZ#+(SP(7I7rdfC= zjzdqj%L`i5!?_34Ge5;m9SW+w5$p)@MhzQKL#;Qx=E{E7+s|RH^!9D=rZsz0l?5^O z4417ETd=V)_R}umd0gn!o2kd+;_|!7QG+&~wh^XsrM|u9e)X<$aRPV2f8TV?=*V6_y1E4IK+qqOFTjlLOUMxY(c>Dq2+xzd6cE5 zLe&V2*R1A(vfQiM2$}_v`i*9ch<{jdD z!G;>>CxO$KBlvWS@Y3VMSXCDxS?AyF`Dy|)L4hRCX^T6q}_T6r+bubxN&LrE*7O&-bq>fv^@aUOBs9#PMcj|a&iDn zxhb}*XMNlSm&FadG+zSH9~A zJb@J-C|3gIT%a6&=-+fm_x+8&U75jf)>zjOy$F_dX!7z+=vJ}`Sez;L#wV&Wz+gLZ zsxMVp`)C7Wh4FQ+-*7vy2;*>@mQJ52)nl%n%f4 zwnPDzQh*Bp;4Z`nsdX3_SKsVWk|O}1MV*fcX}Wr{eFVNAAF5Apjh~G-M5SHEvqfyI z6mw9-LGy+%>W0``&Nf~Xqr{(}#Lv>&&&JSa42i5$URPYJ{c#F#n$~_gMljX6zPnz# z#i;$1O18!LzQEpkH3Gvd&c;FEzE^54>nEQ+Va6+6CTYx`%kywx=m-zpNX*B}p)D2T z4cK%ZD@VhFjAp)kfZe~6-h}m=I8BG?n;u2s8BX$V zn%I?-M|BXgl)}1hI#+npITE>trnxPh3VH^97-!D#E% zr?w}v%p&#e?SgM6r9pjd=Mb*5#drxVJG_XWLzK<2xQB*EkBHW@BjAH^!gbYIU>7E5 zX~|zVIPhwJ$KbicifLTEzJ3jL05CiRyPSBHOD)q(F1a2~v(z_tzJHkV6<$-r!WtAD zE1Oi;ju_u_fm8SGLdECD0v8u>W{Po*yCHYcy9&6vf3z07)~r7UhbA*a8t5-tU?PW% zq;b=K|J7s+*>@EnhWvRo*F^Sod`}$1?6X~<*DvUz&dOt3Y8C|;Kc8*I4XkoRcL#M2!~4e}Y>S>Qic#$3P?1N`2otIyUxd{ru;QW7uCI0mhbOrv~R zSr&AO^XPn540rPOukpY-j!^FfiI1(^fSt%maWlzS~&M89dlb$@cf1p!N#bj-O0(NbwDwC zV7RumC5@100~vG7ML}AXnzMVj@X2{^Gxl@TO$RQ|)K6zI?VNWQPq`(^N81fw&lqXt zzUYd@mEL65+mpJK_fXzdckWK;H?a=SjaEz@J&-;msXZP`k3QucG3b(G>jJ*w%431< zxLu9-#p0M|2pzAWSA^*MUJ2bupO>Z`t;a-nknq&rrf-kpcur(F=NLx%S}pv=ZvO13 zux`IIf^l<<_O1HVFGC7eMW^JRo(A=01spFCW)wmpyE`R!0MZYmYzBgV3Ldt;2WkY; zAqd-|@Ec(R!cf5FBa{z=7q-g%+Sez47Gu0j7pXiKgO}+<{|aa;&&9YA4~GkqBLd4z zAoGzJs@#{vNc&*ol7Eb;*bC^51$@#lYNjoYm42trhw?MfCRaH98x8lzrIZlJ;K(#W z>7*sFKR-+f$q&cWTlezne|}Al;fi95h1~gqYh`%J4139Aq%cH1^lPF|o*D~R3{?72 z%n~6t$&(r%G$$nZgf4BQPHgffN(Xw`m1Z%#BqMf%GpcXakfA71!Y#lO{nc=pghw#X zy%W<$9cv=Ehhy8L3)fLT|7s{7ymx`gLKN+rgV#QE@HOTbs zg%{(Vu1@fApV0bv{;%4MUv@Y|HsUyr@a;^wy<~M|O0<~bOifwSm;Y^GbcXlWz0$wn z7TRpTdnq-bK;i0?M#~^oHjP&UN#4{;$v;XHS=cT)-fR(#r z3L+>NcPPdYk;WAQSQ{H7O{T7?@>?;|LH34cJu1H^sTsIFC3A35%7U zwqOU7mJ0b)RWa7*Tf8%kShW#Dzd8kDy*$Mto+E7bMN5-g2SeCIS&ERhvz`mzd1@A& zf{JJ1D1BYJt}t02@F?yZTEr%Blb^D9CpNKa1GusGfkwU8;=(CGh&soD0TnUM8N`vl zr5H0Q#!O3=5mL#y7I7b93aQtqsi9j;sy(qs3c>|T`0zX0 z`F>oMK4+h&u0Y317V%9=&trqKvelFxE2T%o50YcIh}$SR_CXZ&D?&*{sGI`vfSGN9 zxkaG3vIkQme+e8lnQ)S|)cl1eUHAG@BhA-RBmLRZuNTfSR()080l%D-U_lPz`nVd81icw>5DR`e!y^8{1GAUx!-G=FpO6G&A%R3c zSt0V>7I7t{WbYnCkv;;7978BET0*3Bi})x|)U?5Lupa_N;(@~QS~_6zigLzVD(W;X z9qJRlbhz~I=1tZTGWFL9QODm&i1aQcM2Z4eHVRx}q+%peu`}Q`qyqcXR0Gkt#2l)- z(p?tu&u1V`;vI?KB8ekNoCpif2H=jfSfh>~iC-Qib3{479}EEds;ZTVPvkwsiW9(EB#jb)R&@GFH{yq05jo$${pMzgzu zCf6rH;~%c>Wi(Ov1L20f0V{EEO@KZO9AR*y0I`4~&@CxzI}z!Ue;g2#5Jxs^vxs-$ zlv0kQMFH&IvXK^hO#&?$vZYrLe}X)Ogd1WJ|BK*k8C?p@p~J?hMa(@z_``p}-=g9B z6TZI%BMjVO7Jk{unu1d;P5zCT^B5huTxxEai>g-wl06ue`Vx_!yPo~1wxa0fyVZl#eV^fo(*1Ipqx+-g`t4WU(4|@^5)a_UE$v(PR+EkUO;Ob41JD0oEIAX@hhq#k+>TY@r!HejzwAW5Fq z2!1Al8)n{gvUdAlxl!NN=ES4U>csUVtuzsJl`@GPFpoSh)THBtd50Q~VIsj^lMV!V z9hju6KbnOaSAz7T*|rWBvXY(y%hSXi?Xw3#>9niRgS!*yASAXllSr2@BPap4s>MPr zif%K`kdLNe5Kd3cEM~h9n(d89TC3q-((o^tdG}e&isRqc2b}bXi%Cv3$s)S`*-xzD zdxJdkU7*R9`#LGO8T#ZSVWzu@AJM``w3BW*>~-rF2H_+IbvPYv1fU}jZ2+(jup6)y zuovkR~TunDjpune#SFc**xNC0pE9pF*`uGj!} z1F8U<0UH6!01E*bfFytk;19UO0w1sk;0A03tOKk7qytW)Vz%IaMz(&9_z(PPKAPEo%=+*-lP!HGv*s6~+W*5P; z46qQevn=#1x`dqrjZdBALa@$#D^wKvvFbrTIbar}aXPM^GK=Ljz??Gs_7hYG^>8Y+ zmwjefSp+hR_V)^TWP?R4)4ss-;tl%3Sj5frMGdxye>GW<+447SLXVqr$ z1&uz)0>g_yLd(OzVUXOR8k$PYSpCW@KC5v+$7GNyVT%-`hs|D$+a%DJX7NuNIctF_ zMv5NYQTrKgM+Qy)FL_Z>X+igIGpsa`I4-?KTunZevD8dB0o*7I0PGbnveW@&=`%BC zX2i~8h6)}$tjC;@$?c%|#P>b{+DL#;%;FL)96i$`8bu#P)^bY|Ql@q+ePo99MvAY; z4DDl`ONSX6vFtIAoTH7t_t!|BX3?RMqrKf1+LH!_NSZYtOd}z#nQ?wi3_8uzYqDF5 z#F{f$8phxEnKp<;NVm)w#3;POY~|ea?#{?G_Jl7zmq~_5d?)bG9cSA6)V3I8>-$Z7bHa;S!X zk?>t02vb|U1mF7zP7r}&rlWC0&}78E1fMXA-)RKL&A0+))jOb3j_=_&hl(c$ zFe8zUnZ?Xg6u-LPEFL3Nw#h6ukwLJn})aIF^DWG<Wm?F&3R$OBoha9R+`?Vx@|-tKGGA0ypr5jsH)`D?TI4~^XQ6|mWd zeAuenmrJ_{dyQEv(>S6#+Cm=n3n0tC0dn+Y8xUUiVZTp#x(a=t#&Wk=+@xWDPJ%2P z#Ag5D#g^VB>=kCQn2=oZzs#gYh$Q`sm_K<3eVY&cZJe9e~qpU`B3{muEzBVE%2-TmhU0 zbl_s`QMg;n{(WJTOC3L;`VGANw`1bmlPzcT_R%aKc9t6@y=2K7ebVVTiPJZ1IMaPv z_8!`A!J*L=4_-LpumUY`H}HXH#dogRrk>1`PM%>7ghm!VZD@BF%l&~>m6(Ndf|@XZ z{W^}0OL2z*rhN8djRlT4>%uK1)%Bkqd0cPZP#xcSrgk)|K2K}s=(W)pCh#y(-d!ih zq36IR!%9v{vv2}76xiw>JwJ0xMQSZSqlv%2g`eKePt#6qwhiU8SBDGPn*iR2<-Wng za%b|mO57Re^N(p)q#gMMI!Wloy=EPoFwhwD=W9Z;?kyo6HZ-!BaSW^%j1%dH=bO&R zHgs?DePvzH1N^jX?8R{pO3?$n^*9?9if1Ue`OJ4`P$-A=jpI%=G~q;pvr5CDy9$-T zmx8c&ipqX92!&^1Uks{=J*Hi6omc9hFVYJ^Q0takgCLEDalLHk#rqy+*M%a5*y5To z#X8K72p;f9oBO*(ZfIR zd?;7-SXe>`xt1n#H!zZ(!$7oA-VcNg4qaQoo4!rieyI=hel zKgwq}^$+R<|2@gwI+K3}fJ0aJv@#syEn968KSYnJ>6i3*PJv z&Zc0-Md2@c!`Yv;aO|QG_j@VaV@B}vzToRxu&f13nH1bl!O!}Ff6{_o-r&gyX8S03 zy)XEx7W_wVa0UhUAlM~7=?#}IYvI55hTl!$-9*0H7yP{z{Dc-Pr&BQIgq--8FZiMs zj7>#|E?W_d=`4aDMdwo-DIn{l3teIXkkw`lbBV`+fCVdEuol9_va!Ul&8#8Itwc$C zFqGrxHS`BG#%wasusTKXd|&W)T5z5>_$~^@{W4CR?G0wnYQZzT!Q&|SM+%jCpGeHZ}3Dv) zjMD*87;AuzwHu7dohTo{GAyusB}Xz_CQy12oA(1 z5W}-(K76`|UKWKtP4)#23csh!6ZwSBnyMz~i}5E1&_|`#mcbZZWQrt&+Bi?%$g6Al z=&X>H;Dz=YnZh0mB`pnhPMLCblxqnZdp5wdh2F_ITI(EIv-!lCmtj5#ryEj5(0P5K zHA>T)Mh}}1TG~##$!Z)rS@g%SQ->3p7(AN9}Dv&H7?diGHx=im7B zDe=~omHr%#{jVC>D}k{4FBjfSFu*J#lf}5O*_-Krc`6|fGyl^D=}hQB9@`v}ClF`Y zdDfaROm|jeD3|Im3C}_Y6G#`7rB7k5ncjA~^6a3|=IKx$NC0qvE5k`mfGoy5eByvJ zXboLViqtV-B2!n0VF(*yZoT|Esl&=&1m$qL!pt#J?yb^Fyyl4O-sSxzLog|& zfmr%SKN!~`lM0i9@xT#jDZSP&UxfAim=wY!ovBRu#{bozrqUWdEn42K!kd*TpSb)Q!TT> zA}G!tS7@F_FU!IbB&E8vUvTRXCb&n}1?e~ew`uF32#9c;RSWW8`h~L5*Ru6eN!gNX z<6*GvZ`YDX?m#j&0@eYdQOmr#Fr*Z9w(Qikv95r}VGF$KIL^_+?FMTt9z`e;YW-mt z289uhS9A9qN6p5;ccCSa-+f%J2+H3Qj)T)eYaqYlIJS|(?ct!!-!i0e*YRWq7J%gE zgA!nL8wb?#tD$Ynj+Ng_Ss|4KWneIYDrrmyTHscyP6p}uAeRqUEekE5?L*{$b1Z|I z6(&amQ`!>Bzkyky4n{?s^Nv~VZaf8Rb(0d9>N0EkPFxQOP+;U=CV2|YEdSDR>E$3k zS*tfWX}X4s7$0%#du4x=9jRhZdKycPW2*f~P>tSo3lCqG2#^-VHIvqdEkk%0G0Jzq zgf$-O5IZjOw>#v2gyg;HS+m`n&vd z;$`SLLG1~p?bUmuPAd1LmP`7QcXTy3$iPoI*>6Tj{=9MgHII}N8n7K_s-0;JCLb9m zaq+QR-;yHaj}GLIoyOlo&uOL3fW!$nbrN~L~{VQq3$6FB%~x; z-<%)+$x3cZ-2?bqhlg5Il5xQ~AVcSS88i?1AgZ4y`~SI}I%VieaHBjW4IW+i>+L1`J<8EkCVWx? zx~L>TDGcXq0;I#g4sH=(8DI$@8?dEv31-MG&aLgvvI{G&wmneBwhI}$2Bbb$55++P z6L%8+*Y)8A5dlx=uv`$J3sSLJaO(N&>lot3F|_;kcX5mJC3Q{NBkhq3rS6+s_?Jox zVEj`xcf77A^Sed_%eme7juRW^09;v!h*qbsJanfzxSymk&M8 z4MBFoQjB9i6MnzZHm|I)J<6J7Udz8!nDQjO$75utbzj%>^N)D%wIKj1h~ktZ!ZDQ4 zj?1|B+T`KyD;sljq^tednu$lj?lXa1TN%B2O|g}K5sQ_)+D2z@Bi1CJFP~iD)QO>X_pU6XP?H)tRr)wMp@uU;YVnK4 z%jOuNVg;dJ;p7Qe_N5BP7<I=C^7o4o?OeY5-##358fK!6btAl4^9geE`) z3DAy}YX=lThKF+I7WY<4lyk|C7i}Lx=W_`ZC_+?!bF%R?^ef~zqJqY(5muyKx5l_) zLhbxgZ!To{=Ni~Ia0hZ08`sWR8vlOS&M!GS)oph=g=I&}W4u^W2xQ<8X=1Ew)I>1i zU0>Azz1k(V7d;f4)EA0LH;f6}olDhG6amHQpKFx1QC|4jF?jn;3={FSY*eS&6$#n` za3@6fmBg4VR^19Qa?~h@VdoM1@$h*JMNgqpK&asE@Cv|^01^uUV7`C^c+4xn&0h%+ z_G!HqKKQYq+8Os#WZ0kmv>S4?EUuhX_0OtM(17~ChbWiNM)vbTZz zJ|Fj1je9FJdZ0G&vnlQgea$!gT09ISbZyuueK+%7@}dbr04?%~}BK%G5&CL#EOflR5eMTexYDN$w$! zcTT0AH$gI*QAv}?U=J;r*@GIc`ob;k(H?QiPu|bp4Wi1^2T`SZ)2pvzV@^HR6OclD zcl-ECrwJMTDGUOrX@lspYASsiW9b!-W`g7cLWU03i9yDaIEbm%A|?IUC-Gt&8^mB! z?qF1#@{@bTe|j;bMlXgbtyoPOM3KKX z+HDMP@8Lhc*ks4H9tkttH6Mb^0!#&D0-^xk-DGSf*KEFkJ!S8Pa=SBzUUzac`BR2A zHZ=?Gr!YIWx{t!c#&u)naI`=AoK@4(JSx=ElSl}cV=3f<{UTO^woebBsk3v zf0&E4wvjzeKW0K5=%VawdOJ4BYrblLW-Z4ssq_`Eh`#?VTtbXtQ`+!y=R5Qt=C3}u zbzWa{9Qy!xV9mU5nR?a^$ z*3Ri?2zYIwW}9b*0Oa_xp-=^#1;!=*$OEd*e$vviR|evlt7Tse#N72xomYqRyg&0> z+Es4Yz~{D)QkPe9fmu#|hW8Rz{-wuG0NU4vg%a_Z(b+od0zKl=1?HS>Au zY)m}RxU)E+CQ|<7wx+cdIvrMxH;#}lX`k9f*QbY%=kS)h@crk}w;(jdD z<=>b#xS1{P0&)Mr)P!O|ADDVGI)2h(+h>ZzFnN>h;Jz(ylMOM9+*G*mMgH}J-j!37 zJ-#fE%qrv>)$eZ$A$VM&AU8G*d7lqy$8E1i{@CYXf4YrZ z2k5gv0nJi*Qt1DG-{cA;pB{}x0bt*lxa{Syw7LiG62L-0^Jp9b0hR-n0FIBs)(&7U zU^<{RYB6@KqJRik0ayl@510#>3P=Z}0%8GMDpS$KYn^`)e?ElmEdJV|7Uw3t^RG?L z7uucA<8J@agD9HITZVAv>Xzr4n~NIfDM$3ooapy2@$m)ECy>PQ_IPP6MnjBK# z+@KB%vGUJ6trzw#&k9-VEM`skUjRK}m-89PLSeR7J$Vx^74RF@^2L*waiP8_Mq+Xi zEmSPW9PciZgSfKF}SP$qM}X@GX9Lg|I+hwO0Qw|Jfmj;SHqwy+gL= zAU^;8A+W(6U4Qsyl8G>wr`zFyoJI zZ(_u{!$QS5nBzD%M5x$pB`>BDzYDRSXAAfzpw}Q&V8Mc@i1V@#p`yx4A0pG(--g(E z*INE@=rO=HP^17M?!3LmKp1^w2ZTP^H|p1$z$1cCy!Z^32|W35dyagyGp7Np55?BMw7_X%P7b? z>HY4w6zX;Fxgx8Vqn5pSZ;x#Oo!)k?8r9YqIbb{4 z_>0wh^{h#|w~%O}+cn33h0I2_;VMHzBVA>{^$5%^(YZlC*QDpiY@zvUS;S#ZnH$J( zL0mjk!Q!B9raT(R#Jk+^UZYJAxZQ9KMm$*tzkeC58o-^4ZN9m1GXW-iOMn{%*912S zt`2TG+}5$cfqNS6RJiqUs{x+^ssQDHt$j77ABEKI07Xmio|8%&e za2*(u5@KC(+1v1k!$&vV?if;s0} zPKTQfHwkVOKnIwP|L1sQF`yhU7ynD)E`qxb?sB-x;TFN24|hG>jeuG3rvom9c$KtK>zdYsEzUjH{lwOTP0p{{onPvm-u`Qp>*;l=9UiC3^l=k&j z>if)?pkaHfVAbc$yEHE>NclYe^-P;67?qE!-vX{V6-o{5+BUO<-TR&?A9YDDXm)+58&>*UGK=B@6UgIklCdY`y(bt zW$c6bx%$ky>tqJiy1%wBx04%#jXHSUNzNJk|3a+XZYY8`o{*<>vF^i%fqy00BpHfhi z@}hwm9(JB+hG_u;)Tsz9RN0N-MMLQ$mqupQcM?H>_J0cgBO}GSON^dAT&vuW@W4)fCD2kFLz~^DdahhZ`Jg(rNXojMv&o+*Umaj>Dyc?BhMu1t%w(r+7Um&`Kj7!p7gQ>bEsrkT>@6bOih;#}1>sE2F02Tu#K#7hT8*RG zAJ(<44gI#l0ocjNYdwr7z@G>BKPqN)i~de}bY2qIz@E8mAOlbNTKXcLn*^dmotFmixdu2h&9OYqlM zYwexlo~wdir}B-78DZcCO57Sw@Bs6GhBM@S;M@}5Q@%7Y(W!sa0{i-z9Fn-Nmc+?` zES-XppV*AcjkR_Mzw|H+go|m-81=neul1L#*9d>=XVMfg6fK%p^5DP%aSxw!n9fw4 z;mxRfLO@Y%#g%W>UG~tt{GSu2W=qAHdokr!ZKgG_v2vu}F{B7>0VOeV!AeffHkDLr zjKA$?Oj;?_atOBV?*|6<3*>v1#!x0IHq%rSH?V7V=#Nt~_s*D=Y>@9U5!x61D~&*0 ztbf`dPgX+BOxVatCTmI+*;PVYywXKT9}+K&*%Os)GczpyZqu&Z(6dv8if&@nBd`-R zRy+FFR&=j4XsA6;scFi3Gcz*v4DDXzJIts@QRe4A)|ceKy!?N`TktE=RB46EC5f@N zpr0qFlM#U*l>KIAaoE{IuzFCSqsX81M$RTE85SmP%2<=IW8>K;5)17C)TKEpt~~g_ znhQ6wr|z0DEt!Q;q*b3$*A`g@-5FBoixgH$biK!5zqEX5M^qtzJXhI-h}5O;Ul$#Pty_(qiEodgpV-c z`kFPqd@s@3`WNdFAVvI=scb!E>QLJ~UbbquGAoQ3e zZ}&{J^0wwWp!_9P&_~;``b#(2E0r13o2PD`WS!4qpkl*XZNvJ#k*L8YE@~y$gq7y8 zy6PCLG^69Q?rP55EWDY4ty#gWTjO{6*{>CT7&Dv+R3;5$M!UvoqHJLiDK`R9?vYqX#%N-ydXZo0dI`Am1rGF>;m|psK?c>6zQPiZ@@yGf& z3_G@_K5zVaunCrYAOI@E-V!*}mornVLJfV)H81Ig6x;h&_tM~m#+UnvSn>P+UmZ5R4pOj^fBi(+9t%AS5W8dQCwV7p^WlMd z6k+GmNO4Xba?EoA#9ac(Z_tLv1M+lW7``e>q=Xc zJ;RwOm+@QdD1Q)8aCk{_Ko*CVE8k-T@`j2le|gT4Qf^z>mmHY6cf+brAcunhyJ5{3q&rA3PWy9kUx!g|)yWY#(R-z)AG4X#?+wR0$c$M7X4PLTn%QQm+bSA8BU@JG(vH zF_%BCv8=n7u^azM1LdLYshj6cb(2ak`xZ``sdudGbr}Dd^D?R>CBogyY}cZzMRXqo zUui}(_BFor#HUI4C{$cYgjzsmVMLJam0r0bBu7tsi(4s6RCmZOWZ`yqvrwEW6pIlm zI=_R0RxkXm6;~!_p+KapHXt<@6x%{oTtUI>R*x<7%CeDo94st(qF={v=%v+li#ByD z?q!}Ksrt}Xy-lUlK7ne2PA!i>`%}h7F(X}Tdo?bYZUqc2S=g_o=ZRkCF)ck?0to+w z-qLl{Iiz9c@gBY7BlwHmJvH5UdR=?R=VCo=?$j<(mj<*{T>0_3wQ>p8-IKHAR)cL( zuXFynwJFbdBf)MZG{B?^V@?Z>4=5vD3wrZH_Xm{sd2@1JFEh(qaNg=5)O#*`xIaEk zK+_TbzMqjOu%STwR@D@t;-Wf`OIlq>Y_m=ECB>Mt3GB3#*m{`^BJs{nAE1PwYzp+X zQk6IUQImQdY*o&BU;Gn$nIyu$W=F#F#wZVsVn#%b2g=U6C;F(UlX{sknt&}NVBS;8 z=21+NtKs}4{RZ~dnpah);i#AKh+fCA^|0z#cT1xS?_~nLbbfJBfr5K!d{j7ey7)M) zve`^t(KU4z(a;NB1(<;>)bS-jaD*vWE0B9s3|A-gk})h)YuL8O<2) zWqdrQLn$ESpw)dGV@p2=oRB(J>}=S({+&wN@UDj`8#SF28E!j=FB*y27a-dnG2 z23YmZv?i#@N6{mc;Tv#bm7<=9zs&h+U6Z>QZ{p=WSobs+nG92(Gec_X_HlYBZjNZR z-GGgRXh&I=0cX1G3>?=oQ>u{$sLL>s$#{N5&!-`pTHe~ki*z8YWb#a)Ypw-16tl2% z0yh(Inhat9?!4^M;zu znS~3Pu6i2(ybp)(q?b1{S%>NQox_+TcoC; z_(%Mg?m?>EV1+zlXBh?luBx>HpIjwCYaRjE6@QKptnRAGBK}N$lKw$u9u(@c#>N}_ zaUL6PMUUl9Y{T7VXpDEvYBsP`JJ?yV@v$f+EQ z2P$Aq9??_4U62j-*rdCRqIr;z%`}Q3UP2`GSA;H5O7D0nr35df8gCTYK}tEpDEj%L zoH$4c3+{Mf+@QYci!#<1WvnrQvn{>iKvpimj#Isy8-#QqlVkxHs0u937YE-kYT_rs z{PGuH=GqvwFzrVI-U%hsY_6|2Hyle;_ zFBM25;0nhkpgX;GNWU)edh_O18B$E*e9VVldPr8tDHr&GE8bGXy z2nJT>&X#0Fni-heXQW+Xygv@frwqAvcV|YwX$H(EcM9MRY z&1bREfk)KEH-7e}K^krpU!!zWdcsk9+fY+N*p2X&=IY5WZ#0gyFHF($Fe`-p3)t_# zd3IzPYTkX6UZjtKyNzy2;YgU81L9Xhi3Kr`T*kY=U>r~p2|eji;^UFXLkW=D6$MEB z1}|Zs(i?}JM>W|f&ZyV;qgoF&iqr6i7zcrIu^ryQYW)=I7zK2K0i=;S4Pw?HAv?q< z-s2^d0{$PNROBU;Zh8sTc7rGm5>Au+jADwHQq>Pq`l_|O+Dj?_?4@LXHlSL+blKtF z;j7jWsMb4>GuM@$55n^0IFA3Y2HRwUo{?AF;16|JccxC#^U^JJzj1;w&Kg!|9>u?R3-{Sd{B-;~ zx6smZ7#;uCEj$O$bbN`X;z-irfpT=zkVg6nXKvBBY%!zr|JhI+rR&Er0*f;Y2B4d% z)BS+|cxJBMX=!^_iArP=;>TU}T3Jd@X0V2NBBXKCerRHKV0&zSE9d9fu`%hbsMs|t zmB)b`y}E|e7r2)u9iQwdkf7yz$Zy(~n|#2nH9Kn2bw2yN@<}4&%=oFp%EiODYhet_ zSJz8j95!C$JvW5yFR5SL;BTqg3yM}_5%%T^rwr4Kd&2$`|FtsfE+&?FQdx5s6Yi2` z-{9=1)6836AieE|uybQL2eg6JSvNQbeRtFMCc~(62CfC)rI|OlmMjDF8hvJC+5;|l zbfkpR_L2t*N7%u^X@7iHD4iS{m4GD1 zoWn{t`02IL_Z4F|S}>THVq&i8|3GbEw79m58|IjT36Ea3-@s=klLiNZw=|?Hqhi%Ihw@qhP+!~7%u48fp&3?GLXc?jO*&4Pao^}{(V+1fZnq`8Z2-_ zkka@pz4Qbu(*?rALbcC(mv(g|4t)Sq0rlwJ`*61w(<@Bj+MOwF;w?ze;wxtYwwM0B4* zO033teDzVZuno=x6^2?2QoS;MJhZo@r_j_u%=%;AuuP7H9MXGS2G+S=Nu{qK9vg$t zY&+K&zc*u^baxpc2c9?{mg@r*cXZ?XaAoby{zNtJyN;%-L`S~a_l6Dw(gan9g9+)t36Hdy(D zHa|7Ij1|t2<^&#Bn4>EhiCZ60{D2agf?e)TMNGjQ{u((Wa;;n#FiNMOz|@>hn1bV9 zJBL&wCYrkGrK@f1hBp4^TH7B;H(}P9ysNd&j@mUp)Sh89btmMgw8W@g2W77-)hSF= z^tBG?djZY?jsqG1RREvz-F&4lh2f*$za`G3jFwtE*4%%pU+)+Kg|3=ur)*#Dxe$1& zu|dg7Wn%Smh_W=5i5VstLb%!-I-Q{RQ*Ar;VE>&}{*lUzF=6(rsotHtRl;B;$1C5a zGNbufP})fX!~&uKPN==;;C7?BZK>GIXDC4;6VHSzqR3cWb53DcKBO;Q3Z*&dicY+( zT`Cb1P6-xWRZB4RwK{O}a?LKj{|$Ef?0!4NshtgBg5SHg(Wiu|I(V?q5Km)7)T?Q? z)n%RH$V7 z?``=%9`%hrSqZhG$5M@L=*H-^YWC_ad&TmWMg~)T{~5O0*~@EfI=mh$7?d~#!k8&M?AKv7zTK~8(eg|^G?*M)NUVq0qKgY0K zheMZF@|`dYB~7(vfv&;M-tNo^#%+@CxM2l)-Q4_CXU$&Nm3G*51p&JC?b$-=62UY# zy(}6^gwaLR68mno;OS#yQQ;On``s-*Cyw+i?y{&nS#=}cPA7SgA5;3n9x3~KM2 zJ>k#MU+u;8BB;PaE-we!NaS>N>mRppD@j|da}IPDoS*Gkr9GWVzW0xwNFi#915pJT z`6ASSEKm#XqnMZedjLaOX=N}y>%k@GOhc`1%Tp6V^7S6rFwNgS(70S#Jb_8~OIBHB z>jY+UGP}1ETRg%!%tSi#TbR5V9{axj?5VBbhk0Yvl(|zk;~c@u{e7i(0+SG)?rEiC z5cF?}g3%G)l*Rk2s-#T18`I%9<)OQoyZOJj!@TZ{ER?b{6XWK@F^`>HWZ!XMhGh5G zb4GseT%XP-)`-Jvn7v=4KH+=5*;@B423$U~ z-L4yXK5ntTc4Y^>79Nk@ z!cZuL@r^K(Z?)_AqXX3T{Od*`Gv6|k1@YQ*jKIBDYL+RO2K2CVK&c1)e|ij_Ql2$W{AA9?XPEgZInCF~%$FJXRt8OC=T1P*a$ z7#3C1YcEe?<}%K}zdw+mFSl}Ld1W_H8JMCIA0I%E|0&M5zm`4>F1brr6Gm2a z+4NqTj+ewEr*(XJjk?1h7a^hHPSvc1;bZp624lWHkY1st%UkT|6lSte3x5ewxILxqDAnj+y#+n0bhipXm$;@o=%=TG~>QjE)jJK3{az zP4FUQ`OE7&ORV&#Z1cY&7H@@x)#I2fT>^AG0No(`UjfJl%tb#L4L1-l3;w`7=p7Lr z;P~sHfg!za_#5V8!j+5u_Z8p(On?Z0PWfmu!@J~vc8j|2aVx1uU^_X{a|tWMBOF=0 z#3da;J&ZcC3kBFSH7f)dGiY4|cMk`&FFBahh1sPz;XE89nO~$WZMV*6Cu$mXJUwQH# z#xYzy>u*oF`+fZ;|71gPYSD&O>6NR}A+rIwK9x;-V;nj)sgx=-s14f>J?bQfx>>4i+%mB=;p2=X`n zV29&SgJac1R`s{d2m6UDQPnAeO}+@Wc_RqBMTlyxzxq!DuEouOk?}Y^ds)!u+^5-o zbnoa9B-bHMtojP8b1;7k3EY-tgzq~}%)g{1M|zXHP*IIs=)sGMxd!=jB$}4@SYP){ z?MVZNF^CnR(#yW=+02oxEXpal0-wCd+kiS1U!r^>zND!tT+T%IZPag*c@$PK@|QlUv^6jsBPHkqtfpT|NO_9NxOr=+wV)qMyr4$o}pB6S70S zgzS1Rq5Nk~{0QxfA}r;^uCKij{`LRU$pO9y*ZCsEZ2y!m!cCm`lb4R&~!NcnQ_jgd(202uZ)-_))bq&RXdk z3Kq7lkfBu|9Tdv&vZuNCC`VNW*eH0IJ z;vU2jfzfm`XIpR#VOD<~jHng^Ap$e!NI`yuq?R5)Mf${t>gH;~u5vr*(ht(}^c_?c z)e#@&!;Z)?j7|MmLEzp9k_1uh6%jM?aLJks0nI|gstv)bYP0r_)e*U>_0g1 z?HaJCH?Req_-2ik7|BTqiF9Fm4FV-|(vbk~_t_L1JDU^By)^2>ocNlThJ9G086;sF zyd>;QO~4tP__CKoeuxt{dr8y>iG-32DjW$P@R3X>5_uXoKfz#2xZpsp(9@Lc8t9yp z$T?h27*(*tuXACXU-aR!=qb-#XLX#4!r1b)rTbvtGZ{AvXQ`ze zl8(-jWtE+FCe^hG=7M$s>ald-*Vo}`jv(;>eOj zPQ05IrL_&5bU(0LYg#-Luo?HIKmSDy>_6?%^V^#wiRGX9O8%3953P~@WU#wEd`Yv_ z{qth~0(X!6bTB`!PF<&zPGO?3m;25X?AWpF5VQto>vcU&CdPC5qX+O51hy88-7si^ z=j!BpIc&=bHL>iyI4(-X`xR_1cNz`DdMH-?1O{uTFl~-D;Y*kmHx=# zZEct^&&0mkI{^rl6F?*V6^N;90yxFW@%YVjN%5T6_9aZ8aBK!=TiJ}qJ}SmzoSqA@ zz^*20IGYnC9ha4ic)Tr$xIOb2lA@552q z9>8wE3cw;jQ9f+}x$&$Cc7f2X>z&HUsf^Jz(4}7U| z5o%VmXcteyvrJ0n#P4CQMor>!aou(q!la#)u1KV185_xob=Bm#i>5P>Kam4cF02Nx zR^J2~8$oFDa1J{R#Ma5xJpK)uo3d15MviCw4fu$~kUWnQTVWS&HM$4fiz3X$95)(w z%WW#|m~-1n5~WIF;-_GP3c*>h*NoPL+b&>s`Qy)F&=+6T2RKTM5K65dfAcvp33g>y zOZh~@#<${E4(7_L`@)r^9GsbdibKWNSD~`K0J%3Gwk#Z){T014MDF$En}>+q7}5OL z@4LisWJZK~4<`4l{<`9Rdw*WyCaQWL`A9 zo2b(VYz8zKF%ZDr1}F!(0XqOY0mTSg4=4hx1}p+p;rlK?6#QX;az&noX_oBA!R`R2 zhK*g~QBO?->It^rVUJ7C+1)!d%WydKSs##K!$orH#<9(JBUnR{ZUi@sDVgLi;(C#n zNF4~)h|u|CL+_6uVwvmxdi;@pA{wk(*q?%fQ?M%ktUwP{S5X-^or&bwo?zhMy1P*> zQszu&Mw_KBG%b_hZb*#5#VyPV*C;Mvj$to?&uItDsg1<~h^W{WFXq;0T*6m&Psac# zwQB5)xgqLfkimP|e#4$F^B8f12c0BRcOw`)u#Uphhhyy+HI@fh`7CbCg{SsF)dk8U z^70$uA*l0&lNckP2?m*jU!?wYu$^qfZPjkrpAHsRVTz73va5q}%FI&bk^7lZ7U>7C zWPOkf7r?WO@)G55_cM`qvrWN5MW8PcjankKUt-#x9Ks$A7U$yl8NLg_WV65oYWX4M zzxPwd{D-0!j^mJ7s13^vkryf#q=^S>Lvy67jLj?B$|4IXS8%aL)qBm-g*?x;OSu7D5Y;U6F=;m<{w+S$pnQ#`YWMP zSHmh9bD*E8Zt|8YjJV7c&>Z|Q0hQUmUL&m#OJmY*A@_~)d5A)&^haWff(2}jXcbcZ zy_TBa6FK@uO>1*)uvpnl5y{WpiDrOB7vyKx!+zGpuq1G5sZ99sdvRNHvJoAT>sfC- zh5lL;NhS5-64+na=e+T^oM(jDRpm<&g-{uVQkGXhfCMl>iq*$80UoF9M4GbOvDTFz zqjtWrneH%Nlm7fmZicA02IbIfZ6FQy%Iq0aMu~rHPWJESP%))-TEU*sQx||{m@c;~ ztL8EzXR*r=X*Og?jFpyBob1xUBBa_>5NtKR%g;Lk`wiGqa~#34-Jyd~cT{-lY}VWn zLaXg3=Q4ste!`b(UsSWyD@t%4BTQC*gQymI)5pS({&t}+eKXKCst-`|{?xA}PhNh9 zGqvyEg5DxO`oC#drv6tc&tpd1BjthdYNUZOaV{~I=Kd-X(i~#^8!uya$*&m8XO-4G zhIg=w|5xPo(kYbGcJ>jJR0n5ihX&#!>wP7)o+6o!2simkYMNG3(|jH0P;LKMT2Qz9o zk^)S$)Rtq|X4y*J!}u&#Qra9$j7goP^)yiB@lPC|Ymk)Kc}${9oe05pBPU?>W1_F2 zR&GrkE8UInFb{%0L!O{z&;+X5XiH?wMoJGBTl=u1iHwsdPK+ss**xL%mJ|NMYzKX| zLUp(gl^++%gHe?+y)&s_4OTin;`8&yetoi^a%dhi>`^wG$_e5MmHQIMW*Ma~keUBt z?cQoHtT6L@JAl^uZx>E^W!0;2*5#CP4PZ~jdS^WKFD2^bm8@ycAgkN#RPz++TI#v_- zm>-zZP|RT{Uckg;vZ2Ak_6V=Ml1bxh`X71O5aRrZkMo#cab}fU3z*n&If}kf#(J5v zLT#-4s*;k=j2W#C0rymJ$LIksG9y3}!%Y(_R#}nH%yP+Q3dlu;lwPEQB^yeY&D1kE z+zk)T7sLCKS?Ix`wz4K)?CtK|J?$8PS#%VCK^a@s&}&%Rqi>MM*;*kbIRVXJh8DGDPNax-%`3u7pq|MNO!+vorNoyX&O zUf1=yUf27&zrTyEzLsD&<3Yr&t}|HsLB!F?v{?sVq8AwB2(Pk)L8Mc2i>(tFms`@K zGYX6f^BN-`!WU+d`-0~(-q(?sGKd(w%)3%Fjjo5(McFZMdT?XY|JO4R%wTn0^SBa!proe}Z&{e}`8E zXtPZfJR-O&x6sgC)_S$ozyn3w5`R8n9C0mFXK{2e4#)FUCPYM54NB-;EwYRwUtu2Q z5b9*Qi2ISHi(2En8nDcMyrhJ0OY7JUGbSz$#@U=J`8pV9)nK^aq^pB|+fl3tjEzv+ zc9QTpN}nn&(wG-LxLRPr(Pqo6Q+Y+GlKiVbosZQvffuMhz5!(s?Zga~SBAYx(du5N4=R zF|Pd);SaR@pvB-AJjvd{=$0Sifh9uo+CTW+rkD^o%SAA_wUi=J_zhiLusgCxpy?=# z!Ytow`SLatXS7BkAN&l{nSVviUAd?^pNpFEwMOjn#YDnsZDG5^;A8n4SMtZ@YRxzQ zwPNaQ`}$#SMLMkIgEA<7(i$Hq+*QlJl4hApS`OMieo%`W;+Bd+i?!4a-7KLtP9bmB4oExTCXVZ_Hv8u7Qi(T&d<*=C@m zO?4%1(q}Al7`k({j##n5s6HPw55SG8nkQyfH}Jfj@fF6oQq~LO5`5U#a#?F!426s7 zfY$ho&vNA1lGz1jQV5dS^d($&v3#MmO$hn&+`R2Iw|G};>~RAM(_IMoO3GvGhw;Uu zBIe}|p&7)|u@+qO=h}wB{6=`f7alqmYxB(Mo0=zh$J=~eYaC~@b`8GpwtW3q-{+3bJ)j6(u-@GU1VS@W?)Pd^jR%$_t~+?ei?ssS@u`ZLW7!+Wgj4b7Qz_UI|xC zD;r$3{G!DkHTcnzqcuh<@Knw}(v2W(Sq5qIGOh8=b?&M2Hm_}atT)`@{<8gZe=X74 z`@Hp7BD~cfh=D`QONX?^zoAGqufm%cRzrV$dKEHhQg~r1j7|2inPi&Fzbwtw8qXmP(oH9{ zMt9_hbW0I(Edrd55`%wf?c>-}*b~5A9Lpocs}@}IEG>U6pz9+YY8@aOc!Vt(>7cy; zf3A1HtpY$ckO?FKU4Rha9(L|#1B-xKE&JgkoSixE#V3?qW)<|^LA|!7KihHZ5)DN<5DD~7=n-e1kt_ul=(~C!fctK#oE9G&c!`Wm|*`_ zdvn)qoQC&WqqW@wjLiq;gW3cqLATH$2*aWl5#90DZ|tGGj4(rP6#ZGBi-V1)tvDBt zf0MJ0?`Jihv@Wi-;@_^uis!o)zvBOPFRggOYw-*IZ};4axAzu5gZDFIPr%t>q8VLu zJdwz^qINV|a<%#;x6x3QOedIt6zLq#fRFiT0ZlMJ9cfmBBbrw za2+=G=(d}(>P0c(y8+Q;9<1$p16Mh}i-QP7`i^{yH5)pTIAoZ6@#-h4wxLSej)j=P z$jebfaUBI{0nRemDj}&y-N1ty%qr@_%@Hq*eUaO|P0O{$_+K$^IJ&;@nMS`YPL}ID zY2tZtiq{$kKn9QHpzNXfS@KrKTnU*Bb01zp`yh3X@XF&OEnZrL)e&!{q^poJ^@5Pp zOKW>+(c6q#M6#98b;z*ZmNBSZF+KUV$`XY7dbJY*X1ej_zjdu820Y9BxAkuqipx7} zp)*C>s@PgSl^FEG*qDdToUS$cz~|CHt??CqUv7Z*?Tl$T{3LaTpDb}&V~1BfDpqRs zV~*HbdhFKZ%l>>l%vgz**xS6Ed(-scWBt=3*hPt}5}@l;@7+$0)px8x@(e_E|Bjd< z17pt3)7aDv2&w|CzkZI z#)Xx$ZXM{NFS4ZG&nT4P!zXtXxG%`cEgejWhR zkQf4Slfnf}EqNGPYV~&CVk=y$5Che;h={>^4BQ)2wRnyJ_M^1Mrw20(+xv$_XSa$7 zcSog*Zy{qssNU148^ALMavuk3Zw`X1F-}sXwn+)tF**qM{>Nbp??8B1^xTJfZS!8V ztHt_cwY4Z$u)PcxVnQ_pOHL-E&ALCgj(nMcNRKPD1#vF~{4IW5%plwY7FA3<;EkV$mz;+l8xy;aB!;+TSUb}KW?`eg-`e}e|%N{y<-aPm6 zK2}$4cnCi%aYB|_*q*HlM2L}UQhf#vM2^I6{7crsPtg$cbr^sxbiA{M5_;KYKMuw^ zM{~LZwshdT-LyBcEu}CJLu!+({mDZx7JY|;X>rv?>3Tb&Xm3#2dM_5#O__gM;@O?C z*!gF!)u6hn)j+bzHA{_#-`A-#&va;k=K=9haG(4$`U;)JL2K-t53f0(#OWkFy6R}2 z!`H-K!m|0L#@N*+X3}VlCWu+={}D6I=Bs8eASS)g7(3a-B(>HU12MCm_6%Dxj(Fp) zncQ(Cq)GZaSS))JB=-lRfi=1OM#Z9$?-VX#zmFq+-fJ{?_P~&P46R~-);RN5eEN;X zD166!lS#PKB+a4@bMZOJLVL~dq> zl5uktEMkaY`|x$!qg`mkhd!nH_V7ZH{+;vsNPZ&jSR~HE0hvH5FboI-s%wMf3ZMX3 zv&F^c=eWXf)^ikuB?tHzGDUqF-0P$1cS_ABE+rEN9(GX-$K)aqgVax{h& znP_(e8G}P_<};a~cRBufVcK_w9r;nZR(hWB1@c2e4M*~g^vYeOyAp4=SjM-j$z-- zCarLJ&(+yDey?TEXX65yp)4$otRa`!i8Nwt*O%M#ebyr4c1~};f%$2uBk9F?hN73@ zx$Rp-oQc6~U2L!!h+|Jj)Cqr4xR%FfH@io()??P3@k$JnqoMC>d_xp zGA*7%-Xp7-We({?-e=NWvWnbiYvO#?CUxZ+PLgcpuOsPX7nCoYd} za#8G(oG;@F$6?D!>`4r2ibuxf+K~=6c_IkHt=MKKQ3jXjQCAm^Bi;7G+CT$ZmT_oh z!i)V8&vlDPAMy?BZN_xQZZ_Ubu8=pZ^J1Js*w0cHBe?!-$6{ot0qo>rV#Xyyy_b*; zWG1__gd~%6)_W;w<#!(!FG*djmP)p{T|`dg02^`de(>Qqloc!r7(d zvHQmTQL!sxO&zQ`amYwy@B;l)c5WH*lTw!JZJdq_{@_v3qzhn6Y2ugC(TBe?US z;3uB@^v&7ldr6R^?^e88VcDYMPgeM_lD%XQ5n13ql1immwqYMxLb8;m`-xT3o!o?g zVwqpBCB>}exA0?oHsV_n?KpBj3^2Kf#Q>=z+x0EkpP`$CFs5L)1@H){0t$dbz;<9A zkO`y!Nx)#B8xRcy1HOO`csUXFfhwQ`I0obZOM!G?29N~A1ML7`KsB*>Q~3@exeUk$ zb^|%UQeXx!Sb1`YP+%W`>lDwOz%hW5z!)den_a0O z?>WWTcnS5qjx6X3>FLyh^GXhKo-+w#A73GlH6?fP#2m7Zw=(l8iNcXa_H`vrJ)vf( zL~Gogd0ivRa5NzI8fxCVEcZI8AbD)g4P=6C?CTq-bcQRYD)Iv%l&Nl!i{uw}(t}_MwuG;XeOcWhfq_d4<@Icx~n?=k(=UabD#sQI9jCMvc@~)!)jr>Rh{`wVd z#09-0T6o1NCfN+~5zS>8ib9Ts-wA!+5iaycY%owMdsP=ijT6UmYWmWnldgj1C1 ztji-3=Hb48`A2UHbtXkz zW2{})60bIqV_dWHmO(G@qo7ZC?%-4U`sd49>W$Bq1rzcum+*?S=Nkt|9@jiN2uF1F z>L^0)a7)*yjrW!9+efUiLw;N4-wt;sc6F++m&jIbQaLIH$9wD5uz88wH2%5_ZMQAh zIa~((G8=ynuHycV3+%L#Gn`}d*f}=zDLPX5Z01waI{5gqS5vXp>7+S8=5fnjZm!1s zWr%^fTzBcIV64WbLp08(p5pL*Dre$6GQX49k-W1Jx@(kpW^--=me55a@YKMWL`O1) z%TA&(xcY0aLX3e-+GLE3>f3_yR z<4^kL6g1`5c*W%1@Udbm>G_WZcedae>DF$;m!T?R<#~bB@Jwl3^CgZU!Lipi-U}OV z6?g=md~V}CVRg??mR>3HUt|CwGTZQ+gyU+!)6dD0u;Mf{ZNPRQ8%P6^fx$pL&`>n> z&#jsRQ8YG$WxgP{$rP6KH|b)3$}@Dmk#5uZX{!G_qbg{aJ?;eRcW?Tx zH5)%;?Fen5{q!57_`p9RQ{RJ)AvBV-V4Dc-NEo|B=q7jdHwk*de?~#-`~Iy0u13yr zC8cZ;rGZ|rzHaqFb!981v$rw znOQZo1w>kC>11+}ZP3zg7|Gqx()ZP-@+x#0POwl18mu;*t4u%Tc|Dgy6SPO*ZDV5y5Nx5DwgL!`=e2mbaXaJV)J!$9O=P+)6r-rsl_eaO^9(} zQ3)|MXKfwf+z^)LNCy*VR_;hgBYGm8_>>eI?F2K0?Q^1I(CoW8(^BVIOAx-7A+Mj} znNw#njy-m!p|0aNbE!T`w|rE$kWf3`H*lfN+&)+a_I#Rb9GFmpEA*U^7{gttAL-2I zxzGV*Fe`VVO-VSbcA;G`gpG7X6j|6TSK7f-^13-N&gx)&UB@fwr&zUd7A&mTmHMNO z`puPwePI5m>TM~iFF+)DF`WDV@kakYcpv>gctcqdHfwvCrrr$PR@X`Y${Jf|#b<|| z&={puw#kh)>+uaQ55~W(B#zhb#y|fi{lA8Syt|bDM=!>IDc%qhG0jzWv$yU{Uo>FO zQrnwnjIBb=|E~;&sumO=Bim&4;tt%^@9ytePWX;rTSZoaHPA8cP(=a zA9VIWgpygPV`Iw+Tz+yd-CsUQFp0u-y z1vaM9O0^FiY#(`jKBQvH=l3n2Pp)$tcilw0e#q<2mk#1M=KPk_+?;N8J;J%k zBj;0eGVJE`MTSjoLA$wbkYUQ{VET--uSP5AG6&-nJbx4h zDg#kt>(kIxLy$htt&h@4Di62*nbmhKj&*pFiR@V`+CFN8jeFCIiC-IgNQ2&TM!?xp z{PcLsWPpuXft5<1xLlHuORzs;RBP0B@$5=#8byMbTL?`+uX{`g%Dsw}hEOB@htC>`igJ_oLc7u5#4#%=v8%&-8xq)v>5(ixbW(6ynDFkSVk4b3E>Y;Ic`)7tN2 zh}&7MmdDlu$LkKZR-K&aum8S|MDj@1=hqpJ);0JfjNNKWo1?wagi$|AK4!sTG+4?; z9OSV9VKfcXL1)A02vWsDjr5eq;k5tbj{v3#rytSkIc!2W9pgWfM>nFQETo{Lf%lc? zaw|Gj49;z!JDI}%49A_8-I*qWzOQkai@|;!Kf*aA0={U?G9#!L;)6xdNaB=jXODdwtmeU;>0Gmqu({{AHg3-uQrSn=tyGuMCIj1^poq1lk4KP z=98mJTqIpWTF#ye*X_yM_B#v?%7FfF)E8AnBgy%Z^uAF;$Rzgk9aNjc*x>dwoS4{( z_K19ccBDNW;uXlhq2FVT9c7IoIDOI|*V~Y$EI117fG3NOqCv!g&5ELtZf|%py>;!L z73W&n@hDX3o0P~7w3CPgpBarhx>ETenqC$$aN8iG>|9q`#8Qd6Ccz+Yb>Mx2C1 zl@imL4kG@l+4w3R0V&*R)u~V;)y;xFRENmLh{coCutQzwx8$snY@)TqF}j06F4$Ms zNscwh_t@0;>B;6k+=6~{4OWwNssn>+`kt|p=d%-}30qEE1*tqfckQ0m#6=m=jSi>8 zhaKxd-^FCt%O13cS4ZwPa#HL$YqDFon?tf!kBC?e8{CubQ~fmiK(S)qi|&)8TzEU1 z9qCKIMxP-$fksQa!O2thB+xk8dVA`E-0A{Szf?7zejs1@c_959qY-7yU>c6sFqMrT(m4d4CP!6!qVVxRH~30YF$^%D7uolBu6pF7+T zRVFGNUMn5AV)gxe>xTm7z(Xg|cfHRw7^4b6_9?a+`~4XnFOX9#a}xcy=^k#1yj2id zU?@6Ez8MegKgD+o^PNmXu&mR4GHn~Xf{O+d-8P+SYD8^vsm?QXtpE5@vWWBTa3ex# zd`nl7#dU^IcU~DR`Onu}$y|11GCDA6%x?-kJgyy=!|*ViQwYa}xDD=Q2yrhPP%zXW z8wyC|zm_2u%*7U~g;0CayuoH*Jq^ztZ%d$NTzks3LVwTrwoD2_0qc-TJE1|rX6B?1ebN`17KZR{*7CQ;(2q9b~S&6!Hqqu=d3jW%)rf}7gAHqGT@LZ}BteLvocx&!oqC?d9p+5Oe!$ zvl3n>pVWC~BJxg>ZQO|LuC;RzLa_wEV{kKP>9^G)QVa%nvSS>y4N2mP^44V*vbD_S z&q5>nk@D>W z>71-sZimj(rkn7FA9qq=USnW7o#XmE85RtBJ1l6}T&-qR>9mJWvvGa1#&`2T=?_-L z8(hK+ydr3+I^fAV&!^)-)gt4Ndc58!c=5_rH=l?boeMTm;tOeAYtYn`rphZDx_KFS&%qKU)BCAowgW@nbsuH=CP5kBpPMQMtqWdx9ibom^^Wr zkC+2=f8$byy=d^DmKhcyWF$}ACVE*Pz&)zB+&BJoAF)9EY}&&6ynyElsDB!>jyb3T zpRr3hbSV0Y#xLkNTKhTs{0q9qkdw$QyS~=B(72X{q7d@AjnUi+>$ZHfUg`5CT~3fM zuWY6%IDOhRmyVTu_aF+D1G)4D!DPznt!U24_zRcWYhoo zkA6IBrr_e(kJ)gAPVCT$o9bxS7glQ5c=1bXs4Dy?Z`kU<`F5{tdj6G2oBsJfdLtwG z$mq?KZu#^G3GOxYU?YdE*yAxyo%dDd#zqHz8-#McR3j{P$y>^c{4&i*&pWY|tmXIg zd7tqE@$tPOx}>N=GM1~Oh@pf>!)UIt(+MSEaiKxor}hkqandE}q=a7R&DYCuTVx1V z+ic(i16j&Zn$|e#Kjx7Q=G-jc5>(xb|LQy(KOt3}D3tw2YLn^@WJG?^$Ib5_mszE~4?cvpum0y^<}wHki%7gc2&SBbU%J?`E$qq2-#unp~z~ z%?2jGGdLcN4Pz?OmuqY#KUAmlJY_^BJmE4e(q!H+$ib+9QdwjLZSCyL#q>|D*li3; z4s1#VjrCbnVUR=WFsS|*lb=9hC06PvzCAIK!-YGz8F>>aE&S9b@}3}UeiQV z{Od=z@Qh~iYfPd1#$2zUv{kaUS7;lT^R}qEXbt{Ar|M}SCCa2L^c~`y$=PV#MOzh> z&JJFsZKU8|4RR9u?JCVjuK4m-8t4&abLIxo`(S9;)FvCjF8zuOU|@cgw5^X97tmvx z*n=ymUTElYq_Q!UXnSf{ekGj|cs(A5$$d(`Lp0r}gZC>qgRfNJw%+=7=OT;0M!TaM z^Z7NT`GF1Bsg-QsaD#65?8Ie%QVHE8mgEq1*yf3j?8pr?^_lF+4LV(ujYukeike-S zRD~HY^1V`d6M=L|=>?lTL&Ej0$oLUtJTu&;Pf4EQd51=*q%zn-Z~Pv8qPfx=g6Oba zX7AspGb6v}+Mbn|zE-%(T;ed+E#QFa#=+LVR_;Yx_gxKw@Quxm3 z0Sm_cFM5WCs4#eH|A3CrF5;4g5^s{lHb0;yr!-kK4tg`tbEfrDjCjCi6{o;6#jHcJfT`Cg8HUEyXIx^)?8r!?IO(e8lr1}4f z1aR%*->td`oyxS(+Oq^>wPy7q*vO1eHvV7vM$A-=iBdadUp1XZ-O_rhk4iUUEQa^f$FaB1qc^gl+6rbnx1jQ)(+TUnQ zeOS~>df)kGcbkohk9m*v!$x&Z&2H13e zTB8GOeS-uxqy~MQ`7Eb~p2X7>Nww&-gt0BP=)zYs=?(3StpVNNpv@JOmUU<>rD|jX z7dF6(RuTOqD_!HK>sIf1rx)7@BgZW_MjFCOIJUZ?sRioD4b&a;no zEA&U7UB+W{!R)zK4D=Yu`KG_D4TFSgZ2)S8PzTYkYkzJM+>2YbDRrvgUbqX-5a@e* zlo!tKcqc{_l3rZM&RuvB?}A5(;j{NS16!o*oCMzE>CCbn#6(2V69=(xkT*9(@+n-> zoojlQBCTyIurZIM!v3OhI?;dzez{IGy1(iIAuM^o^io$_5*y{$!j7G)A(nhiwU4-<16B=OV-I( z9Msf-3+oP(f>XHiQl4RV-x^EKg>MPbnRIqjyRk#QVl)PMPkhDa=oSC&CvKn^ihS%Z zwsp0Ofz7ws0M`sJU_bbahsZ@XU60tYuy6FDjGlV6Ui3wqglp*{$QBlB5ShkhA%+Lr zvB#O+G>EgpKa9qQuu~|iP`4=jgf|&fuMe)*yO4fd-&KT&OH^T;-kp5FmIa8r(33U> zB6Vc8B~T3Utb5n?6)%b3uF+K2CA@G39$mQ=C{{Zj<3>@WXGpJNOq1RS5*MP^F}k_9 zpO9{fYp_^I$T4=IrC5n6(7aY+6gKSKZzX<0`mwauVuo`>M_3Qndl?G7LR2J7u?rEs z(H~&VLd86CoRx)&;TRf-ZNy-=ogE;Wzk20S96u_F#hTw%7SjgO7(lcUyOQPXi#B3p zR63Um_6reloKaF+qqc++Ulp0nxd@}LD*PJuydERdIRi%n^`3^3(Jc>PHBsAET;Se^ zvn!rVY!j|;q)Q4v5rJ92&216MaqL)I(S-a$!^CS&m$=w9igJzSwvzo3hU{{ibu@}W z7y%_35z2JsGoy$hm^T~KPCSYJc4(y7ig;~m&z&W`REA2T^E;p7YAD)=9V3(85&5d9 za-zN1fshHxnavEl_glB-DF#6etqcz3ZJEAdL(L86gp zf(N5ccpwPg%J{)zGqqHJoKU8$`bf->&@poyBetME)!^yI1;|@!>N@?t0EcWAVK)s1 zm0?QnapI@Mv)kAJ`6XaKCO}RCElv)QJ(MTOVk0|*K{G`>A!4se=`?X6&5+H_<;ODv zWS6BVx8vZO?{9f^Kr^*Np>Tkmn<<_qX63V4s0KV|XoKWb1SS(mg=g|`Nnb82oh>fM zn(*K>aVz#k)}--+SxU<}ViPKzg3!;b`#iB7O8>|6#1W)Sxi(My(=Jk2hEE_)st`X( zUP1D(e1j~o0C~oO0C`v=T(=8)m&YCC!hl2|S|JO?o_I!?^dlqyj0x3?PXeS%u2;k`na^+8Kmz->2d!QlZSu z7H^v*O(H5r>ZIsmGXEbosb{;|*lEhs zb>dYKIk$;)j};`-81=P1(KiTt)< zlQ^Fz+a~c6$z}s`P`NKr=H`fZC6cL(+$t_q;oHCM6z5B1xiWg6=;w%{^*Ph*p2X-YFO7VjtOo zawJNa5_DedCpnt6#s2oOxPiNuAZeNTve?E^QWyIN#~OOs;nb|1QgB&ZsYYme-w-?L zr1(#f(#qmQ+2{8I~$wlkd?E02Fi2PrvmZH)LyEIwmw=PRfK05 zSi)*V2q1I17-wdbpbu17qDoXk<5k=Elva6P)lsCzssz=$QXZtrSZRW)v!)tKVGS%X zpMI(gDIUsH_C-I{ASoBh0`{t(>RDtpl)_p}N&_x{un?VjP#K5^5`knOmFwYA?>T~y zt>_1+z9lV%b+8Ax0N#K<5DbI?1(2@-s)0P^%|O)&QHlpYlNAnCxx1c%vJ9vO5&>Dc zKU8&6lw8)sx^j4g>KyUOgSrfe2Qqd=zs9k_EsN+H1 z3iED_ba*;aS2R+s8Cj^bn5G(OADakUsXzfx4Y+K=*MKU7KO1-i$j}QaygLn=2&4jO zKrZAnmD6)oXY3s_q0a{LfHGyvLe&(pLp9Vw4!#Na12T{ZWCM9X0Z;`9UqA-%2f~0T zrTY?c(&?8qVZTAC~pS_v%=M?y=Vz1tx=7miI`h&&YOV>i4S7gd9>1 zA5~pYk&DW*0#$~HPOPR_HOK{{^^q4_J07V5R8kT=KT#>IR!!luF)vhOHN>QBx2oQ!)bgY92a(!|U>GEvTL5jRmKqUi z8NzzoODC``&{ZQ%#K>sAM$(8xQkLi>M+&;$NqWZtUELBN=?t~>VV^aY)9qp|{XFSSoa)<|)eKccjVgq(B+oLqaTd=oKV0 zV2E@7$mK*$t?Owcf8%n+%cNUOIf-w%@(cpy4srb@H@j4QhZ z$<>E~BHIcclZRz*%JU+k2S$a!0v%g>x~+Cw3`rS@vOvTewa+m!ddk%|Z^PI5pBz-pNi z^sN-jeV$1+~(V8KsZ2D@Ub{h7k zKYuR#1zLQ^D(nVd!0!(9r4Ow_E|-J80{UC6mkVW}ty=96ib0p;Ul;O0bHDsZ*as@$ zySboE$Dhv-HbN1fVHK8w{;@tuNC&ONBH;|sXpc%E1(bUz5p)F{=+7w>T|gZc=L=Dw zd-m)RLO_Ki>``pcdw@<kk3fZ$R-p>CBs}9Yp@K6YPy#x4 z!+qfx=%>d%750Iyi0LNefPU~nTVZ7bO$RMMD+sBe7ld^}66jhFt1uYU`lBGkgN`3R zUg*|9qd7mjsSpNgFdP&DL91U|1#hm;SYZ%0+M>=X=)kC~tP})L>&utI%T##mvQ>Bl z>c8WvkPW%a%uHb^kNQkZ&4Az5x?iXO<@^%RYHPJn40>q1RmcY&Hmp?016_dUSa#dY zkyM~7?^X-zKr>$7y(=t&;(4`INCOpW(}iTvQuuHf=-rC_LOf_@X0^}-)M~8~LO{>I zel7TeUbt{U@BqzzoGsWl=xe7mmkYnM3e})u9LMG_l>eoUVs1*ij++4^MlA!;pbgVEKv=n)x z8|Z}r-wRQo6{%~5V9=@GMho7ckCW#KD$vhg3&LNMk@n@?ggcWl8DRE2DO?02)yGFT z1^U|hTsQ`L6S+JO^f2gl(EZn~LMj|a%nLct-+lf@Nah~N%oMVr5BOxFkjV8rtimGb z1(Q`s2fdVfRY(E->fU1^5p-kCMj;;b@#AkWy#mGB)C!>;=r4a-g<#MlSFM6SXeV>2 z;0=1F088ee*K)53D$u)CdBR|uM>2)}+(E?1%Sp(zpB@t)f!-V+D^!8Hn^p)Fpwlv6 z3nie5+y4>@KnJa8BOC&K{M;&J?1LgSAy?>y4;2&?2-~55h&0*=S~_$BPAnm9GgF1k z2AT%?8hIlH6s1;31U(3ht(Xe1eng@dM92HDE9wO+yS>H6fB}!GAT^D=F-y3~hrDc}g>;OOelRn8_8E(Z`v^l74Dw9cKzHi6ngX0 zZZjI!FJ9SA7bU^WD|yd1U}30#xX$jjPc;T-Sg{sD0tMM4Jperm^tk5*pqqQZYS)@d zsTgu)vYSNx5jvc)R6Wlz7n}m145(60Q*{dxS#8tX2`JOyo`+=C+ z8|kKQA@xU_oy1nTsWUw7RY7t}b)c-%;1K(>K>1}|Aik-0S9d1Tp(}xMIvekyZcS_b z*#-}FE3BpzdZ^plohpYUV=p|^ZTPstQ{BkU?;;+5YCBU9a=lTl;hn4`Yyd7R_Lq;n zgSInNgt8Qy7o2!?rfK)ew?BB#- zqi;nxt$^7}pcW?%U4SUoH(K2+qn$4{BdpTP={OQM>=V5l4}Bu^Dyv@hhx*Yny_~}V zv$B=&5O{}xTBv2n?S{SoI&%kRf*%%xRzp5pFINEnHTQ*?|5}{QSpzTl89K_tz(@z) zIvCINav%`AK`&QAsLMKdZaw@BOZJd^3H?gY6xK3EJw-DlM=$pUy0aZI>Sn=eDF5qR z*+zH)s0I$fR$6H9EPDDxXsgKgg!2LK62t+kC$kBidbOGLesTyYfU+d)p z&@No|DB_ttm(?}KJNNPNd-ynLFCZ1z2)qpr9wL(q0S0^t?7>i1J)1Uc#_v8ofMa*4Vec5qJ{Y?1FOjTfDXVR&XWK&_yuF!~6|$ z8PwZ>WTj2>^J?%{ Qg2$&}Y|}6Gjy3=P08}A^zyJUM diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index c2f899236..b76613230 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,11 @@ -/* 4.2.0 20170424 +/* 5.0.0 20170425 + * Memory status message update + * Fix setting migration to better preserve settings during move (#382) + * Best practice is first doing a Backup Configuration before installing version 5.0.0 + * Reset save count after setting move + * Start using new linker script without SPIFFS + * + * 4.2.0 20170424 * Prepare for SPIFFS removal by moving settings to EEPROM area * Fix compilation error when webserver is disabled (#378) * diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 4739d0cc9..ca8cbd49d 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -36,7 +36,9 @@ uint32_t getRtcHash() uint32_t hash = 0; uint8_t *bytes = (uint8_t*)&rtcMem; - for (uint16_t i = 0; i < sizeof(RTCMEM); i++) hash += bytes[i]*(i+1); + for (uint16_t i = 0; i < sizeof(RTCMEM); i++) { + hash += bytes[i]*(i+1); + } return hash; } @@ -70,7 +72,7 @@ void RTC_Load() boolean RTC_Valid() { - return (rtcMem.valid == RTC_MEM_VALID); + return (RTC_MEM_VALID == rtcMem.valid); } #ifdef DEBUG_THEO @@ -79,7 +81,10 @@ void RTC_Dump() #define CFG_COLS 16 char log[LOGSZ]; - uint16_t idx, maxrow, row, col; + uint16_t idx; + uint16_t maxrow; + uint16_t row; + uint16_t col; uint8_t *buffer = (uint8_t *) &rtcMem; maxrow = ((sizeof(RTCMEM)+CFG_COLS)/CFG_COLS); @@ -88,12 +93,16 @@ void RTC_Dump() idx = row * CFG_COLS; snprintf_P(log, sizeof(log), PSTR("%04X:"), idx); for (col = 0; col < CFG_COLS; col++) { - if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); + if (!(col%4)) { + snprintf_P(log, sizeof(log), PSTR("%s "), log); + } snprintf_P(log, sizeof(log), PSTR("%s %02X"), log, buffer[idx + col]); } snprintf_P(log, sizeof(log), PSTR("%s |"), log); for (col = 0; col < CFG_COLS; col++) { -// if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); +// if (!(col%4)) { +// snprintf_P(log, sizeof(log), PSTR("%s "), log); +// } snprintf_P(log, sizeof(log), PSTR("%s%c"), log, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); } snprintf_P(log, sizeof(log), PSTR("%s|"), log); @@ -111,7 +120,6 @@ extern "C" { } #include "eboot_command.h" -//extern "C" uint32_t _SPIFFS_start; extern "C" uint32_t _SPIFFS_end; #define SPIFFS_END ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE @@ -145,11 +153,11 @@ void setFlashMode(byte option, byte mode) address = 0; } _buffer = new uint8_t[FLASH_SECTOR_SIZE]; - if (spi_flash_read(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE) == SPI_FLASH_RESULT_OK) { + if (SPI_FLASH_RESULT_OK == spi_flash_read(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE)) { if (_buffer[2] != mode) { _buffer[2] = mode &3; noInterrupts(); - if (spi_flash_erase_sector(address / FLASH_SECTOR_SIZE) == SPI_FLASH_RESULT_OK) { + if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(address / FLASH_SECTOR_SIZE)) { spi_flash_write(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); } interrupts(); @@ -163,7 +171,9 @@ void setFlashMode(byte option, byte mode) void setModuleFlashMode(byte option) { uint8_t mode = 0; // QIO - ESP8266 - if ((sysCfg.module == SONOFF_TOUCH) || (sysCfg.module == SONOFF_4CH)) mode = 3; // DOUT - ESP8285 + if ((SONOFF_TOUCH == sysCfg.module) || (SONOFF_4CH == sysCfg.module)) { + mode = 3; // DOUT - ESP8285 + } setFlashMode(option, mode); } @@ -172,7 +182,9 @@ uint32_t getHash() uint32_t hash = 0; uint8_t *bytes = (uint8_t*)&sysCfg; - for (uint16_t i = 0; i < sizeof(SYSCFG); i++) hash += bytes[i]*(i+1); + for (uint16_t i = 0; i < sizeof(SYSCFG); i++) { + hash += bytes[i]*(i+1); + } return hash; } @@ -215,7 +227,7 @@ void CFG_Load() addLog(LOG_LEVEL_DEBUG, log); if (sysCfg.cfg_holder != CFG_HOLDER) { - if ((sysCfg.version < 0x04020000) || (sysCfg.version > 0x73000000)) { + if ((sysCfg.version < 0x04020000) || (sysCfg.version > 0x06000000)) { noInterrupts(); spi_flash_read((CFG_LOCATION_3) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); spi_flash_read((CFG_LOCATION_3 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); @@ -224,6 +236,8 @@ void CFG_Load() interrupts(); if (sysCfg.cfg_holder != CFG_HOLDER) { CFG_Default(); + } else { + sysCfg.saveFlag = 0; } } else { CFG_Default(); @@ -253,7 +267,7 @@ void CFG_Erase() if (_serialoutput) { Serial.print(F("Flash: Erased sector ")); Serial.print(_sector); - if (result == SPI_FLASH_RESULT_OK) { + if (SPI_FLASH_RESULT_OK == result) { Serial.println(F(" OK")); } else { Serial.println(F(" Error")); @@ -268,7 +282,10 @@ void CFG_Dump() #define CFG_COLS 16 char log[LOGSZ]; - uint16_t idx, maxrow, row, col; + uint16_t idx; + uint16_t maxrow; + uint16_t row; + uint16_t col; uint8_t *buffer = (uint8_t *) &sysCfg; maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS); @@ -277,12 +294,16 @@ void CFG_Dump() idx = row * CFG_COLS; snprintf_P(log, sizeof(log), PSTR("%04X:"), idx); for (col = 0; col < CFG_COLS; col++) { - if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); + if (!(col%4)) { + snprintf_P(log, sizeof(log), PSTR("%s "), log); + } snprintf_P(log, sizeof(log), PSTR("%s %02X"), log, buffer[idx + col]); } snprintf_P(log, sizeof(log), PSTR("%s |"), log); for (col = 0; col < CFG_COLS; col++) { -// if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); +// if (!(col%4)) { +// snprintf_P(log, sizeof(log), PSTR("%s "), log); +// } snprintf_P(log, sizeof(log), PSTR("%s%c"), log, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); } snprintf_P(log, sizeof(log), PSTR("%s|"), log); @@ -424,16 +445,26 @@ void CFG_DefaultSet_3_2_4() void CFG_DefaultSet_3_9_3() { - for (byte i = 0; i < 4; i++) sysCfg.domoticz_switch_idx[i] = 0; - for (byte i = 0; i < 12; i++) sysCfg.domoticz_sensor_idx[i] = 0; + for (byte i = 0; i < 4; i++) { + sysCfg.domoticz_switch_idx[i] = 0; + } + for (byte i = 0; i < 12; i++) { + sysCfg.domoticz_sensor_idx[i] = 0; + } sysCfg.module = MODULE; - for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; + for (byte i = 0; i < MAX_GPIO_PIN; i++){ + sysCfg.my_module.gp.io[i] = 0; + } sysCfg.led_pixels = 0; - for (byte i = 0; i < 5; i++) sysCfg.led_color[i] = 255; + for (byte i = 0; i < 5; i++) { + sysCfg.led_color[i] = 255; + } sysCfg.led_table = 0; - for (byte i = 0; i < 3; i++) sysCfg.led_dimmer[i] = 10; + for (byte i = 0; i < 3; i++){ + sysCfg.led_dimmer[i] = 10; + } sysCfg.led_fade = 0; sysCfg.led_speed = 0; sysCfg.led_scheme = 0; @@ -446,11 +477,17 @@ void CFG_DefaultSet_4_0_4() strlcpy(sysCfg.ntp_server[0], NTP_SERVER1, sizeof(sysCfg.ntp_server[0])); strlcpy(sysCfg.ntp_server[1], NTP_SERVER2, sizeof(sysCfg.ntp_server[1])); strlcpy(sysCfg.ntp_server[2], NTP_SERVER3, sizeof(sysCfg.ntp_server[2])); - for (byte j =0; j < 3; j++) - for (byte i = 0; i < strlen(sysCfg.ntp_server[j]); i++) - if (sysCfg.ntp_server[j][i] == ',') sysCfg.ntp_server[j][i] = '.'; + for (byte j =0; j < 3; j++) { + for (byte i = 0; i < strlen(sysCfg.ntp_server[j]); i++) { + if (sysCfg.ntp_server[j][i] == ',') { + sysCfg.ntp_server[j][i] = '.'; + } + } + } sysCfg.pulsetime[0] = sysCfg.ex_pulsetime; - for (byte i = 1; i < MAX_PULSETIMERS; i++) sysCfg.pulsetime[i] = 0; + for (byte i = 1; i < MAX_PULSETIMERS; i++) { + sysCfg.pulsetime[i] = 0; + } } void CFG_DefaultSet_4_0_9() @@ -535,7 +572,9 @@ void CFG_Delta() sysCfg.my_module.gp.io[MAX_GPIO_PIN -1] = 0; // Clear ADC0 } if (sysCfg.version < 0x04000700) { - for (byte i = 0; i < 5; i++) sysCfg.pwmvalue[i] = 0; + for (byte i = 0; i < 5; i++) { + sysCfg.pwmvalue[i] = 0; + } } if (sysCfg.version < 0x04000804) { CFG_DefaultSet_4_0_9(); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index b2af00202..cb4c6ceeb 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -6,11 +6,11 @@ * - Change libraries/PubSubClient/src/PubSubClient.h * #define MQTT_MAX_PACKET_SIZE 512 * - * - Select IDE Tools - Flash size: "1M (64k SPIFFS)" + * - Select IDE Tools - Flash size: "1M (no SPIFFS)" * ==================================================== */ -#define VERSION 0x04020000 // 4.2.0 +#define VERSION 0x05000000 // 5.0.0 enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum week_t {Last, First, Second, Third, Fourth}; @@ -292,13 +292,15 @@ void getClient(char* output, const char* input, byte size) } } } - if (!digits) strlcpy(output, input, size); + if (!digits) { + strlcpy(output, input, size); + } } void setLatchingRelay(uint8_t power, uint8_t state) { power &= 1; - if (state == 2) { // Reset relay + if (2 == state) { // Reset relay state = 0; latching_power = power; latching_relay_pulse = 0; @@ -307,14 +309,16 @@ void setLatchingRelay(uint8_t power, uint8_t state) latching_power = power; latching_relay_pulse = 2; // max 200mS (initiated by stateloop()) } - if (pin[GPIO_REL1 +latching_power] < 99) digitalWrite(pin[GPIO_REL1 +latching_power], rel_inverted[latching_power] ? !state : state); + if (pin[GPIO_REL1 +latching_power] < 99) { + digitalWrite(pin[GPIO_REL1 +latching_power], rel_inverted[latching_power] ? !state : state); + } } void setRelay(uint8_t power) { uint8_t state; - if ((sysCfg.module == SONOFF_DUAL) || (sysCfg.module == CH4)) { + if ((SONOFF_DUAL == sysCfg.module) || (CH4 == sysCfg.module)) { Serial.write(0xA0); Serial.write(0x04); Serial.write(power); @@ -322,16 +326,18 @@ void setRelay(uint8_t power) Serial.write('\n'); Serial.flush(); } - else if (sysCfg.module == SONOFF_LED) { + else if (SONOFF_LED == sysCfg.module) { sl_setPower(power &1); } - else if (sysCfg.module == EXS_RELAY) { + else if (EXS_RELAY == sysCfg.module) { setLatchingRelay(power, 1); } else { for (byte i = 0; i < Maxdevice; i++) { state = power &1; - if (pin[GPIO_REL1 +i] < 99) digitalWrite(pin[GPIO_REL1 +i], rel_inverted[i] ? !state : state); + if (pin[GPIO_REL1 +i] < 99) { + digitalWrite(pin[GPIO_REL1 +i], rel_inverted[i] ? !state : state); + } power >>= 1; } } @@ -340,7 +346,9 @@ void setRelay(uint8_t power) void setLed(uint8_t state) { - if (state) state = 1; + if (state) { + state = 1; + } digitalWrite(pin[GPIO_LED1], (led_inverted[0]) ? !state : state); } @@ -348,10 +356,14 @@ void setLed(uint8_t state) void json2legacy(char* stopic, char* svalue) { - char *p, *token; - uint16_t i, j; + char *p; + char *token; + uint16_t i; + uint16_t j; - if (!strstr(svalue, "{\"")) return; // No JSON + if (!strstr(svalue, "{\"")) { + return; // No JSON + } // stopic = stat/sonoff/RESULT // svalue = {"POWER2":"ON"} @@ -366,7 +378,9 @@ void json2legacy(char* stopic, char* svalue) token = strtok(svalue, "{\""); // Topic p = strrchr(stopic, '/') +1; i = p - stopic; - for (j = 0; j < strlen(token)+1; j++) stopic[i+j] = toupper(token[j]); + for (j = 0; j < strlen(token)+1; j++) { + stopic[i+j] = toupper(token[j]); + } token = strtok(NULL, "\""); // : or :3} or :3, or :{ if (strstr(token, ":{")) { token = strtok(NULL, "\""); // Subtopic @@ -375,7 +389,9 @@ void json2legacy(char* stopic, char* svalue) if (strlen(token) > 1) { token++; p = strchr(token, ','); - if (!p) p = strchr(token, '}'); + if (!p) { + p = strchr(token, '}'); + } i = p - token; token[i] = '\0'; // Value } else { @@ -393,7 +409,9 @@ void json2legacy(char* stopic, char* svalue) char* getStateText(byte state) { - if (state > 2) state = 1; + if (state > 2) { + state = 1; + } return sysCfg.state_text[state]; } @@ -415,7 +433,9 @@ void mqtt_publish_sec(const char* topic, const char* data, boolean retained) } addLog(LOG_LEVEL_INFO, log); - if (sysCfg.ledstate &0x04) blinks++; + if (sysCfg.ledstate &0x04) { + blinks++; + } } void mqtt_publish(const char* topic, const char* data, boolean retained) @@ -424,7 +444,9 @@ void mqtt_publish(const char* topic, const char* data, boolean retained) if (!strcmp(sysCfg.mqtt_prefix[0],sysCfg.mqtt_prefix[1])) { me = strstr(topic,sysCfg.mqtt_prefix[0]); - if (me == topic) mqtt_cmnd_publish += 8; + if (me == topic) { + mqtt_cmnd_publish += 8; + } } mqtt_publish_sec(topic, data, retained); } @@ -436,7 +458,8 @@ void mqtt_publish(const char* topic, const char* data) void mqtt_publish_topic_P(uint8_t prefix, const char* subtopic, const char* data) { - char romram[16], stopic[TOPSZ]; + char romram[16]; + char stopic[TOPSZ]; snprintf_P(romram, sizeof(romram), ((prefix > 3) && !sysCfg.mqtt_response) ? PSTR("RESULT") : subtopic); prefix &= 1; @@ -446,9 +469,13 @@ void mqtt_publish_topic_P(uint8_t prefix, const char* subtopic, const char* data void mqtt_publishPowerState(byte device) { - char stopic[TOPSZ], sdevice[10], svalue[64]; // was MESSZ + char stopic[TOPSZ]; + char sdevice[10]; + char svalue[64]; // was MESSZ - if ((device < 1) || (device > Maxdevice)) device = 1; + if ((device < 1) || (device > Maxdevice)) { + device = 1; + } snprintf_P(sdevice, sizeof(sdevice), PSTR("%d"), device); snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), sysCfg.mqtt_prefix[1], sysCfg.mqtt_topic, (sysCfg.mqtt_response)?"POWER":"RESULT"); @@ -461,9 +488,12 @@ void mqtt_publishPowerState(byte device) void mqtt_publishPowerBlinkState(byte device) { - char sdevice[10], svalue[64]; // was MESSZ + char sdevice[10]; + char svalue[64]; // was MESSZ - if ((device < 1) || (device > Maxdevice)) device = 1; + if ((device < 1) || (device > Maxdevice)) { + device = 1; + } snprintf_P(sdevice, sizeof(sdevice), PSTR("%d"), device); snprintf_P(svalue, sizeof(svalue), PSTR("{\"POWER%s\":\"BLINK %s\"}"), (Maxdevice > 1) ? sdevice : "", getStateText(bitRead(blink_mask, device -1))); @@ -472,7 +502,8 @@ void mqtt_publishPowerBlinkState(byte device) void mqtt_connected() { - char stopic[TOPSZ], svalue[128]; // was MESSZ + char stopic[TOPSZ]; + char svalue[128]; // was MESSZ if (sysCfg.mqtt_enabled) { @@ -502,14 +533,16 @@ void mqtt_connected() #ifdef USE_WEBSERVER if (sysCfg.webserver) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"WebserverMode\":\"%s\", \"Hostname\":\"%s\", \"IPaddress\":\"%s\"}"), - (sysCfg.webserver == 2) ? "Admin" : "User", Hostname, WiFi.localIP().toString().c_str()); + (2 == sysCfg.webserver) ? "Admin" : "User", Hostname, WiFi.localIP().toString().c_str()); mqtt_publish_topic_P(1, PSTR("INFO2"), svalue); } #endif // USE_WEBSERVER snprintf_P(svalue, sizeof(svalue), PSTR("{\"Started\":\"%s\"}"), (getResetReason() == "Exception") ? ESP.getResetInfo().c_str() : getResetReason().c_str()); mqtt_publish_topic_P(1, PSTR("INFO3"), svalue); - if (sysCfg.tele_period) tele_period = sysCfg.tele_period -9; + if (sysCfg.tele_period) { + tele_period = sysCfg.tele_period -9; + } status_update_timer = 2; #ifdef USE_DOMOTICZ domoticz_setUpdateTimer(2); @@ -520,7 +553,9 @@ void mqtt_connected() void mqtt_reconnect() { - char stopic[TOPSZ], svalue[TOPSZ], log[LOGSZ]; + char stopic[TOPSZ]; + char svalue[TOPSZ]; + char log[LOGSZ]; mqttcounter = MQTT_RETRY_SECS; @@ -581,19 +616,20 @@ void mqtt_reconnect() boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) { boolean serviced = true; - char stemp1[TOPSZ], stemp2[10]; + char stemp1[TOPSZ]; + char stemp2[10]; uint16_t i; if (!strcmp(type,"MQTTHOST")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_host))) { - strlcpy(sysCfg.mqtt_host, (payload == 1) ? MQTT_HOST : dataBuf, sizeof(sysCfg.mqtt_host)); + strlcpy(sysCfg.mqtt_host, (1 == payload) ? MQTT_HOST : dataBuf, sizeof(sysCfg.mqtt_host)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"MqttHost\",\"%s\"}"), sysCfg.mqtt_host); } else if (!strcmp(type,"MQTTPORT")) { if ((data_len > 0) && (payload > 0) && (payload < 32766)) { - sysCfg.mqtt_port = (payload == 1) ? MQTT_PORT : payload; + sysCfg.mqtt_port = (1 == payload) ? MQTT_PORT : payload; restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"MqttPort\":%d}"), sysCfg.mqtt_port); @@ -606,8 +642,11 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!strcmp(type,"STATETEXT") && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.state_text[0]))) { - for(i = 0; i <= data_len; i++) if (dataBuf[i] == ' ') dataBuf[i] = '_'; -// strlcpy(sysCfg.state_text[index -1], (payload == 1) ? (index==1)?MQTT_STATUS_OFF:(index==2)?MQTT_STATUS_ON:MQTT_CMND_TOGGLE : dataBuf, sizeof(sysCfg.state_text[0])); + for(i = 0; i <= data_len; i++) { + if (dataBuf[i] == ' ') { + dataBuf[i] = '_'; + } + } strlcpy(sysCfg.state_text[index -1], dataBuf, sizeof(sysCfg.state_text[0])); } snprintf_P(svalue, ssvalue, PSTR("{\"StateText%d\":\"%s\"}"), index, getStateText(index -1)); @@ -615,7 +654,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, #ifdef USE_MQTT_TLS else if (!strcmp(type,"MQTTFINGERPRINT")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_fingerprint))) { - strlcpy(sysCfg.mqtt_fingerprint, (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? MQTT_FINGERPRINT : dataBuf, sizeof(sysCfg.mqtt_fingerprint)); + strlcpy(sysCfg.mqtt_fingerprint, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? MQTT_FINGERPRINT : dataBuf, sizeof(sysCfg.mqtt_fingerprint)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"MqttFingerprint\":\"%s\"}"), sysCfg.mqtt_fingerprint); @@ -623,31 +662,33 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, #endif else if (!grpflg && !strcmp(type,"MQTTCLIENT")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_client))) { - strlcpy(sysCfg.mqtt_client, (payload == 1) ? MQTT_CLIENT_ID : dataBuf, sizeof(sysCfg.mqtt_client)); + strlcpy(sysCfg.mqtt_client, (1 == payload) ? MQTT_CLIENT_ID : dataBuf, sizeof(sysCfg.mqtt_client)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"MqttClient\":\"%s\"}"), sysCfg.mqtt_client); } else if (!strcmp(type,"MQTTUSER")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_user))) { - strlcpy(sysCfg.mqtt_user, (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? MQTT_USER : dataBuf, sizeof(sysCfg.mqtt_user)); + strlcpy(sysCfg.mqtt_user, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? MQTT_USER : dataBuf, sizeof(sysCfg.mqtt_user)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("[\"MqttUser\":\"%s\"}"), sysCfg.mqtt_user); } else if (!strcmp(type,"MQTTPASSWORD")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_pwd))) { - strlcpy(sysCfg.mqtt_pwd, (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? MQTT_PASS : dataBuf, sizeof(sysCfg.mqtt_pwd)); + strlcpy(sysCfg.mqtt_pwd, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? MQTT_PASS : dataBuf, sizeof(sysCfg.mqtt_pwd)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"MqttPassword\":\"%s\"}"), sysCfg.mqtt_pwd); } else if (!strcmp(type,"PREFIX") && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_prefix[0]))) { - for(i = 0; i <= data_len; i++) -// if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; - if ((dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; - strlcpy(sysCfg.mqtt_prefix[index -1], (payload == 1) ? (index==1)?SUB_PREFIX:(index==2)?PUB_PREFIX:PUB_PREFIX2 : dataBuf, sizeof(sysCfg.mqtt_prefix[0])); + for(i = 0; i <= data_len; i++) { + if ((dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { + dataBuf[i] = '_'; + } + } + strlcpy(sysCfg.mqtt_prefix[index -1], (1 == payload) ? (1==index)?SUB_PREFIX:(2==index)?PUB_PREFIX:PUB_PREFIX2 : dataBuf, sizeof(sysCfg.mqtt_prefix[0])); // if (sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] == '/') sysCfg.mqtt_prefix[index -1][strlen(sysCfg.mqtt_prefix[index -1])] = 0; restartflag = 2; } @@ -655,39 +696,59 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!strcmp(type,"GROUPTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_grptopic))) { - for(i = 0; i <= data_len; i++) - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) dataBuf[i] = '_'; - if (!strcmp(dataBuf, MQTTClient)) payload = 1; - strlcpy(sysCfg.mqtt_grptopic, (payload == 1) ? MQTT_GRPTOPIC : dataBuf, sizeof(sysCfg.mqtt_grptopic)); + for(i = 0; i <= data_len; i++) { + if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#')) { + dataBuf[i] = '_'; + } + } + if (!strcmp(dataBuf, MQTTClient)) { + payload = 1; + } + strlcpy(sysCfg.mqtt_grptopic, (1 == payload) ? MQTT_GRPTOPIC : dataBuf, sizeof(sysCfg.mqtt_grptopic)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"GroupTopic\":\"%s\"}"), sysCfg.mqtt_grptopic); } else if (!grpflg && !strcmp(type,"TOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.mqtt_topic))) { - for(i = 0; i <= data_len; i++) - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; - if (!strcmp(dataBuf, MQTTClient)) payload = 1; - strlcpy(sysCfg.mqtt_topic, (payload == 1) ? MQTT_TOPIC : dataBuf, sizeof(sysCfg.mqtt_topic)); + for(i = 0; i <= data_len; i++) { + if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { + dataBuf[i] = '_'; + } + } + if (!strcmp(dataBuf, MQTTClient)) { + payload = 1; + } + strlcpy(sysCfg.mqtt_topic, (1 == payload) ? MQTT_TOPIC : dataBuf, sizeof(sysCfg.mqtt_topic)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"Topic\":\"%s\"}"), sysCfg.mqtt_topic); } else if (!grpflg && !strcmp(type,"BUTTONTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.button_topic))) { - for(i = 0; i <= data_len; i++) - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; - if (!strcmp(dataBuf, MQTTClient)) payload = 1; - strlcpy(sysCfg.button_topic, (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? sysCfg.mqtt_topic : dataBuf, sizeof(sysCfg.button_topic)); + for(i = 0; i <= data_len; i++) { + if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { + dataBuf[i] = '_'; + } + } + if (!strcmp(dataBuf, MQTTClient)) { + payload = 1; + } + strlcpy(sysCfg.button_topic, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? sysCfg.mqtt_topic : dataBuf, sizeof(sysCfg.button_topic)); } snprintf_P(svalue, ssvalue, PSTR("{\"ButtonTopic\":\"%s\"}"), sysCfg.button_topic); } else if (!grpflg && !strcmp(type,"SWITCHTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.switch_topic))) { - for(i = 0; i <= data_len; i++) - if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) dataBuf[i] = '_'; - if (!strcmp(dataBuf, MQTTClient)) payload = 1; - strlcpy(sysCfg.switch_topic, (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? sysCfg.mqtt_topic : dataBuf, sizeof(sysCfg.switch_topic)); + for(i = 0; i <= data_len; i++) { + if ((dataBuf[i] == '/') || (dataBuf[i] == '+') || (dataBuf[i] == '#') || (dataBuf[i] == ' ')) { + dataBuf[i] = '_'; + } + } + if (!strcmp(dataBuf, MQTTClient)) { + payload = 1; + } + strlcpy(sysCfg.switch_topic, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? sysCfg.mqtt_topic : dataBuf, sizeof(sysCfg.switch_topic)); } snprintf_P(svalue, ssvalue, PSTR("{\"SwitchTopic\":\"%s\"}"), sysCfg.switch_topic); } @@ -705,7 +766,7 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, } else if (!strcmp(type,"SWITCHRETAIN")) { if ((data_len > 0) && (payload >= 0) && (payload <= 1)) { - strlcpy(sysCfg.button_topic, sysCfg.mqtt_topic, sizeof(sysCfg.button_topic)); + strlcpy(sysCfg.button_topic, sysCfg.mqtt_topic, sizeof(sysCfg.button_topic)); if (!payload) { for(i = 1; i <= 4; i++) { send_button_power(1, i, 3); // Clear MQTT retain in broker @@ -748,14 +809,26 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if (!strcmp(sysCfg.mqtt_prefix[0],sysCfg.mqtt_prefix[1])) { str = strstr(topic,sysCfg.mqtt_prefix[0]); if ((str == topic) && mqtt_cmnd_publish) { - if (mqtt_cmnd_publish > 8) mqtt_cmnd_publish -= 8; else mqtt_cmnd_publish = 0; + if (mqtt_cmnd_publish > 8) { + mqtt_cmnd_publish -= 8; + } else { + mqtt_cmnd_publish = 0; + } return; } } - char topicBuf[TOPSZ], dataBuf[data_len+1], dataBufUc[128], svalue[MESSZ], stemp1[TOPSZ]; - char *p, *mtopic = NULL, *type = NULL; - uint16_t i = 0, grpflg = 0, index; + char topicBuf[TOPSZ]; + char dataBuf[data_len+1]; + char dataBufUc[128]; + char svalue[MESSZ]; + char stemp1[TOPSZ]; + char *p; + char *mtopic = NULL; + char *type = NULL; + uint16_t i = 0; + uint16_t grpflg = 0; + uint16_t index; uint32_t address; strncpy(topicBuf, topic, sizeof(topicBuf)); @@ -768,7 +841,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) #ifdef USE_DOMOTICZ if (sysCfg.mqtt_enabled) { - if (domoticz_mqttData(topicBuf, sizeof(topicBuf), dataBuf, sizeof(dataBuf))) return; + if (domoticz_mqttData(topicBuf, sizeof(topicBuf), dataBuf, sizeof(dataBuf))) { + return; + } } #endif // USE_DOMOTICZ @@ -784,17 +859,27 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) type = str; } } - if (!strcmp(mtopic, sysCfg.mqtt_grptopic)) grpflg = 1; + if (!strcmp(mtopic, sysCfg.mqtt_grptopic)) { + grpflg = 1; + } index = 1; if (type != NULL) { - for (i = 0; i < strlen(type); i++) type[i] = toupper(type[i]); - while (isdigit(type[i-1])) i--; - if (i < strlen(type)) index = atoi(type +i); + for (i = 0; i < strlen(type); i++) { + type[i] = toupper(type[i]); + } + while (isdigit(type[i-1])) { + i--; + } + if (i < strlen(type)) { + index = atoi(type +i); + } type[i] = '\0'; } - for (i = 0; i <= sizeof(dataBufUc); i++) dataBufUc[i] = toupper(dataBuf[i]); + for (i = 0; i <= sizeof(dataBufUc); i++) { + dataBufUc[i] = toupper(dataBuf[i]); + } snprintf_P(svalue, sizeof(svalue), PSTR("RSLT: DataCb Topic %s, Group %d, Index %d, Type %s, Data %s (%s)"), mtopic, grpflg, index, type, dataBuf, dataBufUc); @@ -803,24 +888,42 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) // snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/RESULT"), PUB_PREFIX, sysCfg.mqtt_topic); if (type != NULL) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Command\":\"Error\"}")); - if (sysCfg.ledstate &0x02) blinks++; + if (sysCfg.ledstate &0x02) { + blinks++; + } - if (!strcmp(dataBufUc,"?")) data_len = 0; + if (!strcmp(dataBufUc,"?")) { + data_len = 0; + } int16_t payload = atoi(dataBuf); // -32766 - 32767 uint16_t payload16 = atoi(dataBuf); // 0 - 65535 - if (!strcmp(dataBufUc,"OFF") || !strcmp(dataBufUc,"FALSE") || !strcmp(dataBufUc,"STOP")) payload = 0; - if (!strcmp(dataBufUc,"ON") || !strcmp(dataBufUc,"TRUE") || !strcmp(dataBufUc,"START") || !strcmp(dataBufUc,"USER")) payload = 1; - if (!strcmp(dataBufUc,"TOGGLE") || !strcmp(dataBufUc,"ADMIN")) payload = 2; - if (!strcmp(dataBufUc,"BLINK")) payload = 3; - if (!strcmp(dataBufUc,"BLINKOFF")) payload = 4; + if (!strcmp(dataBufUc,"OFF") || !strcmp(dataBufUc,"FALSE") || !strcmp(dataBufUc,"STOP")) { + payload = 0; + } + if (!strcmp(dataBufUc,"ON") || !strcmp(dataBufUc,"TRUE") || !strcmp(dataBufUc,"START") || !strcmp(dataBufUc,"USER")) { + payload = 1; + } + if (!strcmp(dataBufUc,"TOGGLE") || !strcmp(dataBufUc,"ADMIN")) { + payload = 2; + } + if (!strcmp(dataBufUc,"BLINK")) { + payload = 3; + } + if (!strcmp(dataBufUc,"BLINKOFF")) { + payload = 4; + } if (!strcmp(type,"POWER") && (index > 0) && (index <= Maxdevice)) { - if ((data_len == 0) || (payload > 4)) payload = 9; + if ((0 == data_len) || (payload > 4)) { + payload = 9; + } do_cmnd_power(index, payload); return; } else if (!strcmp(type,"STATUS")) { - if ((data_len == 0) || (payload < 0) || (payload > MAX_STATUS)) payload = 99; + if ((0 == data_len) || (payload < 0) || (payload > MAX_STATUS)) { + payload = 99; + } publish_status(payload); return; } @@ -840,18 +943,22 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if (!strcmp(type,"BLINKTIME")) { if ((data_len > 0) && (payload > 2) && (payload <= 3600)) { sysCfg.blinktime = payload; - if (blink_timer) blink_timer = sysCfg.blinktime; + if (blink_timer) { + blink_timer = sysCfg.blinktime; + } } snprintf_P(svalue, sizeof(svalue), PSTR("{\"BlinkTime\":%d}"), sysCfg.blinktime); } else if (!strcmp(type,"BLINKCOUNT")) { if (data_len > 0) { sysCfg.blinkcount = payload16; // 0 - 65535 - if (blink_counter) blink_counter = sysCfg.blinkcount *2; + if (blink_counter) { + blink_counter = sysCfg.blinkcount *2; + } } snprintf_P(svalue, sizeof(svalue), PSTR("{\"BlinkCount\":%d}"), sysCfg.blinkcount); } - else if ((sysCfg.module == SONOFF_LED) && sl_command(type, index, dataBufUc, data_len, payload, svalue, sizeof(svalue))) { + else if ((SONOFF_LED == sysCfg.module) && sl_command(type, index, dataBufUc, data_len, payload, svalue, sizeof(svalue))) { // Serviced } else if (!strcmp(type,"SAVEDATA")) { @@ -859,9 +966,13 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) sysCfg.savedata = payload; savedatacounter = sysCfg.savedata; } - if (sysCfg.savestate) sysCfg.power = power; + if (sysCfg.savestate) { + sysCfg.power = power; + } CFG_Save(); - if (sysCfg.savedata > 1) snprintf_P(stemp1, sizeof(stemp1), PSTR("Every %d seconds"), sysCfg.savedata); + if (sysCfg.savedata > 1) { + snprintf_P(stemp1, sizeof(stemp1), PSTR("Every %d seconds"), sysCfg.savedata); + } snprintf_P(svalue, sizeof(svalue), PSTR("{\"SaveData\":\"%s\"}"), (sysCfg.savedata > 1) ? stemp1 : getStateText(sysCfg.savedata)); } else if (!strcmp(type,"SAVESTATE")) { @@ -895,7 +1006,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) byte new_modflg = (sysCfg.module != payload); sysCfg.module = payload; if (new_modflg) { - for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; + for (byte i = 0; i < MAX_GPIO_PIN; i++) { + sysCfg.my_module.gp.io[i] = 0; + } setModuleFlashMode(0); } restartflag = 2; @@ -907,7 +1020,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("{\"Modules1\":\""), svalue); byte jsflg = 0; for (byte i = 0; i < MAXMODULE /2; i++) { - if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + if (jsflg) { + snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), modules[i].name); snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i +1, stemp1); @@ -917,7 +1032,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("{\"Modules2\":\""), svalue); jsflg = 0; for (byte i = MAXMODULE /2; i < MAXMODULE; i++) { - if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + if (jsflg) { + snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), modules[i].name); snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i +1, stemp1); @@ -927,9 +1044,11 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if (!strcmp(type,"GPIO") && (index < MAX_GPIO_PIN)) { mytmplt cmodule; memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule)); - if ((data_len > 0) && (cmodule.gp.io[index] == GPIO_USER) && (payload >= 0) && (payload < GPIO_SENSOR_END)) { + if ((data_len > 0) && (GPIO_USER == cmodule.gp.io[index]) && (payload >= 0) && (payload < GPIO_SENSOR_END)) { for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if ((cmodule.gp.io[i] == GPIO_USER) && (sysCfg.my_module.gp.io[i] == payload)) sysCfg.my_module.gp.io[i] = 0; + if ((GPIO_USER == cmodule.gp.io[i]) && (sysCfg.my_module.gp.io[i] == payload)) { + sysCfg.my_module.gp.io[i] = 0; + } } sysCfg.my_module.gp.io[index] = payload; restartflag = 2; @@ -937,8 +1056,10 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("{"), svalue); byte jsflg = 0; for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (cmodule.gp.io[i] == GPIO_USER) { - if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + if (GPIO_USER == cmodule.gp.io[i]) { + if (jsflg) { + snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), sensors[sysCfg.my_module.gp.io[i]]); snprintf_P(svalue, sizeof(svalue), PSTR("%s\"GPIO%d\":%d (%s)"), svalue, i, sysCfg.my_module.gp.io[i], stemp1); @@ -954,7 +1075,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("{\"GPIOs1\":\""), svalue); byte jsflg = 0; for (byte i = 0; i < GPIO_SENSOR_END /2; i++) { - if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + if (jsflg) { + snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), sensors[i]); snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i, stemp1); @@ -964,7 +1087,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) snprintf_P(svalue, sizeof(svalue), PSTR("{\"GPIOs2\":\""), svalue); jsflg = 0; for (byte i = GPIO_SENSOR_END /2; i < GPIO_SENSOR_END; i++) { - if (jsflg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + if (jsflg) { + snprintf_P(svalue, sizeof(svalue), PSTR("%s, "), svalue); + } jsflg = 1; snprintf_P(stemp1, sizeof(stemp1), sensors[i]); snprintf_P(svalue, sizeof(svalue), PSTR("%s%d (%s)"), svalue, i, stemp1); @@ -988,21 +1113,24 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } else if (!strcmp(type,"SLEEP")) { if ((data_len > 0) && (payload >= 0) && (payload < 251)) { - if ((!sysCfg.sleep && payload) || (sysCfg.sleep && !payload)) restartflag = 2; + if ((!sysCfg.sleep && payload) || (sysCfg.sleep && !payload)) { + restartflag = 2; + } sysCfg.sleep = payload; sleep = payload; -// restartflag = 2; } snprintf_P(svalue, sizeof(svalue), PSTR("{\"Sleep\":\"%d%s (%d%s)\"}"), sleep, (sysCfg.value_units) ? " mS" : "", sysCfg.sleep, (sysCfg.value_units) ? " mS" : ""); } else if (!strcmp(type,"FLASHMODE")) { // 0 = QIO, 1 = QOUT, 2 = DIO, 3 = DOUT if ((data_len > 0) && (payload >= 0) && (payload <= 3)) { - if (ESP.getFlashChipMode() != payload) setFlashMode(0, payload &3); + if (ESP.getFlashChipMode() != payload) { + setFlashMode(0, payload &3); + } } snprintf_P(svalue, sizeof(svalue), PSTR("{\"FlashMode\":%d}"), ESP.getFlashChipMode()); } else if (!strcmp(type,"UPGRADE") || !strcmp(type,"UPLOAD")) { - if ((data_len > 0) && (payload == 1)) { + if ((data_len > 0) && (1 == payload)) { otaflag = 3; snprintf_P(svalue, sizeof(svalue), PSTR("{\"Upgrade\":\"Version %s from %s\"}"), Version, sysCfg.otaUrl); } else { @@ -1011,7 +1139,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } else if (!strcmp(type,"OTAURL")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.otaUrl))) - strlcpy(sysCfg.otaUrl, (payload == 1) ? OTA_URL : dataBuf, sizeof(sysCfg.otaUrl)); + strlcpy(sysCfg.otaUrl, (1 == payload) ? OTA_URL : dataBuf, sizeof(sysCfg.otaUrl)); snprintf_P(svalue, sizeof(svalue), PSTR("{\"OtaUrl\":\"%s\"}"), sysCfg.otaUrl); } else if (!strcmp(type,"SERIALLOG")) { @@ -1032,13 +1160,13 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } else if (!strcmp(type,"LOGHOST")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.syslog_host))) { - strlcpy(sysCfg.syslog_host, (payload == 1) ? SYS_LOG_HOST : dataBuf, sizeof(sysCfg.syslog_host)); + strlcpy(sysCfg.syslog_host, (1 == payload) ? SYS_LOG_HOST : dataBuf, sizeof(sysCfg.syslog_host)); } snprintf_P(svalue, sizeof(svalue), PSTR("{\"LogHost\":\"%s\"}"), sysCfg.syslog_host); } else if (!strcmp(type,"LOGPORT")) { if ((data_len > 0) && (payload > 0) && (payload < 32766)) { - sysCfg.syslog_port = (payload == 1) ? SYS_LOG_PORT : payload; + sysCfg.syslog_port = (1 == payload) ? SYS_LOG_PORT : payload; } snprintf_P(svalue, sizeof(svalue), PSTR("{\"LogPort\":%d}"), sysCfg.syslog_port); } @@ -1048,12 +1176,16 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) // restartflag = 2; } snprintf_P(stemp1, sizeof(stemp1), PSTR(" (%s)"), WiFi.localIP().toString().c_str()); - snprintf_P(svalue, sizeof(svalue), PSTR("{\"IPAddress%d\":\"%s%s\"}"), index, IPAddress(sysCfg.ip_address[index -1]).toString().c_str(), (index == 1) ? stemp1:""); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"IPAddress%d\":\"%s%s\"}"), index, IPAddress(sysCfg.ip_address[index -1]).toString().c_str(), (1 == index) ? stemp1:""); } else if (!strcmp(type,"NTPSERVER") && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.ntp_server[0]))) { - strlcpy(sysCfg.ntp_server[index -1], (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? (index==1)?NTP_SERVER1:(index==2)?NTP_SERVER2:NTP_SERVER3 : dataBuf, sizeof(sysCfg.ntp_server[0])); - for (i = 0; i < strlen(sysCfg.ntp_server[index -1]); i++) if (sysCfg.ntp_server[index -1][i] == ',') sysCfg.ntp_server[index -1][i] = '.'; + strlcpy(sysCfg.ntp_server[index -1], (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? (1==index)?NTP_SERVER1:(2==index)?NTP_SERVER2:NTP_SERVER3 : dataBuf, sizeof(sysCfg.ntp_server[0])); + for (i = 0; i < strlen(sysCfg.ntp_server[index -1]); i++) { + if (sysCfg.ntp_server[index -1][i] == ',') { + sysCfg.ntp_server[index -1][i] = '.'; + } + } restartflag = 2; } snprintf_P(svalue, sizeof(svalue), PSTR("{\"NtpServer%d\":\"%s\"}"), index, sysCfg.ntp_server[index -1]); @@ -1074,7 +1206,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } else if (!strcmp(type,"SSID") && (index > 0) && (index <= 2)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.sta_ssid[0]))) { - strlcpy(sysCfg.sta_ssid[index -1], (payload == 1) ? (index == 1) ? STA_SSID1 : STA_SSID2 : dataBuf, sizeof(sysCfg.sta_ssid[0])); + strlcpy(sysCfg.sta_ssid[index -1], (1 == payload) ? (1 == index) ? STA_SSID1 : STA_SSID2 : dataBuf, sizeof(sysCfg.sta_ssid[0])); sysCfg.sta_active = 0; restartflag = 2; } @@ -1082,7 +1214,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } else if (!strcmp(type,"PASSWORD") && (index > 0) && (index <= 2)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.sta_pwd[0]))) { - strlcpy(sysCfg.sta_pwd[index -1], (payload == 1) ? (index == 1) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(sysCfg.sta_pwd[0])); + strlcpy(sysCfg.sta_pwd[index -1], (1 == payload) ? (1 == index) ? STA_PASS1 : STA_PASS2 : dataBuf, sizeof(sysCfg.sta_pwd[0])); sysCfg.sta_active = 0; restartflag = 2; } @@ -1090,8 +1222,10 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } else if (!grpflg && !strcmp(type,"HOSTNAME")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.hostname))) { - strlcpy(sysCfg.hostname, (payload == 1) ? WIFI_HOSTNAME : dataBuf, sizeof(sysCfg.hostname)); - if (strstr(sysCfg.hostname,"%")) strlcpy(sysCfg.hostname, WIFI_HOSTNAME, sizeof(sysCfg.hostname)); + strlcpy(sysCfg.hostname, (1 == payload) ? WIFI_HOSTNAME : dataBuf, sizeof(sysCfg.hostname)); + if (strstr(sysCfg.hostname,"%")) { + strlcpy(sysCfg.hostname, WIFI_HOSTNAME, sizeof(sysCfg.hostname)); + } restartflag = 2; } snprintf_P(svalue, sizeof(svalue), PSTR("{\"Hostname\":\"%s\"}"), sysCfg.hostname); @@ -1113,12 +1247,12 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } else if (!strcmp(type,"FRIENDLYNAME") && (index > 0) && (index <= 4)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.friendlyname[0]))) { - if (index == 1) { + if (1 == index) { snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME)); } else { snprintf_P(stemp1, sizeof(stemp1), PSTR(FRIENDLY_NAME "%d"), index); } - strlcpy(sysCfg.friendlyname[index -1], (payload == 1) ? stemp1 : dataBuf, sizeof(sysCfg.friendlyname[index -1])); + strlcpy(sysCfg.friendlyname[index -1], (1 == payload) ? stemp1 : dataBuf, sizeof(sysCfg.friendlyname[index -1])); } snprintf_P(svalue, sizeof(svalue), PSTR("{\"FriendlyName%d\":\"%s\"}"), index, sysCfg.friendlyname[index -1]); } @@ -1135,14 +1269,14 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } if (sysCfg.webserver) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Webserver\":\"Active for %s on %s with IP address %s\"}"), - (sysCfg.webserver == 2) ? "ADMIN" : "USER", Hostname, WiFi.localIP().toString().c_str()); + (2 == sysCfg.webserver) ? "ADMIN" : "USER", Hostname, WiFi.localIP().toString().c_str()); } else { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Webserver\":\"%s\"}"), getStateText(0)); } } else if (!strcmp(type,"WEBPASSWORD")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.web_password))) { - strlcpy(sysCfg.web_password, (!strcmp(dataBuf,"0")) ? "" : (payload == 1) ? WEB_PASSWORD : dataBuf, sizeof(sysCfg.web_password)); + strlcpy(sysCfg.web_password, (!strcmp(dataBuf,"0")) ? "" : (1 == payload) ? WEB_PASSWORD : dataBuf, sizeof(sysCfg.web_password)); } snprintf_P(svalue, sizeof(svalue), PSTR("{\"WebPassword\":\"%s\"}"), sysCfg.web_password); } @@ -1164,8 +1298,10 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) #endif // USE_WEBSERVER else if (!strcmp(type,"TELEPERIOD")) { if ((data_len > 0) && (payload >= 0) && (payload < 3601)) { - sysCfg.tele_period = (payload == 1) ? TELE_PERIOD : payload; - if ((sysCfg.tele_period > 0) && (sysCfg.tele_period < 10)) sysCfg.tele_period = 10; // Do not allow periods < 10 seconds + sysCfg.tele_period = (1 == payload) ? TELE_PERIOD : payload; + if ((sysCfg.tele_period > 0) && (sysCfg.tele_period < 10)) { + sysCfg.tele_period = 10; // Do not allow periods < 10 seconds + } tele_period = sysCfg.tele_period; } snprintf_P(svalue, sizeof(svalue), PSTR("{\"TelePeriod\":\"%d%s\"}"), sysCfg.tele_period, (sysCfg.value_units) ? " Sec" : ""); @@ -1199,7 +1335,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } } else if (!strcmp(type,"TIMEZONE")) { - if ((data_len > 0) && (((payload >= -12) && (payload <= 12)) || (payload == 99))) { + if ((data_len > 0) && (((payload >= -12) && (payload <= 12)) || (99 == payload))) { sysCfg.timezone = payload; } snprintf_P(svalue, sizeof(svalue), PSTR("{\"Timezone\":%d}"), sysCfg.timezone); @@ -1224,7 +1360,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if (!strcmp(type,"LEDSTATE")) { if ((data_len > 0) && (payload >= 0) && (payload < MAX_LED_OPTION)) { sysCfg.ledstate = payload; - if (!sysCfg.ledstate) setLed(0); + if (!sysCfg.ledstate) { + setLed(0); + } } snprintf_P(svalue, sizeof(svalue), PSTR("{\"LedState\":%d}"), sysCfg.ledstate); } @@ -1255,7 +1393,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) #endif // USE_IR_REMOTE #ifdef DEBUG_THEO else if (!strcmp(type,"EXCEPTION")) { - if (data_len > 0) exception_tst(payload); + if (data_len > 0) { + exception_tst(payload); + } snprintf_P(svalue, sizeof(svalue), PSTR("{\"Exception\":\"Triggered\"}")); } #endif // DEBUG_THEO @@ -1279,17 +1419,21 @@ void send_button_power(byte key, byte device, byte state) // key 0 = button_topic // key 1 = switch_topic - char stopic[TOPSZ], svalue[TOPSZ], stemp1[10]; + char stopic[TOPSZ]; + char svalue[TOPSZ]; + char stemp1[10]; - if (!key && (device > Maxdevice)) device = 1; + if (!key && (device > Maxdevice)) { + device = 1; + } snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), device); snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/POWER%s"), sysCfg.mqtt_prefix[0], (key) ? sysCfg.switch_topic : sysCfg.button_topic, (key || (Maxdevice > 1)) ? stemp1 : ""); - if (state == 3) { + if (3 == state) { svalue[0] = '\0'; } else { - if (!strcmp(sysCfg.mqtt_topic,(key) ? sysCfg.switch_topic : sysCfg.button_topic) && (state == 2)) { + if (!strcmp(sysCfg.mqtt_topic,(key) ? sysCfg.switch_topic : sysCfg.button_topic) && (2 == state)) { state = ~(power >> (device -1)) & 0x01; } snprintf_P(svalue, sizeof(svalue), PSTR("%s"), getStateText(state)); @@ -1313,7 +1457,9 @@ void do_cmnd_power(byte device, byte state) // state 4 = Stop blinking relay // state 9 = Show power state - if ((device < 1) || (device > Maxdevice)) device = 1; + if ((device < 1) || (device > Maxdevice)) { + device = 1; + } byte mask = 0x01 << (device -1); pulse_timer[(device -1)&3] = 0; if (state <= 2) { @@ -1337,7 +1483,7 @@ void do_cmnd_power(byte device, byte state) #endif // USE_DOMOTICZ pulse_timer[(device -1)&3] = (power & mask) ? sysCfg.pulsetime[(device -1)&3] : 0; } - else if (state == 3) { // Blink + else if (3 == state) { // Blink if (!(blink_mask & mask)) { blink_powersave = (blink_powersave & (0xFF ^ mask)) | (power & mask); // Save state blink_power = (power >> (device -1))&1; // Prep to Toggle @@ -1348,11 +1494,13 @@ void do_cmnd_power(byte device, byte state) mqtt_publishPowerBlinkState(device); return; } - else if (state == 4) { // No Blink + else if (4 == state) { // No Blink byte flag = (blink_mask & mask); blink_mask &= (0xFF ^ mask); // Clear device mask mqtt_publishPowerBlinkState(device); - if (flag) do_cmnd_power(device, (blink_powersave >> (device -1))&1); // Restore state + if (flag) { + do_cmnd_power(device, (blink_powersave >> (device -1))&1); // Restore state + } return; } mqtt_publishPowerState(device); @@ -1360,9 +1508,9 @@ void do_cmnd_power(byte device, byte state) void stop_all_power_blink() { - byte i, mask; + byte mask; - for (i = 1; i <= Maxdevice; i++) { + for (byte i = 1; i <= Maxdevice; i++) { mask = 0x01 << (i -1); if (blink_mask & mask) { blink_mask &= (0xFF ^ mask); // Clear device mask @@ -1374,14 +1522,17 @@ void stop_all_power_blink() void do_cmnd(char *cmnd) { - char stopic[TOPSZ], svalue[128]; + char stopic[TOPSZ]; + char svalue[128]; char *start; char *token; token = strtok(cmnd, " "); if (token != NULL) { start = strrchr(token, '/'); // Skip possible cmnd/sonoff/ preamble - if (start) token = start; + if (start) { + token = start; + } } snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s"), sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, token); token = strtok(NULL, ""); @@ -1397,74 +1548,76 @@ void publish_status(uint8_t payload) // Workaround MQTT - TCP/IP stack queueing when SUB_PREFIX = PUB_PREFIX option = (!strcmp(sysCfg.mqtt_prefix[0],sysCfg.mqtt_prefix[1]) && (!payload)); - if ((!sysCfg.mqtt_enabled) && (payload == 6)) payload = 99; - if ((!hlw_flg) && ((payload == 8) || (payload == 9))) payload = 99; + if ((!sysCfg.mqtt_enabled) && (6 == payload)) { + payload = 99; + } + if ((!hlw_flg) && ((8 == payload) || (9 == payload))) { + payload = 99; + } - if ((payload == 0) || (payload == 99)) { + if ((0 == payload) || (99 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"Status\":{\"Module\":%d, \"FriendlyName\":\"%s\", \"Topic\":\"%s\", \"ButtonTopic\":\"%s\", \"Power\":%d, \"PowerOnState\":%d, \"LedState\":%d, \"SaveData\":%d, \"SaveState\":%d, \"ButtonRetain\":%d, \"PowerRetain\":%d}}"), sysCfg.module +1, sysCfg.friendlyname[0], sysCfg.mqtt_topic, sysCfg.button_topic, power, sysCfg.poweronstate, sysCfg.ledstate, sysCfg.savedata, sysCfg.savestate, sysCfg.mqtt_button_retain, sysCfg.mqtt_power_retain); mqtt_publish_topic_P(option, PSTR("STATUS"), svalue); } - if ((payload == 0) || (payload == 1)) { + if ((0 == payload) || (1 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusPRM\":{\"Baudrate\":%d, \"GroupTopic\":\"%s\", \"OtaUrl\":\"%s\", \"Uptime\":%d, \"Sleep\":%d, \"BootCount\":%d, \"SaveCount\":%d}}"), Baudrate, sysCfg.mqtt_grptopic, sysCfg.otaUrl, uptime, sysCfg.sleep, sysCfg.bootcount, sysCfg.saveFlag); mqtt_publish_topic_P(option, PSTR("STATUS1"), svalue); } - if ((payload == 0) || (payload == 2)) { -// snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusFWR\":{\"Program\":\"%s\", \"BuildDateTime\":\"%s/%s\", \"Boot\":%d, \"Core\":\"%s\", \"SDK\":\"%s\"}}"), -// Version, __DATE__, __TIME__, ESP.getBootVersion(), ESP.getCoreVersion().c_str(), ESP.getSdkVersion()); + if ((0 == payload) || (2 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusFWR\":{\"Program\":\"%s\", \"BuildDateTime\":\"%s\", \"Boot\":%d, \"Core\":\"%s\", \"SDK\":\"%s\"}}"), Version, getBuildDateTime().c_str(), ESP.getBootVersion(), ESP.getCoreVersion().c_str(), ESP.getSdkVersion()); mqtt_publish_topic_P(option, PSTR("STATUS2"), svalue); } - if ((payload == 0) || (payload == 3)) { + if ((0 == payload) || (3 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusLOG\":{\"Seriallog\":%d, \"Weblog\":%d, \"Syslog\":%d, \"LogHost\":\"%s\", \"SSId1\":\"%s\", \"SSId2\":\"%s\", \"TelePeriod\":%d}}"), sysCfg.seriallog_level, sysCfg.weblog_level, sysCfg.syslog_level, sysCfg.syslog_host, sysCfg.sta_ssid[0], sysCfg.sta_ssid[1], sysCfg.tele_period); mqtt_publish_topic_P(option, PSTR("STATUS3"), svalue); } - if ((payload == 0) || (payload == 4)) { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusMEM\":{\"ProgramSize\":%d, \"Free\":%d, \"Heap\":%d, \"FlashSize\":%d, \"ProgramFlashSize\":%d, \"FlashMode\":%d}}"), - ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipSize()/1024, ESP.getFlashChipMode()); + if ((0 == payload) || (4 == payload)) { + snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusMEM\":{\"ProgramSize\":%d, \"Free\":%d, \"Heap\":%d, \"ProgramFlashSize\":%d, \"FlashSize\":%d, \"FlashMode\":%d}}"), + ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ESP.getFlashChipSize()/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipMode()); mqtt_publish_topic_P(option, PSTR("STATUS4"), svalue); } - if ((payload == 0) || (payload == 5)) { + if ((0 == payload) || (5 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusNET\":{\"Host\":\"%s\", \"IP\":\"%s\", \"Gateway\":\"%s\", \"Subnetmask\":\"%s\", \"DNSServer\":\"%s\", \"Mac\":\"%s\", \"Webserver\":%d, \"WifiConfig\":%d}}"), Hostname, WiFi.localIP().toString().c_str(), IPAddress(sysCfg.ip_address[1]).toString().c_str(), IPAddress(sysCfg.ip_address[2]).toString().c_str(), IPAddress(sysCfg.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(), sysCfg.webserver, sysCfg.sta_config); mqtt_publish_topic_P(option, PSTR("STATUS5"), svalue); } - if (((payload == 0) || (payload == 6)) && sysCfg.mqtt_enabled) { + if (((0 == payload) || (6 == payload)) && sysCfg.mqtt_enabled) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusMQT\":{\"Host\":\"%s\", \"Port\":%d, \"ClientMask\":\"%s\", \"Client\":\"%s\", \"User\":\"%s\", \"MAX_PACKET_SIZE\":%d, \"KEEPALIVE\":%d}}"), sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.mqtt_client, MQTTClient, sysCfg.mqtt_user, MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); mqtt_publish_topic_P(option, PSTR("STATUS6"), svalue); } - if ((payload == 0) || (payload == 7)) { + if ((0 == payload) || (7 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusTIM\":{\"UTC\":\"%s\", \"Local\":\"%s\", \"StartDST\":\"%s\", \"EndDST\":\"%s\", \"Timezone\":%d}}"), rtc_time(0).c_str(), rtc_time(1).c_str(), rtc_time(2).c_str(), rtc_time(3).c_str(), sysCfg.timezone); mqtt_publish_topic_P(option, PSTR("STATUS7"), svalue); } if (hlw_flg) { - if ((payload == 0) || (payload == 8)) { + if ((0 == payload) || (8 == payload)) { hlw_mqttStatus(svalue, sizeof(svalue)); mqtt_publish_topic_P(option, PSTR("STATUS8"), svalue); } - if ((payload == 0) || (payload == 9)) { + if ((0 == payload) || (9 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusPTH\":{\"PowerLow\":%d, \"PowerHigh\":%d, \"VoltageLow\":%d, \"VoltageHigh\":%d, \"CurrentLow\":%d, \"CurrentHigh\":%d}}"), sysCfg.hlw_pmin, sysCfg.hlw_pmax, sysCfg.hlw_umin, sysCfg.hlw_umax, sysCfg.hlw_imin, sysCfg.hlw_imax); mqtt_publish_topic_P(option, PSTR("STATUS9"), svalue); } } - if ((payload == 0) || (payload == 10)) { + if ((0 == payload) || (10 == payload)) { uint8_t djson = 0; snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusSNS\":")); sensors_mqttPresent(svalue, sizeof(svalue), &djson); @@ -1472,7 +1625,7 @@ void publish_status(uint8_t payload) mqtt_publish_topic_P(option, PSTR("STATUS10"), svalue); } - if ((payload == 0) || (payload == 11)) { + if ((0 == payload) || (11 == payload)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusSTS\":")); state_mqttPresent(svalue, sizeof(svalue)); snprintf_P(svalue, sizeof(svalue), PSTR("%s}"), svalue); @@ -1491,7 +1644,7 @@ void state_mqttPresent(char* svalue, uint16_t ssvalue) snprintf_P(svalue, ssvalue, PSTR("%s, \"Vcc\":%s"), svalue, stemp1); #endif for (byte i = 0; i < Maxdevice; i++) { - if (Maxdevice == 1) { // Legacy + if (1 == Maxdevice) { // Legacy snprintf_P(svalue, ssvalue, PSTR("%s, \"POWER\":"), svalue); } else { snprintf_P(svalue, ssvalue, PSTR("%s, \"POWER%d\":"), svalue, i +1); @@ -1507,7 +1660,7 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) snprintf_P(svalue, ssvalue, PSTR("%s{\"Time\":\"%s\""), svalue, getDateTime().c_str()); for (byte i = 0; i < 4; i++) { if (pin[GPIO_SWT1 +i] < 99) { - boolean swm = ((sysCfg.switchmode[i] == FOLLOW_INV)||(sysCfg.switchmode[i] == PUSHBUTTON_INV)); + boolean swm = ((FOLLOW_INV == sysCfg.switchmode[i]) || (PUSHBUTTON_INV == sysCfg.switchmode[i])); snprintf_P(svalue, ssvalue, PSTR("%s, \"Switch%d\":\"%s\""), svalue, i +1, getStateText(swm ^ lastwallswitch[i])); *djson = 1; } @@ -1518,7 +1671,9 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) *djson = 1; } #endif - if (sysCfg.module == SONOFF_SC) sc_mqttPresent(svalue, ssvalue, djson); + if (SONOFF_SC == sysCfg.module) { + sc_mqttPresent(svalue, ssvalue, djson); + } if (pin[GPIO_DSB] < 99) { #ifdef USE_DS18B20 dsb_mqttPresent(svalue, ssvalue, djson); @@ -1528,7 +1683,9 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) #endif // USE_DS18x20 } #ifdef USE_DHT - if (dht_type) dht_mqttPresent(svalue, ssvalue, djson); + if (dht_type) { + dht_mqttPresent(svalue, ssvalue, djson); + } #endif // USE_DHT #ifdef USE_I2C if (i2c_flg) { @@ -1555,7 +1712,11 @@ void every_second() { char svalue[MESSZ]; - for (byte i = 0; i < MAX_PULSETIMERS; i++) if (pulse_timer[i] > 111) pulse_timer[i]--; + for (byte i = 0; i < MAX_PULSETIMERS; i++) { + if (pulse_timer[i] > 111) { + pulse_timer[i]--; + } + } if (seriallog_timer) { seriallog_timer--; @@ -1584,7 +1745,9 @@ void every_second() if (status_update_timer) { status_update_timer--; if (!status_update_timer) { - for (byte i = 1; i <= Maxdevice; i++) mqtt_publishPowerState(i); + for (byte i = 1; i <= Maxdevice; i++) { + mqtt_publishPowerState(i); + } } } @@ -1601,7 +1764,9 @@ void every_second() #endif // USE_DS18x20 } #ifdef USE_DHT - if (dht_type) dht_readPrep(); + if (dht_type) { + dht_readPrep(); + } #endif // USE_DHT #ifdef USE_I2C if (i2c_flg) { @@ -1630,46 +1795,65 @@ void every_second() uint8_t djson = 0; svalue[0] = '\0'; sensors_mqttPresent(svalue, sizeof(svalue), &djson); - if (djson) mqtt_publish_topic_P(1, PSTR("SENSOR"), svalue); + if (djson) { + mqtt_publish_topic_P(1, PSTR("SENSOR"), svalue); + } - if (hlw_flg) hlw_mqttPresent(); + if (hlw_flg) { + hlw_mqttPresent(); + } } } - if (hlw_flg) hlw_margin_chk(); + if (hlw_flg) { + hlw_margin_chk(); + } - if ((rtcTime.Minute == 2) && uptime_flg) { + if ((2 == rtcTime.Minute) && uptime_flg) { uptime_flg = false; uptime++; snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", \"Uptime\":%d}"), getDateTime().c_str(), uptime); mqtt_publish_topic_P(1, PSTR("UPTIME"), svalue); } - if ((rtcTime.Minute == 3) && !uptime_flg) uptime_flg = true; + if ((3 == rtcTime.Minute) && !uptime_flg) { + uptime_flg = true; + } } void stateloop() { - uint8_t button = NOT_PRESSED, flag, switchflag, power_now; - char scmnd[20], log[LOGSZ], svalue[80]; // was MESSZ + uint8_t button = NOT_PRESSED; + uint8_t flag; + uint8_t switchflag; + uint8_t power_now; + char scmnd[20]; + char log[LOGSZ]; + char svalue[80]; // was MESSZ timerxs = millis() + (1000 / STATES); state++; - if (state == STATES) { // Every second + if (STATES == state) { // Every second state = 0; every_second(); } - if (mqtt_cmnd_publish) mqtt_cmnd_publish--; // Clean up + if (mqtt_cmnd_publish) { + mqtt_cmnd_publish--; // Clean up + } if (latching_relay_pulse) { latching_relay_pulse--; - if (!latching_relay_pulse) setLatchingRelay(0, 0); + if (!latching_relay_pulse) { + setLatchingRelay(0, 0); + } } for (byte i = 0; i < MAX_PULSETIMERS; i++) if ((pulse_timer[i] > 0) && (pulse_timer[i] < 112)) { pulse_timer[i]--; - if (!pulse_timer[i]) do_cmnd_power(i +1, 0); + if (!pulse_timer[i]) { + do_cmnd_power(i +1, 0); + } } if (blink_mask) { @@ -1687,26 +1871,34 @@ void stateloop() } } - if (sysCfg.module == SONOFF_LED) sl_animate(); + if (SONOFF_LED == sysCfg.module) { + sl_animate(); + } #ifdef USE_WS2812 - if (pin[GPIO_WS2812] < 99) ws2812_animate(); + if (pin[GPIO_WS2812] < 99) { + ws2812_animate(); + } #endif // USE_WS2812 - if ((sysCfg.module == SONOFF_DUAL) || (sysCfg.module == CH4)) { + if ((SONOFF_DUAL == sysCfg.module) || (CH4 == sysCfg.module)) { if (ButtonCode) { snprintf_P(log, sizeof(log), PSTR("APP: Button code %04X"), ButtonCode); addLog(LOG_LEVEL_DEBUG, log); button = PRESSED; - if (ButtonCode == 0xF500) holdcount = (STATES *4) -1; + if (0xF500 == ButtonCode) { + holdcount = (STATES *4) -1; + } ButtonCode = 0; } else { button = NOT_PRESSED; } } else { - if (pin[GPIO_KEY1] < 99) button = digitalRead(pin[GPIO_KEY1]); + if (pin[GPIO_KEY1] < 99) { + button = digitalRead(pin[GPIO_KEY1]); + } } - if ((button == PRESSED) && (lastbutton[0] == NOT_PRESSED)) { + if ((PRESSED == button) && (NOT_PRESSED == lastbutton[0])) { multipress = (multiwindow) ? multipress +1 : 1; snprintf_P(log, sizeof(log), PSTR("APP: Multipress %d"), multipress); addLog(LOG_LEVEL_DEBUG, log); @@ -1714,11 +1906,11 @@ void stateloop() multiwindow = STATES /2; // 1/2 second multi press window } lastbutton[0] = button; - if (button == NOT_PRESSED) { + if (NOT_PRESSED == button) { holdcount = 0; } else { holdcount++; - if (!sysCfg.button_restrict && (holdcount == (STATES *4))) { // 4 seconds button hold + if (!sysCfg.button_restrict && ((STATES *4) == holdcount)) { // 4 seconds button hold snprintf_P(scmnd, sizeof(scmnd), PSTR("reset 1")); multipress = 0; do_cmnd(scmnd); @@ -1728,15 +1920,15 @@ void stateloop() multiwindow--; } else { if ((!restartflag) && (!holdcount) && (multipress > 0) && (multipress < MAX_BUTTON_COMMANDS +3)) { - if ((sysCfg.module == SONOFF_DUAL) || (sysCfg.module == CH4)) { - flag = ((multipress == 1) || (multipress == 2)); + if ((SONOFF_DUAL == sysCfg.module) || (CH4 == sysCfg.module)) { + flag = ((1 == multipress) || (2 == multipress)); } else { - flag = (multipress == 1); + flag = (1 == multipress); } if (flag && sysCfg.mqtt_enabled && mqttClient.connected() && (strlen(sysCfg.button_topic) != 0) && strcmp(sysCfg.button_topic, "0")) { send_button_power(0, multipress, 2); // Execute command via MQTT using ButtonTopic to sync external clients } else { - if ((multipress == 1) || (multipress == 2)) { + if ((1 == multipress) || (2 == multipress)) { if (WIFI_State()) { // WPSconfig, Smartconfig or Wifimanager active restartflag = 1; } else { @@ -1753,46 +1945,54 @@ void stateloop() } } - for (byte i = 1; i < Maxdevice; i++) if (pin[GPIO_KEY1 +i] < 99) { - button = digitalRead(pin[GPIO_KEY1 +i]); - if ((button == PRESSED) && (lastbutton[i] == NOT_PRESSED)) { - if (sysCfg.mqtt_enabled && mqttClient.connected() && (strlen(sysCfg.button_topic) != 0) && strcmp(sysCfg.button_topic, "0")) { - send_button_power(0, i +1, 2); // Execute commend via MQTT - } else { - do_cmnd_power(i +1, 2); // Execute command internally - } - } - lastbutton[i] = button; - } - - for (byte i = 0; i < 4; i++) if (pin[GPIO_SWT1 +i] < 99) { - button = digitalRead(pin[GPIO_SWT1 +i]); - if (button != lastwallswitch[i]) { - switchflag = 3; - switch (sysCfg.switchmode[i]) { - case TOGGLE: - switchflag = 2; // Toggle - break; - case FOLLOW: - switchflag = button & 0x01; // Follow wall switch state - break; - case FOLLOW_INV: - switchflag = ~button & 0x01; // Follow inverted wall switch state - break; - case PUSHBUTTON: - if ((button == PRESSED) && (lastwallswitch[i] == NOT_PRESSED)) switchflag = 2; // Toggle with pushbutton to Gnd - break; - case PUSHBUTTON_INV: - if ((button == NOT_PRESSED) && (lastwallswitch[i] == PRESSED)) switchflag = 2; // Toggle with releasing pushbutton from Gnd - } - if (switchflag < 3) { - if (sysCfg.mqtt_enabled && mqttClient.connected() && (strlen(sysCfg.switch_topic) != 0) && strcmp(sysCfg.switch_topic, "0")) { - send_button_power(1, i +1, switchflag); // Execute commend via MQTT + for (byte i = 1; i < Maxdevice; i++) { + if (pin[GPIO_KEY1 +i] < 99) { + button = digitalRead(pin[GPIO_KEY1 +i]); + if ((PRESSED == button) && (NOT_PRESSED == lastbutton[i])) { + if (sysCfg.mqtt_enabled && mqttClient.connected() && (strlen(sysCfg.button_topic) != 0) && strcmp(sysCfg.button_topic, "0")) { + send_button_power(0, i +1, 2); // Execute commend via MQTT } else { - do_cmnd_power(i +1, switchflag); // Execute command internally (if i < Maxdevice) + do_cmnd_power(i +1, 2); // Execute command internally } } - lastwallswitch[i] = button; + lastbutton[i] = button; + } + } + + for (byte i = 0; i < 4; i++) { + if (pin[GPIO_SWT1 +i] < 99) { + button = digitalRead(pin[GPIO_SWT1 +i]); + if (button != lastwallswitch[i]) { + switchflag = 3; + switch (sysCfg.switchmode[i]) { + case TOGGLE: + switchflag = 2; // Toggle + break; + case FOLLOW: + switchflag = button & 0x01; // Follow wall switch state + break; + case FOLLOW_INV: + switchflag = ~button & 0x01; // Follow inverted wall switch state + break; + case PUSHBUTTON: + if ((PRESSED == button) && (NOT_PRESSED == lastwallswitch[i])) { + switchflag = 2; // Toggle with pushbutton to Gnd + } + break; + case PUSHBUTTON_INV: + if ((NOT_PRESSED == button) && (PRESSED == lastwallswitch[i])) { + switchflag = 2; // Toggle with releasing pushbutton from Gnd + } + } + if (switchflag < 3) { + if (sysCfg.mqtt_enabled && mqttClient.connected() && (strlen(sysCfg.switch_topic) != 0) && strcmp(sysCfg.switch_topic, "0")) { + send_button_power(1, i +1, switchflag); // Execute commend via MQTT + } else { + do_cmnd_power(i +1, switchflag); // Execute command internally (if i < Maxdevice) + } + } + lastwallswitch[i] = button; + } } } @@ -1808,10 +2008,14 @@ void stateloop() } if (!blinkstate) { blinks--; - if (blinks == 200) blinks = 0; + if (200 == blinks) { + blinks = 0; + } } } else { - if (sysCfg.ledstate &0x01) setLed(power); + if (sysCfg.ledstate &0x01) { + setLed(power); + } } } @@ -1819,14 +2023,15 @@ void stateloop() case (STATES/10)*2: if (otaflag) { otaflag--; - if (otaflag == 2){ + if (2 == otaflag) { otaretry = OTA_ATTEMPTS; ESPhttpUpdate.rebootOnUpdate(false); - sl_blank(1); } if (otaflag <= 0) { #ifdef USE_WEBSERVER - if (sysCfg.webserver) stopWebserver(); + if (sysCfg.webserver) { + stopWebserver(); + } #endif // USE_WEBSERVER otaflag = 92; otaok = 0; @@ -1834,11 +2039,13 @@ void stateloop() if (otaretry) { // snprintf_P(log, sizeof(log), PSTR("OTA: Attempt %d"), OTA_ATTEMPTS - otaretry); // addLog(LOG_LEVEL_INFO, log); - otaok = (ESPhttpUpdate.update(sysCfg.otaUrl) == HTTP_UPDATE_OK); - if (!otaok) otaflag = 2; + otaok = (HTTP_UPDATE_OK == ESPhttpUpdate.update(sysCfg.otaUrl)); + if (!otaok) { + otaflag = 2; + } } } - if (otaflag == 90) { // Allow MQTT to reconnect + if (90 == otaflag) { // Allow MQTT to reconnect otaflag = 0; if (otaok) { setModuleFlashMode(1); // QIO - ESP8266, DOUT - ESP8285 (Sonoff 4CH and Touch) @@ -1857,26 +2064,35 @@ void stateloop() if (savedatacounter <= 0) { if (sysCfg.savestate) { byte mask = 0xFF; - for (byte i = 0; i < MAX_PULSETIMERS; i++) - if ((sysCfg.pulsetime[i] > 0) && (sysCfg.pulsetime[i] < 30)) mask &= ~(1 << i); - if (!((sysCfg.power &mask) == (power &mask))) sysCfg.power = power; + for (byte i = 0; i < MAX_PULSETIMERS; i++) { + if ((sysCfg.pulsetime[i] > 0) && (sysCfg.pulsetime[i] < 30)) { + mask &= ~(1 << i); + } + } + if (!((sysCfg.power &mask) == (power &mask))) { + sysCfg.power = power; + } } CFG_Save(); savedatacounter = sysCfg.savedata; } } if (restartflag) { - if (restartflag == 211) { + if (211 == restartflag) { CFG_Default(); restartflag = 2; } - if (restartflag == 212) { + if (212 == restartflag) { CFG_Erase(); CFG_Default(); restartflag = 2; } - if (sysCfg.savestate) sysCfg.power = power; - if (hlw_flg) hlw_savestate(); + if (sysCfg.savestate) { + sysCfg.power = power; + } + if (hlw_flg) { + hlw_savestate(); + } CFG_Save(); restartflag--; if (restartflag <= 0) { @@ -1890,7 +2106,7 @@ void stateloop() wificheckflag = WIFI_RESTART; break; case (STATES/10)*8: - if (WiFi.status() == WL_CONNECTED) { + if (WL_CONNECTED == WiFi.status()) { if (sysCfg.mqtt_enabled) { if (!mqttClient.connected()) { if (!mqttcounter) { @@ -1926,10 +2142,12 @@ void serial() ButtonCode = (ButtonCode << 8) | SerialInByte; SerialInByte = 0; } else { - if (SerialInByte != 0xA1) ButtonCode = 0; // 0xA1 - End of Sonoff dual button code + if (SerialInByte != 0xA1) { + ButtonCode = 0; // 0xA1 - End of Sonoff dual button code + } } } - if (SerialInByte == 0xA0) { // 0xA0 - Start of Sonoff dual button code + if (0xA0 == SerialInByte) { // 0xA0 - Start of Sonoff dual button code SerialInByte = 0; ButtonCode = 0; Hexcode = 3; @@ -1976,16 +2194,24 @@ void GPIO_init() uint8_t mpin; mytmplt def_module; - if (!sysCfg.module || (sysCfg.module >= MAXMODULE)) sysCfg.module = MODULE; + if (!sysCfg.module || (sysCfg.module >= MAXMODULE)) { + sysCfg.module = MODULE; + } memcpy_P(&def_module, &modules[sysCfg.module], sizeof(def_module)); strlcpy(my_module.name, def_module.name, sizeof(my_module.name)); for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (sysCfg.my_module.gp.io[i] > GPIO_NONE) my_module.gp.io[i] = sysCfg.my_module.gp.io[i]; - if ((def_module.gp.io[i] > GPIO_NONE) && (def_module.gp.io[i] < GPIO_USER)) my_module.gp.io[i] = def_module.gp.io[i]; + if (sysCfg.my_module.gp.io[i] > GPIO_NONE) { + my_module.gp.io[i] = sysCfg.my_module.gp.io[i]; + } + if ((def_module.gp.io[i] > GPIO_NONE) && (def_module.gp.io[i] < GPIO_USER)) { + my_module.gp.io[i] = def_module.gp.io[i]; + } } - for (byte i = 0; i < GPIO_MAX; i++) pin[i] = 99; + for (byte i = 0; i < GPIO_MAX; i++) { + pin[i] = 99; + } for (byte i = 0; i < MAX_GPIO_PIN; i++) { mpin = my_module.gp.io[i]; @@ -2001,12 +2227,14 @@ void GPIO_init() led_inverted[mpin - GPIO_LED1_INV] = 1; mpin -= 4; } - else if (mpin == GPIO_DHT11) dht_type = mpin; - else if (mpin == GPIO_DHT21) { + else if (GPIO_DHT11 == mpin) { + dht_type = mpin; + } + else if (GPIO_DHT21 == mpin) { dht_type = mpin; mpin--; } - else if (mpin == GPIO_DHT22) { + else if (GPIO_DHT22 == mpin) { dht_type = mpin; mpin -= 2; } @@ -2014,25 +2242,27 @@ void GPIO_init() } } - if (pin[GPIO_TXD] == 2) Serial.set_tx(2); + if (2 == pin[GPIO_TXD]) { + Serial.set_tx(2); + } analogWriteRange(PWM_RANGE); // Default is 1023 (Arduino.h) analogWriteFreq(PWM_FREQ); // Default is 1000 (core_esp8266_wiring_pwm.c) Maxdevice = 1; - if (sysCfg.module == SONOFF_DUAL) { + if (SONOFF_DUAL == sysCfg.module) { Maxdevice = 2; Baudrate = 19200; } - else if (sysCfg.module == CH4) { + else if (CH4 == sysCfg.module) { Maxdevice = 4; Baudrate = 19200; } - else if (sysCfg.module == SONOFF_SC) { + else if (SONOFF_SC == sysCfg.module) { Maxdevice = 0; Baudrate = 19200; } - else if (sysCfg.module == SONOFF_LED) { + else if (SONOFF_LED == sysCfg.module) { pwm_idxoffset = 2; pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led if (!my_module.gp.io[4]) { @@ -2056,7 +2286,9 @@ void GPIO_init() pinMode(pin[GPIO_REL1 +i], OUTPUT); Maxdevice++; } - if (pin[GPIO_KEY1 +i] < 99) pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP); + if (pin[GPIO_KEY1 +i] < 99) { + pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP); + } } } for (byte i = 0; i < 4; i++) { @@ -2078,34 +2310,46 @@ void GPIO_init() } } - if (sysCfg.module == EXS_RELAY) { + if (EXS_RELAY == sysCfg.module) { setLatchingRelay(0,2); setLatchingRelay(1,2); } setLed(sysCfg.ledstate &8); hlw_flg = ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)); - if (hlw_flg) hlw_init(); + if (hlw_flg) { + hlw_init(); + } #ifdef USE_DHT - if (dht_type) dht_init(); + if (dht_type) { + dht_init(); + } #endif // USE_DHT #ifdef USE_DS18x20 - if (pin[GPIO_DSB] < 99) ds18x20_init(); + if (pin[GPIO_DSB] < 99) { + ds18x20_init(); + } #endif // USE_DS18x20 #ifdef USE_I2C i2c_flg = ((pin[GPIO_I2C_SCL] < 99) && (pin[GPIO_I2C_SDA] < 99)); - if (i2c_flg) Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]); + if (i2c_flg) { + Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]); + } #endif // USE_I2C #ifdef USE_WS2812 - if (pin[GPIO_WS2812] < 99) ws2812_init(); + if (pin[GPIO_WS2812] < 99) { + ws2812_init(); + } #endif // USE_WS2812 #ifdef USE_IR_REMOTE - if (pin[GPIO_IRSEND] < 99) ir_send_init(); + if (pin[GPIO_IRSEND] < 99) { + ir_send_init(); + } #endif // USE_IR_REMOTE } @@ -2166,31 +2410,41 @@ void setup() getClient(MQTTClient, sysCfg.mqtt_client, sizeof(MQTTClient)); - if (sysCfg.module == MOTOR) sysCfg.poweronstate = 1; // Needs always on else in limbo! + if (MOTOR == sysCfg.module) { + sysCfg.poweronstate = 1; // Needs always on else in limbo! + } if (ESP.getResetReason() == "Power on") { - if (sysCfg.poweronstate == 0) { // All off + if (0 == sysCfg.poweronstate) { // All off power = 0; setRelay(power); } - else if (sysCfg.poweronstate == 1) { // All on + else if (1 == sysCfg.poweronstate) { // All on power = ((0x00FF << Maxdevice) >> 8); setRelay(power); } - else if (sysCfg.poweronstate == 2) { // All saved state toggle + else if (2 == sysCfg.poweronstate) { // All saved state toggle power = (sysCfg.power & ((0x00FF << Maxdevice) >> 8)) ^ 0xFF; - if (sysCfg.savestate) setRelay(power); + if (sysCfg.savestate) { + setRelay(power); + } } - else if (sysCfg.poweronstate == 3) { // All saved state + else if (3 == sysCfg.poweronstate) { // All saved state power = sysCfg.power & ((0x00FF << Maxdevice) >> 8); - if (sysCfg.savestate) setRelay(power); + if (sysCfg.savestate) { + setRelay(power); + } } } else { power = sysCfg.power & ((0x00FF << Maxdevice) >> 8); - if (sysCfg.savestate) setRelay(power); + if (sysCfg.savestate) { + setRelay(power); + } } blink_powersave = power; - if (sysCfg.module == SONOFF_SC) sc_init(); + if (SONOFF_SC == sysCfg.module) { + sc_init(); + } rtc_init(); @@ -2208,12 +2462,20 @@ void loop() #endif // USE_WEBSERVER #ifdef USE_EMULATION - if (sysCfg.emulation) pollUDP(); + if (sysCfg.emulation) { + pollUDP(); + } #endif // USE_EMULATION - if (millis() >= timerxs) stateloop(); - if (sysCfg.mqtt_enabled) mqttClient.loop(); - if (Serial.available()) serial(); + if (millis() >= timerxs) { + stateloop(); + } + if (sysCfg.mqtt_enabled) { + mqttClient.loop(); + } + if (Serial.available()){ + serial(); + } // yield(); // yield == delay(0), delay contains yield, auto yield in loop delay(sleep); // https://github.com/esp8266/Arduino/issues/2021 diff --git a/sonoff/support.ino b/sonoff/support.ino index 5730146d9..37f7a0730 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -51,7 +51,7 @@ void osw_osWatch() snprintf_P(log, sizeof(log), PSTR("osWatch: FreeRam %d, rssi %d, last_run %d"), ESP.getFreeHeap(), WIFI_getRSSIasQuality(WiFi.RSSI()), last_run); addLog(LOG_LEVEL_DEBUG, log); #endif // DEBUG_THEO - if(last_run >= (OSWATCH_RESET_TIME * 1000)) { + if (last_run >= (OSWATCH_RESET_TIME * 1000)) { addLog_P(LOG_LEVEL_INFO, PSTR("osWatch: Warning, loop blocked. Restart now")); rtcMem.osw_flag = 1; RTC_Save(); @@ -131,7 +131,7 @@ Decoding 14 results 00:00:08 MQTT: tele/sonoff/INFO3 = {"Started":"Fatal exception:28 flag:2 (EXCEPTION) epc1:0x4000bf64 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000007 depc:0x00000000"} */ - if (type == 1) { + if (1 == type) { char svalue[10]; snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); // Exception 28 as number in string (7 in excvaddr) } @@ -145,7 +145,7 @@ Decoding 14 results 14:51:42 osWatch: FreeRam 25360, rssi 62, last_run 38771 14:51:42 osWatch: Warning, loop blocked. Restart now */ - if (type == 2) { + if (2 == type) { while(1) delay(1000); // this will trigger the os watch } } @@ -155,23 +155,6 @@ Decoding 14 results * General \*********************************************************************************************/ -boolean parseIPx(char* str, uint16_t len, uint32_t* addr) -{ - uint8_t *part = (uint8_t *)addr; - byte i; - - if (!len) return false; - *addr = 0; - for (i = 0; i <= len; i++) if (*(str +i) == ',') *(str +i) = '.'; - for (i = 0; i < 4; i++) { - part[i] = strtoul(str, NULL, 10); // Convert byte - str = strchr(str, '.'); - if (str == NULL || *str == '\0') break; // No more separators, exit - str++; // Point to next character after separator - } - return (i == 3); -} - boolean parseIP(uint32_t* addr, const char* str) { uint8_t *part = (uint8_t*)addr; @@ -181,10 +164,12 @@ boolean parseIP(uint32_t* addr, const char* str) for (i = 0; i < 4; i++) { part[i] = strtoul(str, NULL, 10); // Convert byte str = strchr(str, '.'); - if (str == NULL || *str == '\0') break; // No more separators, exit + if (str == NULL || *str == '\0') { + break; // No more separators, exit + } str++; // Point to next character after separator } - return (i == 3); + return (3 == i); } /*********************************************************************************************\ @@ -196,7 +181,12 @@ boolean parseIP(uint32_t* addr, const char* str) #define WIFI_CHECK_SEC 20 // seconds #define WIFI_RETRY_SEC 30 // seconds -uint8_t _wificounter, _wifiretry, _wifistatus, _wpsresult, _wificonfigflag = 0, _wifiConfigCounter = 0; +uint8_t _wificounter; +uint8_t _wifiretry; +uint8_t _wifistatus; +uint8_t _wpsresult; +uint8_t _wificonfigflag = 0; +uint8_t _wifiConfigCounter = 0; int WIFI_getRSSIasQuality(int RSSI) { @@ -214,7 +204,9 @@ int WIFI_getRSSIasQuality(int RSSI) boolean WIFI_configCounter() { - if (_wifiConfigCounter) _wifiConfigCounter = WIFI_MANAGER_SEC; + if (_wifiConfigCounter) { + _wifiConfigCounter = WIFI_MANAGER_SEC; + } return (_wifiConfigCounter); } @@ -239,7 +231,7 @@ void WIFI_wps_status_cb(wps_cb_status status) */ _wpsresult = status; - if (_wpsresult == WPS_CB_ST_SUCCESS) { + if (WPS_CB_ST_SUCCESS == _wpsresult) { wifi_wps_disable(); } else { snprintf_P(log, sizeof(log), PSTR("WPSconfig: FAILED with status %d"), _wpsresult); @@ -256,17 +248,27 @@ boolean WIFI_WPSConfigDone(void) boolean WIFI_beginWPSConfig(void) { _wpsresult = 99; - if (!wifi_wps_disable()) return false; - if (!wifi_wps_enable(WPS_TYPE_PBC)) return false; // so far only WPS_TYPE_PBC is supported (SDK 2.0.0) - if (!wifi_set_wps_cb((wps_st_cb_t) &WIFI_wps_status_cb)) return false; - if (!wifi_wps_start()) return false; + if (!wifi_wps_disable()) { + return false; + } + if (!wifi_wps_enable(WPS_TYPE_PBC)) { + return false; // so far only WPS_TYPE_PBC is supported (SDK 2.0.0) + } + if (!wifi_set_wps_cb((wps_st_cb_t) &WIFI_wps_status_cb)) { + return false; + } + if (!wifi_wps_start()) { + return false; + } return true; } void WIFI_config(uint8_t type) { if (!_wificonfigflag) { - if (type == WIFI_RETRY) return; + if (WIFI_RETRY == type) { + return; + } #ifdef USE_EMULATION UDP_Disconnect(); #endif // USE_EMULATION @@ -275,14 +277,14 @@ void WIFI_config(uint8_t type) _wifiConfigCounter = WIFI_CONFIG_SEC; // Allow up to WIFI_CONFIG_SECS seconds for phone to provide ssid/pswd _wificounter = _wifiConfigCounter +5; blinks = 1999; - if (_wificonfigflag == WIFI_RESTART) { + if (WIFI_RESTART == _wificonfigflag) { restartflag = 2; } - else if (_wificonfigflag == WIFI_SMARTCONFIG) { + else if (WIFI_SMARTCONFIG == _wificonfigflag) { addLog_P(LOG_LEVEL_INFO, PSTR("Smartconfig: Active for 1 minute")); WiFi.beginSmartConfig(); } - else if (_wificonfigflag == WIFI_WPSCONFIG) { + else if (WIFI_WPSCONFIG == _wificonfigflag) { if (WIFI_beginWPSConfig()) { addLog_P(LOG_LEVEL_INFO, PSTR("WPSconfig: Active for 1 minute")); } else { @@ -291,7 +293,7 @@ void WIFI_config(uint8_t type) } } #ifdef USE_WEBSERVER - else if (_wificonfigflag == WIFI_MANAGER) { + else if (WIFI_MANAGER == _wificonfigflag) { addLog_P(LOG_LEVEL_INFO, PSTR("Wifimanager: Active for 1 minute")); beginWifiManager(); } @@ -313,11 +315,15 @@ void WIFI_begin(uint8_t flag) } WiFi.disconnect(); WiFi.mode(WIFI_STA); // Disable AP mode -// if (sysCfg.sleep) wifi_set_sleep_type(LIGHT_SLEEP_T); // Allow light sleep during idle times - if (sysCfg.sleep) WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times -// WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times -// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) WiFi.setPhyMode(WIFI_PHY_MODE_11N); - if (!WiFi.getAutoConnect()) WiFi.setAutoConnect(true); + if (sysCfg.sleep) { + WiFi.setSleepMode(WIFI_LIGHT_SLEEP); // Allow light sleep during idle times + } +// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { +// WiFi.setPhyMode(WIFI_PHY_MODE_11N); +// } + if (!WiFi.getAutoConnect()) { + WiFi.setAutoConnect(true); + } // WiFi.setAutoReconnect(true); switch (flag) { case 0: // AP1 @@ -327,9 +333,12 @@ void WIFI_begin(uint8_t flag) case 2: // Toggle sysCfg.sta_active ^= 1; } // 3: Current AP - if (strlen(sysCfg.sta_ssid[1]) == 0) sysCfg.sta_active = 0; - if (sysCfg.ip_address[0]) + if (0 == strlen(sysCfg.sta_ssid[1])) { + sysCfg.sta_active = 0; + } + if (sysCfg.ip_address[0]) { WiFi.config(sysCfg.ip_address[0], sysCfg.ip_address[1], sysCfg.ip_address[2], sysCfg.ip_address[3]); // Set static IP + } WiFi.hostname(Hostname); WiFi.begin(sysCfg.sta_ssid[sysCfg.sta_active], sysCfg.sta_pwd[sysCfg.sta_active]); snprintf_P(log, sizeof(log), PSTR("Wifi: Connecting to AP%d %s in mode 11%c as %s..."), @@ -339,7 +348,7 @@ void WIFI_begin(uint8_t flag) void WIFI_check_ip() { - if ((WiFi.status() == WL_CONNECTED) && (static_cast(WiFi.localIP()) != 0)) { + if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0)) { _wificounter = WIFI_CHECK_SEC; _wifiretry = WIFI_RETRY_SEC; addLog_P((_wifistatus != WL_CONNECTED) ? LOG_LEVEL_INFO : LOG_LEVEL_DEBUG_MORE, PSTR("Wifi: Connected")); @@ -360,24 +369,36 @@ void WIFI_check_ip() break; case WL_NO_SSID_AVAIL: addLog_P(LOG_LEVEL_INFO, PSTR("Wifi: Connect failed as AP cannot be reached")); - if (_wifiretry > (WIFI_RETRY_SEC / 2)) _wifiretry = WIFI_RETRY_SEC / 2; - else if (_wifiretry) _wifiretry = 0; + if (_wifiretry > (WIFI_RETRY_SEC / 2)) { + _wifiretry = WIFI_RETRY_SEC / 2; + } + else if (_wifiretry) { + _wifiretry = 0; + } break; case WL_CONNECT_FAILED: addLog_P(LOG_LEVEL_INFO, PSTR("Wifi: Connect failed with AP incorrect password")); - if (_wifiretry > (WIFI_RETRY_SEC / 2)) _wifiretry = WIFI_RETRY_SEC / 2; - else if (_wifiretry) _wifiretry = 0; + if (_wifiretry > (WIFI_RETRY_SEC / 2)) { + _wifiretry = WIFI_RETRY_SEC / 2; + } + else if (_wifiretry) { + _wifiretry = 0; + } break; default: // WL_IDLE_STATUS and WL_DISCONNECTED - if (!_wifiretry || (_wifiretry == (WIFI_RETRY_SEC / 2))) { + if (!_wifiretry || ((WIFI_RETRY_SEC / 2) == _wifiretry)) { addLog_P(LOG_LEVEL_INFO, PSTR("Wifi: Connect failed with AP timeout")); } else { addLog_P(LOG_LEVEL_DEBUG, PSTR("Wifi: Attempting connection...")); } } if (_wifiretry) { - if (_wifiretry == WIFI_RETRY_SEC) WIFI_begin(3); // Select default SSID - if (_wifiretry == (WIFI_RETRY_SEC / 2)) WIFI_begin(2); // Select alternate SSID + if (WIFI_RETRY_SEC == _wifiretry) { + WIFI_begin(3); // Select default SSID + } + if ((WIFI_RETRY_SEC / 2) == _wifiretry) { + WIFI_begin(2); // Select alternate SSID + } _wificounter = 1; _wifiretry--; } else { @@ -404,18 +425,28 @@ void WIFI_Check(uint8_t param) _wifiConfigCounter--; _wificounter = _wifiConfigCounter +5; if (_wifiConfigCounter) { - if ((_wificonfigflag == WIFI_SMARTCONFIG) && WiFi.smartConfigDone()) _wifiConfigCounter = 0; - if ((_wificonfigflag == WIFI_WPSCONFIG) && WIFI_WPSConfigDone()) _wifiConfigCounter = 0; + if ((WIFI_SMARTCONFIG == _wificonfigflag) && WiFi.smartConfigDone()) { + _wifiConfigCounter = 0; + } + if ((WIFI_WPSCONFIG == _wificonfigflag) && WIFI_WPSConfigDone()) { + _wifiConfigCounter = 0; + } if (!_wifiConfigCounter) { - if (strlen(WiFi.SSID().c_str())) strlcpy(sysCfg.sta_ssid[0], WiFi.SSID().c_str(), sizeof(sysCfg.sta_ssid[0])); - if (strlen(WiFi.psk().c_str())) strlcpy(sysCfg.sta_pwd[0], WiFi.psk().c_str(), sizeof(sysCfg.sta_pwd[0])); + if (strlen(WiFi.SSID().c_str())) { + strlcpy(sysCfg.sta_ssid[0], WiFi.SSID().c_str(), sizeof(sysCfg.sta_ssid[0])); + } + if (strlen(WiFi.psk().c_str())) { + strlcpy(sysCfg.sta_pwd[0], WiFi.psk().c_str(), sizeof(sysCfg.sta_pwd[0])); + } sysCfg.sta_active = 0; snprintf_P(log, sizeof(log), PSTR("Wificonfig: SSID1 %s and Password1 %s"), sysCfg.sta_ssid[0], sysCfg.sta_pwd[0]); addLog(LOG_LEVEL_INFO, log); } } if (!_wifiConfigCounter) { - if (_wificonfigflag == WIFI_SMARTCONFIG) WiFi.stopSmartConfig(); + if (WIFI_SMARTCONFIG == _wificonfigflag) { + WiFi.stopSmartConfig(); + } restartflag = 2; } } else { @@ -424,7 +455,7 @@ void WIFI_Check(uint8_t param) _wificounter = WIFI_CHECK_SEC; WIFI_check_ip(); } - if ((WiFi.status() == WL_CONNECTED) && (static_cast(WiFi.localIP()) != 0) && !_wificonfigflag) { + if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0) && !_wificonfigflag) { #ifdef USE_DISCOVERY if (!mDNSbegun) { mDNSbegun = MDNS.begin(Hostname); @@ -444,7 +475,9 @@ void WIFI_Check(uint8_t param) stopWebserver(); } #ifdef USE_EMULATION - if (sysCfg.emulation) UDP_Connect(); + if (sysCfg.emulation) { + UDP_Connect(); + } #endif // USE_EMULATION #endif // USE_WEBSERVER } else { @@ -461,8 +494,12 @@ int WIFI_State() { int state; - if ((WiFi.status() == WL_CONNECTED) && (static_cast(WiFi.localIP()) != 0)) state = WIFI_RESTART; - if (_wificonfigflag) state = _wificonfigflag; + if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0)) { + state = WIFI_RESTART; + } + if (_wificonfigflag) { + state = _wificonfigflag; + } return state; } @@ -482,10 +519,13 @@ void WIFI_Connect() #ifdef MQTT_HOST_DISCOVERY boolean mdns_discoverMQTTServer() { - char log[LOGSZ], ip_str[20]; + char log[LOGSZ]; + char ip_str[20]; int n; - if (!mDNSbegun) return false; + if (!mDNSbegun) { + return false; + } n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service @@ -536,13 +576,14 @@ int32_t i2c_read(uint8_t addr, uint8_t reg, uint8_t size) do { Wire.beginTransmission(addr); // start transmission to device Wire.write(reg); // sends register address to read from - if (Wire.endTransmission(false) == 0) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... + if (0 == Wire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... Wire.requestFrom((int)addr, (int)size); // send data n-bytes read - if (Wire.available() == size) + if (Wire.available() == size) { for(byte i = 0; i < size; i++) { data <<= 8; data |= Wire.read(); // receive DATA } + } } x++; } while (Wire.endTransmission(true) != 0 && x <= I2C_RETRY_COUNTER); // end transmission @@ -594,19 +635,23 @@ void i2c_write8(uint8_t addr, uint8_t reg, uint8_t val) void i2c_scan(char *devs, unsigned int devs_len) { - byte error, address, any = 0; + byte error; + byte address; + byte any = 0; char tstr[10]; snprintf_P(devs, devs_len, PSTR("{\"I2Cscan\":\"Device(s) found at")); for (address = 1; address <= 127; address++) { Wire.beginTransmission(address); error = Wire.endTransmission(); - if (error == 0) { + if (0 == error) { snprintf_P(tstr, sizeof(tstr), PSTR(" 0x%2x"), address); strncat(devs, tstr, devs_len); any = 1; } - else if (error == 4) snprintf_P(devs, devs_len, PSTR("{\"I2Cscan\":\"Unknown error at 0x%2x\"}"), address); + else if (4 == error) { + snprintf_P(devs, devs_len, PSTR("{\"I2Cscan\":\"Unknown error at 0x%2x\"}"), address); + } } if (any) { strncat(devs, "\"}", devs_len); @@ -637,15 +682,24 @@ Ticker tickerRTC; static const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // API starts months from 1, this array starts from 0 static const char monthNames[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; -uint32_t utctime = 0, loctime = 0, dsttime = 0, stdtime = 0, ntptime = 0, midnight = 1451602800; +uint32_t utctime = 0; +uint32_t loctime = 0; +uint32_t dsttime = 0; +uint32_t stdtime = 0; +uint32_t ntptime = 0; +uint32_t midnight = 1451602800; String getBuildDateTime() { // "2017-03-07T11:08:02" char bdt[21]; - char *str, *p, *smonth; + char *str; + char *p; + char *smonth; char mdate[] = __DATE__; // "Mar 7 2017" - int month, day, year; + int month; + int day; + int year; // sscanf(mdate, "%s %d %d", bdt, &day, &year); // Not implemented in 2.3.0 and probably too many code byte i = 0; @@ -682,7 +736,9 @@ void breakTime(uint32_t timeInput, TIME_T &tm) // this is a more compact version of the C library localtime function // note that year is offset from 1970 !!! - uint8_t year, month, monthLength; + uint8_t year; + uint8_t month; + uint8_t monthLength; uint32_t time; unsigned long days; @@ -710,7 +766,7 @@ void breakTime(uint32_t timeInput, TIME_T &tm) month = 0; monthLength = 0; for (month = 0; month < 12; month++) { - if (month == 1) { // february + if (1 == month) { // february if (LEAP_YEAR(year)) { monthLength = 29; } else { @@ -750,7 +806,7 @@ uint32_t makeTime(TIME_T &tm) // add days for this year, months start from 1 for (i = 1; i < tm.Month; i++) { - if ((i == 2) && LEAP_YEAR(tm.Year)) { + if ((2 == i) && LEAP_YEAR(tm.Year)) { seconds += SECS_PER_DAY * 29; } else { seconds += SECS_PER_DAY * monthDays[i-1]; // monthDay array starts from 0 @@ -767,16 +823,17 @@ uint32_t toTime_t(TimeChangeRule r, int yr) { TIME_T tm; uint32_t t; - uint8_t m, w; // temp copies of r.month and r.week + uint8_t m; + uint8_t w; // temp copies of r.month and r.week m = r.month; w = r.week; - if (w == 0) { // Last week = 0 - if (++m > 12) { // for "Last", go to the next month - m = 1; - yr++; - } - w = 1; // and treat as first week of next month, subtract 7 days later + if (0 == w) { // Last week = 0 + if (++m > 12) { // for "Last", go to the next month + m = 1; + yr++; + } + w = 1; // and treat as first week of next month, subtract 7 days later } tm.Hour = r.hour; @@ -788,7 +845,9 @@ uint32_t toTime_t(TimeChangeRule r, int yr) t = makeTime(tm); // First day of the month, or first day of next month for "Last" rules breakTime(t, tm); t += (7 * (w - 1) + (r.dow - tm.Wday + 7) % 7) * SECS_PER_DAY; - if (r.week == 0) t -= 7 * SECS_PER_DAY; //back up a week if this is a "Last" rule + if (0 == r.week) { + t -= 7 * SECS_PER_DAY; //back up a week if this is a "Last" rule + } return t; } @@ -797,9 +856,9 @@ String rtc_time(int type) char stime[25]; // Skip newline uint32_t time = utctime; - if (type == 1) time = loctime; - if (type == 2) time = dsttime; - if (type == 3) time = stdtime; + if (1 == type) time = loctime; + if (2 == type) time = dsttime; + if (3 == type) time = stdtime; snprintf_P(stime, sizeof(stime), PSTR("%s"), sntp_get_real_time(time)); return String(stime); } @@ -818,16 +877,17 @@ void rtc_second() { char log[LOGSZ]; byte ntpsync; - uint32_t stdoffset, dstoffset; + uint32_t stdoffset; + uint32_t dstoffset; TIME_T tmpTime; ntpsync = 0; if (rtcTime.Year < 2016) { - if (WiFi.status() == WL_CONNECTED) { + if (WL_CONNECTED == WiFi.status()) { ntpsync = 1; // Initial NTP sync } } else { - if ((rtcTime.Minute == 1) && (rtcTime.Second == 1)) { + if ((1 == rtcTime.Minute) && (1 == rtcTime.Second)) { ntpsync = 1; // Hourly NTP sync at xx:01:01 } } @@ -850,7 +910,7 @@ void rtc_second() utctime++; loctime = utctime; if (loctime > 1451602800) { // 2016-01-01 - if (sysCfg.timezone == 99) { + if (99 == sysCfg.timezone) { dstoffset = myDST.offset * SECS_PER_MIN; stdoffset = mySTD.offset * SECS_PER_MIN; if ((utctime >= (dsttime - stdoffset)) && (utctime < (stdtime - dstoffset))) { @@ -913,11 +973,14 @@ void addLog(byte loglevel, const char *line) if (sysCfg.webserver && (loglevel <= sysCfg.weblog_level)) { Log[logidx] = String(mxtime) + " " + String(line); logidx++; - if (logidx > MAX_LOG_LINES -1) logidx = 0; + if (logidx > MAX_LOG_LINES -1) { + logidx = 0; + } } #endif // USE_WEBSERVER -// if (sysCfg.emulation) return; // Disable syslog (UDP) when emulation using UDP is selected - if ((WiFi.status() == WL_CONNECTED) && (loglevel <= syslog_level)) syslog(line); + if ((WL_CONNECTED == WiFi.status()) && (loglevel <= syslog_level)) { + syslog(line); + } } void addLog_P(byte loglevel, const char *formatP) diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index aaf9f5dcc..f1011fa2d 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -286,7 +286,10 @@ ESP8266WebServer *webServer; boolean _removeDuplicateAPs = true; int _minimumQuality = -1; -uint8_t _httpflag = HTTP_OFF, _uploaderror = 0, _uploadfiletype, _colcount; +uint8_t _httpflag = HTTP_OFF; +uint8_t _uploaderror = 0; +uint8_t _uploadfiletype; +uint8_t _colcount; void startWebserver(int type, IPAddress ipweb) { @@ -294,7 +297,7 @@ void startWebserver(int type, IPAddress ipweb) if (!_httpflag) { if (!webServer) { - webServer = new ESP8266WebServer((type==HTTP_MANAGER)?80:WEB_PORT); + webServer = new ESP8266WebServer((HTTP_MANAGER==type)?80:WEB_PORT); webServer->on("/", handleRoot); webServer->on("/cn", handleConfig); webServer->on("/md", handleModule); @@ -323,12 +326,12 @@ void startWebserver(int type, IPAddress ipweb) webServer->on("/rb", handleRestart); webServer->on("/fwlink", handleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. #ifdef USE_EMULATION - if (sysCfg.emulation == EMUL_WEMO) { + if (EMUL_WEMO == sysCfg.emulation) { webServer->on("/upnp/control/basicevent1", HTTP_POST, handleUPnPevent); webServer->on("/eventservice.xml", handleUPnPservice); webServer->on("/setup.xml", handleUPnPsetupWemo); } - if (sysCfg.emulation == EMUL_HUE) { + if (EMUL_HUE == sysCfg.emulation) { webServer->on("/description.xml", handleUPnPsetupHue); } #endif // USE_EMULATION @@ -357,7 +360,7 @@ void stopWebserver() void beginWifiManager() { // setup AP - if ((WiFi.status() == WL_CONNECTED) && (static_cast(WiFi.localIP()) != 0)) { + if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0)) { WiFi.mode(WIFI_AP_STA); addLog_P(LOG_LEVEL_DEBUG, PSTR("Wifimanager: Set AccessPoint and keep Station")); } else { @@ -379,18 +382,22 @@ void beginWifiManager() void pollDnsWeb() { - if (dnsServer) dnsServer->processNextRequest(); - if (webServer) webServer->handleClient(); + if (dnsServer) { + dnsServer->processNextRequest(); + } + if (webServer) { + webServer->handleClient(); + } } void showPage(String &page) { - if((_httpflag == HTTP_ADMIN) && (sysCfg.web_password[0] != 0) && !webServer->authenticate(WEB_USERNAME, sysCfg.web_password)) { + if((HTTP_ADMIN == _httpflag) && (sysCfg.web_password[0] != 0) && !webServer->authenticate(WEB_USERNAME, sysCfg.web_password)) { return webServer->requestAuthentication(); } page.replace("{ha}", my_module.name); page.replace("{h}", sysCfg.friendlyname[0]); - if (_httpflag == HTTP_MANAGER) { + if (HTTP_MANAGER == _httpflag) { if (WIFI_configCounter()) { page.replace("", ""); page += FPSTR(HTTP_COUNTER); @@ -412,7 +419,7 @@ void handleRoot() return; } - if (_httpflag == HTTP_MANAGER) { + if (HTTP_MANAGER == _httpflag) { handleWifi0(); } else { char stemp[10], line[100]; @@ -422,7 +429,7 @@ void handleRoot() page += F("
"); if (Maxdevice) { - if (sysCfg.module == SONOFF_LED) { + if (SONOFF_LED == sysCfg.module) { snprintf_P(line, sizeof(line), PSTR(""), sysCfg.led_dimmer[0]); page += line; @@ -438,7 +445,7 @@ void handleRoot() page += F(""); } - if (_httpflag == HTTP_ADMIN) { + if (HTTP_ADMIN == _httpflag) { page += FPSTR(HTTP_BTN_MENU1); page += FPSTR(HTTP_BTN_RSTRT); } @@ -450,23 +457,35 @@ void handleAjax2() { char svalue[16]; - if (strlen(webServer->arg("o").c_str())) do_cmnd_power(atoi(webServer->arg("o").c_str()), 2); + if (strlen(webServer->arg("o").c_str())) { + do_cmnd_power(atoi(webServer->arg("o").c_str()), 2); + } if (strlen(webServer->arg("d").c_str())) { snprintf_P(svalue, sizeof(svalue), PSTR("dimmer %s"), webServer->arg("d").c_str()); do_cmnd(svalue); } String tpage = ""; - if (hlw_flg) tpage += hlw_webPresent(); - if (sysCfg.module == SONOFF_SC) tpage += sc_webPresent(); + if (hlw_flg) { + tpage += hlw_webPresent(); + } + if (SONOFF_SC == sysCfg.module) { + tpage += sc_webPresent(); + } #ifdef USE_DS18B20 - if (pin[GPIO_DSB] < 99) tpage += dsb_webPresent(); + if (pin[GPIO_DSB] < 99) { + tpage += dsb_webPresent(); + } #endif // USE_DS18B20 #ifdef USE_DS18x20 - if (pin[GPIO_DSB] < 99) tpage += ds18x20_webPresent(); + if (pin[GPIO_DSB] < 99) { + tpage += ds18x20_webPresent(); + } #endif // USE_DS18x20 #ifdef USE_DHT - if (dht_type) tpage += dht_webPresent(); + if (dht_type) { + tpage += dht_webPresent(); + } #endif // USE_DHT #ifdef USE_I2C if (i2c_flg) { @@ -504,7 +523,7 @@ void handleAjax2() } /* * Will interrupt user action when selected - if (sysCfg.module == SONOFF_LED) { + if (SONOFF_LED == sysCfg.module) { snprintf_P(line, sizeof(line), PSTR(""), sysCfg.led_dimmer[0]); page += line; @@ -518,20 +537,26 @@ void handleAjax2() boolean httpUser() { - boolean status = (_httpflag == HTTP_USER); - if (status) handleRoot(); + boolean status = (HTTP_USER == _httpflag); + if (status) { + handleRoot(); + } return status; } void handleConfig() { - if (httpUser()) return; + if (httpUser()) { + return; + } addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle config")); String page = FPSTR(HTTP_HEAD); page.replace("{v}", "Configuration"); page += FPSTR(HTTP_BTN_MENU2); - if (sysCfg.mqtt_enabled) page += FPSTR(HTTP_BTN_MENU3); + if (sysCfg.mqtt_enabled) { + page += FPSTR(HTTP_BTN_MENU3); + } page += FPSTR(HTTP_BTN_MENU4); page += FPSTR(HTTP_BTN_MAIN); showPage(page); @@ -541,29 +566,49 @@ boolean inModule(byte val, uint8_t *arr) { int offset = 0; - if (!val) return false; // None + if (!val) { + return false; // None + } #ifndef USE_I2C - if (val == GPIO_I2C_SCL) return true; - if (val == GPIO_I2C_SDA) return true; + if (GPIO_I2C_SCL == val) { + return true; + } + if (GPIO_I2C_SDA == val) { + return true; + } #endif #ifndef USE_WS2812 - if (val == GPIO_WS2812) return true; + if (GPIO_WS2812 == val) { + return true; + } #endif #ifndef USE_IR_REMOTE - if (val == GPIO_IRSEND) return true; + if (GPIO_IRSEND == val) { + return true; + } #endif - if (((val >= GPIO_REL1) && (val <= GPIO_REL4)) || ((val >= GPIO_LED1) && (val <= GPIO_LED4))) offset = 4; - if (((val >= GPIO_REL1_INV) && (val <= GPIO_REL4_INV)) || ((val >= GPIO_LED1_INV) && (val <= GPIO_LED4_INV))) offset = -4; + if (((val >= GPIO_REL1) && (val <= GPIO_REL4)) || ((val >= GPIO_LED1) && (val <= GPIO_LED4))) { + offset = 4; + } + if (((val >= GPIO_REL1_INV) && (val <= GPIO_REL4_INV)) || ((val >= GPIO_LED1_INV) && (val <= GPIO_LED4_INV))) { + offset = -4; + } for (byte i = 0; i < MAX_GPIO_PIN; i++) { - if (arr[i] == val) return true; - if (arr[i] == val + offset) return true; + if (arr[i] == val) { + return true; + } + if (arr[i] == val + offset) { + return true; + } } return false; } void handleModule() { - if (httpUser()) return; + if (httpUser()) { + return; + } char stemp[20], line[128]; addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Module config")); @@ -596,9 +641,9 @@ void handleModule() } func += F("\";os=o0.replace(/-1/g,\"


Device will restart in a few seconds"); restartflag = 2; @@ -1081,17 +1165,21 @@ void handleUploadLoop() char log[LOGSZ]; boolean _serialoutput = (LOG_LEVEL_DEBUG <= seriallog_level); - if (_httpflag == HTTP_USER) return; + if (HTTP_USER == _httpflag) { + return; + } if (_uploaderror) { - if (!_uploadfiletype) Update.end(); + if (!_uploadfiletype) { + Update.end(); + } return; } HTTPUpload& upload = webServer->upload(); - if (upload.status == UPLOAD_FILE_START) { + if (UPLOAD_FILE_START == upload.status) { restartflag = 60; - if (upload.filename.c_str()[0] == 0) { + if (0 == upload.filename.c_str()[0]) { _uploaderror = 1; return; } @@ -1102,18 +1190,21 @@ void handleUploadLoop() #ifdef USE_EMULATION UDP_Disconnect(); #endif // USE_EMULATION - if (sysCfg.mqtt_enabled) mqttClient.disconnect(); + if (sysCfg.mqtt_enabled) { + mqttClient.disconnect(); + } uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; if (!Update.begin(maxSketchSpace)) { //start with max available size - if (_serialoutput) Update.printError(Serial); + if (_serialoutput) { + Update.printError(Serial); + } _uploaderror = 2; return; } } - sl_blank(1); _colcount = 0; - } else if (!_uploaderror && (upload.status == UPLOAD_FILE_WRITE)) { - if (upload.totalSize == 0) + } else if (!_uploaderror && (UPLOAD_FILE_WRITE == upload.status)) { + if (0 == upload.totalSize) { if (_uploadfiletype) { if (upload.buf[0] != CONFIG_FILE_SIGN) { @@ -1134,7 +1225,7 @@ void handleUploadLoop() _uploaderror = 4; return; } - if ((sysCfg.module == SONOFF_TOUCH) || (sysCfg.module == SONOFF_4CH)) { + if ((SONOFF_TOUCH == sysCfg.module) || (SONOFF_4CH == sysCfg.module)) { upload.buf[2] = 3; // DOUT - ESP8285 addLog_P(LOG_LEVEL_DEBUG, PSTR("FLSH: Set Flash Mode to 3")); } @@ -1142,27 +1233,39 @@ void handleUploadLoop() } if (_uploadfiletype) { // config if (!_uploaderror) { - if (upload.buf[1]) for (uint16_t i = 2; i < upload.currentSize; i++) upload.buf[i] ^= (CONFIG_FILE_XOR +i); + if (upload.buf[1]) { + for (uint16_t i = 2; i < upload.currentSize; i++) { + upload.buf[i] ^= (CONFIG_FILE_XOR +i); + } + } CFG_DefaultSet2(); memcpy((char*)&sysCfg +16, upload.buf +16, upload.currentSize -16); } } else { // firmware if (!_uploaderror && (Update.write(upload.buf, upload.currentSize) != upload.currentSize)) { - if (_serialoutput) Update.printError(Serial); + if (_serialoutput) { + Update.printError(Serial); + } _uploaderror = 5; return; } if (_serialoutput) { Serial.printf("."); _colcount++; - if (!(_colcount % 80)) Serial.println(); + if (!(_colcount % 80)) { + Serial.println(); + } } } - } else if(!_uploaderror && (upload.status == UPLOAD_FILE_END)) { - if (_serialoutput && (_colcount % 80)) Serial.println(); + } else if(!_uploaderror && (UPLOAD_FILE_END == upload.status)) { + if (_serialoutput && (_colcount % 80)) { + Serial.println(); + } if (!_uploadfiletype) { if (!Update.end(true)) { // true to set the size to the current progress - if (_serialoutput) Update.printError(Serial); + if (_serialoutput) { + Update.printError(Serial); + } _uploaderror = 6; return; } @@ -1171,18 +1274,22 @@ void handleUploadLoop() snprintf_P(log, sizeof(log), PSTR("Upload: Successful %u bytes. Restarting"), upload.totalSize); addLog(LOG_LEVEL_INFO, log); } - } else if(upload.status == UPLOAD_FILE_ABORTED) { + } else if (UPLOAD_FILE_ABORTED == upload.status) { restartflag = 0; mqttcounter = 0; _uploaderror = 7; - if (!_uploadfiletype) Update.end(); + if (!_uploadfiletype) { + Update.end(); + } } delay(0); } void handleCmnd() { - if (httpUser()) return; + if (httpUser()) { + return; + } char svalue[128]; // was MESSZ addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle cmnd")); @@ -1210,7 +1317,9 @@ void handleCmnd() byte counter = curridx; do { if (Log[counter].length()) { - if (message.length()) message += F("\n"); + if (message.length()) { + message += F("\n"); + } if (sysCfg.mqtt_enabled) { // [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [RESULT = {"POWER":"OFF"}] // message += Log[counter].substring(17 + strlen(PUB_PREFIX) + strlen(sysCfg.mqtt_topic)); @@ -1221,7 +1330,9 @@ void handleCmnd() } } counter++; - if (counter > MAX_LOG_LINES -1) counter = 0; + if (counter > MAX_LOG_LINES -1) { + counter = 0; + } } while (counter != logidx); } else { message = F("Enable weblog 2 if response expected\n"); @@ -1238,7 +1349,9 @@ void handleCmnd() void handleConsole() { - if (httpUser()) return; + if (httpUser()) { + return; + } addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle console")); @@ -1253,9 +1366,13 @@ void handleConsole() void handleAjax() { - if (httpUser()) return; - char log[LOGSZ], svalue[128]; // was MESSZ - byte cflg = 1, counter = 99; + if (httpUser()) { + return; + } + char log[LOGSZ]; + char svalue[128]; // was MESSZ + byte cflg = 1; + byte counter = 99; if (strlen(webServer->arg("c1").c_str())) { snprintf_P(svalue, sizeof(svalue), PSTR("%s"), webServer->arg("c1").c_str()); @@ -1267,7 +1384,9 @@ void handleAjax() syslog_level = syslog_now; } - if (strlen(webServer->arg("c2").c_str())) counter = atoi(webServer->arg("c2").c_str()); + if (strlen(webServer->arg("c2").c_str())) { + counter = atoi(webServer->arg("c2").c_str()); + } String message = F(""); message += String(logidx); @@ -1279,17 +1398,23 @@ void handleAjax() } message += F(""); if (counter != logidx) { - if (counter == 99) { + if (99 == counter) { counter = logidx; cflg = 0; } do { if (Log[counter].length()) { - if (cflg) message += F("\n"); else cflg = 1; + if (cflg) { + message += F("\n"); + } else { + cflg = 1; + } message += Log[counter]; } counter++; - if (counter > MAX_LOG_LINES -1) counter = 0; + if (counter > MAX_LOG_LINES -1) { + counter = 0; + } } while (counter != logidx); } message += F(""); @@ -1302,7 +1427,9 @@ void handleAjax() void handleInfo() { - if (httpUser()) return; + if (httpUser()) { + return; + } addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle info")); int freeMem = ESP.getFreeHeap(); @@ -1356,9 +1483,15 @@ void handleInfo() page += F("Emulation"); #ifdef USE_EMULATION - if (sysCfg.emulation == EMUL_WEMO) page += F("Belkin WeMo"); - else if (sysCfg.emulation == EMUL_HUE) page += F("Hue Bridge"); - else page += F("None"); + if (EMUL_WEMO == sysCfg.emulation) { + page += F("Belkin WeMo"); + } + else if (EMUL_HUE == sysCfg.emulation) { + page += F("Hue Bridge"); + } + else { + page += F("None"); + } #else page += F("Disabled"); #endif // USE_EMULATION @@ -1395,13 +1528,15 @@ void handleInfo() void handleRestart() { - if (httpUser()) return; + if (httpUser()) { + return; + } addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Restarting")); String page = FPSTR(HTTP_HEAD); page.replace("{v}", "Info"); page += FPSTR(HTTP_MSG_RSTRT); - if (_httpflag == HTTP_MANAGER) { + if (HTTP_MANAGER == _httpflag) { _httpflag = HTTP_ADMIN; } else { page += FPSTR(HTTP_BTN_MAIN); @@ -1421,7 +1556,7 @@ void handleNotFound() #ifdef USE_EMULATION String path = webServer->uri(); - if ((sysCfg.emulation == EMUL_HUE) && (path.startsWith("/api"))) { + if ((EMUL_HUE == sysCfg.emulation) && (path.startsWith("/api"))) { handle_hue_api(&path); } else #endif // USE_EMULATION @@ -1448,7 +1583,7 @@ void handleNotFound() /* Redirect to captive portal if we got a request for another domain. Return true in that case so the page handler do not try to handle the request again. */ boolean captivePortal() { - if ((_httpflag == HTTP_MANAGER) && !isIp(webServer->hostHeader())) { + if ((HTTP_MANAGER == _httpflag) && !isIp(webServer->hostHeader())) { addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Request redirected to captive portal")); webServer->sendHeader("Location", String("http://") + webServer->client().localIP().toString(), true); diff --git a/sonoff/xdrv_domoticz.ino b/sonoff/xdrv_domoticz.ino index 9600ff6f0..114dbf587 100644 --- a/sonoff/xdrv_domoticz.ino +++ b/sonoff/xdrv_domoticz.ino @@ -56,14 +56,16 @@ void mqtt_publishDomoticzPowerState(byte device) char svalue[64]; // was MESSZ if (sysCfg.domoticz_relay_idx[device -1] && (strlen(sysCfg.domoticz_in_topic) != 0)) { - if ((device < 1) || (device > Maxdevice)) device = 1; + if ((device < 1) || (device > Maxdevice)) { + device = 1; + } - if (sysCfg.module == SONOFF_LED) { + if (SONOFF_LED == sysCfg.module) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":2,\"svalue\":\"%d\"}"), sysCfg.domoticz_relay_idx[device -1], sysCfg.led_dimmer[device -1]); mqtt_publish(sysCfg.domoticz_in_topic, svalue); } - else if ((device == 1) && (pin[GPIO_WS2812] < 99)) { + else if ((1 == device) && (pin[GPIO_WS2812] < 99)) { snprintf_P(svalue, sizeof(svalue), PSTR("{\"idx\":%d,\"nvalue\":2,\"svalue\":\"%d\"}"), sysCfg.domoticz_relay_idx[device -1], sysCfg.ws_dimmer); mqtt_publish(sysCfg.domoticz_in_topic, svalue); @@ -76,7 +78,9 @@ void mqtt_publishDomoticzPowerState(byte device) void domoticz_updatePowerState(byte device) { - if (domoticz_update_flag) mqtt_publishDomoticzPowerState(device); + if (domoticz_update_flag) { + mqtt_publishDomoticzPowerState(device); + } domoticz_update_flag = 1; } @@ -86,7 +90,9 @@ void domoticz_mqttUpdate() domoticz_update_timer--; if (domoticz_update_timer <= 0) { domoticz_update_timer = sysCfg.domoticz_update_timer; - for (byte i = 1; i <= Maxdevice; i++) mqtt_publishDomoticzPowerState(i); + for (byte i = 1; i <= Maxdevice; i++) { + mqtt_publishDomoticzPowerState(i); + } } } } @@ -130,17 +136,25 @@ boolean domoticz_update() boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uint16_t sdataBuf) { - char log[LOGSZ], stemp1[10]; + char log[LOGSZ]; + char stemp1[10]; unsigned long idx = 0; - int16_t nvalue, found = 0; + int16_t nvalue; + int16_t found = 0; domoticz_update_flag = 1; if (!strncmp(topicBuf, sysCfg.domoticz_out_topic, strlen(sysCfg.domoticz_out_topic)) != 0) { - if (sdataBuf < 20) return 1; + if (sdataBuf < 20) { + return 1; + } StaticJsonBuffer<400> jsonBuf; JsonObject& domoticz = jsonBuf.parseObject(dataBuf); - if (!domoticz.success()) return 1; -// if (strcmp(domoticz["dtype"],"Light/Switch")) return 1; + if (!domoticz.success()) { + return 1; + } +// if (strcmp(domoticz["dtype"],"Light/Switch")) { +// return 1; +// } idx = domoticz["idx"]; nvalue = domoticz["nvalue"]; @@ -151,16 +165,22 @@ boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uin for (byte i = 0; i < Maxdevice; i++) { if ((idx > 0) && (idx == sysCfg.domoticz_relay_idx[i])) { snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), i +1); - if (nvalue == 2) { + if (2 == nvalue) { nvalue = domoticz["svalue1"]; - if ((pin[GPIO_WS2812] < 99) && (sysCfg.ws_dimmer == nvalue)) return 1; - if ((sysCfg.module == SONOFF_LED) && (sysCfg.led_dimmer[i] == nvalue)) return 1; + if ((pin[GPIO_WS2812] < 99) && (sysCfg.ws_dimmer == nvalue)) { + return 1; + } + if ((SONOFF_LED == sysCfg.module) && (sysCfg.led_dimmer[i] == nvalue)) { + return 1; + } snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/DIMMER%s"), sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp1 : ""); snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue); found = 1; } else { - if (((power >> i) &1) == nvalue) return 1; + if (((power >> i) &1) == nvalue) { + return 1; + } snprintf_P(topicBuf, stopicBuf, PSTR("%s/%s/POWER%s"), sysCfg.mqtt_prefix[0], sysCfg.mqtt_topic, (Maxdevice > 1) ? stemp1 : ""); snprintf_P(dataBuf, sdataBuf, PSTR("%d"), nvalue); @@ -170,7 +190,9 @@ boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uin } } } - if (!found) return 1; + if (!found) { + return 1; + } snprintf_P(log, sizeof(log), PSTR("DMTZ: Receive topic %s, data %s"), topicBuf, dataBuf); addLog(LOG_LEVEL_DEBUG_MORE, log); @@ -191,14 +213,14 @@ boolean domoticz_command(const char *type, uint16_t index, char *dataBuf, uint16 if (!strncmp(type,"DOMOTICZ",8)) { if (!strcmp(type +8,"INTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_in_topic))) { - strlcpy(sysCfg.domoticz_in_topic, (payload == 1) ? DOMOTICZ_IN_TOPIC : dataBuf, sizeof(sysCfg.domoticz_in_topic)); + strlcpy(sysCfg.domoticz_in_topic, (1 == payload) ? DOMOTICZ_IN_TOPIC : dataBuf, sizeof(sysCfg.domoticz_in_topic)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzInTopic\":\"%s\"}"), sysCfg.domoticz_in_topic); } else if (!strcmp(type +8,"OUTTOPIC")) { if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_out_topic))) { - strlcpy(sysCfg.domoticz_out_topic, (payload == 1) ? DOMOTICZ_OUT_TOPIC : dataBuf, sizeof(sysCfg.domoticz_out_topic)); + strlcpy(sysCfg.domoticz_out_topic, (1 == payload) ? DOMOTICZ_OUT_TOPIC : dataBuf, sizeof(sysCfg.domoticz_out_topic)); restartflag = 2; } snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzOutTopic\":\"%s\"}"), sysCfg.domoticz_out_topic); @@ -246,7 +268,7 @@ boolean domoticz_button(byte key, byte device, byte state, byte svalflg) char svalue[80]; // was MESSZ snprintf_P(svalue, sizeof(svalue), PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"), - (key) ? sysCfg.domoticz_switch_idx[device -1] : sysCfg.domoticz_key_idx[device -1], (state) ? (state == 2) ? "Toggle" : "On" : "Off"); + (key) ? sysCfg.domoticz_switch_idx[device -1] : sysCfg.domoticz_key_idx[device -1], (state) ? (2 == state) ? "Toggle" : "On" : "Off"); mqtt_publish(sysCfg.domoticz_in_topic, svalue); return 1; } else { @@ -315,7 +337,7 @@ void domoticz_sensor5(uint16_t lux) #ifdef USE_WEBSERVER void handleDomoticz() { - if (_httpflag == HTTP_USER) { + if (HTTP_USER == _httpflag) { handleRoot(); return; } diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino index 3a31cfa8d..0c2d71a12 100644 --- a/sonoff/xdrv_ir_send.ino +++ b/sonoff/xdrv_ir_send.ino @@ -115,7 +115,9 @@ boolean ir_send_command(char *type, uint16_t index, char *dataBufUc, uint16_t da } else error = true; } } else error = true; - if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"No protocol, bits or data\"}")); + if (error) { + snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"No protocol, bits or data\"}")); + } } #ifdef USE_IR_HVAC else if (!strcmp(type,"IRHVAC")) { @@ -145,7 +147,9 @@ boolean ir_send_command(char *type, uint16_t index, char *dataBufUc, uint16_t da else error = true; } } else error = true; - if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRHVAC\":\"Wrong Vendor, Mode and/or FanSpeed\"}")); + if (error) { + snprintf_P(svalue, ssvalue, PSTR("{\"IRHVAC\":\"Wrong Vendor, Mode and/or FanSpeed\"}")); + } } #endif // USE_IR_HVAC else { @@ -160,7 +164,8 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean unsigned int rawdata[2 + 2*8*HVAC_TOSHIBA_DATALEN + 2]; byte data[HVAC_TOSHIBA_DATALEN] = { 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00 }; - char *p, *token; + char *p; + char *token; uint8_t mode; if (HVAC_Mode == NULL) { @@ -168,19 +173,27 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean } else { p = strchr(HVACMODE, HVAC_Mode[0]); } - if (!p) return true; + if (!p) { + return true; + } data[6] = (p - HVACMODE) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00 - if (!HVAC_Power) data[6] = (byte) 0x07; // Turn OFF HVAC + if (!HVAC_Power) { + data[6] = (byte) 0x07; // Turn OFF HVAC + } if (HVAC_FanMode == NULL) { p = (char*)FANSPEED; // default FAN_SPEED_AUTO } else { p = strchr(FANSPEED, HVAC_FanMode[0]); } - if (!p) return true; + if (!p) { + return true; + } mode = p - FANSPEED +1; - if ((mode == 1) || (mode == 7)) mode = 0; + if ((1 == mode) || (7 == mode)) { + mode = 0; + } mode = mode << 5; // AUTO = 0x00, SPEED = 0x40, 0x60, 0x80, 0xA0, 0xC0, SILENT = 0x00 data[6] = data[6] | mode; @@ -191,7 +204,9 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean else if (HVAC_Temp < 17) { Temp = 17; } - else Temp = HVAC_Temp; + else { + Temp = HVAC_Temp; + } data[5] = (byte) Temp - 17 << 4; data[HVAC_TOSHIBA_DATALEN-1] = 0; @@ -234,7 +249,8 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp) { - char *p, *token; + char *p; + char *token; uint8_t mode; char log[LOGSZ]; @@ -245,7 +261,9 @@ boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boole } else { p = strchr(HVACMODE, HVAC_Mode[0]); } - if (!p) return true; + if (!p) { + return true; + } mode = (p - HVACMODE +1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20 mitsubir->setMode(mode); @@ -256,7 +274,9 @@ boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boole } else { p = strchr(FANSPEED, HVAC_FanMode[0]); } - if (!p) return true; + if (!p) { + return true; + } mode = p - FANSPEED; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6 mitsubir->setFan(mode); diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino index d3802cdb4..b0550a9f1 100644 --- a/sonoff/xdrv_snfled.ino +++ b/sonoff/xdrv_snfled.ino @@ -45,10 +45,11 @@ uint8_t ledTable[] = { 184,186,189,191,193,195,197,199,201,204,206,208,210,212,215,217, 219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 }; -uint8_t sl_dcolor[2], sl_tcolor[2], sl_lcolor[2]; +uint8_t sl_dcolor[2]; +uint8_t sl_tcolor[2]; +uint8_t sl_lcolor[2]; uint8_t sl_power; -uint8_t sl_blankv; uint8_t sl_any; uint8_t sl_wakeupActive = 0; uint8_t sl_wakeupDimmer = 0; @@ -56,17 +57,23 @@ uint16_t sl_wakeupCntr = 0; uint32_t Atoh(char *s) { - uint32_t value = 0, digit; + uint32_t value = 0; + uint32_t digit; int8_t c; - while((c = *s++)){ - if('0' <= c && c <= '9') + while((c = *s++)) { + if ('0' <= c && c <= '9') { digit = c - '0'; - else if('A' <= c && c <= 'F') + } + else if ('A' <= c && c <= 'F') { digit = c - 'A' + 10; - else if('a' <= c && c<= 'f') + } + else if ('a' <= c && c <= 'f') { digit = c - 'a' + 10; - else break; + } + else { + break; + } value = (value << 4) | digit; } return value; @@ -74,11 +81,9 @@ uint32_t Atoh(char *s) void sl_setDim(uint8_t myDimmer) { - float newDim, fmyCld, fmyWrm; - - newDim = 100 / (float)myDimmer; - fmyCld = (float)sysCfg.led_color[0] / newDim; - fmyWrm = (float)sysCfg.led_color[1] / newDim; + float newDim = 100 / (float)myDimmer; + float fmyCld = (float)sysCfg.led_color[0] / newDim; + float fmyWrm = (float)sysCfg.led_color[1] / newDim; sl_dcolor[0] = (uint8_t)fmyCld; sl_dcolor[1] = (uint8_t)fmyWrm; } @@ -89,31 +94,13 @@ void sl_init(void) { sysCfg.pwmvalue[0] = 0; // We use led_color sysCfg.pwmvalue[1] = 0; // We use led_color - sl_blankv = 0; sl_power = 0; sl_any = 0; sl_wakeupActive = 0; } -void sl_blank(byte state) -{ -// Called by interrupt disabling routines like OTA or web upload -// state = 0: No blank -// 1: Blank led to solve flicker - -/* - * Disabled when used with latest arduino-esp8266 pwm files - if (sysCfg.module == SONOFF_LED) { - sl_blankv = state; - sl_wakeupActive = 0; - sl_animate(); - } -*/ -} - void sl_setPower(uint8_t power) { - sl_blankv = 0; sl_power = power &1; sl_wakeupActive = 0; sl_animate(); @@ -125,26 +112,34 @@ void sl_animate() char svalue[32]; // was MESSZ uint8_t fadeValue; - if ((sl_power == 0) || sl_blankv) { // Power Off + if (0 == sl_power) { // Power Off sl_tcolor[0] = 0; sl_tcolor[1] = 0; } else { if (!sl_wakeupActive) { // Power On sl_setDim(sysCfg.led_dimmer[0]); - if (sysCfg.led_fade == 0) { + if (0 == sysCfg.led_fade) { sl_tcolor[0] = sl_dcolor[0]; sl_tcolor[1] = sl_dcolor[1]; } else { if ((sl_tcolor[0] != sl_dcolor[0]) || (sl_tcolor[1] != sl_dcolor[1])) { - if (sl_tcolor[0] < sl_dcolor[0]) sl_tcolor[0] += ((sl_dcolor[0] - sl_tcolor[0]) >> sysCfg.led_speed) +1; - if (sl_tcolor[1] < sl_dcolor[1]) sl_tcolor[1] += ((sl_dcolor[1] - sl_tcolor[1]) >> sysCfg.led_speed) +1; - if (sl_tcolor[0] > sl_dcolor[0]) sl_tcolor[0] -= ((sl_tcolor[0] - sl_dcolor[0]) >> sysCfg.led_speed) +1; - if (sl_tcolor[1] > sl_dcolor[1]) sl_tcolor[1] -= ((sl_tcolor[1] - sl_dcolor[1]) >> sysCfg.led_speed) +1; + if (sl_tcolor[0] < sl_dcolor[0]) { + sl_tcolor[0] += ((sl_dcolor[0] - sl_tcolor[0]) >> sysCfg.led_speed) +1; + } + if (sl_tcolor[1] < sl_dcolor[1]) { + sl_tcolor[1] += ((sl_dcolor[1] - sl_tcolor[1]) >> sysCfg.led_speed) +1; + } + if (sl_tcolor[0] > sl_dcolor[0]) { + sl_tcolor[0] -= ((sl_tcolor[0] - sl_dcolor[0]) >> sysCfg.led_speed) +1; + } + if (sl_tcolor[1] > sl_dcolor[1]) { + sl_tcolor[1] -= ((sl_tcolor[1] - sl_dcolor[1]) >> sysCfg.led_speed) +1; + } } } - } else { // Power On using wak up duration - if (sl_wakeupActive == 1) { + } else { // Power On using wake up duration + if (1 == sl_wakeupActive) { sl_wakeupActive = 2; sl_tcolor[0] = 0; sl_tcolor[1] = 0; @@ -185,11 +180,12 @@ void sl_animate() boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) { - boolean serviced = true, coldim = false; + boolean serviced = true; + boolean coldim = false; if (!strcmp(type,"COLOR")) { uint8_t my_color[5]; - if (data_len == 4) { + if (4 == data_len) { char ccold[3], cwarm[3]; memcpy(ccold, dataBufUc, 2); ccold[2] = '\0'; @@ -198,7 +194,9 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le my_color[0] = Atoh(ccold); my_color[1] = Atoh(cwarm); uint16_t temp = my_color[0]; - if (temp < my_color[1]) temp = my_color[1]; + if (temp < my_color[1]) { + temp = my_color[1]; + } float mDim = (float)temp / 2.55; sysCfg.led_dimmer[0] = (uint8_t)mDim; float newDim = 100 / mDim; @@ -274,8 +272,12 @@ boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_le } if (coldim) { // do_cmnd_power(index, (sysCfg.led_dimmer[0]>0)); - if (sysCfg.led_dimmer[0] && !(power&1)) do_cmnd_power(1, 1); - else if (!sysCfg.led_dimmer[0] && (power&1)) do_cmnd_power(1, 0); + if (sysCfg.led_dimmer[0] && !(power&1)) { + do_cmnd_power(1, 1); + } + else if (!sysCfg.led_dimmer[0] && (power&1)) { + do_cmnd_power(1, 0); + } #ifdef USE_DOMOTICZ mqtt_publishDomoticzPowerState(1); #endif // USE_DOMOTICZ diff --git a/sonoff/xdrv_snfsc.ino b/sonoff/xdrv_snfsc.ino index ef21363f4..a8c849226 100644 --- a/sonoff/xdrv_snfsc.ino +++ b/sonoff/xdrv_snfsc.ino @@ -70,14 +70,19 @@ void sc_init() void sc_rcvstat(char *rcvstat) { - char *p, *str; + char *p; + char *str; uint16_t value[5] = { 0 }; - if (!strncmp(rcvstat,"AT+UPDATE=",10)) { + if (!strncmp(rcvstat, "AT+UPDATE=", 10)) { int8_t i = -1; - for (str = strtok_r(rcvstat, ":", &p); str && i < 5; str = strtok_r(NULL, ":", &p)) value[i++] = atoi(str); + for (str = strtok_r(rcvstat, ":", &p); str && i < 5; str = strtok_r(NULL, ":", &p)) { + value[i++] = atoi(str); + } if (value[0] > 0) { - for (byte i = 0; i < 5; i++) sc_value[i] = value[i]; + for (byte i = 0; i < 5; i++) { + sc_value[i] = value[i]; + } sc_value[2] = (11 - sc_value[2]) * 10; // Invert light level sc_value[3] *= 10; sc_value[4] = (11 - sc_value[4]) * 10; // Invert dust level @@ -103,10 +108,13 @@ float sc_convertCtoF(float c) void sc_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { if (sc_value[0] > 0) { - char stemp1[10], stemp2[10]; + char stemp1[10]; + char stemp2[10]; float t = sc_value[1]; - if (TEMP_CONVERSION) t = sc_convertCtoF(t); + if (TEMP_CONVERSION) { + t = sc_convertCtoF(t); + } dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1); float h = sc_value[0]; dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp2); @@ -126,10 +134,14 @@ String sc_webPresent() String page = ""; if (sc_value[0] > 0) { - char stemp[10], sensor[80], scstype[] = "SC"; + char stemp[10]; + char sensor[80]; + char scstype[] = "SC"; float t = sc_value[1]; - if (TEMP_CONVERSION) t = sc_convertCtoF(t); + if (TEMP_CONVERSION) { + t = sc_convertCtoF(t); + } dtostrf(t, 1, TEMP_RESOLUTION &3, stemp); snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, scstype, stemp, (TEMP_CONVERSION) ? 'F' : 'C'); page += sensor; diff --git a/sonoff/xdrv_wemohue.ino b/sonoff/xdrv_wemohue.ino index f9f31ab99..5092ea6d0 100644 --- a/sonoff/xdrv_wemohue.ino +++ b/sonoff/xdrv_wemohue.ino @@ -53,6 +53,7 @@ const char WEMO_MSEARCH[] PROGMEM = String wemo_serial() { char serial[16]; + snprintf_P(serial, sizeof(serial), PSTR("201612K%08X"), ESP.getChipId()); return String(serial); } @@ -60,13 +61,15 @@ String wemo_serial() String wemo_UUID() { char uuid[27]; + snprintf_P(uuid, sizeof(uuid), PSTR("Socket-1_0-%s"), wemo_serial().c_str()); return String(uuid); } void wemo_respondToMSearch() { - char message[TOPSZ], log[LOGSZ]; + char message[TOPSZ]; + char log[LOGSZ]; if (portUDP.beginPacket(portUDP.remoteIP(), portUDP.remotePort())) { String response = FPSTR(WEMO_MSEARCH); @@ -113,6 +116,7 @@ const char HUE_ST3[] PROGMEM = String hue_bridgeid() { char bridgeid[16]; + snprintf_P(bridgeid, sizeof(bridgeid), PSTR("5CCF7FFFFE%03X"), ESP.getChipId()); return String(bridgeid); } @@ -120,18 +124,20 @@ String hue_bridgeid() String hue_UUID() { char serial[36]; + snprintf_P(serial, sizeof(serial), PSTR("f6543a06-da50-11ba-8d8f-5ccf7f%03x"), ESP.getChipId()); return String(serial); } void hue_respondToMSearch() { - char message[TOPSZ], log[LOGSZ]; + char message[TOPSZ]; + char log[LOGSZ]; if (portUDP.beginPacket(portUDP.remoteIP(), portUDP.remotePort())) { String response = FPSTR(HUE_RESPONSE); - String response_st=FPSTR(HUE_ST1); - String response_usn=FPSTR(HUE_USN1); + String response_st = FPSTR(HUE_ST1); + String response_usn = FPSTR(HUE_USN1); response += response_st + response_usn; response.replace("{r1}", WiFi.localIP().toString()); response.replace("{r2}", hue_bridgeid()); @@ -141,8 +147,8 @@ void hue_respondToMSearch() // addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); response = FPSTR(HUE_RESPONSE); - response_st=FPSTR(HUE_ST2); - response_usn=FPSTR(HUE_USN2); + response_st = FPSTR(HUE_ST2); + response_usn = FPSTR(HUE_USN2); response += response_st + response_usn; response.replace("{r1}", WiFi.localIP().toString()); response.replace("{r2}", hue_bridgeid()); @@ -152,7 +158,7 @@ void hue_respondToMSearch() // addLog(LOG_LEVEL_DEBUG_MORE, response.c_str()); response = FPSTR(HUE_RESPONSE); - response_st=FPSTR(HUE_ST3); + response_st = FPSTR(HUE_ST3); response += response_st + response_usn; response.replace("{r1}", WiFi.localIP().toString()); response.replace("{r2}", hue_bridgeid()); @@ -202,14 +208,16 @@ void pollUDP() if (udpConnected) { if (portUDP.parsePacket()) { int len = portUDP.read(packetBuffer, UDP_BUFFER_SIZE -1); - if (len > 0) packetBuffer[len] = 0; + if (len > 0) { + packetBuffer[len] = 0; + } String request = packetBuffer; // addLog_P(LOG_LEVEL_DEBUG_MORE, packetBuffer); if (request.indexOf("M-SEARCH") >= 0) { - if ((sysCfg.emulation == EMUL_WEMO) &&(request.indexOf("urn:Belkin:device:**") > 0)) { + if ((EMUL_WEMO == sysCfg.emulation) &&(request.indexOf("urn:Belkin:device:**") > 0)) { wemo_respondToMSearch(); } - else if ((sysCfg.emulation == EMUL_HUE) && ((request.indexOf("ST: urn:schemas-upnp-org:device:basic:1") > 0) || (request.indexOf("ST: upnp:rootdevice") > 0) || (request.indexOf("ST: ssdp:all") > 0))) { + else if ((EMUL_HUE == sysCfg.emulation) && ((request.indexOf("ST: urn:schemas-upnp-org:device:basic:1") > 0) || (request.indexOf("ST: upnp:rootdevice") > 0) || (request.indexOf("ST: ssdp:all") > 0))) { hue_respondToMSearch(); } } @@ -340,8 +348,12 @@ void handleUPnPevent() addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle WeMo basic event")); String request = webServer->arg(0); - if (request.indexOf("State>1 0) do_cmnd_power(1, 1); - if (request.indexOf("State>0 0) do_cmnd_power(1, 0); + if (request.indexOf("State>1 0) { + do_cmnd_power(1, 1); + } + if (request.indexOf("State>0 0) { + do_cmnd_power(1, 0); + } webServer->send(200, "text/plain", ""); } @@ -408,12 +420,13 @@ void hue_global_cfg(String *path) path->remove(0,1); // cut leading / to get response = "{\"lights\":{\""; - for (uint8_t i = 1; i <= Maxdevice; i++) - { + for (uint8_t i = 1; i <= Maxdevice; i++) { response += i; response += "\":"; response += FPSTR(HUE_LIGHT_STATUS_JSON); - if (i < Maxdevice) response += ",\""; + if (i < Maxdevice) { + response += ",\""; + } response.replace("{state}", (power & (0x01 << (i-1))) ? "true" : "false"); response.replace("{j1}", sysCfg.friendlyname[i-1]); response.replace("{j2}", hue_deviceId(i)); @@ -421,8 +434,7 @@ void hue_global_cfg(String *path) #ifdef USE_WS2812 ws2812_replaceHSB(&response); #endif // USE_WS2812 - } else - { + } else { response.replace("{h}", "0"); response.replace("{s}", "0"); response.replace("{b}", "0"); @@ -477,7 +489,9 @@ void hue_lights(String *path) response += i; response += "\":"; response += FPSTR(HUE_LIGHT_STATUS_JSON); - if (i < Maxdevice) response += ",\""; + if (i < Maxdevice) { + response += ",\""; + } response.replace("{state}", (power & (0x01 << (i-1))) ? "true" : "false"); response.replace("{j1}", sysCfg.friendlyname[i-1]); response.replace("{j2}", hue_deviceId(i)); @@ -498,13 +512,15 @@ void hue_lights(String *path) path->remove(0,8); // Remove /lights/ path->remove(path->indexOf("/state")); // Remove /state device = atoi(path->c_str()); - if ((device < 1) || (device > Maxdevice)) device = 1; + if ((device < 1) || (device > Maxdevice)) { + device = 1; + } response = "["; response += FPSTR(HUE_LIGHT_RESPONSE_JSON); response.replace("{api}", "/lights"); response.replace("{id}", String(device)); response.replace("{cmd}", "state/on"); - if (webServer->args() == 1) { + if (1 == webServer->args()) { StaticJsonBuffer<400> jsonBuffer; JsonObject &hue_json = jsonBuffer.parseObject(webServer->arg(0)); if (hue_json.containsKey("on")) { @@ -557,8 +573,8 @@ void hue_lights(String *path) change = true; } if (change && (pin[GPIO_WS2812] < 99)) { - ws2812_setHSB(hue,sat,bri); - change=false; + ws2812_setHSB(hue, sat, bri); + change = false; } #endif // USE_WS2812 response += "]"; @@ -572,7 +588,9 @@ void hue_lights(String *path) else if(path->indexOf("/lights/") >= 0) { // Got /lights/ID path->remove(0,8); // Remove /lights/ device = atoi(path->c_str()); - if ((device < 1) || (device > Maxdevice)) device = 1; + if ((device < 1) || (device > Maxdevice)) { + device = 1; + } response = FPSTR(HUE_LIGHT_STATUS_JSON); response.replace("{state}", (power & (0x01 << (device -1))) ? "true" : "false"); response.replace("{j1}", sysCfg.friendlyname[device -1]); diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index 695fad9d6..b598b8a8d 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -108,7 +108,9 @@ uint8_t ledTable[] = { 219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 }; */ uint8_t lany = 0; -RgbColor dcolor, tcolor, lcolor; +RgbColor dcolor; +RgbColor tcolor; +RgbColor lcolor; uint8_t wakeupDimmer = 0; uint16_t wakeupCntr = 0; @@ -128,7 +130,8 @@ void ws2812_setDim(uint8_t myDimmer) void ws2812_setColor(uint16_t led, char* colstr) { HtmlColor hcolor; - char log[LOGSZ], lcolstr[8]; + char log[LOGSZ]; + char lcolstr[8]; snprintf_P(lcolstr, sizeof(lcolstr), PSTR("#%s"), colstr); uint8_t result = hcolor.Parse((char *)lcolstr, 7); @@ -143,8 +146,12 @@ void ws2812_setColor(uint16_t led, char* colstr) // addLog(LOG_LEVEL_DEBUG, log); uint16_t temp = dcolor.R; - if (temp < dcolor.G) temp = dcolor.G; - if (temp < dcolor.B) temp = dcolor.B; + if (temp < dcolor.G) { + temp = dcolor.G; + } + if (temp < dcolor.B) { + temp = dcolor.B; + } float mDim = (float)temp / 2.55; sysCfg.ws_dimmer = (uint8_t)mDim; @@ -164,7 +171,7 @@ void ws2812_setColor(uint16_t led, char* colstr) void ws2812_replaceHSB(String *response) { ws2812_setDim(sysCfg.ws_dimmer); - HsbColor hsb=HsbColor(dcolor); + HsbColor hsb = HsbColor(dcolor); response->replace("{h}", String((uint16_t)(65535.0f * hsb.H))); response->replace("{s}", String((uint8_t)(254.0f * hsb.S))); response->replace("{b}", String((uint8_t)(254.0f * hsb.B))); @@ -173,10 +180,10 @@ void ws2812_replaceHSB(String *response) void ws2812_getHSB(float *hue, float *sat, float *bri) { ws2812_setDim(sysCfg.ws_dimmer); - HsbColor hsb=HsbColor(dcolor); - *hue=hsb.H; - *sat=hsb.S; - *bri=hsb.B; + HsbColor hsb = HsbColor(dcolor); + *hue = hsb.H; + *sat = hsb.S; + *bri = hsb.B; } void ws2812_setHSB(float hue, float sat, float bri) @@ -184,9 +191,9 @@ void ws2812_setHSB(float hue, float sat, float bri) char rgb[7]; HsbColor hsb; - hsb.H=hue; - hsb.S=sat; - hsb.B=bri; + hsb.H = hue; + hsb.S = sat; + hsb.B = bri; RgbColor tmp = RgbColor(hsb); sprintf(rgb,"%02X%02X%02X", tmp.R, tmp.G, tmp.B); ws2812_setColor(0,rgb); @@ -238,7 +245,9 @@ void ws2812_resetStripTimer() int mod(int a, int b) { int ret = a % b; - if (ret < 0) ret += b; + if (ret < 0) { + ret += b; + } return ret; } @@ -308,7 +317,9 @@ void ws2812_gradient() RgbColor c; ColorScheme scheme = schemes[sysCfg.ws_scheme -3]; - if (scheme.count < 2) return; + if (scheme.count < 2) { + return; + } uint8_t repeat = repeatValues[sysCfg.ws_width]; // number of scheme.count per ledcount uint8_t range = (uint8_t)ceil((float)sysCfg.ws_pixels / (float)repeat); @@ -319,7 +330,9 @@ void ws2812_gradient() ws2812_gradientColor(&oldColor, range, gradRange, offset); currentColor = oldColor; for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) { - if (repeatValues[sysCfg.ws_width] > 1) ws2812_gradientColor(¤tColor, range, gradRange, i +offset); + if (repeatValues[sysCfg.ws_width] > 1) { + ws2812_gradientColor(¤tColor, range, gradRange, i +offset); + } if (sysCfg.ws_speed > 0) { // Blend old and current color based on time for smooth movement. c.R = map(stripTimerCntr % speedValues[sysCfg.ws_speed], 0, speedValues[sysCfg.ws_speed], oldColor.red, currentColor.red); @@ -351,7 +364,9 @@ void ws2812_bars() ColorScheme scheme = schemes[sysCfg.ws_scheme -3]; uint8_t maxSize = sysCfg.ws_pixels / scheme.count; - if (widthValues[sysCfg.ws_width] > maxSize) maxSize = 0; + if (widthValues[sysCfg.ws_width] > maxSize) { + maxSize = 0; + } uint8_t offset = speedValues[sysCfg.ws_speed] > 0 ? stripTimerCntr / speedValues[sysCfg.ws_speed] : 0; @@ -368,8 +383,9 @@ void ws2812_bars() } uint8_t colorIndex = offset % scheme.count; for (i = 0; i < sysCfg.ws_pixels; i++) { - if (maxSize) + if (maxSize) { colorIndex = ((i + offset) % (scheme.count * widthValues[sysCfg.ws_width])) / widthValues[sysCfg.ws_width]; + } c.R = mcolor[colorIndex].red; c.G = mcolor[colorIndex].green; c.B = mcolor[colorIndex].blue; @@ -384,7 +400,7 @@ void ws2812_animate() uint8_t fadeValue; stripTimerCntr++; - if (power == 0) { // Power Off + if (0 == power) { // Power Off sleep = sysCfg.sleep; stripTimerCntr = 0; tcolor = 0; @@ -394,22 +410,34 @@ void ws2812_animate() switch (sysCfg.ws_scheme) { case 0: // Power On ws2812_setDim(sysCfg.ws_dimmer); - if (sysCfg.ws_fade == 0) { + if (0 == sysCfg.ws_fade) { tcolor = dcolor; } else { if (tcolor != dcolor) { - if (tcolor.R < dcolor.R) tcolor.R += ((dcolor.R - tcolor.R) >> sysCfg.ws_speed) +1; - if (tcolor.G < dcolor.G) tcolor.G += ((dcolor.G - tcolor.G) >> sysCfg.ws_speed) +1; - if (tcolor.B < dcolor.B) tcolor.B += ((dcolor.B - tcolor.B) >> sysCfg.ws_speed) +1; - if (tcolor.R > dcolor.R) tcolor.R -= ((tcolor.R - dcolor.R) >> sysCfg.ws_speed) +1; - if (tcolor.G > dcolor.G) tcolor.G -= ((tcolor.G - dcolor.G) >> sysCfg.ws_speed) +1; - if (tcolor.B > dcolor.B) tcolor.B -= ((tcolor.B - dcolor.B) >> sysCfg.ws_speed) +1; + if (tcolor.R < dcolor.R) { + tcolor.R += ((dcolor.R - tcolor.R) >> sysCfg.ws_speed) +1; + } + if (tcolor.G < dcolor.G) { + tcolor.G += ((dcolor.G - tcolor.G) >> sysCfg.ws_speed) +1; + } + if (tcolor.B < dcolor.B) { + tcolor.B += ((dcolor.B - tcolor.B) >> sysCfg.ws_speed) +1; + } + if (tcolor.R > dcolor.R) { + tcolor.R -= ((tcolor.R - dcolor.R) >> sysCfg.ws_speed) +1; + } + if (tcolor.G > dcolor.G) { + tcolor.G -= ((tcolor.G - dcolor.G) >> sysCfg.ws_speed) +1; + } + if (tcolor.B > dcolor.B) { + tcolor.B -= ((tcolor.B - dcolor.B) >> sysCfg.ws_speed) +1; + } } } break; case 1: // Wake up light wakeupCntr++; - if (wakeupDimmer == 0) { + if (0 == wakeupDimmer) { tcolor = 0; wakeupDimmer++; } @@ -426,11 +454,17 @@ void ws2812_animate() } break; case 2: // Clock - if ((state == (STATES/10)*2) || (lany != 2)) ws2812_clock(); + if (((STATES/10)*2 == state) || (lany != 2)) { + ws2812_clock(); + } lany = 2; break; default: - if (sysCfg.ws_fade == 1) ws2812_gradient(); else ws2812_bars(); + if (1 == sysCfg.ws_fade) { + ws2812_gradient(); + } else { + ws2812_bars(); + } lany = 1; break; } @@ -445,9 +479,13 @@ void ws2812_animate() // addLog(LOG_LEVEL_DEBUG, log); if (sysCfg.ws_ledtable) { - for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) strip->SetPixelColor(i, RgbColor(ledTable[lcolor.R],ledTable[lcolor.G],ledTable[lcolor.B])); + for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) { + strip->SetPixelColor(i, RgbColor(ledTable[lcolor.R],ledTable[lcolor.G],ledTable[lcolor.B])); + } } else { - for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) strip->SetPixelColor(i, lcolor); + for (uint16_t i = 0; i < sysCfg.ws_pixels; i++) { + strip->SetPixelColor(i, lcolor); + } } strip->Show(); } @@ -502,14 +540,14 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_ snprintf_P(svalue, ssvalue, PSTR("{\"Pixels\":%d}"), sysCfg.ws_pixels); } else if (!strcmp(type,"LED") && (index > 0) && (index <= sysCfg.ws_pixels)) { - if (data_len == 6) { + if (6 == data_len) { // ws2812_setColor(index, dataBufUc); ws2812_setColor(index, dataBuf); } ws2812_getColor(index, svalue, ssvalue); } else if (!strcmp(type,"COLOR")) { - if (data_len == 6) { + if (6 == data_len) { // ws2812_setColor(0, dataBufUc); ws2812_setColor(0, dataBuf); power = 1; @@ -570,14 +608,18 @@ boolean ws2812_command(char *type, uint16_t index, char *dataBuf, uint16_t data_ else if (!strcmp(type,"WAKEUP")) { if ((data_len > 0) && (payload > 0) && (payload < 3601)) { sysCfg.ws_wakeup = payload; - if (sysCfg.ws_scheme == 1) sysCfg.ws_scheme = 0; + if (1 == sysCfg.ws_scheme) { + sysCfg.ws_scheme = 0; + } } snprintf_P(svalue, ssvalue, PSTR("{\"WakeUp\":%d}"), sysCfg.ws_wakeup); } else if (!strcmp(type,"SCHEME")) { if ((data_len > 0) && (payload >= 0) && (payload <= 9)) { sysCfg.ws_scheme = payload; - if (sysCfg.ws_scheme == 1) ws2812_resetWakupState(); + if (1 == sysCfg.ws_scheme) { + ws2812_resetWakupState(); + } power = 1; ws2812_resetStripTimer(); } diff --git a/sonoff/xsns_bh1750.ino b/sonoff/xsns_bh1750.ino index 93292d60a..6247f9a00 100644 --- a/sonoff/xsns_bh1750.ino +++ b/sonoff/xsns_bh1750.ino @@ -34,7 +34,8 @@ POSSIBILITY OF SUCH DAMAGE. #define BH1750_CONTINUOUS_HIGH_RES_MODE 0x10 // Start measurement at 1lx resolution. Measurement time is approx 120ms. -uint8_t bh1750addr, bh1750type = 0; +uint8_t bh1750addr; +uint8_t bh1750type = 0; char bh1750stype[7]; uint16_t bh1750_readLux(void) @@ -48,7 +49,9 @@ uint16_t bh1750_readLux(void) boolean bh1750_detect() { - if (bh1750type) return true; + if (bh1750type) { + return true; + } char log[LOGSZ]; uint8_t status; @@ -84,7 +87,9 @@ boolean bh1750_detect() void bh1750_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { - if (!bh1750type) return; + if (!bh1750type) { + return; + } uint16_t l = bh1750_readLux(); snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Illuminance\":%d}"), svalue, bh1750stype, l); diff --git a/sonoff/xsns_bmp.ino b/sonoff/xsns_bmp.ino index 1bc472222..391cba0a2 100644 --- a/sonoff/xsns_bmp.ino +++ b/sonoff/xsns_bmp.ino @@ -39,7 +39,8 @@ #define BMP_REGISTER_CHIPID 0xD0 -uint8_t bmpaddr, bmptype = 0; +uint8_t bmpaddr; +uint8_t bmptype = 0; char bmpstype[7]; /*********************************************************************************************\ @@ -67,8 +68,16 @@ char bmpstype[7]; #define BMP180_OSS 3 -int16_t cal_ac1,cal_ac2,cal_ac3,cal_b1,cal_b2,cal_mc,cal_md; -uint16_t cal_ac4,cal_ac5,cal_ac6; +int16_t cal_ac1; +int16_t cal_ac2; +int16_t cal_ac3; +int16_t cal_b1; +int16_t cal_b2; +int16_t cal_mc; +int16_t cal_md; +uint16_t cal_ac4; +uint16_t cal_ac5; +uint16_t cal_ac6; int32_t bmp180_b5 = 0; boolean bmp180_calibration() @@ -85,21 +94,22 @@ boolean bmp180_calibration() cal_md = i2c_read16(bmpaddr, BMP180_MD); // Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF - if(!cal_ac1 | !cal_ac2 | !cal_ac3 | !cal_ac4 | !cal_ac5 | - !cal_ac6 | !cal_b1 | !cal_b2 | !cal_mc | !cal_md) - return false; + if (!cal_ac1 | !cal_ac2 | !cal_ac3 | !cal_ac4 | !cal_ac5 | !cal_ac6 | !cal_b1 | !cal_b2 | !cal_mc | !cal_md) { + return false; + } - if((cal_ac1==0xFFFF)| - (cal_ac2==0xFFFF)| - (cal_ac3==0xFFFF)| - (cal_ac4==0xFFFF)| - (cal_ac5==0xFFFF)| - (cal_ac6==0xFFFF)| - (cal_b1==0xFFFF)| - (cal_b2==0xFFFF)| - (cal_mc==0xFFFF)| - (cal_md==0xFFFF)) - return false; + if ((cal_ac1 == 0xFFFF)| + (cal_ac2 == 0xFFFF)| + (cal_ac3 == 0xFFFF)| + (cal_ac4 == 0xFFFF)| + (cal_ac5 == 0xFFFF)| + (cal_ac6 == 0xFFFF)| + (cal_b1 == 0xFFFF)| + (cal_b2 == 0xFFFF)| + (cal_mc == 0xFFFF)| + (cal_md == 0xFFFF)) { + return false; + } return true; } @@ -119,7 +129,9 @@ double bmp180_readTemperature() double bmp180_readPressure() { int32_t p; - uint8_t msb,lsb,xlsb; + uint8_t msb; + uint8_t lsb; + uint8_t xlsb; i2c_write8(bmpaddr, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution @@ -268,7 +280,8 @@ boolean bme280_calibrate() double bmp280_readTemperature(void) { - int32_t var1, var2; + int32_t var1; + int32_t var2; int32_t adc_T = i2c_read24(bmpaddr, BME280_REGISTER_TEMPDATA); adc_T >>= 4; @@ -283,7 +296,9 @@ double bmp280_readTemperature(void) double bmp280_readPressure(void) { - int64_t var1, var2, p; + int64_t var1; + int64_t var2; + int64_t p; // Must be done first to get the t_fine variable set up // bmp280_readTemperature(); @@ -297,7 +312,7 @@ double bmp280_readPressure(void) var2 = var2 + (((int64_t)_bme280_calib.dig_P4) << 35); var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) >> 8) + ((var1 * (int64_t)_bme280_calib.dig_P2) << 12); var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)_bme280_calib.dig_P1) >> 33; - if (var1 == 0) { + if (0 == var1) { return 0; // avoid exception caused by division by zero } p = 1048576 - adc_P; @@ -354,7 +369,9 @@ double bmp_readTemperature(bool S) t = bmp280_readTemperature(); } if (!isnan(t)) { - if(S) t = bmp_convertCtoF(t); + if (S) { + t = bmp_convertCtoF(t); + } return t; } return 0; @@ -386,7 +403,9 @@ double bmp_readHumidity(void) boolean bmp_detect() { - if (bmptype) return true; + if (bmptype) { + return true; + } char log[LOGSZ]; boolean success = false; @@ -426,9 +445,13 @@ boolean bmp_detect() void bmp_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { - if (!bmptype) return; + if (!bmptype) { + return; + } - char stemp1[10], stemp2[10], stemp3[10]; + char stemp1[10]; + char stemp2[10]; + char stemp3[10]; double t = bmp_readTemperature(TEMP_CONVERSION); double p = bmp_readPressure(); @@ -454,7 +477,8 @@ String bmp_webPresent() { String page = ""; if (bmptype) { - char stemp[10], sensor[80]; + char stemp[10]; + char sensor[80]; double t_bmp = bmp_readTemperature(TEMP_CONVERSION); double p_bmp = bmp_readPressure(); diff --git a/sonoff/xsns_dht.ino b/sonoff/xsns_dht.ino index ddab80c70..d391bad1b 100644 --- a/sonoff/xsns_dht.ino +++ b/sonoff/xsns_dht.ino @@ -36,9 +36,11 @@ POSSIBILITY OF SUCH DAMAGE. uint8_t data[5]; char dhtstype[7]; -uint32_t _lastreadtime, _maxcycles; +uint32_t _lastreadtime; +uint32_t _maxcycles; bool _lastresult; -float mt, mh = 0; +float mt; +float mh = 0; void dht_readPrep() { @@ -49,8 +51,11 @@ uint32_t dht_expectPulse(bool level) { uint32_t count = 0; - while (digitalRead(pin[GPIO_DHT11]) == level) - if (count++ >= _maxcycles) return 0; + while (digitalRead(pin[GPIO_DHT11]) == level) { + if (count++ >= _maxcycles) { + return 0; + } + } return count; } @@ -79,17 +84,17 @@ boolean dht_read() delayMicroseconds(40); pinMode(pin[GPIO_DHT11], INPUT_PULLUP); delayMicroseconds(10); - if (dht_expectPulse(LOW) == 0) { + if (0 == dht_expectPulse(LOW)) { addLog_P(LOG_LEVEL_DEBUG, PSTR("DHT: Timeout waiting for start signal low pulse")); _lastresult = false; return _lastresult; } - if (dht_expectPulse(HIGH) == 0) { + if (0 == dht_expectPulse(HIGH)) { addLog_P(LOG_LEVEL_DEBUG, PSTR("DHT: Timeout waiting for start signal high pulse")); _lastresult = false; return _lastresult; } - for (int i=0; i<80; i+=2) { + for (int i = 0; i < 80; i += 2) { cycles[i] = dht_expectPulse(LOW); cycles[i+1] = dht_expectPulse(HIGH); } @@ -98,13 +103,15 @@ boolean dht_read() for (int i=0; i<40; ++i) { uint32_t lowCycles = cycles[2*i]; uint32_t highCycles = cycles[2*i+1]; - if ((lowCycles == 0) || (highCycles == 0)) { + if ((0 == lowCycles) || (0 == highCycles)) { addLog_P(LOG_LEVEL_DEBUG, PSTR("DHT: Timeout waiting for pulse")); _lastresult = false; return _lastresult; } data[i/8] <<= 1; - if (highCycles > lowCycles) data[i/8] |= 1; + if (highCycles > lowCycles) { + data[i/8] |= 1; + } } snprintf_P(log, sizeof(log), PSTR("DHT: Received %02X, %02X, %02X, %02X, %02X =? %02X"), @@ -141,7 +148,9 @@ boolean dht_readTempHum(bool S, float &t, float &h) case GPIO_DHT11: h = data[0]; t = data[2]; - if(S) t = dht_convertCtoF(t); + if (S) { + t = dht_convertCtoF(t); + } break; case GPIO_DHT22: case GPIO_DHT21: @@ -153,12 +162,20 @@ boolean dht_readTempHum(bool S, float &t, float &h) t *= 256; t += data[3]; t *= 0.1; - if (data[2] & 0x80) t *= -1; - if(S) t = dht_convertCtoF(t); + if (data[2] & 0x80) { + t *= -1; + } + if (S) { + t = dht_convertCtoF(t); + } break; } - if (!isnan(t)) mt = t; - if (!isnan(h)) mh = h; + if (!isnan(t)) { + mt = t; + } + if (!isnan(h)) { + mh = h; + } } return (!isnan(t) && !isnan(h)); } @@ -192,8 +209,10 @@ void dht_init() void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { - char stemp1[10], stemp2[10]; - float t, h; + char stemp1[10]; + char stemp2[10]; + float t; + float h; if (dht_readTempHum(TEMP_CONVERSION, t, h)) { // Read temperature dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1); @@ -212,10 +231,13 @@ void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) String dht_webPresent() { String page = ""; - float t, h; + float t; + float h; if (dht_readTempHum(TEMP_CONVERSION, t, h)) { // Read temperature as Celsius (the default) - char stemp[10], sensor[80]; + char stemp[10]; + char sensor[80]; + dtostrf(t, 1, TEMP_RESOLUTION &3, stemp); snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, dhtstype, stemp, (TEMP_CONVERSION) ? 'F' : 'C'); page += sensor; diff --git a/sonoff/xsns_ds18b20.ino b/sonoff/xsns_ds18b20.ino index 3735d9a36..b84ff0857 100644 --- a/sonoff/xsns_ds18b20.ino +++ b/sonoff/xsns_ds18b20.ino @@ -39,7 +39,9 @@ uint8_t dsb_reset() pinMode(pin[GPIO_DSB], INPUT); do { // wait until the wire is high... just in case - if (--retries == 0) return 0; + if (--retries == 0) { + return 0; + } delayMicroseconds(2); } while (!digitalRead(pin[GPIO_DSB])); pinMode(pin[GPIO_DSB], OUTPUT); @@ -71,8 +73,11 @@ uint8_t dsb_read(void) uint8_t bitMask; uint8_t r = 0; - for (bitMask = 0x01; bitMask; bitMask <<= 1) - if (dsb_read_bit()) r |= bitMask; + for (bitMask = 0x01; bitMask; bitMask <<= 1) { + if (dsb_read_bit()) { + r |= bitMask; + } + } return r; } @@ -97,8 +102,9 @@ void dsb_write(uint8_t ByteToWrite) { uint8_t bitMask; - for (bitMask = 0x01; bitMask; bitMask <<= 1) + for (bitMask = 0x01; bitMask; bitMask <<= 1) { dsb_write_bit((bitMask & ByteToWrite) ? 1 : 0); + } } uint8 dsb_crc(uint8 inp, uint8 crc) @@ -173,7 +179,9 @@ boolean dsb_readTemp(bool S, float &t) sign = -1; } t = (float)sign * DSTemp * 0.0625; - if(S) t = dsb_convertCtoF(t); + if(S) { + t = dsb_convertCtoF(t); + } } if (!isnan(t)) dsb_mt = t; return !isnan(t); @@ -206,7 +214,9 @@ String dsb_webPresent() float st; if (dsb_readTemp(TEMP_CONVERSION, st)) { // Check if read failed - char stemp[10], sensor[80]; + char stemp[10]; + char sensor[80]; + dtostrf(st, 1, TEMP_RESOLUTION &3, stemp); snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, "DS18B20", stemp, (TEMP_CONVERSION) ? 'F' : 'C'); page += sensor; diff --git a/sonoff/xsns_ds18x20.ino b/sonoff/xsns_ds18x20.ino index 6fc3fec89..8afc60863 100644 --- a/sonoff/xsns_ds18x20.ino +++ b/sonoff/xsns_ds18x20.ino @@ -59,18 +59,20 @@ void ds18x20_search() uint8_t i; ds->reset_search(); - for (num_sensors = 0; num_sensors < DS18X20_MAX_SENSORS; num_sensors) - { + for (num_sensors = 0; num_sensors < DS18X20_MAX_SENSORS; num_sensors) { if (!ds->search(ds18x20_addr[num_sensors])) { ds->reset_search(); break; } // If CRC Ok and Type DS18S20, DS18B20 or MAX31850 if ((OneWire::crc8(ds18x20_addr[num_sensors], 7) == ds18x20_addr[num_sensors][7]) && - ((ds18x20_addr[num_sensors][0]==DS18S20_CHIPID) || (ds18x20_addr[num_sensors][0]==DS18B20_CHIPID) || (ds18x20_addr[num_sensors][0]==MAX31850_CHIPID))) - num_sensors++; + ((ds18x20_addr[num_sensors][0]==DS18S20_CHIPID) || (ds18x20_addr[num_sensors][0]==DS18B20_CHIPID) || (ds18x20_addr[num_sensors][0]==MAX31850_CHIPID))) { + num_sensors++; + } + } + for (int i = 0; i < num_sensors; i++) { + ds18x20_idx[i] = i; } - for (int i = 0; i < num_sensors; i++) ds18x20_idx[i] = i; for (int i = 0; i < num_sensors; i++) { for (int j = i + 1; j < num_sensors; j++) { if (uint32_t(ds18x20_addr[ds18x20_idx[i]]) > uint32_t(ds18x20_addr[ds18x20_idx[j]])) { @@ -91,7 +93,9 @@ String ds18x20_address(uint8_t sensor) char addrStr[20]; uint8_t i; - for (i = 0; i < 8; i++) sprintf(addrStr+2*i, "%02X", ds18x20_addr[ds18x20_idx[sensor]][i]); + for (i = 0; i < 8; i++) { + sprintf(addrStr+2*i, "%02X", ds18x20_addr[ds18x20_idx[sensor]][i]); + } return String(addrStr); } @@ -122,7 +126,9 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t) ds->select(ds18x20_addr[ds18x20_idx[sensor]]); ds->write(W1_READ_SCRATCHPAD); // Read Scratchpad - for (i = 0; i < 9; i++) data[i] = ds->read(); + for (i = 0; i < 9; i++) { + data[i] = ds->read(); + } if (OneWire::crc8(data, 8) == data[8]) { switch(ds18x20_addr[ds18x20_idx[sensor]][0]) { case DS18S20_CHIPID: // DS18S20 @@ -150,7 +156,9 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t) temp9 = (data[0] >> 1) * sign; } t = (temp9 - 0.25) + ((16.0 - data[6]) / 16.0); - if(S) t = ds18x20_convertCtoF(t); + if(S) { + t = ds18x20_convertCtoF(t); + } break; case DS18B20_CHIPID: // DS18B20 case MAX31850_CHIPID: // MAX31850 @@ -160,7 +168,9 @@ boolean ds18x20_read(uint8_t sensor, bool S, float &t) sign = -1; } t = sign * temp12 * 0.0625; - if(S) t = ds18x20_convertCtoF(t); + if(S) { + t = ds18x20_convertCtoF(t); + } break; } } @@ -189,7 +199,8 @@ void ds18x20_type(uint8_t sensor) void ds18x20_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { - char stemp1[10], stemp2[10]; + char stemp1[10]; + char stemp2[10]; float t; byte dsxflg = 0; @@ -211,14 +222,18 @@ void ds18x20_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) #endif // USE_DOMOTICZ } } - if (dsxflg) snprintf_P(svalue, ssvalue, PSTR("%s}"), svalue); + if (dsxflg) { + snprintf_P(svalue, ssvalue, PSTR("%s}"), svalue); + } } #ifdef USE_WEBSERVER String ds18x20_webPresent() { String page = ""; - char stemp[10], stemp2[16], sensor[80]; + char stemp[10]; + char stemp2[16]; + char sensor[80]; float t; for (byte i = 0; i < ds18x20_sensors(); i++) { diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino index bc5db1f4c..a64e521e7 100644 --- a/sonoff/xsns_hlw8012.ino +++ b/sonoff/xsns_hlw8012.ino @@ -53,13 +53,26 @@ byte hlw_mkwh_state = 0; uint16_t hlw_mplw_counter = 0; #endif // FEATURE_POWER_LIMIT -byte hlw_SELflag, hlw_cf_timer, hlw_cf1_timer, hlw_fifth_second, hlw_startup; -unsigned long hlw_cf_plen, hlw_cf_last; -unsigned long hlw_cf1_plen, hlw_cf1_last, hlw_cf1_ptot, hlw_cf1_pcnt, hlw_cf1u_plen, hlw_cf1i_plen; -unsigned long hlw_Ecntr, hlw_EDcntr, hlw_kWhtoday; +byte hlw_SELflag; +byte hlw_cf_timer; +byte hlw_cf1_timer; +byte hlw_fifth_second; +byte hlw_startup; +unsigned long hlw_cf_plen; +unsigned long hlw_cf_last; +unsigned long hlw_cf1_plen; +unsigned long hlw_cf1_last; +unsigned long hlw_cf1_ptot; +unsigned long hlw_cf1_pcnt; +unsigned long hlw_cf1u_plen; +unsigned long hlw_cf1i_plen; +unsigned long hlw_Ecntr; +unsigned long hlw_EDcntr; +unsigned long hlw_kWhtoday; uint32_t hlw_lasttime; -unsigned long hlw_cf1u_pcntmax, hlw_cf1i_pcntmax; +unsigned long hlw_cf1u_pcntmax; +unsigned long hlw_cf1i_pcntmax; Ticker tickerHLW; @@ -72,7 +85,9 @@ void hlw_cf_interrupt() // Service Power { hlw_cf_plen = micros() - hlw_cf_last; hlw_cf_last = micros(); - if (hlw_cf_plen > 4000000) hlw_cf_plen = 0; // Just powered on + if (hlw_cf_plen > 4000000) { + hlw_cf_plen = 0; // Just powered on + } hlw_cf_timer = 15; // Support down to 4W which takes about 3 seconds hlw_EDcntr++; hlw_Ecntr++; @@ -85,16 +100,19 @@ void hlw_cf1_interrupt() // Service Voltage and Current if ((hlw_cf1_timer > 2) && (hlw_cf1_timer < 8)) { // Allow for 300 mSec set-up time and measure for up to 1 second hlw_cf1_ptot += hlw_cf1_plen; hlw_cf1_pcnt++; - if (hlw_cf1_pcnt == 10) hlw_cf1_timer = 8; // We need up to ten samples within 1 second (low current could take up to 0.3 second) + if (10 == hlw_cf1_pcnt) { + hlw_cf1_timer = 8; // We need up to ten samples within 1 second (low current could take up to 0.3 second) + } } } void hlw_200mS() { - unsigned long hlw_len, hlw_temp; + unsigned long hlw_len; + unsigned long hlw_temp; hlw_fifth_second++; - if (hlw_fifth_second == 5) { + if (5 == hlw_fifth_second) { hlw_fifth_second = 0; if (hlw_EDcntr) { @@ -111,7 +129,7 @@ void hlw_200mS() rtcMem.hlw_kWhtoday = hlw_kWhtoday; hlw_mkwh_state = 3; } - if ((rtcTime.Hour == sysCfg.hlw_mkwhs) && (hlw_mkwh_state == 3)) { + if ((rtcTime.Hour == sysCfg.hlw_mkwhs) && (3 == hlw_mkwh_state)) { hlw_mkwh_state = 0; } if (hlw_startup && (rtcTime.DayOfYear == sysCfg.hlw_kWhdoy)) { @@ -124,7 +142,9 @@ void hlw_200mS() if (hlw_cf_timer) { hlw_cf_timer--; - if (!hlw_cf_timer) hlw_cf_plen = 0; // No load for over three seconds + if (!hlw_cf_timer) { + hlw_cf_plen = 0; // No load for over three seconds + } } hlw_cf1_timer++; @@ -158,8 +178,13 @@ void hlw_savestate() boolean hlw_readEnergy(byte option, float &ed, uint16_t &e, uint16_t &w, uint16_t &u, float &i, float &c) { - unsigned long hlw_len, hlw_temp, hlw_w, hlw_u, hlw_i; - int hlw_period, hlw_interval; + unsigned long hlw_len; + unsigned long hlw_temp; + unsigned long hlw_w; + unsigned long hlw_u; + unsigned long hlw_i; + int hlw_period; + int hlw_interval; //char log[LOGSZ]; //snprintf_P(log, sizeof(log), PSTR("HLW: CF %d, CF1U %d (%d), CF1I %d (%d)"), hlw_cf_plen, hlw_cf1u_plen, hlw_cf1u_pcntmax, hlw_cf1i_plen, hlw_cf1i_pcntmax); @@ -222,7 +247,7 @@ boolean hlw_readEnergy(byte option, float &ed, uint16_t &e, uint16_t &w, uint16_ void hlw_init() { - if (!sysCfg.hlw_pcal || (sysCfg.hlw_pcal == 4975)) { + if (!sysCfg.hlw_pcal || (4975 == sysCfg.hlw_pcal)) { sysCfg.hlw_pcal = HLW_PREF_PULSE; sysCfg.hlw_ucal = HLW_UREF_PULSE; sysCfg.hlw_ical = HLW_IREF_PULSE; @@ -264,7 +289,9 @@ boolean hlw_margin(byte type, uint16_t margin, uint16_t value, byte &flag, byte { byte change; - if (!margin) return false; + if (!margin) { + return false; + } change = saveflag; if (type) { flag = (value > margin); @@ -282,10 +309,18 @@ void hlw_setPowerSteadyCounter(byte value) void hlw_margin_chk() { - char log[LOGSZ], svalue[200]; // was MESSZ - float ped, pi, pc; - uint16_t uped, piv, pe, pw, pu; - boolean flag, jsonflg; + char log[LOGSZ]; + char svalue[200]; // was MESSZ + float ped; + float pi; + float pc; + uint16_t uped; + uint16_t piv; + uint16_t pe; + uint16_t pw; + uint16_t pu; + boolean flag; + boolean jsonflg; if (power_steady_cntr) { power_steady_cntr--; @@ -343,7 +378,9 @@ void hlw_margin_chk() snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxPowerReached\":\"%d%s\"}"), pw, (sysCfg.value_units) ? " W" : ""); mqtt_publish_topic_P(0, PSTR("WARNING"), svalue); do_cmnd_power(1, 0); - if (!hlw_mplr_counter) hlw_mplr_counter = MAX_POWER_RETRY +1; + if (!hlw_mplr_counter) { + hlw_mplr_counter = MAX_POWER_RETRY +1; + } hlw_mplw_counter = sysCfg.hlw_mplw; } } @@ -381,7 +418,7 @@ void hlw_margin_chk() mqtt_publish_topic_P(4, PSTR("ENERGYMONITOR"), svalue); do_cmnd_power(1, 1); } - else if ((hlw_mkwh_state == 1) && (uped >= sysCfg.hlw_mkwh)) { + else if ((1 == hlw_mkwh_state) && (uped >= sysCfg.hlw_mkwh)) { hlw_mkwh_state = 2; dtostrf(ped, 1, 3, svalue); snprintf_P(svalue, sizeof(svalue), PSTR("{\"MaxEnergyReached\":\"%s%s\"}"), svalue, (sysCfg.value_units) ? " kWh" : ""); @@ -463,13 +500,13 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len } else if (!strcmp(type,"MAXPOWERHOLD")) { if ((data_len > 0) && (payload >= 0) && (payload < 3601)) { - sysCfg.hlw_mplh = (payload == 1) ? MAX_POWER_HOLD : payload; + sysCfg.hlw_mplh = (1 == payload) ? MAX_POWER_HOLD : payload; } snprintf_P(svalue, ssvalue, PSTR("{\"MaxPowerHold\":\"%d%s\"}"), sysCfg.hlw_mplh, (sysCfg.value_units) ? " Sec" : ""); } else if (!strcmp(type,"MAXPOWERWINDOW")) { if ((data_len > 0) && (payload >= 0) && (payload < 3601)) { - sysCfg.hlw_mplw = (payload == 1) ? MAX_POWER_WINDOW : payload; + sysCfg.hlw_mplw = (1 == payload) ? MAX_POWER_WINDOW : payload; } snprintf_P(svalue, ssvalue, PSTR("{\"MaxPowerWindow\":\"%d%s\"}"), sysCfg.hlw_mplw, (sysCfg.value_units) ? " Sec" : ""); } @@ -481,13 +518,13 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len } else if (!strcmp(type,"SAFEPOWERHOLD")) { if ((data_len > 0) && (payload >= 0) && (payload < 3601)) { - sysCfg.hlw_msplh = (payload == 1) ? SAFE_POWER_HOLD : payload; + sysCfg.hlw_msplh = (1 == payload) ? SAFE_POWER_HOLD : payload; } snprintf_P(svalue, ssvalue, PSTR("{\"SafePowerHold\":\"%d%s\"}"), sysCfg.hlw_msplh, (sysCfg.value_units) ? " Sec" : ""); } else if (!strcmp(type,"SAFEPOWERWINDOW")) { if ((data_len > 0) && (payload >= 0) && (payload < 1440)) { - sysCfg.hlw_msplw = (payload == 1) ? SAFE_POWER_WINDOW : payload; + sysCfg.hlw_msplw = (1 == payload) ? SAFE_POWER_WINDOW : payload; } snprintf_P(svalue, ssvalue, PSTR("{\"SafePowerWindow\":\"%d%s\"}"), sysCfg.hlw_msplw, (sysCfg.value_units) ? " Min" : ""); } @@ -517,9 +554,17 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue) { - char stemp0[10], stemp1[10], stemp2[10], stemp3[10], speriod[20]; - float ped, pi, pc; - uint16_t pe, pw, pu; + char stemp0[10]; + char stemp1[10]; + char stemp2[10]; + char stemp3[10]; + char speriod[20]; + float ped; + float pi; + float pc; + uint16_t pe; + uint16_t pw; + uint16_t pu; hlw_readEnergy(option, ped, pe, pw, pu, pi, pc); dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, ENERGY_RESOLUTION &7, stemp0); @@ -542,10 +587,6 @@ void hlw_mqttPresent() snprintf_P(svalue, sizeof(svalue), PSTR("{\"Time\":\"%s\", "), getDateTime().c_str()); hlw_mqttStat(1, svalue, sizeof(svalue)); - -// snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/ENERGY"), sysCfg.mqtt_prefix[2], sysCfg.mqtt_topic); -// mqtt_publish(stopic, svalue); - mqtt_publish_topic_P(1, PSTR("ENERGY"), svalue); } @@ -568,9 +609,17 @@ const char HTTP_ENERGY_SNS[] PROGMEM = String hlw_webPresent() { String page = ""; - char stemp[10], stemp2[10], stemp3[10], stemp4[10], sensor[300]; - float ped, pi, pc; - uint16_t pe, pw, pu; + char stemp[10]; + char stemp2[10]; + char stemp3[10]; + char stemp4[10]; + char sensor[300]; + float ped; + float pi; + float pc; + uint16_t pe; + uint16_t pw; + uint16_t pu; hlw_readEnergy(0, ped, pe, pw, pu, pi, pc); diff --git a/sonoff/xsns_htu21.ino b/sonoff/xsns_htu21.ino index ba6a44179..fb943a710 100644 --- a/sonoff/xsns_htu21.ino +++ b/sonoff/xsns_htu21.ino @@ -58,18 +58,20 @@ #define HTU21_CRC8_POLYNOM 0x13100 -uint8_t htuaddr, htutype = 0; -uint8_t delayT, delayH = 50; +uint8_t htuaddr; +uint8_t htutype = 0; +uint8_t delayT; +uint8_t delayH = 50; char htustype[7]; uint8_t check_crc8(uint16_t data) { - for (uint8_t bit = 0; bit < 16; bit++) - { - if (data & 0x8000) + for (uint8_t bit = 0; bit < 16; bit++) { + if (data & 0x8000) { data = (data << 1) ^ HTU21_CRC8_POLYNOM; - else + } else { data <<= 1; + } } return data >>= 8; } @@ -143,29 +145,36 @@ float htu21_convertCtoF(float c) float htu21_readHumidity(void) { - uint8_t checksum=0; - uint16_t sensorval=0; - float humidity=0.0; + uint8_t checksum = 0; + uint16_t sensorval = 0; + float humidity = 0.0; Wire.beginTransmission(HTU21_ADDR); Wire.write(HTU21_READHUM); - if(Wire.endTransmission() != 0) return 0.0; // In case of error + if (Wire.endTransmission() != 0) { + return 0.0; // In case of error + } delay(delayH); // Sensor time at max resolution Wire.requestFrom(HTU21_ADDR, 3); - if(3 <= Wire.available()) - { + if (3 <= Wire.available()) { sensorval = Wire.read() << 8; // MSB sensorval |= Wire.read(); // LSB checksum = Wire.read(); } - if(check_crc8(sensorval) != checksum) return 0.0; // Checksum mismatch + if (check_crc8(sensorval) != checksum) { + return 0.0; // Checksum mismatch + } sensorval ^= 0x02; // clear status bits humidity = 0.001907 * (float)sensorval - 6; - if(humidity > 100) return 100.0; - if(humidity < 0) return 0.01; + if (humidity > 100) { + return 100.0; + } + if (humidity < 0) { + return 0.01; + } return humidity; } @@ -178,33 +187,43 @@ float htu21_readTemperature(bool S) Wire.beginTransmission(HTU21_ADDR); Wire.write(HTU21_READTEMP); - if(Wire.endTransmission() != 0) return 0.0; // In case of error + if (Wire.endTransmission() != 0) { + return 0.0; // In case of error + } delay(delayT); // Sensor time at max resolution Wire.requestFrom(HTU21_ADDR, 3); - if(3 == Wire.available()) - { + if (3 == Wire.available()) { sensorval = Wire.read() << 8; // MSB sensorval |= Wire.read(); // LSB checksum = Wire.read(); } - if(check_crc8(sensorval) != checksum) return 0.0; // Checksum mismatch + if (check_crc8(sensorval) != checksum) { + return 0.0; // Checksum mismatch + } t = (0.002681 * (float)sensorval - 46.85); - if(S) t = htu21_convertCtoF(t); + if(S) { + t = htu21_convertCtoF(t); + } return t; } float htu21_compensatedHumidity(float humidity, float temperature) { - if(humidity == 0.00 && temperature == 0.00) return 0.0; - if(temperature > 0.00 && temperature < 80.00) + if(humidity == 0.00 && temperature == 0.00) { + return 0.0; + } + if(temperature > 0.00 && temperature < 80.00) { return (-0.15)*(25-temperature)+humidity; + } } uint8_t htu_detect() { - if (htutype) return true; + if (htutype) { + return true; + } char log[LOGSZ]; boolean success = false; @@ -253,9 +272,12 @@ uint8_t htu_detect() void htu_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { - if (!htutype) return; + if (!htutype) { + return; + } - char stemp1[10], stemp2[10]; + char stemp1[10]; + char stemp2[10]; float t = htu21_readTemperature(TEMP_CONVERSION); float h = htu21_readHumidity(); @@ -274,7 +296,8 @@ String htu_webPresent() { String page = ""; if (htutype) { - char stemp[10], sensor[80]; + char stemp[10]; + char sensor[80]; float t_htu21 = htu21_readTemperature(TEMP_CONVERSION); float h_htu21 = htu21_readHumidity(); diff --git a/sonoff/xsns_sht1x.ino b/sonoff/xsns_sht1x.ino index 1d129566d..7365c2fb9 100644 --- a/sonoff/xsns_sht1x.ino +++ b/sonoff/xsns_sht1x.ino @@ -38,7 +38,9 @@ enum { SHT1X_CMD_SOFT_RESET = B00011110 }; -uint8_t sht_sda_pin, sht_scl_pin, shttype = 0; +uint8_t sht_sda_pin; +uint8_t sht_scl_pin; +uint8_t shttype = 0; boolean sht_reset() { @@ -71,10 +73,14 @@ boolean sht_sendCommand(const byte cmd) boolean ackerror = false; digitalWrite(sht_scl_pin, HIGH); pinMode(sht_sda_pin, INPUT_PULLUP); - if (digitalRead(sht_sda_pin) != LOW) ackerror = true; + if (digitalRead(sht_sda_pin) != LOW) { + ackerror = true; + } digitalWrite(sht_scl_pin, LOW); delayMicroseconds(1); // Give the sensor time to release the data line - if (digitalRead(sht_sda_pin) != HIGH) ackerror = true; + if (digitalRead(sht_sda_pin) != HIGH) { + ackerror = true; + } if (ackerror) { shttype = 0; addLog_P(LOG_LEVEL_DEBUG, PSTR("SHT1X: Sensor did not ACK command")); @@ -86,7 +92,9 @@ boolean sht_awaitResult() { // Maximum 320ms for 14 bit measurement for (byte i = 0; i < 16; i++) { - if (digitalRead(sht_sda_pin) == LOW) return true; + if (LOW == digitalRead(sht_sda_pin)) { + return true; + } delay(20); } addLog_P(LOG_LEVEL_DEBUG, PSTR("SHT1X: Data not ready")); @@ -117,21 +125,33 @@ int sht_readData() boolean sht_readTempHum(float &t, float &h) { - float tempRaw, humRaw, rhLinear; + float tempRaw; + float humRaw; + float rhLinear; t = NAN; h = NAN; - if (!sht_reset()) return false; - if (!sht_sendCommand(SHT1X_CMD_MEASURE_TEMP)) return false; - if (!sht_awaitResult()) return false; + if (!sht_reset()) { + return false; + } + if (!sht_sendCommand(SHT1X_CMD_MEASURE_TEMP)) { + return false; + } + if (!sht_awaitResult()) { + return false; + } tempRaw = sht_readData(); // Temperature conversion coefficients from SHT1X datasheet for version 4 const float d1 = -39.7; // 3.5V const float d2 = 0.01; // 14-bit t = d1 + (tempRaw * d2); - if (!sht_sendCommand(SHT1X_CMD_MEASURE_RH)) return false; - if (!sht_awaitResult()) return false; + if (!sht_sendCommand(SHT1X_CMD_MEASURE_RH)) { + return false; + } + if (!sht_awaitResult()) { + return false; + } humRaw = sht_readData(); // Temperature conversion coefficients from SHT1X datasheet for version 4 const float c1 = -2.0468; @@ -141,13 +161,16 @@ boolean sht_readTempHum(float &t, float &h) const float t2 = 0.00008; rhLinear = c1 + c2 * humRaw + c3 * humRaw * humRaw; h = (t - 25) * (t1 + t2 * humRaw) + rhLinear; - if(!isnan(t) && TEMP_CONVERSION) t = t * 1.8 + 32; + if (!isnan(t) && TEMP_CONVERSION) { + t = t * 1.8 + 32; + } return (!isnan(t) && !isnan(h)); } boolean sht_readCharTempHum(char* temp, char* hum) { - float t, h; + float t; + float h; boolean success = sht_readTempHum(t, h); dtostrf(t, 1, TEMP_RESOLUTION &3, temp); @@ -157,9 +180,12 @@ boolean sht_readCharTempHum(char* temp, char* hum) boolean sht_detect() { - if (shttype) return true; + if (shttype) { + return true; + } - float t, h; + float t; + float h; sht_sda_pin = pin[GPIO_I2C_SDA]; sht_scl_pin = pin[GPIO_I2C_SCL]; @@ -179,9 +205,13 @@ boolean sht_detect() void sht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) { - if (!shttype) return; + if (!shttype) { + return; + } - char stemp[10], shum[10]; + char stemp[10]; + char shum[10]; + if (sht_readCharTempHum(stemp, shum)) { snprintf_P(svalue, ssvalue, JSON_SNS_TEMPHUM, svalue, "SHT1X", stemp, shum); *djson = 1; @@ -196,7 +226,9 @@ String sht_webPresent() { String page = ""; if (shttype) { - char stemp[10], shum[10]; + char stemp[10]; + char shum[10]; + if (sht_readCharTempHum(stemp, shum)) { char sensor[80]; snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, "SHT1X", stemp, (TEMP_CONVERSION) ? 'F' : 'C');