From 2fe226f8a1755e1cf487c972b56b9166b4f2ff4b Mon Sep 17 00:00:00 2001 From: sandyjmacdonald Date: Fri, 8 Nov 2019 20:26:45 +0000 Subject: [PATCH] Adding all in one weather and light display example --- examples/icons/bulb-bright.png | Bin 0 -> 2533 bytes examples/icons/bulb-dark.png | Bin 0 -> 2817 bytes examples/icons/bulb-dim.png | Bin 0 -> 2817 bytes examples/icons/bulb-light.png | Bin 0 -> 2820 bytes examples/icons/humidity-bad.png | Bin 0 -> 2983 bytes examples/icons/humidity-good.png | Bin 0 -> 2530 bytes examples/icons/humidity.png | Bin 0 -> 2983 bytes examples/icons/temperature.png | Bin 0 -> 3188 bytes examples/icons/weather-change.png | Bin 0 -> 2770 bytes examples/icons/weather-dry.png | Bin 0 -> 3155 bytes examples/icons/weather-fair.png | Bin 0 -> 3155 bytes examples/icons/weather-rain.png | Bin 0 -> 2850 bytes examples/icons/weather-storm.png | Bin 0 -> 2732 bytes examples/weather-and-light.py | 409 ++++++++++++++++++++++++++++++ 14 files changed, 409 insertions(+) create mode 100644 examples/icons/bulb-bright.png create mode 100644 examples/icons/bulb-dark.png create mode 100644 examples/icons/bulb-dim.png create mode 100644 examples/icons/bulb-light.png create mode 100644 examples/icons/humidity-bad.png create mode 100644 examples/icons/humidity-good.png create mode 100644 examples/icons/humidity.png create mode 100644 examples/icons/temperature.png create mode 100644 examples/icons/weather-change.png create mode 100644 examples/icons/weather-dry.png create mode 100644 examples/icons/weather-fair.png create mode 100644 examples/icons/weather-rain.png create mode 100644 examples/icons/weather-storm.png create mode 100644 examples/weather-and-light.py diff --git a/examples/icons/bulb-bright.png b/examples/icons/bulb-bright.png new file mode 100644 index 0000000000000000000000000000000000000000..5697a81bf2fe2f2a7f45f7e448650ba321cb92e5 GIT binary patch literal 2533 zcmbVN2~-nz8XrYak<ww?E8@;`px@4LU8^zv{c z=x@~r0D!=E=lS5jCfav{9{&APbRY--E7~Mnu9ue*^$JHZ6!dX(0RZc)v)O_OU+2x5 z^L(pF@4Z=T$g3T880*#xHve_%fpyNmG(F_(zVBb(XH<61)QjZhA37&!=5&k>RgRfY zCT%`AV|fSZC#DzdG5X;~OxXQs)-yz}d8Fo#-DH_dHneTLTS+x-DyI}%Ry4<5JN`Ap zzb8WtIMw#($L3F-N(}DZ2;BVw-}c8AyH!SlMRkURuR;)nGiZzseBXJ-dqe z)$d}|u08dNRrz~&M^-=RNP0f(;*eP6;X}wLfsal;_JUU4-p((`o7KC_8f#mDmCZi* z>gmbT<(J9k$9;2Bu8h;)-<5OLwyANv)MA90+oCa;n8;7RYv}Oj$NSRR)amz5*#ZX# zdx|+t2X}mO_?StokXe|q{Zea+ft$wag4@i#)@Tz0H)Y;jwYTNYp?ZGciPo#^^TYKI zGYaDzzG+BJEgT{HC+eH_9&QR4ot6J1=)J?aEu$|7+ZtwSW4#Z2|HRlC?sb|owMxDlS@wF>t@6##76u6}krph&okQ$#AI z^U6g+3L-^hh#XVlSlTickCH&J41XuBOty?xVXjAUixz!*CtBqftw1O~hzgBV3K7?% zxJJt*!xY+%R)wSg#gFCdWp5M^SBbzFs`Nuq=~ANR=Yp06BoRmdFO*0KiBY8t#$zLq z!C?qRArG6^ArL@(xe9~jLWIv_6LH(f5{U?MuxBvs5T=ksV}y!Hj8LYS6v`6YljwB1 zJ&j7EGMG%^k~|L;Mr!l6Brp1v@}5cw-Z!xHxAQFL1>&MoR4G73cv$U-;7{j#d}1q6 zu|$er{Csk2D|^1eAa{uhPh<3AulOQI7FSXUIA2r{EY#LLn<&&K91#&0k0rl3dJDAb za0DlPcMU8cRHztJ!%DevxiO;T0#v^qAu(E*9bM^~3{-`6^-PhZ6wW8$9qkF6qk#T>7{Tsjdz zo71owQu-(o;YgYL)$4mU(db)+o2a4 z%bd^Iy)`Ctdv=#)H;Pvs_|}lTgE8>-&NJlW1VX$i=rh_$SQppz;^1J)ps{I1>6aHL z@06(&^?AXim8q>94!NVky5MSFghOzc^f2e`Yr>fij9FvTVA{iN5d+(7PIV5mA`B`g zcg4J}SLa+v(A3HuH)IKO+nMA)+&CnjX)eFj6l+nT`no%=Y@-=1m+$%cMX)$1(W867 zhZVcWvxE)nJ_%fdet@+%5V#LGI`%R8_ooNi?@ZtDJaTBALA=)&(&Cgenm7KgCfG;N zj=nt<>{eqw)6pZ$sxQCf_f^l;CFWKH6{j(1jOtv=>5g;scds=Ro5!}VJzwZ|Q(`*0 zW;_aHSvKFS=nA%N{F^Ub7MO9Y(aQ#VYMN%2 zsw;?)!+Y03<_!ZnZ%B{M^pA~@GOOg@>I2D)7wyb|O zb+5^3@LXj@MYnN@niE^;`u4WH4$N$O`nb0!f&H-NhgU6zE`R?PRz-fAS5Ntjr#&1aPZ@Kx;INv9?_Fg@kRc)Pi_g)Ln@k-GgBs=P9Bb_3= t?>sl%Zk<-`v;W9hy;l?5QL`!a=;}7%Yn_)i8e8pOHQ&{Pcg-av`QNaA<`Vz_ literal 0 HcmV?d00001 diff --git a/examples/icons/bulb-dark.png b/examples/icons/bulb-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a91e24b580505621046235f3ded1a7058bb0281a GIT binary patch literal 2817 zcmcgudsGuw9v(#j5e17Yz8xpRTFT@(nUGmhN&*6v@Dd9ub)C#iAcbT?G8ka7pcNF+ zQe<6^rUEIIm#nXqZYd}aU8{7dh@!OA(pKxLRjI;S6skKD9`)>MkEeg^oHLoZ_kQ#J zUf=!QOmms*0sz3Yu+X3w_Bn^U-5uHAKWD500boL>PNj;9GSN{BfeO5Wc&fjK(dar$b0aa|REQSOS}o2v)J3trv5&-d)ffy0aYP-}ah>rX%J-|?x3 zY}cjm9SY&2=>@((!p)xAfU^nS@2vgPoGb#ZEc7Zrx7jr$Z%J9mQ24owIj$il+vCP) zp3m);uvJ^n9Z;0sZMjfbxk2`I>y|B*ef+o_m-)SG&&J;yHhi{b`dVxIy&rFOwhlFA zMZaK_~F?xkn2mO6GI|4 zsy+}VX6J zlP&TTW9TX~0L=2@?g?QrOMV0Z$3wcEh!80#lk-KW1d+>qL9tNeClLAx zL=sqpVu%nEi^0(gVy&4-Efy2BY}6JzQb0)zW5fgki^amXNcglVQ6Q4b5PnyHh>%>uA$Qy1;lzf5`x}1PHQlario3MARRXfM0_C^ zk{w7A<2YlQDaCG_Bm`6nrKb#xnZ=66v22#q>T&opY4!SXw3!KB&w4Z(+cVMT*bE~j zh@s4Mnu(x-*RvLRV~!cQ9c@mcpA*OU@^~~xOl6{QhBn30bjnzv?0tb_0aYrlFmiCI z8YgrHj{0TJ)aX}K5YA8vh(o|45iInJ6^Sq@ib?!dkD%174oIBA{}(65gfdJb9K+G1 zPMh&-D3ZXmv`LS%xzXwIL`q;ZB-(AL)mWIp%-{xs3JX#|tZ#gsj>NL)|Q5}3ph z4UA|tI4sAdtdFRSl%paMLdo&5?}KO}jjJ2?{fLA~nqWD`vxSNLq=<~7a9AQF30OoT z2#jmQ2rL(q8d54H2&o1cV~aHD*jivaicX2t``hPsFN1gX3a9i3TBr1S^B*x&Dhtf3xeO+(Z&? zNTk@7Du8}_FfXR*|9db3u9J=^Oz_|0v#&kXb=gANr`T4`y^fzD>|p#9q6}=FOzas$ zKlsa40GK#8EGRHGK9?ANV!!6(`LFxnVCup+aG^xeY`BNrd*4RHSJ&#uaO zcXB%B1iL@l4z2&W{Wx>~%tzYTf+njn$x2+?b2)Qq{cjdx3UZU z4bklzio$t?wT%UDoo_9;cn^60K~6{Sr06@T9=s1rPsMx|;kGNl^83A;0Mpb3OS>o7 z&}BB4hTC3M#mC%LPA(U>O+h|c=Gax@m0dlbmwnlG|BK%DDoW#n^PS%aI>y4<$y&~a7ND>_}=jrk86 zJ5g(E&)_7*7SV|mZ-D5Z>3L;Ogtg!?y5Xy zs~M^ec6%C&iQ7W-hHOZQJmmKj6#-%l>yY2dd}sYMz7^ zMkEeg^oHLoZ_kQ#J zUf=!QOmms*0sz3Yu+X3w_Bn^U-5uHAKWD500boL>PNj;9GSN{BfeO5Wc&fjK(dar$b0aa|REQSOS}o2v)J3trv5&-d)ffy0aYP-}ah>rX%J-|?x3 zY}cjm9SY&2=>@((!p)xAfU^nS@2vgPoGb#ZEc7Zrx7jr$Z%J9mQ24owIj$il+vCP) zp3m);uvJ^n9Z;0sZMjfbxk2`I>y|B*ef+o_m-)SG&&J;yHhi{b`dVxIy&rFOwhlFA zMZaK_~F?xkn2mO6GI|4 zsy+}VX6J zlP&TTW9TX~0L=2@?g?QrOMV0Z$3wcEh!80#lk-KW1d+>qL9tNeClLAx zL=sqpVu%nEi^0(gVy&4-Efy2BY}6JzQb0)zW5fgki^amXNcglVQ6Q4b5PnyHh>%>uA$Qy1;lzf5`x}1PHQlario3MARRXfM0_C^ zk{w7A<2YlQDaCG_Bm`6nrKb#xnZ=66v22#q>T&opY4!SXw3!KB&w4Z(+cVMT*bE~j zh@s4Mnu(x-*RvLRV~!cQ9c@mcpA*OU@^~~xOl6{QhBn30bjnzv?0tb_0aYrlFmiCI z8YgrHj{0TJ)aX}K5YA8vh(o|45iInJ6^Sq@ib?!dkD%174oIBA{}(65gfdJb9K+G1 zPMh&-D3ZXmv`LS%xzXwIL`q;ZB-(AL)mWIp%-{xs3JX#|tZ#gsj>NL)|Q5}3ph z4UA|tI4sAdtdFRSl%paMLdo&5?}KO}jjJ2?{fLA~nqWD`vxSNLq=<~7a9AQF30OoT z2#jmQ2rL(q8d54H2&o1cV~aHD*jivaicX2t``hPsFN1gX3a9i3TBr1S^B*x&Dhtf3xeO+(Z&? zNTk@7Du8}_FfXR*|9db3u9J=^Oz_|0v#&kXb=gANr`T4`y^fzD>|p#9q6}=FOzas$ zKlsa40GK#8EGRHGK9?ANV!!6(`LFxnVCup+aG^xeY`BNrd*4RHSJ&#uaO zcXB%B1iL@l4z2&W{Wx>~%tzYTf+njn$x2+?b2)Qq{cjdx3UZU z4bklzio$t?wT%UDoo_9;cn^60K~6{Sr06@T9=s1rPsMx|;kGNl^83A;0Mpb3OS>o7 z&}BB4hTC3M#mC%LPA(U>O+h|c=Gax@m0dlbmwnlG|BK%DDoW#n^PS%aI>y4<$y&~a7ND>_}=jrk86 zJ5g(E&)_7*7SV|mZ-D5Z>3L;Ogtg!?y5Xy zs~M^ec6%C&iQ7W-hHOZQJmmKj6#-%l>yY2dd}sYMz7^ zDr)fob&F*fK(S?#nPifXsR1F;5FiLhE54A)%mkuICQb$dXccHd ztx^lDMUM}}2O@fWuC*Sk5ba`NeNc9FTTzQzMYk1vu!{oQ-5Fl>Y_-SJb2jHpa_8Rf ze*f#c|IM0&cPDo&xgbapbz$9%H z0EComE!8iX9XYo7+c~gdQCC;4R@!0{H|wBA>}uVT12I-cmH(}JMnFgld>Lr zH*#gs&u+d8PdxE|nm>L)PvBSdEvUFE#`nR|-1Lh%$~M}gvE$SyS4EbnQvA)%t1RNz za7?^E@QcO|4itWa&1qTh0H)Qpj99+=>Ds(S-+Ke+j`Od#mhab|$OLQZ##ySoSEtwg z=qqx7D}eV-j^n2H4wKivlk1q#;3gTI63iyZocQosvo6#&PyM8X^VokYkT4@woR_*B!&B+_#_kC(Z%A;QEU*?Za-F)HE!~4x= zdTN&^zJK?+*ZFOSCl{~l99ixg|Mt$?P)TFho7!V_b819)n&)o5FdX@bIP^vmMr7CqMv06xLO2TjQ-T#7ypCmD-~pcn%!%C^{eGyqJC$hHyW z5}E@Ibh^o^f;vvtLZFFKL33n!L~m2m8K&r5mY$s(pG@X1A(a#q5e`nv#(4q@%@JU> z#cZ|X*(#`y7w5;qv={>WAlwoa6e$=4Q}hX-nqg^BCX&M>ipfBQQiRH-m{J)EN)R+m zjD(3%DU8Z-48bK5aNq;+)>z7jCuwF5*y7(*PzJ}@aIx6oaEKgI5yPg7QKeETMkHd1 z1m+R2J;%xs*|60fILM%(?IdfmaVEwJ3XFt-$>dZJ?`eMs7TXZ5)jp6WK4Ic)!X`#V zh!9dAkRpe0woKOCXPhF%w3)WhR?g02(IG6KCB1$K{z6)dWe9EOW@Pam4aD|Bv^_b; zMvIeZJCn(h^o%UtV&I@-HsM6uGnkjeF|<4sjSW|`G{G@!GQ*e$3)R;b1Qt-O77C*T zL-Yh`vI^8w1ycjNXbr*9Do8-UC<-HC$ta4;wqFS;@3C{jwo;$I*4N^ zlQHMFP!x$98P-DZxiMLYbXsh)ruW&<>v5gc&Jk9U)@f7_@0-YEqHqZohDwYi0wW4q z31bLGzy>LTz+osRSD=(sW}vab{ThbM6zV4I@0T#ekUYmwws15IHOLW(oZl`nzy>)c zfy1OSDQq+n7^M^p86|^kvse>EqhU-!$zX#)p@0!gN*WCYibfQQ!O(y0`Y$5=-L4O$mCPWl z=``O`#nA5$=G8R)vO4_Vf)NXyv|nN3{}o@~+H+l(FJ#{o-^zvI&>h0R4BbMsmCqB) z-!X5+4Qm1b*GW1}WO7R3^^LJ1nnb_)j%c6IPhX!oyfV5}>mv{GX^by1YhrYt8P68E zk6eGqJMpVe3)6Gr)Qf{EyjVrTXIx*!|ORrDYe+>M>hg8b7bD^tIH_J+kUU_pH>2@N2QvAs_Gf;XCJnSmf#=v)`=X zeQ9l>8(W*MHI`3n2NpDJIO-Z&d_3Q|EOh0T$axiYZ3)k+PTjxjvcD$n+3jodW=u`X zD?2zVnQ%*68nCZa8ch|hp0xBCR5 zdANApcV}X{Rr5vD%j-{0h!r1AyAXKLUspaeHvAqwVPvZ$e`o%V@L?VEwk@uj|KKuo zrDKbWK6uAyuXYVfrMj0j-+y?g)454Y_)Kq}{^R77h^hF|AHdovx<#w4v^@XOitRUx z!#6$-+3y~HudOcpRDs_*&slIco746f>RJ}>8L-Qd($QO*nsxljtUq^~7v`pa=C`ZD zy4$kz^X@x_rfGW|#)ioDy#e+K*{9uVI>*m`%}I85Q9;9&ul?rTC$-9B;Vx^g*G;+P SB&G=eWOOs)H3y>73jPa}A{>^gG5?}8?;@95zj5Q^`zlsl|0)R;)CKCDkYjOW5T#r)&#a;j~BYQ`VbY+mI zP5Lg$R71dmY;(F9cbeVEYN^fM->=QcYe{dW=RElJ%~f{!o$hM6x^#|bQhM)jN<{f9 z$F3BcrQJ^7q7P}A`{z@hpGr_(jpsi`P3zjuZEB*cymAB+JDRl2NwuYnqfXz{tu9Wx z&JJnLiUsCgXeK4@>)M#S>^>Q|Tt>V;Ogt(sH&72(S*!MwHz=!~QRuPMHNc_@YyD?E zBRH34C&cTkx5o^4jf`-(GlelMnj^j@buNf6Tb$FBo>-S+c*V$MhioRilZ% zr03eDM;W=L2kDM!L3!&Ab+9J8=k0K*t?4*1rH!+_KHZ|Tb6@6VYwng?3p0hxx0V}S zfTd5Hk9yQDowhdeU-pRz=RlV8o`!W6;`FJ7;_ihF@%9#CZBcJ!fYYqjYDw6Jh9kmV zFRE{39azo1cX9pt18ww>WYVPjk+q@iJ?bBpSVnHIZ-4o;@nZLd#DK-W-nF>0^W?P5 zFFQu(QT%4@c|^;u<4qKoR)rj<|I!$?y?zw46+U4XNV6EXYna$CMYNk4B_rkJ=GKg} z4sfax7aerUrrdepVw+@DSTd@u&dYpN$Ls1NN!@FPANI;Wl%1MJA&NXo;~S;}09$9{ zV1T7kr;1`S}tVH;7nuj}eZk&K1P@#I58mEd@>jZH^S|6`~7#pV< zG-@A2zfwr^G#aFaO8u!KT#HiO=o}D%*ltuVpAK}hHHz6%buh$3|jM&&%daNrQ*D4thpU-D7Sqv5nBoLr3Uag1Y zK()?kkii?(AzDnM$8a^($Oy}DgI-7@Jnaubr5U1C>ju(9B#aRUYZwrnX$+|kC`X2H z8iO{v&$t|6pwXxbRqJ&G78=45S&~YJ;2)$_sfN%xy-y6`(Lih;MC*d%H7Fwx)!_y$ zg8IY|7M%ti(-=>*E(-rh97D@P(P#uBEeh*#Z7_~U4;HGgFBn;%Ab}f4;K~c{M@b1C$YDMFR~$mTa;}^s2O$LEgKUV+ z26+ky0a2DK%15{?6m>-g_j}`r!B{ur{(cF|afIL)%9emHW3pWlHyDIq76h`~*nCjN z=D31Phz%n$rkscH*n@1JYcb*!!O`!t8oiPej9fQj7s^3Eh%HlqY#B!Z%J>R5ki}xT zK}?9r=5PqF{geG(JEi18E%X^64>sGK%1jeQ`OpXPNxZEO@ukbYPZ{Rkbd(8t1B)Kf{M{L>W2 z_?YuLIOgwNSIGHX8H-Q=Q6nD6=JH{X&q7(CLdHd4H#w8d<+27t|EueNiu515K9E)< z3RWvoqNOru|2&va)AYyc@P7-2VeF*+3S<1Q`1;n~>$*fC`=*FiZX6EXA;injErhCx zJZXtL=E{xyBmfvzCGqwQ4o$1S{kgAAz$CMmI}H0HoJF^K85Pmw@eXyVz2XQN9ZVso zo*d=1)$G|==cvi^XYLJpUX&W0ZD~uM8oHTkLngxk59i&?@hl)MIO}|-_U!SRPVU7! zn@(NG&*+J8pObWN`+fXP{dR87STFOIxA(J6dKoWU4R-=aySVv=2fb#Juu=A1R@E8{ z`o^D|s}pCg+nr!xdj3YtXcu>^DR^S|)zFS{9IMe0`ekW5&;I-QiuubMowV~-Uu%79 zNhzr`e-rZ5S~5$6SbdfFHs(>AmQv``Q})yA$rHlIg~d1)Z+x1?Al1~VpDccTdHOhJ zb8f}El938~Ua)V5)vfP}T7Ps535R*4kgkr)-NjWYeqFl74-bVsemB{2e91A&3y&3= zi{U5ETRZ$@xy7@qeP&O)gXOhMyQJZG{?*9FD>bs2!>msnBOkur(=g zym)?1OF~@kz3HnS(T@pllIm$=vdbL-yJWvqvl%Z@IcOWP@$#9JrdR zHYvEGlsjj(G~GUZZrkm9GYUA>cgryGoH8@T6mr4pS+{_Z1vj+CzX(rf9XGs`VOaB9K1y_}MUaF44aI~~KMk*4;uzV%sPL*D)T@|hBC zEnW_8OY3mo<9J#>qYH2i^56a6;uV{vjWHX({<`AbvMo%*+B{0d=7Wxkx}t?Ys58!& zAIQ3%@fb@QOPcUSQ(1Yy=^J@)Qfgk_#%_o9duzezQ4cRX`2LwlAF(dQj^Wt6Y(v`P z<*)1}fj>L%RIiKO6l7v`%(f6)b!+~Of+y9OUFC>Qhvfe#x2ckYmK4v+0P0ktlZ$>e}!Y6>K=A(c?B7U)vi$;=m$CCS7j7+|dm z0+lMu0^3q$6<7;+upV_?wb&J^)rwUp+Uf(VZSCqtYKv`Cbp^FET=m(X8P zj)%s-{z*!WLU{Ypb+J(1)uGOW6M6I3Z=_ig6!3Sb3V;Kk@L-%_2lm!&2KvO&GoAT z?~NW_k^cOZ3qc=l-ZQ^uz2{er5vhx|e1X*U%4Tc!b!TrETpq}6Iu#(iM(&QxK!QS= zy)~(2s=o@2`oQ{zh9e=N>HKa@>sEeU#QD!+!&g1l@^-*TuhM^+=lh-=t43GO*sk2L zt**Q>f=zOOEjiZ#LE$mn>!ru+ACD<{yj3Mwi#9637k~o8KjxG&WF?Ik;1#u{aOQdkTT!6=kC31NzEE3`} zOen)}F^b0#5+NZH!IKZdTC>vzB18T3q%C%)K#WeOjleLM%O!A$1&qA_!{u^0CKO>J z5y~P^M~T%*7Nb@Ne~Lj39F*N;bD9_{%rTOBrpT#4Sfvv#SZvd@R>x$R*nnZhqz%Ib zLe8ZrpicMmP>W?6?Qkwx&RUt&`#@qxR*4N@8Nk65*(tDOIj}nUQ^sg&`mC+UZXWlP zrZ8Xz78d4Uh2hhtY}}1@7@42&V|shq8ylgr1JcRZvlzxam8kK)z_Gw86_*$}yii9{ zCM!q%1Sf0q6i|~+pg=eTisPtImW9g*TtY}hFHE3xY#q>~ll(;-Lz@gGzkt%|2(8uO zB&`(Csuc*ULSQn{gixZF>V>!v#SK7;N@#XO>ZKx7Dwh~!QaLH7a4@chJ+Ee{A}(m$ z`H5ns8H(kYjtfCk00%Un&^W!AMuoIQjLKwq9E!`uVi5@>2DwB$#rCY-#NHRud_OCv zie?#QKqS)RQh-WjA{ilO%I6h!}&5n>oNkC^uZM|fp9Per;D_Mqyjb(4_9&6PlQTk+9DI;ku0BlRe5Y8ElYd#Z6!TvX2<9qitswp_z{kY+D+hr%yjT=~5YCGGO zn`HY%><9h>tvV?yr;-}GH~vKV&KfIA^A_>m`B$hi;V(h01=o2JuPb$BZ5tXBjehg| z?_7E#XS-pc(8lP-2Lc)c)TI?&KFU!-Wy}xv z|LUxF>zcD`#eQ>lZ%lHpsp8#6v&Q@+?Jor+x?}p^d^7B|lhNUqV$EfxFya4P9&gs= z+`sW|pLx;$-HvjZ<6c;zTly^Q8L8wAhHorv_9VJb#n1D!%|4KVi1ub~j#>ugWPDye zAW#n<@j3eI+U$^do{kr;z0VKI`+fATTa{;&{~lf-s!iJ*RqZqK!N+>b^Y&?^&HVIONlI^G}V-pJ0MQmY$J`GcHEH^}5D=F*5p%_GMe@4BtQI3;*Mz z^gG5?}8?;@95zj5Q^`zlsl|0)R;)CKCDkYjOW5T#r)&#a;j~BYQ`VbY+mI zP5Lg$R71dmY;(F9cbeVEYN^fM->=QcYe{dW=RElJ%~f{!o$hM6x^#|bQhM)jN<{f9 z$F3BcrQJ^7q7P}A`{z@hpGr_(jpsi`P3zjuZEB*cymAB+JDRl2NwuYnqfXz{tu9Wx z&JJnLiUsCgXeK4@>)M#S>^>Q|Tt>V;Ogt(sH&72(S*!MwHz=!~QRuPMHNc_@YyD?E zBRH34C&cTkx5o^4jf`-(GlelMnj^j@buNf6Tb$FBo>-S+c*V$MhioRilZ% zr03eDM;W=L2kDM!L3!&Ab+9J8=k0K*t?4*1rH!+_KHZ|Tb6@6VYwng?3p0hxx0V}S zfTd5Hk9yQDowhdeU-pRz=RlV8o`!W6;`FJ7;_ihF@%9#CZBcJ!fYYqjYDw6Jh9kmV zFRE{39azo1cX9pt18ww>WYVPjk+q@iJ?bBpSVnHIZ-4o;@nZLd#DK-W-nF>0^W?P5 zFFQu(QT%4@c|^;u<4qKoR)rj<|I!$?y?zw46+U4XNV6EXYna$CMYNk4B_rkJ=GKg} z4sfax7aerUrrdepVw+@DSTd@u&dYpN$Ls1NN!@FPANI;Wl%1MJA&NXo;~S;}09$9{ zV1T7kr;1`S}tVH;7nuj}eZk&K1P@#I58mEd@>jZH^S|6`~7#pV< zG-@A2zfwr^G#aFaO8u!KT#HiO=o}D%*ltuVpAK}hHHz6%buh$3|jM&&%daNrQ*D4thpU-D7Sqv5nBoLr3Uag1Y zK()?kkii?(AzDnM$8a^($Oy}DgI-7@Jnaubr5U1C>ju(9B#aRUYZwrnX$+|kC`X2H z8iO{v&$t|6pwXxbRqJ&G78=45S&~YJ;2)$_sfN%xy-y6`(Lih;MC*d%H7Fwx)!_y$ zg8IY|7M%ti(-=>*E(-rh97D@P(P#uBEeh*#Z7_~U4;HGgFBn;%Ab}f4;K~c{M@b1C$YDMFR~$mTa;}^s2O$LEgKUV+ z26+ky0a2DK%15{?6m>-g_j}`r!B{ur{(cF|afIL)%9emHW3pWlHyDIq76h`~*nCjN z=D31Phz%n$rkscH*n@1JYcb*!!O`!t8oiPej9fQj7s^3Eh%HlqY#B!Z%J>R5ki}xT zK}?9r=5PqF{geG(JEi18E%X^64>sGK%1jeQ`OpXPNxZEO@ukbYPZ{Rkbd(8t1B)Kf{M{L>W2 z_?YuLIOgwNSIGHX8H-Q=Q6nD6=JH{X&q7(CLdHd4H#w8d<+27t|EueNiu515K9E)< z3RWvoqNOru|2&va)AYyc@P7-2VeF*+3S<1Q`1;n~>$*fC`=*FiZX6EXA;injErhCx zJZXtL=E{xyBmfvzCGqwQ4o$1S{kgAAz$CMmI}H0HoJF^K85Pmw@eXyVz2XQN9ZVso zo*d=1)$G|==cvi^XYLJpUX&W0ZD~uM8oHTkLngxk59i&?@hl)MIO}|-_U!SRPVU7! zn@(NG&*+J8pObWN`+fXP{dR87STFOIxA(J6dKoWU4R-=aySVv=2fb#Juu=A1R@E8{ z`o^D|s}pCg+nr!xdj3YtXcu>^DR^S|)zFS{9IMe0`ekW5&;I-QiuubMowV~-Uu%79 zNhzr`e-rZ5S~5$6SbdfFHs(>AmQv``Q})yA$rHlIg~d1)Z+x1?Al1~VpDccTdHOhJ zb8f}El938~Ua)V5)vfP}T7Ps535R*4kgkr)-NjWYeqFl74-bVsemB{2e91A&3y&3= zi{U5ETRZ$@xy7@qeP&O)gXOhMyQJZG{?*9FD>bs2!>msnBOkur(=g zym)?1OF~@kz3HnS(T@pllIm$=vdbL-yJWvqvl%Z@IcOWP@$#9JrdR zHYvEGlsjj(G~GUZZrkm9GYUA>cgryGoH8@T6mr4pS+{_Z1vj+CzX(rf9XGs`VOaB9K1y_}MUaF44aI~~KMk*4;uzV%sPL*D)T@|hBC zEnW_8OY3mo<9J#>qYH2i^56a6;uV{vjWHX({<`AbvMo%*+B{0d=7Wxkx}t?Ys58!& zAIQ3%@fb@QOPcUSQ(1Yy=^J@)Qfgk_#%_o9duzezQ4cRX`2LwlAF(dQj^Wt6Y(v`P z<*)1}fj>L%RIiKO6l7v`%(f6)b!+~Of+y9OUFC>Qhvfe#x2ckYmKHox3AZ11LlZB8Q-&(&_F%grs999Em6%1a&na zpyePcpbH*&qYfSjh@}IrfG`S*qX;VNi3gsbvmLInc67>`s_m*yzkcs~-~au``#bCX z{k(@-kFlmuC_|+_UIFBDwE6ztiu~QIpGT!oENYdWp8oy>?jMQkaB6_J2Zb^|ZAZE+ zDo`>aIa}%yGiO%XAjUv}tHXdY*@%C=uNlAfZgL|dz3IW5D(n)E)i$wYRle=Ih|iH2w2tO^Z2OQ@`rbGY`Sa{eA&M^8o6#_1FDH{mzY(=I3@=?S)>| zTIh~-)?92^pK)R@!`T?PHECZvd+e00J0?|>w;%bjjh}TT+2-xrJkupR!Ita3CNb;7 zcN->A!X7prm|79$x@OU`(Fq8DPwKec)k!wq$u2qG9lq82(Kg;h?x(YJ=o6llN$0Jr zE)ZuwE2~T0vs`fd{Mxm9+87}#t)1>HstA42slL46yG2=7UOazTd%mM2Vb0tKzuEkI z=TTSF#`Ymw?foX~ZlR@B3LU*ql!okQ+^?ONb!9N?34FvMfMzp1yPvn;D$iZ4NV#=- zMn?H?yE*hy@7%rgH2a38Nuv^n>)fLtC`05L#5hYLZIsB9J}WU_=zkOP2x z5tk)mv#C87jkHFf3Q>U9j2>I$o0t}<(`iIZW?WnxBaXwsi3lbLK@gM0X0q7;i2$^E zwGNI4)LMEkgBPYn2&G1+#MM+YBP_>bbYdE*wA%%hrjJ&w?FkbZFlIcgVS)^n*`+QZ ziuB<$F+_BiaTH-<(U=NT>$D^m?8A~#lF9nuU!+y3`p{b4^jK0+k8fW@YlHL}j2VDw z@fZTZrpJ;N>Ak`<<`b=r#J}Q4-*TTf8j&Y~!8)7>!tvBmU*-P6i1#PZuzckhpj#7NRFS41~Liz{?-Fo8)T$dG?q z#WBAoUJJ+mwR9E+Vi*tM0T2w4Wq`6-fRG1a02fn0Fe;a0Y$4X``k$r$QKWxcdQVu9 zNLU?#ku8-;`}@v(TTOp05C1o3nC4E}U17}sExxX`&$=#|$gU}}m79ls-w^Vp?<<6< z$v6?@H^#YU_Gt>m(j@hg1ce%})Gv#+kvI)}z91wf5(*{&;OdN#iD7x`2T8b}Y?FpV zE*^ASscq`ir1-a~hHMI3k$7+$&2T3J`gM$pg)q}`efVe%i$e9@dlnR?_*|%<9VENvFNU8 z*piakh^g-1f6R`#p#EK7y7h4B@~FElZt_$3#ITO1&M{s`&#%vDswcqG<=R~R$ivmf zis{c|x5t0nA=89cEq>;MjtaYJF}W^01lU+;JXF$ot|6^;9LvpmO#OdMQ7a`A-0B~4 z9ez=iNt&|8o?b!qaDRIy_XXH^@Va9f>fO(DByK>^Y>zg&gVMO+pG{YDHOB^gs9yi{ zy*#&dN@K?^!LD_87Qd`Rtt#j3Or(r$3^$B)UokkPU{%Yd@@7Kj!2iK%*OX$53O|4| z?9I!BAKHE&<632Wk>GD@*VKSIa3poN!5>2JHK#rExntMilXc_Pig(LLMK5N~ee9F; z>9YLX>7;?K`_7#O@luXNT&J$2?q}b#F+d7TMQ!YkTuC;ib^3y^7)utfcE+U9aSkn!>)GjmSAu&`^Q3ArURaj$f`{N7p?G<@5kG6z35oM%~kz;9>R z-s>CQk6ICKSG0X%rh%UBl*aWlJ~6RwS`NvAJ%>5{I{x~rJ8QP+kEA&N8f0}Y^S*tN z@6@M>KE$$v3HG|SRaL)f40i72;>|w?-wHf&ZcV|0@CQK+byaWJ;a9DSmr7&rJ&grR zi>sUV`!+1xo9w%#rD=O;=-GftaVH;{X1yE>wytY^-MQ(CgNu7E20IpwlOEl0f6A3LkG#{f<{L*h2kl*GT~`ZBETbPL zGd}GunQvA9bmc4OY0imyvH1Di!?%lELJoG8*Hp@yQAYNeqMJ@*EweR{sb#ZPQ(vGv zZ%5BLI^?!Z>FNciJ<}a+k)g+fOHal$4=R3`1chCTO-X)V4tXrN@OZH>hex$f)p;Mk zIjJT$lPK}sm$SJbBW8Zl((%j1))O;lPjeI)CkBSs{v+~U>}{1X_*TJ<_bsnCwcc(@ d-S({Al5y-cx{J}2Z~o^fo$lv#$Rm99e*wVY+0p<2 literal 0 HcmV?d00001 diff --git a/examples/icons/weather-change.png b/examples/icons/weather-change.png new file mode 100644 index 0000000000000000000000000000000000000000..21215b78d5a1946229fb900aac9fe2dccc7b10d0 GIT binary patch literal 2770 zcmcIm3se(V8jjim0_sv+krmtNAd1RlW|GNkG*VuMC}APc1(aGQlL?uHWa1>4K&_zV zQQBHdu!|L+tvs|;UAvyGg;nuU0Y#84^+C5HJ<3wqMyl2atnLht)YIy&r{`?WnatdK zzx(~K@BTBT3Gu2)-oNt}2n3VVvC&%Y9>`z6@!p?WfF{xjRCZ( zNP!@LmgH`ZO=|Y_6i0@@R4W?cGa4Q=}80aqAL` z1T`Oo>w-UPd3|ruIV`1XgI%!jNSF8Os=IF&yn5MBaO$tzuxE9h>QD}_=cvD_+V9QG zqt^q3c3_R*<$8bHOGD2{znGtAkLhZ(JX5vwrJRQL^J~BRK2lb&Ctf?L3IaMyze>Qz z9}ZDh?;P@|Rov_tXFD*|{>8VYy^m;$!~`V()+sV!kg1)zp>)Az}2L*W<$tFZH2z7;#oUXgK=%Sfxaqs z=YxjC;CcOx>a;i8K2~o3zVYuHYF?LpbF8GK#wAQC@D94XqB(V7$b5SFL2(NaeRklt<`icG1wV>~F z+sCWo*G7Ga7pY%_^kDcRV4(x&2uzfX z034=lvlVwJ!C_vUd*-KM5EzEovXo#1ZxBe;BmhwiO92w06e3Yf0>~6XR4T?4iZDQg zpmG?I!>AZSr8tJ*A`vk9137D~-hgYP7mwQFMoQ3VvsrK$w%hGOyI9DunJ}tQC}2bc zi$oBIfULP@8{vS=*5EOQXv#{mw8cg(mLhBno6IoTV}%;-3p@)D6~z}u z0fcG@k~Z_yb9qyvyQpZwMkzra0ih^_$dgeNmq>B3eAx&}!|6az*oa@^L^vwPMT#*T zqo)nI{|%)laRbAe2rf6YiO8g2i#c=HhDL*{%~l&>CMk8a66Aan(zG7ei^T*fBQQv& z*JBWdU?PYxNOcfGpaz{tE+=$^Y;1otL+0>xe&qEX|!FBKuKR-YY%FD3f4PF(oA-6w?_XOeZx!I)y<3 zi9{j^X9B^bQW6AyvKz%@GpvTub4eCII`dW6<)q&U*YD`Es;Weheu!BP>KT*{wL zaqyFzw-T%VhwD;QB*icVB$kLN2$P7#kPeaSAQ?&O400XCX+%C2`Y&DoNuY(qxFrmpTd#r2}ji3wSS_s3s2=i$HM;@MLN3aV$~{l}Izw7oz1(!TID zt}VsYrdrXx%5tjgWZFuP-pW>w>78ETZO!bbDoN>Kg`%p%OA-(_e`xB?^!;_qca=J> z5nlM2xcLolHHFH*o{|!Vkjee$J`4HU`}9`C(D~Z4bDc}J-R*w9Khf#)Llb^grfCxS z&8zh(s;_y^`;8X%K-%IzU7=q-`s2P(MPK3lIf09UUimOBaaqRpzoZ^&4GI5bV+if( zx49S5o_KL!U>*i9)9OpMEZHmXEB13<$kU#%c=h(~nz1-Gtb9fO?RyH#>1pl9OY8=4 z$Fhic$W?sK$AZn!<{%$z>G~lkHo)mq2Zr~|0)kyI{6}MbNtVAQW5Vawz_%RE&dFJy zXVCMLzdV+rMU1aDeYr?GeqHnBwe?e;f2Z-bw{gLp^zND_S95-T=EK~3;+Ss)OC6hv Ug65=L*Z*`SQRmW$##i#Tb+bk}8 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 literal 0 HcmV?d00001 diff --git a/examples/icons/weather-storm.png b/examples/icons/weather-storm.png new file mode 100644 index 0000000000000000000000000000000000000000..20172459e6d0f2f58b0e4bf61310592ba25b4ead GIT binary patch literal 2732 zcmcIm3se->86LsHf`}p(d=-b~5o(y7$G!(PxC>-ib;l*u5~_#~Vp4_Es8}FA5CYL+s}xd=&wx>hk*F1nompVxNi@gPp3XV5JNMr2 ze*f#c|4fN4Q9adrjyC`RQ#A>3$?X4Z?w;=fTDan}AJG06c6fD7gZfAgxWCokyvJ`#X6sjh zf?RMN@a8dp$HLLclGCrQ&W-PHvrevCyfCNv+{N{`?y97P`xBF=) zTGk}Jb@N|7T|56AzV+SVDV2eV3wB-Omv_qMs+(Gu?ibwXNw4nqLT(cu%}VC`%&2iw zC$5kE6JpeRS8UsMVupWGNUOSbZ%BDy?-!8)1=HR?7=6fm|-7?sQAFoMAt z2C)dpo^Npwd62~(GQki>+ew?r>M$`DkYgnDOpZgrXFVMY!EANWTI}O#ViN}E5mp!# zAY4dJAVs=x)*M^5(>O)KbT)0KEe<=2MO|1nOIoc9{#;tK*@d<{;#aXAjmP#}v^_Q7 zO2f&toyoD0bo?sTV#tJJR_;XGjm!(;a4ox{vEs2dns6|-REEi(D3r4=a4cYKELRvg z7@;LdlZB)HC1+}U7ad19Xa%1`Kqv|!vQ!ks#S&a7`_&jq%j$q49K?@t7>=Phf=%EU z%4Ep@DHKKG2F7M4*xZ=RL?#VeEtyUmS}m@z*d2t0q&0C0KI@ynWTJ3dE+(XyR1P7C z5P?JzIRWVrS`3K{C?zKh61`Y1o7f-6kU3o4xcy@irWlgtaAgaZi42qolZhY{qY(&^ zi%>`=)Jq|R#-vg?D#1tun_zpxW@1kfk^L+y=M}{=O2s0Hkd}}TD$*MukzQhe^m2n3 z!Z1vXA}At~NJu{Tz1>(Qo3UvbicPZc*?A4yzio`cl+7+Y+s8SbJN1SqnCxs(^T$t4 z3cYgtDcb}(C596ucM24Ik}E$=@yDl4&&lP>c|As(YouAy=PP0iVP_1ET*5{xGuf2C zoZ{dYId3Oc{j}?}P)bu0LJ!IHh=i4aSi%*K%Rh#S2$Z7rdROQ_cKv&i{@1RLr^r6^BfXUUS~;bOQ>LaBk)uzY*X-ixjM^o~+Nbaom;F?S?<)tM&X9>dRu0ace(U5b zygQy#J6lT6+0K;3HhIy1cG9iZyLla0FbJ5>XV4+js^%OfD)x@oF`9c?G)bn!~(^enu{ z@ZMfT+|x#8P@%gwbj>RNG~|u>`!c?i=-;du^s8I&&2YJQ#a;gc6AP^$P5iJ&$a~ULBD2TDb_ZW_w=TT%&Ah1Nug)kq?&h9! z;7rrz(?J=JJ!@OwlSAvX4sGvKU%PrfX|l@ReCk8Nt*AOlQm-*|a@WHvl`A0kTDZCP z@8Q^DNZ%$<^6otLJ=Q#3xM|(fvgB&x_Qu}_DUJ7QdT(U?Ay{-HsL;KSvYim!u6i6F zWxl;DJ!qw-Rj~7q33Eqg8GjzKxi^WtN-g+6@Amrnh_cAa;&Y!zfsTQ9`g%74B0~R9@%4I5hEzaR*fy8~y`E!S9~{ literal 0 HcmV?d00001 diff --git a/examples/weather-and-light.py b/examples/weather-and-light.py new file mode 100644 index 0000000..a0d755d --- /dev/null +++ b/examples/weather-and-light.py @@ -0,0 +1,409 @@ +import time +import numpy +import colorsys +from PIL import Image, ImageDraw, ImageFont, ImageFilter +from fonts.ttf import RobotoMedium as UserFont + +import ST7735 +from bme280 import BME280 +from ltr559 import LTR559 + +import pytz +from astral import Astral +from datetime import datetime, timedelta + +try: + from smbus2 import SMBus +except ImportError: + from smbus import SMBus + + +def calculate_y_pos(x, centre): + """Calculates the y-coordinate on a parabolic curve, given x.""" + centre = 80 + y = 1 / centre * (x - centre) ** 2 + + return int(y) + + +def circle_coordinates(x, y, radius): + """Calculates the bounds of a circle, given centre and radius.""" + + x1 = x - radius # Left + x2 = x + radius # Right + y1 = y - radius # Bottom + y2 = y + radius # Top + + return (x1, y1, x2, y2) + + +def map_colour(x, centre, start_hue, end_hue, day): + """Given an x coordinate and a centre point, a start and end hue (in degrees), + and a Boolean for day or night (day is True, night False), calculate a colour + hue representing the 'colour' of that time of day.""" + + start_hue = start_hue / 360 # Rescale to between 0 and 1 + end_hue = end_hue / 360 + + sat = 1.0 + + # Dim the brightness as you move from the centre to the edges + val = 1 - (abs(centre - x) / (2 * centre)) + + # Ramp up towards centre, then back down + if x > centre: + x = (2 * centre) - x + + # Calculate the hue + hue = start_hue + ((x / centre) * (end_hue - start_hue)) + + # At night, move towards purple/blue hues and reverse dimming + if not day: + hue = 1 - hue + val = 1 - val + + r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(hue, sat, val)] + + return (r, g, b) + + +def x_from_sun_moon_time(progress, period, x_range): + """Recalculate/rescale an amount of progress through a time period.""" + + x = int((progress / period) * x_range) + + return x + + +def sun_moon_time(dt, city_name, time_zone): + """Calculate the progress through the current sun/moon period (i.e day or + night) from the last sunrise or sunset, given a datetime object 't'.""" + + a = Astral() + city = a[city_name] + + # Datetime objects for yesterday, today, tomorrow + today = dt.date() + dt = pytz.timezone(time_zone).localize(dt) + yesterday = today - timedelta(1) + tomorrow = today + timedelta(1) + + # Sun objects for yesterfay, today, tomorrow + sun_yesterday = city.sun(date=yesterday, local=True) + sun = city.sun(date=today, local=True) + sun_tomorrow = city.sun(date=tomorrow, local=True) + + # Work out sunset yesterday, sunrise/sunset today, and sunrise tomorrow + sunset_yesterday = sun_yesterday["sunset"] + sunrise_today = sun["sunrise"] + sunset_today = sun["sunset"] + sunrise_tomorrow = sun_tomorrow["sunrise"] + + # Work out lengths of day or night period and progress through period + if sunrise_today < dt < sunset_today: + day = True + period = sunset_today - sunrise_today + mid = sunrise_today + (period / 2) + progress = dt - sunrise_today + + elif dt > sunset_today: + day = False + period = sunrise_tomorrow - sunset_today + mid = sunset_today + (period / 2) + progress = dt - sunset_today + + else: + day = False + period = sunrise_today - sunset_yesterday + mid = sunset_yesterday + (period / 2) + progress = dt - sunset_yesterday + + # Convert time deltas to seconds + progress = progress.total_seconds() + period = period.total_seconds() + + return (progress, period, day) + + +def draw_background(progress, period, day): + """Given an amount of progress through the day or night, draw the + background colour and overlay a blurred sun/moon.""" + + # x-coordinate for sun/moon + x = x_from_sun_moon_time(progress, period, WIDTH) + + # If it's day, then move right to left + if day: + x = WIDTH - x + + # Calculate position on sun/moon's curve + centre = WIDTH / 2 + y = calculate_y_pos(x, centre) + + # Background colour + background = map_colour(x, 80, mid_hue, day_hue, day) + + # New image for background colour + img = Image.new('RGBA', (WIDTH, HEIGHT), color=background) + draw = ImageDraw.Draw(img) + + # New image for sun/moon overlay + overlay = Image.new('RGBA', (WIDTH, HEIGHT), color=(0, 0, 0, 0)) + overlay_draw = ImageDraw.Draw(overlay) + + # Draw the sun/moon + circle = circle_coordinates(x, y, sun_radius) + overlay_draw.ellipse(circle, fill=(200, 200, 50, opacity)) + + # Overlay the sun/moon on the background as an alpha matte + composite = Image.alpha_composite(img, overlay).filter(ImageFilter.GaussianBlur(radius=blur)) + + return composite + + +def overlay_text(img, position, text, font, align_right=False, rectangle=False): + draw = ImageDraw.Draw(img) + w, h = font.getsize(text) + if align_right: + x, y = position + x -= w + position = (x, y) + if rectangle: + x += 1 + y += 1 + position = (x, y) + border = 1 + rect = (x - border, y, x + w, y + h + border) + rect_img = Image.new('RGBA', (WIDTH, HEIGHT), color=(0, 0, 0, 0)) + rect_draw = ImageDraw.Draw(rect_img) + rect_draw.rectangle(rect, (255, 255, 255)) + rect_draw.text(position, text, font=font, fill=(0, 0, 0, 0)) + img = Image.alpha_composite(img, rect_img) + else: + draw.text(position, text, font=font, fill=(255, 255, 255)) + return img + + +def get_cpu_temperature(): + with open("/sys/class/thermal/thermal_zone0/temp", "r") as f: + temp = f.read() + temp = int(temp) / 1000.0 + return temp + + +def correct_humidity(humidity, temperature, corr_temperature): + dewpoint = temperature - ((100 - humidity) / 5) + corr_humidity = 100 - (5 * (corr_temperature - dewpoint)) + return min(100, corr_humidity) + + +def analyse_pressure(pressure, t): + global time_vals, pressure_vals, trend + if len(pressure_vals) > num_vals: + pressure_vals = pressure_vals[1:] + [pressure] + time_vals = time_vals[1:] + [t] + + # Calculate line of best fit + line = numpy.polyfit(time_vals, pressure_vals, 1, full=True) + + # Calculate slope, variance, and confidence + slope = line[0][0] + intercept = line[0][1] + variance = numpy.var(pressure_vals) + residuals = numpy.var([(slope * x + intercept - y) for x, y in zip(time_vals, pressure_vals)]) + r_squared = 1 - residuals / variance + + # Calculate change in pressure per hour + change_per_hour = slope * 60 * 60 + variance_per_hour = variance * 60 * 60 + + mean_pressure = numpy.mean(pressure_vals) + + # Calculate trend + if r_squared > 0.5: + if change_per_hour > 0.5: + trend = ">" + elif change_per_hour < -0.5: + trend = "<" + elif -0.5 <= change_per_hour <= 0.5: + trend = "-" + + if trend != "-": + if abs(change_per_hour) > 3: + trend *= 2 + else: + pressure_vals.append(pressure) + time_vals.append(t) + mean_pressure = numpy.mean(pressure_vals) + change_per_hour = 0 + trend = "-" + +# time.sleep(interval) + + return (mean_pressure, change_per_hour, trend) + +def describe_pressure(pressure): + """Convert pressure into barometer-type description.""" + if pressure < 970: + description = "storm" + elif 970 <= pressure < 990: + description = "rain" + elif 990 <= pressure < 1010: + description = "change" + elif 1010 <= pressure < 1030: + description = "fair" + elif pressure >= 1030: + description = "dry" + else: + description = "" + return description + + +def describe_humidity(humidity): + """Convert relative humidity into good/bad description.""" + if 40 < humidity < 60: + description = "good" + else: + description = "bad" + return description + + +def describe_light(light): + """Convert light level in lux to descriptive value.""" + if light < 50: + description = "dark" + elif 50 <= light < 100: + description = "dim" + elif 100 <= light < 500: + description = "light" + elif light >= 500: + description = "bright" + return description + + +# Initialise the LCD +disp = ST7735.ST7735( + port=0, + cs=1, + dc=9, + backlight=12, + rotation=270, + spi_speed_hz=10000000 +) + +disp.begin() + +WIDTH = disp.width +HEIGHT = disp.height + +# The city and timezone that you want to display. +city_name = "Sheffield" +time_zone = "Europe/London" + +# Values that alter the look of the background +blur = 50 +opacity = 125 + +mid_hue = 0 +day_hue = 25 + +sun_radius = 50 + +# Fonts +font_sm = ImageFont.truetype(UserFont, 12) +font_lg = ImageFont.truetype(UserFont, 14) + +# Margins +margin = 3 + +dt = datetime.now() + +# Set up BME280 weather sensor +bus = SMBus(1) +bme280 = BME280(i2c_dev=bus) + +min_temp = bme280.get_temperature() +max_temp = bme280.get_temperature() + +factor = 2.25 +cpu_temps = [get_cpu_temperature()] * 5 + +# Set up light sensor +ltr559 = LTR559() + +# Pressure variables +pressure_vals = [] +time_vals = [] +num_vals = 1000 +interval = 1 +trend = "-" + +while True: + dt = datetime.now() +# dt += timedelta(minutes=5) + progress, period, day = sun_moon_time(dt, city_name, time_zone) + background = draw_background(progress, period, day) + + # Time. + date_string = dt.strftime("%d %b %y").lstrip('0') + time_string = dt.strftime("%H:%M") + img = overlay_text(background, (0 + margin, 0 + margin), time_string, font_lg) + img = overlay_text(img, (WIDTH - margin, 0 + margin), date_string, font_lg, align_right=True) + + # Temperature + temperature = bme280.get_temperature() + + # Corrected temperature + cpu_temp = get_cpu_temperature() + cpu_temps = cpu_temps[1:] + [cpu_temp] + avg_cpu_temp = sum(cpu_temps) / float(len(cpu_temps)) + corr_temperature = temperature - ((avg_cpu_temp - temperature) / factor) + + if corr_temperature < min_temp: + min_temp = corr_temperature + elif corr_temperature > max_temp: + max_temp = corr_temperature + + temp_string = f"{corr_temperature:.0f}°C" + img = overlay_text(img, (68, 18), temp_string, font_lg, align_right=True) + spacing = font_lg.getsize(temp_string)[1] + 1 + range_string = f"{min_temp:.0f}-{max_temp:.0f}" + img = overlay_text(img, (68, 18 + spacing), range_string, font_sm, align_right=True, rectangle=True) + temp_icon = Image.open("icons/temperature.png") + img.paste(temp_icon, (margin, 18), mask=temp_icon) + + # Humidity + humidity = bme280.get_humidity() + corr_humidity = correct_humidity(humidity, temperature, corr_temperature) + humidity_string = f"{corr_humidity:.0f}%" + img = overlay_text(img, (68, 48), humidity_string, font_lg, align_right=True) + spacing = font_lg.getsize(humidity_string)[1] + 1 + humidity_desc = describe_humidity(corr_humidity).upper() + img = overlay_text(img, (68, 48 + spacing), humidity_desc, font_sm, align_right=True, rectangle=True) + humidity_icon = Image.open("icons/humidity-" + humidity_desc.lower() + ".png") + img.paste(humidity_icon, (margin, 48), mask=humidity_icon) + + # Light + light = ltr559.get_lux() + light_string = f"{int(light):,}" + img = overlay_text(img, (WIDTH - margin, 18), light_string, font_lg, align_right=True) + spacing = font_lg.getsize(light_string.replace(",", ""))[1] + 1 + light_desc = describe_light(light).upper() + img = overlay_text(img, (WIDTH - margin - 1, 18 + spacing), light_desc, font_sm, align_right=True, rectangle=True) + light_icon = Image.open("icons/bulb-" + light_desc.lower() + ".png") + img.paste(humidity_icon, (80, 18), mask=light_icon) + + # Pressure + pressure = bme280.get_pressure() + t = time.time() + mean_pressure, change_per_hour, trend = analyse_pressure(pressure, t) + pressure_string = f"{int(mean_pressure):,} {trend}" + img = overlay_text(img, (WIDTH - margin, 48), pressure_string, font_lg, align_right=True) + pressure_desc = describe_pressure(mean_pressure).upper() + spacing = font_lg.getsize(pressure_string.replace(",", ""))[1] + 1 + img = overlay_text(img, (WIDTH - margin - 1, 48 + spacing), pressure_desc, font_sm, align_right=True, rectangle=True) + pressure_icon = Image.open("icons/weather-" + pressure_desc.lower() + ".png") + img.paste(pressure_icon, (80, 48), mask=pressure_icon) + + # Display image + disp.display(img) -- 2.30.2