From 6bcd0174be1aa204499dada4805d24e49577f567 Mon Sep 17 00:00:00 2001 From: Sophia Zheng Date: Wed, 9 Nov 2016 19:25:27 -0800 Subject: [PATCH] Project code --- .DS_Store | Bin 0 -> 6148 bytes greener-house-app/.DS_Store | Bin 0 -> 8196 bytes greener-house-app/assets/.DS_Store | Bin 0 -> 8196 bytes greener-house-app/assets/airflow.png | Bin 0 -> 622 bytes greener-house-app/assets/back.png | Bin 0 -> 411 bytes greener-house-app/assets/big_sun_b.png | Bin 0 -> 1348 bytes .../assets/core-button-2x-colorized.png | Bin 0 -> 15720 bytes greener-house-app/assets/core-button-2x.png | Bin 0 -> 439 bytes greener-house-app/assets/core-button.png | Bin 0 -> 253 bytes .../assets/core-glyph-strip-60px.png | Bin 0 -> 20437 bytes greener-house-app/assets/core-glyph-strip.png | Bin 0 -> 8856 bytes .../assets/core-slide-button.png | Bin 0 -> 520 bytes greener-house-app/assets/fan.png | Bin 0 -> 882 bytes greener-house-app/assets/fan_g.png | Bin 0 -> 1131 bytes greener-house-app/assets/home.png | Bin 0 -> 770 bytes greener-house-app/assets/home_g.png | Bin 0 -> 854 bytes greener-house-app/assets/humidity.png | Bin 0 -> 908 bytes greener-house-app/assets/irrigation.png | Bin 0 -> 963 bytes greener-house-app/assets/irrigation_g.png | Bin 0 -> 1139 bytes greener-house-app/assets/main.png | Bin 0 -> 22446 bytes greener-house-app/assets/settings.png | Bin 0 -> 981 bytes greener-house-app/assets/sun.png | Bin 0 -> 1142 bytes greener-house-app/assets/sun_b.png | Bin 0 -> 673 bytes greener-house-app/assets/sun_diagram.png | Bin 0 -> 9268 bytes greener-house-app/assets/sun_g.png | Bin 0 -> 856 bytes greener-house-app/assets/temp.png | Bin 0 -> 1307 bytes greener-house-app/assets/temp_b.png | Bin 0 -> 1122 bytes greener-house-app/assets/temp_g.png | Bin 0 -> 1520 bytes greener-house-app/assets/toggle-switch.png | Bin 0 -> 29434 bytes greener-house-app/buttons.js | 10 + greener-house-app/drawer.js | 62 +++ greener-house-app/field.js | 10 + greener-house-app/greenhouses_around.js | 64 +++ greener-house-app/irrigation.js | 14 + greener-house-app/keyboard.js | 1 + greener-house-app/main.js | 458 ++++++++++++++++ greener-house-app/project.json | 17 + greener-house-app/sliders.js | 1 + greener-house-app/sunlight.js | 14 + greener-house-app/switch.js | 1 + greener-house-app/temperature.js | 35 ++ greener-house-app/theme.js | 2 + greener-house-app/transition.js | 499 ++++++++++++++++++ greener-house-app/ventilation.js | 124 +++++ greener-house-device/main.js | 51 ++ greener-house-device/project.json | 14 + 46 files changed, 1377 insertions(+) create mode 100644 .DS_Store create mode 100644 greener-house-app/.DS_Store create mode 100644 greener-house-app/assets/.DS_Store create mode 100644 greener-house-app/assets/airflow.png create mode 100644 greener-house-app/assets/back.png create mode 100644 greener-house-app/assets/big_sun_b.png create mode 100644 greener-house-app/assets/core-button-2x-colorized.png create mode 100644 greener-house-app/assets/core-button-2x.png create mode 100644 greener-house-app/assets/core-button.png create mode 100644 greener-house-app/assets/core-glyph-strip-60px.png create mode 100644 greener-house-app/assets/core-glyph-strip.png create mode 100644 greener-house-app/assets/core-slide-button.png create mode 100644 greener-house-app/assets/fan.png create mode 100644 greener-house-app/assets/fan_g.png create mode 100644 greener-house-app/assets/home.png create mode 100644 greener-house-app/assets/home_g.png create mode 100644 greener-house-app/assets/humidity.png create mode 100644 greener-house-app/assets/irrigation.png create mode 100644 greener-house-app/assets/irrigation_g.png create mode 100644 greener-house-app/assets/main.png create mode 100644 greener-house-app/assets/settings.png create mode 100644 greener-house-app/assets/sun.png create mode 100644 greener-house-app/assets/sun_b.png create mode 100644 greener-house-app/assets/sun_diagram.png create mode 100644 greener-house-app/assets/sun_g.png create mode 100644 greener-house-app/assets/temp.png create mode 100644 greener-house-app/assets/temp_b.png create mode 100644 greener-house-app/assets/temp_g.png create mode 100644 greener-house-app/assets/toggle-switch.png create mode 100644 greener-house-app/buttons.js create mode 100644 greener-house-app/drawer.js create mode 100644 greener-house-app/field.js create mode 100644 greener-house-app/greenhouses_around.js create mode 100644 greener-house-app/irrigation.js create mode 100644 greener-house-app/keyboard.js create mode 100644 greener-house-app/main.js create mode 100644 greener-house-app/project.json create mode 100644 greener-house-app/sliders.js create mode 100644 greener-house-app/sunlight.js create mode 100644 greener-house-app/switch.js create mode 100644 greener-house-app/temperature.js create mode 100644 greener-house-app/theme.js create mode 100644 greener-house-app/transition.js create mode 100644 greener-house-app/ventilation.js create mode 100644 greener-house-device/main.js create mode 100644 greener-house-device/project.json diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cc0d3302cfaf5753989116f3d417ac397b9b4ae1 GIT binary patch literal 6148 zcmeHKJ8r^I5S&dYkkSw-1?9T{MQ-qf$O*VWBCtrL$RH5Z?sDzSei8wOlqr&3Yj^zC zJAU>QUM~Qd?w60i2*8l8hz|{Y)9dOzyNQgV*gaY_*kXcLtb5g$6Ux2EimZmmF@KL8 zGZVaEgUw;SZQs}J%6G!UkBlXG2fSf{=8Sjw88Vv+qynixDv%2NCk5EE)rNPD8B>8& zAQkvlK)(-#u2=&*NBeXz*a$!zFm1+jnCw7*YP{ej;zF0Y=I%Z4-Qh`$iZhbk@{{KY3GXI~Fa+M0C0)I*Y8O-LhDPJji zYwzW>*B1IS{mWQuou@*G&=J}C+3fU>XMcU{DuObu}LCu literal 0 HcmV?d00001 diff --git a/greener-house-app/.DS_Store b/greener-house-app/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..09a421eb0ee6ceb96eb2ba0fbcbbfba0a5eb7872 GIT binary patch literal 8196 zcmeHML2nyH6n>M2b{*HrHVtt>fK~*gN{uR~Qd?CBYTO`XA(W_2OG477YwyP1X1%lQ zu4B>=8@jk8$s%fHS^Xp@0;(vZ+CV* zYa(Kmj>U7m)DPYs}7}rQa~x76i^B% z1^y2T;F&FoHsZM-kE&KFpcHs26%h9a169~^VtcWbw+=LN3jjNgZdq`QeSpLmi7h9# z7h4I%obm2~B~X@ZF<1=8xFOtO%Zcs9Hii?6;lvVVmh4cNWCzZW?!?NmRjpD$DR5K) zv3EaBCWZLe1N(QelwL#q`al*5&iK~5p`Yyaf2#Yg6Go-dZ*1(;_%o-^XquMS3i*4r z7Vp*~GwOsDGgz139LugJ$19w>hsS39u48vM^_g4Ti%iF}gOvNmdyZ%EZiRO|E0psr zn^6ncTrQ{OHud7(-nG*8d84#HZ|q&Yabw7$i_n&mF?E3JT zdD0;#eLJviZ@n2f*3#BiXh*App%HM`UFM+^Iow-IjjnA-_Q-Bmy)6z#5y6r#+`_wd z5W*h8udbOvV0ulvvU|@p>$bb(Rd^Kf_Ns#{MC6j7=9>-2YtG&L^ZR%28@`vDD_@L7 zMc29Cw>Q4PjeYLsUrAqI@0`w7MD%c9PKL_wB!e1VqBp5V8}tG7=u`TNexM)e7y5(# zrUO=Bv+QMdiOsXC>O>8qU(0vClU@Vk*0JM$>-hP1YJul+uZfvO%o9|n4i;lXoIEVd%k(hwVofZ} zZ{hk%YGLNcq5uoIi)9>)M0}Y-XtYHRyj>uNF<|Lu7z*$X@NuXKo(NV%Hw4Lw1IRpW zgJ&06aUg>ce8`BtNyT@D+VFOUbI2Rh#gzA1@-Z`qQZ_XZos3IFn0g_Z=tgPW1oU;m zVoBYGYAy1~M3x7pgSZ5)Nv%FxmPw-0OgW&sKtzbIHB`4x26!gnYeNNJ#wIlHAV+&7 zHqEBNyCu;>{e^xkeKi!|FRmYPy@?o)Kf7tXP_?Kte= mABH$K;3_cX#P(u~9+Z=K5s-dPs^|ZKJP+#mFJ*XYntuRH$TG12 literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/.DS_Store b/greener-house-app/assets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7f62f9a8916a91bf3072a63b4bc84b5025bcbbef GIT binary patch literal 8196 zcmeHMJ#Q2-5Pc?*viX1n1R|gmTTsvh0R;`sDhdTPKj65#9LI@E_H>sMNvdu58x#~s z{7QIZTZ_GChYle!j@IMboi`uP_O8YOV2+k2FMxdj1uv0%+w2lep3Ak;ZuvWpDGl+! z6g58M8D=|{ULq?m8z=3n zgPkn_DA#%0HjY^bSWM|<<09*l-M7)l1ao|d>i6;6X+0cF>j5=nQ@!SH|N7H5Yo@?}xFJ6I zdOxARb`a>_rv3zD^svB^=L0?db|(d0n2ZeM9Nzf5hQ#ixBSnjBL*SG!q?JjH3JPFSDNPo(xxhK?X*&Kg)ZF*7sJcpUp{pL^*|+ zTwKCjxR37APtEM*Js~@B!IM^5i$ku>B=@qXBMY2xZOTB)z?vKFOa1>QfBxU<>p&S$ z2L3+=%=+=W<0IzfYwMK^rPeNaz2_xO^cp8Egq9HuU>%r$M_L#=tL3!`IaS literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/airflow.png b/greener-house-app/assets/airflow.png new file mode 100644 index 0000000000000000000000000000000000000000..704be736036a83b5ffb9bf60bc1aa8291b7976c5 GIT binary patch literal 622 zcmV-!0+IcRP)OV8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10qaRbK~z|U?bgqWjbRiA@Xr~yX%=cmM3a<}G$AZxN>S|WY*0#y zg{Ca+5#ItMy4!DR%%M}qlQt8g=ugs?sK_gZWH&qbE7%+^gf;Qeb4iK z-}CE<%+yKg>gef91eOT=EdmkI6%jp)P9P$BBVrUEFdY$N5i!^R*Buc%BjR9049qcR zX44C|ka&g1W&av0>M(~eS!}g+7Xz8uJOOMi&c;zGx-&<z7cl8*X9*6LqBfS|PBv zI6hpb+gY5SM|b)1uh>zC37jpsbFGG8Bckk=<8pC)vX0D+2JiJ_7EdcBNlxJyj^F|| zFPwh!k_^@s5>Idydy4tuulUS-6A>@4u2OWpScx92Lf@YdDDoV4Fp`-wxE&E|GIO#4 z;oaDP2Q7u5$*>KnCT`+HsAld^6JOkn^kZAuU(3v+@X*{EZReWCeH^d-ky-|KOezZ* zBVr4#t7iAOYL(o>rY6pM>t~XF{4D~Q!FznclxpL7ht*9GSdU@si-=vNQd*k@O*E=2 zN~5Y_+IAm^i2Zn`IuB&#CtND#?KNCGFCk4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKj7wM;ZO|z_}3UHl7~*mK?Nmdq1_K_3?!}w+ zg}$=>yK*y}^X-L)F;*fcCzu7uOtLJWpeo)}G-GGP*4sjL%oEQxF}sv;^G&eOu{dxz z>7eoQ$9@0#=U@59sJ`QnXtJnoer&*&wx^36<6QKuc9i zTq8MtT2rr-pNstY}`DrEPiAAXl<>lpinR(g8$%zH2dih1^v)|cB0TnTLy85}Sb4q9e E0FGIJPXGV_ literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/big_sun_b.png b/greener-house-app/assets/big_sun_b.png new file mode 100644 index 0000000000000000000000000000000000000000..fa9a73f167425b9b0ee3978bd9a9b8f6a0323074 GIT binary patch literal 1348 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!n2Vh}LpV4%Za?&Y0OWEOctjQh zMXNxVaoHl?-9SOf64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq!<_&6#{%h zT>t<74^%%2aD~9T|7jjTx%iSGzhDMNW_C_4egQ!tVKH%OIYlKEH62}jOJ{d4U%!B$ z;E?cyl+3KW(z42?=9bpB&aUoBQ>IRvzHsTXD977@wZ=Ig2EFCD&+V2_?v?Zf+o0pU8 zm2B;hJ)*v@T_u7GAO8IRf04Y|?AUMb+H$PtPpVEoch|c7*_j>@&CBZQm%9{;8H(rL zPG?lOz4C9sUB(ssr5qcagUhTo%kN>&k=`NyhC_jU!byfFR!lcob53t+ysIwR|IcLKvRHok4Wzf4ejo}hwgUEqdLbF{?r8#9YtXv>|zM;Ei%Y)$c^X25` zU907;)GTD2BRQ{7E+P2U{=9qD^=SugO3t{M|Ld`pW-ikiX@;Qf3_qXnGrZ&Ce^kGr zfc?Pv6uAdxsa;E4p9?T}<;%U_r}=Z6c<;iT%JVUAIP<=X>~+|9=H!GT`Kq0#oxg6| zJ?*Z6XY117^`EaCUH133|IyFCsR z>*Mt=@1Nz5`&j*nZ$-=P{)Z|Hq;E2qum3B>+ORR8A$NhHhNu3V&-JyZ)#N^1_QyZp(R(OVJJ9!s6#EW_`ClTQ%`( zIydvAFPsUdN=`HG&$GR~s{Y_{D!oi+?{)2v@)8vi){c-X^(!-^cd%%X|LUGah>O VS}M-xi~uP2db;|#taD0e0su8!>x=*Z literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/core-button-2x-colorized.png b/greener-house-app/assets/core-button-2x-colorized.png new file mode 100644 index 0000000000000000000000000000000000000000..ce61a78ccafda04bad8e7eb2442d2d77b558eff3 GIT binary patch literal 15720 zcmeI3e^3Y)w2~MPrKdzUlu`S2$-f<@ zrv)>#Vxw20{aUYhe?(+Lr+^h1A16p0?^VmXw3DxsEEqf?j^1&zBrSVWY3J(&ic6-!emb* zEW8yWD`W=uO4)oYE%ClGo_AX#yR2jaq1t9sud>q&=arFu!;Hi8gpy5WSV@HV50yrM*V8Mdgv z3I=jG&P5SAf-o8ZIvoQ_Fjq&qv`(iXPwO-p^o%RlsB;pAFhsjOF?@=20ngOQr4p5P z0ciuRce?Zjqn4=3rM0;XkTx+!otDneGmxw)U*|NE6VeIcQ=~WeIMC*3cfuU`>i^pm z)5uIoRmh28b2cVyTCjD)jcgOUW%B5R!_9>ol0f@JRxUS-W}@C=9W2(M<-zis*~10o0KGPiqk0zf2A7t!7rY2g!)EYF)|3Va~U$B?xaNU5uF=Z^CIWpfN*P**EJl_bq96{iue2j)By5Z1r zbZDX*4vj}{_HvR{7tIC@Cq&7Am62Ay2|U%Y);xnj4>~S93`dl3e%9?M;6Tq6z2KHs1#Bb@#RE4yZ zBoGj^so+BMfxHSX2ngC#aH07?UIiBf1Z^s~(0m}Tf(rtIHWgfGK9E`Rd7K-(58Y5%?I)-xF8^CQ^AGi19=r(5D>Jf;6n3(yb3M|2-;L| zq4_{w1s4PaZ7R6Xd?2ra3j%^R6F0zTPsH{MOi#$~iq^scl~Q>3wydw&(3y_h#i^0=JLc>8tqlPkgr? z+S76AAtn%LeQbT2UzMGl(QF#XJ7XB^tscl6P3pUKanIxF-qc=gWr{z!e{Y2z3pM}t z;`k#s-uwI08Rq2l=5tG&-#YV6;TiVAmCXZ#y+0gCzqzM;Z!3GDX@1Xwp7gexuNSBE zz554u@arz5I_| z`})fq&mK#45UCY~Tf2YOE55zx+7ovM`@c)%C8uR~_1^U$WDlg-F0Qy|^u4c))g~|f zYVwMey#d?6w#PrX^vS%rT`85TlZu;nCkgKd9{a(+vpaWQ`K4p9C-?U4Wv7}Am04e_ zpMP-k_IJjPGZ~Jj+?I^y#TUolI9+^o;b_*_^0(Q~-whmTJa_)avKQ`@jGX(YJLBYt zb>xjp?T?5nM?2a!4n1?@fn%-nt|b|NzhEqLtkk~)x$Wq8$U)@TM@`O;EV~Rf-O8)D^d3yRIh#I%u}CdRo7)K3VUW#A84AkWLy?d4-e6Vyj*5(_b7C z&9=KB;(LLi^x}^z@k$rOzw}O;wDsC|Il1mymu?}a|Jz*7+T?iucj{Eny$~$6ZK3^y zifeAU|L5IY+J58h)4iX4w%Z~r^K&r}J^!fJ_m-dOKq%gd`A`w~=oS6Em@mxA!KE`b3`XYShjDU~9K^9@c#B`CIcLCiilf8=!a#J!~`C0E6v%EV!X`f^M zxnmD6?f&9=T+-5RPTx-EM@ADrf9G~=W0a@Uvs%^6k9-%_*!S;Qg|8d=369@HPmX1cC;N4-J4JQTXDv8>{!prL!Z*~35kxD6O?72hm)Wo#7ybSi_VtDnm{r-UW|TLWQC literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/core-glyph-strip-60px.png b/greener-house-app/assets/core-glyph-strip-60px.png new file mode 100644 index 0000000000000000000000000000000000000000..c8b77bd49816b87bd56b0e6f3f2d4b22452578f8 GIT binary patch literal 20437 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 ZREaIS2FYG`pp2RT40TO(YP2vh{|Dq9(Juf1 literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/core-slide-button.png b/greener-house-app/assets/core-slide-button.png new file mode 100644 index 0000000000000000000000000000000000000000..277ffa6a32bf5e612a86326a6c89426109fb04ef GIT binary patch literal 520 zcmV+j0{8uiP)X?y|g)m}S^kATnjITufXG{AZm_0K;W>r-J`azJ_8+KIZH> zoEguJpJi|a4#6JS2CHDsO;*0aCwK-=;1S$|mem(zz@#dQQAmq>T2ZsvQAlJQy*5T3%aXOR5Z%!F33!m&@*u2n5fwR zY4Fg$3HhwH*!bbnPpQyTwammzS{*tMtbiA=L@$Zb23u00dCD}2ILwRC99@_tCqlFI zV3w@BLtnuOoQU{flz32x{kajw;6kc{I6bJ7duT@e|!K;GToWXJ&vEmkhTZU2YT zXezVXVm0X&2bpFY*|3cqhJy}dIxUT+~oE1f53<99k{)7V-DQ@3NQd<-z!Q|X9S1<0000< KMNUMnLSTZEb?RyW literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/fan.png b/greener-house-app/assets/fan.png new file mode 100644 index 0000000000000000000000000000000000000000..a7890c3b086508a481bba0289c38554e61bb22ab GIT binary patch literal 882 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKj7wMQ8eUYDB1(mfi4* zE}vv3#nRe)W{P9u!ziPma^Hx6K!uqq#=Zg)JGGUTFfDHNF1_%AJBov?ZH8c&$kH$D zB3~R6xp^0QDD6#uc5i#@6v5*B!t?KB=6!x#DR-~9WrFFRbJZ+m-ru}89OGiH$h{K$ zers!{6XOyF6Baf&2nk%yA1__zkYZuU9u;ef6ex-xbaOw2aT$t$QtS*o3)TXXCV#l_y_aT~xATH(yV$F8ef#37h7> z&Qnv>{l3&s@3ZqV3C5R`Wvvu5YZv%FJL;gN;G}pid)tG=$Cu>azm3t*G1mHg%XjJ4 zWA^UzSmey!-<+pEt?)tE1h$a&HMeTYpEEsJ5y)Jp^xd+4*OsY?A|AU%S8x9}E4A~!CQ7>u^UwU`eizprLhC4jQt9PI6R6TOE_0jv|C7*Qb zeN#_p)R#N-N_403J3T3F#N|qV2%Un-wVbL6}4RbWHEnh5EqcrCQ<|QIe8al4_M)lnSI6j0_CTbPWx44J<

gcyqV(DCY@~pS7(8A5T-G@yGywpER#&$G literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/fan_g.png b/greener-house-app/assets/fan_g.png new file mode 100644 index 0000000000000000000000000000000000000000..96a32f0a2871e54e3ba6cbed5f32e0068212d7fb GIT binary patch literal 1131 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+0817lu*Plzi}LE+=R!bjbO zkGl&WbrpaZJs|F*uEK{v5`+qX>_^=V{~I7&5c_IF@jalju962p^MjDA-vcu9AyirZ%huwXKz3IVNDyRB`P~kvr9czz_k*1DxVz$E zJJjCCAZGwY3V_DmhY5mR2zETwwLmwdotX)9YFF;_HXu9y-UOhU+}o2t;t#uXpLCYo z=`MQOTlBE2=t(aq1b~J=?8{2;^p8WsS`{%E#Cx1DxgZ0mkKGCJ(6ZwA6k`a@gZJ{!=QI&gAl~RdjTb{mL zhG~+GmXl$adAh%CXtcA}f_;9bs~FUQZeUFEc6VXuV3qX%aySb-B8!2^>^cZDI%&+V z01C2~c>21sKj7wM6*Rokq6ZXWwDELt46!&}dok1ekfX%0hxN0&JWlEb26Z@jro;;c zZCi6wvwGT(+M2>WCj!s^%}RUs`i$lIo<)B;z1D_l2AM1nY!oX|T5;+1YL^59snxCl z$wpVbYUl3UcP~lQf!R#Dmnmb>j5NkA7jC&#Ki$W?d(~yf@TL21cdmASee7oRzV8oA zw}1W0AJDwsCs#J*gnUB8`4brvF6@syeyGQt$H0)YZN=OVFYec6-7*qRyJlv-zaekp z($rSGCai3DOukCc2(9fXUdYk4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKj7wMRh5k`+nB?^z<9ya#WBR=_}NLe9x{$14g0tE zx&Pt3m!%NS!piwDhedmK14m#|w(=4Iq57hv{F&FT9TGOLNDvS3NOcgg+%Q!{&G*F9 zE|y;RNB%758>*}|-%YuCdv5H;ldIG2z4^Yka~yBWSAWVTwbmIQFXnIfaAU~?1DP{ioX5{{bvDfw5#r?!^9Zr=P`p@J z-+G7bd+>?3AF^6YTgC4*POP!uQ?4v;VDg;mtM2gN?W}jJ=losp`Rhi>@>xGzvX}n< z`mv7t&f?XV!zLwuUEAlq$0urnl#<-$WHZYRHEz{)7f$M2jq!e(RCY#fo)i;nz`kvd z!~S_Jj#}32ymwW)TAk(Bln(hliPx12;{WZ8S@o)GRr_;?*(E1;7@u-}^d#6`y(wyy z-%i(r`27!*b@wE5eVLQ7h+Ar##nZ-nn|I%QBKJ07t%TfGE7O=O-3h6E)jxO+oQ%+m zSny}k*Wmj3ACKJCc%NdugYmxffr5?SG`VY@YgZO*H*ERjzyH@+i3a1-OJruUh&@}u zYPoxH!{`6e1&;;2&%SIa*Z*$1>)dQ@Q||>1%{4pnt}tBA`sEgRKBgk-g0=+PvF_~i z8UL9Vow@7nz(032FuGMsTq8mmtT}V T`<;yxP!WTttDnm{r-UW|3`#V# literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/home_g.png b/greener-house-app/assets/home_g.png new file mode 100644 index 0000000000000000000000000000000000000000..6eabe9b5f9590a278854290143f6265ecb213ade GIT binary patch literal 854 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10;!=Q5h%1mTz28;%u)FYa zci|%-*#{)^9(6PP|6lN^3&<|N+W{o=A9oi$=`Fb54`dfS?kRfI6Z(G@P*>KgsX!5s z-pAbqkGf0lbf-OQ0E_e$JOCM3@TjNgAxNqKY(9_+k_DlzBB1&gAU2QzG#sS(0gw$> z(4G6dt>|GFP;cSmuENJ4aiCE^OMwmpne(ux2q+E`0T~50vm59g<=)b>K+2^g$S;^d z;@I`aD$jKocRl1^X>K8KD`+nB4W8`}&b5hgy_fcW6Oew#;dSJh?{|y1zaCVZ>NMr^ z%_E|-TV~eHt6W^NBHwFkMfbnIh+L^k;TAhxemgNP8zc- zfP(BLp1!W^54bs5RYil>TE+o|zI(bjhFF}gJ^wQ3kby|sL*Y|FVwzEAfdP!7fnlt7 z7I^IcyHG`?fmT=7r9wCPndf`a9xmPS>pNWEIa0n10?g({_Dh zRfyjD8dj-!;&*e4E@YMOx^BB`r)zv;+M9U{%!Qxc{bO_v=XaB^w|iLGBz~#+rMBBY z>HS8=46~9qMKEb!XIYm0b91>7*NBpo#FA92VbLJuST6P?J>hCc*2E^-mN2e4$BasLIoA6G3Kd@LyTmZU(ai9~Zb#xka ze$z}4XisFN$}@c99AHT2jsvUGCID188$Z@|2v{1TbIM2fN)!T}x=05$`~3)86nnG! z9Cr!u3&>8H08r&vQK8sL9sedE?gRVqazq(kaH>m*fLiiSmD?RW6ZoX~%>cb8Dr?p8 zbshHx-H0#(M;uE^e6nLI8w1ulc(L=vwkx*Y!FEiG05Bi;s7lQN@_Be~fo2D@Q7 zzeDi`|5}McaSgBFZ|wD z?5K{1fnvp0I_uRZbpcR_=d%LfDv3_8%>jaam>OUS_R7UyM-Q;KMS#D+n&}XzRfP}0 zPVIkBKp;omB)|s6HUk5W5d!=H_5`hwF~uiPuI)2mo6m=S_YE0ix`2(U_g+L^8Dk2u z8M9p7)FL8Zg4PHkFrsZP@K*a-#+WP-83~x5=hH((`hiIr=u5X0o0hAviRC%a i2DFJtPtsGKr2GRbdHWMIgaZZu0000! literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/irrigation.png b/greener-house-app/assets/irrigation.png new file mode 100644 index 0000000000000000000000000000000000000000..c9843ff7ffa88ff030499b0f033073a26ab27b2a GIT binary patch literal 963 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKj7wMQPjxGzEuO%G||(=F~sBe+$r83R{}-a_gANf zq_Au~ zipm+9Eh!37Qdtv2KL406mTYo<*3A2N?|k0%bRaSiQln-0>D=dV?{T2D?NY%?PN}v7CMhd8i N!PC{xWt~$(698c9ej@+? literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/irrigation_g.png b/greener-house-app/assets/irrigation_g.png new file mode 100644 index 0000000000000000000000000000000000000000..a09bb1f411a2d5adf7d25591ed5de6eb07e5a0ba GIT binary patch literal 1139 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+0817m!EPlzi}LD8e`LJ;Z# zp@$GQh|GQ71{Uv5d)83!xErMGVGl$ENLD;-2a*L3`U@ZR0ChF|ZvZiXx^7PbsR60) zDu9~YT@2FL0~7(OWcdFdqyUB*?l%*D$Am@S12a*qgdO=Qt83Gi9IxO`6Dxkv(?zaP7TY4X8LLbma1&=}QEO-bq z2dJ^=NiWF!hyA%vIzd)H?oK;16KF!gW2oPY?|~Q%R~vv9fouV5hlC8!sG`SR`9P;W z1i1tlwmgk~i9o8jB*-tAq5I6G0G9C`lq$>T>4A5{0gu$fS2U>hoSD)U#v{2Mp#+`a#WkNLU+ ziv(wU*$nF?E7XjYWPZM6E%ZFGK>h<;!7Pvd{K>h&dT|bXnmj=38I!!-T^Kr8Wj%l# z&H|6fVqlWG4#JF18nY{ag6t)pzOL*KxH(yc`0Y+42mtj&c)B=-Se&k%oF2?%D9|>& ztY8bX;}T8RrE^v&L|9 z)@|*g{{>YHZ1c=dIG)$!aGQKHsa4@Xmf`IluBN@+>g~b>Rx6_O!v$hq6i#OUFyS`$ z^ri=&7jM^RU};kPQOm{D`a95FTFvzi^VUBJEmi`3#~yu*F!AAW*;uS+q@vu#DY-p~ z^>D_bpUFKvYLicjJW4)Sl2(&cq}4ZN&x5m{coTPR)4x9B`78FPX|K39&zQWVX7z;W zDw%N(Y6k_xI>a^}*^yM)+N7~X^yJ!gKYfpu-ewEeExNoT)p5E4oSVn_o84oYHCOxA(>AiLiysTmJf!(L_58WclSiLkH4Waum^br~Y{B_c z_6rV$%1Is)p2xb!pe20I-p9>~HBSG|#;;M@^zu=;=|6@uIY}zLdFyq6!LC~38c~vx zSdwa$T$Bo=7>o=I&2$Y7bqy>-3{0&IEvyVpwG9ld3=I18u6#k!kei>9nO2Eg!~fzO yP;5(rYzWRzD=AMbN@XZ7FW1Y=%Pvk%EJ)SMFG`>N&PEETh{4m<&t;ucLK6Tss0&{J literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/main.png b/greener-house-app/assets/main.png new file mode 100644 index 0000000000000000000000000000000000000000..b9fc78df1f549548e16febbfc770d657a7a143f9 GIT binary patch literal 22446 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 literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/sun_b.png b/greener-house-app/assets/sun_b.png new file mode 100644 index 0000000000000000000000000000000000000000..bba7c9d7c7ed90ecfef3b92681a458227b945e55 GIT binary patch literal 673 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 F0RY2MT6X{d literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/temp.png b/greener-house-app/assets/temp.png new file mode 100644 index 0000000000000000000000000000000000000000..5aadfe4217af1de122b768fbabf9d9ded17e6807 GIT binary patch literal 1307 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5m^kh={g8AI%&+V01C2~c>21sKj7wMQDSA7dG!z3!)&AIkzF4BR-y5;yI3j|j227^sN8kHV?Nu3U<;<0zVkZH z1|B7kClwf+oRE1^VPa}pKvQ$vTfxmUHUGG#JbEZA%y7@=E0_5ecHi5oo6?y?BH8A2 ztaLMLnwMd*r*LZYlIzRQl?sVYw3c14hDpzF^$zJta&x&CJYtA^rfqgUys<@e-}y(+ za|Jv0?z_(rVPt)P?~rJ`V8Ysn*$+N1dT?%$kb?6Y!@ODA>(Y&vKQ;fzbLYv)V;O;q zru|N5j!|y5^Y;$<%Kjux^2?8;w7pz9yIwOj>?<~FaI!w}{P8bUfz`=gYfpKlY)C(+ zb}HZ1RC?Cr#aSO#nL35lzOq$pI62j*({XoCl=J3oPO|?FUObz;aR1^}roUu)eJgc( zZ>EVaHCwaCO+q4lN}!u0Gfy#(fXQ(-fj*YA8w3T`UypWVyk7ZJ@PhQYi#fA&Gc_3n zj?VI}Xy7i}opw1Vhe1F-^x2pW92r&9nj=R{xI@%wJsOAp2$h6Lkgd7uWk&Gu}JI^k|LQ%h(f+ zAql3t4`wh2E;;i3&V_HMYpgbGn5R`-WG)?;xs>q*bE=`|GF9edzbESWS18%sU6Xxg z+mtRFnM-wgw>IUTn6JIMH)e&@1^+-Mg+B$~rC8<`-<`bU1^13tSDT0La<)Wo z3sRVMXZgYB;(B&-#TjbecklgksQ8xrM#=x$pEMl3&)G2kVzN5%c-M-~Evo$Oa?@|O zaHlL?o;i=fVvEbgLM8=4hk$)AGiQA){yW_!ZrKzjnUYV7pME}d`oHS8zEAx7bz@~i zPHw&gEC*CeTq8~}U&Kt&9m Lu6{1-oD!MV&@eqGm>o zAb}`|DVg=8L_R2pK8fgqFlnVF_L49l+Jj-_|;!sys=_6f%lPFJK1n1~35_1oQ)1fZu?_z?Z=Hs@ncI z1SD+*MC3JKn@`%6Gy-p_>M@V)155@a!S|-B{+Ju7YMug51KR<0y#Z_iHUyXgD}m2} zTRv_B)&XU}cad+bb-DSX$tMGs-03nf3)`kL;Jo99y#2vr%7J;nO~;$CEmGhBuqV(9 zjxT+L08jy3bcf@>;J~)Z@o#~iz!@LU4}4w#eu;i*m9OX&_t{j4z-Mke0*nGGU0(w3 z_!3WbY>xY01%?N{sMmCC5ilZ=S; z20r!i#RQ*W*lE53gjcO6c0(RuS2C1m>Eep#2w?Yo5O7{qM~6ly_m@vRN>%?3Y(udF z`@5=EMR8|=>S73#0CnEqpJ1=XetmN|Ie@BO23mni5veF*}EJ#p<)TC9e7SeDk9s9*kg1R(8!jQ zh7%=&Ww$0QncOSjdn*MW(nVZBDN)rnU;&nF0Pgx^S-sEkkpQnJK0p15IO4@;!9h)2Y_K503ZV&z=3k9WlBxD+@+XPTWD z*cLf{0(*R}`FLvJGcox1<^azT@Nt!YUxC?iMKl5{G!;ui%ds>n*lkfdE29RFc?#I* zOP-A@b=x~wwp6T$8RqzVS)xfbVF|DTxKC%T_civ|gw@V^U>|k>L;OHM?0#hXFsPnv z3u6LNiFGvkK$1QH8i0Bqe-tcrN94QPZN1#~XDWe!NHy>Q@C8=wo&@#+n}KC`?TBSn z1&#!;C=jhd9m-AA(rgX|tw&O;B-wBX z9@P*PJgd|LD+8ojK?fD73W!0Bp{E$`?XDR8!f*mYlU!tiekPQd&<$O?N7dl2 z5}y_BupqPPAYz0jl@d5iTtNk_*7g1SU`MDg=z)_|;UmKEQHb!v;+ptNfdsQs(5-+z zA;9w{NWgdDSYXUG<-ywVJRCxg3a4SHL=S1>$ANG8SRwi=T*@Q~v0O0eGtJ%Jk*>y~ zFk*C1%R-mPs720)`}d<;$_C%$+5K$BmfPyPMQ@3A0{DDiDLLE=pSZQ9%cs?RjJpYNSjj7L5Nnj=?gUNtg3=1?Uy_>o3z_}W|9mwJ{^>DVrcH^ z8F`Aek;6$frg>!LvJm}Ew-cvU^>Zzz!GK1g50Uu7Lqjiy}_K#cYKh@z?E`^Gtzx-YZ6T;F$%M?kPINiM9WYmB_#%gGeu z`?}~1srT8ftjUy*d8??DLlJ1Gj!#D1bvLxHg;$DvWi#B#^?bJm&M@;*Kk<-*arzSa zer|E8{>=rs=DgE|&LsaiZKP&(%v^4im=v_O)jpO=Ra6XXgLmDqcaG;;rf~e~re!Tp zEB36OQ7;7|*W66`fNxM)gimvfy>KeH?d{}fen&j+9Z*=w@3k&fA1G>U#%9+ZxzCkV z9$tE6XK-iJqokiodpp>d#QLN?jtX;oZRLsKx{K7Ll9|SCn{_s~ckHzG{HA?4gbtpd zyu8kNC6g7V*H<=@Z~x*v^0c*g!550uTW2-pA8vh}#EbF6RuV<4nLBRLxlY61Z;#s% zh}aYy94WkKd7BknQ##b*^~$5@f#r(sg$Dn3`b$_mNqUMTgOMi6fC~ts(&&LSS|D}t z3Tg<0wulizpHHPRsMN+hwfDaYvIXhuGB^K!fwsf192SuA4qQQ|Bqv3b0djJ3DC@r3 cAWlm`GAII3mU>``7bF2TE0%dKJo%eH0nn1+vH$=8 literal 0 HcmV?d00001 diff --git a/greener-house-app/assets/toggle-switch.png b/greener-house-app/assets/toggle-switch.png new file mode 100644 index 0000000000000000000000000000000000000000..f4bb51dddd1dc6c3e2b07de807f6f3339c1d9353 GIT binary patch literal 29434 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 literal 0 HcmV?d00001 diff --git a/greener-house-app/buttons.js b/greener-house-app/buttons.js new file mode 100644 index 0000000..8b36138 --- /dev/null +++ b/greener-house-app/buttons.js @@ -0,0 +1,10 @@ +/* * Copyright (C) 2010-2016 Marvell International Ltd. * Copyright (C) 2002-2010 Kinoma, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * * This is an updated version of the buttons.js module from the Controls library * https://github.com/Kinoma/kinomajs/blob/master/kinoma/kpr/libraries/Controls/src/controls/buttons.js * */ import { THEME } from 'theme'; export class ButtonBehavior extends Behavior { onCreate(container, data) { this.data = data; container.state = container.active ? 1 : 0; } onTouchBegan(container, id, x, y, ticks) { this.changeState(container, 2); } onTouchCancelled(container, id, x, y, ticks) { this.changeState(container, 1); } onTouchEnded(container, id, x, y, ticks) { this.changeState(container, 1); container.delegate("onTap"); } changeState(container, state) { container.state = state; if (false == ("length" in container)) debugger if (container.length > 0) { var content = container.first; while (content) { content.state = state; content = content.next; } } } }; export var Button = Container.template($ => ({ active: true, style: THEME.buttonStyle, skin: THEME.buttonSkin, Behavior: ButtonBehavior })); class ToggleButtonBehavior extends ButtonBehavior { onCreate(data) { + this.selectedVariant = data.selectedVariant || 0; + this.unselectedVariant = data.unselectedVariant || 0; + } onTouchBegan(container, id, x, y, ticks) { ButtonBehavior.prototype.onTouchBegan.call(this, container, id, x, y, ticks); container.delegate("doToggle", false); } doToggle(container, silent) { var button = container if (button.state != 0) button.variant = (button.variant == this.selectedVariant) ? this.unselectedVariant : this.selectedVariant if (! silent) { if (button.variant == this.selectedVariant) container.delegate("onSelected"); else container.delegate("onUnselected"); } } isSelected(container) { return container.variant == this.selectedVariant; } setSelected(container, selected, silent) { if (selected != container.delegate("isSelected")) container.delegate("doToggle", silent); } }; class CheckboxBehavior extends ToggleButtonBehavior { + onCreate(container) { + super.onCreate({ selectedVariant: THEME.CHECKBOX_SELECTED, unselectedVariant: THEME.CHECKBOX_UNSELECTED }) + } }; var Checkbox = Container.template($ => ({ active: true, variant: THEME.CHECKBOX_UNSELECTED, skin: THEME.glyphSkin, Behavior: CheckboxBehavior })); export var LabeledCheckbox = Line.template($ => ({ style: THEME.labeledButtonStyle, contents: [ Checkbox( $, { name: "button", left: 0, Behavior : class extends CheckboxBehavior { onSelected(container) { container.container.delegate("onSelected"); } onUnselected(container) { container.container.delegate("onUnselected"); } } }), Label( $, {name: "buttonLabel", left: 0, string: $.name} ) ] })); class RadioButtonBehavior extends ToggleButtonBehavior { onTouchBegan(container, id, x, y, ticks) { this.ignoreTouchEnded = false; if (container.variant == this.selectedVariant) this.ignoreTouchEnded = true; else { ButtonBehavior.prototype.onTouchBegan.call(this, container, id, x, y, ticks); container.delegate("doToggle", false); } } onTouchEnded(container, id, x, y, ticks) { if (! this.ignoreTouchEnded) ButtonBehavior.prototype.onTouchEnded.call(this, container, id, x, y, ticks); } }; class RadioBehavior extends RadioButtonBehavior { + onCreate(container) { + super.onCreate({ selectedVariant: THEME.RADIO_SELECTED, unselectedVariant: THEME.RADIO_UNSELECTED }); + } }; var Radio = Container.template($ => ({ active: true, variant: THEME.RADIO_UNSELECTED, skin: THEME.glyphSkin, Behavior: RadioBehavior })); var LabeledRadio = Line.template($ => ({ style: THEME.labeledButtonStyle, contents: [ Radio( $, { name: "button", left: 0, Behavior : class extends RadioBehavior{ onSelected(container) { var labeledRadio = container.container; var radioGroup = labeledRadio.container; labeledRadio.delegate("onSelected"); radioGroup.delegate("onGroupButtonSelected", labeledRadio); } onUnselected(container) { container.container.delegate("onUnselected"); } } }), Label( $, {name: "buttonLabel", left: 0, string: $.name} ) ] })); export class RadioGroupBehavior extends Behavior{ onCreate(column, data) { this.data = data; } onDisplaying(column) { var data = this.data; var buttonStr = "buttonNames" in data ? data.buttonNames : "please add,buttonNames,and,selected,properties,to data"; var buttonNames = buttonStr.split(","); var selectedName = "selected" in data ? data.selected : buttonNames[0]; for (var i=0; i < buttonNames.length; i++) { var buttonName = buttonNames[i]; var button = new LabeledRadio( { name : buttonName } ); button.coordinates = { left : 0, top : undefined, right : undefined, bottom : undefined }; column.add( button ); if (buttonName == selectedName) button.button.delegate("doToggle", true); } } onGroupButtonSelected(column, labeledButton) { var aLabeledButton = column.first; while (aLabeledButton) { if (aLabeledButton === labeledButton) aLabeledButton.button.delegate("setSelected", true, true); else aLabeledButton.button.delegate("setSelected", false, true); aLabeledButton = aLabeledButton.next; } var buttonName = labeledButton.buttonLabel.string this.onRadioButtonSelected(buttonName); column.delegate("onRadioGroupButtonSelected", buttonName); } }; export var RadioGroup = Column.template($ => ({ active: true, Behavior: RadioGroupBehavior })); \ No newline at end of file diff --git a/greener-house-app/drawer.js b/greener-house-app/drawer.js new file mode 100644 index 0000000..39380d2 --- /dev/null +++ b/greener-house-app/drawer.js @@ -0,0 +1,62 @@ +import { Greenhouses } from "greenhouses_around"; +import { name_h, naviBar_h, padding, drawerScreen, + currentScreen, Home, adjustFanIcons, adjustNavButtons } from "main"; + +// Skins let blackSkin = new Skin ({fill: 'black'}); let whiteSkin = new Skin ({fill: 'white'}); +let graySkin = new Skin ({fill: '#6c6c6c'}); +let greenSkin = new Skin ({fill: '#71e28b'}); + +// Fonts var titleW = new Style({font: 'bold 20px', color: 'white'}); +var titleB = new Style({font: 'bold 20px', color: 'black'}); +var titleG = new Style({font: 'bold 20px', color: '#71e28b'}); +var regularW = new Style({font: '20px', color: 'white'}); +var regularB = new Style({font: '20px', color: 'black'}); +var regularG = new Style({font: '20px', color: '#71e28b'}); + +// Greenhouses buttons +export let greenhouseBtn = Container.template($ => ({ left: 0, right: 0, top: 0, bottom: undefined, + height: 50, active: true, + + behavior: Behavior({ onCreate: function(content){ this.upSkin = new Skin({ fill: "transparent", borders: {left: 0, right: 0, top: 0, bottom: 1}, + stroke: "black", }); this.downSkin = new Skin({ fill: "#71e28b", borders: {left: 0, right: 0, top: 1, bottom: 1}, + stroke: "black", }); content.skin = this.upSkin; }, onTouchBegan: function(content){ content.skin = this.downSkin; }, onTouchEnded: function(content){ content.skin = this.upSkin; + application.remove(currentScreen); + currentScreen = new Home(); + application.add(currentScreen); + application.distribute("updateState"); + adjustFanIcons(); + adjustNavButtons(0); + application.distribute("updateNavButtons"); + application.distribute("updateInfo", 1); + }, }), contents: [ Label($, { + top: 0, bottom: 0, left: 10, right: undefined, + style: regularW, string: $.text, + }) ] })); + +var drawerWidth = 200; +export var gh = []; +gh[0] = new greenhouseBtn({text: "Greenhouse 1", id: 1}); + +export var Drawer = Container.template($ => ({ left: 0, right: undefined, top: name_h, bottom: naviBar_h, + width: drawerWidth, skin: graySkin, contents: [ Column($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + gh, + new addBtn({}), + ] + }), ] })); + +// Add greenhous button +let addBtn = Container.template($ => ({ left: 0, right: 0, top: 0, bottom: undefined, + height: 50, active: true, + + behavior: Behavior({ onCreate: function(content){ this.upSkin = new Skin({ fill: "transparent", borders: {left: 0, right: 0, top: 0, bottom: 1}, + stroke: "black", }); this.downSkin = new Skin({ fill: "#71e28b", borders: {left: 0, right: 0, top: 0, bottom: 1}, + stroke: "black", }); content.skin = this.upSkin; }, onTouchBegan: function(content){ content.skin = this.downSkin; }, onTouchEnded: function(content){ content.skin = this.upSkin; + application.distribute("updateDrawer"); + application.add(ghAroundScreen); + }, }), + contents: [ new Label({ top: 0, bottom: 0, left: padding, right: undefined, + style: regularW, string: "Add" }) ] })); + +export var ghAroundScreen = new Greenhouses(); diff --git a/greener-house-app/field.js b/greener-house-app/field.js new file mode 100644 index 0000000..3514ee7 --- /dev/null +++ b/greener-house-app/field.js @@ -0,0 +1,10 @@ +import { + SystemKeyboard +} from 'keyboard'; + +export class FieldLabelBehavior extends Behavior { onCreate(label, data) { this.data = data; } onDisplayed(label) { this.onEdited(label); } onEdited(label) { } onFocused(label) { label.select(0, label.length); + SystemKeyboard.show(); } onKeyDown(label, key, repeat, ticks) { if (key) { var code = key.charCodeAt(0); var edited = false; switch (code) { case 1: /* home */ label.select(0, 0); break; case 2: /* delete selection */ label.insert(); edited = true; break; case 3: /* enter */ return false; case 4: /* end */ label.select(label.length, 0); break; case 5: /* help */ return false; case 8: /* backspace */ if (label.selectionLength == 0) label.select(label.selectionOffset - 1, 1) label.insert() edited = true; break; case 9: /* tab */ return false; case 11: /* page up */ return false; case 12: /* page down */ return false; case 13: /* return */ if (label instanceof Text) { label.insert(key); edited = true; } else return false; break; case 27: /* escape */ return false; case 28: /* left */ if (shiftKey) { label.select(label.selectionOffset - 1, label.selectionLength + 1); } else { if (label.selectionLength == 0) label.select(label.selectionOffset - 1, 0); else label.select(label.selectionOffset, 0); } break; case 29: /* right */ if (shiftKey) label.select(label.selectionOffset, label.selectionLength + 1); else { if (label.selectionLength == 0) label.select(label.selectionOffset + 1, 0); else label.select(label.selectionOffset + label.selectionLength, 0); } break; case 30: /* up */ return false; case 31: /* down */ return false; case 127: /* delete */ if (label.selectionLength == 0) label.select(label.selectionOffset, 1) label.insert() edited = true; break; default: if ((Event.FunctionKeyPlay <= code) && (code <= Event.FunctionKeyPower)) return false; if (code > 0x000F0000) return false; label.insert(key); edited = true; } } else { label.insert() edited = true; } this.onReveal(label); if (edited) this.onEdited(label); return true; } onKeyUp(label, key, repeat, ticks) { if (!key) return false var code = key.charCodeAt(0); var edited = false; switch (code) { case 3: /* enter */ case 5: /* help */ case 9: /* tab */ case 11: /* page up */ case 12: /* page down */ case 27: /* escape */ case 30: /* up */ case 31: /* down */ return false; case 13: /* return */ return label instanceof Text; default: if ((Event.FunctionKeyPlay <= code) && (code <= Event.FunctionKeyPower)) return false; return code <= 0x000F0000; } } onReveal(label) { label.container.reveal(label.selectionBounds); } onTouchBegan(label, id, x, y, ticks) { this.position = label.position; var offset = label.hitOffset(x - this.position.x, y - this.position.y); if (shiftKey) { if (offset < label.selectionOffset) this.anchor = label.selectionOffset + label.selectionLength; else this.anchor = label.selectionOffset; } else this.anchor = offset; this.onTouchMoved(label, id, x, y, ticks); } onTouchCancelled(label, id, x, y, ticks) { } onTouchEnded(label, id, x, y, ticks) { this.onTouchMoved(label, id, x, y, ticks); } onTouchMoved(label, id, x, y, ticks) { this.offset = label.hitOffset(x - this.position.x, y - this.position.y); label.select(this.offset, 0); } onUnfocused(label) { } }; + +export class FieldScrollerBehavior extends Behavior { + onTouchBegan(scroller, id, x, y, ticks) { let label = scroller.first; this.tracking = label.focused; if (this.tracking) label.behavior.onTouchBegan(label, id, x, y, ticks); else label.focus(); } onTouchMoved(scroller, id, x, y, ticks) { let label = scroller.first; if (this.tracking) label.behavior.onTouchMoved(label, id, x, y, ticks); } onTouchEnded(scroller, id, x, y, ticks) { let label = scroller.first; if (this.tracking) label.behavior.onTouchEnded(label, id, x, y, ticks); } +} \ No newline at end of file diff --git a/greener-house-app/greenhouses_around.js b/greener-house-app/greenhouses_around.js new file mode 100644 index 0000000..7fd42c0 --- /dev/null +++ b/greener-house-app/greenhouses_around.js @@ -0,0 +1,64 @@ +import { gh, greenhouseBtn, ghAroundScreen } from "drawer"; +import { fanState } from "ventilation"; +import { padding, drawerScreen, currentScreen, Home, + adjustFanIcons, adjustNavButtons, greenhouseNum, + currTemperature, currSunlight, currHumidity, currAirFlow } from "main"; + +// Skins let blackSkin = new Skin ({fill: 'black'}); let whiteSkin = new Skin ({fill: 'white'}); +let graySkin = new Skin ({fill: '#6c6c6c'}); +let greenSkin = new Skin ({fill: '#71e28b'}); + +// Fonts var titleW = new Style({font: 'bold 20px', color: 'white'}); +var titleB = new Style({font: 'bold 20px', color: 'black'}); +var titleG = new Style({font: 'bold 20px', color: '#71e28b'}); +var regularW = new Style({font: '20px', color: 'white'}); +var regularB = new Style({font: '20px', color: 'black'}); +var regularG = new Style({font: '20px', color: '#71e28b'}); + +var conWH = 200; + +export var Greenhouses = Container.template($ => ({ left: undefined, right: undefined, top: undefined, bottom: undefined, + width: conWH, height: conWH, skin: graySkin, contents: [ Column($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + new ghABtn({text: "Greenhouse 1", id: 1}), + new ghABtn({text: "XYZ_123-%PO", id: 2}), + ] + }), ] })); + +// Greenhouses buttons +let ghABtn = Container.template($ => ({ left: 0, right: 0, top: 0, bottom: undefined, + height: 50, active: true, + + behavior: Behavior({ onCreate: function(content){ this.upSkin = new Skin({ fill: "transparent", borders: {left: 0, right: 0, top: 0, bottom: 1}, + stroke: "black", }); this.downSkin = new Skin({ fill: "#71e28b", borders: {left: 0, right: 0, top: 1, bottom: 1}, + stroke: "black", }); content.skin = this.upSkin; }, onTouchBegan: function(content){ content.skin = this.downSkin; }, onTouchEnded: function(content){ + content.skin = this.upSkin; + application.remove(ghAroundScreen); + application.remove(currentScreen); + currentScreen = new Home(); + application.add(currentScreen); + application.distribute("updateState"); + adjustFanIcons(); + adjustNavButtons(0); + application.distribute("updateNavButtons"); + if ($.id == 1) { + //application.distribute("updateInfo", 1); + } else if ($.id == 2) { + gh[1] = new greenhouseBtn({text: "Greenhouse 2", id: 2}); + //application.distribute("updateInfo", 2); + greenhouseNum = 2; + currTemperature = 62; + currSunlight = 34; + currHumidity = 45; + currAirFlow = 5; + fanState = [0,0,0,0,0,0]; + application.distribute("updateGhNum"); + application.distribute("updateState"); + application.distribute("updateFanString"); + application.distribute("updateNavButtons"); + + } }, }), contents: [ Label($, { + top: 0, bottom: 0, left: 10, right: undefined, + style: regularW, string: $.text, + }) ] })); diff --git a/greener-house-app/irrigation.js b/greener-house-app/irrigation.js new file mode 100644 index 0000000..7cb342f --- /dev/null +++ b/greener-house-app/irrigation.js @@ -0,0 +1,14 @@ +import {name_h, naviBar_h} from "main"; + +// Skins let blackSkin = new Skin ({fill: 'black'}); let whiteSkin = new Skin ({fill: 'white'}); +let graySkin = new Skin ({fill: '#999999'}); +let greenSkin = new Skin ({fill: '#71e28b'}); + +// Fonts var titleW = new Style({font: 'bold 20px', color: 'white'}); +var titleB = new Style({font: 'bold 20px', color: 'black'}); +var titleG = new Style({font: 'bold 20px', color: '#71e28b'}); +var regularW = new Style({font: '20px', color: 'white'}); +var regularB = new Style({font: '20px', color: 'black'}); +var regularG = new Style({font: '20px', color: '#71e28b'}); + +export var IrrigationScreen = Column.template($ => ({ left: 0, right: 0, top: name_h, bottom: naviBar_h, skin: whiteSkin, contents: [ Label($, { left: 0, right: 0, top: 10, bottom: undefined, style: titleG, string: "Irrigation" }), ] })); \ No newline at end of file diff --git a/greener-house-app/keyboard.js b/greener-house-app/keyboard.js new file mode 100644 index 0000000..0d7b180 --- /dev/null +++ b/greener-house-app/keyboard.js @@ -0,0 +1 @@ +/* * Copyright (C) 2010-2016 Marvell International Ltd. * Copyright (C) 2002-2010 Kinoma, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ export var SystemKeyboard = { show () { if (!system.keyboard.visible) { system.keyboard.visible = true; } }, hide() { if (system.keyboard.visible) { system.keyboard.visible = false; } } }; \ No newline at end of file diff --git a/greener-house-app/main.js b/greener-house-app/main.js new file mode 100644 index 0000000..7f47ac3 --- /dev/null +++ b/greener-house-app/main.js @@ -0,0 +1,458 @@ +// Import layouts from other files and pins +import { SunlightScreen } from "sunlight"; +import { TemperatureScreen } from "temperature"; +import { VentilationScreen, fanState } from "ventilation"; +import { IrrigationScreen } from "irrigation"; +import { Drawer, ghAroundScreen } from "drawer"; +import Pins from "pins"; +import { CrossFade, Push, Flip, TimeTravel } from 'transition'; + +// Skins let blackSkin = new Skin ({fill: 'black'}); let whiteSkin = new Skin ({fill: 'white'}); +let graySkin = new Skin ({fill: '#999999'}); +let greenSkin = new Skin ({fill: '#71e28b'}); +let navBarSkin = new Skin({ fill: "white", borders: {left: 0, right: 0, top: 1, bottom: 0}, stroke: "#999999" }); +let fanWhiteSkin = new Skin({ fill: "white", borders: {left: 1, right: 1, top: 1, bottom: 1}, stroke: "#999999" }); +let fanGreenSkin = new Skin({ fill: "#71e28b", borders: {left: 1, right: 1, top: 1, bottom: 1}, stroke: "#999999" }); + +// Fonts var titleW = new Style({font: 'bold 20px', color: 'white'}); +var titleB = new Style({font: 'bold 20px', color: 'black'}); +var titleG = new Style({font: 'bold 20px', color: '#71e28b'}); +var regularW = new Style({font: '20px', color: 'white'}); +var regularB = new Style({font: '20px', color: 'black'}); +var regularG = new Style({font: '20px', color: '#71e28b'}); +var smallB = new Style({font: '12px', color: 'black'}); + +// Screen layout sizes +export var name_h = 50; +export var naviBar_h = 60; +export let padding = 10; + + +// Info variables +export var currTemperature = 86; +export var currSunlight = 55; +export var currHumidity = 62; +export var currAirFlow = 15; +export var greenhouseNum = 1; + +// Nav buttons icons +var sunlightBtn = "assets/sun.png"; +var temperatureBtn = "assets/temp.png"; +var homeBtn = "assets/home_g.png"; +var ventilationBtn = "assets/fan.png"; +var irrigationBtn = "assets/irrigation.png"; +var addBtnIcon = "assets/settings.png"; + +// State variables +export var greenhouses = []; +export var UVLights = {}; +export var heater = false; +export var drawerState = "closed"; +export var drawerScreen = new Drawer(); + +var fanIcons = []; + +// Screen layout export var Home = Container.template($ => ({ left: 0, right: 0, top: name_h, bottom: naviBar_h, skin: whiteSkin, contents: [ + + Column($, { left: 0, right: 0, top: 0, bottom: 0, + contents: [ + // Current info + new CurrInfo, + + // Sunlight diagram + new FanDiagram + ] + }), + ] })); + +// Current conditions inside the greenhouse. +var CurrInfo = Column.template($ => ({ + left: 0, right: 0, top: 0, bottom: undefined, height: 250, + contents: [ + + new Label ({ left: padding, right: undefined, top: padding, style: titleG, + string: "Current info:" + }), + Line($, { + left: 0, right: 0, top: padding, bottom: 0, skin: navBarSkin, + contents: [ + new Picture({left: padding, right: undefined, top: 0, bottom: 0, + url: "assets/sun_b.png", height: 32, width: 32, + }), + Label($, { + left: padding, right: undefined, top: 0, bottom: 0, style: regularB, + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Sunlight: " + Math.round(currSunlight) + "%"; } } + }), + ] + }), + Line($, { + left: 0, right: 0, top: 0, bottom: 0, skin: navBarSkin, + contents: [ + new Picture({left: padding, right: undefined, top: 0, bottom: 0, + url: "assets/temp_b.png", height: 32, width: 32, + }), + Label($, { + left: padding, right: undefined, top: 0, bottom: 0, style: regularB, + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Temperature: " + Math.round(currTemperature) + " F"; } } + }), + ] + }), + Line($, { + left: 0, right: 0, top: 0, bottom: 0, skin: navBarSkin, + contents: [ + new Picture({left: padding, right: undefined, top: 0, bottom: 0, + url: "assets/humidity.png", height: 32, width: 32, + }), + Label($, { + left: padding, right: undefined, top: 0, bottom: 0, style: regularB, + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Humidity: " + Math.round(currHumidity) + "%"; } } + }), + ] + }), + Line($, { + left: 0, right: 0, top: 0, bottom: 0, skin: navBarSkin, + contents: [ + new Picture({left: padding, right: undefined, top: 0, bottom: 0, + url: "assets/airflow.png", height: 32, width: 32, + }), + Label($, { + left: padding, right: undefined, top: 0, bottom: 0, style: regularB, + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Airflow: " + Math.round(currAirFlow) + "%"; } } + }), + ] + }), + /* + new Label ({ left: 0, right: 0, top: padding, style: titleG, + string: "Current info" + }), + + Line($, { + left: 0, right: 0, top: padding, bottom: 0, + contents: [ + + Column($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + + + new Picture({left: 0, right: 0, top: 0, bottom: 0, url: "assets/sun_b.png"}), + Label($, { + left: 0, right: 0, top: 0, bottom: 0, style: regularB, string: "Sunlight: " + Math.round(currSunlight) + "%", + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Sunlight: " + Math.round(currSunlight) + "%"; } } + }), + ] + }), + + Column($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + + + new Picture({left: 0, right: 0, top: 0, bottom: 0, url: "assets/temp_b.png"}), + Label($, { + left: 0, right: 0, top: 0, bottom: 0, style: regularB, string: "Temperature: " + Math.round(currTemperature) + " F", + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Temperature: " + Math.round(currTemperature) + " F"; } } + }), + ] + }), + ] + }), + Line($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + + Column($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + + + new Picture({left: 0, right: 0, top: 0, bottom: 0, url: "assets/humidity.png"}), + Label($, { + left: 0, right: 0, top: 0, bottom: 0, style: regularB, string: "Humidity: " + Math.round(currHumidity) + "%", + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Humidity: " + Math.round(currHumidity) + "%"; } } + }), + ] + }), + + Column($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + + + new Picture({left: 0, right: 0, top: 0, bottom: 0, url: "assets/airflow.png"}), + Label($, { + left: 0, right: 0, top: 0, bottom: 0, style: regularB, string: "Airflow: " + Math.round(currAirFlow) + "%", + Behavior: class extends Behavior{ updateState(container, string) { container.string = "Airflow: " + Math.round(currAirFlow) + "%"; } } + }), + ] + }), + ] + }),*/ + ] +})); + +// Sunlight over a day. +var FanDiagram = Column.template($ => ({ + left: 0, right: 0, top: 0, bottom: 0, height: Home.height / 2, skin: navBarSkin, + contents: [ + + new Label({ left: 10, right: undefined, top: padding, bottom : 0, + style: titleG, string: "Current fans state: " + }), + + Line($, { + left: 10, right: 10, top: 10, bottom: 0, + contents: [ + fanIcons[0] = new Fan({skin: fanWhiteSkin, id: 0}), + fanIcons[1] = new Fan({skin: fanWhiteSkin, id: 1}), + fanIcons[2] = new Fan({skin: fanWhiteSkin, id: 2}), + ] + }), + + Line($, { + left: 10, right: 10, top: 0, bottom: 10, + contents: [ + fanIcons[3] = new Fan({skin: fanWhiteSkin, id: 3}), + fanIcons[4] = new Fan({skin: fanWhiteSkin, id: 4}), + fanIcons[5] = new Fan({skin: fanWhiteSkin, id: 5}), + ] + }), + ] +})); + +var Fan = Column.template($ => ({ + left: 0, right: 0, top: 0, bottom: 0, skin: $.skin, id: $.id, + contents: [ + Label($, { + left: 0, right: 0, top: 0, bottom: 0, + style: regularB, string: fanState[$.id], + }), + ], +})); + +//navigation buttons +var navBtn = Picture.template($ => ({ left: padding / 2, right: padding / 2, top: padding / 2, bottom: undefined, + height: 32, width: 32, active: true, url: $.img, + + behavior: Behavior({ onTouchEnded: function(content){ + + adjustNavButtons($.id); + application.remove(currentScreen); + currentScreen = new $.nextScreen; application.add(currentScreen); + application.distribute("updateNavButtons"); }, + updateNavButtons(container, url) { + if ($.id == 1) { + container.url = sunlightBtn; + } else if ($.id == 2) { + container.url = temperatureBtn; + application.distribute("updateCurrTemp"); + application.distribute("adjustTempSlider"); + } else if ($.id == 0) { + container.url = homeBtn; + application.distribute("updateState"); + adjustFanIcons(); + } else if ($.id == 3) { + container.url = ventilationBtn; + application.distribute("adjustVentSlider", 0); + } else if ($.id == 4) { + container.url = irrigationBtn; + } + application.distribute("updateDrawer"); }, + updateDrawer() { + if (drawerState == "open") { + application.remove(drawerScreen); + drawerState = "closed"; + addBtnIcon = "assets/settings.png"; + application.distribute("updateSettingsBtn"); + } + }, }), })); + +// Changes the fans bg depending on state +export function adjustFanIcons(){ + for (var i = 0; i < fanState.length; i++) { + if (fanState[i] > 0) { + fanIcons[i].skin = fanGreenSkin; + } else { + fanIcons[i].skin = fanWhiteSkin; + } + } +} + +// Update button +let updateBtn = Container.template($ => ({ left: undefined, right: 0, top: 0, bottom: 0, width: 100, active: true, + + behavior: Behavior({ onCreate: function(content){ this.upSkin = new Skin({ fill: "#999999", borders: {left: 1, right: 1, top: 1, bottom: 1}, }); this.downSkin = new Skin({ fill: "#71e28b", borders: {left: 1, right: 1, top: 1, bottom: 1}, }); content.skin = this.upSkin; }, onTouchBegan: function(content){ content.skin = this.downSkin; + application.distribute("getTemperature"); + application.distribute("getHumidity"); }, onTouchEnded: function(content){ content.skin = this.upSkin; + + // fetch info from device and update on screen + application.distribute("updateInfo"); }, + updateInfo(container) { + + setCurrentState(); } }), contents: [ new Label({ top: 0, bottom: 0, left: 0, right: 0, + style: regularW, string: "update" }) ] })); + +// add greenhouse button +let settingsBtn = Container.template($ => ({ left: 0, right: undefined, top: 0, bottom: 0, + width: 50, active: true, + + behavior: Behavior({ onCreate: function(content){ this.upSkin = new Skin({ fill: "transparent", }); this.downSkin = new Skin({ fill: "#71e28b", }); content.skin = this.upSkin; }, onTouchBegan: function(content){ content.skin = this.downSkin; }, onTouchEnded: function(content){ content.skin = this.upSkin; + // Opening or closing drawer + if (drawerState == "closed") { + application.add(drawerScreen); + drawerState = "open"; + addBtnIcon = "assets/back.png"; + } else { + application.remove(drawerScreen); + drawerState = "closed"; + addBtnIcon = "assets/settings.png"; + } + application.distribute("updateSettingsBtn"); }, }), contents: [ Picture($, { top: padding, bottom: undefined, left: undefined, + right: undefined, url: addBtnIcon, + Behavior: class extends Behavior{ updateSettingsBtn(container, url) { container.url = addBtnIcon; } } + }) ] })); + +// Transition for the side drawer. +/*let transitioningBehavior = Behavior({ onCreate: function(container, data) { this.numTransitions = 2; }, onDisplayed: function(container) { container.interval = 1800; container.start(); }, onTimeChanged: function(container) { container.bubble( "onTriggerTransition" ); }, onTriggerTransition: function(container) { let toScreen = new NumberedScreen({ transitionNumber: (data.index + 1) % this.numTransitions, }); switch ( data.index ) { case 0: container.run( new Push(), container.last, toScreen, { duration: 400, direction: "left" } ); break; case 1: container.run( new Push(), container.last, toScreen, { direction: "right", duration: 400 } ); break; } data.index = (data.index + 1) % this.numTransitions; }, }) +*/ + +export function adjustNavButtons(id) { + + if (id == 1) { + sunlightBtn = "assets/sun_g.png"; + temperatureBtn = "assets/temp.png"; + homeBtn = "assets/home.png"; + ventilationBtn = "assets/fan.png"; + irrigationBtn = "assets/irrigation.png"; + } else if (id == 2) { + sunlightBtn = "assets/sun.png"; + temperatureBtn = "assets/temp_g.png"; + homeBtn = "assets/home.png"; + ventilationBtn = "assets/fan.png"; + irrigationBtn = "assets/irrigation.png"; + } else if (id == 0) { + sunlightBtn = "assets/sun.png"; + temperatureBtn = "assets/temp.png"; + homeBtn = "assets/home_g.png"; + ventilationBtn = "assets/fan.png"; + irrigationBtn = "assets/irrigation.png"; + } else if (id == 3) { + sunlightBtn = "assets/sun.png"; + temperatureBtn = "assets/temp.png"; + homeBtn = "assets/home.png"; + ventilationBtn = "assets/fan_g.png"; + irrigationBtn = "assets/irrigation.png"; + } else if (id == 4) { + sunlightBtn = "assets/sun.png"; + temperatureBtn = "assets/temp.png"; + homeBtn = "assets/home.png"; + ventilationBtn = "assets/fan.png"; + irrigationBtn = "assets/irrigation_g.png"; + } +} + +// App's top bar. +var TopBar = Line.template($ => ({ left: 0, right: 0, top: 0, height: name_h, skin: graySkin, contents: [ + // add greenhouse button + new settingsBtn({}), + + // Greenhouse's name Label($, {left: 50, right: undefined, top: 0, bottom: 0, + style: regularW, string: "Greenhouse " + greenhouseNum, + Behavior: class extends Behavior{ updateGhNum(container, string) { container.string = "Greenhouse " + greenhouseNum; } } + }), + + // Update button + //new updateBtn({}), ] })); + +// Navigation bar +var NavBar = new Line({ left: 0, right: 0, bottom: 0, + skin: navBarSkin, height: naviBar_h, contents: [ + new Column({left: 0, right: 0, top: 0, bottom: 0, + contents: [ + new navBtn({nextScreen: Home, img: homeBtn, id: 0}), + new Label({left: 0, right: 0, top: 0, bottom: 0, + style: smallB, string: "Home", + }), + ] + }), + new Column({left: 0, right: 0, top: 0, bottom: 0, + contents: [ + new navBtn({nextScreen: SunlightScreen, img: sunlightBtn, id: 1}), + new Label({left: 0, right: 0, top: 0, bottom: 0, + style: smallB, string: "Sunlight", + }), + ] + }), + new Column({left: 0, right: 0, top: 0, bottom: 0, + contents: [ + new navBtn({nextScreen: TemperatureScreen, img: temperatureBtn, id: 2}), + new Label({left: 0, right: 0, top: 0, bottom: 0, + style: smallB, string: "Temperature", + }), + ] + }), + new Column({left: 0, right: 0, top: 0, bottom: 0, + contents: [ + new navBtn({nextScreen: VentilationScreen, img: ventilationBtn, id: 3}), + new Label({left: 0, right: 0, top: 0, bottom: 0, + style: smallB, string: "Ventilation", + }), + ] + }), + new Column({left: 0, right: 0, top: 0, bottom: 0, + contents: [ + new navBtn({nextScreen: IrrigationScreen, img: irrigationBtn, id: 4}), + new Label({left: 0, right: 0, top: 0, bottom: 0, + style: smallB, string: "Irrigation", + }), + ] + }), ] }); + +// Get's current info from device +function setCurrentState() { + + // update info on screen + application.distribute("updateState"); +} + +/* Application definition */ +export var currentScreen = new Home(); +export let remotePins; + class AppBehavior extends Behavior { onLaunch(application) { + + // Sets the pin connection + let discoveryInstance = Pins.discover( connectionDesc => { if (connectionDesc.name == "pins-share") { trace("Connecting to remote pins\n"); remotePins = Pins.connect(connectionDesc); } }, connectionDesc => { if (connectionDesc.name == "pins-share") { trace("Disconnected from remote pins\n"); remotePins = undefined; } } ); + + // Adds the top bar, current screen and + // navigation bar to the screen. + application.add(new TopBar()); application.add(currentScreen); + application.add(NavBar); + application.distribute("updateState"); } + onToggleFan(application, value) { if (remotePins) { + remotePins.invoke("/Fan/write", value); + } } + onToggleIrrigation(application, value) { if (remotePins) { + remotePins.invoke("/Irrigation/write", value); + } } + getTemperature(application) { + if (remotePins) { + remotePins.invoke("/TemperatureIn/read", function(result) { if (result) { + currTemperature = result * 100 + 20; } else { trace("no result\n"); } }); + } + } + getHumidity(application) { + if (remotePins) { + remotePins.invoke("/HumidityIn/read", function(result) { if (result) { + currHumidity = result * 100; } else { trace("no result\n"); } }); + } + } + setTemperature(application, value) { + if (remotePins) { + remotePins.invoke("/TemperatureOut/write", value); + } + } + setHumidity(application, value) { + if (remotePins) { + remotePins.invoke("/HumidityOut/write", value); + } + } } application.behavior = new AppBehavior(); diff --git a/greener-house-app/project.json b/greener-house-app/project.json new file mode 100644 index 0000000..b641419 --- /dev/null +++ b/greener-house-app/project.json @@ -0,0 +1,17 @@ +{ + "title":"greener_house_app", + "description":"This template can be used to create a basic KinomaJS application .", + "id":"greener-house-app.project.kinoma.marvell.com", + "tags":[ + "emptySample" + ], + "Create":{ + "main":"main" + }, + "Element":{ + "main":"main" + }, + "iap140": { + "main":"main" + } +} \ No newline at end of file diff --git a/greener-house-app/sliders.js b/greener-house-app/sliders.js new file mode 100644 index 0000000..eff7147 --- /dev/null +++ b/greener-house-app/sliders.js @@ -0,0 +1 @@ +/* * Copyright (C) 2010-2016 Marvell International Ltd. * Copyright (C) 2002-2010 Kinoma, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * * This is the JavaScript equivalent of the the sliders.xml module from the Controls library * https://github.com/Kinoma/kinomajs/blob/master/kinoma/kpr/libraries/Controls/src/controls/sliders.xml * */ import { THEME } from 'theme'; class SliderBehavior extends Behavior { changeState(container, state) { if (container.last) container.last.state = state; } getMax(container) { return this.data.max; } getMin(container) { return this.data.min; } getOffset(container, size) { var min = this.getMin(container); var max = this.getMax(container); var value = this.getValue(container); return Math.round(((value - min) * size) / (max - min)); } getValue(container) { return this.data.value; } onAdapt(container) { this.onLayoutChanged(container); } onCreate(container, data) { this.data = data; } onDisplaying(container) { this.onValueChanged(container); } onTouchBegan(container, id, x, y, ticks) { container.captureTouch(id, x, y, ticks); this.changeState(container, 1); this.onTouchMoved(container, id, x, y, ticks); } onTouchEnded(container, id, x, y, ticks) { this.changeState(container, 0); } setOffset(container, size, offset) { var min = this.getMin(container); var max = this.getMax(container); var value = min + ((offset * (max - min)) / size); if (value < min) value = min; else if (value > max) value = max; this.setValue(container, value); } setValue(container, value) { this.data.value = value; } } export class HorizontalSliderBehavior extends SliderBehavior { onLayoutChanged(container) { var button = container.last; var bar = button.previous; var background = bar.previous; var size = (background.width - button.width); var offset = this.getOffset(container, size); button.x = background.x + offset; bar.width = button.width + offset; } onTouchMoved(container, id, x, y, ticks) { var button = container.last; var bar = button.previous; var background = bar.previous; var size = (background.width - button.width); var offset = (x - (button.width >> 1) - background.x); this.setOffset(container, size, offset); this.onLayoutChanged(container); this.onValueChanged(container); } } export var HorizontalSlider = Layout.template($ => ({ active: true, contents: [ Content($, { left: 0, right: 0, top: 0, bottom: 0, skin: THEME.horizontalSliderBarSkin, state: 0, }), Content($, { left: 0, width: 30, top: 0, bottom: 0, skin: THEME.horizontalSliderBarSkin, state: 1, }), Content($, { left: 0, width: 30, top: 0, bottom: 0, skin: THEME.horizontalSliderButtonSkin, state: 0, }), ] })); export class HorizontalLogSliderBehavior extends HorizontalSliderBehavior { getOffset(container, size) { var min = this.getMin(container); var max = this.getMax(container); var value = this.getValue(container); var logMin = Math.log(min); var maxv = Math.log(max); return Math.round(((Math.log(value) - logMin) * size) / (maxv - logMin)); } setOffset(container, size, offset) { var min = this.getMin(container); var max = this.getMax(container); var logMin = Math.log(min); var logMax = Math.log(max); var value = Math.exp(logMin + (offset * (logMax - logMin) / size)); if (value < min) value = min; else if (value > max) value = max; this.setValue(container, value); } } export class VerticalSliderBehavior extends SliderBehavior { onLayoutChanged(container) { var button = container.last; var bar = button.previous; var background = bar.previous; var size = (background.height - button.height); var offset = this.getOffset(container, size); button.y = background.y + background.height - offset - button.height; bar.height = button.height + offset; } onTouchMoved(container, id, x, y, ticks) { var button = container.last; var bar = button.previous; var background = bar.previous; var size = (background.height - button.height); var offset = background.y + background.height - (y + (button.height >> 1)); this.setOffset(container, size, offset); this.onLayoutChanged(container); this.onValueChanged(container); } } export var VerticalSlider = Layout.template($ => ({ active: true, contents: [ Content($, { left: 0, right: 0, top: 0, bottom: 0, skin: THEME.verticalSliderBarSkin, state: 0, }), Content($, { left: 0, right: 0, height: 30, bottom: 0, skin: THEME.verticalSliderBarSkin, state: 1, }), Content($, { left: 0, right: 0, top: 0, height: 30, skin: THEME.verticalSliderButtonSkin, state: 0, }), ], })); export class VerticalLogSliderBehavior extends VerticalSliderBehavior { getOffset(container, size) { var min = this.getMin(container); var max = this.getMax(container); var value = this.getValue(container); var logMin = Math.log(min); var maxv = Math.log(max); return Math.round(((Math.log(value) - logMin) * size) / (maxv - logMin)); } setOffset(container, size, offset) { var min = this.getMin(container); var max = this.getMax(container); var logMin = Math.log(min); var logMax = Math.log(max); var value = Math.exp(logMin + (offset * (logMax - logMin) / size)); if (value < min) value = min; else if (value > max) value = max; this.setValue(container, value); } } \ No newline at end of file diff --git a/greener-house-app/sunlight.js b/greener-house-app/sunlight.js new file mode 100644 index 0000000..7c1e347 --- /dev/null +++ b/greener-house-app/sunlight.js @@ -0,0 +1,14 @@ +import {name_h, naviBar_h} from "main"; + +// Skins let blackSkin = new Skin ({fill: 'black'}); let whiteSkin = new Skin ({fill: 'white'}); +let graySkin = new Skin ({fill: '#999999'}); +let greenSkin = new Skin ({fill: '#71e28b'}); + +// Fonts var titleW = new Style({font: 'bold 20px', color: 'white'}); +var titleB = new Style({font: 'bold 20px', color: 'black'}); +var titleG = new Style({font: 'bold 20px', color: '#71e28b'}); +var regularW = new Style({font: '20px', color: 'white'}); +var regularB = new Style({font: '20px', color: 'black'}); +var regularG = new Style({font: '20px', color: '#71e28b'}); + +export var SunlightScreen = Column.template($ => ({ left: 0, right: 0, top: name_h, bottom: naviBar_h, skin: whiteSkin, contents: [ Label($, { left: 0, right: 0, top: 10, bottom: undefined, style: titleG, string: "Sunlight" }), ] })); \ No newline at end of file diff --git a/greener-house-app/switch.js b/greener-house-app/switch.js new file mode 100644 index 0000000..a30fc13 --- /dev/null +++ b/greener-house-app/switch.js @@ -0,0 +1 @@ +/* * Copyright (C) 2010-2016 Marvell International Ltd. * Copyright (C) 2002-2010 Kinoma, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * * This is the JavaScript equivalent of the the switch.xml module from the Controls library * https://github.com/Kinoma/kinomajs/blob/master/kinoma/kpr/libraries/Controls/src/controls/switch.xml * */ import { THEME } from 'theme'; export class SwitchButtonBehavior extends Behavior { changeOffset(container, offset) { var label = container.last; var line = label.first; var button = line.first.next; var bar = label.previous; var background = bar.previous; if (offset < 0) offset = 0; else if (offset > this.size) offset = this.size; this.offset = offset; bar.width = button.width + Math.round(this.size - offset); line.x = label.x - Math.round(offset); } onCreate(container, data) { this.data = data; } onDisplaying(container) { var label = container.last; var line = label.first; var button = line.first.next; var bar = label.previous; var background = bar.previous; this.half = background.width >> 1; this.size = background.width - button.width; line.first.coordinates = line.last.coordinates = { width: this.size - 9 }; this.changeOffset(container, (this.data.value > 0) ? 0 : this.size); } onTimeChanged(container) { this.changeOffset(container, this.anchor + Math.round(this.delta * container.fraction)); } onTouchBegan(container, id, x, y, ticks) { if (container.running) { container.stop(); container.time = container.duration; } this.anchor = x; this.capturing = false; this.delta = this.offset + x; container.last.first.first.next.state = 1; } onTouchCancelled(container, id, x, y, ticks) { container.last.first.first.next.state = 0; } onTouchEnded(container, id, x, y, ticks) { var offset = this.offset; var size = this.size; var delta = size >> 1; if (this.capturing) { if (offset < delta) delta = 0 - offset; else delta = size - offset; } else { if (offset == 0) delta = size; else if (offset == size) delta = 0 - size; else if (x < this.half) delta = 0 - offset; else delta = size - offset; } if (delta) { this.anchor = offset; this.delta = delta; container.duration = 250 * Math.abs(delta) / size; container.time = 0; container.start(); } var newValue = ((this.offset + delta) == 0) ? 1 : 0; if (this.data.value != newValue) { this.data.value = newValue; this.onValueChanged(container, this.data.value); } container.last.first.first.next.state = 0; } onTouchMoved(container, id, x, y, ticks) { if (this.capturing) { this.changeOffset(container, this.delta - x); } else if (Math.abs(x - this.anchor) >= 8) { this.capturing = true; container.captureTouch(id, x, y, ticks); this.changeOffset(container, this.delta - x); } } onValueChanged(container, value) { this.changeOffset(container, value ? 0 : this.size); } } export var SwitchButton = Container.template($ => ({ width: 100, height: 40, active: true, contents: [ Content($, { left: 0, right: 0, top: 0, bottom: 0, skin: THEME.switchBarSkin, state: 0, }), Content($, { left: 0, width: 40, top: 0, bottom: 0, skin: THEME.switchBarSkin, state: 1, }), Container($, { left: 9, right: 9, top: 0, bottom: 0, clip: true, contents: [ Line($, { left: 0, contents: [ Content($, { skin: THEME.switchTextSkin, state: 1, }), Content($, { width: 40, top: 0, bottom: 0, skin: THEME.switchButtonSkin, state: 0, }), Content($, { skin: THEME.switchTextSkin, state: 0, }), ], }), ], }), ], })); \ No newline at end of file diff --git a/greener-house-app/temperature.js b/greener-house-app/temperature.js new file mode 100644 index 0000000..9257111 --- /dev/null +++ b/greener-house-app/temperature.js @@ -0,0 +1,35 @@ +import {name_h, naviBar_h, padding, currTemperature} from "main"; +import { HorizontalSlider, HorizontalSliderBehavior } from 'sliders'; + +// Skins let blackSkin = new Skin ({fill: 'black'}); let whiteSkin = new Skin ({fill: 'white'}); +let graySkin = new Skin ({fill: '#999999'}); +let greenSkin = new Skin ({fill: '#71e28b'}); + +// Fonts var titleW = new Style({font: 'bold 20px', color: 'white'}); +var titleB = new Style({font: 'bold 20px', color: 'black'}); +var titleG = new Style({font: 'bold 20px', color: '#71e28b'}); +var regularW = new Style({font: '20px', color: 'white'}); +var regularB = new Style({font: '20px', color: 'black'}); +var regularG = new Style({font: '20px', color: '#71e28b'}); + + +// Sliders let TempSlider = HorizontalSlider.template($ => ({ height: 40, left: 50, right: 50, active: true, Behavior: class extends HorizontalSliderBehavior { + onValueChanged(container) { + setTemp = this.data.value; + setTemp = Math.round(setTemp); + application.distribute("updateSetTemp"); } + adjustTempSlider(container) { + tempSlider.delegate("setValue", setTemp); + tempSlider.delegate("onLayoutChanged"); + } } })); +var tempSlider; + +var setTemp = 0; + +export var TemperatureScreen = Column.template($ => ({ left: 0, right: 0, top: name_h, bottom: naviBar_h, skin: whiteSkin, contents: [ Label($, { left: 0, right: 0, top: padding, bottom: undefined, style: titleG, string: "Temperature" }), + new Picture({left: 0, right: 0, top: padding, bottom: undefined, url: "assets/big_sun_b.png"}), + Label($, { left: 0, right: 0, top: padding, bottom: undefined, style: regularB, + Behavior: class extends Behavior{ updateCurrTemp(container, string) { container.string = "Current temperature: " + currTemperature + " F"; } } }), + tempSlider = new TempSlider({min: 0, max: 140, value: setTemp}), + Label($, { left: 0, right: 0, top: padding, bottom: undefined, style: regularB, string: setTemp, + Behavior: class extends Behavior{ updateSetTemp(container, string) { container.string = setTemp + ""; } } }), ] })); \ No newline at end of file diff --git a/greener-house-app/theme.js b/greener-house-app/theme.js new file mode 100644 index 0000000..810b7f2 --- /dev/null +++ b/greener-house-app/theme.js @@ -0,0 +1,2 @@ +/* * Copyright (C) 2010-2016 Marvell International Ltd. * Copyright (C) 2002-2010 Kinoma, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * * This is the JavaScript equivalent of the flat theme module used by the Controls library * https://github.com/Kinoma/kinomajs/tree/master/kinoma/kpr/libraries/Controls/src/themes/flat * */ let DynamicSkin = function(texture, disabledEffect, enabledEffect, selectedEffect, variantWidth, tiles, margins, aspect) { let saveEffect = texture.effect; let srcScale = texture.scale; let srcWidth = texture.width; let srcHeight = texture.height; let dstScale = screenScale; let dstWidth = Math.round(srcWidth / dstScale); let dstHeight = Math.round(srcHeight / dstScale); let port = new Port({width: dstWidth, height: dstHeight * 3}); port.behavior = { onDraw: function(port) { port.effect = disabledEffect; port.drawImage(texture, 0, 0, dstWidth, dstHeight, 0, 0, srcWidth, srcHeight); port.effect = enabledEffect; port.drawImage(texture, 0, dstHeight, dstWidth, dstHeight, 0, 0, srcWidth, srcHeight); port.effect = selectedEffect; port.drawImage(texture, 0, dstHeight << 1, dstWidth, dstHeight, 0, 0, srcWidth, srcHeight); } } let result = new Texture(port, srcScale); let height = Math.round(srcHeight / srcScale); let width = (variantWidth == undefined) ? height : Math.round(variantWidth / scale); Skin.call(this, result, {x:0, y:0, width:height, height:height}, width, height, tiles, margins, aspect); result.effect = saveEffect; }; DynamicSkin.prototype = Skin.prototype; let disabledEffect = new Effect(); disabledEffect.colorize('#9d9d9d', 1); let enabledEffect = new Effect(); enabledEffect.colorize('gray', 1); let selectedEffect = new Effect(); selectedEffect.colorize('#88a4ee', 1); let buttonTexture = new Texture('assets/core-button-2x.png', 2); let buttonSkin = new DynamicSkin( buttonTexture, disabledEffect, enabledEffect, selectedEffect, undefined, { left : 10, top : 10, right : 10, bottom : 10 }); let buttonStyle = new Style({ color: ['black', 'black', 'black'], font: 'bold 20px', horizontal: 'center' }); let labeledButtonStyle = new Style({ color: ['gray', 'gray', '#88a4ee'], font: 'bold 20px', horizontal: 'left' }); let glyphTexture = new Texture('assets/core-glyph-strip-60px.png', 2); let glyphSkin = new DynamicSkin(glyphTexture, disabledEffect, enabledEffect, selectedEffect); let CHECKBOX_UNSELECTED = 0; let CHECKBOX_SELECTED = 1; let RADIO_UNSELECTED = 2; let RADIO_SELECTED = 3; let mainTexture = new Texture('assets/main.png', 1); let horizontalSliderBarSkin = new Skin({ texture: mainTexture, x: 45, y: 50, width: 60, height: 50, states: 50, tiles: { left:15, right:25 } }); let horizontalSliderButtonSkin = new Skin({ texture: mainTexture, x: 110, y: 50, width: 30, height: 50, states: 50 }); let verticalSliderBarSkin = new Skin({ texture: mainTexture, x: 200, y: 95, width: 50, height: 60, states: 50, tiles: { top:15, bottom:25 } }); let verticalSliderButtonSkin = new Skin({ texture: mainTexture, x: 250, y: 110, width: 50, height: 30, states: 50 }); let switchButtonTexture = new Texture('assets/toggle-switch.png', 2); let switchBarSkin = new Skin({ texture: switchButtonTexture, x: 100, width: 60, height: 40, states: 40, tiles: { left:20, right:20 } }); let switchButtonSkin = new Skin({ texture: switchButtonTexture, x: 160, width: 40, height: 40, states: 40 }); let switchTextSkin = new Skin({ texture: switchButtonTexture, x: 200, width: 40, height: 40, states: 40 }); + export var THEME = { DynamicSkin, buttonStyle, buttonTexture, buttonSkin, labeledButtonStyle, glyphTexture, glyphSkin, CHECKBOX_SELECTED, CHECKBOX_UNSELECTED, RADIO_SELECTED, RADIO_UNSELECTED, mainTexture, horizontalSliderBarSkin, horizontalSliderButtonSkin, verticalSliderBarSkin, verticalSliderButtonSkin, switchButtonTexture, switchBarSkin, switchButtonSkin, switchTextSkin } \ No newline at end of file diff --git a/greener-house-app/transition.js b/greener-house-app/transition.js new file mode 100644 index 0000000..c8687f6 --- /dev/null +++ b/greener-house-app/transition.js @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2010-2016 Marvell International Ltd. + * Copyright (C) 2002-2010 Kinoma, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + var AbstractTransition = function(duration) { + if (!duration) duration = 500; + Transition.call(this, duration); +} +AbstractTransition.prototype = Object.create(Transition.prototype, { + easeType: { value: 'quadEaseOut', writable: true }, + removeFormerContent: { value: true, writable: true }, + addCurrentContent: { value: true, writable: true }, + addCurrentBehind: { value: false, writable: true }, + optionFields: { value: 'easeType,removeFormerContent,addCurrentContent,addCurrentBehind', writable: true }, + onBegin: { value: + function(container, formerContent, currentContent, formerData, currentData) { + // make these transitions compatible with mobile framework pattern (where options will be supplied in currentData) + var options = (undefined != currentData) ? currentData : formerData; + this.applyOptions(options); + if (this.addCurrentContent) { + if (false == this.addCurrentBehind) + container.add( currentContent ); + else + container.insert( currentContent, container.first ); + } + this.formerLayer = new Layer({alpha: false}); + this.currentLayer = new Layer({alpha: false}); + this.formerLayer.attach( formerContent ); + this.currentLayer.attach( currentContent ); + this.onBeginTransition( container, formerContent, currentContent, formerData, currentData ); + }, + }, + onStep: { value: + function(fraction) { + if ( this.easeType != "linear" ) + fraction = Math[this.easeType]( fraction ); + this.onStepTransition( fraction ); + }, + }, + onEnd: { value: + function(container, formerContent, currentContent) { + this.currentLayer.detach(); + this.formerLayer.detach(); + if ( this.removeFormerContent ) + container.remove( formerContent); + this.onEndTransition( container, formerContent, currentContent ); + }, + }, + applyOptions: { value: + function(options) { + if ( undefined != options ) { + this.applyDurationOption(options); + var optionFields = this.optionFields; + optionFields = optionFields.split(","); + for ( var i=0; i < optionFields.length; i++) + this.applyFieldOption(options, optionFields[i]); + } + }, + }, + applyDurationOption: { value: + function(options) { + if ("duration" in options) + this.duration = options.duration; + }, + }, + applyFieldOption: { value: + function(options, fieldName) { + if (fieldName in options) + this[fieldName] = options[fieldName]; + }, + }, + onBeginTransition: { value: + function(container, formerContent, currentContent, formerData, currentData) { + + }, + }, + onStepTransition: { value: + function(fraction) { + + }, + }, + onEndTransition: { value: + function(container, formerContent, currentContent) { + + }, + }, +}); + +export var CrossFade = function(duration) { + if (!duration) duration = 1500; + AbstractTransition.call(this, duration); +} +CrossFade.prototype = Object.create(AbstractTransition.prototype, { + easeType: { value: 'linear', writable: true }, + onStepTransition: { value: + function(fraction) { + this.currentLayer.opacity = fraction; + }, + }, +}); + + +export var Push = function(duration) { + if (!duration) duration = 500; + AbstractTransition.call(this, duration); +} +Push.prototype = Object.create(AbstractTransition.prototype, { + direction: { value: 'left', writable: true }, + optionFields: { value: 'easeType,removeFormerContent,addCurrentContent,direction', writable: true }, + onBeginTransition: { value: + function(container, formerContent, currentContent, formerData, currentData) { + this.formerFromX = this.formerToX = this.currentFromX = this.currentToX = 0; + this.formerFromY = this.formerToY = this.currentFromY = this.currentToY = 0; + switch (this.direction) { + case "left": + this.formerFromX = 0; + this.formerToX = - formerContent.width + this.currentLayer.translation = { x : currentContent.width, y : 0 } + this.currentFromX = currentContent.width + this.currentToX = 0 + break + case "right": + this.formerFromX = 0; + this.formerToX = formerContent.width + this.currentLayer.translation = { x : -currentContent.width, y : 0 } + this.currentFromX = -currentContent.width + this.currentToX = 0 + break + case "up": + this.formerFromY = 0; + this.formerToY = -formerContent.height + this.currentLayer.translation = { x : 0, y : currentContent.height } + this.currentFromY = currentContent.height + this.currentToY = 0 + break + case "down": + this.formerFromY = 0; + this.formerToY = formerContent.height + this.currentLayer.translation = { x : 0, y : -currentContent.height } + this.currentFromY = -currentContent.height + this.currentToY = 0 + break + } + }, + }, + onStepTransition: { value: + function(fraction) { + var formerX = lerp( this.formerFromX, this.formerToX, fraction ); + var formerY = lerp( this.formerFromY, this.formerToY, fraction ); + this.formerLayer.translation = { x : formerX, y : formerY } + var currentX = lerp( this.currentFromX, this.currentToX, fraction ); + var currentY = lerp( this.currentFromY, this.currentToY, fraction ); + this.currentLayer.translation = { x : currentX, y : currentY } + }, + }, +}); + + +export var Flip = function(duration) { + if (!duration) duration = 500; + AbstractTransition.call(this, duration); +} +Flip.prototype = Object.create(AbstractTransition.prototype, { + direction: { value: 'left', writable: true }, + optionFields: { value: 'easeType,removeFormerContent,addCurrentContent,direction', writable: true }, + onBeginTransition: { value: + function(container, formerContent, currentContent, formerData, currentData) { + var formerLayer = this.formerLayer; + formerLayer.origin = { y: formerLayer.height / 2 }; + this.formerStarts = [ + { x: 0, y: 0 }, + { x: 1, y: 0 }, + { x: 1, y: 1 }, + { x: 0, y: 1 }, + ]; + this.formerSteps = [ + { x: 0, y: 0 }, + { x: 1, y: 0 }, + { x: 1, y: 1 }, + { x: 0, y: 1 }, + ]; + var currentLayer = this.currentLayer; + currentLayer.origin = { y: currentLayer.height / 2 }; + this.currentStops = [ + { x: 0, y: 0 }, + { x: 1, y: 0 }, + { x: 1, y: 1 }, + { x: 0, y: 1 }, + ]; + this.currentSteps = [ + { x: 0, y: 0 }, + { x: 1, y: 0 }, + { x: 1, y: 1 }, + { x: 0, y: 1 }, + ]; + switch ( this.direction ) { + case "left": + this.formerStops = [ + { x: 0.49, y: 0.1 }, + { x: 0.51, y: -0.1 }, + { x: 0.51, y: 1.1 }, + { x: 0.49, y: 0.9 }, + ]; + this.currentStarts = [ + { x: 0.49, y: -0.1 }, + { x: 0.51, y: 0.1 }, + { x: 0.51, y: 0.9 }, + { x: 0.49, y: 1.1 }, + ]; + break + case "right": + this.formerStops = [ + { x: 0.49, y: -0.1 }, + { x: 0.51, y: 0.1 }, + { x: 0.51, y: 0.9 }, + { x: 0.49, y: 1.1 }, + ]; + this.currentStarts = [ + { x: 0.49, y: 0.1 }, + { x: 0.51, y: -0.1 }, + { x: 0.51, y: 1.1 }, + { x: 0.49, y: 0.9 }, + ]; + break + case "up": + this.currentStarts = [ + { x: -0.2, y: 0.49 }, + { x: 1.2, y: 0.49 }, + { x: 0.8, y: 0.51 }, + { x: 0.2, y: 0.51 }, + ]; + this.formerStops = [ + { x: 0.2, y: 0.49 }, + { x: 0.8, y: 0.49 }, + { x: 1.2, y: 0.51 }, + { x: -0.2, y: 0.51 }, + ]; + break + case "down": + this.formerStops = [ + { x: -0.2, y: 0.49 }, + { x: 1.2, y: 0.49 }, + { x: 0.8, y: 0.51 }, + { x: 0.2, y: 0.51 }, + ]; + this.currentStarts = [ + { x: 0.2, y: 0.49 }, + { x: 0.8, y: 0.49 }, + { x: 1.2, y: 0.51 }, + { x: -0.2, y: 0.51 }, + ]; + break + } + }, + }, + onStepTransition: { value: + function(fraction) { + if (fraction <= 0.5) { + fraction *= 2; + var layer = this.formerLayer; + var starts = this.formerStarts; + var stops = this.formerStops; + var steps = this.formerSteps; + for (var i = 0; i < 4; i++) { + var start = starts[i]; + var stop = stops[i]; + var step = steps[i]; + step.x = (start.x * (1 - fraction)) + (stop.x * fraction); + step.y = (start.y * (1 - fraction)) + (stop.y * fraction); + } + layer.opacity = 1; + layer.corners = steps; + this.currentLayer.opacity = 0; + } + else { + fraction = 2 * (fraction - 0.5); + var layer = this.currentLayer; + var starts = this.currentStarts; + var stops = this.currentStops; + var steps = this.currentSteps; + for (var i = 0; i < 4; i++) { + var start = starts[i]; + var stop = stops[i]; + var step = steps[i]; + step.x = (start.x * (1 - fraction)) + (stop.x * fraction); + step.y = (start.y * (1 - fraction)) + (stop.y * fraction); + } + layer.opacity = 1; + layer.corners = steps; + this.formerLayer.opacity = 0; + } + }, + }, +}); + + +export var Reveal = function(duration) { + if (!duration) duration = 350; + AbstractTransition.call(this, duration); +} +Reveal.prototype = Object.create(AbstractTransition.prototype, { + direction: { value: 'up', writable: true }, + optionFields: { value: 'easeType,removeFormerContent,addCurrentContent,direction', writable: true }, + onBeginTransition: { value: + function(container, formerContent, currentContent, formerData, currentData) { + this.currentFromX = this.currentToX = 0; + this.currentFromY = this.currentToY = 0; + + this.effect = new Effect(); + + switch (this.direction) { + case "left": + this.currentLayer.translation = { x : currentContent.width, y : 0 } + this.currentFromX = currentContent.width + break + case "right": + this.currentLayer.translation = { x : -currentContent.width, y : 0 } + this.currentFromX = -currentContent.width + break + case "up": + this.currentLayer.translation = { x : 0, y : currentContent.height } + this.currentFromY = currentContent.height + break + case "down": + this.currentLayer.translation = { x : 0, y : -currentContent.height } + this.currentFromY = -currentContent.height + break + } + }, + }, + onStepTransition: { value: + function(fraction) { + var currentX = lerp( this.currentFromX, this.currentToX, fraction ); + var currentY = lerp( this.currentFromY, this.currentToY, fraction ); + this.currentLayer.translation = { x : currentX, y : currentY } + + var effect = new Effect(); + effect.colorize("black", fraction / 2); + this.formerLayer.effect = effect; + }, + }, +}); + + +export var Hide = function(duration) { + if (!duration) duration = 350; + AbstractTransition.call(this, duration); +} +Hide.prototype = Object.create(AbstractTransition.prototype, { + direction: { value: 'down', writable: true }, + addCurrentBehind: { value: 'true', writable: true }, + easeType: { value: 'quadEaseIn', writable: true }, + optionFields: { value: 'easeType,removeFormerContent,addCurrentContent,direction', writable: true }, + onBeginTransition: { value: + function(container, formerContent, currentContent, formerData, currentData) { + this.formerFromX = this.formerToX = 0; + this.formerFromY = this.formerToY = 0; + + switch (this.direction) { + case "left": + this.formerToX = -formerContent.width + break + case "right": + this.formerToX = formerContent.width + break + case "up": + this.formerToY = -formerContent.height; + break + case "down": + this.formerToY = formerContent.height; + break + } + }, + }, + onStepTransition: { value: + function(fraction) { + var formerX = lerp( this.formerFromX, this.formerToX, fraction ); + var formerY = lerp( this.formerFromY, this.formerToY, fraction ); + this.formerLayer.translation = { x : formerX, y : formerY } + + var effect = new Effect(); + effect.colorize("black", 0.5 - (fraction / 2)); + this.currentLayer.effect = effect; + }, + }, +}); + +export var TimeTravel = function(duration) { + if (!duration) duration = 500; + AbstractTransition.call(this, duration); +} +TimeTravel.prototype = Object.create(AbstractTransition.prototype, { + direction: { value: 'forward', writable: true }, + optionFields: { value: 'easeType,removeFormerContent,addCurrentContent,direction,xOrigin,yOrigin', writable: true }, + onBeginTransition: { value: + function(container, formerContent, currentContent, formerData, currentData) { + if (this.hasOwnProperty("xOrigin") && this.hasOwnProperty("yOrigin")) { + this.formerLayer.origin = { x : this.xOrigin, y : this.yOrigin }; + this.currentLayer.origin = { x : this.xOrigin, y : this.yOrigin }; + } + else { + this.formerLayer.origin = { x : this.formerLayer.width / 2, y : this.formerLayer.height / 2 }; + this.currentLayer.origin = { x : this.currentLayer.width / 2, y : this.currentLayer.height / 2 }; + } + switch (this.direction) { + case "forward": + this.fromFormerScale = 1.0; + this.toFormerScale = 2.0; + this.fromCurrentScale = 0.5; + this.toCurrentScale = 1.0; + break + case "back": + this.fromFormerScale = 1.0; + this.toFormerScale = 0.5; + this.fromCurrentScale = 2.0; + this.toCurrentScale = 1.0; + break + } + this.onStepTransition( 0 ); + }, + }, + onStepTransition: { value: + function(fraction) { + var formerScale = lerp( this.fromFormerScale, this.toFormerScale, fraction ); + this.formerLayer.scale = { x : formerScale, y : formerScale } + this.formerLayer.opacity = 1 - fraction + var currentScale = lerp( this.fromCurrentScale, this.toCurrentScale, fraction ); + this.currentLayer.scale = { x : currentScale, y : currentScale } + this.currentLayer.opacity = fraction + }, + }, +}); + +export var ZoomAndSlide = function(duration) { + if (!duration) duration = 500; + AbstractTransition.call(this, duration); +} +ZoomAndSlide.prototype = Object.create(AbstractTransition.prototype, { + direction: { value: 'forward', writable: true }, + optionFields: { value: 'easeType,removeFormerContent,addCurrentContent,addCurrentBehind,direction', writable: true }, + onBeginTransition: { value: + function(container, formerContent, currentContent, formerData, currentData) { + this.formerLayer.origin = { x : this.formerLayer.width / 2, y : this.formerLayer.height / 2 }; + this.currentLayer.origin = { x : this.currentLayer.width / 2, y : this.currentLayer.height / 2 }; + this.currentaFromX = currentContent.width + this.formerFromY = this.formerToY = this.currentFromY = this.currentToY = 0; + switch (this.direction) { + case "forward": + this.fromFormerScale = 1.0; + this.toFormerScale = 0.8; + this.currentLayer.translation = { x : currentContent.width, y : 0 }; + this.currentFromX = currentContent.width; + this.currentToX = 0; + break + case "back": + this.fromCurrentScale = 0.8; + this.toCurrentScale = 1.0; + this.formerLayer.translation = { x : 0, y : 0 }; + this.formerFromX = 0; + this.formerToX = currentContent.width + break + } + }, + }, + onStepTransition: { value: + function(fraction) { + switch (this.direction) { + case "forward": + var formerScale = lerp( this.fromFormerScale, this.toFormerScale, fraction); + this.formerLayer.scale = { x : formerScale, y : formerScale }; + var currentX = lerp( this.currentFromX, this.currentToX, fraction ); + this.currentLayer.translation = { x : currentX, y : 0 }; + break + case "back": + var currentScale = lerp( this.fromCurrentScale, this.toCurrentScale, fraction); + this.currentLayer.scale = { x : currentScale, y : currentScale }; + var formerX = lerp( this.formerFromX, this.formerToX, fraction ); + this.formerLayer.translation = { x : formerX, y : 0 }; + break + } + }, + }, +}); + +var lerp = function(from, to, fraction) { + return from + fraction * (to - from); +} \ No newline at end of file diff --git a/greener-house-app/ventilation.js b/greener-house-app/ventilation.js new file mode 100644 index 0000000..fa7e68b --- /dev/null +++ b/greener-house-app/ventilation.js @@ -0,0 +1,124 @@ +// Imports +import { name_h, naviBar_h, currHumidity } from "main"; +import { HorizontalSlider, HorizontalSliderBehavior } from 'sliders'; + +// Skins let blackSkin = new Skin ({fill: 'black'}); let whiteSkin = new Skin ({fill: 'white'}); +let graySkin = new Skin ({fill: '#999999'}); +let greenSkin = new Skin ({fill: '#71e28b'}); +let upperLineSkin = new Skin({ fill: "white", borders: {left: 0, right: 0, top: 1, bottom: 0}, stroke: "#999999" }); + +// Fonts var titleW = new Style({font: 'bold 20px', color: 'white'}); +var titleB = new Style({font: 'bold 20px', color: 'black'}); +var titleG = new Style({font: 'bold 20px', color: '#71e28b'}); +var regularW = new Style({font: '20px', color: 'white'}); +var regularB = new Style({font: '20px', color: 'black'}); +var regularG = new Style({font: '20px', color: '#71e28b'}); + + +// Fan button. +let FanBtn = Container.template($ => ({ left: 0, right: 0, top: 0, bottom: 0, active: true, string: $.speed, + + behavior: Behavior({ onCreate: function(content){ this.upSkin = new Skin({ fill: "transparent", borders: {left: 1, right: 1, top: 1, bottom: 1}, stroke: "#999999" }); this.downSkin = new Skin({ fill: "#71e28b", borders: {left: 1, right: 1, top: 1, bottom: 1}, stroke: "#999999" }); content.skin = this.upSkin; }, onTouchBegan: function(content){ content.skin = this.downSkin; + // Since a button was clicked, + // we can now adjust the fan slider. + fanSlider.active = true; + fanClicked = $.id; + fanSpeed = fanState[fanClicked]; }, onTouchEnded: function(content){ + // When a fan button clicked, + // change the skin of the rest of them back to white. + for (var i = 0; i < fanButtons.length; i++) { + if ($.id != i) { + fanButtons[i].skin = this.upSkin; + } + } + // Update the fan slider position and label. + application.distribute("adjustVentSlider", fanState[fanClicked]); }, }), contents: [ new Label({ top: 0, bottom: 0, left: 0, right: 0, + style: titleB, string: fanState[$.id], + Behavior: class extends Behavior{ updateFanString(container, string) { container.string = fanState[$.id] + ""; } } + }) ] })); + +export var fanState = [0,0,0,0,0,0]; +var fanButtons = []; +let maxFanSpeed = 4; +let padding = 10; +var humidity = 0; +var fanSpeed = 0; +var fanClicked = -1; + +// Sliders let MySlider = HorizontalSlider.template($ => ({ height: 40, left: 50, right: 50, active: $.on, Behavior: class extends HorizontalSliderBehavior { + onValueChanged(container) { + if ($.id == "fan") { + // Changing the fan speed of a specific fan + // when the user uses the slider. + fanSpeed = this.data.value; + fanSpeed = Math.round(fanSpeed); + if (fanSlider.active) {fanState[fanClicked] = fanSpeed;} + application.distribute("updateFanString"); + if (fanSpeed > 0) {application.distribute("onToggleFan", 1)} + else {application.distribute("onToggleFan", 0)} + + } else if ($.id == "humidity") { + // Changing humidity using a slider. + humidity = this.data.value; + humidity = Math.round(humidity); application.distribute("updateHumidity"); + } } + // Adjust fan and humidity slider when + // going back to the ventilation screen. + adjustVentSlider(container, fanValue) { + fanSlider.delegate("setValue", fanValue); + fanSlider.delegate("onLayoutChanged"); + humiditySlider.delegate("setValue", humidity); + humiditySlider.delegate("onLayoutChanged"); + } } })); +var fanSlider; +var humiditySlider; + +// Screen layout +export var VentilationScreen = Column.template($ => ({ left: 0, right: 0, top: name_h, bottom: naviBar_h, skin: whiteSkin, contents: [ + Label($, { left: 0, right: 0, top: padding, style: titleG, string: "Ventilation" }), + Label($, { left: 0, right: 0, top: padding, style: regularB, string: "fans" }), + + // Greenhouse's fans controller. + new FanGrid(), + + // Greenhouse's humidity controller. + new Humidity(), ] })); + +// Fan grid layout. +var FanGrid = Column.template($ => ({ left: padding, right: padding, top: padding, bottom: 0, contents: [ + Line($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + fanButtons[0] = new FanBtn({id: 0}), + fanButtons[1] = new FanBtn({id: 1}), + fanButtons[2] = new FanBtn({id: 2}), + ] + }), + Line($, { + left: 0, right: 0, top: 0, bottom: 0, + contents: [ + fanButtons[3] = new FanBtn({id: 3}), + fanButtons[4] = new FanBtn({id: 4}), + fanButtons[5] = new FanBtn({id: 5}), + ] + }), + + fanSlider = new MySlider({ min: 0, max: maxFanSpeed, value: fanSpeed, id: "fan", on: false}), ] })); + +// Humidity layout +var Humidity = Column.template($ => ({ + left: 0, right: 0, top: 0, bottom: 0, height: VentilationScreen.height / 2, skin: upperLineSkin, + contents: [ + + new Label({ left: 0, right: 0, top: padding, style: titleG, string: "Humidity" }), + + new Label ({left: 0, right: 0, top: padding, + style: regularB, string: "current humidity: " + Math.round(currHumidity) + "%", + }), + + humiditySlider = new MySlider({ min: 0, max: 100, value: humidity, id: "humidity", on: true}), + Label ($, {left: 0, right: 0, top: 0, style: regularB, + Behavior: class extends Behavior{ updateHumidity(container, string) { container.string = humidity + "%"; } } + }), + ] +})); diff --git a/greener-house-device/main.js b/greener-house-device/main.js new file mode 100644 index 0000000..6fcac25 --- /dev/null +++ b/greener-house-device/main.js @@ -0,0 +1,51 @@ + let Pins = require("pins"); + class AppBehavior extends Behavior { onLaunch(application) { Pins.configure({ Fan: { require: "Digital", pins: { ground: { pin: 51, type: "Ground" }, digital: { pin: 52, direction: "output" } } }, + Irrigation: { require: "Digital", pins: { ground: { pin: 53, type: "Ground" }, digital: { pin: 54, direction: "output" } } }, + TemperatureIn: { + require: "Analog", + pins: { + power: {pin: 55, type: "Power", voltage: 3.3}, analog: {pin: 56, type: "Analog", direction: "input"}, ground: {pin: 57, type: "Ground"} + } + }, + HumidityIn: { + require: "Analog", + pins: { + power: {pin: 58, type: "Power", voltage: 3.3}, analog: {pin: 59, type: "Analog", direction: "input"}, ground: {pin: 60, type: "Ground"} + } + }, }, function(success) { if (!success) {trace("Failed to configure\n");} + else { + Pins.share("ws", {zeroconf: true, name: "pins-share"}); + /* + Pins.repeat("/AC/read", 500, function(result) { if (result) { + ac = "ac on"; + application.distribute("updateACState"); } else { ac = "ac off"; + application.distribute("updateACState"); } }); + Pins.repeat("/Feeder/read", 20, function(result) { if (result) { + feeder = "unicorn fed"; + application.distribute("updateFeederState"); } else { + counter++; + if (counter > 500 && feeder != "") { + feeder = "";counter = 0; + + application.distribute("updateFeederState"); + } } });*/ + } }); } } application.behavior = new AppBehavior(); +// Skins +var graySkin = new Skin ({fill: '#202020'}); + +// Fonts +var titleG = new Style({font: 'bold 30px', color: '#3AFF3E'}); +var regularW = new Style({font: '20px', color: 'white'}); + +// Layout var DeviceScreen = Column.template($ => ({ left: 0, right: 0, top: 0, bottom: 0, skin: graySkin, contents: [ new Label({left: 0, right: 0, top: 0, style: titleG, string: "greener house"}), + + Label($, {left: 0, right: 0, top: 10, style: regularW, + string: "", + Behavior: class extends Behavior{ updateACState(container, string) { //container.string = ac; } } + }), + + Label($, {left: 0, right: 0, top: 10, style: regularW, + string: "", + Behavior: class extends Behavior{ updateFeederState(container, string) { //container.string = feeder; } } + }), ] })); + application.add(new DeviceScreen()); diff --git a/greener-house-device/project.json b/greener-house-device/project.json new file mode 100644 index 0000000..7461747 --- /dev/null +++ b/greener-house-device/project.json @@ -0,0 +1,14 @@ +{ + "title":"greener_house_device", + "description":"This template can be used to create a basic KinomaJS application .", + "id":"greener-house-device.project.kinoma.marvell.com", + "tags":[ + "emptySample" + ], + "Create":{ + "main":"main" + }, + "Element":{ + "main":"main" + } +} \ No newline at end of file