jonasbkarlsson / ev_smart_charging

Electric vehicle smart charging for Home Assistant.
MIT License
169 stars 25 forks source link

Support of Epex Spot prices from ha_epex_spot #231

Closed andreasd closed 1 month ago

andreasd commented 9 months ago

I've tried using the extension but realized that the price information has to come from a supported source extension. I'm using https://github.com/mampfes/ha_epex_spot to get current and next day hourly prices. The extension provides a sensor with the prices in attributes and hourly intervals like this:

Screenshot 2023-12-12 at 22 32 28

there are various other sensors (with options to add tax, surcharges, etc.) but all have in common that they provide prices (price_ct_per_kwh) and interval data (start_time, end_time) as attributes as seen in the screenshot above.

i have no experience with home_assistant addon development, but can help out debugging and testing, if this would increase the chance to support this data source ;)

thanks in advance!

johny-mnemonic commented 9 months ago

@jonasbkarlsson seems like there will be more requests like this. What about specifying some standard format that your integration can consume? Reformatting the json should be doable using some template sensor, so even sources not supported natively by your integration could be used. I am also in the situation, that my price source is not supported and none of the supported sources provide data relevant for me. My source generates json like this:

"2023-12-13T00:00:00+01:00": 1.90246
"2023-12-13T01:00:00+01:00": 1.8414
"2023-12-13T02:00:00+01:00": 1.80916
"2023-12-13T03:00:00+01:00": 1.7542
"2023-12-13T04:00:00+01:00": 1.78596
"2023-12-13T05:00:00+01:00": 1.89049
"2023-12-13T06:00:00+01:00": 2.1919
"2023-12-13T07:00:00+01:00": 2.66892
"2023-12-13T08:00:00+01:00": 2.62837
"2023-12-13T09:00:00+01:00": 2.71899
"2023-12-13T10:00:00+01:00": 2.65231
"2023-12-13T11:00:00+01:00": 2.66916
"2023-12-13T12:00:00+01:00": 2.62666
"2023-12-13T13:00:00+01:00": 2.71337
"2023-12-13T14:00:00+01:00": 2.69994
"2023-12-13T15:00:00+01:00": 2.80423
"2023-12-13T16:00:00+01:00": 2.76906
"2023-12-13T17:00:00+01:00": 2.80985
"2023-12-13T18:00:00+01:00": 2.71435
"2023-12-13T19:00:00+01:00": 2.6296
"2023-12-13T20:00:00+01:00": 2.44397
"2023-12-13T21:00:00+01:00": 2.21974
"2023-12-13T22:00:00+01:00": 2.25565
"2023-12-13T23:00:00+01:00": 2.05781

Or would you share examples of the data format used by currently supported sources and a way how to configure your integration to read an entity with compatible format even when the supported source is not present/detected?

jonasbkarlsson commented 9 months ago

The three currently supported price sources as well as EPEX Spot mentioned by @andreasd all have very similar formats. When I added the second (and the third) price source I was thinking about providing a more general solution. But since it was so easy to add a slightly different price source, I did that instead.

Basically they provide the price information in one (or two) attributes as an array of dictionary. And the dictionary use a certain key for the start time and another key for the price.

