From 31c5b85e11aaf84229a44becbf2a144c9ef76b7f Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 10 Oct 2019 15:31:42 +0300 Subject: [PATCH 1/3] Port from internal doc --- wnt/media/image1.png | Bin 0 -> 20475 bytes wnt/media/image2.png | Bin 0 -> 69522 bytes wnt/wntclientapi.md | 2892 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 2892 insertions(+) create mode 100644 wnt/media/image1.png create mode 100644 wnt/media/image2.png create mode 100644 wnt/wntclientapi.md diff --git a/wnt/media/image1.png b/wnt/media/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..3dd030a16048fd4724a4caf93c974dff161f7ad7 GIT binary patch literal 20475 zcmd>F1y>tPvj*DYPATq%QY?6JC~ifIySuvtDehL>in~K_cXtgC+})iE@Aorq&dJHi z?%2-m&dNL+A}1q;f{2d@1qFp7Aug-{1@!>{1qCe#5BpYfx3H1^_Jd$6uI2y*#X#}? zg?7#3cYZ6xa}-f^RJ1X6bkVang8FG_qi;kiVWnqcq+q0H=w>%)!~+E-8!RFG^SA5L zQLC)|CPz(0#L3>hJOrh-FxjQQF?MlTG1>m z^$l#>oLc82)3G5=m`I2>R5a-|4+f&j;%5XH(j7e|U8n9{oR29UK8+@IeK<8+ys1zVVwD3{xaH zI}UlhaO4dqnu!GO($E1DnYJ)Lo~<;<`F7|l;>u3w+*`E1 zKmJ%DhkKV2jDw4-INop4Mt^G6b_k833ouJAH+6rn>Om6FZU`24MXWTvHCxQ!YIse) zyW30Pe6O?Zu=(BDIW_Z2VW!&v$>+C*X}c9s7nN{rbfi``lv+x@Uk?32|MbhNXMfk? zL2cdR!yD5CD&Y-U(oErt@qx`gS8?2>NPQ?TN-iStlt&Y&v|IetWofHvhvhE|`TH#S z2W?5fZFzuy;=&dn#Y(zPu35BTPOJI#&r*rm$uxz=!75wQyE~y~{Nocp6!b|B7LVP~ zTpvfrr)Ax{4jlBGxksf2UMv3?slBv#S5HV&+Cs>Y;(0OSxg$7;RgifJ>qQ3m@R>n$ zc-gd0oalu@Y~IW0(|@{&OIv){4oY8`&%g~b0ZT#=9`W=#w~-aC5*0vcS(rCz0xdo| z>*OVHSzGp1KS8!c#}3)IEo?GRq1OBI?^ZRF{k~xQ*i~xESP*DUD1KfpN~#$?SFt>7 z)!X{8gzuteXZ1$q;};a4c;+99+h2_$73(LA-6f!mAlxJV65Svp%!syag=x*{cvIfy zXj`#iP`mT}T{86>i>+`NZto8o&4aNM6G4;mUG(nTsuCrWDC8h&=7gZx27T~*<@W<2(;djELK)JzZ zL>vqP2q8iuPt3jaAJ=U)$5F8bx@n@Uux4}shU}+zx(!O*Rkn@^gmirw&^WB}1fSM3;q4uHItc`)0Zk)c`9AxvSN zU+n>Qv|UO1_VJzI95d7wW72+hdV7~9O_PbpO=Hv@9e^N<@Lst=`O!c%{P{5>%r5UI zjO8gMmk$*!)u&%v=r}e!|M@035#5#fCG9fR_O$cWDEzMoj>nBFuSB>+B+k2l9;x;{ zNs-UucKLl?hf7ybDP_`YyoCd2zF%=xE^6N?NVOk!s46cs)yvzY(W)?%G?(2tob-pV z4Bq=3Y9o((=A0X`RMp@Y<6?jhMhpfw-!W$i!+YJE>IV2)%|zB;9#wkFA|x95T}DFj z?`)*nf}}Ipk;%PtRetOsr}(Xz1Z*$S{B`(ZR%&Q5yf{ga+#1qm>z9rL55V$&0O138q^7 z=3}_;wg|L*6#49W-&T7ciwh~L;=2KXSxe*4FeqN&{?s*Idm|zs?orTzvz)x8`xAgU4KE$#t zCH(AWj_fme8KiJ){%-t@;5`n;_V~uM z`M$)U1K^|?^k?R}pt)uEe?UWabP^!mgjud`N0m_$s@q7@3^DuC{7AfsSChL}HTp*H z^RjOU@Vk>gaEtZX&Wz8b)r2xA*zQg#qC0noQ{?H1=*%i}iAqxX^n5n_+d+~r9{0h& z3i{tOGQ4Tp{=+oS%VhfR2A(tXO_IZGuCi+UbS<AOXGjMJ$1%wqWT3&I*bZ8EiO5y`3=i? zZ)$Fddsq6eol5ZEjoUEt=`zah>SZ4}?GJCtsQ7#x74o6vPtW!Zb!&e!v`Yv#2`v^4 z?&_}};GW`WuZN!K_b?uuxPET9y!|aE`M5Y(KMU_>Y&Z`8bpx)JSXXD^?hHwO9WzB$ zl~ng#!#OkQOy~0TmkinnWzcYC)TqhFLb-4!9V4|AS(30UQjHZE-m5C~03?`qkD~)V zY;{e$0cc-{Lv;qG=0n)*7pIWBU$=!C8c@HL@-bwEeZXL>NA`ZB^>IZY(TSXvN9lfP z+4X3@A##!&_r`DV8T1dEZW_2(K=CC&S$XgJH$seb>`YfKpb-Pk3Lofb|3>8?aU(s= zM*>x(ff_*kn22@*oBBriHj=NxRD^y#n-wEJDxtxM`b!ne|F*NW?7Hy1r;h6%(4U0L zgnQC?qts<2{2e=lTHTp>a3HB=aJzb!S=4Sp@Js5j#58*N*(&8Ow9vcv*ZAn`Kc}ke ziHcm5_GG=XrrLx0cRj!h0;LJGYM40u)@m4176=Pk;@w%5nfYJy8CDGZFruL4J-d>t zeuwnSFjvW_D5cU-uJVH(PvfLpvoswP)doYWP}jHq_F3bsjZdTlHv+tDSZXS0u@X^H z)|5+-=~cw>wWL(iw(u3lN9niSu420LZ25(BoCbBT-{UDd02(pL+k>mlu#CT&^$!k> z{u1sDNng|bm5qeDrbgOmPC_pvDNrv+sb`?INjoIQBk^mR1&KzF^Kw7#lW1<+*!vzt zpo4G6$VN+E1%d1=H}YlOY|QzbYz{2Ps7K6g)OaNv(d(01v4T$KZR;zcN6($4Qu zD`aA5(9oY18GZs9=w0<`Rmf?t zXdxljG{oNN>}(a@aqyU}Ew3usFa!RxYG*w8Kzud$GjyUWOlaw>)NHyQ52daBJnSp!w|zRQ&P#vjKj+?msdrS3-rV^nxk<2s_x)$o5*bfXRt2vBqPiOQIl2BFWt9I;q!G z=xX9**ZU#Io*+HbOX=~5*RN$bzx@BS5CZX8xfB~JJtGg8YfMSN;_lN>eUH@-vbCt0 z9!b9G{;J=In31+#ax}f8Nva}uOFB>%hV!ozS0P%Ne^#<|8yT&jv(cD>p3jMQGy&CM3atUjf1tyElT=V1CygT|^0E$)pbM|7pD)%>zb zx5P;#Pc4l4s+=sta$fq6EJ^{dptL)>%rQq<0fTfcGMytv&JPE*n!6z=YQEotD=>hM{rRFi~8(b=L$lq;=9TD{plbK z#-^0Z&q=m}?LFGpt7(oCAbpWTn$(!G&?a^^hzVQ8)Tu;sFd6U%)b9CiOfXJ(`f2It ziINy3&@){klpWG|qe`XG`DJ=Lt?fgGf{+M^dH9PcIozL?%r9I>?Z~FH*~cE2`lcI{ z^{vc^|42$5|4`uB7rZ$6qa8@0=uMhumRlDTJG}5E7y9fwk(7tF*r<Ym+73lgh3zQB#l@w9CnQPd7u1-1F2=Yk;LLuW~- zM9*-NoFC6`l0+^*Sz=_s@W^JXe+vxDZ)jVU{#z;GO8-xZ%k2BRO8gh6A_L$Dx=M_k zm;&a-mNN=jfCp_>psZ-Y>7N2J{O@ZKMfm0EZHh#~-$ouBqJf;>G>t#t6KDsrH~P93 z?ermYhdoGR$vy1k`MDo>vK2Allj@m*`!|Z81ZdQSTTEW0kS=-u30e3!y+g)X89QeDlM!|KaIbMy56RP>Q{ zc$TXca)fdllO;@) zpu(`E!i10U#O zIOZ`?l3vArQd9ZadZ7`VmU@;GH3(Jr<97pMVt!+|AY@5}fT+i6X|fIy7IxX_ zRkVayyC9&`cYrbr^@+?D>}v-Aj&DDb;c^R{9((y%0ZtpIvqXS|2C+kV_i6O2CXQuJ z37(nqZH&$}p`9o)_OdBHQEWZ{w13K4>fJMT+FYHFL5egjRNRm%T*J zXaCq*NNHw0b9uTlr}s<{Y$))7fn*ZPtp(6YiHGg3P_KC}huTdT8X_8T1D zmEoD$gD|f2_L4Q%Dfg6A5+Jwr%s-shNF1%?h3~qC0*rd)9ds7(3m#JIl+XIeVEQs- zZWS-UK@Ovnqbx&C`LH`$FL^pYG@js9v@T#@HH97nIne8vdX%l&OJTN(L^Oth zN5S*P%b;{UL#wz=&*rO#|MQab@;}ChDH4Ci#(1WsN|cR zXD*zz=!48Myc#m_X-TKF-7-A|xLUjwKIz1js+GrB7uxsPP=m4pbD&O4 z<|={TVsm<`l3b^3yPAb-Tj0kcv^Kgy1MGvFDP6rBCyxfMk(SEv#vu9htH<)gs?!0Z z)U0-nM`8QT+)RT_DpqbcoxaI$J+{2;)=vWIw+Ld5T7QoExsr8R#!U3}Hwyt@_r<8b zMvjb^ux?B{@&umaoZBb)HD2?=ewHsT@^L@^+VrKVt6Hj~^m>~dRt)DukmhM24P$^w zK836D18VY-0T0*ydgCzGWs04C?m&%IvpF+DrwLTrRZtmz83@MsfD9+vrnz{0g<08G zYHGX@jVX&<6lBD=+x|!xwj`q41)r| zpk~HtQ@I4=p$*k%-8*ulc3Cy6Z(Tz!?3MWMVRy*4D%2HEB~z6viPU!Gn`c;_ zrT=QqDSGezz0q#}ev&`ZMlVo|5D~6k>0h^hPJHqX3r3um*N;r_pmKtssP=DWf#-}2 z2eW;X4F$PgihVxzTRn@9cg%D-8GTXo>u%`|R`<&pasfHrb8=2|-*~p1_oYbhEAdFU zFl%!N9N;!9E5LuZ0=OrA-H+Xk-E{8282Fb4w)xhADuX#x?q%u#v=teuOr!FsS9x4? zqqFf_r~CS?^pHc*i9-q7@I3E9$bSoOYcmlriCGc8)Ang;LobPm%J|BRJXfpwWtpuS7P$V|Pdsfp=zLZcVH zApOWb`(ufZ3GJV(W8Jinr_&DRgg)tUx2oyS32>hy)dO&RSb;cnzSxQj0aKSGrPgj}_H-e<{%gTicOZ=qj2-0DSrXU?$Akz% z(nWHvAek-=VcE2nnjmxP0kG@bRB8?GLahWv<65o-Eh~dSJRfKHHT77ezSMbsm-%p% z6VrQ*2^lL2LcB)wy$J#7>su_{+tFKgPuEj_Bh_w;1HbB&baQC}IX`R8sKCRTEA`zK z7TBX`!2^CZFD}RL)Zr1Z>zDs(OJsPkO0`%!g@KA!-Epo;7C5x5o>Cyqn3NKw)>d~E zNH}dOIE^ki#P`B(y$&OT^Oa5|7D1S0o9)q5b8K2cX)3Q2+q%1-ejzJC|W}NFb&t@=?y6`0Oq)} zY+r~)|0-tFVu~IAy(0apudJ0q22IZj4_hmo&SItg+X-c)JZDoRGK$s@ebCEaD&g~d zAb-)|;=_hSixTk|-^bjA%<1;+%+!dR zd$x`CHe1l%?l&dTma%MEx{L^R2yclz1A%v<)ha1;LDzO~XG2&ep-Ox7i>-lMN<{Cq zm3=eM>0YJ^Umu&;0Gp=OvwG5ae3I44bK0Is_Z-+a7>B7)!QfDwTQoT|L0sGg6{SMx z0Jj{);@sEunogIGT$k;tBG{uCVm0qYx?fX0k*J)G(=W|`k^XqqYynKb{GfzIs6yYa zVWPh^vf&o_t9c^#5+4gDMkHO2@R3O_lQ6tKmG9Dbz&V+(JazSQU;I%d_s<;2%Q8ca zKqqw;_2;zl2sVc8F?cQUvS40~pq_RIi^w5I@Nvf~OXK2}o} zJ{-}l=nyFvg~SVh4VVT21l+QKR^PR$^pRCcBiBwbBTXAwk1tI=yB*ypkgLy1v?mq% zdT*{d(hl3#9;fCBs`uqxwWKCE_bxkP{ob2&tY7&-Mvujo_h_nS*rN>muxq5>XHF%f~-A6 z&eX#3*fY7f+gJnoK`B59TxM_?iV)Fg1SI16b`UfX2w2JoWfg}FSRRMw?^yYnY?te|H2&ztW+F!$K=HqefI^Ncg51v;_ZW1k_=pr3QpYyE_pAE-{YmdXc zQ^7lA{5bSuWUv#*s1$?wQC6r{+(H5J7?|^{QWeX&<8!}sjbazw2_8GBh8Fl@s@RWV z6g{^*_f3&wclUWKZ$?0glB7^YkmjoJ{w=rfKcpMPJTNHGLhooL7z6UrhS5UMtm+x} zi&un#t`BFa<<>6_7I9MweaJ3CG|ows;Dgz>0_?%`>W`SsBD}NMcLrAb^H7_)PG=Ou z%M2bWuyho>&arQ4rIo<6E~OU@6o0fhn`M_v+j*fZ12G0|X{slXp%<2U7po2SeShJ>05 zD01YamQ)0m!h-1tvuh4*xz{ch4^qooIBLfpMDF6oponKn+b};D%f4o((!|P!rf1V> zgXU2FNdMKF#?r?sqp@9J?k%Z@8V-?iI_|724d1$0%mj!iI~HeoxteZqc$(^BbTJag z=CCSy@p0tlh|s0+=RN1QyMOWVDGLZQ-ILE~XqUt&WEPWwGSC!kmBo)olJLR+ zpLm8mqiBC3fFMQi(;^w1H^-5s(Z3Y=-9$?%cP1xrL;KU}4i?KAHg1npV+?IN1KxUB z2!)$8*b5#vk(`2wzKf&2Lj=knq*?3=R)HHe1i=X(HzKU97629u(C1n5mPtrF30%4#Z zQJ0aC1I*iSkPuooq^RD}QYl~6_|icA8zasNh2-;H%Mp{UqMtnBMBhf~QBRC!dVOAv z?C6Qn#)#>nf69?uZ=YRv>6P2o<2+HhAw5hX2&sl5?Zg*TBOHxfRhj#v&@o>_KdDtJ z4q5S?H&%|n+KbmcZVp{~CG`4+;%C-s2|C~d*WkT^vay>@{T-b0%qsuvov!m#b1OA0<5;ov4$QgbGcu26i3X} zKOQTAL8%9k8#*ePmu;th zew2f16U;)kRZ3nM&KTXt1(vav*n=y)dC)+O7&m|ECC1ZhJp*glK^TC$<}1I_S{^x+ z%Hc2Qn~O@doWtiO#|M_|Ow-0C#{v6H2WHluW7!p}=DecnQQmvwMf+Y(#$36xi9f?| z*lGb5g=fiLTMZs40iG)T|6;#}xTj}Xlf=bGfyuqe^(0eALDKOEB(GyWVZ&(3ZVU&!OQAuzL}|I@V7&Z^BD%_(+5gk_<0>S$>OJyFR^Av*F`X5eB*G z{g@!|4zZ;+SG-5>tPQ2vqW1~?$sujj(fD!RVm++{_-Iz4Lo?KY5$1xlH`McmHS<0b zGZUv~g*WtpNN}z+rxHA6vFH0^Qx3yd?m0+CuE+f6=Aji}~CL@}U zBgO(SR8mO|i)1e+zg#C7F8(l29UIP5>^$|#;e@947%k+$Rh&-i? zXrWLi(01Gp1CZe_l~Dzsq_Cb{LNA*iq`FHVbCYrSC8tiLJ$WC9qw>Mp5xmAmo^SVR zf6k2M%Z0%9*BQwGIJthE!h@#6%>Yg)6PODWx5Plb$vpoB)WI}oReixfsL_85n)|pr z29|NB5e$_9GWj7957u@mKkr=71Y5R{)3j=shhW^1c*Kd8S1Fq3jL*KO=e^pF; z!w7s~V~{W92LyL5)*jy=R&*iW;FE^rL6g%>IV@K_zz|o4Ftf8+d$L&WvF%F1@kDC1 zJaK*OuG<_+OTou*@41ua#~eItG0CBK7|}_9Pkh9HPxOW*xWv=UnmcNHXqY+vA-{6@ zr6R_wEqQ!4T?8fTbCKMG#*%1&8<8Ns?(6bpJyjzw$N*vJ-(y6xc@DeNT;4xikyO~O zbUz0k`G_^lw=hp;$27;TAkTg<*z>P94BsV@SM#B|T(9T_S1do1QrxYPDE{6*ciWq} zTee({icZG@F(TjZutlO>n!mc(paxrZX(u(bR5FV&+Go)uja>}`SA#gZ0$Qhl_Gb*^ z@aYUxOp~Ts2G!I@SE#YK)7o;s{?;+8xz4H%+(hGpZMe-=czy}vJdM6`2KK3PKx}XV zm?$ecQ}jt!1|J@m%pOg&BI@X1vwgaADZHAVGAqp5Zj-{US?lKtk^UatRk(v#k zKaJGFt&?l?XzJXGg6SQ*ZIw3hTno{u)Z{|s>CG%=NFleiAo$b8-l2(9==oa;T!Aq^50`(V> z2VZ*xhicT?3mP^~3E=iO1;?7D;VsL2<+y<%`%dH?0k)1>V9(A+8g^yMKHJ*OJ7rj( zjMIrUmKyYl0?O-#gv$B+RXTai?tfm)FD7X{A^fX##rdMrIvZEkvW?CmW#A8oQREDs zW485QNUQbZ+H!vo_s=GUpLp4RcC$>$Fo?;p5Qz{ZAl!0Bz-}ynL%XItZ4ct>6A8&R zUXrb)5;Cogu8$b)(}czNZj_nOm3L@6MTT*Fj#q?*AoJp-C4}o-b*x`4>r+hHaF`W| z#WIz2mlYg_Z%N3}{dkp1E?m7k_yKOWb(Xu+dHmeA0Z3nBnyG?uo zG_;bbv6v1M0*y!}#lPNf8_t^tJ@Gv^mr}R7du0XNs!i76lhr7fn=E1mZIIqfn83#@ zLq~e*P%ZJ>6v>;CyNh{wUr5)XLMpIelukFJO!E#rs5@=u%AfSE9)6&%@@hn+;qjEV zAg2;^-!zfHs-msOn$e?bZdOMC?^@Bx8@V;h+N6slO*jevAyo}a@ zpv50Yrq($h)oC)7@XBa($EMqCx8(-Bwy?VT^N8?gX`SiZGl>#x;t~K%))c!{7gJiV z_H_>%?rD}H?toX+LTm4=pm>6Tgw0+%6|kfTvMPL8SiXT8(z*f_;;wu7$juNY!MVtMv9zghQcfD?Yoks^R5cDK}+aahO56TuoK2aR~=5Jfoy)EgF z=8c)CZy*%BHD*`!Q2mAxFxQU*Q|>R2j8Prv<)i^n{iX1dqpaA;)NYbJFd5KL$<@iV zXM7G6dA|O-Pf4bD4MQUf2-crm-FUqN)FnMnKibvDc z%g=x;xX8R?u`@O3#^mXNH4vhA{prboMZRg@j39Qj$6+N6V31PVNW8&8d^Hpn=np*7 z^U?a$VkB++IhaxT*9zX>R#9(t2r&M2ocJN(szl4p%Fx!JH=pmqz9zjcoHub?d2O>0 z0(c9&KQ3un6NAXUc*1AJ=IJ-HCgo1+ zz-f};z#cFNe%XEf)qwu_j$yIj zEn>Td2f=bi>TYKb_slo~_Id3Y&zG%5ZuaM6RC_Yb1fk=!&M=&nZivyRAYv+Zed)4@ zu!So-S)*HbEo}PxyE7+~g?#sx;H3Esis}Gs)g@R$H4i$-T<5)-+dc`745(Vk_@~mJ z?%Un`-2o+bEdIEraX(Q7Zu~XX2EuAvJbzbtXe^hnx+kny9?^xHY#MzB4m)dvz$2@b zyXB1dn;Z>ndJt^bRlkc`NLC3a&c8!cLTalAXXf0>6bhU{TDXF)+fOf@Kdlq{Gcu8? zHZA+cYhdRwAw8E@nHLB^>CaV8r6r<%JM&qef7bvXKQq#zun{n0beq>-=jnqEp$CUM z0DSb->KmPMjj>iH2P_{TZioBLb)OVuyO5VR^skL*lG}0cH}XhzHC>PwY1sWKYq383LUG3VQ!#wE8*<~Y+tus&P#Vsp{@LT;c_=?xAAx=xlNUlJ}9NpkQ0P9!&hnboI;LNjJ~ZJ8U(#i$-_m z70Q{EV!1yzfC~npaL~TZIj&BikZ5mtSn{ltvJNWoTWc6#d^vyxOD)6ZJDx@E>_#n` z#nCZVM)T?ni6E0wEZl;9C$IU#2(Eua0D}gEm11%!&u`|rza)vN_o=I+Jb6ENDm3)N z=Txo;l?l#^5YUCUH=K|UMDbn`BugB3XT4ZM@fp5hFj}+P*c9tD!u0p~uUwcp&s9Qx zc~tr;dSx9Vi?&=D`J)n@lX2QFpz?hTM;0t77jitjDYMCMhj$YDTK5ijOnef>u4P6v zDGn5&_a4LxO6E$)tTO11$a`{@*2<86(wVwRbOzeZP@(N}0x3mW4;mrjziTM9(BF79 zJBOrLI>}KrFJWP`a2u;n&nA@zOs!G%&+D-W+g@XB;3OQeNGK=kK-58a3rqQ5;tO@_@QCPb#l}B;PbC;bfVbthw2iwjI z8$L4hf8hNe1kOt&?0CdICcty*a$|sp0fR#SNM4~r<@>?C;`Oh&CZS&M48e(dh>0yeZ>QTqMC8u_{pH7@G51%Q znCI2YoBV7@N1))p|A7E;&_r`e&gy@C3=hsTP$v~9OQqz)egpOhCPh>7L}($(9{W|W z^#lbcxnQ>msZPE@+TZ+w^#&1tSs&yWLr_rZ$Q3nB--@$rHWSNnkNf&}UrZ3WJ@r(6 zhy0jevAyE=o>v_D91WMIt-(P>if6D@(EJVk)H@Og9l#)tB9N??d8_JAo4yZ$(->Z= zDqDoh-`{P`3LXWy0;l;5r{PTU-3*(H>~K)VzcH=6cPBdFq=7^LPu0y#%&4`<7JYrn zIe=8-Qxyg#4w3i&a6-(ihN;o}Ce5lb;#m3#*=^VeS|BFxIdq2dKdj3d@JXO9GxcRI zW$cJjxV?8I-`m!!r`Knw>p;qZ-NQdDiWKGcQMeH9y!x;?>ni>@qwozS1O*j=>sZS) z8eo^qvf3l=E)|idT zojIg>T#5Cix5`kLe@R^@0Su$ zhnu3DI)IcC!<|F#05igJ*Gas~RQ#YJJ0*-3!4dv*F#-c@{Q3CPW0&ca67TzJ5JJ#% z!>)}B@BAyvf3pQuy@i#Pt0XcV*410dsEf4pJFN44S|QX)_Hj-VoVnUKLB^||jv>?a z^TDv4j5(8bgJ3G0k9gSvZsf#%oAN-L3I@s2<)TE>#AyF>hb zdXM7Q|IJEtz-V&#SqAZblZONi`Ir->HolG2j6F#h$D&;@eA@I?gVE@vl{-473-nIP zTho0o7<=Rf^}|I_q9DD_|29OC!KpEbEI7Zd%2ES0T}Q*n{}`wR^VOT-dfk)!{F|}c za~D>ABLp#Qen&UIWyL7Kz6ZukQMBQ$`GVA+H=R@QbE5LK*Zv3zEj?xx>p1>)(SWle z;yz#@_XnY5q=UKwj`g|kPG4Va)Ix^;1Y5pb^1oiDs6(&0!BX$*Ox0Jf5X_ssE=|0` z(rNc3NkvpP3>YygqtTx2-{S5R7G-j2o!8l}d0af2HqP>i3{{ zwwAv1FiAMniOag>pGThE70G5+YRye#GcJ2YK3g@%BQgI6Irn@O&@Wcek`8*o?Zk`a z%*0o5BHiUAj7PJO*Hou8d`1NQn1J==GgVje|V%d`G@E=$1n`AJ;BPZ1cnlwg;G^|1i| z4HMXbSFI53W$lFhd70eF9n1A`+{}BS*G7oG0l%pJ;=aN=-E)M8oh^Io?y5Niq2HI= zx@ud(6M1!ih{R3n4b5nGkm7$0+?t0CHiZpwryi!03`9?`D?+6KB=1sr}8 zbRL|DNj5!~KL5E7T7u`(1cs|Mt{Gz|_KtKL5Ft57OwZXy>H8ICt1 zN!#D$2OO6S&l&OZ&gc|m_CUTp?1X{)x2^A%6U zg$JjE7szyYiv`{-)N4=w&HJsqEy#605srwifLF_V+Ig1JB=}oVCk^UC1>9HNQY>=G z3BTIaHryWwggj35 zj4eA<;yute&Je?24=$Yj_K@KcnZ;Y_spT))Nw@j>VRG(iJR0-tkC(mB3!V_M_Cwsp z-DylecZhKJuZP<*(6o>e_aHkFwv?>Li3aGB=V)+c?ZNZjIsQ`nnA14Vs;Z7x#kuWD zQwp2N=+;(eHp=`)qR6kg*eb(gDCU_LoX@imLbhM957gXR{b}FcANg@uWVS($z1*y| z{cj6S$&z;h!KOYDT**KbXZznLUhlCeJ2sqzHV)Vxs(L9h6}U?vNOfhm@YCh;U7OiN zxf}R=`D5FqeqmN@dUnk;ka8Y8$K-0U+TV}#B9Jn=*lMmX0=`M~-K#avqrk>;Ao|+0 zu<`A~WLWu`fNRSf<4Z;OTc%ZK3TLOJNZTkO@$|7=uK3|mfAPlyCgdAKY?l-t3wk!b zQN6qNlm%~*-fy;_b)!f)jq_KRuoH7{cWBNYrX|XES;G@1w$HhxS*=f2^S2#msD0{?(9FlTB`b~>>0&wE zczbZRyY9ZNmD<{2+H6G&8@brBlz*-|NPOLfMc*%f z;<+2ZWGXMtuy^TsKf6{oH+brv0U3=dL8(FPF5&oDGv)rG^|;h{)A@B?h24Fm=-v*z z?sRgyXreSFGrgSDG7{gqP;cU~L=E{?V{&;*bnV8r1ub5$vV!fOUgqk`z+)g5z(mE* zFoHB+W9D6PDtoyp*~hFB$*gh6qyjfjxoO#UBpSpZOT8K>N+VV0ihma|H6PUk{!ttIyfe8nSmxuT<+1$GLJ zV@+OEp*;B0*h|98HWz)FZECat3 z5n5-p?s>tddU()5H-DqlRd(Qck6oTQRscK0GY^oxye;0<+P`VNZCO`pk;M+H;k^cp zh9n$zvFY=Qz3|;2s=U1u+4dhso2;=1a(}O#G|-E;lBd2klkhOPR&xm;bA+b2jzzmM zXa*j29-To?Leg;_Hh8dTtibI#A^BPcVt5wxm&Rg5bPir>PMN3ddOjPkWz#rqA^Htg`-#KIXeP12G4##=K zVRZ2CFuTFm4N6UD3ct0O?#>@zevc)iDgM^Eb04^+C?D7+a(3Yi7{Y%#u3a7`(_;D! zk@Y%HRo%MZu|8rV9Q0nloc^&}*;+LT07;tT`@Z5Dc|5_fqm0k?;95Ggsdalbu25KC z?uK&jZT#5sQOtc&>rTdT32#>W?TQL0_LlNCgXqHCo4JQ;f?X^5v`x+7^3u?A zl~3)ODJ#(RoK`>g(#wB(R<8bAW8z6}5B1_666G9rTE1vS+U?YlGkmyx|Iq#Efu@*4 zO0b=mP1l(2BN@JybykY+Duu3@{P>@LyNkT6M~)64}C*=c@!kO}wP6K%3i zt}uzl4{`gXPyMP%-BJnZ6+u9d=seGE-@!2Ec`Sta#!37-+|`W1kS{ypj-$RD`8U-y z4IUH)Hd8zw8BNcalhRsWgTqH>N_E5d;bi&rOU|N4`&gWNi-%V3)Odt42=!Vy&!m_0 zup$adBMU?&YrF9wKZO1=P?vA{$SGj*EAUL&WE6ln9`PijY*4N>&Mx#lr06UR5qICu zN+m0)=l*;#Bjps_PZP(tbMY{O2$ZnQdu8Ico*%}Xj+Cjy$^K~UgkBPT+JgE!n##R> z+S9QE)4S?te)^Ja1+N2 zZ*RLd0+Mn8ZHku$2?wS@OpT@74yhtXQ^18qWNWJ0-fvW98#OrqYXXXw=#OE8cueJe z{`_2RQ9r_}Zzor2rx}D#<~D1zKtM}*gAGy=VvmyXXZIjq62VLt25m_}f1T4M=XpCK zo*n-wk@9gAhI*t8BhRkhE$xd6r%&ObNm22+%gS}^Uc6R|dwz8{wZQ$pY8jCZ*42lC zV@?u*c`Qg`W0a>#Qr&|g5sAGri zUEZvcBF>Ho=nU)j)rJkkVf$y1)A*}rUWl1A(<0~=n?@ZJBaRwxaBguDcA396fxYuHSJ!lPhOTjYIamw<&7EPxoJ6)4jHK zm8So%n=Ai^@@vCWRJLp>WgELhc1q0HTE3Vp+4p6TB}+tvqLN)wj3`4{GIlX&>=}lU zov{qUScfcQvW&?))A#-1{Ttrrr|0v0u5-?PpY8da`?}ASp3I)KE^77d&^e|YQ>wCX zRO|tRm6BSrfy({&fm~88E6djB3}=w~Tb}V)UaSr4_H}VRo?Pxioh_JTixf)&QyO7_nVCs^uy$91oVHQ&`e%9y{T7uzF94}7?$XC zZ+GVRQ(%B@{b@j#SFl6JnvWf%A17l`SEsO{pN-`yuhTZHns#Yby9>~ zkkh&;4(y=tBu;JqV1yx566s3@Y{yI3%AOX{UM}} zXVHP1YuOV>1niBmIS=}{@2P*Y)U$F#ompAkY7Vhn)n?tsK5^&>IM5GK$Lpa3HNckbJ-Z)5dFj@pdB*a5C+Urm^GI>s4Qgd5H5RlX8R=V0CCGD-&5PIxPgD3uqKP|;*s;sI5uQiw z#C`ZWQLR~ONIE6!@KGGc-7|HMpLp6mH`i{|&@9*|ei&;Eacl0v09h=V)#sdFCNib^ zFHtgHkPsanS3-6u_}7Ug^54*(A=>^C54;8_myMK064;RosO&tyCeMcz?+4$iXj*|W zdY?(}(m(gCOq%_^?Q1dLpU$SJWCoxXl9lf%fz81s5*uS)yDcVN%;X<-Zkv&@>K{4f zL6=a^_$k!bWVTlJWc;w+?)`v~!b{wh&X=rF-#R>qVgf0qqEoTIvYYo=uj`hTAQ zuvwe``A8WZOpV!Z^XDJF>LizhXBB##8{j3}GztpH)m6+xX`eN+1v}Xx*a5j#7Y??= zS7hS$8|$&%gCi|&dZXcJi}jtC7R*ubFRF89X&ek941fWV8|=$LydVy0PMq43+T@Ek zn60^}EqG>*_t`{~_a=+HW1M$?HG;dMicWiR9<8`>TtH&Y3Jk zhSvvIJOLvHJhW|=PXIb~!F7-!wLr1?Q%XB|!jYA=-EI{rn>G)2Cvq05Kge@)JQGaK ze1lOAJF`$&YP+<3DJ@iAmj})%zSE9UoDK5eAr-h`W{rCLW#kMIoPbs!U#V~pb*=sA z;+8Ydg2H^ktS_4rC=q7KtfCsWlw1tdy*9-s3a9K+TnTuxFAs6e(j9UDYA@K(lT#i^ zjNU!Y6alQ|ssjmOJ)dH`l`W(=;^Gb@=&BGi@x8xR8n9K2khW!Xrj{Td_O1qc@@uF! zVNXQnDm}ce_5OE*R&|HR>`;&cdAi;!JFe{!UK^tyZg0l~%VU0C!FFOmyA?xvpcJ5-5va08YpHD0NijveV0@h{2o%3^nxROT|w%f4SV4j;w&FZKpEv(6PT;JFr%kV z$W!NV@ku*ecbocIDAAd5afd^$C(DsIx^JxO4Z;-c9cn;9p1LV#Qw!+`jkELeEYxG_Lret-x?_?P~LacShO6YiCA^EF~e!)YrL;nq*pAw8$H> zO8WG4aWQP%lx-Ladn!;}U{DADn0*+}P*6H=JX9mQ2eKfIrnteN?q2QKE6w6{^r$-< zSA=6oD&Kh8*PGmBi-N1@pKk?(h;m50r?`rA7cc3nR?<5$Kdu~g#`}RXz&u?l=02i@ zdpm>i;>Fy}!#+~3s36_f?UOG!Jw&dj!I3m_`QJUZTe|rO zPNI`zttKv0<8#cg24=C7W498k<%fW?=8Ws8*kU2l-IigEHM82aDkk6@B8)BxLaSGA zUN$wbm!E}qB18f%IoLxOFWN=ziQp@j%vYh0o6`xSSdYS-bIzm{Agg zt}R!QeZ+L~w&-N{SXueY4%PU}bQsN0J?gDOJ??u~0_^t_@Uh&Bknc8z*6X!h*p4M- zz8MA(T_mKlopy^|N0GHu^VoFZBFyO5HObUQnQt*fO{qS6<`Qu#-Yex24HsofBQF?b z3P&nm3pmOTZS}MXbKz7T>{cB>(z0rf-1Gpl83lxlTZ5#l@yszKF#y@unYgj%QCy{|bZ$ zHB?j=;*QXIsCdsezLAujZcLNoTUl;ep)%dat{?T6a5pqh#0@^Y^)sl?!A1E&k0 zZHF=qK^u}9_qBulifH_DVQ0b{j-ueA?PC&VeCEU@bA=8dNlv4t0G&V^v{Jz)=XRXfg=eyD+AZFdh3i1!42LA z1_IgBG738sXm+E>>SO=AS~hst zUAnRdi=6ag3d+<`%O&9dRS|v4s762Du7Coc|Fa zxm0TB$fb{?1a{LcZ4D6CUyS}dzf#L^LaYR6cxLfOnvUG>cQ!Y%(8I8;_nb;s6W_H- zdS|}d%yML+6^IIr_BgqO9;XDXyRJgXdRP!PT|*Im096wl&9>jmMoSxk_UGtT3p+aR zo|MFb=9Nxby2>IG&gReL_tEluuZR*ebLf3w0u=Z?$1vfT{~_pFpwbCFR43S2^^Zjpo4|Yd(Y%t!LlV9fJf* zGc{IRU;ekNoyTc;vpqp|5&J*#PaiY3py9D=^Z(OB34-uVAPjsFkI z;RO^}O#74logDH<@MCI5zE*}RyF+1@-xtOIeutm*NdI&F+9LSs4l3v`XAX!GPv<;+ wOs;r)nW{K^?DvnsUjZjN{{Q32+d5`d0GMFi1r28!eds>v-!i&cuIv2#Kk0xiivR!s literal 0 HcmV?d00001 diff --git a/wnt/media/image2.png b/wnt/media/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..d26345349d29566d54b111957ceb0128b7e00e48 GIT binary patch literal 69522 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∋sTn9!c+<@O?RPt5pIZJ5} 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

    b+QFOLwHGHw> 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 literal 0 HcmV?d00001 diff --git a/wnt/wntclientapi.md b/wnt/wntclientapi.md new file mode 100644 index 0000000..35a6b1a --- /dev/null +++ b/wnt/wntclientapi.md @@ -0,0 +1,2892 @@ + + + + + + + +# WNT backend API + + + +- [Introduction](#introduction) +- [Backend interface components](#backend-interface-components) + - [Authentication service](#authentication-service) + - [Metadata service](#metadata-service) + - [Real time situation service](#real-time-situation-service) + - [Time series service](#time-series-service) + - [Protocol version](#protocol-version) +- [Authentication service messages](#authentication-service-messages) + - [Login](#login) + - [Get users](#get-users) + - [Create user](#create-user) + - [Update user](#update-user) + - [Delete user](#delete-user) +- [Metadata service messages](#metadata-service-messages) + - [Get buildings](#get-buildings) + - [Create building](#create-building) + - [Update building](#update-building) + - [Delete building](#delete-building) + - [Get building's floor plans](#get-buildings-floor-plans) + - [Create floor plan](#create-floor-plan) + - [Update floor plan](#update-floor-plan) + - [Delete floor plan](#delete-floor-plan) + - [Get floor plan image data](#get-floor-plan-image-data) + - [Set floor plan image data](#set-floor-plan-image-data) + - [Get areas](#get-areas) + - [Create area](#create-area) + - [Update area](#update-area) + - [Delete area](#delete-area) + - [Get networks](#get-networks) + - [Create network](#create-network) + - [Update network](#update-network) + - [Delete network](#delete-network) + - [Add node to floor plan](#add-node-to-floor-plan) + - [Remove node from floor plan](#remove-node-from-floor-plan) + - [Set node metadata](#set-node-metadata) + - [Delete node](#delete-node) + - [Set network data](#set-network-data) + - [Send data message](#send-data-message) + - [Get scratchpad status](#get-scratchpad-status) + - [Get components information](#get-components-information) +- [Real time situation service authentication](#real-time-situation-service-authentication) +- [Time series service data](#time-series-service-data) + - [Example CURL command to query data](#example-curl-command-to-query-data) + - [Example column names decoding](#example-column-names-decoding) +- [Basic data flow and real time situation data](#basic-data-flow-and-real-time-situation-data) + - [Basic data flow to get continuous data](#basic-data-flow-to-get-continuous-data) + - [Real time situation data](#real-time-situation-data) +- [Coordinate conversions](#coordinate-conversions) + - [Introduction](#introduction-1) + - [WGS84 to pixels](#wgs84-to-pixels) + - [Pixels to WGS84](#pixels-to-wgs84) + - [WGS84 to ECEF conversion](#wgs84-to-ecef-conversion) + - [ECEF to WGS84 conversion](#ecef-to-wgs84-conversion) +- [References](#references) + + + + + +Introduction +============ + +This document describes the Wirepas Network Tool (WNT) server backend +API and is intended for Wirepas licensee to implement own services on +top of the WNT server. Prerequisites include overall knowledge of +Wirepas Mesh (WM) and WNT client. APIs are implemented on top of web +sockets and HTTP connections using JSON and Protocol Buffers (version 2) +data encoding. + +This document is compliant with WNT backend version 2.0. + +Backend interface components +============================ + +Backend client interface consists of four individual components which +all use secure versions of the protocols (WSS, HTTPS). + +Figure 1 Simplified architecture + +![](./media/image2.png){width="6.820178258967629in" +height="2.9400590551181103in"} + +Table 1: Components + + Component Protocol Port Data encoding + --------------------- ------------ ------ --------------------- + Authentication Web socket 8813 JSON + Metadata Web socket 8812 JSON + Real time situation Web socket 8811 Protocol Buffers \* + Time series HTTP 8886 JSON \*\* + +\* Authentication is done by using JSON + +\*\* Queries are sent via HTTP GET + +The MQTT connection between the gateway and WNT backend is described in +document: WP-RM-128 - API between a Gateway and Wirepas Backends. + +Authentication service +---------------------- + +The service handles user management and access to metadata and real time +situation service. The time series service share the same credentials as +the authentication service. Any credentials changes made through +authentication service are propagated automatically to the time series +service. Credentials can only be changed via authentication service. +Other clients are notified about the users related changes (except +password changes) via real time situation connection. + +Metadata service +---------------- + +Metadata service provides access to: + +- node metadata + +- buildings + +- floor plans + +- areas + +- network information + +- downlink communication with the nodes + +The clients are notified about the metadata changes via real time +situation connection. + +Real time situation service +--------------------------- + +The real time information of all the nodes and changes to metadata are +available from the real time situation service. After the connection is +established, and authentication has succeeded, the service will send all +real time information via the connection. When the service receives new +information from the nodes it forwards only the data that has changed to +the client connections. + +Time series service +------------------- + +Time series service contains diagnostics - and auxiliary data. It is +implemented as direct access to the Influx database version 1.5. For +more information please see chapter 7. + +Protocol version +---------------- + +Authentication, metadata and real time situation (authentication) +messages contains protocol version field. This field needs to match the +correct protocol version supported by the WNT backend. At the moment the +backend cannot handle messages of older protocol version. + +Table 2: Protocol versions + + Protocol version Backend version + ------------------ ----------------- + 2 1.6, 1.7 + 3 2.0 + +**\ +** + +Authentication service messages +=============================== + +Authentication service works in request / response principle. User is +automatically logged out when the connection is closed, and session id +received via login message cannot be used later. Authenticated real time +situation connection will work after the authentication service +connection is closed. Access to methods are depending on user's role. + +Table 3: Roles + + Role Number + --------------- -------- + Administrator 1 + Operator 2 + +Simple rule between the roles is that operator can only query data, but +administrator can also make changes. + +All requests have common version field which denotes the protocol +version and distinct type field per message type. + +Table 4: Message types + + Message Type Role + ------------- ------ --------------- + Login 1 All + Get users 11 Administrator + Create user 12 Administrator + Update user 13 Administrator + Delete user 14 Administrator + +Due to possibility that the information about the change comes earlier +from the real time situation connection than the response from the +authentication service, some methods contain an *originator\_token* +field which can be used to check if the change was originated from the +current client. The token can be e.g. UUID (version 1 / 4) as string. + +Responses contains *result* field which contains information if any +error occurred. + +Table 5: Result codes + + Message Code + ------------------------------------------------- ------ + Ok 1 + Generic error 2 + Invalid credentials while logging in 3 + Wrong protocol version 4 + User does not have rights to perform the action 5 + Invalid user id 6 + User which was tried to create already exists 7 + Received message was invalid 8 + Invalid session id 9 + +User information fields have minimum and maximum lengths in characters. + +Table 6: Minimum and maximum lengths + + Field Minimum Maximum + ------------ --------- --------- + username 1 63 + password 6 255 + full\_name 1 255 + +Login +----- + +*Login* message is used to login to the services and it returns a +session id that is used to authenticate to the metadata and real time +situation services. + +Table 7: Login message + ++----------------------------------+-------------------------------------+ +| Request | Response | ++==================================+=====================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"username\": \"\\", | \"role\": 1, | +| | | +| \"password\": \"\\" | \"session\_id\": \"\\" | +| | | +| }, | }, | +| | | +| \"type\": 1, | \"result\": 1, | +| | | +| \"version\": 3 | \"type\": 1, | +| | | +| } | \"version\": 3 | +| | | +| | } | ++----------------------------------+-------------------------------------+ + +Get users +--------- + +Message returns list of users and users' information. + +Table 8:Get users message + ++--------------------------------------+-------------------------------+ +| Request | Example response | ++======================================+===============================+ +| { | { | +| | | +| \"data\": {}, | \"data\": { | +| | | +| \"session\_id\": \"\\", | \"users\": \[ | +| | | +| \"type\": 11, | { | +| | | +| \"version\": 3 | \"full\_name\": \"John Doe\", | +| | | +| } | \"role\": 2, | +| | | +| | \"username\": \"johndoe\" | +| | | +| | }, | +| | | +| | { | +| | | +| | \"full\_name\": \"Jane Doe\", | +| | | +| | \"role\": 1, | +| | | +| | \"username\": \"janedoe\" | +| | | +| | } | +| | | +| | \] | +| | | +| | }, | +| | | +| | \"result\": 1, | +| | | +| | \"type\": 11, | +| | | +| | \"version\": 3 | +| | | +| | } | ++--------------------------------------+-------------------------------+ + +Create user +----------- + +New user can be created with *create user* message. Only a single user +can be created with the message although *users* field is an array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_users* message. + +Table 9: Create user message + ++---------------------------------------+----------------+ +| Request | Response | ++=======================================+================+ +| { | { | +| | | +| \"data\": { | \"data\": {}, | +| | | +| \"originator\_token\": \"\\", | \"result\": 1, | +| | | +| \"users\": \[ | \"type\": 12, | +| | | +| { | \"version\": 3 | +| | | +| \"full\_name\": \"\\", | } | +| | | +| \"password\": \"\\", | | +| | | +| \"role\": \, | | +| | | +| \"username\": \"\\" | | +| | | +| } | | +| | | +| \] | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 12, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++---------------------------------------+----------------+ + +Update user +----------- + +User can be updated with *update user* message. Only a single user can +be updated with the message although *users* field is an array. In user +data only *username* field is required. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_users* message. + +Table 10: Update user message + ++-----------------------------------------+----------------+ +| Request | Response | ++=========================================+================+ +| { | { | +| | | +| \"data\": { | \"data\": {}, | +| | | +| \"originator\_token\": \"\\", | \"result\": 1, | +| | | +| \"users\": \[ | \"type\": 13, | +| | | +| { | \"version\": 3 | +| | | +| \"full\_name\": \"\\", | } | +| | | +| \"password\": \"\\", | | +| | | +| \"role\": \, | | +| | | +| \"username\": \"\\" | | +| | | +| } | | +| | | +| \] | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 13, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++-----------------------------------------+----------------+ + +Delete user +----------- + +User can be deleted with *delete user* message. Only a single user can +be deleted with the message although *users* field is an array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_users* message. + +Table 11: Delete user message + ++---------------------------------------+----------------+ +| Request | Response | ++=======================================+================+ +| { | { | +| | | +| \"data\": { | \"data\": {}, | +| | | +| \"originator\_token\": \"\\", | \"result\": 1, | +| | | +| \"users\": \[ | \"type\": 14, | +| | | +| { | \"version\": 3 | +| | | +| \"username\": \"\\" | } | +| | | +| } | | +| | | +| \] | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 14, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++---------------------------------------+----------------+ + +Metadata service messages +========================= + +Metadata service works in request / response principle. All the messages +require *session id*, which can be get from authentication service. + +All requests have a common *version* field which denotes the protocol +version and distinct *type* field per message type. + +Table 12: Message types + + Message Type Role + --------------------------------------- ------ --------------- + Get buildings 1001 All + Create building 1002 Administrator + Update building 1003 Administrator + Delete building 1004 Administrator + Get building's floor plans 1011 All + Create floor plan 1012 Administrator + Update floor plan 1013 Administrator + Delete floor plan 1014 Administrator + Get floor plan image data 1021 All + Set floor plan image data 1022 Administrator + Get map areas 1031 All + Create map area 1032 Administrator + Update map area 1033 Administrator + Delete map area 1034 Administrator + Get networks 1041 All + Create network 1042 Administrator + Update network 1043 Administrator + Delete network 1044 Administrator + Add node to floor plan 1051 Administrator + Remove node from floor plan 1052 Administrator + Set node metadata 1061 Administrator + Change node id and / or network id \* 1062 Administrator + Delete node 1063 Administrator + Set network data 1071 Administrator + Send Remote API request \* 1072 Administrator + Send data message 1073 Administrator + Get scratchpad status 1074 Administrator + Load scratchpad \* 1075 Administrator + Get components information 1081 All + +\* Message will be documented later + +Due to possibility that the information about the change comes earlier +from the real time situation connection than the response from the +metadata service, some methods contain an *originator\_token* field +which can be used to check if the change was originated from the current +client. The token can be e.g. UUID (version 1 / 4) as string. + +Responses contains *result* field which contains information if any +error occurred. + +Table 13: Result codes + + Message Code + ------------------------------------------------- ------ + Ok 1 + Generic error 2 + Wrong protocol version 4 + User does not have rights to perform the action 5 + Invalid id (building, floor plan, area etc.) 6 + Received message was invalid 8 + Invalid session id 9 + +Get buildings +------------- + +The message returns name and id of all the buildings. + +Table 14: Get buildings message + ++-----------------------------------+-----------------------------------+ +| Request | Example response | ++===================================+===================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"originator\_token\": | \"buildings\": \[ | +| \"\\" | | +| | { | +| }, | | +| | \"id\": | +| \"session\_id\": \"\\", | 47812\", | +| | | +| \"type\": 1001, | \"name\": \"Main building\" | +| | | +| \"version\": 3 | }, | +| | | +| } | { | +| | | +| | \"id\": | +| | \"e936d185-42db-ff18-57b5-4deb02d | +| | 05c58\", | +| | | +| | \"name\": \"Other building\" | +| | | +| | } | +| | | +| | \] | +| | | +| | }, | +| | | +| | \"result\": 1, | +| | | +| | \"type\": 1001, | +| | | +| | \"version\": 3 | +| | | +| | } | ++-----------------------------------+-----------------------------------+ + +Create building +--------------- + +New building can be created with *create building* message which returns +building id that can be used later to reference the building. Only a +single building can be created with the message although *buildings* +field is an array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_buildings* message. + +Table 15: Create building message + ++--------------------------------------+-----------------------------+ +| Request | Response | ++======================================+=============================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"buildings\": \[ | \"buildings\": \[ | +| | | +| { | { | +| | | +| \"name\": \"\\" | \"id\": \"\\" | +| | | +| } | } | +| | | +| \], | \] | +| | | +| \"originator\_token\": \"\\" | }, | +| | | +| }, | \"result\": 1, | +| | | +| \"session\_id\": \"\\", | \"type\": 1002, | +| | | +| \"type\": 1002, | \"version\": 3 | +| | | +| \"version\": 3 | } | +| | | +| } | | ++--------------------------------------+-----------------------------+ + +Update building +--------------- + +Building name can be updated with *update building* message. Only a +single building can be updated with the message although *buildings* +field is an array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_buildings* message. + +Table 16: Update building message + ++-----------------------------------------+-----------------+ +| Request | Response | ++=========================================+=================+ +| { | { | +| | | +| \"data\": { | \"data\": {}, | +| | | +| \"buildings\": \[ | \"result\": 1, | +| | | +| { | \"type\": 1003, | +| | | +| \"id\": \"\\", | \"version\": 3 | +| | | +| \"name\": \"\\" | } | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1003, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++-----------------------------------------+-----------------+ + +Delete building +--------------- + +Building can be deleted with *delete building* message. Only a single +building can be deleted with the message although *buildings* field is +an array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_buildings* message. + +Table 17: Delete building message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"buildings\": \[ | \"type\": 1004, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": \"\\" | } | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1004, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Get building's floor plans +-------------------------- + +The message returns information about the floor plans in a building. +Only a single building's floor plans can be fetched with the message +although *buildings* field is an array. + +The *rotation\_matrix*, *offset\_ecef\_to\_local, +offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for +mapping between WGS84 and pixel coordinates. For more information please +see chapter 9. + +Table 18: Get building's floor plans message + ++-----------------------------------+-----------------------------------+ +| Request | Example response (only one floor | +| | plan) | ++===================================+===================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"buildings\": \[ | \"buildings\": \[ | +| | | +| { | { | +| | | +| \"id\": \"\\" | \"id\": | +| | \"3b326217-676d-f547-019b-6d8e0e1 | +| } | fc5dc\", | +| | | +| \], | \"floor\_plans\": \[ | +| | | +| \"originator\_token\": | { | +| \"\\" | | +| | \"id\": | +| }, | \"1e19239c-bcd2-829a-44a1-900e083 | +| | f0bfe\", | +| \"session\_id\": \"\\", | \"name\": \"New floor plan\", | +| | | +| \"type\": 1011, | \"level\": 0, | +| | | +| \"version\": 3 | "image\_width": null, | +| | | +| } | "image\_height": null, | +| | | +| | \"image\_id\": null, | +| | | +| | \"image\_thumbnail\_id\": null, | +| | | +| | \"altitude\_leftbottom\": null, | +| | | +| | \"altitude\_lefttop\": null, | +| | | +| | \"altitude\_rightbottom\": null, | +| | | +| | \"altitude\_righttop\": null, | +| | | +| | \"distance\_in\_m\": 1, | +| | | +| | \"latitude\_leftbottom\": null, | +| | | +| | \"latitude\_lefttop\": null, | +| | | +| | \"latitude\_rightbottom\": null, | +| | | +| | \"latitude\_righttop\": null, | +| | | +| | \"longitude\_leftbottom\": null, | +| | | +| | \"longitude\_lefttop\": null, | +| | | +| | \"longitude\_rightbottom\": null, | +| | | +| | \"longitude\_righttop\": null, | +| | | +| | \"x\_distance\_point1\": 0.3, | +| | | +| | \"x\_distance\_point2\": 0.7, | +| | | +| | \"x\_normcoord\_leftbottom\": 0, | +| | | +| | \"x\_normcoord\_lefttop\": 0, | +| | | +| | \"x\_normcoord\_rightbottom\": 1, | +| | | +| | \"x\_normcoord\_righttop\": 1, | +| | | +| | \"y\_distance\_point1\": 0.5, | +| | | +| | \"y\_distance\_point2\": 0.5, | +| | | +| | \"y\_normcoord\_leftbottom\": 1, | +| | | +| | \"y\_normcoord\_lefttop\": 0, | +| | | +| | \"y\_normcoord\_rightbottom\": 1, | +| | | +| | \"y\_normcoord\_righttop\": 0, | +| | | +| | \"rotation\_matrix\": { | +| | | +| | \"m11\": null, | +| | | +| | \"m12\": null, | +| | | +| | \"m13\": null, | +| | | +| | \"m21\": null, | +| | | +| | \"m22\": null, | +| | | +| | \"m23\": null, | +| | | +| | \"m31\": null, | +| | | +| | \"m32\": null, | +| | | +| | \"m33\": null | +| | | +| | }, | +| | | +| | \"offset\_ecef\_to\_local\": { | +| | | +| | \"x\": null, | +| | | +| | \"y\": null, | +| | | +| | \"z\": null | +| | | +| | }, | +| | | +| | \"offset\_local\_to\_ecef\": { | +| | | +| | \"x\": null, | +| | | +| | \"y\": null, | +| | | +| | \"z\": null | +| | | +| | }, | +| | | +| | \"pixels\_per\_meter\": null | +| | | +| | } | +| | | +| | \] | +| | | +| | } | +| | | +| | \] | +| | | +| | }, | +| | | +| | \"result\": 1, | +| | | +| | \"type\": 1011, | +| | | +| | \"version\": 3 | +| | | +| | } | ++-----------------------------------+-----------------------------------+ + +Create floor plan +----------------- + +New floor plan can be created with *create floor plan* message which +returns floor plan id that can be used later to reference the floor +plan. It is recommended to use the values defined below when creating a +new floor plan. Only a single floor plan can be created to a single +building with the message although *buildings* and *floor­\_plans* +fields are arrays. + +The *rotation\_matrix*, *offset\_ecef\_to\_local, +offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for +mapping between WGS84 and pixel coordinates. For more information please +see chapter 9. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_floor\_plans* +message. + +Table 19: Create floor plan message + ++--------------------------------------+-----------------------------------+ +| Request | Response | ++======================================+===================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"buildings\": \[ | \"buildings\": \[ | +| | | +| { | { | +| | | +| \"id\": \"\\", | \"floor\_plans\": \[ | +| | | +| \"floor\_plans\": \[ | { | +| | | +| { | \"id\": \"\\", | +| | | +| \"name\": \"\\", | \"name\": "\\", | +| | | +| \"level\": \, | \"level\": \, | +| | | +| "image\_width": null, | "image\_width": null, | +| | | +| "image\_height": null, | "image\_height": null, | +| | | +| \"altitude\_leftbottom\": null, | \"image\_id\": null, | +| | | +| \"altitude\_lefttop\": null, | \"image\_thumbnail\_id\": null, | +| | | +| \"altitude\_rightbottom\": null, | \"altitude\_leftbottom\": null, | +| | | +| \"altitude\_righttop\": null, | \"altitude\_lefttop\": null, | +| | | +| \"distance\_in\_m\": 1, | \"altitude\_rightbottom\": null, | +| | | +| \"latitude\_leftbottom\": null, | \"altitude\_righttop\": null, | +| | | +| \"latitude\_lefttop\": null, | \"distance\_in\_m\": 1, | +| | | +| \"latitude\_rightbottom\": null, | \"latitude\_leftbottom\": null, | +| | | +| \"latitude\_righttop\": null, | \"latitude\_lefttop\": null, | +| | | +| \"longitude\_leftbottom\": null, | \"latitude\_rightbottom\": null, | +| | | +| \"longitude\_lefttop\": null, | \"latitude\_righttop\": null, | +| | | +| \"longitude\_rightbottom\": null, | \"longitude\_leftbottom\": null, | +| | | +| \"longitude\_righttop\": null, | \"longitude\_lefttop\": null, | +| | | +| \"x\_distance\_point1\": 0.3, | \"longitude\_rightbottom\": null, | +| | | +| \"x\_distance\_point2\": 0.7, | \"longitude\_righttop\": null, | +| | | +| \"x\_normcoord\_leftbottom\": 0, | \"x\_distance\_point1\": 0.3, | +| | | +| \"x\_normcoord\_lefttop\": 0, | \"x\_distance\_point2\": 0.7, | +| | | +| \"x\_normcoord\_rightbottom\": 1, | \"x\_normcoord\_leftbottom\": 0, | +| | | +| \"x\_normcoord\_righttop\": 1, | \"x\_normcoord\_lefttop\": 0, | +| | | +| \"y\_distance\_point1\": 0.5, | \"x\_normcoord\_rightbottom\": 1, | +| | | +| \"y\_distance\_point2\": 0.5, | \"x\_normcoord\_righttop\": 1, | +| | | +| \"y\_normcoord\_leftbottom\": 1, | \"y\_distance\_point1\": 0.5, | +| | | +| \"y\_normcoord\_lefttop\": 0, | \"y\_distance\_point2\": 0.5, | +| | | +| \"y\_normcoord\_rightbottom\": 1, | \"y\_normcoord\_leftbottom\": 1, | +| | | +| \"y\_normcoord\_righttop\": 0 | \"y\_normcoord\_lefttop\": 0, | +| | | +| } | \"y\_normcoord\_rightbottom\": 1, | +| | | +| \] | \"y\_normcoord\_righttop\": 0, | +| | | +| } | \"rotation\_matrix\": { | +| | | +| \], | \"m11\": null, | +| | | +| \"originator\_token\": \"\\" | \"m12\": null, | +| | | +| }, | \"m13\": null, | +| | | +| \"session\_id\": \"\\", | \"m21\": null, | +| | | +| \"type\": 1012, | \"m22\": null, | +| | | +| \"version\": 3 | \"m23\": null, | +| | | +| } | \"m31\": null, | +| | | +| | \"m32\": null, | +| | | +| | \"m33\": null | +| | | +| | }, | +| | | +| | \"offset\_ecef\_to\_local\": { | +| | | +| | \"x\": null, | +| | | +| | \"y\": null, | +| | | +| | \"z\": null | +| | | +| | }, | +| | | +| | \"offset\_local\_to\_ecef\": { | +| | | +| | \"x\": null, | +| | | +| | \"y\": null, | +| | | +| | \"z\": null | +| | | +| | }, | +| | | +| | \"pixels\_per\_meter\": null | +| | | +| | } | +| | | +| | \], | +| | | +| | \"id\": \"\\" | +| | | +| | } | +| | | +| | \] | +| | | +| | }, | +| | | +| | \"result\": 1, | +| | | +| | \"type\": 1012, | +| | | +| | \"version\": 3 | +| | | +| | } | ++--------------------------------------+-----------------------------------+ + +Update floor plan +----------------- + +Floor plan information can be updated with *update floor plan* message. +Only a single floor plan in single building can be updated with the +message although *buildings* and *floor\_plans* fields are arrays. +Request below shows how a floor plan image and thumbnail are bound to +the floor plan. + +The *rotation\_matrix*, *offset\_ecef\_to\_local, +offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for +mapping between WGS84 and pixel coordinates. For more information please +see chapter 9. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_floor\_plans* +message. + +Table 20: Update floor plan message + ++-----------------------------------+-----------------------------------+ +| > Example request | > Response | ++===================================+===================================+ +| > { | > { | +| > | > | +| > \"data\": { | > \"data\": { | +| > | > | +| > \"buildings\": \[ | > \"buildings\": \[ | +| > | > | +| > { | > { | +| > | > | +| > \"floor\_plans\": \[ | > \"floor\_plans\": \[ | +| > | > | +| > { | > { | +| > | > | +| > \"id\": \"\\", | > \"id\": \"\\", | +| > | > | +| > \"image\_id\": \"\ \"name\": "\ id\>\", | > name\>\", | +| > | > | +| > \"image\_thumbnail\_id\": | > \"level\": \, | +| > \"\\", | > | +| > | > "image\_width": null, | +| > "image\_width": 640, | > | +| > | > "image\_height": null, | +| > "image\_height": 480 | > | +| > | > \"image\_id\": null, | +| > } | > | +| > | > \"image\_thumbnail\_id\": null, | +| > \] | > | +| > | > \"altitude\_leftbottom\": null, | +| > } | > | +| > | > \"altitude\_lefttop\": null, | +| > \], | > | +| > | > \"altitude\_rightbottom\": | +| > \"originator\_token\": | > null, | +| > \"\\" | > | +| > | > \"altitude\_righttop\": null, | +| > }, | > | +| > | > \"distance\_in\_m\": 1, | +| > \"session\_id\": \"\ | +| > id\>\", | > \"latitude\_leftbottom\": null, | +| > | > | +| > \"type\": 1013, | > \"latitude\_lefttop\": null, | +| > | > | +| > \"version\": 3 | > \"latitude\_rightbottom\": | +| > | > null, | +| > } | > | +| | > \"latitude\_righttop\": null, | +| | > | +| | > \"longitude\_leftbottom\": | +| | > null, | +| | > | +| | > \"longitude\_lefttop\": null, | +| | > | +| | > \"longitude\_rightbottom\": | +| | > null, | +| | > | +| | > \"longitude\_righttop\": null, | +| | > | +| | > \"x\_distance\_point1\": 0.3, | +| | > | +| | > \"x\_distance\_point2\": 0.7, | +| | > | +| | > \"x\_normcoord\_leftbottom\": | +| | > 0, | +| | > | +| | > \"x\_normcoord\_lefttop\": 0, | +| | > | +| | > \"x\_normcoord\_rightbottom\": | +| | > 1, | +| | > | +| | > \"x\_normcoord\_righttop\": 1, | +| | > | +| | > \"y\_distance\_point1\": 0.5, | +| | > | +| | > \"y\_distance\_point2\": 0.5, | +| | > | +| | > \"y\_normcoord\_leftbottom\": | +| | > 1, | +| | > | +| | > \"y\_normcoord\_lefttop\": 0, | +| | > | +| | > \"y\_normcoord\_rightbottom\": | +| | > 1, | +| | > | +| | > \"y\_normcoord\_righttop\": 0, | +| | > | +| | > \"rotation\_matrix\": { | +| | > | +| | > \"m11\": null, | +| | > | +| | > \"m12\": null, | +| | > | +| | > \"m13\": null, | +| | > | +| | > \"m21\": null, | +| | > | +| | > \"m22\": null, | +| | > | +| | > \"m23\": null, | +| | > | +| | > \"m31\": null, | +| | > | +| | > \"m32\": null, | +| | > | +| | > \"m33\": null | +| | > | +| | > }, | +| | > | +| | > \"offset\_ecef\_to\_local\": { | +| | > | +| | > \"x\": null, | +| | > | +| | > \"y\": null, | +| | > | +| | > \"z\": null | +| | > | +| | > }, | +| | > | +| | > \"offset\_local\_to\_ecef\": { | +| | > | +| | > \"x\": null, | +| | > | +| | > \"y\": null, | +| | > | +| | > \"z\": null | +| | > | +| | > }, | +| | > | +| | > \"pixels\_per\_meter\": null | +| | > | +| | > } | +| | > | +| | > \] | +| | > | +| | > } | +| | > | +| | > \] | +| | > | +| | > }, | +| | > | +| | > \"result\": 1, | +| | > | +| | > \"type\": 1013, | +| | > | +| | > \"version\": 3 | +| | > | +| | > } | ++-----------------------------------+-----------------------------------+ + +Delete floor plan +----------------- + +Floor plan can be deleted with *delete floor plan* message. Only a +single floor plan in single building can be deleted with the message +although *buildings* and *floor\_plans* fields are arrays. + +Updates are sent to clients via real time situation connection\ +*metadata\_update\_message -\> deleted\_floor\_plans* message. + +Table 21: Delete floor plan message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"buildings\": \[ | \"type\": 1014, | +| | | +| { | \"version\": 3 | +| | | +| \"floor\_plans\": \[ | } | +| | | +| { | | +| | | +| \"id\": \"\\" | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1014, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Get floor plan image data +------------------------- + +The method can be used to fetch floor plan image or thumbnail data. The +image binary data is encoded using Base64 (RFC 3548) encoding. + +Table 22: Get floor plan image data message + ++-----------------------------------+-----------------------------------+ +| Request | Response | ++===================================+===================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"image\_id\": \"\" | +| thumbnail id\>\", | | +| | }, | +| \"originator\_token\": | | +| \"\\" | \"result\": 1, | +| | | +| }, | \"type\": 1021, | +| | | +| \"session\_id\": \"\\", | | +| | } | +| \"type\": 1021, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++-----------------------------------+-----------------------------------+ + +Set floor plan image data +------------------------- + +The method can be used to upload floor plan image or thumbnail data. The +image binary data needs to be encoded using Base64 (RFC 3548) encoding. +The method returns image id which can be used to reference the image +later. Supported image formats are BMP, TIFF, JPEG, GIF, PNG and JPEG +XR. + +Table 23: Set floor plan image data message + ++--------------------------------------+---------------------------------+ +| Request | Response | ++======================================+=================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"image\_base64\": \"\", | \"image\_id\": \"\\" | +| | | +| \"originator\_token\": \"\\" | }, | +| | | +| }, | \"result\": 1, | +| | | +| \"session\_id\": \"\\", | \"type\": 1022, | +| | | +| \"type\": 1022, | \"version\": 3 | +| | | +| \"version\": 3 | } | +| | | +| } | | ++--------------------------------------+---------------------------------+ + +Get areas +--------- + +The message returns areas for given floor plan id. Only a single floor +plan's areas in a single building can be queried with the message +although *buildings* and *floor\_plans* fields are arrays. Area color +values (alpha, red, green and blue) are integers between 0...255. *llas* +is an array of area corner points' coordinates in WGS84 format and can +contain 3...n items. *altitude* is in meters. + +Table 24: Get areas message + ++--------------------------------------+------------------------------------+ +| Request | Response | ++======================================+====================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"buildings\": \[ | \"buildings\": \[ | +| | | +| { | { | +| | | +| \"floor\_plans\": \[ | \"floor\_plans\": \[ | +| | | +| { | { | +| | | +| \"id\": \"\\" | \"id\": \"\\", | +| | | +| } | \"areas\": \[ | +| | | +| \] | { | +| | | +| } | \"id\": \"\\", | +| | | +| \], | \"name\": \"\\", | +| | | +| \"originator\_token\": \"\\" | \"a\": \, | +| | | +| }, | \"r\": \, | +| | | +| \"session\_id\": \"\\", | \"g\": \, | +| | | +| \"type\": 1031, | \"b\": \, | +| | | +| \"version\": 3 | \"llas\": \[ | +| | | +| } | { | +| | | +| | \"altitude\": \, | +| | | +| | \"latitude\": \, | +| | | +| | \"longitude\": \ | +| | | +| | }, | +| | | +| | { | +| | | +| | \"altitude\": \, | +| | | +| | \"latitude\": \, | +| | | +| | \"longitude\": \ | +| | | +| | }, | +| | | +| | { | +| | | +| | \"altitude\": \, | +| | | +| | \"latitude\": \, | +| | | +| | \"longitude\": \ | +| | | +| | } | +| | | +| | \] | +| | | +| | } | +| | | +| | \] | +| | | +| | } | +| | | +| | \] | +| | | +| | } | +| | | +| | \] | +| | | +| | }, | +| | | +| | \"result\": 1, | +| | | +| | \"type\": 1031, | +| | | +| | \"version\": 3 | +| | | +| | } | ++--------------------------------------+------------------------------------+ + +Create area +----------- + +New area can be created with *create area* message which returns area id +that can be used later to reference the area. Only a single area in a +single floor plan and single building can be created with the message +although *buildings*, *floor\_plans* and *areas* fields are arrays. Area +color values (alpha, red, green and blue) are integers between 0...255. +*llas* is an array of area corner points' coordinates in WGS84 format +and can contain 3...n items. *altitude* is in meters. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_areas* message. + +Table 25: Create area message + ++--------------------------------------+--------------------------------+ +| Request | Response | ++======================================+================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"buildings\": \[ | \"buildings\": \[ | +| | | +| { | { | +| | | +| \"floor\_plans\": \[ | \"floor\_plans\": \[ | +| | | +| { | { | +| | | +| \"id\": \"\\", | \"id\": \"\\", | +| | | +| \"areas\": \[ | \"areas\": \[ | +| | | +| { | { | +| | | +| \"name\": \"\\", | \"id\": \"\\" | +| | | +| \"a\": \, | } | +| | | +| \"r\": \, | \] | +| | | +| \"g\": \, | } | +| | | +| \"b\": \, | \] | +| | | +| \"llas\": \[ | } | +| | | +| { | \] | +| | | +| \"altitude\": \, | }, | +| | | +| \"latitude\": \, | \"result\": 1, | +| | | +| \"longitude\": \ | \"type\": 1032, | +| | | +| }, | \"version\": 3 | +| | | +| { | } | +| | | +| \"altitude\": \, | | +| | | +| \"latitude\": \, | | +| | | +| \"longitude\": \ | | +| | | +| }, | | +| | | +| { | | +| | | +| \"altitude\": \, | | +| | | +| \"latitude\": \, | | +| | | +| \"longitude\": \ | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1032, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+--------------------------------+ + +Update area +----------- + +Existing area can be updated with *update area* message. Area color +values (alpha, red, green and blue) are integers between 0...255. *llas* +is an array of area corner points' coordinates in WGS84 format and can +contain 3...n items. *altitude* is in meters. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_areas* message. + +Table 26: Update area message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"buildings\": \[ | \"type\": 1033, | +| | | +| { | \"version\": 3 | +| | | +| \"floor\_plans\": \[ | } | +| | | +| { | | +| | | +| \"id\": \"\\", | | +| | | +| \"areas\": \[ | | +| | | +| { | | +| | | +| \"id\": \"\\", | | +| | | +| \"name\": \"\\", | | +| | | +| \"a\": \, | | +| | | +| \"r\": \, | | +| | | +| \"g\": \, | | +| | | +| \"b\": \, | | +| | | +| \"llas\": \[ | | +| | | +| { | | +| | | +| \"altitude\": \, | | +| | | +| \"latitude\": \, | | +| | | +| \"longitude\": \ | | +| | | +| }, | | +| | | +| { | | +| | | +| \"altitude\": \, | | +| | | +| \"latitude\": \, | | +| | | +| \"longitude\": \ | | +| | | +| }, | | +| | | +| { | | +| | | +| \"altitude\": \, | | +| | | +| \"latitude\": \, | | +| | | +| \"longitude\": \ | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1033, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Delete area +----------- + +Area can be deleted with delete building message. Only a single area can +be deleted with the message although *buildings, floor\_plans* and +*areas* fields are arrays. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_areas* message. + +Table 27: Delete building message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"buildings\": \[ | \"type\": 1034, | +| | | +| { | \"version\": 3 | +| | | +| \"floor\_plans\": \[ | } | +| | | +| { | | +| | | +| \"id\": \"\\", | | +| | | +| \"areas\": \[ | | +| | | +| { | | +| | | +| \"id\": \"\\" | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \] | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1034, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Get networks +------------ + +The message returns network id and name mappings. + +Table 28: Get networks message + ++--------------------------------------+--------------------------------+ +| Request | Example response | ++======================================+================================+ +| { | { | +| | | +| \"data\": { | \"data\": { | +| | | +| \"originator\_token\": \"\\" | \"networks\": \[ | +| | | +| }, | { | +| | | +| \"session\_id\": \"\\", | \"id\": \, | +| | | +| \"type\": 1041, | \"name\": \"\\" | +| | | +| \"version\": 3 | }, | +| | | +| } | { | +| | | +| | \"id\": \, | +| | | +| | \"name\": \"\\" | +| | | +| | } | +| | | +| | \] | +| | | +| | }, | +| | | +| | \"result\": 1, | +| | | +| | \"type\": 1041, | +| | | +| | \"version\": 3 | +| | | +| | } | ++--------------------------------------+--------------------------------+ + +Create network +-------------- + +The message is used to create a new network id to name mapping. Only a +single network mapping can be created with the message although +*networks* field is an array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_networks* message. + +Table 29: Create network message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"networks\": \[ | \"type\": 1042, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": \, | } | +| | | +| \"name\": \"\\" | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1042, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Update network +-------------- + +Network name can be updated with *update network* message. Only a single +network can be updated with the message although *networks* field is an +array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_networks* message. + +Table 30: Update network message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"networks\": \[ | \"type\": 1043, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": \, | } | +| | | +| \"name\": \"\\" | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1043, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Delete network +-------------- + +Network id to name mapping can be deleted with *delete network* message. +Only a single network can be deleted with the message although +*networks* field is an array. + +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_networks* message. + +Table 31: Delete network message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"networks\": \[ | \"type\": 1044, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": \ | } | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1044, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Add node to floor plan +---------------------- + +Node can be bound to floor plan with *add node to floor plan* message. +Only a single node can be added with the message although *nodes* field +is an array. In order to see node in the floor plan the node needs to be +approved with valid location information with *set node metadata* +message. + +Updates are sent to clients via real time situation connection using +*node\_metadata* message. + +Table 32: Add node to floor plan message + ++---------------------------------------------+-----------------+ +| Request | Response | ++=============================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"nodes\": \[ | \"type\": 1051, | +| | | +| { | \"version\": 3 | +| | | +| \"floor\_plan\_id\": \"\\", | } | +| | | +| \"id\": \, | | +| | | +| \"network\_id\": \ | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1051, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++---------------------------------------------+-----------------+ + +Remove node from floor plan +--------------------------- + +Node can be removed from floor plan with *remove node from floor plan* +message. Only a single node can be removed with the message although +*nodes* field is an array. + +Updates are sent to clients via real time situation connection using +*node\_metadata* message. + +Table 33: Remove node from floor plan message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"nodes\": \[ | \"type\": 1052, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": \, | } | +| | | +| \"network\_id\": \ | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1052, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Set node metadata +----------------- + +The method is used set node related metadata. *is\_virtual* denotes the +planning node feature in WNT client \[2\]. + +Updates are sent to clients via real time situation connection using +*node\_metadata* message. + +Table 34: Set node metadata message + ++----------------------------------------+-----------------+ +| Example request | Response | ++========================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"nodes\": \[ | \"type\": 1061, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": 1, | } | +| | | +| \"network\_id\": 112233, | | +| | | +| \"name\": \"some name\", | | +| | | +| \"description\": \"some description\", | | +| | | +| \"is\_approved\": true, | | +| | | +| \"is\_virtual\": false, | | +| | | +| \"latitude\": 61.4547593371768, | | +| | | +| \"longitude\": 23.8856021513505, | | +| | | +| \"altitude\": 0.0 | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1061, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++----------------------------------------+-----------------+ + +Delete node +----------- + +The method is used to delete node real time situation and metadata. Only +a single node's data can be deleted with the message although *nodes* +field is an array. Note that if node sends any data afterwards it will +be shown again. Boolean type *is\_sink* information is required to let +the WNT backend to perform additional clean ups if needed. + +Updates are sent to clients via real time situation connection using +*node\_metadata* message. + +Table 35: Delete node message + ++--------------------------------------+-----------------+ +| Request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"nodes\": \[ | \"type\": 1063, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": \, | } | +| | | +| \"network\_id\": \, | | +| | | +| \"is\_sink\":\ | | +| | | +| } | | +| | | +| \], | | +| | | +| \"originator\_token\": \"\\" | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1063, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Set network data +---------------- + +The method can be used to set network wide application configuration +data and diagnostics interval \[1\]. Only a single network's data can be +set with the message although *networks* field is an array. + +Updates are sent to clients per sink via real time situation connection +using *app\_config* message. + +Table 36: Set network data message + ++-----------------------------------+-----------------------------------+ +| Example request | Response | ++===================================+===================================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"networks\": \[ | \"type\": 1071, | +| | | +| { | \"version\": 3 | +| | | +| \"application\_data\": | } | +| \"112233445566778899AABBCCDDEEFF\ | | +| ", | | +| | | +| \"diagnostics\_interval\": 60, | | +| | | +| \"id\": \"112233\" | | +| | | +| } | | +| | | +| \] | | +| | | +| }, | | +| | | +| \"originator\_token\": | | +| \"\\", | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1071, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++-----------------------------------+-----------------------------------+ + +Send data message +----------------- + +The method can be used to send arbitrary data message to a node. The +message requires that receiving node sink's node id is defined so the +message sending does not create unneeded load to the network. *Payload* +is hexadecimal encoded binary data. At the moment it is not possible to +get confirmation that node received the message. + +For more information about the fields please see DSAP-DATA\_TX.request +\[1\]. + +Table 37:Send data message + ++---------------------------------------+-----------------+ +| Example request | Response | ++=======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"command\": { | \"type\": 1073, | +| | | +| \"network\_id\": 777555, | \"version\": 3 | +| | | +| \"node\_id\": 2, | } | +| | | +| \"sink\_node\_id\": 1, | | +| | | +| \"source\_end\_point\": 255, | | +| | | +| \"destination\_end\_point\": 240, | | +| | | +| \"payload\": \"040001000300\", | | +| | | +| \"qos\": 0 | | +| | | +| } | | +| | | +| }, | | +| | | +| \"originator\_token\": \"\\", | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1073, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++---------------------------------------+-----------------+ + +Get scratchpad status +--------------------- + +The method can be used to query scratchpad status from the nodes in the +network. Only a single network's data can be get with the message +although *networks* field is an array. The query can be a single shot or +continuous. Continuous query sending interval can be defined by setting +*rerun\_interval\_s* property. + +Table 38:Query types + + Query rerun\_interval\_s is\_close + ------------------ -------------------- ----------- + Single shot 0 false + Start continuous Interval false + Stop continuous 0 true + +Data is sent to clients per node via real time situation connection +using *scratchpad\_status* message. + +Table 39: Get scratchpad status message + ++--------------------------------------+-----------------+ +| Example request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"networks\": \[ | \"type\": 1074, | +| | | +| { | \"version\": 3 | +| | | +| \"id\": 112233, | } | +| | | +| \"rerun\_interval\_s": 180, | | +| | | +| \"is\_close\": false | | +| | | +| } | | +| | | +| \] | | +| | | +| }, | | +| | | +| \"session\_id\": \"\\", | | +| | | +| \"type\": 1074, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + +Get components information +-------------------------- + +The method can be used to query backend components' and gateways' +information. + +Responses are sent to clients via the real time situation connection +using *backend\_component\_info* and *gateway\_info* messages. + +Please note that the backend component information is returned only from +the metadata service, and *originator\_token* is not yet returned via +the real time situation connection. + +Table 40: Get components information message + ++--------------------------------------+-----------------+ +| Example request | Response | ++======================================+=================+ +| { | { | +| | | +| \"data\": { | \"result\": 1, | +| | | +| \"originator\_token\": \"\\" | \"type\": 1081, | +| | | +| }, | \"version\": 3 | +| | | +| \"session\_id\": \"\\", | } | +| | | +| \"type\": 1081, | | +| | | +| \"version\": 3 | | +| | | +| } | | ++--------------------------------------+-----------------+ + + Real time situation service authentication +============================================ + +The service provides all nodes related data and changes to the metadata. +Authentication is done in the start by sending the *session id* received +from the authentication service. + +Table 41: Authentication + ++--------------------------------------+----------------+ +| Request | Response | ++======================================+================+ +| { | { | +| | | +| \"session\_id\": \"\\", | \"result\": 1, | +| | | +| \"version\": 3 | \"version\": 3 | +| | | +| } | } | ++--------------------------------------+----------------+ + +After a successful authentication the service starts to send Protocol +Buffers encoded data and moves into write only mode. First message(s) +will contain the node count per real time situation cluster cell. This +information can be used to determine how much data needs to be received +before the initial data is received. After this only the changed +information is sent to client. + +Table 42: Node count message + ++-----------------------------------+---------------+ +| Path | Data | ++===================================+===============+ +| Message -\> rtsituation\_metadata | cluster\_no | +| | | +| | cluster\_size | +| | | +| | node\_count | ++-----------------------------------+---------------+ + +Note that all received Protocol Buffers messages has message "Message" +as a root item (message.proto). + +Time series service data +======================== + +Time series data is provided by direct access to Influx database. The +same credentials used to login to authentication service can be used +also to access the database. + +The "wirepas*"* database contains several *measurements* (Influx +equivalent of database table). + +Table 43: Database measurements + + Measurement Description + ---------------------------- ------------------------------------------------------- + analytics\_next\_hop Hop count to sink + analytics\_nodestate Node online information \* + analytics\_packet High level information about every received packet + analytics\_traveltime\_kpi Processed information about packets' travel times + endpoint\_251 Traffic diagnostics \[3\] \*\* + endpoint\_252 Neighbor diagnostics \[3\] \*\* + endpoint\_253 Node diagnostics \[3\] \*\* + endpoint\_254 Boot diagnostics \[3\] \*\* + location\_measurement Positioning measurements received from the nodes \*\* + location\_update Computed positions for nodes \*\* + remote\_api\_response Remote API response information \*\* + +\* Online state uses the values defined in *OnlineStatus* message +(internal.proto). + +\*\* Column names use numbering from the WNT Protocol Buffers files. + +Wirepas Backend-client \[4\] contains *influx\_viewer* example which can +be used to query information from the Influx with the decoded column +names. + +Please note that in WNT 2.0, *analytics\_packet* measurement's +*travel\_time\_ms* column is replaced by *travel\_time\_ms\_qos0* and +*travel\_time\_ms\_qos1* columns. Also separate *qos* column is added to +the measurement. + +Example CURL command to query data +---------------------------------- + +curl.exe -G https://someaddresswnt.extwirepas.com:8886/query +\--data-urlencode \"u=\\" \--data-urlencode +\"p=\\" \--data-urlencode \"pretty=true\" \--data-urlencode +\"db=wirepas\" \--data-urlencode \"q=show measurements\" + +Example column names decoding +----------------------------- + +In the example the query used to query data is "*q=select \* from +endpoint\_252*". + +Table 44: Example response + ++-------------------------------------+ +| Response from Influx | ++=====================================+ +| { | +| | +| \"results\": \[ | +| | +| { | +| | +| \"statement\_id\": 0, | +| | +| \"series\": \[ | +| | +| { | +| | +| \"name\": \"endpoint\_252\", | +| | +| \"columns\": \[ | +| | +| \"time\", | +| | +| \"Message\_2\", | +| | +| \"Message\_4\", | +| | +| \"Message\_5\", | +| | +| \"Message\_50\_1\", | +| | +| \"Message\_50\_49\", | +| | +| \"Message\_51\_2\", | +| | +| \"Message\_51\_4\", | +| | +| \"Message\_51\_5\", | +| | +| \"Message\_51\_7\", | +| | +| \"Message\_7\", | +| | +| \"Message\_8\", | +| | +| \"Message\_9\", | +| | +| \"network\_id\", | +| | +| \"nodegroup\", | +| | +| \"nodeid\" | +| | +| \], | +| | +| \"values\": \[ | +| | +| \[ | +| | +| \"2018-11-28T16:48:41.301000003Z\", | +| | +| 112233, | +| | +| 1543423721301, | +| | +| 1543423721340, | +| | +| \"\[Message\_50\_1\_1=12499145, | +| | +| Message\_50\_1\_2=2399.0, | +| | +| Message\_50\_1\_3=-4.0, | +| | +| Message\_50\_1\_4=1, | +| | +| Message\_50\_1\_5=-23.0\]\", | +| | +| 123, | +| | +| 252, | +| | +| 255, | +| | +| 0, | +| | +| \"\", | +| | +| 123, | +| | +| 123, | +| | +| 39, | +| | +| \"112233\", | +| | +| \"0\", | +| | +| 123 | +| | +| \] | +| | +| \] | +| | +| } | +| | +| \] | +| | +| } | +| | +| \] | +| | +| } | ++-------------------------------------+ + +For example to decode column *Message\_2*, open main WNT Protocol +Buffers file *message.proto* and look for message called *Message*. This +message is used as base of all columns starting with *Message\_* and the +number after the underscore is the field number of the corresponding +message. In this case *Message\_2* can be decoded to *network\_id*. + +Table 45: Part of message.proto + ++-----------------------------------------+ +| message.proto | ++=========================================+ +| message Message { | +| | +| repeated uint32 id = 1 \[packed=true\]; | +| | +| optional uint32 network\_id = 2; | +| | +| optional string gateway\_id = 3; | +| | +| . | +| | +| . | +| | +| . | ++-----------------------------------------+ + +Decoding *Message\_51\_2* column name can be done the same way except +that the number 51 is sub-message *rx\_time* which is instance of +*RxData* message. Following the previous rules the *Message\_51\_2* can +be decoded to be source endpoint of a data message packet. + +Table 46: Part of message.proto + ++-----------------------------------------------------------+ +| message.proto | ++===========================================================+ +| message Message { | +| | +| . | +| | +| . | +| | +| . | +| | +| optional DiagnosticsData diagnostics = 50; | +| | +| optional RxData rx\_data = 51; | +| | +| optional AppConfigData app\_config = 52; | +| | +| . | +| | +| . | +| | +| . | +| | +| } | +| | +| message RxData { | +| | +| optional uint32 source\_endpoint = 2; | +| | +| optional uint32 destination\_endpoint = 4; | +| | +| optional uint32 qos = 5 \[default = 0\]; | +| | +| optional bytes payload = 7 \[(nanopb).max\_size = 1024\]; | +| | +| } | ++-----------------------------------------------------------+ + +Basic data flow and real time situation data +============================================ + +Basic data flow to get continuous data +-------------------------------------- + +- Generate e.g. UUID (version 4) which is used as *originator token* + for metadata changes. + +- Connect to authentication service and send [*login*](#login) + message. + + - Authentication service sends back *session id*. + + - Do not close the connection as the *session id* will become + invalid. + +- Query needed information from the metadata service and use the + *session id* for the authentication. + + - If you need this non-node metadata in your application, you need + to store the related information as the real time situation + connection message's *metadata\_update\_message* will only + contain the changed information. + +- Connect to the real time situation service and authenticate with the + *session id*. + + - Real time situation service starts to push the initial real time + data. + +- Close the authentication service connection. + + - Real time situation connection will still continue to work. + +- Read the data from the real time situation. + + - Get the initial node data + + - Sum up the node counts from the real time situation + services. + + - When the distinct received node count is the same as the + sum of the node counts, the initial real time situation + is received. + + - Get the changed node data + + - From now on the real time situation component will only send + changed information (aka delta) when compared to the + previous node data. + + - You need to keep the initial node state and then apply the + changed fields incrementally. + + - Messages will contain *network\_id* and *source\_address* + fields to distinguish between the nodes. + + - Any metadata change will be provided via the connection. + + - You can use the *originator\_token* to distinct the changes + made by you. + +- When you wish to stop receiving the real time data please close the + real time situation connection. + +If you wish to do metadata changes after authentication service +connection is closed, you need to connect and [*login*](#login) again to +the authentication service, and the service will provide a new *session +id*. + +Real time situation data +------------------------ + +Real time situation component uses Protocol Buffers messages to send the +data. All the incoming messages have a message called Message as a root +item (please see message.proto). + +Table 47: Important message fields + + Field name Description + ------------------------------ ------------------------------------------------------------------------------------- + network\_id Network id of the node which sent the message. + source\_address Node id of the node which sent the message. + gateway\_id Id of the gateway which routed the message. + tx\_time Time when the packet was generated by the node. + rx\_time Time when the packet was received by the gateway. + travel\_time\_ms How long it took for gateway to receive the packet (rx\_time -- tx\_time). + diagnostics \* Diagnostics data that the node has generated. Contains also the node role and mode. + rx\_data \* Data message information (end points, qos etc.). + app\_config \* Application configuration data and diagnostics interval (sent only by the sinks). + network\_channel Network channel (sent only by the sinks). + security\_enabled Are cipher and encryption keys set for the network (sent only by the sinks). + app\_config\_response \* Response for setting of the app config (sent only by the sinks). + gateway\_info \* Gateway information response data. + scratchpad\_status \* Scratchpad status response data. + online\_status \* Node online status determined by the backend. + node\_metadata \* Node metadata (location, name, description, positioning role etc.) + rtsituation\_metadata \* Information about real time situation manager (node count). + metadata\_update\_message \* Non-node related metadata update information. + +\*) Sub-message + +The backend processes all the incoming messages from the nodes every 30 +seconds as a batch processing, so the incoming message via the real time +situation connection can contain merged information from several +messages of a node. + +Coordinate conversions +====================== + +Introduction +------------ + +When a floor plan is added into WNT it is required to input the +latitude/longitude/altitude (WGS84) of four reference points (A, B, C, +D) and a scaling value. + +The reference points are used to determine the rotation and translation +of the floorplan to the corresponding position on the Earth. + +Scaling is used to determine the relation between floor plan image +pixels and the real world distance. + +Starting from WNT version 2.0 the floorplan information retrieved from +the WNT backend includes the rotation and translation information +required to make the conversion from/to WGS84 coordinate to/from pixels. + +The coordinate conversion assumes that the top-left floorplan image +corner has the coordinate (0,0) pixels. + +Given the floorplan information provided by the WNT API the following +matrices/vectors are used: + +- Rotation matrix (using *rotation\_matrix*): + +$$R = \begin{bmatrix} +m_{11} & m_{12} & m_{13} \\ +m_{21} & m_{22} & m_{23} \\ +m_{31} & m_{32} & m_{33} \\ +\end{bmatrix}$$ + +- Translation matrix (using *offset\_local\_to\_ecef* ): + +$$T_{r} = \begin{bmatrix} +x \\ +y \\ +z \\ +\end{bmatrix}$$ + +- Scaling: + +$$s = \ pixels\_ per\_ meter$$ + +WGS84 to pixels +--------------- + +To convert a WGS84 coordinate to pixels the following steps are +required: + +1. Convert the WGS84 coordinate to ECEF (see chapter 9.4 for the + conversion method) + +2. Given $E$ the ECEF coordinate vector compute the pixel coordinates + $P$ as: + +$$P = R \bullet \left( E - T_{r} \right) \bullet s$$ + +The matrix operations can be equivalently expressed as: + +$$p_{x} = (m_{11} \bullet dx + m_{12} \bullet dy\ + \ m_{13} \bullet dz) \bullet s$$ + +$$p_{y} = (m_{21} \bullet dx + m_{22} \bullet dy\ + \ m_{23} \bullet dz) \bullet s$$ + +where: + +$$\begin{bmatrix} +\text{dx} \\ +\text{dy} \\ +\text{dz} \\ +\end{bmatrix} = E - T_{r}$$ + +Pixels to WGS84 +--------------- + +To convert a pixel coordinate $(p_{x},p_{y})$ to WGS84 the following +steps are required: + +1. Compute the ECEF coordinate as: + +$$E = \frac{R^{'} \bullet P}{s} + T_{r}$$ + +where: + +$$P = \begin{bmatrix} +p_{x} \\ +p_{y} \\ +0 \\ +\end{bmatrix}$$ + +and $R^{'}$ denote the transpose matrix. + +2. Convert the ECEF coordinate to WGS84 as shown in chapter 9.5. + +WGS84 to ECEF conversion +------------------------ + +Given a WGS84 coordinate as: ϕ latitude in radians, λ longitude in +radians, $h$ altitude in meters the ECEF coordinate $E = \begin{bmatrix} +x \\ +y \\ +z \\ +\end{bmatrix}\ $in meters is computed as: + +$$x = (v + h) \bullet cos(\varphi) \bullet cos(\lambda)$$ + +$$y = (v + h) \bullet cos(\varphi) \bullet sin(\lambda)$$ + +$$z = (v \bullet (1 - e_{2}) + h) \bullet sin(\varphi)$$ + +where: + +$$v = \frac{a}{\sqrt{1 - e_{2} \bullet {sin(\varphi)}^{2}}}$$ + +$$a = 6378137.0$$ + +$$e_{2} = \ 0.00669437999014133$$ + +ECEF to WGS84 conversion +------------------------ + +The conversion from ECEF to WGS84 is an iterative process. + +Starting from an initial state computed as: + +$$p = \sqrt{x^{2} + y^{2}}$$ + +$$\varphi = atan2(z,\ p \bullet (1 - e_{2})$$ + +$$h = 0$$ + +$$\Delta h = 0$$ + +$$\Delta\varphi = 0$$ + +Iterate the following equations until $\Delta\varphi < 10^{- 12}\ $and +$\Delta h < \ 10^{- 5}$: + +$$\varphi_{0} = \varphi$$ + +$$h_{0} = h$$ + +$$v = \frac{a}{\sqrt{1 - e_{2} \bullet {sin(\varphi)}^{2}}}$$ + +$$h = \frac{p}{cos(\varphi)} - v$$ + +$$\varphi = atan2(z,\ p \bullet (1 - e_{2} \bullet \frac{v}{(v + h)})$$ + +$$\Delta\varphi = \ \left| \varphi - \varphi_{0} \right|$$ + +$$\Delta h = \ \left| h - h_{0} \right|$$ + +where $\left| \bullet \right|$ denotes the absolute value and +$e_{2}\ $is the same as in chapter 9.4. + +Finally compute longitude as: + +$$\lambda = atan2(y,\ x)$$ + +Note that the latitude and longitude values are in radians and the +altitude in meters. + +References +========== + +\[1\] WP-RM-100 - Wirepas Connectivity Dual-MCU API Reference Manual + +\[2\] WP-UG-421 - Wirepas Network Tool - Client User Guide + +\[3\] WP-RM-104 - Wirepas Mesh Diagnostics Reference Manual + +\[4\] https://github.com/wirepas/backend-client From d12ad7065feb7105174ff67b22d909c022af95bb Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 10 Oct 2019 15:44:34 +0300 Subject: [PATCH 2/3] remark pass --- wnt/wntclientapi.md | 3417 +++++++++++++++++++++---------------------- 1 file changed, 1690 insertions(+), 1727 deletions(-) diff --git a/wnt/wntclientapi.md b/wnt/wntclientapi.md index 35a6b1a..3294956 100644 --- a/wnt/wntclientapi.md +++ b/wnt/wntclientapi.md @@ -10,9 +10,6 @@ This document describes the Wirepas Network Tool backend API. > Public --> - - - -- [Introduction](#introduction) -- [Backend interface components](#backend-interface-components) - - [Authentication service](#authentication-service) - - [Metadata service](#metadata-service) - - [Real time situation service](#real-time-situation-service) - - [Time series service](#time-series-service) - - [Protocol version](#protocol-version) -- [Authentication service messages](#authentication-service-messages) - - [Login](#login) - - [Get users](#get-users) - - [Create user](#create-user) - - [Update user](#update-user) - - [Delete user](#delete-user) -- [Metadata service messages](#metadata-service-messages) - - [Get buildings](#get-buildings) - - [Create building](#create-building) - - [Update building](#update-building) - - [Delete building](#delete-building) - - [Get building's floor plans](#get-buildings-floor-plans) - - [Create floor plan](#create-floor-plan) - - [Update floor plan](#update-floor-plan) - - [Delete floor plan](#delete-floor-plan) - - [Get floor plan image data](#get-floor-plan-image-data) - - [Set floor plan image data](#set-floor-plan-image-data) - - [Get areas](#get-areas) - - [Create area](#create-area) - - [Update area](#update-area) - - [Delete area](#delete-area) - - [Get networks](#get-networks) - - [Create network](#create-network) - - [Update network](#update-network) - - [Delete network](#delete-network) - - [Add node to floor plan](#add-node-to-floor-plan) - - [Remove node from floor plan](#remove-node-from-floor-plan) - - [Set node metadata](#set-node-metadata) - - [Delete node](#delete-node) - - [Set network data](#set-network-data) - - [Send data message](#send-data-message) - - [Get scratchpad status](#get-scratchpad-status) - - [Get components information](#get-components-information) -- [Real time situation service authentication](#real-time-situation-service-authentication) -- [Time series service data](#time-series-service-data) - - [Example CURL command to query data](#example-curl-command-to-query-data) - - [Example column names decoding](#example-column-names-decoding) -- [Basic data flow and real time situation data](#basic-data-flow-and-real-time-situation-data) - - [Basic data flow to get continuous data](#basic-data-flow-to-get-continuous-data) - - [Real time situation data](#real-time-situation-data) -- [Coordinate conversions](#coordinate-conversions) - - [Introduction](#introduction-1) - - [WGS84 to pixels](#wgs84-to-pixels) - - [Pixels to WGS84](#pixels-to-wgs84) - - [WGS84 to ECEF conversion](#wgs84-to-ecef-conversion) - - [ECEF to WGS84 conversion](#ecef-to-wgs84-conversion) -- [References](#references) +- [Introduction](#introduction) +- [Backend interface components](#backend-interface-components) + - [Authentication service](#authentication-service) + - [Metadata service](#metadata-service) + - [Real time situation service](#real-time-situation-service) + - [Time series service](#time-series-service) + - [Protocol version](#protocol-version) +- [Authentication service messages](#authentication-service-messages) + - [Login](#login) + - [Get users](#get-users) + - [Create user](#create-user) + - [Update user](#update-user) + - [Delete user](#delete-user) +- [Metadata service messages](#metadata-service-messages) + - [Get buildings](#get-buildings) + - [Create building](#create-building) + - [Update building](#update-building) + - [Delete building](#delete-building) + - [Get building's floor plans](#get-buildings-floor-plans) + - [Create floor plan](#create-floor-plan) + - [Update floor plan](#update-floor-plan) + - [Delete floor plan](#delete-floor-plan) + - [Get floor plan image data](#get-floor-plan-image-data) + - [Set floor plan image data](#set-floor-plan-image-data) + - [Get areas](#get-areas) + - [Create area](#create-area) + - [Update area](#update-area) + - [Delete area](#delete-area) + - [Get networks](#get-networks) + - [Create network](#create-network) + - [Update network](#update-network) + - [Delete network](#delete-network) + - [Add node to floor plan](#add-node-to-floor-plan) + - [Remove node from floor plan](#remove-node-from-floor-plan) + - [Set node metadata](#set-node-metadata) + - [Delete node](#delete-node) + - [Set network data](#set-network-data) + - [Send data message](#send-data-message) + - [Get scratchpad status](#get-scratchpad-status) + - [Get components information](#get-components-information) +- [Real time situation service authentication](#real-time-situation-service-authentication) +- [Time series service data](#time-series-service-data) + - [Example CURL command to query data](#example-curl-command-to-query-data) + - [Example column names decoding](#example-column-names-decoding) +- [Basic data flow and real time situation data](#basic-data-flow-and-real-time-situation-data) + - [Basic data flow to get continuous data](#basic-data-flow-to-get-continuous-data) + - [Real time situation data](#real-time-situation-data) +- [Coordinate conversions](#coordinate-conversions) + - [Introduction](#introduction-1) + - [WGS84 to pixels](#wgs84-to-pixels) + - [Pixels to WGS84](#pixels-to-wgs84) + - [WGS84 to ECEF conversion](#wgs84-to-ecef-conversion) + - [ECEF to WGS84 conversion](#ecef-to-wgs84-conversion) +- [References](#references) - - -Introduction -============ +# Introduction This document describes the Wirepas Network Tool (WNT) server backend API and is intended for Wirepas licensee to implement own services on @@ -157,8 +151,7 @@ data encoding. This document is compliant with WNT backend version 2.0. -Backend interface components -============================ +# Backend interface components Backend client interface consists of four individual components which all use secure versions of the protocols (WSS, HTTPS). @@ -171,7 +164,9 @@ height="2.9400590551181103in"} Table 1: Components Component Protocol Port Data encoding - --------------------- ------------ ------ --------------------- + +* * * + Authentication Web socket 8813 JSON Metadata Web socket 8812 JSON Real time situation Web socket 8811 Protocol Buffers \* @@ -184,8 +179,7 @@ Table 1: Components The MQTT connection between the gateway and WNT backend is described in document: WP-RM-128 - API between a Gateway and Wirepas Backends. -Authentication service ----------------------- +## Authentication service The service handles user management and access to metadata and real time situation service. The time series service share the same credentials as @@ -195,8 +189,7 @@ service. Credentials can only be changed via authentication service. Other clients are notified about the users related changes (except password changes) via real time situation connection. -Metadata service ----------------- +## Metadata service Metadata service provides access to: @@ -215,8 +208,7 @@ Metadata service provides access to: The clients are notified about the metadata changes via real time situation connection. -Real time situation service ---------------------------- +## Real time situation service The real time information of all the nodes and changes to metadata are available from the real time situation service. After the connection is @@ -225,15 +217,13 @@ real time information via the connection. When the service receives new information from the nodes it forwards only the data that has changed to the client connections. -Time series service -------------------- +## Time series service Time series service contains diagnostics - and auxiliary data. It is implemented as direct access to the Influx database version 1.5. For more information please see chapter 7. -Protocol version ----------------- +## Protocol version Authentication, metadata and real time situation (authentication) messages contains protocol version field. This field needs to match the @@ -243,15 +233,16 @@ backend cannot handle messages of older protocol version. Table 2: Protocol versions Protocol version Backend version - ------------------ ----------------- + +* * * + 2 1.6, 1.7 3 2.0 -**\ +**\\ ** -Authentication service messages -=============================== +# Authentication service messages Authentication service works in request / response principle. User is automatically logged out when the connection is closed, and session id @@ -262,7 +253,9 @@ connection is closed. Access to methods are depending on user's role. Table 3: Roles Role Number - --------------- -------- + +* * * + Administrator 1 Operator 2 @@ -275,7 +268,9 @@ version and distinct type field per message type. Table 4: Message types Message Type Role - ------------- ------ --------------- + +* * * + Login 1 All Get users 11 Administrator Create user 12 Administrator @@ -284,7 +279,7 @@ Table 4: Message types Due to possibility that the information about the change comes earlier from the real time situation connection than the response from the -authentication service, some methods contain an *originator\_token* +authentication service, some methods contain an *originator_token* field which can be used to check if the change was originated from the current client. The token can be e.g. UUID (version 1 / 4) as string. @@ -294,7 +289,9 @@ error occurred. Table 5: Result codes Message Code - ------------------------------------------------- ------ + +* * * + Ok 1 Generic error 2 Invalid credentials while logging in 3 @@ -310,13 +307,14 @@ User information fields have minimum and maximum lengths in characters. Table 6: Minimum and maximum lengths Field Minimum Maximum - ------------ --------- --------- + +* * * + username 1 63 password 6 255 - full\_name 1 255 + full_name 1 255 -Login ------ +## Login *Login* message is used to login to the services and it returns a session id that is used to authenticate to the metadata and real time @@ -324,215 +322,210 @@ situation services. Table 7: Login message -+----------------------------------+-------------------------------------+ +\+----------------------------------+-------------------------------------+ | Request | Response | -+==================================+=====================================+ +\+==================================+=====================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"username\": \"\\", | \"role\": 1, | -| | | -| \"password\": \"\\" | \"session\_id\": \"\\" | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"username\\": \\"\\<user name>\\", | \\"role\\": 1, | +\| \| \| +| \\"password\\": \\"\\<password>\\" | \\"session_id\\": \\"\\<session id>\\" | +\| \| \| | }, | }, | -| | | -| \"type\": 1, | \"result\": 1, | -| | | -| \"version\": 3 | \"type\": 1, | -| | | -| } | \"version\": 3 | -| | | +\| \| \| +| \\"type\\": 1, | \\"result\\": 1, | +\| \| \| +| \\"version\\": 3 | \\"type\\": 1, | +\| \| \| +| } | \\"version\\": 3 | +\| \| \| | | } | -+----------------------------------+-------------------------------------+ +\+----------------------------------+-------------------------------------+ -Get users ---------- +## Get users Message returns list of users and users' information. Table 8:Get users message -+--------------------------------------+-------------------------------+ +\+--------------------------------------+-------------------------------+ | Request | Example response | -+======================================+===============================+ +\+======================================+===============================+ | { | { | -| | | -| \"data\": {}, | \"data\": { | -| | | -| \"session\_id\": \"\\", | \"users\": \[ | -| | | -| \"type\": 11, | { | -| | | -| \"version\": 3 | \"full\_name\": \"John Doe\", | -| | | -| } | \"role\": 2, | -| | | -| | \"username\": \"johndoe\" | -| | | +\| \| \| +| \\"data\\": {}, | \\"data\\": { | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | \\"users\\": \[ \| +\| \| \| +| \\"type\\": 11, | { | +\| \| \| +| \\"version\\": 3 | \\"full_name\\": \\"John Doe\\", | +\| \| \| +| } | \\"role\\": 2, | +\| \| \| +| | \\"username\\": \\"johndoe\\" | +\| \| \| | | }, | -| | | +\| \| \| | | { | -| | | -| | \"full\_name\": \"Jane Doe\", | -| | | -| | \"role\": 1, | -| | | -| | \"username\": \"janedoe\" | -| | | +\| \| \| +| | \\"full_name\\": \\"Jane Doe\\", | +\| \| \| +| | \\"role\\": 1, | +\| \| \| +| | \\"username\\": \\"janedoe\\" | +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | }, | -| | | -| | \"result\": 1, | -| | | -| | \"type\": 11, | -| | | -| | \"version\": 3 | -| | | +\| \| \| +| | \\"result\\": 1, | +\| \| \| +| | \\"type\\": 11, | +\| \| \| +| | \\"version\\": 3 | +\| \| \| | | } | -+--------------------------------------+-------------------------------+ +\+--------------------------------------+-------------------------------+ -Create user ------------ +## Create user New user can be created with *create user* message. Only a single user can be created with the message although *users* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_users* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_users* message. Table 9: Create user message -+---------------------------------------+----------------+ +\+---------------------------------------+----------------+ | Request | Response | -+=======================================+================+ +\+=======================================+================+ | { | { | -| | | -| \"data\": { | \"data\": {}, | -| | | -| \"originator\_token\": \"\\", | \"result\": 1, | -| | | -| \"users\": \[ | \"type\": 12, | -| | | -| { | \"version\": 3 | -| | | -| \"full\_name\": \"\\", | } | -| | | -| \"password\": \"\\", | | -| | | -| \"role\": \, | | -| | | -| \"username\": \"\\" | | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": {}, | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\", | \\"result\\": 1, | +\| \| \| +| \\"users\\": \[ | \\"type\\": 12, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"full_name\\": \\"\\<first last>\\", | } | +\| \| \| +| \\"password\\": \\"\\<password>\\", | | +\| \| \| +| \\"role\\": \\<role>, | | +\| \| \| +| \\"username\\": \\"\\<user name>\\" | | +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 12, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 12, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+---------------------------------------+----------------+ +\+---------------------------------------+----------------+ -Update user ------------ +## Update user User can be updated with *update user* message. Only a single user can be updated with the message although *users* field is an array. In user data only *username* field is required. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_users* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_users* message. Table 10: Update user message -+-----------------------------------------+----------------+ +\+-----------------------------------------+----------------+ | Request | Response | -+=========================================+================+ +\+=========================================+================+ | { | { | -| | | -| \"data\": { | \"data\": {}, | -| | | -| \"originator\_token\": \"\\", | \"result\": 1, | -| | | -| \"users\": \[ | \"type\": 13, | -| | | -| { | \"version\": 3 | -| | | -| \"full\_name\": \"\\", | } | -| | | -| \"password\": \"\\", | | -| | | -| \"role\": \, | | -| | | -| \"username\": \"\\" | | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": {}, | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\", | \\"result\\": 1, | +\| \| \| +| \\"users\\": \[ | \\"type\\": 13, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"full_name\\": \\"\\<new first last>\\", | } | +\| \| \| +| \\"password\\": \\"\\<new password>\\", | | +\| \| \| +| \\"role\\": \\<new role>, | | +\| \| \| +| \\"username\\": \\"\\<new user name>\\" | | +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 13, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 13, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+-----------------------------------------+----------------+ +\+-----------------------------------------+----------------+ -Delete user ------------ +## Delete user User can be deleted with *delete user* message. Only a single user can be deleted with the message although *users* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> deleted\_users* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> deleted_users* message. Table 11: Delete user message -+---------------------------------------+----------------+ +\+---------------------------------------+----------------+ | Request | Response | -+=======================================+================+ +\+=======================================+================+ | { | { | -| | | -| \"data\": { | \"data\": {}, | -| | | -| \"originator\_token\": \"\\", | \"result\": 1, | -| | | -| \"users\": \[ | \"type\": 14, | -| | | -| { | \"version\": 3 | -| | | -| \"username\": \"\\" | } | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": {}, | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\", | \\"result\\": 1, | +\| \| \| +| \\"users\\": \[ | \\"type\\": 14, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"username\\": \\"\\<user name>\\" | } | +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 14, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 14, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+---------------------------------------+----------------+ +\+---------------------------------------+----------------+ -Metadata service messages -========================= +# Metadata service messages Metadata service works in request / response principle. All the messages require *session id*, which can be get from authentication service. @@ -543,7 +536,9 @@ version and distinct *type* field per message type. Table 12: Message types Message Type Role - --------------------------------------- ------ --------------- + +* * * + Get buildings 1001 All Create building 1002 Administrator Update building 1003 Administrator @@ -578,7 +573,7 @@ Table 12: Message types Due to possibility that the information about the change comes earlier from the real time situation connection than the response from the -metadata service, some methods contain an *originator\_token* field +metadata service, some methods contain an *originator_token* field which can be used to check if the change was originated from the current client. The token can be e.g. UUID (version 1 / 4) as string. @@ -588,7 +583,9 @@ error occurred. Table 13: Result codes Message Code - ------------------------------------------------- ------ + +* * * + Ok 1 Generic error 2 Wrong protocol version 4 @@ -597,349 +594,343 @@ Table 13: Result codes Received message was invalid 8 Invalid session id 9 -Get buildings -------------- +## Get buildings The message returns name and id of all the buildings. Table 14: Get buildings message -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ | Request | Example response | -+===================================+===================================+ +\+===================================+===================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"originator\_token\": | \"buildings\": \[ | -| \"\\" | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"originator_token\\": | \\"buildings\\": \[ \| +| \\"\\<token>\\" | | | | { | | }, | | -| | \"id\": | -| \"session\_id\": \"\\", | 47812\", | -| | | -| \"type\": 1001, | \"name\": \"Main building\" | -| | | -| \"version\": 3 | }, | -| | | +| | \\"id\\": | +| \\"session_id\\": \\"\\<session | \\"c6ddb790-24e4-6449-075a-a6638f1 | +| id>\\", | 47812\\", | +\| \| \| +| \\"type\\": 1001, | \\"name\\": \\"Main building\\" | +\| \| \| +| \\"version\\": 3 | }, | +\| \| \| | } | { | -| | | -| | \"id\": | -| | \"e936d185-42db-ff18-57b5-4deb02d | -| | 05c58\", | -| | | -| | \"name\": \"Other building\" | -| | | +\| \| \| +| | \\"id\\": | +| | \\"e936d185-42db-ff18-57b5-4deb02d | +| | 05c58\\", | +\| \| \| +| | \\"name\\": \\"Other building\\" | +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | }, | -| | | -| | \"result\": 1, | -| | | -| | \"type\": 1001, | -| | | -| | \"version\": 3 | -| | | +\| \| \| +| | \\"result\\": 1, | +\| \| \| +| | \\"type\\": 1001, | +\| \| \| +| | \\"version\\": 3 | +\| \| \| | | } | -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ -Create building ---------------- +## Create building New building can be created with *create building* message which returns building id that can be used later to reference the building. Only a single building can be created with the message although *buildings* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_buildings* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_buildings* message. Table 15: Create building message -+--------------------------------------+-----------------------------+ +\+--------------------------------------+-----------------------------+ | Request | Response | -+======================================+=============================+ +\+======================================+=============================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"buildings\": \[ | \"buildings\": \[ | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"buildings\\": \[ | \\"buildings\\": \[ \| +\| \| \| | { | { | -| | | -| \"name\": \"\\" | \"id\": \"\\" | -| | | +\| \| \| +| \\"name\\": \\"\\<building name>\\" | \\"id\\": \\"\\<building id>\\" | +\| \| \| | } | } | -| | | -| \], | \] | -| | | -| \"originator\_token\": \"\\" | }, | -| | | -| }, | \"result\": 1, | -| | | -| \"session\_id\": \"\\", | \"type\": 1002, | -| | | -| \"type\": 1002, | \"version\": 3 | -| | | -| \"version\": 3 | } | -| | | +\| \| \| +\| ], | ] \| +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | }, | +\| \| \| +| }, | \\"result\\": 1, | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | \\"type\\": 1002, | +\| \| \| +| \\"type\\": 1002, | \\"version\\": 3 | +\| \| \| +| \\"version\\": 3 | } | +\| \| \| | } | | -+--------------------------------------+-----------------------------+ +\+--------------------------------------+-----------------------------+ -Update building ---------------- +## Update building Building name can be updated with *update building* message. Only a single building can be updated with the message although *buildings* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_buildings* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_buildings* message. Table 16: Update building message -+-----------------------------------------+-----------------+ +\+-----------------------------------------+-----------------+ | Request | Response | -+=========================================+=================+ +\+=========================================+=================+ | { | { | -| | | -| \"data\": { | \"data\": {}, | -| | | -| \"buildings\": \[ | \"result\": 1, | -| | | -| { | \"type\": 1003, | -| | | -| \"id\": \"\\", | \"version\": 3 | -| | | -| \"name\": \"\\" | } | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": {}, | +\| \| \| +| \\"buildings\\": \[ | \\"result\\": 1, | +\| \| \| +| { | \\"type\\": 1003, | +\| \| \| +| \\"id\\": \\"\\<building id>\\", | \\"version\\": 3 | +\| \| \| +| \\"name\\": \\"\\<updated building name>\\" | } | +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1003, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1003, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+-----------------------------------------+-----------------+ +\+-----------------------------------------+-----------------+ -Delete building ---------------- +## Delete building Building can be deleted with *delete building* message. Only a single building can be deleted with the message although *buildings* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> deleted\_buildings* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> deleted_buildings* message. Table 17: Delete building message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"buildings\": \[ | \"type\": 1004, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": \"\\" | } | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"buildings\\": \[ | \\"type\\": 1004, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": \\"\\<building id>\\" | } | +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1004, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1004, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Get building's floor plans --------------------------- +## Get building's floor plans The message returns information about the floor plans in a building. Only a single building's floor plans can be fetched with the message although *buildings* field is an array. -The *rotation\_matrix*, *offset\_ecef\_to\_local, -offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for +The *rotation_matrix*, *offset_ecef_to_local, +offset_local_to_ecef* and *pixels_per_meter* fields are used for mapping between WGS84 and pixel coordinates. For more information please see chapter 9. Table 18: Get building's floor plans message -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ | Request | Example response (only one floor | | | plan) | -+===================================+===================================+ +\+===================================+===================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"buildings\": \[ | \"buildings\": \[ | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"buildings\\": \[ | \\"buildings\\": \[ \| +\| \| \| | { | { | -| | | -| \"id\": \"\\" | \"id\": | -| | \"3b326217-676d-f547-019b-6d8e0e1 | -| } | fc5dc\", | -| | | -| \], | \"floor\_plans\": \[ | -| | | -| \"originator\_token\": | { | -| \"\\" | | -| | \"id\": | -| }, | \"1e19239c-bcd2-829a-44a1-900e083 | -| | f0bfe\", | -| \"session\_id\": \"\\", | \"name\": \"New floor plan\", | -| | | -| \"type\": 1011, | \"level\": 0, | -| | | -| \"version\": 3 | "image\_width": null, | -| | | -| } | "image\_height": null, | -| | | -| | \"image\_id\": null, | -| | | -| | \"image\_thumbnail\_id\": null, | -| | | -| | \"altitude\_leftbottom\": null, | -| | | -| | \"altitude\_lefttop\": null, | -| | | -| | \"altitude\_rightbottom\": null, | -| | | -| | \"altitude\_righttop\": null, | -| | | -| | \"distance\_in\_m\": 1, | -| | | -| | \"latitude\_leftbottom\": null, | -| | | -| | \"latitude\_lefttop\": null, | -| | | -| | \"latitude\_rightbottom\": null, | -| | | -| | \"latitude\_righttop\": null, | -| | | -| | \"longitude\_leftbottom\": null, | -| | | -| | \"longitude\_lefttop\": null, | -| | | -| | \"longitude\_rightbottom\": null, | -| | | -| | \"longitude\_righttop\": null, | -| | | -| | \"x\_distance\_point1\": 0.3, | -| | | -| | \"x\_distance\_point2\": 0.7, | -| | | -| | \"x\_normcoord\_leftbottom\": 0, | -| | | -| | \"x\_normcoord\_lefttop\": 0, | -| | | -| | \"x\_normcoord\_rightbottom\": 1, | -| | | -| | \"x\_normcoord\_righttop\": 1, | -| | | -| | \"y\_distance\_point1\": 0.5, | -| | | -| | \"y\_distance\_point2\": 0.5, | -| | | -| | \"y\_normcoord\_leftbottom\": 1, | -| | | -| | \"y\_normcoord\_lefttop\": 0, | -| | | -| | \"y\_normcoord\_rightbottom\": 1, | -| | | -| | \"y\_normcoord\_righttop\": 0, | -| | | -| | \"rotation\_matrix\": { | -| | | -| | \"m11\": null, | -| | | -| | \"m12\": null, | -| | | -| | \"m13\": null, | -| | | -| | \"m21\": null, | -| | | -| | \"m22\": null, | -| | | -| | \"m23\": null, | -| | | -| | \"m31\": null, | -| | | -| | \"m32\": null, | -| | | -| | \"m33\": null | -| | | +\| \| \| +| \\"id\\": \\"\\<building id>\\" | \\"id\\": | +| | \\"3b326217-676d-f547-019b-6d8e0e1 | +| } | fc5dc\\", | +\| \| \| +\| ], | \\"floor_plans\\": \[ \| +\| \| \| +| \\"originator_token\\": | { | +| \\"\\<token>\\" | | +| | \\"id\\": | +| }, | \\"1e19239c-bcd2-829a-44a1-900e083 | +| | f0bfe\\", | +| \\"session_id\\": \\"\\<session | | +| id>\\", | \\"name\\": \\"New floor plan\\", | +\| \| \| +| \\"type\\": 1011, | \\"level\\": 0, | +\| \| \| +| \\"version\\": 3 | "image_width": null, | +\| \| \| +| } | "image_height": null, | +\| \| \| +| | \\"image_id\\": null, | +\| \| \| +| | \\"image_thumbnail_id\\": null, | +\| \| \| +| | \\"altitude_leftbottom\\": null, | +\| \| \| +| | \\"altitude_lefttop\\": null, | +\| \| \| +| | \\"altitude_rightbottom\\": null, | +\| \| \| +| | \\"altitude_righttop\\": null, | +\| \| \| +| | \\"distance_in_m\\": 1, | +\| \| \| +| | \\"latitude_leftbottom\\": null, | +\| \| \| +| | \\"latitude_lefttop\\": null, | +\| \| \| +| | \\"latitude_rightbottom\\": null, | +\| \| \| +| | \\"latitude_righttop\\": null, | +\| \| \| +| | \\"longitude_leftbottom\\": null, | +\| \| \| +| | \\"longitude_lefttop\\": null, | +\| \| \| +| | \\"longitude_rightbottom\\": null, | +\| \| \| +| | \\"longitude_righttop\\": null, | +\| \| \| +| | \\"x_distance_point1\\": 0.3, | +\| \| \| +| | \\"x_distance_point2\\": 0.7, | +\| \| \| +| | \\"x_normcoord_leftbottom\\": 0, | +\| \| \| +| | \\"x_normcoord_lefttop\\": 0, | +\| \| \| +| | \\"x_normcoord_rightbottom\\": 1, | +\| \| \| +| | \\"x_normcoord_righttop\\": 1, | +\| \| \| +| | \\"y_distance_point1\\": 0.5, | +\| \| \| +| | \\"y_distance_point2\\": 0.5, | +\| \| \| +| | \\"y_normcoord_leftbottom\\": 1, | +\| \| \| +| | \\"y_normcoord_lefttop\\": 0, | +\| \| \| +| | \\"y_normcoord_rightbottom\\": 1, | +\| \| \| +| | \\"y_normcoord_righttop\\": 0, | +\| \| \| +| | \\"rotation_matrix\\": { | +\| \| \| +| | \\"m11\\": null, | +\| \| \| +| | \\"m12\\": null, | +\| \| \| +| | \\"m13\\": null, | +\| \| \| +| | \\"m21\\": null, | +\| \| \| +| | \\"m22\\": null, | +\| \| \| +| | \\"m23\\": null, | +\| \| \| +| | \\"m31\\": null, | +\| \| \| +| | \\"m32\\": null, | +\| \| \| +| | \\"m33\\": null | +\| \| \| | | }, | -| | | -| | \"offset\_ecef\_to\_local\": { | -| | | -| | \"x\": null, | -| | | -| | \"y\": null, | -| | | -| | \"z\": null | -| | | +\| \| \| +| | \\"offset_ecef_to_local\\": { | +\| \| \| +| | \\"x\\": null, | +\| \| \| +| | \\"y\\": null, | +\| \| \| +| | \\"z\\": null | +\| \| \| | | }, | -| | | -| | \"offset\_local\_to\_ecef\": { | -| | | -| | \"x\": null, | -| | | -| | \"y\": null, | -| | | -| | \"z\": null | -| | | +\| \| \| +| | \\"offset_local_to_ecef\\": { | +\| \| \| +| | \\"x\\": null, | +\| \| \| +| | \\"y\\": null, | +\| \| \| +| | \\"z\\": null | +\| \| \| | | }, | -| | | -| | \"pixels\_per\_meter\": null | -| | | +\| \| \| +| | \\"pixels_per_meter\\": null | +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | }, | -| | | -| | \"result\": 1, | -| | | -| | \"type\": 1011, | -| | | -| | \"version\": 3 | -| | | +\| \| \| +| | \\"result\\": 1, | +\| \| \| +| | \\"type\\": 1011, | +\| \| \| +| | \\"version\\": 3 | +\| \| \| | | } | -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ -Create floor plan ------------------ +## Create floor plan New floor plan can be created with *create floor plan* message which returns floor plan id that can be used later to reference the floor @@ -948,417 +939,413 @@ new floor plan. Only a single floor plan can be created to a single building with the message although *buildings* and *floor­\_plans* fields are arrays. -The *rotation\_matrix*, *offset\_ecef\_to\_local, -offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for +The *rotation_matrix*, *offset_ecef_to_local, +offset_local_to_ecef* and *pixels_per_meter* fields are used for mapping between WGS84 and pixel coordinates. For more information please see chapter 9. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_floor\_plans* +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_floor_plans* message. Table 19: Create floor plan message -+--------------------------------------+-----------------------------------+ +\+--------------------------------------+-----------------------------------+ | Request | Response | -+======================================+===================================+ +\+======================================+===================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"buildings\": \[ | \"buildings\": \[ | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"buildings\\": \[ | \\"buildings\\": \[ \| +\| \| \| | { | { | -| | | -| \"id\": \"\\", | \"floor\_plans\": \[ | -| | | -| \"floor\_plans\": \[ | { | -| | | -| { | \"id\": \"\\", | -| | | -| \"name\": \"\\", | \"name\": "\\", | -| | | -| \"level\": \, | \"level\": \, | -| | | -| "image\_width": null, | "image\_width": null, | -| | | -| "image\_height": null, | "image\_height": null, | -| | | -| \"altitude\_leftbottom\": null, | \"image\_id\": null, | -| | | -| \"altitude\_lefttop\": null, | \"image\_thumbnail\_id\": null, | -| | | -| \"altitude\_rightbottom\": null, | \"altitude\_leftbottom\": null, | -| | | -| \"altitude\_righttop\": null, | \"altitude\_lefttop\": null, | -| | | -| \"distance\_in\_m\": 1, | \"altitude\_rightbottom\": null, | -| | | -| \"latitude\_leftbottom\": null, | \"altitude\_righttop\": null, | -| | | -| \"latitude\_lefttop\": null, | \"distance\_in\_m\": 1, | -| | | -| \"latitude\_rightbottom\": null, | \"latitude\_leftbottom\": null, | -| | | -| \"latitude\_righttop\": null, | \"latitude\_lefttop\": null, | -| | | -| \"longitude\_leftbottom\": null, | \"latitude\_rightbottom\": null, | -| | | -| \"longitude\_lefttop\": null, | \"latitude\_righttop\": null, | -| | | -| \"longitude\_rightbottom\": null, | \"longitude\_leftbottom\": null, | -| | | -| \"longitude\_righttop\": null, | \"longitude\_lefttop\": null, | -| | | -| \"x\_distance\_point1\": 0.3, | \"longitude\_rightbottom\": null, | -| | | -| \"x\_distance\_point2\": 0.7, | \"longitude\_righttop\": null, | -| | | -| \"x\_normcoord\_leftbottom\": 0, | \"x\_distance\_point1\": 0.3, | -| | | -| \"x\_normcoord\_lefttop\": 0, | \"x\_distance\_point2\": 0.7, | -| | | -| \"x\_normcoord\_rightbottom\": 1, | \"x\_normcoord\_leftbottom\": 0, | -| | | -| \"x\_normcoord\_righttop\": 1, | \"x\_normcoord\_lefttop\": 0, | -| | | -| \"y\_distance\_point1\": 0.5, | \"x\_normcoord\_rightbottom\": 1, | -| | | -| \"y\_distance\_point2\": 0.5, | \"x\_normcoord\_righttop\": 1, | -| | | -| \"y\_normcoord\_leftbottom\": 1, | \"y\_distance\_point1\": 0.5, | -| | | -| \"y\_normcoord\_lefttop\": 0, | \"y\_distance\_point2\": 0.5, | -| | | -| \"y\_normcoord\_rightbottom\": 1, | \"y\_normcoord\_leftbottom\": 1, | -| | | -| \"y\_normcoord\_righttop\": 0 | \"y\_normcoord\_lefttop\": 0, | -| | | -| } | \"y\_normcoord\_rightbottom\": 1, | -| | | -| \] | \"y\_normcoord\_righttop\": 0, | -| | | -| } | \"rotation\_matrix\": { | -| | | -| \], | \"m11\": null, | -| | | -| \"originator\_token\": \"\\" | \"m12\": null, | -| | | -| }, | \"m13\": null, | -| | | -| \"session\_id\": \"\\", | \"m21\": null, | -| | | -| \"type\": 1012, | \"m22\": null, | -| | | -| \"version\": 3 | \"m23\": null, | -| | | -| } | \"m31\": null, | -| | | -| | \"m32\": null, | -| | | -| | \"m33\": null | -| | | +\| \| \| +| \\"id\\": \\"\\<building id>\\", | \\"floor_plans\\": \[ \| +\| \| \| +| \\"floor_plans\\": \[ | { | +\| \| \| +| { | \\"id\\": \\"\\<floor plan id>\\", | +\| \| \| +| \\"name\\": \\"\\<floor plan name>\\", | \\"name\\": "\\<floor plan name>\\", | +\| \| \| +| \\"level\\": \\<level>, | \\"level\\": \\<level>, | +\| \| \| +| "image_width": null, | "image_width": null, | +\| \| \| +| "image_height": null, | "image_height": null, | +\| \| \| +| \\"altitude_leftbottom\\": null, | \\"image_id\\": null, | +\| \| \| +| \\"altitude_lefttop\\": null, | \\"image_thumbnail_id\\": null, | +\| \| \| +| \\"altitude_rightbottom\\": null, | \\"altitude_leftbottom\\": null, | +\| \| \| +| \\"altitude_righttop\\": null, | \\"altitude_lefttop\\": null, | +\| \| \| +| \\"distance_in_m\\": 1, | \\"altitude_rightbottom\\": null, | +\| \| \| +| \\"latitude_leftbottom\\": null, | \\"altitude_righttop\\": null, | +\| \| \| +| \\"latitude_lefttop\\": null, | \\"distance_in_m\\": 1, | +\| \| \| +| \\"latitude_rightbottom\\": null, | \\"latitude_leftbottom\\": null, | +\| \| \| +| \\"latitude_righttop\\": null, | \\"latitude_lefttop\\": null, | +\| \| \| +| \\"longitude_leftbottom\\": null, | \\"latitude_rightbottom\\": null, | +\| \| \| +| \\"longitude_lefttop\\": null, | \\"latitude_righttop\\": null, | +\| \| \| +| \\"longitude_rightbottom\\": null, | \\"longitude_leftbottom\\": null, | +\| \| \| +| \\"longitude_righttop\\": null, | \\"longitude_lefttop\\": null, | +\| \| \| +| \\"x_distance_point1\\": 0.3, | \\"longitude_rightbottom\\": null, | +\| \| \| +| \\"x_distance_point2\\": 0.7, | \\"longitude_righttop\\": null, | +\| \| \| +| \\"x_normcoord_leftbottom\\": 0, | \\"x_distance_point1\\": 0.3, | +\| \| \| +| \\"x_normcoord_lefttop\\": 0, | \\"x_distance_point2\\": 0.7, | +\| \| \| +| \\"x_normcoord_rightbottom\\": 1, | \\"x_normcoord_leftbottom\\": 0, | +\| \| \| +| \\"x_normcoord_righttop\\": 1, | \\"x_normcoord_lefttop\\": 0, | +\| \| \| +| \\"y_distance_point1\\": 0.5, | \\"x_normcoord_rightbottom\\": 1, | +\| \| \| +| \\"y_distance_point2\\": 0.5, | \\"x_normcoord_righttop\\": 1, | +\| \| \| +| \\"y_normcoord_leftbottom\\": 1, | \\"y_distance_point1\\": 0.5, | +\| \| \| +| \\"y_normcoord_lefttop\\": 0, | \\"y_distance_point2\\": 0.5, | +\| \| \| +| \\"y_normcoord_rightbottom\\": 1, | \\"y_normcoord_leftbottom\\": 1, | +\| \| \| +| \\"y_normcoord_righttop\\": 0 | \\"y_normcoord_lefttop\\": 0, | +\| \| \| +| } | \\"y_normcoord_rightbottom\\": 1, | +\| \| \| +\| ] | \\"y_normcoord_righttop\\": 0, | +\| \| \| +| } | \\"rotation_matrix\\": { | +\| \| \| +\| ], | \\"m11\\": null, | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | \\"m12\\": null, | +\| \| \| +| }, | \\"m13\\": null, | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | \\"m21\\": null, | +\| \| \| +| \\"type\\": 1012, | \\"m22\\": null, | +\| \| \| +| \\"version\\": 3 | \\"m23\\": null, | +\| \| \| +| } | \\"m31\\": null, | +\| \| \| +| | \\"m32\\": null, | +\| \| \| +| | \\"m33\\": null | +\| \| \| | | }, | -| | | -| | \"offset\_ecef\_to\_local\": { | -| | | -| | \"x\": null, | -| | | -| | \"y\": null, | -| | | -| | \"z\": null | -| | | +\| \| \| +| | \\"offset_ecef_to_local\\": { | +\| \| \| +| | \\"x\\": null, | +\| \| \| +| | \\"y\\": null, | +\| \| \| +| | \\"z\\": null | +\| \| \| | | }, | -| | | -| | \"offset\_local\_to\_ecef\": { | -| | | -| | \"x\": null, | -| | | -| | \"y\": null, | -| | | -| | \"z\": null | -| | | +\| \| \| +| | \\"offset_local_to_ecef\\": { | +\| \| \| +| | \\"x\\": null, | +\| \| \| +| | \\"y\\": null, | +\| \| \| +| | \\"z\\": null | +\| \| \| | | }, | -| | | -| | \"pixels\_per\_meter\": null | -| | | +\| \| \| +| | \\"pixels_per_meter\\": null | +\| \| \| | | } | -| | | -| | \], | -| | | -| | \"id\": \"\\" | -| | | +\| \| \| +\| \| ], | +\| \| \| +| | \\"id\\": \\"\\<building id>\\" | +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | }, | -| | | -| | \"result\": 1, | -| | | -| | \"type\": 1012, | -| | | -| | \"version\": 3 | -| | | +\| \| \| +| | \\"result\\": 1, | +\| \| \| +| | \\"type\\": 1012, | +\| \| \| +| | \\"version\\": 3 | +\| \| \| | | } | -+--------------------------------------+-----------------------------------+ +\+--------------------------------------+-----------------------------------+ -Update floor plan ------------------ +## Update floor plan Floor plan information can be updated with *update floor plan* message. Only a single floor plan in single building can be updated with the -message although *buildings* and *floor\_plans* fields are arrays. +message although *buildings* and *floor_plans* fields are arrays. Request below shows how a floor plan image and thumbnail are bound to the floor plan. -The *rotation\_matrix*, *offset\_ecef\_to\_local, -offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for +The *rotation_matrix*, *offset_ecef_to_local, +offset_local_to_ecef* and *pixels_per_meter* fields are used for mapping between WGS84 and pixel coordinates. For more information please see chapter 9. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_floor\_plans* +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_floor_plans* message. Table 20: Update floor plan message -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ | > Example request | > Response | -+===================================+===================================+ +\+===================================+===================================+ | > { | > { | | > | > | -| > \"data\": { | > \"data\": { | +| > \\"data\\": { | > \\"data\\": { | | > | > | -| > \"buildings\": \[ | > \"buildings\": \[ | +| > \\"buildings\\": \[ | > \\"buildings\\": \[ \| | > | > | | > { | > { | | > | > | -| > \"floor\_plans\": \[ | > \"floor\_plans\": \[ | +| > \\"floor_plans\\": \[ | > \\"floor_plans\\": \[ \| | > | > | | > { | > { | | > | > | -| > \"id\": \"\\", | > \"id\": \"\\", | +| > \\"id\\": \\"\\<floor plan id>\\", | > \\"id\\": \\"\\<floor plan id>\\", | | > | > | -| > \"image\_id\": \"\ \"name\": "\ id\>\", | > name\>\", | +| > \\"image_id\\": \\"\\<image | > \\"name\\": "\\<floor plan | +| > id>\\", | > name>\\", | | > | > | -| > \"image\_thumbnail\_id\": | > \"level\": \, | -| > \"\\", | > | -| > | > "image\_width": null, | -| > "image\_width": 640, | > | -| > | > "image\_height": null, | -| > "image\_height": 480 | > | -| > | > \"image\_id\": null, | +| > \\"image_thumbnail_id\\": | > \\"level\\": \\<level>, | +| > \\"\\<thumbnail id>\\", | > | +| > | > "image_width": null, | +| > "image_width": 640, | > | +| > | > "image_height": null, | +| > "image_height": 480 | > | +| > | > \\"image_id\\": null, | | > } | > | -| > | > \"image\_thumbnail\_id\": null, | -| > \] | > | -| > | > \"altitude\_leftbottom\": null, | +| > | > \\"image_thumbnail_id\\": null, | +| > ] | > | +| > | > \\"altitude_leftbottom\\": null, | | > } | > | -| > | > \"altitude\_lefttop\": null, | -| > \], | > | -| > | > \"altitude\_rightbottom\": | -| > \"originator\_token\": | > null, | -| > \"\\" | > | -| > | > \"altitude\_righttop\": null, | +| > | > \\"altitude_lefttop\\": null, | +| > ], | > | +| > | > \\"altitude_rightbottom\\": | +| > \\"originator_token\\": | > null, | +| > \\"\\<token>\\" | > | +| > | > \\"altitude_righttop\\": null, | | > }, | > | -| > | > \"distance\_in\_m\": 1, | -| > \"session\_id\": \"\ | -| > id\>\", | > \"latitude\_leftbottom\": null, | +| > | > \\"distance_in_m\\": 1, | +| > \\"session_id\\": \\"\\<session | > | +| > id>\\", | > \\"latitude_leftbottom\\": null, | | > | > | -| > \"type\": 1013, | > \"latitude\_lefttop\": null, | +| > \\"type\\": 1013, | > \\"latitude_lefttop\\": null, | | > | > | -| > \"version\": 3 | > \"latitude\_rightbottom\": | +| > \\"version\\": 3 | > \\"latitude_rightbottom\\": | | > | > null, | | > } | > | -| | > \"latitude\_righttop\": null, | +| | > \\"latitude_righttop\\": null, | | | > | -| | > \"longitude\_leftbottom\": | +| | > \\"longitude_leftbottom\\": | | | > null, | | | > | -| | > \"longitude\_lefttop\": null, | +| | > \\"longitude_lefttop\\": null, | | | > | -| | > \"longitude\_rightbottom\": | +| | > \\"longitude_rightbottom\\": | | | > null, | | | > | -| | > \"longitude\_righttop\": null, | +| | > \\"longitude_righttop\\": null, | | | > | -| | > \"x\_distance\_point1\": 0.3, | +| | > \\"x_distance_point1\\": 0.3, | | | > | -| | > \"x\_distance\_point2\": 0.7, | +| | > \\"x_distance_point2\\": 0.7, | | | > | -| | > \"x\_normcoord\_leftbottom\": | +| | > \\"x_normcoord_leftbottom\\": | | | > 0, | | | > | -| | > \"x\_normcoord\_lefttop\": 0, | +| | > \\"x_normcoord_lefttop\\": 0, | | | > | -| | > \"x\_normcoord\_rightbottom\": | +| | > \\"x_normcoord_rightbottom\\": | | | > 1, | | | > | -| | > \"x\_normcoord\_righttop\": 1, | +| | > \\"x_normcoord_righttop\\": 1, | | | > | -| | > \"y\_distance\_point1\": 0.5, | +| | > \\"y_distance_point1\\": 0.5, | | | > | -| | > \"y\_distance\_point2\": 0.5, | +| | > \\"y_distance_point2\\": 0.5, | | | > | -| | > \"y\_normcoord\_leftbottom\": | +| | > \\"y_normcoord_leftbottom\\": | | | > 1, | | | > | -| | > \"y\_normcoord\_lefttop\": 0, | +| | > \\"y_normcoord_lefttop\\": 0, | | | > | -| | > \"y\_normcoord\_rightbottom\": | +| | > \\"y_normcoord_rightbottom\\": | | | > 1, | | | > | -| | > \"y\_normcoord\_righttop\": 0, | +| | > \\"y_normcoord_righttop\\": 0, | | | > | -| | > \"rotation\_matrix\": { | +| | > \\"rotation_matrix\\": { | | | > | -| | > \"m11\": null, | +| | > \\"m11\\": null, | | | > | -| | > \"m12\": null, | +| | > \\"m12\\": null, | | | > | -| | > \"m13\": null, | +| | > \\"m13\\": null, | | | > | -| | > \"m21\": null, | +| | > \\"m21\\": null, | | | > | -| | > \"m22\": null, | +| | > \\"m22\\": null, | | | > | -| | > \"m23\": null, | +| | > \\"m23\\": null, | | | > | -| | > \"m31\": null, | +| | > \\"m31\\": null, | | | > | -| | > \"m32\": null, | +| | > \\"m32\\": null, | | | > | -| | > \"m33\": null | +| | > \\"m33\\": null | | | > | | | > }, | | | > | -| | > \"offset\_ecef\_to\_local\": { | +| | > \\"offset_ecef_to_local\\": { | | | > | -| | > \"x\": null, | +| | > \\"x\\": null, | | | > | -| | > \"y\": null, | +| | > \\"y\\": null, | | | > | -| | > \"z\": null | +| | > \\"z\\": null | | | > | | | > }, | | | > | -| | > \"offset\_local\_to\_ecef\": { | +| | > \\"offset_local_to_ecef\\": { | | | > | -| | > \"x\": null, | +| | > \\"x\\": null, | | | > | -| | > \"y\": null, | +| | > \\"y\\": null, | | | > | -| | > \"z\": null | +| | > \\"z\\": null | | | > | | | > }, | | | > | -| | > \"pixels\_per\_meter\": null | +| | > \\"pixels_per_meter\\": null | | | > | | | > } | | | > | -| | > \] | +| | > ] \| | | > | | | > } | | | > | -| | > \] | +| | > ] \| | | > | | | > }, | | | > | -| | > \"result\": 1, | +| | > \\"result\\": 1, | | | > | -| | > \"type\": 1013, | +| | > \\"type\\": 1013, | | | > | -| | > \"version\": 3 | +| | > \\"version\\": 3 | | | > | | | > } | -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ -Delete floor plan ------------------ +## Delete floor plan Floor plan can be deleted with *delete floor plan* message. Only a single floor plan in single building can be deleted with the message -although *buildings* and *floor\_plans* fields are arrays. +although *buildings* and *floor_plans* fields are arrays. -Updates are sent to clients via real time situation connection\ -*metadata\_update\_message -\> deleted\_floor\_plans* message. +Updates are sent to clients via real time situation connection\\ +*metadata_update_message -> deleted_floor_plans* message. Table 21: Delete floor plan message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"buildings\": \[ | \"type\": 1014, | -| | | -| { | \"version\": 3 | -| | | -| \"floor\_plans\": \[ | } | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"buildings\\": \[ | \\"type\\": 1014, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"floor_plans\\": \[ | } | +\| \| \| | { | | -| | | -| \"id\": \"\\" | | -| | | +\| \| \| +| \\"id\\": \\"\\<floor plan id>\\" | | +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1014, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1014, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Get floor plan image data -------------------------- +## Get floor plan image data The method can be used to fetch floor plan image or thumbnail data. The image binary data is encoded using Base64 (RFC 3548) encoding. Table 22: Get floor plan image data message -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ | Request | Response | -+===================================+===================================+ +\+===================================+===================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"image\_id\": \"\" | -| thumbnail id\>\", | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"image_id\\": \\"\\<image or | \\"image_base64\\": "\\<data>" | +| thumbnail id>\\", | | | | }, | -| \"originator\_token\": | | -| \"\\" | \"result\": 1, | -| | | -| }, | \"type\": 1021, | -| | | -| \"session\_id\": \"\\", | | +| \\"originator_token\\": | | +| \\"\\<token>\\" | \\"result\\": 1, | +\| \| \| +| }, | \\"type\\": 1021, | +\| \| \| +| \\"session_id\\": \\"\\<session | \\"version\\": 3 | +| id>\\", | | | | } | -| \"type\": 1021, | | -| | | -| \"version\": 3 | | -| | | +| \\"type\\": 1021, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ -Set floor plan image data -------------------------- +## Set floor plan image data The method can be used to upload floor plan image or thumbnail data. The image binary data needs to be encoded using Base64 (RFC 3548) encoding. @@ -1368,578 +1355,569 @@ XR. Table 23: Set floor plan image data message -+--------------------------------------+---------------------------------+ +\+--------------------------------------+---------------------------------+ | Request | Response | -+======================================+=================================+ +\+======================================+=================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"image\_base64\": \"\", | \"image\_id\": \"\\" | -| | | -| \"originator\_token\": \"\\" | }, | -| | | -| }, | \"result\": 1, | -| | | -| \"session\_id\": \"\\", | \"type\": 1022, | -| | | -| \"type\": 1022, | \"version\": 3 | -| | | -| \"version\": 3 | } | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"image_base64\\": \\"\\<data>", | \\"image_id\\": \\"\\<image id>\\" | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | }, | +\| \| \| +| }, | \\"result\\": 1, | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | \\"type\\": 1022, | +\| \| \| +| \\"type\\": 1022, | \\"version\\": 3 | +\| \| \| +| \\"version\\": 3 | } | +\| \| \| | } | | -+--------------------------------------+---------------------------------+ +\+--------------------------------------+---------------------------------+ -Get areas ---------- +## Get areas The message returns areas for given floor plan id. Only a single floor plan's areas in a single building can be queried with the message -although *buildings* and *floor\_plans* fields are arrays. Area color +although *buildings* and *floor_plans* fields are arrays. Area color values (alpha, red, green and blue) are integers between 0...255. *llas* is an array of area corner points' coordinates in WGS84 format and can contain 3...n items. *altitude* is in meters. Table 24: Get areas message -+--------------------------------------+------------------------------------+ +\+--------------------------------------+------------------------------------+ | Request | Response | -+======================================+====================================+ +\+======================================+====================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"buildings\": \[ | \"buildings\": \[ | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"buildings\\": \[ | \\"buildings\\": \[ \| +\| \| \| | { | { | -| | | -| \"floor\_plans\": \[ | \"floor\_plans\": \[ | -| | | +\| \| \| +| \\"floor_plans\\": \[ | \\"floor_plans\\": \[ \| +\| \| \| | { | { | -| | | -| \"id\": \"\\" | \"id\": \"\\", | -| | | -| } | \"areas\": \[ | -| | | -| \] | { | -| | | -| } | \"id\": \"\\", | -| | | -| \], | \"name\": \"\\", | -| | | -| \"originator\_token\": \"\\" | \"a\": \, | -| | | -| }, | \"r\": \, | -| | | -| \"session\_id\": \"\\", | \"g\": \, | -| | | -| \"type\": 1031, | \"b\": \, | -| | | -| \"version\": 3 | \"llas\": \[ | -| | | +\| \| \| +| \\"id\\": \\"\\<floor plan id>\\" | \\"id\\": \\"\\<floor plan id>\\", | +\| \| \| +| } | \\"areas\\": \[ \| +\| \| \| +\| ] | { | +\| \| \| +| } | \\"id\\": \\"\\<area id>\\", | +\| \| \| +\| ], | \\"name\\": \\"\\<area name>\\", | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | \\"a\\": \\<area color alpha>, | +\| \| \| +| }, | \\"r\\": \\<area color red>, | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | \\"g\\": \\<area color green>, | +\| \| \| +| \\"type\\": 1031, | \\"b\\": \\<area color blue>, | +\| \| \| +| \\"version\\": 3 | \\"llas\\": \[ \| +\| \| \| | } | { | -| | | -| | \"altitude\": \, | -| | | -| | \"latitude\": \, | -| | | -| | \"longitude\": \ | -| | | +\| \| \| +| | \\"altitude\\": \\<point altitude>, | +\| \| \| +| | \\"latitude\\": \\<point latitude>, | +\| \| \| +| | \\"longitude\\": \\<point longitude> \| +\| \| \| | | }, | -| | | +\| \| \| | | { | -| | | -| | \"altitude\": \, | -| | | -| | \"latitude\": \, | -| | | -| | \"longitude\": \ | -| | | +\| \| \| +| | \\"altitude\\": \\<point altitude>, | +\| \| \| +| | \\"latitude\\": \\<point latitude>, | +\| \| \| +| | \\"longitude\\": \\<point longitude> \| +\| \| \| | | }, | -| | | +\| \| \| | | { | -| | | -| | \"altitude\": \, | -| | | -| | \"latitude\": \, | -| | | -| | \"longitude\": \ | -| | | +\| \| \| +| | \\"altitude\\": \\<point altitude>, | +\| \| \| +| | \\"latitude\\": \\<point latitude>, | +\| \| \| +| | \\"longitude\\": \\<point longitude> \| +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | }, | -| | | -| | \"result\": 1, | -| | | -| | \"type\": 1031, | -| | | -| | \"version\": 3 | -| | | +\| \| \| +| | \\"result\\": 1, | +\| \| \| +| | \\"type\\": 1031, | +\| \| \| +| | \\"version\\": 3 | +\| \| \| | | } | -+--------------------------------------+------------------------------------+ +\+--------------------------------------+------------------------------------+ -Create area ------------ +## Create area New area can be created with *create area* message which returns area id that can be used later to reference the area. Only a single area in a single floor plan and single building can be created with the message -although *buildings*, *floor\_plans* and *areas* fields are arrays. Area +although *buildings*, *floor_plans* and *areas* fields are arrays. Area color values (alpha, red, green and blue) are integers between 0...255. *llas* is an array of area corner points' coordinates in WGS84 format and can contain 3...n items. *altitude* is in meters. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_areas* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_areas* message. Table 25: Create area message -+--------------------------------------+--------------------------------+ +\+--------------------------------------+--------------------------------+ | Request | Response | -+======================================+================================+ +\+======================================+================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"buildings\": \[ | \"buildings\": \[ | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"buildings\\": \[ | \\"buildings\\": \[ \| +\| \| \| | { | { | -| | | -| \"floor\_plans\": \[ | \"floor\_plans\": \[ | -| | | +\| \| \| +| \\"floor_plans\\": \[ | \\"floor_plans\\": \[ \| +\| \| \| | { | { | -| | | -| \"id\": \"\\", | \"id\": \"\\", | -| | | -| \"areas\": \[ | \"areas\": \[ | -| | | +\| \| \| +| \\"id\\": \\"\\<floor plan id>\\", | \\"id\\": \\"\\<floor plan id>\\", | +\| \| \| +| \\"areas\\": \[ | \\"areas\\": \[ \| +\| \| \| | { | { | -| | | -| \"name\": \"\\", | \"id\": \"\\" | -| | | -| \"a\": \, | } | -| | | -| \"r\": \, | \] | -| | | -| \"g\": \, | } | -| | | -| \"b\": \, | \] | -| | | -| \"llas\": \[ | } | -| | | -| { | \] | -| | | -| \"altitude\": \, | }, | -| | | -| \"latitude\": \, | \"result\": 1, | -| | | -| \"longitude\": \ | \"type\": 1032, | -| | | -| }, | \"version\": 3 | -| | | +\| \| \| +| \\"name\\": \\"\\<area name>\\", | \\"id\\": \\"\\<area id>\\" | +\| \| \| +| \\"a\\": \\<area color alpha>, | } | +\| \| \| +| \\"r\\": \\<area color red>, | ] \| +\| \| \| +| \\"g\\": \\<area color green>, | } | +\| \| \| +| \\"b\\": \\<area color blue>, | ] \| +\| \| \| +| \\"llas\\": \[ | } | +\| \| \| +| { | ] \| +\| \| \| +| \\"altitude\\": \\<point altitude>, | }, | +\| \| \| +| \\"latitude\\": \\<point latitude>, | \\"result\\": 1, | +\| \| \| +| \\"longitude\\": \\<point longitude> | \\"type\\": 1032, | +\| \| \| +| }, | \\"version\\": 3 | +\| \| \| | { | } | -| | | -| \"altitude\": \, | | -| | | -| \"latitude\": \, | | -| | | -| \"longitude\": \ | | -| | | +\| \| \| +| \\"altitude\\": \\<point altitude>, | | +\| \| \| +| \\"latitude\\": \\<point latitude>, | | +\| \| \| +| \\"longitude\\": \\<point longitude> \| \| +\| \| \| | }, | | -| | | +\| \| \| | { | | -| | | -| \"altitude\": \, | | -| | | -| \"latitude\": \, | | -| | | -| \"longitude\": \ | | -| | | +\| \| \| +| \\"altitude\\": \\<point altitude>, | | +\| \| \| +| \\"latitude\\": \\<point latitude>, | | +\| \| \| +| \\"longitude\\": \\<point longitude> \| \| +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1032, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1032, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+--------------------------------+ +\+--------------------------------------+--------------------------------+ -Update area ------------ +## Update area Existing area can be updated with *update area* message. Area color values (alpha, red, green and blue) are integers between 0...255. *llas* is an array of area corner points' coordinates in WGS84 format and can contain 3...n items. *altitude* is in meters. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_areas* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_areas* message. Table 26: Update area message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"buildings\": \[ | \"type\": 1033, | -| | | -| { | \"version\": 3 | -| | | -| \"floor\_plans\": \[ | } | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"buildings\\": \[ | \\"type\\": 1033, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"floor_plans\\": \[ | } | +\| \| \| | { | | -| | | -| \"id\": \"\\", | | -| | | -| \"areas\": \[ | | -| | | +\| \| \| +| \\"id\\": \\"\\<floor plan id>\\", | | +\| \| \| +| \\"areas\\": \[ \| \| +\| \| \| | { | | -| | | -| \"id\": \"\\", | | -| | | -| \"name\": \"\\", | | -| | | -| \"a\": \, | | -| | | -| \"r\": \, | | -| | | -| \"g\": \, | | -| | | -| \"b\": \, | | -| | | -| \"llas\": \[ | | -| | | +\| \| \| +| \\"id\\": \\"\\<area id>\\", | | +\| \| \| +| \\"name\\": \\"\\<area name>\\", | | +\| \| \| +| \\"a\\": \\<area color alpha>, | | +\| \| \| +| \\"r\\": \\<area color red>, | | +\| \| \| +| \\"g\\": \\<area color green>, | | +\| \| \| +| \\"b\\": \\<area color blue>, | | +\| \| \| +| \\"llas\\": \[ \| \| +\| \| \| | { | | -| | | -| \"altitude\": \, | | -| | | -| \"latitude\": \, | | -| | | -| \"longitude\": \ | | -| | | +\| \| \| +| \\"altitude\\": \\<point altitude>, | | +\| \| \| +| \\"latitude\\": \\<point latitude>, | | +\| \| \| +| \\"longitude\\": \\<point longitude> \| \| +\| \| \| | }, | | -| | | +\| \| \| | { | | -| | | -| \"altitude\": \, | | -| | | -| \"latitude\": \, | | -| | | -| \"longitude\": \ | | -| | | +\| \| \| +| \\"altitude\\": \\<point altitude>, | | +\| \| \| +| \\"latitude\\": \\<point latitude>, | | +\| \| \| +| \\"longitude\\": \\<point longitude> \| \| +\| \| \| | }, | | -| | | +\| \| \| | { | | -| | | -| \"altitude\": \, | | -| | | -| \"latitude\": \, | | -| | | -| \"longitude\": \ | | -| | | +\| \| \| +| \\"altitude\\": \\<point altitude>, | | +\| \| \| +| \\"latitude\\": \\<point latitude>, | | +\| \| \| +| \\"longitude\\": \\<point longitude> \| \| +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1033, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1033, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Delete area ------------ +## Delete area Area can be deleted with delete building message. Only a single area can -be deleted with the message although *buildings, floor\_plans* and +be deleted with the message although *buildings, floor_plans* and *areas* fields are arrays. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> deleted\_areas* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> deleted_areas* message. Table 27: Delete building message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"buildings\": \[ | \"type\": 1034, | -| | | -| { | \"version\": 3 | -| | | -| \"floor\_plans\": \[ | } | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"buildings\\": \[ | \\"type\\": 1034, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"floor_plans\\": \[ | } | +\| \| \| | { | | -| | | -| \"id\": \"\\", | | -| | | -| \"areas\": \[ | | -| | | +\| \| \| +| \\"id\\": \\"\\<floor plan id>\\", | | +\| \| \| +| \\"areas\\": \[ \| \| +\| \| \| | { | | -| | | -| \"id\": \"\\" | | -| | | +\| \| \| +| \\"id\\": \\"\\<area id>\\" | | +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1034, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1034, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Get networks ------------- +## Get networks The message returns network id and name mappings. Table 28: Get networks message -+--------------------------------------+--------------------------------+ +\+--------------------------------------+--------------------------------+ | Request | Example response | -+======================================+================================+ +\+======================================+================================+ | { | { | -| | | -| \"data\": { | \"data\": { | -| | | -| \"originator\_token\": \"\\" | \"networks\": \[ | -| | | +\| \| \| +| \\"data\\": { | \\"data\\": { | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | \\"networks\\": \[ \| +\| \| \| | }, | { | -| | | -| \"session\_id\": \"\\", | \"id\": \, | -| | | -| \"type\": 1041, | \"name\": \"\\" | -| | | -| \"version\": 3 | }, | -| | | +\| \| \| +| \\"session_id\\": \\"\\<token>\\", | \\"id\\": \\<network id>, | +\| \| \| +| \\"type\\": 1041, | \\"name\\": \\"\\<network name>\\" | +\| \| \| +| \\"version\\": 3 | }, | +\| \| \| | } | { | -| | | -| | \"id\": \, | -| | | -| | \"name\": \"\\" | -| | | +\| \| \| +| | \\"id\\": \\<network id>, | +\| \| \| +| | \\"name\\": \\"\\<network name>\\" | +\| \| \| | | } | -| | | -| | \] | -| | | +\| \| \| +\| \| ] \| +\| \| \| | | }, | -| | | -| | \"result\": 1, | -| | | -| | \"type\": 1041, | -| | | -| | \"version\": 3 | -| | | +\| \| \| +| | \\"result\\": 1, | +\| \| \| +| | \\"type\\": 1041, | +\| \| \| +| | \\"version\\": 3 | +\| \| \| | | } | -+--------------------------------------+--------------------------------+ +\+--------------------------------------+--------------------------------+ -Create network --------------- +## Create network The message is used to create a new network id to name mapping. Only a single network mapping can be created with the message although *networks* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_networks* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_networks* message. Table 29: Create network message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"networks\": \[ | \"type\": 1042, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": \, | } | -| | | -| \"name\": \"\\" | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"networks\\": \[ | \\"type\\": 1042, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": \\<network id>, | } | +\| \| \| +| \\"name\\": \\"\\<network name>\\" | | +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1042, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1042, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Update network --------------- +## Update network Network name can be updated with *update network* message. Only a single network can be updated with the message although *networks* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> added\_or\_changed\_networks* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> added_or_changed_networks* message. Table 30: Update network message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"networks\": \[ | \"type\": 1043, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": \, | } | -| | | -| \"name\": \"\\" | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"networks\\": \[ | \\"type\\": 1043, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": \\<network id>, | } | +\| \| \| +| \\"name\\": \\"\\<network name>\\" | | +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1043, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1043, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Delete network --------------- +## Delete network Network id to name mapping can be deleted with *delete network* message. Only a single network can be deleted with the message although *networks* field is an array. -Updates are sent to clients via real time situation connection using\ -*metadata\_update\_message -\> deleted\_networks* message. +Updates are sent to clients via real time situation connection using\\ +*metadata_update_message -> deleted_networks* message. Table 31: Delete network message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"networks\": \[ | \"type\": 1044, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": \ | } | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"networks\\": \[ | \\"type\\": 1044, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": \\<network id> | } | +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1044, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1044, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Add node to floor plan ----------------------- +## Add node to floor plan Node can be bound to floor plan with *add node to floor plan* message. Only a single node can be added with the message although *nodes* field @@ -1948,245 +1926,240 @@ approved with valid location information with *set node metadata* message. Updates are sent to clients via real time situation connection using -*node\_metadata* message. +*node_metadata* message. Table 32: Add node to floor plan message -+---------------------------------------------+-----------------+ +\+---------------------------------------------+-----------------+ | Request | Response | -+=============================================+=================+ +\+=============================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"nodes\": \[ | \"type\": 1051, | -| | | -| { | \"version\": 3 | -| | | -| \"floor\_plan\_id\": \"\\", | } | -| | | -| \"id\": \, | | -| | | -| \"network\_id\": \ | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"nodes\\": \[ | \\"type\\": 1051, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"floor_plan_id\\": \\"\\<floor plan id>\\", | } | +\| \| \| +| \\"id\\": \\<node id>, | | +\| \| \| +| \\"network_id\\": \\<network id> \| \| +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1051, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1051, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+---------------------------------------------+-----------------+ +\+---------------------------------------------+-----------------+ -Remove node from floor plan ---------------------------- +## Remove node from floor plan Node can be removed from floor plan with *remove node from floor plan* message. Only a single node can be removed with the message although *nodes* field is an array. Updates are sent to clients via real time situation connection using -*node\_metadata* message. +*node_metadata* message. Table 33: Remove node from floor plan message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"nodes\": \[ | \"type\": 1052, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": \, | } | -| | | -| \"network\_id\": \ | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"nodes\\": \[ | \\"type\\": 1052, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": \\<node id>, | } | +\| \| \| +| \\"network_id\\": \\<network id> \| \| +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1052, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1052, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Set node metadata ------------------ +## Set node metadata -The method is used set node related metadata. *is\_virtual* denotes the -planning node feature in WNT client \[2\]. +The method is used set node related metadata. *is_virtual* denotes the +planning node feature in WNT client \[2]. Updates are sent to clients via real time situation connection using -*node\_metadata* message. +*node_metadata* message. Table 34: Set node metadata message -+----------------------------------------+-----------------+ +\+----------------------------------------+-----------------+ | Example request | Response | -+========================================+=================+ +\+========================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"nodes\": \[ | \"type\": 1061, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": 1, | } | -| | | -| \"network\_id\": 112233, | | -| | | -| \"name\": \"some name\", | | -| | | -| \"description\": \"some description\", | | -| | | -| \"is\_approved\": true, | | -| | | -| \"is\_virtual\": false, | | -| | | -| \"latitude\": 61.4547593371768, | | -| | | -| \"longitude\": 23.8856021513505, | | -| | | -| \"altitude\": 0.0 | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"nodes\\": \[ | \\"type\\": 1061, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": 1, | } | +\| \| \| +| \\"network_id\\": 112233, | | +\| \| \| +| \\"name\\": \\"some name\\", | | +\| \| \| +| \\"description\\": \\"some description\\", | | +\| \| \| +| \\"is_approved\\": true, | | +\| \| \| +| \\"is_virtual\\": false, | | +\| \| \| +| \\"latitude\\": 61.4547593371768, | | +\| \| \| +| \\"longitude\\": 23.8856021513505, | | +\| \| \| +| \\"altitude\\": 0.0 | | +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1061, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1061, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+----------------------------------------+-----------------+ +\+----------------------------------------+-----------------+ -Delete node ------------ +## Delete node The method is used to delete node real time situation and metadata. Only a single node's data can be deleted with the message although *nodes* field is an array. Note that if node sends any data afterwards it will -be shown again. Boolean type *is\_sink* information is required to let +be shown again. Boolean type *is_sink* information is required to let the WNT backend to perform additional clean ups if needed. Updates are sent to clients via real time situation connection using -*node\_metadata* message. +*node_metadata* message. Table 35: Delete node message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"nodes\": \[ | \"type\": 1063, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": \, | } | -| | | -| \"network\_id\": \, | | -| | | -| \"is\_sink\":\ | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"nodes\\": \[ | \\"type\\": 1063, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": \\<node id>, | } | +\| \| \| +| \\"network_id\\": \\<network id>, | | +\| \| \| +| \\"is_sink\\":\\<true / false> \| \| +\| \| \| | } | | -| | | -| \], | | -| | | -| \"originator\_token\": \"\\" | | -| | | +\| \| \| +\| ], | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | | +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1063, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1063, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Set network data ----------------- +## Set network data The method can be used to set network wide application configuration -data and diagnostics interval \[1\]. Only a single network's data can be +data and diagnostics interval \[1]. Only a single network's data can be set with the message although *networks* field is an array. Updates are sent to clients per sink via real time situation connection -using *app\_config* message. +using *app_config* message. Table 36: Set network data message -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ | Example request | Response | -+===================================+===================================+ +\+===================================+===================================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"networks\": \[ | \"type\": 1071, | -| | | -| { | \"version\": 3 | -| | | -| \"application\_data\": | } | -| \"112233445566778899AABBCCDDEEFF\ | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"networks\\": \[ | \\"type\\": 1071, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"application_data\\": | } | +| \\"112233445566778899AABBCCDDEEFF\\ | | | ", | | -| | | -| \"diagnostics\_interval\": 60, | | -| | | -| \"id\": \"112233\" | | -| | | +\| \| \| +| \\"diagnostics_interval\\": 60, | | +\| \| \| +| \\"id\\": \\"112233\\" | | +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | }, | | -| | | -| \"originator\_token\": | | -| \"\\", | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1071, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"originator_token\\": | | +| \\"\\<token>\\", | | +\| \| \| +| \\"session_id\\": \\"\\<session | | +| id>\\", | | +\| \| \| +| \\"type\\": 1071, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+-----------------------------------+-----------------------------------+ +\+-----------------------------------+-----------------------------------+ -Send data message ------------------ +## Send data message The method can be used to send arbitrary data message to a node. The message requires that receiving node sink's node id is defined so the @@ -2194,140 +2167,139 @@ message sending does not create unneeded load to the network. *Payload* is hexadecimal encoded binary data. At the moment it is not possible to get confirmation that node received the message. -For more information about the fields please see DSAP-DATA\_TX.request -\[1\]. +For more information about the fields please see DSAP-DATA_TX.request +\[1]. Table 37:Send data message -+---------------------------------------+-----------------+ +\+---------------------------------------+-----------------+ | Example request | Response | -+=======================================+=================+ +\+=======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"command\": { | \"type\": 1073, | -| | | -| \"network\_id\": 777555, | \"version\": 3 | -| | | -| \"node\_id\": 2, | } | -| | | -| \"sink\_node\_id\": 1, | | -| | | -| \"source\_end\_point\": 255, | | -| | | -| \"destination\_end\_point\": 240, | | -| | | -| \"payload\": \"040001000300\", | | -| | | -| \"qos\": 0 | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"command\\": { | \\"type\\": 1073, | +\| \| \| +| \\"network_id\\": 777555, | \\"version\\": 3 | +\| \| \| +| \\"node_id\\": 2, | } | +\| \| \| +| \\"sink_node_id\\": 1, | | +\| \| \| +| \\"source_end_point\\": 255, | | +\| \| \| +| \\"destination_end_point\\": 240, | | +\| \| \| +| \\"payload\\": \\"040001000300\\", | | +\| \| \| +| \\"qos\\": 0 | | +\| \| \| | } | | -| | | +\| \| \| | }, | | -| | | -| \"originator\_token\": \"\\", | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1073, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\", | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1073, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+---------------------------------------+-----------------+ +\+---------------------------------------+-----------------+ -Get scratchpad status ---------------------- +## Get scratchpad status The method can be used to query scratchpad status from the nodes in the network. Only a single network's data can be get with the message although *networks* field is an array. The query can be a single shot or continuous. Continuous query sending interval can be defined by setting -*rerun\_interval\_s* property. +*rerun_interval_s* property. Table 38:Query types - Query rerun\_interval\_s is\_close - ------------------ -------------------- ----------- + Query rerun_interval_s is_close + +* * * + Single shot 0 false Start continuous Interval false Stop continuous 0 true Data is sent to clients per node via real time situation connection -using *scratchpad\_status* message. +using *scratchpad_status* message. Table 39: Get scratchpad status message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Example request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"networks\": \[ | \"type\": 1074, | -| | | -| { | \"version\": 3 | -| | | -| \"id\": 112233, | } | -| | | -| \"rerun\_interval\_s": 180, | | -| | | -| \"is\_close\": false | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"networks\\": \[ | \\"type\\": 1074, | +\| \| \| +| { | \\"version\\": 3 | +\| \| \| +| \\"id\\": 112233, | } | +\| \| \| +| \\"rerun_interval_s": 180, | | +\| \| \| +| \\"is_close\\": false | | +\| \| \| | } | | -| | | -| \] | | -| | | +\| \| \| +\| ] \| \| +\| \| \| | }, | | -| | | -| \"session\_id\": \"\\", | | -| | | -| \"type\": 1074, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | | +\| \| \| +| \\"type\\": 1074, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ -Get components information --------------------------- +## Get components information The method can be used to query backend components' and gateways' information. Responses are sent to clients via the real time situation connection -using *backend\_component\_info* and *gateway\_info* messages. +using *backend_component_info* and *gateway_info* messages. Please note that the backend component information is returned only from -the metadata service, and *originator\_token* is not yet returned via +the metadata service, and *originator_token* is not yet returned via the real time situation connection. Table 40: Get components information message -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ | Example request | Response | -+======================================+=================+ +\+======================================+=================+ | { | { | -| | | -| \"data\": { | \"result\": 1, | -| | | -| \"originator\_token\": \"\\" | \"type\": 1081, | -| | | -| }, | \"version\": 3 | -| | | -| \"session\_id\": \"\\", | } | -| | | -| \"type\": 1081, | | -| | | -| \"version\": 3 | | -| | | +\| \| \| +| \\"data\\": { | \\"result\\": 1, | +\| \| \| +| \\"originator_token\\": \\"\\<token>\\" | \\"type\\": 1081, | +\| \| \| +| }, | \\"version\\": 3 | +\| \| \| +| \\"session_id\\": \\"\\<token>\\", | } | +\| \| \| +| \\"type\\": 1081, | | +\| \| \| +| \\"version\\": 3 | | +\| \| \| | } | | -+--------------------------------------+-----------------+ +\+--------------------------------------+-----------------+ - Real time situation service authentication -============================================ +# Real time situation service authentication The service provides all nodes related data and changes to the metadata. Authentication is done in the start by sending the *session id* received @@ -2335,17 +2307,17 @@ from the authentication service. Table 41: Authentication -+--------------------------------------+----------------+ +\+--------------------------------------+----------------+ | Request | Response | -+======================================+================+ +\+======================================+================+ | { | { | -| | | -| \"session\_id\": \"\\", | \"result\": 1, | -| | | -| \"version\": 3 | \"version\": 3 | -| | | +\| \| \| +| \\"session_id\\": \\"\\<session id>\\", | \\"result\\": 1, | +\| \| \| +| \\"version\\": 3 | \\"version\\": 3 | +\| \| \| | } | } | -+--------------------------------------+----------------+ +\+--------------------------------------+----------------+ After a successful authentication the service starts to send Protocol Buffers encoded data and moves into write only mode. First message(s) @@ -2356,21 +2328,20 @@ information is sent to client. Table 42: Node count message -+-----------------------------------+---------------+ +\+-----------------------------------+---------------+ | Path | Data | -+===================================+===============+ -| Message -\> rtsituation\_metadata | cluster\_no | -| | | -| | cluster\_size | -| | | -| | node\_count | -+-----------------------------------+---------------+ +\+===================================+===============+ +| Message -> rtsituation_metadata | cluster_no | +\| \| \| +| | cluster_size | +\| \| \| +| | node_count | +\+-----------------------------------+---------------+ Note that all received Protocol Buffers messages has message "Message" as a root item (message.proto). -Time series service data -======================== +# Time series service data Time series data is provided by direct access to Influx database. The same credentials used to login to authentication service can be used @@ -2382,237 +2353,235 @@ equivalent of database table). Table 43: Database measurements Measurement Description - ---------------------------- ------------------------------------------------------- - analytics\_next\_hop Hop count to sink - analytics\_nodestate Node online information \* - analytics\_packet High level information about every received packet - analytics\_traveltime\_kpi Processed information about packets' travel times - endpoint\_251 Traffic diagnostics \[3\] \*\* - endpoint\_252 Neighbor diagnostics \[3\] \*\* - endpoint\_253 Node diagnostics \[3\] \*\* - endpoint\_254 Boot diagnostics \[3\] \*\* - location\_measurement Positioning measurements received from the nodes \*\* - location\_update Computed positions for nodes \*\* - remote\_api\_response Remote API response information \*\* + +* * * + + analytics_next_hop Hop count to sink + analytics_nodestate Node online information \* + analytics_packet High level information about every received packet + analytics_traveltime_kpi Processed information about packets' travel times + endpoint_251 Traffic diagnostics \[3] \*\* + endpoint_252 Neighbor diagnostics \[3] \*\* + endpoint_253 Node diagnostics \[3] \*\* + endpoint_254 Boot diagnostics \[3] \*\* + location_measurement Positioning measurements received from the nodes \*\* + location_update Computed positions for nodes \*\* + remote_api_response Remote API response information \*\* \* Online state uses the values defined in *OnlineStatus* message (internal.proto). \*\* Column names use numbering from the WNT Protocol Buffers files. -Wirepas Backend-client \[4\] contains *influx\_viewer* example which can +Wirepas Backend-client \[4] contains *influx_viewer* example which can be used to query information from the Influx with the decoded column names. -Please note that in WNT 2.0, *analytics\_packet* measurement's -*travel\_time\_ms* column is replaced by *travel\_time\_ms\_qos0* and -*travel\_time\_ms\_qos1* columns. Also separate *qos* column is added to +Please note that in WNT 2.0, *analytics_packet* measurement's +*travel_time_ms* column is replaced by *travel_time_ms_qos0* and +*travel_time_ms_qos1* columns. Also separate *qos* column is added to the measurement. -Example CURL command to query data ----------------------------------- +## Example CURL command to query data -curl.exe -G https://someaddresswnt.extwirepas.com:8886/query -\--data-urlencode \"u=\\" \--data-urlencode -\"p=\\" \--data-urlencode \"pretty=true\" \--data-urlencode -\"db=wirepas\" \--data-urlencode \"q=show measurements\" +curl.exe -G +\--data-urlencode \\"u=\\<username>\\" --data-urlencode +\\"p=\\<password>\\" --data-urlencode \\"pretty=true\\" --data-urlencode +\\"db=wirepas\\" --data-urlencode \\"q=show measurements\\" -Example column names decoding ------------------------------ +## Example column names decoding In the example the query used to query data is "*q=select \* from -endpoint\_252*". +endpoint_252*". Table 44: Example response -+-------------------------------------+ +\+-------------------------------------+ | Response from Influx | -+=====================================+ +\+=====================================+ | { | -| | -| \"results\": \[ | -| | +\| \| +| \\"results\\": \[ \| +\| \| | { | -| | -| \"statement\_id\": 0, | -| | -| \"series\": \[ | -| | +\| \| +| \\"statement_id\\": 0, | +\| \| +| \\"series\\": \[ \| +\| \| | { | -| | -| \"name\": \"endpoint\_252\", | -| | -| \"columns\": \[ | -| | -| \"time\", | -| | -| \"Message\_2\", | -| | -| \"Message\_4\", | -| | -| \"Message\_5\", | -| | -| \"Message\_50\_1\", | -| | -| \"Message\_50\_49\", | -| | -| \"Message\_51\_2\", | -| | -| \"Message\_51\_4\", | -| | -| \"Message\_51\_5\", | -| | -| \"Message\_51\_7\", | -| | -| \"Message\_7\", | -| | -| \"Message\_8\", | -| | -| \"Message\_9\", | -| | -| \"network\_id\", | -| | -| \"nodegroup\", | -| | -| \"nodeid\" | -| | -| \], | -| | -| \"values\": \[ | -| | -| \[ | -| | -| \"2018-11-28T16:48:41.301000003Z\", | -| | +\| \| +| \\"name\\": \\"endpoint_252\\", | +\| \| +| \\"columns\\": \[ \| +\| \| +| \\"time\\", | +\| \| +| \\"Message_2\\", | +\| \| +| \\"Message_4\\", | +\| \| +| \\"Message_5\\", | +\| \| +| \\"Message_50_1\\", | +\| \| +| \\"Message_50_49\\", | +\| \| +| \\"Message_51_2\\", | +\| \| +| \\"Message_51_4\\", | +\| \| +| \\"Message_51_5\\", | +\| \| +| \\"Message_51_7\\", | +\| \| +| \\"Message_7\\", | +\| \| +| \\"Message_8\\", | +\| \| +| \\"Message_9\\", | +\| \| +| \\"network_id\\", | +\| \| +| \\"nodegroup\\", | +\| \| +| \\"nodeid\\" | +\| \| +\| ], | +\| \| +| \\"values\\": \[ \| +\| \| +\| \[ \| +\| \| +| \\"2018-11-28T16:48:41.301000003Z\\", | +\| \| | 112233, | -| | +\| \| | 1543423721301, | -| | +\| \| | 1543423721340, | -| | -| \"\[Message\_50\_1\_1=12499145, | -| | -| Message\_50\_1\_2=2399.0, | -| | -| Message\_50\_1\_3=-4.0, | -| | -| Message\_50\_1\_4=1, | -| | -| Message\_50\_1\_5=-23.0\]\", | -| | +\| \| +| \\"\[Message_50_1_1=12499145, | +\| \| +| Message_50_1_2=2399.0, | +\| \| +| Message_50_1_3=-4.0, | +\| \| +| Message_50_1_4=1, | +\| \| +| Message_50_1_5=-23.0]\\", | +\| \| | 123, | -| | +\| \| | 252, | -| | +\| \| | 255, | -| | +\| \| | 0, | -| | -| \"\", | -| | +\| \| +| \\"\\", | +\| \| | 123, | -| | +\| \| | 123, | -| | +\| \| | 39, | -| | -| \"112233\", | -| | -| \"0\", | -| | +\| \| +| \\"112233\\", | +\| \| +| \\"0\\", | +\| \| | 123 | -| | -| \] | -| | -| \] | -| | +\| \| +\| ] \| +\| \| +\| ] \| +\| \| | } | -| | -| \] | -| | +\| \| +\| ] \| +\| \| | } | -| | -| \] | -| | +\| \| +\| ] \| +\| \| | } | -+-------------------------------------+ +\+-------------------------------------+ -For example to decode column *Message\_2*, open main WNT Protocol +For example to decode column *Message_2*, open main WNT Protocol Buffers file *message.proto* and look for message called *Message*. This message is used as base of all columns starting with *Message\_* and the number after the underscore is the field number of the corresponding -message. In this case *Message\_2* can be decoded to *network\_id*. +message. In this case *Message_2* can be decoded to *network_id*. Table 45: Part of message.proto -+-----------------------------------------+ +\+-----------------------------------------+ | message.proto | -+=========================================+ +\+=========================================+ | message Message { | -| | -| repeated uint32 id = 1 \[packed=true\]; | -| | -| optional uint32 network\_id = 2; | -| | -| optional string gateway\_id = 3; | -| | +\| \| +| repeated uint32 id = 1 \[packed=true]; | +\| \| +| optional uint32 network_id = 2; | +\| \| +| optional string gateway_id = 3; | +\| \| | . | -| | +\| \| | . | -| | +\| \| | . | -+-----------------------------------------+ +\+-----------------------------------------+ -Decoding *Message\_51\_2* column name can be done the same way except -that the number 51 is sub-message *rx\_time* which is instance of -*RxData* message. Following the previous rules the *Message\_51\_2* can +Decoding *Message_51_2* column name can be done the same way except +that the number 51 is sub-message *rx_time* which is instance of +*RxData* message. Following the previous rules the *Message_51_2* can be decoded to be source endpoint of a data message packet. Table 46: Part of message.proto -+-----------------------------------------------------------+ +\+-----------------------------------------------------------+ | message.proto | -+===========================================================+ +\+===========================================================+ | message Message { | -| | +\| \| | . | -| | +\| \| | . | -| | +\| \| | . | -| | +\| \| | optional DiagnosticsData diagnostics = 50; | -| | -| optional RxData rx\_data = 51; | -| | -| optional AppConfigData app\_config = 52; | -| | +\| \| +| optional RxData rx_data = 51; | +\| \| +| optional AppConfigData app_config = 52; | +\| \| | . | -| | +\| \| | . | -| | +\| \| | . | -| | +\| \| | } | -| | +\| \| | message RxData { | -| | -| optional uint32 source\_endpoint = 2; | -| | -| optional uint32 destination\_endpoint = 4; | -| | -| optional uint32 qos = 5 \[default = 0\]; | -| | -| optional bytes payload = 7 \[(nanopb).max\_size = 1024\]; | -| | +\| \| +| optional uint32 source_endpoint = 2; | +\| \| +| optional uint32 destination_endpoint = 4; | +\| \| +| optional uint32 qos = 5 \[default = 0]; | +\| \| +| optional bytes payload = 7 \[(nanopb).max_size = 1024]; | +\| \| | } | -+-----------------------------------------------------------+ +\+-----------------------------------------------------------+ -Basic data flow and real time situation data -============================================ +# Basic data flow and real time situation data -Basic data flow to get continuous data --------------------------------------- +## Basic data flow to get continuous data - Generate e.g. UUID (version 4) which is used as *originator token* for metadata changes. @@ -2630,7 +2599,7 @@ Basic data flow to get continuous data - If you need this non-node metadata in your application, you need to store the related information as the real time situation - connection message's *metadata\_update\_message* will only + connection message's *metadata_update_message* will only contain the changed information. - Connect to the real time situation service and authenticate with the @@ -2663,12 +2632,12 @@ Basic data flow to get continuous data - You need to keep the initial node state and then apply the changed fields incrementally. - - Messages will contain *network\_id* and *source\_address* + - Messages will contain *network_id* and *source_address* fields to distinguish between the nodes. - Any metadata change will be provided via the connection. - - You can use the *originator\_token* to distinct the changes + - You can use the *originator_token* to distinct the changes made by you. - When you wish to stop receiving the real time data please close the @@ -2679,8 +2648,7 @@ connection is closed, you need to connect and [*login*](#login) again to the authentication service, and the service will provide a new *session id*. -Real time situation data ------------------------- +## Real time situation data Real time situation component uses Protocol Buffers messages to send the data. All the incoming messages have a message called Message as a root @@ -2689,25 +2657,27 @@ item (please see message.proto). Table 47: Important message fields Field name Description - ------------------------------ ------------------------------------------------------------------------------------- - network\_id Network id of the node which sent the message. - source\_address Node id of the node which sent the message. - gateway\_id Id of the gateway which routed the message. - tx\_time Time when the packet was generated by the node. - rx\_time Time when the packet was received by the gateway. - travel\_time\_ms How long it took for gateway to receive the packet (rx\_time -- tx\_time). + +* * * + + network_id Network id of the node which sent the message. + source_address Node id of the node which sent the message. + gateway_id Id of the gateway which routed the message. + tx_time Time when the packet was generated by the node. + rx_time Time when the packet was received by the gateway. + travel_time_ms How long it took for gateway to receive the packet (rx_time -- tx_time). diagnostics \* Diagnostics data that the node has generated. Contains also the node role and mode. - rx\_data \* Data message information (end points, qos etc.). - app\_config \* Application configuration data and diagnostics interval (sent only by the sinks). - network\_channel Network channel (sent only by the sinks). - security\_enabled Are cipher and encryption keys set for the network (sent only by the sinks). - app\_config\_response \* Response for setting of the app config (sent only by the sinks). - gateway\_info \* Gateway information response data. - scratchpad\_status \* Scratchpad status response data. - online\_status \* Node online status determined by the backend. - node\_metadata \* Node metadata (location, name, description, positioning role etc.) - rtsituation\_metadata \* Information about real time situation manager (node count). - metadata\_update\_message \* Non-node related metadata update information. + rx_data \* Data message information (end points, qos etc.). + app_config \* Application configuration data and diagnostics interval (sent only by the sinks). + network_channel Network channel (sent only by the sinks). + security_enabled Are cipher and encryption keys set for the network (sent only by the sinks). + app_config_response \* Response for setting of the app config (sent only by the sinks). + gateway_info \* Gateway information response data. + scratchpad_status \* Scratchpad status response data. + online_status \* Node online status determined by the backend. + node_metadata \* Node metadata (location, name, description, positioning role etc.) + rtsituation_metadata \* Information about real time situation manager (node count). + metadata_update_message \* Non-node related metadata update information. \*) Sub-message @@ -2716,11 +2686,9 @@ seconds as a batch processing, so the incoming message via the real time situation connection can contain merged information from several messages of a node. -Coordinate conversions -====================== +# Coordinate conversions -Introduction ------------- +## Introduction When a floor plan is added into WNT it is required to input the latitude/longitude/altitude (WGS84) of four reference points (A, B, C, @@ -2742,28 +2710,27 @@ corner has the coordinate (0,0) pixels. Given the floorplan information provided by the WNT API the following matrices/vectors are used: -- Rotation matrix (using *rotation\_matrix*): +- Rotation matrix (using *rotation_matrix*): -$$R = \begin{bmatrix} -m_{11} & m_{12} & m_{13} \\ -m_{21} & m_{22} & m_{23} \\ -m_{31} & m_{32} & m_{33} \\ -\end{bmatrix}$$ +$$R = \\begin{bmatrix} +m*{11} & m*{12} & m*{13} \\ +m*{21} & m*{22} & m*{23} \\ +m*{31} & m*{32} & m\_{33} \\ +\\end{bmatrix}$$ -- Translation matrix (using *offset\_local\_to\_ecef* ): +- Translation matrix (using *offset_local_to_ecef* ): -$$T_{r} = \begin{bmatrix} +$$T\_{r} = \\begin{bmatrix} x \\ y \\ z \\ -\end{bmatrix}$$ +\\end{bmatrix}$$ - Scaling: -$$s = \ pixels\_ per\_ meter$$ +$$s = \\ pixels\_ per\_ meter$$ -WGS84 to pixels ---------------- +## WGS84 to pixels To convert a WGS84 coordinate to pixels the following steps are required: @@ -2774,119 +2741,115 @@ required: 2. Given $E$ the ECEF coordinate vector compute the pixel coordinates $P$ as: -$$P = R \bullet \left( E - T_{r} \right) \bullet s$$ +$$P = R \\bullet \\left( E - T\_{r} \\right) \\bullet s$$ The matrix operations can be equivalently expressed as: -$$p_{x} = (m_{11} \bullet dx + m_{12} \bullet dy\ + \ m_{13} \bullet dz) \bullet s$$ +$$p*{x} = (m*{11} \\bullet dx + m*{12} \\bullet dy\\ + \\ m*{13} \\bullet dz) \\bullet s$$ -$$p_{y} = (m_{21} \bullet dx + m_{22} \bullet dy\ + \ m_{23} \bullet dz) \bullet s$$ +$$p*{y} = (m*{21} \\bullet dx + m*{22} \\bullet dy\\ + \\ m*{23} \\bullet dz) \\bullet s$$ where: -$$\begin{bmatrix} -\text{dx} \\ -\text{dy} \\ -\text{dz} \\ -\end{bmatrix} = E - T_{r}$$ +$$\\begin{bmatrix} +\\text{dx} \\ +\\text{dy} \\ +\\text{dz} \\ +\\end{bmatrix} = E - T\_{r}$$ -Pixels to WGS84 ---------------- +## Pixels to WGS84 -To convert a pixel coordinate $(p_{x},p_{y})$ to WGS84 the following +To convert a pixel coordinate $(p*{x},p*{y})$ to WGS84 the following steps are required: 1. Compute the ECEF coordinate as: -$$E = \frac{R^{'} \bullet P}{s} + T_{r}$$ +$$E = \\frac{R^{'} \\bullet P}{s} + T\_{r}$$ where: -$$P = \begin{bmatrix} -p_{x} \\ -p_{y} \\ +$$P = \\begin{bmatrix} +p*{x} \\ +p*{y} \\ 0 \\ -\end{bmatrix}$$ +\\end{bmatrix}$$ and $R^{'}$ denote the transpose matrix. 2. Convert the ECEF coordinate to WGS84 as shown in chapter 9.5. -WGS84 to ECEF conversion ------------------------- +## WGS84 to ECEF conversion Given a WGS84 coordinate as: ϕ latitude in radians, λ longitude in -radians, $h$ altitude in meters the ECEF coordinate $E = \begin{bmatrix} +radians, $h$ altitude in meters the ECEF coordinate $E = \\begin{bmatrix} x \\ y \\ z \\ -\end{bmatrix}\ $in meters is computed as: +\\end{bmatrix}\\ $in meters is computed as: -$$x = (v + h) \bullet cos(\varphi) \bullet cos(\lambda)$$ +$$x = (v + h) \\bullet cos(\\varphi) \\bullet cos(\\lambda)$$ -$$y = (v + h) \bullet cos(\varphi) \bullet sin(\lambda)$$ +$$y = (v + h) \\bullet cos(\\varphi) \\bullet sin(\\lambda)$$ -$$z = (v \bullet (1 - e_{2}) + h) \bullet sin(\varphi)$$ +$$z = (v \\bullet (1 - e\_{2}) + h) \\bullet sin(\\varphi)$$ where: -$$v = \frac{a}{\sqrt{1 - e_{2} \bullet {sin(\varphi)}^{2}}}$$ +$$v = \\frac{a}{\\sqrt{1 - e\_{2} \\bullet {sin(\\varphi)}^{2}}}$$ $$a = 6378137.0$$ -$$e_{2} = \ 0.00669437999014133$$ +$$e\_{2} = \\ 0.00669437999014133$$ -ECEF to WGS84 conversion ------------------------- +## ECEF to WGS84 conversion The conversion from ECEF to WGS84 is an iterative process. Starting from an initial state computed as: -$$p = \sqrt{x^{2} + y^{2}}$$ +$$p = \\sqrt{x^{2} + y^{2}}$$ -$$\varphi = atan2(z,\ p \bullet (1 - e_{2})$$ +$$\\varphi = atan2(z,\\ p \\bullet (1 - e\_{2})$$ $$h = 0$$ -$$\Delta h = 0$$ +$$\\Delta h = 0$$ -$$\Delta\varphi = 0$$ +$$\\Delta\\varphi = 0$$ -Iterate the following equations until $\Delta\varphi < 10^{- 12}\ $and -$\Delta h < \ 10^{- 5}$: +Iterate the following equations until $\\Delta\\varphi < 10^{- 12}\\ $and +$\\Delta h < \\ 10^{- 5}$: -$$\varphi_{0} = \varphi$$ +$$\\varphi\_{0} = \\varphi$$ -$$h_{0} = h$$ +$$h\_{0} = h$$ -$$v = \frac{a}{\sqrt{1 - e_{2} \bullet {sin(\varphi)}^{2}}}$$ +$$v = \\frac{a}{\\sqrt{1 - e\_{2} \\bullet {sin(\\varphi)}^{2}}}$$ -$$h = \frac{p}{cos(\varphi)} - v$$ +$$h = \\frac{p}{cos(\\varphi)} - v$$ -$$\varphi = atan2(z,\ p \bullet (1 - e_{2} \bullet \frac{v}{(v + h)})$$ +$$\\varphi = atan2(z,\\ p \\bullet (1 - e\_{2} \\bullet \\frac{v}{(v + h)})$$ -$$\Delta\varphi = \ \left| \varphi - \varphi_{0} \right|$$ +$$\\Delta\\varphi = \\ \\left| \\varphi - \\varphi\_{0} \\right|$$ -$$\Delta h = \ \left| h - h_{0} \right|$$ +$$\\Delta h = \\ \\left| h - h\_{0} \\right|$$ -where $\left| \bullet \right|$ denotes the absolute value and -$e_{2}\ $is the same as in chapter 9.4. +where $\\left| \\bullet \\right|$ denotes the absolute value and +$e\_{2}\\ $is the same as in chapter 9.4. Finally compute longitude as: -$$\lambda = atan2(y,\ x)$$ +$$\\lambda = atan2(y,\\ x)$$ Note that the latitude and longitude values are in radians and the altitude in meters. -References -========== +# References -\[1\] WP-RM-100 - Wirepas Connectivity Dual-MCU API Reference Manual +\[1] WP-RM-100 - Wirepas Connectivity Dual-MCU API Reference Manual -\[2\] WP-UG-421 - Wirepas Network Tool - Client User Guide +\[2] WP-UG-421 - Wirepas Network Tool - Client User Guide -\[3\] WP-RM-104 - Wirepas Mesh Diagnostics Reference Manual +\[3] WP-RM-104 - Wirepas Mesh Diagnostics Reference Manual -\[4\] https://github.com/wirepas/backend-client +\[4] From 3876c9a4b49bb971108d04212dd8469367a98488 Mon Sep 17 00:00:00 2001 From: Pedro Silva Date: Thu, 10 Oct 2019 17:04:02 +0300 Subject: [PATCH 3/3] Update tables to json syntax and render equations --- wnt/media/eq_dxyz.gif | Bin 0 -> 836 bytes wnt/media/eq_e_matrix.gif | Bin 0 -> 552 bytes wnt/media/eq_ecef_coordinate_vector.gif | Bin 0 -> 575 bytes wnt/media/eq_ecef_coordinates.gif | Bin 0 -> 566 bytes wnt/media/eq_ecef_x.gif | Bin 0 -> 840 bytes wnt/media/eq_ecef_y.gif | Bin 0 -> 866 bytes wnt/media/eq_ecef_z.gif | Bin 0 -> 833 bytes wnt/media/eq_initial_state.gif | Bin 0 -> 1795 bytes wnt/media/eq_iterations.gif | Bin 0 -> 3219 bytes wnt/media/eq_lambda_atan.gif | Bin 0 -> 556 bytes wnt/media/eq_p_vector.gif | Bin 0 -> 655 bytes wnt/media/eq_px.gif | Bin 0 -> 1091 bytes wnt/media/eq_py.gif | Bin 0 -> 1143 bytes wnt/media/eq_rotation_matrix.gif | Bin 0 -> 1365 bytes wnt/media/eq_scale_pixel_meter.gif | Bin 0 -> 644 bytes wnt/media/eq_translation_matrix.gif | Bin 0 -> 574 bytes wnt/media/eq_v_a_e.gif | Bin 0 -> 2278 bytes wnt/wntclientapi.md | 4079 +++++++++++------------ 18 files changed, 1863 insertions(+), 2216 deletions(-) create mode 100644 wnt/media/eq_dxyz.gif create mode 100644 wnt/media/eq_e_matrix.gif create mode 100644 wnt/media/eq_ecef_coordinate_vector.gif create mode 100644 wnt/media/eq_ecef_coordinates.gif create mode 100644 wnt/media/eq_ecef_x.gif create mode 100644 wnt/media/eq_ecef_y.gif create mode 100644 wnt/media/eq_ecef_z.gif create mode 100644 wnt/media/eq_initial_state.gif create mode 100644 wnt/media/eq_iterations.gif create mode 100644 wnt/media/eq_lambda_atan.gif create mode 100644 wnt/media/eq_p_vector.gif create mode 100644 wnt/media/eq_px.gif create mode 100644 wnt/media/eq_py.gif create mode 100644 wnt/media/eq_rotation_matrix.gif create mode 100644 wnt/media/eq_scale_pixel_meter.gif create mode 100644 wnt/media/eq_translation_matrix.gif create mode 100644 wnt/media/eq_v_a_e.gif diff --git a/wnt/media/eq_dxyz.gif b/wnt/media/eq_dxyz.gif new file mode 100644 index 0000000000000000000000000000000000000000..fd437f7ffbfcd72f0f77a5b28be750950f061148 GIT binary patch literal 836 zcmV-K1H1f3Nk%w1VRQgP0J8u9|Ns90004-Hh^nfp%*@OX5D+plGThwU?(Xioy1Hg& zW>i#Ec6N4{n3zOFL?R+0A^8LW00000EC2ui0CWID000F35QIsAy*TGbC(&Rij$~~%p3yHsdib#T(jG-uY39C zqT;lxnqV|mSU|%NFdhm8hK8)}@6mD&7Y%V14hj|v2q=Jlju}ltW)=tq2@Q*kkDGrO z2?3b^lNJe2?87+1O)*K2avPRVyHpk;#=f5>E}x8XY94+JMQpf^5yla_v-uk_FDA(fsqnW z;F^B#3<5Mq#MnWF3r9RjxCMa%ZVECga1cNckOuw*7BFCdXXJuB7*M$?QP73~hZYDR z0;0?UN>U9{%3DdIWsVjZdi^*6R1~fY1e#e;xyyvl6RcuhD7u3xAy1(sG-~r^;+$^B zU@k?7gTaFfGq)^=B`ZS%k8%p#`o=3*m=?3!2hJ_*ZRZ*R0|nA@5_1UqaDm@CD<8!mAUY7wXj*_; zp;d#l0o1HvFdtqE13Ds2ayaZmfC3Hnw zB#K1tsKJpeCdtw)T){y}0B#K6z*(|6`J{VrT_p-=SDX@Q3F~9+==2kkhvwYmfcw|Wi zilaK@vO2+N&NL9$)Q#_&yz9K+1c)OFc}80DSX-K$%%`t7jW(+QN2B0s7z7rm)niw1-udx}bm$0q2Ik=^|uC$B1q`2gb{@o0z>T1uk#aav zNXW3JLsMbW0XT3I-^&WyKHgapAl*cnjsz@g_G}NceiXKBDQfMQPYepCRkg|vOT`aJ ze{q$ijh-H}Te&7_Aa&5#b!6XGb1BzY-Em{%Qpv0LPhPliqX3@kXE0yGfAbh1Ajk|| zwRReKQcyt9W2<5WSiXD=%BNa{hvs1r_A2BH3pmC>b~mB{1q(RY3Cv_I009qF4m*vv q_1?sGdH)FQCV&G0$c0)+E`R~;BOx}BU>1V-7zEg}lgO?;0suQ!R_6r( literal 0 HcmV?d00001 diff --git a/wnt/media/eq_ecef_coordinate_vector.gif b/wnt/media/eq_ecef_coordinate_vector.gif new file mode 100644 index 0000000000000000000000000000000000000000..19a594f2b1bf7c3bcd730c6d3570b35ea83a4b78 GIT binary patch literal 575 zcmV-F0>J%8Nk%w1VWR*N0J8u9|Ns90004G&b|NAoW@ctYL`2NY%v4lVy1KgD+}xO$ znC|ZGh=_;~5D+plGODVoA^8LW00000EC2ui0HXjB000F35XecZy*TTAm*QY3O3E^x zXsUw5>V`}EYQhi*I8hjLRR;tC;Xp8{7(7a>0VFsJfx=ADIN%x$+#zd0FnXE7fr1Dm zz>|VZQd>DNjxoisULA}8t_1P1ywMf`eG&@+Uw{D*6b}JOCklfVi57<|35pU40SFTY zoRpY=duDT+fMs|9TPg)-T>(app(?Wq0c5G2a-skN4HX4{Xad3j1PzXhHVu&!zZY#1 zb$|!O8qXFF%gq%JkP5C6aTE*=xifLz)s@`=?(W=q7y}MM4bx~1>>9V(@9-E92w=l5 z3Ihf>K3y1cprJ#D12Z(5Kp-9f2mb@;NI?i8G81{h zq+km}Mt2rEUSJfKtMPHQb4WX^G&964GWS#A93)4*Xh{72r!vF!vXGmx{F5xcsvEKG0dxX N;bDD<61*Y+06Q{v-9i8W literal 0 HcmV?d00001 diff --git a/wnt/media/eq_ecef_coordinates.gif b/wnt/media/eq_ecef_coordinates.gif new file mode 100644 index 0000000000000000000000000000000000000000..0c01f31ef527cd4ac1ab737deb7d5dfa41a82b34 GIT binary patch literal 566 zcmV-60?GYHNk%w1VS)fE0J8u9|Ns90008dp?q+6Y5D*YVL_{(&GE`Jl%*@QHs;Y>H zh`PGEc6N3mA|l+}+?be{A^8LW00000EC2ui0D=H2000F35XecZy*TU5yZ>M)dQLN* zXsW7=vc7N(8-i@#c;+y9?~jZ|V89q01~o*DC1f}U1;lUqDGVqZrg1RT_`CXk>c z0#aDuK@kL8;&?Z(lpF{#FL;6oEaZRy3-eH3QmlF#H51c6R1@7m2yuV^V^bC5ZTq zj8QTXuVgOkV6g_^;>;d3J!tCCz(5fKK7Zl}+JS(`3*cPJtYGAT)vH$}QUJ!atJkk! zfpK8EK_xK^XJ9UAsdPkDs|GA(&7c6Mh5?f(plnN$?S%s5CI~2UkCikFNvUF8%#bez zvSaX-p_4$HN|Ux6%Yclb&shY4CB$P0QHV~>DmYhAFhEEF273V1LM=zN(6h9EoDPvU zx9{J;F=Be~Aa?M63#PR={;!CH-OP*inT0z#v;=pozuPyVnf6l!U?%<^XaRBJnj-)J EJ6ZxozG4gsiBel?VZ}Fg=Z#WAAiJwLS*-1DMmqLSCQ<|hynUzvd94y#uMj^%s z3>b3Rq-L+(KgXs04sm*e0?2T;Gz4`Y1AQfbfiHv;2?1XfhKCM~HF+Qik`)PPhZ&J9 znVX!K6b}RzpArHC1O=%EqBT%l13U|sFM1va2nnqgu@(Xk0SJi{sR9C$0u8E56RCrZ zzY|l`2nc`_)5gNY8OO=b%mmJ;g9FkT4G$Nw1z);=yGYY0^8gCC8I&*g4v7IS2naxs zU@-s;O5sz;pjxd71r!pfwoO2}WeX0_0T2*aL4*Dm5=v0O(BZF$5++L6rXzs92_3T) zU`c_2ftxsUDy(pT9Yg>JIs$0$ssg_b4t74sHsL`I3JN|BvoN5Iv#JzarlcjIr=tlj zhE{NDA?in#SS4JgqZI%Fu0VZWsHJJtQ@3@Ic&$L7?m?S46)4boff3BR0LWI5O3+s^ zZyEwPTNJ>7v%M4gFa?lEaaP8TLr0!W&~jI~6?P1?;2Gb+9uLPdeNEvgh6KL^Yy?2l zY{6|oMFoE*6qSKku{CH0o2a)`;D#v-M^zla8RRr?jDS3$Ui6nUa*8*wvjWQiIT92# z3f@m$2UA|sEFg6=fJHomLapY2>91{?6!+ka5avZuA12iupx*=v@aJE5rYMjD0UJRv z6K5T%$3!PtyD(k`T}(HA0ebfS7~i zZ~y}XFeA%3wIz~CY1KGVCJ1Mqqb8efLUaxxV-8u41muyq$pUiV@g)hnfdW>d6inGc zqmBZAC>)!R1Dg*8dIbAcdPJ!NmKu_XS+?qG1*@J=Yan5j3d5|a S5rP0>nE}gdt{ChZ0RTIJAxRGa literal 0 HcmV?d00001 diff --git a/wnt/media/eq_ecef_y.gif b/wnt/media/eq_ecef_y.gif new file mode 100644 index 0000000000000000000000000000000000000000..9a9ea2d438581ffb2d133875c5cc491b9e6cd8a3 GIT binary patch literal 866 zcmV-o1D*UwNk%w1Vcq}|0J8u9|Ns90007L)%&MxYW@ctoR8;Qn?wFXE5D*Y{c6PeD zy4>8{A|fJ)h=?*WGDJi~A^8LW00000EC2ui0Nwx+000F35XecZy;z!)yZ^vpfMkhn zq-d@y>Zxoz5wf{FBW2KaZ}Fg=Z#WAAiJyi5nGrk?7e#|vQ<|jI$pA{SQWTDb1)I${ z%9lX_b4HumZ?r*7f>Q{Oi`^|baB2q%AO(LG4Fh~2ek_NHABz?O0dy3NjsOpoF@Ycm zniK+Sml>HXp`)aq6ATHFq5=azYD`=c3I{v}o*kSX3ka|Wq7=0i0}KHOg%$$`0|S%; z4F?HJT7Cy~#S&8!4G0K`#2ClP%f{GZx3Ucl8^VGU+m#F#P$<9>1+7TM_|^{MVd%vx zAEt8w(gawz@SFq!{2cHj&`p;uehIp58()8sUeGlxs@GQ{iHNO`V3a;nYa@*6x zVri%jD=@tvpcYKada7<~`H8uf+iJM@)*yQ3Ihk!4%9IdYUPk~31Ul9r^TvqF<0J&g z@jz$=#6aV_PtP@n0HsTL8XERsicOgcRQ@#@0Fn%almrfR^8i$}Y$J*S)(BAnfC5^u zpgi2w6VHKm2{exY4&;!)9<{7@R98%tQePjB=vRRQg-jxVK&M1Om2MU=KuH5)=*SI! z_5q=y1YpE+)B!_EP~#Xk4k!T*O7f6EE8T4M5S0@oDS(e*jYpti2~cAq6Od>@K$*O_ zNCB4sgt?3*EG*zA3=5n&%@^1#gXWj3q2-N}B;10{1Ol8XVj%)#Bo&$rdr7zP6f z2L!7V#T3B8mle~4eY!jc2?-n2pw|Fq5(xtXj1;&82M7soO2r}3Yt8@%0ssHDNkAvz z7?B5r5b(1Qpjjh*01z7c1u$TjWdIbAiSRL&966a}(<9fAQov_P)b~|s3oamC53Wp5 znFKANr`2p1R7in)I5_YK0TVL76D*~?wuU6VDKr6!7W@_fhZO)J0RlHDu#6eOiMHbe z9{zR!4J>)s7bzSBMI#Z0U{hFzBs2+v0uKb>fC3ZBaFk)O@RLaiDqfb#8<%{Uf-cFt zSXdDD+^Er0Qr;*)XM>To-WO7+ktZvYG{I9K7ZfK0pnQU0Rs}eAKv~5 zV7iE484Hy{dcmU;Xp}*wtT5$-sFmad5KRpxlB%W^FeM@et5&jB6|=HR+ogrzYU`{6 L=o$k65dZ)?135tg literal 0 HcmV?d00001 diff --git a/wnt/media/eq_initial_state.gif b/wnt/media/eq_initial_state.gif new file mode 100644 index 0000000000000000000000000000000000000000..94cb737c1640d30605d3b5f40647b6f2042e5d6b GIT binary patch literal 1795 zcmV+e2mJU)Nk%w1VZ{K(0J8u9|Ns9000640s)&e)+}zxln3!f}X729p%*@OX5D<2D zc2rbUL_|a)A|f&}GP=6DA^8LW00000EC2ui0L1{t000F35XecZy*TT=PxxRcj$~<` zAE&Nt>%K5+AaQNqc&_i(!SKMKa7g4R9vi_xVJHHWOs8}@^mPW3g@Sm%0<_ey*ftPs z9u7$%Jw&V7>y%oa%R6A8fZ)?)+S01U5gAXpIK zfCWbsy14)+&Vd7R7Zd_O5MUo52D&5!$cTeRfO!5A(qVAG5ymPF4a@{WXi-eTkPR*{ z90xIjf_4)a7;F|`&%6~UGrarF7Gm#f09T6+bm}u%3Yq{08WZ_IHjdbmol~!nsJgZ5*RW&Do=v;9?c2C>>)y?~ zx9{J;g9{%{ytwh>$dfBy&b+zv=g^}|pH98H_3PNPYv0bjyZ7(l!;2qJzI+a6EzvJ3 zAR2f;Yw!JNwnboRjRFGCbp=QY^T1_~FAb@CdLjoKrP}M)BT|`y@A__6k1j-DMz%V=vP=)|$AfSK) z4Ma%ej%;A!3|L)lc+Uk3pcqw)=;){kC+IW~fRh*CQ~``UY$A#Z?X)$464X=(!+~G; zgC<%Tg#*9=`DDZ+PYi0QMq5jGm_#nS6exfQdfGVwmpY({01{Bd2S8Q5s27M#G|>dr zRB-5}Q6XzgpckSX4t4P+%a+{3ww(|aV4Iw}RQR)7El+;;2jvI!XAr9o~` zYJskfGU%uc@9cppAO5r}!Mnjma^aW-9w6vMF@DO?Min@~Y7hG^+OGy4T(t*h613yZ z153>ZX{6#nMG=iZAaNj^7t4|{Eh`ETQzQ>?)Qg}GMAGXDLy1g}2rD=I>cJU!Aev~3 zRL~9@m}$ZQlrAJ-5CINsp-YC320L`ozGk}17GA8C@&lNmmC6IkLOg>z3$&-!g-TuU zSxOlEd_lH0I1otz8vZonyaWXRDiBW{Lx8dd2@s)AZwYYs00s#;uL6KKEP_8EszFNw zWKW=to)my37SM*2L@NXS0TgXt4YZC+BPtb;IIp6!S;0cg60?Y&4F!%6zMBG@ zC$Yg{vDPldJ0O5ma=T*=4G$__S|>x z{rBL9FaG%Cmv8?0=%=s#`s}yw{`>I9FaP}X*Khy*_~)KI@r*DOS>ozvNy5P;eG4Mu?X$@Zuu}Nzj5C^q>e$s6rRY(1tqn zp%9IzM7AeN(TZC1q8QDnMmNgQj(YT?Aax%i{m{sPW-pR*uw+tnhdxbCvk0J6Lp#q$ z%H$0pl~Q3JGp|yk8%56rv)m;6ZplC~g#>U!%YiFNn9uD6Q<14m+M7%^v1Hb8rwX(H zG($P2$mO7#(tBz6w5csZr3*j+WdS(XH_l3}BVwdmqNMyqqnV2Do$*ZB0OlDL2lT7} lX1nJlo0`3So`6FG`M}(OAW;7OMUb)+q}m4AJUB)G06QZu2Xg=b literal 0 HcmV?d00001 diff --git a/wnt/media/eq_iterations.gif b/wnt/media/eq_iterations.gif new file mode 100644 index 0000000000000000000000000000000000000000..e5ff844a992adce0e5d20ab8f60279300724caee GIT binary patch literal 3219 zcmV;E3~cj9Nk%w1VG#i!0kZ%A|Ns90004-Hh!7AEs;a8Y%*^iY?%dqmGBPrln3z;l zRJyvlW@ctYL_~IWb|NAoA^8LW00000EC2ui01*Ko0RRO45C9>i7=zT!yZ_U6WngKZ zXsWJk>%MSY5ydPR2O zoJq5$&6_xL>fFh*r_Y}R4>YKkM<`LC2@5o!l}0I3qzMTS$|Du(LIsS@V701nfUZ1V zxgs=FfIxz&WyqRED;8ja0YVyJ;o)P++qhZV@@r7;L7OU9K5**9r5p#o75wTA7~pGw zdT`_@XZ6)2pEa0I0jo_g zM>`VYb59OmJeMIi3plXf0Sesk;fW}wsN#yfERX;u1~AB?G-ALd!89XizAx@Nt2?-RsL2`OAAVfrrmQaZY3Sg)gr+vyA4*|NBAi%09 zI4VL7mLjE11qX~1fUWT0paQ2S{`9vW4&XrL0J0Jsn-HBV=qG_{NluCsvjA9&&?_wf z109JUh)c&6-hM#90|6)qf>~F<;^HVo+;By#8{}Hd2zLUI>rYC7L2b1MzX0Hu33EWe zl6i#+z&AD4V88;ZVZmR&4zEfC4w_boRG(gMfanJ5%HTj11~^cUqOIPzbPq4jtg^8!l-3_t_^cF?jjhCB}Ov#h#>BEhR14Ez)2tM*w!+%Vv11+S=fkV*hr z9!Au#4t()Lffa}yf&}DNU<)g`aA0m*0hAMH2Q4=c00Iv1`a;WA7s~GoE?PZJ)kKXm z4aIIS!ptzyPGC7w4H#H7AG;O;iR#A3TmiU13E<_)d^~$V`Fljq!8spr(PEIs2L2UA zN$uJLqg=-U(k-TK0H_p3Ms*JlTV1NN@$bJoyQ+2@4AsnvR$RFYSzpXrPcT z5J18i8HE>TVORdJSmcym9LP{r;YHsJ^+i*3j)O8P#q1ccz9FgQEF8Jl=+Y>gy8v&A z4yo9U8YdRSNT7Bc01{z9$d4UWNB~>ZOW;a&1UNZTNgZ%n)S_0tAZ`gd5!x6>YKKRt z5b<&pIG7+kfeg5YI z_yJ-Hla{!g!ugJAg5a&-cr`T3h-^R(UeW7l67ZJ@Fc2`)q0o04{DcnYD7;SqP&YKN z0mwKYvKI1g2bp4;1ZqYUp8;(VV>neCLnyD(twBvf=vo7WV9&Gx!VPNMr=cFi0fr8t zol>DijQ%!2IDB&Kg%oP&88!F=%=zu38xS27TIJ0U#txAHK-DJ~H>}I~Xn44A<_?y& z!eUi#TUEn`@T`UhY|XS8<-RTWUMjkT<* zR=3L4u6p&WU=1sCKE%7MMTVXqsI;T2-`u6RAibfkrW)d-ngc;z-8n)6r@OnZWb3FwX{ z!-9Y=mNC$HKuwwJfSq`-Tov3f067H5!<3X4@Xi(m3;WFp2ArhV?qW4T%V!|Rv;}Xy zGlI4G%7wS0v(^d#f6mxeYdg>i7Wfc|Y{8q7a#hd{gtrAN8=cDv2sUfvO&)7Q8$yqe zTLvxQDLwuQI3pOX;%=bD##`nIR?4WYHFU)CkeeO2FVP$YdiW*TiqDHj)jZ+0~-ax!jr%)VUV|3X$WHnXhl+m=HsspE5RCVZdLw$nNWfYN zu1pT_yG*H8fzVMv$7#?MjT|6rjLf=p6TES0CH>Rjq|i48>X(&vOf)-Nh-5?ds039n zfge*Eu(j0`$`dnE7P^1{1h~ezNcL2l~jCOX(%tsLf!@z z?R-pSxK`}OB= z+S~s2xX-=rchCFY<6iW606u~YZbI!C0Pc?xk~C%1 z=79zU7;9jGJ#j;Zh9P1G1wPkaV>Sa80V1_ny+ddX=!1ba zI^G8>ML1Hiuq{lXgF2xfw-$w`;aNGO3dECiNT3X-Ry;tkg~5Xw+p=5LF#u80TGO_1 zN8l%Cm<_=|J|d7CrC}cbW(J5dhe%+D$B_(iSRN5~28hy!=Dw~3tCiJth0{-79&qBx4ASc;~2il~^1s$fPNm+}MXB(%H8X_~2J3)p}Vm6%D zk7}0~!vSaG8cB6pfC6mx~br F06S2fq8k7J literal 0 HcmV?d00001 diff --git a/wnt/media/eq_lambda_atan.gif b/wnt/media/eq_lambda_atan.gif new file mode 100644 index 0000000000000000000000000000000000000000..c7e70b60951f042f83ec7b4a0e79ab2d76d60858 GIT binary patch literal 556 zcmV+{0@M9RNk%w1VSWG-0J8u9|Ns90006qWx-v2{+}zw|W@bc0M9j?0A|fJoc6Nw} zi0}s+gFVA^8LW00000EC2ui0Db@x000F35XecZy*TU5>v~<7J&S0b zXbKeSxv-Tm5UolaHSj2fAyf)nE+kM`dc%_e)FMd;0S9G}6j3XO0Ik~5)(}EK12K6p zxf_MFf=Hk@2S$!@P6Q@~?K^X5SQKP?3Th5i2MGghXM+xf5)OkO4-G#TV-s=|2M#a* z4t^#M4+#RI4SE2X6bk{BTuTxSpa8IVOtJtA0#Hnj7OZQjs~`+Q4Q?X400azD#T0iQ z46{eF*4M`u4_9JmUJ~0A4In=bfdC2y7Y0U8=Kw!Yn64db0;+5!6E6sjvJgO@0iYsS3A8EU00KQA z|CJyxzzqm6=nRf6t3wC3glPdBC?KFNCp@SCR9)6;0)Yk^FARJT?EtDi63|k}mP9~; zMt>EQaFF1Ez{d_Em#7>xfnkhGalS#cw|Wi z%%eUgg{)67wsb4k-i`0t%vZXf5D**^ea2mJxJ=TTKd7@LRU)Uh>x02aC=`S&7PovX z0tyL%VXBTVMZ?0-mpQ1s;3WlNRC;?o76oY%XaEmjTWmmtg%(W#3la|l01GS! z3NMtBlN3t^0SOWgNCT*FqN9pe3Z4oAtrK;Iuo+997Apk+2)7e%uuBbk4+6CcETOx+ zNC^Q^ug5+J4gmz0WY?p{PvDc{V$rTs=7sBn=;==FZ}NN;0w4nU1O?<)>Q@E+NI-CE z4?Sr>5=l4%Y0N=g0}Dm>J(5SSp_+C?3l#hGvY-f4v0z)%l2 zb&BPAf{-Oln$iro1eMf`Gtba9G1W@d!j1qma?QG}K-^tTW___WVG95Q!6HdjT)~$G z0W9)CTfDbI(FzF&C>XG{GUcfhs9~6)*E8iJ+PJBdkf38Nc%R#SX~;PC(R!ajCwUm} zHp1MzC)@s)Tla-63K(>TeOeTP!~pF69*)89gju+$!$wfLc5@8WZkbx`eX$g}6D2Y? zFA2Q__v@ufp_c6|#P1rmKIrbYc$KOWU_Nypdl@`8L0bdL_X=_ZEGHa(yZJ_3Z~jRb p-#fvTC*K1Jbf{Db9wuOlg}a4NO$`m0NTLx7wCExZF1{E606QwC4y6D9 literal 0 HcmV?d00001 diff --git a/wnt/media/eq_px.gif b/wnt/media/eq_px.gif new file mode 100644 index 0000000000000000000000000000000000000000..f2e43f94512f9c16a3f7a37f4f03c06531f68a6c GIT binary patch literal 1091 zcmV-J1ibr4Nk%w1VNL-O0J8u9|Ns9000640s)&e)+}zxln3!f}X729p%*@OX5D<2D zc2rbUL_|a)A|f&}GP=6DA^8LW00000EC2ui08RlC000F35XecZy*PtYwEtizj$~<` zXsWKovA(bY&l9l_bWYp2?*9^=<{$$aEd#{ygkU6=&`z&In0hf=|2MkeJBh)gA@&hBz%V+iF1YHDXXoo6`2CE5(omFY9hNK zy}zfaCd958$jTE7*$;{UpB31~6tr(W0tW$b23wvK2jJ}zt8fJjssa4`<^T-fEU*L) z0D%O85?H$s&B8na^~yBBr|*P-e*P{5lrV5Z2ZjC|6)cJr;$g&l67pHZ7_q`e03A~b zKrldoxd0a~V*K|&Bmf0l5F9}8Nr9yg1_ml!y1-`z0u3nKSp_Pp1fvuPR1C7!f&-T0 zQnG;wM-YGqVR@0fFx4u60&cO^*osL(rwU&&rY$gbL5DjKCnQ)4qM?VjRVT>hIw9GB zyA$&E+uPUNrV9;R;01fZt^~~z1{`God57Bx2AnpX@baw!x3x}JV9C!yHVFyBEw+$U zsRIW~ol;2M&1vh{pW&^xKpSU;+u{t#Mc~{+?}5LAgCHJ~H67#H!!mY~51FfwY4KM`EW4YF614NdCr8SP=CSMA!xS;kI7@{aN(@8+=_L zU@K2SxXd^Wm^Hvy&@A{tgW^0GVGR7mP!(AYU??Q^J1VYuh034>RAg6@Bjh^EcD`06+BxgYnovTieI&a zgXvF5E}0aRf&#q)*sEDBwY)hJ z2>|~jurCA`9OMWHD-0}D&|3Me2oJpRM!^Y+V_#P!zzZ)L{+?9uaa5b)I9BO&_mt zW)=nnpvhTfpDjrW52Q^1ME%5>0ufh@-A3DH;}D8nNdrMQ4Z0f8_YoYdZTJyyM11%e JE#wdZ06T3ryU_pu literal 0 HcmV?d00001 diff --git a/wnt/media/eq_py.gif b/wnt/media/eq_py.gif new file mode 100644 index 0000000000000000000000000000000000000000..54596d53185e207f6a0f9a35348773eed1873a69 GIT binary patch literal 1143 zcmV--1c>`bNk%w1VNC%P0J8u9|Ns9000640s)&e)+}zxln3!f}X729p%*@OX5D<2D zc2rbUL_|a)A|f&}GP=6DA^8LW00000EC2ui08IfD000F35XecZy*PtYwEtizj$~<` zXsW8kvA(bY&l0f^bWYp2?*9{B<{$$aEd#{SgkU6=&`z%In0hn={*AieJBh)gA)ygC47e(iFkVl)B+0|akH zKvWY2nj8fS52Oo9Cjt!t33Nz-0-yo~3J~{e-{Eu7`UN>!j1k4NHp~DFycK4`SxA>2T1fvr&Dey#~q6G&! z$Dw2cU;!LK03L|dFjA_-suQrb?Y9oYXCk_IB^iipG#2A96(^$wr^jc zZoNXY3!9;Nv1=@C5%G1pd&&18neBLv50U^^}0jtmObp7qnFYfYn99 z&VU6vK;T$kDM$fCJrG4f185CER$(Pj2;hYhY-pK5v4QfgdR))}%GB*4Yu1o?bAON!!0zeZq z9N<+6Nx)cT9}1Jua}PuR5a%Ktt1xt^1@!yFi7a4f!Itp)`{rc>* J*A99F06W@f)UyBp literal 0 HcmV?d00001 diff --git a/wnt/media/eq_rotation_matrix.gif b/wnt/media/eq_rotation_matrix.gif new file mode 100644 index 0000000000000000000000000000000000000000..85b6ebaa02f2356902df36edae43fcbd9120b2a0 GIT binary patch literal 1365 zcmV-b1*-Z-Nk%w1VXy#00J8u9|Ns90004G&b|NAoW@ctoR8;Qn?nFdHs;a8Y%*?vF zx)2Z$GBPrln3#x&h}_)VA^8LW00000EC2ui0I&c<000F35XecZy%>khv;SZyj$|nf z+?JT^6*x$Yv~+FXnIa>>ikrQka7YCDil88J$wVrfnj>^dEj_D~D|XAJXtCd}m>MQa z$7pDIs%3xKN=(h!Wmu0#=IzMF9R3FG{3ffPn#nVze~UMN`O zqQcwn}OP6bi5iDSHEoCgI2UJwK=x(R6q4;pbuSL8H7H>e12KFB$Z?HZmt*S^i$ z%5EaLdka7Gdr0u%$TJ)VUOc(;#I&DFAFL+K(_Vn=#zfy z7#J}Q?&)o734jz5d=K~IN1vb|fcXLoIR0^+erSBh6aWM)FyIGmyfKI$3w|I7AB5b2 z#DsHH_y-MFFi-#jb1+cZc@wPii7QPNbxKE@m|$Wnp~$i#Br}rm;w~|&hzca8uy@vv z5)cqj1>+T9xvMf|G|q*-%u|ObNh0B49}gGf{d;PfPYx zz@!BIQP6-*MKItOg8rmqPd+X^*3Ue4PJ-u6e|klNJX99+55 z**X*jx=s-62(w9Mi3JZc+Z6y~8)`Ddg9Tb3DLbnq< z6;`;omSvCt3^{)g0dxeb!`Qf&p zWR&f@1jNx$%ml@l0TU&&N)4#m2GqF5#K!>$K(dlToJ`4z=4BC~!vx0HFo!S43`Wf@ z%xtq6`|UiP&MW}!bEG&2UG&hp^^A0KLi@J#b4`;F_0vC0O&rxsAMG^O*=a4c*Ie6R zbqEdaks*XjVAw|?7dl8G+Bt)Lb%~6yg5y_6+z1NZMCgs;wMHl{=E8w(JPV7YRI|&I z8W+_gjXNr?OqPxFNQ>qEp+c7u9)y0`XBGuDzzqwXgPA6p4VZ~C2&I4CO+l!uw}qq= zaB8VNnR+xSsht88=z$`P+EA(bs`H4VLu%e}1;zGqtdyzhNo=pizC=>0pq9|QOI(#C zoA`rq^xW2bVp%01u49iXS8U5Ou*E~_loe278u>VOz zEaD;o0VOaPvV3bq02o^m2BffG2yh4$L|9+ahA2sNFnm>jPsR!-vDRcp7#2gq2!pZ0 zjR9$SEr3mVUJ@GAG(m=wNx|xVfWwu=2828dTW=)DAOxf)HA3XV5g(8MBH||na7yA7 X763*4fxrM*%%TSrv5-YAMgRaihu2Sb literal 0 HcmV?d00001 diff --git a/wnt/media/eq_scale_pixel_meter.gif b/wnt/media/eq_scale_pixel_meter.gif new file mode 100644 index 0000000000000000000000000000000000000000..b64c6ad11ad19274b2e17d66bc12757805c45773 GIT binary patch literal 644 zcmV-~0(<>ONk%w1VXFWU0J8u9|Ns9000640s+gFV+}zx{y1I6Dc8G|GW@cvY?(WRY z%tS;)R8&+D5D+3FA~G^EA^8LW00000EC2ui0IL8I000F35XecZy*TTg$>Crqj$~<` zfY6{uGoWzXDRONl1nlH?k1j8ta5zb6~+X=DGosc z3lzh(!gB!CiN`O=yJiU(2n^)q=E@lg2~`sYhycxJV^+Hl5(x(3t`!F080zeHMUiwb zpDh6nHXKYSVE{t_?%LS{fG-??B@zo7duBmFfB^mr8X-9lMVOg>79vt;fWVDKk`+9H z6nO!r$y6<~SOkCoU51`c0yT-V6CPsiS}x$u@e@+x+Tt>U2h-)SVV{^A>6iO(C(yokpK>1b5m*1+gC6J zeE~qklQ0>;0DHDZ4GuTUnC8duB6qc@zzh+OJRUSM0Ov!26$3;oNDX&@y2x`DkT%^B ztZE4lYSXw3f_TGez&?NqKEXBs2Q-!ow>*&o88=N9Jz`QiDKP{B6bLXN04~0w5Cp))rgAOYH!-V_+ffnW#S-9Nk%w1VMhQ%0J8u9|Ns90005Ynm=F*UR8&-Uc6RRW?z+0V+}zx%s;bP) z%rY`Eh=_o^*}QwruaFzWco31y~~rj{xIIiR3X$&t?%fl_Hf1LE$AJASzL7j|w<^ z5rfu%92S#|t@0q#cGJm|0^x3V;w1|Le0@281_57X7IlPRR0nec0TK#{6pW1VuNtVZv#ox&w6UkWueF-GvQ@&Qxy6gV$p8Wa1O){H z1JDH1s=zk@1O^k<5(k2&*h!Uf00;r2lsp5(?*?lLue`yKd}M7;x0Jz)~K83Pw&SNufalWJ(^y zVX&_uih>gi6mTGbK{yK%D+;}c3rxKRL>P$H8wCMicl8}eY_Q)#hUp?sOzy2= zcWwzmX59EkAqvcdrJm+cr> M&t3!j_7MO8J1s%;@&Et; literal 0 HcmV?d00001 diff --git a/wnt/media/eq_v_a_e.gif b/wnt/media/eq_v_a_e.gif new file mode 100644 index 0000000000000000000000000000000000000000..bd184311dc578423713d808e2f25172aaaccd96f GIT binary patch literal 2278 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 A761SM literal 0 HcmV?d00001 diff --git a/wnt/wntclientapi.md b/wnt/wntclientapi.md index 3294956..53930b1 100644 --- a/wnt/wntclientapi.md +++ b/wnt/wntclientapi.md @@ -10,6 +10,9 @@ This document describes the Wirepas Network Tool backend API. > Public --> + + + -- [Introduction](#introduction) -- [Backend interface components](#backend-interface-components) - - [Authentication service](#authentication-service) - - [Metadata service](#metadata-service) - - [Real time situation service](#real-time-situation-service) - - [Time series service](#time-series-service) - - [Protocol version](#protocol-version) -- [Authentication service messages](#authentication-service-messages) - - [Login](#login) - - [Get users](#get-users) - - [Create user](#create-user) - - [Update user](#update-user) - - [Delete user](#delete-user) -- [Metadata service messages](#metadata-service-messages) - - [Get buildings](#get-buildings) - - [Create building](#create-building) - - [Update building](#update-building) - - [Delete building](#delete-building) - - [Get building's floor plans](#get-buildings-floor-plans) - - [Create floor plan](#create-floor-plan) - - [Update floor plan](#update-floor-plan) - - [Delete floor plan](#delete-floor-plan) - - [Get floor plan image data](#get-floor-plan-image-data) - - [Set floor plan image data](#set-floor-plan-image-data) - - [Get areas](#get-areas) - - [Create area](#create-area) - - [Update area](#update-area) - - [Delete area](#delete-area) - - [Get networks](#get-networks) - - [Create network](#create-network) - - [Update network](#update-network) - - [Delete network](#delete-network) - - [Add node to floor plan](#add-node-to-floor-plan) - - [Remove node from floor plan](#remove-node-from-floor-plan) - - [Set node metadata](#set-node-metadata) - - [Delete node](#delete-node) - - [Set network data](#set-network-data) - - [Send data message](#send-data-message) - - [Get scratchpad status](#get-scratchpad-status) - - [Get components information](#get-components-information) -- [Real time situation service authentication](#real-time-situation-service-authentication) -- [Time series service data](#time-series-service-data) - - [Example CURL command to query data](#example-curl-command-to-query-data) - - [Example column names decoding](#example-column-names-decoding) -- [Basic data flow and real time situation data](#basic-data-flow-and-real-time-situation-data) - - [Basic data flow to get continuous data](#basic-data-flow-to-get-continuous-data) - - [Real time situation data](#real-time-situation-data) -- [Coordinate conversions](#coordinate-conversions) - - [Introduction](#introduction-1) - - [WGS84 to pixels](#wgs84-to-pixels) - - [Pixels to WGS84](#pixels-to-wgs84) - - [WGS84 to ECEF conversion](#wgs84-to-ecef-conversion) - - [ECEF to WGS84 conversion](#ecef-to-wgs84-conversion) -- [References](#references) +- [Introduction](#introduction) +- [Backend interface components](#backend-interface-components) + - [Authentication service](#authentication-service) + - [Metadata service](#metadata-service) + - [Real time situation service](#real-time-situation-service) + - [Time series service](#time-series-service) + - [Protocol version](#protocol-version) +- [Authentication service messages](#authentication-service-messages) + - [Login](#login) + - [Get users](#get-users) + - [Create user](#create-user) + - [Update user](#update-user) + - [Delete user](#delete-user) +- [Metadata service messages](#metadata-service-messages) + - [Get buildings](#get-buildings) + - [Create building](#create-building) + - [Update building](#update-building) + - [Delete building](#delete-building) + - [Get building's floor plans](#get-buildings-floor-plans) +- [Create floor plan](#create-floor-plan) + - [Update floor plan](#update-floor-plan) + - [Delete floor plan](#delete-floor-plan) + - [Get floor plan image data](#get-floor-plan-image-data) + - [Set floor plan image data](#set-floor-plan-image-data) + - [Get areas](#get-areas) + - [Create area](#create-area) + - [Update area](#update-area) + - [Delete area](#delete-area) + - [Get networks](#get-networks) + - [Create network](#create-network) + - [Update network](#update-network) + - [Delete network](#delete-network) + - [Add node to floor plan](#add-node-to-floor-plan) + - [Remove node from floor plan](#remove-node-from-floor-plan) + - [Set node metadata](#set-node-metadata) + - [Delete node](#delete-node) + - [Set network data](#set-network-data) + - [Send data message](#send-data-message) + - [Get scratchpad status](#get-scratchpad-status) + - [Get components information](#get-components-information) +- [Real time situation service authentication](#real-time-situation-service-authentication) +- [Time series service data](#time-series-service-data) + - [Example CURL command to query data](#example-curl-command-to-query-data) + - [Example column names decoding](#example-column-names-decoding) +- [Basic data flow and real time situation data](#basic-data-flow-and-real-time-situation-data) + - [Basic data flow to get continuous data](#basic-data-flow-to-get-continuous-data) + - [Real time situation data](#real-time-situation-data) +- [Coordinate conversions](#coordinate-conversions) + - [WGS84 to pixels](#wgs84-to-pixels) + - [Pixels to WGS84](#pixels-to-wgs84) + - [WGS84 to ECEF conversion](#wgs84-to-ecef-conversion) + - [ECEF to WGS84 conversion](#ecef-to-wgs84-conversion) +- [References](#references) -# Introduction + + +## Introduction This document describes the Wirepas Network Tool (WNT) server backend API and is intended for Wirepas licensee to implement own services on @@ -151,26 +155,23 @@ data encoding. This document is compliant with WNT backend version 2.0. -# Backend interface components +## Backend interface components Backend client interface consists of four individual components which all use secure versions of the protocols (WSS, HTTPS). Figure 1 Simplified architecture -![](./media/image2.png){width="6.820178258967629in" -height="2.9400590551181103in"} +![](./media/image2.png) Table 1: Components - Component Protocol Port Data encoding - -* * * - - Authentication Web socket 8813 JSON - Metadata Web socket 8812 JSON - Real time situation Web socket 8811 Protocol Buffers \* - Time series HTTP 8886 JSON \*\* +| Component | Protocol | Port | Data encoding | +| ---------------------| ------------| ------| ---------------------| +| Authentication | Web socket | 8813 | JSON | +| Metadata | Web socket | 8812 | JSON | +| Real time situation | Web socket | 8811 | Protocol Buffers \* | +| Time series | HTTP | 8886 | JSON \*\* | \* Authentication is done by using JSON @@ -179,7 +180,7 @@ Table 1: Components The MQTT connection between the gateway and WNT backend is described in document: WP-RM-128 - API between a Gateway and Wirepas Backends. -## Authentication service +### Authentication service The service handles user management and access to metadata and real time situation service. The time series service share the same credentials as @@ -189,26 +190,22 @@ service. Credentials can only be changed via authentication service. Other clients are notified about the users related changes (except password changes) via real time situation connection. -## Metadata service +### Metadata service Metadata service provides access to: - node metadata - - buildings - - floor plans - - areas - - network information - - downlink communication with the nodes The clients are notified about the metadata changes via real time situation connection. -## Real time situation service +### Real time situation service + The real time information of all the nodes and changes to metadata are available from the real time situation service. After the connection is @@ -217,13 +214,15 @@ real time information via the connection. When the service receives new information from the nodes it forwards only the data that has changed to the client connections. -## Time series service +### Time series service + Time series service contains diagnostics - and auxiliary data. It is implemented as direct access to the Influx database version 1.5. For more information please see chapter 7. -## Protocol version +### Protocol version + Authentication, metadata and real time situation (authentication) messages contains protocol version field. This field needs to match the @@ -232,17 +231,14 @@ backend cannot handle messages of older protocol version. Table 2: Protocol versions - Protocol version Backend version - -* * * +| Protocol version | Backend version | +| :------------------:| :-----------------: | +| 2 | 1.6, 1.7 | +| 3 | 2.0 | - 2 1.6, 1.7 - 3 2.0 -**\\ -** +## Authentication service messages -# Authentication service messages Authentication service works in request / response principle. User is automatically logged out when the connection is closed, and session id @@ -252,12 +248,10 @@ connection is closed. Access to methods are depending on user's role. Table 3: Roles - Role Number - -* * * - - Administrator 1 - Operator 2 +|Role | Number | +|---------------| --------| +|Administrator | 1 | +|Operator | 2 | Simple rule between the roles is that operator can only query data, but administrator can also make changes. @@ -267,19 +261,17 @@ version and distinct type field per message type. Table 4: Message types - Message Type Role - -* * * - - Login 1 All - Get users 11 Administrator - Create user 12 Administrator - Update user 13 Administrator - Delete user 14 Administrator +| Message | Type | Role | +| ------------- | ------ | ---------------| +| Login | 1 | All | +| Get users | 11 | Administrator | +| Create user | 12 | Administrator | +| Update user | 13 | Administrator | +| Delete user | 14 | Administrator | Due to possibility that the information about the change comes earlier from the real time situation connection than the response from the -authentication service, some methods contain an *originator_token* +authentication service, some methods contain an *originator\_token* field which can be used to check if the change was originated from the current client. The token can be e.g. UUID (version 1 / 4) as string. @@ -288,244 +280,219 @@ error occurred. Table 5: Result codes - Message Code - -* * * - - Ok 1 - Generic error 2 - Invalid credentials while logging in 3 - Wrong protocol version 4 - User does not have rights to perform the action 5 - Invalid user id 6 - User which was tried to create already exists 7 - Received message was invalid 8 - Invalid session id 9 +|Message | Code | +|-------------------------------------------------| ------| +|Ok | 1 | +|Generic error | 2 | +|Invalid credentials while logging in | 3 | +|Wrong protocol version | 4 | +|User does not have rights to perform the action | 5 | +|Invalid user id | 6 | +|User which was tried to create already exists | 7 | +|Received message was invalid | 8 | +|Invalid session id | 9 | User information fields have minimum and maximum lengths in characters. Table 6: Minimum and maximum lengths - Field Minimum Maximum - -* * * - - username 1 63 - password 6 255 - full_name 1 255 +|Field | Minimum | Maximum | +|------------| ---------| ---------| +|username | 1 | 63 | +|password | 6 | 255 | +|full\_name | 1 | 255 | -## Login +### Login *Login* message is used to login to the services and it returns a session id that is used to authenticate to the metadata and real time situation services. -Table 7: Login message - -\+----------------------------------+-------------------------------------+ -| Request | Response | -\+==================================+=====================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"username\\": \\"\\<user name>\\", | \\"role\\": 1, | -\| \| \| -| \\"password\\": \\"\\<password>\\" | \\"session_id\\": \\"\\<session id>\\" | -\| \| \| -| }, | }, | -\| \| \| -| \\"type\\": 1, | \\"result\\": 1, | -\| \| \| -| \\"version\\": 3 | \\"type\\": 1, | -\| \| \| -| } | \\"version\\": 3 | -\| \| \| -| | } | -\+----------------------------------+-------------------------------------+ - -## Get users +Login example request: + +```json +{ + "data": { + "username": "", + "password": "" + }, + "type": 1, + "version": 3 +} +``` + +Login example response: + +```json +{ + "data": { + "role": 1, + "session_id": "" + }, + "result": 1, + "type": 1, + "version": 3 +} +``` + +### Get users Message returns list of users and users' information. -Table 8:Get users message - -\+--------------------------------------+-------------------------------+ -| Request | Example response | -\+======================================+===============================+ -| { | { | -\| \| \| -| \\"data\\": {}, | \\"data\\": { | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | \\"users\\": \[ \| -\| \| \| -| \\"type\\": 11, | { | -\| \| \| -| \\"version\\": 3 | \\"full_name\\": \\"John Doe\\", | -\| \| \| -| } | \\"role\\": 2, | -\| \| \| -| | \\"username\\": \\"johndoe\\" | -\| \| \| -| | }, | -\| \| \| -| | { | -\| \| \| -| | \\"full_name\\": \\"Jane Doe\\", | -\| \| \| -| | \\"role\\": 1, | -\| \| \| -| | \\"username\\": \\"janedoe\\" | -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | }, | -\| \| \| -| | \\"result\\": 1, | -\| \| \| -| | \\"type\\": 11, | -\| \| \| -| | \\"version\\": 3 | -\| \| \| -| | } | -\+--------------------------------------+-------------------------------+ - -## Create user +Get users example request: + +```json +{ + "data": {}, + "session_id": "", + "type": 11, + "version": 3 +} +``` + +Get users example response: + +```json +{ + "data": { + "users": [ + { + "full_name": "John Doe", + "role": 2, + "username": "johndoe" + }, + { + "full_name": "Jane Doe", + "role": 1, + "username": "janedoe" + } + ] + }, + "result": 1, + "type": 11, + "version": 3 +} +``` + +### Create user New user can be created with *create user* message. Only a single user can be created with the message although *users* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_users* message. - -Table 9: Create user message - -\+---------------------------------------+----------------+ -| Request | Response | -\+=======================================+================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": {}, | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\", | \\"result\\": 1, | -\| \| \| -| \\"users\\": \[ | \\"type\\": 12, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"full_name\\": \\"\\<first last>\\", | } | -\| \| \| -| \\"password\\": \\"\\<password>\\", | | -\| \| \| -| \\"role\\": \\<role>, | | -\| \| \| -| \\"username\\": \\"\\<user name>\\" | | -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 12, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+---------------------------------------+----------------+ - -## Update user +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_users* message. + +Create user example request: + +```json +{ + "data": { + "originator_token": "", + "users": [ + { + "full_name": "", + "password": "", + "role": , + "username": "" + } + ] + }, + "session_id": "", + "type": 12, + "version": 3 +} +``` + +Create user example response: + +```json +{ + "data": {}, + "result": 1, + "type": 12, + "version": 3 +} +``` + +### Update user User can be updated with *update user* message. Only a single user can be updated with the message although *users* field is an array. In user data only *username* field is required. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_users* message. - -Table 10: Update user message - -\+-----------------------------------------+----------------+ -| Request | Response | -\+=========================================+================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": {}, | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\", | \\"result\\": 1, | -\| \| \| -| \\"users\\": \[ | \\"type\\": 13, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"full_name\\": \\"\\<new first last>\\", | } | -\| \| \| -| \\"password\\": \\"\\<new password>\\", | | -\| \| \| -| \\"role\\": \\<new role>, | | -\| \| \| -| \\"username\\": \\"\\<new user name>\\" | | -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 13, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+-----------------------------------------+----------------+ - -## Delete user +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_users* message. + +Update user example request: + +```json +{ + "data": { + "originator_token": "", + "users": [ + { + "full_name": "", + "password": "", + "role": , + "username": "" + } + ] + }, + "session_id": "", + "type": 13, + "version": 3 +} +``` + +Update user example response: + +```json +{ + "data": {}, + "result": 1, + "type": 13, + "version": 3 +} +``` + +### Delete user User can be deleted with *delete user* message. Only a single user can be deleted with the message although *users* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> deleted_users* message. - -Table 11: Delete user message - -\+---------------------------------------+----------------+ -| Request | Response | -\+=======================================+================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": {}, | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\", | \\"result\\": 1, | -\| \| \| -| \\"users\\": \[ | \\"type\\": 14, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"username\\": \\"\\<user name>\\" | } | -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 14, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+---------------------------------------+----------------+ - -# Metadata service messages +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_users* message. + +Delete user request example: + +```json +{ + "data": { + "originator_token": "", + "users": [ + { + "username": "" + } + ] + }, + "session_id": "", + "type": 14, + "version": 3 +} +``` + +Delete user response example: + +```json +{ + "data": {}, + "result": 1, + "type": 14, + "version": 3 +} +``` + +## Metadata service messages Metadata service works in request / response principle. All the messages require *session id*, which can be get from authentication service. @@ -535,45 +502,43 @@ version and distinct *type* field per message type. Table 12: Message types - Message Type Role - -* * * - - Get buildings 1001 All - Create building 1002 Administrator - Update building 1003 Administrator - Delete building 1004 Administrator - Get building's floor plans 1011 All - Create floor plan 1012 Administrator - Update floor plan 1013 Administrator - Delete floor plan 1014 Administrator - Get floor plan image data 1021 All - Set floor plan image data 1022 Administrator - Get map areas 1031 All - Create map area 1032 Administrator - Update map area 1033 Administrator - Delete map area 1034 Administrator - Get networks 1041 All - Create network 1042 Administrator - Update network 1043 Administrator - Delete network 1044 Administrator - Add node to floor plan 1051 Administrator - Remove node from floor plan 1052 Administrator - Set node metadata 1061 Administrator - Change node id and / or network id \* 1062 Administrator - Delete node 1063 Administrator - Set network data 1071 Administrator - Send Remote API request \* 1072 Administrator - Send data message 1073 Administrator - Get scratchpad status 1074 Administrator - Load scratchpad \* 1075 Administrator - Get components information 1081 All - -\* Message will be documented later +| Message | Type | Role | +| --------------------------------------- | ------| ---------------| +| Get buildings | 1001 | All | +| Create building | 1002 | Administrator | +| Update building | 1003 | Administrator | +| Delete building | 1004 | Administrator | +| Get building's floor plans | 1011 | All | +| Create floor plan | 1012 | Administrator | +| Update floor plan | 1013 | Administrator | +| Delete floor plan | 1014 | Administrator | +| Get floor plan image data | 1021 | All | +| Set floor plan image data | 1022 | Administrator | +| Get map areas | 1031 | All | +| Create map area | 1032 | Administrator | +| Update map area | 1033 | Administrator | +| Delete map area | 1034 | Administrator | +| Get networks | 1041 | All | +| Create network | 1042 | Administrator | +| Update network | 1043 | Administrator | +| Delete network | 1044 | Administrator | +| Add node to floor plan | 1051 | Administrator | +| Remove node from floor plan | 1052 | Administrator | +| Set node metadata | 1061 | Administrator | +| Change node id and / or network id \* | 1062 | Administrator | +| Delete node | 1063 | Administrator | +| Set network data | 1071 | Administrator | +| Send Remote API request \* | 1072 | Administrator | +| Send data message | 1073 | Administrator | +| Get scratchpad status | 1074 | Administrator | +| Load scratchpad \* | 1075 | Administrator | +| Get components information | 1081 | All | + +\* Message will be documented later (add link instead) Due to possibility that the information about the change comes earlier from the real time situation connection than the response from the -metadata service, some methods contain an *originator_token* field +metadata service, some methods contain an *originator\_token* field which can be used to check if the change was originated from the current client. The token can be e.g. UUID (version 1 / 4) as string. @@ -582,355 +547,283 @@ error occurred. Table 13: Result codes - Message Code +|Message | Code | +|-------------------------------------------------| ------| +|Ok | 1 | +|Generic error | 2 | +|Wrong protocol version | 4 | +|User does not have rights to perform the action | 5 | +|Invalid id (building, floor plan, area etc.) | 6 | +|Received message was invalid | 8 | +|Invalid session id | 9 | -* * * - - Ok 1 - Generic error 2 - Wrong protocol version 4 - User does not have rights to perform the action 5 - Invalid id (building, floor plan, area etc.) 6 - Received message was invalid 8 - Invalid session id 9 - -## Get buildings +### Get buildings The message returns name and id of all the buildings. -Table 14: Get buildings message - -\+-----------------------------------+-----------------------------------+ -| Request | Example response | -\+===================================+===================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"originator_token\\": | \\"buildings\\": \[ \| -| \\"\\<token>\\" | | -| | { | -| }, | | -| | \\"id\\": | -| \\"session_id\\": \\"\\<session | \\"c6ddb790-24e4-6449-075a-a6638f1 | -| id>\\", | 47812\\", | -\| \| \| -| \\"type\\": 1001, | \\"name\\": \\"Main building\\" | -\| \| \| -| \\"version\\": 3 | }, | -\| \| \| -| } | { | -\| \| \| -| | \\"id\\": | -| | \\"e936d185-42db-ff18-57b5-4deb02d | -| | 05c58\\", | -\| \| \| -| | \\"name\\": \\"Other building\\" | -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | }, | -\| \| \| -| | \\"result\\": 1, | -\| \| \| -| | \\"type\\": 1001, | -\| \| \| -| | \\"version\\": 3 | -\| \| \| -| | } | -\+-----------------------------------+-----------------------------------+ - -## Create building +Get buildings example request: + +```json +{ + "data": { + "originator_token": "" + }, + "session_id": "", + "type": 1001, + "version": 3 +} +``` + +Get buildings example response: + +```json +{ + "data": { + "buildings": [ + { + "id": "c6ddb790-24e4-6449-075a-a6638f147812", + "name": "Main building" + }, + { + "id": "e936d185-42db-ff18-57b5-4deb02d05c58", + "name": "Other building" + } + ] + }, + "result": 1, + "type": 1001, + "version": 3 +} +``` + +### Create building New building can be created with *create building* message which returns building id that can be used later to reference the building. Only a single building can be created with the message although *buildings* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_buildings* message. - -Table 15: Create building message - -\+--------------------------------------+-----------------------------+ -| Request | Response | -\+======================================+=============================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"buildings\\": \[ | \\"buildings\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"name\\": \\"\\<building name>\\" | \\"id\\": \\"\\<building id>\\" | -\| \| \| -| } | } | -\| \| \| -\| ], | ] \| -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | }, | -\| \| \| -| }, | \\"result\\": 1, | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | \\"type\\": 1002, | -\| \| \| -| \\"type\\": 1002, | \\"version\\": 3 | -\| \| \| -| \\"version\\": 3 | } | -\| \| \| -| } | | -\+--------------------------------------+-----------------------------+ - -## Update building +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_buildings* message. + +Create building example request: + +```json +{ + "data": { + "buildings": [ + { + "name": "" + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1002, + "version": 3 +} +``` + +Create building example response: + +```json +{ + "data": { + "buildings": [ + { + "id": "" + } + ] + }, + "result": 1, + "type": 1002, + "version": 3 +} +``` + +### Update building Building name can be updated with *update building* message. Only a single building can be updated with the message although *buildings* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_buildings* message. - -Table 16: Update building message - -\+-----------------------------------------+-----------------+ -| Request | Response | -\+=========================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": {}, | -\| \| \| -| \\"buildings\\": \[ | \\"result\\": 1, | -\| \| \| -| { | \\"type\\": 1003, | -\| \| \| -| \\"id\\": \\"\\<building id>\\", | \\"version\\": 3 | -\| \| \| -| \\"name\\": \\"\\<updated building name>\\" | } | -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1003, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+-----------------------------------------+-----------------+ - -## Delete building +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_buildings* message. + +Update building example request: + +```json +{ + "data": { + "buildings": [ + { + "id": "", + "name": "" + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1003, + "version": 3 +} +``` + +Update building example response: + +```json +{ + "data": {}, + "result": 1, + "type": 1003, + "version": 3 +} +``` + +### Delete building Building can be deleted with *delete building* message. Only a single building can be deleted with the message although *buildings* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> deleted_buildings* message. - -Table 17: Delete building message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"buildings\\": \[ | \\"type\\": 1004, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": \\"\\<building id>\\" | } | -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1004, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Get building's floor plans +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_buildings* message. + +Delete building request example: + +```json +{ + "data": { + "buildings": [ + { + "id": "" + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1004, + "version": 3 +} +``` + +Delete building response example: + +```json +{ + "result": 1, + "type": 1004, + "version": 3 +} +``` + +### Get building's floor plans The message returns information about the floor plans in a building. Only a single building's floor plans can be fetched with the message although *buildings* field is an array. -The *rotation_matrix*, *offset_ecef_to_local, -offset_local_to_ecef* and *pixels_per_meter* fields are used for +The *rotation\_matrix*, *offset\_ecef\_to\_local, +offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for mapping between WGS84 and pixel coordinates. For more information please see chapter 9. -Table 18: Get building's floor plans message - -\+-----------------------------------+-----------------------------------+ -| Request | Example response (only one floor | -| | plan) | -\+===================================+===================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"buildings\\": \[ | \\"buildings\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"id\\": \\"\\<building id>\\" | \\"id\\": | -| | \\"3b326217-676d-f547-019b-6d8e0e1 | -| } | fc5dc\\", | -\| \| \| -\| ], | \\"floor_plans\\": \[ \| -\| \| \| -| \\"originator_token\\": | { | -| \\"\\<token>\\" | | -| | \\"id\\": | -| }, | \\"1e19239c-bcd2-829a-44a1-900e083 | -| | f0bfe\\", | -| \\"session_id\\": \\"\\<session | | -| id>\\", | \\"name\\": \\"New floor plan\\", | -\| \| \| -| \\"type\\": 1011, | \\"level\\": 0, | -\| \| \| -| \\"version\\": 3 | "image_width": null, | -\| \| \| -| } | "image_height": null, | -\| \| \| -| | \\"image_id\\": null, | -\| \| \| -| | \\"image_thumbnail_id\\": null, | -\| \| \| -| | \\"altitude_leftbottom\\": null, | -\| \| \| -| | \\"altitude_lefttop\\": null, | -\| \| \| -| | \\"altitude_rightbottom\\": null, | -\| \| \| -| | \\"altitude_righttop\\": null, | -\| \| \| -| | \\"distance_in_m\\": 1, | -\| \| \| -| | \\"latitude_leftbottom\\": null, | -\| \| \| -| | \\"latitude_lefttop\\": null, | -\| \| \| -| | \\"latitude_rightbottom\\": null, | -\| \| \| -| | \\"latitude_righttop\\": null, | -\| \| \| -| | \\"longitude_leftbottom\\": null, | -\| \| \| -| | \\"longitude_lefttop\\": null, | -\| \| \| -| | \\"longitude_rightbottom\\": null, | -\| \| \| -| | \\"longitude_righttop\\": null, | -\| \| \| -| | \\"x_distance_point1\\": 0.3, | -\| \| \| -| | \\"x_distance_point2\\": 0.7, | -\| \| \| -| | \\"x_normcoord_leftbottom\\": 0, | -\| \| \| -| | \\"x_normcoord_lefttop\\": 0, | -\| \| \| -| | \\"x_normcoord_rightbottom\\": 1, | -\| \| \| -| | \\"x_normcoord_righttop\\": 1, | -\| \| \| -| | \\"y_distance_point1\\": 0.5, | -\| \| \| -| | \\"y_distance_point2\\": 0.5, | -\| \| \| -| | \\"y_normcoord_leftbottom\\": 1, | -\| \| \| -| | \\"y_normcoord_lefttop\\": 0, | -\| \| \| -| | \\"y_normcoord_rightbottom\\": 1, | -\| \| \| -| | \\"y_normcoord_righttop\\": 0, | -\| \| \| -| | \\"rotation_matrix\\": { | -\| \| \| -| | \\"m11\\": null, | -\| \| \| -| | \\"m12\\": null, | -\| \| \| -| | \\"m13\\": null, | -\| \| \| -| | \\"m21\\": null, | -\| \| \| -| | \\"m22\\": null, | -\| \| \| -| | \\"m23\\": null, | -\| \| \| -| | \\"m31\\": null, | -\| \| \| -| | \\"m32\\": null, | -\| \| \| -| | \\"m33\\": null | -\| \| \| -| | }, | -\| \| \| -| | \\"offset_ecef_to_local\\": { | -\| \| \| -| | \\"x\\": null, | -\| \| \| -| | \\"y\\": null, | -\| \| \| -| | \\"z\\": null | -\| \| \| -| | }, | -\| \| \| -| | \\"offset_local_to_ecef\\": { | -\| \| \| -| | \\"x\\": null, | -\| \| \| -| | \\"y\\": null, | -\| \| \| -| | \\"z\\": null | -\| \| \| -| | }, | -\| \| \| -| | \\"pixels_per_meter\\": null | -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | }, | -\| \| \| -| | \\"result\\": 1, | -\| \| \| -| | \\"type\\": 1011, | -\| \| \| -| | \\"version\\": 3 | -\| \| \| -| | } | -\+-----------------------------------+-----------------------------------+ - -## Create floor plan +Get building's floor plans request example: + +```json +{ + "data": { + "buildings": [ + { + "id": "" + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1011, + "version": 3 +} +``` + +Get building's floor plans response example (only one floor is shown): + +```json +{ + "data": { + "buildings": [ + { + "id": "3b326217-676d-f547-019b-6d8e0e1fc5dc", + "floor_plans": [ + { + "id": "1e19239c-bcd2-829a-44a1-900e083f0bfe", + "name": "New floor plan", + "level": 0, + "image_width": null, + "image_height": null, + "image_id": null, + "image_thumbnail_id": null, + "altitude_leftbottom": null, + "altitude_lefttop": null, + "altitude_rightbottom": null, + "altitude_righttop": null, + "distance_in_m": 1, + "latitude_leftbottom": null, + "latitude_lefttop": null, + "latitude_rightbottom": null, + "latitude_righttop": null, + "longitude_leftbottom": null, + "longitude_lefttop": null, + "longitude_rightbottom": null, + "longitude_righttop": null, + "x_distance_point1": 0.3, + "x_distance_point2": 0.7, + "x_normcoord_leftbottom": 0, + "x_normcoord_lefttop": 0, + "x_normcoord_rightbottom": 1, + "x_normcoord_righttop": 1, + "y_distance_point1": 0.5, + "y_distance_point2": 0.5, + "y_normcoord_leftbottom": 1, + "y_normcoord_lefttop": 0, + "y_normcoord_rightbottom": 1, + "y_normcoord_righttop": 0, + "rotation_matrix": { + "m11": null, + "m12": null, + "m13": null, + "m21": null, + "m22": null, + "m23": null, + "m31": null, + "m32": null, + "m33": null + }, + "offset_ecef_to_local": { + "x": null, + "y": null, + "z": null + }, + "offset_local_to_ecef": { + "x": null, + "y": null, + "z": null + }, + "pixels_per_meter": null + } + ] + } + ] + }, + "result": 1, + "type": 1011, + "version": 3 +} +``` + + +Create floor plan +----------------- New floor plan can be created with *create floor plan* message which returns floor plan id that can be used later to reference the floor @@ -939,413 +832,331 @@ new floor plan. Only a single floor plan can be created to a single building with the message although *buildings* and *floor­\_plans* fields are arrays. -The *rotation_matrix*, *offset_ecef_to_local, -offset_local_to_ecef* and *pixels_per_meter* fields are used for +The *rotation\_matrix*, *offset\_ecef\_to\_local, +offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for mapping between WGS84 and pixel coordinates. For more information please see chapter 9. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_floor_plans* +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_floor\_plans* message. -Table 19: Create floor plan message - -\+--------------------------------------+-----------------------------------+ -| Request | Response | -\+======================================+===================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"buildings\\": \[ | \\"buildings\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"id\\": \\"\\<building id>\\", | \\"floor_plans\\": \[ \| -\| \| \| -| \\"floor_plans\\": \[ | { | -\| \| \| -| { | \\"id\\": \\"\\<floor plan id>\\", | -\| \| \| -| \\"name\\": \\"\\<floor plan name>\\", | \\"name\\": "\\<floor plan name>\\", | -\| \| \| -| \\"level\\": \\<level>, | \\"level\\": \\<level>, | -\| \| \| -| "image_width": null, | "image_width": null, | -\| \| \| -| "image_height": null, | "image_height": null, | -\| \| \| -| \\"altitude_leftbottom\\": null, | \\"image_id\\": null, | -\| \| \| -| \\"altitude_lefttop\\": null, | \\"image_thumbnail_id\\": null, | -\| \| \| -| \\"altitude_rightbottom\\": null, | \\"altitude_leftbottom\\": null, | -\| \| \| -| \\"altitude_righttop\\": null, | \\"altitude_lefttop\\": null, | -\| \| \| -| \\"distance_in_m\\": 1, | \\"altitude_rightbottom\\": null, | -\| \| \| -| \\"latitude_leftbottom\\": null, | \\"altitude_righttop\\": null, | -\| \| \| -| \\"latitude_lefttop\\": null, | \\"distance_in_m\\": 1, | -\| \| \| -| \\"latitude_rightbottom\\": null, | \\"latitude_leftbottom\\": null, | -\| \| \| -| \\"latitude_righttop\\": null, | \\"latitude_lefttop\\": null, | -\| \| \| -| \\"longitude_leftbottom\\": null, | \\"latitude_rightbottom\\": null, | -\| \| \| -| \\"longitude_lefttop\\": null, | \\"latitude_righttop\\": null, | -\| \| \| -| \\"longitude_rightbottom\\": null, | \\"longitude_leftbottom\\": null, | -\| \| \| -| \\"longitude_righttop\\": null, | \\"longitude_lefttop\\": null, | -\| \| \| -| \\"x_distance_point1\\": 0.3, | \\"longitude_rightbottom\\": null, | -\| \| \| -| \\"x_distance_point2\\": 0.7, | \\"longitude_righttop\\": null, | -\| \| \| -| \\"x_normcoord_leftbottom\\": 0, | \\"x_distance_point1\\": 0.3, | -\| \| \| -| \\"x_normcoord_lefttop\\": 0, | \\"x_distance_point2\\": 0.7, | -\| \| \| -| \\"x_normcoord_rightbottom\\": 1, | \\"x_normcoord_leftbottom\\": 0, | -\| \| \| -| \\"x_normcoord_righttop\\": 1, | \\"x_normcoord_lefttop\\": 0, | -\| \| \| -| \\"y_distance_point1\\": 0.5, | \\"x_normcoord_rightbottom\\": 1, | -\| \| \| -| \\"y_distance_point2\\": 0.5, | \\"x_normcoord_righttop\\": 1, | -\| \| \| -| \\"y_normcoord_leftbottom\\": 1, | \\"y_distance_point1\\": 0.5, | -\| \| \| -| \\"y_normcoord_lefttop\\": 0, | \\"y_distance_point2\\": 0.5, | -\| \| \| -| \\"y_normcoord_rightbottom\\": 1, | \\"y_normcoord_leftbottom\\": 1, | -\| \| \| -| \\"y_normcoord_righttop\\": 0 | \\"y_normcoord_lefttop\\": 0, | -\| \| \| -| } | \\"y_normcoord_rightbottom\\": 1, | -\| \| \| -\| ] | \\"y_normcoord_righttop\\": 0, | -\| \| \| -| } | \\"rotation_matrix\\": { | -\| \| \| -\| ], | \\"m11\\": null, | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | \\"m12\\": null, | -\| \| \| -| }, | \\"m13\\": null, | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | \\"m21\\": null, | -\| \| \| -| \\"type\\": 1012, | \\"m22\\": null, | -\| \| \| -| \\"version\\": 3 | \\"m23\\": null, | -\| \| \| -| } | \\"m31\\": null, | -\| \| \| -| | \\"m32\\": null, | -\| \| \| -| | \\"m33\\": null | -\| \| \| -| | }, | -\| \| \| -| | \\"offset_ecef_to_local\\": { | -\| \| \| -| | \\"x\\": null, | -\| \| \| -| | \\"y\\": null, | -\| \| \| -| | \\"z\\": null | -\| \| \| -| | }, | -\| \| \| -| | \\"offset_local_to_ecef\\": { | -\| \| \| -| | \\"x\\": null, | -\| \| \| -| | \\"y\\": null, | -\| \| \| -| | \\"z\\": null | -\| \| \| -| | }, | -\| \| \| -| | \\"pixels_per_meter\\": null | -\| \| \| -| | } | -\| \| \| -\| \| ], | -\| \| \| -| | \\"id\\": \\"\\<building id>\\" | -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | }, | -\| \| \| -| | \\"result\\": 1, | -\| \| \| -| | \\"type\\": 1012, | -\| \| \| -| | \\"version\\": 3 | -\| \| \| -| | } | -\+--------------------------------------+-----------------------------------+ - -## Update floor plan +Create floor plan request example: + +```json +{ + "data": { + "buildings": [ + { + "id": "", + "floor_plans": [ + { + "name": "", + "level": , + "image_width": null, + "image_height": null, + "altitude_leftbottom": null, + "altitude_lefttop": null, + "altitude_rightbottom": null, + "altitude_righttop": null, + "distance_in_m": 1, + "latitude_leftbottom": null, + "latitude_lefttop": null, + "latitude_rightbottom": null, + "latitude_righttop": null, + "longitude_leftbottom": null, + "longitude_lefttop": null, + "longitude_rightbottom": null, + "longitude_righttop": null, + "x_distance_point1": 0.3, + "x_distance_point2": 0.7, + "x_normcoord_leftbottom": 0, + "x_normcoord_lefttop": 0, + "x_normcoord_rightbottom": 1, + "x_normcoord_righttop": 1, + "y_distance_point1": 0.5, + "y_distance_point2": 0.5, + "y_normcoord_leftbottom": 1, + "y_normcoord_lefttop": 0, + "y_normcoord_rightbottom": 1, + "y_normcoord_righttop": 0 + } + ] + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1012, + "version": 3 +} +``` + +Create floor plan response example: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "name": "", + "level": , + "image_width": null, + "image_height": null, + "image_id": null, + "image_thumbnail_id": null, + "altitude_leftbottom": null, + "altitude_lefttop": null, + "altitude_rightbottom": null, + "altitude_righttop": null, + "distance_in_m": 1, + "latitude_leftbottom": null, + "latitude_lefttop": null, + "latitude_rightbottom": null, + "latitude_righttop": null, + "longitude_leftbottom": null, + "longitude_lefttop": null, + "longitude_rightbottom": null, + "longitude_righttop": null, + "x_distance_point1": 0.3, + "x_distance_point2": 0.7, + "x_normcoord_leftbottom": 0, + "x_normcoord_lefttop": 0, + "x_normcoord_rightbottom": 1, + "x_normcoord_righttop": 1, + "y_distance_point1": 0.5, + "y_distance_point2": 0.5, + "y_normcoord_leftbottom": 1, + "y_normcoord_lefttop": 0, + "y_normcoord_rightbottom": 1, + "y_normcoord_righttop": 0, + "rotation_matrix": { + "m11": null, + "m12": null, + "m13": null, + "m21": null, + "m22": null, + "m23": null, + "m31": null, + "m32": null, + "m33": null + }, + "offset_ecef_to_local": { + "x": null, + "y": null, + "z": null + }, + "offset_local_to_ecef": { + "x": null, + "y": null, + "z": null + }, + "pixels_per_meter": null + } + ], + "id": "" + } + ] + }, + "result": 1, + "type": 1012, + "version": 3 +} +``` + +### Update floor plan Floor plan information can be updated with *update floor plan* message. Only a single floor plan in single building can be updated with the -message although *buildings* and *floor_plans* fields are arrays. +message although *buildings* and *floor\_plans* fields are arrays. Request below shows how a floor plan image and thumbnail are bound to the floor plan. -The *rotation_matrix*, *offset_ecef_to_local, -offset_local_to_ecef* and *pixels_per_meter* fields are used for +The *rotation\_matrix*, *offset\_ecef\_to\_local, +offset\_local\_to\_ecef* and *pixels\_per\_meter* fields are used for mapping between WGS84 and pixel coordinates. For more information please see chapter 9. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_floor_plans* +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_floor\_plans* message. -Table 20: Update floor plan message - -\+-----------------------------------+-----------------------------------+ -| > Example request | > Response | -\+===================================+===================================+ -| > { | > { | -| > | > | -| > \\"data\\": { | > \\"data\\": { | -| > | > | -| > \\"buildings\\": \[ | > \\"buildings\\": \[ \| -| > | > | -| > { | > { | -| > | > | -| > \\"floor_plans\\": \[ | > \\"floor_plans\\": \[ \| -| > | > | -| > { | > { | -| > | > | -| > \\"id\\": \\"\\<floor plan id>\\", | > \\"id\\": \\"\\<floor plan id>\\", | -| > | > | -| > \\"image_id\\": \\"\\<image | > \\"name\\": "\\<floor plan | -| > id>\\", | > name>\\", | -| > | > | -| > \\"image_thumbnail_id\\": | > \\"level\\": \\<level>, | -| > \\"\\<thumbnail id>\\", | > | -| > | > "image_width": null, | -| > "image_width": 640, | > | -| > | > "image_height": null, | -| > "image_height": 480 | > | -| > | > \\"image_id\\": null, | -| > } | > | -| > | > \\"image_thumbnail_id\\": null, | -| > ] | > | -| > | > \\"altitude_leftbottom\\": null, | -| > } | > | -| > | > \\"altitude_lefttop\\": null, | -| > ], | > | -| > | > \\"altitude_rightbottom\\": | -| > \\"originator_token\\": | > null, | -| > \\"\\<token>\\" | > | -| > | > \\"altitude_righttop\\": null, | -| > }, | > | -| > | > \\"distance_in_m\\": 1, | -| > \\"session_id\\": \\"\\<session | > | -| > id>\\", | > \\"latitude_leftbottom\\": null, | -| > | > | -| > \\"type\\": 1013, | > \\"latitude_lefttop\\": null, | -| > | > | -| > \\"version\\": 3 | > \\"latitude_rightbottom\\": | -| > | > null, | -| > } | > | -| | > \\"latitude_righttop\\": null, | -| | > | -| | > \\"longitude_leftbottom\\": | -| | > null, | -| | > | -| | > \\"longitude_lefttop\\": null, | -| | > | -| | > \\"longitude_rightbottom\\": | -| | > null, | -| | > | -| | > \\"longitude_righttop\\": null, | -| | > | -| | > \\"x_distance_point1\\": 0.3, | -| | > | -| | > \\"x_distance_point2\\": 0.7, | -| | > | -| | > \\"x_normcoord_leftbottom\\": | -| | > 0, | -| | > | -| | > \\"x_normcoord_lefttop\\": 0, | -| | > | -| | > \\"x_normcoord_rightbottom\\": | -| | > 1, | -| | > | -| | > \\"x_normcoord_righttop\\": 1, | -| | > | -| | > \\"y_distance_point1\\": 0.5, | -| | > | -| | > \\"y_distance_point2\\": 0.5, | -| | > | -| | > \\"y_normcoord_leftbottom\\": | -| | > 1, | -| | > | -| | > \\"y_normcoord_lefttop\\": 0, | -| | > | -| | > \\"y_normcoord_rightbottom\\": | -| | > 1, | -| | > | -| | > \\"y_normcoord_righttop\\": 0, | -| | > | -| | > \\"rotation_matrix\\": { | -| | > | -| | > \\"m11\\": null, | -| | > | -| | > \\"m12\\": null, | -| | > | -| | > \\"m13\\": null, | -| | > | -| | > \\"m21\\": null, | -| | > | -| | > \\"m22\\": null, | -| | > | -| | > \\"m23\\": null, | -| | > | -| | > \\"m31\\": null, | -| | > | -| | > \\"m32\\": null, | -| | > | -| | > \\"m33\\": null | -| | > | -| | > }, | -| | > | -| | > \\"offset_ecef_to_local\\": { | -| | > | -| | > \\"x\\": null, | -| | > | -| | > \\"y\\": null, | -| | > | -| | > \\"z\\": null | -| | > | -| | > }, | -| | > | -| | > \\"offset_local_to_ecef\\": { | -| | > | -| | > \\"x\\": null, | -| | > | -| | > \\"y\\": null, | -| | > | -| | > \\"z\\": null | -| | > | -| | > }, | -| | > | -| | > \\"pixels_per_meter\\": null | -| | > | -| | > } | -| | > | -| | > ] \| -| | > | -| | > } | -| | > | -| | > ] \| -| | > | -| | > }, | -| | > | -| | > \\"result\\": 1, | -| | > | -| | > \\"type\\": 1013, | -| | > | -| | > \\"version\\": 3 | -| | > | -| | > } | -\+-----------------------------------+-----------------------------------+ - -## Delete floor plan +Update floor plan request example: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "image_id": "", + "image_thumbnail_id": "", + "image_width": 640, + "image_height": 480 + } + ] + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1013, + "version": 3 +} +``` + +Update floor plan response example: +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "name": "", + "level": , + "image_width": null, + "image_height": null, + "image_id": null, + "image_thumbnail_id": null, + "altitude_leftbottom": null, + "altitude_lefttop": null, + "altitude_rightbottom": null, + "altitude_righttop": null, + "distance_in_m": 1, + "latitude_leftbottom": null, + "latitude_lefttop": null, + "latitude_rightbottom": null, + "latitude_righttop": null, + "longitude_leftbottom": null, + "longitude_lefttop": null, + "longitude_rightbottom": null, + "longitude_righttop": null, + "x_distance_point1": 0.3, + "x_distance_point2": 0.7, + "x_normcoord_leftbottom": 0, + "x_normcoord_lefttop": 0, + "x_normcoord_rightbottom": 1, + "x_normcoord_righttop": 1, + "y_distance_point1": 0.5, + "y_distance_point2": 0.5, + "y_normcoord_leftbottom": 1, + "y_normcoord_lefttop": 0, + "y_normcoord_rightbottom": 1, + "y_normcoord_righttop": 0, + "rotation_matrix": { + "m11": null, + "m12": null, + "m13": null, + "m21": null, + "m22": null, + "m23": null, + "m31": null, + "m32": null, + "m33": null + }, + "offset_ecef_to_local": { + "x": null, + "y": null, + "z": null + }, + "offset_local_to_ecef": { + "x": null, + "y": null, + "z": null + }, + "pixels_per_meter": null + } + ] + } + ] + }, + "result": 1, + "type": 1013, + "version": 3 +} +``` + +### Delete floor plan Floor plan can be deleted with *delete floor plan* message. Only a single floor plan in single building can be deleted with the message -although *buildings* and *floor_plans* fields are arrays. - -Updates are sent to clients via real time situation connection\\ -*metadata_update_message -> deleted_floor_plans* message. - -Table 21: Delete floor plan message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"buildings\\": \[ | \\"type\\": 1014, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"floor_plans\\": \[ | } | -\| \| \| -| { | | -\| \| \| -| \\"id\\": \\"\\<floor plan id>\\" | | -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1014, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Get floor plan image data +although *buildings* and *floor\_plans* fields are arrays. + +Updates are sent to clients via real time situation connection\ +*metadata\_update\_message -\> deleted\_floor\_plans* message. + +Delete floor plan request example: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "" + } + ] + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1014, + "version": 3 +} +``` + +Delete floor plan response example: + +```json +{ + "result": 1, + "type": 1014, + "version": 3 +} +``` + +### Get floor plan image data The method can be used to fetch floor plan image or thumbnail data. The image binary data is encoded using Base64 (RFC 3548) encoding. -Table 22: Get floor plan image data message - -\+-----------------------------------+-----------------------------------+ -| Request | Response | -\+===================================+===================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"image_id\\": \\"\\<image or | \\"image_base64\\": "\\<data>" | -| thumbnail id>\\", | | -| | }, | -| \\"originator_token\\": | | -| \\"\\<token>\\" | \\"result\\": 1, | -\| \| \| -| }, | \\"type\\": 1021, | -\| \| \| -| \\"session_id\\": \\"\\<session | \\"version\\": 3 | -| id>\\", | | -| | } | -| \\"type\\": 1021, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+-----------------------------------+-----------------------------------+ - -## Set floor plan image data +Get floor plan image data example request: + +```json +{ + "data": { + "image_id": "", + "originator_token": "" + }, + "session_id": "", + "type": 1021, + "version": 3 +} +``` + +Get floor plan image data example response: + +```json +{ + "data": { + "image_base64": "" + }, + "result": 1, + "type": 1021, + "version": 3 +} +``` + +### Set floor plan image data The method can be used to upload floor plan image or thumbnail data. The image binary data needs to be encoded using Base64 (RFC 3548) encoding. @@ -1353,571 +1164,466 @@ The method returns image id which can be used to reference the image later. Supported image formats are BMP, TIFF, JPEG, GIF, PNG and JPEG XR. -Table 23: Set floor plan image data message - -\+--------------------------------------+---------------------------------+ -| Request | Response | -\+======================================+=================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"image_base64\\": \\"\\<data>", | \\"image_id\\": \\"\\<image id>\\" | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | }, | -\| \| \| -| }, | \\"result\\": 1, | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | \\"type\\": 1022, | -\| \| \| -| \\"type\\": 1022, | \\"version\\": 3 | -\| \| \| -| \\"version\\": 3 | } | -\| \| \| -| } | | -\+--------------------------------------+---------------------------------+ - -## Get areas +Set floor plan image data example request: +```json +{ + "data": { + "image_base64": "", + "originator_token": "" + }, + "session_id": "", + "type": 1022, + "version": 3 +} +``` +Set floor plan image data example response: + +```json +{ + "data": { + "image_id": "" + }, + "result": 1, + "type": 1022, + "version": 3 +} +``` + +### Get areas The message returns areas for given floor plan id. Only a single floor plan's areas in a single building can be queried with the message -although *buildings* and *floor_plans* fields are arrays. Area color +although *buildings* and *floor\_plans* fields are arrays. Area color values (alpha, red, green and blue) are integers between 0...255. *llas* is an array of area corner points' coordinates in WGS84 format and can contain 3...n items. *altitude* is in meters. -Table 24: Get areas message - -\+--------------------------------------+------------------------------------+ -| Request | Response | -\+======================================+====================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"buildings\\": \[ | \\"buildings\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"floor_plans\\": \[ | \\"floor_plans\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"id\\": \\"\\<floor plan id>\\" | \\"id\\": \\"\\<floor plan id>\\", | -\| \| \| -| } | \\"areas\\": \[ \| -\| \| \| -\| ] | { | -\| \| \| -| } | \\"id\\": \\"\\<area id>\\", | -\| \| \| -\| ], | \\"name\\": \\"\\<area name>\\", | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | \\"a\\": \\<area color alpha>, | -\| \| \| -| }, | \\"r\\": \\<area color red>, | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | \\"g\\": \\<area color green>, | -\| \| \| -| \\"type\\": 1031, | \\"b\\": \\<area color blue>, | -\| \| \| -| \\"version\\": 3 | \\"llas\\": \[ \| -\| \| \| -| } | { | -\| \| \| -| | \\"altitude\\": \\<point altitude>, | -\| \| \| -| | \\"latitude\\": \\<point latitude>, | -\| \| \| -| | \\"longitude\\": \\<point longitude> \| -\| \| \| -| | }, | -\| \| \| -| | { | -\| \| \| -| | \\"altitude\\": \\<point altitude>, | -\| \| \| -| | \\"latitude\\": \\<point latitude>, | -\| \| \| -| | \\"longitude\\": \\<point longitude> \| -\| \| \| -| | }, | -\| \| \| -| | { | -\| \| \| -| | \\"altitude\\": \\<point altitude>, | -\| \| \| -| | \\"latitude\\": \\<point latitude>, | -\| \| \| -| | \\"longitude\\": \\<point longitude> \| -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | }, | -\| \| \| -| | \\"result\\": 1, | -\| \| \| -| | \\"type\\": 1031, | -\| \| \| -| | \\"version\\": 3 | -\| \| \| -| | } | -\+--------------------------------------+------------------------------------+ - -## Create area +Get areas example request: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "" + } + ] + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1031, + "version": 3 +} +``` + +Get areas example response: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "areas": [ + { + "id": "", + "name": "", + "a": , + "r": , + "g": , + "b": , + "llas": [ + { + "altitude": , + "latitude": , + "longitude": + }, + { + "altitude": , + "latitude": , + "longitude": + }, + { + "altitude": , + "latitude": , + "longitude": + } + ] + } + ] + } + ] + } + ] + }, + "result": 1, + "type": 1031, + "version": 3 +} +``` + +### Create area New area can be created with *create area* message which returns area id that can be used later to reference the area. Only a single area in a single floor plan and single building can be created with the message -although *buildings*, *floor_plans* and *areas* fields are arrays. Area +although *buildings*, *floor\_plans* and *areas* fields are arrays. Area color values (alpha, red, green and blue) are integers between 0...255. *llas* is an array of area corner points' coordinates in WGS84 format and can contain 3...n items. *altitude* is in meters. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_areas* message. - -Table 25: Create area message - -\+--------------------------------------+--------------------------------+ -| Request | Response | -\+======================================+================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"buildings\\": \[ | \\"buildings\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"floor_plans\\": \[ | \\"floor_plans\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"id\\": \\"\\<floor plan id>\\", | \\"id\\": \\"\\<floor plan id>\\", | -\| \| \| -| \\"areas\\": \[ | \\"areas\\": \[ \| -\| \| \| -| { | { | -\| \| \| -| \\"name\\": \\"\\<area name>\\", | \\"id\\": \\"\\<area id>\\" | -\| \| \| -| \\"a\\": \\<area color alpha>, | } | -\| \| \| -| \\"r\\": \\<area color red>, | ] \| -\| \| \| -| \\"g\\": \\<area color green>, | } | -\| \| \| -| \\"b\\": \\<area color blue>, | ] \| -\| \| \| -| \\"llas\\": \[ | } | -\| \| \| -| { | ] \| -\| \| \| -| \\"altitude\\": \\<point altitude>, | }, | -\| \| \| -| \\"latitude\\": \\<point latitude>, | \\"result\\": 1, | -\| \| \| -| \\"longitude\\": \\<point longitude> | \\"type\\": 1032, | -\| \| \| -| }, | \\"version\\": 3 | -\| \| \| -| { | } | -\| \| \| -| \\"altitude\\": \\<point altitude>, | | -\| \| \| -| \\"latitude\\": \\<point latitude>, | | -\| \| \| -| \\"longitude\\": \\<point longitude> \| \| -\| \| \| -| }, | | -\| \| \| -| { | | -\| \| \| -| \\"altitude\\": \\<point altitude>, | | -\| \| \| -| \\"latitude\\": \\<point latitude>, | | -\| \| \| -| \\"longitude\\": \\<point longitude> \| \| -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1032, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+--------------------------------+ - -## Update area +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_areas* message. + +Create area example request: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "areas": [ + { + "name": "", + "a": , + "r": , + "g": , + "b": , + "llas": [ + { + "altitude": , + "latitude": , + "longitude": + }, + { + "altitude": , + "latitude": , + "longitude": + }, + { + "altitude": , + "latitude": , + "longitude": + } + ] + } + ] + } + ] + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1032, + "version": 3 +} +``` + +Create area example response: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "areas": [ + { + "id": "" + } + ] + } + ] + } + ] + }, + "result": 1, + "type": 1032, + "version": 3 +} +``` + +### Update area Existing area can be updated with *update area* message. Area color values (alpha, red, green and blue) are integers between 0...255. *llas* is an array of area corner points' coordinates in WGS84 format and can contain 3...n items. *altitude* is in meters. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_areas* message. - -Table 26: Update area message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"buildings\\": \[ | \\"type\\": 1033, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"floor_plans\\": \[ | } | -\| \| \| -| { | | -\| \| \| -| \\"id\\": \\"\\<floor plan id>\\", | | -\| \| \| -| \\"areas\\": \[ \| \| -\| \| \| -| { | | -\| \| \| -| \\"id\\": \\"\\<area id>\\", | | -\| \| \| -| \\"name\\": \\"\\<area name>\\", | | -\| \| \| -| \\"a\\": \\<area color alpha>, | | -\| \| \| -| \\"r\\": \\<area color red>, | | -\| \| \| -| \\"g\\": \\<area color green>, | | -\| \| \| -| \\"b\\": \\<area color blue>, | | -\| \| \| -| \\"llas\\": \[ \| \| -\| \| \| -| { | | -\| \| \| -| \\"altitude\\": \\<point altitude>, | | -\| \| \| -| \\"latitude\\": \\<point latitude>, | | -\| \| \| -| \\"longitude\\": \\<point longitude> \| \| -\| \| \| -| }, | | -\| \| \| -| { | | -\| \| \| -| \\"altitude\\": \\<point altitude>, | | -\| \| \| -| \\"latitude\\": \\<point latitude>, | | -\| \| \| -| \\"longitude\\": \\<point longitude> \| \| -\| \| \| -| }, | | -\| \| \| -| { | | -\| \| \| -| \\"altitude\\": \\<point altitude>, | | -\| \| \| -| \\"latitude\\": \\<point latitude>, | | -\| \| \| -| \\"longitude\\": \\<point longitude> \| \| -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1033, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Delete area +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_areas* message. + +Update area example request: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "areas": [ + { + "id": "", + "name": "", + "a": , + "r": , + "g": , + "b": , + "llas": [ + { + "altitude": , + "latitude": , + "longitude": + }, + { + "altitude": , + "latitude": , + "longitude": + }, + { + "altitude": , + "latitude": , + "longitude": + } + ] + } + ] + } + ] + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1033, + "version": 3 +} +``` + +Update area example response: + +```json +{ + "result": 1, + "type": 1033, + "version": 3 +} +``` + +### Delete area Area can be deleted with delete building message. Only a single area can -be deleted with the message although *buildings, floor_plans* and +be deleted with the message although *buildings, floor\_plans* and *areas* fields are arrays. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> deleted_areas* message. - -Table 27: Delete building message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"buildings\\": \[ | \\"type\\": 1034, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"floor_plans\\": \[ | } | -\| \| \| -| { | | -\| \| \| -| \\"id\\": \\"\\<floor plan id>\\", | | -\| \| \| -| \\"areas\\": \[ \| \| -\| \| \| -| { | | -\| \| \| -| \\"id\\": \\"\\<area id>\\" | | -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1034, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Get networks +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_areas* message. + +Delete building example request: + +```json +{ + "data": { + "buildings": [ + { + "floor_plans": [ + { + "id": "", + "areas": [ + { + "id": "" + } + ] + } + ] + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1034, + "version": 3 +} + +``` + +Delete building example response: + +```json +{ + "result": 1, + "type": 1034, + "version": 3 +} +``` + + +### Get networks + The message returns network id and name mappings. -Table 28: Get networks message - -\+--------------------------------------+--------------------------------+ -| Request | Example response | -\+======================================+================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"data\\": { | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | \\"networks\\": \[ \| -\| \| \| -| }, | { | -\| \| \| -| \\"session_id\\": \\"\\<token>\\", | \\"id\\": \\<network id>, | -\| \| \| -| \\"type\\": 1041, | \\"name\\": \\"\\<network name>\\" | -\| \| \| -| \\"version\\": 3 | }, | -\| \| \| -| } | { | -\| \| \| -| | \\"id\\": \\<network id>, | -\| \| \| -| | \\"name\\": \\"\\<network name>\\" | -\| \| \| -| | } | -\| \| \| -\| \| ] \| -\| \| \| -| | }, | -\| \| \| -| | \\"result\\": 1, | -\| \| \| -| | \\"type\\": 1041, | -\| \| \| -| | \\"version\\": 3 | -\| \| \| -| | } | -\+--------------------------------------+--------------------------------+ - -## Create network +Get networks example request: +```json +{ + "data": { + "originator_token": "" + }, + "session_id": "", + "type": 1041, + "version": 3 +} +``` + +Get networks example response: +```json +{ + "data": { + "networks": [ + { + "id": , + "name": "" + }, + { + "id": , + "name": "" + } + ] + }, + "result": 1, + "type": 1041, + "version": 3 +} +``` + +### Create network The message is used to create a new network id to name mapping. Only a single network mapping can be created with the message although *networks* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_networks* message. - -Table 29: Create network message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"networks\\": \[ | \\"type\\": 1042, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": \\<network id>, | } | -\| \| \| -| \\"name\\": \\"\\<network name>\\" | | -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1042, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Update network +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_networks* message. + +Create network example request: + +```json +{ + "data": { + "networks": [ + { + "id": , + "name": "" + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1042, + "version": 3 +} +``` + +Create network example response: + +```json +{ + "result": 1, + "type": 1042, + "version": 3 +} +``` + +### Update network Network name can be updated with *update network* message. Only a single network can be updated with the message although *networks* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> added_or_changed_networks* message. - -Table 30: Update network message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"networks\\": \[ | \\"type\\": 1043, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": \\<network id>, | } | -\| \| \| -| \\"name\\": \\"\\<network name>\\" | | -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1043, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Delete network +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> added\_or\_changed\_networks* message. + +Update network example request: + +```json +{ + "data": { + "networks": [ + { + "id": , + "name": "" + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1043, + "version": 3 +} +``` + +Update network example response: + +```json +{ + "result": 1, + "type": 1043, + "version": 3 +} +``` + +### Delete network Network id to name mapping can be deleted with *delete network* message. Only a single network can be deleted with the message although *networks* field is an array. -Updates are sent to clients via real time situation connection using\\ -*metadata_update_message -> deleted_networks* message. - -Table 31: Delete network message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"networks\\": \[ | \\"type\\": 1044, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": \\<network id> | } | -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1044, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Add node to floor plan +Updates are sent to clients via real time situation connection using\ +*metadata\_update\_message -\> deleted\_networks* message. + +Delete network example request: + +```json +{ + "data": { + "networks": [ + { + "id": + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1044, + "version": 3 +} +``` + +Delete network example response: + +```json +{ + "result": 1, + "type": 1044, + "version": 3 +} +``` + +### Add node to floor plan Node can be bound to floor plan with *add node to floor plan* message. Only a single node can be added with the message although *nodes* field @@ -1926,240 +1632,201 @@ approved with valid location information with *set node metadata* message. Updates are sent to clients via real time situation connection using -*node_metadata* message. - -Table 32: Add node to floor plan message - -\+---------------------------------------------+-----------------+ -| Request | Response | -\+=============================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"nodes\\": \[ | \\"type\\": 1051, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"floor_plan_id\\": \\"\\<floor plan id>\\", | } | -\| \| \| -| \\"id\\": \\<node id>, | | -\| \| \| -| \\"network_id\\": \\<network id> \| \| -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1051, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+---------------------------------------------+-----------------+ - -## Remove node from floor plan +*node\_metadata* message. + +Add node to floor plan example request: + +```json +{ + "data": { + "nodes": [ + { + "floor_plan_id": "", + "id": , + "network_id": + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1051, + "version": 3 +} +``` + +Add node to floor plan example response: + +```json +{ + "result": 1, + "type": 1051, + "version": 3 +} +``` + +### Remove node from floor plan Node can be removed from floor plan with *remove node from floor plan* message. Only a single node can be removed with the message although *nodes* field is an array. Updates are sent to clients via real time situation connection using -*node_metadata* message. - -Table 33: Remove node from floor plan message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"nodes\\": \[ | \\"type\\": 1052, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": \\<node id>, | } | -\| \| \| -| \\"network_id\\": \\<network id> \| \| -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1052, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Set node metadata - -The method is used set node related metadata. *is_virtual* denotes the -planning node feature in WNT client \[2]. +*node\_metadata* message. + +Remove node from floor plan example request: + +```json +{ + "data": { + "nodes": [ + { + "id": , + "network_id": + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1052, + "version": 3 +} +``` + +Remove node from floor plan example response: + +```json +{ + "result": 1, + "type": 1052, + "version": 3 +} +``` + +### Set node metadata + +The method is used set node related metadata. *is\_virtual* denotes the +planning node feature in WNT client \[2\]. Updates are sent to clients via real time situation connection using -*node_metadata* message. - -Table 34: Set node metadata message - -\+----------------------------------------+-----------------+ -| Example request | Response | -\+========================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"nodes\\": \[ | \\"type\\": 1061, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": 1, | } | -\| \| \| -| \\"network_id\\": 112233, | | -\| \| \| -| \\"name\\": \\"some name\\", | | -\| \| \| -| \\"description\\": \\"some description\\", | | -\| \| \| -| \\"is_approved\\": true, | | -\| \| \| -| \\"is_virtual\\": false, | | -\| \| \| -| \\"latitude\\": 61.4547593371768, | | -\| \| \| -| \\"longitude\\": 23.8856021513505, | | -\| \| \| -| \\"altitude\\": 0.0 | | -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1061, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+----------------------------------------+-----------------+ - -## Delete node +*node\_metadata* message. + +Set node metadata example request: + +```json +{ + "data": { + "nodes": [ + { + "id": 1, + "network_id": 112233, + "name": "some name", + "description": "some description", + "is_approved": true, + "is_virtual": false, + "latitude": 61.4547593371768, + "longitude": 23.8856021513505, + "altitude": 0.0 + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1061, + "version": 3 +} +``` + +Set node metadata example response: + +```json +{ + "result": 1, + "type": 1061, + "version": 3 +} +``` + +### Delete node The method is used to delete node real time situation and metadata. Only a single node's data can be deleted with the message although *nodes* field is an array. Note that if node sends any data afterwards it will -be shown again. Boolean type *is_sink* information is required to let +be shown again. Boolean type *is\_sink* information is required to let the WNT backend to perform additional clean ups if needed. Updates are sent to clients via real time situation connection using -*node_metadata* message. - -Table 35: Delete node message - -\+--------------------------------------+-----------------+ -| Request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"nodes\\": \[ | \\"type\\": 1063, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": \\<node id>, | } | -\| \| \| -| \\"network_id\\": \\<network id>, | | -\| \| \| -| \\"is_sink\\":\\<true / false> \| \| -\| \| \| -| } | | -\| \| \| -\| ], | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | | -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1063, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Set network data +*node\_metadata* message. + +Delete node example request: + +```json +{ + "data": { + "nodes": [ + { + "id": , + "network_id": , + "is_sink": + } + ], + "originator_token": "" + }, + "session_id": "", + "type": 1063, + "version": 3 +} +``` + +Delete node example response: + +```json +{ + "result": 1, + "type": 1063, + "version": 3 +} +``` + +### Set network data The method can be used to set network wide application configuration -data and diagnostics interval \[1]. Only a single network's data can be +data and diagnostics interval \[1\]. Only a single network's data can be set with the message although *networks* field is an array. Updates are sent to clients per sink via real time situation connection -using *app_config* message. - -Table 36: Set network data message - -\+-----------------------------------+-----------------------------------+ -| Example request | Response | -\+===================================+===================================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"networks\\": \[ | \\"type\\": 1071, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"application_data\\": | } | -| \\"112233445566778899AABBCCDDEEFF\\ | | -| ", | | -\| \| \| -| \\"diagnostics_interval\\": 60, | | -\| \| \| -| \\"id\\": \\"112233\\" | | -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| }, | | -\| \| \| -| \\"originator_token\\": | | -| \\"\\<token>\\", | | -\| \| \| -| \\"session_id\\": \\"\\<session | | -| id>\\", | | -\| \| \| -| \\"type\\": 1071, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+-----------------------------------+-----------------------------------+ - -## Send data message +using *app\_config* message. + +Set network data example request: + +```json +{ + "data": { + "networks": [ + { + "application_data": "112233445566778899AABBCCDDEEFF", + "diagnostics_interval": 60, + "id": "112233" + } + ] + }, + "originator_token": "", + "session_id": "", + "type": 1071, + "version": 3 +} +``` + +Set network data example response: + +```json +{ + "result": 1, + "type": 1071, + "version": 3 +} +``` + +### Send data message The method can be used to send arbitrary data message to a node. The message requires that receiving node sink's node id is defined so the @@ -2167,157 +1834,148 @@ message sending does not create unneeded load to the network. *Payload* is hexadecimal encoded binary data. At the moment it is not possible to get confirmation that node received the message. -For more information about the fields please see DSAP-DATA_TX.request -\[1]. - -Table 37:Send data message - -\+---------------------------------------+-----------------+ -| Example request | Response | -\+=======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"command\\": { | \\"type\\": 1073, | -\| \| \| -| \\"network_id\\": 777555, | \\"version\\": 3 | -\| \| \| -| \\"node_id\\": 2, | } | -\| \| \| -| \\"sink_node_id\\": 1, | | -\| \| \| -| \\"source_end_point\\": 255, | | -\| \| \| -| \\"destination_end_point\\": 240, | | -\| \| \| -| \\"payload\\": \\"040001000300\\", | | -\| \| \| -| \\"qos\\": 0 | | -\| \| \| -| } | | -\| \| \| -| }, | | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\", | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1073, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+---------------------------------------+-----------------+ - -## Get scratchpad status +For more information about the fields please see DSAP-DATA\_TX.request +\[1\]. + +Send data example request: + +```json +{ + "data": { + "command": { + "network_id": 777555, + "node_id": 2, + "sink_node_id": 1, + "source_end_point": 255, + "destination_end_point": 240, + "payload": "040001000300", + "qos": 0 + } + }, + "originator_token": "", + "session_id": "", + "type": 1073, + "version": 3 +} +``` + +Send data example response: + +```json +{ + "result": 1, + "type": 1073, + "version": 3 +} +``` + +### Get scratchpad status The method can be used to query scratchpad status from the nodes in the network. Only a single network's data can be get with the message although *networks* field is an array. The query can be a single shot or continuous. Continuous query sending interval can be defined by setting -*rerun_interval_s* property. +*rerun\_interval\_s* property. Table 38:Query types - Query rerun_interval_s is_close - -* * * - - Single shot 0 false - Start continuous Interval false - Stop continuous 0 true +| Query | rerun\_interval\_s | is\_close | +| ------------------ | -------------------- | ----------- | +| Single shot | 0 | false | +| Start continuous | Interval | false | +| Stop continuous | 0 | true | Data is sent to clients per node via real time situation connection -using *scratchpad_status* message. - -Table 39: Get scratchpad status message - -\+--------------------------------------+-----------------+ -| Example request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"networks\\": \[ | \\"type\\": 1074, | -\| \| \| -| { | \\"version\\": 3 | -\| \| \| -| \\"id\\": 112233, | } | -\| \| \| -| \\"rerun_interval_s": 180, | | -\| \| \| -| \\"is_close\\": false | | -\| \| \| -| } | | -\| \| \| -\| ] \| \| -\| \| \| -| }, | | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | | -\| \| \| -| \\"type\\": 1074, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -## Get components information +using *scratchpad\_status* message. + +Get scratchpad status example request: + +```json +{ + "data": { + "networks": [ + { + "id": 112233, + "rerun_interval_s": 180, + "is_close": false + } + ] + }, + "session_id": "", + "type": 1074, + "version": 3 +} +``` + +Get scratchpad status example response: + +```json +{ + "result": 1, + "type": 1074, + "version": 3 +} +``` + +### Get components information The method can be used to query backend components' and gateways' information. Responses are sent to clients via the real time situation connection -using *backend_component_info* and *gateway_info* messages. +using *backend\_component\_info* and *gateway\_info* messages. Please note that the backend component information is returned only from -the metadata service, and *originator_token* is not yet returned via +the metadata service, and *originator\_token* is not yet returned via the real time situation connection. -Table 40: Get components information message - -\+--------------------------------------+-----------------+ -| Example request | Response | -\+======================================+=================+ -| { | { | -\| \| \| -| \\"data\\": { | \\"result\\": 1, | -\| \| \| -| \\"originator_token\\": \\"\\<token>\\" | \\"type\\": 1081, | -\| \| \| -| }, | \\"version\\": 3 | -\| \| \| -| \\"session_id\\": \\"\\<token>\\", | } | -\| \| \| -| \\"type\\": 1081, | | -\| \| \| -| \\"version\\": 3 | | -\| \| \| -| } | | -\+--------------------------------------+-----------------+ - -# Real time situation service authentication +Get components information example request: + +```json +{ + "data": { + "originator_token": "" + }, + "session_id": "", + "type": 1081, + "version": 3 +} +``` + +Get components information example response: + +```json +{ + "result": 1, + "type": 1081, + "version": 3 +} +``` + +## Real time situation service authentication + The service provides all nodes related data and changes to the metadata. Authentication is done in the start by sending the *session id* received from the authentication service. -Table 41: Authentication +Authentication request example: + +```json +{ + "session_id": "", + "version": 3 +} +``` -\+--------------------------------------+----------------+ -| Request | Response | -\+======================================+================+ -| { | { | -\| \| \| -| \\"session_id\\": \\"\\<session id>\\", | \\"result\\": 1, | -\| \| \| -| \\"version\\": 3 | \\"version\\": 3 | -\| \| \| -| } | } | -\+--------------------------------------+----------------+ +Authentication request response: + +```json +{ + "result": 1, + "version": 3 +} +``` After a successful authentication the service starts to send Protocol Buffers encoded data and moves into write only mode. First message(s) @@ -2328,20 +1986,18 @@ information is sent to client. Table 42: Node count message -\+-----------------------------------+---------------+ -| Path | Data | -\+===================================+===============+ -| Message -> rtsituation_metadata | cluster_no | -\| \| \| -| | cluster_size | -\| \| \| -| | node_count | -\+-----------------------------------+---------------+ +| Path | Data | +|---------------------------------- | ----------------| +| Message -\> rtsituation\_metadata | cluster\_no | +| | | +| | cluster\_size | +| | | +| | node\_count | Note that all received Protocol Buffers messages has message "Message" as a root item (message.proto). -# Time series service data +## Time series service data Time series data is provided by direct access to Influx database. The same credentials used to login to authentication service can be used @@ -2352,236 +2008,160 @@ equivalent of database table). Table 43: Database measurements - Measurement Description - -* * * - - analytics_next_hop Hop count to sink - analytics_nodestate Node online information \* - analytics_packet High level information about every received packet - analytics_traveltime_kpi Processed information about packets' travel times - endpoint_251 Traffic diagnostics \[3] \*\* - endpoint_252 Neighbor diagnostics \[3] \*\* - endpoint_253 Node diagnostics \[3] \*\* - endpoint_254 Boot diagnostics \[3] \*\* - location_measurement Positioning measurements received from the nodes \*\* - location_update Computed positions for nodes \*\* - remote_api_response Remote API response information \*\* +| Measurement | Description | +| ---------------------------- | -------------------------------------------------------| +| analytics\_next\_hop | Hop count to sink | +| analytics\_nodestate | Node online information \* | +| analytics\_packet | High level information about every received packet | +| analytics\_traveltime\_kpi | Processed information about packets' travel times | +| endpoint\_251 | Traffic diagnostics \[3\] \*\* | +| endpoint\_252 | Neighbor diagnostics \[3\] \*\* | +| endpoint\_253 | Node diagnostics \[3\] \*\* | +| endpoint\_254 | Boot diagnostics \[3\] \*\* | +| location\_measurement | Positioning measurements received from the nodes \*\* | +| location\_update | Computed positions for nodes \*\* | +| remote\_api\_response | Remote API response information \*\* | \* Online state uses the values defined in *OnlineStatus* message (internal.proto). \*\* Column names use numbering from the WNT Protocol Buffers files. -Wirepas Backend-client \[4] contains *influx_viewer* example which can +Wirepas Backend-client \[4\] contains *influx\_viewer* example which can be used to query information from the Influx with the decoded column names. -Please note that in WNT 2.0, *analytics_packet* measurement's -*travel_time_ms* column is replaced by *travel_time_ms_qos0* and -*travel_time_ms_qos1* columns. Also separate *qos* column is added to +Please note that in WNT 2.0, *analytics\_packet* measurement's +*travel\_time\_ms* column is replaced by *travel\_time\_ms\_qos0* and +*travel\_time\_ms\_qos1* columns. Also separate *qos* column is added to the measurement. -## Example CURL command to query data +### Example CURL command to query data -curl.exe -G -\--data-urlencode \\"u=\\<username>\\" --data-urlencode -\\"p=\\<password>\\" --data-urlencode \\"pretty=true\\" --data-urlencode -\\"db=wirepas\\" --data-urlencode \\"q=show measurements\\" +```bash +curl -G https://someaddresswnt.extwirepas.com:8886/query + --data-urlencode "u=" + --data-urlencode "p=" + --data-urlencode "pretty=true" + --data-urlencode "db=wirepas" + --data-urlencode "q=show measurements" +``` -## Example column names decoding +### Example column names decoding In the example the query used to query data is "*q=select \* from -endpoint_252*". +endpoint\_252*". Table 44: Example response -\+-------------------------------------+ -| Response from Influx | -\+=====================================+ -| { | -\| \| -| \\"results\\": \[ \| -\| \| -| { | -\| \| -| \\"statement_id\\": 0, | -\| \| -| \\"series\\": \[ \| -\| \| -| { | -\| \| -| \\"name\\": \\"endpoint_252\\", | -\| \| -| \\"columns\\": \[ \| -\| \| -| \\"time\\", | -\| \| -| \\"Message_2\\", | -\| \| -| \\"Message_4\\", | -\| \| -| \\"Message_5\\", | -\| \| -| \\"Message_50_1\\", | -\| \| -| \\"Message_50_49\\", | -\| \| -| \\"Message_51_2\\", | -\| \| -| \\"Message_51_4\\", | -\| \| -| \\"Message_51_5\\", | -\| \| -| \\"Message_51_7\\", | -\| \| -| \\"Message_7\\", | -\| \| -| \\"Message_8\\", | -\| \| -| \\"Message_9\\", | -\| \| -| \\"network_id\\", | -\| \| -| \\"nodegroup\\", | -\| \| -| \\"nodeid\\" | -\| \| -\| ], | -\| \| -| \\"values\\": \[ \| -\| \| -\| \[ \| -\| \| -| \\"2018-11-28T16:48:41.301000003Z\\", | -\| \| -| 112233, | -\| \| -| 1543423721301, | -\| \| -| 1543423721340, | -\| \| -| \\"\[Message_50_1_1=12499145, | -\| \| -| Message_50_1_2=2399.0, | -\| \| -| Message_50_1_3=-4.0, | -\| \| -| Message_50_1_4=1, | -\| \| -| Message_50_1_5=-23.0]\\", | -\| \| -| 123, | -\| \| -| 252, | -\| \| -| 255, | -\| \| -| 0, | -\| \| -| \\"\\", | -\| \| -| 123, | -\| \| -| 123, | -\| \| -| 39, | -\| \| -| \\"112233\\", | -\| \| -| \\"0\\", | -\| \| -| 123 | -\| \| -\| ] \| -\| \| -\| ] \| -\| \| -| } | -\| \| -\| ] \| -\| \| -| } | -\| \| -\| ] \| -\| \| -| } | -\+-------------------------------------+ - -For example to decode column *Message_2*, open main WNT Protocol +```json +{ + "results": [ + { + "statement_id": 0, + "series": [ + { + "name": "endpoint_252", + "columns": [ + "time", + "Message_2", + "Message_4", + "Message_5", + "Message_50_1", + "Message_50_49", + "Message_51_2", + "Message_51_4", + "Message_51_5", + "Message_51_7", + "Message_7", + "Message_8", + "Message_9", + "network_id", + "nodegroup", + "nodeid" + ], + "values": [ + [ + "2018-11-28T16:48:41.301000003Z", + 112233, + 1543423721301, + 1543423721340, + "[Message_50_1_1=12499145, + Message_50_1_2=2399.0, + Message_50_1_3=-4.0, + Message_50_1_4=1, + Message_50_1_5=-23.0]", + 123, + 252, + 255, + 0, + "", + 123, + 123, + 39, + "112233", + "0", + 123 + ] + ] + } + ] + } + ] +} +``` + +For example to decode column *Message\_2*, open main WNT Protocol Buffers file *message.proto* and look for message called *Message*. This message is used as base of all columns starting with *Message\_* and the number after the underscore is the field number of the corresponding -message. In this case *Message_2* can be decoded to *network_id*. - -Table 45: Part of message.proto - -\+-----------------------------------------+ -| message.proto | -\+=========================================+ -| message Message { | -\| \| -| repeated uint32 id = 1 \[packed=true]; | -\| \| -| optional uint32 network_id = 2; | -\| \| -| optional string gateway_id = 3; | -\| \| -| . | -\| \| -| . | -\| \| -| . | -\+-----------------------------------------+ - -Decoding *Message_51_2* column name can be done the same way except -that the number 51 is sub-message *rx_time* which is instance of -*RxData* message. Following the previous rules the *Message_51_2* can +message. In this case *Message\_2* can be decoded to *network\_id*. + +Part of message.proto: + +```protobuf +message Message { + repeated uint32 id = 1 [packed=true]; + optional uint32 network_id = 2; + optional string gateway_id = 3; + . + . + . + +``` + +Decoding *Message\_51\_2* column name can be done the same way except +that the number 51 is sub-message *rx\_time* which is instance of +*RxData* message. Following the previous rules the *Message\_51\_2* can be decoded to be source endpoint of a data message packet. -Table 46: Part of message.proto - -\+-----------------------------------------------------------+ -| message.proto | -\+===========================================================+ -| message Message { | -\| \| -| . | -\| \| -| . | -\| \| -| . | -\| \| -| optional DiagnosticsData diagnostics = 50; | -\| \| -| optional RxData rx_data = 51; | -\| \| -| optional AppConfigData app_config = 52; | -\| \| -| . | -\| \| -| . | -\| \| -| . | -\| \| -| } | -\| \| -| message RxData { | -\| \| -| optional uint32 source_endpoint = 2; | -\| \| -| optional uint32 destination_endpoint = 4; | -\| \| -| optional uint32 qos = 5 \[default = 0]; | -\| \| -| optional bytes payload = 7 \[(nanopb).max_size = 1024]; | -\| \| -| } | -\+-----------------------------------------------------------+ - -# Basic data flow and real time situation data - -## Basic data flow to get continuous data +Part of message.proto: + +```protobuf +message Message { + . + . + . + optional DiagnosticsData diagnostics = 50; + optional RxData rx_data = 51; + optional AppConfigData app_config = 52; + . + . + . +} + +message RxData { + optional uint32 source_endpoint = 2; + optional uint32 destination_endpoint = 4; + optional uint32 qos = 5 [default = 0]; + optional bytes payload = 7 [(nanopb).max_size = 1024]; +} +``` + +## Basic data flow and real time situation data + + +### Basic data flow to get continuous data - Generate e.g. UUID (version 4) which is used as *originator token* for metadata changes. @@ -2599,7 +2179,7 @@ Table 46: Part of message.proto - If you need this non-node metadata in your application, you need to store the related information as the real time situation - connection message's *metadata_update_message* will only + connection message's *metadata\_update\_message* will only contain the changed information. - Connect to the real time situation service and authenticate with the @@ -2632,12 +2212,12 @@ Table 46: Part of message.proto - You need to keep the initial node state and then apply the changed fields incrementally. - - Messages will contain *network_id* and *source_address* + - Messages will contain *network\_id* and *source\_address* fields to distinguish between the nodes. - Any metadata change will be provided via the connection. - - You can use the *originator_token* to distinct the changes + - You can use the *originator\_token* to distinct the changes made by you. - When you wish to stop receiving the real time data please close the @@ -2648,7 +2228,7 @@ connection is closed, you need to connect and [*login*](#login) again to the authentication service, and the service will provide a new *session id*. -## Real time situation data +### Real time situation data Real time situation component uses Protocol Buffers messages to send the data. All the incoming messages have a message called Message as a root @@ -2656,28 +2236,26 @@ item (please see message.proto). Table 47: Important message fields - Field name Description - -* * * - - network_id Network id of the node which sent the message. - source_address Node id of the node which sent the message. - gateway_id Id of the gateway which routed the message. - tx_time Time when the packet was generated by the node. - rx_time Time when the packet was received by the gateway. - travel_time_ms How long it took for gateway to receive the packet (rx_time -- tx_time). - diagnostics \* Diagnostics data that the node has generated. Contains also the node role and mode. - rx_data \* Data message information (end points, qos etc.). - app_config \* Application configuration data and diagnostics interval (sent only by the sinks). - network_channel Network channel (sent only by the sinks). - security_enabled Are cipher and encryption keys set for the network (sent only by the sinks). - app_config_response \* Response for setting of the app config (sent only by the sinks). - gateway_info \* Gateway information response data. - scratchpad_status \* Scratchpad status response data. - online_status \* Node online status determined by the backend. - node_metadata \* Node metadata (location, name, description, positioning role etc.) - rtsituation_metadata \* Information about real time situation manager (node count). - metadata_update_message \* Non-node related metadata update information. +| Field name | Description | +| ------------------------------ | -------------------------------------------------------------------------------------| +| network\_id | Network id of the node which sent the message. | +| source\_address | Node id of the node which sent the message. | +| gateway\_id | Id of the gateway which routed the message. | +| tx\_time | Time when the packet was generated by the node. | +| rx\_time | Time when the packet was received by the gateway. | +| travel\_time\_ms | How long it took for gateway to receive the packet (rx\_time -- tx\_time). | +| diagnostics \* | Diagnostics data that the node has generated. Contains also the node role and mode. | +| rx\_data \* | Data message information (end points, qos etc.). | +| app\_config \* | Application configuration data and diagnostics interval (sent only by the sinks). | +| network\_channel | Network channel (sent only by the sinks). | +| security\_enabled | Are cipher and encryption keys set for the network (sent only by the sinks). | +| app\_config\_response \* | Response for setting of the app config (sent only by the sinks). | +| gateway\_info \* | Gateway information response data. | +| scratchpad\_status \* | Scratchpad status response data. | +| online\_status \* | Node online status determined by the backend. | +| node\_metadata \* | Node metadata (location, name, description, positioning role etc.) | +| rtsituation\_metadata \* | Information about real time situation manager (node count). | +| metadata\_update\_message \* | Non-node related metadata update information. | \*) Sub-message @@ -2686,9 +2264,9 @@ seconds as a batch processing, so the incoming message via the real time situation connection can contain merged information from several messages of a node. -# Coordinate conversions +## Coordinate conversions -## Introduction + When a floor plan is added into WNT it is required to input the latitude/longitude/altitude (WGS84) of four reference points (A, B, C, @@ -2710,27 +2288,40 @@ corner has the coordinate (0,0) pixels. Given the floorplan information provided by the WNT API the following matrices/vectors are used: -- Rotation matrix (using *rotation_matrix*): +- Rotation matrix (using *rotation\_matrix*): -$$R = \\begin{bmatrix} -m*{11} & m*{12} & m*{13} \\ -m*{21} & m*{22} & m*{23} \\ -m*{31} & m*{32} & m\_{33} \\ -\\end{bmatrix}$$ +![](./media/eq_rotation_matrix.gif) -- Translation matrix (using *offset_local_to_ecef* ): + + +- Translation matrix (using *offset\_local\_to\_ecef* ): + +![](./media/eq_translation_matrix.gif) -$$T\_{r} = \\begin{bmatrix} + - Scaling: -$$s = \\ pixels\_ per\_ meter$$ +![](./media/eq_scale_pixel_meter.gif) -## WGS84 to pixels + + + +### WGS84 to pixels To convert a WGS84 coordinate to pixels the following steps are required: @@ -2741,115 +2332,171 @@ required: 2. Given $E$ the ECEF coordinate vector compute the pixel coordinates $P$ as: -$$P = R \\bullet \\left( E - T\_{r} \\right) \\bullet s$$ +![](./media/eq_ecef_coordinate_vector.gif) + + The matrix operations can be equivalently expressed as: -$$p*{x} = (m*{11} \\bullet dx + m*{12} \\bullet dy\\ + \\ m*{13} \\bullet dz) \\bullet s$$ +![](./media/eq_px.gif) + +![](./media/eq_py.gif) -$$p*{y} = (m*{21} \\bullet dx + m*{22} \\bullet dy\\ + \\ m*{23} \\bullet dz) \\bullet s$$ + where: -$$\\begin{bmatrix} -\\text{dx} \\ -\\text{dy} \\ -\\text{dz} \\ -\\end{bmatrix} = E - T\_{r}$$ +![](./media/eq_dxyz.gif) -## Pixels to WGS84 + -To convert a pixel coordinate $(p*{x},p*{y})$ to WGS84 the following +### Pixels to WGS84 + +To convert a pixel coordinate $(p_{x},p_{y})$ to WGS84 the following steps are required: 1. Compute the ECEF coordinate as: -$$E = \\frac{R^{'} \\bullet P}{s} + T\_{r}$$ + + +![](./media/eq_ecef_coordinates.gif) where: -$$P = \\begin{bmatrix} -p*{x} \\ -p*{y} \\ + + +![](./media/eq_p_vector.gif) and $R^{'}$ denote the transpose matrix. 2. Convert the ECEF coordinate to WGS84 as shown in chapter 9.5. -## WGS84 to ECEF conversion +### WGS84 to ECEF conversion -Given a WGS84 coordinate as: ϕ latitude in radians, λ longitude in -radians, $h$ altitude in meters the ECEF coordinate $E = \\begin{bmatrix} +Given a WGS84 coordinate as: :phi: latitude in radians, :lambda: longitude in +radians, $h$ altitude in meters the ECEF coordinate + +![](./media/eq_e_matrix.gif) + + + +in meters is computed as: + + -$$x = (v + h) \\bullet cos(\\varphi) \\bullet cos(\\lambda)$$ +![](./media/eq_ecef_x.gif) -$$y = (v + h) \\bullet cos(\\varphi) \\bullet sin(\\lambda)$$ +![](./media/eq_ecef_y.gif) -$$z = (v \\bullet (1 - e\_{2}) + h) \\bullet sin(\\varphi)$$ +![](./media/eq_ecef_z.gif) where: -$$v = \\frac{a}{\\sqrt{1 - e\_{2} \\bullet {sin(\\varphi)}^{2}}}$$ +![](./media/eq_v_a_e.gif) + + -## ECEF to WGS84 conversion +### ECEF to WGS84 conversion The conversion from ECEF to WGS84 is an iterative process. Starting from an initial state computed as: -$$p = \\sqrt{x^{2} + y^{2}}$$ +![](./media/eq_initial_state.gif) + + -$$\\varphi\_{0} = \\varphi$$ +Iterate the following equations until $\Delta\varphi < 10^{- 12}\ $and +$\Delta h < \ 10^{- 5}$: -$$h\_{0} = h$$ +![](./media/eq_iterations.gif) -$$v = \\frac{a}{\\sqrt{1 - e\_{2} \\bullet {sin(\\varphi)}^{2}}}$$ + -where $\\left| \\bullet \\right|$ denotes the absolute value and -$e\_{2}\\ $is the same as in chapter 9.4. +where $\left| \bullet \right|$ denotes the absolute value and +$e_{2}\ $is the same as in chapter 9.4. Finally compute longitude as: -$$\\lambda = atan2(y,\\ x)$$ + + +![](./media/eq_lambda_atan.gif) Note that the latitude and longitude values are in radians and the altitude in meters. -# References +## References -\[1] WP-RM-100 - Wirepas Connectivity Dual-MCU API Reference Manual +\[1\] WP-RM-100 - Wirepas Connectivity Dual-MCU API Reference Manual -\[2] WP-UG-421 - Wirepas Network Tool - Client User Guide +\[2\] WP-UG-421 - Wirepas Network Tool - Client User Guide -\[3] WP-RM-104 - Wirepas Mesh Diagnostics Reference Manual +\[3\] WP-RM-104 - Wirepas Mesh Diagnostics Reference Manual -\[4] +\[4\] https://github.com/wirepas/backend-client