New to parsing json data

I am attempting to retrieve hourly data, from a glowmarkt api call, directly into a rest sensor. Ideally, what I am after is the time to the last hour (i.e. if this runs at 01:45 in morning, it will pick up the 01:00 data from the API results) and the value recorded in the api for that time.

I have done daily readings using node red but thought the hourly could be done via a single rest sensor. I am sure this should be simpler although I could adapt to use node red if required.

An example call to the api is:

https://api.glowmarkt.com/api/v0-1/resource/resourceid/readings?from=2022-10-08T01:00:00&to=2022-10-08T01:00:01&period=PT1H&offset=-60&function=sum

This returns:

{
    "status": "OK",
    "name": "electricity cost",
    "resourceTypeId": "rrrrrrr",
    "resourceId": "rrrrrrr",
    "query": {
        "from": "2022-10-08T01:00:00",
        "to": "2022-10-08T01:00:01",
        "period": "PT1H",
        "function": "sum"
    },
    "data": [
        [
            1665190800,
            3.228244
        ]
    ],
    "units": "pence",
    "classifier": "electricity.consumption.cost"
}

The 1665190800 is the epoch value for Saturday, 8 October 2022 01:00:00 and the 3.228244 is the value I want to record in the sensor against that time.

I saw similar ideas online so started to experiment with a rest sensor where the GET statement is fixed to the same value as the get statement above (will want to change this at some point to ensure the from and to values are built from the population time so that every hour, it picks up that hours value only) but I clearly don’t understand how the value_template picks up the 3.228244 value as the sensor has remained with a value of unknown.

My test sensor yaml is below:

- platform: rest
  name: elec_cost_per_hour_test
  method: GET
  resource_template: https://api.glowmarkt.com/api/v0-1/resource/resourceid/readings?from=2022-10-08T01:00:00&to=2022-10-08T01:00:01&period=PT1H&offset=-60&function=sum HTTP/1.1
  headers:
    applicationId: xxxxxxx
    Content-Type: application/json
    Host: api.glowmarkt.com
    Token: tokenid
    # Cookie:    
  value_template: >
    {%- set time = utcnow().replace(minute=0).replace(second=0).replace(microsecond=0) %}
    {%- set time = time.strftime("%Y-%m-%dT%H:%M:%SZ") %}
    {%- set selections = value_json.indicator['data'] | selectattr('datetime_utc','eq',time) | list %}
    {{ selections[0,1].value | float if selections | length > 0 else 0.0 }}
  scan_interval: 120

Please note I am aware the scan interval is not every hour. While testing I wanted it to occur more often

So what is your question exectly? The JSON path to the data you want would be data.0.1 or data[0][1]. However, HA comes with the feature to extract the values for you. For testing I installed this sensor (Yes cats, because its the internet :wink: ):

rest: 
    - resource: https://catfact.ninja/fact
      scan_interval: 10
      sensor:
        - name: "fact"
          value_template: "{{ value_json.fact }}"
          json_attributes_path: "$."

The JSON provided by this API looks like:

{
  "fact": "The strongest climber among the big cats, a leopard can carry prey twice its weight up a tree.",
  "length": 94
}

In the developer tools → templating a simple {{ states('sensor.fact') }} gives:

A cat has more bones than a human being; humans have 206 and the cat has 230 bones.

Thanks. The info you gave me helped, particularly the data.0.x info.

For info, I eventually created rest sensors using the rest (not sensor) type and, as there appeared to be some delay in hildebrand receiving data, I set it to pick up data from 6 hours ago every hour. The Rest method was flexible regarding making one call and saving both pieces of data. Below is the rest.yaml I created as a result:

- resource_template: https://api.glowmarkt.com/api/v0-1/resource/{{states('input_text.electric_cost_resource_id')}}/readings?from={{ (now()).strftime("%Y-%m-%d") }}T{{ (now()-timedelta(hours=6)).strftime("%H") }}:00:00&to={{ (now()-timedelta(hours=6)).strftime("%Y-%m-%d") }}T{{ (now()).strftime("%H") }}:00:01&period=PT1H&offset=-60&function=sum HTTP/1.1
  method: GET  
  headers:
    applicationId: !secret hildebrand_glowmarkt_applicationId
    Content-Type: application/json
    Host: api.glowmarkt.com
    Token: "{{ states('input_text.hildebrand_token1') }}{{ states('input_text.hildebrand_token2') }}"
    # Cookie:    
  scan_interval: 3600
  sensor:
    - name: "test elec cost time"
      value_template: "{{ value_json.data.0.0 }}"
    - name: "test elec cost"
      value_template: "{{ value_json.data.0.1 }}"
      unit_of_measurement: "p"

