GeoSphere Austria (ZAMG) - Weather Forecast

Hello @killer0071234,
Would it be possible to integrate the weather forecast?
Ideally even with the option to choose the algorithm?
ensemble-v1-1h-2500m
nowcast-v1-15min-1km
nwp-v1-1h-2500m
Thanks.

Hi 011V32,
Direct tagging people not already involved in the conversation is generally not a good thing to do.

Here is the site FAQ for more about how to get help from the volunteers here.

How to help us help you - or How to ask a good question.

I would also love to see this feature if possible in any feasible way.
Thanks in advance for all your work for the community!!!

While it’s not an integration, I managed to get a working weather forecast entity utilizing the geosphere API data. It needs two sensors (nowcast for the first 3h and then the high resolution model for the rest of the 60h that geosphere provides via their API). There is also some more logic integrated in the code block which you can tweak, skip or extend to your likings.

The full weather entity block for configuration.yaml:

template:
  - weather:
      - name: Geosphere Forecast
        unique_id: geosphere_forecast
        condition_template: >-
          {% set code = state_attr('sensor.geosphere_raw_response','sy').data[0] if state_attr('sensor.geosphere_raw_response','sy') and state_attr('sensor.geosphere_raw_response','sy').data is not none else 1 %}
          {% set is_night = is_state('sun.sun','below_horizon') %}
          {% if code in [1, 2] %}{{ 'clear-night' if is_night else 'sunny' }}
          {% elif code in [3, 4] %}partlycloudy
          {% elif code == 5 %}cloudy
          {% elif code in [6, 7] %}fog
          {% elif code in [8, 9, 17, 18, 19] %}rainy
          {% elif code == 10 %}pouring
          {% elif code in [11, 12, 13, 20, 21, 22] %}snowy-rainy
          {% elif code in [14, 15, 16, 23, 24, 25] %}snowy
          {% elif code in [26, 27, 28, 29, 30, 31, 32] %}lightning
          {% else %}exceptional
          {% endif %}
        temperature_template: >-
          {% set nowcast = state_attr('sensor.geosphere_nowcast_response', 't2m') %}
          {% if nowcast and nowcast.data and nowcast.data|length > 0 %}
            {{ nowcast.data[0]|float(0) }}
          {% endif %}
        humidity_template: >-
          {% set forecast_rh2m = state_attr('sensor.geosphere_raw_response', 'rh2m').data if state_attr('sensor.geosphere_raw_response', 'rh2m') and state_attr('sensor.geosphere_raw_response', 'rh2m').data is not none else [] %}
          {{ forecast_rh2m[0] if forecast_rh2m|length > 0 else 0 }}
        wind_speed_template: >-
          {% set u = state_attr('sensor.geosphere_raw_response', 'u10m').data[0] if state_attr('sensor.geosphere_raw_response', 'u10m') and state_attr('sensor.geosphere_raw_response', 'u10m').data is not none else 0 %}
          {% set v = state_attr('sensor.geosphere_raw_response', 'v10m').data[0] if state_attr('sensor.geosphere_raw_response', 'v10m') and state_attr('sensor.geosphere_raw_response', 'v10m').data is not none else 0 %}
          {{ ((u**2 + v**2)**0.5 * 3.6) | round(1) }}
        wind_bearing_template: >-
          {% set u = state_attr('sensor.geosphere_raw_response', 'u10m').data[0] if state_attr('sensor.geosphere_raw_response', 'u10m') and state_attr('sensor.geosphere_raw_response', 'u10m').data is not none else 0 %}
          {% set v = state_attr('sensor.geosphere_raw_response', 'v10m').data[0] if state_attr('sensor.geosphere_raw_response', 'v10m') and state_attr('sensor.geosphere_raw_response', 'v10m').data is not none else 0 %}
          {% set deg = (270 - (180 / 3.14159) * atan2(v, u)) % 360 %}
          {{ deg | round(0) }}
        precipitation_unit: "mm"

        forecast_hourly_template: >
          {% set n_hours_nowcast = 3 %}
          {% set nowcast_t2m = state_attr('sensor.geosphere_nowcast_response', 't2m').data if state_attr('sensor.geosphere_nowcast_response', 't2m') and state_attr('sensor.geosphere_nowcast_response', 't2m').data is not none else [] %}
          {% set nowcast_rr = state_attr('sensor.geosphere_nowcast_response', 'rr').data if state_attr('sensor.geosphere_nowcast_response', 'rr') and state_attr('sensor.geosphere_nowcast_response', 'rr').data is not none else [] %}
          {% set forecast_t2m = state_attr('sensor.geosphere_raw_response', 't2m').data if state_attr('sensor.geosphere_raw_response', 't2m') and state_attr('sensor.geosphere_raw_response', 't2m').data is not none else [] %}
          {% set forecast_sy = state_attr('sensor.geosphere_raw_response', 'sy').data if state_attr('sensor.geosphere_raw_response', 'sy') and state_attr('sensor.geosphere_raw_response', 'sy').data is not none else [] %}
          {% set forecast_rh2m = state_attr('sensor.geosphere_raw_response', 'rh2m').data if state_attr('sensor.geosphere_raw_response', 'rh2m') and state_attr('sensor.geosphere_raw_response', 'rh2m').data is not none else [] %}
          {% set forecast_rr = state_attr('sensor.geosphere_raw_response', 'rr_acc').data if state_attr('sensor.geosphere_raw_response', 'rr_acc') and state_attr('sensor.geosphere_raw_response', 'rr_acc').data is not none else [] %}
          {% set u = state_attr('sensor.geosphere_raw_response', 'u10m').data if state_attr('sensor.geosphere_raw_response', 'u10m') and state_attr('sensor.geosphere_raw_response', 'u10m').data is not none else [] %}
          {% set v = state_attr('sensor.geosphere_raw_response', 'v10m').data if state_attr('sensor.geosphere_raw_response', 'v10m') and state_attr('sensor.geosphere_raw_response', 'v10m').data is not none else [] %}
          {% set base = now().replace(minute=0, second=0, microsecond=0) %}
          {% set n_forecast = [60, forecast_t2m|length, forecast_sy|length, forecast_rh2m|length, forecast_rr|length, u|length, v|length]|min %}
          [
          {%- for i in range(n_hours_nowcast) if nowcast_t2m|length >= (i+1)*4 and nowcast_rr|length >= (i+1)*4 -%}
            {%- set idx = i * 4 -%}
            {%- set dt = base + timedelta(hours=i) -%}
            {%- set temp = (nowcast_t2m[idx] + nowcast_t2m[idx+1] + nowcast_t2m[idx+2] + nowcast_t2m[idx+3]) / 4 -%}
            {%- set precip = (nowcast_rr[idx] + nowcast_rr[idx+1] + nowcast_rr[idx+2] + nowcast_rr[idx+3]) -%}
            {%- set code = forecast_sy[i]|int if forecast_sy|length > i else 1 -%}
            {%- set hum = forecast_rh2m[i] if forecast_rh2m|length > i else 0 -%}
            {%- set u_val = u[i] if u|length > i else 0 -%}
            {%- set v_val = v[i] if v|length > i else 0 -%}
            {%- set month = dt.month -%}
            {%- if month in [11, 12, 1] -%}
              {% set day_start = 8 %}
              {% set day_end = 17 %}
            {%- elif month in [2, 3, 4] -%}
              {% set day_start = 6 %}
              {% set day_end = 20 %}
            {%- elif month in [5, 6, 7] -%}
              {% set day_start = 5 %}
              {% set day_end = 21 %}
            {%- else -%}
              {% set day_start = 7 %}
              {% set day_end = 18 %}
            {%- endif -%}
            {% set hour = dt.hour %}
            {% set is_night = hour < day_start or hour >= day_end %}
            {
              "datetime": "{{ dt.isoformat() }}",
              "temperature": {{ temp|round(2) }},
              "condition": "{% if code in [1,2] %}{{ 'clear-night' if is_night else 'sunny' }}{% elif code in [3,4] %}partlycloudy{% elif code == 5 %}cloudy{% elif code in [6,7] %}fog{% elif code in [8,9,17,18,19] %}rainy{% elif code == 10 %}pouring{% elif code in [11,12,13,20,21,22] %}snowy-rainy{% elif code in [14,15,16,23,24,25] %}snowy{% elif code in [26,27,28,29,30,31,32] %}lightning{% else %}exceptional{% endif %}",
              "humidity": {{ hum|round(0) }},
              "wind_speed": {{ ((u_val**2 + v_val**2)**0.5 * 3.6)|round(1) }},
              "wind_bearing": {{ (270 - (180 / 3.14159) * atan2(v_val, u_val)) % 360 | round(0) }},
              "precipitation": {{ precip|round(2) }}
            }{% if not (loop.last and n_forecast == n_hours_nowcast) %},{% endif %}
          {%- endfor %}
          {%- for i in range(n_hours_nowcast, n_forecast) %}
            {%- set dt = base + timedelta(hours=i) -%}
            {%- set code = forecast_sy[i]|int -%}
            {%- set hum = forecast_rh2m[i] if forecast_rh2m|length > i else 0 -%}
            {%- set u_val = u[i] if u|length > i else 0 -%}
            {%- set v_val = v[i] if v|length > i else 0 -%}
            {%- set precip = forecast_rr[i] - forecast_rr[i-1] if i > 0 else forecast_rr[0] -%}
            {%- set month = dt.month -%}
            {%- if month in [11, 12, 1] -%}
              {% set day_start = 8 %}
              {% set day_end = 17 %}
            {%- elif month in [2, 3, 4] -%}
              {% set day_start = 6 %}
              {% set day_end = 20 %}
            {%- elif month in [5, 6, 7] -%}
              {% set day_start = 5 %}
              {% set day_end = 21 %}
            {%- else -%}
              {% set day_start = 7 %}
              {% set day_end = 18 %}
            {%- endif -%}
            {% set hour = dt.hour %}
            {% set is_night = hour < day_start or hour >= day_end %}
            {
              "datetime": "{{ dt.isoformat() }}",
              "temperature": {{ forecast_t2m[i] }},
              "condition": "{% if code in [1,2] %}{{ 'clear-night' if is_night else 'sunny' }}{% elif code in [3,4] %}partlycloudy{% elif code == 5 %}cloudy{% elif code in [6,7] %}fog{% elif code in [8,9,17,18,19] %}rainy{% elif code == 10 %}pouring{% elif code in [11,12,13,20,21,22] %}snowy-rainy{% elif code in [14,15,16,23,24,25] %}snowy{% elif code in [26,27,28,29,30,31,32] %}lightning{% else %}exceptional{% endif %}",
              "humidity": {{ hum|round(0) }},
              "wind_speed": {{ ((u_val**2 + v_val**2)**0.5 * 3.6)|round(1) }},
              "wind_bearing": {{ (270 - (180 / 3.14159) * atan2(v_val, u_val)) % 360 | round(0) }},
              "precipitation": {{ precip|round(2) }}
            }{% if not loop.last %},{% endif %}
          {%- endfor %}
          ]
        attribution_template: "GeoSphere forecast via API"

