One REST sensor with multiple array queries

Despite my best efforts with the documentation, I must confess to being stuck. Any help would be appreciated.

I’m trying to set up some REST sensors to poll my local bike share, and although I have it working, it seems a little kludgy and inelegant.

Basically, the way the JSON feed stores individual stations is in an array, and I only really want data from items in the array that match certain criteria.

Right now I have this in my rest.yaml:


- scan_interval: 60
  resource: https://gbfs.citibikenyc.com/gbfs/en/station_status.json
  sensor:
    - name: "CitiBikeTest3"
      state_class: measurement
      json_attributes_path: "$.data.stations[?(@.station_id == '72')]"
      value_template: '{{value_json.num_bikes_available}}'
      json_attributes:
          - "num_bikes_available"

Now, if I have to make multiple calls, so be it, but I was wondering if there is a way to have this part:

[?(@.station_id == '72')]

with different values to search for appear as different attributes for the same sensor.

I’ve tried a variety of combinations, and am having a lot of difficulty.

If you use the new rest integration instead of the rest sensor platform you can define as many sensors as you want and they will be populated using the one resource call:

Don’t be fooled by all the example value_templates just being “OK” they can be any jinja template.

Thank you, although I’m struggling with how to search (versus simply indexing) through an array to find a matching key:value pair.

The examples in the documentation has a number of key:value pairs, and the one example

sensor:
  - platform: rest
    name: JSON users
    json_attributes_path: "$.[0].address"
    json_attributes:
      - street
      - suite
      - city
      - zipcode
    resource: https://jsonplaceholder.typicode.com/users
    value_template: "{{ value_json[0].name }}"

that accesses an array does so with a set index value. The feed I’m accessing changes as stations are moved/added/removed, so a hard-coded index won’t work for long.

Can the json_attributes_path be defined so that each attribute in the sensor uses a different path?

Not sure if this is helpful, but I recently discovered that if you set the value_template attribute of a rest sensor to “OK”, you can get the retrieved JSON as an attribute. You might then be able to use templates to step through your data and apply logic.

  - platform: rest
    name: JSON Retrieval
    value_template: "OK"
    json_attributes:
      - variable_name_for_stored
    resource: https://url.com
    timeout: 30
    scan_interval: 3600
1 Like

What?

No. That is completely untrue. The value_template and attributes are unrelated. You don’t have to set the state to OK. You can set it to anything and still get attributes. The only requirement is that the result be under 255 characters in length. Not an issue if you are only making one sensor with a value (see below).

Again no. There is no need for template sensors with the new integration. You can create as many sensors as you need and they will all be populated with a value from one resource call.

So instead of storing your entire json data in an attribute and using templates to pick the bits you want, you just define a bunch of sensors to pick the bits you want. Seriously check out the link to the documentation I posted above.

No. That can’t be done for the one sensor.

So create more than one sensor instead of attributes. It does not require another call to the resource. Create as many sensors as you need.

Talking through this helped me understand what was going on with that first example.

I have now successfully used one API call to return multiple values with different paths.

Thank you.

1 Like

From the rest sensor docs:

This configuration shows how to extract multiple values from a dictionary with json_attributes and template . This avoids flooding the REST service by only requesting the result once, then creating multiple attributes from that single result using templates. By default, the sensor state would be set to the full JSON — here, that would exceed the 255-character maximum allowed length for the state, so we override that default by using value_template to set a static value of OK .

That is for the legacy restful sensor platform.

This whole topic I have been advising to use the new restful integration.

While the value template of the new integration still has the 255 character limit you can make as many sensors as you want, from the one service call to the resource.

Using this new method, each attribute you want gets it’s own sensor and value_template, completely avoiding the need for template sensors.

And I’ll repeat this, it is all done with one call to the resource. Where-as using the legacy sensor platform each sensor makes it’s own call to the resource. Which is why we used to load up all the data we wanted into attributes (not the state - to avoid the 255 limit), so that only one call was made to the resource and it did not get overloaded. These attributes were then split out into separate sensors using template sensors.

This new integration completely avoids the need for this work-around.

I still don’t get the expansion of a dictionary.
My glances sensor http://192.168.x.x:61208/api/3/fs yields this dictionary:

[{"device_name": "/dev/sda2", "fs_type": "ext4", "mnt_point": "/", "size": 116002414592, "used": 66471817216, "free": 43670044672, "percent": 60.4, "key": "mnt_point"},
{"device_name": "/dev/sda1", "fs_type": "vfat", "mnt_point": "/boot/efi", "size": 535805952, "used": 8413184, "free": 527392768, "percent": 1.6, "key": "mnt_point"},
{"device_name": "/dev/sdb1", "fs_type": "ext4", "mnt_point": "/mnt/SanDisk1T", "size": 983351443456, "used": 738204069888, "free": 195120336896, "percent": 79.1, "key": "mnt_point"},
{"device_name": "/dev/sdc1", "fs_type": "ext4", "mnt_point": "/mnt/ST6DM3", "size": 5952693100544, "used": 5375985111040, "free": 276632539136, "percent": 95.1, "key": "mnt_point"},
{"device_name": "/dev/sdd1", "fs_type": "ext4", "mnt_point": "/mnt/WD80EZZX", "size": 7937301327872, "used": 5501409464320, "free": 2035797049344, "percent": 73.0, "key": "mnt_point"}]

I want to extract the sizes (since the glances integration omits all totals).
But: the disk count and order may change.
Thus, I can’t just hardcode the sensors like:

- platform: rest
  resource: http://192.168.x.x:61208/api/3/fs
  scan_interval: 86400 #daily
  timeout: 58 #default 10s is too low; must be lower than scan_interval
  name: Host HDD0
  icon: mdi:harddisk
  json_attributes_path: "$[0]"
  json_attributes:
  - size
  - device_name
  - mnt_point
  value_template: >
    {% if value_json %}
    root
    {% else %}
    ??
    {% endif %}

- platform: rest
  resource: http://192.168.x.x:61208/api/3/fs
  scan_interval: 86400 #daily
  timeout: 58 #default 10s is too low; must be lower than scan_interval
  name: Host HDD1
  icon: mdi:harddisk
  json_attributes_path: "$[1]"
  json_attributes:
  - size
  - device_name
  - mnt_point
  value_template: >
    {% if value_json %}
    boot
    {% else %}
    ??
    {% endif %}

So how can I extract the needed attributes from a dictionary of not predetermined size?

1 Like

Can you post what you’ve done please? Bike season is starting again… :slight_smile:

Do you have a solution for this meanwhile? Could need that, too :slight_smile: