Moderne Sportuhren der Firma Garmin sind mehr als nur ein Aufzeichnungsgerät für Laufstrecken. Neben vielzähligen Sensorwerten lässt sich auch mit überschaubarem Aufwand eine Anbindung an SmartHomeNG erreichen, so dass bspw. Temperaturwerte auf der Uhr dargestellt werden.

Dieser Artikel beschreibt, wie man Itemwerte von SmartHomeNG als ConnectIQ App auf Garmin Sportuhren bringt. Das Beispiel wurde dazu auf einer Garmin Fenix® 5 erstellt und erprobt.

Weiterführend wäre auf die gleiche Art und Weise auch eine Steuerung von Hausfunktionen (bspw. Tor öffnen, wenn man vom Laufen zurück kommt) denkbar.

Die ConnectIQ App bedient sich dabei technisch der Garmin Connect App am Handy, um Anfragen auf Webservices von SmartHomeNG zu richten. Getestet wurde dies mit der Android Version dieser App.

Einrichten der Entwicklungsumgebung:

Als erstes muss die Entwicklungsumgebung aufgesetzt werden. Verwendet wird dabei die Software Eclipse, die im Bereich der Java Entwicklung sehr populär ist. Zum Stand dieses Artikel liegt sie in der Version Oxygen.3 Release (4.7.3) vor.

Nach erfolgter Installation, muss der ConnectIQ SDK von Garmin heruntergeladen und eingerichtet werden. Detaillierte Informationen dazu finden sich unter https://developer.garmin.com/connect-iq/programmers-guide/getting-started/ bzw. https://developer.garmin.com/connect-iq/sdk/.

Die Installation in Eclipse geht dabei gemäß dem ersten Link wie folgt:

Zuerst muss das Eclipse Plugin installiert werden:

  1.  Im installierten Eclipse auf das „Help“ Menü klicken.
  2. Dort „Install New Software…“ auswählen und den Knopf „Add…“ drücken.
  3. Im nun folgenden Dialog die URL „https://developer.garmin.com/downloads/connect-iq/eclipse/“ als Name und Location eintragen (siehe Screenshot) und mit „OK“ bestätigen.
  4. Im nun folgenden Fenster die Checkbox direkt neben „Connect IQ“ anhaken und auf „Next“ klicken.
  5. Den Lizenzbedingungen zustimmen und „Finish“ anklicken.
  6. Eclipse neu starten

Als nächstes muss das SDK heruntergeladen werden.

  1. Auf das nun sichtbare Menüitem „Connect IQ“ klicken und „Open SDK Manager auswählen.
  2. Dort nun das Ziel-Verzeichnis eintragen und beim jeweiligen SDK (idealerweise der aktuellste) den Knopf „Download“ bestätigen. Dabei müssen ebenfalls die Lizenzbedingungen bestätigt werden.
  3. Sobald der Download erfolgt ist, „Yes“ anklicken um die SDK Version als aktiven SDK zu verwenden. Im Nachhinein kann die SDK Version aber auch noch gewechselt werden. Im Beispiel wurde der aktuellste SDK (2.4.4) gewählt.
  4. Ist dies erfolgt, kann der SDK Manager geschlossen werden.

Projekt erstellen

Als nächstes muss über „File“ -> „New“ -> „Connect IQ Project“ ein neues Projekt erstellt werden.

