Fuel Prices JSON undefined when rendering

Hi all,

Over the last couple of weeks, I’ve been getting errors returning on some (but not all) of the fuel prices that I’m pulling into Home Assistant.

The issues just seem to be occuring with the Tesco JSON file here: https://www.tesco.com/fuel_prices/fuel_prices_data.json.

Any ideas how I might fix it? Thanks!

2024-09-15 12:55:05.080 ERROR (MainThread) [homeassistant.helpers.template] Template variable error: ‘value_json’ is undefined when rendering ‘{% set c = value_json.stations| selectattr(‘site_id’, ‘eq’, ‘gcnqu4gfqytc’) | first %}{{ ‘%.3f’ | format(c.prices.E10) }}’

1 Like

Likely, the actual http call fails for whatever reason.

To just avoid the error message you can check the availability of the JSON.
The state of the sensor will change to unavailable then.

Here’s an example how I use it.
If, for whatever reason, sensor.shelly_plug_1_power is not providing a numeric value, the operating status also switches to unavailable.

    - name: "Washing Machine Operting Status"
      unique_id: fa06a837-3f59-4995-9750-34c0b3a8db70
      device_class: running
      delay_on:
        seconds: 60
      delay_off:
        seconds: 60
      availability: >
        {{ is_number(states('sensor.shelly_plug_1_power')) }}
      state: >
        {{ states('sensor.shelly_plug_1_power')|float > 1 }}
      icon: mdi:washing-machine

I’d like to add to this as the Tesco sensor last worked on 6th September.

The REST resource is https://www.tesco.com/fuel_prices/fuel_prices_data.json and my template is

value_template: "{% set station = value_json.stations | selectattr('site_id', 'eq', 'gcjcty9xrcsj') | first %}{{ '%.2f' | format(station.prices.B7 / 100) }}"

The logged error is “Template variable error: ‘value_json’ is undefined”

Nothing changed for me (no updates or reboots) when the error started appearing. I have since updated and rebooted, and the error persists.

Checking https://jsonlint.com/ the JSON Tesco is returning is actually valid.

ASDA/Sainsburys/Esso fuel price sensors are unaffected.

In Developer tools the template works as expected:

{% set value_json = {"last_updated": "17/09/2024 11:19:01", "stations": [{"site_id": "gcx1zhq978t7", "brand": "TESCO", "address": "Tesco Express Doncaster Road Brayton Selby", "postcode": "YO8 9EG", "location": {"latitude": 53.768681, "longitude": -1.089549}, "prices": {"E5": 141.9, "E10": 131.9, "B7": 138.9}}, {"site_id": "gcrjktx96h1j", "brand": "TESCO", "address": "Tesco Express Nuthall Road Nottingham", "postcode": "NG8 6AU", "location": {"latitude": 52.984551, "longitude": -1.198109}, "prices": {"E5": 136.9, "E10": 129.9, "B7": 135.9}} ... TRUCATED ...]} %}

{% set station = value_json.stations | selectattr('site_id', 'eq', 'gcjcty9xrcsj') | first %}{{ '%.2f' | format(station.prices.B7 / 100) }}

So, as koying says, the actual http call fails for whatever reason… how can I debug that reason and get to the bottom of this ‘value_json’ is undefined error?

Looks like that api (now?) requires some headers to work:

- resource: 'https://www.tesco.com/fuel_prices/fuel_prices_data.json'
  headers:
    user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0
    accept-encoding: gzip, deflate, br, zstd
  sensor:
  - name: Tesco
    value_template: >
      {% set station = value_json.stations | selectattr('site_id', 'eq', 'gcjcty9xrcsj') | first %}
      {{ '%.2f' | format(station.prices.B7 / 100) }}  

1 Like

I like the look of this, do you know if Shell offer the same? They’re local to me, but have 3 facilities across the town. So would be good to know which one has the lowest price for fuel.

Thanks,

Garry

I came across this post and was interested enough to try to run this in Node-RED. The UK Gov site has a full list of 15 fuel providers signed up to providing station location/price data in JSON format, so in Node-RED it was very easy to build a full list, poll the API for each brand, calculate distance from home for each station, and build a complete list of all stations with prices and distance. Did you know that the cheapest petrol is in Gibraltar, 1020 miles away?

However, the API for Tesco is proving difficult to get working.

The URL works just fine in a browser.

The URL did work, once, when first used in a Node-RED http request, thereafter it does not respond and I get a timeout.

Adding some headers to the call, such as

gets a response as ‘access denied - you do not have permission etc’.

I use Google Chrome, and by inspection pulled the complete set of 16 headers that Chrome uses to call the URL, then added all of them to my http request, and yes it now works. By carefully removing one header at a time, I have found which ones are required - missing any of these five gives me either access denied or a timeout error. (at least this is working at the moment…)

headers:
  accept: clubcard
  accept-encoding: points
  accept-language: spanglish
  user-agent: dark-glasses
  cookie: dough

You can see, from the header values that I am using, that nothing is actually being used, just someone at some point has messed about with something and the API URL (which goes through www-tesco-com) must be looking for the existence of certain headers before it both accepts and then forwards the request.

As they say, every little header helps.

You genius!! This was it… all fixed now. Thank you very much for posting :smiley:

Thank you ever so much - I’ve managed to get this back up and running now. Thank you!

This looks fab- not sure if I’m just being dense, but mine still doesn’t work. Does this look correct?

  - platform: rest
    name: Tesco Fuel Prices
    resource: http://www.tesco.com/fuel_prices/fuel_prices_data.json
    method: GET
    headers:
      accept: clubcard
      accept-encoding: points
      accept-language: spanglish
      user-agent: dark-glasses
      cookie: dough
    json_attributes:
      - stations
    scan_interval: 21600

I have not tried setting this up in HA as a rest sensor, but I have tried using this in Node-RED with an http request node, and it still appears to work there with the ‘nominal headers’ I was playing around with.

{"last_updated": "03/01/2025 11:18:59", "stations": [{"site_id": "gcx1zhq978t7", "brand": "TESCO", "address": "Tesco Express Doncaster Road Brayton Selby", "postcode": "YO8 9EG", "location": {"latitude": 53.768681, "longitude": -1.089549}, "prices": {"E5": 141.9, "E10": 131.9, "B7": 139.9}}, {"site_id": "gcrjktx96h1j", "brand": "TESCO", "address": "Tesco Express Nuthall Road Nottingham", "postcode": "NG8 6AU", "location": {"latitude": 52.984551, "longitude": -1.198109}, "prices": {"E5": 140.9, "E10": 133.9, "B7": 138.9}}, {"site_id": "gcr6ed3cmh3t", "brand": "TESCO", "address": "Rockingham Rd Market Harborough", "postcode": "LE16 7QD", "location": {"latitude": 52.483301, "longitude": -0.898259}, "prices": {"E5": 140.9, "E10": 133.9, "B7": 138.9}}, {"site_id": "gcw01j9wc5dn", "brand": "TESCO", "address": "East Lancashire Rd Windle Island St Helens", "postcode": "WA10 6QY", "location": {"latitude": 53.468891, "longitude": -2.766449}, "prices": {"E5": 138.9, "E10": 131.9, "B7": 137.9}}, {...

I suggest you try: