Owntracks Presence Detection and Location Display on Google Map Tutorial

Long time lurker here who has benefited a huge amount from this forum. I’ve seen lots of posts with questions on this topic and I have learned from some of them. I thought I would provide my solution for a working setup. This setup uses the mqtt binding for grabbing the location data and Owntracks/Mqttitude binding for geofence switches. It utilizes google maps for the display of the locations.

I have a “notify on motion” switch setup which when turned on, stores the users location in a variable, then every time the users location is updated it compares the new location with the stored location. if the calculated distance is greater than 300 meters it sends me a push notification via pushover(not covered in this tutorial) then turns off the switch. I don’t use this much but I could see it coming in very handy when my daughter gets older.

Screenshots:

I’m sure there are probably more elegant ways to accomplish this but it has been working well for me. Feel free to offer suggestions.

Step1
Install the mqtt broker mosquitto. I’m running openhabian so this was activated in openhabian-config.

Step2
Install and setup Owntracks app on your smartphone. I’m using TLS encryption (which I advise) but will not be covering here. It will work with or without the encryption, however the default port will be different. I advise you get it working without encryption, then take the time to set it up. Important note here is that you will need to setup port forwarding on whichever port you are using. Here are some screenshots from my Samsung S8.

Enter your ddns name or router ip address and port under the Host connection setting.

Enter your mosquitto credentials under the Identification connection setting. What you enter as device_id will be correlated to the mqtt topic which you will setup openhab to subscribe too.

This is a good point to test whether the mqtt broker (mosquitto) is receiving messages published by your owntracks app. In a terminal window type the following command to subscribe to a topic. We are going to use the ‘#’ wildcard to view anything received by the broker.
Without encryption

sudo mosquitto_sub -h localhost -p 1883 -u openhabian -P <yourPW> -t "#"

With encryption:

sudo mosquitto_sub -h localhost -p 8883 --cafile <path to certificate> -u <username> -P <password> -t "#"

Now in your owntracks app on your phone, publish your location and you should see something like this in your terminal window:

Google Map for display
you will need to register as a google developer and get an api key.
on your openhab box create a file at html/Map.html. You will need to modify this file in several places to suit your location. I grabbed this example from the internet somewhere and left some of the variable names unchanged. It displays 2 locations and home and zooms the map relative to those 3 points but could be modified to your liking. Its sort of pieced together but it works for me. YMMV
Map.html:


