27 July 2021

Buienalarm / Buienradar Apple Watch complication using Home Assistant

Know if you're getting wet with a quick glance at your Apple Watch

By In Make 20 min read

Living in the Netherlands, one of the things I really miss on my Apple Watch is a Buienradar complication. Buienradar, Dutch for rain radar, is a popular site here that uses weather radar images to predict if it’s going to rain in the next few hours. For many people living here, it’s completely normal to check Buienradar before going out. It can make the difference between walking out the door and getting drenched or grabbing an umbrella in time. When the radar’s rain blob moves over your location, you know it’s going to get wet.

Buienradar rain image
Buienradar rain radar images

That’s why my latest project has been building a Buienradar Apple Watch complication through Home Assistant! If you just want to know how to install this complication, click here. If you want to read more about the background and the process, keep on reading!

Update August 2, 2021: Added a section on using your current location to request the rain forecast for where you are, as opposed to the forecast for where your Home Assistant installation is.

My Buienradar rain forecast chart in action in the top right of my Apple Watch
My Buienradar rain forecast chart in action in the top right of my Apple Watch

Buienradar and Buienalarm versus Apple

Buienalarm app graph
Buienalarm app graph

Buienradar is not the only site that provides this service. A popular alternative here is Buienalarm – you guessed it, rain alarm in Dutch. This app also provides a prediction for how much rain will fall at your location in the upcoming hours. It even sends out push notifications in case of incoming rain. If you get a notification and see a big blue spike, you know you’re better off staying indoors.

In the Netherlands, this is what we’re used to and what we expect when we talk about rain forecasts. But it doesn’t seem to be the norm for weather apps in many other countries. Apple’s weather app, for example, has a rain complication for the Watch. But it just tells you if there’s an x% chance of rain in the coming hour – which is basically useless. I have absolutely no idea what a ‘30% chance of rain’ means in real life. There is nothing actionable about 30%, it’s just preparing you to roll the dice. In comparison, Buienradar and Buienalarm are simple and very clear. They tell you how much rain is predicted to hit your current location soon: get ready.

Sadly neither Buienradar nor Buienalarm provides an Apple Watch complication for their popular apps. In fact, Buienradar does not even have an Apple Watch app. I don’t even want any fancy radar images, I just want a simple chart that will show me if I’m going to get wet or not. I guess that if I want a single-glance rain forecast right on my watch face, I’ll have to build it myself.

Home Assistant

Now you may know I’m using Home Assistant to control my smart home. I was really happy to find out that the Home Assistant iOS app lets you create custom Apple Watch complications! Anything that my smart home knows, I can potentially put on my Watch face. That gives me a very interesting option to build my own rain radar complication, as long as I manage to get the necessary Buienradar and Buienalarm data into Home Assistant!

To work outside of your own home, your Home Assistant does need to be reachable outside of your home network. This requires either port forwarding set up manually or a subscription to Nabu Casa. Subscribing to Nabu Casa also means financially supporting the full-time developers working on the open-source Home Assistant platform. I highly recommend it!

My Buienradar Apple Watch complication in action (top right)
My Buienradar Apple Watch complication in action (top right)

Apple Watch Complications

Home Assistant Apple Watch temperature complication in the bottom right
Home Assistant temperature complication in the bottom right

Complications are the term Apple uses for additional features that are displayed on their watch faces. It’s based on the old horological term used for mechanical watches, as each additional feature on a watch required minuscule gears and springs to build. Luckily, complications are not as complicated (ta-dum tsssh) on a smartwatch.

I started by experimenting with the complication options in the Home Assistant iOS app. Sadly, we can’t do anything graphical with the complications, so line graphs similar to what the official Buienradar and Buienalarm sites offer are out of the question. Apple’s complication rings and gauges can only be set to a single color via the Home Assistant app, so we can’t use color gradients as a way to convey information either. Basically, the only thing you can really use in the complications is the text output. For my first successful experiment, I used text and some emojis to build a Stack Text complication that displays the temperatures of the various rooms in my apartment.

Mission successful! But that simple temperature complication is still a far cry from an entire rain forecast chart. How can we show a chart when we only have text at our disposal?

Sparklines

Apple Watch sparklines

The text limitation immediately made me think of sparklines, a concept coined by Edward Tufte to describe small charts embedded in texts and interfaces. They’re used to convey a lot of information that would otherwise require too many words to describe, without taking up the space of a complete chart. To quote Tufte: “Sparklines were driven by 3 overlapping principles: maximize data density, minimize or zero-out non-data, and the shrink principle (graphics can be shrunk way down).”

Simple financial sparklines

Some financial sites embed sparkline stock charts when talking about companies in their news articles, so readers immediately know what direction a stock is headed. The simple dashboard visualizations of online analytics packages, which indicate trends that require further investigation, are sparklines. And many of the highly simplified graphs on the Apple Watch itself are considered sparklines too.

Why is all this relevant? Well, a popular way to create sparklines in text without access to actual graphics is to use Unicode block characters:

Unicode Block Elements
Unicode Block Elements table from Wikipedia

By using the U+2581 to U+2588 and U+2593 Unicode characters we have access to 8 increasingly higher bars and a shaded full bar. Many basic system fonts support these characters, which means they can be used in text displays without requiring graphic capabilities. Using these blocks it’s easy to make a simple bar chart, as long as you require no more than 8 levels of bars. For my complication, this would be perfect.

Buienalarm and Buienradar data

Neerslag-app's Home Assistant card
Neerslag-app’s Lovelace card

We know how we’re going to make the chart. Now getting the data for the complication into Home Assistant is the next step. Buienradar is a standard weather provider for Home Assistant, but this weather data does not contain the detailed rain forecast we want. Luckily, I am not the first person who wants to import this data into their Home Assistant setup. There’s a variety of custom components available, but I settled on aex351’s awesome Neerslag-app which contains sensors for both Buienradar and Buienalarm, and a Lovelace card to display it in your regular Home Assistant interface – a win-win. The Neerslag-app provides you with 2 default sensors: sensor.neerslag_buienradar_regen_data and sensor.neerslag_buienalarm_regen_data.

The Neerslag-app sensors for both sites provide rain forecasts for the next 2 hours, based on a location you set up during installation. Both sensors provide predictions in 5-minute intervals which means you get 24 readings in the data – although Buienalarm adds an unused 25th reading. But the sensors differ in the unit used. Buienalarm will give you predictions in the traditional mm/h unit used to measure rain intensity. Buienradar on the other hand uses an arbitrary unit from 0 (no rain) to 255 (Noah’s flood). To map this unit to the more useful mm/h, the following formula is applied by the site:

Rain intensity (in mm/h) = 10^((reading-109)/32)

The data the sites provide also differs in how well-formatted they are. The Buienalarm data is nicely formatted, easy to work with, and very stable in actual use. In comparison the Buienradar sensor data is quite ugly: an unformatted string of readings and timestamps pairs concatenated with pipes. It’s also not the most reliable source, during testing it regularly returned no data at all. From personal experience, I prefer the accuracy of the Buienradar forecast but want the stability of Buienalarm. So I decided to use both – Buienradar as my main source of data, and Buienalarm as my fallback when there were issues with Buienradar.

Rainfall intensity

While all the apps and weather institutes measure rainfall intensity in mm/h, they have different definitions of light, moderate and heavy rain. As an example, I’ve made an overview of threshold values from the American Manual of Surface Weather Observation (MANOBS), Royal Netherlands Meteorological Institute (KNMI), Norwegian Meteorological Institute (yr.no), Buienalarm, Buienradar, and Neerslag-app.

MANOBSKNMIyr.noBuienalarmBuienradarNeerslag-app
Light rain<2.5 mm/h0.1 mm/h0.25 mm/h< 2 mm/h0.5 mm/h
Moderate rain2.5 mm/h0.5 mm/h1 mm/h2 mm/h2 mm/h
Heavy rain7.5 mm/h1 mm/h2.5 mm/h5 mm/h5 mm/h
Downpour25 mm/h10 mm/h
Violent rain>50 mm/h>50 mm/h> 100 mm/h

