Multiple sensors in one REST call - returned as an array

In Multiple sensors in one REST call the question was about handling data returned from a REST service as a JSON dictionary.

My problem relates to a service that returns its items as an array - which could be transformed to a dictionary (but unfortunately aren’t), so how would the documented bedoom1/bedroom2/bedroom3 sensor be configured if the returned JSON instead looked like this:-

[
    {
        "room": "bedroom1",
        "temperature": 14.98,
        "humidity": 53.68,
        "battery": 5.26,
        "timestamp": "2019-02-25T21:27:52Z"
    },
    {
        "room": "bedroom2",
        "temperature": 18.49,
        "humidity": 47.65,
        "battery": 5.08,
        "timestamp": "2019-02-25T21:27:26Z"
    },
    {
        "room": "bedroom3",
        "temperature": 18.14,
        "humidity": 48.16,
        "battery": 5.15,
        "timestamp": "2019-02-25T21:31:16Z"
    }
]

Is it possible to use the json_attributes or json_attributes_path to be able to end up with sets of attributes for bedroom1, bedroom2 and bedroom3.

For a real world application for this, the York Bin Collection API returns between 1 and 3 dictionaries for a property, each of which describes one type of bin collection - it is not specified (but appears to be generally consistant) what order the sets of bin collection data are returned in, which is why I would like to link it to one entry within the dictionary as an index.

An example of the sort of entry you may get is given below - for two sets of bins (for my own properly there are three sets, for a total of approx 3.5KB of JSON)

[
    {
        "AlternativeRoundNumber": null,
        "AlternativeRoundNumberDescription": null,
        "BinType": "GREY 240",
        "BinTypeDescription": "Grey Bin 240L",
        "CollectionAvailable": "Y",
        "CollectionCalendar": "?",
        "CollectionDay": "MON",
        "CollectionDayFull": "Monday",
        "CollectionDayOfWeek": 1,
        "CollectionFrequency": "Alternate Weeks",
        "CollectionFrequencyShort": "WEEK 1",
        "CollectionPoint": "FRONT",
        "CollectionPointDescription": "Edge of Property at Front",
        "CollectionPointLocation": null,
        "CollectionType": "GREY BIN/SACK",
        "CollectionTypeDescription": "Grey Bin/Black Sack Collection",
        "Frequency": {
            "ExcludeSunday": null,
            "FrequencyInDays": 14,
            "StartingWeekNumber": 2
        },
        "ImageName": "blackbin",
        "LastCollection": "/Date(1586732400000)/",
        "Locality": null,
        "MaterialsCollected": "General Domestic",
        "NextCollection": "/Date(1587942000000)/",
        "NumberOfBins": "1",
        "Postcode": "YO24 1NB",
        "PropertyName": null,
        "PropertyNumber": "10",
        "Provider": "City of York Council",
        "ProviderShort": "CYC",
        "RoundNumber": "TEAM 2",
        "RoundNumberDescription": "Team 2",
        "SaonName": null,
        "SaonNo": null,
        "ShortAddress": "10 LYCETT ROAD",
        "Street": "LYCETT ROAD",
        "UPRN": 100050567115,
        "Ward": "Dringhouses & Woodthorpe",
        "WasteType": "GREY BIN/SACK",
        "WasteTypeDescription": "Grey Bin/Black Sack Collection"
    },
    {
        "AlternativeRoundNumber": null,
        "AlternativeRoundNumberDescription": null,
        "BinType": "BOX 55",
        "BinTypeDescription": "Box 55L",
        "CollectionAvailable": "Y",
        "CollectionCalendar": "?",
        "CollectionDay": "WED",
        "CollectionDayFull": "Wednesday",
        "CollectionDayOfWeek": 3,
        "CollectionFrequency": "Alternate Weeks",
        "CollectionFrequencyShort": "WEEK 2",
        "CollectionPoint": "FRONT",
        "CollectionPointDescription": "Edge of Property at Front",
        "CollectionPointLocation": null,
        "CollectionType": "KERBSIDE",
        "CollectionTypeDescription": "Kerbside Collection",
        "Frequency": {
            "ExcludeSunday": null,
            "FrequencyInDays": 14,
            "StartingWeekNumber": 1
        },
        "ImageName": "box",
        "LastCollection": "/Date(1586300400000)/",
        "Locality": null,
        "MaterialsCollected": "Paper/Card : Plastic/Cans : Glass",
        "NextCollection": "/Date(1587510000000)/",
        "NumberOfBins": "3",
        "Postcode": "YO24 1NB",
        "PropertyName": null,
        "PropertyNumber": "10",
        "Provider": "City of York Council",
        "ProviderShort": "CYC",
        "RoundNumber": "B",
        "RoundNumberDescription": "Round B",
        "SaonName": null,
        "SaonNo": null,
        "ShortAddress": "10 LYCETT ROAD",
        "Street": "LYCETT ROAD",
        "UPRN": 100050567115,
        "Ward": "Dringhouses & Woodthorpe",
        "WasteType": "KERBSIDE",
        "WasteTypeDescription": "Kerbside Collection"
    }
]

