Google Map

Hi,
I am new in openhab and at first thank you for the code, but I have some questions:

  1. I got the map on the sitemap, but the zoom is to much (no road or something else next to my home icon).
    How could I adjust this?

  2. I will also show the battery, accuracy, the location string (lon, lat) in a group.
    But there is nothing, no data.

Could someone help me?


UPDATE: I found my mistake (the configuration in the OwnTrack app - mobile phone - was wrong)
Everything work now how it should

1 Like

Hi all,

I did a major refactoring of the map display to make it more flexible and easier to use. It uses now ajax/xhr to update the positions (without the need to reload the page). Also some decent animation was thrown in.

2019-02-25%2009_11_31-Window

To use please download the ā€œmap.zip.txtā€, rename it & place the content in ā€œconf/html/ā€.

map.zip.txt (12.8 KB)

To configure add your Google API key in ā€œindex.htmlā€. The markers can be configured in ā€œ./lib/map21.jsā€:

2019-02-25%2009_19_01-Window

You can configure as many elements as you need.

Hope this is of use :slight_smile:.

with kind regards,
Patrik Gfeller

2 Likes

Hi @patrik_gfeller,

Thanks for putting the time into this. It is much appreciated. Are you paying google for the api access? I ended up shelving the feature in my sitemap due to google starting to charge for the api calls.

Hi Paul,

I think there is still a free quota; it lead I do not pay for my requests to the AP.

with kind regards,
Patrik

@patrik_gfeller Thanks for releasing this for the community to use!
Is it possible for you to include some new examples of things/sitemap/rules that use your new code?
It looks like it may have changed?

I know this is getting on a year old but Iā€™m trying to make it work, So far Iā€™ve failed but I canā€™t see what Iā€™m doing wrong. Iā€™m using GPSTracker which makes things significantly simpler and based on watching events.log the History Item is being populated correctly. Hereā€™s what Iā€™ve doneā€¦

NOTE: Iā€™m not using the gecoding API so I didnā€™t reproduce that Rule.

Preconditions

  • GPSTracker installed and configured correctly.
  • OwnTracks installed on phones and reporting to OH.
  • Things created for each of the reporting phones and the Channels linked to Items.

Get Google Maps API Key

Navigate to https://developers.google.com/maps/documentation/embed/start and select ā€œGet an API keyā€ on the left and follow the instructions. I already have a billing account. I chose the Maps JS API. Copy the key, we will need it later.

@sintei, it would be helpful if you posted exactly what you needed to change to get the Embedded API URL to work. I tried and failed.

Items

I created a few new Items.

Location vHome "Home Location"

String vMaps_API "Google Maps API Key"

Group:String LocationHistories

Group:Location Locations

// Rich
Location vRich_Location "Rich's Current Lat/Lon [%s]"
    <motion> (gChart, Locations)
    { channel="gpstracker:tracker:RK:lastLocation" }

Number vRich_Phone_Battery "Rich's Phone Battery [%d %%]"
    <battery>
    { channel="gpstracker:tracker:RK:batteryLevel" }

DateTime vRich_Last_GPS "Rich's Last Location Report [%1$tm/%1$td %1$tH:%1$tM]"
    <time>
    { channel="gpstracker:tracker:RK:lastReport" }

Number:Length vRich_GPS_Accuracy "Rich's Location Accuracy [%d ft]"
    <motion>
    { channel="gpstracker:tracker:RK:gpsAccuracy" }

String vRich_Region "Rich's Location [%s]"
    <motion>

Number:Length vRich_Distance "Rich's Distance from Home [%.1f mi]"
    <motion>
    { channel="gpstracker:tracker:RK:distanceSystem" }

String vRich_Location_History
    (LocationHistories)

// Jenn
Location vJenn_Location "Jenn's Current Lat/Lon [%s]"
    <motion> (gChart, Locations)
    { channel="gpstracker:tracker:JC:lastLocation" }

Number vJenn_Phone_Battery "Jenn's Phone Battery [%d %%]"
    <battery>
    { channel="gpstracker:tracker:JC:batteryLevel" }

DateTime vJenn_Last_GPS "Jenn's Last Location Report [%1$tm/%1$td %1$tH:%1$tM]"
    <time>
    { channel="gpstracker:tracker:JC:lastReport" }

Number:Length vJenn_GPS_Accuracy "Jenn's Location Accuracy [%d ft]"
    <motion>
    { channel="gpstracker:tracker:JC:gpsAccuracy" }

String vJenn_Region "Jenn's Location [%s]"
    <motion>

Number:Length vJenn_Distance "Jenn's Distance from Home [%.1f mi]"
    <motion>
    { channel="gpstracker:tracker:JC:distanceSystem" }

String vJenn_Location_History
    (LocationHistories)

Rules

