Rainradar forecast Apple watch complication built using Buienradar/Buienalarm sensors and a unicode barchart (sparkline)

I’ve recently purchased an Apple Watch 6 and was overjoyed to find out that you could use the Home Assistant iOS app to create custom complications to display on its face. One of the things that I really wanted to have was a rain complication which would give me a rain intensity forecast in mm/h. Apple’s built-in weather app only indicates an x% chance of rain for the current hour which is completely useless. Sadly, neither Buienradar nor Buienalarm - the two most popular rain intensity forecast sites for the Netherlands - have a complication for this in their iOS apps.

To make my own I started experimenting with the complication options in the HA iOS app. As far as I could find out we can’t do anything graphical with the complications, so graphs similar to what the official sites offered were out of the question - I had at first hoped to use different color gradients in a gauge to indicate rainfall. But working within the limitations, I figured my best alternative was to create a sparkline bar chart (using unicode block characters) in a Graphic Corner, Text Image complication. My first attempt now looks like this (top-right):

raincomplication
(using some test data, not a realistic forecast of my current whereabouts)

On my 40mm Apple Watch there’s room for 8 bars in the chart, which happens to be perfect for a 2-hour forecast, with each bar representing the heaviest rain intensity to expect in that 15-minute time period. Data for the complication comes from Buienalarm, and the sensor that retrieves this information comes from @aex351 's Neerslag app:

The sensor is meant for the Neerslag lovelace card that shows the rain forecast in HA, but we can use it for this Apple Watch complication quite nicely. Neerslag offers both Buienradar and Buienalarm as sensors, but the Buienalarm data was a bit easier to work with. If you prefer Buienradar, it shouldn’t be hard to modify the Jinja template to work with that sensor instead.

Both Buienalarm and Buienradar give you a rain intensity prediction for the next 2 hours based on a certain location. The predictions are set in 5-minute intervals, so for 2 hours, you should have 24 readings in the data (Buienalarm actually provides 25 in its data, but as far as I can see the last one is discarded when they build the graph).
Furthermore, the values of the prediction are in an arbitrary unit from 0 to 255 that maps to actual mm/h units through the following formula:

Rain intensity (in mm/h) = 10^((value-109)/32)
from Buienradar.nl - Actuele neerslag, weerbericht, weersverwachting, sneeuwradar en satellietbeelden

So to build the complication template we had to group a set of 3 5-minute readings together to get 15 minutes, take the maximum value of the 3 to represent the heaviest rainfall we could experience in that time, get the max from each of the 8 15-minute groups and discard the last unused reading. Then, translate that max value to a corresponding bar unicode character. I used the definitions I found on the internet (light rain: 0,25mm/h, moderate rain: 1mm/h, heavy rain: 2,5mm/h, cloudburst: 25mm/h) and tried to apply some common sense to map the bar height to that.

The resulting template to put into the HA iOS app is:

{%- set raindata = state_attr("sensor.neerslag_buienalarm_regen_data","data")["precip"] %}
{%- for fifteenminutes in raindata|batch(3) %}
{%- if loop.index > 8 %}{{""}}
{%- else %}
{%- set rainintensity = fifteenminutes|max %}
{%- if rainintensity < 44 %}{{" "}}
{%- elif 45 <= rainintensity < 77 %}{{"▁"}}
{%- elif 77 <= rainintensity < 90 %}{{"▂"}}
{%- elif 90 <= rainintensity < 103 %}{{"▃"}}
{%- elif 103 <= rainintensity < 109 %}{{"▄"}}
{%- elif 109 <= rainintensity < 117 %}{{"▅"}}
{%- elif 117 <= rainintensity < 122 %}{{"▆"}}
{%- elif 122 <= rainintensity < 154 %}{{"▇"}}
{%- else %}{{"█"}}
{%- endif %}
{%- endif %}
{%- endfor %}

(please excuse the code quality, this is my first time ever using Jinja templates and I’m not a coder. I’m also using an em space for an ‘empty’ bar, which seems to work okay on my watch, but that’s just checking the spacing by eye)

There is something important I have to note - I haven’t been able to test this with rain in real life yet. It’s been sunny for the past few days and the forecast for this entire week is the same. So my Apple Watch just gives me an empty bar chart right now - no rain expected, which is correct but rather boring. I suspect I will have to change the bar height mapping as I get to use the complication in real life.
Furthermore, the Neerslag sensors currently only use a single location you set (probably the location of your HA install) to get data. What I would love to try to do in the future is change the location based on the lat/long of a device you select running the HA iOS app (which can provide geo lat/long). That way the complication doesn’t just give you the forecast of where your HA server is running - it’s a forecast for where you actually are.