As you can see, the thresholds vary heavily across sources. What the Norwegian Meteorological Institute considers heavy rain doesn’t even register as light in the American MANOBS. And even within the same country, Buienradar and Buienalarm have a factor 2 difference between their thresholds. The two apps also visualize the data differently.

Buienalarm uses a zooming linear graph that resizes the Y-axis when heavier rain is forecast. This can make the graph harder to read when brief, violent storms hit and the Y-axis becomes very compressed on the low end. Buienradar, on the other hand, uses an exponential graph with much less granularity at the high end. The distance on the Y-axis of their graph between a 5 mm/h rain and an 80 mm/h storm is about as big as the distance between that 5 mm/h rain and a 0.1 mm/h drizzle. This means the Buienradar graph always looks the same, making it easier to read, but heavy storms lose their visual impact as they won’t show up as a massive peak.

Buienradar app with exponential graph
The exponential graph of the Buienradar app

We’ll need to make some choices about which values and mapping we want to use in our watch complication. What kind of maximum and minimum value do we want to map to the bar chart height – what mm/h value should the full bar represent? What is the lowest mm/h value that should register with the smallest slice of a bar? How do the intermediate bars map to intensity values? And what value do we want to use the shaded full bar character for?

Building the Apple Watch complication

There are many positions on an Apple Watch face you can build complications for. Since I mainly use the Infograph watch face, I wanted a complication in one of its corners. The position I picked was the Graphic Corner, Text Image complication. The Image part is quite simple, I just pick an icon that obviously conveys ‘rain’, like a raincloud. We fill the Text part with the actual code for our complication.

Graphic Corner complication variations from the Apple Human Interface Guidelines
All possible Graphic Corner complication variations from the Apple Human Interface Guidelines

Testing reveals that there’s room for 8 block characters in the Text part of the Text Image complication, so there’s room for an 8-bar chart. That just happens to be perfect for a 2-hour forecast! Each bar can represent the heaviest rain intensity we expect in that 15-minute time period.

To build the complication template we have to group each set of three 5-minute readings from the sensors together to get 15-minute segments. Then we take the maximum value of the segment to represent the heaviest rainfall we could experience in that time. Once we have this for the eight 15-minute segments, we discard any additional data – specifically to ignore the extraneous 25th reading that Buienalarm provides.

Mapping the chart bars

Home Assistant Buienradar complication in the top right
Home Assistant Buienradar complication in the top right

The next step is converting the values of our eight segments into the corresponding bar character. For Buienalarm, the data is already in mm/h units, but for Buienradar we still need to convert. Remember, the formula to convert from a given Buienradar reading to an mm/h value is:

Rain intensity (in mm/h) = 10^((reading-109)/32)

For my complication, I decide to map the effective range of this chart from 0.1 mm/h to 5 mm/h. The chart has loosely increasing intervals between each bar, though I wouldn’t go so far as to call this exponential. The lowest bar character indicates an empty bar, so 15 minutes with no rain predicted. This might look confusing because a thin blue line could also indicate a little bit of rain is coming. But when I used an actually empty (em space) character for this, the chart instantly became harder to read. The thin line in an empty bar lets you count how many blocks of 15 minutes you have before rain arrives. It’s almost impossible to guess the same amount of empty space.

Now, for the first bar for rain, I use an interval from 0.1 mm/h to 0.5 mm/h (0.4 mm/h total), while on the other end a bar has an interval of 3.5 mm/h to 5 mm/h (1.5 mm/h total). The shaded full bar represents downpours over 10 mm/h – similar to the red in the Buienradar radar images. You don’t know how much rain it represents exactly, but you know it’s a lot. If you see this shaded block headed your way, it’s time to get indoors.

Apple Watch Complication Jinja templates

With the Buienradar and Buienalarm data being collected by Home Assistant, and the decision made on how to analyze the data and map the values to bar charts, all that’s left to do is create the code. The Home Assistant iOS app uses Jinja templates to control each text field of a complication. Using Jinja you can code simple operations to modify the presentation of your data. In our case, it’s how we’re going to transform the raw Buienalarm and Buienradar numbers to the bars that will form the chart to display in the complication.

