Jan VdA
Published © GPL3+

Generating GPS Traces for Upload in OpenStreetMap

How to generate detailed GPS traces on your phone, upload them in real time, and visualize them directly on OpenStreetMap. Read further.

IntermediateFull instructions provided4 hours2,594

Things used in this project

Hardware components

Android device
Android device
×1

Software apps and online services

Tasker
RESTask for Tasker
This tasker plugin is used to send a POST HTTP request to Artik Cloud containing the manifest data.
ARTIK Cloud for IoT
Samsung ARTIK Cloud for IoT
Node-RED on IBM Cloud
Node-RED on IBM Cloud
Currently you can run one instance of node-red with 512 MB of memory for free on IBM Bluemix. Instead of using this cloud service, you can also use a Node-RED instance that is running on a raspberry pi (or another device).
node-red-dashboard
This module provides a set of nodes in Node-RED to quickly create a live data dashboard.
node-red-contrib-web-worldmap
This module provides a node in Node-RED that I have used to plot my tracks.

Story

Read more

Code

"Send Location" Tasker Task

XML
For more information see A.2.2.
Don't forget to replace __YOUR_ARTIK_CLOUD_DEVICE_ID__" (appearing 3 times) and __YOUR_ARTIK_CLOUD_DEVICE_TOKEN__ with you Device ID and Device Toke (see A.1.3)
<TaskerData sr="" dvi="1" tv="4.8u5m">
<Task sr="task2">
<cdate>1474669609880</cdate>
<edate>1475649395190</edate>
<id>2</id>
<nme>Send Location</nme>
<pri>100</pri>
<stayawake>true</stayawake>
<Action sr="act0" ve="7">
<code>902</code>
<Int sr="arg0" val="0"/>
<Int sr="arg1" val="20"/>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="1"/>
</Action>
<Action sr="act1" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">%LOC
%LOCN</Str>
<Int sr="arg1" val="0"/>
</Action>
<Action sr="act10" ve="7">
<code>410</code>
<Str sr="arg0" ve="3">jsonmsg</Str>
<Str sr="arg1" ve="3">{"data" :
{"battery_level":"%BATT",
"location_from_gps":{"accuracy":"%LOCACC",
"altitude":"%LOCALT",
"fix_time":"%LOCTMS",
"latitude":"%gps_location1",
"longitude":"%gps_location2",
"speed":"%LOCSPD"},
"location_from_net":{"accuracy":"%LOCNACC",
"fix_time":"%LOCNTMS",
"latitude":"%net_location1",
"longitude":"%net_location2"},
"time_seconds":"%TIMES"}
"sdid": "__YOUR_ARTIK_CLOUD_DEVICE_ID__",  
"type": "message" }</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="1"/>
</Action>
<Action sr="act2" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%gps_location</Str>
<Str sr="arg1" ve="3">%LOC</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act3" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%net_location</Str>
<Str sr="arg1" ve="3">,</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act4" ve="7">
<code>590</code>
<Str sr="arg0" ve="3">%gps_location</Str>
<Str sr="arg1" ve="3">,</Str>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act5" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%net_location</Str>
<Str sr="arg1" ve="3">%LOCN</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act6" ve="7">
<code>554915598</code>
<Bundle sr="arg0">
<Vals sr="val">
<bundle_header>Content-Type application/json||Authorization Bearer __YOUR_ARTIK_CLOUD_DEVICE_TOKEN__</bundle_header>
<bundle_header-type>java.lang.String</bundle_header-type>
<bundle_param></bundle_param>
<bundle_param-type>java.lang.String</bundle_param-type>
<com.freehaha.restask.BASICAUTH></com.freehaha.restask.BASICAUTH>
<com.freehaha.restask.BASICAUTH-type>java.lang.String</com.freehaha.restask.BASICAUTH-type>
<com.freehaha.restask.BODY>{"data" :
{"battery_level":%BATT,
"location_from_gps":{"accuracy":%LOCACC,
"altitude":%LOCALT,
"fix_time":%LOCTMS,
"latitude":%gps_location1,
"longitude":%gps_location2,
"speed":%LOCSPD},
"location_from_net":{"accuracy":%LOCNACC,
"fix_time":%LOCNTMS,
"latitude":%net_location1,
"longitude":%net_location2},
"time_seconds":%TIMES},
"sdid": "__YOUR_ARTIK_CLOUD_DEVICE_ID__",  
"type": "message" }</com.freehaha.restask.BODY>
<com.freehaha.restask.BODY-type>java.lang.String</com.freehaha.restask.BODY-type>
<com.freehaha.restask.CERT></com.freehaha.restask.CERT>
<com.freehaha.restask.CERT-type>java.lang.String</com.freehaha.restask.CERT-type>
<com.freehaha.restask.CERTPATH>empty</com.freehaha.restask.CERTPATH>
<com.freehaha.restask.CERTPATH-type>java.lang.String</com.freehaha.restask.CERTPATH-type>
<com.freehaha.restask.CHUNKED>n</com.freehaha.restask.CHUNKED>
<com.freehaha.restask.CHUNKED-type>java.lang.String</com.freehaha.restask.CHUNKED-type>
<com.freehaha.restask.COOKIE>%rtck</com.freehaha.restask.COOKIE>
<com.freehaha.restask.COOKIE-type>java.lang.String</com.freehaha.restask.COOKIE-type>
<com.freehaha.restask.COOKIEJAR>restask</com.freehaha.restask.COOKIEJAR>
<com.freehaha.restask.COOKIEJAR-type>java.lang.String</com.freehaha.restask.COOKIEJAR-type>
<com.freehaha.restask.CUSTOMBODY>y</com.freehaha.restask.CUSTOMBODY>
<com.freehaha.restask.CUSTOMBODY-type>java.lang.String</com.freehaha.restask.CUSTOMBODY-type>
<com.freehaha.restask.CUSTOMECERT>n</com.freehaha.restask.CUSTOMECERT>
<com.freehaha.restask.CUSTOMECERT-type>java.lang.String</com.freehaha.restask.CUSTOMECERT-type>
<com.freehaha.restask.HEADER>%rthdr</com.freehaha.restask.HEADER>
<com.freehaha.restask.HEADER-type>java.lang.String</com.freehaha.restask.HEADER-type>
<com.freehaha.restask.HOST>https://api.artik.cloud/v1.1/messages</com.freehaha.restask.HOST>
<com.freehaha.restask.HOST-type>java.lang.String</com.freehaha.restask.HOST-type>
<com.freehaha.restask.KEEP_COOKIE>n</com.freehaha.restask.KEEP_COOKIE>
<com.freehaha.restask.KEEP_COOKIE-type>java.lang.String</com.freehaha.restask.KEEP_COOKIE-type>
<com.freehaha.restask.OUTPUT_FILE>response.txt</com.freehaha.restask.OUTPUT_FILE>
<com.freehaha.restask.OUTPUT_FILE-type>java.lang.String</com.freehaha.restask.OUTPUT_FILE-type>
<com.freehaha.restask.REDIRECT>y</com.freehaha.restask.REDIRECT>
<com.freehaha.restask.REDIRECT-type>java.lang.String</com.freehaha.restask.REDIRECT-type>
<com.freehaha.restask.RESPONSE>%rtres</com.freehaha.restask.RESPONSE>
<com.freehaha.restask.RESPONSE-type>java.lang.String</com.freehaha.restask.RESPONSE-type>
<com.freehaha.restask.RETCODE>%rtcode</com.freehaha.restask.RETCODE>
<com.freehaha.restask.RETCODE-type>java.lang.String</com.freehaha.restask.RETCODE-type>
<com.freehaha.restask.SYNCCALL>n</com.freehaha.restask.SYNCCALL>
<com.freehaha.restask.SYNCCALL-type>java.lang.String</com.freehaha.restask.SYNCCALL-type>
<com.freehaha.restask.TIMEOUT>30</com.freehaha.restask.TIMEOUT>
<com.freehaha.restask.TIMEOUT-type>java.lang.String</com.freehaha.restask.TIMEOUT-type>
<com.freehaha.restask.TYPE>POST</com.freehaha.restask.TYPE>
<com.freehaha.restask.TYPE-type>java.lang.String</com.freehaha.restask.TYPE-type>
<com.twofortyfouram.locale.intent.extra.BLURB>REST call</com.twofortyfouram.locale.intent.extra.BLURB>
<com.twofortyfouram.locale.intent.extra.BLURB-type>java.lang.String</com.twofortyfouram.locale.intent.extra.BLURB-type>
<net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS>com.freehaha.restask.TYPE com.freehaha.restask.HOST com.freehaha.restask.TIMEOUT com.freehaha.restask.BASICAUTH com.freehaha.restask.CUSTOMBODY com.freehaha.restask.BODY com.freehaha.restask.CUSTOMECERT com.freehaha.restask.CERTPATH com.freehaha.restask.SYNCCALL com.freehaha.restask.HEADER com.freehaha.restask.COOKIE com.freehaha.restask.COOKIEJAR com.freehaha.restask.KEEP_COOKIE com.freehaha.restask.REDIRECT com.freehaha.restask.CHUNKED com.freehaha.restask.OUTPUT_FILE bundle_param bundle_header</net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS>
<net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS-type>java.lang.String</net.dinglisch.android.tasker.extras.VARIABLE_REPLACE_KEYS-type>
<net.dinglisch.android.tasker.subbundled>true</net.dinglisch.android.tasker.subbundled>
<net.dinglisch.android.tasker.subbundled-type>java.lang.Boolean</net.dinglisch.android.tasker.subbundled-type>
</Vals>
</Bundle>
<Str sr="arg1" ve="3">com.freehaha.restask</Str>
<Str sr="arg2" ve="3">com.freehaha.restask.EditActivity</Str>
<Int sr="arg3" val="10"/>
</Action>
<Action sr="act7" ve="7">
<code>417</code>
<Str sr="arg0" ve="3">response.txt</Str>
<Str sr="arg1" ve="3">%responsetxt</Str>
</Action>
<Action sr="act8" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">%responsetxt</Str>
<Int sr="arg1" val="0"/>
</Action>
<Action sr="act9" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">{"data" :
{"battery_level":%BATT,
"location_from_gps":{"accuracy":%LOCACC,
"altitude":%LOCALT,
"fix_time":%LOCTMS,
"latitude":%gps_location1,
"longitude":%gps_location2,
"speed":%LOCSPD},
"location_from_net":{"accuracy":%LOCNACC,
"fix_time":%LOCNTMS,
"latitude":%net_location1,
"longitude":%net_location2},
"time_seconds":%TIMES},
"sdid": "__YOUR_ARTIK_CLOUD_DEVICE_ID__",  
"type": "message" }</Str>
<Int sr="arg1" val="0"/>
</Action>
</Task>
</TaskerData>