price_list = {
    {
        start_of_hour: xxx
        price: xxx
    }
}
price_list_tomorrow {
    {
       start_of_hour: xxx
        price: xxx
    {
}

So one way to make the integration more generic would be to add a forth "generic" price source, where the user can provide strings for "price_list", "start_of_hour", "price" and optionally "price_list_tomorrow". How about that?

For the EPEX spot case,

"price_list" = "data"
"start_of_hour" = "start_time"
"price" = "price_ct_per_kwh"
andreasd commented 9 months ago

thanks for the quick response! i think it's just important to not limit this awesome extension by the price sources. so providing a generic price source that can either be configured via variables (like you showed in your example) or by reformatting other source data to a fixed input data, sound like a good way. i tried to find out if there is a somehow common data structure for hourly prices in home assistant, but it seems there is no standard so every extension follows a different approach.

johny-mnemonic commented 9 months ago

@jonasbkarlsson adding the generic/configurable price source would be great. But for now, let's say I would reformat my source to the format compatible with either of the supported sources. What do I need to do for your integration to accept it? How do I tell it in which format it is? Do I need to create some entity that is used to detect which supported source is present in the system, to fake it?

jonasbkarlsson commented 9 months ago

@johny-mnemonic I made a template sensor to try out how the integration would react to that, but in one of the validation steps, the integration checks that there exist in entry with the supplied entity name in the EntityRegistry. And it seems like a template sensor is not added to the EntityRegistry. So the current implementation will not accept a template sensor.

To make your own integration that will fake one of the three supported price integration would work. Is that something you are considering to do?

johny-mnemonic commented 9 months ago

@jonasbkarlsson no, I was hoping the template sensor would be enough 😞 Thanks for looking into it anyway!

jonasbkarlsson commented 9 months ago

@johny-mnemonic How would you make the templete sensor?

I have experimented with the following templete sensor. It mimics the format of the Entsoe price integration. But it has one inconvenient problem. The attribute prices_todaybecomes a string, and not an array of dictionaries. Would your template sensor be able to create arrays of dictionaries?

In the below example, prices_tomorrowshould have the same format as prices_today, when the prices for tomorrow is available.

template:
  - sensor:
      - name: "my_price_sensor"
        state: 123.45
        attributes:
          prices_today: >
            [
              {
                "time": "2023-12-31 00:00:00+01:00",
                "price": 120.00
              },
              {
                "time": "2023-12-31 01:00:00+01:00",
                "price": 121.00
              },
              {
                "time": "2023-12-31 02:00:00+01:00",
                "price": 122.00
              },
              {
                "time": "2023-12-31 03:00:00+01:00",
                "price": 123.00
              },
              {
                "time": "2023-12-31 04:00:00+01:00",
                "price": 124.00
              },
              {
                "time": "2023-12-31 05:00:00+01:00",
                "price": 125.00
              },
              {
                "time": "2023-12-31 06:00:00+01:00",
                "price": 126.00
              },
              {
                "time": "2023-12-31 07:00:00+01:00",
                "price": 127.00
              },
              {
                "time": "2023-12-31 08:00:00+01:00",
                "price": 128.00
              },
              {
                "time": "2023-12-31 09:00:00+01:00",
                "price": 129.00
              },
              {
                "time": "2023-12-31 10:00:00+01:00",
                "price": 130.00
              },
              {
                "time": "2023-12-31 11:00:00+01:00",
                "price": 131.00
              },
              {
                "time": "2023-12-31 12:00:00+01:00",
                "price": 132.00
              },
              {
                "time": "2023-12-31 13:00:00+01:00",
                "price": 133.00
              },
              {
                "time": "2023-12-31 14:00:00+01:00",
                "price": 134.00
              },
              {
                "time": "2023-12-31 15:00:00+01:00",
                "price": 135.00
              },
              {
                "time": "2023-12-31 16:00:00+01:00",
                "price": 136.00
              },
              {
                "time": "2023-12-31 17:00:00+01:00",
                "price": 137.00
              },
              {
                "time": "2023-12-31 18:00:00+01:00",
                "price": 138.00
              },
              {
                "time": "2023-12-31 19:00:00+01:00",
                "price": 139.00
              },
              {
                "time": "2023-12-31 20:00:00+01:00",
                "price": 140.00
              },
              {
                "time": "2023-12-31 21:00:00+01:00",
                "price": 141.00
              },
              {
                "time": "2023-12-31 22:00:00+01:00",
                "price": 142.00
              },
              {
                "time": "2023-12-31 23:00:00+01:00",
                "price": 143.00
              }
            ]
          prices_tomorrow: None
andreasd commented 6 months ago

is there anything i could do to help adding support for a broader range of price data sources? it seems like a defined structure for a sensor and then using some templates to gather this data from various sources seems like the most flexible option.

jonasbkarlsson commented 6 months ago

@andreasd Can you contruct a template sensor that takes the output from your price data source and provies the state and attributes price_today and price_tomorrow?

andreasd commented 6 months ago

hi! thanks for the quick response. yes, I'm confident that I can construct such a sensor. I'm not entirely sure about the price_today and price_tomorrow attributes. the epex spot integration updates daily at around noon and will provide data until midnight the next day. so e.g. today i already have data until tomorrow 24:00 but tomorrow morning I will have only data until midnight. so there will be a period where there is no "price_tomorrow". is this separation of the hours needed or can we simply supply a list of hours and prices no matter how long in the future they are available?

i could integrate a split of the data in today and tomorrow, but think it would offer more flexibility in the data sources if the integration handles this.

andreasd commented 6 months ago
- sensor: 
    - name: "epex_spot_transformed"
      state: > 
            {{ states('sensor.epex_spot_data_net_price') | float }}
      attributes:
        prices_today: >
          {%- set hours_list = (state_attr('sensor.epex_spot_data_net_price', 'data') | sort(attribute='start_time',reverse=false)) %}
          {%- set today = namespace(items=[]) -%}
          {%- set tomorrow = namespace(items=[]) -%}
          {%- for r in hours_list -%}
            {% set item = {'start_of_hour': r.start_time, 'price': r.price_ct_per_kwh} %}
            {% set item_day = as_datetime(as_timestamp(r.start_time)).strftime("%d") | int %}
            {% set day_today = now().day %}
            {% set day_tomorrow = (now().date() + timedelta(days=1)).strftime("%d") | int %}

            {% if item_day == day_tomorrow -%}            
              {% set tomorrow.items = tomorrow.items + [item]  %}                                 
            {% endif -%}
            {% if item_day == day_today -%}            
              {% set today.items = today.items + [item]  %}                                 
            {% endif -%}
          {%- endfor %} 
          {{today.items}}
        prices_tomorrow: >
          {%- set hours_list = (state_attr('sensor.epex_spot_data_net_price', 'data') | sort(attribute='start_time',reverse=false)) %}
          {%- set today = namespace(items=[]) -%}
          {%- set tomorrow = namespace(items=[]) -%}
          {%- for r in hours_list -%}
            {% set item = {'start_of_hour': r.start_time, 'price': r.price_ct_per_kwh} %}
            {% set item_day = as_datetime(as_timestamp(r.start_time)).strftime("%d") | int %}
            {% set day_today = now().day %}
            {% set day_tomorrow = (now().date() + timedelta(days=1)).strftime("%d") | int %}

            {% if item_day == day_tomorrow -%}            
              {% set tomorrow.items = tomorrow.items + [item]  %}                                 
            {% endif -%}
            {% if item_day == day_today -%}            
              {% set today.items = today.items + [item]  %}                                 
            {% endif -%}
          {%- endfor %} 
          {{tomorrow.items}}

something like this could be used to make the split in today and tomorrow and would output start_of_hour and price for each element from the epex spot sensor. state would be the current price

andreas-berg commented 6 months ago

@andreasd , Hi, should we perhaps coordinate these interfaces in the ha_epex_spot & hass_entsoe_dayahead-components, since we're both active we could be make the same nice interface for Jonas (and his clients) in both components. I think it's a good feature of the price-interfaces to tell clients clearly "today" (always available) and "tomorrow"-prices (only available after our sources decides to publish), since we know the desired/requested TZ. We should also design the interfaces so that nothing breaks when markets eventually move to 15min-slots (it is happening eventually)...

andreasd commented 6 months ago

@andreas-berg i have no play in ha_epex_spot and think a better approach for this integration would be to offer a standardized interface to read in price data, like in the format proposed here. this way every user can build a template sensor (like the one from me above) that will provide data in the desired format. maybe those template sensors can be directly packaged with ev_smart_charging or collected in the documentation.

with a standardized interface in ev_smart_charging for price data, it does not matter where the data is coming from. users won't have to hope that their price source provides it in the correct format, but they can reformat it themselves.

this would in theory already work, it ev_smart_charging would not also check for other variables to determine if one of the supported data provider addons is installed. so it would also require minimal changes in ev_smart_charging.

jonasbkarlsson commented 3 months ago

@andreasd, finally I got some time to test your template sensor above. For me it seems like it will not select today's and tomorrow's prices in the local time zone, but in UTC time. Was that your intention?

The first price I get is the following:

Prices today
- time: '2024-06-06T02:00:00+02:00'
- price: 24.721

But the first price for today in local time is at the time 2024-06-06T00:00:00+02:00.

Also note that I changed your start_of_hour to time, since the format should be prepared for 15-minutes data.

But otherwise, the template sensor seems to work.

andreasd commented 3 months ago

thanks for taking time to work on this! my template sensor was a quick proof of concept that it is possible to integrate different sources via templating to a format that ev_smart_charging defines. so things like "use utc/local time", names of the attributes, etc. should all be defined in ev_smart_charging and then we can start making template sensors from different sources that work with that standard. we could collect them in the wiki here so others have something to start of to integrate other sources or simply copy&paste them, if their source is already present.

you for sure have the best insight how the sensor should be structured, so if you give me/us the requirements, I'm sure we can make use of it :)

johny-mnemonic commented 3 months ago

yeah, we need definition of what generic format ev_smart_charging expects and also the way to tell ev_smart_charging we are giving it a generic source so it should not check for the presence of the currently supported sources.

jonasbkarlsson commented 3 months ago

I will make a proposed definition, and ask for comments.

Also, I have noticed that some electricty price integration use datetime objects to decribe the time, but others use str objects. When I tried template sensors a long time ago, I think the template sensor that I made gave a str object as time.

Is it possible to make a template sensor that gives a datetimeobject? (I haven't checked yet what your template sensor gives, @andreasd.)

jonasbkarlsson commented 3 months ago

Here is one definition of a price sensor.

I added an OPEN ISSUE in the end. Should the format require the "today" and "tomorrow" data to only contain price data for today and tomorrow?

The integration will work even if this is not the case, and I think I have seen price integrations that does not fulfill such a requirement.

andreasd commented 3 months ago

i'll take a look and will adapt the template sensor to fit this description! thank you!

andreasd commented 3 months ago

i have modified the template sensor and it should now fit the format.

  - sensor:
      - name: "epex_spot_transformed"
        state: >-
            {{ states('sensor.epex_spot_data_net_price') | float }}
        attributes:
            prices_today: >-
                {%- set hours_list = (state_attr('sensor.epex_spot_data_net_price', 'data') | sort(attribute='start_time',reverse=false)) %}
                {%- set today = namespace(items=[]) -%}
                {%- set tomorrow = namespace(items=[]) -%}
                {%- for r in hours_list -%}
                  {% set item = {'time': as_datetime(as_timestamp(r.start_time) | timestamp_local), 'price': r.price_ct_per_kwh} %}
                  {% set item_day = as_datetime(as_timestamp(r.start_time) | timestamp_local).strftime("%d") | int %}
                  {% set day_today = now().day %}
                  {% set day_tomorrow = (now().date() + timedelta(days=1)).strftime("%d") | int %}

                  {% if item_day == day_tomorrow -%}            
                    {% set tomorrow.items = tomorrow.items + [item]  %}                                 
                  {% endif -%}
                  {% if item_day == day_today -%}            
                    {% set today.items = today.items + [item]  %}                                 
                  {% endif -%}
                {%- endfor %} 
                {{ today.items }}
            prices_tomorrow: >-
                {%- set hours_list = (state_attr('sensor.epex_spot_data_net_price', 'data') | sort(attribute='start_time',reverse=false)) %}
                {%- set today = namespace(items=[]) -%}
                {%- set tomorrow = namespace(items=[]) -%}
                {%- for r in hours_list -%}
                  {% set item = {'time': as_datetime(as_timestamp(r.start_time) | timestamp_local), 'price': r.price_ct_per_kwh} %}
                  {% set item_day = as_datetime(as_timestamp(r.start_time) | timestamp_local).strftime("%d") | int %}
                  {% set day_today = now().day %}
                  {% set day_tomorrow = (now().date() + timedelta(days=1)).strftime("%d") | int %}

                  {% if item_day == day_tomorrow -%}            
                    {% set tomorrow.items = tomorrow.items + [item]  %}                                 
                  {% endif -%}
                  {% if item_day == day_today -%}            
                    {% set today.items = today.items + [item]  %}                                 
                  {% endif -%}
                {%- endfor %}
                {{ tomorrow.items }}

generated sensor attributes:

prices_today: [{'time': datetime.datetime(2024, 6, 7, 0, 0, tzinfo=UTC+02:00), 'price': 30.341}, {'time': datetime.datetime(2024, 6, 7, 1, 0, tzinfo=UTC+02:00), 'price': 29.486}, {'time': datetime.datetime(2024, 6, 7, 2, 0, tzinfo=UTC+02:00), 'price': 28.836}, {'time': datetime.datetime(2024, 6, 7, 3, 0, tzinfo=UTC+02:00), 'price': 28.192}, {'time': datetime.datetime(2024, 6, 7, 4, 0, tzinfo=UTC+02:00), 'price': 27.691}, {'time': datetime.datetime(2024, 6, 7, 5, 0, tzinfo=UTC+02:00), 'price': 29.482}, {'time': datetime.datetime(2024, 6, 7, 6, 0, tzinfo=UTC+02:00), 'price': 31.136}, {'time': datetime.datetime(2024, 6, 7, 7, 0, tzinfo=UTC+02:00), 'price': 32.184}, {'time': datetime.datetime(2024, 6, 7, 8, 0, tzinfo=UTC+02:00), 'price': 30.282}, {'time': datetime.datetime(2024, 6, 7, 9, 0, tzinfo=UTC+02:00), 'price': 27.482}, {'time': datetime.datetime(2024, 6, 7, 10, 0, tzinfo=UTC+02:00), 'price': 25.379}, {'time': datetime.datetime(2024, 6, 7, 11, 0, tzinfo=UTC+02:00), 'price': 22.967}, {'time': datetime.datetime(2024, 6, 7, 12, 0, tzinfo=UTC+02:00), 'price': 22.069}, {'time': datetime.datetime(2024, 6, 7, 13, 0, tzinfo=UTC+02:00), 'price': 21.043}, {'time': datetime.datetime(2024, 6, 7, 14, 0, tzinfo=UTC+02:00), 'price': 20.527}, {'time': datetime.datetime(2024, 6, 7, 15, 0, tzinfo=UTC+02:00), 'price': 20.816}, {'time': datetime.datetime(2024, 6, 7, 16, 0, tzinfo=UTC+02:00), 'price': 25.01}, {'time': datetime.datetime(2024, 6, 7, 17, 0, tzinfo=UTC+02:00), 'price': 26.164}, {'time': datetime.datetime(2024, 6, 7, 18, 0, tzinfo=UTC+02:00), 'price': 28.792}, {'time': datetime.datetime(2024, 6, 7, 19, 0, tzinfo=UTC+02:00), 'price': 33.742}, {'time': datetime.datetime(2024, 6, 7, 20, 0, tzinfo=UTC+02:00), 'price': 30.95}, {'time': datetime.datetime(2024, 6, 7, 21, 0, tzinfo=UTC+02:00), 'price': 34.387}, {'time': datetime.datetime(2024, 6, 7, 22, 0, tzinfo=UTC+02:00), 'price': 31.344}, {'time': datetime.datetime(2024, 6, 7, 23, 0, tzinfo=UTC+02:00), 'price': 30.088}]
prices_tomorrow: [{'time': datetime.datetime(2024, 6, 8, 0, 0, tzinfo=UTC+02:00), 'price': 29.639}, {'time': datetime.datetime(2024, 6, 8, 1, 0, tzinfo=UTC+02:00), 'price': 28.658}, {'time': datetime.datetime(2024, 6, 8, 2, 0, tzinfo=UTC+02:00), 'price': 27.659}, {'time': datetime.datetime(2024, 6, 8, 3, 0, tzinfo=UTC+02:00), 'price': 27.469}, {'time': datetime.datetime(2024, 6, 8, 4, 0, tzinfo=UTC+02:00), 'price': 27.679}, {'time': datetime.datetime(2024, 6, 8, 5, 0, tzinfo=UTC+02:00), 'price': 27.464}, {'time': datetime.datetime(2024, 6, 8, 6, 0, tzinfo=UTC+02:00), 'price': 27.092}, {'time': datetime.datetime(2024, 6, 8, 7, 0, tzinfo=UTC+02:00), 'price': 25.926}, {'time': datetime.datetime(2024, 6, 8, 8, 0, tzinfo=UTC+02:00), 'price': 22.751}, {'time': datetime.datetime(2024, 6, 8, 9, 0, tzinfo=UTC+02:00), 'price': 19.088}, {'time': datetime.datetime(2024, 6, 8, 10, 0, tzinfo=UTC+02:00), 'price': 17.749}, {'time': datetime.datetime(2024, 6, 8, 11, 0, tzinfo=UTC+02:00), 'price': 17.734}, {'time': datetime.datetime(2024, 6, 8, 12, 0, tzinfo=UTC+02:00), 'price': 16.302}, {'time': datetime.datetime(2024, 6, 8, 13, 0, tzinfo=UTC+02:00), 'price': 14.228}, {'time': datetime.datetime(2024, 6, 8, 14, 0, tzinfo=UTC+02:00), 'price': 13.459}, {'time': datetime.datetime(2024, 6, 8, 15, 0, tzinfo=UTC+02:00), 'price': 14.934}, {'time': datetime.datetime(2024, 6, 8, 16, 0, tzinfo=UTC+02:00), 'price': 17.22}, {'time': datetime.datetime(2024, 6, 8, 17, 0, tzinfo=UTC+02:00), 'price': 18.496}, {'time': datetime.datetime(2024, 6, 8, 18, 0, tzinfo=UTC+02:00), 'price': 23.771}, {'time': datetime.datetime(2024, 6, 8, 19, 0, tzinfo=UTC+02:00), 'price': 26.161}, {'time': datetime.datetime(2024, 6, 8, 20, 0, tzinfo=UTC+02:00), 'price': 26.382}, {'time': datetime.datetime(2024, 6, 8, 21, 0, tzinfo=UTC+02:00), 'price': 27.308}, {'time': datetime.datetime(2024, 6, 8, 22, 0, tzinfo=UTC+02:00), 'price': 28.342}, {'time': datetime.datetime(2024, 6, 8, 23, 0, tzinfo=UTC+02:00), 'price': 25.793}]
friendly_name: epex_spot_transformed

I'm not sure if the integration i use (epex spot) can fulfill the requirement of "An array with 12 or fewer elements is considered to be invalid.". Is there an issue if the "tomorrow" element is empty because there is no data available yet? I only get data for the next day at 1-2pm each day, so until then, there simply is no data available.

i'm also unsure about the datetime format. i guess calling as_datetime should provide it in the required format? otherwise I can change it back to the str representation.

please let me know if there is anything else I can help with.

jonasbkarlsson commented 3 months ago

Having problems with the development environment. Have not got the debugger to work with Python 3.12 of HA yet... Temportairly switching back to 3.11 to test the template sensor.

So, the "price_today" and "price_tomorrow" in you example are not arrays of dict, they are strings. For example this:

"[{'time': datetime.datetime(2024, 6, 24, 0, 0, tzinfo=UTC+02:00), 'price': 27.211}, {'time': datetime.datetime(2024, 6, 24, 1, 0, tzinfo=UTC+02:00), 'price': 25.496}, {'time': datetime.datetime(2024, 6, 24, 2, 0, tzinfo=UTC+02:00), 'price': 24.607}, {'time': datetime.datetime(2024, 6, 24, 3, 0, tzinfo=UTC+02:00), 'price': 24.549}, {'time': datetime.datetime(2024, 6, 24, 4, 0, tzinfo=UTC+02:00), 'price': 24.61}, {'time': datetime.datetime(2024, 6, 24, 5, 0, tzinfo=UTC+02:00), 'price': 26.088}, {'time': datetime.datetime(2024, 6, 24, 6, 0, tzinfo=UTC+02:00), 'price': 30.874}, {'time': datetime.datetime(2024, 6, 24, 7, 0, tzinfo=UTC+02:00), 'price': 30.866}, {'time': datetime.datetime(2024, 6, 24, 8, 0, tzinfo=UTC+02:00), 'price': 26.82}, {'time': datetime.datetime(2024, 6, 24, 9, 0, tzinfo=UTC+02:00), 'price': 23.921}, {'time': datetime.datetime(2024, 6, 24, 10, 0, tzinfo=UTC+02:00), 'price': 20.801}, {'time': datetime.datetime(2024, 6, 24, 11, 0, tzinfo=UTC+02:00), 'price': 18.831}, {'time': datetime.datetime(2024, 6, 24, 12, 0, tzinfo=UTC+02:00), 'price': 18.02}, {'time': datetime.datetime(2024, 6, 24, 13, 0, tzinfo=UTC+02:00), 'price': 17.869}, {'time': datetime.datetime(2024, 6, 24, 14, 0, tzinfo=UTC+02:00), 'price': 17.988}, {'time': datetime.datetime(2024, 6, 24, 15, 0, tzinfo=UTC+02:00), 'price': 20.062}, {'time': datetime.datetime(2024, 6, 24, 16, 0, tzinfo=UTC+02:00), 'price': 22.326}, {'time': datetime.datetime(2024, 6, 24, 17, 0, tzinfo=UTC+02:00), 'price': 24.307}, {'time': datetime.datetime(2024, 6, 24, 18, 0, tzinfo=UTC+02:00), 'price': 26.256}, {'time': datetime.datetime(2024, 6, 24, 19, 0, tzinfo=UTC+02:00), 'price': 32.987}, {'time': datetime.datetime(2024, 6, 24, 20, 0, tzinfo=UTC+02:00), 'price': 39.853}, {'time': datetime.datetime(2024, 6, 24, 21, 0, tzinfo=UTC+02:00), 'price': 33.318}, {'time': datetime.datetime(2024, 6, 24, 22, 0, tzinfo=UTC+02:00), 'price': 28.487}, {'time': datetime.datetime(2024, 6, 24, 23, 0, tzinfo=UTC+02:00), 'price': 25.46}]"

Note the " in the beginning and the end.

Is it possible to change something in the template sensor code to not make it a string?

jonasbkarlsson commented 3 months ago

The datetimeformat caused problems. I changed the template sensor to provide the time as strinstead, and then it became an array of dicts.

I have now made a pre-release v1.11.0-dev1. I have not spent a lot a of time to verify the code... but please check if it works!

I updated the price template definition and added an example for EPEX Spot.

And the documentation page is not updated.

andreasd commented 3 months ago

i'll take a close look next week when I'm back home! thank you!

andreasd commented 2 months ago

had a chance to test it out now and no issues so far :) i'm seeing the prices and times in the extension (i included the dashboards from the readme.md) and calculcations of charging time also seems to work. so if everything goes well, the extension should trigger the first charge of my car tonight. I'll let you know if I took the car or the bike tomorrow morning :P