I also think the sparkline bar chart in a text complication can be a very interesting way to chart various other HA data, given our lack of graphical capabilities in Apple Watch complications at this point. Having the rain forecast was just something I really wanted right now, but I could imagine other small HA charts making sense on the wrist as well!

6 Likes

My complication has finally (sadly?) gotten tested now that the weather has turned around and it’s been raining since this weekend. It ended up needing some modifications for real-life use, but I’m pretty happy with it right now!

IMG_2114

The above screenshot actually shows the view that saved me from being drenched last Sunday - it was a sunny afternoon but the complication warned me of a sudden summer storm (the shaded blocks are heavy downpours) in time for me to get home.

So my new code for the complication, which defaults to Buienradar rain forecast data and fallbacks to Buienalarm data if Buienradar has issues (which happens regularly), looks like this:

{%- if state_attr("sensor.neerslag_buienradar_regen_data","data") != "" %}
{%- set buienradarraw = state_attr("sensor.neerslag_buienradar_regen_data","data").split(' ') %}
{%- set raindata = namespace(list=[]) -%}
{%- for n in buienradarraw -%}
{%- set raindata.list = raindata.list + [n[0:3]] %}
{%- endfor -%}
{%- for fifteenminutes in raindata.list|batch(3) %}
{%- if loop.index > 8 %}{{""}}
{%- else %}
{%- set rainvalue = fifteenminutes|max|int %}
{%- set rainintensity = 10**((rainvalue-109)/32) %}
{%- if rainintensity < 0.1 %}{{"▁"}}
{%- elif 0.1 <= rainintensity < 0.5 %}{{"▂"}}
{%- elif 0.5 <= rainintensity < 1 %}{{"▃"}}
{%- elif 1 <= rainintensity < 1.5 %}{{"▄"}}
{%- elif 1.5 <= rainintensity < 2 %}{{"▅"}}
{%- elif 2 <= rainintensity < 3.5 %}{{"▆"}}
{%- elif 3.5 <= rainintensity < 5 %}{{"▇"}}
{%- elif 5 <= rainintensity < 10 %}{{"█"}}
{%- else %}{{"▓"}}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- else %}
{%- set raindata = state_attr("sensor.neerslag_buienalarm_regen_data","data")["precip"] %}
{%- for fifteenminutes in raindata|batch(3) %}
{%- if loop.index > 8 %}{{""}}
{%- else %}
{%- set rainintensity = fifteenminutes|max %}
{%- if rainintensity < 0.1 %}{{"▁"}}
{%- elif 0.1 <= rainintensity < 0.5 %}{{"▂"}}
{%- elif 0.5 <= rainintensity < 1 %}{{"▃"}}
{%- elif 1 <= rainintensity < 1.5 %}{{"▄"}}
{%- elif 1.5 <= rainintensity < 2 %}{{"▅"}}
{%- elif 2 <= rainintensity < 3.5 %}{{"▆"}}
{%- elif 3.5 <= rainintensity < 5 %}{{"▇"}}
{%- elif 5 <= rainintensity < 10 %}{{"█"}}
{%- else %}{{"▓"}}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- endif %}

I also wrote a blog on the process if anyone is interested:

1 Like

I’ve started working on making dynamic versions of the neerslag-app sensors with a Node-RED flow to make the complication show the rain forecast for my current location.

Turns out to be quite simple: I have a phone running the HA companion app, so my person.guy entity has my lat/long data. I pull this periodically, convert them to the required decimals for each service (Buienradar wants 2 decimals, Buienalarm wants 3 decimals) and then make the same requests that neerslag-app does. I feed the results into HA sensors and then use a slightly modified Jinja template to show the result on my Watch.

So far so good! I haven’t really been able to test this extensively because, well, with the pandemic I’m basically always working from home. But in debug so far I see the location requested changing as I move around in the neighbourhood, so it’s definitely doing something :smiley:

I think this is running pretty stable now so I’ve shared the new Node-RED flow and the complication code in the blog:

If you’re going to use this Node-RED flow you also don’t have to install neerslag-app, so it’s a bit more self-contained.