nordpool icon indicating copy to clipboard operation
nordpool copied to clipboard

The sensor is not updating every 15 minutes

Open Emlben opened this issue 7 months ago • 48 comments

Version of the custom_component

0.0.17

Homeassistant version

2025.9.4

Configuration


Add your configuration here.

Describe the bug

A clear and concise description of what the bug is. We have hade 15 minute intervals of electric prices since midnight. Yesterday it was confirmed that the new price interval was received ok by the component.

But now it seemes like the sensor itself is only updated every hour - and not every 15 minutes.

Debug log

Add your logs here.

History of the sensor since midnight, shows that the sensor are only updated once per hour:

sensor.nordpool_kwh_se3_sek_3_10_025 | 1.413 | 2025-10-01T00:00:00.205Z

sensor.nordpool_kwh_se3_sek_3_10_025 | 1.336 | 2025-10-01T01:00:00.208Z sensor.nordpool_kwh_se3_sek_3_10_025 | 1.335 | 2025-10-01T02:00:00.264Z sensor.nordpool_kwh_se3_sek_3_10_025 | 1.462 | 2025-10-01T03:00:00.209Z sensor.nordpool_kwh_se3_sek_3_10_025 | 1.911 | 2025-10-01T04:00:00.259Z

Emlben avatar Oct 01 '25 04:10 Emlben

Also current_price is hourly

Tabbe70 avatar Oct 01 '25 05:10 Tabbe70

Same issue, current value is first value of each hour.

developerfromjokela avatar Oct 01 '25 05:10 developerfromjokela

