Yevgenium / weather-chart-card

Custom weather card with charts
MIT License
275 stars 81 forks source link

24 hour forecast #74

Open scstraus opened 3 years ago

scstraus commented 3 years ago

Hi, since switching away from a weather source that generated forecasts in 3 hour increments to one that generated forecasts in 1 hour increments, I very much missed being able to see a graph for a full 24 hours, so I made a fork to the original card that averaged together 3 hour periods and presented them as one unit for graphing so that the graph would show a full 24 hours rather than 8. Is there any chance that we could have this as a standard optional feature in the new card?

X1pheR commented 2 years ago

+1

opet commented 2 years ago

This would be great! Maybe a variable to change the increments?

Sku4l commented 2 years ago

Hi, definitely +1 on my side, I was doing the exact same work on a 2 hours increment!

Actually, I have an extra feature request which I was also working on: would it be possible to include a way to skip an array of hours ? (I actually don't care of weather forecast from 22h to 7h)?

scstraus commented 2 years ago

I'd be happy trying to port my old feature over to the new card (it would be pretty easy to change the increments I think).

I would just need confirmation from Yevgeniy that he would accept such a PR, because I don't feel like maintaining another fork.

X1pheR commented 2 years ago

That would be great! hope @Yevgenium can accept this...

Yevgenium commented 2 years ago

@scstraus Could you please provide a screenshot of what it looked like with the old version of the card?

scstraus commented 2 years ago

@Yevgenium You can see everything in my repo for my config. A screenshot can be found here and the source of my version can be found here. It is admittedly very ugly as it was just for my personal use so I never attempted to make things proper options and whatnot, but it did work.

Sku4l commented 2 years ago

hey @scstraus, I was actually having a look at the Weather Template: https://www.home-assistant.io/integrations/weather.template/

We would just need to rebuild a weather template with half or third of the forecasts to skip the ones we don't need. For example, we could easily set temperature and precipitation with means or additions accordingly:

temperature_next: "{{ (state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[3].temperature / 2) | round(1) }}"

precipitations_next: "{{ state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[1].precipitation}}"

The idea would be to build the 'forecast' property, unfortunately I am way too noob in Yaml to know how to build a complicated object such as the forecast one, which is used by the card. Do you have any idea how we could achieve this?

scstraus commented 2 years ago

The forecast object is populated by home assistant and then just imported by the card. It contains all the data we need if configured correctly. I already made this feature on the older version of the card.

But nothing will happen without Yevgeniy indicating that he's interested in merging such a PR. I believe there is even a similar PR open already for a couple months that he hasn't answered. The only other option is for someone to maintain a fork with more features.

Sku4l commented 2 years ago

oh sorry to hear that.

To make sure I understand correctly: are you saying that there is no way to manually re-create aforecast object from the templating syntax in our configuration.yaml?

Sku4l commented 2 years ago

hey @scstraus,

I think i am getting there actually, I managed to have a weather template with a 1/2 hours, summed precipitations and average temperatures.

My problem is that it is not working with the weather-chart-card yet, it is working with the standard weather forecast though

Here is the code for the weather template:

weather:
  - platform: template
    unique_id: "paris_18eme_custom"
    name: "Weather Paris 18eme custom"
    condition_template: "{{ states('weather.paris_18eme_arrondissement') }}"
    temperature_template: "{{ ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[1].temperature) / 2) | round(1) $
    humidity_template: "{{ state_attr('weather.home', 'humidity') | float }}"
    forecast_template: >-
      {{[
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[1].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[1].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[3].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[3].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[5].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[5].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[7].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[7].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[9].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[9].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[11].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[11].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[13].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[13].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[15].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[15].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[17].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[17].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[19].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[19].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[21].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[21].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].datetime},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[23].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[23].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].datetime}
      ]}}

I have not yet figured out what is not working, I suspect that I am missing wind or something like that! What do you think of this solution?

Sku4l commented 2 years ago

Just had another try with wind, but no luck yet. Will have to keep testing..

Here is what I have for now:

weather:
  - platform: template
    unique_id: "paris_18eme_custom"
    name: "Weather Paris 18eme custom"
    condition_template: "{{ states('weather.paris_18eme_arrondissement') }}"
    temperature_template: "{{ ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[1].temperature) / 2) | round(1) $
    humidity_template: "{{ state_attr('weather.paris_18eme_arrondissement', 'humidity') }}"
    pressure_template: "{{ state_attr('weather.paris_18eme_arrondissement', 'pressure') }}"
    wind_bearing_template: "{{ state_attr('weather.paris_18eme_arrondissement', 'wind_bearing') }}"
    wind_speed_template: "{{ state_attr('weather.paris_18eme_arrondissement', 'wind_speed') }}"
    forecast_template: >-
      {{[
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[1].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[1].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[0].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[3].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[3].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[2].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[5].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[5].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[4].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[7].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[7].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[6].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[9].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[9].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[8].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[11].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[11].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[10].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[13].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[13].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[12].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[15].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[15].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[14].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[17].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[17].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[16].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[19].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[19].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[18].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[21].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[21].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[20].wind_bearing},
      {'condition': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].condition,
      'precipitation': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].precipitation + state_attr('weather.paris_18eme_arrondissement', 'forecast')[23].precipitation,
      'temperature': ((state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].temperature + state_attr('weather.paris_18eme_arrondissement', 'forecast')[23].temperature) / 2) | round(1),
      'datetime': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].datetime,
      'wind_speed': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].wind_speed,
      'wind_bearing': state_attr('weather.paris_18eme_arrondissement', 'forecast')[22].wind_bearing}
      ]}}
scstraus commented 2 years ago

I would personally change the code of the card to have this feature rather than try to change my weather entity, but probably you can make it work with enough effort. My previous solution on the old version of the card was about 10-20 lines of code.

I've never tried to make my own weather entity so I can't give you much advice there.

scstraus commented 2 years ago

Hi @Yevgenium, what is your feeling on this FR? I've provided the source of my implantation against the old card and there is another PR listed here which appears to do the same against the new card. Could we roll it into the new version?