<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://chameth.com/">
    <title>Chameth.com - posts like sense-api, tracking-pbs-without-the-dark-patterns but not coming-around-on-llms, why-you-should-be-using-https</title>
    <subtitle>Personal homepage of Chris Smith</subtitle>
    <link href="https://chameth.com/feeds/posts/like/sense-api,tracking-pbs-without-the-dark-patterns/unlike/coming-around-on-llms,why-you-should-be-using-https/" rel="self"/>
    <link href="https://chameth.com/"/>
    <icon>https://chameth.com/favicon.png</icon>
    <updated>2026-09-01T00:00:00Z</updated>
    <id>https://chameth.com/</id>
    <author>
        <name>Chris Smith</name>
    </author>
    <entry>
        <title>Monthly Meanderings: August 2026</title>
        <link href="https://chameth.com/monthly-meanderings-2026-08/"/>
        <updated>2026-09-01T00:00:00Z</updated>
        <id>https://chameth.com/monthly-meanderings-2026-08/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Another month, another edition of “What’s Chris been up to?”. Fun fact: I very nearly published this post with a “[intro]” placeholder here instead of this
paragraph, despite proofreading it multiple times. “Yep, that’s where the intro will go, all good”. Now instead we have this weirdly meta introduction.&lt;/p&gt;
&lt;h3 id=&#34;website-updates-and-other-projects&#34;&gt;Website updates and other projects&lt;/h3&gt;
&lt;p&gt;A few website updates this month, and one of them neatly addresses the “other projects” bit too. First, I’ve added a new &lt;a href=&#34;https://chameth.com/fitness/&#34;&gt;fitness page&lt;/a&gt; which has some stats
and information about my cycling and running. I’ve also added some fitness-related widgets to support that page and these monthly summaries, and a new music one you can
see a bit further down.&lt;/p&gt;
&lt;p&gt;I’ve also added what I think is quite a fun new feature: a &lt;a href=&#34;https://chameth.com/feeds/posts/build/&#34;&gt;post feed builder&lt;/a&gt; that lets you build RSS feeds containing
only posts that are semantically similar (or dissimilar) to other posts. So if you want to only hear about my fitness journey you can pin a few of those
posts, or if you want to exclude posts that talk about LLMs you can exclude a few of those. It’s basically super-charged fuzzy tags, but it means I don’t
have to actually tag things.&lt;/p&gt;
&lt;p&gt;I blogged about &lt;a href=&#34;https://chameth.com/building-a-family-of-single-user-services/&#34;&gt;building a family of single-user services&lt;/a&gt; which is where most of my coding
energy went this month. Those projects were almost entirely authored by LLMs, and I’m not hating the process. The models have got a lot better at coding,
and I enjoyed getting to focus on the bigger picture aspects rather than getting bogged down in details.
Rest assured, all the writing on my website is still 100% me. I am the load-bearing seam, here.&lt;/p&gt;
&lt;h3 id=&#34;entertainment&#34;&gt;Entertainment&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://chameth.com/monthly-meanderings-2026-03/&#34;&gt;Back in March&lt;/a&gt; I said ‘I can’t do “what I listened to last month” stats until next month’, and then for the next four months completely forgot about it.
Well, not any more! Now I come equipped with some stats about my monthly music habits:&lt;/p&gt;
&lt;div class=&#34;played-albums raised-box&#34; data-title=&#34;Top albums · 1 Aug – 31 Aug 2026&#34;&gt;
    &lt;table class=&#34;plain-table&#34;&gt;
        &lt;thead&gt;
        &lt;tr&gt;
            &lt;th scope=&#34;col&#34;&gt;&lt;/th&gt;
            &lt;th scope=&#34;col&#34;&gt;&lt;/th&gt;
            &lt;th scope=&#34;col&#34;&gt;&lt;/th&gt;
            &lt;th scope=&#34;col&#34;&gt;Album&lt;/th&gt;
            &lt;th scope=&#34;col&#34;&gt;Artist&lt;/th&gt;
            &lt;th scope=&#34;col&#34; class=&#34;numeric&#34;&gt;Unique tracks played&lt;/th&gt;
            &lt;th scope=&#34;col&#34; class=&#34;numeric&#34;&gt;Total tracks played&lt;/th&gt;
        &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;1&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #4&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/190/cover.jpg&#34; alt=&#34;Cover art for Fallen&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;Fallen&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;Evanescence&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;8&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;40&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;2&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #5&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/341/cover.jpg&#34; alt=&#34;Cover art for Love, Drugs &amp;amp; Misery&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;Love, Drugs &amp;amp; Misery&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;Eva Under Fire&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;12&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;32&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;3&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #10&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/378/cover.jpg&#34; alt=&#34;Cover art for NEON VOID&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;NEON VOID&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;Sumo Cyco&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;6&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;23&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;4&lt;/td&gt;
            &lt;td class=&#34;movement movement-down&#34; title=&#34;Down from #1&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-down&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 13l-6 6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 13l6 6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/522/cover.jpg&#34; alt=&#34;Cover art for The Strange Case of…&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;The Strange Case of…&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;Halestorm&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;11&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;21&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;5&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #7&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/120/cover.jpg&#34; alt=&#34;Cover art for Coming in Hot&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;Coming in Hot&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;DIAMANTE&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;9&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;20&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;6&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #8&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/180/cover.jpg&#34; alt=&#34;Cover art for Everest&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;Everest&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;Halestorm&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;7&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;20&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;7&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #126&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/227/cover.jpg&#34; alt=&#34;Cover art for Glory Days&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;Glory Days&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;Little Mix&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;5&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;20&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;8&lt;/td&gt;
            &lt;td class=&#34;movement movement-down&#34; title=&#34;Down from #3&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-down&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 13l-6 6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 13l6 6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/212/cover.jpg&#34; alt=&#34;Cover art for From Zero&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;From Zero&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;Linkin Park&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;9&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;19&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;9&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #78&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/310/cover.jpg&#34; alt=&#34;Cover art for KPop Demon Hunters (Soundtrack from the Netflix Film)&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;KPop Demon Hunters (Soundtrack from the Netflix Film)&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;KPop Demon Hunters Cast&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;7&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;19&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td class=&#34;position&#34;&gt;10&lt;/td&gt;
            &lt;td class=&#34;movement movement-up&#34; title=&#34;Up from #430&#34;&gt;
                &lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; width=&#34;16&#34; height=&#34;16&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34; class=&#34;icon icon-tabler icons-tabler-outline icon-tabler-arrow-up&#34; aria-hidden=&#34;true&#34;&gt;&lt;path stroke=&#34;none&#34; d=&#34;M0 0h24v24H0z&#34; fill=&#34;none&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M12 5l0 14&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M18 11l-6 -6&#34;&gt;&lt;/path&gt;&lt;path d=&#34;M6 11l6 -6&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
            &lt;/td&gt;
            &lt;td class=&#34;art&#34;&gt;
                &lt;img src=&#34;https://chameth.com/music/albums/387/cover.jpg&#34; alt=&#34;Cover art for No Need to Argue&#34; loading=&#34;lazy&#34;/&gt;
            &lt;/td&gt;
            &lt;td&gt;No Need to Argue&lt;/td&gt;
            &lt;td class=&#34;artist&#34;&gt;The Cranberries&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;6&lt;/td&gt;
            &lt;td class=&#34;numeric&#34;&gt;19&lt;/td&gt;
        &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;I suspect I won’t show this every month, as it’s probably going to be quite same-y. I, shockingly, tend to play music that I like more than that which I don’t.
