From 2199ea21510121c35cb448fba6096e26fe63414c Mon Sep 17 00:00:00 2001 From: YunHorn Technology Date: Tue, 19 Nov 2024 21:00:19 +0800 Subject: [PATCH] workable L8 with decoder updated and function test report revised --- STM32CubeIDE/Release/WLE5CC_NODE_STS.elf | Bin 261920 -> 261776 bytes STS/Core/Inc/yunhorn_sts_sensors.h | 7 + STS/Core/Src/yunhorn_sts_process.c | 27 +- STS/TOF/App/app_tof.c | 93 +- hk_as923_decoder.js | 1511 +++++++++++++++------- 5 files changed, 1112 insertions(+), 526 deletions(-) diff --git a/STM32CubeIDE/Release/WLE5CC_NODE_STS.elf b/STM32CubeIDE/Release/WLE5CC_NODE_STS.elf index 0e218860d0515562aab0312ff763e6009bcfc7b3..0506f66488ae68b3064c179a107505483909860b 100644 GIT binary patch delta 51976 zcma&P30zdw|Nno^odE`98E|70hDF5)fJIn^khDIc(0?23mWwc0rwS2B7PoE% zz-G(byLI{U2xZGyHPAXZy&3V+vM0^8_V6L_f8DmPvHsTBR`0aNIy^2EH*K4``3Cjq z|Ce>7U)W%9CuXBG=)>abZRy4wm|&FSe_0(6**&46P+BZirh>SwrZJ|x|6CEvEPE(k zT?$)8VdX=S&j!f>m60*OOF6u07^L-WjfO)G8x);L~o z?PCF7ZVt=~&~J7IVB6kewwpi}^{w8mnd_Y4wgCN*QzS>)Be3eu z`;^Ls>Mwof$cgIczW2mh_5H0sILlXwwa1+zz6oic4LNJCR>vN^cjsZdHmI7bH?kdvIF#qjk0t0-{usNih}o-o0OCc z`{(CPBgS7fcMQ-|)SS$=g)t4|uVzn@n@ExUp`ySM4cRGjQ)-^+IoJjU=t1xiBjhHE zl`N*!0eW-26+YKOjSSGQ)~g#b+vT3GPqru718rt~Wefe^(?T4Ct;bsEf0e-Rd?Z z-Q2w-qhMX`^+%VbSX9eKlqe-!4b<;fpXz^|yiq;Wzn^?qZSLPo-lp~#FgoGAdX&dq zM-}y_Z#V1zY1wf5o^#f0v;Ov8b=80lUHZ1#?AATmW?>UmFI42Y6Z*L+8e0mIJk=DS zzuv4K9$+taB5!xU*K&4z%ID{mjL*-T#pmY(g#x!gy{z7)#Zkv-v{aeVfm-XTT3hSJ zw6xZJhvk_jp>JtcbW@|yE1H|mQcR-isfwORNFt%fo7B4pCWqBETDG><{nQ$o7pQkq zUm2Jrv(*m=ro@eFN-l{((R&_6v-eX}1%+R>C<28auF9-F1;?5c)TyaiBzLz(+Rggm zrtaXzCToRtkJu;DM0V+DAt+-LoaO>)`_Ne~_MEez^YkFyET)_F0`z9Ho~J&T730Ws zk}8t~di?&~rK3wnx19C-5z!xpO60O~x7b&15;h6XHaisjx9sqENbFsY?iKrvDbTU) z!1iMI_WjsCjc}!-vk~Tx8Z=dQfPSGy<^|~mF*RZzH3}tAz0;ilw%^>VrVq+!o9(17 zN{t(!4|bZ-l{3_ZgSv%eHe_!N0R7gezCNgX$W=EUZB%Oq4engg7+@D^e;v(CmiAy& zc?L#x%lw;I4AM`p)1)Q_(vng2XocCXYz(to^|MXt z;Oi0`WJXSMtyOAC3U)xX*s7mzjx3O=@ufn4*J;%+*N5j>_27o^0^}<XwGq zI%|W_&Gm{N2%mp!3v=4T;T3@ltBdU#ErBpx4?KN{li_v8p#lG1Sq-7))OO;|1NfG)R zt;U#up7`m`d4U))lcX&|U$@U%m3!H`$WkcMqW78XL3t^~R{i#dq!Kec|7@UaE7+>o zsTPiiF1WunBoD{`B(uJm>JLXTvCyo)*+@~FTs+6DzqG3qXI~hW@)WoCbGwXT%3xQR z73zOR#5s~1y4#cTU_q!Qjot0t>)wNp#nn39t0 zzhz2Da*t&ZdR!}pxa2hZrP3h1u2JmJOIOziWJq;&y*WduBH3CHX*VG@*%FbbRO~rd zik)iUPLUi6JEiiMqxsjfr!i24y0beM^@UR*+kIHC#P> zlclsO0S!e}5#JbxEmyHR7>9N-rz2X&+Sma#x3xY9M^Cf8XsbwW>rQw_Gi4?+Z=zM# zcUZ?p7GVD{aP&9dRbJ~(V_8|S<1_cp*TYvg2)h#t*3o;dt zHPv_gM2t@p)!0$-ZHtVta_-TTb}~4YA~vs z63JIz9@THw9}P9RmZLNV#njvKy4ziia#uq_L3G~nB?4VCs8QNC?vTl`1y*~69^EWb zV~`!CKDwY|UQEd=xmo*?5PEriTUbZchgIl%0{dJ%8l>-PP}A+PgZ^qdc{VKo{Q`L% zkG#&rLX}Ttp$51aOl3j~*cM}3arcWf^feli_n+1qE9A8FA36P)U9LMJ3emd3F}?0J;#XEJqvRiwTeKDm#td{V8y(JmmV_VyxFN%FPO_r7RpJVw0%NzZKgdFI;A~thqXW^n{2M}B|=}jv(1=uX9N43M#nEu!wO;w9&0#)u4)W1?p{v4+gg>B zmsI#f1q#z5lH!w18ecNJht$V2T2PBY*U8g2U*d9S5QB$OacD0UJmm<^U6`^*~ZNia$ zsEr%d-wV2?ecfa`eftvGBj~7DBGZ&3N}4!g!TwR@6rIB^C5oq(4`DC`o+e4A&bInQi z5UgWbg7N<(&U43KePB_feS71Tt2pOGYr&^pG0t{3JSGK|Wd-61!ugJDwBWqyfxF|> zZet^@OY1$yHyS3kPf_#7E=VeAmYcHdpF7RVO#0mBWP1)SJWcw8Eot^-oV1wqCF-|h zyC$KYlY?nYnP9@jCC*j$$YlMjNH)Q?Y@tb?tR{|oCiav1pcnexW3yYZtLy)ksr9JZ zWK`?^BK6a8=^b8hRx~WTa((bk_ZZ{CzEDU_Q`GSB&-SNE7y7Ba=7P8-DLc&h0ZG!< zTDN=;ojdM^TliFJb&8GSPcWVJ1gToPY!Xxk&sF4hT4Xx-KN zjImC$9yQk8tdVo?C!xD_;{9J@-2+94ZMEht!-Y-+PHd9wVR;tpS>tepVa*Q7w-|+d zboZpvqi5C9|DOG-^z*ZA7k+kj(!xWixaDZ0>~L3~9Dpj2W3mx8L#>;TqhyDxgD3V> zF1M&96Vp0<-}0QZXU3#m&!NL#w+m+^rLA?Nn+q=&Wwh2Ms#_+G>TPR2g&3)Kw?jo5 z2MKHsz&52q6}+hG=E9qig3aDim!c+3N{oCImu>|u=sl$^b%&Z->wZ@!OuAHLMn_0A zjuGK{3yxy#^a#a#w4a@Z=5YP5=Jrl`9i2XOG<;-cxc*yncF*6A(mjQ?I1vfge?||E zbjR?0v-<4hWXJ8u2xV>y)*0vtKVTg>4Tl2^E*-HBsuKEmTtzmcJ4Y{zD;LQxY!hmv zJ-~=?bF=G8L+A@J)+|Fj`3RFy^;(5UT56095&8$slTw~?S~A98Enl?78ImDEp&2c8 zQyWtYg=3reEnBptB$Z=rt!TWWKjjP)iP+ovHzhAgDG%-5@km^V-lN@-=?E5{5rktm zwQ0ESz?HqSsY714UfR+w9~~1dzNsOlB4ba~*w(t&TYFr~YJ`#1Y0YLMhLrNBoYsuk zkRDh^*e2jW0&`>rVN^z&)c>B1!ic#TrJ#nV5#PU$CCsGm&f-C<|bN_S?Pn>!>&Z+a4${i9h8ow|7N zCEO%vC~m2{(jb!WGLGEg`fE)t+xZ5W^2n98<*jugX#2lgemW~sEgPS5+Oh-n#~an1 zQ{#g^u0MRXweCap`>9>yZiiE!rjaQrr6T2~QrX#>@>=OHrJWbH)OAr4r;UxgvB`qd zsleu*$(Bv&$U%Sg!D+qQJlqnv#S^7S=0^3WY2)P6YM<#Hi{D0(_hF&p z|A;m9)P(8M@}hHY#-JWQ)gsS%)+CeO>b%ok!2M0h_UKKwA^NRN^U)ep&boXL*UrN^ zCi$Ls&c%_Cw$3=!jnii(-QGCH9r)fRdmfE=;rgvjBi&88!D&~I&qz`8X2eRfdee*> z+s8M>z$hWz6`q$2o)CopmKB(_L?gwW@1x`vWeeW0DuRAihd~3UHGg=RdP>xQg)9ZT6B?oeQDLW$YQoF$KkIEtK^j7ncqtWAka86$q z(q)P>HKVfe?<=FQ&a#875&HAan}U?1*$7_ml$qH*FCN`<&iOP&-zJX|%7Iem{1W5n z(kBYY%%UYL(E;q>+LMDPPxm{*k)1e{ZW-)omZkdpz@2Hu>4C7`wnAP2fZ~ge&laQBlG0Y z2z`XJz1|w|-O(_34RxlagyzwSz$>V~0nQEEOmyUZn(8CFxAXh6aq%gsKe=<5G*eol zu+X5|3+vXpS{!a;mvqOqm1#_DDfNsX+`poeH7b!>Iy=7O7#x7|u#CoH#}bzJs9ow$ ztFO)O=6I{Vxo%4n?&S#tMOEP20?)SwxR-(JD=2!ElJ+?6`i!WZn6d>!UQ&UgCKZ^l z1Yk)X8>l811gYb%rr(6SgHsfoUJLy~L*A}V;}gau6xf}qMH05_iiK{i&)9mGZWgfx za$W4Q;0oQbN3I)xIn=Z+H{$4ZB~zWLBCcf3Xpwdi6gB2M!$N%K=r3pQ(gVd$_-{7; zOYy_mOSt*pAIqayc3>$);eN-uDP7n^Z(%!t0?{CR5v-(HszPfm1(y7{l8H{6c)>_V z-Fsu(0K;4T=EffGt-xZ>)_`kUw_MwL-m_Ktaq(j^a3EUYx|!<4xi8Di%FA=xO4++I zaNd3?i_}kU?h!e-#r)T&H!Vw!v0FBp)NsA8YP#j&K?|Gr?m*n=4%cU>Rks!d4oAKY7FGt9)R^RCb>Hp3BUt6T3+^>Xl|or^ z1MZE?!SW-mD+ermPs%;&?{~+@3N>ia&4GFFxmZ|v_o8ftZ>eu(bAoo-*d>}%>ovVkJPB1ss-Q=wNW@)@)o!lB=Pbqn! zbFn+ zW^Syz-Kl=OqI*l6V@xXAs#q$pWEQC>R{x|FZB_R^*F~w=s{Z<1nS5To{rOSy z9(C*U_vH?146=XYT%EBtDErbI%NpwXG=3Nt+2gO{=F<&zJsS5T%1T7}^x4>wWL+w; z#SL{fglMfB)gsb%9BHVFX;g31hDFpjkTDv@=Z-eiT~@2L-jOE^TYa-g8-DfP|1{Kn zsn%&ZVOwGCS28mo;8;W5JL;%4DG_T8%k=?{zXrqWS@pg(y$3wd5NQ7v*;*GA4ZlSV zk04WjAGe>StfrvRKE}GC?pA~(%L_pPUpLehH>fAq#D`Bn(CbQ01cV}BL4z8&cCf8i z!#B=V8PwQ8_K&fZbGbZ=EC>guga);EZ9AoHgL?1U?qSXK`{S}lT{?c`*M_<}b<5hM zuwMH0YOb8Fq6CXu!r zb+No&#D%2&eS8YMmeyxu`@hG>WBXq9KkH(Y`St3j>mJMOTpwuPRq~xF2H8oheZ#hO@!!e)4)q>dua>=#7Ey=p^{vy==eUVVqN}@JNDBJ_ zwp}GJ7?$Je`4>{cJ~1pa49oj!%=%t(qdIzh=k}U2$X;187tw~ADt}uZaSRb-$6Mbo zY7s)DxRa}amHPAgzRIetYQy>jTE)IN-P};u)~Vk6qFw%}?s>6?JYISJ#UQCnX;m-3 zv_`(HKKXKw$jjI#e=d0;P<}0JS$pd1E~uZp+)aM1UV6EsJfsG1xKHWSRJnY^dIftx z;%i%EedXt`nF2%V*9c3_T45QxRz0z4q+D5<_;xRotW(Es>8CumR$ad3A^DCf-~CAD z;s5Z;!2i4?V`tQlKf7*zu5MA*%~^n5pry6-Pq9p7zp=h@Z^aWb_TSD4*YrD?zVOA$ zx!VRy41X_H#>jis>dN;OeXIJw_LE9-lRCZX1G!&~d+$;Cp!&*tcPUBDl~L7p8Q%XT zVfp@LVR>V{uq=F0y`^S(pmm#Kv20WSsF|mvHdIdDkt6$L37e^)wiMqGm&7eFZH>lv zMQdPNZP=q1ll^)hyZZ6Y&%&T);^4V>pssW0v7fjiot?z%Am_KGYuefOkDV++@S z1<@sRNer)NcmFXeXp68&Ebaec>9^U}-pH83c$PTzqdj?)gEZuz1nXO~)Y!e#f{iU< zTa%?eu=h#iCvaai*(zKfAMfi8+u!>JE5WUmefK+LC%1nz>SO`7%dk*+sN~18)Gywj zMrHVAldzEG{kMhXo`LFs4{q-UBHyv^pz+@omO0ymd7*Qwx_$d)wd7C$wBJJ2h?ELvk~HA zmOA&N(UBnXyoivWR|-q~pvs*ejZnx;CUVTi7ggp#mEi|F$^gTxc0bg+*KpiC9z`ww zl{2qj+pX8nceS`-%Wu16gl;yq#kKgK`^3Jb;*055v}EEF1HLZRNJg z4?g=$>FmzV61%XS#I`wK*lHoCA-NS;?nd;hcBtFFm=p|kIxL{@|NfVVl3ul=^4I^4 zmXU6pj@WC-DO(+ObZ|Ija5JRUFd_4g9UT#XFq?;~UmPuPZzX*BZ6|mf!*UgiGh5h> z$^{ImMm^;473^wv1Y%gr9eEXXZCDkSsXW7uNqp}C757Z8KXK!!qt>j8o zf^4TB?-2u{I;8f?HjPM_o;y8-aF_$I;2q<<-$r=BwZQ^>hF_=8Amv zw!f!!!d3vr#I{>w?_ZwVa8&eYQyjX_WJCO;;c@EkID}~UyDRzGf)tUq)r_{X^feWe zhr}ZG!EadIt?l8VWbNM;nYL~p_WoI~Yuyd4A}e~IG`=}pQ>cd5-oPoF0N<`TDnj#CezKTqt7_HO~QsbAk)V*6zk8SKPtiDZ=`BGW6LwnC8 zCx$GkR4mi6tlCi>g>EQ2BhXmzP%NXcL^rjziVJ}Q*R2iC&aMj{=@wQ)i6Led^)QQU zBO_raowNhko?cl!Gg#h*+R;7@kq)f#+sHb1n)Xon4lI{LWpAvK!{j%C%{YMU*;d^W zCT}svz0xG@_=>XbH+-{ysqS3krMeRhW<9j|Qr&yijwt!P>~aptEW`3L7Ce4XfbV*w z#08RKQ}prf?{jxmRxfWSdn$5P^?y3ZF^VGIt8R#vA1K|$dx}L=VcCu&c~#a{+;|>i zEv`)#`t}C&h&_s}>Fi+?qIj3~Yn+kC4)O9r;F1~ysjd#}gz_TaQ3>+P!Bl2Tm9%G| zi&~PSON5?U&!ezZxs(_v9j_^3-{C?nAyJM;GDafvD{&o{ zT=$J;jn#filDEsT+PGwSBQ=B=t8Gh`U6h$Sv=cBP4}()=4>;VCB5zDE9N>goPL`_i zxP+FtHAJ_g6x*e`GuqE7^4S<9DX@%9k(P7tKZ50btF-)R)mEm;u88TqR5={0zf)y_ z99xZV+;3GP5nvV;3Xp|$_}J>5UFBKnu~Q^&`?hX!k!%m2G8~3iprXsd>O0R z1LeRNgcr${s!01sxZ@n%Dhq;=V@oZ2klMQgo5P06w`j8jRWek@$6TtLQ={}~x6gvd4*otXZCB4`;me#$bxX9w zVX`lkSmGW!2G!BU#&))QTf1$TOq>9dLXQZQl7raia#<@1?{&u`Br^rEM|pSRnotu$NEPp2$Tb8>{XL@TXikunm+WXqj@Xwd^F> z&Ls2>+I1sjmjGB+P1bH1A#;_(JGHk*$WmowlNLWxJ~#+c4VD$y!M0;vVYuRS8*3}N zAnK*;?)O^jrnH(0MmTNOGSm!xGrwkX^_L@M2dP{w(k_gW`LrHjm)&VS*N$|se$y@| zVqM)}mr+vLSfqvL$rQ?qWr8*!PxkF#LCxXdSNQY%HKSj0^wWr~(GR`zi$-$^y_@Gxn44a;{}TCp5Jew2KAbXe%~@tof()M&4KY1x2v zPDyCNT097cr@D>^eQ(PvCBb0jhz)l{t6P372?UuzR0Vi6ZZE}8@%5a7b8;-!sx}2} z3PbZ_ixEOQI##A8!Ac&F4?)L6irw)vVF2#S(spNKTk9}Rb`N|7deaomK2ADyq}G0-Op@dVxqI@?VIV`P;7#C{qgQ7+55c-CujN&AmX$buVEoYMK6uP2G zW?Vk{=UH4rPStLkB#Y%#?XyYpr5L0BTI-rH%$wcYb;h=~e6lQ&FKNF`mb>Kh+FMiP z)5^G3Eo-W@DMMSenN#KSQN7Sn`e7M}1$WHFt`XJBG?^f$J~~=j)?#VzxBR0mPg*{N z-z2O({=3}UWcS#v&#S(7y3CXE32omDIU{fw5*@#*I$@@amGVAq(Dib@%+p@GUfwS| zX`N=tjt*)yk>YB%9>ssu4X*d8>wT`44RrgEN4l?v(ehkR{vW-qJ;WY^yJffU6r$I8 zJ?H%^A=BQv+&Z9bx}qiCAUlT4#A8GvRiRZ^R@*Rc+X zblY=Us=vHJjx#GYMb*i3WpY4=Z}1IrEtd9JPGI>3r-naF(PrK%V*^4$Y?GI0pWiAw zRaf0Ahspk7A+||3-?`|nyKVF5*@kw`$XsFz3lSl1+n75SEuOPrfi3Um`L~uVhMqak zcE=qd)t5`;uX5s?JLb;6`Od|*5|=vv&iRYe)6>JmqQ#4Bi` z5w`TsedndyTo&!y+vL=LcU&N=J1$VR&hRP9w3M!Snj|&jJC0K#jt}3>uG2YZx@!Wm52w+c`TlA$6-GN9#f;;a#ZQp5koT#{3P>%{F$vow2McT z%}V?bZQYkjLR2}%=V&;^lP5kKhG?IDsf<%j57A=3Qevaxhf1R@sXghFHdM2JrKBsF zL$!OqQf^V^4b@J4rOZ|~4Aq7mQwBW$tzr&5gN}1xsP^tLr9&`nm*VJT)#e;i+G?kd zDdu#WBE&M-k`Z4{xTQ>4DFww(cKVpHq+%g{b(j|QwUV4f+c;^mkljB_3+xu{=yyuT zfQ@hq)E0iN#L11?Q(r5I!RKHp8;)nnv%414wU>UYoXKUlWQM$+q?VfLxfq~~>+Kyl_1-3&bYhByH+1PH%M&67h!l)<< zV6x?)>a=H$DIJ4X0DA)Sw8-yJ3k$wgtd1Jk=!5(jr6*ntAI|>z{~zD`58){p%91BN zH^*Kx@C27o1k_X=gG=z@)&oGZ3(J8I0Rz1aY26508En*fMx!CM{a-8Xw9;?T2aZ76 zkfW`uRr)4d0)@!T#TR;T%L%uZnIAPhMs02bleQ#R`=eG#kC{%}BfR~MxQy6n+njRX zDqwd68yRjclX)Qr!bNTyJN{D+NZ$!P727%C(T@a{1w3kg%=B+csvYUtQ^%E#f#i02 zg!cAvrF$@K)2E%*=Mc*BXv13C8wCyOwZ584$P%_MT(3nJ1LkU}GDnRYla; zZRINMnG;H4;6->W&DY*LfsnL)Fkd@yLP-xCi5)b%fVxaq8baq4NQ+JT@f#&2a6PcB zfcjT*2sO_^@aqNI7vG`pox^rTf%eCDN_QEp#hg?Uu^MzziR%=Nu{X7&Fm{~~dw6J> z=}{D~pbhQ9(b__|!1Jk-%0T5nu=epu1FevmC4{YPb(jHMDy0nH0FddAAM+Mys~g zsr;;DPN;sUUU@e_IWwg?y;Vt<*r=LqdRIxBnB%QYD(!T}6wyJgm&ugqsP!|SW=z4( zFs5MfxxUe+GA8{rW22H8lfHVSPk4ve%?#vljxj}`GbVlWD4z(#e#WHZdlPrvD}utm z$(Z!rKAa-Niag%{HH<01GVKnt>E*~zSU8IJpw=k>^|vwK8#)Yo`6loJ$O`@_bZCKB zr(o?E_lAFa@M`A2g6UPz>A5Z1d!=Y2x+kLk!8CFZBR+@N$O2G;2N)aqWK8<{LT`p9 zBLR9y$c$r%J3_Ia>Eu7sZ?D1aGgiMNFw`;w1z5tEGO&!XkpVxB(rySe*&N6QobhR6 z)Ekx4KsQr8aHc1>d^p^f=`km+)1yzE>2WB|%9wENk3ds`LyYs5kFvXl@gme0Jz}&0 zL8-nT2GgTPbfhPK5loL7c^Zt0e}ILj_%1Rg{VHSV4iS%&T-fn(b>LLS6hR?lieNHh z(w8zOy^JyGn;Db7o$)lhmnBa67+fWWA3m<8p%NPCX5(Qi!{E|IZ*80fHF<``LkWfA ztlSmORj@98+|!ST`SAijKEs#_R)Q-5Py9IGIs`qL)=_-;R5=f}G__eTULxd9w9*_$Dw#K;iL__&&GR;HE^VoG<6WPUNo_$ct*@bZ)t zHxjSaR6poD!1JVc)Qg_#)u|x3S98sO9Q-?hLz#d4G_MYShe-1^h}nMpsUM%5?h}C+ zHp7=wulF(){2*h>;9(y|)9F42>@~A|BgiiHGDR?%F(pto*H>TV$D42R>f}GT~|2@{iV^^K>TG5Kxtx=nYHuTE>*t zNyemS-R<=!J)1G<(;1UKi!td-8Fy|YwCk;=$T`cHaS*Nw9|mW_+0#PXnNC-YRp3Im zPLW<^IwdL=c{54+0d0%blsIwmVy~IpR{3%CJ-+&KKfcJAqFr&XHY^f#xaMAOxQCFv zwcrfslzk(4rc=5H8Iyj7G3gf>lP>P_#!tGLG4v=gof*iXSbHkc6c7p$Jj`dG3m>eXtNQ{QNF~RHrZ?M_cDb$&6xE45BTZ_{rF2iKEs&8I~ngo|7eUd zMLL?8@hentGnnqRc=|{5zr2b51U&}a)2&ma*-WQQk7WE8{6`VHkGO`u)Ei%LD2}+J zU>L^|e3m(+;l7Cq&S&~brjLgHJ$N$HGamFNKnZ^7$L5E;x^ddM-QhJ*fEvbB!UYfe z>WlsOfrqtm?Mw+#5Bb?YeOP-4_P*_wd&5(FHpY}*Dr3@TE!Vz4ILACcdnscIx0o@7 zTgI65GRCCWFed!~W74lOemzuZx3{P6!HhMi?Pf4m!qYwQ;@!0qtj{0>gSp<0>8BvH z2h+_cPxvlOZ-Cy_H@rh+GKVmH&(I%y%pC#c`XbY*RF*PthDfhvO!^tdq>D$r{-m23 z8|TtJ%Y7ZP7*hlpPx$GKjSN2Nt2-H!-fo4j9?f`KdpKlr12OL5bVUEiV)l`!nL%Ls z^2JlNcBW5*J{oLe`YlW^g?=kImg&owP8p3}>CNbqVM2SSBl<@?Gm_H^##EiF7?ZxA zG3f^wlddx+{VHS9hdk}g1oWFkHZzdJGR71^8DrAZR{2CAdiwE5#^k@|8SSNL)b@sF zyy3`R%b3zR$(VH8vtEDF(-@OJk}>Idew^>iCNce4ZCDI4Qo@AK(QNa;|uVA(9eGb)5(7oV~VeWF?5I6&J5&GtooL80b|k+Go}QNF(y50wQu-r#-uN0 z979*PWz0YhHH;~N-F}?@oNofJ`*FMHef0fO*<8frudZ!vDo#_g88{s z{2Fh-UeG&%rz5WJxjOTL7k&Lp8Nc8_fQ2v|U;#4lo(0gbPzEv?Z-zg;hp~~}062noG7NWjjhtls zA^ho`jn|p~;#a)>#wFM?W}p%-e$DGZ8CdVfBVYH`L*MY_3O|m0(^p^W<$=cjzW6O) zhcd>Lp#y%bZ`I!IgwA`A*{`6ahrqZAcdc`pH+tg@!x#C+>nhMCu76{|7J7Zf!&rwh ze=2ymA6tESgoyGrh?o5MQ$G&b0qcK!6KLnhnT*N*aD~@D7zxtT zBiA}3^ovZNhV(`DR&Rg@u)p4eUUeCEPw$`1bV^`1;}?+ty-{@zb}CUPFuhTQ)wS^F zm_LO#!yhYr6k!aIq0B%vkl@D|j46UyjLE;4G3lw5-ULX`V@&#HFS`dwlo)n=T=$x( z1`KpF^%2e`S=z7^)9^WdX6okLjrMxZG%RqYVTLnR9Oq+M+Nl%_Ulrc`iV>(;diKY2 z1x4klVfu~G=~c5V*gXxno9T<7({n>S`~jv@eH~={lok63Jyb+bh)@fY!(ryI2@x9a zw7GT4&}pWV|2f7r@TZ5Cy!!x-h}*pl_6~G>@3_3+^LKX35%8YX0r!_aGvQCKW5u&CftE7=wK%Rl2=<)IQG6?yj(j-8DrT62 z2rhlr9pK0YdimH<`4&+UIgS39ASDl==2gI-dmWa*fnJMT#cE_0)61aW0M26xu4XzV_&Vd4;Qxl7{~3?&KprT-MUMfz z9RYp^7qJ8~-}h#a{D(096#hfOSDC-{17H6P#(%)S515|RL;2ko_{@P4*w2{u+ua{| zBMfUR#0xl4cl8;ZxI;h4bn-9%#OqJ`8pcTozZN_a&+a05R|bwT2MTbK@pTA5Z>g5T z?(xq)=$k+xV`JdbKJSi`MPtli5=Fg=G3l#5^NnghW72aE`|3rENnd@$S6}00hjBGE z{iv@)F=L8g{V`wtBxBMqGNuCPj7hhB?Hj)5HFo#!CD#m!n1ITpcWOPOI7L{_bc%4~ zH@*=TGA4a4V+#K(W73z^y2E?=_ZpAE-P*euQv}(^y$MnTncsQY&>54y=6hfLb;hJe zopR|I-(B5n%@4i-HZ!IGsXzMa8H`D{{p_bRCcT(3Ww^w}bh7Nqzj zn+8z>-Ar#`bEYAQGc_S+Ixusl1GD@2Y*zw_?kb@SQ4VdVw1?773CiZ5wU@AVl%Me} z;S+wm!jD(_@hU%F?Z?mi@fu%th;_aO@sc0E>c?;T@!Nj9*P67 z=j{F})5(9?FTPE`f-&hQ8B^Ce%^12vIGKSQnix|A?SA!5Aeu4hLl{%|k&H>7&Y1LB zjHe0hLWU_h`53d&^HJ~M2!$gZ3hjEdVnx38MIWjx=C>J@a~zxrKhJ^1a@L#I524fB z^{GZYt{X9-OsBkMFs8g^GA6y0F?5Gm%nanPo-swRfida(8Iyj1G3l5++JY56t{wXf zW74hXxQ>3_jv2@yjWH$AlQHS#j7eX?nDo_*NngX5^o^Wx(t#?~?(B!A*vy2VQPo?( zo?For(PgIBLB9fi8+K|c($}B&mMjn#4KIR+xOGbSO{SCo+l-+*#4%<_Mg+Uj*8EJi zmgzmA9|u3-PJkkucfp$hqb3*|8DwnK1Y_e{ht14D4*MBX1PA=s@|$mh@r=pe#+c$; z%$W2gjHiu)VdO<`gyfLNm?F5qnDjpwlWzN68`mEXOr`zq8&4@?^4rXq;;CRv`o=%J z;fZ%+W&y+-wVBzC{Qar@LH3qEz5ZmsMb{Drpi5<6^4ck$LdH*^1@Sp-2_K@4 zF`fKN|MF&tGQ5;A>E(<`KgM`kCJg4keIu|irU;4|Qv?gNEramtz^poNFmjvc^fI|E zVNCj&dSCsVA15^U>Zy#4_!%R9hbZwihy{!(z^q2!2kC*;YmM^GWqK9j44A|j46CJW73x}-jAlG z8G&4Pr*XH0nyQRBP=NJ*d=9f34K*dm4ce9=ro^aEnM~`B6emj61=PCN%PlYAIlPIgjq>Nntk5^vrF%=}`C##wU8s(d7;@ zLjfW@1TH~9&ylKUm^VR+FvE`r`|;g=e2y^{K!mgSkiIZ8gHb}pl%S0<=~;|PAHtaQ za>k^uU`+Z(#>RJco0)+e4lt$&4l*XamNDrk8I$g0OnMXJTTsKz;KQ(^hNl^~;dV!` zDuHm&k1sN&1UzquqVA0F#uQtydmh%u>{sJ*a4s5+`2-9zlA>@ntM(A=b5s57lNnQn zXZdldAD8)YIb%wv#;UdC;Qf}}%wCRy)BFasGkJD~{Y-xeI!%LRbL$jOEz>bmji7m^ zJUb)h^EA`9A^eZN;c@xT94LUm+y}IxEPRXrG#3KTkeTVV&;$H*3)8Pcr->MN_)w;| zbQq6u&(Fci9D+L{Kj35|JFW}IOs2PmPBS@N`;JFDo`dt5t}xRi4}2dz$bwNhk1-wq zf0{@F-+5iD_>)W@0i7nL;9ss?W%@+uGcjqGtKvCZ!_nJ*|p#-MnO|4<(c~hYdly5&Gft@%N@Wi(pGp~64aYQ=84F5s^ znwq7Y1<1y9E#3g=TZ~u0pQdxcPg!0|pdF@j;r=}tzX*St2Ic`HyT~vd5jQf23OLYw zF#A~snwU-{F2bBKo&fc>5NhUcVW zGIRI=I!!L)Ijf-zEM+=1Ng3nc;7=3N9Aq`Jnd#)e+sm#mrlQe#VaLbShJ}nN!RdZX z88+O7>z*pjhv;J0CCWKJrdbEMPDd6O4|D~fD&!6{W2K8-31A{BpA0J6&@pte>6fp0 zj63uf;?8m2C$!F|U?68q6;Zx@a?&zSTBoaqQ~gc&Hn zMaC3BXH0r%XWtsIYGd2_vVrrN9(7g~H}{^=6K^gfXSHpE2pj{MhNo z$=V%-*jsASShNU76H(GZnZ~VdV47-Ex|yOq!2Bs$Cu7n@H*b8Tr!gkIr!PB%t-Egk zJ7Wrv&zK@S$Cz{{W73m*c;h3z3uDr^GaeL!FAf&?m2kiI)L2vurd{?KU7Gwjx~EsC zcqcQabZ7bTD#qk5dU?Z>zr~mF9+Iy?%=Y7Xj48qej48rW#-uM{O!`vBq?a)^?lzV) z13A3Tm?GH7nDp(8Nv~l{`hLcwA7D)SVa743FdSh9a;RlY5uDU+7-veHaE_VD?J8q( zb2279KHXdMd2oowl$aH;dycd=t=D){+%4ovdjnSZxDH9=>SEU+i1rQ_yYv!2roP2> zI@WN;B(^UVnG*VJU|FIpzv;)D{dk-9AhI}$Txe<1KKYNoH|fZe(aLn5ME_6BD?AK&nXzY(9SXBkCe zOm%J`dgdAA`T9xtZfUh&BpVp($OKKa>lxey-n=VkO!cyn`BSEjFed#NW73-#L+>X< zU*A$>`Y|PlaQL`NwPLcCFd27AvY8(xG`X)fZn7y6Gv(gtTCK#&!E#%K+|%5?p3=+& z(>%W(o)2CHrZ(|Z`E-^D<$ft+O0>+6AM;~JIWtfM2N+WX2N{!I(a&2Oq#t2S`b9sc z48x3%t9EF@Vgp^AVw8{>j2hrvGgH8Uzet_{b zfiJAu4e-rCG-HY&ZJ<{t#)Qt}rlIDt{p^K|H=}0uv#w@joaq!#8DrAR8I!(-G3o0W zL+>YQn1LL2Go}cRF($ospq4((6x*J*ty#W>nx}1!;8#^6eM;!4pW4`K^>86CpT0gs0>oo)WbUY>tMPPgs@gwy)@B)Ke zrw%D0!2A1HLVx$)fqOWi`{ue*@!R5I;>Goo$3R;>Tki%z*-&W_$$!egu2& zy-+c&L%kUwf11q{D|}oTPGwAb8e8__*@7l<}ZAmqP!|;!-R5(=4hktLw7=RX?T~ zQ@KtvrFu9o4m-W)Bjd;8<+#-FavYOdIC)F z3qU2LIb}WiTIfOF4>mM>elhwivA6Fk( z#+VYM$!iVSt*>DGkWYLL*Zxe?+j;^#2Zv|C-Hqs7`!`K*>(MEJ(~K#@O{2W}2A>36 z@muX)ox)%AFx{o62zrk8btq#@dg>UjzT+Pf=*e{QPs{iEQ-VDiA7bHSJ)LYRbD#j2 zNH@Kh4)O)wh$!M>#ur#bo_J`cUAW=nZW_jo|KMN7bc%li!+5_GCCr$SCkDB7keXnt}E5|FY8C<-5iZ<*fQ^EwA;NMl*E_;(7hfnp@={N7W zKmFW1=X~wKn@owy+tai!ZZf6k(hqBMS@mQ3U2Cq>&p~tkX@)jz9`*;CM3UQS5=qYV zGrOGWhjTg8kL_}%AKv9mKf>$7zVq2Rj2Ha515E(HnSQI0^Bg~3=*JKH@k&3Y_msTx z;mqNkZQAUcQ4{pEl~-^*jm4QB)ZT#wA`#95+g`DXJz&P*nWrv{OPT&sodtW|G zzX4`^Ts_Ko7Kbx_Xp8Ig<6E5Rrx-Xl`7lmOjh~WY5#pz|R^EcCrRdkEctH9AE6()O zNu2T1JhKtbLBAxz?eyaw9^Q<>pi?*3JH$~KTi*vak9EEAnhgFD9GvKS)|2#~z(d0^ zT{ECtAb!$RB?40Su?gWvD&dbgGI z8Q`%su6YHC?*-G3E{t>gKMEeSMHu(QNPixDGsb3{Ti*cwJlZwwR1|)_?LU}nSKQE3 zTKc*j-iJdKN<`lcQv_dwA7mN21Xk1B5kNO53h@!n>)&?!hk`q!g!KI%h3^ag@qX89 z^TfH}$5Xr+n(BZd7&&@?0w6~>g6GWlW`Oi6oSo7!fg&g;Mh0-h%HXx&C-Gv4hmm

