From bc175426d4a089fc803ecf027d82a6b70c6bd9e0 Mon Sep 17 00:00:00 2001 From: Moirtz Wagner Date: Fri, 2 Jan 2026 20:36:28 +0100 Subject: [PATCH] Make tahoma communication more robust and add Possibility to change setTemp via MQTT --- KiCAD/raumtemp_relay_schematic.pdf | Bin 0 -> 28001 bytes Raumtermostat/platformio.ini | 7 +- Raumtermostat/src/MQTT.cpp | 16 ++- Raumtermostat/src/MQTT.h | 1 + Raumtermostat/src/lv_conf.h | 2 +- Raumtermostat/src/main.cpp | 7 +- Raumtermostat/src/tahoma.cpp | 27 ++++- Raumtermostat/src/tahoma.h | 9 +- Raumtermostat/src/ui/actions.cpp | 176 +++++++++++++++-------------- Raumtermostat/src/ui/actions.h | 4 +- Raumtermostat/src/ui/screens.c | 27 +++-- Raumtermostat/src/ui/ui.cpp | 7 +- 12 files changed, 175 insertions(+), 108 deletions(-) create mode 100644 KiCAD/raumtemp_relay_schematic.pdf diff --git a/KiCAD/raumtemp_relay_schematic.pdf b/KiCAD/raumtemp_relay_schematic.pdf new file mode 100644 index 0000000000000000000000000000000000000000..309277bff457dc90a945ddc838debe400db3398b GIT binary patch literal 28001 zcmV*RKwiHkP((&8F)lX>3N#=vAa7!73OqatFGgu>bY*fNFGg%(bY(HGBpZ5J_>Vma%Ev{3V59DeanvHNU!F;o}$(RIH3rIZci}40JE5xNBDvN zGzRI#oXx!cQP>K89~D%lEm5wjZa2_C7HtRP!r(o~=40rZ`M;mdN7Lv(E=~1WH+3Iv zoc|hr{_FbV|NRK%gZhvE{Er{?kk=m}#Q4$mP18*Pe=6`WwI9R$XUHGOcNFxmAOHUG zzjon|F?AmyHX#g*pTVIUhmUSvWmFT;;4*{eqYFcy24nyJ_kaHpe*Ta7|Nr|V2=IT- zzvxr*^Z)jqzic31!gdMqp2D zq3u7?a6h;9V@$V?XEJWvk3Rp+U=M8FN0V37uCNKX9Y4nLMxFDWY12oyuz=~KAD2mF zaFhQLf2QUm^a93|oBKt=ltVRB@YeE2o5g^jYx~K?$xt0)+sa4fl1c+ zF~tfPKT=cu{4Ty2Plk=-0;3-bY^r`6?z@*^7&{q1CfMVf+lBDa&YL@Sbj0qP+kP}@ zy%FIfrDZNtA&Ph>pcQP{2>CF>hPc2|8BcJ?h7c_A0W7~&d)SqI9h>!B5)S3I#tIgy z-^wzpGdaNRnq^^KzDLWjR|R(D2tyNuiH=1uWo*rjEsgWi;z!Kb;*4!*+M<&%_;E5E zr}z1q#%3Oqd61%++n~4OBg?}_PFe!p* zDvrxrJl0dUlRs;_pCpqR;1l&| zI_KY2k&a1V|7b;e=w=OI{wqYSNxQNJQl&F#WQ`+ET9+QWSh&1WrWJgbHhm^B?o+3Q z_V%gM^7DU~I(_Ovo~%#f$p5DLG#0o^pXU8}kv37~%qxn=UZ&lgh`+`?BCrH&||UN6fu%wt*Lm0chYd z-HV0%LL5M53I4#qhPj!cJ_8Z)=X!TF&lcblB(UgyVb*bD0iGd(LOJiYRt6d+8DgdR zW3&0^a)NA3Ttt_>uxlMq&5z3nEdm`tc1bj@%*ru!q5sQR1 zIR@=2b{V4*yeb;*DS8>B622;f!BhOs15da4_q`Ut^HgRUnelYJuL!9)e zwj9B_Ss05+!)*FV5nV=Dl-(6JEx4E8tps-xD2wQ+ub>A-^o@1o>2&E26w;&ICX&Zv zeZ|fay^rkh&}@&iY4z#H0k;tj1gT2k9*9o^8>H(D47F?Hm45W}=pDHLwj|PBUO}H4? z7}Fx!KTJwP50Z)4*$g*HMt>h9GsBk{`B&eUt=}5Qb3NdidOcC7Ue7~uaazyj_nEtI zjB_~6g3{vK4zWL#296IL5Dtj*XHVK}s1DgyWOzF`E^uCl1RE8;PQ+h36$$B!59`qD zON}3|o|R{WHhFynpV#Miemt&PpKM}=FDmEf`uhvhzQg5$Zhv3sU~8PmWkx^tH*Oc^ z874{nIMs2>CY31mY%7|vL(ySus}M3r_&h7K5D7|K0hEOfMxaz#!j>%M>Y_ux#rx2a z9tG2iq3q`!9j4MLl&hd`1;a^F_miX+<=Z09i86diMN+q@A181}1t$%O#(9ED zd4`e-_A<@JRI2M_qi>b!MkN9miiJ|DIT5K(74#IPx}SQRaT2^1M2{UIjr{r}6rS>3 z+{d(qFC0romT?pI8U&MHb`>lsVt&S2!xzdH*XM8 zYb0@-x0&ue^AaQc&~ZG!=S6OXsxAOe=Tbhv#oXX{Q74A+=`4Ed|C$y5@njpQuWg$1Zz zo(YTLTwWvLivl8bu9T;APst|ylx*qF-)F*48&bp^e|wx~2!CYn(s_h02O*no6Mmhc z=TG>t(CIgXFZAq1_=091;agd(zn1XXD-MljzcZmI)DIPffP<(QWI~PdO`$6|CrRxvJ(isE($eRnba}4CY-uy)XyV@MebyXZ6RjY~#uYiP`+*vDOA6_65cxKcGK(a8|iB!LYWn&8Q8g(&Ypw$n* z^u1n|#>s^Mk_QYwR}axr&HXuqL~;U_aH>TD{rq?wm*SZuks0opbEC$koSO`n+@Aru zu=@T`lm{Ir-TZzJ9eit?<8k6>a@u~h)71F;%#rx}`*MYHtd6pfUY(|9N@uz1O#|RF z(zy|R=X>d##tOP2olVybfG0_3MC2raN977-xRv{}`aVcz3Ve09zAsz9HIC0c2e-yKzMfH{F|7n7DLAwF3-U5<4&}NkWC5*K#Yu;H zD(p<;Rc-!)GmSQfI=-sV%1aV`JLj(#KIprTc+$1TND_NcHY2JIwIfxLYABN+*KY)M z(B#|6bMmp_Inp!CAnCN((Jhsf9WbWy+H$pBF&HQ3f|2f=#zkBo5xE+HUa7E!8Q3fsQ3r1Q{d)ZEagMJCQ8MgPUe5r!aoxX;_lfoo>Ss_H z+Z~^;$k7a!^Btl7=X~pO)fs+x-jtK8>1+aBtNFqHSL>O_k#nr>!Lx~;z_`=zpT5#5 zYj@$+o8qzdEU?26=^Gp~>1Y5Xc^h7gRRRdoxdjS$gYx<<3(y*6Q8QUl09VY&x7EekA*NUt>cbwIm}EF z%4sa$pGX8kW!e6|+CO_74<~cc>ec>@QIz^7X;EKTKAb5EZk+F9PG0|)w2d#mFI&Ggj_Z0Fb~4j?0y&NO`+?ux z(R#MN-;k4eV;qlXIbxRam1ejnOXP9IaLD+`3grEuj2yKe)4=3}B@>goo>9oO)Z;-trEnFWHCFx-=VOnlcH++w-p4Oy)xnddN&<5iE-VZYQm3GTX1 zB|>md!epMC$0MUf6;N6~!S%hQM@i~F(c>s}|9IZjK0PE7Vr$&sU;ASArP}kJ1WMAL zPfwu4J28tjUp3s5ba`B6eTa+es~iWu;<)!BTLe=lO2DBA1ZgU5fWh1 z?U34_l&>y;#8_Da+|@Om>xR}!{#CjC=2s~dN9KW|1?)o3aJte|22*{X%3zXo z*#5qd%+@%^*VEgsM8JJnOOJ$xMgleW@}jlt*QcCmEmg02-O+J)>9@%kK_}&&q1hZJrxEG= zihLQ)l7EJayk*Hhk{DnKKiF=rVIcR?KFP0V{*El1Ci%zS%%33m&N%vN<^IVVT%4V10yA2` zw!YMSeN$rq4ck>&xklohNlqr^J${g5qjdg1p&-V%ZuIEh4w$?E=Dg;DhT9woMv8NRgfBq&%@{MQU`y+w1|GOQ@ zk^D)CyV7k{Wz^LzK8{b~1H{#?3O==5JfVZGlOU2aeDOjM7yH!nCiwAr57?)c^GruW z;D74xtNBTPk?rrds1&y~j_Z0Fs#nA73H;QAzR%Ku*R%C~=Jp%o98X@Hpt?!j@_W&E zp@$A}H_zIdTw;*no_%*Fa;z{uh9_A!@Xcp4jOl0n$L15I`SaWQD8VNT^f5p9~IR*6%W=ypuGF zg8%iSLsn9o8uSM4V=~~M3O-*mSqqQD@V|b<5DG&2^ZFyAV;jLg6&!zls&N?p*NtAS zH4M-O)fyN+Q0EjLhv9$y`1gPNN08#*e|^uhuIYv^j!W0o^fN(IzcRdQ0=i2dWtEI? z7MaUBW_&|ikPzHsef_O3_c+Y!>#&~+K6$LK#y6|kSUL>QQ(4a;`0-D*DQv+ zhkHhi8&G*8LVgqcli``ZM8vE8AD$5Xv*?KP50(XK8k!^#Gw=P+sT+Nyq0&F-5Oz^J$)Pv3Ke*AmsQuxMepCBHhu|nnI?kbFS;E?c(ji@R z?=lZCM5PPESGLlEB*It0#WraDYGSf(3Vf^ib#Q~J`6;+Hj>G&+niamP zZV$c&>uyQ6?}vE}^I|84JK%%2V}%d!k=$k(zWgJ@K_4`~v1;UTu1+>oZp4R}XD;7$ z``tXUSl2h^xpyT^11FR2~f4%=y=lRVW)uv9^?EGiUCz;>DGMsA{dg4QuyDR&$3GRz8Kglg( zxP`}?;LiAn_!K^uTUq17Ica>p=O-CadVLIU9r3jic1STXy%0P;p|;(kFI!^{n^uMMXxy32<2{T-N*4+<6bxR-vb|UGjdF~EtJ}J@`%A2__ny}tMR!Q zQwF}o^g{dTiZ6*vT1gFti{0pqPsYvo#By}L?-m`Nxu2~q^+`&(N_`r4ORE9g7vGi? z_QAKvjV&!|kV7-~bFVtx_VWHIwOz3{XMEi#rX1iN_!`g!<70SJP|tF)o5ToiDR)QB zFP7LV<|or?rx>~ce|)?D5#vrJN|ou0<~P-W$Nl(d{}n!hQw~<1$KoMKU@doe;U_IQ zan!txbM&B7#Yc%wYwi1?&|YV05bidkWPOv$E-B~qnntX21uNk`BORU6Cj|$Ybplhp zNSBWjzbjgBP=j2Vi)w_ocnK7&jqBfn41nW_L&=Rq?%~@MCEws**8`Mq9g0d9qnnFC(1c1vCn6QJ_n=1&7Dg=pc^x*6NY8B*EK$ zM41kIca1n5$r}E-`SO!rZqoyz0#v==%g@Y#M>B_w;k)u>(c=j2$&M z)O>W#FAZcULXw8;uF^*N;XBlSW5`V zU8Zh2$IrSJc#`~gz819?|J!T9F^I>nMO)O$IxO+{wUFQLxE5pe+uhf~M>?^+!P04` zy%FT8(V6zf#oCpNwSC`Inc*uahsdEU0g{DrA#K*EKSFi_rj)FpnNobqfv}Y!$}n9j zsU%6yXNB7n35P<$F|BdvSY64gq}yZJZWp5LsoqKb&@EP`+B2*i8qSI4(YG{Y)+OP3 zF<;S;u3s1n5dhH!4Gop~vx|nvc>02d5;Nv6X~<%i4Y6gRp^4U#>gyy6)cYee#C0CF zXvm50v8Bv>Z=d=R8rW6sZNZ^Ef$x3&E_ve)HpGsG;%hNPr3QxTpy=$0r-(?cU%y&U z{F73fYHR;uxdr%Q07&=Bc>BB0HIw^$FA*?QiTCF{f7^3pU2VrX8ntL0y*`|SgC~1B zHwQMgN-A8z>H7n6dEzL8Zht>|#BUy758w_DiMsCo@ICzO!id6=u@^52!9N*J505^1 z90hksYemUX{nUx!p6RO?SMLbHW9#>d_|{{%ot2~1|0Eygt>f=-dm-8d{od07qcw2G z*fzHiY^SE;jInDF#(vEjH!3y*|HgEF~d)&yVr(`7u7v^XsIKg+4!m zyPhB8I2VPs4>ztR3CWW z!+G;2QxMMDMLIV6^iSs>No$qR++Un7^C0;B`KfxI?1FDB`+48zCCQB7 zdfm;0OzRd^@67q_zV|RP^t~sz>%H$%c@_}jQWxizNz3r5&MVkrchZ_qO16P_WL9;)NM%4uZPNM5T3B7ddM zM7>z0x9Pbv2U!fD%$-A>stPR^fZ)I_QiT}W)>EzbNyYGGQiqvH*B6aQGcAUDGA$mL znN}wc{58{}OQx7sC%OF2^OI+Ap&{pxg14x^<%&#bt2I+n)q z6$qi5m?g_;1N?adFB;)AfngC1OcSwmwbpT5dhWPkWgrX?SO3NP(ep zRvq{ZhiZ{#D7Erw1hXHC%1AWYb~aXR2JmV6xs=#e{S3N#$m3b~;)2v#FvC5y;69dY zIIRUU+*1qg<|9+%TqF`SoFLgjXq=8xedjH=1B?PN!*i=W!#W&i*$CXfvM24siFyM3pA3 zo-=%(dX65GZ}t3lR?igUqE_} zg6BT;hzCG=kkZS~NjFD*H?s$rAVLc<1?;U$J=WL(B=&=!D=VPgeEhOo7LP3?CK~|^ z_cQ`Va_O@Xz;I6^V3bzc+6Z9EWFvsTzt0F5B{G=B*1~bz#nuaHK3e2$(!3#`94|sG z2#t%dn+Z;>9g`#YP9})PP?-sG7X7bhg7oGQ4`!2V$Pm{C3B&gpB$I^E-v-GaZ;(s@VZ=9Qe>G>{yT>hxO=}B>;hq+bIqnLdr-g&c z+RDNK*w?}#bZp_^awrQ2oimk%gX-qW!kNhAceHR4S~4r)&T!Yj`y{2s!jfaS;ENoP z_tUDU(G0xLTL}S12{a0BBzEteM_wNV-o=_wa7Sw*HIluitO*5ov?kQ~u{D7atntds5;= z0@YMNhUz*={g_bUAl_uMR+y&>xR{a(HddGgMl+P(Dtoo9R(x2b#=t>usKyNURE;BL zR1+4>Zjh2P+GvT7f8`VphVyWJs$nC^5ufC_}^~ zMKsCQSe-Bqs}-p+ANeY{r@_@u<|AJP_cXZBmPH#}d^_0S;_vS>xLQQD;J`ai0`ItY zL~v83EL*wmDhI{;-gTlEnG&5YW2}L{@G{nwpAQRzF4zHBg6|XtsYmEdLNR9w1JZH- zL}Ad@RK-MDcLciF+N=!uM+gIyGto9C!}r;kNeWrKZOlL3#!QI!z9rm0Qo`*$=hU_4 zGkFE~w0O;NSNJ?F-Y#0tBNCn`tcWARpPwd2s^ zx-&d^He{u7xojAfvx+`t!)kmTH-JSW0fIZ@6W_%OUxP-Kp7;_sm?nI_=O@{RdVLIc zZKx~lFLTXttD$uS_jmxGZi~JeQ>t~SHEiK>ZHs1#Gi5zdPGtA zPdz{596jh%@lm4FTKj&oEqX*5vfr~Uy6V7vT3htm8}@ix^x8djv@LoTV@pKm)osyT z4&}>M>8JLpuN!e~ABxk>WIK*;reUW#v`>#|#nA;mfukQUrwUTc6?2EFRAdC_Ph8F! z;zYqcBtqHGd3{4Sm3HQUXSY$tJ-FbLvedK=ErD_c+k3{LYM-v)hw01I>{O#hLqmD8 zeR}Rrwut?6+ou~%joB%D;rImy01EWE_UYf1YAk)CRR-smud1Kv6FoN7&n*`=@5-L` z=|=1AXWFMv_0PHY=r`@tN3d4u6D_cB+NTQ=tDEkQ_UT`C+kWC&pnZD2Sj(M0xAK^M zEzWA6Zd{9J+NU497LT`2-*YXbefk;K!fc;zU5iKCr(4&;YM*}cweXQnY?rWf+G&^I zVc(f{$;H~0Z`-FIYJL4o`*aSNpVj*MNc;4S*4K}=Pv2;LeM0;6GtH>qlZK?bFc9sb zAu^tRGaCB3eflFbQj8LvihEEpPucl+j4%B_UUH#`p4UDTSZg<%(mN4wolLY zl}Nc->q}p-?Xhy6PlPx?W60D zJ_mcorHQG)o$(Eb+bMj5N1W+SYJE4Lxt=IuR|W5h;#~1bIUS7;{o)+UsXcbCP4jvo4I%7+m8ccvr%hpEr1Els?0yk!haa63A@vuHsYAyDzffxQD%K#jI}= z)w}BE>sRL8MPz7pEt*RwY7}{V9zEzlo@zMU%`nq=dXy(Hh zM!g@8%cL$zlbyVhvohP+{l*?m@wBmd8fr%!Js-f&%_j*LPANAuy$ioeU?|jCu7BDY z*d%bw6T8R@8uf%hQsI?TRzurZjR2u1648OWkZG8yWl4IPsVntz>jC$`HyG4;RdCna zn(n16V_f3{T-~00b&cD@@Opj^-KyM&t?a0zW&Mgk0h>yQX~FpqN@ZGS`W5n{5t4O@ zFUfqa)2RSNnQw%!dPR=}Yvqu!iQOUE5Xb(Ld zGN`~L0+R+z5&-s&5tVs9dek0D91KCN#MK7kLq|&L&6t#<=Bzh-w5diAoI_v)oN6W@ z(uyo`@(0xquqY^PzUq^)Np_LXSzw;3-$?JJSoND4sG6+$jYi4h{qun8H%fN~t@;7( ztNKmkR$Tm$RX?b5iWUg2X#wspO$+2;-bo7+Zrypb@Qg}`v>-YJ zWc5(S$|THg*^{U|oooR+`t^EJP7*0C3hwCF>s#sgm;H2z`Q*1u zixR;ZwmsfHwVs)`eIuE$c|Wo4M(w{Fo9`R)R*_Z5aBH9U<3kLM{g8dr8}pd=ITweR z&m|6ft;oJXG!G-3z%nH9O^AWCFRHrmMdd=P`h+qdQ?U-(evL!QMi2wBBKe%nLLvX2 z?2@rrW4TanT~`COStEL=(OX&Z)AcSsb*#a1XrEU=g!EL}wGNzEl5^-7WFuwE`7QVfyH^Z#J7q9BnA!%-)gap7{@ueoffFgVZKQ6?F87SWCg#Bdrm}+`)z?XZ% zNzxp{(HqTSKWDlqSAXcCgbien0`7}%j3}U!8i7WFL!MuBah+Yj-GY!N$MkOIDJ3G z@@IyJ@}kXMr`9*bFW0v_;M7ajcL&uwKZ*h01>6H) z;u}Z!2p(ZiWcc!r3|~V2pL%}ME9b=Xrv0za`>{ttm~j*dernDcz1cM?OmH=BDz#+P z?Y11f^3qTJSYT7-z%?sVsKQTmF{s0*30HbzsK+S{_0%Fr+<}Od47JR%T zjIZsCc^p3hesn%I(AQLPOnPe7Mp^eJeB{zy=$N<-cX_I|tcQ#0($g`9>v_<;TiiT* z9EV5#JdYOo|JFQ?7ZtF^o$-Yp`|pWwYkgGG?kRk;UK>#LGC_7DDG&^ZCoA92rNzyX6;V#-wrG3);l=iur2hE!b6xidqYG;J+x;YO=?Nj3e zgYw0CaC!4#SV| z>f#L**Q#oS#co2kN?R%)^)J6h4z0 z9qcr^J*vn)!Rxr!BX&~^6ZG%4`0`KiLt3v;q=QNQpxkbQ&OXDs7BROfLGfyNA;XoB zsdhM*N0x?GT>DzOR{@cjQamMjw8KT*TbNp7Q~jK4I#~VDo;k-(nlvE;_=Iy@{?z3L z#2n>QLl+);`xgaB5B<8n0>W5T&FcHHLL|?5cuLg5zG>FKCLcAO1l2_n^P4(s#BmL? z=~v9?y60GRu=~#@Ut4KWL$6_(40_{rstdkU-Y8u)oVp#Vc{p~nRQTvYkAh1lD`$KZ z08;CVyl#2@qPk>e_!3x)?846QrD2&l@7)4}1d$RL1m7tzI+zu2f$;|mjGU>Jf8V_Y z#y>$|bYpoYrv(O)fvdn^d@L{+&H{tyQ3;Gk3A(h4I=7jjQHDv?=`tQ)Gg0D7s6HCy zo2nto*i=AV3HrIbRi-%!jDPKEiQrFdi8P_Mv^)fG5E9V>81PU1{fPUcz8}~3>RC&v z5nK5!_rZhj}adF&j!Tg}Mn?!i2(jLzRgVQS+V zjlaS~32p0rbPznPyy(m9elgzesr`iv0ROy&Tb7p8u^G_)S$+Rrh4ofQSdC9`Ps>j+ zGJ?AbXj13`hb2j&3yBpy`aadvQ{Ug!qF@N_bK8v3%~dGDtz zM{dG{;Aq?PxiOAQWbxz~KEclM(2PbnFQZTD5~INJJcjUP`4fNLvhsS-r}5>u@XA1g z0wx&q?*YDa=$qa{ax^6o{-S5IK=T+fUxGtQ$*}e64`udQS?Gzfcon?5Cl67;FqJ1B zG{V;uFkiASPnqjwrm!R7yd<0LhmGV56*Pa;;`r!F>esyae(aG9?G=yiQ6pD!> z!T3Zci+G3miK?pBJghk+)$rwBC*1T&`qImvj0pY|0w#*k$9_Dt2+NW6k}44N80O>J=6~B`JOnY3I3_zaJhV{aTx9((2?%0ojeTp6x=kf z-VuVk6i~dMz>ut7=GPy?C^fxQFLQ?TJa`<2A3p&enMLuyJ+^l_Xoi;h*Nd=ozxh_w zP8{N@H-z+%Aeh7(Nj5C^k7AI5gD$7Qs9wBPl_25;C;878bgEa@^09(Rs!PyGV3UvLD=U$ zfLAK`ar#H^;7$^R^13HsVSszkoiti)d#=k*^8ox)&u@U8$m1~F;~o|*Ud@l-dLEse zqnbCtt@-V~7s!z&ad=g5tCGrYI_(2G)kO5&Q1Gr^p9?;!+`@c@E4O60^y5gyACci` zMm~~Vnc;kr3WM8X|wcAHX#E z`wV}E=xAj5)1T->1EVwGC>r%tf`!heBo0hxw;8^K3;QBQB5^nlFaqZbPZj0!#Oif9 za9uJ^l&OHGwtG#5nF&d|%k-{xcKiFGYG)7a?$EH7`+{boGD+&%PK&7fNX`5x92Z%9>?5Qb1lJ8E*Tcy}(gPQJs4t*uk_;gAA}c>9;SEHIsS=&GiH4fd z0G18$GzfDc#ibFKG6;uGn*J#Rh#K0kBYhZDmrVLTb>;Lln21FwgNayFZ7@B?qR{H5 zJMUfF#kw6A>TAh)(XluskQXiVO*D_|qk(n)w%}Cvpskc6>a$n3F-*$;8Y<@pro-*x zWoitRY4FcwGhFE%owSt!I0VqUrvXUgDg%r0v4J(;$I<|=Hl!XC0)w%_6NG@MPBkx6 z0yb3Qkh;MN6DM_@sC4{_O3?+=>eP8*mwc>=a{OWGvgEO zf;pE=DOtfN<@a6Iq5QtWO6g`vZ_}}&TE(x0*ViO(zTaUl zV*7Gcxt(*L*1)4|e{6cT=0yczIC6f*X5fscWwa5^-w68iUq8l-anV=k>j8I}h7N&~ zftHEPgB)I=Iq+4%c^VXBqA9lsV(JwpSTOW;*hf4x+C@6A&>Hxv;CdP*n#WTf`Mi0B z6F>MUUytzO(a@0sGp;K%2fivePb1*X4^6q{^QIL>w3+3v!^_A+cL)W!u2A1Y@v4nY zV1#Zd5UYg%U)vlF_`||)8!38oSNGb`&KIlx<5=QsrC>um%3t!wy~c5qR$ol@aH+z2 ze@3zVgG82$M{Zme(F^RJIBTTpRwLF6elksbKue1EA)Ijt`}dLVN1Ui1+kmD3aq7y8 zHVT(0Xev^Q#vnGddvXb)yrD`~IYeKWXJfRk*^SSn)9cM+SlE+=Z{C(+Oh4;CHVcdo zOD2}MS>nX02IT2%j7ns?@nKwz5A!hb?aeeB+rAKnY6Uc=wrC`(6%fHylM)(7!H;K} zjVP5tBVQHVv;7H;yV?j_}o)s7I{ z@dSnm(FV1?1{$5(X@YYeERVx*hZ7*Bj`L3$Ui;d7@aY{PxJyICiVLa49OgEhzshiq z%kVf1_vJzyA!0b^ID6vLJ3?H~p$SuIq>*WQ38kl&Q=?{@URu%<{2BG0jC~s6-9qJe zX`w=QIkS@?qPiNNKH3C>e0^3YJRjE z-z01&rJnE++-i5V7ay@BRRfj;6T#2JmnIADfDZzXy6h-?1V4_?9{0TUFoOz z$o2eE7jS;`h?U?D>odpI_~M9U*W>FGx~FlkYTaky8~E+hB&ssO9q1Fxk+l5lkB*%9 zmiF&}FCdhB-I#~#{oCR%rX$q>pK_$~etP1gMRl4o4P`~~A83i29!o9i>0ka*m` z{Q14;+*R{|#uFdtb0TZ_75qiD&oueYaePyc$1==c7;e3-+>H+})Rkq$a8Ld+b(WXp zy0PvP@e$m0KezCmw4dY9nt>?B=gB`6K9aZgJbdX>?Pm<<(93Aao$LJFhF*_3E^uSu zj4|Hz-!7cDrHW*_uVR-zS3=>VEANVLv{bRx5uQaeibe_U$zwJavRa`hM%&x3ZlURe z-o2ydxaZw^=3e|%P{Gf_M+f*_6vyHGbh^SxTwC!jO`-I`i|&Lul@m2JlNGauv}2Lc*}D@ za0km1h0w#)qb53^E8q_Jz|)kc(DqomdJeYE&#d{r`~1j*Jd!0(aHG7K&;8ptKeF(B z*N3CL^1URu>wVwEhm22Od>B_p20Za?d1B5wKk|_4?suaI;ildv^6;En>(J|) zqMv-JwzBY_880AL$bcAKXAM z(U)w!^hEvhB>iP`KTW;Ol|D7TKAocPwn4(FN`K+|K6*wz%xZ_xvALHX3HhUfp_|QK`ukS2;6P_=ze}dqyK0CXd z-u1^20uh5IS*fb zQ0ZrYpS7PF-&yM;y;k8f_t|wn_4%EIkL_4g;yls5rRMJ=@fU^9k-upeE-hE7e-O4 zl|2^m09n0EJxnhcSJUT7_{bTq_zO8bUGE=_t6u7yhL6rKl6^#cmEf-H)BM`xTbCgvM_6zW_zueB1 zcAyutCew9e9w+8}e^aBwgI+fAdG4p#Fys4@e;)Wa{{CIn85evc-+7-s;{o=#-`6$T zjnAx}b6zD1TMm3zN9m#Nth3s)6u2afQkVW+Pxkw!@~8+n7JTTsvF=ZB?@2zc%1&Qq zv9#`mPM`(Vz2-{4Zb**tE?kSS>ilu92#9*_3s{E#wj$sYP3330EE^3|;l0uB8{H25 zz0QuxMSX9y|3;5O(PR(2H`;xpbJ3=y^fpoqTwQbZ?yYHPi>TD5wM-#8|}Z*)Z6~O(PwV-5Tu38 zd!tX>=yB*|qv6JUZ?yYHGmn06^qCtyHByrQz0oIbbZD9h4TIl1{TgZb-sl(UckhjU z5tDxFcdug7@0~t%r{lc=VISVi<7GjX_8p%+aie1@4!rk9pXw={#0sZm)AvUEZ!`tM z@e1m_(f%7vsU71xZ1@`1@#fL5q3HKUpSsa$cvJK%Ho70ix2Ns(WgFRN#X75c=1NR(@9^o(Qnpq=0>;gH=VEE=r@l(HG!s) zss?EqKEkan`D&xvDTZ#qAKz3pvk#$-W$%~2K7U||&20`hAU1}8@m3CP_4D}A^%_rx zjpZol#{wIh^>3Fdt{HY&EQ(nzU?j_r309STdvb%?(0;_sJEosq6F$p{SBM&gUG`h{wmz5V2!+_ys|jT+-}{D8 z;z~d~LnszejODQ1h(bm@nEV>!4o?nIv2(f$=0|KmtB4k2VT=fgdN&ra$ z;^*=)Bccn3DUqziczb(>#xE*3rhv`@AMFB&Nr<#eMOl$5srG1a6w~A;k}H4}3&Nyw5xjzV{60 z{pWE!`2odM)c&XbBj$V2jeTWQTtTuhE)(2?ClK6qa1X)Vg1fuB1$Xy>1ef6M7Tnz( z26xv-cK5xvXTKlcyXV|Ked<Dy(%Ghh6Cj>09>;Fj{3zTK;_AUzz;$Rqcw z#@2UV>+<&%Ru+)G1@=@9Du)KUHr2u2em|_5` zwf%aS?dhy05`nddSS~%ovJeNd6P<%%CCA(?w!D?@tGgcqvgl3>6TRK#5xa3Z{3^Q0 zmS^q4m?_?fHFMEM-=`QXD<%6Gwjn+2d1#;L(V2DL3;5L8~Kz5=_DVjAMCEF{#hmHrMy|jW?oJn5VNQpF5O3#qU%)*y_Hz zwNTD)ViTgV69FRV!%#KfWF~h4$UauFVlQFoi!vcPJ3$PN^%EXb2 zl4d^ywiwo`6+RLA?*KNWya(3(1b@I`mC*{-Vj||1qG(LKP{6R%6@?3E`b3D|J(A(t z%PnfJGQDd{o|ugp=F2Z2*W~P=WphSdVkMii1sVsQ>G1yi&fU{y_w*_AY6HfbQJh(U zvfuKoK+rItUL$jOj2pnI`%lHrAjNwqUABYo0{J{206oYIt6r?Fyc-)2GE_pEUAU(A z7KC+UyA)hyHBx=gd(JNY;LV1LtfEa?FF)F^vtsDA;R*^ro&OZMtv%tXa3WZGv6gV= zdL(yFwrjAW1bgZf@oxxId-*fsy_V)H=0o1mD-cG!RlT@?_Sq~?O(|uirhb(c?K&)VIFv0)DrSG zF`^m)yF0G>O@YzVy#YpCU{}S91iH6z2^#*+0D`IA0qVSs?R0GZyomj{l-@L@gw(Jt z1ESK(0E}y_uv1VkwM7H@1KdtSGIX35G|R{ER88{=)w09;3t2j5T#57;S3PVE@?(21 zHUjJMGKxtIrh+m1}WnrsSN70NY*| zfvDGqH2GCy+_xw0L@j3820HfgWGcXn?Q;sOZ;<|H& z;p=zFrOkZGj^S-~vJ)Hnz~*xocXnI%+b{Xj7=OID@>_Qov%idEAfhK_b&)hyYZ3zk zGHpn9W(rQncz5f%p1b(aOJsQacLQ5x%uD!55As3|J447=&TrsBpmmMRIpXC-Swgy> z+x~Kyk?*r!Iw7O#b~Y%_?Ibc9s^Z{y53(c z{B|>h)e$>MVxa+JtJvDEPwDn#d8{_QB{$qJ1|yhXlAPS2lRbgMyxbj}dP-xj^ag^P zWNv|+8Xsj(2{&(64Dq*il*W0=*T3`4wKW^gHID3z7Oh1d3W*gWeo;zm1xQSP1=9T(8PImcRviTngJVzLb zJ>7|sE8*+afsS&Fcz9a+p2sKIY(mFRG0e7L>Ms2zf?lp48PeDxh+1n#H1;6423_JX z`BOKl^&U$M10J~Z(4Gh+-fc3g)8J%NhrAUk8LmPNCb9& z)%&g)v2@hdYWvbUYQ4Gpav93Vu)(r>iqqDb7A#lUz?_syY;uu7Ex+bd)KFa;6B&Zx zsWm9ENbhY|DRXf%sFs;&cAZBNK;jFh`^3$|cA%Ad$v(B^DM?sH; zk+WY)LHlWjgqB=)AHGC>OTd)5RxgiCnTc!IT>qA33KQAO){f1j2-sGJOb{+hyLX1W z+iiJr^8`%9`M^VYJ%#F2-13UPo8Of%F)C2Fe*$a_VH*sxu;Q#jBne6nk_++!Fu)`1 z1?e3Fi5v)BzwmyQamQ%+lp3j*)MCdc)LjYTYDgrd|1h`A$?NC%d*pVnA5s>fWKERa zX|cmUGkK$pl2^5~GS3w&Idpx8l4qQ}Z30Zl#nk3&Vbn6^zocMwt>0j;mfH!H&`>tmBLKZ3d{ zWYPCRgzqV8O1`)`@!C?6Q&*XQrydM@Mi}Aq$72`&-f6O;eo41wUyYEK9E|mXAsSs* zWmuj>^ZHr&B2r2r$W%MI=t_$0jiRo~SgGT8)M_EXt&xKxPCc!48=ANzs*PK**k9(a zf|M7se`%pAi7M#*NX>43X~ARFA5Z;ke@7JADk^5PHv7Hf50Z!viq^*n`p?B+?+Wp) z%Za}d+`d+Wb#n3Qst`}V6L{9iDH3R&VOkjSWY5C{_g;rCEwsNE(`i8rQY!z%(L7@v z4?N@Raes3sl=Ja>@9Ir~VA=Ieq4fJ1e2@0L`1YlHu4>)cfA3sS>#Ef5L$lA6u;mG! zaEk!zGkpafL+>Sp%1;Q?`92>}6}M`R+u?@$<)wwMgNIQ|3kF->ngp84PqvnZ5h2Gn zbyZginW|!o00b?%4vzUXW7Gny-<{(f6;XVXuJ2>cH`jM#Vr^w;kWp9F^nhhyNYJ;a zYHjr?OuMdX-Q?2NfOH~38y-W7=MeT5oobT7pj{v3QS$nS{ z?!pW7%tM1aJ`f}s`Vk5vBbJ*F-w$h8M(S1%!taImhM-?dKCwto^Gd%p2oF%r-`xDd ztJ~Mtl^P8@9WOx^_mHQ46(R~~*MN45MnlHTc1*sYW&%?$w^4uh5oPHln2Q&%+Zj2d z64ND#qRQ(9)FpT(+&5C@`mz`P51K48h#<~_RkmC+!=;)a`E;;>NS=sV$> z>aWkYQtOmTLfe3%Q%UxXw}%_uj@OL0yi*sJCGpq(w^!Yc>$A7ix3@PR^T$Qs zFQB6OsNDTV_5jYlJc&|whfk*QPfkGr1mD^#gZkM zsohhufwRSBjOuzU?}m!=)t&E7{e$XOsesD7Q3Ur;sNbXbV`ME z&4!KrA7v3QWJ*6y^NnSTc^~3XMhB-A{-&)zn6cxb|AHuyYJ~P%RD|#XHqd)cll0dn zx7U|?K5LUsCvhXHx;*<-#Q3(5)}<{rZ{7=DAZ9k$X)}TI!4ufQdJ2~PcoVX&^mNux z<3AW*k)1VYbX%U;d-<7ro+Z%&FQ&dhkHvt>faMpY^w(6qYUP*!)n_0Udx>K``K-Yl zU59t}pep@P-f7?1FwMdS44140o^!lQ^5L=Ir;O4$ltSE6m7IW|a0M9;U+W@K;ncn3 zU&?N~5_3oW@RJmXCNlOMLo8&z%uI9H@b$&&SqQ9G@03lBKUHQDn(l8$CnMBpSbLaR zjTxz?=BJ-(=7%H)y8(nMkM14S$tYkfd$on5kQ2pJpErS|Xf8BnTJ&U-*cg9Hs4H9TdiVH<37Njd2RZu9L@^n}`vCCjhsng`gYyQ#6prJ|7tF|Mxi znoH0hK%VOHBgqK&Ni+<dzdC!Mq!qePPxC$$4$N`f5nRMwv1y8_a3)_v z$c>A96#yIJM0)bZC#dw%xVVsyd(oxU0-+b>1o6)zoHHWtc9 zbMDXbY3z{vgj5LCZidvf)lBfRR}Du_^iVf*R(gsM2YBpl2H)2tMbWDPNmlGU_+yeq z-z0u(;l`$}qX__0HNuc=yTU(;BjC$`Nt6a0_ z%VsLSH0+)2Jzf9!;_Oqg+28;Dw7fv6oK)| z@yor;QkZb3PAcMgrH{=DyjcW!1lkK>ZbV;=TV=si?wmUPlNvK&H|jZFd~7s2l( zZWTA?JYxG^z+cg_$hj$1G}wQd_HgukA=tnFbUoWVyo0Ewfy};=g#2OvcZ?PIxqF~a zL@cX;oo#Fm)~ZN&s>bl?lbuOe*YySz`Sz{=FZUX&j+JOk^qt&6{VZNaFT{Cww5Ud9Gy1-|ynM$QwV?fp z509YIMn^cAFm&5HC3o2N{sk&z-Ike3;wCt`!n4xW5!FQcK*@(FNqwJy^=+$Z)0CI) z;J1c{Qny%APqJ_5TIZScvS-lvB*C0?Rn{Mmssrg~r`fWW7PmG1aQ8L2HElw2*p>)r zC4O&LjgwNEMBLC?hf)a~sCM%MWPOSfOl!JoJpIdknEEI^OczW>_%cs0Ixui`7K<^q z1Ol5e)&ehU;rptoMDuF-nN|oB!g&0B7Vuo=PDAlzs((EGmpT7>H@s6PXb^t?i=g!Y z`-*)ayak)M9r#WM1Tlip`5`7e!(#p_SdqQ{rTJ$z3|D}BVyA-ao4@rqYOf%J01R=r zVm7znIE@KZ9=sdGFzI%X5{v9`;>8p-X6NOA?d&jXFdX9;>>^5ZjXQcx_;1IuH`?31 zk%W_q#whmUpS8Oja}zLLG0W=14OyL5X=#|OCxQ(jb#Z9~E5xDVe{3QnQzBqv8*MuT z2Vs-FF<+vgSCQx9MRdm!$T)i!+#O0zjkx6eBHk;Kgj{mbTS>dTLLDJv2{lEQRdz65 zMNBT&E|V~BIwo01gn;*z|JA4KLS`HEQ$w7;4YqB8`RmsSsk6umImYcjGA6$^LnV&{ zl~}x}Hr+nADK9&yn-|igJ#Sq1D$A(x&IgMzKQ|}onCjs73ZRYWgNd}aY%*EA6cJZq zJOw*))MT4++b&5y7A7c+W6)#+lzLy=&Ofi=01qZ2Toi96jWdM_VfY;~buN;--Nl}H zJ$Nf#v2pmMe7Hzhb$Fv4UR%2!Fo7c^wT3#!M7USs_Y?N*7$k`yuh%&Guh+yc*OGP{ zDYodUh(ZF);tFUh*yA^znr?j^@2p5o1Y;Y9m_?7r_P7uG6_Rtc)2RI zedBL9#svejXFo5P9(iONy zQ4btKplVp1R)+`|I!gmHAJX=tUe3uXp%Nb*lpbGp&~WbnAxyl;MkRCwSNf?K$A}AtcauY$uTR z-qiFQbznE7_hjH6Hb}bj8V&Vk2In1L$U_m~br496jP^Xeq4I!svH^6}C_;O7+#9@A z(^`FL>k{a+`g||WwAr~qvXF=x7JWE#8FJMt#AXN% z3-sFI{SVD%9`Z{Odl!Mq_6XCIy65|aGsK|+4j zn1~=UG%`CMr+GJ3PH?ttMh@7>j-3AaWBbA)^K5j)p^RGt^S&hV#>qL$CC$698aGt) z_0#Ecg|Dh(FIl!lV#oz%$L>U!jyxoPxA%vOWc<}Xkxv73KAFUWLfg>I5$5Yc0@WFu zs;a^3wk=^fKy0&z5MaU_4{iIHSYDz0*@z5~QR*B!wNb*4cFUtwmTiehJOS;9DU<x)WEZ$ki3|wT~Dh zFh^3_c1Y}SdVljuQJSGr9mfn31{KkL;3SjluoU`vQk}cT z85!8_TKg1=mMsYJ3n_P;Xh8Dwj-YDEj33(au1C2pT29I9IZ))hTI_O>PacuEiALpS zEMgtrra7y>x~1jZn%MN%%Aw9q=G)UwIN92IwB7XHF+%t`jBWu!Qio&kFVI7blmg zho+D1g}o9zJJ&={U$P*wJFf34--N5O>(&fYK7F!mYq zzUfGzkT0}e)7J13JoPC}_FU{D*`Dbt)KSHc`5MrGCslz$f>Fq{SEV_4*#0>D5_@>o z;zsse)jDlZg?`!NJ<@G*=@?lBzvo_A3|d1ZFi)%U*$>sHqcZ~w`RNH>_Pf~~^LFhM z&P%RW>Mvgc;S4N|Zxfd{dnl-JN2A)ORdDtRKTo*o-oj|zY@bT97V;|WdT zYfDaBruD6Ln_%S)+M|`lTs7;hz@M1VZ?mX&z*O)IJg~|LW(am|w3rdQVDGvYf;Q6T zm*&|REN9u{Z!n_?S`t}N;*$G8AOP3-fM~X?u*biA9<+Z=e;vZqCAM>B&e?t~SjP#y zVvQ&}+SdKsmD-=RiLCFlhptHSro?FeOjhxX*f?byJFf&Y9?oqrJbQpn)AuBNL3yHw zi`!%IQf8~Ik_{g2F?X#S>l1O0dVwLIJR2#cDtea}&BH9NIanNoo&Zm`eTj{xo<65I)L_k zVxN~NNerHahc`p|*GSa&cS7U-2vZJ6=BJ$1snSykz&!@QYM;sIJ=vvj`u}dX-If_R zNSvz4IW~|mq_?EJrP?BELqg09e11G*-Y(N+d8M%PX&ZVWPPzDQX?n=JyDUJQu9lEeK1RD`c%Y!a`~ETb zhu3{5kO3T4GQzkQc0~J)SCwC<7J56R=I$O?IK~ZNB#iW>Yr}eY(b@65i%i&$(vs1+ zCUcm*hhsD*#yydrY>S+pW#1BcD3oH1NwCTgdmETjj|>@-;Q(G_nDuWxcLS|mJBUdr zv8`jDVC=>=>SuT1=~K}8W2V}&Uba`4W$+{m;On`jNWCh-gjO+|K4!+Adf}!N1s=Mj zhCxSq&d?{0e)1kRXuLgzPi=G@1@JD8Qx}0~uhf0mHR1?$F$+^mX=!^|DWZfOp)sWv z4Wx4i=h0W?I0Z=<1m{072$p49<3Cm;@v6s<$M-#zXh;n1cv4#QK}){+zo0ldNGDo> zcTfB=-4*uTved+LZJg&+A81)GPIX2Fg#;pI^ZHvn)mTfwosl9k4?kwD7*Rc3;mLuZO!%VeMSSy<0&n4B`NknLd-%X1lH%lwTK}>_zW$FHMVV@YJC# zUgig7mIaZEEkA3$`>f`-2z@v(scm&;Z0EH2lqK#WUKe|6x!A+QpuxNA-Vez?GZuTj zU?bhlZ(vP^_!L?f)yp`S;#Svh%tL%4U0(=s7M0*;Q~EX_v}7|;k2W7=d5OSRWFh*1 z$jWya!v*UTy`xg63)}7!QMfo!G?)jR@4@zpxV)}FZRhK(ESu~3>V}ZHXo1wWg*S?% z%h1EZH^vTh5)p0@hS<30M(KRH9{2=*#WDRM85Uy1)L`56xY4=9#Dv&&F#Z~?F<3aB zjPT}m@vW++~YP>Jb1zn z6a4~|Wjud{CUc;k>obc^aQS8!_x!`D1og$StKizsKY z;SsX%2clzs@Cq#Fzi{S?+4&LJY6`3|hH2>EWlPpUbLnyhz&TYE|9PPdp{+;%=~g(T zjS*<$tw!($F>%D&l3W(HyFA?ZZC>B_j zz(fX|qhIeou2flqKiPARWusBvlDH%N$XpoT{xrd42|rtP>&79&^prsePVc}7o%V>9C2jZB`Mp6!532{sj^0xuTTFYRIaxU28-1uv`WU}UmSChN zWB0FYTs8faZ{|6({1k9ydy;itu#X}DKUCjejr7N6XE3`CRy$u{t%WwAZJ~4amjXci ze@sdDCxJNIHN(pV&b!-Q*bEbwb~gDb2i-r#DI|_!G1W_cGM4)+4;zZJ38JCF8T@!X zp5#$Ca~oTf-tnT0s_z_<{b6gKD!6UufPL%YhMgm=m?tt!+aPX~_N||w_W1=Q;yt}X zV_6!8Th~QP|GA(~_ChyB!FKdm_IaiM@j%+TIN|V;ajyTt!$4UmJ4|$h!J))03Lx%yl4 z1n!!d&b(Ss$Bht%6^633Zpje2VHg0%4EMt9m9=^6i~gNkQ4y-ik|y3m4J*;y6gElq zJEt!&sW$CFPd|vjz6O-h$eV1mdrSP358Lm4ZW$bUiR(L5f8_UhxtHZ)Zp7YC5~0`b z!ia~BGoO8%d}m)#aDKg2uDiIWbd=!dPmN5?hn-)kd*}%6nP&qHTwkGC;otNT#3}>G z#qI-l=OM-gl-qBkA6^#whZfeVpfz3AE@Xjg?mdfKxLI;#_{dodB8<|wSQn@c%|%qR z4$TyjsMV z!6YE<5ih{}{Ww1cw5N~y7oM}b*2T;WzahAGQ1{!R%wV!nbSYAj8Fl%EBB>8(CDkFn z$79OFN9fD>yL|wbkZ#p;fJHb6wXL(b$U)#63q-rW2&F8cTb7mXpPxsn01N8ItK%b` z?o)zB)@Jh`*mNYbfk$q5Ulx*Ep->H)R@@#-zkvpy* zT|N0HZ-4jOp?nbqwq+KNKME82gLS{3(e4-rOG&>XDG@tl&>uQ*ab0*BH)h@;kPw9_ zHJ2Q%SP>&iq*To)vroq1ce7==4>&RJ@}1oy;lhr>uT?JW+DYd8V6G_K9``bZn$MJS z(c9<_AO@4LxoF*p2+3W2qUZxR9&RKHB98g8H4wfydFb7E;TOi<73%oC|j((4awCs|^o= z$_0a&{gL>m2rMm+@8}(O_OEP{Qr%XuYQ%dMFt=H$D{H+)X;P=?+xber%49i3{j^*i zV$Dh^pkj|a^pkfF&V9EeL5M2nt?`}p+IqxpohR<_+Ihr`jL8v~s3GU;yy;ER`dGm! zc}64h#nJwy|V87DE!Rmg<65 z4#3|ma0z?OnXh*Wk3pT^BGS!BVjot&AjT7-}uK53YRX_!yoSv)AQRfk+^lkRj1$di&nuNsx_ zR>_W~LCLzcb#r?3N^# zm&n-9{?dif5Jqc?ya&Sr{;TPJ& zwoNCX?XPvh6d>s#`-FGkz&4d#Ka?)~a2hJp4trv$)eAv@8jFpEo@?L1chc?g)zdHS zpU^md;6me%JiGnriVh2et=c_yGDx(40PB9KpA+kwuyIT#7SK9=Vtyi?u%VY=>EEq1 zJ#oS58z)}+sMb=u?9M(+L|W@*-auQoOeU31HVz zFT3;?>(KoEU}Qpj;swhATo0~jhptL+$PdHRu&EgJ^73o9tsB{% zFCa=*1&AVN|Ln_;su--Ywr@xw!1rAY6-cuPl88Zv3nE3lcYX(gS5L!!i&A}j#QxbM z@dEu?xo!c5&tD|&DKe#$_=uE>=dL0cma7pN6uvzrwP->J=+OW$G+f%D|mn0yA@(M~z#xvUwDNWm3OSpU2F#5yPgNl^X72 z3U6$Z^;5W{y>QI1TBkLp$gZi7%-=uH5z21{#GAwXrQmj7Rd7Zt7O6?m9*MTAjV2%= z!&O}9TjU+;bZDTK8ZlH6CB@kZf9^^t5V`eds=w~`*PAx|uHZb;y(}O)>J0x~d_d!H zHfKb%x0Ft4En}!&uGl%BM83eDtt%1m7Ej&jI8%XZpSAElyS%U^A6WBxh5y#+(G0rk4AW|mk4YkuTV^wpc_p)X zh(|5-oK85)ryi3ULLC-;G@x=@mdfS5wMAZgxxLZ3+`hS)19RI6?e@`&=FU>sb{{k6BY;By3ZJZoQHA(;Gt5PKW ztF~7p)dnz%IM~_=+q%6!U}9kU#|>m-X5eCBVqzm@=VE7IeXlY9MU*i%GS~ko%F42P5+I6^WO-B zoSn>U9Z0FHnW+Dcim|?vxvh=pUrwn+xmlQ4*qND`fy_V_R%T9GCT2<|Cdzj_8C#?O zABwz#t&y|gdsZ+i8FNDiTSr?HCvH-C2lIEqlx<1h(}=w{qipVE_1=$?p_#swlbw~m z4XKfXv!SK24fVe<>*io=0$?HqA_JKI=OX1`XJ=(6HTf5eg_E7_eG>m(q&EKpV*|bq z%zwaGxPbow`-{N!A28= 5.0 && newSetTemp <= 30.0){ + glblData.settemp = newSetTemp; + ui_settemp(glblData.settemp); + } + } } void MQTT::reconnect(void) { @@ -138,6 +147,11 @@ void MQTT::reconnect(void) { // Attempt to connect if (psclient.connect(Settings::prefs.hostname)) { psclient.subscribe("weatherStation/tempAmb"); + char newtopic[60]; + strcpy(newtopic,Settings::prefs.mqtt_topic); + strcat(newtopic,"/"); + strcat(newtopic,"changeSetTemp"); + psclient.subscribe(newtopic); Serial.println("connected"); } else { diff --git a/Raumtermostat/src/MQTT.h b/Raumtermostat/src/MQTT.h index 23c648c..62d80d6 100644 --- a/Raumtermostat/src/MQTT.h +++ b/Raumtermostat/src/MQTT.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/Raumtermostat/src/lv_conf.h b/Raumtermostat/src/lv_conf.h index dd8d358..a2c2ecc 100644 --- a/Raumtermostat/src/lv_conf.h +++ b/Raumtermostat/src/lv_conf.h @@ -52,7 +52,7 @@ #if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN /*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/ - #define LV_MEM_SIZE (64 * 1024U) /*[bytes]*/ + #define LV_MEM_SIZE (96 * 1024U) /*[bytes]*/ /*Size of the memory expand for `lv_malloc()` in bytes*/ #define LV_MEM_POOL_EXPAND_SIZE 0 diff --git a/Raumtermostat/src/main.cpp b/Raumtermostat/src/main.cpp index 35c5a22..ae4046c 100644 --- a/Raumtermostat/src/main.cpp +++ b/Raumtermostat/src/main.cpp @@ -22,7 +22,7 @@ #define MEASINT_S 5 #define SCREEN_UPDATE_S 30 //update screen every 30 secs #define HISTINT_S (5*60) //make history point every 5 min. -#define WDT_TIMEOUT SCREEN_UPDATE_S*3 //set WDT timeout to 3 times the screen update time +#define WDT_TIMEOUT SCREEN_UPDATE_S*7 //set WDT timeout to 3 times the screen update time // -- Initial password to connect to the Thing, when it creates an own Access Point. @@ -48,7 +48,7 @@ BME280I2C::Settings settings( BME280I2C bme(settings); #define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 2 * (LV_COLOR_DEPTH / 8)) -uint32_t draw_buf[DRAW_BUF_SIZE / 4]; +uint32_t draw_buf[DRAW_BUF_SIZE / 5]; bool newMeasurement=false,newHistory=false; float temp(NAN), hum(NAN), pres(NAN),seaLevelPress(NAN); bool presAlarm = false; @@ -156,8 +156,9 @@ void loop() update_wifi_strength(glblData.wifiStrength,glblData.wifiMode); } } + checkTahomaActions(); //slowdown done in loop function + if(millis() - secondsTick > 1000){ - checkTahomaActions(); secondsTick = millis(); update_status(); } diff --git a/Raumtermostat/src/tahoma.cpp b/Raumtermostat/src/tahoma.cpp index 5de2b03..8e54185 100644 --- a/Raumtermostat/src/tahoma.cpp +++ b/Raumtermostat/src/tahoma.cpp @@ -1,6 +1,7 @@ #include "tahoma.h" #include "settings.h" extern constexpr char Tahoma::serverURL[]; +extern unsigned long lastCheck; extern Tahoma::rolloCommand_t Tahoma::movement[]; Tahoma::Tahoma(void) {} @@ -125,6 +126,8 @@ uint8_t Tahoma::sendMove(uint8_t deviceIndex, uint8_t position, if (position != 0 && rotation > 20) { movement[deviceIndex].position = position; movement[deviceIndex].rotation = rotation; + movement[deviceIndex].movingFilter = 0; + lastCheck = millis(); rotation = 0; } url = url + "?action=move&pos=" + String(position) + @@ -133,7 +136,7 @@ uint8_t Tahoma::sendMove(uint8_t deviceIndex, uint8_t position, .index); // Construct the URL to fetch all devices http.begin(url); // Initialize the HTTP connection int httpCode = http.GET(); // Send the GET request and get the response code - if (httpCode > 0) { // Check if the request was successful + if (httpCode > 199 && httpCode < 300) { // Check if the request was successful String response = http.getString(); // Get the response as a string if (response.indexOf("stop") != -1) { movement[deviceIndex].position = 0; @@ -165,7 +168,7 @@ uint8_t Tahoma::sendfinalRot(uint8_t deviceIndex) { HTTPClient http; // Create an HTTP client object String url = serverURL; if (movement[deviceIndex].position == 0) { - return 0; // no movement stored + return 1; // no movement stored } url = url + "?action=move&pos=" + String(movement[deviceIndex].position) + "&angle=" + String(movement[deviceIndex].rotation) + "&device=" + @@ -173,8 +176,9 @@ uint8_t Tahoma::sendfinalRot(uint8_t deviceIndex) { .index); // Construct the URL to fetch all devices http.begin(url); // Initialize the HTTP connection int httpCode = http.GET(); // Send the GET request and get the response code - if (httpCode > 0) { // Check if the request was successful + if (httpCode > 199 && httpCode < 300) { // Check if the request was successful movement[deviceIndex].position = 0; + movement[deviceIndex].movingFilter = 0; ret = 1; } else { ret = 0; @@ -191,11 +195,26 @@ void Tahoma::selectDev(uint8_t i,bool _select) { void Tahoma::loop(void) { + static uint8_t errorCnt = 0; + if (millis() - lastCheck < 1000) { + return; + } + lastCheck = millis(); for (uint8_t i = 0; i < numDevs; i++) { if (movement[i].position != 0) { Serial.print(devicelist[i].index); if (!checkMovement(i)) { - sendfinalRot(i); + if(movement[i].movingFilter++ >= 1){ + if(!sendfinalRot(i)){ + errorCnt++; + }else{ + errorCnt = 0; + } + if(errorCnt > 10){ //give up after 10 errors regardless what devices caused errors. + movement[i].position = 0; + errorCnt = 0; + } + } } } } diff --git a/Raumtermostat/src/tahoma.h b/Raumtermostat/src/tahoma.h index 36b3d9e..e22df68 100644 --- a/Raumtermostat/src/tahoma.h +++ b/Raumtermostat/src/tahoma.h @@ -12,10 +12,12 @@ class Tahoma { public: typedef union { - uint16_t movement; + uint32_t movement; struct { - uint16_t position : 8; - uint16_t rotation : 8; + uint32_t position : 8; + uint32_t rotation : 8; + uint32_t movingFilter : 8; + uint32_t reserved : 8; }; } rolloCommand_t; @@ -44,6 +46,7 @@ typedef union { private: bool checkMovement(uint8_t deviceIndex); static constexpr char serverURL[]{"http://nas.local/smart/ajax/tahoma.php"}; // Hostname of the Tahoma system + unsigned long lastCheck{0}; Ticker movementCheckTicker; // Simulate fetching data from the Tahoma system }; diff --git a/Raumtermostat/src/ui/actions.cpp b/Raumtermostat/src/ui/actions.cpp index c33e60e..f79ca30 100644 --- a/Raumtermostat/src/ui/actions.cpp +++ b/Raumtermostat/src/ui/actions.cpp @@ -4,7 +4,8 @@ #include bool arc_pressed = false; -bool animating = false; +bool zoomed = false; +uint32_t last_press_time = 0; float curr_temp = 0.0; int32_t scale_max = 0, scale_min = 0, lastSelChartValue = 0; @@ -85,32 +86,34 @@ void update_status(void) { ledcWrite(PWM_REL, 0); // relay off lv_obj_add_flag(objects.heaterIcn, LV_OBJ_FLAG_HIDDEN); } + if(objects.rolloScr != NULL) { + lv_label_set_text_fmt(objects.temp_txt,SYM_THERMOMETER_HALF"%2.1f°C(%2.0f°C) "SYM_NATURE"%2.1f°C",glblData.temp,glblData.settemp,glblData.outTemp); + }else if (objects.mainScr != NULL) { + if(zoomed) { + glblData.settemp = lv_arc_get_value(objects.temp_arc); + lv_label_set_text_fmt(objects.temp_txt, "%2.1f °C", glblData.settemp); + return; + } + dotState = !dotState; - if (objects.mainScr == NULL) { - return; - } - dotState = !dotState; + tm timeinfo; + getLocalTime(&timeinfo); + char buffer[15]; + if (dotState) { + strftime(buffer, sizeof(buffer), "%H : %M", &timeinfo); + } else { + strftime(buffer, sizeof(buffer), "%H %M", &timeinfo); + } - tm timeinfo; - getLocalTime(&timeinfo); - char buffer[15]; - if (dotState) { - strftime(buffer, sizeof(buffer), "%H : %M", &timeinfo); - } else { - strftime(buffer, sizeof(buffer), "%H %M", &timeinfo); - } - - lv_label_set_text_fmt(objects.press_txt, "%4.2f hPa", glblData.seaLevelPress); - lv_label_set_text_fmt(objects.hum_txt, "%2.0f %%rH", glblData.hum); - lv_label_set_text_fmt(objects.outTemp_txt, SYM_NATURE " %2.1f °C", - glblData.outTemp); - lv_label_set_text(objects.time_txt, buffer); - if (!arc_pressed && !animating) { + lv_label_set_text_fmt(objects.press_txt, "%4.2f hPa", glblData.seaLevelPress); + lv_label_set_text_fmt(objects.hum_txt, "%2.0f %%rH", glblData.hum); + lv_label_set_text_fmt(objects.outTemp_txt, SYM_NATURE " %2.1f °C", + glblData.outTemp); + lv_label_set_text(objects.time_txt, buffer); lv_label_set_text_fmt(objects.temp_txt, "%2.1f °C", glblData.temp); - } else { - glblData.settemp = lv_arc_get_value(objects.temp_arc); - lv_label_set_text_fmt(objects.temp_txt, "%2.1f °C", glblData.settemp); } + + } void update_wifi_strength(wifistrength_t strength, wifimode_t mode) { @@ -323,6 +326,10 @@ void moveRolloUp(lv_event_t *e) { ; tahoma.moveSelected(0, 0); } +void resetAnimationFlags(void) { + arc_pressed = false; + zoomed = false; +} void zoomAniWrapper(void *var, int32_t val) { lv_obj_t *obj = (lv_obj_t *)var; @@ -335,26 +342,33 @@ void zoomAniWrapper(void *var, int32_t val) { lv_obj_set_style_text_opa(objects.outTemp_txt, 255 - val, 0); lv_obj_set_style_text_opa(objects.time_txt, 255 - val, 0); } -void zomFinishedCB(lv_anim_t *var) { - - if (arc_pressed) { - arc_pressed = false; - animating = false; - lv_label_set_text_fmt(objects.temp_txt, "%2.1f °C", glblData.temp); - } else if (ui_getCurrentScreen() == objects.mainScr) { - // only set arc pressed true if main screen is - // still active, otherwise we'll lock screen - // switching - arc_pressed = true; - animating = false; +void zoomFinishedCB(lv_anim_t *var) { lv_label_set_text_fmt(objects.temp_txt, "%2.1f °C", glblData.settemp); +} +void unzoomFinishedCB(lv_anim_t *var) { + lv_label_set_text_fmt(objects.temp_txt, "%2.1f °C", glblData.temp); +} + + +void checkZoomState(void){ + if (zoomed && !arc_pressed && (millis() - last_press_time) > 3000) { + zoomed = false; + lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_var(&a, objects.temp_txt); + lv_anim_set_values(&a, 255, 0); + lv_anim_set_duration(&a, 200); + lv_anim_set_exec_cb(&a, zoomAniWrapper); + lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); + lv_anim_set_completed_cb(&a, unzoomFinishedCB); + lv_anim_start(&a); } } void action_zoom_set_temp(lv_event_t *e) { if ((int)lv_event_get_user_data(e) == 1) { - if (arc_pressed == false && animating == false) { - animating = true; + if (arc_pressed == false && zoomed == false) { + zoomed = true; lv_anim_t a; lv_anim_init(&a); lv_anim_set_var(&a, objects.temp_txt); @@ -362,23 +376,13 @@ void action_zoom_set_temp(lv_event_t *e) { lv_anim_set_duration(&a, 200); lv_anim_set_exec_cb(&a, zoomAniWrapper); lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); - lv_anim_set_completed_cb(&a, zomFinishedCB); + lv_anim_set_completed_cb(&a, zoomFinishedCB); lv_anim_start(&a); } + arc_pressed = true; + last_press_time = millis(); } else { - if (arc_pressed == true && animating == false) { - animating = true; - lv_anim_t a; - lv_anim_init(&a); - lv_anim_set_var(&a, objects.temp_txt); - lv_anim_set_values(&a, 255, 0); - lv_anim_set_delay(&a, 3000); - lv_anim_set_duration(&a, 200); - lv_anim_set_exec_cb(&a, zoomAniWrapper); - lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out); - lv_anim_set_completed_cb(&a, zomFinishedCB); - lv_anim_start(&a); - } + arc_pressed = false; } // lv_label_set_text_fmt(objects.temp_txt,"%2.1f // °C",lv_arc_get_value(objects.temp_arc)/2.0); @@ -390,7 +394,7 @@ static void anim_height_cb(void *var, int32_t v) { lv_obj_set_height(obj, v); } -void action_switch_screens(lv_event_t *e) { +void action_switch_charts(lv_event_t *e) { lv_dir_t gestDir = lv_indev_get_gesture_dir(lv_indev_get_act()); lastChartPt.x = -1; // clear labels on chart change int32_t chartheight = lv_obj_get_height(objects.chart); @@ -423,29 +427,29 @@ void action_switch_screens(lv_event_t *e) { } void showChartScreen(lv_event_t *e) { if (ui_getCurrentScreen() != objects.chartScr) { + objects.debugScr = NULL; + objects.mainScr = NULL; + objects.rolloScr = NULL; + objects.menuScr = NULL; + objects.rolloPosScr = NULL; create_screen_chart(); loadChart(ui_getCurrentChart()); update_status(); update_wifi_strength(glblData.wifiStrength, glblData.wifiMode); } - objects.debugScr = NULL; - objects.mainScr = NULL; - objects.rolloScr = NULL; - objects.menuScr = NULL; - objects.rolloPosScr = NULL; loadScreen(objects.chartScr); } void showMenuScreen(lv_event_t *e) { if (ui_getCurrentScreen() != objects.menuScr) { + objects.debugScr = NULL; + objects.mainScr = NULL; + objects.rolloScr = NULL; + objects.chartScr = NULL; + objects.rolloPosScr = NULL; create_screen_menu(); update_status(); update_wifi_strength(glblData.wifiStrength, glblData.wifiMode); } - objects.debugScr = NULL; - objects.mainScr = NULL; - objects.rolloScr = NULL; - objects.chartScr = NULL; - objects.rolloPosScr = NULL; loadScreen(objects.menuScr); } @@ -460,6 +464,11 @@ void toggleRolloChooser(lv_event_t *e) { void showRolloScreen(lv_event_t *e) { if (ui_getCurrentScreen() != objects.rolloScr) { + objects.debugScr = NULL; + objects.mainScr = NULL; + objects.chartScr = NULL; + objects.menuScr = NULL; + objects.rolloPosScr = NULL; create_screen_rollos(); update_status(); update_wifi_strength(glblData.wifiStrength, glblData.wifiMode); @@ -476,16 +485,16 @@ void showRolloScreen(lv_event_t *e) { setRolloListText(); // lv_dropdown_add_option(objects.deviceDropdown, "Alle", // LV_DROPDOWN_POS_LAST); - objects.debugScr = NULL; - objects.mainScr = NULL; - objects.chartScr = NULL; - objects.menuScr = NULL; - objects.rolloPosScr = NULL; loadScreen(objects.rolloScr); } void showRolloPosScreen(lv_event_t *e) { if (ui_getCurrentScreen() != objects.rolloPosScr) { + objects.debugScr = NULL; + objects.mainScr = NULL; + objects.chartScr = NULL; + objects.menuScr = NULL; + objects.rolloScr = NULL; create_screen_rolloPos(); update_status(); update_wifi_strength(glblData.wifiStrength, glblData.wifiMode); @@ -497,16 +506,16 @@ void showRolloPosScreen(lv_event_t *e) { lv_obj_send_event(objects.rolloRot,LV_EVENT_VALUE_CHANGED,NULL); lv_obj_send_event(objects.rolloPos,LV_EVENT_VALUE_CHANGED,NULL); } - objects.debugScr = NULL; - objects.mainScr = NULL; - objects.chartScr = NULL; - objects.menuScr = NULL; - objects.rolloScr = NULL; loadScreen(objects.rolloPosScr); } void showDebugScreen(lv_event_t *e) { if (ui_getCurrentScreen() != objects.debugScr) { + objects.chartScr = NULL; + objects.mainScr = NULL; + objects.rolloScr = NULL; + objects.menuScr = NULL; + objects.rolloPosScr = NULL; create_screen_debug(); update_status(); update_wifi_strength(glblData.wifiStrength, glblData.wifiMode); @@ -517,11 +526,6 @@ void showDebugScreen(lv_event_t *e) { glblData.myIP, Settings::prefs.hostname, Settings::prefs.mqtt_server, Settings::prefs.mqtt_port, Settings::prefs.mqtt_topic, glblData.enBuff); } - objects.chartScr = NULL; - objects.mainScr = NULL; - objects.rolloScr = NULL; - objects.menuScr = NULL; - objects.rolloPosScr = NULL; loadScreen(objects.debugScr); } @@ -529,16 +533,18 @@ void rebootESP(lv_event_t *e) { ESP.restart(); } void showMainScreen(lv_event_t *e) { if (ui_getCurrentScreen() != objects.mainScr) { + objects.chartScr = NULL; + objects.debugScr = NULL; + objects.rolloScr = NULL; + objects.menuScr = NULL; + objects.rolloPosScr = NULL; create_screen_main(); + resetAnimationFlags(); + ui_settemp(glblData.settemp); update_status(); update_wifi_strength(glblData.wifiStrength, glblData.wifiMode); - ui_settemp(glblData.settemp); + } - objects.chartScr = NULL; - objects.debugScr = NULL; - objects.rolloScr = NULL; - objects.menuScr = NULL; - objects.rolloPosScr = NULL; loadScreen(objects.mainScr); Serial.println("Main screen loaded"); } @@ -575,7 +581,9 @@ void setRolloListText(void) { } else { txt = "Rollos wählen"; } - lv_obj_set_style_anim_duration(objects.selDevicesLbl, 50*(lv_text_get_width(txt.c_str(),txt.length(),&symbol_font_12,0)), LV_PART_MAIN); + lv_point_t size; + lv_text_get_size(&size,txt.c_str(),&symbol_font_12,0,0,LV_COORD_MAX,LV_TEXT_FLAG_NONE); + lv_obj_set_style_anim_duration(objects.selDevicesLbl, 50*(size.x), LV_PART_MAIN); lv_label_set_text(objects.selDevicesLbl, txt.c_str()); } diff --git a/Raumtermostat/src/ui/actions.h b/Raumtermostat/src/ui/actions.h index ed08a50..5de5ca5 100644 --- a/Raumtermostat/src/ui/actions.h +++ b/Raumtermostat/src/ui/actions.h @@ -11,8 +11,10 @@ extern "C" { void ui_settemp(float tmp); +void checkZoomState(void); void action_zoom_set_temp(lv_event_t * e); -void action_switch_screens(lv_event_t * e); +void resetAnimationFlags(void); +void action_switch_charts(lv_event_t * e); void showDebugScreen(lv_event_t * e); void showChartScreen(lv_event_t * e); void showMainScreen(lv_event_t * e); diff --git a/Raumtermostat/src/ui/screens.c b/Raumtermostat/src/ui/screens.c index 036be77..40ca06a 100644 --- a/Raumtermostat/src/ui/screens.c +++ b/Raumtermostat/src/ui/screens.c @@ -246,6 +246,7 @@ void rolloCheckbox_finish(void) { lv_obj_set_style_text_font(obj, &symbol_font_16, LV_PART_MAIN | LV_STATE_DEFAULT); lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT); + } void create_screen_rollos() { @@ -271,7 +272,7 @@ void create_screen_rollos() { { // rolloChooser BTN lv_obj_t *obj = lv_btn_create(parent_obj); lv_obj_set_size(obj, 130, 35); - lv_obj_set_pos(obj, 55, 20); + lv_obj_set_pos(obj, 55, 18); lv_obj_set_style_bg_color(obj, lv_color_hex(0xff2f3237), LV_PART_MAIN | LV_STATE_DEFAULT); lv_obj_add_event_cb(obj, toggleRolloChooser, LV_EVENT_RELEASED, NULL); @@ -297,8 +298,8 @@ label scrolls back to the initial position*/ } { // UP BTN lv_obj_t *obj = lv_btn_create(parent_obj); - lv_obj_set_size(obj, 120, 60); - lv_obj_align(obj, LV_ALIGN_CENTER, 0, -18); + lv_obj_set_size(obj, 120, 50); + lv_obj_align(obj, LV_ALIGN_CENTER, 0, -35); lv_obj_set_style_bg_color(obj, lv_color_hex(0xff2f3237), LV_PART_MAIN | LV_STATE_DEFAULT); lv_obj_add_event_cb(obj, moveRolloUp, LV_EVENT_RELEASED, NULL); @@ -314,8 +315,8 @@ label scrolls back to the initial position*/ } { // DOWN BTN lv_obj_t *obj = lv_btn_create(parent_obj); - lv_obj_set_size(obj, 120, 60); - lv_obj_align(obj, LV_ALIGN_CENTER, 0, 52); + lv_obj_set_size(obj, 120, 50); + lv_obj_align(obj, LV_ALIGN_CENTER, 0, 35); lv_obj_set_style_bg_color(obj, lv_color_hex(0xff2f3237), LV_PART_MAIN | LV_STATE_DEFAULT); lv_obj_add_event_cb(obj, moveRolloDown, LV_EVENT_RELEASED, NULL); @@ -329,6 +330,17 @@ label scrolls back to the initial position*/ lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT); } + { // infoLBL + obj = lv_label_create(parent_obj); + objects.temp_txt = obj; + lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_label_set_text(obj, SYM_THERMOMETER_HALF"24.5°C(20°C) "SYM_NATURE"18.0°C"); + lv_obj_set_style_text_font(obj, &symbol_font_12, + LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_align(obj, LV_ALIGN_CENTER, + LV_PART_MAIN | LV_STATE_DEFAULT); + } { // ROLLOPOS BTN lv_obj_t *obj = lv_btn_create(parent_obj); @@ -356,7 +368,7 @@ label scrolls back to the initial position*/ lv_obj_align(obj, LV_ALIGN_CENTER, -95, 0); lv_obj_set_style_bg_color(obj, lv_color_hex(0xff2f3237), LV_PART_MAIN | LV_STATE_DEFAULT); - lv_obj_add_event_cb(obj, showMenuScreen, LV_EVENT_RELEASED, NULL); + lv_obj_add_event_cb(obj, showMainScreen, LV_EVENT_RELEASED, NULL); lv_obj_t *parent_obj = obj; @@ -373,6 +385,7 @@ label scrolls back to the initial position*/ { lv_obj_t *main_cont = lv_obj_create(parent_obj); objects.deviceDropdown = main_cont; + lv_obj_remove_flag(main_cont, LV_OBJ_FLAG_SCROLL_ELASTIC); lv_obj_set_flex_flow(main_cont, LV_FLEX_FLOW_COLUMN); lv_obj_add_event_cb(main_cont, rolloChanged, LV_EVENT_CLICKED, 0); lv_obj_add_flag(main_cont, LV_OBJ_FLAG_HIDDEN); @@ -651,7 +664,7 @@ void create_screen_chart() { objects.chartScr = obj; lv_obj_set_pos(obj, 0, 0); lv_obj_set_size(obj, 240, 240); - lv_obj_add_event_cb(obj, action_switch_screens, LV_EVENT_GESTURE, (void *)1); + lv_obj_add_event_cb(obj, action_switch_charts, LV_EVENT_GESTURE, (void *)1); lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT); { diff --git a/Raumtermostat/src/ui/ui.cpp b/Raumtermostat/src/ui/ui.cpp index 791cd5b..8ca9acb 100644 --- a/Raumtermostat/src/ui/ui.cpp +++ b/Raumtermostat/src/ui/ui.cpp @@ -17,7 +17,7 @@ Arduino_GC9A01 *gfx = TouchDrvCSTXXX touch; Ticker fadeTicker; bool isPressed = false, sleeping = false; -unsigned long lastTouch; +unsigned long lastTouch=0, lastAniTick=0; static lv_obj_t *currentScreen = NULL; static enum ChartsEnum currentChart = CHART_ID_TEMP; /* @@ -136,6 +136,11 @@ void ui_tick() { lv_task_handler(); // let the GUI do its work sleeping = false; isPressed = false; + }else{ + if(currentScreen == objects.mainScr && millis() - lastAniTick > 100){ + lastAniTick = millis(); + checkZoomState(); + } } }