I’ll usually either put on my “favourites” playlist, or my “daily mix” playlist which biases higher-rated tracks over lower ones. So effectively this just
becomes a noisy view over how highly I’ve rated the tracks in an album. Maybe I can control for that, but then I’m not sure what it’d actually be showing…
“Here are all the albums I played this month that I don’t usually play because I don’t like them as much as the other albums I’m not showing any more”?
It’s a bit wordy. Back to the drawing board with that idea, I think.&lt;/p&gt;
&lt;p&gt;I was away for a few weeks this month, including a few days at a small LAN event. Being at a computer gaming event meant that we, naturally, played some board games.
Apparently I hit an h-index of 23 from these plays. That’s 23 games I’ve played at least 23 times each. I’ve been at 22 since December last year: obviously
the higher the number goes, the harder it is to reach. I also go on and off games (and the whole hobby at times), which doesn’t help on that front. Anyway, here’s
&lt;del&gt;Wonderwall&lt;/del&gt; the plays for this month:&lt;/p&gt;
&lt;ul class=&#34;played-boardgames&#34;&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Codenames (2015)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/178900/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/178900/image.jpg&#34; alt=&#34;Box art of Codenames&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;6 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Just One (2018)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/254640/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/254640/image.jpg&#34; alt=&#34;Box art of Just One&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;3 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Martian Fluxx (2009)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/35369/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/35369/image.jpg&#34; alt=&#34;Box art of Martian Fluxx&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;3 plays&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Arkham Horror: Lovecraft Letter (2025)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/424784/image.png&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/424784/image.png&#34; alt=&#34;Box art of Arkham Horror: Lovecraft Letter&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;1 play&lt;/p&gt;
  &lt;/li&gt;
  &lt;li class=&#34;raised-box&#34;&gt;
    &lt;div class=&#34;image-container&#34; title=&#34;Take 5 (1994)&#34;&gt;
      &lt;img class=&#34;background&#34; src=&#34;https://chameth.com/boardgames/432/image.jpg&#34; aria-hidden=&#34;true&#34; loading=&#34;lazy&#34;/&gt;
      &lt;img class=&#34;foreground&#34; src=&#34;https://chameth.com/boardgames/432/image.jpg&#34; alt=&#34;Box art of Take 5&#34; loading=&#34;lazy&#34;/&gt;
    &lt;/div&gt;
    &lt;p&gt;1 play&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No films this month, but my &lt;a href=&#34;https://chameth.com/wow/&#34;&gt;World of Warcraft&lt;/a&gt; habit has picked back up with the launch of the new season. They’ve made Mistweaver Monk, my previous specialisation, a
lot less fun to play, so I’m focusing on one of my many alts: a Restoration Shaman:&lt;/p&gt;
&lt;div class=&#34;wow-char-grid&#34;&gt;
&lt;div class=&#34;wow-char raised-box&#34; data-title=&#34;World of Warcraft Character Data&#34;&gt;
&lt;div class=&#34;overview&#34;&gt;
&lt;img src=&#34;https://chameth.com/wow/characters/Hirameth.png&#34; alt=&#34;Hirameth&#34; loading=&#34;lazy&#34;/&gt;
&lt;p class=&#34;detail&#34;&gt;Level 90&lt;/p&gt;
&lt;p class=&#34;detail&#34;&gt;Female Dwarf&lt;/p&gt;
&lt;p class=&#34;detail&#34;&gt;&lt;span class=&#34;wow-class-shaman&#34;&gt;Restoration Shaman&lt;/span&gt;&lt;/p&gt;
&lt;p class=&#34;detail&#34;&gt;309 average item level&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;info&#34;&gt;
&lt;h3 class=&#34;plain-header&#34;&gt;Hirameth&lt;span class=&#34;realm&#34;&gt;-Terenas&lt;/span&gt;&lt;/h3&gt;
&lt;h4 class=&#34;plain-header&#34;&gt;Professions&lt;/h4&gt;
&lt;table class=&#34;plain-table professions&#34;&gt;
&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Midnight Blacksmithing&lt;/td&gt;&lt;td&gt;&lt;progress class=&#34;tier-progress&#34; value=&#34;41&#34; max=&#34;100&#34;&gt;&lt;/progress&gt;&lt;/td&gt;&lt;td class=&#34;tier-count&#34;&gt;41/100&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Midnight Inscription&lt;/td&gt;&lt;td&gt;&lt;progress class=&#34;tier-progress&#34; value=&#34;72&#34; max=&#34;100&#34;&gt;&lt;/progress&gt;&lt;/td&gt;&lt;td class=&#34;tier-count&#34;&gt;72/100&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Midnight Fishing&lt;/td&gt;&lt;td&gt;&lt;progress class=&#34;tier-progress&#34; value=&#34;35&#34; max=&#34;300&#34;&gt;&lt;/progress&gt;&lt;/td&gt;&lt;td class=&#34;tier-count&#34;&gt;35/300&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4 class=&#34;plain-header&#34;&gt;Mythic+&lt;/h4&gt;
&lt;table class=&#34;plain-table mythic-plus&#34;&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;Altar of Fangs&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+10&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;23:10&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;329&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;Den of Nalorakk&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+10&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;27:36&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;325&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;Kings&amp;#39; Rest&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+12&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;28:57&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;370&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;Murder Row&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+12&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;28:37&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;371&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;Ruby Life Pools&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+11&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;24:28&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;340&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;Temple of Sethraliss&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+10&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;30:57&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;321&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;The Blinding Vale&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+10&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;24:38&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;327&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&#34;dungeon&#34;&gt;Voidscar Arena&lt;/td&gt;
&lt;td class=&#34;level&#34;&gt;+10&lt;/td&gt;
&lt;td class=&#34;duration&#34;&gt;22:37&lt;/td&gt;
&lt;td class=&#34;rating&#34;&gt;329&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&#34;total&#34;&gt;
&lt;th colspan=&#34;3&#34; class=&#34;plain-header&#34;&gt;Total M+ rating&lt;/th&gt;
&lt;td class=&#34;rating&#34;&gt;2711&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&#34;links&#34;&gt;
&lt;a href=&#34;https://worldofwarcraft.blizzard.com/en-gb/character/eu/terenas/hirameth&#34;&gt;View on blizzard.com&lt;/a&gt;
&lt;a href=&#34;https://raider.io/characters/eu/terenas/Hirameth&#34;&gt;View on raider.io&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;I don’t quite like it as much as Mistweaver in season 1, but it’s a lot nicer than Mistweaver in season 2. You can actually make health bars move when you press your healing buttons, rather than
ignoring half of them because they’re not worth using.&lt;/p&gt;
&lt;h3 id=&#34;fitness&#34;&gt;Fitness&lt;/h3&gt;
&lt;p&gt;My running kick is still going. I’ve “officially” finished the couch-to-5k programme I was doing, and I actually hit 5k on the last day of the programme. I didn’t actually mean to do that:
I was saving the 5k run for this week, but by the time I noticed I’d run “too far” it was close enough that I just kept going. I have an actual 5k race coming up
this month, which is exciting. Once that’s over I’m planning to work my way up to 10k. I’ve added a few widgets to keep track of some stats:&lt;/p&gt;
&lt;div class=&#34;workout-summary-sections&#34;&gt;
&lt;div class=&#34;workout-summary-section raised-box&#34; data-title=&#34;Cycling · 1 Aug – 31 Aug 2026&#34;&gt;
&lt;div class=&#34;stat-row&#34;&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;3&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;activities&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;6h 5m&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;total time&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;103.6km&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;total distance&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;42.3km&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;longest distance&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul class=&#34;workout-summary-pbs&#34;&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;1km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;2:17&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;1:52&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;2km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;5:34&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;4:13&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;5km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;14:51&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;12:32&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;10km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;36:00&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;27:21&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;20km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;1:43:33&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;1:13:24&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;30km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;no previous&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;1:54:25&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;40km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;no previous&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;2:55:52&lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&#34;workout-summary-section raised-box&#34; data-title=&#34;Running · 1 Aug – 31 Aug 2026&#34;&gt;
&lt;div class=&#34;stat-row&#34;&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;12&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;activities&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;6h 16m&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;total time&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;43.1km&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;total distance&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;stat&#34;&gt;
&lt;p class=&#34;stat-value&#34;&gt;5km&lt;/p&gt;
&lt;p class=&#34;stat-label&#34;&gt;longest distance&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul class=&#34;workout-summary-pbs&#34;&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;800m&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;5:56&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;6:02&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;1km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;7:35&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;7:36&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;1 mile&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;12:28&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;12:16&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;2km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;15:35&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;15:16&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;3km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;24:32&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;23:05&lt;/span&gt;
&lt;/li&gt;
&lt;li class=&#34;workout-summary-pb&#34;&gt;
&lt;span class=&#34;pb-trophy&#34;&gt;🏆️&lt;/span&gt;
&lt;span class=&#34;pb-label&#34;&gt;New PB&lt;/span&gt;
&lt;span class=&#34;pb-distance&#34;&gt;5km&lt;/span&gt;
&lt;span class=&#34;pb-previous&#34;&gt;no previous&lt;/span&gt;
&lt;span class=&#34;pb-time&#34;&gt;38:40&lt;/span&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;As well as the running, I did a couple of long (for me) cycle rides, clocking in at around 40 km. It’s a fun loop, but both times I did it I started flagging towards the end. The second time
I made sure to eat and drink plenty along the way, and my legs still raised objections about halfway round. My next goal is 50 km which would let me get to the next town over and back but
the route has a lot more elevation to go with its increased length, so it’s probably going to be quite a bit more taxing. I’m not sure when I’ll attempt that, as the weather is starting to
turn. I was previously bemused when people mentioned “cycling seasons” and switching to indoor trainers. Then I wanted to go out when it was raining, and suddenly I understood. Running in
the rain: surprisingly pleasant; cycling in the rain: no thank you.&lt;/p&gt;
&lt;h3 id=&#34;around-the-web&#34;&gt;Around the web&lt;/h3&gt;
&lt;h4 id=&#34;hacker-news-in-uncompromised-detailhttpsvalerockspostshacker-news&#34;&gt;&lt;a href=&#34;https://vale.rocks/posts/hacker-news&#34;&gt;Hacker News In Uncompromised Detail&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When I first read the title my gut reaction was “I know everything I need to know about Hacker News, right?”.
The title is accurate though. There’s so much interesting stuff, presented really cleanly. It’s a good read.&lt;/p&gt;
&lt;h4 id=&#34;a-proposal-for-new-netflix-content-rating-iconshttpsericwbaileywebsitepublisheda-proposal-for-new-netflix-content-rating-icons&#34;&gt;&lt;a href=&#34;https://ericwbailey.website/published/a-proposal-for-new-netflix-content-rating-icons/&#34;&gt;A proposal for new Netflix content rating icons&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Another dry sounding title, another fun article. It starts with a treatise on rating systems and
ends with a lovely satirical list of rating ideas.&lt;/p&gt;
&lt;h4 id=&#34;find-git-commits-by-commit-message-texthttpshamvockecombloggit-revisions-by-text&#34;&gt;&lt;a href=&#34;https://hamvocke.com/blog/git-revisions-by-text/&#34;&gt;Find Git commits by commit message text&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;I like to think I’m relatively well versed in how to use Git. I can do an interactive rebase
and everything! This tip from Ham was new to me, though, and is incredibly useful.&lt;/p&gt;
&lt;h4 id=&#34;novice-marathon-training-planhttpswwwhalhigdoncomtraining-programsmarathon-trainingnovice-1-marathon&#34;&gt;&lt;a href=&#34;https://www.halhigdon.com/training-programs/marathon-training/novice-1-marathon/&#34;&gt;Novice Marathon Training Plan&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Hal Higdon has a whole bunch of training plans. He literally wrote the book on marathon training.
I’ll hopefully be following this plan next year, assuming I manage the 5k, 10k and half-marathon training!
This would be the perfect plan for someone who’s run a half marathon a while ago, and is tempted
to join me in my “marathon before I’m 40” goal…&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>Monthly Meanderings: July 2026</title>
        <link href="https://chameth.com/monthly-meanderings-2026-07/"/>
        <updated>2026-08-01T00:00:00Z</updated>
        <id>https://chameth.com/monthly-meanderings-2026-07/</id>
        <content xml:lang="en" type="html">&lt;p&gt;Another month, another roundup post. This month has been very… exercise-y. Which is, for the record, not normal for me. For the previous year my only source of exercise has basically been walking, but that’s not a great fitness activity for me. When my regular walks entered the 10-15km territory it got more and more annoying to find the time and/or an interesting route.&lt;/p&gt;
