From 43dbe5587c2e56aa9e164d0e89dff1cde1d59338 Mon Sep 17 00:00:00 2001 From: Mateus Henrique Date: Fri, 7 Jun 2024 12:19:57 -0300 Subject: [PATCH] feat/connectors-robeau-tektelic (#11) * chore: Update schema for connector_details.json * feat: Add Robeau/Tektelic sensor decoders * Added fake image for no break the schema * chore: Update biome.jsonc to ignore specific decoder files --- .../connector/robeau/robeau/assets/logo.png | Bin 0 -> 44317 bytes .../connector/robeau/robeau/connector.jsonc | 13 + .../connector/robeau/robeau/description.md | 1 + .../robeau/robeau/v1.0.0/payload-config.jsonc | 98 +++ .../connector/robeau/robeau/v1.0.0/payload.js | 121 +++ .../tektelic/asset-tracker/assets/logo.png | Bin 0 -> 11884 bytes .../tektelic/asset-tracker/connector.jsonc | 13 + .../tektelic/asset-tracker/description.md | 1 + .../asset-tracker/v1.0.0/payload-config.jsonc | 25 + .../tektelic/asset-tracker/v1.0.0/payload.js | 623 +++++++++++++ .../assets/logo.png | 0 .../connector.jsonc | 13 + .../description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../v1.0.0/payload.js | 118 +++ .../clover-agriculture-sensor/assets/logo.png | Bin 0 -> 11970 bytes .../clover-agriculture-sensor/connector.jsonc | 13 + .../clover-agriculture-sensor/description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../v1.0.0/payload.js | 146 ++++ .../assets/logo.png | Bin 0 -> 13686 bytes .../connector.jsonc | 13 + .../description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../v1.0.0/payload.js | 623 +++++++++++++ .../tektelic/cold-room/assets/logo.png | Bin 0 -> 16182 bytes .../tektelic/cold-room/connector.jsonc | 13 + .../tektelic/cold-room/description.md | 1 + .../cold-room/v1.0.0/payload-config.jsonc | 25 + .../tektelic/cold-room/v1.0.0/payload.js | 188 ++++ .../finch-indoor-panic-button/assets/logo.png | Bin 0 -> 7996 bytes .../finch-indoor-panic-button/connector.jsonc | 13 + .../finch-indoor-panic-button/description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../v1.0.0/payload.js | 111 +++ .../flux-smart-ac-outlet/assets/logo.png | Bin 0 -> 46022 bytes .../flux-smart-ac-outlet/connector.jsonc | 13 + .../flux-smart-ac-outlet/description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../flux-smart-ac-outlet/v1.0.0/payload.js | 146 ++++ .../industrial-transceiver/assets/logo.png | Bin 0 -> 14300 bytes .../industrial-transceiver/connector.jsonc | 13 + .../industrial-transceiver/description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../industrial-transceiver/v1.0.0/payload.js | 105 +++ .../mulch-temperature-sensor/assets/logo.png | Bin 0 -> 27497 bytes .../mulch-temperature-sensor/connector.jsonc | 13 + .../mulch-temperature-sensor/description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../v1.0.0/payload.js | 108 +++ .../assets/logo.png | Bin 0 -> 22308 bytes .../connector.jsonc | 13 + .../description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../v1.0.0/payload.js | 827 ++++++++++++++++++ .../panic-button-sensor/assets/logo.png | Bin 0 -> 4173 bytes .../panic-button-sensor/connector.jsonc | 13 + .../panic-button-sensor/description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../panic-button-sensor/v1.0.0/payload.js | 623 +++++++++++++ .../assets/logo.png | Bin 0 -> 16775 bytes .../connector.jsonc | 13 + .../description.md | 1 + .../v1.0.0/payload-config.jsonc | 52 ++ .../v1.0.0/payload.js | 710 +++++++++++++++ .../tektelic/tundra-sensor/assets/logo.png | Bin 0 -> 16182 bytes .../tektelic/tundra-sensor/connector.jsonc | 13 + .../tektelic/tundra-sensor/description.md | 1 + .../tundra-sensor/v1.0.0/payload-config.jsonc | 25 + .../tektelic/tundra-sensor/v1.0.0/payload.js | 145 +++ .../assets/logo.png | Bin 0 -> 8664 bytes .../connector.jsonc | 13 + .../description.md | 1 + .../v1.0.0/payload-config.jsonc | 25 + .../v1.0.0/payload.js | 238 +++++ 75 files changed, 5517 insertions(+) create mode 100644 decoders/connector/robeau/robeau/assets/logo.png create mode 100644 decoders/connector/robeau/robeau/connector.jsonc create mode 100644 decoders/connector/robeau/robeau/description.md create mode 100644 decoders/connector/robeau/robeau/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/robeau/robeau/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/asset-tracker/assets/logo.png create mode 100644 decoders/connector/tektelic/asset-tracker/connector.jsonc create mode 100644 decoders/connector/tektelic/asset-tracker/description.md create mode 100644 decoders/connector/tektelic/asset-tracker/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/asset-tracker/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/assets/logo.png create mode 100644 decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/connector.jsonc create mode 100644 decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/description.md create mode 100644 decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/clover-agriculture-sensor/assets/logo.png create mode 100644 decoders/connector/tektelic/clover-agriculture-sensor/connector.jsonc create mode 100644 decoders/connector/tektelic/clover-agriculture-sensor/description.md create mode 100644 decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/cold-room-temperature-sensor/assets/logo.png create mode 100644 decoders/connector/tektelic/cold-room-temperature-sensor/connector.jsonc create mode 100644 decoders/connector/tektelic/cold-room-temperature-sensor/description.md create mode 100644 decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/cold-room/assets/logo.png create mode 100644 decoders/connector/tektelic/cold-room/connector.jsonc create mode 100644 decoders/connector/tektelic/cold-room/description.md create mode 100644 decoders/connector/tektelic/cold-room/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/cold-room/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/finch-indoor-panic-button/assets/logo.png create mode 100644 decoders/connector/tektelic/finch-indoor-panic-button/connector.jsonc create mode 100644 decoders/connector/tektelic/finch-indoor-panic-button/description.md create mode 100644 decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/flux-smart-ac-outlet/assets/logo.png create mode 100644 decoders/connector/tektelic/flux-smart-ac-outlet/connector.jsonc create mode 100644 decoders/connector/tektelic/flux-smart-ac-outlet/description.md create mode 100644 decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/industrial-transceiver/assets/logo.png create mode 100644 decoders/connector/tektelic/industrial-transceiver/connector.jsonc create mode 100644 decoders/connector/tektelic/industrial-transceiver/description.md create mode 100644 decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/mulch-temperature-sensor/assets/logo.png create mode 100644 decoders/connector/tektelic/mulch-temperature-sensor/connector.jsonc create mode 100644 decoders/connector/tektelic/mulch-temperature-sensor/description.md create mode 100644 decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/orca-industrial-gps-tracker/assets/logo.png create mode 100644 decoders/connector/tektelic/orca-industrial-gps-tracker/connector.jsonc create mode 100644 decoders/connector/tektelic/orca-industrial-gps-tracker/description.md create mode 100644 decoders/connector/tektelic/orca-industrial-gps-tracker/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/orca-industrial-gps-tracker/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/panic-button-sensor/assets/logo.png create mode 100644 decoders/connector/tektelic/panic-button-sensor/connector.jsonc create mode 100644 decoders/connector/tektelic/panic-button-sensor/description.md create mode 100644 decoders/connector/tektelic/panic-button-sensor/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/panic-button-sensor/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/sparrow-enterprise-asset-tracker/assets/logo.png create mode 100644 decoders/connector/tektelic/sparrow-enterprise-asset-tracker/connector.jsonc create mode 100644 decoders/connector/tektelic/sparrow-enterprise-asset-tracker/description.md create mode 100644 decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/tundra-sensor/assets/logo.png create mode 100644 decoders/connector/tektelic/tundra-sensor/connector.jsonc create mode 100644 decoders/connector/tektelic/tundra-sensor/description.md create mode 100644 decoders/connector/tektelic/tundra-sensor/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/tundra-sensor/v1.0.0/payload.js create mode 100644 decoders/connector/tektelic/vivid-smart-room-occupancy-sensor/assets/logo.png create mode 100644 decoders/connector/tektelic/vivid-smart-room-occupancy-sensor/connector.jsonc create mode 100644 decoders/connector/tektelic/vivid-smart-room-occupancy-sensor/description.md create mode 100644 decoders/connector/tektelic/vivid-smart-room-occupancy-sensor/v1.0.0/payload-config.jsonc create mode 100644 decoders/connector/tektelic/vivid-smart-room-occupancy-sensor/v1.0.0/payload.js diff --git a/decoders/connector/robeau/robeau/assets/logo.png b/decoders/connector/robeau/robeau/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..80c8afe5e7852b052065a322a4fb235c7431317c GIT binary patch literal 44317 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 Z^Dxcj!5D_^?#n^yLQ)bDXa(BCV~ zDZP0s4u_*Z|Jgpd_KdY~iyMc$bz6tzX0%%t=EW{rt(9xEy@v6u`UvkJB@`V5K1v@4 zHX(8lDnYnHj${IUdlRO21DFR1Kr8qepHrnVGg+v36hK;_VnYI&vBYDlq`L-SHE51)>Rq4a?)!6+z=f*(0s9-g&D0}di@|7yz1XeGfPkY zLUqHv8wb;27RaJGlQqk?ev)S|D&9W(#*dzT8O$3`v<_eJd*f#G_X5+I-}njctco|E zOAqtGWqV!9A|vVa{K!H;ie_%?a5tp&BV|8m-#;Uptd!zRh8Vz_-6*=po_t8euLI^_ z-HMOo#Lpo}5-SY7k_4qb2c@9CCmH7$2hz|0ZC7e6A=;*tn5Uik)MxrAX$KZ4Qw)JF z0UT&3TuQo=4Iw;Pk3bSVSVjf8}m2GNCH=z zyEo2b`*yC-Ie>+BtsS@z%u{E%TR2wjO>o@8$;b01 z>=ok`J<22@MgjN)P#_wb0#Zust%jn=dqW2bh9%HSLqd8^g~q-#+JGW1Ap`_8RfZaF zICq7L4IN;RkRJrh%2##_4qpJk9P75ap&hpov@yUk$NNXF?OTqT05Ey+`W!oWVt+r* z;7#R*&8FP(u{V5on}5x8^c$dX$<-MBU+O!Gk#F3DJBLa|`9%P6y)aK}_b*S~k0#F! zuiZZOq?7x2yPekKakmZ$9Lljaqmfv9MAfh!$K>moyB_T*i(jq0x6+2PP$^ac(1OM@ zsVZ@3AMhYcMG-D*2LL3~S|Ja`cHo|SwymdNT5Fo860`vkiV#dQO^76MB*FsW3;QMI z1%};ItCeX!j&2M=%AM86YxHBW-8$vW{Z##JBMzej-XRl9x zJeq%Qb{_1T-^@?{VcR(xxxy&SVe{roUV0cf!q;G?ne7`JPNz3sIlhjog~|qSU@mfI zlmu|S&L9a*c*p~-}@yyAUpGN=yd@lgXeEw{RbTJ1C2R>*85R@jI z0@^T8)Tv`I4>3RdOr|Kn0?jB;gb0CxqnJ@zl?q`yFfu?^D}Sr)%G_$K*EoZC_h)eI z;@th%1t1g$((C-b4X*>jH171R9oIEKdr;-K2O*aEv3_UlWPM;WOy|zpK`IZG_vy~%|92=7ZY0*>oGYCK+#fH9zWD- z9w3+8cvDLKUgP?AFPV-y*Fdi&*agW&%Kmaaz3w#Ufk(2~T3*Ag@*xY7gLQ>DSm)q< zSG_!^xE#SwvghjuuP1;LyHSkLjU&WIjThyA;o~$^SKN|*GW^I8M^}8GqJ#$y^&W5T zd42}GS_CBEb7%_60k>3W?Zw=$Zu$8wRLSuPs-zFSjK*GsK-Xa!P%$P>a7U&`#0bNX z|5vNF)~0R*agXs7zTo|HN8m^4$SEKH)#pIs^5~TDbwg|0>PW4+bH@h`)cjd1o*J_K z?xdMhFx`pdw`upiXl|6am7hVgS{OmP80us)UkirL8pfGH`f48o5$MP@l!pgJu)} zrZHztPXwT{n8E6(y<=QKK)d3%6-eBeTGc}}U>SXpYU2$m`=jgHRpl1-`u?Gf?Wk|$ z$V^asc&>HtVIiYt^UjBF4EsBGr(F2o{li$a8*`DQ(*dySv&9$x9P_2qyFiXP4VeW- z3!9g^c-KN&0^S|p3HMgR=6*yzFuz=Dv8{gVQ|{0vwk1DwQm(Up_{{t@&&t6eF$93w z)nG^tuDIrQnE*@%07g-TKv?3vTh~Apph{^%Inh+3q6H+wM>vR6@yyoja z_VRNtv|fEqDkct!5fl#BSAHT}fwQt&F>{ptJ_ImYQJ%~I8r6~6D&rnhoT1QE(;!5t z*yfVTv!S|}p%Rk&Ty{kx2aN z0~qpgRRkJHHftVfqZyvR^@z3R(9T77Zn&K8=>GKL#O9IyY`fbASKT*uH(vLF!|Pf% z4UxKW8U}`Rv2V#lk)A!1{gsJtGfJMH^bLz2g*UpaevzwX3ksH+9t=zXGL-aS1A_ zMNusR9;+kpI3yyWrR?8CQI{MVp4|?MGbI}gcR=Tm(*WRs=d^+bQ<@P*A9D$2EHkwH z`p#;+ca6h{xWo}4eO`Cn5b_ZrCUPjm$NtX=W9E`&t@{)>kOr5Xcx~(cG#}r8cxQaT z6qiDwW_=T$GrW2IP;o6Tr0Xu-jpNT8$;Zd2&0Qm6n9$J%ee#8KskiNgq+xs_ukHJX z)E*|H&b}RKcVppvvuEwW6USU(7rD#9@xt1>9=MZW#HL!+oyNeP-;_3Zgb#F*4jXCR zK|X~^(aVioZ{=78y7^0ptY}ST29)@XDP4iy8z{!5p8*=RB1&mg89SO2iL|I@Fv=y9 zyi`OHTzUwgD?Y1mbgI7tlT{|I%k&y#BP)3t4LN zvB8tdKm5B0wQfQs8y>VyK=XN5*UO!nefD^5ZMs=*wI5*xcdlYcR30XU%`|C$;EMEc z>h^=q7jwt(J2#3$YUv#Dcxvq55;Wco0PUMDUni<4r#a`U$+mlHtn-4_p6b8f(^$@& zc5+Ja?6z;bXu7MRTP8G!YqlMMmAlN=-IUEpIKZqM?;*Wz46q8S}amjC6$mGfG0f^l%yV)TqE$HV?t?EtCZTMj5LWh z^=*Tz6*MJB>dEVuKWqMM`o+(C_PXz$bjouIC*&8`-2b-;A;>SP+>zP#95!Bl2ex&c}UB4$XhK1!WkX~!Wc+?#Yj`og^^4VN}-`ShXi6L=RpD-@G&c@ z#l~KMYwmLmpjy>HT2qe(Gka(19)hJ32f(F*Yy;G2;wXkRLc%#C3w^7%0kW{?4s81D zg=T?uJLC=fE_(Zx^Ioxj^X}P8rcDciGN0*%&!WBxStISUbwb#;=qX_ zjYsYeckp|CcOBZ_d`}unAm5FC7jmRdXb*Q^|DPA#_vddp`2BP4T`TeFO0i!LV(*pX zXRB~F@uXt3PKeGm{prC0Ew8x{}^$~yq8Ll`+iy9J;QYkJy6j3b3MYNIk zwU&VP1BE3i14s|ti7BAdg@n;2nvs4<>?w7>6>{3Cs5 z>^c0mJIV3}^l?JD3wrmDm!e8>*X9tw?)|a}d}lwQcB6PAmvZfK{1mnSE?{38oI2!F zH)r|(bUYfnXMFJ7-+X2H$}6U4KeID$)Vu#~AOS<$wBPiWvlaV@pg;UGu(I{w!`%v8 zD_typ=A$$9t@+ozIOqaIN5vfabiZQ=CkX)wNtuB2CIKGA7kW2kRL!r#airo1j8ZU1 z`yfUe$cjXqk$H{)ER)$g(?8=-k8{qX=Pv`*l4WA575I}QBR8%%3mB82mZg!&q)TZf3d{q5cHjjCWPre@YOm5g*Mm>} znc0RvGZR2^$)p!#B$xg`kSlTUO)`(sw3k+GpF-&a&DaL;XS<&fJ$aREx90c!Hc8_5RTC8Tz%s>D8vl_ z=1^W~cV$TcCMm(Mh>Cy+RUMpz%OF$XK_(};*2qivy$Nn`h+NN(5)!_wa|yl#UrUVd zg0tc!Zj42jdA*3ZHPCaM!NS-|0FI?KS>y-eu=7cgGiiC1OLt>$i zozzJo7wKEhnn9CE$(zf|l|!uUH=Ef{*l0eLgNxxP9Eq9$-UlcR465I)?{e+9pxdrf z9#}?t+gmz(;eH&TKhJg0VeJ>RTC;ze?196O_5Bt9%!Bx`41b_IB^=BAVH?+)X2`c=Oldrw>*g zZvhfb_pe3mci%g{cy1@+9nA^1ar?(O#@DYOs}3lElvJOJ+O^LfeDdML zM`o7ZJMH77v9z9OZJ3KoLp)0En@aBb;`7gY&ib!@A=`x^Hc&)hJ^J2r)-7C|wKaAD zF0rs-r7<&XV|rSY03w1AMF5<^%ORIT(5N2OU*p`9SOPM|N(LI7@*Kbw^L&n+^pKPN zD2!9;KmZC%G36CSY1B`AWuJ9J!0@1H8v8*8p;~)BtG^5QX?7Da2SF!bpDUM$cWz2$ma)a%xbB5aXQsu|~C$^C00P z*PxKV-VD#^;`n&R;*#fhFoTNkXL7|{u`~%zeJ;80`I+J-^jE8z#Er(Or+Q3L%HW2W z^+r5@)9!bFU9A!o<$87-43h3hi7smt!O;rrWdp)Z6jfY9^Nh5e5Xy`DI0mi4wf)KM z``v{FE`&gP${%gFI*g@3S@K=8Sg@?f?J~Qa#)a>B;m*#QFHS}$eG7zGm_ir=pcW_z zh~4ci*f1A!bq6`ULMpT%>aG=gGP zL+_OmkX(9oufJ9WfPUJ8S`^Jog*gECME-Pn5G$Ul>6xw$6v$L>r=@9=5S$`}u?dJY zil7`)drq^89J{i6B}>-4TD>J^N*!rExTEvBuf6NUL9Vd8R1Wvc=5bN$)3_9!PILnR z@>>C&w%P$6;u_or(CB*`f6Ldhcl`TBqI1U@@-PGX29NLSb0{&L4&%$}uLoNG@^Vs6 z>UFfYJW?s`U;peYQJeodV8@sQ&Go_KsJS2XA~9v`Re+a8GhDib4_4#l4zB0Y0=32N(^7 zn4O+T`d2GgslSA0N-)R`bde>5Ll%J$gb594O1V-$A_rwNOS`}L=6jO(Mjx|dBUkok z;Kyg3{sOT}^z-G0U0Z`jzpvGI!Y z`u*(shZq1pe;;MG-6xy_#S-t>wqp~UQXN0@l&{?U#^b`Dec)mYUu1ar-!-Fd04Qd& zZ0FI1%QYBRKU?7_NO#wP1)vxT$|%*3Vl9vvpm(h~M^#thOJ4%jO}g%3Mug!=kupFA zUIwz!(*&!gVRJxgN`W{mRz--3iRlp~vDsP$PSSxN-lRH>Nh>W7q6|YCykR(qy$s1A zU1Vp2*j_00_f@BVzO#AH)RD7pJjV|IDHBYb{w}HGGx@H2hr9ta!Oy<5{5jI!A-U61 zFZ#rK*CJ6E$30>J>MuNWXH39JtJuWy*4)p_FZ=dJ=aOH4_=`6S?d-dq;lZti{k#kO z^rtmqmnlfG#0iWyxDy|YhCE^=pTt?OM?8rT6u{)ss}Sg>*a|?j%Ru)2+59+G1c|xW zHZ&bp+rG9WKzxMl9Ha*ylF3S?OLOC>_`1r$flbA|&_1BWXjH98F1hprc(OY)Gqa51 zXd$w_JMSrJ4M0>Ii2S)7?YTSmU$H~23TJOGrzUWDgBN=mUT{e0gj{mSlkS>eg;Ut> z+-9Uwm0v9G-M(kbzI$h8y0yP}`Au(At!C1g`q_b#vq-P|@D+1!Qdq0*x)Esw`u)4X=y+oKMfGUOD_3rd1Z`98|bA02M9=tO$3}aKUAJP#*GC#~}O*0f0 z0w6I)Myj3E`ltFX!-xEBmxKT&du&`&0--vy=foeBJ;`I^fFlr4O#D%F{{(9z-a@3MGK4 z5Rj*!+ z=T5W}zB~%am`!pvNHIr36hROY0x0^E`#$}{!gc4`-T0{QZAZ{jw}z`@9|i@L3g-gL6OQbBWwI_dUs#;>`2m^PGoDWgMaQ zJ?;TqQKlU*Vyk^pbXGiy7^f>O^z{R%G@(HRfZ`M&ipVtx`M0@5vrl zfy!+=W-mBAU%m6E!CWc$<>-cC+a|Pr@Kp8muw1f>Hh{>4)#?(Y@f07^W9yCS&MwX! zD?1CdsxGDhClc?t?(Nu0~R0kzZFS z8sQReM%LUy-2iNWHzZo_{QlJ14UR6Z6OZb9i>b$$psgrD3ZS@c!z-^CA3OZE6_Iqr zwRdjdaFk}6TY?MbLTH!R&2|k3EXyI5(?W+5TK6jrR5MEmIFM<`Ib=MZDFn{4t`0yl zY594ujF*F_sN~23`{zh!sIB_)6W5(_oB$) zYM?8$)jzELhHpFhpR47is2v1;wKEmAXDWM`>LTY(X>VX)de36i+1B5o9lI>TBG*48 z6n_Z-oC8%D3v~B;7j}e}VK$4YjMI`03=CPE!QpL&I1HBBIW( zr`j{QzFmX+^x)uGXDG0Tr(_uiYI#yhliM41vD>m;*!p|%xb^5%Q*nN{0(jeAN8HO^ zBe(494rzMC8scr&#Ss4Gs+QGP8%990lv}MD2b|(kF1LTsZiKLtDBTiAvrGVbau&!S z@c-fscl5UU%AJqBeeE8MEv_(y>r$&lAT_`<0)%!$oAj{X!AQ_%m?8kW5Pe-R07f$? z1{e?n3G`V>fOJfeP@;I!vO6{sN_c3KZi`Z7VS996ccpSH7;gjHZiO_qAwVdO!qWk! z1f~iFz4*h+HlF$8PyN%kcidWta&FmnmW0k#x_v2uFqxiEe48((Cp-qWQ*>1=HS8Q% z8xCh#snIHguscxfucO4WM}QUp@G3FXzdiis;diRmzAhu(aEP{jN-V?F%Xg>U%9>@^ z5o-b5E+IfJH=Ee|g`~>1*g^&XCVM*cIY6MQcxjl`0mK43@!i{}CcpRTeKoOybmgmI zT_n_iFhJLRPjp4!G6#X-mSzcr?Up%(jj)dy13+@4p={a=dn&USL=Mdj%|5C@n^|a} z3!pb>4Ou&``SCMXx;#mc=BOHt*BXC z=DP7ffcf0QDZfB^av=lWx3k)id;5@E7>2pw)5pE?x~I*ae+LQ=7Ha?uY*z#RQNKGn zCICV{Rys^oU+Aci4x_?`m|}o}TW*rju>hUeNs7TfnOB&$isTqWK-I4PXcWD+cv>fpdoFQJIG>#6#7|se)($q6-aR zN`$?KB%|65f=ainZ^=qp#9p2ef-jS9f3P-s>i+TcK64C+Gye-)Q)P+Dpw@IBC6P zFO5!$Ak(pizy?fziozaXa{z=m%K8NgAcN`v(miFMnlG)JL-5M2$>43Gop(V{m*B}xVev~9*RI;riQauh<-O);Sw9EzdY z7b*)2LFlzj=L=u^lKtk*vwgK651zlPN2^O(#V`cA)IwbX1XY57NA1O?NKV`X5)p?@nwUzC8|*VJ;A&=u{yd%>*WaRC_L+5M!+k>{M}p z0KOlB3cG6#-BE2eA8NNbFldSXe6C9yj10|R={$RQah6{7{YnF%=4c%ao7UdJMX$co z8H19(yLnl+1DJRT`b)=kn{GD<;+$J}*}+y_CgbmjP8)mJq1+hA70N|3oy? zL^|EQrvqQ5*T8aUeF_(cc|d~$q-ggb z5V~$?Qy=<`Fh&B^Dn@6ntJC>H8rdYiOke%Q;f>j5SWbd2JO(+KT|TJfWWSWlONa^_ z86bjD9CjCgo@zi80cfKM8it+qOVjI#bmuznP-Lc3aaXG2M*wILFats<(9N1E1rWMi zz;p*C0P`4tlStT*0K#mKl3v+#IpICi(O#A!!_b%TrL`KOtZrOLwIpw0Hl`dL6%+v- z_6qb2rn+;5mLQ#zwm-R8x0PS(?~~wqu491au+1sodB?7uDXU|tV9{RVY+v&?`|%%* zPOy0hC><51Hob(9Hqxgmz@Q6Mr7l{tXAb4An9!At z>#~Rr)L|ggoE_aY05IUe5eae*DnK=7sEKKuo{P=VTQ|Sq+iA0C>gTMmd}5C#RS5yO z_Cp#;lL<4h%LE)u3i2o;PZ9v&px}TM`l#hwWexx$tD)6V3IZRLGHSA7HN+qXkDND) z5E+ySry+`fkV51p1<(NcY0%eVT%{n4*0$qkhD$M=#=??B1F_YtSkbIirH!_oDP?)5 z{+jK0-`ma5-=hYEAR#S+G++MrOkOL&&8>pH+GT;URxisB=u zORMyShfWN_%?CIkr3yi!R3|{X&P5$i@hCU)GS98px~w5oQQKQor`ttM*zrIeo$8wD z0Ir#qa=rTbf+l6!81=cOSN@qqUoAYa0tgd$=>%wTI)s=5n3~0o!JI3TQb*lY&MAc35}enPJUwZMVEhGVCz!xMCNd zMX{jj->PlYe|8EywX-$cQ#Amfj1Yh`uQ=+8xssazN_kEIkTW(w018Nw1PRChuyt78 z?kJ^g18^-c4~~OuHVYe|j1mBq$*v`4s4hY~ritUYJ!FvVd5N$Gq_t86!&(>`5GR)E zg@aMP69Z(ksSz=^+HDV4R7Lzsb+96+$h};M)?9hobZr|3;{j~hw!)}CMZuB;0L?=w zf|_R(B$~J!6aol%@Cd?)XCuc?^{X`?NuzF~0&$(IW&p_0OaUA4Y6AXfRH)!Ss6J2t zNdhD;@e&oNu(Wu`@#BF8!B&_WiY9&BW@wk-q$m$_tiN3ppXRrQH{ z6`5Pf!o)`01HvwJKu^OpVa=&3@29ls{sAR2IEg!`4GTZhbA-ExF0F)*Obc(7ZWhJ#*2$e-2Kud5-Z=WwL&ZCGj<};=<0WIqI zgLZumKrD(VB2liY0Bm6ZJ{>#?Ao@YXY?5sLLR1vW6D8hO(SDFfm3(R46kSyQ+jp4p z*;(T>v$Ny3qc9-Ad9lWr5DLcHZ7)PhfiyG$*bE?~lyF^!gDf~K5VET<#|8mF2?bnu zuyrSEhs(+c0jF?TfMx!{tGa6L)SWwWDDV#|hqZYcJUi_ooY0Wg0BCjL45qc5~HAJ$sac&IBLDC~N45!C+}4K_0Ouy7Y#O%)KfZSSUms05mX>mi+` zr8;aq=?Tq4wv+%syPegE%uz~+UMxk0tP_uTHY^I;X>S*0K-`1m0q|f)r_5;SYWKyV zFWi18RO>=aI5w<#w&vJ~d%?H~z=0xE6bvuP^*ksd0546qZmC0UO-$%4F3haY)ha5= zqpnE;<-uIDT*z5t$&ej19i+!gDjSmj*d*h(!?Rh`XSiAar z8=5QBN3lNZZajh-TIcK?1p@8=51R6l(7vwyGr;7beQqW-6^ZVw?lebL!n zFe`om0dRwGmwUtmWKLzX7C>$PA<0646}J(cSrZdMBgeUs%O%T2 zEUUy*A#Gjmq)&zMlM^3p?0<6!?2M7uSK_o6-Ha7Y^mP~I%(>t7%Wh1`E&9?&SAumJ+778e4yg)032M;o%Xu8_B)smmk z6{>L>;3V+}1C1$C$cAPOw)wV`559RN+q6ULcD2thFoP{0sL05j8F z(V41Al}6gmok436{KIokx0hG-nGl;Tt0y}?Rf-T#$r-pY6@^O?5Gnva52cbB!?4xr z%5)#pg7NtF?c1BS#X?HI>Jhy~q&&b&0H-&;bmp$WYDNf*+;(T$5$3 zQr}pw+^|xHBav9@JQqT7k|O}PdQb%nC!mBIbs(2xY96^1*~QT%Yg^-GtXFo$bTvdhO~(y?h=0ELk!ug%Q=_zfsK19Uz;X-@@jME6a6ADRC8(>b(*PS1 z2(3e1ZJAeBK|R+DhEW91pzTyh$P%rt4rY_^s7F0w7M&i6GcZ&HlYc8HUGp+eTYEvF zBw&@t@UMAgo8Rv>&41DMdxt!wHP^;9$0{wM%+BOe2o@=108k_Od}CwEXmlA$+_>kG z9{mP{dmmX+Wu%)81p8DuA562np>-$)&1%Kgt<-xssZbA^s}D!0uRE|uSi zP)yYT2ByN7(LyN$0CGrflXBKBA5j=UAQJHxo9mE79@~Z0lTG~qR5Mk>Pz_bl_5bb~ zXejBveQyQM`y#WshfX@9Gg&ea0AL84fWRZRa3CR2G@n{yfB-ZGpb=DS;)JpGraBD( zb_l{;5~zdF71S{fn65)TRe*r*+6vRAb}cDG)&1@xv%_mvJz3`}6z`;S7scl^h5mBi zjEi(%WvaDmYtVwo!((t^1MmR=uk!l?xo`kBtpZwPSEHGz2GgV2q|wK2)_b(gtqhF#B5K0aXteeVd}A1-~g4#Km>?_(x|W^^`q)BX~k*p-|N6NVF1RSrm_=kIcMS6d;f`se?^YSb}WMKK>^^m zvN1x4?*(%&HRS_i&bU8+u$BP=C^u!eB3ZFp z^1#psk~9>}Wsm_~gRUi*VIT@SQz?AIGx;IgML4Y`-~vuI2n0^|K%rpyfWklD7<2a_ zLkAswhkTN+Sz#~Ek0I=;ZZ>Vc=paF34)RJ`m+aBJA zmUNDje1oxe!7(TJIu?Z`MIM?*0L?IJ4MPY+00ImtQ?1i9*NyLRz#w{}4hVR5&XI_R zW=jtTgWw>5o$v(_cYrpL-F0y!ZWDXg2?{E#E4MXAy7O_25b*;DP30uFgK{>R5Jl3!~rDpjWGGtK28{MxGo%` zd2WK^Z!!gi3I4|VPpcDX7eXtW|H-%O939*HF1WcR$2QMgbe!BFf5n3p310^!1AYYj+a^r{Fbo0$ zHmTMD7h%S^X9F@c1?e)!l^l;!?rH!)Jc&sXtB=ESgHRkBU`z<%*piSu2*3u*bhTDF z%8r_S98G>^S&9i5FiogXpi?d1e%Q74uihMDAHk5cH3WHc(SRE;Y#3+uu1Qn})wonWmcB1<5 z#*y6U0CRmM{}aaqwyFLA;CStt5_FsdbKnR^X@?v3$`Z|ja$*`n z3MLW>jkrb29CgEyHdb23vR?7d3&Myg0BBJY^l3OT+p=JD8 zgeyu63ZaTf5P(n_3I%S{3&KltcT_6;V>WCEpJEaGBF!A&$>pZ=!RQIx$M?pN4K7MhpJ}^EkR#MR>0qJLa0IFCa8n?l%d?i9r zAQ@~8pqwVT8+io)Zu;|;rtZ_F+P({_03cX96<0viHZWeO=!aX=N@w$F6rJ|U+`kl? z2c6aQO{?!=#pyQ#z>Ta}kKV1V%)job{EO)o`cOU?E{i!G}v!J`l= zn2j?2@{0c3{GrDAz)y3H_C8IpQcQa6L*rkYd(`4VHP;MWVRc~al|pruP1Z|m{zk`%OT zqzz#`oD*8Q{Iu!s>(~o+gGayfhf&5-?Z&||zwl=bJd&XLL1)~P^V)bMUIW{$$UGNV zZYdxhhyg&sK3`Z(4<9<~+5Ve#GOG8bM|{$;G=_oGBwpNDy!(nt&ppH;P*=QW7pMF6KMg&1x^BzMmSW1qycSCenF7MLJMbmG`K8YI z%b2rI#O?DY?AW91YI^YHNd1;PQ=^17TTJ)`>?F~-M-0{Vs~O7jxTPLuZCGZ&8I zh~jb_u19{?qIp?Y3MaQJL?TXk-3aPfnMb{x%sJ`S9ym^e?ZhJ)Nz8tqBO!7=K znwH>rk}qEpwUl^S~4g{G2ht}Ya+?dD`$JpL~0KVC&kMr&O06vNGS9@*q{`2c5gNl`4MH`=3co2TYuljt*_Ei0kfG z*1+m%*|7@IZz~00pfH+85|(Reqdq`)%$VG5WlEZ6^TfE^c{}%JGfg%7X7b9Q%1Y;6 z_!k$5`2ZCxl|vw(>bp%rKwR?|H3tnUszU&-my+N9#0_(u^*q0hQ9??J>J#}QxulLXoB ze?C4p3rqg>RGxLM{g0!1+eXd1s!x+AuWh~P!)HIu=Ow9QAE_C9%8ER(T>gC0*sZq&jOr3Yc6|S`Ebah~QaJ3WRArVIdOF(;&FL2C6ft4;=*cxO zd*89h+q?dER6QAM-jc}W+geFx7%^qXQ2k8UO251XC0hE{>52wBn7Hk*>^6kFeDu#p z20jjK@syO;R^R%;mdw0uXV2`vK;Gy$_!jKGX`}=bq33?QwOvfUuy2c_cI{g`oHa{J z&YLf5n%;Cy?z|5UZnQe$vOv@M_-o(amMIrKazFo|MKJ-@hz_l>bjy7nEni8LBBEyw z+95(cN;h!_fFxR)s>FbpmMHJB#pB%po@PV_)zsvBx46?&$#0Wo2Z|&~vLr#)>(;Fs zok!54w$HFC+k{yeEE%JRbJUcL6N05x)mdHfmQ430()F4vaWERUcf>aRXKRhMTvweA z4-DH{<1ae~x8bFVE*I1rgltRPJUI_u5#Fe5{NsjEKD`48)0!SV;p{;O;a}vQ-`v3?c;Z;1#Ul>^oAHZK{Ci#8I39<2TWygpaEc*Hb2GUfN2_r2~81s zYn!!bky8wg(hhkT*7mcV9pe1^){X4?H#R(N`^p=yYX(tzFIXKjAFLW@8;Z6sK|MuL z^x%mz7?jGreZbDU+FGoUlKxYDw1nF`4_WW4yI$bxEt~R`L9Ho$ZdwTV6M~hOjZG?3C zS!?BjE`PTcQ>h{MK51-%Wn8THp8jNwrI-MisF>OiAYRLm4O_mpIqtZdYPMNC?fX1Y zjQVJW!q3`7)O90u$1TdplG9a<*|%!OYHPrb)2rrh-1jly!ckF(XBKWATW%6nMd)lX z+@X^HHt(5yK}2hyKE|i zmd$+r*kgB(f){#GtG?ukfA`De*>^ZCiUh+q_Rey@m*LGjynh_L(JVT>k~qUKquA~r z_>A$jk8m_oIk$;Wrm+p4>Hu(*!pd`V*#Vi1mOQ0-C+nKcQw@3iACLdZ%Fr{HT)o!l z$Y(i@=A}hb!_VA!+W_Z?#KXgDZ&>i3gUa4oATPH2816|GsqoE1m!$S~9v#BYk)7x( zvuB*Su|m_ukVdJWMd!Zu(Xm)7XMx-@!0Vpw~dvQuwys0TV3%s zH6uEH`bmFXbm8Kum$t?`_;hk4*%QMqj<2eS{^7PqSFC+~c)Qou+@5sOEnm?7Xe%ep z{^gE9H(&?JDMYX7;kJ5{CoQixyDoSTs+V@(zF_&g!xZ8(G$%XmCAD9M>5j(t0G}cg zLnuRf%=i;dSuLyaz+?`CmsUv3%9U)`Ns2Dz_Gjd*)7I z^FX<5R7Deak4rb2od-`ffAd!yafVUVoX_{YH@o{k zs7BSy`PD8!Ti*Fy;f+u7nrCzZx|5q`tsXRY{D(C!INLgY9IC-jp1pK&zJ^V_VP*1v zc~I4(-@2!ccO|bsR-);#(Eonr4!wK8GgQ_1Jp8j)Tc=FM@Wo+wL(>}bz59K=E~_|v zOLa@C7tj#tp?&t4V#Km{O&sY+;Qkg|zUq!9d-n!Z!*B7l28dDbe6z`hVs5x$HK4zH zdY>=8I{4<>+U8$)HBfcB{_7{&>#~aKnH^1oK6zHtdu~Jv|uavDu)&{t{6KBTm-kSX?Qm^S1_fijfIQHZk_Zz!X4SB%Dg(|UT zm~+>cf(ON{icKAV$;FV(UjE=4@24!SBfVKw&x{`RVC&{3E*%m-@BEE!$3yO_;Xn4l z=aM6JWy~JL?z=t5j*|#W2PppL9Z`K;F(ap)Tbwwzni=eSLbq}iv!kree@rW z!SA=;1>kNS+FuZl%T_S8$qS;|e{*~6YjGn@j~=VoS=h@j$hhBB28O05|L>YAR_W3) zA7J;MO{F?s?-t(B;wnZb2$|#T9nwhW z_B&=&cA`lh=}f4Ky|`$dO%5M*=LeSBZ39wO7>EYt7h12z)j%7xkm18{n;)HLyi1#ZX1 zpfjZt>Jc-|MfK!}+m~Mdrb4=Jx~=NLq&3k$Db^)dG9U+C3jr=H$d(TVY!3Tb%!yt` z>MULTnmJI+sy`>V)Shme__LP1B#ZRBdglPFs|qi9VyxM!pKfZxCV%XO*FSbj|(_uRU8L5~ibl;7S74aPe2rb(|n zv!N`r<5FW8ZRJk4Vdn@*a?-h%-d_CNh|=FI8?AXEAY-WozsFpIk|&3SPq^f$8=l=! zZ%UHke7$0ELJzLzk$Y^>PFL(X_+qCIsc)uE@6hJtR~(bj>|Fi5mnkcA)bY8VJLoj4 zx`pTx|JJ9g<{7kNaB5q%&NFbx{dcVCBy^EOYnS+0vT*3!t(^%*kxr$v9o_oIYc&gp zPF;NG!hH8>O#skbQ!%4TSfu9mXus%^XE3>#7Z&^XGdO4Q#ybNoF;~HVNrvi~2i*w* zeT8()l=NQiuVVISonk>PEBoZ-uWMCJSEK$XpL%;DKX%Q?oUyHsaov&IGkNSycPaoe zxNmIYcNg3mHT%@7{RdywDTN6@n=otX8pf*+oizIC&NvR8(wT<8_ZuynmwMx`S~+E2 zxA~f1b>T3eTK*{MpUFIrUG2fV)(iWHCe|t&_+K@x>HY6b+ZwQR_}@R@n+{h@de)JR zQf@@L$IOji-?Bms-=O=?zo2F)u*Qm4^g^io*2Y``fI{JtuT--N0@qXxxn$(h|BQP; zS-{TvurT+XNzI*-I;ck9K{v$=z5T&ux4vg|MgmCZ@<<1l|Lv`+|G4AJ|IFX)rWg9x z(ExNnqh5s}k5~m@c)Gz&m>x6sV2l*gclxhiFO#rh?jh^>Z>`pIjnV!CMoP`-+Ax+VZWJ=7w9ABUOCX*4+e?Ne{D8r)7o z7acg~h5FI_mgnzl+t4WiAe~GCKDzaZc|%~ERZpzl(EZ>6D%pd>piuW4Vx=1L@r&== zA%>#Ni{!Dk>ybX>9;a`i9IOiz(i)B|X)w|Nt5FO1%Z0>o^ zwf=se9@TW=yM>(QbUSvA<0ukmU(2B65;Gm)e8V@Tqpvx*ji`}XccfN-OO~jk82s!O zuhgb2urmK&Au%CIM(o{&+umJ$xSFP3X>3DNLv((4avT=24O1 z#JuDDki31pz7>B-=#*(l|MS!Dcq6I9&wc1-pn%YC{)SKG%=y+XV^3UQC4BM9n@Jzr7PH}20iGFBhL4t(Wc-}?tJ$LQJabxK6BF2 zFd+T$tuw#7Nw;dq1D<)7^x**nZfxEIcvOd~L_)ude5ng5owmR8_85xUyt$$c$OUr8zgGChnVC>M!!X-!iAwi|C%pE21#v;0 z972Fg0TtBH)0dpN`1o?8elrxJcOjqi-eqEytIk+*?dr~p59vyRRNukV3;%Y@69-?v z@}f;?%`?7d=&DXQzNNX=Em`qoD6mg26~&zR>J@=LTq?=G_zjcyrRIdJXjMBOIf#t^ z$K1Cr!V8lhztnjFAV0d0MD){#xhr)`=|UxqO7tJk8uQbBZhPdQJM&!#V3RJXtiHYe z*7WvqAGT{R&71mJOLy|p`_LKA?El;K4 z{c2`COv(^H;i|>A=a<^wpXg~ikIv3JTPrHk`gA(}t$iewG(8gdMYfl%d7kmeUdw<~ z4<-Ora{}Cm8qs2Vdw)AASm;=Z@1A35L#K_K1Zk9e+R!jf9lWa z&)n||JWcl>bydPg+l9s(hTRhL_EqE+v)|p@eWeA>L*R;UYiXvE-6d?rmM8XZW~Ylq zdx{x7YuZsWm(;dD`26hcUE-uzmo~zkw%Rw29lZXy#H@+=*WUWLkYn80|H!Fa_x0a$ zadK<9+>*--yJ!8rm#hlpt^R%+oOn}C-LCJQ&~O|_Xq21AH0LdOr8 zedIZPcb3paTdd_u*ZL@Rbt^T#rymPwu;acb7Ef(oncx5ZrsfjmZct;{&;M^TmCTOib{CeP8`~Dy&_g&!u1i{7u4n4VX`5$w z_iR)aa5?ti|7~gOV&OOIGT|>tak};F32W6u%fzO`+_NWr(OO^~EkNFPOXrzYCw~5u zEk?5+spJb+KeW>19dsTfk+)8;wxOk`kdNEZO1=*ZUEI7QPoUFV=cgR{*FRjpc5_#$ zDAx6I5TPWTx^ZR8d|Zn<_3N+t%c{e7<|Uc!2lOM-i9jpFz?ea*$ zmge@pCh_u<4JA8G-t8`@DjDRE!*4qGflvE-iyBmZ((Pzuop9NOW(%tq23Dia_U68$T@G z8s64>Df{W2FJH4Zrx{Ks3vP4S_^2Sw@sINrqm#{sw!dwj;)w~~&o^d6pPPg4nsVE` z?np`|-6s{%P~hqGCD$M$)7X$eRn6^eWx`TGJhST`4w$rT{N)$SG&gV!z?>J(>AODP zg{!OS;o!|-@P#}M`k)3s6lo8pTGwxQR^s*RotwR5D#M}*E# zG+IC>Qv-JAkE=8={@Sx=Vil~iQnVHN_np2y)m7?L)5F16PkazKbosAlPfg|X`!9N| z>4W>vUKgiLNoVv&*Z+P+H)Yn5?$qhTPw~g6uIp!jGnIULsKT0kC>+&X}3;N;Pvh>eTr=9eh9)VTan0!H@L1}hGMJgd_Q4g7_*~3`r^Wrg>KcH3e3U%62IfEYvsqT9HaHVYDKF1 zWSgM-^*b@-YR#FGULexY0v5AIw2Hz#FCKhB&!+mAqVGyh-&0gY1wpZHSS~pvxb_jJ zEWX9snWPm23X-SEt-o!u^zMxBYPwvNfAuNl=tMKhqP||&r&_y_QqZ8whxfR5W3v+d zL>6P-yrr8S2m22@DAYCm!6A)rTvK;dn>KE7z&dJe-3h;(URCL5w-}k#c`dJ)P^b$6 zZ&#TQ2yyAIat+qC>u=NSMLp9<1G3KnEQ6!Z(v>6zJS?OR20 z2e;az|D>jNttU2lL$r|JcS9m>qsz}d1tucLiCG&j_(SCu7c_b7EkoY1y7e8hf3PcF zIzKH5ytZMAclGdj+PF1_FFEJzV=QvrE4DTz(pxl!SJT55`m%rl6+z?Z_5Hc)^L>U{ z96N07GfPx(R|crzoBeF%aplQue!n>JD$yfVcds*?IFoRY8}-q$d+Hi&bjfW|iEGLy ztJ#_3CXZe#a~My(ezUj4?%pRP*^eO)*HqQvJINbOmt4tPaT3!`JTYz7NDFkm8HDgNxlhYWxtgH6s!pG%xD&%~O zaA^i1gFgPO967$GCFY`=J(N9EBG6IZQ^{w0sD?daaj;55s88XZ+~$l9Xy|~vYtVt{ zSXXRMK3}#r`bip<4-dNa&a#j8L&3&=#tu-4u9$MQ$CW2reV2N;+|nyC3~K-wU>*Ry zJPAkQMC=*^oC(1IZF%dNb6&ZyXEI&@_A5{PrFjn4w7vS2*Hc9{nrJ^H@C)t5DTyk& znG_ob?2E!vJz~J$>)=4kUyquxTK~~1H-o^VgC4#)w@lv;Z0UZ-Zg-Y3?Ohg(JsI5m zr@AX#nF1M|+gb=21Sm2gAcIirN%NqE4EESh=R8yBSGdM$Hl2L&xsUH7N1pa!_w;?@ z^i?oDowgr>-{0>qC+Ce8U&LI+1QZGndtn7skm7)b=vdcxe-l=R=a({d*gQ>p{Pjt0 zb85dR{Okd^XKu;uySX5XdWWVHYl7zV7tFaT>{_zFzPChdzkiRe4-w5>GB zqkBW|-%VfjaGzQ^a!xf9iqTxs({rP^<8||wJ?mn+S!^iyKfNCSsPJe}qiZD8rzZQ? z*8G+L4}7AcRSP`&Y;e}6vHcXHAm7``P#u6Kv~Wo-oOwQ&FI)t`11@#42xehZ2|p=R zDf-2sbf7)0Tj-#r=@#`4UzvQ5;=A+;BAAja-&|f5pXF*Vs+T2BPTOnK#;(=@%KwaA z2WUt=g!>v^*m%JMcA&{A$T|I_&qVshtD*~2`zx+XzQ3c{MN|Sbq;cZ2t6K0pqHq96 zNaErdQ-(ALblui>S8R~)xuCD8o_%FCw+wE7!zWZ%DA{P^z}B)5^MRC2NsL#%@Nc7e zmib!GK27z+cy7jfTMvqjm)*}7hQ_Zdqyd!cCx<7w`c8YlImiUxcfn(ku;jAsv)J&R zLOMhR@TuhWY}B(37sf8dWa0-|3Uy7|C-mEcwokc4X0VuI=qYG}q=Z^Hh?Grv_6A_f z_(FRbvDCUqsTW6Y%S0;m$OSqc&^L_>ta39tw2<-Spoh;M-LTZ!j~+7lLC$CI&?xxf zaQlkSTz-Q>?+d)kKtN6X=CmtySfGKb7008|m=)i1Gog04l z3mNpIhtI3nzSG*T_L}@qCxmZIr6C>&4E*p*g=ZofjP9JD^8QidxS5av2Efy^HkDxp z`h+qe^adtAu=-V;lUD_?SyUEsP6tqK(I=j%K99G=TxI`$AA$pG&(A$@b(Fp7t%aNa ztI*x$v72eA7V^gw%; z1v9@Iyv_G~iAES`CO`p~y08F1hE=2!G8nfw1i03dys8%ps;@dQzytAItipM9rkaGwP1J+~!K!*k$TF7A5Gvt}V!0hF2 zK2xyJeWCpW*md43)&WkmFzIPN42^8_U3!rOaJ9e`0H%k>CqIr$V;6IxT#TBQ(&Z$N z{ms4}z^;QM)#;#=tZ6>89*^|)0Y-Bez>l9sm0wC;ETfmXl_hAhm=EwhJxmW^w{MPT zvGIcln7o7pqT8b|M-=~UeRB9p$%{*AMgQ(Rssq^lQ0f!ARiR1%Y8U%ISkkV){r(As z1K4#;014c0h?asMhEO2iAdgU>#To)`4|k g9asm}|KHdD2XUBf`2(Fm2mk;807*qoM6N<$g3_JJlmGw# literal 0 HcmV?d00001 diff --git a/decoders/connector/robeau/robeau/connector.jsonc b/decoders/connector/robeau/robeau/connector.jsonc new file mode 100644 index 00000000..1375c25e --- /dev/null +++ b/decoders/connector/robeau/robeau/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Robeau", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/robeau/robeau/description.md b/decoders/connector/robeau/robeau/description.md new file mode 100644 index 00000000..c27fdd10 --- /dev/null +++ b/decoders/connector/robeau/robeau/description.md @@ -0,0 +1 @@ +LoRaWAN device to measure water consumption and detect leaks \ No newline at end of file diff --git a/decoders/connector/robeau/robeau/v1.0.0/payload-config.jsonc b/decoders/connector/robeau/robeau/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..7b2141cd --- /dev/null +++ b/decoders/connector/robeau/robeau/v1.0.0/payload-config.jsonc @@ -0,0 +1,98 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "In-building water management solution composed with\n- one sensor using turbine to calculate flow and volume of water\n- one datalogger to transmit data with Lora protocole\nWith this IoT device, you can :\n- detect leaks in real time and receive alerts (emailor text message) in case of over-consumption or leak\n- monitor your water network and analyse your water consumption everywhere in your building and do predictive maintenance\n- save water and then save money on your water bill\n- conserve water and have an environmental impact", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [ + { + "type": "dropdown", + "label": "Sensor 1 type", + "name": "sensor_1", + "group": "advanced", + "options": [ + { + "is_default": true, + "label": "DN20", + "value": "1000" + }, + { + "is_default": false, + "label": "DN25", + "value": "336.89" + } + ] + }, + { + "name": "sensor_2", + "label": "Sensor 2 type", + "type": "dropdown", + "group": "advanced", + "options": [ + { + "is_default": true, + "label": "DN20", + "value": "1000" + }, + { + "is_default": false, + "label": "DN25", + "value": "336.89" + } + ] + }, + { + "name": "sensor_3", + "label": "Sensor 3 type", + "type": "dropdown", + "group": "advanced", + "options": [ + { + "is_default": true, + "label": "DN20", + "value": "1000" + }, + { + "is_default": false, + "label": "DN25", + "value": "336.89" + } + ] + }, + { + "name": "sensor_4", + "label": "Sensor 4 type", + "type": "dropdown", + "group": "advanced", + "options": [ + { + "is_default": true, + "label": "DN20", + "value": "1000" + }, + { + "is_default": false, + "label": "DN25", + "value": "336.89" + } + ] + } + ], + "networks": [ + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} diff --git a/decoders/connector/robeau/robeau/v1.0.0/payload.js b/decoders/connector/robeau/robeau/v1.0.0/payload.js new file mode 100644 index 00000000..2b32f366 --- /dev/null +++ b/decoders/connector/robeau/robeau/v1.0.0/payload.js @@ -0,0 +1,121 @@ +/* This is an generic payload parser example. +** The code find the payload variable and parse it if exists. +** +** IMPORTANT: In most case, you will only need to edit the parsePayload function. +** +** Testing: +** You can do manual tests to this parse by using the Device Emulator. Copy and Paste the following code: +** [{ "variable": "payload", "value": "0109611395" }] +** +** The ignore_vars variable in this code should be used to ignore variables +** from the device that you don't want. +*/ +// Add ignorable variables in this array. +const ignore_vars = []; + +/** + * This is the main function to parse the payload. Everything else doesn't require your attention. + * @param {String} payload_raw + * @returns {Object} containing key and value to TagoIO + */ +// const device = { params: [{ key: 'sensor_1', value: '1000' }, { key: 'sensor_2', value: '1000' }, { key: 'sensor_4', value: '1000' }] }; + +function parsePayload(payload_raw, port) { + try { + // if (port === 100) + const buffer = Buffer.from(payload_raw, 'hex'); + const data = []; + + const header_data = (`00000000${(parseInt(payload_raw.substr(0, 2), 16)).toString(2)}`).substr(-8); + const sensor = header_data.substr(2, 4); + console.log(sensor[3]); + + const battery_voltage = buffer.readUInt8(1); + + data.push({ + variable: 'battery_voltage', value: battery_voltage / 100, unit: 'v', + }); + + if (buffer.length > 2) { + const sensor_1_param = device.params.find(param => param.key === 'sensor_1'); + const sensor_1 = buffer.readUIntBE(2, 6); + if (sensor_1_param) { + data.push({ + variable: 'sensor_1', value: sensor_1 / +sensor_1_param.value, unit: 'L', + }); + } else { + data.push({ + variable: 'sensor_1', value: sensor_1, unit: 'L', metadata: { error: 'Missing sensor_1 parameter' }, + }); + } + } + + if (buffer.length > 8) { + const sensor_2_param = device.params.find(param => param.key === 'sensor_2'); + const sensor_2 = buffer.readUIntBE(8, 6); + if (sensor_2_param) { + data.push({ + variable: 'sensor_2', value: sensor_2 / +sensor_2_param.value, unit: 'L', + }); + } else { + data.push({ + variable: 'sensor_2', value: sensor_2, unit: 'L', metadata: { error: 'Missing sensor_2 parameter' }, + }); + } + } + + if (buffer.length > 14) { + const sensor_3_param = device.params.find(param => param.key === 'sensor_3'); + const sensor_3 = buffer.readUIntBE(14, 6); + if (sensor_3_param) { + data.push({ + variable: 'sensor_3', value: sensor_3 / +sensor_3_param.value, unit: 'L', + }); + } else { + data.push({ + variable: 'sensor_3', value: sensor_3, unit: 'L', metadata: { error: 'Missing sensor_3 parameter' }, + }); + } + } + + if (buffer.length > 20) { + const sensor_4_param = device.params.find(param => param.key === 'sensor_4'); + const sensor_4 = buffer.readUIntBE(20, 6); + if (sensor_4_param) { + data.push({ + variable: 'sensor_4', value: sensor_4 / +sensor_4_param.value, unit: 'L', + }); + } else { + data.push({ + variable: 'sensor_4', value: sensor_4, unit: 'L', metadata: { error: 'Missing sensor_4 parameter' }, + }); + } + } + + return data; + } catch (e) { + console.log(e); + // Return the variable parse_error for debugging. + return [{ variable: 'parse_error', value: e.message }]; + } +} + +// let payload = [{ variable: 'payload', value: 'C5FE000000001777' }]; +// Remove unwanted variables. +payload = payload.filter(x => !ignore_vars.includes(x.variable)); + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const payload_raw = payload.find(x => x.variable === 'payload_raw' || x.variable === 'payload' || x.variable === 'data'); +// const port = payload.find(x => x.variable === 'port' || x.variable === 'fport'); +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value, serie, time } = payload_raw; + + // Parse the payload_raw to JSON format (it comes in a String format) + if (value) { + payload = payload.concat(parsePayload(value).map(x => ({ ...x, serie, time: x.time || time }))); + } +} + +// console.log(payload); diff --git a/decoders/connector/tektelic/asset-tracker/assets/logo.png b/decoders/connector/tektelic/asset-tracker/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..19327dfabb31773f271dbf3e0618d4310bfbdac5 GIT binary patch literal 11884 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 offset_in_byte; + let hi = 0; + if (byte < total_bytes - 1) { + hi = (chunk[chunk_idx + 1] & ((1 << offset_in_byte) - 1)) << (8 - offset_in_byte); + } else if (end_bit_chunk !== 0) { + // Truncate last bits + lo &= ((1 << end_bit_chunk) - 1); + } + arr[byte] = hi | lo; + } + return arr; + } + + function apply_data_type(bytes, data_type) { + output = 0; + if (data_type === 'unsigned') { + for (var i = 0; i < bytes.length; ++i) { + output = (to_uint(output << 8)) | bytes[i]; + } + return output; + } + + if (data_type === 'signed') { + for (var i = 0; i < bytes.length; ++i) { + output = (output << 8) | bytes[i]; + } + // Convert to signed, based on value size + if (output > Math.pow(2, 8 * bytes.length - 1)) { + output -= Math.pow(2, 8 * bytes.length); + } + return output; + } + if (data_type === 'bool') { + return !(bytes[0] === 0); + } + if (data_type === 'hexstring') { + return toHexString(bytes); + } + // Incorrect data type + return null; + } + + function decode_field(chunk, start_bit, end_bit, data_type) { + chunk_size = chunk.length; + if (end_bit >= chunk_size * 8) { + return null; // Error: exceeding boundaries of the chunk + } + if (end_bit < start_bit) { + return null; // Error: invalid input + } + arr = extract_bytes(chunk, start_bit, end_bit); + return apply_data_type(arr, data_type); + } + + decoded_data = {}; + decoder = []; + + if (port === 10) { + decoder = [ + { + key: [0x00, 0xBA], + fn(arg) { + decoded_data.battery_status_life = 2.5 + decode_field(arg, 0, 6, 'unsigned') * 0.01; + decoded_data.battery_status_eos_alert = decode_field(arg, 7, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x04], + fn(arg) { + decoded_data.fsm_state = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x67], + fn(arg) { + decoded_data.mcu_temperature = decode_field(arg, 0, 15, 'signed') * 0.1; + return 2; + }, + }, + { + key: [0x00, 0x00], + fn(arg) { + decoded_data.acceleration_alarm = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x71], + fn(arg) { + decoded_data.acceleration_xaxis = decode_field(arg, 0, 15, 'signed') * 0.001; + decoded_data.acceleration_yaxis = decode_field(arg, 16, 31, 'signed') * 0.001; + decoded_data.acceleration_zaxis = decode_field(arg, 32, 47, 'signed') * 0.001; + return 6; + }, + }, + ]; + } + if (port === 100) { + decoder = [ + { + key: [0x00], + fn(arg) { + decoded_data.device_eui = decode_field(arg, 0, 63, 'hexstring'); + return 8; + }, + }, + { + key: [0x01], + fn(arg) { + decoded_data.app_eui = decode_field(arg, 0, 63, 'hexstring'); + return 8; + }, + }, + { + key: [0x02], + fn(arg) { + decoded_data.app_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x03], + fn(arg) { + decoded_data.device_address = decode_field(arg, 0, 31, 'hexstring'); + return 4; + }, + }, + { + key: [0x04], + fn(arg) { + decoded_data.network_session_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x05], + fn(arg) { + decoded_data.app_session_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x10], + fn(arg) { + decoded_data.loramac_join_mode = decode_field(arg, 7, 7, 'unsigned'); + return 2; + }, + }, + { + key: [0x11], + fn(arg) { + decoded_data.loramac_opts_confirm_mode = decode_field(arg, 8, 8, 'unsigned'); + decoded_data.loramac_opts_sync_word = decode_field(arg, 9, 9, 'unsigned'); + decoded_data.loramac_opts_duty_cycle = decode_field(arg, 10, 10, 'unsigned'); + decoded_data.loramac_opts_adr = decode_field(arg, 11, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x12], + fn(arg) { + decoded_data.loramac_dr_tx_dr_number = decode_field(arg, 0, 3, 'unsigned'); + decoded_data.loramac_dr_tx_tx_power_number = decode_field(arg, 8, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x13], + fn(arg) { + decoded_data.loramac_rx2_frequency = decode_field(arg, 0, 31, 'unsigned'); + decoded_data.loramac_rx2_dr_number = decode_field(arg, 32, 39, 'unsigned'); + return 5; + }, + }, + { + key: [0x20], + fn(arg) { + decoded_data.seconds_per_core_tick = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x21], + fn(arg) { + decoded_data.tick_per_battery = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x24], + fn(arg) { + decoded_data.tick_per_accelerometer = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x25], + fn(arg) { + decoded_data.tick_per_ble_default = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x26], + fn(arg) { + decoded_data.tick_per_ble_stillness = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x27], + fn(arg) { + decoded_data.tick_per_ble_mobility = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x28], + fn(arg) { + decoded_data.tick_per_temperature = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x2A], + fn(arg) { + decoded_data.mode_reed_event_type = decode_field(arg, 7, 7, 'unsigned'); + decoded_data.mode_battery_voltage_report = decode_field(arg, 8, 8, 'unsigned'); + decoded_data.mode_acceleration_vector_report = decode_field(arg, 9, 9, 'unsigned'); + decoded_data.mode_temperature_report = decode_field(arg, 10, 10, 'unsigned'); + decoded_data.mode_ble_report = decode_field(arg, 11, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x2B], + fn(arg) { + decoded_data.event_type1_m_value = decode_field(arg, 0, 3, 'unsigned'); + decoded_data.event_type1_n_value = decode_field(arg, 4, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x2C], + fn(arg) { + decoded_data.event_type2_t_value = decode_field(arg, 0, 3, 'unsigned'); + return 1; + }, + }, + { + key: [0x40], + fn(arg) { + decoded_data.accelerometer_xaxis_enabled = decode_field(arg, 0, 0, 'unsigned'); + decoded_data.accelerometer_yaxis_enabled = decode_field(arg, 1, 1, 'unsigned'); + decoded_data.accelerometer_zaxis_enabled = decode_field(arg, 2, 2, 'unsigned'); + return 1; + }, + }, + { + key: [0x41], + fn(arg) { + decoded_data.sensitivity_accelerometer_sample_rate = decode_field(arg, 0, 2, 'unsigned') * 1; + switch (decoded_data.sensitivity_accelerometer_sample_rate) { + case 1: + decoded_data.sensitivity_accelerometer_sample_rate = 1; + break; + case 2: + decoded_data.sensitivity_accelerometer_sample_rate = 10; + break; + case 3: + decoded_data.sensitivity_accelerometer_sample_rate = 25; + break; + case 4: + decoded_data.sensitivity_accelerometer_sample_rate = 50; + break; + case 5: + decoded_data.sensitivity_accelerometer_sample_rate = 100; + break; + case 6: + decoded_data.sensitivity_accelerometer_sample_rate = 200; + break; + case 7: + decoded_data.sensitivity_accelerometer_sample_rate = 400; + break; + default: // invalid value + decoded_data.sensitivity_accelerometer_sample_rate = 0; + break; + } + + decoded_data.sensitivity_accelerometer_measurement_range = decode_field(arg, 4, 5, 'unsigned') * 1; + switch (decoded_data.sensitivity_accelerometer_measurement_range) { + case 0: + decoded_data.sensitivity_accelerometer_measurement_range = 2; + break; + case 1: + decoded_data.sensitivity_accelerometer_measurement_range = 4; + break; + case 2: + decoded_data.sensitivity_accelerometer_measurement_range = 8; + break; + case 3: + decoded_data.sensitivity_accelerometer_measurement_range = 16; + break; + default: + decoded_data.sensitivity_accelerometer_measurement_range = 0; + } + return 1; + }, + }, + { + key: [0x42], + fn(arg) { + decoded_data.acceleration_alarm_threshold_count = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x43], + fn(arg) { + decoded_data.acceleration_alarm_threshold_period = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x44], + fn(arg) { + decoded_data.acceleration_alarm_threshold = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x45], + fn(arg) { + decoded_data.acceleration_alarm_grace_period = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x46], + fn(arg) { + decoded_data.accelerometer_tx_report_periodic_enabled = decode_field(arg, 0, 0, 'unsigned'); + decoded_data.accelerometer_tx_report_alarm_enabled = decode_field(arg, 1, 1, 'unsigned'); + return 1; + }, + }, + { + key: [0x50], + fn(arg) { + decoded_data.ble_mode = decode_field(arg, 7, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x51], + fn(arg) { + decoded_data.ble_scan_interval = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x52], + fn(arg) { + decoded_data.ble_scan_window = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x53], + fn(arg) { + decoded_data.ble_scan_duration = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x54], + fn(arg) { + decoded_data.ble_reported_devices = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x60], + fn(arg) { + decoded_data.temperature_sample_period_idle = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x61], + fn(arg) { + decoded_data.temperature_sample_period_active = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x62], + fn(arg) { + decoded_data.temperature_threshold_high = decode_field(arg, 0, 7, 'unsigned'); + decoded_data.temperature_threshold_low = decode_field(arg, 8, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x63], + fn(arg) { + decoded_data.temperature_threshold_enabled = decode_field(arg, 0, 0, 'unsigned'); + return 1; + }, + }, + { + key: [0x71], + fn(arg) { + decoded_data.firmware_version_app_major_version = decode_field(arg, 0, 7, 'unsigned'); + decoded_data.firmware_version_app_minor_version = decode_field(arg, 8, 15, 'unsigned'); + decoded_data.firmware_version_app_revision = decode_field(arg, 16, 23, 'unsigned'); + decoded_data.firmware_version_loramac_major_version = decode_field(arg, 24, 31, 'unsigned'); + decoded_data.firmware_version_loramac_minor_version = decode_field(arg, 32, 39, 'unsigned'); + decoded_data.firmware_version_loramac_revision = decode_field(arg, 40, 47, 'unsigned'); + decoded_data.firmware_version_region = decode_field(arg, 48, 55, 'unsigned'); + return 7; + }, + }, + ]; + } + + if (port === 25) { + decoder = [ + { + key: [0x0A], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 7 * 8) { + dev_id = decode_field(arg, i, i + 6 * 8 - 1, 'hexstring'); + decoded_data[dev_id] = decode_field(arg, i + 6 * 8, i + 7 * 8 - 1, 'signed'); + count += 7; + } + return count; + }, + }, + ]; + } + + bytes = convertToUint8Array(bytes); + decoded_data.raw = JSON.stringify(byteToArray(bytes)); + decoded_data.port = port; + + for (let bytes_left = bytes.length; bytes_left > 0;) { + let found = false; + for (let i = 0; i < decoder.length; i++) { + const item = decoder[i]; + const key = item.key; + const keylen = key.length; + header = slice(bytes, 0, keylen); + // Header in the data matches to what we expect + if (is_equal(header, key)) { + const f = item.fn; + consumed = f(slice(bytes, keylen, bytes.length)) + keylen; + bytes_left -= consumed; + bytes = slice(bytes, consumed, bytes.length); + found = true; + break; + } + } + if (found) { + continue; + } + // Unable to decode -- headers are not as expected, send raw payload to the application! + decoded_data = {}; + decoded_data.raw = JSON.stringify(byteToArray(bytes)); + decoded_data.port = port; + return decoded_data; + } + + // Converts value to unsigned + function to_uint(x) { + return x >>> 0; + } + + // Checks if two arrays are equal + function is_equal(arr1, arr2) { + if (arr1.length != arr2.length) { + return false; + } + for (let i = 0; i != arr1.length; i++) { + if (arr1[i] != arr2[i]) { + return false; + } + } + return true; + } + + function byteToArray(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(byteArray[i]); + } + return arr; + } + + function convertToUint8Array(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(to_uint(byteArray[i]) & 0xff); + } + return arr; + } + + function toHexString(byteArray) { + const arr = []; + for (let i = 0; i < byteArray.length; ++i) { + arr.push((`0${(byteArray[i] & 0xFF).toString(16)}`).slice(-2)); + } + return arr.join(''); + } + + return decoded_data; +} + + +// Remove unwanted variables. + +payload = payload.filter(x => !ignore_vars.includes(x.variable)); + + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const payload_raw = payload.find(x => x.variable === 'payload_raw' || x.variable === 'payload' || x.variable === 'data'); +const port = payload.find(x => x.variable === 'port' || x.variable === 'fport'); + + +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value, time } = payload_raw; + let { serie } = payload_raw; + serie = new Date().getTime(); + + + // Parse the payload_raw to JSON format (it comes in a String format) + + if (value) { + payload = payload.concat(toTagoFormat(Decoder(Buffer.from(value.replace(/ /g, ''), 'hex'), Number(port.value)), serie)); + } +} diff --git a/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/assets/logo.png b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/assets/logo.png new file mode 100644 index 00000000..e69de29b diff --git a/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/connector.jsonc b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/connector.jsonc new file mode 100644 index 00000000..56f17306 --- /dev/null +++ b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Breeze Indoor Air Quality & CO2 Sensor", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/description.md b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/description.md new file mode 100644 index 00000000..b84e9652 --- /dev/null +++ b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/description.md @@ -0,0 +1 @@ +Non dispersive infrared (NDIR) CO2 sensor over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..46ab3687 --- /dev/null +++ b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "The TEKTELIC BREEZE is a compact and versatile member of the Smart Room Sensor family, designed to enhance the monitoring of indoor environments. It comes in two variants: the standard BREEZE, which measures CO2 levels, temperature, humidity, and light; and the BREEZE-V, which includes all the functionalities of the standard model plus a PIR motion sensor for enhanced environment monitoring.\n\nKey features of the BREEZE series include: \n * user-configurable parameters and thresholds;\n * optimal Battery Life, boasting up to 5+ years;\n * it can be paired with an E-Ink display for easy viewing of measurements.\n\nThese sensors are particularly noted for their precision and reliability, enhanced by features such as automatic CO2 calibration and barometric pressure compensation, which adjust readings based on the deployment altitude to provide accurate and reliable data.\n", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload.js b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload.js new file mode 100644 index 00000000..f7a77099 --- /dev/null +++ b/decoders/connector/tektelic/breeze-indoor-air-quality-co2-sensor/v1.0.0/payload.js @@ -0,0 +1,118 @@ +/* + * Smart Room Sensor (Gen 4) + */ +function signed_convert(val, bitwidth) { + const isnegative = val & (1 << (bitwidth - 1)); + const boundary = 1 << bitwidth; + const minval = -boundary; + const mask = boundary - 1; + return isnegative ? minval + (val & mask) : val; +} +function Decoder(bytes, port, string_find) { + // Decode an uplink message from a buffer + // (array) of bytes to an object of fields. + // Device Info Not Repeated + const array_result = []; + if (port === 10) { + // CO2 Concentration(PressureCompensated) + if (string_find.search("0be4") !== -1) { + const result = string_find.search("0be4") / 2 + 2; + const co2_pressure_compensated = (bytes[result] << 8) | bytes[result + 1]; + array_result.push({ variable: "co2_pressure_compensated", value: co2_pressure_compensated, unit: "ppm" }); + } + if (string_find.search("0BE4") !== -1) { + const result = string_find.search("0BE4") / 2 + 2; + const co2_pressure_compensated = (bytes[result] << 8) | bytes[result + 1]; + array_result.push({ variable: "co2_pressure_compensated", value: co2_pressure_compensated, unit: "ppm" }); + } + // CO2 Concentration(Raw) + if (string_find.search("0ee4") !== -1) { + const result = string_find.search("0be4") / 2 + 2; + const co2_raw = (bytes[result] << 8) | bytes[result + 1]; + array_result.push({ variable: "co2_raw", value: co2_raw, unit: "ppm" }); + } + if (string_find.search("0EE4") !== -1) { + const result = string_find.search("0EE4") / 2 + 2; + const co2_raw = (bytes[result] << 8) | bytes[result + 1]; + array_result.push({ variable: "co2_raw", value: co2_raw, unit: "ppm" }); + } + // Atmospheric Pressure + if (string_find.search("0c73") !== -1) { + const result = string_find.search("0c73") / 2 + 2; + const atmospheric_pressure = ((bytes[result] << 8) | bytes[result + 1]) * 0.1; + array_result.push({ variable: "atmospheric_pressure", value: atmospheric_pressure, unit: "hPa" }); + } + if (string_find.search("0C73") !== -1) { + const result = string_find.search("0C73") / 2 + 2; + const atmospheric_pressure = ((bytes[result] << 8) | bytes[result + 1]) * 0.1; + array_result.push({ variable: "atmospheric_pressure", value: atmospheric_pressure, unit: "hPa" }); + } + // Motion (PIR) Event State + if (string_find.search("0a00") !== -1) { + const result = string_find.search("0a00") / 2 + 2; + const motion_event_state = bytes[result]; + array_result.push({ variable: "motion_event_state", value: motion_event_state }); + } + if (string_find.search("0A00") !== -1) { + const result = string_find.search("0A00") / 2 + 2; + const motion_event_state = bytes[result]; + array_result.push({ variable: "motion_event_state", value: motion_event_state }); + } + // Motion (PIR) Event Count + if (string_find.search("0d04") !== -1) { + const result = string_find.search("0d04") / 2 + 2; + const motion_event_count = (bytes[result] << 8) | bytes[result + 1]; + array_result.push({ variable: "motion_event_count", value: motion_event_count }); + } + if (string_find.search("0D04") !== -1) { + const result = string_find.search("0D04") / 2 + 2; + const motion_event_count = (bytes[result] << 8) | bytes[result + 1]; + array_result.push({ variable: "motion_event_count", value: motion_event_count }); + } + // Ambient Temperature + if (string_find.search("0367") !== -1) { + const result = string_find.search("0367") / 2 + 2; + const ambient_temperature = (bytes[result] << 8) | bytes[result + 1]; + const temperature = signed_convert(ambient_temperature, 16) * 0.1; + array_result.push({ variable: "temperature", value: temperature, unit: "°C" }); + } + // Ambient RH + if (string_find.search("0468") !== -1) { + const result = string_find.search("0468") / 2 + 2; + const relative_humidity = bytes[result] * 0.5; + array_result.push({ variable: "relative_humidity", value: relative_humidity, unit: "%" }); + } + // Ambient Light State + if (string_find.search("0200") !== -1) { + const result = string_find.search("0200") / 2 + 2; + const light_state = bytes[result]; + array_result.push({ variable: "light_state", value: light_state }); + } + + // Ambient Light Intensity + if (string_find.search("1002") !== -1) { + const result = string_find.search("1002") / 2 + 2; + const light_intensity = ((bytes[result] << 8) | bytes[result + 1]) * 0.1; + array_result.push({ variable: "light_intensity", value: light_intensity }); + } + return array_result; + } +} + +const payload_raw = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data" || x.variable === "payload_hex"); +const port = payload.find((x) => x.variable === "port" || x.variable === "fport" || x.variable === "FPort"); +if (payload_raw) { + try { + // Convert the data from Hex to Javascript Buffer. + const buffer = Buffer.from(payload_raw.value, "hex"); + const serie = new Date().getTime(); + const string_find = payload_raw.value; + const payload_aux = Decoder(buffer, port.value, string_find); + payload = payload.concat(payload_aux.map((x) => ({ ...x, serie }))); + } catch (e) { + // Print the error to the Live Inspector. + console.error(e); + // Return the variable parse_error for debugging. + payload = [{ variable: "parse_error", value: e.message }]; + } +} diff --git a/decoders/connector/tektelic/clover-agriculture-sensor/assets/logo.png b/decoders/connector/tektelic/clover-agriculture-sensor/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..864538a785823be80365c9100bc0b95b14fa5f89 GIT binary patch literal 11970 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 F{x3q%g1i6# literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/clover-agriculture-sensor/connector.jsonc b/decoders/connector/tektelic/clover-agriculture-sensor/connector.jsonc new file mode 100644 index 00000000..a71bafa7 --- /dev/null +++ b/decoders/connector/tektelic/clover-agriculture-sensor/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Clover Agriculture Sensor", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/clover-agriculture-sensor/description.md b/decoders/connector/tektelic/clover-agriculture-sensor/description.md new file mode 100644 index 00000000..ce586b52 --- /dev/null +++ b/decoders/connector/tektelic/clover-agriculture-sensor/description.md @@ -0,0 +1 @@ +Soil and ambient sensor for smart agriculture deployments over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..eec922ac --- /dev/null +++ b/decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "The Tektelic CLOVER Agriculture Sensor provies a complete solution for the collection of key soil and environmental metrics \nfor crops such as soil moisture and temperature, air temperature and humidity, and outdoor light monitoring.\n\n• Ruggedized IP-67 enclosure for use in the most challenging outdoor environmental conditions\n• Integrated C-Cell LTC battery provides substantial battery life up to 10 years with a battery status indicator for easy reference\n• All Global ISM Bands\n• Soil Surface or Elevated Mounting Options\n• Internal or Optional External Antenna\n• LoRa device Class A (B)\n• RF power up to 23 dBm (200mW)\n\nThe CLOVER sensor is fully wireless, providing the flexibility to be deployed anywhere without the need for direct power access, and it includes a battery status indicator for maintenance alerts. It's designed to support multiple sensing functions, which not only monitor the basic environmental metrics but also detect changes in light and movement, crucial for comprehensive agricultural management.\n\n", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload.js b/decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload.js new file mode 100644 index 00000000..c951fa71 --- /dev/null +++ b/decoders/connector/tektelic/clover-agriculture-sensor/v1.0.0/payload.js @@ -0,0 +1,146 @@ +function Decoder(bytes, port) { + const decoded = []; + if (port === 10) { + let soil_temp_cont = 0; + let soil_moist_cont = 0; + for (let i = 0; i < bytes.length; ) { + const channel = bytes[i++]; + const type = bytes[i++]; + + if (channel === 0x00 && type === 0xba) { + const byte = bytes.readUInt8(i++); + decoded.push({ variable: "battery_voltage", value: (byte & 0x7f) * 0.01 + 2.5, unit: "V" }); + decoded.push({ variable: "eos_alert", value: byte >> 7 }); + } else if (channel === 0x00 && type === 0xff) { + const byte = bytes.readUInt16BE(i); + i += 2; + decoded.push({ variable: "battery_voltage", value: byte * 0.01, unit: "V" }); + } else if (channel === 0x01 && type === 0x04) { + const byte = bytes.readUInt16BE(i); + decoded.push({ variable: "soil_moisture_raw", value: byte, unit: "kHz" }); + i += 2; + if (byte > 1402 && byte <= 1399) decoded.push({ variable: "soil_gwc", value: 0 }); + else if (byte > 1399 && byte <= 1396) decoded.push({ variable: "soil_gwc", value: 0.1 }); + else if (byte > 1396 && byte <= 1391) decoded.push({ variable: "soil_gwc", value: 0.2 }); + else if (byte > 1391 && byte <= 1386) decoded.push({ variable: "soil_gwc", value: 0.3 }); + else if (byte > 1386 && byte <= 1381) decoded.push({ variable: "soil_gwc", value: 0.4 }); + else if (byte > 1381 && byte <= 1376) decoded.push({ variable: "soil_gwc", value: 0.5 }); + else if (byte > 1376 && byte <= 1371) decoded.push({ variable: "soil_gwc", value: 0.6 }); + else if (byte > 1371 && byte <= 1366) decoded.push({ variable: "soil_gwc", value: 0.7 }); + else if (byte > 1366 && byte <= 1361) decoded.push({ variable: "soil_gwc", value: 0.8 }); + else if (byte > 1361 && byte <= 1356) decoded.push({ variable: "soil_gwc", value: 0.9 }); + else if (byte > 1356 && byte <= 1351) decoded.push({ variable: "soil_gwc", value: 1 }); + else if (byte > 1351 && byte <= 1346) decoded.push({ variable: "soil_gwc", value: 1.1 }); + else if (byte > 1346 && byte <= 1341) decoded.push({ variable: "soil_gwc", value: 1.2 }); + else if (byte > 1341 && byte <= 1322) decoded.push({ variable: "soil_gwc", value: 2 }); + } else if (channel === 0x02 && type === 0x02) { + const byte = bytes.readUInt16BE(i); + decoded.push({ variable: "soil_temp_raw", value: byte, unit: "mV" }); + decoded.push({ variable: "soil_temp", value: -32.46 * Math.log(byte) + 236.36, unit: "°C" }); + i += 2; + } else if (channel === 0x03 && type === 0x02) { + const byte = bytes.readUInt16BE(i); + decoded.push({ variable: "soil_temp_raw1", value: byte, unit: "mV" }); + decoded.push({ variable: "soil_temp1", value: -31.96 * Math.log(byte) + 213.25, unit: "°C" }); + i += 2; + soil_temp_cont += 1; + } else if (channel === 0x04 && type === 0x02) { + const byte = bytes.readUInt16BE(i); + decoded.push({ variable: "soil_temp_raw2", value: byte, unit: "mV" }); + decoded.push({ variable: "soil_temp2", value: -31.96 * Math.log(byte) + 213.25, unit: "°C" }); + i += 2; + soil_temp_cont += 2; + } else if (channel === 0x05 && type === 0x04) { + const byte = bytes.readUInt16BE(i); + decoded.push({ variable: "soil_moisture_raw1", value: byte, unit: "Hz" }); + i += 2; + if (byte < 293) decoded.push({ variable: "soil_water_tension1", value: 200, unit: "kPa" }); + else if (byte <= 485) decoded.push({ variable: "soil_water_tension1", value: 200 - (byte - 293) * 0.5208, unit: "kPa" }); + else if (byte <= 600) decoded.push({ variable: "soil_water_tension1", value: 100 - (byte - 485) * 0.2174, unit: "kPa" }); + else if (byte <= 770) decoded.push({ variable: "soil_water_tension1", value: 75 - (byte - 600) * 0.1176, unit: "kPa" }); + else if (byte <= 1110) decoded.push({ variable: "soil_water_tension1", value: 55 - (byte - 770) * 0.05884, unit: "kPa" }); + else if (byte <= 2820) decoded.push({ variable: "soil_water_tension1", value: 35 - (byte - 1110) * 0.0117, unit: "kPa" }); + else if (byte <= 4330) decoded.push({ variable: "soil_water_tension1", value: 15 - (byte - 2820) * 0.003974, unit: "kPa" }); + else if (byte <= 6430) decoded.push({ variable: "soil_water_tension1", value: 9 - (byte - 4330) * 0.004286, unit: "kPa" }); + else if (byte > 6430) decoded.push({ variable: "soil_water_tension1", value: 0, unit: "kPa" }); + // adjust with soil_temp1 after all variables are collected + soil_moist_cont += 1; + } else if (channel === 0x06 && type === 0x04) { + const byte = bytes.readUInt16BE(i); + decoded.push({ variable: "soil_moisture_raw2", value: byte, unit: "Hz" }); + i += 2; + if (byte < 293) decoded.push({ variable: "soil_water_tension2", value: 200, unit: "kPa" }); + else if (byte <= 485) decoded.push({ variable: "soil_water_tension2", value: 200 - (byte - 293) * 0.5208, unit: "kPa" }); + else if (byte <= 600) decoded.push({ variable: "soil_water_tension2", value: 100 - (byte - 485) * 0.2174, unit: "kPa" }); + else if (byte <= 770) decoded.push({ variable: "soil_water_tension2", value: 75 - (byte - 600) * 0.1176, unit: "kPa" }); + else if (byte <= 1110) decoded.push({ variable: "soil_water_tension2", value: 55 - (byte - 770) * 0.05884, unit: "kPa" }); + else if (byte <= 2820) decoded.push({ variable: "soil_water_tension2", value: 35 - (byte - 1110) * 0.0117, unit: "kPa" }); + else if (byte <= 4330) decoded.push({ variable: "soil_water_tension2", value: 15 - (byte - 2820) * 0.003974, unit: "kPa" }); + else if (byte <= 6430) decoded.push({ variable: "soil_water_tension2", value: 9 - (byte - 4330) * 0.004286, unit: "kPa" }); + else if (byte > 6430) decoded.push({ variable: "soil_water_tension2", value: 0, unit: "kPa" }); + // adjust with soil_temp2 after all variables are collected + soil_moist_cont += 2; + } else if (channel === 0x09 && type === 0x65) { + const byte = bytes.readUInt16BE(i); + decoded.push({ variable: "ambient_light", value: byte, unit: "lux" }); + i += 2; + } else if (channel === 0x09 && type === 0x00) { + const byte = bytes.readUInt8(i++); + decoded.push({ variable: "ambient_light_detected", value: byte === 0x00 ? "no" : "yes" }); + } else if (channel === 0x0a && type === 0x71) { + const byte_x = bytes.readInt16BE(i); + i += 2; + const byte_y = bytes.readInt16BE(i); + i += 2; + const byte_z = bytes.readInt16BE(i); + i += 2; + decoded.push({ variable: "acceleration_xaxis", value: byte_x * 0.001, unit: "g" }); + decoded.push({ variable: "acceleration_yaxis", value: byte_y * 0.001, unit: "g" }); + decoded.push({ variable: "acceleration_zaxis", value: byte_z * 0.001, unit: "g" }); + } else if (channel === 0x0a && type === 0x00) { + const byte = bytes.readUInt8(i++); + decoded.push({ variable: "orientation_alarm", value: byte === 0x00 ? "no" : "yes" }); + } else if (channel === 0x0b && type === 0x67) { + const byte = bytes.readInt16BE(i); + i += 2; + decoded.push({ variable: "ambient_temp", value: byte * 0.1, unit: "°C" }); + } else if (channel === 0x0b && type === 0x68) { + const byte = bytes.readUInt8(i++); + decoded.push({ variable: "ambient_hum", value: byte * 0.5, unit: "%" }); + } else if (channel === 0x0c && type === 0x67) { + const byte = bytes.readInt8(i++); + decoded.push({ variable: "mcu_temp", value: byte * 0.1, unit: "°C" }); + } + } + if (soil_moist_cont > 0 && soil_temp_cont > 0) { + const temp1 = decoded.find((x) => x.variable === "soil_temp1"); + const temp2 = decoded.find((x) => x.variable === "soil_temp2"); + const moist1 = decoded.find((x) => x.variable === "soil_water_tension1"); + const moist2 = decoded.find((x) => x.variable === "soil_water_tension2"); + + if (temp1.value && temp1.value !== 24.0 && moist1.value) { + decoded.push({ variable: "soil_water_tension1_adjusted", value: moist1.value * (1 - 0.019 * (temp1.value - 24)), unit: "kPa" }); + } + if (temp2.value && temp2.value !== 24.0 && moist2.value) { + decoded.push({ variable: "soil_water_tension2_adjusted", value: moist2.value * (1 - 0.019 * (temp2.value - 24)), unit: "kPa" }); + } + } + } + + return decoded; +} + +// let payload = [ +// { variable: "payload", value: "096500000b6700e10b6892" }, +// { variable: "port", value: "10" }, +// ]; + +const data = payload.find((x) => x.variable === "payload" || x.variable === "payload_raw" || x.variable === "data"); +const port = payload.find((x) => x.variable === "port" || x.variable === "fport"); +if (data) { + const serie = new Date().getTime(); + const bytes = Buffer.from(data.value, "hex"); + payload = payload.concat(Decoder(bytes, parseInt(port.value, 10))).map((x) => ({ ...x, serie })); +} + +// console.log(payload); diff --git a/decoders/connector/tektelic/cold-room-temperature-sensor/assets/logo.png b/decoders/connector/tektelic/cold-room-temperature-sensor/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..897bea88a65676e74b35f456a8e92811b289a0f5 GIT binary patch literal 13686 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 literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/cold-room-temperature-sensor/connector.jsonc b/decoders/connector/tektelic/cold-room-temperature-sensor/connector.jsonc new file mode 100644 index 00000000..1c3322f5 --- /dev/null +++ b/decoders/connector/tektelic/cold-room-temperature-sensor/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Cold Room Temperature Sensor", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/cold-room-temperature-sensor/description.md b/decoders/connector/tektelic/cold-room-temperature-sensor/description.md new file mode 100644 index 00000000..897b35f8 --- /dev/null +++ b/decoders/connector/tektelic/cold-room-temperature-sensor/description.md @@ -0,0 +1 @@ +Device for cold chain environment monitoring over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..d30012de --- /dev/null +++ b/decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "* 10 Year Battery Life\n* Restaurant and Food Service Cold Chain\n* Medical and Pharmaceutical Storage\n* Vaccine Storage\n* All Global ISM Bands\n* Small Form Factor for Diverse Deployments\n* Easily Integrated into LoRaWAN® Networks\n* Internal Antenna\n* -40° to +60°C operability ", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload.js b/decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload.js new file mode 100644 index 00000000..989c7938 --- /dev/null +++ b/decoders/connector/tektelic/cold-room-temperature-sensor/v1.0.0/payload.js @@ -0,0 +1,623 @@ +/* This is an generic payload parser example. +** The code find the payload variable and parse it if exists. +** +** IMPORTANT: In most case, you will only need to edit the parsePayload function. +** +** Testing: +** You can do manual tests to this parse by using the Device Emulator. Copy and Paste the following code: +** [{ "variable": "payload", "value": "00 BA 70 00 00 00" }] +** +** The ignore_vars variable in this code should be used to ignore variables +** from the device that you don't want. +*/ + +// let payload = [{ variable: 'payload', value: '00 BA 70 00 00 00'.replace(/ /g, '') }]; + +// Add ignorable variables in this array. + +const ignore_vars = []; + + +function toTagoFormat(object_item, serie, prefix = '') { + const result = []; + + for (const key in object_item) { + if (ignore_vars.includes(key)) continue; + + + if (typeof object_item[key] === 'object') { + result.push({ + + variable: object_item[key].variable || `${prefix}${key}`.toLowerCase(), + + value: object_item[key].value, + + serie: object_item[key].serie || serie, + + metadata: object_item[key].metadata, + + location: object_item[key].location, + + unit: object_item[key].unit, + + }); + } else { + result.push({ + + variable: `${prefix}${key}`.toLowerCase(), + + value: object_item[key], + + serie, + + }); + } + } + + + return result; +} + +function Decoder(bytes, port) { // bytes - Array of bytes (signed) + function slice(a, f, t) { + const res = []; + for (let i = 0; i < t - f; i++) { + res[i] = a[f + i]; + } + return res; + } + + function extract_bytes(chunk, start_bit, end_bit) { + const total_bits = end_bit - start_bit + 1; + const total_bytes = total_bits % 8 === 0 ? to_uint(total_bits / 8) : to_uint(total_bits / 8) + 1; + const offset_in_byte = start_bit % 8; + const end_bit_chunk = total_bits % 8; + const arr = new Array(total_bytes); + for (byte = 0; byte < total_bytes; ++byte) { + const chunk_idx = to_uint(start_bit / 8) + byte; + let lo = chunk[chunk_idx] >> offset_in_byte; + let hi = 0; + if (byte < total_bytes - 1) { + hi = (chunk[chunk_idx + 1] & ((1 << offset_in_byte) - 1)) << (8 - offset_in_byte); + } else if (end_bit_chunk !== 0) { + // Truncate last bits + lo &= ((1 << end_bit_chunk) - 1); + } + arr[byte] = hi | lo; + } + return arr; + } + + function apply_data_type(bytes, data_type) { + output = 0; + if (data_type === 'unsigned') { + for (var i = 0; i < bytes.length; ++i) { + output = (to_uint(output << 8)) | bytes[i]; + } + return output; + } + + if (data_type === 'signed') { + for (var i = 0; i < bytes.length; ++i) { + output = (output << 8) | bytes[i]; + } + // Convert to signed, based on value size + if (output > Math.pow(2, 8 * bytes.length - 1)) { + output -= Math.pow(2, 8 * bytes.length); + } + return output; + } + if (data_type === 'bool') { + return !(bytes[0] === 0); + } + if (data_type === 'hexstring') { + return toHexString(bytes); + } + // Incorrect data type + return null; + } + + function decode_field(chunk, start_bit, end_bit, data_type) { + chunk_size = chunk.length; + if (end_bit >= chunk_size * 8) { + return null; // Error: exceeding boundaries of the chunk + } + if (end_bit < start_bit) { + return null; // Error: invalid input + } + arr = extract_bytes(chunk, start_bit, end_bit); + return apply_data_type(arr, data_type); + } + + decoded_data = {}; + decoder = []; + + if (port === 10) { + decoder = [ + { + key: [0x00, 0xBA], + fn(arg) { + decoded_data.battery_status_life = 2.5 + decode_field(arg, 0, 6, 'unsigned') * 0.01; + decoded_data.battery_status_eos_alert = decode_field(arg, 7, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x04], + fn(arg) { + decoded_data.fsm_state = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x67], + fn(arg) { + decoded_data.mcu_temperature = decode_field(arg, 0, 15, 'signed') * 0.1; + return 2; + }, + }, + { + key: [0x00, 0x00], + fn(arg) { + decoded_data.acceleration_alarm = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x71], + fn(arg) { + decoded_data.acceleration_xaxis = decode_field(arg, 0, 15, 'signed') * 0.001; + decoded_data.acceleration_yaxis = decode_field(arg, 16, 31, 'signed') * 0.001; + decoded_data.acceleration_zaxis = decode_field(arg, 32, 47, 'signed') * 0.001; + return 6; + }, + }, + ]; + } + if (port === 100) { + decoder = [ + { + key: [0x00], + fn(arg) { + decoded_data.device_eui = decode_field(arg, 0, 63, 'hexstring'); + return 8; + }, + }, + { + key: [0x01], + fn(arg) { + decoded_data.app_eui = decode_field(arg, 0, 63, 'hexstring'); + return 8; + }, + }, + { + key: [0x02], + fn(arg) { + decoded_data.app_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x03], + fn(arg) { + decoded_data.device_address = decode_field(arg, 0, 31, 'hexstring'); + return 4; + }, + }, + { + key: [0x04], + fn(arg) { + decoded_data.network_session_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x05], + fn(arg) { + decoded_data.app_session_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x10], + fn(arg) { + decoded_data.loramac_join_mode = decode_field(arg, 7, 7, 'unsigned'); + return 2; + }, + }, + { + key: [0x11], + fn(arg) { + decoded_data.loramac_opts_confirm_mode = decode_field(arg, 8, 8, 'unsigned'); + decoded_data.loramac_opts_sync_word = decode_field(arg, 9, 9, 'unsigned'); + decoded_data.loramac_opts_duty_cycle = decode_field(arg, 10, 10, 'unsigned'); + decoded_data.loramac_opts_adr = decode_field(arg, 11, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x12], + fn(arg) { + decoded_data.loramac_dr_tx_dr_number = decode_field(arg, 0, 3, 'unsigned'); + decoded_data.loramac_dr_tx_tx_power_number = decode_field(arg, 8, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x13], + fn(arg) { + decoded_data.loramac_rx2_frequency = decode_field(arg, 0, 31, 'unsigned'); + decoded_data.loramac_rx2_dr_number = decode_field(arg, 32, 39, 'unsigned'); + return 5; + }, + }, + { + key: [0x20], + fn(arg) { + decoded_data.seconds_per_core_tick = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x21], + fn(arg) { + decoded_data.tick_per_battery = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x24], + fn(arg) { + decoded_data.tick_per_accelerometer = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x25], + fn(arg) { + decoded_data.tick_per_ble_default = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x26], + fn(arg) { + decoded_data.tick_per_ble_stillness = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x27], + fn(arg) { + decoded_data.tick_per_ble_mobility = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x28], + fn(arg) { + decoded_data.tick_per_temperature = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x2A], + fn(arg) { + decoded_data.mode_reed_event_type = decode_field(arg, 7, 7, 'unsigned'); + decoded_data.mode_battery_voltage_report = decode_field(arg, 8, 8, 'unsigned'); + decoded_data.mode_acceleration_vector_report = decode_field(arg, 9, 9, 'unsigned'); + decoded_data.mode_temperature_report = decode_field(arg, 10, 10, 'unsigned'); + decoded_data.mode_ble_report = decode_field(arg, 11, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x2B], + fn(arg) { + decoded_data.event_type1_m_value = decode_field(arg, 0, 3, 'unsigned'); + decoded_data.event_type1_n_value = decode_field(arg, 4, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x2C], + fn(arg) { + decoded_data.event_type2_t_value = decode_field(arg, 0, 3, 'unsigned'); + return 1; + }, + }, + { + key: [0x40], + fn(arg) { + decoded_data.accelerometer_xaxis_enabled = decode_field(arg, 0, 0, 'unsigned'); + decoded_data.accelerometer_yaxis_enabled = decode_field(arg, 1, 1, 'unsigned'); + decoded_data.accelerometer_zaxis_enabled = decode_field(arg, 2, 2, 'unsigned'); + return 1; + }, + }, + { + key: [0x41], + fn(arg) { + decoded_data.sensitivity_accelerometer_sample_rate = decode_field(arg, 0, 2, 'unsigned') * 1; + switch (decoded_data.sensitivity_accelerometer_sample_rate) { + case 1: + decoded_data.sensitivity_accelerometer_sample_rate = 1; + break; + case 2: + decoded_data.sensitivity_accelerometer_sample_rate = 10; + break; + case 3: + decoded_data.sensitivity_accelerometer_sample_rate = 25; + break; + case 4: + decoded_data.sensitivity_accelerometer_sample_rate = 50; + break; + case 5: + decoded_data.sensitivity_accelerometer_sample_rate = 100; + break; + case 6: + decoded_data.sensitivity_accelerometer_sample_rate = 200; + break; + case 7: + decoded_data.sensitivity_accelerometer_sample_rate = 400; + break; + default: // invalid value + decoded_data.sensitivity_accelerometer_sample_rate = 0; + break; + } + + decoded_data.sensitivity_accelerometer_measurement_range = decode_field(arg, 4, 5, 'unsigned') * 1; + switch (decoded_data.sensitivity_accelerometer_measurement_range) { + case 0: + decoded_data.sensitivity_accelerometer_measurement_range = 2; + break; + case 1: + decoded_data.sensitivity_accelerometer_measurement_range = 4; + break; + case 2: + decoded_data.sensitivity_accelerometer_measurement_range = 8; + break; + case 3: + decoded_data.sensitivity_accelerometer_measurement_range = 16; + break; + default: + decoded_data.sensitivity_accelerometer_measurement_range = 0; + } + return 1; + }, + }, + { + key: [0x42], + fn(arg) { + decoded_data.acceleration_alarm_threshold_count = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x43], + fn(arg) { + decoded_data.acceleration_alarm_threshold_period = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x44], + fn(arg) { + decoded_data.acceleration_alarm_threshold = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x45], + fn(arg) { + decoded_data.acceleration_alarm_grace_period = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x46], + fn(arg) { + decoded_data.accelerometer_tx_report_periodic_enabled = decode_field(arg, 0, 0, 'unsigned'); + decoded_data.accelerometer_tx_report_alarm_enabled = decode_field(arg, 1, 1, 'unsigned'); + return 1; + }, + }, + { + key: [0x50], + fn(arg) { + decoded_data.ble_mode = decode_field(arg, 7, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x51], + fn(arg) { + decoded_data.ble_scan_interval = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x52], + fn(arg) { + decoded_data.ble_scan_window = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x53], + fn(arg) { + decoded_data.ble_scan_duration = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x54], + fn(arg) { + decoded_data.ble_reported_devices = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x60], + fn(arg) { + decoded_data.temperature_sample_period_idle = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x61], + fn(arg) { + decoded_data.temperature_sample_period_active = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x62], + fn(arg) { + decoded_data.temperature_threshold_high = decode_field(arg, 0, 7, 'unsigned'); + decoded_data.temperature_threshold_low = decode_field(arg, 8, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x63], + fn(arg) { + decoded_data.temperature_threshold_enabled = decode_field(arg, 0, 0, 'unsigned'); + return 1; + }, + }, + { + key: [0x71], + fn(arg) { + decoded_data.firmware_version_app_major_version = decode_field(arg, 0, 7, 'unsigned'); + decoded_data.firmware_version_app_minor_version = decode_field(arg, 8, 15, 'unsigned'); + decoded_data.firmware_version_app_revision = decode_field(arg, 16, 23, 'unsigned'); + decoded_data.firmware_version_loramac_major_version = decode_field(arg, 24, 31, 'unsigned'); + decoded_data.firmware_version_loramac_minor_version = decode_field(arg, 32, 39, 'unsigned'); + decoded_data.firmware_version_loramac_revision = decode_field(arg, 40, 47, 'unsigned'); + decoded_data.firmware_version_region = decode_field(arg, 48, 55, 'unsigned'); + return 7; + }, + }, + ]; + } + + if (port === 25) { + decoder = [ + { + key: [0x0A], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 7 * 8) { + dev_id = decode_field(arg, i, i + 6 * 8 - 1, 'hexstring'); + decoded_data[dev_id] = decode_field(arg, i + 6 * 8, i + 7 * 8 - 1, 'signed'); + count += 7; + } + return count; + }, + }, + ]; + } + + bytes = convertToUint8Array(bytes); + decoded_data.raw = JSON.stringify(byteToArray(bytes)); + decoded_data.port = port; + + for (let bytes_left = bytes.length; bytes_left > 0;) { + let found = false; + for (let i = 0; i < decoder.length; i++) { + const item = decoder[i]; + const key = item.key; + const keylen = key.length; + header = slice(bytes, 0, keylen); + // Header in the data matches to what we expect + if (is_equal(header, key)) { + const f = item.fn; + consumed = f(slice(bytes, keylen, bytes.length)) + keylen; + bytes_left -= consumed; + bytes = slice(bytes, consumed, bytes.length); + found = true; + break; + } + } + if (found) { + continue; + } + // Unable to decode -- headers are not as expected, send raw payload to the application! + decoded_data = {}; + decoded_data.raw = JSON.stringify(byteToArray(bytes)); + decoded_data.port = port; + return decoded_data; + } + + // Converts value to unsigned + function to_uint(x) { + return x >>> 0; + } + + // Checks if two arrays are equal + function is_equal(arr1, arr2) { + if (arr1.length != arr2.length) { + return false; + } + for (let i = 0; i != arr1.length; i++) { + if (arr1[i] != arr2[i]) { + return false; + } + } + return true; + } + + function byteToArray(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(byteArray[i]); + } + return arr; + } + + function convertToUint8Array(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(to_uint(byteArray[i]) & 0xff); + } + return arr; + } + + function toHexString(byteArray) { + const arr = []; + for (let i = 0; i < byteArray.length; ++i) { + arr.push((`0${(byteArray[i] & 0xFF).toString(16)}`).slice(-2)); + } + return arr.join(''); + } + + return decoded_data; +} + + +// Remove unwanted variables. + +payload = payload.filter(x => !ignore_vars.includes(x.variable)); + + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const payload_raw = payload.find(x => x.variable === 'payload_raw' || x.variable === 'payload' || x.variable === 'data'); +const port = payload.find(x => x.variable === 'port' || x.variable === 'fport'); + + +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value, time } = payload_raw; + let { serie } = payload_raw; + serie = new Date().getTime(); + + + // Parse the payload_raw to JSON format (it comes in a String format) + + if (value) { + payload = payload.concat(toTagoFormat(Decoder(Buffer.from(value.replace(/ /g, ''), 'hex'), Number(port.value)), serie)); + } +} diff --git a/decoders/connector/tektelic/cold-room/assets/logo.png b/decoders/connector/tektelic/cold-room/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c41b4f6bf1642095929660b020530d68d0d91430 GIT binary patch literal 16182 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 literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/cold-room/connector.jsonc b/decoders/connector/tektelic/cold-room/connector.jsonc new file mode 100644 index 00000000..9a9dbdfd --- /dev/null +++ b/decoders/connector/tektelic/cold-room/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Cold Room", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/cold-room/description.md b/decoders/connector/tektelic/cold-room/description.md new file mode 100644 index 00000000..b50877a3 --- /dev/null +++ b/decoders/connector/tektelic/cold-room/description.md @@ -0,0 +1 @@ +Temperature and Humidity Sensor over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/cold-room/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/cold-room/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..ee2d9301 --- /dev/null +++ b/decoders/connector/tektelic/cold-room/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "TEKTELIC’s TUNDRA Sensor is the ideal solution for maintaining optimal and consistent temperatures within cold rooms and refrigerated areas. Applications include food and pharmaceutical storage, where safeguarding the integrity, quality, and safety of products is vital. The device can be implemented within cold storage such as fridges, coolers, cold rooms and even freezers with minimal impact on battery life or radio signal strength.\n\n**General Specifications**\n* Operational Temperature: -40°C to +60°C\n* Ingress Protection: IP67\n* Size: 47 x 43 x 36 mm\n* Battery: C Cell\n\n\n\n", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/cold-room/v1.0.0/payload.js b/decoders/connector/tektelic/cold-room/v1.0.0/payload.js new file mode 100644 index 00000000..b8e43cf4 --- /dev/null +++ b/decoders/connector/tektelic/cold-room/v1.0.0/payload.js @@ -0,0 +1,188 @@ +/* eslint-disable no-nested-ternary */ +/* eslint-disable no-bitwise */ +/* eslint-disable no-plusplus */ +function Decoder(bytes, port) { + const decoded = []; + if (port === 10) { + for (let i = 0; i < bytes.length; ) { + const channel = bytes[i++]; + const type = bytes[i++]; + // battery voltage + if (channel === 0x00 && type === 0xff) { + decoded.push({ variable: "battery_voltage", value: bytes.readInt16BE(i) * 0.01, unit: "V" }); + i += 2; + } + // external connector: digital input state + else if (channel === 0x0e && type === 0x00) { + if (bytes.readUInt8(i) !== 0xff && bytes.readUInt8(i) !== 0x00) { + return [{ variable: "parser_error", value: "Parser error: digital input state only accepts 0x00 or 0xFF" }]; + } + decoded.push({ variable: "extconnector_state", value: bytes[i++] === 0xff ? "open-circuited" : "short-circuited" }); + } + // external connector: digital input count + else if (channel === 0x0f && type === 0x04) { + decoded.push({ variable: "extconnector_count", value: bytes.readUInt16BE(i) }); + i += 2; + } + // mcu temperature + else if (channel === 0x0b && type === 0x67) { + decoded.push({ variable: "mcu_temperature", value: bytes.readInt16BE(i) * 0.1, unit: "°C" }); + i += 2; + } + // ambient temperature + else if (channel === 0x03 && type === 0x67) { + decoded.push({ variable: "ambient_temperature", value: bytes.readInt16BE(i) * 0.1, unit: "°C" }); + i += 2; + } + // ambient rh + else if (channel === 0x04 && type === 0x68) { + decoded.push({ variable: "relative_humidity", value: bytes.readUInt8(i++) * 0.5, unit: "%" }); + } + } + } else if (port === 100) { + for (let i = 0; i < bytes.length; ) { + const address = bytes[i++]; + + if (address === 0x10) { + decoded.push({ variable: "loramac_join_mode", value: bytes.readUInt16BE(i) >> 15 }); + i += 2; + } else if (address === 0x11) { + const opts = bytes.readUInt16BE(i); + decoded.push({ variable: "loramac_opts_confirm_mode", value: opts & 0x01 }); + decoded.push({ variable: "loramac_opts_sync_word", value: (opts >> 1) & 0x01 }); + decoded.push({ variable: "loramac_opts_duty_cycle", value: (opts >> 2) & 0x01 }); + decoded.push({ variable: "loramac_opts_adr", value: (opts >> 3) & 0x01 }); + i += 2; + } else if (address === 0x12) { + const dr_tx = bytes.readUInt16BE(i); + decoded.push({ variable: "loramac_dr_tx_dr_number", value: (dr_tx >> 8) & 0x0f }); + decoded.push({ variable: "loramac_dr_tx_tx_power_number", value: dr_tx & 0x0f }); + i += 2; + } else if (address === 0x13) { + const rx2 = bytes.slice(i, i + 5); + decoded.push({ variable: "loramac_rx2_frequency", value: rx2.readUInt32BE(0), unit: "Hz" }); + decoded.push({ variable: "loramac_rx2_dr_number", value: rx2.readUInt8(4) }); + i += 5; + } else if (address === 0x20) { + const ticks = bytes.readUInt32BE(i); + i += 4; + if ((ticks > 0 && ticks < 60) || ticks > 86400) { + continue; + } + decoded.push({ variable: "seconds_per_core_tick", value: ticks, unit: "sec" }); + } else if (address === 0x21) { + decoded.push({ variable: "tick_per_battery", value: bytes.readUInt16BE(i) }); + i += 2; + } else if (address === 0x22) { + decoded.push({ variable: "tick_per_ambient_temperature", value: bytes.readUInt16BE(i) }); + i += 2; + } else if (address === 0x23) { + decoded.push({ variable: "tick_per_relative_humidity", value: bytes.readUInt16BE(i) }); + i += 2; + } else if (address === 0x27) { + decoded.push({ variable: "tick_per_mcu_temperature", value: bytes.readUInt16BE(i) }); + i += 2; + } else if (address === 0x39) { + const idle = bytes.readUInt32BE(i); + i += 4; + if (idle < 30 || idle > 86400) { + continue; + } + decoded.push({ variable: "temperature_relative_humidity_sample_period_idle", value: idle, unit: "sec" }); + } else if (address === 0x3a) { + const active = bytes.readUInt32BE(i); + if (active < 30 || active > 86400) { + continue; + } + decoded.push({ variable: "temperature_relative_humidity_sample_period_active", value: active, unit: "sec" }); + i += 4; + } else if (address === 0x3b) { + const high = bytes.readInt8(i++); + const low = bytes.readInt8(i++); + if (high <= low) { + continue; + } + decoded.push({ variable: "ambient_temperature_threshold_high", value: high, unit: "°C" }); + decoded.push({ variable: "ambient_temperature_threshold_low", value: low, unit: "°C" }); + } else if (address === 0x3c) { + decoded.push({ variable: "ambient_temperature_threshold_enabled", value: bytes.readUInt8(i++) & 0x01 }); + } else if (address === 0x3d) { + const high = bytes.readUInt8(i++); + const low = bytes.readUInt8(i++); + if (high <= low) { + continue; + } + decoded.push({ variable: "relative_humidity_threshold_high", value: high, unit: "%" }); + decoded.push({ variable: "relative_humidity_threshold_low", value: low, unit: "%" }); + } else if (address === 0x3e) { + decoded.push({ variable: "relative_humidity_threshold_enabled", value: bytes.readUInt8(i++) & 0x01 }); + } else if (address === 0x40) { + const mcu_temperature_period = bytes.readUInt32BE(i); + i += 4; + if (mcu_temperature_period < 30 || mcu_temperature_period > 86400) { + continue; + } + decoded.push({ variable: "mcu_temperature_sample_period_idle", value: mcu_temperature_period, unit: "sec" }); + } else if (address === 0x41) { + const mcu_temperature_period = bytes.readUInt32BE(i); + i += 4; + if (mcu_temperature_period < 30 || mcu_temperature_period > 86400) { + continue; + } + decoded.push({ variable: "mcu_temperature_sample_period_active", value: mcu_temperature_period, unit: "sec" }); + } else if (address === 0x42) { + const high = bytes.readInt8(i++); + const low = bytes.readInt8(i++); + if (high <= low) { + continue; + } + decoded.push({ variable: "mcu_temperature_threshold_high", value: high, unit: "°C" }); + decoded.push({ variable: "mcu_temperature_threshold_low", value: low, unit: "°C" }); + } else if (address === 0x43) { + decoded.push({ variable: "mcu_temperature_threshold_enabled", value: bytes.readUInt8(i++) & 0x01 }); + } else if (address === 0x70) { + const flash = bytes.readUInt16BE(i); + decoded.push({ variable: "write_to_flash_app_configuration", value: (flash >> 14) & 0x01 }); + decoded.push({ variable: "write_to_flash_lora_configuration", value: (flash >> 13) & 0x01 }); + decoded.push({ variable: "write_to_flash_restart_sensor", value: flash & 0x01 }); + i += 2; + } else if (address === 0x71) { + decoded.push({ variable: "firmware_version_app_major_version", value: bytes.readUInt8(i++) }); + decoded.push({ variable: "firmware_version_app_minor_version", value: bytes.readUInt8(i++) }); + decoded.push({ variable: "firmware_version_app_revision", value: bytes.readUInt8(i++) }); + decoded.push({ variable: "firmware_version_loramac_major_version", value: bytes.readUInt8(i++) }); + decoded.push({ variable: "firmware_version_loramac_minor_version", value: bytes.readUInt8(i++) }); + decoded.push({ variable: "firmware_version_loramac_revision", value: bytes.readUInt8(i++) }); + decoded.push({ variable: "firmware_version_region", value: bytes.readUInt8(i++) }); + } else if (address === 0x72) { + const reset = bytes[i++]; + if (reset !== 0x0a && reset !== 0xb0 && reset !== 0xba) { + continue; + } + decoded.push({ + variable: "configuration_factory_reset", + value: `0x${reset.toString(16)}`, + }); + } + } + } + return decoded; +} +/* +let payload = [ + // { variable: "payload", value: "0367000a046828" }, + { variable: "payload", value: "3b46d8" }, + { variable: "port", value: 100 }, +]; +*/ +const data = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data"); +const port = payload.find((x) => x.variable === "port" || x.variable === "fport"); + +if (data && port) { + const buffer = Buffer.from(data.value, "hex"); + const serie = new Date().getTime(); + payload = Decoder(buffer, port.value); + payload = payload.map((x) => ({ ...x, serie })); +} + +// console.log(payload); diff --git a/decoders/connector/tektelic/finch-indoor-panic-button/assets/logo.png b/decoders/connector/tektelic/finch-indoor-panic-button/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1abd0d39c6e5c00e573cd79bf5a91bdc6d7cbbbd GIT binary patch literal 7996 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 literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/finch-indoor-panic-button/connector.jsonc b/decoders/connector/tektelic/finch-indoor-panic-button/connector.jsonc new file mode 100644 index 00000000..1769f2ea --- /dev/null +++ b/decoders/connector/tektelic/finch-indoor-panic-button/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Finch Indoor Panic Button", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/finch-indoor-panic-button/description.md b/decoders/connector/tektelic/finch-indoor-panic-button/description.md new file mode 100644 index 00000000..b51bfee5 --- /dev/null +++ b/decoders/connector/tektelic/finch-indoor-panic-button/description.md @@ -0,0 +1 @@ +Instant Panic Event Notification over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..de9ad3ac --- /dev/null +++ b/decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "TEKTELIC’s SafeAlert Sensor is a compact, mobile, wireless BLE panic button that transmits an emergency signal from any location. SafeAlert is ideal for lone workers, seniors, and children to signal for help in an emergency situation. When triggered, this device instantly sends an SOS message containing location details to designated support staff or security personnel to ensure a rapid response in the event of a panic situation. This device combines the long-range, low-power communication capabilities of LoRaWAN™ with the universal availability and reliability of Bluetooth Low Energy (BLE) to provide real-time location information.\n\n**Specifications**\n* Operational Temperature: 0°C to +60°C\n* 5-year battery life\n* Ingress Protection: IP67\n* Size: 70 x 22 x 25 mm\n* Battery: AA LTC\n* RF Power: 15 dBm\n* RF Sensitivity: up to -137dBm (SF12, 125kHz)\n* ISM Band: All Global ISM Bands\n* Antenna: Internal\n* LoRa Class: Class A", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload.js b/decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload.js new file mode 100644 index 00000000..6599555d --- /dev/null +++ b/decoders/connector/tektelic/finch-indoor-panic-button/v1.0.0/payload.js @@ -0,0 +1,111 @@ +/** + * ## PORTS ## + * - 10: Sensor data from the MCU, battery gauge and accelerometer + * - 25: Report discovered BLE devices + * - 100: Response to configuration and control commands + */ + +function Decoder(bytes, port) { + const decoded = []; + if (port === 10) { + for (let i = 0; i < bytes.length; ) { + const channel = bytes[i++]; + const type = bytes[i++]; + + // battery status - 1byte unsigned + if (channel === 0x00 && type === 0xba) { + const value = bytes.readUInt8(i++); + decoded.push({ variable: "battery_status_life", value: 2.5 + (value & 0x7f) * 0.01, unit: "V" }); + } + // acceleration alarm status - 1byte unsigned + else if (channel === 0x00 && type === 0x00) { + const value = bytes.readUInt8(i++); + decoded.push({ variable: "acceleration_alarm", value: value === 0x00 ? 0 : 1 }); + } + // acceleration vector = 6bytes signed + else if (channel === 0x00 && type === 0x71) { + const valuex = bytes.readInt16BE(i); + i += 2; + const valuey = bytes.readInt16BE(i); + i += 2; + const valuez = bytes.readInt16BE(i); + i += 2; + decoded.push({ variable: "acceleration_vector_xaxis", value: valuex * 0.001, unit: "g" }); + decoded.push({ variable: "acceleration_vector_yaxis", value: valuey * 0.001, unit: "g" }); + decoded.push({ variable: "acceleration_vector_zaxis", value: valuez * 0.001, unit: "g" }); + } + // mcu temperature - 2b signed + else if (channel === 0x00 && type === 0x67) { + const value = bytes.readInt16BE(i); + i += 2; + decoded.push({ variable: "temperature", value: value * 0.1, unit: "°C" }); + } + } + } else if (port === 25) { + const type = bytes[0]; + switch (type) { + case 0x0a: + decoded.push({ variable: "message_type", value: "basic mode" }); + for (let i = 1, j = 1; i < bytes.length; j++) { + const bd_addr = bytes.readUIntBE(i, 6); + i += 6; + const rssi = bytes.readInt8(i++); + decoded.push({ variable: `bd_addr${j}`, value: bd_addr.toString(16).toUpperCase().padStart(12, "0") }); + decoded.push({ variable: `rssi${j}`, value: rssi }); + } + break; + case 0xb0: + decoded.push({ variable: "message_type", value: "whitelisting mode, range 0" }); + for (let i = 1, j = 1; i < bytes.length; j++) { + const bd_addr_lap = bytes.readUIntBE(i, 3); + i += 3; + const rssi = bytes.readInt8(i++); + decoded.push({ variable: `bd_addr_lap${j}`, value: bd_addr_lap.toString(16).toUpperCase().padStart(6, "0") }); + decoded.push({ variable: `rssi${j}`, value: rssi }); + } + break; + case 0xb1: + decoded.push({ variable: "message_type", value: "whitelisting mode, range 1" }); + for (let i = 1, j = 1; i < bytes.length; j++) { + const bd_addr_lap = bytes.readUIntBE(i, 3); + i += 3; + const rssi = bytes.readInt8(i++); + decoded.push({ variable: `bd_addr_lap${j}`, value: bd_addr_lap.toString(16).toUpperCase().padStart(6, "0") }); + decoded.push({ variable: `rssi${j}`, value: rssi }); + } + break; + case 0xb2: + decoded.push({ variable: "message_type", value: "whitelisting mode, range 2" }); + for (let i = 1, j = 1; i < bytes.length; j++) { + const bd_addr_lap = bytes.readUIntBE(i, 3); + i += 3; + const rssi = bytes.readInt8(i++); + decoded.push({ variable: `bd_addr_lap${j}`, value: bd_addr_lap.toString(16).toUpperCase().padStart(6, "0") }); + decoded.push({ variable: `rssi${j}`, value: rssi }); + } + break; + case 0xb3: + decoded.push({ variable: "message_type", value: "whitelisting mode, range 3" }); + for (let i = 1, j = 1; i < bytes.length; j++) { + const bd_addr_lap = bytes.readUIntBE(i, 3); + i += 3; + const rssi = bytes.readInt8(i++); + decoded.push({ variable: `bd_addr_lap${j}`, value: bd_addr_lap.toString(16).toUpperCase().padStart(6, "0") }); + decoded.push({ variable: `rssi${j}`, value: rssi }); + } + break; + default: + break; + } + } + return decoded; +} + +const data = payload.find((x) => x.variable === "payload" || x.variable === "payload_raw" || x.variable === "data"); +const port = payload.find((x) => x.variable === "port" || x.variable === "fport"); + +if (data) { + const serie = data.serie || new Date().getTime(); + const bytes = Buffer.from(data.value, "hex"); + payload = payload.concat(Decoder(bytes, Number(port.value))).map((x) => ({ ...x, serie })); +} diff --git a/decoders/connector/tektelic/flux-smart-ac-outlet/assets/logo.png b/decoders/connector/tektelic/flux-smart-ac-outlet/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2be6b40a181697804c52e570a94534d07d4f1e7b GIT binary patch literal 46022 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 D*Y>5u literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/flux-smart-ac-outlet/connector.jsonc b/decoders/connector/tektelic/flux-smart-ac-outlet/connector.jsonc new file mode 100644 index 00000000..7bfc8d3c --- /dev/null +++ b/decoders/connector/tektelic/flux-smart-ac-outlet/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic FLUX Smart AC Outlet", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/flux-smart-ac-outlet/description.md b/decoders/connector/tektelic/flux-smart-ac-outlet/description.md new file mode 100644 index 00000000..d31077de --- /dev/null +++ b/decoders/connector/tektelic/flux-smart-ac-outlet/description.md @@ -0,0 +1 @@ +Electrical Outlet over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..67b5fecc --- /dev/null +++ b/decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "The TEKTELIC FLUX Smart AC Outlet is an advanced solution for Smart Home and Office automation. It allows for both manual and remote operation of a 120VAC, 60Hz switch via a LoRaWAN® network, offering significant improvements in power consumption management and safety. Features include tamper resistance, easy installation, and integration with comprehensive LoRaWAN® systems. Additionally, the FLUX enables real-time monitoring of energy usage, facilitating energy savings and enhanced security across various settings, making it an ideal choice for energy-conscious users looking to modernize their living or workspace.", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload.js b/decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload.js new file mode 100644 index 00000000..5541c604 --- /dev/null +++ b/decoders/connector/tektelic/flux-smart-ac-outlet/v1.0.0/payload.js @@ -0,0 +1,146 @@ +/* This is an example code for Everynet Parser. +** Everynet send several parameters to TagoIO. The job of this parse is to convert all these parameters into a TagoIO format. +** One of these parameters is the payload of your device. We find it too and apply the appropriate sensor parse. +** +** IMPORTANT: In most case, you will only need to edit the parsePayload function. +** +** Testing: +** You can do manual tests to this parse by using the Device Emulator. Copy and Paste the following code: +** [{ "variable": "everynet_payload", "value": "{ \"params\": { \"payload\": \"0109611395\" } }" }] +** +** The ignore_vars variable in this code should be used to ignore variables +** from the device that you don't want. +*/ +// payload example from the documentation '00FE0001518000006A50000000'; | '0080CB750180415C0081FF'; +// Add ignorable variables in this array. +const ignore_vars = ['device_addr', 'port', 'duplicate', 'network', 'packet_hash', 'application', 'device', 'packet_id']; + + +/** + * Convert an object to TagoIO object format. + * Can be used in two ways: + * toTagoFormat({ myvariable: myvalue , anothervariable: anothervalue... }) + * toTagoFormat({ myvariable: { value: myvalue, unit: 'C', metadata: { color: 'green' }} , anothervariable: anothervalue... }) + * + * @param {Object} object_item Object containing key and value. + * @param {String} serie Serie for the variables + * @param {String} prefix Add a prefix to the variables name + */ +function toTagoFormat(object_item, serie, prefix = '') { + const result = []; + for (const key in object_item) { + if (ignore_vars.includes(key)) continue; + + if (typeof object_item[key] == 'object') { + result.push({ + variable: object_item[key].variable || `${prefix}${key}`, + value: object_item[key].value, + serie: object_item[key].serie || serie, + metadata: object_item[key].metadata, + location: object_item[key].location, + unit: object_item[key].unit, + }); + } else { + result.push({ + variable: `${prefix}${key}`, + value: object_item[key], + serie, + }); + } + } + + return result; +} + +/** + * In the solutions params is where usually latitude and longitude for your antenna signal comes from. + * @param {Object} solutions gateway object from everynet + * @param {String|Number} serie serie for the variables + */ +function transformSolutionParam(solutions, serie) { + let to_tago = []; + for (const s of solutions) { + let convert_json = {}; + convert_json.base_location = { value: `${s.lat}, ${s.lng}`, location: { lat: s.lat, lng: s.lng } }; + delete s.lat; + delete s.lng; + + convert_json = { ...convert_json, ...s }; + to_tago = to_tago.concat(toTagoFormat(convert_json, serie)); + } + + return to_tago; +} + +function parsePayload(payload_raw, serie) { + // If your device is sending something different than hex, like base64, just specify it bellow. + const buffer = Buffer.from(payload_raw, 'hex'); + + const data = {}; + let msg_byte; + let channel; + for (let x = 1; x < buffer.length;) { + switch (buffer[x]) { + case 254: // FE + msg_byte = Buffer.from(buffer.slice(x += 1, x += 4)); + data.elapsed_time = { value: msg_byte.readInt32BE(0), unit: 'seconds', serie }; + msg_byte = Buffer.from(buffer.slice(x, x += 4)); + data.energy_consumed = { value: msg_byte.readInt32BE(0), unit: 'W-h', serie }; + x += 1; + break; + case 0: // 00 + msg_byte = Buffer.from(buffer.slice(x += 1)); + data.energy_consumption_meter_status = { value: msg_byte.readUInt8(0) === 0 ? 'idde' : 'active', serie }; + x += 1; + break; + case 128: // 80 + channel = buffer[x - 1]; + msg_byte = Buffer.from(buffer.slice(x += 1, x += 2)); + if (channel === 0) { + data.real_power = { value: msg_byte.readInt16BE(0) * 0.1, unit: 'W', serie }; + } else { + data.apparent_power = { value: msg_byte.readInt16BE(0) * 0.1, unit: 'W', serie }; + } + x += 1; + break; + case 129: // 81 + msg_byte = Buffer.from(buffer.slice(x += 1)); + data.power_factor = { value: msg_byte.readUInt8(0) < 254 ? msg_byte.readUInt8(0) : 'N/A', unit: 'W', serie }; + x += 1; + break; + case 116: // 74 + msg_byte = Buffer.from(buffer.slice(x += 1, x += 2)); + data.voltmeter = { value: msg_byte.readInt16BE(0) * 0.1, unit: 'Vrms', serie }; + x += 1; + break; + case 117: // 75 + msg_byte = Buffer.from(buffer.slice(x += 1, x += 2)); + data.ammeter = { value: msg_byte.readInt16BE(0) * 0.1, unit: 'Arms', serie }; + x += 1; + break; + case 1: // 01 + msg_byte = Buffer.from(buffer.slice(x += 1)); + data.relay_status = { value: msg_byte.readUInt8(0) === 0 ? 'Open' : 'Closed', serie }; + x += 1; + break; + default: + } + } + + return data; +} + +const everynet_payload = payload.find(x => x.variable === 'payload' || x.variable === 'payload_raw' || x.variable === 'data'); +if (everynet_payload) { + // Get a unique serie for the incoming data. + const serie = everynet_payload.serie || new Date().getTime(); + let vars_to_tago = []; + try { + vars_to_tago = vars_to_tago.concat(toTagoFormat(parsePayload(everynet_payload.value, serie), serie)); + } catch (e) { + // Catch any error in the parse code and send to parse_error variable. + vars_to_tago = vars_to_tago.concat({ variable: 'parse_error', value: e.message || e }); + } + + payload = payload.concat(vars_to_tago); +} diff --git a/decoders/connector/tektelic/industrial-transceiver/assets/logo.png b/decoders/connector/tektelic/industrial-transceiver/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2f6e5e2ae0028b439918bb05a15cd104d9d4af4d GIT binary patch literal 14300 zcmbWeWmH`~&@g&%cZcH8;_j}6gS$HvcXxLR#o^#u++7ZC#oe_OcXzlv-}~Nm@9!^b zC7H~c%+5@bnPex4Qc{pYK_o;3001aJX$cho0HWi+2oLp%v1=J)_$&xpiHj>)nVJFs zo>_kJ-LjBQ_(Q@=>Zw{Nyd2nHsO4dlWmSX16)+wt=YQY4D(AUxJcwnC<(FATez!p= zSQ+~A3>BP5j#yB&kQbg9Q-i9bG1nW;2A6!$sf@lsh#lRGgZk9uNm15jpma4m zMP}MgKE5Z-f=G6o$YM)Bg$CX#9P#1?SL4m`*DO{1fhlh1SB`@b)?j)xJa_$$--EZ! zE;j}%2{k0!OzVYkNqFK-n9RfSV-O3dbYGNfa~1VZEryv|cg7KrOqjRF$FtBI_S)P@ zPu=}s7F`EF4fm4*9;@#|>URqW0o@4J%&^-BeWh(>G1UUYJLk)R9j0EyG>>!EllLxe?)xkM%}0sd4Wi^<@R?mr2Yy@X>Pv=WVk~w_#S2V zuVJ0JUl!*JKNsbnVFqwZEIWK z*l2EPsjjJMXl(rV8TR%*fzM)XU2T3r{?_)Er>AFEcXwP|Tu*PWj;@Zmg@wL>K~PW- zCoB1 ztO;Bql2ov(48&eLhOU-x4KrmJ>=yKG{c2lSl#>1q{Yi`9D6Q=R03c!g7a;%{S@@sG z#vfWhb0Clo0RLHl1zT(XK4GH&g$+Jon*XJN{DiR}|37-G2jBIV=DW4+r?KB`j>LED#C*14Ddr0Ob8Io|T0KBJY1VetZA`ka_>Z zvE!2s)c+6uWC5Tbi1+~jkO6=aqH3P2XJ8wb-NjVu)=44eco|ku^XQ(>87OYV(qk$j z?){_Nw4l4~?~t0>LQ{=wv05}{)Xl1e5P+;#lTQ^O8PxaNmN%td!pOLLX@v;?N3!yF zg8$28uPV|r%Fu-QD6Xv~G&`)D>@v&A0gj(uWXHL7?$vslpV56$7t!dStTP*Q)GMJ} z2@j)dQjeE8ZrZ<#>bDTGqw6207BFqT4e>P0@NI)`()XfTLfywvb95U`+NosQX@&t$ zZri1A*EVh#np)U@gy3fn!WFa7`8>|d5FmwQ03w78_Vw?tCsNxEJvd4RFN1B22S>F@ zU-gxJ!q06_$Yf@koP@!++vaKzhCKCkuhxWyL_At z$^2V9nf5sKnm5RUx~yv|;S`vy zqHg?AxnCD3vgDygf?kNDEAvyk_hJ}1>PO-|>KbD3y=L=?)iOPyw!CS^KtY7uc2hMx`Ok8O+~De}yr<$}6T z9Kk*RsKqDemd63;`>(wtwh)K#5`eZ#qvah}6UlKb4Kw<5LViRtYSOWYM0i#<3CQQ%0+lbP9o60Gp71Wb7nuiVX6f7n{B%e zqp-?nue-@$2^(cv364`n@%%BSh|h=Mo#x}PkfbUPl^AON&PI#kAcH-C!QS^aHT1zh zmZ__8{i8hV+YHngV4qA&S$BFaOp=GT!cr^>~M znw4%8vzNDo3tz-iG~j#k3kbPwSw9M(807Sg-BSZxZXLB0Hz83g-Nu~?x|n)X z09X#Ra6{@ru^VFw+)HGslks8OTnUBES&<2pK3AHI8xPF!6>~s36M{fx>UfC7x?@m` z($@k-FOer=NlVy3Eqc)7>CY!M-WzwLGrzqDnW+YK@9Q0=40?~h_tSrD)8)vHZ0SW1 zeq_vkLyl(aYFGIEgJaNwyU+)T>|E$}GY?uzc-$O~l>F)ea|tc}Z)n@I)pZpJnyRYa zkpNnRR)k?L`J9!ep#NYs}Y07j@2RtEdD{7Duc?F!v7iAuwXb2+#(+ zzMGe=H-<*vQ!V*nW`a=I0CYlLdw$UM&()r^4UFoYk8f%4#lP z(WoO${-KQ}zdvIafa#7n!f&v>rMw8MU1iQkozW4+$QX*1f2j5UjiOHW&p2-ihyJ^} zn}Pv>fT-lPLbj{{4N_O*9V(TSQ7t5`AyuWwNd0D2k(>8Rzla|1{Q~HWo9@kwLe6B) zQH0)*{Y?&(rWs02ZR(g?0o|;1o+&3{#U!Ic0HEnXbakM5k7EG~!lc|_^NO7~b>`9= zKn!*SiNS3rrQ>+eZ~W^4r{Ki<);ue0I!k#q`(W&yn*taHam&IuCTT0yh<_t(`e zs=5IOC-F%KLdAwTqs4DRFw_I|Eg?oRBFLYwy%*WA-s=6myv<0^Bq zdKWevhrI)re(|kZxMlTd9-l;3y+@3RN?%0&l1f~3d=F=XY@-7^@IWtPS9248l7n^i zbn_fQoc{cCB7V}%zBA^lPOXL?JhBBNq#9$lQ;Nn`-OM442Q8o#3BAsan+SZgE&N98 z0Vmi##e0X&#`~kpv#-Y30x`el&dMH0ejr3AkpE-;n3GNG0)_fOp5jt(29B+&3&5yf zx8Toy)jR;{GYNZp^#il;_{Z2q^t|)Dq>o%(s;@Jrp`89bkgiYdU1$7>uG=mIN&k5^>-~rSviUPt$s_L*B*fn=ZwuybRKIww zwS@g0!BINtyMy_T70E*P&~3P_CXqd5|Aw}+wy*ms5O4Dhe|%>|n+!Q!exzaB_0aUx ziL)*dedw6y8rb`jrFXGHzsa<{XzZ>ryD#=70R31XI4N-4U#6l}Q<#XOVXBKn># z8AWSK*17+cB^$(}9-BpwHfgmS8r2-m*|KFL(A<*HJJP;@kCA=I`=aRhO15=4@G>Sf;U=33dQ0yoyzy* zJ0Ty;*=;?7Kb$x0F+()M4V2^_Xu#krzgPf9=U38*9;Io-v-jI6#e_ey*- zz~Z0urH^|a;qW`LLDse=NN$c%#rS#1*?emGOd*I!VR7RRQ$_U|{|7_3M$IyYk^!5P z9Dsskk#MUF*Dhy)uP{j=sDF@{E0;79@_J zNzMFIoSL@;WITf_@FiU`9C+|4szc#lF$S^NH4xcm=fYmCf#b z@+0LOS!QnIWaH={wCt7w%Y#|`UoMBw>2$x}5V8Kle%R{Wa>S zGLm^FgV=XeW(7=}-~m)KoQWwAj3gNM-{yW&UVHI=SLuFjw(7<8V6LQyKu@#=Aqnix z)02Lb1Ig43ySwX*>bCQwVb(TY$0PqorwmuD>UP)W8u4)k(Sn;&pqIV7qMt$#rJ2W! z8l|V7(S(gWrjHQs4Tu2uPIt0%JtN(1SToF>JPNdbn#@b&j*B<>(>(%c;x{gS?J6Z}{E)}z1wZGTAJ}7Qrbx_*_&)_v<=}9zEOIR-AFnpaG zPfQK=W+7vuKfkEvW7L)BJH_Oh5BQMQ@mo%BelF0HpkLfIcV(a^{NSZCT8pdI)%hz# z6#a|3w;-k+J3<1|@- zXNz1C{$Ma}>$rS64(s*RsmUCrR)u0?a z1|ygNe)0V9AEsvxJ#rmqWXfh?#CH02!%H&ftgAtJzEi|c6|Ec%Ih_TI| zc4rB?#eACTui2jGv4u{@N16(lyK@Nx*IstNX@w0~!tbc+#GC8z5|;_;ZsdXE`p@HY z%fi4@Ue)dA{>iQ|)bj-O{0;u2DG=n6MI~l!V6sCTm3wtQ&)ai{@1OFtUz=soSp@v@ znEf~K{*;D$6+cK6OBQCbl`kSKJm-=IF8e+iE%19?biNkp98iz!R;yQs(jYG(`hqR3^nqR1=LZ;V|>UL#VCMl^DPP_ailEuA8 zLky~y-Y)8V+^VGd?F{gM-Q)m@$-5|FFzSBOE&D?B?Q)ArZ(r_xImDZ)_wZ&Q%7t%W3c0z}1Z7e$cS^kO3y-HzI>6>?f`XjKyhJ14)6>s+1id1!< z?PvBkKeLK+r~;boXK}eS(@3^YOYb4cTQB%U%&pk%6Ol!+DzE@6`3pPYz&=P7Vly99 zb?2$+L#z;w*MSXm$a7a@3&XBlAWe%&40wlFDsw=rebPW+^;o{;XTM~%)eFjDR#+}P z-TN-Dpt>Bw7P>hxm$Lj`ts|P^t?O>s)b}>trvb|4kB#<)Pi+>vE%sNX-OgpMTN$`U zW1U!k&2{+5zB6{8al_I5#Swh`h99D7!R6%;N`>p)?LqP=?n+5C&4XCoUxjp)H8xht z53KBTHLx3q8llTmh?d$dpFY5`O}Q{`9Obn*?Lf-qW>DyetwI7;x;&amwjL_ae2(>N z7DilvT*>Yzv9t-8p-8K94`}k+RCzGFjX}(z32L5Et8K2p6d)m<0ok&N@Y09W@k<_) z{i?E|^FI;QjYS74a_7dH>kY>){*qu1XQA{ysNS_S( zR^zxR1j*z}n8MEnJMKYE7*u9jJFR|!yGMPoWsPjMP6V~jpD7TFy370A!({jh$>cQp zy^r868|<0*X?100V4k-da+`1&kLsWN)LClo|27n0_15H`=I|vA2>p$9D)1SZkk8%( z)djIPx+Q(;qnec@_O({HO^6Rx1uilDh2q{3RfxUJc5t)g^pk%2iw15%e&aNh z_*uze5FEQpaqs#};P|Xt*nU`Riqx!YzW?|LKS)Wid}SrCNSoy}UuOTOx{H0Bsyh3Ea}6qp#j)ra@raQG5SRky3WpAR(IycNHUIS_Va z*zB>y`9k)1CyL3h%ed+-GCTabxSo9^0D}sSA80?)PX{X}Y8|vkcc1K$0Y0k>Q%3Dj zP4xQO2RvNGP6nOS?=RdoPbcPFoGGCExbS{EBASec%T2-jwv*$}D(l1rlDAnqnxz_%7@)k^V0X>psmD@x>2AUOoL^^v(g&1_qGo-{7`VtkZTQb#tgbjO}$yzdL zbQXfhPZ4NwEVK%diL9DpcwCWK68XrFPm-zb#b`s5M#SAHuw3IBRr(|-W z6tdF`yKo{YhB;J=pe<>zM8@swvmrt)C&lujId*xJL%*_se=BZqq_vxp$l|8vU7fRs z=Ark7S>*d`MOm3_`cZ)lM?!(nBo0I#;3|)9dPxi&p+{7PW9brxF7BfL-wzL=Q(IyQ z8+CmX!6OA!Tce1i$Ye-pXsDwT5nAsG?XG^;dgp+8^o_#7Y*-5YS2+*ucPK zfDBYo2oms_;!!^vqa&J%%i;PU(j7D{uK5$fNRL1&At3qqgY0&p?ZqPi>O94O+JKMPGauJ&Q8ibLUaO$rqs#` z(`%3f{g%iL9SPx=JF0wo6}=LR;7QsS5~t`#B)ZFZt1S4g1dhEyvN)&YxsLisW&biF zSIqER0zI(jb-qSG>b!ze7%tT1Z%%3aVAi-_^IR73K=c^8X=S0;f|f!U(sGwQsHX4( z=8yg|h9-#EXpA7u0D`bQnng~3a6Y<+zOP{^HQxp zdrXc&;K-RrM_URLI_tnX7J7bgoD$3Brdo^4)A^X$v$dnp8oXK5TISx?2c~_w@K#r- z|N6SUfxbWFeL&B|nY_5vW1*HcB(iU%brT}&AUfGT^?4r_`s-IU zQl2B%nxwmbQBgJrQvrvxQjnv^MN}Ml8S|AQ2*=KccOJVmx4Tw+Mi!DX?BD2bGel+O zs_?pwcBdF87+YxTa4p}hU}7h1UQX@|HSn^I9l=GJjP&0Z3Lhd2{I=o6hy-B(T>zzw zWeomFi(ym^C24le?GK2%;XGct7QG^T)!~!6Rgc`d&ekF*T!|5 zPY-^=bCkD;{({%bh`e0)&F`~+c62`loO~nKE^`2^+io1B8kP%nxl61DY3@cKo^bQZ zYtN(m5=pHnwwC%2vEj6>kEP&iQ2pXV1R z-7-aBHEg&y#DJ%_Sl1RED5kam?*?AVKgp{*qCI zMWMxIhm7%$bsL`kANBK!Sq`Z!TQl5ciyH9G=mIB3*>0JP!3KhK#kzX*`hF^BF;R5o zTA)^_2aT7q$&*Sl)m@9IC;~Ecek9Df+asttF*Bv0*&cD2*!tNOYsHHjI!3-+LGG;? z!7g{0uEG$feJ-tufN7!d6S9FSs059H9Ymrud49%nLh7b14R*s-R}n5KXqEwsOy9F& zUHdwJHHmUH2ib>4iad_4XT~WfAJ~r+{d3@j_n+TY(!O@Mv3s5R!&&OH(>&F5m3hJ~ z2`NKOl#&(@`DrR=D6=;&KmS}mN)QS!v|Zc%e6%8|FVyGOC4iu>jmgoRwvHiwJ4>B= zlyv{I$9|7-kL&S@;M+GHv0r9gmQKIuA zZ3)++(umRhmecCDj&gH?FyNi6j3)vBI7Y}fs!}yyZ=}XARXXF^r08OS>gntf11k+_$q6Ke zb>PWERWKr*K*_0hAsdI;dWJt{F}2~%dMU)q7WntRvNbK_I)DF-Oa&uKl^Y#^CB(p~T7M1KKL6JJH^OdY1@?`T=GcZlAPv+~_2+eR}%!042kDE^mK2PyC?y*9o zy>bhAyv5t|5QR*kf#}i=jj`EsERNAXZ?dqEluOf9XaX7F5x#<`c8a$KtL;cquEpRO zlhm82GHuIg=712vH0@%a3dt)fL`F7O&M!%hrUm}3fl~a<&!{qqP&2k=H){4d`06{~ z$CecKS3wVyj-@HduMFNfwokY?K?^@867_bC7$xW)MdjnN9BpSiCTz)feA$kBM|^K# zsd<8U7hyQj)T!gU%1(TLj99&9TS~`Rr*2_2 zO+Q-j%6E(WnmzgF^_xNVMCG|_G&vFY=f#ci>lvC&aLTfO)Nys=bH0@Sm#Tapmek&k zX;A6hfM+5QV2dN6;RS4u=2K@d!H5~fZ%;;q*M@3%ZvtUo&n`yH#7o|h*Q1L?B8!+6 ztU9ZVij~p)Fse0LWRs-9Swesc09iIBjyOjxm3f?Cavo%cG1PqgJ=W_vzqQ`3Y%t`= zwJ9E_kO!wBW6}Tn%Lj;Mq0thQlWFf|#QWoC#H3AcXyMoBVb6Mz`-YpJ%=@ttt8;+# z(%zC%NvbXc6=2aS4CY6X?e&(U8!PKB%+v_WIC2cL?Vx}?ZQS!bCapmzE>q}|#90cm z45eLey@uOf)QSs*D^6ivtUUtvCN#1RP5hjj4R^NN%%nKZ;g-IXnyElOz+)_d2*5l| zeNs1VDRY*It)W#3=v~%=8-roq!g)mD%RW-8gFm#h7*&{D=!!9Rzhg!o4V>KQP0APpxcNf6g zO?IZ*UB_alb|`Kv8&d18lCs*o5`KIvih0po1xgeS472|IK<5$|7vmvRyD`)1e$s4> z=GKq}>pw#TJRR_ntZb3avZyZY<&XP9TAOEc4atBf`)5v&2!CP_(5f zPUoejx%MXaz$UXTW@|Bk^YHA*00~@}+MpS{g>)Krz`u@-5tY z`+7e+LO3^1DPL1uld{E*jr@tc+lA9Tw#Ch-v2)dtWEvcfwQ~}>6S>FnsDFSB7qanH zcj++>)pDy{3yjyQrTHTQwK+>@wX7QQabGZkQ_}oR?Jy55k*~!H#YY_lq$$=mYcJIc zhwVrNhH5{kGv(d=+`Z9t&%U0E1kk|kmh)MV{|2P;qoE=7hROwtg09;cvW!$^Mpudo z_RGpn$i&E4T*fQVX)N&6?WqvV%~Ro`9g`6l07ZHjigaasA{2-+&NpQABE8z0X=ge} zyCMW-$7q7`6819l@?Dw>$}#Y#Uqs6;?h54)lEVu;s`gJ+cKJ{57c)s1FPz>o4B|r= zOZHMG?p{y;X{F+miwy>i3$mo;1uDfZ{E~AtPvnZ?NwuV!;8dt}D&*MnCh7)gbr~2_B!*%IU=TruBc>iM@vyH+ZG*TpYBzWSqb*A+8h6Nm74W^O zqwYAw@C-eanj0}=d>c9|(r8a%GXQf!nS*?Q@1O-}fbre8xz^}<0SRr|Kup!bU>H5i zRU+u%usLPx{omt>FwJT;^{c2phrC+S9k(tVzHFbqUadrt?!AK>5&rPva>Sbh6^aOzeJi+{q)de}IliE#8gt!D3|;e{-9JsHMMCmiwz|(5Y{Wii{xt%M)p=R@4NS zpOwOVE>ao`C-JQfLdoo@krRQVp%jY*Ax7va(hOLz`xmP%qQ@nYIlNv=S_+UsQPu%c zy2=L%8@yi#>D1Krk1BqBjg)g!ZS@xmE+xg#4$*YG=b{a%nj&r@CS9U-wIDA!N=g?e zueO>8Q@7NXO4~yP zPqn1!YRVfx{2RJb-%I8*wufQpP^dAnzVH;X55~>-t!Oe?PTu=cDi&rS`OXMF5^U!g zX2@*b(_?(Hnt+E!>ZQ;$Pl}?CCXfg>!Kq)DC8Z))XU$TfK}s%Hqh9S|UMQkW`ni;N z_iWaLj!r-)3ZW1aj{s1AueLfi9dqO>)~mN#bA(I|O2(F+E6j}ykEDlU*HTMW6&*~T z72d4!ri{vV5q{c9Z`ki?Iet@5>vgV6wsXg>j?e_E&>ZF9={Pp^@+Q zoeh&UkL-`bPYbtSvN#afGF6~6^>~mHO*k&mZ`DC!?3E*${sXIcZF@O$1DAX*wAOMp zv_E`B6YKNqhdJwWU^ftZZ;@Dv&=?%D;l-lcq;CUF;6-!8-9EIB+cUIIrMc{)am7mE zG>1-GS?i;`Lo>r@!MX(VP+@J>w*ord>KXyfqm2;1tVU_{riL}&o48FoUNBvGK|629 zzU1ct2}HZ$?Q$nSzx!J1jge0(LTQ~%`4r(O-hxnUyAW}@rdr-DmZa7}(B2{fnH(pP zwH644lM(9kMpHCRUC0-SP5lE+qA_vb)KR+mACqrl1bMz*Qu|z{k6aC0;&EK5E(>NS zZbOrh3=#{(@@!$|1$bISlu;r$`r2loRMpucxj-ra4!7b$nUf5V0w5ebohlB9}~S z2ChcjZofnABjM0pt6b{`x>_3s3(45l72+lrsMq|G&4%g&MCA!thp-DF`LV#hXDNQk z7=!tEcc?sa=owTNNKiIB#XrijQlBB3X8lKzo_?`bf5!b4J9A=}@0coSV@;o1hrhp{ zdazr*o^&=w7vOxy2La6@M_ARbB@{I&8uA8{85h=+X=>!@$ciN-T{nH4+4myUWvquq z`1Vv*?Xw-+cG#UJd66~)p2N^tf#`zmz^^7|%I_u4*d*7EFYtz@yv0Kv{QpK)&1Jsh zD72HAMEaP)n@vOd+ZEB2-s?pDzg z%DIk4G^-p(aHlF;3eOIq4mcbs_5s*m<{6#uQ*++dX0!Hu-jCV;0)$N`!z!4~uTN7` zC1JovhNWqkvC}c!638w-veMkC7_R=B^u-o-87`nful;0p!1MAfZQ4z=q1=xo`b!jX zUZ!@(*`oN0Z`R-7%X0U*TvM#Dw(OzW#~O2p>|hP`Ui8RFwL9HX-thQ}CsqCx0_{Wm zF!O_B_OTZHqUqYr>M=CXVt!Y!y|N7@AwH2#6^~LtDN>QjQ0Y!!z@SlB_I&@x& zO6Cu8yBFnaUz1bum_D)7e6$*%Pv zRl~UQt3v+*KW8JiZEmB`^Othi(M4WxQ%A!I?oqqKJsb^O*94_IGll;sTV^D@2ux28 z(IHOs#P8z8OClY^A6ld~9)yooM@%Dt^q}(t{KZN3ipQ_;vHVp<$x$he4A4Os&Oenc zXVGI@Z1y4NBU18@#|3`8Lj{3Ie@u=)8JAY555(hkdun0IL|1 z<=4;-DG5}{eF>Vo`UPN!8K!ka3hA{U#0cp<+ed&@s-z7tq~4}R%)6BlS1-hA?9-4$ zK6zCj?^!&M_D_S*gW^84`)*A(9rZ_rox>64-S`EO1AXa$3T5;eIj7>5*@EL6fa?pw z{vM`z4;^=r)}SKC7`>wpig-+Kg!iF`nsP#P^a-Zs4*WEOsv4hKC??$KI2r-|D=aG~ z`XTg5@RhhvWB>h3LTNdPw*+xW-@FFr{5J1e5!|o2nB`ZlW$yU&Md;bp2KNmwu zl72T8`Z{;EWhOQm;(q6x%?3DmqYlyZjy=D0Cn7L9=1%nAG|D&!3mM|PF7KoyT<}Z% zRA4gfLy7Br2)wK{c${oph7txVoNn?1OUo~It8jCElbU~Ucs|0;LzZcRSe$GiWuJ;S zbp<@Lh1rk_88^mZQ8&q~XHr9{MaWcLdj7rqSqO&y zVXQ)UcYdp~9kIH>>J($3UC;!7k$3(izMe}83WMz=uIraoA4iLohWXrA`|4ip43lbG zwqH@Yf5Yt-^hJi#pgOj`mAUEL#GMg*a$pE#)$nR_3`0HEcj>XeS#2Nazn_1Ltjl@A zEa2|%slX_+^T2CXmxI%vvXBzt@edOJO@Q+Kq7vp(JZV!|pJ1&aCU#PNx{A@l>Gl9M zZG)RCvn+#KR&Tc@)4_E2!nM@xLUt3?6z%Xw#(ve0)hb26Tz;P!4+}?}BTG^T@!fgj zUxED6F}mSRM_;1GzrFf_FoC2QKvUmK{eZBi<+s!=0s)f;=e_Z!y7k32;kkBSB~ApW zgD4b=N!!{2O2p!0{|#g0yVT92{tAolr;hE3>DCoQXNUSWf;VY3wb6p&l78?|CDAAV zenp?Bo>USphC*gKLwdaVK-l*h@O`N(JKHDSx%}sJ_z+r$mYT@S2Ep)eF zRmaqj7TJM-9}ByV1sn$BNoZw3Be=;dLHR!37d*>?S4ZIR=71Pl4qg)3B2Sl&d&=8Qd@kK z+F(=iQ1M`x!-$7lk+3MI3DX)E{wCVrY8tBC(QrSP!AkPQTJ(l~JV=l?ZI{)Ai_-Zt zfAHtZiw4fl#Y)ZXBLc%w^FQoPGrL21)CpDO_Ywnn0Y-5?@avoC{@cPVgZ^mxO}2${ zr8j)U2e9(-FrL14k(@Q0e5##^)R;3Ck8}XpVOAhIlLTO zPGDDPp?$z23rXVZknWI-oY-|dH&CvteWP=5tILqoVFn=+4%MLf*fl4qYeoR*f{rw~$K;?;U=O zC)WO_`XvRnaCceB_<`HEeCqVA5NUPojtCV)9(xKH^pY0)Pt)l=K!Uu`Fd*W_>OG8Q z0?vL=im3(#M8m&QGL*Dpo4SHG@SvOrA4$-LsC%aizs zFsEeId__~OTuE0RjEyT>)@U*3DGa~X9Zs0`RlpQpfIF7LsUJELPpaN&X0yzXTb(AIDk#;9hZcu zZw=)eH@931x7wL^O&XY9Ij=IP!u)g>qH9o%wTq#Aa_XE!VD~%NM|lv-b>b01E2SvMZ?KL;qtI4nYKXCTws`;*8WvK=de+bYQMZaB5@~s_kTB znVY%vBvnI_m>3z-c1z&kfhYO2u_HTG7Y#%Cw%6U=Rkf0fY{Q)oZ^gK}p)*)9^@QfYvXB z(7wjti(Kw2gbqj=ulgNGCR!2t0)9`1i7+#Fs3FwaO-yL)-@1}@e>I?lw?Fy=ZYEC0 zuW=>V!d5YSMY8JLU!7D#xf=&@i_s9X=b9pjoSDgX>i z9t0Z+fR2rz5R%DogHR9KIb^u{-v6FZabliz$lKg??}j42#@?6-xhUTyW=fmb4Q2tG!u45HpU!Y%o=q}7_mbiP2o?r(f`XN?)4)wEi*x7 TTT$r0M@m3R1&L}gqu~Ds`&)$~ literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/industrial-transceiver/connector.jsonc b/decoders/connector/tektelic/industrial-transceiver/connector.jsonc new file mode 100644 index 00000000..fb907c28 --- /dev/null +++ b/decoders/connector/tektelic/industrial-transceiver/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Industrial Transceiver", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/industrial-transceiver/description.md b/decoders/connector/tektelic/industrial-transceiver/description.md new file mode 100644 index 00000000..62b63392 --- /dev/null +++ b/decoders/connector/tektelic/industrial-transceiver/description.md @@ -0,0 +1 @@ + Supports MODBUS® or CAN bus via serial (RS232, RS422, RS485) over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..56223a9f --- /dev/null +++ b/decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "##\nThe Industrial Transceiver and Sensor is used to interface automation and control instrumentation to a LoRaWAN™ network.\n\nIt provides a full suite of serial connectivity options including RS232, RS422 and RS485 to support applications such as MODBUS® or CAN bus over LoRa™.\n\nIt also includes three analog and digital inputs as well as two switched outputs that can be used to control industrial equipment. It comes in an IP67 rated enclosure to support most industrial installation requirements.\n\n", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload.js b/decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload.js new file mode 100644 index 00000000..23496031 --- /dev/null +++ b/decoders/connector/tektelic/industrial-transceiver/v1.0.0/payload.js @@ -0,0 +1,105 @@ +/* eslint-disable no-plusplus */ +const ignore_vars = []; + +/** + * This is the main function to parse the payload. Everything else doesn't require your attention. + * @param {String} payload_raw + * @returns {Object} containing key and value to TagoIO + */ +function parsePayload(payload_raw) { + try { + // If your device is sending something different than hex, like base64, just specify it bellow. + const buffer = Buffer.from(payload_raw, "hex"); + + const data = []; + for (let i = 0; i < buffer.length; ) { + const channel = buffer[i++]; + const type = buffer[i++]; + + // battery voltage + if (channel === 0x00 && type === 0xff) { + data.push({ variable: "battery_voltage", value: buffer.readInt16BE(i) * 0.01, unit: "V" }); + i += 2; + } + // Output 1 + else if (channel === 0x01 && type === 0x01) { + const value = buffer[i++]; + if (value !== 0x00 && value !== 0xff) { + return [{ variable: "parser_error", value: "Parser Error: Output 1 value must be 0x00 or 0xFF" }]; + } + data.push({ variable: "output_1", value: value === 0xff ? "Closed" : "Opened" }); + } + // Output 2 + else if (channel === 0x02 && type === 0x01) { + const value = buffer[i++]; + if (value !== 0x00 && value !== 0xff) { + return [{ variable: "parser_error", value: "Parser Error: Output 2 value must be 0x00 or 0xFF" }]; + } + data.push({ variable: "output_2", value: value === 0xff ? "Closed" : "Opened" }); + } + // Temperature + else if (channel === 0x03 && type === 0x67) { + data.push({ variable: "temperature", value: buffer.readInt16BE(i) * 0.1, unit: "°C" }); + i += 2; + } + // Input 1 State + else if (channel === 0x05 && type === 0x00) { + const value = buffer[i++]; + if (value !== 0x00 && value !== 0x01) { + return [{ variable: "parser_error", value: "Parser Error: Input value must be 0x00 or 0x01" }]; + } + data.push({ variable: "input_1", value: value === 0x01 ? "Opened" : "Closed" }); + } + // Input 2 + else if (channel === 0x06 && type === 0x02) { + data.push({ variable: "input_2", value: buffer.readUInt16BE(i), unit: "uA" }); + i += 2; + } + // Input 3 + else if (channel === 0x07 && type === 0x02) { + data.push({ variable: "input_3", value: buffer.readUInt16BE(i), unit: "mV" }); + i += 2; + } + // Input 1 Count + else if (channel === 0x08 && type === 0x04) { + data.push({ variable: "input_1_count", value: buffer.readUInt16BE(i), unit: "count" }); + i += 2; + } + // MCU temperature + else if (channel === 0x09 && type === 0x67) { + data.push({ variable: "mcu_temperature", value: buffer.readInt16BE(i) * 0.1, unit: "°C" }); + i += 2; + } + } + return data; + } catch (e) { + // eslint-disable-next-line no-console + console.log(e); + // Return the variable parse_error for debugging. + return [{ variable: "parser_error", value: e.message }]; + } +} + +// let payload = [{ variable: "payload", value: "0500ff08040005" }]; + +// Remove unwanted variables. +payload = payload.filter((x) => !ignore_vars.includes(x.variable)); + +const payload_raw = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data"); +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value } = payload_raw; + + let { serie } = payload_raw; + + if (!serie) { + serie = new Date().getTime(); + } + + // Parse the payload_raw to JSON format (it comes in a String format) + if (value) { + payload = payload.concat(parsePayload(value)).map((x) => ({ ...x, serie })); + } +} + +// console.log(payload); diff --git a/decoders/connector/tektelic/mulch-temperature-sensor/assets/logo.png b/decoders/connector/tektelic/mulch-temperature-sensor/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9553b4efca81740ae7c15962f2a6aca70b7404a0 GIT binary patch literal 27497 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 Y7w4NB$scNX%K!iX07*qoM6N<$g3Hddd;kCd literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/mulch-temperature-sensor/connector.jsonc b/decoders/connector/tektelic/mulch-temperature-sensor/connector.jsonc new file mode 100644 index 00000000..f61993b4 --- /dev/null +++ b/decoders/connector/tektelic/mulch-temperature-sensor/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Mulch Temperature Sensor", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/mulch-temperature-sensor/description.md b/decoders/connector/tektelic/mulch-temperature-sensor/description.md new file mode 100644 index 00000000..ac963cd9 --- /dev/null +++ b/decoders/connector/tektelic/mulch-temperature-sensor/description.md @@ -0,0 +1 @@ +Mulch temperature monitoring sensor over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..12b6550c --- /dev/null +++ b/decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "* Commercial Mulch/Compost Storage\n* Precision Agriculture\n* Hydroponics and Smart Greenhouses ", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload.js b/decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload.js new file mode 100644 index 00000000..6d02f7fb --- /dev/null +++ b/decoders/connector/tektelic/mulch-temperature-sensor/v1.0.0/payload.js @@ -0,0 +1,108 @@ +/* This is an generic payload parser example. + ** The code find the payload variable and parse it if exists. + ** + ** IMPORTANT: In most case, you will only need to edit the parsePayload function. + ** + ** Testing: + ** You can do manual tests to this parse by using the Device Emulator. Copy and Paste the following code: + ** [{ "variable": "payload", "value": "0109611395" }] + ** + ** The ignore_vars variable in this code should be used to ignore variables + ** from the device that you don't want. + */ +// Add ignorable variables in this array. +const ignore_vars = []; + +function toTagoFormat(object_item, serie, prefix = "") { + const result = []; + for (const key in object_item) { + if (ignore_vars.includes(key)) continue; + + if (typeof object_item[key] === "object") { + result.push({ + variable: object_item[key].variable || `${prefix}${key}`.toLowerCase(), + value: object_item[key].value, + serie: object_item[key].serie || serie, + metadata: object_item[key].metadata, + location: object_item[key].location, + unit: object_item[key].unit, + }); + } else { + result.push({ + variable: `${prefix}${key}`.toLowerCase(), + value: object_item[key], + serie, + }); + } + } + + return result; +} + +/** + * This is the main function to parse the payload. Everything else doesn't require your attention. + * @param {String} payload_raw + * @returns {Object} containing key and value to TagoIO + */ +function Decoder(payload_raw) { + try { + // If your device is sending something different than hex, like base64, just specify it bellow. + const buffer = Buffer.from(payload_raw, "hex"); + const data = []; + for (let x = 1; x < buffer.length; x++) { + // console.log(buffer.slice(x, x+1).toString('hex')) + if (buffer[x] === 0x00) { + x += 2; + data.push({ variable: "battery_voltage", value: buffer.readInt16BE(x++) * 0.01, unit: "V" }); + } else if (buffer[x] === 0x01) { + x += 2; + data.push({ variable: "output_1", value: buffer.readInt8(x) === -1 ? "Closed" : "Opened" }); + } else if (buffer[x] === 0x02) { + x += 2; + data.push({ variable: "output_2", value: buffer.readInt8(x) === -1 ? "Closed" : "Opened" }); + } else if (buffer[x] === 0x03) { + x += 2; + data.push({ variable: "temperature", value: buffer.readInt16BE(x++) * 0.1, unit: "°C" }); + } else if (buffer[x] === 0x04) { + x += 2; + data.push({ variable: "humidity", value: buffer.readUInt8(x) / 2, unit: "% RH" }); + } else if (buffer[x] === 0x05) { + x += 2; + data.push({ variable: "input_1", value: buffer.readInt8(x) === -1 ? "Closed" : "Opened" }); + } else if (buffer[x] === 0x06) { + x += 2; + data.push({ variable: "input_2", value: buffer.readUInt16LE(x++), unit: "uA" }); + } else if (buffer[x] === 0x07) { + x += 2; + data.push({ variable: "input_3", value: buffer.readUInt16LE(x++), unit: "mV" }); + } else if (buffer[x] === 0x08) { + x += 2; + data.push({ variable: "input_1_count", value: buffer.readUInt16BE(x++), unit: "mV" }); + } + } + return data; + } catch (e) { + console.log(e); + // Return the variable parse_error for debugging. + return [{ variable: "parse_error", value: e.message }]; + } +} +// let payload = [{ variable: 'payload', value: '0104 68 2A 03 67 FF FF 00 FF 01 2C'.replace(/ /g, '') }]; +// let payload = [{ variable: "payload", value: "0104 68 14 05 00 FF 08 04 00 05".replace(/ /g, "") }]; + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const payload_raw = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data"); + +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value, time } = payload_raw; + let { serie } = payload_raw; + serie = new Date().getTime(); + + // Parse the payload_raw to JSON format (it comes in a String format) + + if (value) { + payload = payload.concat(toTagoFormat(Decoder(Buffer.from(value.replace(/ /g, ""), "hex")), serie)); + } +} \ No newline at end of file diff --git a/decoders/connector/tektelic/orca-industrial-gps-tracker/assets/logo.png b/decoders/connector/tektelic/orca-industrial-gps-tracker/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7894d91013d8fe4d5d437b7e4ee66fd0f4dec095 GIT binary patch literal 22308 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 q>*0F19 x.key === "beacon_decoder"); +beacon_decoder = beacon_decoder && beacon_decoder.value === "simple" ? "simple" : null; + +function toTagoFormat(object_item, serie, prefix = "") { + const result = []; + for (const key in object_item) { + if (ignore_vars.includes(key)) continue; + + if (typeof object_item[key] === "object") { + result.push({ + variable: object_item[key].variable || `${prefix}${key}`.toLowerCase(), + value: object_item[key].value, + serie: object_item[key].serie || serie, + metadata: object_item[key].metadata, + location: object_item[key].location, + unit: object_item[key].unit, + }); + } else { + result.push({ + variable: `${prefix}${key}`.toLowerCase(), + value: object_item[key], + serie, + }); + } + } + + return result; +} + +function transformLatLngToLocation(fields, serie, prefix = "") { + if ((fields.latitude && fields.longitude) || (fields.lat && fields.lng)) { + const lat = fields.lat || fields.latitude; + const lng = fields.lng || fields.longitude; + + // Change to TagoIO format. + // Using variable "location". + const variable = { + variable: `${prefix}location`, + value: `${lat}, ${lng}`, + location: { lat, lng }, + serie, + }; + + delete fields.latitude; // remove latitude so it's not parsed later + delete fields.longitude; // remove latitude so it's not parsed later + delete fields.lat; // remove latitude so it's not parsed later + delete fields.lng; // remove latitude so it's not parsed later + + return variable; + } + return null; +} + +function Decoder(bytes, port) { + // bytes - Array of bytes + function slice(a, f, t) { + const res = []; + for (let i = 0; i < t - f; i++) { + res[i] = a[f + i]; + } + return res; + } + + function extract_bytes(chunk, start_bit, end_bit) { + const total_bits = end_bit - start_bit + 1; + const total_bytes = total_bits % 8 === 0 ? to_uint(total_bits / 8) : to_uint(total_bits / 8) + 1; + const offset_in_byte = start_bit % 8; + const end_bit_chunk = total_bits % 8; + const arr = new Array(total_bytes); + for (byte = 0; byte < total_bytes; ++byte) { + const chunk_idx = to_uint(start_bit / 8) + byte; + let lo = chunk[chunk_idx] >> offset_in_byte; + let hi = 0; + if (byte < total_bytes - 1) { + hi = (chunk[chunk_idx + 1] & ((1 << offset_in_byte) - 1)) << (8 - offset_in_byte); + } else if (end_bit_chunk !== 0) { + // Truncate last bits + lo &= (1 << end_bit_chunk) - 1; + } + arr[byte] = hi | lo; + } + return arr; + } + + function apply_data_type(bytes, data_type) { + output = 0; + if (data_type === "unsigned") { + for (var i = 0; i < bytes.length; ++i) { + output = to_uint(output << 8) | bytes[i]; + } + return output; + } + if (data_type === "signed") { + for (var i = 0; i < bytes.length; ++i) { + output = (output << 8) | bytes[i]; + } + // Convert to signed, based on value size + if (output > Math.pow(2, 8 * bytes.length - 1)) { + output -= Math.pow(2, 8 * bytes.length); + } + return output; + } + if (data_type === "bool") { + return !(bytes[0] === 0); + } + if (data_type === "hexstring") { + return toHexString(bytes); + } + // Incorrect data type + return null; + } + + function decode_field(chunk, start_bit, end_bit, data_type) { + chunk_size = chunk.length; + if (end_bit >= chunk_size * 8) { + return null; // Error: exceeding boundaries of the chunk + } + if (end_bit < start_bit) { + return null; // Error: invalid input + } + arr = extract_bytes(chunk, start_bit, end_bit); + return apply_data_type(arr, data_type); + } + + let decoded_data = {}; + let decoder = []; + + if (port === 10) { + decoder = [ + { + key: [0x00, 0xba], + fn(arg) { + decoded_data.battery1_status_life = 2.5 + decode_field(arg, 0, 6, "unsigned") * 0.01; + decoded_data.battery1_status_eos_alert = decode_field(arg, 7, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x01, 0xba], + fn(arg) { + decoded_data.battery2_status_life = 2.5 + decode_field(arg, 0, 6, "unsigned") * 0.01; + decoded_data.battery2_status_eos_alert = decode_field(arg, 7, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x02, 0xba], + fn(arg) { + decoded_data.battery3_status_life = 2.5 + decode_field(arg, 0, 6, "unsigned") * 0.01; + decoded_data.battery3_status_eos_alert = decode_field(arg, 7, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x00, 0x85], + fn(arg) { + const year = decode_field(arg, 0, 15, "unsigned"); + const month = decode_field(arg, 16, 23, "unsigned"); + const day = decode_field(arg, 24, 31, "unsigned"); + const hour = decode_field(arg, 32, 39, "unsigned"); + const minute = decode_field(arg, 40, 47, "unsigned"); + const second = decode_field(arg, 48, 55, "unsigned"); + decoded_data.timestamp = `${year}-${month}-${day} ${hour}:${minute}:${second}`; + + return 7; + }, + }, + { + key: [0x00, 0x92], + fn(arg) { + const ground_speed = decode_field(arg, 0, 15, "unsigned") * 0.1; + decoded_data.ground_speed = Math.round(ground_speed * 10) / 10; + return 2; + }, + }, + { + key: [0x00, 0x88], + fn(arg) { + decoded_data.latitude = decode_field(arg, 0, 23, "signed") * 0.0000125; + decoded_data.longitude = decode_field(arg, 24, 55, "signed") * 0.0000001; + decoded_data.altitude = decode_field(arg, 56, 71, "signed") * 0.5; + return 9; + }, + }, + { + key: [0x00, 0x04], + fn(arg) { + decoded_data.fsm_state = decode_field(arg, 0, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x00, 0x06], + fn(arg) { + decoded_data.fix_status_time = decode_field(arg, 0, 0, "unsigned"); + decoded_data.fix_status_position = decode_field(arg, 1, 1, "unsigned"); + return 1; + }, + }, + { + key: [0x01, 0x06], + fn(arg) { + decoded_data.geofence_status_one = decode_field(arg, 4, 7, "unsigned"); + decoded_data.geofence_status_two = decode_field(arg, 0, 3, "unsigned"); + decoded_data.geofence_status_three = decode_field(arg, 12, 15, "unsigned"); + decoded_data.geofence_status_four = decode_field(arg, 8, 11, "unsigned"); + return 2; + }, + }, + { + key: [0x00, 0x67], + fn(arg) { + decoded_data.mcu_temperature = decode_field(arg, 0, 15, "signed") * 0.1; + return 2; + }, + }, + { + key: [0x00, 0x00], + fn(arg) { + decoded_data.acceleration_alarm = decode_field(arg, 0, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x00, 0x71], + fn(arg) { + decoded_data.acceleration_xaxis = decode_field(arg, 0, 15, "signed") * 0.001; + decoded_data.acceleration_yaxis = decode_field(arg, 16, 31, "signed") * 0.001; + decoded_data.acceleration_zaxis = decode_field(arg, 32, 47, "signed") * 0.001; + return 6; + }, + }, + ]; + } + if (port === 100) { + decoder = [ + { + key: [0x00], + fn(arg) { + decoded_data.device_eui = decode_field(arg, 0, 63, "hexstring"); + return 8; + }, + }, + { + key: [0x01], + fn(arg) { + decoded_data.app_eui = decode_field(arg, 0, 63, "hexstring"); + return 8; + }, + }, + { + key: [0x02], + fn(arg) { + decoded_data.app_key = decode_field(arg, 0, 127, "hexstring"); + return 16; + }, + }, + { + key: [0x03], + fn(arg) { + decoded_data.device_address = decode_field(arg, 0, 31, "hexstring"); + return 4; + }, + }, + { + key: [0x04], + fn(arg) { + decoded_data.network_session_key = decode_field(arg, 0, 127, "hexstring"); + return 16; + }, + }, + { + key: [0x05], + fn(arg) { + decoded_data.app_session_key = decode_field(arg, 0, 127, "hexstring"); + return 16; + }, + }, + { + key: [0x10], + fn(arg) { + decoded_data.loramac_join_mode = decode_field(arg, 7, 7, "unsigned"); + return 2; + }, + }, + { + key: [0x11], + fn(arg) { + decoded_data.loramac_opts_confirm_mode = decode_field(arg, 8, 8, "unsigned"); + decoded_data.loramac_opts_sync_word = decode_field(arg, 9, 9, "unsigned"); + decoded_data.loramac_opts_duty_cycle = decode_field(arg, 10, 10, "unsigned"); + decoded_data.loramac_opts_adr = decode_field(arg, 11, 11, "unsigned"); + return 2; + }, + }, + { + key: [0x12], + fn(arg) { + decoded_data.loramac_dr_tx_dr_number = decode_field(arg, 0, 3, "unsigned"); + decoded_data.loramac_dr_tx_tx_power_number = decode_field(arg, 8, 11, "unsigned"); + return 2; + }, + }, + { + key: [0x13], + fn(arg) { + decoded_data.loramac_rx2_frequency = decode_field(arg, 0, 31, "unsigned"); + decoded_data.loramac_rx2_dr_number = decode_field(arg, 32, 39, "unsigned"); + return 5; + }, + }, + { + key: [0x20], + fn(arg) { + decoded_data.seconds_per_core_tick = decode_field(arg, 0, 31, "unsigned"); + return 4; + }, + }, + { + key: [0x21], + fn(arg) { + decoded_data.tick_per_battery = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x22], + fn(arg) { + decoded_data.tick_per_gps_stillness = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x23], + fn(arg) { + decoded_data.tick_per_gps_mobility = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x24], + fn(arg) { + decoded_data.tick_per_accelerometer = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x25], + fn(arg) { + decoded_data.tick_per_ble_default = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x26], + fn(arg) { + decoded_data.tick_per_ble_stillness = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x27], + fn(arg) { + decoded_data.tick_per_ble_mobility = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x28], + fn(arg) { + decoded_data.tick_per_temperature = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x2a], + fn(arg) { + decoded_data.mode_reed_event_type = decode_field(arg, 7, 7, "unsigned"); + decoded_data.mode_battery_voltage_report = decode_field(arg, 8, 8, "unsigned"); + decoded_data.mode_acceleration_vector_report = decode_field(arg, 9, 9, "unsigned"); + decoded_data.mode_temperature_report = decode_field(arg, 10, 10, "unsigned"); + decoded_data.mode_ble_report = decode_field(arg, 11, 11, "unsigned"); + return 2; + }, + }, + { + key: [0x2b], + fn(arg) { + decoded_data.event_type1_m_value = decode_field(arg, 0, 3, "unsigned"); + decoded_data.event_type1_n_value = decode_field(arg, 4, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x2c], + fn(arg) { + decoded_data.event_type2_t_value = decode_field(arg, 0, 3, "unsigned"); + return 1; + }, + }, + { + key: [0x30], + fn(arg) { + decoded_data.gps_enabled = decode_field(arg, 7, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x31], + fn(arg) { + decoded_data.speed_threshold_mobility = decode_field(arg, 0, 7, "unsigned") * 0.1; + decoded_data.speed_threshold_stillness = decode_field(arg, 8, 15, "unsigned") * 0.1; + return 2; + }, + }, + { + key: [0x32], + fn(arg) { + decoded_data.average_speed_count_mobility = decode_field(arg, 4, 7, "unsigned"); + decoded_data.average_speed_count_stillness = decode_field(arg, 0, 3, "unsigned"); + return 1; + }, + }, + { + key: [0x33], + fn(arg) { + decoded_data.tx_utc_report_enabled = decode_field(arg, 0, 0, "unsigned"); + decoded_data.tx_coordinate_report_enabled = decode_field(arg, 1, 1, "unsigned"); + decoded_data.tx_fsm_report_enabled = decode_field(arg, 2, 2, "unsigned"); + return 1; + }, + }, + { + key: [0x34], + fn(arg) { + decoded_data.geofence_definition1_latitude = decode_field(arg, 0, 23, "unsigned") * 0.0000125; + decoded_data.geofence_definition1_longitude = decode_field(arg, 24, 47, "unsigned") * 0.000025; + decoded_data.geofence_definition1_radius = decode_field(arg, 48, 63, "unsigned") * 10; + return 8; + }, + }, + { + key: [0x35], + fn(arg) { + decoded_data.geofence_definition2_latitude = decode_field(arg, 0, 23, "unsigned") * 0.0000125; + decoded_data.geofence_definition2_longitude = decode_field(arg, 24, 47, "unsigned") * 0.000025; + decoded_data.geofence_definition2_radius = decode_field(arg, 48, 63, "unsigned") * 10; + return 8; + }, + }, + { + key: [0x36], + fn(arg) { + decoded_data.geofence_definition3_latitude = decode_field(arg, 0, 23, "unsigned") * 0.0000125; + decoded_data.geofence_definition3_longitude = decode_field(arg, 24, 47, "unsigned") * 0.000025; + decoded_data.geofence_definition3_radius = decode_field(arg, 48, 63, "unsigned") * 10; + return 8; + }, + }, + { + key: [0x37], + fn(arg) { + decoded_data.geofence_definition4_latitude = decode_field(arg, 0, 23, "unsigned") * 0.0000125; + decoded_data.geofence_definition4_longitude = decode_field(arg, 24, 47, "unsigned") * 0.000025; + decoded_data.geofence_definition4_radius = decode_field(arg, 48, 63, "unsigned") * 10; + return 8; + }, + }, + { + key: [0x40], + fn(arg) { + decoded_data.accelerometer_xaxis_enabled = decode_field(arg, 0, 0, "unsigned"); + decoded_data.accelerometer_yaxis_enabled = decode_field(arg, 1, 1, "unsigned"); + decoded_data.accelerometer_zaxis_enabled = decode_field(arg, 2, 2, "unsigned"); + return 1; + }, + }, + { + key: [0x41], + fn(arg) { + // } + decoded_data.sensitivity_accelerometer_sample_rate = decode_field(arg, 0, 2, "unsigned") * 1; + switch (decoded_data.sensitivity_accelerometer_sample_rate) { + case 1: + decoded_data.sensitivity_accelerometer_sample_rate = 1; + break; + case 2: + decoded_data.sensitivity_accelerometer_sample_rate = 10; + break; + case 3: + decoded_data.sensitivity_accelerometer_sample_rate = 25; + break; + case 4: + decoded_data.sensitivity_accelerometer_sample_rate = 50; + break; + case 5: + decoded_data.sensitivity_accelerometer_sample_rate = 100; + break; + case 6: + decoded_data.sensitivity_accelerometer_sample_rate = 200; + break; + case 7: + decoded_data.sensitivity_accelerometer_sample_rate = 400; + break; + default: + // invalid value + decoded_data.sensitivity_accelerometer_sample_rate = 0; + break; + } + + decoded_data.sensitivity_accelerometer_measurement_range = decode_field(arg, 4, 5, "unsigned") * 1; + switch (decoded_data.sensitivity_accelerometer_measurement_range) { + case 0: + decoded_data.sensitivity_accelerometer_measurement_range = 2; + break; + case 1: + decoded_data.sensitivity_accelerometer_measurement_range = 4; + break; + case 2: + decoded_data.sensitivity_accelerometer_measurement_range = 8; + break; + case 3: + decoded_data.sensitivity_accelerometer_measurement_range = 16; + break; + default: + decoded_data.sensitivity_accelerometer_measurement_range = 0; + } + return 1; + }, + }, + { + key: [0x42], + fn(arg) { + decoded_data.acceleration_alarm_threshold_count = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x43], + fn(arg) { + decoded_data.acceleration_alarm_threshold_period = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x44], + fn(arg) { + decoded_data.acceleration_alarm_threshold = decode_field(arg, 0, 15, "unsigned") * 0.001; + return 2; + }, + }, + { + key: [0x45], + fn(arg) { + decoded_data.acceleration_alarm_grace_period = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x46], + fn(arg) { + decoded_data.accelerometer_tx_report_periodic_enabled = decode_field(arg, 0, 0, "unsigned"); + decoded_data.accelerometer_tx_report_alarm_enabled = decode_field(arg, 1, 1, "unsigned"); + return 1; + }, + }, + { + key: [0x50], + fn(arg) { + decoded_data.ble_mode = decode_field(arg, 7, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x51], + fn(arg) { + decoded_data.ble_scan_interval = decode_field(arg, 0, 15, "unsigned") * 0.001; + return 2; + }, + }, + { + key: [0x52], + fn(arg) { + decoded_data.ble_scan_window = decode_field(arg, 0, 15, "unsigned") * 0.001; + return 2; + }, + }, + { + key: [0x53], + fn(arg) { + decoded_data.ble_scan_duration = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x54], + fn(arg) { + decoded_data.ble_reported_devices = decode_field(arg, 0, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x60], + fn(arg) { + decoded_data.temperature_sample_period_idle = decode_field(arg, 0, 31, "unsigned"); + return 4; + }, + }, + { + key: [0x61], + fn(arg) { + decoded_data.temperature_sample_period_active = decode_field(arg, 0, 31, "unsigned"); + return 4; + }, + }, + { + key: [0x62], + fn(arg) { + decoded_data.temperature_threshold_high = decode_field(arg, 0, 7, "unsigned"); + decoded_data.temperature_threshold_low = decode_field(arg, 8, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x63], + fn(arg) { + decoded_data.temperature_threshold_enabled = decode_field(arg, 0, 0, "unsigned"); + return 1; + }, + }, + { + key: [0x71], + fn(arg) { + decoded_data.firmware_version_app_major_version = decode_field(arg, 0, 7, "unsigned"); + decoded_data.firmware_version_app_minor_version = decode_field(arg, 8, 15, "unsigned"); + decoded_data.firmware_version_app_revision = decode_field(arg, 16, 23, "unsigned"); + decoded_data.firmware_version_loramac_major_version = decode_field(arg, 24, 31, "unsigned"); + decoded_data.firmware_version_loramac_minor_version = decode_field(arg, 32, 39, "unsigned"); + decoded_data.firmware_version_loramac_revision = decode_field(arg, 40, 47, "unsigned"); + decoded_data.firmware_version_region = decode_field(arg, 48, 55, "unsigned"); + return 7; + }, + }, + ]; + } + + if (port === 25) { + decoder = [ + { + key: [0x0a], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 7 * 8) { + dev_id = decode_field(arg, i, i + 6 * 8 - 1, "hexstring"); + if (beacon_decoder === "simple") { + dev_id = `${dev_id}_beacon`; + } + decoded_data[dev_id] = decode_field(arg, i + 6 * 8, i + 7 * 8 - 1, "signed"); + count += 7; + } + return count; + }, + }, + ]; + } + + bytes = convertToUint8Array(bytes); + + for (let bytes_left = bytes.length; bytes_left > 0; ) { + let found = false; + for (let i = 0; i < decoder.length; i++) { + const item = decoder[i]; + const { key } = item; + const keylen = key.length; + header = slice(bytes, 0, keylen); + // Header in the data matches to what we expect + if (is_equal(header, key)) { + const f = item.fn; + consumed = f(slice(bytes, keylen, bytes.length)) + keylen; + bytes_left -= consumed; + bytes = slice(bytes, consumed, bytes.length); + found = true; + break; + } + } + if (found) { + continue; + } + // Unable to decode -- headers are not as expected, send raw payload to the application! + decoded_data = {}; + decoded_data.raw = JSON.stringify(byteToArray(bytes)); + decoded_data.port = port; + return decoded_data; + } + + // Converts value to unsigned + function to_uint(x) { + return x >>> 0; + } + + // Checks if two arrays are equal + function is_equal(arr1, arr2) { + if (arr1.length != arr2.length) { + return false; + } + for (let i = 0; i != arr1.length; i++) { + if (arr1[i] != arr2[i]) { + return false; + } + } + return true; + } + + function byteToArray(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(byteArray[i]); + } + return arr; + } + + function convertToUint8Array(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(to_uint(byteArray[i]) & 0xff); + } + return arr; + } + + function toHexString(byteArray) { + const arr = []; + for (let i = 0; i < byteArray.length; ++i) { + arr.push(`0${(byteArray[i] & 0xff).toString(16)}`.slice(-2)); + } + return arr.join(""); + } + + return decoded_data; +} + +// Remove unwanted variables. +payload = payload.filter((x) => !ignore_vars.includes(x.variable)); + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const payload_raw = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data" || x.variable === "payload_hex"); +const port = payload.find((x) => x.variable === "port" || x.variable === "fport" || x.variable === "FPort"); + +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value, time } = payload_raw; + let { serie } = payload_raw; + serie = new Date().getTime(); + + // Parse the payload_raw to JSON format (it comes in a String format) + + if (value) { + let decoded = Decoder(Buffer.from(value.replace(/ /g, ""), "hex"), Number(port.value)); + + // Apply simplified beacon version; + const beacons = Object.keys(decoded).filter((x) => x.includes("_beacon")); + if (beacons.length) { + decoded.beacons = { + variable: "beacons", + value: beacons.map((x) => `${x.replace("_beacon", "")}: ${decoded[x]}`).join("; "), + metadata: beacons.reduce((final, x) => { + final[x.replace("_beacon", "")] = decoded[x]; + return final; + }, {}), + }; + + decoded = Object.keys(decoded).reduce((final, x) => { + if (!x.includes("_beacon")) { + final[x] = decoded[x]; + } + + return final; + }, {}); + } + + const loc = transformLatLngToLocation(decoded, serie); + if (loc) { + payload = payload.concat(loc); + } + + const timesTamp = decoded.timestamp; + // Parse the payload_raw to JSON format (it comes in a String format) + payload = payload.concat(toTagoFormat(decoded, serie)).map((x) => ({ ...x, serie, time: timesTamp })); + } +} diff --git a/decoders/connector/tektelic/panic-button-sensor/assets/logo.png b/decoders/connector/tektelic/panic-button-sensor/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fc988157f79b7d531962f1f181ce08c13be3bf GIT binary patch literal 4173 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 offset_in_byte; + let hi = 0; + if (byte < total_bytes - 1) { + hi = (chunk[chunk_idx + 1] & ((1 << offset_in_byte) - 1)) << (8 - offset_in_byte); + } else if (end_bit_chunk !== 0) { + // Truncate last bits + lo &= ((1 << end_bit_chunk) - 1); + } + arr[byte] = hi | lo; + } + return arr; + } + + function apply_data_type(bytes, data_type) { + output = 0; + if (data_type === 'unsigned') { + for (var i = 0; i < bytes.length; ++i) { + output = (to_uint(output << 8)) | bytes[i]; + } + return output; + } + + if (data_type === 'signed') { + for (var i = 0; i < bytes.length; ++i) { + output = (output << 8) | bytes[i]; + } + // Convert to signed, based on value size + if (output > Math.pow(2, 8 * bytes.length - 1)) { + output -= Math.pow(2, 8 * bytes.length); + } + return output; + } + if (data_type === 'bool') { + return !(bytes[0] === 0); + } + if (data_type === 'hexstring') { + return toHexString(bytes); + } + // Incorrect data type + return null; + } + + function decode_field(chunk, start_bit, end_bit, data_type) { + chunk_size = chunk.length; + if (end_bit >= chunk_size * 8) { + return null; // Error: exceeding boundaries of the chunk + } + if (end_bit < start_bit) { + return null; // Error: invalid input + } + arr = extract_bytes(chunk, start_bit, end_bit); + return apply_data_type(arr, data_type); + } + + decoded_data = {}; + decoder = []; + + if (port === 10) { + decoder = [ + { + key: [0x00, 0xBA], + fn(arg) { + decoded_data.battery_status_life = 2.5 + decode_field(arg, 0, 6, 'unsigned') * 0.01; + decoded_data.battery_status_eos_alert = decode_field(arg, 7, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x04], + fn(arg) { + decoded_data.fsm_state = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x67], + fn(arg) { + decoded_data.mcu_temperature = decode_field(arg, 0, 15, 'signed') * 0.1; + return 2; + }, + }, + { + key: [0x00, 0x00], + fn(arg) { + decoded_data.acceleration_alarm = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x00, 0x71], + fn(arg) { + decoded_data.acceleration_xaxis = decode_field(arg, 0, 15, 'signed') * 0.001; + decoded_data.acceleration_yaxis = decode_field(arg, 16, 31, 'signed') * 0.001; + decoded_data.acceleration_zaxis = decode_field(arg, 32, 47, 'signed') * 0.001; + return 6; + }, + }, + ]; + } + if (port === 100) { + decoder = [ + { + key: [0x00], + fn(arg) { + decoded_data.device_eui = decode_field(arg, 0, 63, 'hexstring'); + return 8; + }, + }, + { + key: [0x01], + fn(arg) { + decoded_data.app_eui = decode_field(arg, 0, 63, 'hexstring'); + return 8; + }, + }, + { + key: [0x02], + fn(arg) { + decoded_data.app_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x03], + fn(arg) { + decoded_data.device_address = decode_field(arg, 0, 31, 'hexstring'); + return 4; + }, + }, + { + key: [0x04], + fn(arg) { + decoded_data.network_session_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x05], + fn(arg) { + decoded_data.app_session_key = decode_field(arg, 0, 127, 'hexstring'); + return 16; + }, + }, + { + key: [0x10], + fn(arg) { + decoded_data.loramac_join_mode = decode_field(arg, 7, 7, 'unsigned'); + return 2; + }, + }, + { + key: [0x11], + fn(arg) { + decoded_data.loramac_opts_confirm_mode = decode_field(arg, 8, 8, 'unsigned'); + decoded_data.loramac_opts_sync_word = decode_field(arg, 9, 9, 'unsigned'); + decoded_data.loramac_opts_duty_cycle = decode_field(arg, 10, 10, 'unsigned'); + decoded_data.loramac_opts_adr = decode_field(arg, 11, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x12], + fn(arg) { + decoded_data.loramac_dr_tx_dr_number = decode_field(arg, 0, 3, 'unsigned'); + decoded_data.loramac_dr_tx_tx_power_number = decode_field(arg, 8, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x13], + fn(arg) { + decoded_data.loramac_rx2_frequency = decode_field(arg, 0, 31, 'unsigned'); + decoded_data.loramac_rx2_dr_number = decode_field(arg, 32, 39, 'unsigned'); + return 5; + }, + }, + { + key: [0x20], + fn(arg) { + decoded_data.seconds_per_core_tick = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x21], + fn(arg) { + decoded_data.tick_per_battery = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x24], + fn(arg) { + decoded_data.tick_per_accelerometer = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x25], + fn(arg) { + decoded_data.tick_per_ble_default = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x26], + fn(arg) { + decoded_data.tick_per_ble_stillness = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x27], + fn(arg) { + decoded_data.tick_per_ble_mobility = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x28], + fn(arg) { + decoded_data.tick_per_temperature = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x2A], + fn(arg) { + decoded_data.mode_reed_event_type = decode_field(arg, 7, 7, 'unsigned'); + decoded_data.mode_battery_voltage_report = decode_field(arg, 8, 8, 'unsigned'); + decoded_data.mode_acceleration_vector_report = decode_field(arg, 9, 9, 'unsigned'); + decoded_data.mode_temperature_report = decode_field(arg, 10, 10, 'unsigned'); + decoded_data.mode_ble_report = decode_field(arg, 11, 11, 'unsigned'); + return 2; + }, + }, + { + key: [0x2B], + fn(arg) { + decoded_data.event_type1_m_value = decode_field(arg, 0, 3, 'unsigned'); + decoded_data.event_type1_n_value = decode_field(arg, 4, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x2C], + fn(arg) { + decoded_data.event_type2_t_value = decode_field(arg, 0, 3, 'unsigned'); + return 1; + }, + }, + { + key: [0x40], + fn(arg) { + decoded_data.accelerometer_xaxis_enabled = decode_field(arg, 0, 0, 'unsigned'); + decoded_data.accelerometer_yaxis_enabled = decode_field(arg, 1, 1, 'unsigned'); + decoded_data.accelerometer_zaxis_enabled = decode_field(arg, 2, 2, 'unsigned'); + return 1; + }, + }, + { + key: [0x41], + fn(arg) { + decoded_data.sensitivity_accelerometer_sample_rate = decode_field(arg, 0, 2, 'unsigned') * 1; + switch (decoded_data.sensitivity_accelerometer_sample_rate) { + case 1: + decoded_data.sensitivity_accelerometer_sample_rate = 1; + break; + case 2: + decoded_data.sensitivity_accelerometer_sample_rate = 10; + break; + case 3: + decoded_data.sensitivity_accelerometer_sample_rate = 25; + break; + case 4: + decoded_data.sensitivity_accelerometer_sample_rate = 50; + break; + case 5: + decoded_data.sensitivity_accelerometer_sample_rate = 100; + break; + case 6: + decoded_data.sensitivity_accelerometer_sample_rate = 200; + break; + case 7: + decoded_data.sensitivity_accelerometer_sample_rate = 400; + break; + default: // invalid value + decoded_data.sensitivity_accelerometer_sample_rate = 0; + break; + } + + decoded_data.sensitivity_accelerometer_measurement_range = decode_field(arg, 4, 5, 'unsigned') * 1; + switch (decoded_data.sensitivity_accelerometer_measurement_range) { + case 0: + decoded_data.sensitivity_accelerometer_measurement_range = 2; + break; + case 1: + decoded_data.sensitivity_accelerometer_measurement_range = 4; + break; + case 2: + decoded_data.sensitivity_accelerometer_measurement_range = 8; + break; + case 3: + decoded_data.sensitivity_accelerometer_measurement_range = 16; + break; + default: + decoded_data.sensitivity_accelerometer_measurement_range = 0; + } + return 1; + }, + }, + { + key: [0x42], + fn(arg) { + decoded_data.acceleration_alarm_threshold_count = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x43], + fn(arg) { + decoded_data.acceleration_alarm_threshold_period = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x44], + fn(arg) { + decoded_data.acceleration_alarm_threshold = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x45], + fn(arg) { + decoded_data.acceleration_alarm_grace_period = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x46], + fn(arg) { + decoded_data.accelerometer_tx_report_periodic_enabled = decode_field(arg, 0, 0, 'unsigned'); + decoded_data.accelerometer_tx_report_alarm_enabled = decode_field(arg, 1, 1, 'unsigned'); + return 1; + }, + }, + { + key: [0x50], + fn(arg) { + decoded_data.ble_mode = decode_field(arg, 7, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x51], + fn(arg) { + decoded_data.ble_scan_interval = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x52], + fn(arg) { + decoded_data.ble_scan_window = decode_field(arg, 0, 15, 'unsigned') * 0.001; + return 2; + }, + }, + { + key: [0x53], + fn(arg) { + decoded_data.ble_scan_duration = decode_field(arg, 0, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x54], + fn(arg) { + decoded_data.ble_reported_devices = decode_field(arg, 0, 7, 'unsigned'); + return 1; + }, + }, + { + key: [0x60], + fn(arg) { + decoded_data.temperature_sample_period_idle = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x61], + fn(arg) { + decoded_data.temperature_sample_period_active = decode_field(arg, 0, 31, 'unsigned'); + return 4; + }, + }, + { + key: [0x62], + fn(arg) { + decoded_data.temperature_threshold_high = decode_field(arg, 0, 7, 'unsigned'); + decoded_data.temperature_threshold_low = decode_field(arg, 8, 15, 'unsigned'); + return 2; + }, + }, + { + key: [0x63], + fn(arg) { + decoded_data.temperature_threshold_enabled = decode_field(arg, 0, 0, 'unsigned'); + return 1; + }, + }, + { + key: [0x71], + fn(arg) { + decoded_data.firmware_version_app_major_version = decode_field(arg, 0, 7, 'unsigned'); + decoded_data.firmware_version_app_minor_version = decode_field(arg, 8, 15, 'unsigned'); + decoded_data.firmware_version_app_revision = decode_field(arg, 16, 23, 'unsigned'); + decoded_data.firmware_version_loramac_major_version = decode_field(arg, 24, 31, 'unsigned'); + decoded_data.firmware_version_loramac_minor_version = decode_field(arg, 32, 39, 'unsigned'); + decoded_data.firmware_version_loramac_revision = decode_field(arg, 40, 47, 'unsigned'); + decoded_data.firmware_version_region = decode_field(arg, 48, 55, 'unsigned'); + return 7; + }, + }, + ]; + } + + if (port === 25) { + decoder = [ + { + key: [0x0A], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 7 * 8) { + dev_id = decode_field(arg, i, i + 6 * 8 - 1, 'hexstring'); + decoded_data[dev_id] = decode_field(arg, i + 6 * 8, i + 7 * 8 - 1, 'signed'); + count += 7; + } + return count; + }, + }, + ]; + } + + bytes = convertToUint8Array(bytes); + decoded_data.raw = JSON.stringify(byteToArray(bytes)); + decoded_data.port = port; + + for (let bytes_left = bytes.length; bytes_left > 0;) { + let found = false; + for (let i = 0; i < decoder.length; i++) { + const item = decoder[i]; + const key = item.key; + const keylen = key.length; + header = slice(bytes, 0, keylen); + // Header in the data matches to what we expect + if (is_equal(header, key)) { + const f = item.fn; + consumed = f(slice(bytes, keylen, bytes.length)) + keylen; + bytes_left -= consumed; + bytes = slice(bytes, consumed, bytes.length); + found = true; + break; + } + } + if (found) { + continue; + } + // Unable to decode -- headers are not as expected, send raw payload to the application! + decoded_data = {}; + decoded_data.raw = JSON.stringify(byteToArray(bytes)); + decoded_data.port = port; + return decoded_data; + } + + // Converts value to unsigned + function to_uint(x) { + return x >>> 0; + } + + // Checks if two arrays are equal + function is_equal(arr1, arr2) { + if (arr1.length != arr2.length) { + return false; + } + for (let i = 0; i != arr1.length; i++) { + if (arr1[i] != arr2[i]) { + return false; + } + } + return true; + } + + function byteToArray(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(byteArray[i]); + } + return arr; + } + + function convertToUint8Array(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(to_uint(byteArray[i]) & 0xff); + } + return arr; + } + + function toHexString(byteArray) { + const arr = []; + for (let i = 0; i < byteArray.length; ++i) { + arr.push((`0${(byteArray[i] & 0xFF).toString(16)}`).slice(-2)); + } + return arr.join(''); + } + + return decoded_data; +} + + +// Remove unwanted variables. + +payload = payload.filter(x => !ignore_vars.includes(x.variable)); + + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const payload_raw = payload.find(x => x.variable === 'payload_raw' || x.variable === 'payload' || x.variable === 'data'); +const port = payload.find(x => x.variable === 'port' || x.variable === 'fport'); + + +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value, time } = payload_raw; + let { serie } = payload_raw; + serie = new Date().getTime(); + + + // Parse the payload_raw to JSON format (it comes in a String format) + + if (value) { + payload = payload.concat(toTagoFormat(Decoder(Buffer.from(value.replace(/ /g, ''), 'hex'), Number(port.value)), serie)); + } +} diff --git a/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/assets/logo.png b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6b487fccd0bd9567b8dd60d9a114fa4ba7d8d21a GIT binary patch literal 16775 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 I*x>j71)LP95C8xG literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/connector.jsonc b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/connector.jsonc new file mode 100644 index 00000000..1b4bc233 --- /dev/null +++ b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Sparrow Enterprise Asset Tracker", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/description.md b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/description.md new file mode 100644 index 00000000..1968dc5d --- /dev/null +++ b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/description.md @@ -0,0 +1 @@ +Indoor Asset Tracking over BLE and LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..aa113112 --- /dev/null +++ b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload-config.jsonc @@ -0,0 +1,52 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "The TEKTELIC SPARROW is a highly versatile asset tracker that combines the long-range, low-power capabilities of LoRaWAN® with the widespread availability and reliability of Bluetooth Low Energy (BLE). This dual functionality allows the SPARROW to serve as both a tracker and a BLE beacon, making it suitable for a wide range of asset tracking applications in various environments like offices, retail spaces, and manufacturing facilities.\n\nKey features of the SPARROW include:\n * 5 Year Battery Life - Tracker Mode\n * 16 Month Battery Life - Beacon Mode\n * Accelerometer\n * Bluetooth Low Energy Functionality\n * Data Transmission via LoRaWAN™ and BLE\n * All Global ISM Bands\n * Small Form Factor for Diverse Deployments\n * Easily Integrated into LoRaWAN™ Networks\n * Internal Antenna.\n\nThe SPARROW can be configured to increase its reporting frequency when the tracked asset is in motion, which is particularly useful for dynamic asset management. Additionally, it integrates seamlessly with TEKTELIC's Locus application for asset visualization, and it offers an API for integration with third-party real-time location tracking applications. This level of flexibility makes SPARROW an ideal solution for enhancing operational efficiency, reducing asset loss, and improving inventory management across multiple sectors.\n", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [ + { + "default": "", + "group": "main", + "label": "Beacon decoder type", + "name": "beacon_decoder", + "type": "dropdown", + "options": [ + { + "is_default": false, + "label": "One variable with all beacons", + "value": "simple" + }, + { + "is_default": true, + "label": "Split beacon in different variables", + "value": "splitted" + } + ] + }, + { + "default": "2.5", + "group": "main", + "label": "Battery offset", + "name": "battery_offset", + "type": "number" + } + ], + "networks": [ + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js" + ] +} diff --git a/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload.js b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload.js new file mode 100644 index 00000000..1af9113c --- /dev/null +++ b/decoders/connector/tektelic/sparrow-enterprise-asset-tracker/v1.0.0/payload.js @@ -0,0 +1,710 @@ +/* This is an generic payload parser example. + ** The code find the payload variable and parse it if exists. + ** + ** IMPORTANT: In most case, you will only need to edit the parsePayload function. + ** + ** Testing: + ** You can do manual tests to this parse by using the Device Emulator. Copy and Paste the following code: + ** [{ "variable": "payload", "value": "00 BA 70 00 00 00" }] + ** + ** The ignore_vars variable in this code should be used to ignore variables + ** from the device that you don't want. + */ + +// let payload = [{ variable: 'payload', value: '00 BA 70 00 00 00'.replace(/ /g, '') }]; + +// Add ignorable variables in this array. +const ignore_vars = []; +let battery_offset = device.params.find((x) => x.key === "battery_offset"); +battery_offset = battery_offset ? Number(battery_offset.value) : 2.5; + +let beacon_decoder = device.params.find((x) => x.key === "beacon_decoder"); +beacon_decoder = beacon_decoder && beacon_decoder.value === "simple" ? "simple" : null; + +function toTagoFormat(object_item, serie, prefix = "") { + const result = []; + + for (const key in object_item) { + if (ignore_vars.includes(key)) continue; + if (object_item[key] === undefined || object_item[key] === null) { + continue; + } + if (typeof object_item[key] === "object") { + result.push({ + variable: object_item[key].variable || `${prefix}${key}`.toLowerCase(), + + value: object_item[key].value, + + serie: object_item[key].serie || serie, + + metadata: object_item[key].metadata, + + location: object_item[key].location, + + unit: object_item[key].unit, + }); + } else { + result.push({ + variable: `${prefix}${key}`.toLowerCase(), + + value: object_item[key], + + serie, + }); + } + } + + return result; +} + +function Decoder(bytes, port) { + // bytes - Array of bytes (signed) + function slice(a, f, t) { + const res = []; + for (let i = 0; i < t - f; i++) { + res[i] = a[f + i]; + } + return res; + } + + function extract_bytes(chunk, start_bit, end_bit) { + const total_bits = end_bit - start_bit + 1; + const total_bytes = total_bits % 8 === 0 ? to_uint(total_bits / 8) : to_uint(total_bits / 8) + 1; + const offset_in_byte = start_bit % 8; + const end_bit_chunk = total_bits % 8; + const arr = new Array(total_bytes); + for (byte = 0; byte < total_bytes; ++byte) { + const chunk_idx = to_uint(start_bit / 8) + byte; + let lo = chunk[chunk_idx] >> offset_in_byte; + let hi = 0; + if (byte < total_bytes - 1) { + hi = (chunk[chunk_idx + 1] & ((1 << offset_in_byte) - 1)) << (8 - offset_in_byte); + } else if (end_bit_chunk !== 0) { + // Truncate last bits + lo &= (1 << end_bit_chunk) - 1; + } + arr[byte] = hi | lo; + } + return arr; + } + + function apply_data_type(bytes, data_type) { + output = 0; + if (data_type === "unsigned") { + for (var i = 0; i < bytes.length; ++i) { + output = to_uint(output << 8) | bytes[i]; + } + return output; + } + + if (data_type === "signed") { + for (var i = 0; i < bytes.length; ++i) { + output = (output << 8) | bytes[i]; + } + // Convert to signed, based on value size + if (output > Math.pow(2, 8 * bytes.length - 1)) { + output -= Math.pow(2, 8 * bytes.length); + } + return output; + } + if (data_type === "bool") { + return !(bytes[0] === 0); + } + if (data_type === "hexstring") { + return toHexString(bytes); + } + // Incorrect data type + return null; + } + + function decode_field(chunk, start_bit, end_bit, data_type) { + chunk_size = chunk.length; + if (end_bit >= chunk_size * 8) { + return null; // Error: exceeding boundaries of the chunk + } + if (end_bit < start_bit) { + return null; // Error: invalid input + } + arr = extract_bytes(chunk, start_bit, end_bit); + return apply_data_type(arr, data_type); + } + + decoded_data = {}; + decoder = []; + + if (port === 10) { + decoder = [ + { + key: [0x00, 0xd3], + fn(arg) { + decoded_data.battery_status_life = { value: decode_field(arg, 0, 6, "unsigned"), "unit": "%" }; + return 1; + }, + }, + { + key: [0x00, 0xba], + fn(arg) { + decoded_data.battery_status_life = { value: battery_offset + decode_field(arg, 0, 6, "unsigned") * 0.01, unit: "V" }; + decoded_data.battery_status_eos_alert = decode_field(arg, 7, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x00, 0x04], + fn(arg) { + decoded_data.fsm_state = decode_field(arg, 0, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x00, 0x67], + fn(arg) { + decoded_data.mcu_temperature = decode_field(arg, 0, 15, "signed") * 0.1; + return 2; + }, + }, + { + key: [0x00, 0x00], + fn(arg) { + decoded_data.acceleration_alarm = decode_field(arg, 0, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x00, 0x71], + fn(arg) { + decoded_data.acceleration_xaxis = decode_field(arg, 0, 15, "signed") * 0.001; + decoded_data.acceleration_yaxis = decode_field(arg, 16, 31, "signed") * 0.001; + decoded_data.acceleration_zaxis = decode_field(arg, 32, 47, "signed") * 0.001; + return 6; + }, + }, + ]; + } + if (port === 100) { + decoder = [ + { + key: [0x00], + fn(arg) { + decoded_data.device_eui = decode_field(arg, 0, 63, "hexstring"); + return 8; + }, + }, + { + key: [0x01], + fn(arg) { + decoded_data.app_eui = decode_field(arg, 0, 63, "hexstring"); + return 8; + }, + }, + { + key: [0x02], + fn(arg) { + decoded_data.app_key = decode_field(arg, 0, 127, "hexstring"); + return 16; + }, + }, + { + key: [0x03], + fn(arg) { + decoded_data.device_address = decode_field(arg, 0, 31, "hexstring"); + return 4; + }, + }, + { + key: [0x04], + fn(arg) { + decoded_data.network_session_key = decode_field(arg, 0, 127, "hexstring"); + return 16; + }, + }, + { + key: [0x05], + fn(arg) { + decoded_data.app_session_key = decode_field(arg, 0, 127, "hexstring"); + return 16; + }, + }, + { + key: [0x10], + fn(arg) { + decoded_data.loramac_join_mode = decode_field(arg, 7, 7, "unsigned"); + return 2; + }, + }, + { + key: [0x11], + fn(arg) { + decoded_data.loramac_opts_confirm_mode = decode_field(arg, 8, 8, "unsigned"); + decoded_data.loramac_opts_sync_word = decode_field(arg, 9, 9, "unsigned"); + decoded_data.loramac_opts_duty_cycle = decode_field(arg, 10, 10, "unsigned"); + decoded_data.loramac_opts_adr = decode_field(arg, 11, 11, "unsigned"); + return 2; + }, + }, + { + key: [0x12], + fn(arg) { + decoded_data.loramac_dr_tx_dr_number = decode_field(arg, 0, 3, "unsigned"); + decoded_data.loramac_dr_tx_tx_power_number = decode_field(arg, 8, 11, "unsigned"); + return 2; + }, + }, + { + key: [0x13], + fn(arg) { + decoded_data.loramac_rx2_frequency = decode_field(arg, 0, 31, "unsigned"); + decoded_data.loramac_rx2_dr_number = decode_field(arg, 32, 39, "unsigned"); + return 5; + }, + }, + { + key: [0x20], + fn(arg) { + decoded_data.seconds_per_core_tick = decode_field(arg, 0, 31, "unsigned"); + return 4; + }, + }, + { + key: [0x21], + fn(arg) { + decoded_data.tick_per_battery = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x24], + fn(arg) { + decoded_data.tick_per_accelerometer = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x25], + fn(arg) { + decoded_data.tick_per_ble_default = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x26], + fn(arg) { + decoded_data.tick_per_ble_stillness = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x27], + fn(arg) { + decoded_data.tick_per_ble_mobility = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x28], + fn(arg) { + decoded_data.tick_per_temperature = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x2a], + fn(arg) { + decoded_data.mode_reed_event_type = decode_field(arg, 7, 7, "unsigned"); + decoded_data.mode_battery_voltage_report = decode_field(arg, 8, 8, "unsigned"); + decoded_data.mode_acceleration_vector_report = decode_field(arg, 9, 9, "unsigned"); + decoded_data.mode_temperature_report = decode_field(arg, 10, 10, "unsigned"); + decoded_data.mode_ble_report = decode_field(arg, 11, 11, "unsigned"); + return 2; + }, + }, + { + key: [0x2b], + fn(arg) { + decoded_data.event_type1_m_value = decode_field(arg, 0, 3, "unsigned"); + decoded_data.event_type1_n_value = decode_field(arg, 4, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x2c], + fn(arg) { + decoded_data.event_type2_t_value = decode_field(arg, 0, 3, "unsigned"); + return 1; + }, + }, + { + key: [0x40], + fn(arg) { + decoded_data.accelerometer_xaxis_enabled = decode_field(arg, 0, 0, "unsigned"); + decoded_data.accelerometer_yaxis_enabled = decode_field(arg, 1, 1, "unsigned"); + decoded_data.accelerometer_zaxis_enabled = decode_field(arg, 2, 2, "unsigned"); + return 1; + }, + }, + { + key: [0x41], + fn(arg) { + decoded_data.sensitivity_accelerometer_sample_rate = decode_field(arg, 0, 2, "unsigned") * 1; + switch (decoded_data.sensitivity_accelerometer_sample_rate) { + case 1: + decoded_data.sensitivity_accelerometer_sample_rate = 1; + break; + case 2: + decoded_data.sensitivity_accelerometer_sample_rate = 10; + break; + case 3: + decoded_data.sensitivity_accelerometer_sample_rate = 25; + break; + case 4: + decoded_data.sensitivity_accelerometer_sample_rate = 50; + break; + case 5: + decoded_data.sensitivity_accelerometer_sample_rate = 100; + break; + case 6: + decoded_data.sensitivity_accelerometer_sample_rate = 200; + break; + case 7: + decoded_data.sensitivity_accelerometer_sample_rate = 400; + break; + default: + // invalid value + decoded_data.sensitivity_accelerometer_sample_rate = 0; + break; + } + + decoded_data.sensitivity_accelerometer_measurement_range = decode_field(arg, 4, 5, "unsigned") * 1; + switch (decoded_data.sensitivity_accelerometer_measurement_range) { + case 0: + decoded_data.sensitivity_accelerometer_measurement_range = 2; + break; + case 1: + decoded_data.sensitivity_accelerometer_measurement_range = 4; + break; + case 2: + decoded_data.sensitivity_accelerometer_measurement_range = 8; + break; + case 3: + decoded_data.sensitivity_accelerometer_measurement_range = 16; + break; + default: + decoded_data.sensitivity_accelerometer_measurement_range = 0; + } + return 1; + }, + }, + { + key: [0x42], + fn(arg) { + decoded_data.acceleration_alarm_threshold_count = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x43], + fn(arg) { + decoded_data.acceleration_alarm_threshold_period = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x44], + fn(arg) { + decoded_data.acceleration_alarm_threshold = decode_field(arg, 0, 15, "unsigned") * 0.001; + return 2; + }, + }, + { + key: [0x45], + fn(arg) { + decoded_data.acceleration_alarm_grace_period = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x46], + fn(arg) { + decoded_data.accelerometer_tx_report_periodic_enabled = decode_field(arg, 0, 0, "unsigned"); + decoded_data.accelerometer_tx_report_alarm_enabled = decode_field(arg, 1, 1, "unsigned"); + return 1; + }, + }, + { + key: [0x50], + fn(arg) { + decoded_data.ble_mode = decode_field(arg, 7, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x51], + fn(arg) { + decoded_data.ble_scan_interval = decode_field(arg, 0, 15, "unsigned") * 0.001; + return 2; + }, + }, + { + key: [0x52], + fn(arg) { + decoded_data.ble_scan_window = decode_field(arg, 0, 15, "unsigned") * 0.001; + return 2; + }, + }, + { + key: [0x53], + fn(arg) { + decoded_data.ble_scan_duration = decode_field(arg, 0, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x54], + fn(arg) { + decoded_data.ble_reported_devices = decode_field(arg, 0, 7, "unsigned"); + return 1; + }, + }, + { + key: [0x60], + fn(arg) { + decoded_data.temperature_sample_period_idle = decode_field(arg, 0, 31, "unsigned"); + return 4; + }, + }, + { + key: [0x61], + fn(arg) { + decoded_data.temperature_sample_period_active = decode_field(arg, 0, 31, "unsigned"); + return 4; + }, + }, + { + key: [0x62], + fn(arg) { + decoded_data.temperature_threshold_high = decode_field(arg, 0, 7, "unsigned"); + decoded_data.temperature_threshold_low = decode_field(arg, 8, 15, "unsigned"); + return 2; + }, + }, + { + key: [0x63], + fn(arg) { + decoded_data.temperature_threshold_enabled = decode_field(arg, 0, 0, "unsigned"); + return 1; + }, + }, + { + key: [0x71], + fn(arg) { + decoded_data.firmware_version_app_major_version = decode_field(arg, 0, 7, "unsigned"); + decoded_data.firmware_version_app_minor_version = decode_field(arg, 8, 15, "unsigned"); + decoded_data.firmware_version_app_revision = decode_field(arg, 16, 23, "unsigned"); + decoded_data.firmware_version_loramac_major_version = decode_field(arg, 24, 31, "unsigned"); + decoded_data.firmware_version_loramac_minor_version = decode_field(arg, 32, 39, "unsigned"); + decoded_data.firmware_version_loramac_revision = decode_field(arg, 40, 47, "unsigned"); + decoded_data.firmware_version_region = decode_field(arg, 48, 55, "unsigned"); + return 7; + }, + }, + ]; + } + + if (port === 25) { + decoder = [ + { + key: [0x0a], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 7 * 8) { + dev_id = decode_field(arg, i, i + 6 * 8 - 1, "hexstring"); + if (beacon_decoder === "simple") { + dev_id = `${dev_id}_beacon`; + } + decoded_data[dev_id] = decode_field(arg, i + 6 * 8, i + 7 * 8 - 1, "signed"); + count += 7; + } + return count; + }, + }, + { + key: [0xb0], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 4 * 8) { + dev_id = decode_field(arg, i, i + 3 * 8 - 1, "hexstring"); + if (beacon_decoder === "simple") { + dev_id = `${dev_id}_beacon`; + } + decoded_data[dev_id] = decode_field(arg, i + 3 * 8, i + 4 * 8 - 1, "signed"); + count += 4; + } + return count; + }, + }, + { + key: [0xb1], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 4 * 8) { + dev_id = decode_field(arg, i, i + 3 * 8 - 1, "hexstring"); + if (beacon_decoder === "simple") { + dev_id = `${dev_id}_beacon`; + } + decoded_data[dev_id] = decode_field(arg, i + 3 * 8, i + 4 * 8 - 1, "signed"); + count += 4; + } + return count; + }, + }, + { + key: [0xb2], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 4 * 8) { + dev_id = decode_field(arg, i, i + 3 * 8 - 1, "hexstring"); + if (beacon_decoder === "simple") { + dev_id = `${dev_id}_beacon`; + } + decoded_data[dev_id] = decode_field(arg, i + 3 * 8, i + 4 * 8 - 1, "signed"); + count += 4; + } + return count; + }, + }, + { + key: [0xb3], + fn(arg) { + // RSSI to beacons + let count = 0; + for (let i = 0; i < arg.length * 8; i += 4 * 8) { + dev_id = decode_field(arg, i, i + 3 * 8 - 1, "hexstring"); + if (beacon_decoder === "simple") { + dev_id = `${dev_id}_beacon`; + } + decoded_data[dev_id] = decode_field(arg, i + 3 * 8, i + 4 * 8 - 1, "signed"); + count += 4; + } + return count; + }, + }, + ]; + } + + bytes = convertToUint8Array(bytes); + + for (let bytes_left = bytes.length; bytes_left > 0; ) { + let found = false; + for (let i = 0; i < decoder.length; i++) { + const item = decoder[i]; + const { key } = item; + const keylen = key.length; + header = slice(bytes, 0, keylen); + // Header in the data matches to what we expect + if (is_equal(header, key)) { + const f = item.fn; + consumed = f(slice(bytes, keylen, bytes.length)) + keylen; + bytes_left -= consumed; + bytes = slice(bytes, consumed, bytes.length); + found = true; + break; + } + } + if (found) { + continue; + } + // Unable to decode -- headers are not as expected, send raw payload to the application! + // decoded_data = {}; + return decoded_data; + } + + // Converts value to unsigned + function to_uint(x) { + return x >>> 0; + } + + // Checks if two arrays are equal + function is_equal(arr1, arr2) { + if (arr1.length != arr2.length) { + return false; + } + for (let i = 0; i != arr1.length; i++) { + if (arr1[i] != arr2[i]) { + return false; + } + } + return true; + } + + function byteToArray(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(byteArray[i]); + } + return arr; + } + + function convertToUint8Array(byteArray) { + arr = []; + for (let i = 0; i < byteArray.length; i++) { + arr.push(to_uint(byteArray[i]) & 0xff); + } + return arr; + } + + function toHexString(byteArray) { + const arr = []; + for (let i = 0; i < byteArray.length; ++i) { + arr.push(`0${(byteArray[i] & 0xff).toString(16)}`.slice(-2)); + } + return arr.join(""); + } + + return decoded_data; +} + +payload = payload.filter((x) => !ignore_vars.includes(x.variable)); + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const payload_raw = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data"); +const port = payload.find((x) => x.variable === "port" || x.variable === "fport"); + +if (payload_raw) { + // Get a unique serie for the incoming data. + const { value, time } = payload_raw; + let { serie } = payload_raw; + serie = new Date().getTime(); + + if (value) { + let decoded = Decoder(Buffer.from(value.replace(/ /g, ""), "hex"), Number(port.value)); + + // Apply simplified beacon version; + const beacons = Object.keys(decoded).filter((x) => x.includes("_beacon")); + if (beacons.length) { + decoded.beacons = { + variable: "beacons", + value: beacons.map((x) => `${x.replace("_beacon", "")}`).join("; "), + metadata: beacons.reduce((final, x) => { + final[x.replace("_beacon", "")] = decoded[x]; + return final; + }, {}), + }; + + decoded = Object.keys(decoded).reduce((final, x) => { + if (!x.includes("_beacon")) { + final[x] = decoded[x]; + } + + return final; + }, {}); + } + + // Parse the payload_raw to JSON format (it comes in a String format) + payload = payload.concat(toTagoFormat(decoded, serie)).map((x) => ({ ...x, serie })); + } +} \ No newline at end of file diff --git a/decoders/connector/tektelic/tundra-sensor/assets/logo.png b/decoders/connector/tektelic/tundra-sensor/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c41b4f6bf1642095929660b020530d68d0d91430 GIT binary patch literal 16182 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 literal 0 HcmV?d00001 diff --git a/decoders/connector/tektelic/tundra-sensor/connector.jsonc b/decoders/connector/tektelic/tundra-sensor/connector.jsonc new file mode 100644 index 00000000..1c55ad74 --- /dev/null +++ b/decoders/connector/tektelic/tundra-sensor/connector.jsonc @@ -0,0 +1,13 @@ +{ + "$schema": "../../../../schema/connector.json", + "name": "Tektelic Tundra Sensor", + "images": { + "logo": "./assets/logo.png" + }, + "versions": { + "v1.0.0": { + "src": "./v1.0.0/payload.js", + "manifest": "./v1.0.0/payload-config.jsonc" + } + } +} diff --git a/decoders/connector/tektelic/tundra-sensor/description.md b/decoders/connector/tektelic/tundra-sensor/description.md new file mode 100644 index 00000000..1b8482c5 --- /dev/null +++ b/decoders/connector/tektelic/tundra-sensor/description.md @@ -0,0 +1 @@ +Temperature and Humidity Sensor for cold chain monitoring over LoRaWAN™ \ No newline at end of file diff --git a/decoders/connector/tektelic/tundra-sensor/v1.0.0/payload-config.jsonc b/decoders/connector/tektelic/tundra-sensor/v1.0.0/payload-config.jsonc new file mode 100644 index 00000000..728f354d --- /dev/null +++ b/decoders/connector/tektelic/tundra-sensor/v1.0.0/payload-config.jsonc @@ -0,0 +1,25 @@ +{ + "$schema": "../../../../../schema/connector_details.json", + "description": "../description.md", + "install_text": "Tektelic’s Tundra Sensor is the Lorawan solution for maintaining optimal and consistent temperatures within cold rooms and refrigerated areas. Applications include food and pharmaceutical storage, where safeguarding the integrity, quality, and safety of products is vital. The device can be implemented within cold storage such as fridges, coolers, cold rooms and even freezers with minimal impact on battery life or radio signal strength.\n\nFeatures:\n* 15 Year Battery Life\n* Ability to store up to 3000 data entries for 125 days\n* Restaurant and Food Service Cold Chain\n* Medical and Pharmaceutical Storage\n* Vaccine Storage\n* All Global ISM Bands\n* Small Form Factor for Diverse Deployments\n* Internal Antenna\n* -40° to +85°C operability\n* Temperature and Humidity Monitoring", + "install_end_text": "", + "device_annotation": "", + "device_parameters": [], + "networks": [ + "../../../../network/lorawan-actility/v1.0.0/payload.js", + "../../../../network/lorawan-chirpstack/v1.0.0/payload.js", + "../../../../network/lorawan-citykinect/v1.0.0/payload.js", + "../../../../network/lorawan-everynet/v1.0.0/payload.js", + "../../../../network/lorawan-kerlink/v1.0.0/payload.js", + "../../../../network/lorawan-helium/v1.0.0/payload.js", + "../../../../network/lorawan-loriot-/v1.0.0/payload.js", + "../../../../network/lorawan-machineq/v1.0.0/payload.js", + "../../../../network/lorawan-orbiwise/v1.0.0/payload.js", + "../../../../network/lorawan-senet/v1.0.0/payload.js", + "../../../../network/lorawan-senra/v1.0.0/payload.js", + "../../../../network/lorawan-swisscom/v1.0.0/payload.js", + "../../../../network/lorawan-tektelic/v1.0.0/payload.js", + "../../../../network/lorawan-ttittn-v3/v1.0.0/payload.js", + "../../../../network/lorawan-brdot-/v1.0.0/payload.js" + ] +} \ No newline at end of file diff --git a/decoders/connector/tektelic/tundra-sensor/v1.0.0/payload.js b/decoders/connector/tektelic/tundra-sensor/v1.0.0/payload.js new file mode 100644 index 00000000..871e86ef --- /dev/null +++ b/decoders/connector/tektelic/tundra-sensor/v1.0.0/payload.js @@ -0,0 +1,145 @@ +/* eslint-disable no-plusplus */ +/* eslint-disable prettier/prettier */ +/* eslint-disable no-bitwise */ +/* + * Tundra sensor + */ + +function signed_convert(val, bitwidth) { + const isnegative = val & (1 << (bitwidth - 1)); + const boundary = 1 << bitwidth; + const minval = -boundary; + const mask = boundary - 1; + return isnegative ? minval + (val & mask) : val; +} + +function Decoder(bytes, port) { + // Decode an uplink message from a buffer + // (array) of bytes to an object of fields. + // Device Info Not Repeated + const array_result = []; + if (port === 10) { + for (let i = 0; i < bytes.length; ) { + const channel = bytes[i++]; + const type = bytes[i++]; + + // battery voltage + if (channel === 0x00 && type === 0xff) { + let battery_voltage = (bytes[i] << 8) | bytes[i + 1]; + battery_voltage = signed_convert(battery_voltage, 16); + array_result.push({ variable: "battery_voltage", value: Number((battery_voltage * 0.01).toFixed(2)), unit: "V" }); + i += 2; + } + // mcu temperature + if (channel === 0x0b && type === 0x67) { + let mcu_temperature = (bytes[i] << 8) | bytes[i + 1]; + mcu_temperature = signed_convert(mcu_temperature, 16); + array_result.push({ variable: "mcu_temperature", value: Number((mcu_temperature * 0.1).toFixed(2)), unit: "°C" }); + i += 2; + } + + if (channel === 0x03 && type === 0x67) { + let ambient_temperature = (bytes[i] << 8) | bytes[i + 1]; + ambient_temperature = signed_convert(ambient_temperature, 16); + if (ambient_temperature === 65535) { + ambient_temperature = -1; + } + array_result.push({ variable: "ambient_temperature", value: Number((ambient_temperature * 0.1).toFixed(2)), unit: "°C" }); + i += 2; + } + // impact alarm + if (channel === 0x0c && type === 0x00) { + let impact_alarm = bytes[i]; + if (impact_alarm === 0xff) { + impact_alarm = "Impact alarm active"; + } + if (impact_alarm === 0x00) { + impact_alarm = "Impact alarm inactive"; + } + array_result.push({ variable: "impact_alarm", value: impact_alarm }); + i += 1; + } + // Acceleration Magnitude + if (channel === 0x05 && type === 0x02) { + const acceleration_magnitude = (bytes[i] << 8) | bytes[i + 1]; + array_result.push({ variable: "acceleration_magnitude", value: acceleration_magnitude, unit: "g" }); + i += 2; + } + // Acceleration Vector + if (channel === 0x07 && type === 0x71) { + const acceleration_vector_x = (bytes[i] << 8) | bytes[i + 1]; + array_result.push({ variable: "acceleration_x_axis", value: acceleration_vector_x, unit: "g" }); + const acceleration_vector_y = (bytes[i + 2] << 8) | bytes[i + 3]; + array_result.push({ variable: "acceleration_y_axis", value: acceleration_vector_y, unit: "g" }); + const acceleration_vector_z = (bytes[i + 4] << 8) | bytes[i + 5]; + array_result.push({ variable: "acceleration_z_axis", value: acceleration_vector_z, unit: "g" }); + i += 6; + } + } + return array_result; + } + if (port === 32) { + let flag_entry = 0; + for (let i = 0; i < bytes.length; ) { + if (flag_entry === 0) { + flag_entry = 1; + const tag_entry = (bytes[0] << 8) | bytes[i + 1]; + array_result.push({ variable: "tag_entry", value: tag_entry }); + i += 2; + } + const channel = bytes[i++]; + const type = bytes[i++]; + if (channel === 0x03 && type === 0x67) { + let ambient_temperature = (bytes[i] << 8) | bytes[i + 1]; + ambient_temperature = signed_convert(ambient_temperature, 16); + if (ambient_temperature === 65535) { + ambient_temperature = -1; + } + array_result.push({ variable: "ambient_temperature", value: Number((ambient_temperature * 0.1).toFixed(2)), unit: "°C" }); + i += 2; + } + if (channel === 0x04 && type === 0x68) { + const ambient_rh = bytes[i]; + array_result.push({ variable: "ambient_rh", value: Number((ambient_rh * 0.5).toFixed(2)), unit: "%" }); + i += 1; + } + } + flag_entry = 0; + return array_result; + } + if (port === 33) { + for (let i = 0; i < bytes.length; ) { + const channel = bytes[i++]; + const type = bytes[i++]; + if (channel === 0x03 && type === 0x67) { + let ambient_temperature = (bytes[i] << 8) | bytes[i + 1]; + ambient_temperature = signed_convert(ambient_temperature, 16); + array_result.push({ variable: "ambient_temperature", value: Number((ambient_temperature * 0.1).toFixed(2)), unit: "°C" }); + i += 2; + } + if (channel === 0x04 && type === 0x68) { + const ambient_rh = bytes[i]; + array_result.push({ variable: "ambient_rh", value: Number((ambient_rh * 0.5).toFixed(2)), unit: "%" }); + i += 1; + } + } + return array_result; + } +} + +const payload_raw = payload.find((x) => x.variable === "payload_raw" || x.variable === "payload" || x.variable === "data" || x.variable === "payload_hex"); +const port = payload.find((x) => x.variable === "port" || x.variable === "fport" || x.variable === "FPort"); +if (payload_raw) { + try { + // Convert the data from Hex to Javascript Buffer. + const buffer = Buffer.from(payload_raw.value, "hex"); + const serie = new Date().getTime(); + const payload_aux = Decoder(buffer, port.value); + payload = payload.concat(payload_aux.map((x) => ({ ...x, serie }))); + } catch (e) { + // Print the error to the Live Inspector. + console.error(e); + // Return the variable parse_error for debugging. + payload = [{ variable: "parse_error", value: e.message }]; + } +} diff --git a/decoders/connector/tektelic/vivid-smart-room-occupancy-sensor/assets/logo.png b/decoders/connector/tektelic/vivid-smart-room-occupancy-sensor/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5dea83d1b9ba79d3a9a6683931f7cd4977b8fd6b GIT binary patch literal 8664 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 16 | bytes[i + 3]) / 10; + i += 3; + } + + // Handle humidity + if (bytes[i] === 0x04 && bytes[i + 1] === 0x68) { + params.humidity = 0.5 * bytes[i + 2]; + i += 2; + } + + // Handle impact magnitude + if (bytes[i] === 0x05 && bytes[i + 1] === 0x02) { + // Sign-extend to 32 bits to support negative values, by shifting 24 bits + // (16 too far) to the left, followed by a sign-propagating right shift: + params.impact_magnitude = (bytes[i + 2] << 24 >> 16 | bytes[i + 3]) / 1000; + i += 3; + } + + // Handle break-in + if (bytes[i] === 0x06 && bytes[i + 1] === 0x00) { + if (bytes[i + 2] === 0x00) { + params.break_in = false; + } else if (bytes[i + 2] === 0xFF) { + params.break_in = true; + } + i += 2; + } + + // Handle accelerometer data + if (bytes[i] === 0x07 && bytes[i + 1] === 0x71) { + // Sign-extend to 32 bits to support negative values, by shifting 24 bits + // (16 too far) to the left, followed by a sign-propagating right shift: + params.acceleration_x = (bytes[i + 2] << 24 >> 16 | bytes[i + 3]) / 1000; + params.acceleration_y = (bytes[i + 4] << 24 >> 16 | bytes[i + 5]) / 1000; + params.acceleration_z = (bytes[i + 6] << 24 >> 16 | bytes[i + 7]) / 1000; + i += 7; + } + + // Handle reed switch count + if (bytes[i] === 0x08 && bytes[i + 1] === 0x04) { + params.input_count = (bytes[i + 2] << 8) | bytes[i + 3]; + i += 3; + } + + // Handle moisture + if (bytes[i] === 0x09 && bytes[i + 1] === 0x00) { + i += 1; + // check data + if (bytes[i + 1] === 0x00) { + params.moisture = false; + i += 1; + } else if (bytes[i + 1] === 0xFF) { + params.moisture = true; + i += 1; + } + } + + // Handle PIR activity + // check the channel and type + if (bytes[i] === 0x0A && bytes[i + 1] === 0x00) { + i += 1; + // check data + if (bytes[i + 1] === 0x00) { + params.motion_detected = 0; + i += 1; + } else if (bytes[i + 1] === 0xFF) { + params.motion_detected = -1; + i += 1; + } + } + + // Handle temperature + if (bytes[i] === 0x0B && bytes[i + 1] === 0x67) { + // Sign-extend to 32 bits to support negative values, by shifting 24 bits + // (16 too far) to the left, followed by a sign-propagating right shift: + params.mcu_temperature = (bytes[i + 2] << 24 >> 16 | bytes[i + 3]) / 10; + i += 3; + } + + // Handle impact alarm + if (bytes[i] === 0x0C && bytes[i + 1] === 0x00) { + if (bytes[i + 2] === 0x00) { + params.impact_alarm = false; + } else if (bytes[i + 2] === 0xFF) { + params.impact_alarm = true; + } + i += 2; + } + + // Handle motion (PIR activity) event count + if (bytes[i] === 0x0D && bytes[i + 1] === 0x04) { + params.motion_count = (bytes[i + 2] << 8) | bytes[i + 3]; + i += 3; + } + + // Handle external input state + if (bytes[i] === 0x0E && bytes[i + 1] === 0x00) { + if (bytes[i + 2] === 0x00) { + params.external_input = true; + } else if (bytes[i + 2] === 0xFF) { + params.external_input = false; + } + i += 2; + } + + // Handle external input count + if (bytes[i] === 0x0F && bytes[i + 1] === 0x04) { + params.external_input_count = (bytes[i + 2] << 8) | bytes[i + 3]; + i += 3; + } + } + + return params; +} + +// let payload = [{ variable: 'payload', value: '036700f204686000ff0129', serie: 122 }]; +// Remove unwanted variables. +payload = payload.filter(x => !ignore_vars.includes(x.variable)); + +// Payload is an environment variable. Is where what is being inserted to your device comes in. +// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...] +const data = payload.find(x => x.variable === 'payload_raw' || x.variable === 'payload' || x.variable === 'data'); +if (data) { + // Get a unique serie for the incoming data. + const { value, serie } = data; + + // Parse the payload_raw to JSON format (it comes in a String format) + if (value) { + payload = payload.concat(toTagoFormat(parsePayload(value), serie)); + } +} +// console.log(payload);