"Loop send location" Tasker Task

XML
For more information see A.2.3.
<TaskerData sr="" dvi="1" tv="4.8u5m">
<Task sr="task6">
<cdate>1475420604048</cdate>
<edate>1475649653900</edate>
<id>6</id>
<nme>Loop Send Location</nme>
<pri>100</pri>
<Action sr="act0" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">Starting loop send location</Str>
<Int sr="arg1" val="0"/>
</Action>
<Action sr="act1" ve="7">
<code>902</code>
<Int sr="arg0" val="0"/>
<Int sr="arg1" val="100"/>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act2" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%StopLoopSendLocation</Str>
<Str sr="arg1" ve="3">0</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act3" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%count</Str>
<Str sr="arg1" ve="3">0</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act4" ve="7">
<code>888</code>
<label>LoopStart</label>
<Str sr="arg0" ve="3">%count</Str>
<Int sr="arg1" val="1"/>
<Int sr="arg2" val="0"/>
</Action>
<Action sr="act5" ve="7">
<code>130</code>
<Str sr="arg0" ve="3">Send Location</Str>
<Int sr="arg1">
<var>%priority</var>
</Int>
<Str sr="arg2" ve="3"/>
<Str sr="arg3" ve="3"/>
<Str sr="arg4" ve="3"/>
<Int sr="arg5" val="0"/>
</Action>
<Action sr="act6" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">%count</Str>
<Int sr="arg1" val="0"/>
</Action>
<Action sr="act7" ve="7">
<code>135</code>
<Int sr="arg0" val="1"/>
<Int sr="arg1" val="2"/>
<Str sr="arg2" ve="3">LoopStart</Str>
<ConditionList sr="if">
<bool0>And</bool0>
<Condition sr="c0" ve="3">
<lhs>%count</lhs>
<op>6</op>
<rhs>30</rhs>
</Condition>
<Condition sr="c1" ve="3">
<lhs>%StopLoopSendLocation</lhs>
<op>9</op>
<rhs>1</rhs>
</Condition>
</ConditionList>
</Action>
<Action sr="act8" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">Task Loop send location finished</Str>
<Int sr="arg1" val="0"/>
</Action>
<Img sr="icn" ve="2">
<nme>cust_flag</nme>
</Img>
</Task>
</TaskerData>