&lt;p&gt;I also managed to injure my knee while walking through a particularly muddy field, and spent a few months going slightly stir crazy. Coming out of that I started running three times a week, bought a bicycle, and added in some strength exercises along with the ones the physio recommended. If you told me a few months ago that I’d be annoyed at not being able to exercise too much on rest days I’d think you were mad.&lt;/p&gt;
&lt;h3 id=&#34;website-updates-and-other-projects&#34;&gt;Website updates and other projects&lt;/h3&gt;
&lt;p&gt;Before we talk even more about exercise, let’s do the usual topics I cover in these posts. The only website update this month has been a post about… exercise. Maybe I have a problem. Anyway, in &lt;a href=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/&#34;&gt;Tracking PBs without the dark patterns&lt;/a&gt; I talk about building a slimmed-down, single-player Strava to track my personal bests, without all the nonsense that annoys me.&lt;/p&gt;
&lt;p&gt;Other than the PB tracker, I’ve not been working much on personal projects. I’ve not really had any other itches that need scratching, just the usual background noise of dependency updates and other project maintenance.&lt;/p&gt;
&lt;h3 id=&#34;entertainment&#34;&gt;Entertainment&lt;/h3&gt;
&lt;p&gt;Behold, the section where I normally talk about the films, TV programmes, and board games that have kept me entertained this month: […]. Yep, not a single one.&lt;/p&gt;
&lt;p&gt;I have played a few games, though. A friend and I finally got around to trying out &lt;a href=&#34;https://store.steampowered.com/app/2879840/Escape_Simulator_2/&#34;&gt;Escape Simulator 2&lt;/a&gt;, and it’s just as good as the original. The rooms feel a bit more detailed, and there are a few cool interactions that probably wouldn’t be possible in the old version. There’s also a hard mode for all the rooms which we’ve not yet tried, but sounds like it’ll keep us amused for a bit longer.&lt;/p&gt;
&lt;p&gt;I’ve also been playing a bit of World of Warcraft, but it’s now in the awkward stage where I’ve done most things I can reasonably do this season, and there’s not really any point in doing anything else. All the gear will become mostly irrelevant in a few weeks when season two releases, and we’ve hit the major milestone achievements for Mythic+. Feels a bit anticlimactic to get to a fairly good stage and then just… not play for a bit.&lt;/p&gt;
&lt;h3 id=&#34;fitness&#34;&gt;Fitness&lt;/h3&gt;
&lt;p&gt;Given how much exercise I’ve done, it probably deserves its own section in these monthly posts. I have the vague idea of aiming to run a marathon before I turn 40 (i.e., within around 15 months). That’s both scary and yet not completely impossible. I’m going to work up through the distances and see how it goes. A 5k at the start of September, 10k in November, half marathon around Easter next year, then a full marathon just before my birthday in October. That way even if it gets too tough or something goes wrong I’ll have accomplished &lt;em&gt;something&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;New hobbies mean new toys. My bike is nothing particularly special: a hybrid from Halfords that’s about one step up from entry-level. But it gets the job done, and has helped me remember how much I enjoy cycling. The infrastructure around here is pretty terrible, though. There are lots of little bits of multi-use paths and a few dedicated bike lanes, but they’re not joined up or signed well in the slightest. In most cases it’s easier to just stay on the road and deal with the traffic. It’s a bit sad that they’ve spent time and money to do something and it’s not very useful.&lt;/p&gt;
&lt;p&gt;On the running side, I picked up a Garmin Forerunner 165 watch. I’ve been wearing an Apple Watch for a little over a year now, but using the touchscreen to navigate screens and start/stop activities while running is annoyingly fiddly. The digital crown keeps getting gummed up with sunscreen and requiring cleaning, too. The Forerunner has physical buttons, and is much better at showing the data I want to see in a clear format, and letting me set things up like target pace or distance on the watch itself, instead of via a phone app. Oh, and the battery seems like it’s going to last for a week rather than a day, which is a nice change of pace.&lt;/p&gt;
&lt;p&gt;I’m going to need to make a nice widget to show off my monthly runs and bike rides, but for now here’s some artisanal stats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I went out for 14 runs, totalling 48km, although a significant portion of that was walking for warmup, cooldown or recovery.&lt;/li&gt;
&lt;li&gt;My longest actual run was a 20 minute straight run covering 2.5km.&lt;/li&gt;
&lt;li&gt;My average running pace is 8min/km, which is a “conversational” pace for me right now.&lt;/li&gt;
&lt;li&gt;I went for 9 cycle rides: 2 on rented mountain bikes, then the rest on my own bike. They covered 128km.&lt;/li&gt;
&lt;li&gt;When cycling I made 8 coffee shop stops, which works out to exactly one every 16km on average.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next month I’m hoping to ramp the running up to hit 5k by the very end. I’m mostly following the &lt;a href=&#34;https://www.nhs.uk/better-health/get-active/get-running-with-couch-to-5k/couch-to-5k-running-plan/&#34;&gt;NHS Couch to 5k&lt;/a&gt; plan but I’m tweaking it a little bit as otherwise I’d finish on 3.75km at my current pace. I guess “Couch to 30 minutes of running” isn’t quite as catchy. I made a &lt;a href=&#34;https://chameth.com/couch-to-5k/&#34;&gt;Couch to 5k page&lt;/a&gt; to track my progress and adjustments.&lt;/p&gt;
&lt;h3 id=&#34;around-the-web&#34;&gt;Around the web&lt;/h3&gt;
&lt;h4 id=&#34;blogging-can-just-be-stating-the-obvioushttpsblogjim-nielsencom2026blogging-stating-the-obvious&#34;&gt;&lt;a href=&#34;https://blog.jim-nielsen.com/2026/blogging-stating-the-obvious/&#34;&gt;Blogging Can Just Be Stating The Obvious&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;I often look at my own posts and think, “There’s nothing novel, or important, or deep in here at all — is this even worth saying?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’ve written before about &lt;a href=&#34;https://chameth.com/curse-of-knowledge-blogging/&#34;&gt;The Curse of Knowledge and Blogging&lt;/a&gt;, and this is a very similar take from Jim Nielsen, but it’s still super interesting to see a similar idea expressed in another way by another person.&lt;/p&gt;
&lt;h4 id=&#34;i-built-a-voice-opening-door-to-moria-my-garagehttpswwwyoutubecomwatchvwoyvlnytx0g&#34;&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=woyvLnyTx0g&#34;&gt;I Built a Voice Opening Door to Moria (My Garage)&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A YouTube video documenting a really cool project. What grabs me is the amount of disciplines he dabbles in: he’s part blacksmith, part carpenter, part electrician, part programmer, and so on. It’s one of the best examples of maker culture I’ve seen in ages.&lt;/p&gt;
&lt;p&gt;There’s one bit in particular that sticks in my mind: he tried to find a rendering of the door online, and realised all the existing ones were gibberish or illegible, so he downloaded a font and worked out the exact inscription himself. It makes my inner perfectionist feel validated.&lt;/p&gt;
&lt;h4 id=&#34;linus-torvalds-on-ai-in-the-linux-kernelhttpslorekernelorglinux-mediacahk-wi4zcze8ep3tmv8ttg-80kzsz1syl9anbtmeh5z40vgmailgmailcom&#34;&gt;&lt;a href=&#34;https://lore.kernel.org/linux-media/CAHk-=wi4zC+Ze8e+p3tMv8TtG_80KzsZ1syL9anBtmEh5Z40vg@mail.gmail.com/&#34;&gt;Linus Torvalds on AI in the Linux kernel&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;LLMs are very divisive, and there are a lot of unsettled moral and ethical issues. But at the end of the day they’re a tool that’s not going to go away any time soon. There are people on crusades to try and ban LLM tools in projects, boycott any projects that accept contributions, and so on. It’s a bit like militant veganism. I can understand where they’re coming from, but also please stop shouting at me. Anyway, this take from Linus seems pretty spot on to me.&lt;/p&gt;
&lt;h4 id=&#34;buttonshttpsnielsspdkguisbuttons&#34;&gt;&lt;a href=&#34;https://nielssp.dk/guis/buttons&#34;&gt;Buttons&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;An interactive, graphical history of how buttons have been rendered in various operating systems and desktop environments over time. Maybe it’s just my age and nostalgia, but it really does feel like they peaked around the late 90s/early 2000s. I’m not quite sure why we went from elegant skeuomorphic buttons to ugly plain squares with weird accent colours when you click them.&lt;/p&gt;
&lt;h4 id=&#34;rotating-sandwicheshttpsrotatingsandwichescom&#34;&gt;&lt;a href=&#34;https://rotatingsandwiches.com/&#34;&gt;Rotating sandwiches&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For some reason I expected this to be static pictures of sandwiches which spun in a circle, but it’s actually recordings of sandwiches rotating on a turntable. It’s oddly mesmerising. I wonder why I’ve never seen a restaurant menu with gifs like that?&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>Tracking PBs without the dark patterns</title>
        <link href="https://chameth.com/tracking-pbs-without-the-dark-patterns/"/>
        <updated>2026-07-23T00:00:00Z</updated>
        <id>https://chameth.com/tracking-pbs-without-the-dark-patterns/</id>
        <content xml:lang="en" type="html">&lt;p&gt;I’ve recently been bitten by some kind of strange exercise bug. I’ve gone from being mostly sedentary to struggling to not go out for a cheeky bike ride on a day that’s meant to be a rest day. Maybe this is what a midlife crisis feels like?&lt;/p&gt;
&lt;p&gt;Anyway, one of the things I’ve enjoyed about this development is seeing my personal best efforts gradually go up. There’s something incredibly rewarding about doing a run, and then seeing a nice little gold medal because as part of that you ran your fastest 1km ever. Unfortunately the only software I’ve found that does that is Strava, and boy do I not get on with it.&lt;/p&gt;
&lt;h3 id=&#34;the-many-shortcomings-of-strava&#34;&gt;The many shortcomings of Strava&lt;/h3&gt;
&lt;p&gt;Strava is basically &lt;em&gt;the&lt;/em&gt; app for running and cycling. Everyone talks about it. It sounds like they like it. But I really, really don’t. It’s like someone went through a catalogue of user-hostile behaviours and said “we’ll take them all!”.&lt;/p&gt;
&lt;p&gt;The problems started in the setup wizard: it touts a load of privacy features, but doesn’t offer any way to enable them. All your activities are public by default, and you have to spelunk around in the settings to turn that off. I wasn’t actually sure if I wanted my activities to be public or not, and ended up flip-flopping around a bit. There &lt;em&gt;is&lt;/em&gt; a clunky workflow to bulk change past activities, but it’s arbitrarily time-gated so you can’t use it too often…&lt;/p&gt;
&lt;p&gt;The bulk operations are extremely limited, too: you can set the activity visibility, and your heart rate visibility, and that’s it. Want to bulk delete things? You’re out of luck. Bulk rename? No chance. You either do them one-by-one or use some janky third-party script. I think I pressed around 300 little ‘delete’ links in the course of trying to get my activity history imported in a way I liked.&lt;/p&gt;
&lt;p&gt;Those problems give a bit of a signal about Strava’s priorities, but I could live with them. Once I’ve stopped faffing with the initial import I’m not really going to want to change the privacy settings or bulk edit things. Alas, the problems didn’t end there.&lt;/p&gt;
&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/strava.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/strava.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/strava.png&#34; alt=&#34;Screenshot of Strava notifications that say basically nothing but demand engagement&#34; loading=&#34;lazy&#34; width=&#34;979&#34; height=&#34;500&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Look at me! Look at me! GIVE ME ENGAGEMENT!&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The most obvious one is that everything is an upsell. Vast swathes of the app are premium-only, and they don’t ever get out of your way: they stick around acting as adverts. We’re all used to freemium apps that try to hawk upgrades, but the sheer amount of screen real estate taken up by these is egregious. I started a premium trial, expecting things to get a lot better, and… they didn’t really. All the premium features are still branded as such, so now instead of “look at what you could have if you paid us” it’s “look at what you’re getting for paying us (don’t even think about cancelling)”. Subscribing also makes your avatar get a premium outline, and there’s no way to disable it. I really hate that. Now &lt;em&gt;I’m&lt;/em&gt; an advert myself. I don’t want to be part of their weird dark patterns, thank you very much.&lt;/p&gt;
&lt;p&gt;And while we’re talking about dark patterns: there’s so much engagement bait that I physically cringe at it. You get a notification for logging an activity with a vague call to action to check it out. You get a separate notification when you break or come close to one of your PBs, but it doesn’t tell you which; there’s plenty of space in the notification for it, but they want you to hit the app instead. It all just feels so slimy to me. I don’t know whether it doesn’t bother other people as much, or if they’re desensitised to it, or just don’t realise how pleasant things could actually be.&lt;/p&gt;
&lt;h3 id=&#34;making-a-replacement&#34;&gt;Making a replacement&lt;/h3&gt;
&lt;p&gt;I realised pretty early on that if I only want automatic PB tracking, I could just write something myself to do it. I already use &lt;a href=&#34;https://www.healthyapps.dev/&#34;&gt;Health Auto Export&lt;/a&gt; to exfiltrate data from Apple Health, including workouts. I can just make a service that receives that data, crunches some numbers, and activates the dopamine receivers in my brain when I set a new record. But I didn’t really want to bother doing that if I could avoid it. I tried a whole slew of different apps and none of them did the thing, at least not without a subscription. And Strava had soured me on fitness subscriptions. I finally resigned myself to making something.&lt;/p&gt;
&lt;p&gt;And by “myself” I mean “an LLM”. This is one of the first projects where I’ve not written a single line of code, and I’ve barely even reviewed anything produced by the LLM. I gave it an overall architecture and some sample data, and had it write a plan. I critiqued the plan, had it broken down into a few different phases, and then had it work through them. I occasionally stopped it when I saw it doing something stupid, and gave it a couple of technical steers, but my feedback has mostly been functional. I’m probably not going to be releasing it publicly any time soon for that reason — I don’t want to publish it under my name when I’ve not even looked at the code. I also wouldn’t be comfortable making software this way if other people were going to rely on it, but for non-critical, personal-use-only software I’m happy with the approach.&lt;/p&gt;
&lt;p&gt;Anyway, I called it “Pompei Band”. Project names are hard. One of my common techniques is to put a term into an anagram finder; in this case “PB dopamine” anagrams to “Pompei Band”, and it even abbreviates to PB. Weird, but I like it. This is how it shows recent activities on the homepage:&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/pb1.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/pb1.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/pb1.png&#34; alt=&#34;Screenshot of Pompei Band showing a running activity. Below the activity name, distance and date is a table of best efforts, showing values for 400m, 800m, 1km, 1mi, 2km, and 3km. Each effort shows the time taken, pace and grade-adjusted pace. Some have a golden laurel next to them with the next &amp;#39;New PB&amp;#39;, one has a silver second place medal with &amp;#39;2nd fastest&amp;#39;.&#34; loading=&#34;lazy&#34; width=&#34;975&#34; height=&#34;402&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Dashboard entry for a recent run in PB&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You can click through to see the standard activity details most tracking apps show: a map, heart rate, pace, gradient, and heart rate zones. You can also click on each effort to see a history of them, which gives a nice overview of progress:&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/pb2.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/pb2.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/pb2.png&#34; alt=&#34;Screenshot of Pompei Band showing the PB history for a 1 mile run. Shows six activities, with a pace increasing from 8:55/km to 8:18/km. Each activity shows the name, date, time, pace, grade-adjusted pace, speed, and difference to the previous record. At the bottom is a graph showing all efforts as dots, with a line showing the PB improving over time.&#34; loading=&#34;lazy&#34; width=&#34;1487&#34; height=&#34;992&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;1 mile run PB history&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It pretty much does exactly what I want, and has none of the annoying behaviours that Strava leans into. When I first drafted this post I wrote “there’s a few more bits I’d like to add at some point, but I can happily prompt them into existence when I want them”, but in the time I spent procrastinating before taking screenshots I ended up implementing them all. My favourite is this little history widget I added to the homepage, shown here next to Strava’s:&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/history.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/history.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/tracking-pbs-without-the-dark-patterns/history.png&#34; alt=&#34;Side-by-side screenshots of Pompei Band and Strava showing recent workout history. PB&amp;#39;s is a grid of squares, a la a GitHub activity timeline, with each square coloured by activity or activities, with the brightness corresponding to how long the activity was; there&amp;#39;s a scale at the bottom showing four reference colours for running, walking, and cycling. Strava&amp;#39;s is a mini calendar of circles, with some of them being slightly bigger than others; on the right are weekly line charts showing time done on each type of activity.&#34; loading=&#34;lazy&#34; width=&#34;956&#34; height=&#34;202&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Recent activity calendar in Pompei Band and in Strava&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The Strava one just confuses me. I’m not sure what the scale of the circles means. I’m guessing it’s time, which in effect means it just highlights my bike rides which are longer than runs. The colours for the line charts don’t work for me, and I’m not sure what three zig-zag lines are meant to represent. Pompei Band’s version uses distinct, obvious colours for different activities, and scales the brightness independently for each type of activity based on length (so long cycle rides don’t affect the short runs). I also flipped the axes so it looks more like a GitHub activity timeline, because that’s how my brain works. Nothing groundbreaking, but also none of the paper-cuts the Strava version inflicted on me.&lt;/p&gt;
&lt;h3 id=&#34;software-doesnt-have-to-be-awful&#34;&gt;Software doesn’t have to be awful&lt;/h3&gt;
&lt;p&gt;This blog post has been rattling around in my head for a few days. I didn’t want it to just be a litany about Strava being bad, and I didn’t want to sound like an LLM hype piece, which made it tricky to figure out what I was actually trying to say. I think the core of it is: software doesn’t have to be awful.&lt;/p&gt;
&lt;p&gt;Everyone’s heard of &lt;a href=&#34;https://en.wikipedia.org/wiki/Enshittification&#34;&gt;enshittification&lt;/a&gt;, and it’s so prevalent that it’s easy to accept it as a fact of life. That’s just how late-stage capitalism &lt;em&gt;works&lt;/em&gt;, right? But we can just make better software. And as LLMs slowly become more and more capable, that “we” grows to a broader and broader group. It’s easy to be negative about that: we’re going to drown in vibe-coded products, much like we’re already drowning in written LLM slop. On the other hand, a future where you can just say “make me single-player Strava without all the dark patterns” and get something that works just how you want it is pretty exciting.&lt;/p&gt;
&lt;p&gt;The one thing I can’t decide: if everyone can whip up their own individual software, will the existing platforms actually improve? If Strava didn’t have all the dark patterns and engagement bait I would have just have paid for it. Will they realise that? Or will they double down even harder, try to lock you into their platform, and build moats around user data? Now I’ve said it, it seems pretty obvious they’ll try to do that. But I hope they won’t.&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>10 Weeks with an Apple Watch 10</title>
        <link href="https://chameth.com/10-weeks-with-an-apple-watch-10/"/>
        <updated>2025-09-09T00:00:00Z</updated>
        <id>https://chameth.com/10-weeks-with-an-apple-watch-10/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/10-weeks-with-an-apple-watch-10/watch.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/10-weeks-with-an-apple-watch-10/watch.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/10-weeks-with-an-apple-watch-10/watch.jpg&#34; alt=&#34;An Apple Watch 10 being worn, with a blue analogue clock on the display, and icons/data shown in the corners&#34; loading=&#34;lazy&#34; width=&#34;500&#34; height=&#34;644&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;My watch. Yes, I am available for wrist modelling opportunities.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Around ten weeks ago&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; I picked up an Apple Watch 10, and have been wearing
