Extracting JSON values for REST sensor

I apologize if this has been posted before. I have the following XML feed:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<?xml-stylesheet href="rss.xsl" type="text/xsl" media="screen"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<atom:link href="http://simcoecountyschoolbus.ca/rss.xml" rel="self" type="application/rss+xml" />
<title>Simcoe County Student Transportation Consortium</title>
<link>http://simcoecountyschoolbus.ca</link>
<description>School Bus Arrival Schedule for Simcoe County</description>
<ttl>1</ttl>
<language>en-us</language>
<pubDate>Mon, 22 Nov 2021 20:55:03 -0500</pubDate>
<lastBuildDate>Mon, 22 Nov 2021 20:55:03 -0500</lastBuildDate>
<item><title>North Zone</title><description>No Cancellations</description><pubDate>Mon, 22 Nov 2021 20:55:03 -0500</pubDate><guid isPermaLink="false">16376325031</guid></item>
<item><title>South Zone</title><description>No Cancellations</description><pubDate>Mon, 22 Nov 2021 20:55:03 -0500</pubDate><guid isPermaLink="false">16376325032</guid></item>
<item><title>Central Zone</title><description>No Cancellations</description><pubDate>Mon, 22 Nov 2021 20:55:03 -0500</pubDate><guid isPermaLink="false">16376325033</guid></item>
<item><title>West Zone</title><description>No Cancellations</description><pubDate>Mon, 22 Nov 2021 20:55:03 -0500</pubDate><guid isPermaLink="false">16376325034</guid></item>
<item><title>Muskoka</title><description>No Cancellations</description><pubDate>Mon, 22 Nov 2021 20:55:03 -0500</pubDate><guid isPermaLink="false">16376325035</guid></item>
</channel>
</rss>

I have setup the following sensor which successfully converts the feed to JSON…

  - platform: rest
    resource: https://simcoecountyschoolbus.ca/rss.xml
    scan_interval: 3600
    name: School Bus Cancellations
    value_template: "{{ value_json.rss.channel.item[0].title }}"

That value template works and gives me “North Zone”. But I would like to get all 5 zone titles and descriptions in one sensor. Is that possible? Thank you very much in advance. I love this community!!!

You can use map to get at one attribute of an array:

{{ value_json.rss.channel.item | map(attribute='title') | list }}

This will give you [North Zone, South Zone...], but I’m assuming you want something with multiple like:

North Zone: No Cancellations
South Zone: No Cancellations
etc

This can be done using a for loop:

{% for item in value_json.rss.channel.item -%}
  {{ item.title }}: {{ item.description }}
{% endfor %}

However, my preference is to use separate entities - one to load the data untouched, and then another template entity to pull out the required data (but read on because you may not need the second entity). Also, if you use rest.yaml rather than sensors.yaml, you can reload it on the fly under the “Developer Tools” YAML tab, rather than having to restart HA.

So in rest.yaml:

- resource: https://simcoecountyschoolbus.ca/rss.xml
  scan_interval: 3600
  sensor:
    - name: School Bus Cancellations
      json_attributes_path: "$.rss.channel"
      value_template: "{{ now() }}"
      json_attributes:
        - item

And then in templates.yaml:

- sensor:
    - name: School Bus Cancellation Info
      unique_id: school_bus_cancellation_info
      state: "{{ states('sensor.school_bus_cancellations') }}"
      attributes:
        info: >
          {% for item in state_attr('sensor.school_bus_cancellations', 'item') -%}
            {{ item.title }}: {{ item.description }}
          {% endfor %}

Note that this stores it in an attribute to keep the line breaks. If you don’t need them, you could just put it in the state.

Also, once you’ve loaded the REST data, if all you’re wanting to do is display it, you could look at the HACS addon List Card. It looks built for RSS feeds and produces tabular output.

1 Like

Thank you so much for this! Extremely helpful! What exactly does this mean…

value_template: "{{ now() }}"

You need to give the entity some state using “value_template”. When it does not have an obvious sensible value, I tend to put the time in (which is what now() does), so I can easily see when it last updated.

1 Like