Example flow help required. Live Google Maps Update - Websockets

1,957 views
Skip to first unread message

Ben Orchard

unread,
Apr 28, 2014, 12:43:15 PM4/28/14
to node...@googlegroups.com
Hi Everyone,

I'm really interested in having my phone show up on a map using Own Tracks.
I have been running the app on my Android phone for a while now and it seems to be working well.

This flow here has my attention;


I have two questions;
It clearly states up front that;

You will need to ensure you have your websocket nodes set up correctly with the following settings.

Path: /ws/location
Send/Receive Payload

Googleing around does not provide any hints as to how or where I need to set this path.
(Note, when I hit the map URL, I get a map, so I am not sure if I even need to set this path).

Secondly, the example format is very different from the OwnTracks output.
Here is the example from the flow that it seems to be expecting;

[{"lat":54.9696456,"lng":-1.5069755}]

Here is the OwnTracks output from that Node.

{"_type": "location", "lat": "33.5229008", "lon": "-117.1615798", "tst": "1398471660", "acc": "1174.0", "batt": "38"}

(Not even the spelling of 'lon' is the same??)

Im not sure how or where I need to adjust things to make it work.

Thanks for your help.

Ben.



Doukas Charalampos

unread,
Apr 28, 2014, 4:41:34 PM4/28/14
to node...@googlegroups.com
Hi Ben,

Interesting experiment!

Going briefly through the flow you are using, and the Owntracks wiki (https://github.com/owntracks/owntracks/wiki/Setup), I think you need to setup a MQTT broker  that Owntracks can access for posting the coordinates. Obviously this broker cannot be on your computer, unless you are on a public IP network.

On your NodeRED flow then you would need to subscribe to that broker, receive the location updates, parse the coordinates, and push them to the /ws/location websocket so that the webpage can fetch them and update the map.

Will try to build something similar during the weekend.

Cheers,
Charalampos

Nicholas O'Leary

unread,
Apr 28, 2014, 4:53:07 PM4/28/14
to node...@googlegroups.com
Ben,

to answer a couple of your specific questions...

The flow includes a pair of websocket nodes - they are the ones labelled "[ws] /ws/location" when you import. They are already configured in the manner it says to ensure they are configured... so nothing for you to do there.

As for the json format, there are a lots of different ways latitude and longitude get represented in json - it can be a real pain. Typically latitude is abbreviated to 'lat', but longitude can be anything from 'lon', 'long', 'lng' ... 

You'll need to add a function node at an appropriate point in the flow that parses one format and spits out a new message in the other format. Don't have time right now to get into the fine detail, but hopefully that points you in a direction.

Nick



--
http://nodered.org
---
You received this message because you are subscribed to the Google Groups "Node-RED" group.
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ben Orchard

unread,
Apr 28, 2014, 6:19:46 PM4/28/14
to node...@googlegroups.com
Hi Nick,

Yup, thats a huge help.
(I was confused most about the websocket nodes since this is the first time I have used them).

I have put a function block in and added the following code to change the OwnTracks output;

msg.payload = JSON.parse(msg.payload);
var url = "[{\"lat\":" + msg.payload.lat + ","+"\"lng\":" + msg.payload.lon +"}]";
msg.payload = url;
msg.payload = msg.payload;
return msg;

So now my OwnTracks string looks exactly like the required string, but it does not move the map, so more digging and learning to go.

(For what its worth, it does not move the map to the sample strings either, so just the example flow on its own is simply broken).

Ben.


P.S Charalampos, yep, I have a MQTT broker running on my Ubuntu server and done the port forward on my router.
Works great and am using it for a few things as I experiment with MQTT along side of Node-RED.
I have the OwnTracks Android app pushing updates to the broker just fine.
Node-RED is subscribed to the feed and I have added the code to match the required code, but the map is not updating to the new lat/lng for some reason.
I can see the map in the browser, also, if I connect a debug node to the function block, I can see the HTML code come out with the default map centre cord's. 
Sadly, the debug tab then truncates the remainder of the code, so I cant see the last (interesting) bit of the HTML code.

Thanks for your input, I will keep  digging....

Let me know how you go over the weekend.

Doukas Charalampos

unread,
Apr 29, 2014, 4:56:58 AM4/29/14
to node...@googlegroups.com
Hi Ben, 

Could you post (or email me) the flow to try to replicate it here?

Thanks,
Charalampos

On Monday, April 28, 2014 6:43:15 PM UTC+2, Ben Orchard wrote:

Ben Orchard

unread,
Apr 29, 2014, 9:57:04 AM4/29/14
to node...@googlegroups.com
Hi Charalampos,

Here it is;

I have been able to confirm that it does not work.
The map never moves, so the example is broken.
Im still trying to learn Java Script, so its challenging for me to try and debug why the flow is broken, but it is interesting to learn!

Loving this Node-RED stuff.

Ben.

Dave C-J

unread,
Apr 29, 2014, 2:31:33 PM4/29/14
to node...@googlegroups.com
Hi Ben,

Ok - so the good news is that it can be made to work.... 

The line (20 or so) of the template that you edit - would be better defaulted to
    var server = window.location.hostname;
    var socketaddy = "ws://"+server+":1880/ws/location";
That way in the majority of cases it'll pick up the correct host ip to point at...
However it does assume that you haven't also messed with the settings.js file to move the httpStatic or httpRoot away from their default locations... if so the url would need to be
    "ws://"+server+":1880/{your new path to node red web pages}/ws/location";   etc

here is a tweaked version of that flow (also changed to add some more locations - discussed below), and start the map somewhere in UK and at a lesser zoom level.

[{"id":"54651cc0.ab9ae4","type":"websocket-listener","path":"/ws/location","wholemsg":"false"},{"id":"3ce8dc35.c31724","type":"websocket out","name":"","server":"54651cc0.ab9ae4","x":672,"y":287,"z":"c04f6206.3fb0a","wires":[]},{"id":"a1875909.5e78a8","type":"function","name":"","func":"// The received message is stored in 'msg'\n// It will have at least a 'payload' property:\n//   console.log(msg.payload);\n// The 'context' object is available to store state\n// between invocations of the function\n//   context = {};\ncontext.global.location = msg.payload;\n\nreturn msg;","outputs":1,"x":475,"y":224,"z":"c04f6206.3fb0a","wires":[["3ce8dc35.c31724","3f4c5db6.c0b3a2"]]},{"id":"dced249a.2312d8","type":"websocket in","name":"","server":"54651cc0.ab9ae4","x":255,"y":351,"z":"c04f6206.3fb0a","wires":[["ae7ab97d.518548"]]},{"id":"ae7ab97d.518548","type":"function","name":"","func":"// The received message is stored in 'msg'\n// It will have at least a 'payload' property:\n//   console.log(msg.payload);\n// The 'context' object is available to store state\n// between invocations of the function\n//   context = {};\n\nmsg.payload = context.global.location;\nreturn msg;","outputs":1,"x":483,"y":342,"z":"c04f6206.3fb0a","wires":[["3ce8dc35.c31724"]]},{"id":"7a4c6539.85b39c","type":"template","name":"","template":"<!DOCTYPE html>\n<html>\n<head>\n  <title>Owntracks & Node-Red Live Map</title>\n  <script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js\"></script>\n  <script type=\"text/javascript\" src=\"http://maps.google.com/maps/api/js?sensor=true\"></script>\n  <script type=\"text/javascript\" src=\"http://yourjavascript.com/4594301102/gmaps.js\"></script>\n \n  <style type=\"text/css\" media=\"screen\">\n    #map {\n      position:absolute;\n      top: 0; bottom: 0; left: 0; right: 0;\n    }\n  </style>\n</head>\n<body>\n \n  <div id=\"map\"></div>\n  <script type=\"text/javascript\">\n    var server = window.location.hostname;\n    var socketaddy = \"ws://\"+server+\":1880/admin/ws/location\";\n    var map;\n    var sock;\n    $(document).ready(function(){\n      \n      map = new GMaps({\n        div: '#map',\n        lat: 54,\n        lng: -1\n      });\n      \n      \n      sock = new WebSocket(socketaddy);\n      sock.onopen = function(){ console.log(\"Connected websocket\");\n\t      console.log(\"Sending ping..\");\n\t      sock.send(\"Ping!\");\n\t      console.log(\"Ping sent..\");\n      };\n      sock.onerror = function(){ console.log(\"Websocket error\"); };\n      sock.onmessage = function(evt){\n        var latlng = JSON.parse(evt.data);\n        var array = $.map(latlng, function(el) {\n  \t\t\treturn [[el.lat, el.lng]];\n\t\t\t});\n        \n        map.removeMarkers();\n        map.removePolylines();\n       \tconsole.log(\"Got marker at \" + latlng[0].lat + \", \" + latlng[0].lng, latlng);\n        map.setZoom(12);\n       \tmap.setCenter(latlng[0].lat, latlng[0].lng);\n        map.addMarkers(latlng);\n      \tmap.drawPolyline({\n\t\t  path: array,\n\t\t  strokeColor: '#131540',\n\t\t  strokeOpacity: 0.6,\n\t\t  strokeWeight: 6\n\t\t});\n      }\n    });\n  </script>\n</body>\n</html>","x":465,"y":398,"z":"c04f6206.3fb0a","wires":[["85513d03.7aaec"]]},{"id":"85513d03.7aaec","type":"http response","name":"","x":649,"y":398,"z":"c04f6206.3fb0a","wires":[]},{"id":"ea58b789.15a748","type":"http in","name":"","url":"/map","method":"get","x":244,"y":403,"z":"c04f6206.3fb0a","wires":[["7a4c6539.85b39c"]]},{"id":"3f4c5db6.c0b3a2","type":"debug","name":"","active":true,"console":false,"complete":false,"x":617,"y":174,"z":"c04f6206.3fb0a","wires":[]},{"id":"8cd91314.7326f","type":"inject","name":"Array of Co-ords","topic":"","payload":"[{\"lat\":54.9619349,\"lng\":-1.6003813},{\"lat\":54.9656694,\"lng\":-1.5239833},{\"lat\":54.9696456,\"lng\":-1.5069755},{\"lat\":54.9378907,\"lng\":-1.5273729}]","payloadType":"string","repeat":"","crontab":"","once":false,"x":222,"y":119,"z":"c04f6206.3fb0a","wires":[["a1875909.5e78a8"]]},{"id":"d780c811.287f38","type":"inject","name":"Single Co-ord","topic":"","payload":"[{\"lat\":54.9696456,\"lng\":-1.5069755}]","payloadType":"string","repeat":"","crontab":"","once":false,"x":196,"y":173,"z":"c04f6206.3fb0a","wires":[["a1875909.5e78a8"]]},{"id":"b8a569bc.475a98","type":"inject","name":"Single Co-ord","topic":"","payload":"[{\"lat\":54.5,\"lng\":-1.5}]","payloadType":"string","repeat":"","crontab":"","once":false,"x":213,"y":219,"z":"c04f6206.3fb0a","wires":[["a1875909.5e78a8"]]},{"id":"7bc9c6c3.843638","type":"inject","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":92,"y":273,"z":"c04f6206.3fb0a","wires":[["d5598d86.2aa67"]]},{"id":"d5598d86.2aa67","type":"function","name":"create array of objects","func":"msg.payload = [{ lat:55, lng:-2 }];\nreturn msg;","outputs":1,"x":246,"y":309,"z":"c04f6206.3fb0a","wires":[["d6652fc6.299ad","4a011e0a.b5fee"]]},{"id":"d6652fc6.299ad","type":"function","name":"Stringify it","func":"msg.payload = JSON.stringify(msg.payload);\nreturn msg;","outputs":1,"x":365,"y":264,"z":"c04f6206.3fb0a","wires":[["a1875909.5e78a8"]]},{"id":"4a011e0a.b5fee","type":"debug","name":"","active":true,"console":false,"complete":false,"x":461,"y":303,"z":"c04f6206.3fb0a","wires":[]}]

The thing to note is that actually those injects are passing in strings.... not javascript objects...

So the inject node on my new node - calls a function that creates a location object... which is more likely what is going to happen... eg you would parse a GPS string into  a location object... and add it to an array... so in this instance it's an array [ ]  containing a single object  { lat:51, lng:-1.5 }     - this then gets passed to the next function (stringify) that makes the payload into a string (much like the existing injects are) - and then passes it out to the map.

The other thing to note is that the socket handler in the html page (from the template) - doesn't attempt to reconnect on any error or close - so once you deploy the flow you need to reload the map page first to get the websocket to (re)connect - before then clicking the injects to make things happen.

Hope this helps

Dave C-J

unread,
Apr 29, 2014, 2:35:07 PM4/29/14
to node...@googlegroups.com
aaargh - having just pasted that flow - I realise that on my own pc I serve pages from /admin - so the line in the template node that should be
var socketaddy = "ws://"+server+":1880/ws/location";    <---SHOULD be THIS
currently says var socketaddy = "ws://"+server+":1880/admin/ws/location"; <--- THIS is wrong...
doh... 


--
http://nodered.org
---
You received this message because you are subscribed to the Google Groups "Node-RED" group.
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
regards

Dave Conway-Jones

Dave C-J

unread,
Apr 29, 2014, 2:48:19 PM4/29/14
to node...@googlegroups.com
Ben

other top tip while messing about... is to use the Chrome browser... open the map web page..(in this case). then use Ctrl-Shift-J to open the developer tools window - this should give you a console window in which you can see things like

Connected websocket map:34
Sending ping.. map:35
Ping sent.. map:37
Got marker at 54.5, -1.5
Array[1]
map:48
Got marker at 55, -2
[Object]
map:48


Ben Orchard

unread,
Apr 29, 2014, 3:48:05 PM4/29/14
to node...@googlegroups.com
Dave,

Thanks very much for looking at it.

All working now.

Not exactly sure why changing the server got it working since I was able to call up the map URL.
(I assumed that if the server variable was wrong, I would not be able to call up the map).

My function block out of OwnTracks already stringafied the lat / long, so I just needed the server tweak and I was up and running.

I cant get away from the office to test movement, but will it draw lines between the OwnTracks updates?
Im assuming thats what the 'Polylines' is in the code?

Thanks again, really appreciate the help.

Ben.

Dave C-J

unread,
Apr 29, 2014, 6:45:57 PM4/29/14
to node...@googlegroups.com

Ben,

Glad you got it working. If you pass it a single point it just draws that. If you pass it an array of points it draws the lines also. But if you them send another point it doesn't add it to the line.
(Hence my comment about using objects and adding then to an array before stringifying and passing on.)

chris mobberley

unread,
May 2, 2014, 10:23:38 AM5/2/14
to node...@googlegroups.com
Wow.. never realised my example flow would cause such a fuss!

I had to rip out a lot of the stuff I was doing in the flow to make it a bit more example friendly hence the complete difference between the owntracks output and what you are seeing on the inject. I actually store my owntracks info in to Mysql and then output it from mysql in to the map later on. That way I can always keep a history of movements etc.

Dave,

Thanks for the tip on server Ip. I had it semi hard coded because I've messed around with admin location so many times in the past I could never rely on my flows and the settings.js file. Eitherway I'll probably implement your changes anyway.

All,

Im crap with JS so very likely this flow is no where near perfect =p

Ben Orchard

unread,
May 2, 2014, 2:50:15 PM5/2/14
to node...@googlegroups.com
Chris,

Thanks for the follow up.....

I was going nuts trying to figure the most elegant way to do the array, then I read your email..... MySQL... Duh.. Sometime I baffle myself in how hard I make stuff....
Thats a much better solution, I will take a look at that when I come up for air.
(I spent too much time looking at the heatmap.js solution to try and get it working, and I need to recover that time first).

Thanks again for the flow. Neat stuff.

Ben.

Claudiu O

unread,
Jun 11, 2014, 1:53:07 PM6/11/14
to node...@googlegroups.com
[I know this topic is quite old, please forgive me for posting, I am still in learning node-red mode and one thing that helps a lot is going through old posts and trying to understand them.]

Chris,

Thank you so much for creating this flow (and thanks to the OP and all who commented) - I learned a lot from this thread about using a websocket and serving content.

I just have a question - it is unclear to me why the original flow you posted contains the websocket in node and the following function. I tried without them and everything seems to work but since I want to learn I wanted to make sure there is no hidden reason for the websocket in to be present - please see the screenshots I posted for clarification of what I mean.

Thanks a lot for your help!

   claudiu
modified_flow.PNG
original_flow.PNG

Dave C-J

unread,
Jun 11, 2014, 4:27:35 PM6/11/14
to node...@googlegroups.com

No real reason to be there, is my guess. Presumably the function echoed back some information whenever something arrived. If not needed it should be safe to delete. I have plenty of flows with just an in or just an out websocket.

Christopher Mobberley

unread,
Jun 11, 2014, 5:08:16 PM6/11/14
to node...@googlegroups.com

Yea I used it to send me info from a timed ping in the html. When the ping event occurred it would force some special data through the web socket in node. I didn't add that to the example as it was just messing around. I kept the WS in node just to show it can be used.

On 11 Jun 2014 21:27, "Dave C-J" <dce...@gmail.com> wrote:

No real reason to be there, is my guess. Presumably the function echoed back some information whenever something arrived. If not needed it should be safe to delete. I have plenty of flows with just an in or just an out websocket.

--
http://nodered.org
---
You received this message because you are subscribed to a topic in the Google Groups "Node-RED" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/node-red/yOtqbazqbNA/unsubscribe.
To unsubscribe from this group and all its topics, send an email to node-red+u...@googlegroups.com.

Claudiu O

unread,
Jun 11, 2014, 6:41:36 PM6/11/14
to node...@googlegroups.com
Cool, thanks a lot for clarifying this, it helps a lot to understand things.

David Caparrós

unread,
Feb 25, 2018, 12:00:30 AM2/25/18
to Node-RED
Good Morning

I have being able to implement this on my flows and is working great when I open the window on my laptop however I want to use it to be opened on my mobile and deslpite the fact I have increased the zoom to the max the windows appears very small and even making zoom with the fingers on the screen to the maximum does not allow to zoom it too much, also the buttons on the top left are shown really small, any way to change this?

Any advice is welcome, thanks in advance 
Reply all
Reply to author
Forward
0 new messages