it almost constantly since. It’s not my first Apple Watch — I had a Series 5
for a bit back in 2020 — but it’s the first time I’ve actually stuck with it.
Ten weeks seems like an apt time to reflect on it.&lt;/p&gt;
&lt;p&gt;Firstly, why did I even bother? Well, for a couple of years I’d been wearing
a Xiaomi Smart Band 7, mainly to monitor my sleep stats and set alarms that
won’t wake up everyone else nearby. Its battery life was fantastic — with
notifications and other things turned off, I got about a month of use between
charges — but actually using it felt like trying to order food via the medium
of interpretive dance.&lt;/p&gt;
&lt;p&gt;My biggest gripe was the screen lock. If I didn’t have the screen locked then
I’d periodically trigger it during the night when I moved around
and it came in contact with my chest or leg. With the lock enabled you had to
deliberately swipe up from bottom to top to enable interaction, but it
didn’t work reliably. When I wanted to adjust an alarm, I’d be stood swiping
repeatedly trying to get it to respond. When you finally get it unlocked, the
whole interface is just &lt;em&gt;fiddly&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The other issue was the data quality. There were some nights when I’d been
woken up, sometimes even getting up and moving around, and it just didn’t show
it in the data. If it can’t even get whether I’m asleep right, can I trust
anything else it says?&lt;/p&gt;
&lt;p&gt;I spent a while researching the best devices for sleep tracking. The Oura ring
came highly recommended, but it was expensive and required a subscription to
do anything useful. No thanks! The Apple Watch was consistently rated pretty
well, and I reasoned I could pick up a refurbished older unit. I’ve been
&lt;a href=&#34;https://chameth.com/apple-google-aligned-incentives/&#34;&gt;using an iPhone as my daily driver&lt;/a&gt; for
a while, so it’d fit right into my begrudged walled garden.&lt;/p&gt;
&lt;p&gt;The Series 10 has a significant advantage, though: it charges much quicker than
all the previous generations. On a 30-minute charge, the Series 10 can go from
0 to 60%; the 9 can only make it to 40%, and my old 5 a measly 30%. Shorter
charge times means I’m far less likely to leave it on charge and wander off
without it. In some ways the daily charging is more convenient than monthly: the
wireless charger sits on my desk, and I plop the watch on it for a little while
in the evening; I don’t need to dig out the weird pogo-pin connector that has
vanished sometime in the last four weeks, then carefully arrange it so it stays
attached.&lt;/p&gt;
&lt;h3 id=&#34;how-a-watch-maybe-saved-my-life&#34;&gt;How a watch maybe saved my life&lt;/h3&gt;
&lt;p&gt;One of the big features of the Apple Watch, like many other wearable devices,
is health and fitness tracking. I didn’t think much about this, beyond the
sleep data I wanted, at first. I’ve never had a particularly good relationship
with exercise&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, but I do like some good statistics. I started going for
walks more often to get more data and see the graphs of VO2 max and HR recovery
gradually inch up. That wasn’t the most profound effect on my health, though…&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;The recent versions of the Apple Watch have a feature that monitors for sleep
apnea, a disorder where you don’t breathe properly during your sleep. I knew
I wasn’t sleeping great — that’s why I was paying attention to sleep tracking
data — but was still a bit surprised to get a notification from Apple Health
after wearing the watch for 30 days. It gives you a graph to print and take to
your doctor. So I diligently booked an appointment and a few weeks later went
to see my GP.&lt;/p&gt;
&lt;p&gt;The appointment went about as you’d expect: talking about referral to a sleep
centre for a study, and so on. Towards the end, the doctor took my blood
pressure (sleep apnea can be caused by, and can cause high blood pressure, in
a lovely little vicious cycle). I don’t think either of us expected anything;
it was just one of those standard checks for a related problem. After taking
the reading, the doctor looked at me and said, “I can’t let you leave with a
BP like this”. Yikes!&lt;/p&gt;
&lt;p&gt;Blood pressure readings are split into stages: normal is under 120 mmHg&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;
over 80 mmHg&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;, stage 1 is up to 140/90, stage 2 is up to 180/120,
and above is simply called “crisis”. Guess where I was? Also, fun fact:
depending on how exactly you count and attribute things, hypertension comes out
as the single largest cause of death in humans. It doesn’t kill you outright,
but contributes to strokes, coronary artery disease, heart failure, and lots
of other lovely things you don’t want on your CV.&lt;/p&gt;
&lt;p&gt;After doing a few more readings, it settled down to just under the “crisis”
stage and into the “holy crap, start treatment immediately” stage instead.
I won’t labour on much more about this, but things are definitely moving in
the right direction now&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;While the Apple Watch didn’t literally save my life, it triggered the chain of
events that led to this diagnosis and treatment. Who knows what would have
happened had it remained undetected? Probably nothing good. Also, go check your
blood pressure! It’s simple to do and simple to treat if there is an issue,
but so many people are walking around with hypertension and not even realising.&lt;/p&gt;
&lt;aside class=&#34;update raised-box&#34;&gt;
  &lt;h5 class=&#34;plain-header&#34;&gt;Update 2025-09-09:&lt;/h5&gt;
  &lt;p&gt;Just a couple of hours after I published this post, Apple announced that they’re