wV7F>0$iSVjj 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 delta 54202 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 HR{#D#Ew5DX diff --git a/STS/Core/Inc/yunhorn_sts_sensors.h b/STS/Core/Inc/yunhorn_sts_sensors.h index faf162c..7aeea6d 100644 --- a/STS/Core/Inc/yunhorn_sts_sensors.h +++ b/STS/Core/Inc/yunhorn_sts_sensors.h @@ -252,6 +252,12 @@ typedef struct sts_fhmos_sensor_config } sts_fhmos_sensor_config_t; +typedef struct sts_fhmos_sensor_ambient_height +{ + uint32_t h2cm[64]; //height in 2cm scan data, ensure it less than 250*2=500cm, 5meter +} sts_fhmos_sensor_ambient_height_t; + + /** * @brief Store/Write/Flash Configuration in RW RAM */ @@ -313,6 +319,7 @@ void STS_PRESENCE_SENSOR_Function_Test_Process(uint8_t *self_test_result, uint8_ void STS_PRESENCE_SENSOR_Distance_Measure_Process(void); void STS_TOF_L8_Process(void); +void STS_LMZ_Ambient_Height_Scan_Process(void); void STS_FHMOS_sensor_read(sts_fhmos_sensor_data_t *sts_fhmos_data); void STS_FHMOS_sensor_config_init(void); void STS_FHMOS_sensor_config_update(void); diff --git a/STS/Core/Src/yunhorn_sts_process.c b/STS/Core/Src/yunhorn_sts_process.c index 8bc5ce2..e8e3418 100644 --- a/STS/Core/Src/yunhorn_sts_process.c +++ b/STS/Core/Src/yunhorn_sts_process.c @@ -640,7 +640,7 @@ void USER_APP_Parse_CMD_P(uint8_t *parse_buffer, uint8_t parse_buffer_size) { uint8_t sts_fhmos_cfg_index = (uint8_t)(parse_buffer[CFG_CMD5]-0x30); uint8_t sts_fhmos_cfg_value = (parse_buffer[CFG_CMD6]-0x30)*100+(parse_buffer[CFG_CMD7]-0x30)*10+(parse_buffer[CFG_CMD8]-0x30); - APP_LOG(TS_OFF, VLEVEL_M, "\r\nCFG_CMD VALUE =0X%02X =%d \r\n", sts_fhmos_cfg_value,sts_fhmos_cfg_value); + //APP_LOG(TS_OFF, VLEVEL_M, "\r\nCFG_CMD VALUE =0X%02X =%d \r\n", sts_fhmos_cfg_value,sts_fhmos_cfg_value); switch (sts_fhmos_cfg_index) { case 1: // head level height threshold sts_fhmos_cfg.sts_head_level_height_threshold_cm = sts_fhmos_cfg_value; @@ -1821,9 +1821,11 @@ void STS_SENSOR_Distance_Test_Process(void) #if defined(VL53LX)||defined(L8) //MX_TOF_Init(); - //MX_TOF_Process(); + MX_TOF_Process(); sts_sensor_install_height = (uint16_t)MX_TOF_Ranging_Process(); APP_LOG(TS_OFF, VLEVEL_M, "\n STS SENSOR INSTALLATION HEIGHT =%d mm\n\r", (uint16_t)sts_sensor_install_height); + + STS_LMZ_Ambient_Height_Scan_Process(); #endif #if defined(VL53L0) STS_TOF_VL53L0X_Range_Process(); @@ -1851,24 +1853,34 @@ void STS_SENSOR_Function_Test_Process(void) tstbuf[i++] = (uint8_t) sts_hardware_ver; tstbuf[i++] = (uint8_t) (99*GetBatteryLevel()/254)&0xff; -#if (defined(STS_P2)||defined(STS_T6)) +#if (defined(STS_P2)||defined(STS_T6))||defined(L8) STS_SENSOR_MEMS_Get_ID(&sensor_id); - + printf("\r\n Sensor id =%04x \r\n", sensor_id); +#if defined(L8) + if (((sensor_id & 0xff)!= 0x0C) && (((sensor_id >>8) & 0xFF)!=0xF0)) // no VL53L8X found + { + tstbuf[i++] = (uint8_t) 'X'; // Slave MEMS Not Avaliable + } +#else if (((sensor_id & 0xff)!= 0xCC) && (((sensor_id >>8) & 0xFF)!=0xEA)) // no VL53L1X found { tstbuf[i++] = (uint8_t) 'X'; // Slave MEMS Not Avaliable - } else + } +#endif + else { STS_SENSOR_Distance_Test_Process(); APP_LOG(TS_OFF, VLEVEL_M, "\nSensor Install Height =%4d mm\n", sts_sensor_install_height); - tstbuf[i++] = (uint8_t) (2)&0xff; //length of following data + tstbuf[i++] = (uint8_t) (4)&0xff; //length of following data + tstbuf[i++] = (uint8_t) (sensor_id >>8)&0xFF; + tstbuf[i++] = (uint8_t) (sensor_id) & 0xFF; tstbuf[i++] = (uint8_t) (sts_sensor_install_height>>8)&0xff; // MSB of sensor height tstbuf[i++] = (uint8_t) (sts_sensor_install_height)&0xff; // LSB of sensor height } /* */ /* for STS_P2, set ppc_config -> door_jam_profile and distance threshold accordingly */ /* */ - +#ifdef STS_P2 if ((sts_sensor_install_height >= 1500)&&(sts_sensor_install_height<=4000)) { sts_door_jam_profile = DOOR_JAM_2000; // DOOR_JAM_2000: assume door_jame less 2000mm @@ -1883,6 +1895,7 @@ void STS_SENSOR_Function_Test_Process(void) sts_door_jam_profile ++; //DOOR_JAM_4000 } #endif +#endif #ifdef YUNHORN_STS_O6_ENABLED tstbuf[i++] = (uint8_t)20; //length of following data uint8_t self_test_result[10]={0,0,0,0,0, 0,0,0,0,0}; diff --git a/STS/TOF/App/app_tof.c b/STS/TOF/App/app_tof.c index 314d39b..41735f6 100644 --- a/STS/TOF/App/app_tof.c +++ b/STS/TOF/App/app_tof.c @@ -38,6 +38,8 @@ extern "C" { volatile uint8_t fhmos_fall=0, fhmos_human_movement=0, fhmos_occupancy=0, fhmos_sos_alarm=0; volatile uint32_t fhmos_fall_counter=0; volatile sts_fhmos_sensor_config_t sts_fhmos_cfg; +volatile sts_fhmos_sensor_ambient_height_t sts_fhmos_bg={0x0}; +extern volatile uint16_t sts_sensor_install_height; //in mm #endif #include "stm32wlxx_nucleo.h" @@ -156,6 +158,53 @@ void MX_TOF_Init(void) /* * LM background task */ +void STS_LMZ_Ambient_Height_Scan_Process(void) +{ + + uint8_t i=0; + uint32_t range_distance =0; + + printf("ambient height init...\r\n"); + + for (i=0; i<64; i++) sts_fhmos_bg.h2cm[i] = 0; + + printf("sts sensor install height = %4d \r\n", (int)sts_sensor_install_height); + + for (uint8_t k=0; k<10; k++) + { + int status = VL53L8A1_RANGING_SENSOR_GetDistance(VL53L8A1_DEV_CENTER, &Result); + + for (uint8_t i = 0; i < 64; i++) + { + /* Print distance and status */ + if (Result.ZoneResult[i].NumberOfTargets > 0) + { + range_distance = (uint32_t)Result.ZoneResult[i].Distance[0]; + + if (sts_sensor_install_height > range_distance) + sts_fhmos_bg.h2cm[i] = sts_fhmos_bg.h2cm[i] + ((uint32_t)sts_sensor_install_height - range_distance); + printf("|%4d %4d ", range_distance, sts_fhmos_bg.h2cm[i]); + if (i%8==0) printf("\r\n"); + //sts_fhmos_bg.h2cm[i] += ((uint32_t)sts_sensor_install_height - range_distance; + //sts_fhmos_bg.h2cm[i] += ((uint32_t)sts_sensor_install_height - (uint32_t)Result.ZoneResult[i].Distance[0]); + } + else { + sts_fhmos_bg.h2cm[i] += 0; + printf(" .%2d. ", i); + } + + } + + } + for (i=0; i<64; i++) + { + sts_fhmos_bg.h2cm[i] /= 10; + printf("|%4d ", (uint32_t)sts_fhmos_bg.h2cm[i]); + if (i%8==0) printf("\r\n"); + } + +} + uint16_t MX_TOF_Ranging_Process(void) { @@ -167,32 +216,38 @@ uint16_t MX_TOF_Ranging_Process(void) return (uint16_t) range_distance; #elif defined(L8) - uint16_t range_distance=0; + uint32_t range_distance=0; uint8_t center_roi[4] = {27,28,35,36}; uint8_t range_mode = 2; //STS_TOF_LONG_RANGE; - int status = VL53L8A1_RANGING_SENSOR_GetDistance(VL53L8A1_DEV_CENTER, &Result); + //int status = VL53L8A1_RANGING_SENSOR_GetDistance(VL53L8A1_DEV_CENTER, &Result); printf("\r| 27 | 28 | 35 | 36 |\r\n"); + for (uint8_t k=0; k<10; k++) + { + int status = VL53L8A1_RANGING_SENSOR_GetDistance(VL53L8A1_DEV_CENTER, &Result); - for (uint8_t zone_nbr = 0; zone_nbr < 4; zone_nbr++) - { - /* Print distance and status */ - if (Result.ZoneResult[center_roi[zone_nbr]].NumberOfTargets > 0) - { - printf("| %04ld %2ld", - (long)Result.ZoneResult[center_roi[zone_nbr]].Distance[RANGING_SENSOR_NB_TARGET_PER_ZONE-1], - (long)Result.ZoneResult[center_roi[zone_nbr]].Status[RANGING_SENSOR_NB_TARGET_PER_ZONE-1]); - } - else { - printf("| -- "); - } + for (uint8_t zone_nbr = 0; zone_nbr < 4; zone_nbr++) + { + /* Print distance and status */ + if (Result.ZoneResult[center_roi[zone_nbr]].NumberOfTargets > 0) + { + printf("| %04ld %2ld", + (long)Result.ZoneResult[center_roi[zone_nbr]].Distance[RANGING_SENSOR_NB_TARGET_PER_ZONE-1], + (long)Result.ZoneResult[center_roi[zone_nbr]].Status[RANGING_SENSOR_NB_TARGET_PER_ZONE-1]); + } + else { + printf("| -- "); + } - range_distance += Result.ZoneResult[center_roi[zone_nbr]].Distance[RANGING_SENSOR_NB_TARGET_PER_ZONE-1]; + range_distance += Result.ZoneResult[center_roi[zone_nbr]].Distance[RANGING_SENSOR_NB_TARGET_PER_ZONE-1]; + //printf("| %6d -- ", range_distance); - } - //printf("\n\r"); + } + printf("\n\r"); + } + printf("\n\r"); - range_distance /=4; + range_distance /=40; printf("| %u mm\r\n", (uint16_t)range_distance); return (uint16_t) range_distance; @@ -242,7 +297,7 @@ void STS_TOF_L8_Process(void) if (status == BSP_ERROR_NONE) { - print_result(&Result); + //print_result(&Result); } } } diff --git a/hk_as923_decoder.js b/hk_as923_decoder.js index 8509bf2..e463e1f 100644 --- a/hk_as923_decoder.js +++ b/hk_as923_decoder.js @@ -3,347 +3,159 @@ // - bytes is an array of bytes, e.g. [225, 230, 255, 0] // - variables contains the device variables e.g. {"calibration": "3.5"} (both the key / value are of type string) // The function must return an object, e.g. {"temperature": 22.5} -// for Yunhorn SmarToilets STS-O7 Occupancy/Fall Detection/Over stay sensor +// +// Yunhorn SmarToilets Sensor R20241119A01 +// + function Decode(fPort, data, variables) { var data = {}; data.length = bytes.length; - // R4 soap/sanitizer sensor - if (fPort === 7) { - data.length = bytes.length; - data.led_state = bytes[0] == 0x0 ? "Off" : "On"; - data.mtm_code_1 = bytes[1]; - data.mtm_code_2 = bytes[2]; - data.hw_code = bytes[3]; - data.battery_level = bytes[4] + "%"; - data.size_value = bytes[5]; - data.measure_tech = (bytes[6] === 0) ? "Capacitive" : "Other"; - data.liquid_level_event = (bytes[7] === 0x1) ? "Liquid Detected" : "No Liquid"; + switch (fPort) { + // RESPOND PORT --- bottom of swith fport + // case 1: - return { "Yunhorn_SmarToilets_data": data }; - } - else if ((fPort === 10)) { // STS_O2_O6 V3 version 2023,pixel-network version - switch (bytes[0]) { - case 0x00: - data.LEDcolor = "Dark"; - break; - case 0x01: - data.LEDcolor = "Green"; - data.cubicleOccupyStatus = "Vacant"; - break; - case 0x02: - data.LEDcolor = "Red"; - data.cubicleOccupyStatus = "Occupied"; - break; - case 0x03: - data.LEDcolor = "Blue"; - data.cubicleOccupyStatus = "Maintenance"; - break; - case 0x04: - data.LEDcolor = "Yellow"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x05: - data.LEDcolor = "Pink"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x06: - data.LEDcolor = "Cyan"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x07: - data.LEDcolor = "White"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x08: - data.LEDcolor = "Red_Blue"; - data.cubicleOccupyStatus = "EMERGENCY"; - break; - case 0x23: - data.LEDcolor = "Red_Blue"; - data.cubicleOccupyStatus = "EMERGENCY"; - break; - case 0x20: - data.LEDcolor = "Red_Flash"; - data.cubicleOccupyStatus = "EMERGENCY"; - break; - default: - data.LEDcolor = "TBD_COLOR"; - data.cubicleOccupyStatus = "TBD_status"; - break; - } + // break; - switch (bytes[1]) { - case 0x0: - data.workmode = "Network_mode"; - break; - case 0x01: - data.workmode = "Wired_Mode"; - break; - case 0x02: - data.workmode = "Hall_element_mode"; - break; - case 0x03: - data.workmode = "MotionDetect_mode"; - break; - case 0x04: - data.workmode = "Dual_mode"; - break; - case 0x05: - data.workmode = "Uni_Mode"; - break; - default: - data.workmode = "Unknown Mode"; - break; - } - // select only one below - // For NC(Normal Closed states - data.Sensor1_Door_Contact_Open = bytes[2] === 0 ? "Door Closed" : "Door Open"; + // CMD DOWN LINK PORT + case 2: - // For NC(Normal Closed states - //data.Sensor1_Door_Contact_Open = bytes[3]===1?"Door Closed":"Door Open"; - if (bytes[1] == 0x02) //Hall_element_mode - { - data.Sensor2_SOS_Pushed = bytes[3] === 0 ? "PushDown" : "RelaseUP"; - } else if (bytes[1] > 0x02) { - data.Sensor2_Motion_Detected = bytes[3] === 0 ? "No Motion" : "Motion Detected"; - } + break; - return { "Yunhorn_SmarToilets_data": data }; - } - else if ((fPort === 17) || (fPort === 19) || (fPort === 21)) { - data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; - switch (bytes[1]) { - case 0x00: - data.LEDcolor = "Dark"; - break; - case 0x01: - data.LEDcolor = "Green"; - data.cubicleOccupyStatus = "Vacant"; - break; - case 0x02: - data.LEDcolor = "Red"; - data.cubicleOccupyStatus = "Occupied"; - break; - case 0x03: - data.LEDcolor = "Blue"; - data.cubicleOccupyStatus = "Maintenance"; - break; - case 0x04: - data.LEDcolor = "Yellow"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x05: - data.LEDcolor = "Pink"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x06: - data.LEDcolor = "Cyan"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x07: - data.LEDcolor = "White"; - data.cubicleOccupyStatus = "TBD"; - break; - case 0x08: - data.LEDcolor = "Red_Blue"; - data.cubicleOccupyStatus = "EMERGENCY"; - break; - case 0x23: - data.LEDcolor = "Red_Blue"; - data.cubicleOccupyStatus = "EMERGENCY"; - break; - case 0x20: - data.LEDcolor = "Red_Flash"; - data.cubicleOccupyStatus = "EMERGENCY"; - break; - default: - data.LEDcolor = "TBD_COLOR"; - data.cubicleOccupyStatus = "TBD_status"; - break; - } + // STS-R5 (LEGACY, ULTRASONIC WASTE-BIN) + case 3: + break; - switch (bytes[2]) { - case 0x0: - data.workmode = "Network_mode"; - break; - case 0x01: - data.workmode = "Wired_Mode"; - break; - case 0x02: - data.workmode = "Hall_element_mode"; - break; - case 0x03: - data.workmode = "MotionDetect_mode"; - break; - case 0x04: - data.workmode = "Dual_mode"; - break; - case 0x05: - data.workmode = "Uni_Mode"; - break; - default: - data.workmode = "Unknown Mode"; - break; - } - // select only one below - // For NC(Normal Closed states - data.Sensor1_Door_Contact_Open = bytes[3] === 0 ? "Door Closed" : "Door Open"; - - // For NC(Normal Closed states - //data.Sensor1_Door_Contact_Open = bytes[3]===1?"Door Closed":"Door Open"; - data.Sensor2_Emergency_Button = bytes[4] === 0 ? "Alarm Push Down" : "No Alarm, Released"; - data.Sensor3_Motion_Detected = bytes[5] === 0 ? "No Motion" : "Motion Detected"; - - data.length = bytes.length; - if (data.length === 9) { - data.Over_stay_state = (bytes[6] === 0) ? "False" : "True"; - data.Over_Stay_duration_in_Seconds = (bytes[7] << 8 | bytes[8]); + // STS-O1/O2/O3/O5 REEDSWITCH, OCCUPANCY LED REPORT + case 4: + data.led_state = bytes[0] == 0x0 ? "Off" : "On"; + data.mtm_code_1 = bytes[1]; + data.mtm_code_2 = bytes[2]; + data.hw_code = bytes[3]; + data.battery_level = bytes[4] + "%"; + data.size_value = bytes[5]; + data.door_state = (bytes[6] === 0) ? "Door_Closed" : "Door_Open"; return { "Yunhorn_SmarToilets_data": data }; - } - else if (data.length > 9) { - data.Sensor4_ALARM_MUTE = (bytes[6] === 0) ? "Down Mute" : "No Mute"; - data.Sensor5_ALARM_RESET = (bytes[7] === 0) ? "Down RESET" : "NO Reset"; - data.Distance_in_mm = (bytes[8] << 8 | bytes[9]); - data.MotionLevel = (bytes[10] << 8 | bytes[11]); + break; + // HEART-BEAT FOR STS-O1/O2/O3/O5 REEDSWITCH, OCCUPANCY LED REPORT + case 5: + //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + //data.battery_level = bytes[1] + " %"; + data.battery_level = bytes[1] * 100 + "mV"; + return { "Yunhorn_SmarToilets_data": data }; + break; - data.Unconcious_State = (bytes[12] == 0) ? "False" : "True"; + // STS-M1 water leakage sensor + case 6: + if (data.length === 2) { + data.led_state = bytes[0] == 0x0 ? "Off" : "On"; + data.battery_level = bytes[1] + "%"; + } else { + data.led_state = bytes[0] == 0x0 ? "Off" : "On"; + data.mtm_code_1 = bytes[1]; + data.mtm_code_2 = bytes[2]; + data.hw_code = bytes[3]; + //data.battery_level_mV= bytes[4]*100+" mV"; + data.battery_level = bytes[4] + " %"; + data.size_value = bytes[5]; + data.measure_tech = (bytes[6] === 0) ? "Weak Current" : "Other"; + data.liquid_level_event = (bytes[7] === 0x1) ? "Leakage Detected" : "No Leakage"; + } + return { "Yunhorn_SmarToilets_data": data }; - switch (bytes[13]) { - case 0x0: - data.Fall_Down_Detected_State = "Presence_Normal"; + break; + // temp heart-beat for STS-M1 + case 66: + if (data.length === 2) { + data.led_state = bytes[0] == 0x0 ? "Off" : "On"; + data.battery_level_mV = bytes[1] * 100 + " mV"; + return { "Yunhorn_SmarToilets_data": data }; + } + + break; + // R4 soap/sanitizer sensor + case 7: + data.led_state = bytes[0] == 0x0 ? "Off" : "On"; + data.mtm_code_1 = bytes[1]; + data.mtm_code_2 = bytes[2]; + data.hw_code = bytes[3]; + data.battery_level = bytes[4] + "%"; + data.size_value = bytes[5]; + data.measure_tech = (bytes[6] === 0) ? "Capacitive" : "Other"; + data.liquid_level_event = (bytes[7] === 0x1) ? "Liquid Detected" : "No Liquid"; + + return { "Yunhorn_SmarToilets_data": data }; + + break; + + // STS-R3 soap yes no + case 8: + //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + //data.battery_level = bytes[1] + " %"; + data.battery_level = bytes[1] * 100 + "mV"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + // STS-M3 water tank or cistern level sensor Ultrasonic + case 9: + + break; + + // STS_O2_O6 V3 version 2023,pixel-network version + case 10: + switch (bytes[0]) { + case 0x00: + data.LEDcolor = "Dark"; break; case 0x01: - data.Fall_Down_Detected_State = "Presence_Fall_Down"; + data.LEDcolor = "Green"; + data.cubicleOccupyStatus = "Vacant"; break; case 0x02: - data.Fall_Down_Detected_State = "Presence_Rising_Up"; + data.LEDcolor = "Red"; + data.cubicleOccupyStatus = "Occupied"; break; case 0x03: - data.Fall_Down_Detected_State = "Presence_LayDown"; + data.LEDcolor = "Blue"; + data.cubicleOccupyStatus = "Maintenance"; break; case 0x04: - data.Fall_Down_Detected_State = "Presence_Unconcious"; + data.LEDcolor = "Yellow"; + data.cubicleOccupyStatus = "TBD"; break; case 0x05: - data.Fall_Down_Detected_State = "Presence_Stay_Still"; + data.LEDcolor = "Pink"; + data.cubicleOccupyStatus = "TBD"; + break; + case 0x06: + data.LEDcolor = "Cyan"; + data.cubicleOccupyStatus = "TBD"; + break; + case 0x07: + data.LEDcolor = "White"; + data.cubicleOccupyStatus = "TBD"; + break; + case 0x08: + data.LEDcolor = "Red_Blue"; + data.cubicleOccupyStatus = "EMERGENCY"; + break; + case 0x23: + data.LEDcolor = "Red_Blue"; + data.cubicleOccupyStatus = "EMERGENCY"; + break; + case 0x20: + data.LEDcolor = "Red_Flash"; + data.cubicleOccupyStatus = "EMERGENCY"; break; default: - data.Fall_Down_Detected_State = "Presence_Normal"; + data.LEDcolor = "TBD_COLOR"; + data.cubicleOccupyStatus = "TBD_status"; break; } - data.OverStay_Detected_State = (bytes[14] == 0x0) ? "False" : "True"; - data.OverStay_Duration_in_Seconds = (bytes[15] << 8 | bytes[16]); - data.No_Movement_Duration_in_Seconds = (bytes[17] << 8 | bytes[18]); - data.Unconcious_Duration_in_Seconds = (bytes[17] << 8 | bytes[18]); - data.Fall_Down_Speed_in_m_per_s = (bytes[19]); - data.Fall_Down_Gravity_in_g = (bytes[20]); - data.SOS_PushDown_Stamp = (bytes[21] << 24 | bytes[22] << 16 | bytes[23] << 8 | bytes[24]); - if (data.SOS_PushDown_Stamp != 0) { - var sos_start = new Date(1000 * data.SOS_PushDown_Stamp); - data.SOS_PushDown_Time = "[" + sos_start.getDate() + "." + (sos_start.getMonth() + 1) + "." + (sos_start.getFullYear()) + "] " + sos_start.getHours() + ":" + sos_start.getMinutes() + ":" + sos_start.getSeconds(); - } else data.SOS_PushDown_Time = "N/A"; - data.SOS_ReleaseUP_Stamp = (bytes[25] << 24 | bytes[26] << 16 | bytes[27] << 8 | bytes[28]); - if (data.SOS_ReleaseUP_Stamp != 0) { - var sos_stop = new Date(1000 * data.SOS_ReleaseUP_Stamp); - data.SOS_ReleaseUP_Time = "[" + sos_stop.getDate() + "." + (sos_stop.getMonth() + 1) + "." + (sos_stop.getFullYear()) + "] " + sos_stop.getHours() + ":" + sos_stop.getMinutes() + ":" + sos_stop.getSeconds(); - } else data.SOS_ReleaseUP_Time = "N/A"; - data.Fall_Down_Stamp = (bytes[29] << 24 | bytes[30] << 16 | bytes[31] << 8 | bytes[32]); - if (data.Fall_Down_Stamp != 0) { - var fall_start = new Date(1000 * data.Fall_Down_Stamp); - data.Fall_Down_Time = "[" + fall_start.getDate() + "." + (fall_start.getMonth() + 1) + "." + (fall_start.getFullYear()) + "] " + fall_start.getHours() + ":" + fall_start.getMinutes() + ":" + fall_start.getSeconds(); - } else data.Fall_RiseUp_Stamp = "N/A"; - data.Fall_RiseUp_Stamp = (bytes[33] << 24 | bytes[34] << 16 | bytes[35] << 8 | bytes[36]); - if (data.Fall_RiseUp_Stamp != 0) { - var fall_stop = new Date(1000 * data.Fall_RiseUp_Stamp); - data.Fall_RiseUp_Time = "[" + fall_stop.getDate() + "." + (fall_stop.getMonth() + 1) + "." + (fall_stop.getFullYear()) + "] " + fall_stop.getHours() + ":" + fall_stop.getMinutes() + ":" + fall_stop.getSeconds(); - } else data.Fall_RiseUp_Time = "N/A"; - } - return { "Yunhorn_SmarToilets_data": data }; - } - else if ((fPort === 11) || (fPort === 52)) { - return [ - { - led_state: bytes[0] === 0 ? "Off" : "On", - mtm_code_1: bytes[1], - mtm_code_2: bytes[2], - hw_code: bytes[3], - battery_level: bytes[4] + "%", - //battery_level:(bytes[4])*100+" mV", - size_value: bytes[5], - distance_1_mm: bytes[6] << 8 | bytes[7], - //distance_2_mm:bytes[8]<<8|bytes[9], - //distance_3_mm:bytes[10]<<8|bytes[11], - distance_unit: "mm", - } - ]; - } - // R1D dual roll toilet paper sensor - else if (fPort === 57) { - return [ - { - led_state: bytes[0] === 0 ? "Off" : "On", - mtm_code_1: bytes[1], - mtm_code_2: bytes[2], - hw_code: bytes[3], - battery_level: bytes[4] + "%", - //battery_level:(bytes[4])*100+" mV", - size_value: bytes[5], - distance_1_mm: bytes[6] << 8 | bytes[7], - distance_2_mm: bytes[8] << 8 | bytes[9], - //distance_3_mm:bytes[10]<<8|bytes[11], - distance_unit: "mm", - } - ]; - } - else if ((fPort === 106)) { //STS-P2 bi-directional people counting - data.LED_State = bytes[0] === 0 ? "Off" : "On"; - data.MTM_Code_1 = bytes[1]; - data.MTM_Code_2 = bytes[2]; - data.HW_Code = bytes[3]; - data.Battery_Level = bytes[4] + " %"; - data.Payload_Size = bytes[5]; - data.Walk_In_People_Count = bytes[6] << 8 | bytes[7]; - data.Walk_Out_People_Count = bytes[8] << 8 | bytes[8]; - data.Walk_Around_People_Count = bytes[10] << 8 | bytes[11]; - data.Count_Period = bytes[12]; - data.Count_Period_Unit = String.fromCharCode(bytes[13]); - data.Sum_Day_Walk_In_People_Count = bytes[14] << 8 | bytes[15]; - data.Sum_Day_Walk_Out_People_Count = bytes[16] << 8 | bytes[17]; - data.Sum_Day_Walk_Around_People_Count = bytes[18] << 8 | bytes[19]; - data.Count_Valid = (bytes[20] == 0x0) ? "Error" : "OK"; - - return { "Yunhorn_SmarToilets_data": data }; - } - // Heart Beat - else if ((fPort === 8) || (fPort === 12) || (fPort === 20) || (fPort === 18) || (fPort === 5) || (fPort === 107) || (fPort === 58)) { - var data = {}; - //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; - data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; - //data.battery_level = bytes[1] + " %"; - data.battery_level = bytes[1] * 100 + "mV"; - return { "Yunhorn_SmarToilets_data": data }; - } - - // UPLINK, RFAC - else if (fPort === 1) { - var data = {}; - data.length = bytes.length; - if ((data.length === 10) && (bytes[0] == 0x59) && (bytes[9] == 0x38)) { - data.Yunhorn_PRD = "True"; - data.PRD_String = String.fromCharCode(bytes); - } - else if ((data.length === 4) && (bytes[0] == 0x52) && (bytes[1] == 0x46)) //RFAC - { - data.Request_Performed = "OK"; - data.RFAC = "OK"; - data.AC0 = bytes[0]; - data.AC1 = bytes[1]; - } - else if ((data.length === 4) && (bytes[0] === 0x50) && (bytes[1] === 0x31) && (bytes[2] === 0x31)) { - data.Work_Mode_Switch = "OK"; - switch (bytes[3] - 0x30) { + switch (bytes[1]) { case 0x0: data.workmode = "Network_mode"; break; @@ -366,202 +178,901 @@ function Decode(fPort, data, variables) { data.workmode = "Unknown Mode"; break; } - } - if ((bytes[0] === 0x59) && (bytes[1] === 0x44)) //Duration interval - { - data.Uplink_interval = (bytes[2] - 0x30) * 10 + (bytes[3] - 0x30); - data.Uplink_interval_unit = String.fromCharCode(bytes[4]); - //data.Heart_beat_Duration = (bytes[2]-0x30)*10 + (bytes[3]-0x30); - //data.Unit = String.fromCharCode(bytes[4]); - } + // select only one below + // For NC (Normal Closed states) + data.Sensor1_Door_Contact_Open = bytes[2] === 0 ? "Door Closed" : "Door Open"; - else if ((bytes[0] === 0x59) && (bytes[1] === 0x53)) //Sampling interval or Heart-beat interval - { - data.Heart_Beat_interval = (bytes[2] - 0x30) * 10 + (bytes[3] - 0x30); - data.Heart_Beat_interval_unit = String.fromCharCode(bytes[4]); - //data.Wakeup_sampling_interval = (bytes[2]-0x30)*10 + (bytes[3]-0x30); - //data.Unit = String.fromCharCode(bytes[4]); - } - - else if (bytes[0] === 0x43) { // report current nvm config - data.mtm_code1 = bytes[1]; - data.mtm_code2 = bytes[2]; - data.sts_verion = bytes[3]; - data.sts_hw_ver = bytes[4]; - data.sts_uplink_interval = bytes[5]; - data.sts_uplink_interval_unit = String.fromCharCode(bytes[6]); - data.sts_sampling_interval = bytes[7]; - data.sts_sampling_interval_unit = String.fromCharCode(bytes[8]); - data.sts_work_mode = bytes[9]; - data.sts_service_mask = bytes[10]; - data.sts_reserve01 = bytes[11]; - data.sts_payload_length = bytes[12]; - data.rss_start_distance = bytes[13] * 0.1 + " meter"; - data.rss_range_length = bytes[14] * 0.1 + " meter"; - data.rss_threshold = bytes[15] * 0.1; - data.rss_receiving_gain = bytes[16] + " %"; - data.rss_profile = bytes[17]; - data.rss_rate_tracking = bytes[18]; - data.rss_rate_presence = bytes[19]; - data.rss_HWAAS = bytes[20]; - data.rss_nbr_removed_pc = bytes[21]; - data.rss_inter_frame_deviation_time_const = bytes[22] * 0.1; - data.rss_inter_frame_fast_cutoff = bytes[23]; - data.rss_inter_frame_slow_cutoff = bytes[24]; - data.rss_intra_frame_time_const = bytes[25]; - data.rss_intra_frame_weight = bytes[26] * 0.1; - data.rss_output_time_const = bytes[27] * 0.1; - data.rss_downsampling_factor = bytes[28]; - data.rss_power_saving_mode_active = bytes[29]; - data.rss_reserve02 = bytes[30]; - data.rss_reserve03 = bytes[31]; - data.rss_reserve04 = bytes[32]; - data.reserve2 = bytes[33]; - data.reserve3 = bytes[34]; - data.sensor_install_height = bytes[35] * 10 + " cm"; - - data.alarm_parameter05 = bytes[36]; - data.alarm_mute_expire_timer = bytes[37]; - data.alarm_lamp_bar_flashing_color = bytes[38]; - data.occupancy_overtime_threshold = bytes[39]; - - data.motionless_duration_threshold = bytes[40]; - data.unconcious_threshold = bytes[41]; - - data.fall_detection_acc_threshold = bytes[42]; - data.fall_detection_depth_threshold = bytes[43]; - data.fall_down_confirm_threshold = bytes[44]; - } - else if (bytes[0] === 0x53) { // SELF TEST FUNCTION - data.mtm_code1 = bytes[1]; - data.mtm_code2 = bytes[2]; - data.sts_verion = bytes[3]; - data.sts_hw_ver = bytes[4]; - data.battery_level = bytes[5]; - if ((bytes[6] === 0x03)) { // report sensor install height - data.sts_sensor_install_height = (bytes[7] << 8 | bytes[8]); - data.sts_sensor_install_height_unit = "mm"; - } - else if ((bytes[6] === 0x58)) { - data.sts_Test_Result = "### Motion Sensor Not Detected ###"; - } else if ((bytes[6] === 0x0E)) //result length, 10 rss bytes, 4 distance bytes + // For NC (Normal Closed states) + // data.Sensor1_Door_Contact_Open = bytes[3]===1?"Door Closed":"Door Open"; + if (bytes[1] == 0x02) //Hall_element_mode { - data.sts_Test_Result = "Motion Sensor Test Result:"; - data.sts_test_result_length = bytes[6]; - data.sts_rss_sub_code1 = bytes[7]; - data.sts_rss_sub_code2 = bytes[8]; - data.sts_rss_sub_code3 = bytes[9]; - data.sts_rss_sub_code4 = bytes[10]; - data.sts_rss_sub_code5 = bytes[11]; - data.sts_rss_sub_code6 = bytes[12]; - data.sts_rss_sub_code7 = bytes[13]; - data.sts_rss_sub_code8 = bytes[14]; - data.sts_rss_sub_code9 = bytes[15]; - data.sts_rss_sub_code10 = bytes[16]; - data.sts_sensor_install_height = String.fromCharCode(bytes[17]) + String.fromCharCode(bytes[18]) + String.fromCharCode(bytes[19]) + String.fromCharCode(bytes[20]) + " mm"; + data.Sensor2_SOS_Pushed = bytes[3] === 0 ? "PushDown" : "RelaseUP"; + } else if (bytes[1] > 0x02) { + data.Sensor2_Motion_Detected = bytes[3] === 0 ? "No Motion" : "Motion Detected"; } - } - else if (bytes[0] === 0x44) { // MEASURE INSTALLATION HEIGHT - data.mtm_code1 = bytes[1]; - data.mtm_code2 = bytes[2]; - data.sts_verion = bytes[3]; - data.sts_hw_ver = bytes[4]; - data.battery_level = bytes[5]; - data.payload_length = bytes[6]; - data.Measure_Distance = String.fromCharCode(bytes[7]) + String.fromCharCode(bytes[8]) + String.fromCharCode(bytes[9]) + String.fromCharCode(bytes[10]); - data.Distance_unit = "mm"; - } - else if (bytes[0] === 0x4c) { // LoRaWAN Class A/B/C - data.mtm_code1 = bytes[1]; - data.mtm_code2 = bytes[2]; - data.sts_verion = bytes[3]; - data.LoRaWAN_Class = String.fromCharCode(bytes[4]); - } - else if (bytes[0] === 0x56) { // FIRMWARE VERSION - data.mtm_code1 = bytes[1]; - data.mtm_code2 = bytes[2]; - data.sts_verion = bytes[3]; - data.sts_hw_ver = bytes[4]; - data.sts_major = bytes[5]; - data.sts_minor = bytes[6]; - data.subminor = bytes[7]; + return { "Yunhorn_SmarToilets_data": data }; + break; - if (data.length === 15) { - data.L_year = (bytes[8] << 8 | bytes[9]); - data.L_mon = bytes[10]; - data.L_day = bytes[11]; - data.L_hour = bytes[12]; - data.L_min = bytes[13]; - data.L_sec = bytes[14]; - data.LocalTime_UTC = "UTC: " + data.L_year + "/" + data.L_mon + "/" + data.L_day + " " + data.L_hour + ":" + data.L_min + ":" + data.L_sec; - data.LocalTime_EST8 = "GMT+8: " + data.L_year + "/" + data.L_mon + "/" + data.L_day + " " + (data.L_hour + 8) + ":" + data.L_min + ":" + data.L_sec; - } - } - else if (bytes[0] === 0x54) { //T: date & time - data.L_year = (bytes[1] << 8 | bytes[2]); - data.L_mon = bytes[3]; - data.L_day = bytes[4]; - data.L_hour = bytes[5]; - data.L_min = bytes[6]; - data.L_sec = bytes[7]; - data.LocalTime_UTC = "UTC: " + data.L_year + "/" + data.L_mon + "/" + data.L_day + " " + data.L_hour + ":" + data.L_min + ":" + data.L_sec; + // STS R5 waste bin + case 11: + data.LED_State = (bytes[0] === 0) ? "Off" : "On"; + data.mtm_code_1 = bytes[1]; + data.mtm_code_2 = bytes[2]; + data.hw_code = bytes[3]; + data.battery_level = bytes[4] + "%"; + // data.battery_level_mV = (bytes[4])*100 + " mV"; + data.size_value = bytes[5]; + data.distance_1_mm = bytes[6] << 8 | bytes[7]; + // data.distance_2_mm = bytes[8]<<8|bytes[9]; + // data.distance_3_mm = bytes[10]<<8|bytes[11]; + data.distance_unit = "mm"; + return { "Yunhorn_SmarToilets_data": data }; + break; - } - else if (bytes[0] === 0x50) { // P cmd report - if (data.length == 7) { - switch (bytes[3]) { - case 0x46: // F --- fall down & unconscious detection threshold - data.FALL_acceleration = (bytes[4] == 0x30 ? "Disabled" : ((bytes[4] - 0x30) * 10) + " mg/s2"); - data.FALL_depth_measure = (bytes[5] == 0x30 ? "Disabled" : ((bytes[5] - 0x30) * 10) + " cm"); - data.FALL_confirm_threshold = (bytes[6] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 10) + " seconds"); - //data.FALL_reserved = (bytes[7]==0x0?"Disabled":((bytes[6]-0x30)*10)+" min"); + // STS-M4 water flow sensor + case 12: + //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + //data.battery_level = bytes[1] + " %"; + data.battery_level = bytes[1] * 100 + "mV"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + // STS-M1A Water mark sensor thermal matrix + case 13: + break; + + // STS-M1A Water mark sensor thermal matrix, heart-beat + //case 14: + //break; + + + // STS-T6 O6T ToF Presence Detection + case 14: + data.LED_State = (bytes[0] & 0x7f === 0) ? "Off" : "On"; + data.MTM_Code_1 = bytes[1]; + data.MTM_Code_2 = bytes[2]; + data.HW_Code = bytes[3]; + data.Battery_Level = bytes[4] + " %"; + data.Payload_Size = bytes[5]; + data.Presence_State = (bytes[6] == 1) ? "Occupied" : "Vacant"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + // STS-T6 heart beat + case 15: + //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + //data.battery_level = bytes[1] + " %"; + data.battery_level = bytes[1] * 100 + "mV"; + return { "Yunhorn_SmarToilets_data": data }; + break; + // Multi-Function Sensor for Hong Kong HA.gov.hk + case 16: + data.LED_State = (bytes[0] & 0x7f === 0) ? "Off" : "On"; + data.MTM_Code_1 = bytes[1]; + data.MTM_Code_2 = bytes[2]; + data.HW_Code = bytes[3]; + data.Battery_Level = bytes[4] + " %"; + data.Payload_Size = bytes[5]; + //data.Presence_State = (bytes[6]==1)? "Occupied":"Vacant"; + data.MF_Fall = bytes[6]; + data.MF_Human_Movement = bytes[7]; + data.MF_Occupancy = bytes[8]; + data.MF_SOS_Alarm = bytes[9]; + return { "Yunhorn_SmarToilets_data": data }; + + break; + + case 18: + //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + //data.battery_level = bytes[1] + " %"; + data.battery_level = bytes[1] * 100 + "mV"; + return { "Yunhorn_SmarToilets_data": data }; + + break; + + // Heart-beat for STS-O6 occupancy sensor + case 17: + // STS-O7 Fall detection sensor + case 19: + case 21: + { + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + switch (bytes[1]) { + case 0x00: + data.LEDcolor = "Dark"; break; - } //switch + case 0x01: + data.LEDcolor = "Green"; + data.cubicleOccupyStatus = "Vacant"; + break; + case 0x02: + data.LEDcolor = "Red"; + data.cubicleOccupyStatus = "Occupied"; + break; + case 0x03: + data.LEDcolor = "Blue"; + data.cubicleOccupyStatus = "Maintenance"; + break; + case 0x04: + data.LEDcolor = "Yellow"; + data.cubicleOccupyStatus = "TBD"; + break; + case 0x05: + data.LEDcolor = "Pink"; + data.cubicleOccupyStatus = "TBD"; + break; + case 0x06: + data.LEDcolor = "Cyan"; + data.cubicleOccupyStatus = "TBD"; + break; + case 0x07: + data.LEDcolor = "White"; + data.cubicleOccupyStatus = "TBD"; + break; + case 0x08: + data.LEDcolor = "Red_Blue"; + data.cubicleOccupyStatus = "EMERGENCY"; + break; + case 0x23: + data.LEDcolor = "Red_Blue"; + data.cubicleOccupyStatus = "EMERGENCY"; + break; + case 0x20: + data.LEDcolor = "Red_Flash"; + data.cubicleOccupyStatus = "EMERGENCY"; + break; + default: + data.LEDcolor = "TBD_COLOR"; + data.cubicleOccupyStatus = "TBD_status"; + break; + } + + switch (bytes[2]) { + case 0x0: + data.workmode = "Network_mode"; + break; + case 0x01: + data.workmode = "Wired_Mode"; + break; + case 0x02: + data.workmode = "Hall_element_mode"; + break; + case 0x03: + data.workmode = "MotionDetect_mode"; + break; + case 0x04: + data.workmode = "Dual_mode"; + break; + case 0x05: + data.workmode = "Uni_Mode"; + break; + default: + data.workmode = "Unknown Mode"; + break; + } + // select only one below + // For NC(Normal Closed states + data.Sensor1_Door_Contact_Open = bytes[3] === 0 ? "Door Closed" : "Door Open"; + + // For NC(Normal Closed states + //data.Sensor1_Door_Contact_Open = bytes[3]===1?"Door Closed":"Door Open"; + data.Sensor2_Emergency_Button = bytes[4] === 0 ? "Alarm Push Down" : "No Alarm, Released"; + data.Sensor3_Motion_Detected = bytes[5] === 0 ? "No Motion" : "Motion Detected"; + + data.length = bytes.length; + if (data.length === 9) { + data.Over_stay_state = (bytes[6] === 0) ? "False" : "True"; + data.Over_Stay_duration_in_Seconds = (bytes[7] << 8 | bytes[8]); + + return { "Yunhorn_SmarToilets_data": data }; + } + else if (data.length > 9) { + data.Sensor4_ALARM_MUTE = (bytes[6] === 0) ? "Down Mute" : "No Mute"; + data.Sensor5_ALARM_RESET = (bytes[7] === 0) ? "Down RESET" : "NO Reset"; + data.Distance_in_mm = (bytes[8] << 8 | bytes[9]); + data.MotionLevel = (bytes[10] << 8 | bytes[11]); + + data.Unconcious_State = (bytes[12] == 0) ? "False" : "True"; + + switch (bytes[13]) { + case 0x0: + data.Fall_Down_Detected_State = "Presence_Normal"; + break; + case 0x01: + data.Fall_Down_Detected_State = "Presence_Fall_Down"; + break; + case 0x02: + data.Fall_Down_Detected_State = "Presence_Rising_Up"; + break; + case 0x03: + data.Fall_Down_Detected_State = "Presence_LayDown"; + break; + case 0x04: + data.Fall_Down_Detected_State = "Presence_Unconcious"; + break; + case 0x05: + data.Fall_Down_Detected_State = "Presence_Stay_Still"; + break; + default: + data.Fall_Down_Detected_State = "Presence_Normal"; + break; + } + data.OverStay_Detected_State = (bytes[14] == 0x0) ? "False" : "True"; + data.OverStay_Duration_in_Seconds = (bytes[15] << 8 | bytes[16]); + data.No_Movement_Duration_in_Seconds = (bytes[17] << 8 | bytes[18]); + data.Unconcious_Duration_in_Seconds = (bytes[17] << 8 | bytes[18]); + data.Fall_Down_Speed_in_m_per_s = (bytes[19]); + data.Fall_Down_Gravity_in_g = (bytes[20]); + data.SOS_PushDown_Stamp = (bytes[21] << 24 | bytes[22] << 16 | bytes[23] << 8 | bytes[24]); + if (data.SOS_PushDown_Stamp != 0) { + var sos_start = new Date(1000 * data.SOS_PushDown_Stamp); + data.SOS_PushDown_Time = "[" + sos_start.getDate() + "." + (sos_start.getMonth() + 1) + "." + (sos_start.getFullYear()) + "] " + sos_start.getHours() + ":" + sos_start.getMinutes() + ":" + sos_start.getSeconds(); + } else data.SOS_PushDown_Time = "N/A"; + data.SOS_ReleaseUP_Stamp = (bytes[25] << 24 | bytes[26] << 16 | bytes[27] << 8 | bytes[28]); + if (data.SOS_ReleaseUP_Stamp != 0) { + var sos_stop = new Date(1000 * data.SOS_ReleaseUP_Stamp); + data.SOS_ReleaseUP_Time = "[" + sos_stop.getDate() + "." + (sos_stop.getMonth() + 1) + "." + (sos_stop.getFullYear()) + "] " + sos_stop.getHours() + ":" + sos_stop.getMinutes() + ":" + sos_stop.getSeconds(); + } else data.SOS_ReleaseUP_Time = "N/A"; + + data.Fall_Down_Stamp = (bytes[29] << 24 | bytes[30] << 16 | bytes[31] << 8 | bytes[32]); + if (data.Fall_Down_Stamp != 0) { + var fall_start = new Date(1000 * data.Fall_Down_Stamp); + data.Fall_Down_Time = "[" + fall_start.getDate() + "." + (fall_start.getMonth() + 1) + "." + (fall_start.getFullYear()) + "] " + fall_start.getHours() + ":" + fall_start.getMinutes() + ":" + fall_start.getSeconds(); + } else data.Fall_RiseUp_Stamp = "N/A"; + data.Fall_RiseUp_Stamp = (bytes[33] << 24 | bytes[34] << 16 | bytes[35] << 8 | bytes[36]); + if (data.Fall_RiseUp_Stamp != 0) { + var fall_stop = new Date(1000 * data.Fall_RiseUp_Stamp); + data.Fall_RiseUp_Time = "[" + fall_stop.getDate() + "." + (fall_stop.getMonth() + 1) + "." + (fall_stop.getFullYear()) + "] " + fall_stop.getHours() + ":" + fall_stop.getMinutes() + ":" + fall_stop.getSeconds(); + } else data.Fall_RiseUp_Time = "N/A"; + } + return { "Yunhorn_SmarToilets_data": data }; } - else if (data.length == 8) { - switch (bytes[3]) { - case 0x4f: // O -- over stay, onconscious, long stay - data.OMU_Motionless_duration_in_min = (bytes[4] == 0x30 ? "Disabled" : ((bytes[4] - 0x30)) + " Min"); - data.OMU_Long_Occupy_duration_in_Min = (bytes[5] == 0x30 ? "Disabled" : ((bytes[5] - 0x30) * 10) + " Min"); - data.OMU_Unconcious_Threshold = (bytes[6] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 100) + "ml"); - data.OMU_Alarm_Mute_Reset_Timer = (bytes[7] == 0x30 ? "Disabled" : ((bytes[7] - 0x30) * 10) + " Seconds"); - break; - case 0x46: // F --- fall down & unconscious detection threshold - data.FALL_acceleration = (bytes[4] == 0x30 ? "Disabled" : ((bytes[4] - 0x30) * 10) + " mg/s2"); - data.FALL_depth_measure = (bytes[5] == 0x30 ? "Disabled" : ((bytes[5] - 0x30) * 10) + " cm"); - data.FALL_confirm_threshold = (bytes[6] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 10) + " seconds"); - data.FALL_reserved = (bytes[7] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 10) + " min"); - break; - } //switch - } else if (data.length == 11) { // P 1108201365 - data.RSS_SIMPLE_Start = ((bytes[3] - 0x30) * 100 + (bytes[4] - 0x30) * 10) + " cm"; - data.RSS_SIMPLE_Length = ((bytes[5] - 0x30) * 100 + (bytes[6] - 0x030) * 10) + " cm"; - data.RSS_SIMPLE_Threshold = ((bytes[7] - 0x30) * 1000 + (bytes[8] - 0x30) * 100) + " ml"; - data.RSS_SIMPLE_Gain = ((bytes[9] - 0x30) * 10 + (bytes[10] - 0x30)) + " %"; - } else if (data.length == 33) { // P 11 - data.RSS_FULL_Start = ((bytes[3] - 0x30) * 100 + (bytes[4] - 0x30) * 10) + " cm"; - data.RSS_FULL_Length = ((bytes[5] - 0x30) * 100 + (bytes[6] - 0x30) * 10) + " cm"; - data.RSS_FULL_Threshold = ((bytes[7] - 0x30) * 1000 + (bytes[8] - 0x30) * 100) + " ml"; - data.RSS_FULL_Gain = ((bytes[9] - 0x30) * 10 + (bytes[10] - 0x30)) + " %"; - data.RSS_FULL_Profile = (bytes[11] - 0x30); - data.RSS_FULL_Rate_Tracking = ((bytes[12] - 0x30) * 10 + (bytes[13] - 0x30)); - data.RSS_FULL_Rate_Presence = ((bytes[14] - 0x30) * 10 + (bytes[15] - 0x30)); - data.RSS_FULL_HWAAS = ((bytes[16] - 0x30) * 10 + (bytes[17] - 0x30)); - data.RSS_FULL_Num_Removed_PC = (bytes[18] - 0x30); - data.RSS_FULL_Inter_Deviation_Time_Const_in_Sec = ((bytes[19] - 0x30) + (bytes[20] - 0x30) * 0.1); - data.RSS_FULL_Inter_Fast_Cut_Off = ((bytes[21] - 0x30) * 10 + (bytes[22] - 0x30)); - data.RSS_FULL_Inter_Slow_Cut_Off = ((bytes[23] - 0x30) * 0.1 + (bytes[24] - 0x30) * 0.001); - data.RSS_FULL_Inter_Time_Const_in_Sec = ((bytes[25] - 0x30) * 10 + (bytes[26] - 0x30)); - data.RSS_FULL_Inter_Weight = ((bytes[27] - 0x30) + (bytes[28] - 0x30) * 0.1); - data.RSS_FULL_Output_Time_Const_in_Sec = ((bytes[29] - 0x30) + (bytes[30] - 0x30) * 0.1); - data.RSS_FULL_DownSampling_factor = (bytes[31] - 0x30); - data.RSS_FULL_Power_Saving_mode = (bytes[32] - 0x30); + + + break; + + + break; + + // STS-O6 occupancy sensor heart-beat + case 18: + //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + //data.battery_level = bytes[1] + " %"; + data.battery_level = bytes[1] * 100 + "mV"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + // STS-O7 Fall detection sensor heart-beat + case 20: + break; + + // STS-M7 Vibration sensor + case 20: + break; + + // STS-R6 Weight Scale Sensor + case 27: + data.LED_State = (bytes[0] & 0x7f === 0) ? "Off" : "On"; + data.MTM_Code_1 = bytes[1]; + data.MTM_Code_2 = bytes[2]; + data.HW_Code = bytes[3]; + data.Battery_Level = bytes[4] + " %"; + data.Payload_Size = bytes[5]; + data.Weight_g = (bytes[6] << 8 | bytes[7]); + data.Tare_g = (bytes[8] << 8 | bytes[9]); + return { "Yunhorn_SmarToilets_data": data }; + break; + + + + // STS R3 Soap Yes_No sensor + case 51: + data.LED_State = (bytes[0] === 0) ? "Off" : "On"; + data.mtm_code_1 = bytes[1]; + data.mtm_code_2 = bytes[2]; + data.hw_code = bytes[3]; + data.battery_level = bytes[4] + "%"; + // data.battery_level_mV = (bytes[4])*100 + " mV"; + data.size_value = bytes[5]; + data.Liquid_detected = bytes[6]; + data.Detect_method = (bytes[7] === 0) ? "Capacitive" : "ToF"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + // STS R2 Tissue paper sensor + case 52: + data.LED_State = (bytes[0] === 0) ? "Off" : "On"; + data.mtm_code_1 = bytes[1]; + data.mtm_code_2 = bytes[2]; + data.hw_code = bytes[3]; + data.battery_level = bytes[4] + "%"; + // data.battery_level_mV = (bytes[4])*100 + " mV"; + data.size_value = bytes[5]; + data.distance_1_mm = bytes[6] << 8 | bytes[7]; + // data.distance_2_mm = bytes[8]<<8|bytes[9]; + // data.distance_3_mm = bytes[10]<<8|bytes[11]; + data.distance_unit = "mm"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + + // STS-M8 QUEUE BAR SENSOR + case 55: + + // STS-O4 URINAL OCCUPANCY SENSOR + case 56: + + break; + + // R1D dual roll toilet paper sensor + case 57: + data.LED_State = (bytes[0] === 0) ? "Off" : "On"; + data.mtm_code_1 = bytes[1]; + data.mtm_code_2 = bytes[2]; + data.hw_code = bytes[3]; + data.battery_level = bytes[4] + "%"; + //data.battery_level_mV = (bytes[4])*100 + " mV"; + data.size_value = bytes[5]; + data.distance_1_mm = bytes[6] << 8 | bytes[7]; + data.distance_2_mm = bytes[8] << 8 | bytes[9]; + // data.distance_3_mm = bytes[10]<<8|bytes[11]; + data.distance_unit = "mm"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + // STS-R1 Single roll toilet paper sensor + case 58: + data.LED_State = (bytes[0] === 0) ? "Off" : "On"; + //data.mtm_code_1 = bytes[1]; + //data.mtm_code_2 = bytes[2]; + //data.hw_code = bytes[3]; + //data.battery_level = bytes[1]+"%"; + data.battery_level_mV = (bytes[1]) * 100 + " mV"; + //data.size_value = bytes[5]; + //data.distance_1_mm = bytes[6]<<8|bytes[7]; + //data.distance_2_mm = bytes[8]<<8|bytes[9]; + // data.distance_3_mm = bytes[10]<<8|bytes[11]; + //data.distance_unit = "mm"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + + // STS-M2 TOILET CLOGGING SENSOR + case 59: + + break; + + + // STS-E4 PTAQ, ODOR LEVEL Sensor 4-IN-1 + case 70: + + break; + + // STS-E6 PTAQ, ODOR LEVEL Sensor 6-IN-1 + case 72: + + break; + + // STS-E5 PTAQ, ODOR LEVEL Sensor 5-IN-1 + case 74: + + break; + + + // STS-E2 PTAQ, ODOR LEVEL Sensor + case 101: + + break; + + // STS-E1 Smoking Sensor + case 102: + + break; + + // STS-P1 QUEUEING SENSOR + case 104: + + break; + + // STS-M6 POWER RELAY SENSOR + case 105: + break; + + // STS-P2 IN-OUT PEOPLE COUNTING SENSOR + case 106: + { + var counting = {}; + var counting_today = {}; + // STS-P2 bi-directional people counting + data.LED_State = bytes[0] === 0 ? "Off" : "On"; + data.MTM_Code_1 = bytes[1]; + data.MTM_Code_2 = bytes[2]; + data.HW_Code = bytes[3]; + data.Battery_Level = bytes[4] + " %"; + data.Payload_Size = bytes[5]; + //data.Walk_In_People_Count = bytes[6] << 8 | bytes[7]; + //data.Walk_Out_People_Count = bytes[8] << 8 | bytes[9]; + //data.Walk_Around_People_Count = bytes[10] << 8 | bytes[11]; + counting.Walk_In_People_Count = bytes[6] << 8 | bytes[7]; + counting.Walk_Out_People_Count = bytes[8] << 8 | bytes[9]; + counting.Walk_Around_People_Count = bytes[10] << 8 | bytes[11]; + + data.Count_Period = bytes[12]; + data.Count_Period_Unit = String.fromCharCode(bytes[13]); + + //data.Sum_Day_Walk_In_People_Count = bytes[14] << 8 | bytes[15]; + //data.Sum_Day_Walk_Out_People_Count = bytes[16] << 8 | bytes[17]; + //data.Sum_Day_Walk_Around_People_Count = bytes[18] << 8 | bytes[19]; + counting_today.Sum_Day_Walk_In_People_Count = bytes[14] << 8 | bytes[15]; + counting_today.Sum_Day_Walk_Out_People_Count = bytes[16] << 8 | bytes[17]; + counting_today.Sum_Day_Walk_Around_People_Count = bytes[18] << 8 | bytes[19]; + + data.Count_Valid = (bytes[20] == 0x0) ? "Error" : "OK"; + + return { "Yunhorn_SmarToilets_data": data, "Couting_Now": counting, "Counting_today": counting_today }; } - } - return { "Yunhorn_SmarToilets_data": data }; + break; + + // HEART-BEAT FOR STS-P2 IN-OUT PEOPLE COUNTING SENSOR + case 107: + //data.led_state=(bytes[0] & 0x7f) === 0 ? "Off" : "On"; + data.BoardLED = ((bytes[0] & 0x7F) === 0x01) ? "ON" : "OFF"; + //data.battery_level = bytes[1] + " %"; + data.battery_level = bytes[1] * 100 + "mV"; + return { "Yunhorn_SmarToilets_data": data }; + break; + + + // respond port + case 1: + switch (bytes[0]) { + // NVM config 'C' + case 0x43: + // report current nvm config + data.mtm_code1 = bytes[1]; + data.mtm_code2 = bytes[2]; + data.sts_verion = bytes[3]; + data.sts_hw_ver = bytes[4]; + data.sts_uplink_interval = bytes[5]; + data.sts_uplink_interval_unit = String.fromCharCode(bytes[6]); + data.sts_sampling_interval = bytes[7]; + data.sts_sampling_interval_unit = String.fromCharCode(bytes[8]); + data.sts_work_mode = bytes[9]; + data.sts_service_mask = bytes[10]; + data.sts_reserve01 = bytes[11]; + data.sts_payload_length = bytes[12]; + data.rss_start_distance = bytes[13] * 0.1 + " meter"; + data.rss_range_length = bytes[14] * 0.1 + " meter"; + data.rss_threshold = bytes[15] * 0.1; + data.rss_receiving_gain = bytes[16] + " %"; + data.rss_profile = bytes[17]; + data.rss_rate_tracking = bytes[18]; + data.rss_rate_presence = bytes[19]; + data.rss_HWAAS = bytes[20]; + data.rss_nbr_removed_pc = bytes[21]; + data.rss_inter_frame_deviation_time_const = bytes[22] * 0.1; + data.rss_inter_frame_fast_cutoff = bytes[23]; + data.rss_inter_frame_slow_cutoff = bytes[24]; + data.rss_intra_frame_time_const = bytes[25]; + data.rss_intra_frame_weight = bytes[26] * 0.1; + data.rss_output_time_const = bytes[27] * 0.1; + data.rss_downsampling_factor = bytes[28]; + data.rss_power_saving_mode_active = bytes[29]; + data.rss_reserve02 = bytes[30]; + data.rss_reserve03 = bytes[31]; + data.rss_reserve04 = bytes[32]; + data.reserve2 = bytes[33]; + data.reserve3 = bytes[34]; + data.sensor_install_height = bytes[35] * 10 + " cm"; + + data.alarm_parameter05 = bytes[36]; + data.alarm_mute_expire_timer = bytes[37]; + data.alarm_lamp_bar_flashing_color = bytes[38]; + data.occupancy_overtime_threshold = bytes[39]; + + data.motionless_duration_threshold = bytes[40]; + data.unconcious_threshold = bytes[41]; + + data.fall_detection_acc_threshold = bytes[42]; + data.fall_detection_depth_threshold = bytes[43]; + data.fall_down_confirm_threshold = bytes[44]; + + break; + + // D DISTANCE , INSTALLATION HEIGHT REPORT + case 0x44: + // MEASURE INSTALLATION HEIGHT + data.mtm_code1 = bytes[1]; + data.mtm_code2 = bytes[2]; + data.sts_verion = bytes[3]; + data.sts_hw_ver = bytes[4]; + data.battery_level = bytes[5]; + data.payload_length = bytes[6]; + //data.Measure_Distance = String.fromCharCode(bytes[7]) + String.fromCharCode(bytes[8]) + String.fromCharCode(bytes[9]) + String.fromCharCode(bytes[10]); + // update on 2024-11-02 + data.Measure_Distance = bytes[7] << 8 | bytes[8]; + data.Distance_unit = "mm"; + + break; + + // LoRa Class 'L' + case 0x4c: + // LoRaWAN Class A/B/C + data.mtm_code1 = bytes[1]; + data.mtm_code2 = bytes[2]; + data.sts_verion = bytes[3]; + data.LoRaWAN_Class = String.fromCharCode(bytes[4]); + break; + + // M 'M' for STS-P2 LOG DATA + case 0x4D: + data.sum_day_in = bytes[1] | bytes[2] << 8; + data.sum_day_out = bytes[3] | bytes[4] << 8; + data.sum_day_around = bytes[5] | bytes[6] << 8; + + data.sum_week_in = bytes[7] | bytes[8] << 8; + data.sum_week_out = bytes[9] | bytes[10] << 8; + data.sum_week_around = bytes[11] | bytes[12] << 8; + + data.sum_month_in = bytes[13] | bytes[14] << 8; + data.sum_month_out = bytes[15] | bytes[16] << 8; + data.sum_month_around = bytes[17] | bytes[18] << 8; + + data.sum_year_in = bytes[19] | bytes[20] << 8; + data.sum_year_out = bytes[21] | bytes[22] << 8; + data.sum_year_around = bytes[23] | bytes[24] << 8; + + data.sum_lifeCycle_in = bytes[25] | bytes[26] << 8; + data.sum_lifeCycle_out = bytes[27] | bytes[28] << 8; + data.sum_lifeCycle_around = bytes[29] | bytes[30] << 8; + + break; + // CONTROL COMMAND 'P' + case 0x50: + // P-CMD work mode change + switch (data.length) { + case 4: + if ((data.length === 4) && (bytes[1] === 0x31) && (bytes[2] === 0x31)) { + data.Work_Mode_Switch = "OK"; + switch (bytes[3] - 0x30) { + case 0x0: + data.workmode = "Network_mode"; + break; + case 0x01: + data.workmode = "Wired_Mode"; + break; + case 0x02: + data.workmode = "Hall_element_mode"; + break; + case 0x03: + data.workmode = "MotionDetect_mode"; + break; + case 0x04: + data.workmode = "Dual_mode"; + break; + case 0x05: + data.workmode = "Uni_Mode"; + break; + default: + data.workmode = "Unknown Mode"; + break; + } + } + + break; + case 7: + if (bytes[3] === 0x46) { + // F --- fall down & unconscious detection threshold + data.FALL_acceleration = (bytes[4] == 0x30 ? "Disabled" : ((bytes[4] - 0x30) * 10) + " mg/s2"); + data.FALL_depth_measure = (bytes[5] == 0x30 ? "Disabled" : ((bytes[5] - 0x30) * 10) + " cm"); + data.FALL_confirm_threshold = (bytes[6] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 10) + " seconds"); + //data.FALL_reserved = (bytes[7]==0x0?"Disabled":((bytes[6]-0x30)*10)+" min"); + + } + + break; + case 8: + if (bytes[3] === 0x4f) { + // O -- over stay, onconscious, long stay + data.OMU_Motionless_duration_in_min = (bytes[4] == 0x30 ? "Disabled" : ((bytes[4] - 0x30)) + " Min"); + data.OMU_Long_Occupy_duration_in_Min = (bytes[5] == 0x30 ? "Disabled" : ((bytes[5] - 0x30) * 10) + " Min"); + data.OMU_Unconcious_Threshold = (bytes[6] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 100) + "ml"); + data.OMU_Alarm_Mute_Reset_Timer = (bytes[7] == 0x30 ? "Disabled" : ((bytes[7] - 0x30) * 10) + " Seconds"); + } else if (bytes[3] === 0x46) { + // F --- fall down & unconscious detection threshold + data.FALL_acceleration = (bytes[4] == 0x30 ? "Disabled" : ((bytes[4] - 0x30) * 10) + " mg/s2"); + data.FALL_depth_measure = (bytes[5] == 0x30 ? "Disabled" : ((bytes[5] - 0x30) * 10) + " cm"); + data.FALL_confirm_threshold = (bytes[6] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 10) + " seconds"); + data.FALL_reserved = (bytes[7] == 0x30 ? "Disabled" : ((bytes[6] - 0x30) * 10) + " min"); + } + break; + case 11: + // P 1108201365 + data.RSS_SIMPLE_Start = ((bytes[3] - 0x30) * 100 + (bytes[4] - 0x30) * 10) + " cm"; + data.RSS_SIMPLE_Length = ((bytes[5] - 0x30) * 100 + (bytes[6] - 0x030) * 10) + " cm"; + data.RSS_SIMPLE_Threshold = ((bytes[7] - 0x30) * 1000 + (bytes[8] - 0x30) * 100) + " ml"; + data.RSS_SIMPLE_Gain = ((bytes[9] - 0x30) * 10 + (bytes[10] - 0x30)) + " %"; + break; + case 33: + // P 11 + data.RSS_FULL_Start = ((bytes[3] - 0x30) * 100 + (bytes[4] - 0x30) * 10) + " cm"; + data.RSS_FULL_Length = ((bytes[5] - 0x30) * 100 + (bytes[6] - 0x30) * 10) + " cm"; + data.RSS_FULL_Threshold = ((bytes[7] - 0x30) * 1000 + (bytes[8] - 0x30) * 100) + " ml"; + data.RSS_FULL_Gain = ((bytes[9] - 0x30) * 10 + (bytes[10] - 0x30)) + " %"; + data.RSS_FULL_Profile = (bytes[11] - 0x30); + data.RSS_FULL_Rate_Tracking = ((bytes[12] - 0x30) * 10 + (bytes[13] - 0x30)); + data.RSS_FULL_Rate_Presence = ((bytes[14] - 0x30) * 10 + (bytes[15] - 0x30)); + data.RSS_FULL_HWAAS = ((bytes[16] - 0x30) * 10 + (bytes[17] - 0x30)); + data.RSS_FULL_Num_Removed_PC = (bytes[18] - 0x30); + data.RSS_FULL_Inter_Deviation_Time_Const_in_Sec = ((bytes[19] - 0x30) + (bytes[20] - 0x30) * 0.1); + data.RSS_FULL_Inter_Fast_Cut_Off = ((bytes[21] - 0x30) * 10 + (bytes[22] - 0x30)); + data.RSS_FULL_Inter_Slow_Cut_Off = ((bytes[23] - 0x30) * 0.1 + (bytes[24] - 0x30) * 0.001); + data.RSS_FULL_Inter_Time_Const_in_Sec = ((bytes[25] - 0x30) * 10 + (bytes[26] - 0x30)); + data.RSS_FULL_Inter_Weight = ((bytes[27] - 0x30) + (bytes[28] - 0x30) * 0.1); + data.RSS_FULL_Output_Time_Const_in_Sec = ((bytes[29] - 0x30) + (bytes[30] - 0x30) * 0.1); + data.RSS_FULL_DownSampling_factor = (bytes[31] - 0x30); + data.RSS_FULL_Power_Saving_mode = (bytes[32] - 0x30); + + break; + + default: + break; + + } + + + break; + + // CONTROL COMMAND 'R' + case 0x52: + if (bytes[1] === 0x46) { + data.RFAC_Process_Request = "OK"; + data.RFAC_Req = String.fromCharCode(bytes); + } + break; + + + // Self-Test function 'S' + case 0x53: + // SELF TEST FUNCTION + data.mtm_code1 = bytes[1]; + data.mtm_code2 = bytes[2]; + data.sts_verion = bytes[3]; + data.sts_hw_ver = bytes[4]; + data.battery_level = bytes[5]; + if ((bytes[6] === 0x04)) { // report sensor install height + data.sts_sensor_chip_model_type_ID = (bytes[7] << 8 | bytes[8]); + if ((bytes[7] === 0xF0) && (bytes[8] === 0x0C)) { + data.sts_sensor_chip_model_type = "VL53L8X"; + } + else if ((bytes[7] === 0xEA) & (bytes[8] === 0xCC)) { + data.sts_sensor_chip_model_type = "VL53L1X"; + } + else if ((bytes[7] === 0xEE) & (bytes[8] === 0xAA)) { + data.sts_sensor_chip_model_type = "VL53L0X"; + } + + data.sts_sensor_install_height = (bytes[9] << 8 | bytes[10]); + data.sts_sensor_install_height_unit = "mm"; + } + else if ((bytes[6] === 0x58)) { + data.sts_Test_Result = "### Motion Sensor Not Detected ###"; + } else if ((bytes[6] === 0x0E)) //result length, 10 rss bytes, 4 distance bytes + { + data.sts_Test_Result = "Motion Sensor Test Result:"; + data.sts_test_result_length = bytes[6]; + data.sts_rss_sub_code1 = bytes[7]; + data.sts_rss_sub_code2 = bytes[8]; + data.sts_rss_sub_code3 = bytes[9]; + data.sts_rss_sub_code4 = bytes[10]; + data.sts_rss_sub_code5 = bytes[11]; + data.sts_rss_sub_code6 = bytes[12]; + data.sts_rss_sub_code7 = bytes[13]; + data.sts_rss_sub_code8 = bytes[14]; + data.sts_rss_sub_code9 = bytes[15]; + data.sts_rss_sub_code10 = bytes[16]; + data.sts_sensor_install_height = String.fromCharCode(bytes[17]) + String.fromCharCode(bytes[18]) + String.fromCharCode(bytes[19]) + String.fromCharCode(bytes[20]) + " mm"; + } + + break; + + case 0x54: + //T: date & time + data.L_year = (bytes[1] << 8 | bytes[2]); + data.L_mon = bytes[3]; + data.L_day = bytes[4]; + data.L_hour = bytes[5]; + data.L_min = bytes[6]; + data.L_sec = bytes[7]; + data.LocalTime_UTC = "UTC: " + data.L_year + "/" + data.L_mon + "/" + data.L_day + " " + data.L_hour + ":" + data.L_min + ":" + data.L_sec; + + break; + + + // Firmware version 'V' + case 0x56: + // FIRMWARE VERSION + + data.mtm_code1 = bytes[1]; + data.mtm_code2 = bytes[2]; + data.sts_verion = bytes[3]; + data.sts_hw_ver = bytes[4]; + data.sts_major = bytes[5]; + data.sts_minor = bytes[6]; + data.subminor = bytes[7]; + + if (data.length === 15) { + data.L_year = (bytes[8] << 8 | bytes[9]); + data.L_mon = bytes[10]; + data.L_day = bytes[11]; + data.L_hour = bytes[12]; + data.L_min = bytes[13]; + data.L_sec = bytes[14]; + data.LocalTime_UTC = "UTC: " + data.L_year + "/" + data.L_mon + "/" + data.L_day + " " + data.L_hour + ":" + data.L_min + ":" + data.L_sec; + data.LocalTime_EST8 = "GMT+8: " + data.L_year + "/" + data.L_mon + "/" + data.L_day + " " + (data.L_hour + 8) + ":" + data.L_min + ":" + data.L_sec; + } + break; + + // Respond 'Y' + case 0x59: + + switch (bytes[1]) { + // Uplink Duration interval + case 0x44: + data.Uplink_interval = (bytes[2] - 0x30) * 10 + (bytes[3] - 0x30); + data.Uplink_interval_unit = String.fromCharCode(bytes[4]); + break; + + // Sampling interval or Heart-beat interval, 'YSaab', 'YLaab' + case 0x4C: + case 0x53: + data.Heart_Beat_interval = (bytes[2] - 0x30) * 10 + (bytes[3] - 0x30); + data.Heart_Beat_interval_unit = String.fromCharCode(bytes[4]); + // if sts_mtm1 == O6/O7 ....TODO XXXX + // data.Wakeup_sampling_interval = (bytes[2]-0x30)*10 + (bytes[3]-0x30); + // data.Unit = String.fromCharCode(bytes[4]); + break; + + } + + if (bytes[9] == 0x38) { + data.Yunhorn_PRD = "True"; + data.PRD_String = String.fromCharCode(bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], bytes[16]); + } + + break; + + + default: + break; + + } + switch (data.length) { + // RFAC process + case 4: + if ((bytes[0] == 0x52) && (bytes[1] == 0x46)) { + data.RFAC_Process_Request = "OK"; + data.RFAC_Req = String.fromCharCode(bytes); + } else { + if ((bytes[0] === 0x50) && (bytes[1] === 0x31) && (bytes[2] === 0x31)) { + data.Work_Mode_Switch = "OK"; + switch (bytes[3] - 0x30) { + case 0x0: + data.workmode = "Network_mode"; + break; + case 0x01: + data.workmode = "Wired_Mode"; + break; + case 0x02: + data.workmode = "Hall_element_mode"; + break; + case 0x03: + data.workmode = "MotionDetect_mode"; + break; + case 0x04: + data.workmode = "Dual_mode"; + break; + case 0x05: + data.workmode = "Uni_Mode"; + break; + default: + data.workmode = "Unknown Mode"; + break; + } + } else if ((bytes[0] === 0x59) && (bytes[1] === 0x44)) //Duration interval + { + data.Uplink_interval = (bytes[2] - 0x30) * 10 + (bytes[3] - 0x30); + data.Uplink_interval_unit = String.fromCharCode(bytes[4]); + //data.Heart_beat_Duration = (bytes[2]-0x30)*10 + (bytes[3]-0x30); + //data.Unit = String.fromCharCode(bytes[4]); + } else if ((bytes[0] === 0x59) && (bytes[1] === 0x53)) //Sampling interval or Heart-beat interval + { + data.Heart_Beat_interval = (bytes[2] - 0x30) * 10 + (bytes[3] - 0x30); + data.Heart_Beat_interval_unit = String.fromCharCode(bytes[4]); + //data.Wakeup_sampling_interval = (bytes[2]-0x30)*10 + (bytes[3]-0x30); + //data.Unit = String.fromCharCode(bytes[4]); + } + } + break; + + // YUNHORN PRD MARK + case 10: + if ((bytes[0] == 0x59) && (bytes[9] == 0x38)) + data.Yunhorn_PRD = "True"; + data.PRD_String = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6]); + break; + + // YUNHORN NVM CONFIG LENGTH + case 44: + if (bytes[0] === 0x43) { // report current nvm config + data.mtm_code1 = bytes[1]; + data.mtm_code2 = bytes[2]; + data.sts_verion = bytes[3]; + data.sts_hw_ver = bytes[4]; + data.sts_uplink_interval = bytes[5]; + data.sts_uplink_interval_unit = String.fromCharCode(bytes[6]); + data.sts_sampling_interval = bytes[7]; + data.sts_sampling_interval_unit = String.fromCharCode(bytes[8]); + data.sts_work_mode = bytes[9]; + data.sts_service_mask = bytes[10]; + data.sts_reserve01 = bytes[11]; + data.sts_payload_length = bytes[12]; + data.rss_start_distance = bytes[13] * 0.1 + " meter"; + data.rss_range_length = bytes[14] * 0.1 + " meter"; + data.rss_threshold = bytes[15] * 0.1; + data.rss_receiving_gain = bytes[16] + " %"; + data.rss_profile = bytes[17]; + data.rss_rate_tracking = bytes[18]; + data.rss_rate_presence = bytes[19]; + data.rss_HWAAS = bytes[20]; + data.rss_nbr_removed_pc = bytes[21]; + data.rss_inter_frame_deviation_time_const = bytes[22] * 0.1; + data.rss_inter_frame_fast_cutoff = bytes[23]; + data.rss_inter_frame_slow_cutoff = bytes[24]; + data.rss_intra_frame_time_const = bytes[25]; + data.rss_intra_frame_weight = bytes[26] * 0.1; + data.rss_output_time_const = bytes[27] * 0.1; + data.rss_downsampling_factor = bytes[28]; + data.rss_power_saving_mode_active = bytes[29]; + data.rss_reserve02 = bytes[30]; + data.rss_reserve03 = bytes[31]; + data.rss_reserve04 = bytes[32]; + data.reserve2 = bytes[33]; + data.reserve3 = bytes[34]; + data.sensor_install_height = bytes[35] * 10 + " cm"; + + data.alarm_parameter05 = bytes[36]; + data.alarm_mute_expire_timer = bytes[37]; + data.alarm_lamp_bar_flashing_color = bytes[38]; + data.occupancy_overtime_threshold = bytes[39]; + + data.motionless_duration_threshold = bytes[40]; + data.unconcious_threshold = bytes[41]; + + data.fall_detection_acc_threshold = bytes[42]; + data.fall_detection_depth_threshold = bytes[43]; + data.fall_down_confirm_threshold = bytes[44]; + } + + break; + default: + break; + + } + } -} \ No newline at end of file + return { "Yunhorn_SmarToilets_data": data }; + +} + +// +// Yunhorn SmarToilets Sensor Decoder +//