Template weather provider from UK Met Office DataHub API

@Troon Thank you for the pointers and all the work you’ve done for this!

1 Like

How do I change from the UI showing km for Wind / Visibility when the weather config code shows m/s & m

Click the cog icon on the Weather card:

That just gives me the cannot be changed in UI blurp

This entity (‘weather.met_office_datahub’) does not have a unique ID, therefore its settings cannot be managed from the UI. See the documentation for more detail.

Huh, I must have added that to my config after making this topic.

Add a unique_id: line to the top of your weather file, like this:

- platform: template
  name: "Met Office Datahub"
  unique_id: 884233c7-4b31-4181-bef7-d5562110df5f

It can be anything you like: I use this site: https://www.uuidgenerator.net/

Now to update the original post…

1 Like

Yep that sorted it cheers

1 Like

I’m almost embarrassed to ask this question, as it’s almost certain that I’ve just missed something obvious, but…
Having followed your fantastic guidance in this topic, @Troon, it all looks good for forecast data, but the “local_current_weather” sensor has not been created. What am I missing? Any thoughts would be massively appreciated!

There are a couple of log warnings:

Logger: homeassistant.helpers.template
Source: helpers/template.py:2651
First occurred: 19:21:43 (2 occurrences)
Last logged: 19:21:44
Template variable warning: 'None' has no attribute 'screenTemperature' when rendering '{{ state_attr('sensor.local_current_weather','status')['screenTemperature'] }}'
Logger: homeassistant.components.recorder.db_schema
Source: components/recorder/db_schema.py:625
integration: Recorder (documentation, issues)
First occurred: 19:21:52 (6 occurrences)
Last logged: 20:19:48

State attributes for sensor.local_datahub_hourly exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
State attributes for sensor.local_datahub_3_hourly exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored

My template yaml is below (which I think is a direct copy of the original) & resides in my configuration.yaml. I’ve set up separate yaml files for ‘rest’ (named MetOffice-rest.yaml) and ‘weather’ (MetOffice-weather.yaml), again pasted from the original (with the appropriate api key & latitude/longitude), with the following in my configuration.yaml:

rest: !include MetOffice-rest.yaml
weather: !include MetOffice-weather.yaml
template:
  - sensor:
      - name: Local current weather
        state: >
          {% set tsl = state_attr('sensor.local_datahub_hourly','timeSeries')|map(attribute='time')|map('as_timestamp')|list %}
          {% set ts = tsl|select('>=',(now()-timedelta(minutes=30))|as_timestamp())|first %}
          {{ tsl.index(ts) }}
        attributes:
          status: "{{ state_attr('sensor.local_datahub_hourly','timeSeries')[this.state|int(0)] }}"
        availability: "{{ states('sensor.local_datahub_hourly') not in ('unavailable', 'unknown') }}"

  - sensor:
      - name: Local weather condition
        state: >
          {% from 'met_office_codes.jinja' import code2ha %}
          {{ code2ha(state_attr('sensor.local_current_weather','status')['significantWeatherCode']) }}
        attributes:
          timestamp: "{{ state_attr('sensor.local_current_weather','status')['time'] }}"
        availability: "{{ states('sensor.local_current_weather') not in ('unavailable', 'unknown') }}"

  - sensor:
      - name: Local wind bearing
        state: >
          {% from 'direction.jinja' import dir %}
          {{ dir(state_attr('sensor.local_current_weather','status')['windDirectionFrom10m']) }}
        attributes:
          timestamp: "{{ state_attr('sensor.local_current_weather','status')['time'] }}"
        availability: "{{ states('sensor.local_current_weather') not in ('unavailable', 'unknown') }}"

Can you check that sensor.local_datahub_hourly works? It should look something like this SettingsDeveloper Tools:

Thx for your reply. Yes it does work.

Panic over. All working now. I had another “template:” statement in my configuration.yaml file. All moved to a separate templates.yaml file and all’s well. YAML syntax strikes again!

1 Like

glad you got it working as I was unable to find any typos in your yaml!

1 Like

So i have this working now for a few weeks, and now see this in the log:

2024-10-21 21:28:11.250 WARNING (Recorder) [homeassistant.components.recorder.db_schema] State attributes for sensor.local_datahub_hourly exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
2024-10-21 21:28:11.251 WARNING (Recorder) [homeassistant.components.recorder.db_schema] State attributes for sensor.local_datahub_3_hourly exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored

Anyway to set it up to periodic empty this? No point keeping old json-dumps in the sqlite database, no? I don’t want to disable this entirely (the typical suggestion i get when googling for that message).

I exclude both those from recorder entirely.

1 Like

I tried that but then the weather object broke for me.

Here’s what i came up with, an automation to purge entries older than 5 days:

- id: '1729615371955'
  alias: purge-old-metoffice-datahub
  description: Clean up the very-verbose REST api json results from MetOffice Datahub
    service
  triggers:
  - trigger: time
    at: 02:45:00
  conditions: []
  actions:
  - action: recorder.purge_entities
    data:
      keep_days: 5
      entity_id: sensor.local_datahub_3_hourly
  - action: recorder.purge_entities
    data:
      keep_days: 5
      entity_id:
      - sensor.local_datahub_hourly
  - action: recorder.purge_entities
    data:
      keep_days: 5
      entity_id:
      - sensor.local_datahub_daily

Is it still working for you guys?
I have all 3 sensors “unknown”…

The setup seems to be pretty simple, have no idea what’s wrong.
I tried it with !secret first, now I have details directly, still “unknown”…

Working for me, have you reloaded?

Nice piece of work! Managed to get it all up and running, I’m using NodeRed to scrape the data from the Met Office and populate the initial sensors through MQTT rather than HA scaping away (choice - it means the sensors get populated with the last known value if you use MQTT retention) - couple of things worth pointing out along the way just in case others get here as well.

The Met Office Data Hub - go for the Site Specific-Global Spot free tier, and doing the maths - pulling every hour all three API points 24x7 is still well under the cap.

