A SimpleDataField with WebRequest

I'm a bloody beginner and I'd like to return the data from a web request:

import Toybox.Activity;

import Toybox.Lang;

import Toybox.Time;

import Toybox.WatchUi;

class AareTempView extends WatchUi.SimpleDataField {

    // Set the label of the data field here.

    function initialize() {

        SimpleDataField.initialize();

        label = "°C";

    }

    // The given info object contains all the current workout

    // information. Calculate a value and return it in this method.

    // Note that compute() and onUpdate() are asynchronous, and there is no

    // guarantee that compute() will be called before onUpdate().

    function compute(info as Activity.Info) as Numeric or Duration or String or Null {

        // See Activity.Info in the documentation for available information.

        return „water temperature from url https://aareguru.existenz.ch/v2018/current?city=thun&version=1.0.42&values=aare.temperature; 

    }

}

I've heard that it's only possible with a background service, but I don't how to combine the code above with the following samples (JSON, backgrounding):

https://developer.garmin.com/connect-iq/core-topics/https/ 

https://developer.garmin.com/connect-iq/core-topics/backgrounding/ 

Is anyone interested in helping a non information scientist?

Watch: Instinct 2 Solar Surf Edition

  • I will compare the code with the following app: https://github.com/neusinn/AareWidget

    It’s showing the same information but in a more complex way (not compatible with Instinct2). Same data source and obviously it’s working.

  • I cloned that repo and made a few mods to get it to build:

    diff --git a/monkey.jungle b/monkey.jungle
    index 87796c7..8c02d8e 100644
    --- a/monkey.jungle
    +++ b/monkey.jungle
    @@ -1 +1,2 @@
     project.manifest = manifest.xml
    +project.typecheck = 0
    \ No newline at end of file
    diff --git a/source/AareGuruModel.mc b/source/AareGuruModel.mc
    index 0488a51..434e064 100644
    --- a/source/AareGuruModel.mc
    +++ b/source/AareGuruModel.mc
    @@ -1,4 +1,5 @@
     using Toybox.Communications as Comm;
    +import Toybox.Lang;
    
     class AareGuruData {
            var aare;

    It fails for me on MacOS (as did my own sample data field), when Use Device HTTPS Requirements is enabled.

    On Windows, both apps work, regardless of whether Use Device HTTPS Requirements is enabled or not.

    Ofc the real question is whether or not it would work on a real device - based on what you said, probably not. You may wish to submit a bug report for this problem.

  • On a real device it could vary based on the phone - Android or iOS.

    Sounds to me like the website needs to use a certificate accepted by both.

  • I‘ve got a different data source url, more „official“ than the last one. Maybe it‘s a certificate accepted by both.

    The result isn‘t only the wanted value (see url) How can I extract only the wanted value in order to implement it to the code?

    https://api.existenz.ch/apiv1/hydro/latest?locations=2030&parameters=temperature%2Cflow&version=1.0.42

  • How can I extract only the wanted value in order to implement it to the code?

    Going back to the example I posted:

    1) Change HTTP_RESPONSE_CONTENT_TYPE_TEXT_PLAIN  to HTTP_RESPONSE_CONTENT_TYPE_JSON. This is necessary because now the response is wrapped in a JSON object. It also means your app can now run on much older devices (CIQ 2.3 as opposed to CIQ 3).

    2) The response looks like this (after beautification):

    {
        "source": "Swiss Federal Office for the Environment FOEN \/ BAFU, Hydrology",
        "apiurl": "https:\/\/api.existenz.ch#hydro",
        "opendata": "https:\/\/opendata.swiss\/en\/dataset\/wassertemperatur-der-flusse",
        "license": "https:\/\/www.hydrodaten.admin.ch\/uploads\/attachments\/148\/agb_fur_das_herunterladen_aktueller_hydrologischer_messdaten.pdf",
        "payload": [{
            "timestamp": 1696717200,
            "loc": "2030",
            "par": "temperature",
            "val": 17.22
        }, {
            "timestamp": 1696717200,
            "loc": "2030",
            "par": "flow",
            "val": 68.43
        }]
    }

    makeWebRequest() will return that data to callback in the form of a Monkey C dictionary whose contents can (recursively) be:
    - dictionaries

    - arrays

    - primitives (numerical values, booleans, and strings)

    You have to access the part of the data you're interested in.

    e.g. WaterTempDFApp.mc

    The forum won't let me post the code, so here it is as a screenshot and a pastebin link.

    https://pastebin.com/p4TWanys

  • Also, you can simplify things quite a bit by only requesting temperature data (the link you posted also requests flow data). and by not bothering to check the type of the received data (under the assumption that the API won't change):

    e.g. [https://api.existenz.ch/apiv1/hydro/latest?locations=2030&parameters=temperature&version=1.0.42]

    returns something like this, after beautification:

    {
        "source": "Swiss Federal Office for the Environment FOEN \/ BAFU, Hydrology",
        "apiurl": "https:\/\/api.existenz.ch#hydro",
        "opendata": "https:\/\/opendata.swiss\/en\/dataset\/wassertemperatur-der-flusse",
        "license": "https:\/\/www.hydrodaten.admin.ch\/uploads\/attachments\/148\/agb_fur_das_herunterladen_aktueller_hydrologischer_messdaten.pdf",
        "payload": [{
            "timestamp": 1696717200,
            "loc": "2030",
            "par": "temperature",
            "val": 17.22
        }]
    }

    Your code could look like this:

    https://pastebin.com/P5M2EMf9

    (To be fair, this code would also work in the case that both temperature and flow data are requested, as in the URL you posted, under the reasonable assumption that the API always returns data in the order it's requested.)

  • Thanks a lot again!

    I tested it on the device and waited 5 minutes (.... new time.duration ....) to be sure but no success with this new url. Seems there's nothing we can do apart from reporting the bug.

    Or maybe this:  LINDAS Linked Data Services (SPARQL queries, data format rdf) https://environment.ld.admin.ch/.well-known/void/dataset/hydro?lang=en#blank-1

    I feel like wasting your time... I'm sorry!

  • No problem! I didn't actually test this new code in the sim or device, so I wasn't sure either way if it would work this time.

    Now I see that it does fail on macOS with Use HTTPS Device Requirements enabled.

    Not too surprising since it's the same site and it also uses a Lets Encrypt certificate.

  • Could it work when I link the data through a own website? Or not, because in the core it‘s still the data from the API above?

  • Simple linking using a URI redirect is unlikely to help. You would probably have to write a script on your server, pulling the data from the remote server, and then serving it to the CIQ API on a connection using a compatible SSL certificate (or using plain HTTP instead of HTTPS).