adding hypertension notifications in the new Series 11 watch. It looks like
it will also be supported in Series 9 and Series 10 watches. They expect it to
notify more than one million people of unknown hypertension in the first year.&lt;/p&gt;
&lt;/aside&gt;
&lt;h3 id=&#34;building-gates-in-the-walled-garden&#34;&gt;Building gates in the walled garden&lt;/h3&gt;
&lt;p&gt;Even though the watch is arguably a life-saver, not everything is rosy.
It’s an Apple product, so you’re firmly locked in a walled garden, jealously
guarded by people wearing black turtlenecks. Fortunately, there are a few ways
to make it less painful.&lt;/p&gt;
&lt;p&gt;All the health and fitness data is stored in Apple Health. You can export data
as a big messy file, but it’s a very manual process to do so and the data format
is gnarly. Luckily, there’s an app for that!
&lt;a href=&#34;https://www.healthyapps.dev/&#34;&gt;Health Auto Export&lt;/a&gt; can, well, automatically
export health data. It does what it says on the tin. It can send the data to
Home Assistant, over MQTT, or dump it in some cloud file services, but I just
have it post it all to a REST endpoint on a service I wrote. Then I dump it all
in a database and can do whatever I want with it!&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:6&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Another tool that’s more useful on the watch itself is Apple Shortcuts. This
is their no-code “if-this-then-that”-type thing. You can make automations or
shortcuts that run a number of tasks. I have a whole slew of them I access
via a complication&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:7&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; on my watch face: one which prompts for input and adds an
item to my to-do list (swiping to write letters is surprisingly not horrible),
one which lets me select from a bunch of pre-written ones (“charge kindle”,
“take laundry out in 1 hour”, type things), one to log my weight into Apple
Health, one which can open and close the blinds in my room, and so on. It’s
a surprisingly robust and easy-to-use system and offers just enough freedom
that I’m not constantly grating on the edge of the walled garden.&lt;/p&gt;
&lt;p&gt;Shortcuts being able to initiate arbitrary web requests is the real killer
feature for me. Anything I can’t do on the watch itself, I can just farm off
to a web server and connect it up with a shortcut. No need to learn Swift or
pay Apple for the privilege of being a developer! For a lot of things, like
controlling the blinds or adding to-do items, I already had a HTTP endpoint
available and exposed over Tailscale&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:8&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;. Adding it to the watch was just a case
of entering the right things in the Shortcuts app.&lt;/p&gt;
&lt;h3 id=&#34;daily-nitty-gritty&#34;&gt;Daily nitty-gritty&lt;/h3&gt;
&lt;p&gt;There are lots of other little bits and pieces that come up when using the watch
daily. I don’t think I can bundle them up into a pleasing narrative arc, so
instead please enjoy some disjointed paragraphs of observations.&lt;/p&gt;
&lt;p&gt;The Apple Watch has a lot of nagging abilities. It can notify you about your
fitness “rings”, prompt you to stand up every hour, count how many seconds
you wash your hands for, etc. I think I’d dislike these just on general
principle, but the way it does them is &lt;em&gt;so&lt;/em&gt; condescending it’s painful. I think
there’s probably a cultural divide issue here, but there is no way in British
English to say “Great job! You washed your hands for 30 seconds!” without
it sounding like you’re being amazingly sarcastic or like you’re talking to a
young child. So I turned all of that nonsense off. It’s meant to be a tool
not a wannabe life coach.&lt;/p&gt;
&lt;p&gt;You can access Maps directly on the watch and even do navigation. It works
really well. The navigation mode has some nice haptic feedback: it does a short
pulse as you’re approaching a turn, and then a long pulse at the actual turn.
I like it a lot more than having to dig out my phone or have the directions
read out. You get one pulse, glance down and see where you need to go, then it
reminds you a little later when it’s time to do it. It’s a delightful user
experience.&lt;/p&gt;
&lt;p&gt;Watchfaces aren’t quite so delightful. There’s a limited number of built-in
ones, and some are “exclusive” to the Ultra Series, and you can’t use them on
a peasant watch like a Series 10. Annoyingly, there’s not one that does
exactly what I want: a plain analogue clock with an inset date and four
complication slots around the outside. Instead, I have to use one of the slots
to show the date. There are third-party watchfaces, but they have issues.
Firstly, there’s no actual API for making watchfaces&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:9&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt;, so what they do is
bodge it horribly by using a photo background that has fake widgets on it.
On top of that they’re almost universally subscription-based. Again, no
thanks&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:10&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The issue I had with the Smart Band triggering when I was sleeping is solved
trivially on an Apple Watch, by virtue of it having a physical button in the
crown. When you put it in sleep mode, you have to double-press the crown to
unlock it before it’ll do anything else. It hasn’t misfired once while I’ve
been using it.&lt;/p&gt;
&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/10-weeks-with-an-apple-watch-10/sleep.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/10-weeks-with-an-apple-watch-10/sleep.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/10-weeks-with-an-apple-watch-10/sleep.png&#34; alt=&#34;A graph showing sleep phases over time. There&amp;#39;s a noticeable transition form patchy data to more smooth data.&#34; loading=&#34;lazy&#34; width=&#34;284&#34; height=&#34;597&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Sleep data; spot when I swapped devices!&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Finally, a special mention for the gesture controls. If you raise the watch
it reliably wakes up (switching from a low refresh rate, dimmed screen to
an active, brighter one); you can then double-tap your index finger and thumb
together and it will scroll down or page through whatever you’re looking at.
The killer feature for this is navigating recipes: you can advance to the next
step in a recipe while your hands are covered in flour. It’s also handy for
reading notifications: when one pops up, you can double-tap to expand it, then,
when it gets to the bottom, it’ll outline the default button (often “Dismiss”)
and you can double-tap again to click it.&lt;/p&gt;
&lt;h3 id=&#34;the-verdict&#34;&gt;The verdict&lt;/h3&gt;
&lt;p&gt;I normally don’t like writing an actual labelled conclusion, but it feels
like one is needed here! Overall, I’m happy with the watch. The daily
charging doesn’t bother me, the data gathered seems reliable, the health
monitoring has obviously paid dividends already, and the walled garden isn’t
&lt;em&gt;too&lt;/em&gt; chafing. It’s a straight upgrade over my old Smart Band, and I think
it was worth the cost.&lt;/p&gt;
&lt;p&gt;The original reason for getting the watch was better sleep tracking, though,
so how well did it do? I’m much happier with the data: it seems to more
accurately represent when I was awake in the night, and overall the sleep
phases just seem to make more sense. You can see in the graph that the old
data switched frequently between phases, and they didn’t quite line up for
some reason; towards the right when the Apple Watch is supplying the data
instead there’s a much more consistent pattern of sleep phases that repeat
over the course of the night.&lt;/p&gt;
&lt;p&gt;I’m not going to advocate that you go out and buy one, though. I know my
requirements and usage aren’t typical, and I’ve also not got experience with
any recent Android Wear alternatives or the new version of the Pebble watch
that’s coming soon. You should definitely get your blood pressure checked,
though!&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;OK, it’s more like 14 now, it’s taken a while for this post to make its
way from my brain into text. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Exercise for the sake of exercising just seems so overwhelmingly
tedious and boring to me. And other types of exercise generally require
social interaction, coordinating with people, and so on. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Who decided to use “millimetres of mercury displaced” as a unit? You
can’t just put random chemical symbols in units! That’s not how this works! &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Blood pressure readings have two parts: systolic (the pressure when the
heart is beating) and diastolic (the pressure between those beats). They’re
generally presented with the systolic reading on top and the diastolic reading
below, and read as “X over Y”. Now you know what some of the random numbers
they shout in medical shows mean! Yay learning! &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;No thanks to how much salt is in everything. I’m pretty sure I’ve had at
least twice the recommended daily amount of salt in a single serving before.
Don’t even get me started on the things that are “low salt” but are still full
of sodium from other sources. I don’t have a problem with ionic compounds, I
have a problem with sodium! &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;This mainly looks like drawing graphs that are slightly different to
the graphs in the Apple Health graphs, for reasons I’m not sure I can explain.
Making graphs is fun, OK? &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:6&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;Complications are basically just home screen widgets, but with a fancy
name because they’re on a watch. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:7&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;Tailscale actually causes me some problems here: everything works fine
when the watch is connected to my phone, as the phone handles the Tailscale
part, but if I’m not carrying my phone the watch will try to connect over
WiFi directly and doesn’t understand anything about Tailscale. It happens
infrequently enough that I’ll just live with it; it’s not much worse than
having no signal on a phone. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:8&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:9&#34;&gt;
&lt;p&gt;Yay walled gardens… &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:9&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:10&#34;&gt;
&lt;p&gt;I don’t object to subscribing to things in general, but it has to be
something that’s worth the ongoing cost and offers something in return for
the subscription. A watchface doesn’t need enough ongoing maintenance to
justify subscribing to it, it’s just a cash grab. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:10&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Home Automation Without the Megacorps</title>
        <link href="https://chameth.com/home-automation-without-megacorps/"/>
        <updated>2025-05-21T00:00:00Z</updated>
        <id>https://chameth.com/home-automation-without-megacorps/</id>
        <content xml:lang="en" type="html">&lt;p&gt;I first experimented with home automation in 2016, by picking up a Samsung