You can cut out the dir() macro and leave the raw bearings in the forecast data (HA can show them as compass points and it’s trivial to do that later in the dashboard or wherever else you display (using the very nice dir() macro above).

The forecast structure is fiddly - it doesn’t like unknown attributes in it at all - so stick with the ones shown here - for example visibility, precipitation and dew_point are available in the Met Office data and HA docs say they are supported HA Weather Integration, but adding any will cause large log messages complaining broadly (check the end of the log message to see which field you added to which template that broke it - it’s there at the end) and you won’t see the weather. entity with any or some forecast data - same is true for things like trying to add temphigh and other useful fields - shame really as it would be very nice if the weather provider template wasn’t so temperamental.

If it helps anyone I squeezed these attributes into the various forecasts as couldn’t get any more to work as a recognised forecast (couple more than shown above - but not many).

hourly:

        {% set tsd = { 'datetime': (ts['time']|as_datetime).isoformat(),
                       'condition': ts['significantWeatherCode'],
                       'precipitation_probability': ts['probOfPrecipitation']|round(2),
                       'wind_bearing': ts['windDirectionFrom10m']|round(2),
                       'humidity': ts['screenRelativeHumidity']|round(2),
                       'pressure': ts['mslp']|round(2),
                       'uv_index': ts['uvIndex']|round(2),
                       'dew_point': ts['screenDewPointTemperature']|round(2),
                       'temperature': ts['screenTemperature']|round(2),
                       'apparent_temperature': ts['feelsLikeTemperature']|round(2),
                       'wind_gust_speed': ts['windGustSpeed10m']|round(2),
                       'wind_speed': ts['windSpeed10m']|round(2) } -%}

twice_daily:

        {% set tsd = { 'datetime': (ts['time']|as_datetime).isoformat(),
                       'is_daytime': 'T12' in ts['time'],
                       'condition': ts['significantWeatherCode'],
                       'humidity': dhr|map(attribute='screenRelativeHumidity')|average|round(2),
                       'pressure': dhr|map(attribute='mslp')|average|round(2),
                       'temperature': dhr|map(attribute='maxScreenAirTemp')|max|round(2),
                       'templow': dhr|map(attribute='minScreenAirTemp')|min|round(2),
                       'precipitation_probability': dhr|map(attribute='probOfPrecipitation')|average|round(2),
                       'precipitation': dhr|map(attribute='totalPrecipAmount')|average|round(2),
                       'wind_gust_speed': dhr|map(attribute='windGustSpeed10m')|average|round(2),
                       'wind_bearing': dhr|map(attribute='windDirectionFrom10m')|average|round(2),
                       'wind_speed': dhr|map(attribute='windSpeed10m')|average|round(2) } -%}

daily:

        {% set tsd = { 'datetime': (ts['time']|as_datetime).isoformat(),
                       'condition': ts.get('daySignificantWeatherCode', ts.get('nightSignificantWeatherCode', 'n/a')),
                       'humidity': ts['middayRelativeHumidity']|round(2),
                       'pressure': ts['middayMslp']|round(2),
                       'temperature': ts['dayMaxScreenTemperature']|round(2),
                       'templow': ts['nightLowerBoundMinTemp']|round(2),
                       'wind_gust_speed': ts['midday10MWindGust']|round(2),
                       'wind_bearing': ts['midday10MWindDirection']|round(2),
                       'wind_speed': ts['midday10MWindSpeed']|round(2) } -%}

Don’t skip @Troon 's point about the temperature reading (sweet idea to grab live data from local sensors where available), he suggests putting in:

temperature_template: "{{ state_attr('sensor.local_current_weather','status')['screenTemperature'] }}"

… but I would wrap that in more protection just to handle startup rush and remove the None log message (like all the other top level fields are):

  temperature_template: >
    {% if state_attr('sensor.local_current_weather','status') is mapping %}
      {{ state_attr('sensor.local_current_weather','status').get('screenTemperature', 0) }}
    {% else %}
      0
    {% endif %}

Finally in configuration.yaml, sort out recorder: I have this, but at least put in sensor.met_office_datahub and weather.*

# Recorder exclusions
recorder:
  exclude:
    domains:
      - automation
      - update
    entities:
      - sensor.met_office_datahub
    entity_globs:
      - weather.*
      - sensor.sun*

I also created a few more sensors direct from the next weather forecast (mainly given all the storms we’ve been having!) so I can hang automations off them, again if it helps - you can go wild adding more in…

Also made the icon for the current_condition dynamic - and the icon value is calculated upstream in NodeRed - but here for illustrative purposes!

# Sensors for Met Office Datahub Feed
- sensor:
  - unique_id: local_current_weather
    name: "Local Current Weather"
    icon: "mdi:weather-cloudy"
    state: >
      {% set tsl = state_attr('sensor.local_datahub_hourly', 'forecast') | map(attribute='time') | map('as_timestamp') | list %}
      {% set ts = tsl|select('>=',(now()-timedelta(minutes=30))|as_timestamp())|first %}
      {{ tsl.index(ts) }}
    attributes:
      status: "{{ state_attr('sensor.local_datahub_hourly', 'forecast')[this.state|int(0)] }}"
    availability: "{{ states('sensor.local_datahub_hourly') not in ('unavailable', 'unknown') }}"

- sensor:
  - unique_id: local_current_condition
    name: "Local Current Condition"
    icon: >
      {%- if state_attr('sensor.met_office_current_weather','status') is mapping -%}
        {{ state_attr('sensor.met_office_current_weather','status')['icon'] }}
      {%- else -%}
        mdi:weather-cloudy
      {%- endif -%}
    state: >
      {{ state_attr('sensor.local_current_weather', 'status')['significantWeatherCode'] }}
    attributes:
      timestamp: "{{ state_attr('sensor.local_current_weather', 'status')['time'] }}"
    availability: "{{ states('sensor.local_current_weather') not in ('unavailable', 'unknown') }}"

- sensor:
  - unique_id: local_current_wind_bearing
    name: "Local Current Wind Bearing"
    icon: "mdi:compass"
    state: >
      {{ state_attr('sensor.local_current_weather', 'status')['windDirectionFrom10m'] }}
    attributes:
      timestamp: "{{ state_attr('sensor.local_current_weather', 'status')['time'] }}"
    availability: "{{ states('sensor.local_current_weather') not in ('unavailable', 'unknown') }}"

- sensor:
  - unique_id: local_current_wind_speed
    name: "Local Current Wind Speed"
    icon: "mdi:weather-windy"
    state: >
      {{ state_attr('sensor.local_current_weather', 'status')['windSpeed10m'] }}
    attributes:
      timestamp: "{{ state_attr('sensor.local_current_weather', 'status')['time'] }}"
    availability: "{{ states('sensor.local_current_weather') not in ('unavailable', 'unknown') }}"

- sensor:
  - unique_id: local_current_wind_gust
    name: "Local Current Wind Gust"
    icon: "mdi:weather-windy"
    state: >
      {{ state_attr('sensor.local_current_weather', 'status')['windGustSpeed10m'] }}
    attributes:
      timestamp: "{{ state_attr('sensor.local_current_weather', 'status')['time'] }}"
    availability: "{{ states('sensor.local_current_weather') not in ('unavailable', 'unknown') }}"

- sensor:
  - unique_id: local_current_rain_probability
    name: "Local Current Rain Probability"
    icon: "mdi:weather-rainy"
    unit_of_measurement: "%"
    state: >
      {{ state_attr('sensor.local_current_weather', 'status')['probOfPrecipitation'] }}
    attributes:
      timestamp: "{{ state_attr('sensor.local_current_weather', 'status')['time'] }}"
    availability: "{{ states('sensor.local_current_weather') not in ('unavailable', 'unknown') }}"

@Troon awesome piece of work - a very nice deep dive into the black art of the weather templates!

… in case anyone wants it, nodered flow to grab the data from the Met Office DataHub - fill in your lat long and api key, and you’ll need a working link to an MQTT broker and probably some tweaking on tls depending on your local setup. You could always do it with the HA Companion (but you’d loose the retain functionality of MQTT) - the meat is in the function node just to man handle some data fields to save doing it in the HA sensors (so I put the icons into the weather sensor using NR and do some frippery around the scaling factors in here before it hits HA - just less for HA to do and more done in NR - but if you look you will see the point).

[ { "id": "32355d8ddde6d5b0", "type": "inject", "z": "babcd6f0d89239b1", "name": "Met Office Hourly", "props": [ { "p": "url", "v": "https://data.hub.api.metoffice.gov.uk/sitespecific/v0/point/hourly?dataSource=BD1&excludeParameterMetadata=true&includeLocationName=true&latitude=YOUR_LAT&longitude=YOUR_LONG", "vt": "str" }, { "p": "manual", "v": "true", "vt": "bool" }, { "p": "topic", "vt": "str" } ], "repeat": "900", "crontab": "", "once": true, "onceDelay": "10", "topic": "hourly", "x": 310, "y": 2020, "wires": [ [ "64d06a1387fe18af" ] ], "outputLabels": [ "Calendar URL" ] }, { "id": "11142748fad678a6", "type": "comment", "z": "babcd6f0d89239b1", "name": "Met Office DataHub Scrape", "info": "", "x": 160, "y": 1960, "wires": [] }, { "id": "53a07233acf9e35c", "type": "inject", "z": "babcd6f0d89239b1", "name": "Met Office 3 Hourly", "props": [ { "p": "url", "v": "https://data.hub.api.metoffice.gov.uk/sitespecific/v0/point/three-hourly?dataSource=BD1&excludeParameterMetadata=true&includeLocationName=true&latitude=YOUR_LAT&longitude=YOUR_LONG", "vt": "str" }, { "p": "manual", "v": "true", "vt": "bool" }, { "p": "topic", "vt": "str" } ], "repeat": "900", "crontab": "", "once": true, "onceDelay": "10", "topic": "three_hourly", "x": 300, "y": 2080, "wires": [ [ "64d06a1387fe18af" ] ], "outputLabels": [ "Calendar URL" ] }, { "id": "bd1b87f2d281d64c", "type": "inject", "z": "babcd6f0d89239b1", "name": "Met Office Daily", "props": [ { "p": "url", "v": "https://data.hub.api.metoffice.gov.uk/sitespecific/v0/point/daily?dataSource=BD1&excludeParameterMetadata=true&includeLocationName=true&latitude=YOUR_LAT&longitude=YOUR_LONG", "vt": "str" }, { "p": "manual", "v": "true", "vt": "bool" }, { "p": "topic", "vt": "str" } ], "repeat": "900", "crontab": "", "once": true, "onceDelay": "10", "topic": "daily", "x": 310, "y": 2140, "wires": [ [ "64d06a1387fe18af" ] ], "outputLabels": [ "Calendar URL" ] }, { "id": "a3a6b0a9c9edfc08", "type": "function", "z": "babcd6f0d89239b1", "name": "Convert to HA", "func": "/**\n * Map MET Office Significant Weather to HA symbol\n * @param {number} sig MET Office Significant weather number\n * @returns {string} HA weather value\n */\nconst MetToHA = (sig) => {\n    switch (sig) {\n        case 0: return \"clear-night\"; \n        case 1: return \"sunny\"; \n        case 2: \n        case 3: return \"partlycloudy\"; \n        case 4: return \"N/A\";\n        case 5: \n        case 6: return \"fog\"; \n        case 7: \n        case 8: return \"cloudy\"; \n        case 9: \n        case 10: \n        case 11: \n        case 12: return \"rainy\"; \n        case 13: \n        case 14: \n        case 15: return \"pouring\"; \n        case 16: \n        case 17: \n        case 18: return \"snowy-rainy\"; \n        case 19: \n        case 20: \n        case 21: return \"hail\"; \n        case 22: \n        case 23: \n        case 24: \n        case 25: \n        case 26: \n        case 27: return \"snowy\"; \n        case 28: \n        case 29: return \"lightning-rainy\"; \n        case 30: return \"lightning\"; \n        default:\n            node.warn(\"Unexpected Significant Weather number \" + sig);\n            return \"n/a\";\n    }\n}\n\n/**\n * Convert a bearing into compass points\n * @param {number} [bearing=0] Bearing to convert\n * @returns {string} Compass point\n */\nconst compass = bearing => ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'][Math.round(bearing / 22.5) % 16];\n\n/**\n * Map MET Office Significant Weather to mdi: icon\n * @param {number} sig MET Office Significant weather number\n * @returns {string} HA weather value\n */\nconst MetToMdi = (sig) => {\n    switch(sig) {\n        case 0: return \"mdi:weather-night\";\n        case 1: return \"mdi:weather-sunny\";\n        case 2: return \"mdi:weather-night-partly-cloudy\";\n        case 3: return \"mdi:weather-partly-cloudy\";\n        case 5: \n        case 6: return \"mdi:weather-fog\";\n        case 7:\n        case 8: return \"mdi:weather-cloudy\";\n        case 9:\n        case 10: \n        case 11: \n        case 12: return \"mdi:weather-rainy\";\n        case 13:\n        case 14:\n        case 15: return \"mdi:weather-pouring\";\n        case 16:\n        case 17:\n        case 18: return \"mdi:weather-snowy-rainy\";\n        case 19:\n        case 20:\n        case 21: return \"mdi:weather-hail\";\n        case 22:\n        case 23:\n        case 24: return \"mdi:weather-snowy\";\n        case 25:\n        case 26:\n        case 27: return \"mdi:weather-snowy-heavy\";\n        case 28:\n        case 29: return \"mdi:weather-lightning-rainy\";\n        case 30: return \"mdi:weather-lightning\";\n        default: return \"mdi:weather-cloudy\";\n    }\n}\n\n// For status\nlet c_time = new Date();\n\n// Check we got a valid return\nif (msg.statusCode != 200) {\n    node.status({ fill: \"red\", shape: \"dot\", text: \"API error \" + c_time.toLocaleDateString('en-gb', { day: \"numeric\", month: \"short\", hour: \"numeric\", minute: \"numeric\", second: \"numeric\" }) });\n    return null;\n}\n\n// Check the query got something\nif (typeof (msg.payload) != \"object\" || typeof (msg.payload.features) != \"object\" || msg.payload.features.length != 1) {\n    node.status({ fill: \"red\", shape: \"dot\", text: \"No data \" + c_time.toLocaleDateString('en-gb', { day: \"numeric\", month: \"short\", hour: \"numeric\", minute: \"numeric\", second: \"numeric\" }) });\n    return null;\n}\n\n// Message to pass to MQTT broker\nlet mqtt_msg = {\n    \"topic\": \"dt/weather/metoffice/\" + msg.topic + \"/\" + msg.payload.features[0].properties.location.name.replace(/\\s+/g, '_').toLowerCase(),\n    \"payload\": { \"date\": msg.payload.features[0].properties.modelRunDate},\n};\n\n// Fix up the timeseries to suit HA classifications\nfor (var ts of msg.payload.features[0].properties.timeSeries) {\n    if (typeof (ts.significantWeatherCode) == \"number\") { ts.significantWeatherCode = MetToHA(ts.significantWeatherCode); ts.icon = MetToMdi(ts.significantWeatherCode); }\n    if (typeof (ts.daySignificantWeatherCode) == \"number\") { ts.daySignificantWeatherCode = MetToHA(ts.daySignificantWeatherCode); ts.dayIcon = MetToMdi(ts.daySignificantWeatherCode); }\n    if (typeof (ts.nightSignificantWeatherCode) == \"number\") { ts.nightSignificantWeatherCode = MetToHA(ts.nightSignificantWeatherCode); ts.nightIcon = MetToMdi(ts.nightSignificantWeatherCode); }\n    \n    if (typeof (ts.windDirectionFrom10m) == \"number\") ts.windDirectionFrom10m = ts.windDirectionFrom10m;\n    if (typeof (ts.midnight10MWindDirection) == \"number\") ts.midnight10MWindDirection = ts.midnight10MWindDirection;\n    if (typeof (ts.midday10MWindDirection) == \"number\") ts.midday10MWindDirection = ts.midday10MWindDirection;\n\n    if (typeof (ts.visibility) == \"number\") ts.visibility = ts.visibility / 1000;\n}\n\n// Assign the forecast\nmqtt_msg.payload.forecast = msg.payload.features[0].properties.timeSeries\n\nnode.status({ fill: \"green\", shape: \"dot\", text: mqtt_msg.payload.forecast.length + \" readings \" + c_time.toLocaleDateString('en-gb', { day: \"numeric\", month: \"short\", hour: \"numeric\", minute: \"numeric\", second: \"numeric\" }) });\n\nreturn mqtt_msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 780, "y": 2080, "wires": [ [ "2c4f236b80872225" ] ] }, { "id": "64d06a1387fe18af", "type": "http request", "z": "babcd6f0d89239b1", "name": "Get Met Office Data", "method": "GET", "ret": "obj", "paytoqs": "ignore", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [ { "keyType": "other", "keyValue": "accept", "valueType": "other", "valueValue": "application/json" }, { "keyType": "other", "keyValue": "apikey", "valueType": "other", "valueValue": "XXXXXXXXXXX INSERT APIKEY HERE" } ], "x": 560, "y": 2080, "wires": [ [ "a3a6b0a9c9edfc08" ] ] }, { "id": "2c4f236b80872225", "type": "mqtt out", "z": "babcd6f0d89239b1", "name": "dt/weather/metoffice/#", "topic": "", "qos": "2", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "473be6f2eb76881d", "x": 1000, "y": 2080, "wires": [] }, { "id": "473be6f2eb76881d", "type": "mqtt-broker", "name": "MQTT.broker.url", "broker": "localhost", "port": "8883", "tls": "ef944f1a41479b4d", "clientid": "NodeRed", "autoConnect": true, "usetls": true, "protocolVersion": "5", "keepalive": "60", "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "0", "birthRetain": "false", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closeRetain": "false", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willRetain": "false", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "ef944f1a41479b4d", "type": "tls-config", "name": "local.domain.name", "cert": "YOUR_CERTFILE", "key": "YOUR_CERTFILE", "ca": "YOUR_CERTFILE", "certname": "", "keyname": "", "caname": "", "servername": "", "verifyservercert": false, "alpnprotocol": "" } ]
1 Like

Just as an aside - you can use the same approach for this API too - to get UK flood alerts:

https://environment.data.gov.uk/flood-monitoring/id/floods/?lat=YOUR_LAT&long=YOUR_LONG&dist=10&min-severity=3

… update - did it here: UK Flood Alerts

Works brilliantly. :grin:

An aside for anyone trying to get their voice assistant to tell them what the weather’s like…

It may have trouble pronouncing some of the weather conditions - several of them have hyphens in the middle, and Amazon Polly at least insists on saying “Partlie cloudy”. This fixes it for me:

# Correct text in weather summary that voice assistants find hard to pronounce

template:
  - sensor:
      - name: Weather voice
        unique_id: b8d54f34-1e67-4b4f-aed1-20e3f48ee81a
        state: >
          {% if is_state('weather.met_office_datahub', 'partlycloudy') %}
              partly cloudy
          {% else %}
              {{ states('weather.met_office_datahub') | replace('-', ' ') }}
          {% endif %}
1 Like

Thanks so much for this!