Hi, I have a sort of similar question around parsing a json output to create a sensor. I have json API response that looks like the below. Is actually much bigger than this but tried to cut it down for my example.

{
“id”: “xyz”,
“profileAssociations”: [
{
“serviceArea”: “cdf”,
“priority”: “1”
}
],
“overriddenConfigParams”: [
{
“parameterName”: “Device.DeviceInfo.Location.LocationCheckEnable”,
“parameterValue”: “FALSE”
},
{
“parameterName”: “Device.Time.X_0005B9_PTP.Server”,
“parameterValue”: “192.168.7.2”
},
{
“parameterName”: “Device.PeriodicStatistics.SampleSet.-1.SampleInterval”,
“parameterValue”: “900”
}
],
“provisionedConfigParams”: [

    {
        "parameterName": "Device.IPsec.Enable",
        "parameterValue": "true",
        "valueSource": "GUIOVERRIDE"
    },
    {
        "parameterName": "Device.Time.NTPServer5",
        "parameterValue": "85.199.214.100",
        "valueSource": "WEBGUIOVERRIDE"
    },
    {
        "parameterName": "Device.Time.NTPServer2",
        "parameterValue": "5.101.146.245",
        "valueSource": "WEBGUIOVERRIDE"
    }
],
"operationalParams": [
    {
        "parameterName": "Device.Time.NTPServer2",
        "parameterValue": "5.101.146.245"
    },
    {
        "parameterName": "Device.IP.Interface.1.IPv4Address.2.IPAddress",
        "parameterValue": "10.10.10.2"
    },
    {
        "parameterName": "Device.IP.Interface.1.Name",
        "parameterValue": "eth1"
    }
],
"alarms": [],
"installationParams": {
    "indoorDeployment": false
},
"lastContactTime": "2025-01-13 11:01:05.954",
"replanStatus": "false"

}

I want to get the parameter value for a specific parameter name, for example get the eth1 response from parameter name Device.IP.Interface.1.Name. So far I can achieve this using below value template.

value_template: “{{ value_json.operationalParams[2].parameterValue }}”

However, the challenge I am facing is that the response is quite long and the numbering keeps chaging, so one moment is object number 2 then is object number 5 etc. So instead I want to parse using the specific name which is always static. I tried playing around with the formating of my template to include parameter name but to no luck so far.

Could someone please help advise how can I list a specific parameter within a specific json object

Use selectattr (ref). For example using bracket notation rather than dot notation, because it’s objectively better, and with line breaks only for readability:

{{ value_json['operationalParams']
   |selectattr('parameterName','eq','Device.IP.Interface.1.Name')
   |map(attribute='parameterValue')
   |first }}

selectattr pulls the list item(s) that match the test; map with attribute then pulls all the named attributes out into a list. first just gets the first (and here, only) item from that list.

In future, please post code using the </> button to ensure it’s properly formatted.

Thanks so much about this and making it work…spent a lot of time time trying to make it work as I am not familiar with json and conding in general. Appreciate it!

This was very useful for me. However, One problem is that the value I’m searching for contains blank spaces:

{{ data|selectattr('ClearTextName','eq','Indoor Temp (TE3)')|map(attribute="Value")|first }}

where data includes:

  {
    "Name": "289",
    "ClearTextName": "Indoor temp (TE3)",
    "ValueType": null,
    "Value": "21.2",
    "UnitType": "DegreesCelsius",
    "UnitPresentation": "°C"
  },

All I’m getting is “No first item, sequence was empty.” Any idea how I might get to the ClearTextName in point?

That’s not your problem.

Spell “temp” with a lower-case “t” in your selectattr.

1 Like

Haha, well that’s something. Thanks! Thought there was some trouble with blank spaces.