“SmartThings” hub. It was terrible. The UI to configure things was slow and
clunky, firmware updates were applied whether you wanted them or not, and
everything stopped working if their cloud services stopped. You were also locked
into whatever integrations they deigned to support, of course. After that broke
for the umpteenth time I scaled back and for years the closest I got to home
automation was a couple of Hue bulbs.&lt;/p&gt;
&lt;p&gt;Recently I’ve been building it out again, though. This time using off-the-shelf
components that interop using Zigbee, open-source software, and some code I
wrote myself. It’s great; it runs entirely locally and has had basically zero
downtime. The Zigbee ecosystem lets me integrate all sorts of things without
having to spend lots of money on “smart” alternatives. I think I’ve spent less
on this incarnation than I did on the original SmartThings hub all those years
ago (even without adjusting for inflation!).&lt;/p&gt;
&lt;h3 id=&#34;my-current-setup&#34;&gt;My current setup&lt;/h3&gt;
&lt;p&gt;I run everything on a Raspberry Pi 4, with a Sonoff USB Zigbee adapter based
on the CC2652P chipset&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. Interfacing with the Zigbee stack is handled by
&lt;a href=&#34;https://www.zigbee2mqtt.io/&#34;&gt;zigbee2mqtt&lt;/a&gt; (z2m for short), an open-source project that
basically bridges your devices to an MQTT broker&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. When a device reports some
data, it will send a new message over MQTT; when you want to make a device do
something you just post a message back. It’s incredibly lightweight, but
supports a huge array of devices out of the box. And as it’s just using MQTT,
it’s trivial to integrate with other software or build on top of.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;I know a lot of people building out this kind of home automation use
&lt;a href=&#34;https://www.home-assistant.io/&#34;&gt;Home Assistant&lt;/a&gt;, but I don’t get on with it
terribly well. It felt incredibly sluggish, and the entire project is just a
bit… much. I want a binary or package or docker image I can just run, not an
entire operating system. That’s not how computers are meant to work! In contrast,
z2m is simple to set up, super light weight and responsive.&lt;/p&gt;
&lt;p&gt;Anyway. z2m exposes Zigbee devices over MQTT, so I wrote some code in Go to
connect to the MQTT broker, and listen to the messages. It’s grown a bit beyond
this now, and I’m skipping some boring bits like error handling and JSON
parsing, but at first I had something like:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;topic&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;ReadSlices&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;topic&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;zigbee2mqtt/desk-button&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;Contains&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;single&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;chroma-nx&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;Publish&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;chroma-nb&#34;&gt;byte&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;{\&amp;#34;state\&amp;#34;: \&amp;#34;TOGGLE\&amp;#34;}&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;zigbee2mqtt/room-lights/set&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;chroma-w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I think I actually made this harder to read by trying to simplify it here, but
hopefully you can follow that it was relatively straight forward to listen
for a particular action to happen (in this case me “single”-pressing on the
device called “desk-button”) and then make another device do something in
response (toggling the state of the “room-lights” device).&lt;/p&gt;
&lt;p&gt;So what actually are these devices? At present in z2m I have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some generic buttons&lt;/li&gt;
&lt;li&gt;An air quality sensor (USB powered), and a separate temperature sensor (battery powered)&lt;/li&gt;
&lt;li&gt;A light switch&lt;/li&gt;
&lt;li&gt;Some 240V relay modules, that I use to turn non-smart devices on and off&lt;/li&gt;
&lt;li&gt;Some USB relay modules, for the same purpose&lt;/li&gt;
&lt;li&gt;Some “smart” plugs that I mostly use to monitor power usage&lt;/li&gt;
&lt;li&gt;A motorised blind roller&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think all of these are either Tuya or Moes branded, and were all sourced from
AliExpress. You can get the same things from Amazon or elsewhere, but they tend
to be 3-4x more expensive for the same product.&lt;/p&gt;
&lt;p&gt;One of the cool things about Zigbee devices is that the powered ones work
together to create a mesh network, so you don’t have to worry about network
repeaters or signal strength like you do with Wi-Fi networks. z2m even makes
a map showing the connections:&lt;/p&gt;
&lt;figure class=&#34;image full&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/home-automation-without-megacorps/zigbee-map.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/home-automation-without-megacorps/zigbee-map.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/home-automation-without-megacorps/zigbee-map.png&#34; alt=&#34;A &amp;#34;map&amp;#34; showing how Zigbee devices connect to one another&#34; loading=&#34;lazy&#34; width=&#34;1093&#34; height=&#34;651&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The network map produced by z2m. You can see how all the powered devices form a mesh that the lower power ones can connect to.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&#34;some-interesting-automations&#34;&gt;Some interesting automations&lt;/h3&gt;
&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/home-automation-without-megacorps/relay.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/home-automation-without-megacorps/relay.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/home-automation-without-megacorps/relay.jpg&#34; alt=&#34;A Zigbee relay and some wago connectors wired up in a project box&#34; loading=&#34;lazy&#34; width=&#34;325&#34; height=&#34;500&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;A Zigbee relay spliced into the power cable for the fan&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So what do I actually do with all of this? Some of it is just what I’ll call
“laziness automation”: I want to be able to turn on the lights without getting
up and walking to the light switch. So there’s a Zigbee button on my desk that
does it. Then there are some less manual automations: my blinds are
automatically closed at sunset&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, for example. It feels a bit trivial, but it’s
surprisingly nice just not to have to think about that at all.&lt;/p&gt;
&lt;p&gt;Another nice quality of life automation is the light I have above my monitor.
It’s USB powered, and I now have it going through a Zigbee USB relay that lets
it be toggled on and off. Then I have a small agent running on my desktop that
turns the light on when the computer is unlocked, and off when it locks or
shuts down. I keep meaning to make a “film mode” that detects when I’m watching
a film, and turning all the lights and blinds down, but I haven’t got around
to it yet.&lt;/p&gt;
&lt;p&gt;The most complex automation is probably for a window fan. It’s not smart in
any way, so I cut the power cable and inserted a Zigbee relay. The whole thing
is housed in a little project box to keep it secure. The relay basically acts
as a switch: the live wire leading to the fan runs to the “normally open”&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;
contact, while the upstream power goes to “common”. When the relay is told to
turn the fan on, the two get connected and the fan gets power. Oh, it’s also
not actually a window fan, but I designed and 3D printed some adapters so that
it sits right in the window.&lt;/p&gt;
&lt;p&gt;So now we have a window fan that can be turned off and on automatically. But I don’t
want to have to press a button to do that. I’m lazy, remember? Instead, I made
it so that the Go code constantly monitors the temperature reported by the air
quality sensor, and queries the free &lt;a href=&#34;https://openweathermap.org/&#34;&gt;OpenWeatherMap API&lt;/a&gt;
to get the rough temperature outside. It can then turn the fan on if the room is
too hot, and outside is cool enough to make a difference (there’s no point in
blowing hotter air in!).&lt;/p&gt;
&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/home-automation-without-megacorps/fan-graph.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/home-automation-without-megacorps/fan-graph.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/home-automation-without-megacorps/fan-graph.png&#34; alt=&#34;A graph of room temperature, slowly rising to 23.5 degrees, then sharply dropping to 19, rising to 20, dropping to 19 again, etc&#34; loading=&#34;lazy&#34; width=&#34;540&#34; height=&#34;500&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;A graph of room temperature, showing the effect of the fan being turned on and off&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I don’t want it to do that all the time though. The room doesn’t need to be
cooled if I’m not around. There are various Zigbee presence sensors you can get,
but the cheaper ones seem to be of dubious quality. Instead, I wrote some code
to guess whether I’m present. It uses the state of the monitor light
as a proxy for “is the computer in use”, and then makes some guesses based on
the last time the computer was used and the current time (if I turn the computer
off at midnight it probably means I’m going to sleep; if I turn it off at 2pm
it probably means I’m going out somewhere).&lt;/p&gt;
&lt;p&gt;You can see in the graph that the fan has a decent impact on temperature. I
coded it to cool the room to 19 degrees, but then not turn on again until it
was above 20. This prevents it flip-flopping on and off constantly. You can
clearly see the pattern in the graph, as it actively cools and then slowly
the room warms back up. This arrangement is much better than being woken up at
5am because it’s painfully cold. Trust me.&lt;/p&gt;
&lt;h3 id=&#34;bonuses-metrics-and-3d-printer&#34;&gt;Bonuses: metrics and 3D printer&lt;/h3&gt;
&lt;p&gt;One of the things my custom Go code does is collate all the various stats
reported by the Zigbee devices, and inserts them into a &lt;a href=&#34;https://victoriametrics.com/&#34;&gt;VictoriaMetrics&lt;/a&gt;
database. I originally hosted this on the Pi itself, and it performed fine, but
I’ve since moved it onto a server so that I can use it for some other things
as well.&lt;/p&gt;
&lt;p&gt;I set up Grafana to point to VM, and can create dashboards showing power usage,
what devices are turned on when, and a bunch of environmental conditions. This
also makes it easy to spot how good the data coming from the devices are. For
example, the air quality sensor reports a figure for the amount of Carbon Dioxide
in the air, as well as the amount of Volatile Organic Compounds (VOCs). The
graphs are basically identical, but on a different scale. It turns out this
particular device has no actual way of detecting CO₂, so it just “calculates”
it from the VOCs figure. Useful to know if you want to actually use that data.&lt;/p&gt;
&lt;p&gt;Recently I came across &lt;a href=&#34;https://github.com/torbenconto/bambulabs_api&#34;&gt;a go library for interacting with Bambu Lab printers&lt;/a&gt;,
so I’ve also hooked that into my automation. It exports metrics about the
printer, so I now have a way of seeing what’s going on when I’m not physically
present&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;. I even added a HTTP endpoint (exposed over &lt;a href=&#34;https://tailscale.com/&#34;&gt;Tailscale&lt;/a&gt;) that
shows pictures from the built-in camera.&lt;/p&gt;
&lt;p&gt;On the automation front, I’ve made it automatically turn off the printer’s light
when it finishes a print, and also added push notifications via &lt;a href=&#34;https://pushover.net/&#34;&gt;PushOver&lt;/a&gt;
whenever the state changes. No longer will I be sat in another room blissfully
unaware it ran out of filament seconds after I walked out the door!&lt;/p&gt;
&lt;h3 id=&#34;was-it-worth-it&#34;&gt;Was it worth it?&lt;/h3&gt;
&lt;p&gt;These days you could probably just buy some kind of ‘smart home’ hub that works
well enough, and do most of what I’ve done with a lot less effort and no coding.
I’m still of the opinion that for something so essentially &lt;em&gt;local&lt;/em&gt;, it should
itself be managed entirely locally. I don’t trust companies like Google or
Amazon not to kill their products, or change or remove an API I rely on.&lt;/p&gt;
&lt;p&gt;Obviously the “Not Invented Here” approach of coding everything yourself doesn’t
suit everyone, but as someone who enjoys coding and enjoys having things work
&lt;em&gt;just so&lt;/em&gt; it works very well for me.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;It turns out the chipset is important. I initially used a similar Sonoff
dongle that used a CC2531 chipset, and its performance wasn’t great. It often
failed to pair with new devices, and dropped links to existing ones. The
&lt;a href=&#34;https://www.zigbee2mqtt.io/advanced/zigbee/02_improve_network_range_and_stability.html&#34;&gt;zigbee2mqtt docs&lt;/a&gt;
do explicitly advise against the CC2531 chips for that reason. At the time they
recommended CC2652Ps, so that’s what I went with. If you’re starting new I’d
go with whatever their latest recommendation was. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;MQTT is basically a network protocol for publishing and subscribing to
arbitrary messages. A broker is the thing that sits in the middle and routes
the messages. I use &lt;a href=&#34;https://mosquitto.org/&#34;&gt;Mosquitto&lt;/a&gt; but any will do. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;They originally also re-opened at sunrise but that was a terrible
mistake. Who knew the sun rose so early?! &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;“open” meaning “there’s a gap so it doesn’t work” not
“open for business”. This confusion in terminology also extends to drawbridges. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;I use the printer in LAN mode, which means there’s no way to monitor it
from a phone, even if you’re connected to the same network still. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
</feed>