The two sensor file look like this:

# config/sensors/geosphere_raw.yaml
# REST sensor to fetch raw data from Geosphere API
  platform: rest
  name: Geosphere Raw Response
  unique_id: geosphere_raw_response_data
  scan_interval: 1200
  resource: "https://dataset.api.hub.geosphere.at/v1/timeseries/forecast/nwp-v1-1h-2500m?lat_lon=23.10252596563562,-82.35677247046878&parameters=t2m,rh2m,rr_acc,sy,u10m,v10m&format=json"
  method: GET
  value_template: "{{ value_json.reference_time }}"
  json_attributes_path: "$.features[0].properties.parameters"
  json_attributes:
  - "t2m"
  - "rh2m"
  - "rr_acc"
  - "sy"
  - "u10m"
  - "v10m"
# config/sensors/geosphere_nowcast.yaml
# REST sensor to fetch raw data from Geosphere API
  platform: rest
  name: Geosphere Nowcast Response
  unique_id: geosphere_nowcast_response_data
  scan_interval: 300
  resource: "https://dataset.api.hub.geosphere.at/v1/timeseries/forecast/nowcast-v1-15min-1km?lat_lon=23.10252596563562,-82.35677247046878&parameters=t2m,rr&format=json"
  method: GET
  value_template: "{{ value_json.reference_time }}"
  json_attributes_path: "$.features[0].properties.parameters"
  json_attributes:
  - "t2m"
  - "rr"

Obviously you have to replace LAT/LON with your own location. This may not be elegant or good coding but it works and has proper condition mapping and also has a workaround for night-time symbols (clear-night) implemented (even though clumsily and non-scientific). I didn’t manage to get daily forecast to work within the same forecast card, don’t know if it is even supported by HA and didn’t bother much about it because it doesn’t make much sense with just 60h of data anyways. Feel free to use, adapt, correct or extend the code to your likings and needs.

Happy if some folks will find it useful.

Cheers!