I use Python but these are simple enough they should be understood by all. Because the GPSTracker handles parsing the messages from OwnTracks and Iā€™m not doing geocoding yet so all I need to do is update the history Items.

@rule("Clear Histories",
      description="Clears location histories",
      tags=["location"])
@when("Time cron 0 0 0 ? * * *")
def clear_hist(event):
    for loc in ir.getItems("LocationHistories").members:
        events.postUpdate(loc.name, "")

@rule("Location Changed",
      description="Updates location history",
      tags=["location"])
@when("Member of Locations changed")
def loc_changed(event):
    hist_item = "{}_History".format(event.itemName)
    events.postUpdate(hist_item, "{}{};".format(items[hist_item], event.itemState))

Watching events.log, my History Item is updating as expected:

<lat>,<lon>;<lat>,<lon>;

No spaces. NOTE that I had to initialize the History Item to ā€œā€. I need to update the code to handle that case, but I mention it here. Without initializing the Item it ends up starting with NULL.

Webview

Downloaded and change the name and unzip map.zip.txt from Google Map. Unzip this folder to $OH_CONF/html. Made the following edits:

index.html

  • Change the lang attribute at the top to ā€œenā€.

  • Change the error message ā€œPositionsdaten sind nicht geladen.ā€ to ā€œPosition data is not loaded.ā€

  • Inserted my API Key where indicated at the bottom of the file and change the end of the URL to initMap instead of initialize. The example URL on Googleā€™s site uses initMap. It doesnā€™t work either way sadly. :frowning:

<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="utf-8">
    <!-- Force latest IE rendering engine & Chrome Frame -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="description" content="Displays the current user locations and the location history data in Google-Maps.">
    <meta name="author" content="Patrik Gfeller">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">

    <title>Positionsinformationen</title>

    <link href="./css/style.css" type="text/css" rel="stylesheet">

    <script src="./lib/openHAB.js"></script>
    <script src="./lib/map20.js"></script>
</head>

<body>
    <main>
        <div id="map" class="map">
            <span id="errorMessage" class="errorMessage">Position data is not loaded.</span>
        </div>
    </main>

    <!-- Google-Maps API must be loaded after DOM is initialized completely. -->
    <script
        src="https://maps.googleapis.com/maps/api/js?key=<MY API KEY>&callback=initMap"
        async defer></script>
</body>

</html>

lib/map21.js

Populated openHABLocations with my Items.

I check that the Items are populated properly but whenever I load the page I get the ā€œPosition data is not loaded.ā€ error. Iā€™ve double checked for typos everywhere I can think of to no avail. Everything

    var openHABLocations = {
        "Home": {
            locationItem: "vHome",
            locationIcon: "./img/home.png",
            locationType: locationTypes.home,
            animation: null,
            historyItem: undefined,
            historyIcon: undefined,
            zIndex: 10
        },
        "Rich": {
            locationItem: "vRich_Location",
            locationIcon: "./img/patrik.png",
            locationType: locationTypes.user,
            animation: google.maps.Animation.DROP,
            historyItem: "vRich_Location_History",
            historyIcon: "./img/historyPatrik.png",
            zIndex: 9
        },
        "Jenn": {
            locationItem: "vJenn_Location",
            locationIcon: "./img/karin.png",
            locationType: locationTypes.user,
            animation: google.maps.Animation.DROP,
            historyItem: "vJenn_Location_History",
            historyIcon: "./img/historyKarin.png",
            zIndex: 8
        }
    };

Any assistance or information telling me this no longer works would be appreciated.

It sounds all good to meā€¦ Can you try to open the page in a browser to check the console and network traffic (developer tools)

If I remember correctly initialize is the name of the callback in the code. You should not change it, or you need to update the function name as well.

(from phone)

Thanks! To simplify things I eliminated ā€œJennā€ so itā€™s only configured with ā€œRichā€ from the code above.

I should have thought to do that myself. Looks like there are two problems. The first is the .js file is map21.js but the index.html file is trying to load map20.js.

GET https://openhab.koshak.us/static/map/lib/map20.js net::ERR_ABORTED 404 (Not Found)

Thatā€™s fixed easily enough.

The second is complaining about the initMap.

index.html:1 Uncaught (in promise) xd {message: "initMap is not a function", name: "InvalidValueError", stack: "Errorā†µ    at new xd (https://maps.googleapis.com/mā€¦iptnI2N8Lod4uKjRJxkk6CFE&callback=initMap:146:124"}

I tried using map.initMap as well as your original map.initialize and get the same error. I got the callback=initMap from Googleā€™s website though now that I look at it, the callback is a function we define. But I donā€™t know JS well enough to understand where map is defined. I see MapObject in map21.js. But itā€™s clear to me now that initMap is bogus. I just need to figure out how to properly reference the right entity defined in map21.js.