I’d really like to grab everything as a single API call rather than hammering the API due to deficiencies in the data de-serialisation.

Thanks

Nigel.

1 Like

I’m afraid that this structure is currently not really supported. Normally you would store the payload in one of more attributes of the rest sensor and then use template sensors to extract the data you want.
However, in this case:

  • value_template gives most flexibility in terms of defining a template, but is limited to a maximum of 255 characters.
  • json_attributes_path really only lets you specify where a dict structure is to be found in the JSON payload. It does not you specify a path to each of the 3 dicts in the list.
  • json_attributes: takes a list of keys from a dict, which doesn’t exist in this example.

So, at this point in time I don’t see a way to avoid multiple rest calls

With your example of bin collection I assume that the actual data does not change very often? And for a specific property, is the number of entries in the result always the same?

If so, the rest sensor supports to define scan_interval - the time interval at which it should fetch new data. You could set up multiple rest sensors - one for each entry in the JSON result, then set this scan_interval to a very long time (e.g. 1 year), and then use automations (service homeassistant.update_entity) to manually update each sensor (e.g. first sensor at 6am, 12pm, 6pm; second sensor at 7am, 1pm, 7pm; etc.).

Many thanks for your response - I suspected that was the case.

I’ve now gone at this a slightly different way - I have written a python command line shim program which makes the data a bit better organised for Home Assistant to use, and can be used from a Command Line Sensor:-

sensor:
  # York Bins Collection API - 3 sets, 1 for each bin
  - platform: command_line
    command: /config/york_bin_collection.py 100050567115
    name: Bin Collection
    scan_interval: 86400
    value_template: '{{ value_json.next_collection }}'
    json_attributes:
      - next_collection
      - next_collection_types
      - blackbin
      - greenbin
      - box
      - updated

The code I am using can be found at in this github repository

I haven’t yet put automations etc around this, so I may end up changing things a little yet, but I think it gives a reasonable way of interfacing the York API data into Home Assistant.

Nigel.

1 Like

Has there been any development on this issue?

As far as I can understand from my testing this problem still persists. I hope that I’m wrong but the only native solution seems to make multiple API calls, once for each of the “bedrooms” in the example code.

The following example would get the data for “bedroom2”. Just wanted to add this as this solution was not obvious to me when trying to understand the examples in the documentation.

value_template: '{{value_json[1].room}}'
json_attributes_path: "$[1]"
json_attributes:
    - room
    - temperature

Have a look at the Rest integration. The first example in the documentation shows one REST call used as the source for multiple sensors.

That looks promising as multiple json_attributes_path seems to be possible. Will check in once I can confirm that it works as I’m hoping. Thanks!