I’ll spare you the work of building your own and have put my work in three gists here: one template that only pulls data from Buienalarm, one that only pulls data from Buienradar, and one that uses Buienradar by default but employs Buienalarm as a fallback.

Buienalarm complication

This is the Jinja template for the Buienalarm-only complication:

{%- 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 %}

Buienradar complication

The Buienradar-only template is a bit more jury-rigged because Home Assistant blocks Jinja’s list.append for safety reasons. Instead, I’m using a workaround that I found here to convert the raw Buienradar data to something Home Assistant can work with. This should not negatively impact the complication in any way, though it’s a bit of a hack.

{%- set buienradar = state_attr("sensor.neerslag_buienradar_regen_data","data").split(' ') %}
{%- set raindata = namespace(list=[]) -%}
{%- for n in buienradar -%}
{%- 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 %}

Buienradar with Buienalarm fallback complication

Finally, this is the template that I’m personally using now. It uses Buienradar data by default, which in my experience is more accurate than Buienalarm, but adds Buienalarm as a fallback. That way you always have a rain forecast, even if Buienradar craps out. Please note, this code uses the same hack the Buienradar-only code does.

{%- 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 %}

Installing the Buienalarm / Buienradar Apple Watch Complication

It’s quite easy to install the Buienradar Apple Watch complication, as long as you already have your own Home Assistant running. Remember to make sure that your Home Assistant is securely reachable from outside your home network, either by doing your own port forwarding or by buying a Nabu Casa subscription. Otherwise, this complication will only work when you’re connected to your home wifi network.

  1. First install Neerslag-app on your Home Assistant to get the required sensors. Once installed, restart your Home Assistant.
  2. Set up Neerslag-app, making sure that the location you set is in a supported country (e.g. the Netherlands or Belgium). Confirm that you can see both Buienradar and Buienalarm sensor entities (sensor.neerslag_buienradar_regen_data and sensor.neerslag_buienalarm_regen_data) in the Developer Tools and that they’re both receiving data from their respective sites.
  3. Now, start up the Home Assistant app on your iPhone and select App Configuration > Apple Watch from the menu.
  4. Click on Add in the top right and select the Corner complication under the Graphic category.
  5. Fill in the Display Name – this is the name you’ll see in Apple’s Watch app when you want to select the complication.
  6. Set the Template to Text Image. This will add the Centre template to your screen.
  7. Set the Icon and its colour to your preferences.
  8. Copy the Jinja code from a gist of your choice from the previous section. You can have a Buienradar complication, Buienalarm complication, or a Buienradar with Buienalarm fallback.
  9. Paste the Jinja code in the Centre template.
  10. Set the colour for the Centre complication.
  11. Save the complication with the button in the top right.
  12. You should be back in the app’s Apple Watch menu. Hit the Update Complications button in the middle of the screen. This should trigger an update that will refresh the available complications on your phone.
  13. Exit the Home Assistant app and go to Apple’s Watch app.
  14. Add the complication to a Graphic Corner location in a compatible watch face (e.g. Infograph or one of the more traditional faces like GMT or Chronograph). If you can’t see the complication yet, try hitting the Update Complications button in the Home Assistant app again or wait a few minutes for the list to refresh automatically. If you still only see the default placeholder, make sure you created the complication for the specific position you’re trying to add here. The Watch app won’t list complications made for other positions.
  15. Set the Apple Watch to use this face and wait for the complication to refresh on your wrist.
  16. Tada!

Proof is in the pudding

My Buienradar Apple Watch complication in use
My Buienradar Apple Watch complication in real life use for the very first time

While developing this complication, I could only test it with fake data I generated myself. It’d been absolutely bone-dry here for weeks, without any opportunity for this complication to prove its worth. Eight empty bars kept staring at me from the corner of my watch. But last weekend we were walking through the city downtown in jeans and a t-shirt, enjoying the sun and the warm weather. Feeling a notification come in on the watch, I glanced down at my wrist – but was suddenly distracted when I saw that the complication actually had a chart for me!

And what a chart. There was sudden rain incoming – and a lot of it too. The shaded bars on the second and third spot meant 10+ mm/h downpours would hit in about 15 to 25 minutes. We started walking back home immediately, and not a minute too late. Moments after we shut the door behind us, already walking in through drizzle, the heavens opened up and the city got soaked in a nice little summer storm.

Great success! Not only is my complication working, but it’s also saved me from being drenched by rain once already. Can’t ask for more proof of its value, can you?

Dynamic location using Node-RED

The biggest limitation of this first version of the complication is that it uses a static location. Neerslag-app only tracks one latitude/longitude combination, which you probably set to the location for your home. In effect, the complication tells you when it’s going to rain on your house. During this pandemic that’s probably where you’ll be most of the time. But logically, you want to know if it’s going to rain where you are – even if that’s not at home.

I’ve put in a request for dynamic location support at Neerslag-app’s github but for now, I’ve also made a first workaround that seems to work. It’s a Node-RED flow that copies the requests Neerslag-app makes but changes the latitude and longitude requested based on my location. Building this in Node-RED is far more roundabout than using an existing integration like Neerslag-app or writing it in Home Assistant’s own automation YAML. But for an amateur like me, Node-RED’s visual flow style makes it much easier to get instant results!

You will need to have the Node-RED add-on installed, as well as the Node-RED Companion integration you can find in HACS that lets you create Home Assistant sensors from Node-RED. Then you can import the Node-RED flow from the gist below to get my flow.

[{"id":"7a281822.950da8","type":"change","z":"7ce23c23.7ea124","name":"Get location data to 2 decimals","rules":[{"t":"set","p":"latitude","pt":"msg","to":"$round(data.attributes.latitude, 2)","tot":"jsonata"},{"t":"set","p":"longitude","pt":"msg","to":"$round(data.attributes.longitude, 2)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":100,"wires":[["f2faa1b4.b7939"]]},{"id":"a080c47a.c59908","type":"http request","z":"7ce23c23.7ea124","name":"Get Buienradar data","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://gpsgadget.buienradar.nl/data/raintext?lat={{{latitude}}}&lon={{{longitude}}}&c={{{random}}}","tls":"","persist":false,"proxy":"","authType":"","x":920,"y":100,"wires":[["882f36a5.86dfc8"]]},{"id":"882f36a5.86dfc8","type":"ha-entity","z":"7ce23c23.7ea124","name":"Buienradar sensor","server":"","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"NodeRed Rain Buienradar"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"","stateType":"date","attributes":[{"property":"data","value":"payload","valueType":"msg"}],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1290,"y":100,"wires":[[]]},{"id":"f2faa1b4.b7939","type":"random","z":"7ce23c23.7ea124","name":"Add random number","low":1,"high":"999999999999999","inte":"true","property":"random","x":700,"y":100,"wires":[["a080c47a.c59908"]]},{"id":"f42baf1e.07df","type":"poll-state","z":"7ce23c23.7ea124","name":"Get Guy's data every 3 minutes","server":"","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"updateinterval":"3","updateIntervalUnits":"minutes","outputinitially":false,"outputonchanged":false,"entity_id":"person.guy","state_type":"str","halt_if":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"x":150,"y":100,"wires":[["7a281822.950da8","1d9cd395.ff023c"]]},{"id":"b035056e.17dc18","type":"http request","z":"7ce23c23.7ea124","name":"Get Buienalarm data","method":"GET","ret":"txt","paytoqs":"ignore","url":"https://cdn-secure.buienalarm.nl/api/3.4/forecast.php?lat={{{latitude}}}&lon={{{longitude}}}&region=nl&unit=mm%2Fu&c={{{random}}}","tls":"","persist":false,"proxy":"","authType":"","x":920,"y":160,"wires":[["9c92573c.2f33f8"]]},{"id":"b142b1eb.0730c","type":"ha-entity","z":"7ce23c23.7ea124","name":"Buienalarm sensor","server":"","version":1,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"NodeRed Rain Buienalarm"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":""}],"state":"","stateType":"date","attributes":[{"property":"data","value":"payload","valueType":"msg"}],"resend":true,"outputLocation":"","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1290,"y":160,"wires":[[]]},{"id":"9c92573c.2f33f8","type":"json","z":"7ce23c23.7ea124","name":"Parse JSON","property":"payload","action":"","pretty":false,"x":1110,"y":160,"wires":[["b142b1eb.0730c"]]},{"id":"1d9cd395.ff023c","type":"change","z":"7ce23c23.7ea124","name":"Get location data to 3 decimals","rules":[{"t":"set","p":"latitude","pt":"msg","to":"$round(data.attributes.latitude, 3)","tot":"jsonata"},{"t":"set","p":"longitude","pt":"msg","to":"$round(data.attributes.longitude, 3)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":160,"wires":[["fa8601c9.4e8dc"]]},{"id":"fa8601c9.4e8dc","type":"random","z":"7ce23c23.7ea124","name":"Add random number","low":1,"high":"999999999999999","inte":"true","property":"random","x":700,"y":160,"wires":[["b035056e.17dc18"]]}]

It’s a very simple flow, really. I have basically taken Neerslag-app’s requests and made a Node-RED equivalent of it. Every 3 minutes, the flow will request data from Buienradar and Buienalarm and put the result into their respective sensors. However, instead of a preset location, it will use the location data from my person.guy entity. I’m using the Home Assistant Companion app which also functions as a location device tracker, so my entity always knows my current location. The requests get a random parameter added on to prevent caching issues. Pretty straightforward!

To use the above flow I first recommend disabling Neerslag-app. I have the feeling that Buienradar and Buienalarm limit the number of calls you’re allowed to make in a set timeframe from a single IP. Using both Neerslag-app and the above flow at the same time seems to run into that limit. Second, you have to edit the flow so it will track your person entity instead of mine, and then wait for the new Node-RED sensors to establish themselves in your Home Assistant properly. This can take a little time. Last, you’ll also need to use a modified version of the complication code, as we use other sensor names and the data returned by Node-RED is slightly different. I’ve updated the combined complication gist to adapt to these changes:

{%- if state_attr("sensor.nodered_rain_buienradar","data") %}
{%- set buienradarraw = state_attr("sensor.nodered_rain_buienradar","data").split('\r\n') %}
{%- 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.nodered_rain_buienalarm","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 %}

Copy that in place of the original Jinja code and that’s it! Your Buienradar Apple Watch complication should now update to match your current location.

Future improvements

Still, there’s a lot we could do to improve. Home Assistant watch complications are only updated once every 15 minutes, which can be a bit infrequent during rapidly changing weather. And because we’re combining three 5-minute forecasts into one 15-minute bar, we don’t have great specificity for when rain is actually going to hit. This is inherent to the sparkline-style charts though, which are more indicative of trends than meant as full charts. You should open the Buienradar/Buienalarm app on your phone if you want to get a more detailed view.

Tapping on the complication currently starts up the Home Assistant watch app. It’s not wrong, it’s the obvious behavior, but I would love it if complications could link to another app. Linking to the Buienalarm app or Apple’s weather app would be far more logical from a rain forecast (even if they use other data sources) than going to Home Assistant.

My template code is made specifically for the Graphic Corner complication, but the Apple Watch has tons of watch faces and complication options for positions on those faces. It shouldn’t be too hard to adapt the code to work in other positions, as long as there is enough space in a text output there.

Additionally, I think the sparkline bar chart in a text complication can be a very interesting way to chart just about anything from Home Assistant on your Apple Watch. This Buienradar Apple Watch complication just happened to be the first thing I thought of. Given our lack of graphical capabilities in complications at this point, it might be the only way to have any charts right now.

All in all, there’s still a lot we can do to improve. But the complication is already quite usable right now! If you have any more ideas or suggestions, definitely let me know.

What do you think?