"Loop stop location" Tasker task

XML
For more information see A.2.4.
<TaskerData sr="" dvi="1" tv="4.8u5m">
<Task sr="task7">
<cdate>1475421554436</cdate>
<edate>1475649746484</edate>
<id>7</id>
<nme>Stop Loop Send Location</nme>
<Action sr="act0" ve="7">
<code>547</code>
<Str sr="arg0" ve="3">%StopLoopSendLocation</Str>
<Str sr="arg1" ve="3">1</Str>
<Int sr="arg2" val="0"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act1" ve="7">
<code>548</code>
<Str sr="arg0" ve="3">%StopLoopSendLocation</Str>
<Int sr="arg1" val="0"/>
</Action>
<Img sr="icn" ve="2">
<nme>cust_flag</nme>
</Img>
</Task>
</TaskerData>

Node-RED gps-traces flow

JSON
This flow is explained in detail in section B.2.3.
Before importing this flow you must substitute the following strings __ARTIK_CLOUD_DEVICE_ID__, __NODE_RED_URL__ and __ARTIK_CLOUD_CLIENT_ID__ by the appropriate value (see A.1.3, B.2.1 and B.1)
[{"id":"276b1743.0a9cd8","type":"worldmap","z":"dc5b159e.afc498","lat":"51.17","lon":"4.45","zoom":"","layer":"OSM grey","cluster":"","maxage":"","name":"worldmap","x":911,"y":916,"wires":[]},{"id":"366fc524.8f41da","type":"http in","z":"dc5b159e.afc498","name":"artik callback","url":"/from_artik","method":"get","swaggerDoc":"","x":116,"y":218,"wires":[["506195bf.d1939c","e9e04361.c752f","1675d522.50cc3b","6c3516c5.d7ccd8"]]},{"id":"506195bf.d1939c","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"true","x":292,"y":149,"wires":[]},{"id":"e9e04361.c752f","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"false","x":313,"y":179,"wires":[]},{"id":"be1637bb.646d38","type":"comment","z":"dc5b159e.afc498","name":"Authenticate with Artic Cloud","info":"see [OAuth2 flow examples](https://developer.artik.cloud/documentation/tutorials/oauth2-flow-examples.html)\n","x":125,"y":66,"wires":[]},{"id":"1c0c2e47.996892","type":"ui_template","z":"dc5b159e.afc498","group":"31cdf6b.7b1bf0a","name":"login url to artik","order":1,"width":"0","height":"0","format":"<div>\nClick on link below to retrieve new access token.\nNote that this will open in a new browser window.\n<a href=\"https://accounts.artik.cloud/authorize?client_id=__ARTIK_CLOUD_CLIENT_ID__&response_type=code&redirect_uri=https://__NODE_RED_URL__/from_artik&state=abcdefgh\" target=\"_blank\">login to artik</a>\n</div>","storeOutMessages":true,"fwdInMessages":true,"x":132,"y":128,"wires":[["ef937123.9ef9f"]]},{"id":"ce8e9f1f.baf21","type":"http request","z":"dc5b159e.afc498","name":"","method":"POST","ret":"txt","url":"","tls":"","x":384,"y":317,"wires":[["54c7cedb.f3428","7e1bf0c3.f66b4"]]},{"id":"1675d522.50cc3b","type":"function","z":"dc5b159e.afc498","name":"construct authorization url","func":"// prepare request\n\nmsg.url=\"https://accounts.artik.cloud/token?grant_type=authorization_code&code=\"+\n         msg.payload.code + \n         \"&redirect_uri=https://__NODE_RED_URL__/from_artik&state=abcdefgh\";\n\nreturn msg;","outputs":1,"noerr":0,"x":291,"y":286,"wires":[["ce8e9f1f.baf21"]]},{"id":"ef937123.9ef9f","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"true","x":290,"y":101,"wires":[]},{"id":"e45b0814.2e2168","type":"ui_button","z":"dc5b159e.afc498","name":"","group":"dfa99a3d.e34758","order":1,"width":0,"height":0,"label":"plot all messages","color":"","icon":"","payload":"artik_msgs","payloadType":"flow","topic":"show","x":109,"y":883,"wires":[["a27002d8.ac1c9","f5193dea.2d746"]]},{"id":"34160e36.e5aae2","type":"http request","z":"dc5b159e.afc498","name":"","method":"GET","ret":"txt","url":"","tls":"","x":187,"y":687,"wires":[["e75beac5.acd1e8","6e2662e0.22a36c"]]},{"id":"7f87e3d5.8f977c","type":"function","z":"dc5b159e.afc498","name":"store access token and refresh token in context","func":"// store the access and refresh token in this flow context.\nflow.set(\"access_token\",msg.payload.access_token);\nflow.set(\"refresh_token\",msg.payload.refresh_token);\nreturn msg;","outputs":1,"noerr":0,"x":545,"y":378,"wires":[["12b2c96f.84f737"]]},{"id":"e75beac5.acd1e8","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"payload","x":529,"y":687,"wires":[]},{"id":"77d41c24.cc2b44","type":"function","z":"dc5b159e.afc498","name":"prepare last messages request for artik cloud","func":"msg.headers = { \"Authorization\" : \"Bearer \" + flow.get(\"access_token\") };\nmsg.url = \"https://api.artik.cloud/v1.1/messages/last?sdids=\"+\n           \"__ARTIK_CLOUD_DEVICE_ID__&count=\"+msg.payload;\n\nreturn msg;","outputs":1,"noerr":0,"x":230,"y":657,"wires":[["34160e36.e5aae2","addb855d.f0e638"]]},{"id":"f8073913.dca468","type":"comment","z":"dc5b159e.afc498","name":"Retrieve Messages from Artik Cloud","info":"see [Use and Access Token](https://developer.artik.cloud/documentation/introduction/authentication.html#use-an-access-token)","x":145,"y":522,"wires":[]},{"id":"addb855d.f0e638","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"true","x":511,"y":655,"wires":[]},{"id":"54c7cedb.f3428","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"false","x":575,"y":316,"wires":[]},{"id":"1a81bfb3.c88ed","type":"http in","z":"dc5b159e.afc498","name":"/home page","url":"/home","method":"get","swaggerDoc":"","x":75,"y":23,"wires":[["1c2400fc.6f657f"]]},{"id":"a29ba0b9.c1428","type":"http response","z":"dc5b159e.afc498","name":"","x":595,"y":22,"wires":[]},{"id":"1c2400fc.6f657f","type":"template","z":"dc5b159e.afc498","name":"home page = 2 frames : worldmap and artik ui","field":"payload","fieldType":"msg","format":"html","syntax":"plain","template":"<!DOCTYPE html>\n<html>\n  <frameset cols=\"80%,20%\">\n  <frame src=\"worldmap\">\n  <frame src=\"ui\">\n</frameset>\n</html>","x":343,"y":22,"wires":[["a29ba0b9.c1428"]]},{"id":"a27002d8.ac1c9","type":"function","z":"dc5b159e.afc498","name":"create worldmap LINE for GPS and NET coordinates","func":"\nvar outputMsg  = {\"payload\": { \"name\": \"mytrack\"    , \"iconColor\" : \"Blue\" , \"layer\" : \"GPStrack\", \n                               \"deleted\": ( msg.topic == \"delete\")}};\nvar outputMsg2 = {\"payload\": { \"name\": \"mytrack_net\", \"iconColor\" : \"Red\"  , \"layer\" : \"NETtrack\", \n                               \"deleted\" : ( msg.topic == \"delete\")}};\nvar line = [];\nvar line_net = [];\n\nvar msgs = msg.payload;\nvar msgcount = msgs.length;\nfor (var i = 0; i < msgcount; i++) {\n    line[i]=     [ msgs[i].data.location_from_gps.latitude, msgs[i].data.location_from_gps.longitude];\n    line_net[i]= [ msgs[i].data.location_from_net.latitude, msgs[i].data.location_from_net.longitude];\n}\noutputMsg.payload.line  = line;\noutputMsg2.payload.line = line_net;\nreturn [outputMsg , outputMsg2];","outputs":"2","noerr":0,"x":501,"y":883,"wires":[["f84e3493.008f38","276b1743.0a9cd8"],["eca9e994.2d8478","276b1743.0a9cd8"]]},{"id":"f84e3493.008f38","type":"debug","z":"dc5b159e.afc498","name":"GPS coordinates","active":true,"console":"false","complete":"payload","x":822,"y":833,"wires":[]},{"id":"6e2662e0.22a36c","type":"json","z":"dc5b159e.afc498","name":"convert to json","x":234,"y":718,"wires":[["ebb812a0.cf95a","16d075e7.d63dda","4d9ad473.2f338c"]]},{"id":"f5193dea.2d746","type":"split","z":"dc5b159e.afc498","name":"split array in individual msgs","splt":"\\n","x":422,"y":914,"wires":[["aebb4ed3.b73ea","2ad02196.47532e"]]},{"id":"aebb4ed3.b73ea","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"true","x":642,"y":915,"wires":[]},{"id":"2ad02196.47532e","type":"function","z":"dc5b159e.afc498","name":"create worldmap point for GPS and NET coordinates","func":"var msgGPS = { \"payload\" : {\n    \"name\"   : \"msg_GPS\"+ msg.parts.index,\n    \"lat\"    : msg.payload.data.location_from_gps.latitude,\n    \"lon\"    : msg.payload.data.location_from_gps.longitude,\n    \"accuracy\" : msg.payload.data.location_from_gps.accuracy,\n    \"fix_time\"  : new Date(msg.payload.data.location_from_gps.fix_time*1000),\n    \"time\"      : new Date(msg.payload.data.time_seconds*1000),\n    \"altitude\"  : msg.payload.data.location_from_gps.altitude,\n    \"speed\"     : msg.payload.data.location_from_gps.speed,\n    \"icon\"      : \"globe\",\n    \"iconColor\" : \"Blue\",\n    \"layer\"     : \"GPS\",\n    \"deleted\"   : ( msg.topic == \"delete\")\n    }\n};\n\nvar msgGPSRadius = { \"payload\" : {\n    \"name\"   : \"msg_GPSradius\"+ msg.parts.index,\n    \"lat\"    : msg.payload.data.location_from_gps.latitude,\n    \"lon\"    : msg.payload.data.location_from_gps.longitude,\n    \"radius\" : msg.payload.data.location_from_gps.accuracy,\n    \"iconColor\" : \"Blue\",\n    \"layer\"     : \"GPSradius\",\n    \"deleted\"   : ( msg.topic == \"delete\")\n    }\n};\n\nvar msgNet = { \"payload\" : {\n    \"name\"   : \"msg_NET\"+ msg.parts.index,\n    \"lat\"    : msg.payload.data.location_from_net.latitude,\n    \"lon\"    : msg.payload.data.location_from_net.longitude,\n    \"fix_time\"  : new Date(msg.payload.data.location_from_net.fix_time*1000),\n    \"time\"      : new Date(msg.payload.data.time_seconds*1000),\n    \"accuracy\"  : msg.payload.data.location_from_net.accuracy,\n    \"icon\"      : \"globe\",\n    \"iconColor\" : \"Red\",\n    \"layer\"     : \"NET\" ,\n    \"deleted\"   : ( msg.topic == \"delete\")\n  }\n};\n\nvar msgNetRadius = { \"payload\" : {\n    \"name\"   : \"msg_NETradius\"+ msg.parts.index,\n    \"lat\"    : msg.payload.data.location_from_net.latitude,\n    \"lon\"    : msg.payload.data.location_from_net.longitude,\n    \"radius\"  : msg.payload.data.location_from_net.accuracy,\n    \"iconColor\" : \"Red\",\n    \"layer\"     : \"NETradius\" ,\n    \"deleted\"   : ( msg.topic == \"delete\")\n  }\n};\n\nreturn [ msgGPS, msgGPSRadius, msgNet, msgNetRadius];","outputs":"4","noerr":0,"x":547,"y":960,"wires":[["276b1743.0a9cd8"],["276b1743.0a9cd8"],["276b1743.0a9cd8"],["276b1743.0a9cd8"]]},{"id":"189e6d03.586e13","type":"ui_dropdown","z":"dc5b159e.afc498","name":"specify number of messages to retrieve and plot","label":"number of messages to retrieve","group":"ab3593d0.8618a","order":1,"width":0,"height":0,"options":[{"label":"1 msg","value":"1"},{"label":"5 msgs","value":"5"},{"label":"10 msgs","value":"10"},{"label":"20 msgs","value":"20"},{"label":"50 msgs","value":"50"},{"label":"100 msgs","value":"100"}],"payload":"","topic":"","x":207,"y":553,"wires":[["a705135c.7ac31","ef86dac7.736038"]]},{"id":"a705135c.7ac31","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"payload","x":508,"y":585,"wires":[]},{"id":"ebb812a0.cf95a","type":"function","z":"dc5b159e.afc498","name":"store msgs in context var: \"artik_msgs\" ","func":"\nflow.set(\"artik_msgs\",msg.payload.data);\n\nreturn msg;","outputs":1,"noerr":0,"x":514,"y":719,"wires":[[]]},{"id":"eca9e994.2d8478","type":"debug","z":"dc5b159e.afc498","name":"NET coordinates","active":true,"console":"false","complete":"payload","x":823,"y":864,"wires":[]},{"id":"16d075e7.d63dda","type":"ui_text","z":"dc5b159e.afc498","group":"ab3593d0.8618a","order":3,"width":0,"height":0,"name":"","label":"messages successfully retrieved:","format":"{{msg.payload.data.length}}","layout":"row-spread","x":492,"y":748,"wires":[]},{"id":"a674e0bc.010a","type":"ui_button","z":"dc5b159e.afc498","name":"","group":"ab3593d0.8618a","order":2,"width":0,"height":0,"label":"retrieve messages","color":"","icon":"","payload":"msg_count","payloadType":"flow","topic":"","x":115,"y":627,"wires":[["77d41c24.cc2b44"]]},{"id":"ef86dac7.736038","type":"function","z":"dc5b159e.afc498","name":"store in context var: \"msg_count\"","func":"flow.set(\"msg_count\",msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":575,"y":555,"wires":[[]]},{"id":"42992cd.62a4fd4","type":"ui_button","z":"dc5b159e.afc498","name":"","group":"dfa99a3d.e34758","order":0,"width":0,"height":0,"label":"delete plotted messages","color":"","icon":"","payload":"artik_msgs","payloadType":"flow","topic":"delete","x":139,"y":914,"wires":[["e980a233.91ccf","f5193dea.2d746","a27002d8.ac1c9"]]},{"id":"e980a233.91ccf","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"topic","x":160,"y":943,"wires":[]},{"id":"35342f51.8e19","type":"ui_text","z":"dc5b159e.afc498","group":"31cdf6b.7b1bf0a","order":0,"width":0,"height":0,"name":"","label":"access token","format":"{{msg.payload}}","layout":"row-spread","x":611,"y":447,"wires":[]},{"id":"9b6fe038.65436","type":"inject","z":"dc5b159e.afc498","name":"once at start","topic":"","payload":"access_token","payloadType":"str","repeat":"","crontab":"","once":true,"x":166,"y":420,"wires":[["12b2c96f.84f737"]]},{"id":"12b2c96f.84f737","type":"function","z":"dc5b159e.afc498","name":"return scrambled access and refresh token from context","func":"var msg1 = { payload : flow.get(\"access_token\").substr(0,6) + \"..\" + flow.get(\"access_token\").substr(26) };\nvar msg2 = { payload : flow.get(\"refresh_token\").substr(0,6) + \"..\" + flow.get(\"refresh_token\").substr(26)};\nreturn [ msg1 , msg2 ];","outputs":"2","noerr":0,"x":495,"y":420,"wires":[["35342f51.8e19"],["9f130370.89f8c"]]},{"id":"9f130370.89f8c","type":"ui_text","z":"dc5b159e.afc498","group":"31cdf6b.7b1bf0a","order":0,"width":0,"height":0,"name":"","label":"refresh token","format":"{{msg.payload}}","layout":"row-spread","x":621,"y":475,"wires":[]},{"id":"6c3516c5.d7ccd8","type":"http response","z":"dc5b159e.afc498","name":"","x":291,"y":217,"wires":[]},{"id":"4d9ad473.2f338c","type":"function","z":"dc5b159e.afc498","name":"last message","func":"msg.payload = msg.payload.data[msg.payload.data.length - 1];\nreturn msg;","outputs":1,"noerr":0,"x":427,"y":779,"wires":[["6441082c.9038e8"]]},{"id":"6441082c.9038e8","type":"ui_text","z":"dc5b159e.afc498","group":"ab3593d0.8618a","order":0,"width":"5","height":"5","name":"last message data retrieved","label":"last message data","format":"<PRE>{{msg.payload.data | json : 2 }}</PRE>","layout":"col-center","x":650,"y":779,"wires":[]},{"id":"7e1bf0c3.f66b4","type":"json","z":"dc5b159e.afc498","name":"","x":391,"y":348,"wires":[["7f87e3d5.8f977c"]]},{"id":"204ad8b8.42db48","type":"comment","z":"dc5b159e.afc498","name":"Step 1","info":"","x":76,"y":96,"wires":[]},{"id":"6560ad19.40fe84","type":"comment","z":"dc5b159e.afc498","name":"step 2 (callback)","info":"","x":110,"y":171,"wires":[]},{"id":"2a4735bc.3d2fda","type":"comment","z":"dc5b159e.afc498","name":"step 3: get access token","info":"","x":140,"y":255,"wires":[]},{"id":"c8aaa40c.eb8148","type":"comment","z":"dc5b159e.afc498","name":"Display access token in ui","info":"","x":136,"y":390,"wires":[]},{"id":"f3197432.bf12c8","type":"comment","z":"dc5b159e.afc498","name":"Plot messages on worldmap","info":"","x":126,"y":831,"wires":[]},{"id":"1c117f64.6c6c81","type":"http in","z":"dc5b159e.afc498","name":"gpx","url":"/gpx","method":"get","swaggerDoc":"","x":75,"y":1062,"wires":[["6243ef2e.38f2e"]]},{"id":"99c158e9.7427d8","type":"http response","z":"dc5b159e.afc498","name":"","x":573,"y":1090,"wires":[]},{"id":"6243ef2e.38f2e","type":"function","z":"dc5b159e.afc498","name":"convert artik_msgs to gpx","func":"var artik_msgs = flow.get(\"artik_msgs\");\n\nvar xml = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\" + \n          \"<gpx version=\\\"1.0\\\"\\n\" +\n          \"  xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"\\n\" + \n          \"  xmlns=\\\"http://www.topografix.com/GPX/1/0\\\"\\n\" +\n          \"  xsi:schemaLocation=\\\"http://www.topografix.com/GPX/1/0\\n\" +\n          \"  http://www.topografix.com/GPX/1/0/gpx.xsd\\\">\\n\"+\n          \"  <name>jvda gpx</name>\\n\" +\n          \"  <trk><name>jvda gpx</name><number>1</number><trkseg>\\n\";\n\nfor (var i = 0; i < artik_msgs.length; i++) {\n    xml += \"    <trkpt lat=\\\"\"+ artik_msgs[i].data.location_from_gps.latitude +\n           \"\\\" lon=\\\"\"      + artik_msgs[i].data.location_from_gps.longitude +\n           \"\\\"><ele>\"       + artik_msgs[i].data.location_from_gps.altitude + \"</ele>\" +\n           \"<time>\" + new Date(artik_msgs[i].data.location_from_gps.fix_time*1000).toISOString() + \"</time></trkpt>\\n\";\n}\n\nxml += \"  </trkseg></trk>\\n</gpx>\\n\";\n\nmsg.payload = xml;\n    \nreturn msg;","outputs":1,"noerr":0,"x":257,"y":1062,"wires":[["433f5eb1.644bd","a761b050.abe3b"]]},{"id":"a761b050.abe3b","type":"debug","z":"dc5b159e.afc498","name":"","active":true,"console":"false","complete":"payload","x":466,"y":1058,"wires":[]},{"id":"433f5eb1.644bd","type":"template","z":"dc5b159e.afc498","name":"html page showing gpx track","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html>\n<body>\n    <PRE>{{payload}}</PRE>\n</body>\n</html>","x":373,"y":1092,"wires":[["99c158e9.7427d8"]]},{"id":"2204bcc2.74a394","type":"comment","z":"dc5b159e.afc498","name":"convert to GPX track","info":"","x":105,"y":1021,"wires":[]},{"id":"b0063984.019f28","type":"ui_template","z":"dc5b159e.afc498","group":"6e9506c2.117568","name":"gpx url","order":0,"width":0,"height":0,"format":"<div>\n<a href=\"/gpx\" target=\"_blank\">gpxtrack</a>\n</div>","storeOutMessages":true,"fwdInMessages":true,"x":74,"y":1127,"wires":[[]]},{"id":"31cdf6b.7b1bf0a","type":"ui_group","z":"","name":"Authenticate with Artik Cloud","tab":"9ceeba61.187708","order":1,"disp":true,"width":"6"},{"id":"dfa99a3d.e34758","type":"ui_group","z":"","name":"Plot Messages on Worldmap","tab":"9ceeba61.187708","order":3,"disp":true,"width":"6"},{"id":"ab3593d0.8618a","type":"ui_group","z":"","name":"Retrieve messages from Artik Cloud","tab":"9ceeba61.187708","order":2,"disp":true,"width":"6"},{"id":"6e9506c2.117568","type":"ui_group","z":"dc5b159e.afc498","name":"gpx","tab":"9ceeba61.187708","disp":true,"width":"6"},{"id":"9ceeba61.187708","type":"ui_tab","z":"dc5b159e.afc498","name":"Artik","icon":"dashboard","order":1}]

www.android.com-v7-manifest.json

JSON
The manifest I have used.
{
  "fields": [
    {
      "name": "time_seconds",
      "type": "CUSTOM",
      "valueClass": "Integer",
      "isCollection": false,
      "description": "The current time in seconds: seconds since some time in January, 1970, if you must know",
      "tags": []
    },
    {
      "name": "battery_level",
      "type": "CUSTOM",
      "valueClass": "Integer",
      "isCollection": false,
      "description": "Current device battery level from 0-100",
      "tags": [],
      "unitSymbol": "%"
    },
    {
      "name": "location_from_gps",
      "children": [
        {
          "name": "fix_time",
          "type": "CUSTOM",
          "valueClass": "Integer",
          "isCollection": false,
          "description": "The time in seconds of the last GPS location fix: To get age of fix, take this away from time_seconds",
          "tags": []
        },
        {
          "name": "latitude",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "tags": []
        },
        {
          "name": "longitude",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "tags": []
        },
        {
          "name": "altitude",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "description": "The altitude in metres of the last GPS fix, or 0 if unavailable",
          "tags": [],
          "unitSymbol": "m"
        },
        {
          "name": "speed",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "description": "The speed in metres/second at the last GPS position fix or 0 if unavailable",
          "tags": [],
          "unitSymbol": "m/s"
        },
        {
          "name": "accuracy",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "description": "The accuracy in metres of the last GPS fix",
          "tags": [],
          "unitSymbol": "m"
        }
      ]
    },
    {
      "name": "location_from_net",
      "children": [
        {
          "name": "fix_time",
          "type": "CUSTOM",
          "valueClass": "Integer",
          "isCollection": false,
          "description": "The time in seconds of the last net location fix: To get age of fix, take this away from time_seconds",
          "tags": []
        },
        {
          "name": "latitude",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "description": "latitude of the last network location fix",
          "tags": []
        },
        {
          "name": "longitude",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "description": "longitude of the last network location fix",
          "tags": []
        },
        {
          "name": "accuracy",
          "type": "CUSTOM",
          "valueClass": "Double",
          "isCollection": false,
          "description": "The accuracy in metres of the last network location fix",
          "tags": [],
          "unitSymbol": "m"
        }
      ]
    }
  ],
  "messageFormat": "json",
  "actions": []
}

Credits

Jan VdA

Jan VdA

1 project • 4 followers

Comments