<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <style type="text/css">
   
    .Flexible-container {
      position: relative;
      padding-bottom: 0px;
      padding-top   : 0px;
      height        : 340px ;
      overflow: hidden;
    }

    .Flexible-container iframe,
    .Flexible-container object,
    .Flexible-container embed {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
   
   </style>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=<yourkeyhere>&libraries=places,drawing,geometry"></script>


    <script type="text/javascript">
        ////////////////////////////////////////////////////////////////////////
        // Google Maps JavaScript API:
        // https://developers.google.com/maps/documentation/javascript/?hl=de
        // Marker Icons:
        // https://sites.google.com/site/gmapsdevelopment/
        ////////////////////////////////////////////////////////////////////////

        ////////////////////////////////////////////////////////////////////////
        // JQuery
        ////////////////////////////////////////////////////////////////////////

	var map = null;
        //make an empty bounds variable
        var bounds = new google.maps.LatLngBounds();

        // LatLng's we want to show
        var latlngHome   = new google.maps.LatLng("xx.571369", "-xx.253659");
        var latlngPatrik = new google.maps.LatLng("xx.571369", "-xx.253659"); // initialize to home ...
        var latlngKarin  = new google.maps.LatLng("xx.571369", "-xx.253659"); // initialize to home ...

        var map_options = { center    : latlngHome,
                            zoom      : 11,
                            mapTypeId : google.maps.MapTypeId.ROADMAP };

        $( "#map_canvas" ).ready($(function() {
          var map_canvas = document.getElementById('map_canvas');
          map = new google.maps.Map(map_canvas, map_options)

          var marker = new google.maps.Marker({
                            position  : latlngHome,
                            map       : map,
                            icon      : 'http://maps.google.com/mapfiles/kml/pal2/icon10.png',
                            title     : "Home"
                        })

           var circle = new google.maps.Circle({
                        center        : latlngHome,
                        radius        : 450,
                        map           : map,
                        strokeColor   : '#050505',
                        strokeOpacity : 0.5,
                        strokeWeight  : 1,
                        fillColor     : '#000000',
                        fillOpacity   : 0,
                      }); // end of [Circle]

           bounds.extend(latlngHome);
        }))

        $( document ).ready($(function() {
	 // ******************************************************************************
            $.ajax({
              url     : "../rest/items/locationBecca/state/",
              data    : {},
              success : function( data ) {
                  if ( map == null) { return; }
                  if ( data == "Uninitialized") { return; }

                  var coords = data.split(',');
                  var latlngPatrik = new google.maps.LatLng(coords[0],coords[1]);

                  var marker = new google.maps.Marker({
                    position  : latlngPatrik,
                    map       : map,
                    icon      : 'http://maps.google.com/mapfiles/ms/icons/pink-dot.png',
                    title     : "Becca"
                  }) // end of [Marker]

                  $.ajax({
                    url     : "../rest/items/mqttBeccaAccuracy/state/",
                    data    : {},
                    success : function( data ) {
                    if ( data == "Uninitialized") { return; }
			var accuracy = parseInt(data);
                      var circle = new google.maps.Circle({
                        center        : latlngPatrik,
                        radius        : accuracy,
                        map           : map,
                        strokeColor   : '#f442e2',
                        strokeOpacity : 0.8,
                        strokeWeight  : 2,
                        fillColor     : '#f442e2',
                        fillOpacity   : 0.35,
                      }); // end of [Circle]

                      bounds.extend(latlngPatrik);
                      map.fitBounds(bounds);

                    } // end of [function]
                  }) // end of [$.ajax]
                } // end of [function]
            }) // end of [$.ajax]
	// ******************************************************************************
            $.ajax({
              url     : "../rest/items/locationJosh/state/",
              data    : {},
              success : function( data ) {
                  if ( map == null) { return; }
                  if ( data == "Uninitialized") { return; }

                  var coords = data.split(',');
                  var latlngKarin = new google.maps.LatLng(coords[0],coords[1]);

                  var marker = new google.maps.Marker({
                    position  : latlngKarin,
                    map       : map,
                    icon      : 'http://maps.google.com/mapfiles/ms/icons/green-dot.png',
                    title     : "Josh"
                  }) // end of [Marker]

                  $.ajax({
                    url     : "../rest/items/mqttJoshAccuracy/state/",
                    data    : {},
                    success : function( data ) {
                    if ( data == "Uninitialized") { return; }
                      var accuracy = parseInt(data);
                      var circle = new google.maps.Circle({
                        center        : latlngKarin,
                        radius        : accuracy,
                        map           : map,
                        strokeColor   : '#00FF00',
                        strokeOpacity : 0.8,
                        strokeWeight  : 2,
                        fillColor     : '#00FF00',
                        fillOpacity   : 0.35,
                      }); // end of [Circle]

                      bounds.extend(latlngKarin);
                      map.fitBounds(bounds);
                    } // end of [function]
                  }) // end of [$.ajax]
                } // end of [function]
            }) // end of [$.ajax]
           // map.fitBounds(bounds);
	}))
    </script>
  </head>
  <body>
    <div id="map_canvas" class="Flexible-container" />
  </body>
</html>


			

Step 3
A. Install the mqtt and Owntracks(formerly mqttitude) bindings via your preferred method. I used PaperUI.

image

Step 4
The OwnTracks binding does not need a config file but you will need to uncomment a few lines in services/mqtt.cfg Here are the uncommented lines in my setup:

mosquitto.url=ssl://localhost:8883
mosquitto.user=openhabian
mosquitto.pwd=YourPasswordHere
mosquitto.qos=1

Step 5
Add a region in the owntracks app for any geofences you want. Note that you will want the share switch on. I have a region for my house and my work.

Setup OpenHAB
add a file in the transform directory called mqttitude-tstamp.js which will be used to transform the timestamp from owntracks. Note that I am in US Eastern timezone so I am subtracting the time by 5 hours.

(function(json){ var otdata = JSON.parse(json); 
var this_date = new Date(otdata.tst * 1000);
this_date.setHours(this_date.getHours() - 5);
return this_date.toISOString();
 })
(input)

Items
Duplicate this for any devices you may have. Your mqtt topics may be slightly different depending on usernames, device names, and region names.

//Owntracks/mqttitude Binding
String  josh    "Josh [%s]"     <josh>       (gPresenceChart,gDashboard)
Switch  phone_Josh      "Josh [MAP(presence.map):%s]"   <present>       (gPresence,gPhones)  {mqttitude="mosquitto:owntracks/openhabian/phone_Josh/event:Home"}									              
Switch  phone_Josh_Work "Josh_Work [MAP(presence_work.map):%s]" <ecu>   { mqttitude="mosquitto:owntracks/openhabian/phone_Josh/event:work" }

//MQTT Binding
String  mqttPositionJoshRaw     "Josh's Raw Data [%s]"  { mqtt="<[mosquitto:owntracks/openhabian/phone_Josh:state:default]" }
DateTime        mqttJoshLastUpdated     "Josh's last update [%1$tm/%1$td/%1$tY %1$tH:%1$tM:%1$tS]"      <clock> { mqtt="<[ mosquitto:owntracks/openhabian/phone_Josh:state:JS(mqttitude-tstamp.js)]" }
Location        locationJosh
String  mqttJoshLatitude        
String  mqttJoshLongitude       
String  mqttJoshAccuracy        "Josh's Accuracy [%s]"
String  mqttJoshBattery "Josh's Android Battery [%s%%]" <battery>       (Phone,MQTT,Battery)
Switch josh_moving "Notify on motion" <siren>
Number joshDistanceFromHome "Miles from home [%.1f]"

Add file transform/presence.map:

//--------------presence.map------------------------
ON=Home
OFF=Away
-=Undefined

add file transform/presence_work.map:

ON=At Work
OFF=Off
-=Undefined

Rules
Duplicate for as more devices.

var PointType becca_moving_location
var PointType josh_moving_location

var PointType home = new PointType("XX.571367,-XX.253829")//no spaces after comma

rule "Josh Moving switch on"
when Item josh_moving received update ON
then
	josh_moving_location = locationJosh.state
        logInfo("josh_moving_location updated","josh_moving_location set to" + josh_moving_location)
end


rule "MqttPostionParseJosh"
  when
    Item mqttPositionJoshRaw changed
  then
    val String json = (mqttPositionJoshRaw.state as StringType).toString
    val String type = transform("JSONPATH", "$._type", json)
    if (type == "location") {
      val String lat  = transform("JSONPATH", "$.lat", json)
      val String lon  = transform("JSONPATH", "$.lon", json)
      val String acc  = transform("JSONPATH", "$.acc", json)
      val String batt = transform("JSONPATH", "$.batt", json)

      postUpdate(mqttJoshLatitude,lat)
      postUpdate(mqttJoshLongitude,lon)
      locationJosh.postUpdate(new PointType(lat + "," + lon))
      mqttJoshAccuracy.postUpdate(acc)
      mqttJoshBattery.postUpdate(batt)
	joshDistanceFromHome.postUpdate((home.distanceFrom(locationJosh.state))*0.000621)//meters to miles
    }
        if (josh_moving.state == ON){
                if (josh_moving_location.distanceFrom(locationJosh.state) > 300){
			pushover("Josh is on the move")
                        postUpdate(josh_moving, OFF)
                }
        }
end

rule "System Start"
when
        System started
then
        if(phone_Josh.state == ON){
                postUpdate(josh, "Home")
        }
        else if (phone_Josh_Work.state == ON)
                postUpdate(josh, "Work")
        else postUpdate(josh, "Away")
end

rule "Daddy's Home"
when
        Item phone_Josh changed from OFF to ON

then
        postUpdate(josh, "Home")
end

rule "Josh leaves home"
when Item phone_Josh received update OFF
then
        postUpdate(josh, "Away"
end

rule "Josh gets to work"
when Item phone_Josh_Work received update ON
then postUpdate(josh, "Work")
end

rule "Josh leaves work in Afternoon"
when
        Item phone_Josh_Work received update OFF
then
        postUpdate(josh, "Away")
end

sitemap

Frame label="Presence"{
		Text item=josh  icon="josh"{
                        Switch item=phone_Josh valuecolor=[phone_Josh==Uninitialized="lightgray", ==ON="red", ==OFF="lightgray"]
                        Switch item=phone_Josh_Work valuecolor=[phone_Josh_Work==Uninitialized="lightgray", ==ON="red", ==OFF="lightgray"]
                        Text item=mqttJoshLastUpdated
                        Text item=mqttJoshBattery
                        Switch item=josh_moving
			Default item=joshDistanceFromHome
			Webview url="http://192.168.1.140:8080/static/Map.html" height=10  
                        Chart item=phone_Josh period=d refresh=10000
                }
		Webview url="http://<yourIPaddress>:8080/static/Map.html" height=10  visibility=[phone_Josh==OFF]
	}

I probably forgot something. Let me know if you have any questions and I’ll answer as soon as I can.

19 Likes

hi @iamjoshwilson i actually have nearly the same setup but i could not get it working in the Android APP when i’m connected remotely via myopenhab. the Map is then not geting displayed. same in habpanel via myopenhab.

do you got it working in myopenhab?

I use a VPN to access openhab remotely so unfortunately, I’m not much help when it comes to myopenhab. Before I setup the VPN, I was port forwarding 8080 on my router (this setup was openhab 1.8 which had authentication). With the addition of a hairpin loopback setting in my router, I made the webview url hit my ddns hostname instead of the internal ip of the OH machine. and due to the loopback, the address would resolve correctly both internal and external to the network.

Perhaps someone who uses myopenhab will chime in.

[edit] It’s also working for me in habpanel. The map is displayed in a frame widget. I haven’t completed my buildout of this dashboard but heres a screenshot of what I have.

1 Like

Thank you.
I have set up Owntracks but have been less than impressed. I will carefully go through your setup and see if i can improve anything in mine.

Thank you for the great tutorial. I was wanting to simply display the waypoint descriptions. I was able to use your information and come up with this. I am sure it can be done better, but thought someone might be able to use it.

Items

String  JevetteLocationRaw     "Jevette's Raw Data [%s]"  { mqtt="<[mosquitto:owntracks/openhab/JevettePhone:state:default]" }
String JevetteLocationEvent "Jevette's Raw Data [%s]" { mqtt="<[mosquitto:owntracks/openhab/JevettePhone/event:state:default]" }
String  JevetteLocationDisplay
Location  JevetteLocation
String  JevetteLatitude
String  JevetteLongitude
Switch  JevetteLocationKnown  "Jevette Location Known"

Rules

var PointType home = new PointType("38.949556,-94.696408")//no spaces after comma

rule "MqttPositionParseJevette"
when 
    Item JevetteLocationRaw changed
then
   
    val String json = (JevetteLocationRaw.state as StringType).toString
    val String type = transform("JSONPATH", "$._type", json)
   
    if (type == "location") {
      val String lat  = transform("JSONPATH", "$.lat", json)
      val String lon  = transform("JSONPATH", "$.lon", json)
      val String acc  = transform("JSONPATH", "$.acc", json)
      val String batt = transform("JSONPATH", "$.batt", json)       
       if(JevetteLocationKnown.state == OFF){
           
       postUpdate(JevetteLatitude, lat)
       postUpdate(JevetteLongitude, lon) 
       JevetteLocation.postUpdate(new PointType(lat + "," + lon))
       JevetteLocationDisplay.postUpdate(String::format("%.2f Miles Away",((home.distanceFrom(JevetteLocation.state)) * 0.000621)))

       }

    }

end

rule "MqttEventParseJevette"
when 
    Item JevetteLocationEvent changed
then
    val String json = (JevetteLocationEvent.state as StringType).toString
    val String eventType = transform("JSONPATH", "$.event", json)
    if(eventType == "enter"){
        JevetteLocationKnown.postUpdate(ON)
        val String desc = transform("JSONPATH", "$.desc", json)
        JevetteLocationDisplay.postUpdate(desc)
    }
    else if(eventType == "leave"){
        JevetteLocationKnown.postUpdate(OFF)
        val String lat  = transform("JSONPATH", "$.lat", json)
        val String lon  = transform("JSONPATH", "$.lon", json)
        val String acc  = transform("JSONPATH", "$.acc", json)
        

        postUpdate(JevetteLatitude, lat)
        postUpdate(JevetteLongitude, lon)
        JevetteLocation.postUpdate(new PointType(lat + "," + lon))       
        JevetteLocationDisplay.postUpdate(String::format("%.2f Miles Away",((home.distanceFrom(JevetteLocation.state)) * 0.000621)))
    }
end
2 Likes

Historical data

I’ve been playing around with getting the historical data from the OH database. I’ll start this off by stating that I’m using influxdb for persistence which is new to me. This setup should work similarly with other persistence services however the url to extract the data will be different.

Screenshot: (junk data in a json I manually created for demo purposes)
The pink represents her current location. then the locations get progressively lighter is you go further back in time. If in a browser, you can hover over each icon and view the time associated with that location

image

I discovered that location items are not persisted in the openhab db. This necessitated adding a string item to hold the combined lat and lon values and an update to the rule to populate this new item, and a new html file which gets and displays the values from the database. You could probably get away with using the existing lat and long items but I thought it would be easier having both values in one string.

new Item:

String mqttBeccaLatLon

Addition to rule (second line is the addition, first line to show additions position in rule)

      mqttBeccaBattery.postUpdate(batt)
      mqttBeccaLatLon.postUpdate(lat + ", " + lon)

The map html file is where the work is done here. You will need to modify the file by adding your google api key and modifying the url variables to suit your setup

<!DOCTYPE html>
<html>
  <head>    
  <meta charset="utf-8"/>
    <style type="text/css"> 
    <!--
    .Flexible-container {
      position: relative;
      padding-bottom: 0px;
      padding-top   : 0px;
      height        : 345px ;
      overflow: hidden;
    }

    .Flexible-container iframe,   
    .Flexible-container object,  
    .Flexible-container embed {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
   -->
   </style>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=<yourApiKey>=3.exp&libraries=places,drawing,geometry"></script>     
  </head>
  <body>
  
  <script type="text/javascript">
        ////////////////////////////////////////////////////////////////////////
        // Google Maps JavaScript API:
        // https://developers.google.com/maps/documentation/javascript/?hl=de
        // Marker Icons:
        // https://sites.google.com/site/gmapsdevelopment/
        ////////////////////////////////////////////////////////////////////////

        ////////////////////////////////////////////////////////////////////////
        // JQuery
        ////////////////////////////////////////////////////////////////////////
        var latlngHome   = new google.maps.LatLng("xx.571369", "-xx.253659");
		var openhabLocationUrl = "../rest/items/locationBecca/state/";
		var openhabAccuracyUrl = "../rest/items/mqttBeccaAccuracy/state/";
		//this url returns values from mqttBeccaLatLon from the last 24 hrs
		var databaseUrl = "http://localhost:8086/query?u=username&p=password&db=openhab_db&q=SELECT+*+FROM+%22mqttBeccaLatLon%22+where+time+>+now()+-+24h+order+by+time+desc";
		
		function addHexColor(c1, c2) {
			var hexStr = (parseInt(c1, 16) + parseInt(c2, 16)).toString(16);
			while (hexStr.length < 6) { hexStr = '0' + hexStr; } // Zero pad.
			return hexStr;
		}
		
		var map = null;
        //make an empty bounds variable
        var bounds = new google.maps.LatLngBounds();
		
		
		var map_options = { center    : latlngHome,
                            zoom      : 11,
                            mapTypeId : google.maps.MapTypeId.ROADMAP };
		
		$( "#map_canvas" ).ready($(function() {
          var map_canvas = document.getElementById('map_canvas');
          map = new google.maps.Map(map_canvas, map_options)
          }))
		  
		$( document ).ready($(function() {
            // ******************************************************************************
            $.ajax({
              url     : openhabLocationUrl,
              data    : {},
              success : function( data ) {
                  if ( map == null) { return; }
                  if ( data == "Uninitialized") { return; }
                  
                  var coords = data.split(',');
                  var latlngPatrik = new google.maps.LatLng(coords[0],coords[1]);
                  
                  var marker = new google.maps.Marker({
                    position  : latlngPatrik,
                    map       : map,
                    icon      : 'http://maps.google.com/mapfiles/ms/icons/pink-dot.png',
                    title     : "Becca"
                  }) // end of [Marker]
                  
                  $.ajax({
                    url     : openhabAccuracyUrl,
                    data    : {},
                    success : function( data ) {
                    if ( data == "Uninitialized") { return; }
                      var accuracy = parseInt(data);
                      var circle = new google.maps.Circle({
                        center        : latlngPatrik,
                        radius        : accuracy,
                        map           : map,
                        strokeColor   : '#f442e2',
                        strokeOpacity : 0.8,
                        strokeWeight  : 2,
                        fillColor     : '#f442e2',
                        fillOpacity   : 0.35,
                      }); // end of [Circle]
                      
                      bounds.extend(latlngPatrik);
                      map.fitBounds(bounds);
                      
                    } // end of [function]
                  }) // end of [$.ajax]
                } // end of [function]
            }) // end of [$.ajax]
//-----------------------------------Becca From Database------------------------------------
			$.ajax({
         url: databaseUrl,
         type: 'GET',
         success: function(data) { //we got the response
		 var bArray = data.results[0].series[0].values;
		 //console.log(data.results[0].series[0].values);
		 if ( map == null) { return; }
         if ( data == "Uninitialized") { return; }
		 var time;
		 var coords;
		 var bLocArray = [];
		 var pinColor = '000000';
			
		 for (i=1; i< bArray.length; i++){
			//console.log("Time: " + bArray[i][0]);
			time = bArray[i][0];
			coords = bArray[i][1].split(', ');
			//console.log("Time: " + time + " Location: " + coords[0]);
			var loc = new google.maps.LatLng(coords[0], coords[1]);
			var pinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColor,
				new google.maps.Size(21, 34),
				new google.maps.Point(0,0),
				new google.maps.Point(10, 34));
			pinColor = addHexColor(pinColor, '111111');
			//console.log(pinColor);
			var marker = new google.maps.Marker({
				position	:	loc,
				map			:	map,
				icon		: pinImage,
				title		: time
			})//end of Marker
			
			bounds.extend(loc);
            map.fitBounds(bounds);
		 }//end for loop
         },//end success function,
         error: function(test, status, exception) {
			console.log("Error getting data from database" + exception);
         }
     })
        }))
		
		</script>
     <div id="map_canvas" class="Flexible-container" />
  </body>
</html>
2 Likes

Hi, i try to only locate the device current location, without home location, i’m still newbie about this, can you gice me some clue ?

Is there any specific part you are struggling with?

I am working this and it is mostly working…but there is a reference to “url : “…/rest/items/locationJohn/state/”,” and “url : “…/items/mqttJohnAccuracy/state/”,”…what are these referring to? I can assume they are folders in the items dir, but what files need to be in those folders?

for me it seems like it should be “…/items/locationTravis/state/”, basically removing the “rest” because that folder doesnt exist in relation to the “html” folder where the map.html file exists.

unfortunately I still dont know what should be in those folders to make this run.

I have everything, the sitemap, the google map, the “home” showing up on it, but it isnt showing my phones location. watching the logs from mosquitto, it shows my phone connecting and sending info…so that shouldnt be it…that is why I think these folder references might be an issue.

thoughts? do you need more info?

Hello, please could you help me? I have mosquitto, working well, I have copied all your settings with my ip addresses, I can see map, when i click choose map.html, I have items in openhab, but in control page in paperui there is nothing and I´m unable to make it work. Is there anything, I missed or something else? Thank you very much for your help.

Hello,
I had similar solution, but moved to OpenStreetmap (which tiles i prefer, and there is possibility to use another ones).
Code is presented on gist here: https://gist.github.com/przemas75/f930acd8933f7277c831740dc0c692d5

And it looks like this:

<html lang="en-US" xmlns="http://www.w3.org/1999/xhtml">
   <head profile="http://gmpg.org/xfn/11">
    <style type="text/css"> 
      <!--
      .Flexible-container {
        position: relative;
        padding-bottom: 0px;
        padding-top   : 0px;
        height        : 345px ;
        overflow: hidden;
      }
  
      .Flexible-container iframe,   
      .Flexible-container object,  
      .Flexible-container embed {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
      }
     -->
     </style>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

      <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css"
   integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
   crossorigin=""/>
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
      <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"
   integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA=="
   crossorigin=""></script>
   </head>

   <body>

    <div id="mapid" style="height: 440px; border: 1px solid #AAA;"></div>
    <script>
      var lat = xxx.4672296;
      var lon = yyy.4847917;
      var latlngHome   = [xxx.4672296, yyy.4847917];
      var przemasobraz = L.icon({
          iconUrl: 'http://172.16.8.9:8080/static/przemas.png',
          iconSize: [32, 32],
          iconAnchor: [4, 4],
          popupAnchor: [-3, -76]
      });
      var magdaobraz = L.icon({
          iconUrl: 'http://172.16.8.9:8080/static/magda.png',
          iconSize: [32, 32],
          iconAnchor: [4, 4],
          popupAnchor: [-3, -76]
      });


      // initialize map
      var map = L.map('mapid').setView([lat, lon], 13);



      // set map tiles source
      L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors',
        maxZoom: 18,
      }).addTo(map);

      $.ajax({
         url     : "../rest/items/locationPrzemas/state/",
         data    : {},
         success : function( data ) {
                  if ( map == null) { return; }
                  if ( data == "Uninitialized") { return; }
              
                  var coords = data.split(',');
                  var latlngPrzemas = [coords[0],coords[1]];
                  marker = L.marker([latlngPrzemas[0],latlngPrzemas[1]], {icon: przemasobraz} ).addTo(map).bindPopup("przemas");
          }
       });


      $.ajax({
         url     : "../rest/items/locationMagda/state/",
         data    : {},
         success : function( data ) {
                  if ( map == null) { return; }
                  if ( data == "Uninitialized") { return; }
                  
                  var coords = data.split(',');
                  var latlngMagda = [coords[0],coords[1]];
                  marker = L.marker([latlngMagda[0],latlngMagda[1]], {icon: magdaobraz} ).bindPopup("magda").addTo(map);
          }
       });

    </script>

   </body>
</html>

I have changed this a little bit, now it is not necessary to nest $.ajax. Its much easier to add more persons (just put it in in the array) and the code do the rest. Gist was updated.

Sorry this is a really late reply. The “…/rest/items/locationJohn/state/” makes a call to the rest API to return the state of the item. You can try it in a browser yourself to query the state of an item and see what’s returned.

http://:8080/rest/items/locationTravis/state/

You can enter any of your items in place of “locationTravis”

If the ajax request to the Rest API is successfull, the results from the request are placed in the “data” variable in the AJAX code.

The “coords” variable stores the data as an array split up by commas which results in position 0 being the lat and position 1 being the lon.

Hope all this makes sense. Let me know if you have more questions.

Need more info to troubleshoot. Are you receiving location updates to items in openhab?

I don’t use myopenhab. I use openVPN to connect to openhab from outside my network. Encrypted Owntracks data is the only port I have open on my router which allows successful location transmissions even when not connected to the VPN. Hope this is helpful

Hi!
To use with myopenhab, the string in sitemap should look like this:
Webview url="https://home.myopenhab.org/static/Map.html" height=10
%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9123
It works with android app and chrome extension also…

OK, I’m running OpenHAB in Docker. I’ve discovered that there are a number of other components I was missing… mainly the Map and JSONPath Transformations.