Temporary workaround for my usecase:

    value_template: >
      {# Prev: '{{ int(state_attr("sensor.nordpool", "current_price") * 100 | round(1, default=0)) }}' #}
      {% set data = state_attr('sensor.nordpool','raw_today') or [] %}
      {% set nowts = as_timestamp(now()) %}
      {% set current = namespace(val=None) %}
      {% set nexti = namespace(val=None, start=9999999999) %}
      {% for p in data %}
        {% set s = as_timestamp(as_datetime(p.start)) %}
        {% set e = as_timestamp(as_datetime(p.end)) %}
        {% if nowts >= s and nowts < e %}
          {% set current.val = (p.value * 100) | round(0) | int %}
        {% endif %}
        {% if s >= nowts and s < nexti.start %}
          {% set nexti = namespace(val=p.value, start=s, end=e) %}
        {% endif %}
      {% endfor %}
      {{ current.val if current.val is not none else nexti.val if nexti.val is not none else 'unknown' }}

zgnusrx avatar Oct 01 '25 06:10 zgnusrx

It should also still be able to get the hourly prices for the region. Not all electricity providers are switching to the new 15-minute intervals (at least mine does not (Zonneplan in NL)).

The EPEX day-ahead market still provides 1-hourly interval prices, so the integration should still be able to fetch those, and present 24 hourly prices from the 1-hourly EPEX source...

HindrikDeelstra avatar Oct 01 '25 06:10 HindrikDeelstra

Waiting for a proper fix

rogerthn2019 avatar Oct 01 '25 06:10 rogerthn2019

It should also still be able to get the hourly prices for the region. Not all electricity providers are switching to the new 15-minute intervals (at least mine does not (Zonneplan in NL)).

The EPEX day-ahead market still provides 1-hourly interval prices, so the integration should still be able to fetch those, and present 24 hourly prices from the 1-hourly EPEX source...

Good point, it should be possible to use the hourly prices published by Nord Pool as that is what will be used (for the time being) towards consumers in Norway. https://data.nordpoolgroup.com/auction/day-ahead/price-indices?deliveryDate=latest&currency=NOK&resolutionInMinutes=60&indexNames=AT,NO1

uphillbattle avatar Oct 01 '25 07:10 uphillbattle

Maybe a simple switch that updates every 15 minutes / 1 hour in the app.

cojo3667 avatar Oct 01 '25 08:10 cojo3667

I modified the code to make it work until proper fix is implemented.

In custom_components/nordpool/misc.py I modified the start_of function to be like this:

def start_of(d, typ_="hour"):
    if typ_ == "hour":
        return d.replace(minute=0, second=0, microsecond=0)
    if typ_ == "15min":
        return d.replace(minute=d.minute // 15 * 15, second=0, microsecond=0)
    elif typ_ == "day":
        return d.replace(hour=0, minute=0, microsecond=0)

In custom_components/nordpool/sensor.py I modified the _update_current_price(self) function in a way that start_of(local_now, "hour") is now start_of(local_now, "15min").

And in custom_components/nordpool/init.py I modified the line

cb_new_hr = async_track_time_change(hass, new_hr, minute=0, second=0)

to be

cb_new_hr = async_track_time_change(hass, new_hr, minute='/15', second=0)

sander85 avatar Oct 01 '25 08:10 sander85

@zgnusrx could you please expand , how and where to apply your fix above? 🙏

I first thought it was generic (affecting all Nordpool prices incoming). Now wonder if it needs to be applied in a separate template/ sensor and then we need to swap out references to this new price-sensor ( with your fix applied)?

I was unable to find documentation i understand about value templates - so am alittle stuck... my 'Vibe-coding buddy' says to create a new sensor, but ?

I have two sensors one for spot, and one 'all-in' which contains all extra taxes and fees - both created in the nordpool add-on, not as separate sensors in configuration.yaml.

blueeyes08 avatar Oct 01 '25 08:10 blueeyes08

I modified the code to make it work until proper fix is implemented.

Thank you for great and fast work @sander85 This worked on my system - awesome! Very happy!

blueeyes08 avatar Oct 01 '25 09:10 blueeyes08

I modified the code to make it work until proper fix is implemented.

Also thank you! Works for me.

I did a blueprint fork that is using 15min changes from anhelgesen/Nordpool_price.yaml. Some easy automation to control our new 15min tariffs.

Mad-Jam avatar Oct 01 '25 09:10 Mad-Jam

Hi all, Home Assistant warns that sensor.nordpool_xxx attributes exceed 16 KB. This happens because the sensor stores all day’s prices (all 15-minute intervals) as attributes. Causing this error msg:

WARNING (Recorder) [homeassistant.components.recorder.db_schema] State attributes for sensor.nordpool_xxx exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored

When the attributes are too large, they aren’t stored in the database, which can make updates appear delayed or incomplete.

Workarounds / tips: Use a template sensor to extract only the current price from the raw_today attribute instead of storing the full day’s data.

sensor:
  - platform: template
    sensors:
      nordpool_current_15min:
        friendly_name: "Nordpool Current Price"
        unit_of_measurement: "€/kWh"
        value_template: >
          {% set data = state_attr('sensor.nordpool_xxx', 'raw_today') or [] %}
          {% set nowts = as_timestamp(now()) %}
          {% set current = namespace(val=None) %}
          {% for p in data %}
            {% set s = as_timestamp(as_datetime(p.start)) %}
            {% set e = as_timestamp(as_datetime(p.end)) %}
            {% if nowts >= s and nowts < e %}
              {% set current.val = (p.value * 100) | round(2) %}
            {% endif %}
          {% endfor %}
          {{ current.val if current.val is not none else 'unknown' }}

PetrolHead2 avatar Oct 01 '25 15:10 PetrolHead2

'/15'

Thanks! That solved my issue for now also!

Emlben avatar Oct 01 '25 20:10 Emlben

It should also still be able to get the hourly prices for the region. Not all electricity providers are switching to the new 15-minute intervals (at least mine does not (Zonneplan in NL)). The EPEX day-ahead market still provides 1-hourly interval prices, so the integration should still be able to fetch those, and present 24 hourly prices from the 1-hourly EPEX source...

Good point, it should be possible to use the hourly prices published by Nord Pool as that is what will be used (for the time being) towards consumers in Norway. https://data.nordpoolgroup.com/auction/day-ahead/price-indices?deliveryDate=latest&currency=NOK&resolutionInMinutes=60&indexNames=AT,NO1

Yeah!! That link gives values, which correspond to the ones from my provider (ANWB) which will continue with 1 hour prices! So indeed it would be nice to get an option to choose between 1 hour, or 15 minutes

TheBrankman avatar Oct 01 '25 21:10 TheBrankman

I wanted my hourly prices back. This component uses an older API and there doesn't seem to be any way to make it return hourly prices (I tried adding "&aggregation=Hourly").

So I had to take a less elegant approach - recalculate hourly prices from the quarterly ones. This also solves the "attributes exceeding 16kB" issue.

So in the file aio_price.py, before

        return {
            "start": start_time,
            "end": end_time,
            "updated": updated,
            "currency": currency,
            "areas": area_data,
        }

insert the following snippet:

        # Aggregate quarterly values into hourly
        if data_type == self.HOURLY:
            for area_key, data_dict in area_data.items():
                vals = sorted(data_dict["values"], key=lambda v: v["start"])
                hourly_vals = []
                for i in range(0, len(vals), 4):
                    chunk = vals[i:i+4]
                    if len(chunk) == 4:
                        hour_start = chunk[0]["start"].replace(minute=0, second=0, microsecond=0)
                        hour_end = chunk[-1]["end"].replace(minute=0, second=0, microsecond=0)
                        avg_val = sum(v["value"] for v in chunk) / 4.0
                        hourly_vals.append(
                            {"start": hour_start, "end": hour_end, "value": avg_val}
                        )
                area_data[area_key]["values"] = hourly_vals

jannn0 avatar Oct 01 '25 21:10 jannn0

I wanted my hourly prices back. This component uses an older API and there doesn't seem to be any way to make it return hourly prices (I tried adding "&aggregation=Hourly").

So I had to take a less elegant approach - recalculate hourly prices from the quarterly ones. This also solves the "attributes exceeding 16kB" issue.

So in the file aio_price.py, before

        return {
            "start": start_time,
            "end": end_time,
            "updated": updated,
            "currency": currency,
            "areas": area_data,
        }

insert the following snippet:

        # Aggregate quarterly values into hourly
        if data_type == self.HOURLY:
            for area_key, data_dict in area_data.items():
                vals = sorted(data_dict["values"], key=lambda v: v["start"])
                hourly_vals = []
                for i in range(0, len(vals), 4):
                    chunk = vals[i:i+4]
                    if len(chunk) == 4:
                        hour_start = chunk[0]["start"].replace(minute=0, second=0, microsecond=0)
                        hour_end = chunk[-1]["end"].replace(minute=0, second=0, microsecond=0)
                        avg_val = sum(v["value"] for v in chunk) / 4.0
                        hourly_vals.append(
                            {"start": hour_start, "end": hour_end, "value": avg_val}
                        )
                area_data[area_key]["values"] = hourly_vals

You might also want to write this in #498 also since that is an issue about wanting hourly back

Emlben avatar Oct 02 '25 04:10 Emlben

Hi all, Home Assistant warns that sensor.nordpool_xxx attributes exceed 16 KB. This happens because the sensor stores all day’s prices (all 15-minute intervals) as attributes. Causing this error msg:

WARNING (Recorder) [homeassistant.components.recorder.db_schema] State attributes for sensor.nordpool_xxx exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored

When the attributes are too large, they aren’t stored in the database, which can make updates appear delayed or incomplete.

Workarounds / tips: Use a template sensor to extract only the current price from the raw_today attribute instead of storing the full day’s data.

sensor:
  - platform: template
    sensors:
      nordpool_current_15min:
        friendly_name: "Nordpool Current Price"
        unit_of_measurement: "€/kWh"
        value_template: >
          {% set data = state_attr('sensor.nordpool_xxx', 'raw_today') or [] %}
          {% set nowts = as_timestamp(now()) %}
          {% set current = namespace(val=None) %}
          {% for p in data %}
            {% set s = as_timestamp(as_datetime(p.start)) %}
            {% set e = as_timestamp(as_datetime(p.end)) %}
            {% if nowts >= s and nowts < e %}
              {% set current.val = (p.value * 100) | round(2) %}
            {% endif %}
          {% endfor %}
          {{ current.val if current.val is not none else 'unknown' }}

Thanks and here for the next 15min

sensor:
  - platform: template
    sensors:
      nordpool_next_15min:
        friendly_name: "Nordpool Next 15min Price"
        unique_id: sensor.nordpool__next_15min
        unit_of_measurement: "€/MWh"  #note that i keep it in MWh
        value_template: >
          {% set data = state_attr('sensor.nordpool_xxx', 'raw_today') or [] %}
          {% set nowts = as_timestamp(now()) %}
          {% set next_val = namespace(val=None) %}
          {% for p in data %}
            {% set s = as_timestamp(as_datetime(p.start)) %}
            {% if s > nowts %}
              {% set next_val.val = (p.value * 1) | round(2) %} #note that i keep it in MWh
              {% break %}
            {% endif %}
          {% endfor %}
          {{ next_val.val if next_val.val is not none else 'unknown' }}

cy-bertrand avatar Oct 02 '25 08:10 cy-bertrand

Besides the "exceed maximum size of 16384 bytes" once the values for tomorrow is available

The unit of sensor.nordpool_kwh_se3_sek_2_10_0 is changing, got multiple {None, 'Öre/kWh'}, generation of long term statistics will be suppressed unless the unit is stable and matches the unit of already compiled statistics (Öre/kWh)

Hence

Image

BUT

Image

rogerthn2019 avatar Oct 02 '25 19:10 rogerthn2019

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Tommixoft avatar Oct 03 '25 14:10 Tommixoft

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Troll?

Not okay. The people maintaining the project do so in their spare time without getting paid.

I just want to say to those of you who make this possible: thank you so much, and keep up the good work.

MikaelHoogen avatar Oct 03 '25 14:10 MikaelHoogen

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Then HA should be closed as well?

rogerthn2019 avatar Oct 03 '25 15:10 rogerthn2019

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Then HA should be closed as well?

yes. If noobs cant fix it -than dont make it. People here created million workarounds and creators of module cant?

Tommixoft avatar Oct 03 '25 20:10 Tommixoft

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Then HA should be closed as well?

yes. If noobs cant fix it -than dont make it. People here created million workarounds and creators of module cant?

Then go ahead, open your own HA alternative, we'll be waiting 😊

Let us figure out our nordpool plugin while you rewrite whole HA😂

developerfromjokela avatar Oct 03 '25 20:10 developerfromjokela

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Troll?

Not okay. The people maintaining the project do so in their spare time without getting paid.

I just want to say to those of you who make this possible: thank you so much, and keep up the good work.

oh cry me a river. To fix it it takes MINUTES of time. not days or months. Looks like there is just too little users so nobody cares.... no fame in this project so nobody bothers.

Tommixoft avatar Oct 03 '25 20:10 Tommixoft

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Troll?

Not okay. The people maintaining the project do so in their spare time without getting paid.

I just want to say to those of you who make this possible: thank you so much, and keep up the good work.

oh cry me a river. To fix it it takes MINUTES of time. not days or months. Looks like there is just too little users so nobody cares.... no fame in this project so nobody bothers.

I bet when I'll open an issue on your GitHub repo you won't fix it in "MINUTES of time" at 4 a.m😂

developerfromjokela avatar Oct 03 '25 20:10 developerfromjokela

Ping @bthillerup plesse approve or assign me as maintainer

developerfromjokela avatar Oct 03 '25 20:10 developerfromjokela

this project should be closed, if cant even fix such simple stuff that ws known to happen year ago!!!

Troll? Not okay. The people maintaining the project do so in their spare time without getting paid. I just want to say to those of you who make this possible: thank you so much, and keep up the good work.

oh cry me a river. To fix it it takes MINUTES of time. not days or months. Looks like there is just too little users so nobody cares.... no fame in this project so nobody bothers.

I bet when I'll open an issue on your GitHub repo you won't fix it in "MINUTES of time" at 4 a.m😂

Don’t feed the troll 😂

MikaelHoogen avatar Oct 03 '25 20:10 MikaelHoogen

Yes keep on topic, too much off topic you guys make.

Update: looks like official HA integration was fixed, and as i said it minuts of job to write this code. Not MONTHS of unpaid poor developer's free-time kinda secrafice.

https://github.com/home-assistant/core/pull/153350/commits/8a2539e5ef72a1ac4cc3d65bad322c42b7d6607b

Tommixoft avatar Oct 03 '25 20:10 Tommixoft

I wanted my hourly prices back. This component uses an older API and there doesn't seem to be any way to make it return hourly prices (I tried adding "&aggregation=Hourly").

So I had to take a less elegant approach - recalculate hourly prices from the quarterly ones. This also solves the "attributes exceeding 16kB" issue.

So in the file aio_price.py, before

        return {
            "start": start_time,
            "end": end_time,
            "updated": updated,
            "currency": currency,
            "areas": area_data,
        }

insert the following snippet:

        # Aggregate quarterly values into hourly
        if data_type == self.HOURLY:
            for area_key, data_dict in area_data.items():
                vals = sorted(data_dict["values"], key=lambda v: v["start"])
                hourly_vals = []
                for i in range(0, len(vals), 4):
                    chunk = vals[i:i+4]
                    if len(chunk) == 4:
                        hour_start = chunk[0]["start"].replace(minute=0, second=0, microsecond=0)
                        hour_end = chunk[-1]["end"].replace(minute=0, second=0, microsecond=0)
                        avg_val = sum(v["value"] for v in chunk) / 4.0
                        hourly_vals.append(
                            {"start": hour_start, "end": hour_end, "value": avg_val}
                        )
                area_data[area_key]["values"] = hourly_vals

This works great in my graph based on raw_today and raw_tomorrow, but the state is unknown with this workaround.

Image

I did the workaround from Sander85 + yours, is that correct?

MendelD avatar Oct 06 '25 06:10 MendelD

I did the workaround from Sander85 + yours, is that correct?

No, my workaround should be applied without Sanders85's one. His is for 15 min prices, mine for hourly. Sorry for the confusion.

jannn0 avatar Oct 06 '25 07:10 jannn0