I have something to play with now but any leads would be helpful. Thanks!

EDIT: I got rid of the map. and now it works like a champ.

Iā€™ll take the above and post a new tutorial to show people how to set this up with the GPSTracker binding. Sometimes all I need is a little hint like ā€œlook at the logs.ā€ :smiley:

1 Like

sorry for not responding earlier, but it seems you got it to work!
Just a note, but make sure you set amount of calls in google cloud or you will get a nice surprice bill :wink:

Iā€™d still like to know what you did to get the Embedded Map API to work, in particular the code put into the HTML and JavaScript. I tried a bunch of stuff that seemed to make sense and couldnā€™t get that API to work. As you hint at, the Embedded API doesnā€™t cost while the JavaScript one does. Though so far Iā€™ve used up $0.08 so itā€™s not going to break the bank.

Iā€™m unsure about this, but if I look I only have one html (map.html) in a folder called ā€œgoogle-mapsā€ and I have not edited anything in that one.
However, in my rule file I have:

/*rule InitializeSystem
    when
        System started
    then
        ItemLocationHome.postUpdate(new PointType("longitude,lattitude"))
        ItemGoogleMapAPIKey.postUpdate("my API key")
    end

In google I have enabled several different API which my key can access.
Canā€™t remember that I used .JS at all :frowning:

If you are using the embedded API as you indicated in the post above, at a minimum you would need to change the index.html to use the embedded end point instead of the JS endpoint.

    <!-- Google-Maps API must be loaded after DOM is initialized completely. -->
    <script
        src="https://maps.googleapis.com/maps/api/js?key=<key>&callback=initialize"
        async defer></script>

Thatā€™s the line that uses the JS end point. At a minimum you would need a URL that starts with "https://www.google.com/maps/embed/v1/... to use the embedded API. But as far as I can tell the embedded one doesnā€™t support the callback.

Hmm, in my html file the closest I have is this:

		// Create script element with google maps API key
		var script = document.getElementById("googleMapsUrl");
		script.src = "https://maps.googleapis.com/maps/api/js?key=" + gm_apikey + "&callback=initialize";

Maybe this will help some?
Items file:

//GoogleMap
String		ItemMQTT 																					{ mqtt="<[broker1:owntracks/sintei/Gold:state:default]" }
String		ItemNicklasLocationHistory
String		NicklasLocationString 	"Nicklas [%s]" 										<place>

Location	ItemNicklasLocation 	"Nicklas" 											<location>

Number		ItemNicklasLocationAccuracy
Number		ItemNicklasNatelBattery	"Natel Nicklas [%d %%]"								<battery>		(GroupPersistrrd4jMinute,GroupBattery)

DateTime	ItemNicklasLastPositionUpdate	"Nicklas - last Update [%1$tH:%1$tM, %1$td.%1$tm.%1$ty]" <location>

Switch		ItemNicklasAtHome		"Nicklas" 											<home>
Location	ItemLocationHome
String		ItemGoogleMapAPIKey

String		GoogleMapsDistanceNicklas	"Distance Nicklas [%s]"												(gGoogleMaps)			{ http="<[https://maps.googleapis.com/maps/api/distancematrix/json?origins=LATTITUDE,LONGITUDE&destinations=LATTITUDE,LONGITUDE&language=SE&departure_time=now&traffic_model=best_guess&mode=driving&key=YOUR API KEY!!:300000:JSONPATH($.rows[0].elements[0].distance.text)]" }
String		GoogleMapsDurationNicklas	"Duration Nicklas [%s]"												(gGoogleMaps)			{ http="<[https://maps.googleapis.com/maps/api/distancematrix/json?origins=LATTITUDE,LONGITUDE&destinations=LATTITUDE,LONGITUDE&language=SE&departure_time=now&traffic_model=best_guess&mode=driving&key=YOUR API KEY!!:300000:JSONPATH($.rows[0].elements[0].duration.text)]" }
String		GoogleMapsDurationTrafficNicklas	"Duration [%s]"												(gGoogleMaps)			{ http="<[https://maps.googleapis.com/maps/api/distancematrix/json?origins=LATITUDE,LONGITUDE &destinations=LATTITUDE,LONGITUDE&language=SE&departure_time=now&traffic_model=best_guess&mode=driving&key=YOUR API KEY!!:300000:JSONPATH($.rows[0].elements[0].duration_in_traffic.text)]" }

OK, then you are not using the embedded google maps api then. Thatā€™s the JS endpoint.

sad to say, this is over my head :blush:

It works great! Thanks!
How could this be converted to read data from influxdb, because then the interval could be set?
Unfortunately, this JavaScript is incomprehensible to me :frowning:

did you have any problems trying in local pc?
Reason: CORS header 'Access-Control-Allow-Origin' missing

Working so good, I removed history because I donā€™t need