I’m running the latest OwnTracks and Mosquitto installs also in containers in Docker.

I added Telegram messages to each rule, and the only rules that work are Systems Started, Daddy’s home and leaves work in the afternoon… leaves home also works but is triggered every 60 seconds :smiley:

The only thing working on the sitemap is the initial Text item setting to away… the google map initially looks like it’s going to work then “Opps! Something went wrong.”

Is there something else I am missing?

NOTE: while typing I tried adding the JavaScript transformation and I restarted the container hoping to clear the Google Maps “error”

I will need more info to assist in debugging. Check the status in your owntracks app. Is it able to connect to your MQTT broker? If so, subscribe to the relevant topics and attempt to publish your location via the owntracks app and see if your broker is receiving the messages. If all this is working, make sure openhab is receiving the messages published by owntracks. Let us know specifically what is working and what is not and I’ll be happy to assist any way I can.

-Josh

Thanks, Owntracks and the MQTT broker are communicating. I can even see in the MQTT Logs the posts being published to OpenHAB. And I believe that OpenHAB is seeing the messages since the different rules are being triggered at the right times (i.e. when I leave work, and when I get home)…

What would really help me in troubleshooting is if there was a way I could update a Text item with the latest MQTT message…

And I confirmed that Openhab can talk to the MQTT by setting it to publish a message when a light is turned off :smile:

What information would you need me to provide?

OK, I fixed a chunk of it in the system start up rule… (code edit below)

And I further ID’d my remaining problem…

it appears that mqttPositionJoshRaw isn’t reading the data… state is coming back NULL and has no values… all the other pieces parse their data from this String… once i fix that, I should be golden!