Diesem gibt man dann einen Namen, bspw. „SmartHomeNG_on_a_Watch“ und bestätigt mit „Next“. Nun kann man den Project Type (hier: „Watch App“, die Version der App (hier: 0.0.0) und die minimale SDK Version setzen (hier: 2.4.x). Nach dem Bestätigen mit „Next“ wählt man „Simple“ als Template aus und bestätigt erneut.

Nun kommt die Wahl der unterstützten Geräte. Hier wird im Beispiel „Fenix® 5 / quatix® 5″ selektiert.

Bevor man „Finish“ klick sollte man noch über „Next“ die Sprache wählen. Im Beispiel wird hier „English (eng)“ selektiert.

Mit „Finish“ wird nun das Projekt angelegt und taucht nun links im Project Explorer auf:

Das Programm ausführen

Nun muss über Run -> Run Configuration das Projekt für die Ausführung konfiguriert werden.

Dazu ist wie oben zu sehen ein aussagekräftiger Name zu wählen („Fenix5 Configuration“). Die Projektzuordnung, das Target Device und die Target SDK Version sollten bereits stimmen. Mittels „Apply“ werden die Einstellungen gespeichert. Danach via „Close“ verlassen.

Nun muss noch der Simulator gestartet werden, entweder über das neue Icon in der oberen Iconleiste oder via „Connect IQ“ -> „Start Simulator“. Der Simulator startet als separates Fenster:

Über das bekannte Menü Run -> Run Configuration kann nun die Fenix5 Configuration gewählt und mittels „Run“ die Applikation gestartet werden.

Nach dem erfolgreichen Build ist nun die Dummy App auf dem Simulator zu sehen:

Anbindung von SmartHomeNG

Um SmartHomeNG anzubinden, ist nun folgendes zu tun:

Zuerst sind die anzuzeigenden Items in SmartHomeNG über das Webservices Plugin als Itemset zu definieren. Hier wurde als Setname „1“ gewählt. Details zum Webservices Plugin finden sich in diesem Artikel: https://www.smarthomeng.de/das-smarthomeng-webservices-plugin.

In diesem Set ist bspw. das Item eta_pu.temperature_outside.value. Um Übertragungszeit zu sparen, wurde hier val gesetzt:


eta_pu:
    temperature_outside:
        eta_pu_uri: '40/10241/0/0/12197'
        type: num

        value:
            eta_pu_type: calc
            type: num
            database@mysqldb: init
            webservices_set: 1
            webservices_data: 'val'

Nach einen Restart von SmartHomeNG sollte das Set wie in https://www.smarthomeng.de/das-smarthomeng-webservices-plugin erklärt, verfügbar sein.

Da ConnectIQ über die Garmin Connect App nur Requests gegen Internet Endpunkte machen kann, wurde ein SmartHomeNG vorgeschalteter NGINX wie folgt angepasst.

Tipp: Grundlegende Informationen zur Nutzung von NGINX als Reverse Proxy für SmartHomeNG und die smartVISU können unter https://www.smarthomeng.de/nginx-als-reverseproxy gefunden werden!

In der /etc/nginx/.shng sind dabei mit htpasswd ein Username und ein Passwort generiert worden. So steht der Endpunkt geschützt im Internet. Diese Daten müssen später in der ConnectIQ App eingetragen werden.

location /rest {
        auth_basic "Restricted Area: SmartHomeNG";
        auth_basic_user_file /etc/nginx/.shng;

        proxy_pass http://192.168.178.100:4321/rest;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

Anpassung des ConnectIQ Programms

Auf Site des zuvor angelegten ConnectIQ Programms müssen nun folgende Anpassungen gemacht werden.

Berechtigung für Webservice Aufrufe setzen

Damit die App berechtigt ist, Webservices aufzurufen, muss zuerst das Manifest File unter /manifest.xml editiert werden. Eclipse bietet dazu mit dem ConnectIQ Plugin einen Editor an. Ist die Datei geöffnet, so findet sich der entsprechende Menüpunkt im Reiter „Permissions“ etwa in der Mitte des Fensters. Dort ist „Communications“ anzuklicken und danach die Datei zu speichern.

SmartHomeNG_on_a_WatchApp.mc

Zuerst wird eine Konstante für den Internet Endpunkt angelegt, über den das Itemset erreichbar ist. In der Methode getInitialView wird ein „Loading“ Text ergänzt.
Der Zugriff gegen den REST Webservice wird in der Methode makeRequest gekapselt, die in der Methode onStart beim Start aufgerufen wird. makeRequest bekommt am ende onReceive als Callback mitgegeben. Hier findet das Parsen der JSON Antwort statt, welche danach an ein neues View übergeben wird. Der View schaltet direkt um (Ui.SLIDE_IMMEDIATE), so dass der Loading-Screen bei Antwort verschwindet.

 

using Toybox.Application as App;
using Toybox.WatchUi as Ui;

const URL = "https://<dyndnsurl>/rest/itemset/1";

class SmartHomeNG_on_a_WatchApp extends App.AppBase {

    function initialize() {
        AppBase.initialize();
    }

    // onStart() is called on application start up
    function onStart(state) {
    	makeRequest();
    }

    // onStop() is called when your application is exiting
    function onStop(state) {
    }

    // Return the initial view of your application here
    function getInitialView() {
        return [ new SmartHomeNG_on_a_WatchView("Loading"), new SmartHomeNG_on_a_WatchDelegate() ];
    }
    
    function onReceive(responseCode, data) {
       if (responseCode == 200){
           System.println("Request Successful, Data: "+data);                   // print success
           var tempValue = data["eta_unit.temperature_outside.value"];  
           var resultString = "Temperatur: "+tempValue.format("%.1f")+" °C\n";           
           var view = new SmartHomeNG_on_a_WatchView(resultString);
           var delegate = new SmartHomeNG_on_a_WatchDelegate();
           Ui.switchToView(view, delegate, Ui.SLIDE_IMMEDIATE);           
       }
       else {
           System.println("Response: " + responseCode + ", Data: "+data);            // print response code
       }
    }
   
    function makeRequest() {
       var url = URL;
       
       var params = null;
       
	   var headers = {
	   "Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON, 
	   "Authorization" => "Basic " + StringUtil.encodeBase64(Lang.format("$1$:$2$", [ "<user>", "<password>" ])),
	   "Accept" => "application/json"};
	   
       var options = {                                           
           :method => Communications.HTTP_REQUEST_METHOD_GET,  
           :headers => headers,                                                                 
           :responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
       };

       var responseCallback = method(:onReceive);                  // set responseCallback to 
                                                                   // onReceive() method
       // Make the Communications.makeWebRequest() call
       Communications.makeWebRequest(url, params, options, method(:onReceive));
    }
}

SmartHomeNG_on_a_WatchView.mc

In der zugehörigen View-Datei, wird die Variable _message definiert, die den Text mit dem Temperaturwert aufnimmt. Dieser wird in onLayout gerendert.
Damit dies geschehen kann, muss unter /resources/layouts/layout.xml zuerst ein Label mit ID message hinterlegt werden:


<layout id="MainLayout">
    <label id="message" x="center" y="25" font="Gfx.FONT_XTINY" justification="Gfx.TEXT_JUSTIFY_CENTER"></label>
</layout>

Der Code in SmartHomeNG_on_a_WatchView.mc sieht dann wie folgt aus:


using Toybox.WatchUi as Ui;

class SmartHomeNG_on_a_WatchView extends Ui.View {

    hidden var _message;
	
    function initialize(message) {
        View.initialize();
        _message = message;
        System.println(message);
    }

    // Load your resources here
    function onLayout(dc) {
        setLayout(Rez.Layouts.MainLayout(dc));
    	View.findDrawableById("message").setText(_message);
    }

    // Called when this View is brought to the foreground. Restore
    // the state of this View and prepare it to be shown. This includes
    // loading resources into memory.
    function onShow() {
    }

    // Update the view
    function onUpdate(dc) {
        // Call the parent onUpdate function to redraw the layout
        View.onUpdate(dc);
    }

    // Called when this View is removed from the screen. Save the
    // state of this View here. This includes freeing resources from
    // memory.
    function onHide() {
    }
}

Ausführen des fertigen Programms

Das Programm kann nun wie oben beschrieben über „Run -> Run Configuration“ als Fenix5 Configuration ausgeführt werden. Die Temperatur erscheint nun, sofern alles richtig gemacht wurde, im Emulator.

Wenn man die App auf die Uhr übertragen möchte, so geht dies über „Connect IQ“ -> „Build For Device Wizard..“. Mit einem entsprechenden Developer Key lässt sich nun eine Datei generieren, die auf der Uhr in das Verzeichns \GARMIN\APPS kopiert werden muss. Dies macht der Wizard gleich mit.

Zieht man danach die Uhr vom USB Port ab, kann die App gestartet werden.

 

(Die in diesem Artikel verwendeten Screenshots und Fotos wurden selber erstellt.)


1 Kommentar

Peter Gamma · 14. März 2021 um 10:57

Solides Projekt welches sehr interessant ist. Ich vermisse ein Streaming aller Sensor Daten von Garmin Uhren über MQTT zu InfluxDB und eine Visualisierung in Grafana:

https://github.com/PeterGamma/Live-stream-of-sensor-data-from-Garmin-watches

Schreibe einen Kommentar

Avatar-Platzhalter

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert