<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>videah&#x27;s blog</title>
      <link>https://old.blog.videah.net</link>
      <description>seemed like a good idea at the time</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://old.blog.videah.net/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Mon, 12 May 2025 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Plex Might Be Indavertently Bottlenecking You</title>
          <pubDate>Mon, 12 May 2025 00:00:00 +0000</pubDate>
          <author>videah</author>
          <link>https://old.blog.videah.net/plex-why-oh-why/</link>
          <guid>https://old.blog.videah.net/plex-why-oh-why/</guid>
          <description xml:base="https://old.blog.videah.net/plex-why-oh-why/">&lt;p&gt;Plex has this &lt;a href=&quot;https:&#x2F;&#x2F;support.plex.tv&#x2F;articles&#x2F;216766168-accessing-a-server-through-relay&quot;&gt;Relay feature&lt;&#x2F;a&gt; that basically
pipes your traffic through their servers if direct access isn&#x27;t possible for whatever reason, bypassing NAT and
presumably cutting down on their support tickets.&lt;&#x2F;p&gt;
&lt;p&gt;For free users the relay is capped at a measly &lt;code&gt;1 Mbps&lt;&#x2F;code&gt; and the [ever-growing expense that is the &lt;a href=&quot;https:&#x2F;&#x2F;www.plex.tv&#x2F;plans&quot;&gt;Plex Pass subscription&lt;&#x2F;a&gt;
service only bumps this up to a whopping &lt;code&gt;2 Mbps&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I can imagine this being useful for a selection of people. But as this feature is turned on &lt;strong&gt;by default&lt;&#x2F;strong&gt;, it&#x27;s very easy for any
issues with your server&#x27;s network configuration to go unnoticed. It turns out my port-forwarding rule for Plex hadn&#x27;t been working
for several months (&lt;em&gt;thanks Ubiquiti&lt;&#x2F;em&gt;) and I never noticed because the relay feature was masking the problem.&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -right-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-l-[12px] border-l-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;So... you&#x27;re telling me Plex isn&#x27;t meant to be almost unusably slow this whole time...?&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;dead.gif?h=c48d1178bf9057d37736&quot;
            alt=&quot;Pixel art animation of my fursona with a dead expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;dead.gif?h=c48d1178bf9057d37736&quot;
            alt=&quot;Pixel art animation of my fursona with a dead expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;It doesn&#x27;t help that the remote-access configuration UI has been very buggy for 6+ years, making it
impossible to tell if the issue is with your server or the broken interface.&lt;&#x2F;p&gt;
&lt;p&gt;So please don&#x27;t make the same mistakes as me. Make sure your Plex client is actually connecting to your server directly, and use a &lt;a href=&quot;https:&#x2F;&#x2F;www.yougetsignal.com&#x2F;tools&#x2F;open-ports&quot;&gt;Port Forward Checker&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Attacking My Landlord&#x27;s Boiler</title>
          <pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate>
          <author>videah</author>
          <link>https://old.blog.videah.net/attacking-my-landlords-boiler/</link>
          <guid>https://old.blog.videah.net/attacking-my-landlords-boiler/</guid>
          <description xml:base="https://old.blog.videah.net/attacking-my-landlords-boiler/">&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -right-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-l-[12px] border-l-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;Please do your due diligence and check local laws before attempting anything I do in this post. Transmitting radio signals can become legally problematic &lt;em&gt;very quickly&lt;&#x2F;em&gt;, and the band I specifically transmit on here (&lt;code&gt;868Mhz&lt;&#x2F;code&gt;) is &lt;strong&gt;illegal&lt;&#x2F;strong&gt; in the United States without a license. I&#x27;d rather you didn&#x27;t have men in suits knocking on your door on my account. You&#x27;ve been warned!&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sad.gif?h=34df99035fd1f99481e3&quot;
            alt=&quot;Pixel art animation of my fursona with a sad expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sad.gif?h=34df99035fd1f99481e3&quot;
            alt=&quot;Pixel art animation of my fursona with a sad expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;A little while ago I moved into an apartment to live on my own for the first time. This has given me a decent amount of newfound freedom to sculpt my living environment to my liking, but not enough where I could start knocking down walls. I have a landlord (and a deposit!) to think about, after all. 🙂&lt;&#x2F;p&gt;
&lt;p&gt;While it isn&#x27;t near the level of knocking down walls, I was finding heating my apartment rather frustrating. The boiler&#x27;s thermostat installed by my landlord is a single radio-controlled unit that uses a built-in temperature sensor to modulate the heating on and off to meet a target temperature. This presents a few first-world problems:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The temperature sensor can only sample a single room in the apartment, which heats unevenly.&lt;&#x2F;li&gt;
&lt;li&gt;That room is dependent on the physical proximity of the thermostat&#x27;s controls, which can be annoying to use if I might be in bed and the controls are in the living room or vice versa.&lt;&#x2F;li&gt;
&lt;li&gt;If I forget to turn the heating off before I leave the apartment, I&#x27;m wasting a lot of costly energy.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I automate things around my apartment with &lt;a href=&quot;https:&#x2F;&#x2F;www.home-assistant.io&quot;&gt;Home Assistant&lt;&#x2F;a&gt;, and I wanted to be able to do the same here. There are a lot of off-the-shelf solutions for this, obviously, but to get back to the knocking-down-walls comparison, they would require my landlord&#x27;s cooperation and likely a visit from an electrician. I don&#x27;t want that!&lt;&#x2F;p&gt;
&lt;p&gt;Instead, here&#x27;s how I figured out how to control my apartment&#x27;s heating in a way that leaves no trace using the existing thermostat already fitted by my landlord, and maybe learn a bit about radios along the way.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-do-we-start&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#where-do-we-start&quot; aria-label=&quot;Anchor link for: where-do-we-start&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Where Do We Start?&lt;&#x2F;h2&gt;
&lt;p&gt;I knew that the thermostat communicated with the boiler through some kind of radio protocol. We could try to reverse-engineer the protocol from scratch, but as I&#x27;ll get into later, that turns out to be &lt;em&gt;very involved&lt;&#x2F;em&gt; and way beyond my minimal radio skills.&lt;&#x2F;p&gt;
&lt;p&gt;I eventually decided it was a lot easier to attempt something called a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Replay_attack#Remote_keyless-entry_system_for_vehicles&quot;&gt;Replay Attack&lt;&#x2F;a&gt;. This involves cloning the signals sent between the boiler and the thermostat, and then pretending &lt;em&gt;we&lt;&#x2F;em&gt; are the thermostat by re-broadcasting the signals. This way we don&#x27;t need to understand the protocol, just replay it.&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -right-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-l-[12px] border-l-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;This approach requires some degree of luck and crossing your fingers. Replay attacks can be pretty easily thwarted by using an incrementing counter in the communications to nullify previous signals, ignoring signals with a counter value you&#x27;ve already seen. I was lucky the thermostat does not do this—your mileage may vary!&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;walking.gif?h=e135283307a52678835b&quot;
            alt=&quot;Pixel art animation of my fursona with a walking expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;walking.gif?h=e135283307a52678835b&quot;
            alt=&quot;Pixel art animation of my fursona with a walking expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;&lt;h2 id=&quot;initial-reconnaissance&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#initial-reconnaissance&quot; aria-label=&quot;Anchor link for: initial-reconnaissance&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Initial Reconnaissance&lt;&#x2F;h2&gt;
&lt;p&gt;The first thing I did was check to see if there was any information online about my specific thermostat. I came across &lt;a href=&quot;https:&#x2F;&#x2F;www.wolseley.co.uk&#x2F;product&#x2F;center-rf-wireless-programmable-boiler-thermostat&quot;&gt;a listing for the exact model I had&lt;&#x2F;a&gt;, along with a datasheet in the attachments section. The section on &lt;em&gt;RF Communication&lt;&#x2F;em&gt; is exactly what I was looking for:&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;boiler_datasheet_rf.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
&lt;&#x2F;figure&gt;
&lt;p&gt;From this, we know the thermostat communicates around the &lt;code&gt;868Mhz&lt;&#x2F;code&gt; range. The &lt;code&gt;Protocol: Encrypted&lt;&#x2F;code&gt; part was initially a bit concerning, but it turned out to not be a problem.&lt;&#x2F;p&gt;
&lt;p&gt;The first issue I&#x27;m running into here is that there are shockingly few resources on cloning a &lt;code&gt;868Mhz&lt;&#x2F;code&gt; signal online. Most beefy resources were about using LoRa&#x2F;Meshtastic. I would come across a lot of Reddit posts of people trying to do the same thing as me for things like ceiling fans and garage doors, but nobody seemed to have any answers... 😭&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;normal.gif?h=ca53dc229a6c5551725c&quot;
            alt=&quot;Pixel art animation of my fursona with a normal expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;I &lt;em&gt;suspect&lt;&#x2F;em&gt; this is because unlicensed &lt;code&gt;868Mhz&lt;&#x2F;code&gt; transmission is illegal in the US and nobody cares about Europe, but who really knows. My life would be &lt;em&gt;so much&lt;&#x2F;em&gt; easier if it were &lt;code&gt;433Mhz&lt;&#x2F;code&gt; instead, as there is a plethora of consumer-facing tools for communicating on that band.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;normal.gif?h=ca53dc229a6c5551725c&quot;
            alt=&quot;Pixel art animation of my fursona with a normal expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;&lt;h2 id=&quot;seeing-signals&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#seeing-signals&quot; aria-label=&quot;Anchor link for: seeing-signals&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Seeing Signals&lt;&#x2F;h2&gt;
&lt;p&gt;So without much to go on, I thought the first thing to do would be to actually &lt;em&gt;see&lt;&#x2F;em&gt; the radio packets and inspect them. I&#x27;d read about &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Software-defined_radio&quot;&gt;Software-Defined Radios&lt;&#x2F;a&gt; in the past and guessed it&#x27;d be my best bet. Most SDRs are &lt;em&gt;really&lt;&#x2F;em&gt; expensive, so I went with the budget &lt;a href=&quot;https:&#x2F;&#x2F;www.aliexpress.com&#x2F;item&#x2F;1005005952566458.html?spm=a2g0o.order_list.order_list_main.165.295b1802ErX1lM&quot;&gt;RTL-SDR V4&lt;&#x2F;a&gt; off of AliExpress. (This actually ended up being somewhat unnecessary for reasons we&#x27;ll eventually get to!)&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -right-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-l-[12px] border-l-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;You might have heard of the infamous &lt;a href=&quot;https:&#x2F;&#x2F;flipperzero.one&quot;&gt;Flipper Zero&lt;&#x2F;a&gt; and its ability to clone and replay signals. Maybe you&#x27;re like me and consider using it in this situation, but be warned that the Flipper is &lt;strong&gt;NOT&lt;&#x2F;strong&gt; an SDR. The Flipper is very stingy about what frequencies it can operate on. I found this out the hard way when I borrowed one and assumed all was hopeless when it wouldn&#x27;t work.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sleeping.gif?h=faf0690e4b86d1fddceb&quot;
            alt=&quot;Pixel art animation of my fursona with a sleeping expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sleeping.gif?h=faf0690e4b86d1fddceb&quot;
            alt=&quot;Pixel art animation of my fursona with a sleeping expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;After it arrived, I hooked it up to my laptop with the &lt;a href=&quot;https:&#x2F;&#x2F;www.sdrpp.org&quot;&gt;SDR++&lt;&#x2F;a&gt; software just to see if it worked and get an initial glimpse of my thermostat yapping. After pressing the thermostat&#x27;s buttons a few times, I managed to see the waterfall light up!&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;sdr_plus_plus.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        The &quot;waterfall&quot; at 868Mhz showing long horizontal blips.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;dead.gif?h=c48d1178bf9057d37736&quot;
            alt=&quot;Pixel art animation of my fursona with a dead expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;Ignore the solid vertical line on the waterfall—this is just a common byproduct of using a really cheap SDR, and for me it appears nearby to any frequency I&#x27;m inspecting.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;dead.gif?h=c48d1178bf9057d37736&quot;
            alt=&quot;Pixel art animation of my fursona with a dead expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;This step isn&#x27;t super important, but we can then try to use the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;merbanan&#x2F;rtl_433&quot;&gt;rtl_433&lt;&#x2F;a&gt; tool (it works on other frequencies despite the name) to see if the thermostat is speaking a known protocol. More obscure devices might not work here!&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;rtl_443_results.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
&lt;&#x2F;figure&gt;
&lt;p&gt;It seems like this thermostat speaks the same protocol as another Honeywell one. The demand attribute sets whether the boiler is on (1) or off (0), and then the boiler responds with an acknowledgement (presumably so the thermostat can determine if it&#x27;s out of range).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;trying-to-yell-back&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#trying-to-yell-back&quot; aria-label=&quot;Anchor link for: trying-to-yell-back&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Trying To Yell Back&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we&#x27;ve actually seen the back-and-forth communication, we want to be able to send some packets ourselves and puppeteer the boiler as if we were the thermostat.&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;challenger.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        Using a 868Mhz Challenger Dev Board, first failed attempt...
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;This was the step I got stuck on for &lt;em&gt;months&lt;&#x2F;em&gt;. I was trying the &quot;smart&quot; route of attempting to reverse-engineer and reconstruct the packets &lt;em&gt;by hand&lt;&#x2F;em&gt; using &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jopohl&#x2F;urh&quot;&gt;URH&lt;&#x2F;a&gt; and then broadcasting them with very cheap &lt;code&gt;868Mhz&lt;&#x2F;code&gt; microcontroller boards. I can safely say this was all wayyy outside of my skill set. None of the boards were really designed to talk to anything other than &lt;em&gt;the exact same board&lt;&#x2F;em&gt;, and going any further than that required poking at radio registers in ways I wasn&#x27;t comfortable doing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-hackrf&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#the-hackrf&quot; aria-label=&quot;Anchor link for: the-hackrf&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;The HackRF&lt;&#x2F;h2&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;hackrf-board.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        The official HackRF One board, going on to spawn many AliExpress clones.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;I decided to then go for the &lt;strong&gt;sledgehammer&lt;&#x2F;strong&gt; approach: use a full-blown SDR to just replay the exact same signal without a care for what the signal actually contains. But the cheap RTL-SDR I got earlier only supports receiving, not broadcasting. SDRs that can broadcast are usually &lt;em&gt;hundreds of dollars&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I say &lt;em&gt;usuallyyy&lt;&#x2F;em&gt; because one of the most common broadcast-capable SDRs, the &lt;code&gt;HackRF One&lt;&#x2F;code&gt; (usually upwards of $400), had numerous clones available on AliExpress for a fraction of the price—just $40.&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -right-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-l-[12px] border-l-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;And then I say &lt;em&gt;haddd&lt;&#x2F;em&gt; because, writing this months later, AliExpress has removed pretty much every listing you could find just searching &quot;HackRF&quot;. From my understanding, they were getting nabbed at customs in a lot of countries that were getting pissy about importing a scawy hacking tool, so they just decided to nuke all the listings rather than deal with it. Newer clones can be bought from &lt;a href=&quot;https:&#x2F;&#x2F;opensourcesdrlab.com&#x2F;products&#x2F;r10c-hrf-sdr-software-defined-1mhz-to-6ghz-mainboard-development-board-kit?VariantsId=10158&quot;&gt;here&lt;&#x2F;a&gt;, but they aren&#x27;t nearly as cheap as they used to be... 😭&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sad.gif?h=34df99035fd1f99481e3&quot;
            alt=&quot;Pixel art animation of my fursona with a sad expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sad.gif?h=34df99035fd1f99481e3&quot;
            alt=&quot;Pixel art animation of my fursona with a sad expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;There are some obvious ethical (and probably a few technical) problems with cheap clones of what is meant to be open-source hardware, but I figured it&#x27;d be fine for my small use case. Please &lt;a href=&quot;https:&#x2F;&#x2F;greatscottgadgets.com&#x2F;hackrf&#x2F;one&quot;&gt;support the original hardware project&lt;&#x2F;a&gt; if it&#x27;s within your means to!&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;walking.gif?h=e135283307a52678835b&quot;
            alt=&quot;Pixel art animation of my fursona with a walking expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;As I kinda alluded to earlier, this makes the need for the RTL-SDR sort of redundant? But I guess it&#x27;s always good to have another SDR just to confirm that we&#x27;re not polluting other frequencies.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;walking.gif?h=e135283307a52678835b&quot;
            alt=&quot;Pixel art animation of my fursona with a walking expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;&lt;h2 id=&quot;actually-yelling-back&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#actually-yelling-back&quot; aria-label=&quot;Anchor link for: actually-yelling-back&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Actually Yelling Back&lt;&#x2F;h2&gt;
&lt;p&gt;With the HackRF in hand, we can use the &lt;a href=&quot;https:&#x2F;&#x2F;manpages.debian.org&#x2F;unstable&#x2F;hackrf&#x2F;hackrf_transfer.1.en.html&quot;&gt;hackrf_transfer tool&lt;&#x2F;a&gt; to record signals and, most importantly, &lt;em&gt;replay&lt;&#x2F;em&gt; signals. I perform these commands and then press the appropriate controls on the thermostat to write the signals to individual files:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;shell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-shell &quot;&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span&gt;# We set the frequency to 868.3Mhz and the sample rate to 2000000.
&lt;&#x2F;span&gt;&lt;span&gt;hackrf_transfer -r turn_off.raw -f 868300000 -s 2000000
&lt;&#x2F;span&gt;&lt;span&gt;hackrf_transfer -r turn_on.raw -f 868300000 -s 2000000
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And then we can try and turn the boiler off and on from CLI like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;shell&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-shell &quot;&gt;&lt;code class=&quot;language-shell&quot; data-lang=&quot;shell&quot;&gt;&lt;span&gt;# We use -a to turn on the amplifier and -x to increase the gain a tad.
&lt;&#x2F;span&gt;&lt;span&gt;hackrf_transfer -t turn_off.raw -f 868300000 -s 2000000 -a 1 -x 23
&lt;&#x2F;span&gt;&lt;span&gt;hackrf_transfer -t turn_on.raw -f 868300000 -s 2000000 -a 1 -x 23
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After doing this, I could hear the physical relay inside of my boiler turning on and off!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;automating-the-whole-thing&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#automating-the-whole-thing&quot; aria-label=&quot;Anchor link for: automating-the-whole-thing&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Automating The Whole Thing&lt;&#x2F;h2&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;hackrf_horizontal.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        My HackRF clone in a 3D printed case, plugged into the server.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;I have the HackRF plugged into a powered USB hub connected to my Home Assistant server. I wrote a very basic web server that simply shells out to the transmit commands above in a Docker container.&lt;&#x2F;p&gt;
&lt;p&gt;Then with an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Limych&#x2F;ha-average&quot;&gt;Average Sensor Plugin&lt;&#x2F;a&gt; and the config YAML below:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command_line&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;switch&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Boiler
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command_on&lt;&#x2F;span&gt;&lt;span&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;curl http:&#x2F;&#x2F;docker-vm:1111&#x2F;api&#x2F;on&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;command_off&lt;&#x2F;span&gt;&lt;span&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;curl http:&#x2F;&#x2F;docker-vm:1111&#x2F;api&#x2F;off&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;sensor&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;platform&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;average
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Average Temperature&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;entities&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sensor.bedroom_thermostat_temperature
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sensor.kitchen_thermostat_temperature
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;climate&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;platform&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;generic_thermostat
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;Boiler Thermostat
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;heater&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;switch.boiler
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;target_sensor&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sensor.average_temperature
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;w-full&quot;&gt;
    &lt;video controls&gt;
        &lt;source src=&quot;videos&amp;#x2F;boiler_working.mp4&quot; type=&quot;video&#x2F;mp4&quot;&#x2F;&gt;
    &lt;&#x2F;video&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;We have a working controllable thermostat! 🤯&lt;&#x2F;p&gt;
&lt;p&gt;At this point I was just happy to have the thing &lt;em&gt;working&lt;&#x2F;em&gt; after so many months, so I&#x27;ll be the first to admit this setup with Home Assistant is a bit slapdash and could use some cleanup. It&#x27;d be better to write a proper plugin and control the radio directly instead of shelling out to the CLI. Relying on &lt;code&gt;curl&lt;&#x2F;code&gt; to heat my apartment is maybe a bit cursed?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;was-it-worth-it&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#was-it-worth-it&quot; aria-label=&quot;Anchor link for: was-it-worth-it&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Was It Worth It?&lt;&#x2F;h2&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;boiler_grafana.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        Grafana graph showing the temperatures following the target one.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;I&#x27;ve been using this setup to control the heating of my apartment since the beginning of December and haven&#x27;t had any issues since! It&#x27;s super convenient to dial in the temperature from my phone, and the automations I have make me feel like this project was really worth the work.&lt;&#x2F;p&gt;
&lt;p&gt;I have some basic automations like having the temperature go down when I&#x27;m sleeping and then up in the morning in time for me waking up, but I also have it so the heating turns off when I go into town and turns back on when I&#x27;m just a few train stops away so my place is nice and toasty for me getting home!&lt;&#x2F;p&gt;
&lt;p&gt;The only thing I&#x27;m not happy with is needing to use a very powerful and versatile radio like the HackRF for something as simple as a boiler on&#x2F;off switch. But I&#x27;d rather use something overkill and have it work than spend ages trying to force smaller radios to do my bidding.&lt;&#x2F;p&gt;
&lt;p&gt;The important thing is I&#x27;m not as cold as I used to be! 🐺&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Credits</title>
          <pubDate>Mon, 21 Apr 2025 00:00:00 +0000</pubDate>
          <author>videah</author>
          <link>https://old.blog.videah.net/credits/</link>
          <guid>https://old.blog.videah.net/credits/</guid>
          <description xml:base="https://old.blog.videah.net/credits/">&lt;h2 id=&quot;credits-attribution&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#credits-attribution&quot; aria-label=&quot;Anchor link for: credits-attribution&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Credits &#x2F; Attribution&lt;&#x2F;h2&gt;
&lt;p&gt;Some of the art used around this blog are by other people. Here is a list of them:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Smug Videah by &lt;a href=&quot;https:&#x2F;&#x2F;www.furaffinity.net&#x2F;user&#x2F;kelevtov&quot;&gt;Kelevtov&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Rantsona Sidebar Videah by &lt;a href=&quot;https:&#x2F;&#x2F;bsky.app&#x2F;profile&#x2F;scruffkerfluff.bsky.social&quot;&gt;ScruffKerfluff&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Callout Pixel Art Videah by &lt;a href=&quot;https:&#x2F;&#x2F;bsky.app&#x2F;profile&#x2F;lockedsdcard.bsky.social&quot;&gt;lockedsdcard&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Videah Mutant Standard Emoji by &lt;a href=&quot;https:&#x2F;&#x2F;nocturne.works&quot;&gt;Caius Nocturne&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>My E-Reader Setup</title>
          <pubDate>Thu, 10 Aug 2023 00:00:00 +0000</pubDate>
          <author>videah</author>
          <link>https://old.blog.videah.net/my-e-reader-setup/</link>
          <guid>https://old.blog.videah.net/my-e-reader-setup/</guid>
          <description xml:base="https://old.blog.videah.net/my-e-reader-setup/">&lt;p&gt;I bought an e-reader recently, specifically the &lt;a href=&quot;https:&#x2F;&#x2F;uk.kobobooks.com&#x2F;products&#x2F;kobo-libra-2&quot;&gt;Kobo Libra 2&lt;&#x2F;a&gt;. I felt like I wasn&#x27;t reading books&#x2F;manga as much as I wanted and I think the convenience of being able to carry my entire library around with me will help with that. I own an iPad Pro but I wanted a device I didn&#x27;t need to think about charging that often and wouldn&#x27;t give me eye strain.&lt;&#x2F;p&gt;
&lt;p&gt;This post is a bundle of notes about my current reading setup.&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sleeping.gif?h=faf0690e4b86d1fddceb&quot;
            alt=&quot;Pixel art animation of my fursona with a sleeping expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;I had owned a Kindle Paperwhite before but it was so locked down that I couldn&#x27;t find any joy out of using it since I was forced to use it how Amazon product managers wanted me to.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;sleeping.gif?h=faf0690e4b86d1fddceb&quot;
            alt=&quot;Pixel art animation of my fursona with a sleeping expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;&lt;h2 id=&quot;the-libra-2&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#the-libra-2&quot; aria-label=&quot;Anchor link for: the-libra-2&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;The Libra 2&lt;&#x2F;h2&gt;
&lt;p&gt;I spent several hours doing research and I think the Libra 2 is the best device on the market at the moment, at least for my needs.&lt;&#x2F;p&gt;
&lt;p&gt;I picked it up in white to try and make an important psychological distiction. I wanted it to differ from every other electronic rectangle I own and treat it more like a nice book rather than a computer that will inevitably make me angry. Which all things considered is quite funny with all the computer nonsense I ended up doing to it.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s got a 7-inch screen which is a little shy of the perfect &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Tank%C5%8Dbon&quot;&gt;Tankōbon volume&lt;&#x2F;a&gt; size, but close enough that manga is comfortable to read. I remember reading somewhere that the screen has one of the best contrast ratios in an e-reader and it is indeed very good.&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;uzumaki.jpeg&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        The lineart of Junji Ito&#x27;s Uzumaki looks very crisp on this display.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Navigation buttons are a dying breed in the e-reader space but I really can&#x27;t live without them. Using a touchscreen to navigate is &lt;em&gt;hateful&lt;&#x2F;em&gt; and is really fake skeumorphism. You can pretend all you want but it does not feel like you are flipping a page! Thankfully the Libra 2 has two buttons on the side where you hold it so you can go back and forth with just one hand.&lt;&#x2F;p&gt;
&lt;p&gt;I got the very overpriced official &lt;a href=&quot;https:&#x2F;&#x2F;uk.kobobooks.com&#x2F;products&#x2F;kobo-libra-2-sleepcover&quot;&gt;SleepCover&lt;&#x2F;a&gt; case in orange. Matches my iPad case. Stops the plastic from making flexing sounds. It can let your e-reader stand upright for some reason.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;book-management&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#book-management&quot; aria-label=&quot;Anchor link for: book-management&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Book Management&lt;&#x2F;h2&gt;
&lt;p&gt;The only real book management software in town for e-readers is &lt;a href=&quot;https:&#x2F;&#x2F;calibre-ebook.com&quot;&gt;Calibre&lt;&#x2F;a&gt; but it&#x27;s stuck in the late 2000&#x27;s UNIX school of UI design and I reaaally don&#x27;t want to deal with that kind of thing anymore. I want organising my books to feel comfy. I also don&#x27;t want it to depend on having my laptop with me, constantly wiring it to my e-reader to sync new books.&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;calibre.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        Calibre on macOS. It is very noisy.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;It&#x27;s not perfect but &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;janeczku&#x2F;calibre-web&quot;&gt;Calibre-Web&lt;&#x2F;a&gt; works better for me. Despite the confusing name it&#x27;s a completely distinct project that just happens to be compatible with Calibre&#x27;s database format. I have it hosted on my personal VPS so I can access it anywhere and can give friends access if I need to. It&#x27;s not quite Plex for books but it is close. The bootstrap UI is a little dated but it works for what I need.&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;walking.gif?h=e135283307a52678835b&quot;
            alt=&quot;Pixel art animation of my fursona with a walking expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;I&#x27;m keeping my eye on a relatively new project called &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Librum-Reader&#x2F;Librum&quot;&gt;Librum&lt;&#x2F;a&gt; that&#x27;s in its infancy. If it matures it promises some nice features like syncing reading positions and its own dedicated client.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;walking.gif?h=e135283307a52678835b&quot;
            alt=&quot;Pixel art animation of my fursona with a walking expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;&lt;h2 id=&quot;reader-software&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#reader-software&quot; aria-label=&quot;Anchor link for: reader-software&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Reader Software&lt;&#x2F;h2&gt;
&lt;p&gt;The default reader software the Libra 2 comes with is called Nickel and it&#x27;s fine. It looks and runs ok enough and the built in Kobo Sync functionality can be tweaked to work with my Calibre-Web instance by replacing the endpoint in a config file, which I have to give Rakuten props for letting you do.&lt;&#x2F;p&gt;
&lt;p&gt;But sideloaded files can be very broken. I was half way through a book before I realised Nickel was just throwing all of my notes and highlights into the void whenever I closed it, which was very rude. This is apparently a common problem that&#x27;s been around for a while and it seems Rakuten have no plan to fix it anytime soon.&lt;&#x2F;p&gt;
&lt;p&gt;I went looking around for some open source alternatives. Most people reach for &lt;a href=&quot;https:&#x2F;&#x2F;koreader.rocks&quot;&gt;KOReader&lt;&#x2F;a&gt;. It runs on pretty much everything and is packed with an ungodly amount of features and has a steady community built around it.&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;ereader_ui.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        Comparing library views for KOReader and Plato.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;But if I&#x27;m being honest I just can&#x27;t find any enjoyment using it. The user interface just isn&#x27;t up to snuff. It feels impossible to navigate and there is no real library view, only a file manager. When I&#x27;m holding my e-reader I don&#x27;t want to be reminded that it is a computer all the time. It&#x27;s meant to be a book!&lt;&#x2F;p&gt;
&lt;p&gt;I came across &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;baskerville&#x2F;plato&quot;&gt;Plato&lt;&#x2F;a&gt; which is made exclusively for Kobo devices and worked on by the guy responsible for bspwm. It&#x27;s really fast and responsive, more so than Nickel even. The UI is pretty much exactly what I&#x27;m looking for. It&#x27;s not nearly as feature complete as KOReader but it&#x27;s written in Rust which is a language I feel confident enough in to tweak and implement things to my hearts desire. &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;baskerville&#x2F;plato&#x2F;pull&#x2F;323&quot;&gt;I&#x27;ve already made a small change that got merged upstream too!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;syncing&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#syncing&quot; aria-label=&quot;Anchor link for: syncing&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Syncing&lt;&#x2F;h2&gt;
&lt;p&gt;Originally I was using Kobo Sync with the endpoint changed to point to my Calibre-Web instance to sync my books wirelessly. But it was buggy and slow and could only pull in KEPUB files.&lt;&#x2F;p&gt;
&lt;p&gt;Plato has a built in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;baskerville&#x2F;plato&#x2F;blob&#x2F;master&#x2F;doc&#x2F;HOOKS.md&quot;&gt;hook system&lt;&#x2F;a&gt; that lets you run arbitrary binaries when a directory is opened. Using this I wrote a small CLI tool that just pulls every book that hasn&#x27;t been downloaded yet from my Calibre-Web instance using the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Open_Publication_Distribution_System&quot;&gt;OPDS protocol&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;love.gif?h=c6d357f0544494d1b641&quot;
            alt=&quot;Pixel art animation of my fursona with a love expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;I&#x27;ve stuck the code for this tool up on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;videah&#x2F;plato-opds&quot;&gt;my Github&lt;&#x2F;a&gt; if anyone else is interested in using it!&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;love.gif?h=c6d357f0544494d1b641&quot;
            alt=&quot;Pixel art animation of my fursona with a love expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;In the future I would like to take advantage of this hook system to also sync reading positions and other metadata Plato stores.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tailscale-vpn&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#tailscale-vpn&quot; aria-label=&quot;Anchor link for: tailscale-vpn&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Tailscale VPN&lt;&#x2F;h2&gt;
&lt;p&gt;I love plugging as many of my devices into my Tailscale network as I can and I thought it&#x27;d be a fun little project to try and get it running on the Libra 2. Someone had already done most of the work by &lt;a href=&quot;https:&#x2F;&#x2F;dstaley.com&#x2F;posts&#x2F;tailscale-on-kobo-sage&quot;&gt;getting it to run on the Kobo Sage&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out it&#x27;s a little harder for the Libra, I had to spend a ridiculous amount of time compiling some missing kernel modules in a horrendously slow emulated x86 emulator just to get this thing running. The joys of owning an ARM laptop. I think being able to type &lt;code&gt;ping kobo&lt;&#x2F;code&gt; and have it Just Work makes all the hours spent worthwhile though ☺️&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;love.gif?h=c6d357f0544494d1b641&quot;
            alt=&quot;Pixel art animation of my fursona with a love expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;I packaged all the work I done up nicely in an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;videah&#x2F;kobo-tailscale&quot;&gt;install script&lt;&#x2F;a&gt; so it should be dead easy to get this working on your Libra 2 as well.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;love.gif?h=c6d357f0544494d1b641&quot;
            alt=&quot;Pixel art animation of my fursona with a love expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Tailscale has a built in &lt;a href=&quot;https:&#x2F;&#x2F;tailscale.com&#x2F;kb&#x2F;1106&#x2F;taildrop&quot;&gt;AirDrop-esque file transfer feature&lt;&#x2F;a&gt; that I find really useful for quickly sending PDFs to my e-reader that I don&#x27;t necessarily want to be a permanent part of my library.&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;taildrop.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        Sending a PDF remotely with one click with TailDrop.
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Unfortunately I couldn&#x27;t get Tailscale SSH working which was one of the main reasons I attempted this in the first place 😢 I&#x27;m not sure why but my first guess would be that I need iptable packet filtering but that would require swapping out the whole kernel which I don&#x27;t feel comfortable doing at the moment. Maybe some day though.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ssh&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#ssh&quot; aria-label=&quot;Anchor link for: ssh&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;SSH&lt;&#x2F;h2&gt;
&lt;p&gt;The Libra 2 only has telnet support out of the box behind a developer cheat code (typing devmodeon into the search bar) which is fine because I&#x27;d be using it over a Tailscale wireguard connection anyway. My threat model doesn&#x27;t exactly involve people bruteforcing telnet over public WiFi just to steal my furry books. But for completions sake I stuck the &lt;a href=&quot;https:&#x2F;&#x2F;matt.ucc.asn.au&#x2F;dropbear&#x2F;dropbear.html&quot;&gt;Dropbear SSH server&lt;&#x2F;a&gt; on mine and then disabled telnet.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;storage&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#storage&quot; aria-label=&quot;Anchor link for: storage&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Storage&lt;&#x2F;h2&gt;
&lt;p&gt;The Libra 2 has 32gb of internal storage which is pretty huge for books considering how small EPUBs usually are. But I like reading manga which can be pretty hefty. An average volume is 200mb, with stuff like Uzumaki coming in at 800mb. What if I need to store every uncompressed volume of One Piece for offline reading in the event of the apocalypse?&lt;&#x2F;p&gt;
&lt;p&gt;Most e-readers treat manga as secondary to books and rarely offer higher storage options or mini-SD card slots anymore. Thankfully the Libra 2 has a mini-SD slot... it&#x27;s just an internal one not meant to be user accessable 🫠&lt;&#x2F;p&gt;
&lt;figure &gt;
    
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;images&amp;#x2F;libra2_internals.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
    
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        Libra 2 internals, SD card highlighted in the red circle. &lt;br&gt; Image taken by &lt;a href=&quot;https:&#x2F;&#x2F;www.mobileread.com&#x2F;forums&#x2F;showthread.php?t=342428&quot;&gt;MobileRead user &#x27;supermighty&#x27;&lt;&#x2F;a&gt;
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;This is better than not being able to upgrade the storage at all though and was actually one of the main things that pushed me in the Libra 2&#x27;s direction when doing research. Someone on the MobileRead forums &lt;a href=&quot;https:&#x2F;&#x2F;www.mobileread.com&#x2F;forums&#x2F;showthread.php?t=348546&quot;&gt;replaced the SD card and posted instructions on how to do so.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I haven&#x27;t done this for mine yet but I plan on giving it a shot and sticking something utterly ridiculous like 512gb or 1tb in there. It seems like a pretty risky&#x2F;messy mod to do though, the slot and card are caked in waterproofing glue that you&#x27;ll need to reapply afterwards if you&#x27;re like me and enjoy reading in the bath.&lt;&#x2F;p&gt;
&lt;p&gt;Even if this seems excessive it does let me sleep easier at night knowing I can replace the internal storage in the event it somehow fries itself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dictionary&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#dictionary&quot; aria-label=&quot;Anchor link for: dictionary&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Dictionary&lt;&#x2F;h2&gt;
&lt;p&gt;This is a feature I didn&#x27;t know I wanted till I used it. It&#x27;s a pretty big leg-up over reading physical books when I can easily hold down on a word I&#x27;m not sure about.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m using the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;BoboTiG&#x2F;ebook-reader-dict&quot;&gt;ebook-reader-dict&lt;&#x2F;a&gt; project which is based on Wiktionary since that&#x27;s the one Plato recommends and is designed to work with. Unfortunately it&#x27;s a bit hit or miss. I&#x27;m not too happy about the quality of the definitions sometimes, I&#x27;ll probably look at alternatives at some point.&lt;&#x2F;p&gt;
&lt;div class=&quot;flex flex-col sm:flex-row items-center sm:items-start gap-2&quot;&gt;
    
    &lt;div class=&quot;hidden sm:block&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;normal.gif?h=ca53dc229a6c5551725c&quot;
            alt=&quot;Pixel art animation of my fursona with a normal expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
    

    &lt;!-- Speech box --&gt;
    &lt;div class=&quot;relative callout border-2 content-center p-2 md:p-4 rounded-md max-w-prose w-full&quot;&gt;
        &lt;!-- Triangle for desktop --&gt;
        
        &lt;div class=&quot;hidden sm:block absolute -left-3 top-4 w-0 h-0 border-y-[8px] border-y-transparent border-r-[12px] border-r-inherit&quot;&gt;&lt;&#x2F;div&gt;
        

        &lt;!-- Triangle for mobile --&gt;
        &lt;div class=&quot;block sm:hidden absolute left-1&#x2F;2 -bottom-3 -translate-x-1&#x2F;2 w-0 h-0 border-x-[8px] border-x-transparent border-t-[12px] border-t-inherit&quot;&gt;&lt;&#x2F;div&gt;

        &lt;div class=&quot;inline-block mx-2&quot;&gt;
            &lt;p&gt;Plato renders the definitions without any padding which looks a bit weird. I can probably fix this easily in the code later though. Feels good using open source software sometimes.&lt;&#x2F;p&gt;

        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;

    

    
    &lt;div class=&quot;block sm:hidden&quot;&gt;
        &lt;div class=&quot;flex-shrink-0 flex justify-center&quot;&gt;
    &lt;img
            class=&quot;max-h-[80px] max-w-[80px] p-2 sm:my-auto !mt-0 !mb-0&quot;
            src=&quot;https:&#x2F;&#x2F;old.blog.videah.net&#x2F;images&#x2F;animated&#x2F;normal.gif?h=ca53dc229a6c5551725c&quot;
            alt=&quot;Pixel art animation of my fursona with a normal expression.&quot;
    &#x2F;&gt;
&lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;&lt;h2 id=&quot;font&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#font&quot; aria-label=&quot;Anchor link for: font&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Font&lt;&#x2F;h2&gt;
&lt;p&gt;For reading, I use the font &lt;a href=&quot;https:&#x2F;&#x2F;brailleinstitute.org&#x2F;freefont&quot;&gt;Atkinson Hyperlegible&lt;&#x2F;a&gt; which you might know from &lt;a href=&quot;https:&#x2F;&#x2F;cohost.org&quot;&gt;Cohost&lt;&#x2F;a&gt;, but it&#x27;s also used by the very blog you&#x27;re looking at now! I&#x27;ve fallen in love with it as it&#x27;s really easy to read even when the text is very small. Very pretty and accessible.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Web Push Pitfall</title>
          <pubDate>Thu, 30 Mar 2023 00:00:00 +0000</pubDate>
          <author>videah</author>
          <link>https://old.blog.videah.net/web-push-pitfall/</link>
          <guid>https://old.blog.videah.net/web-push-pitfall/</guid>
          <description xml:base="https://old.blog.videah.net/web-push-pitfall/">&lt;p&gt;Whilst implementing Web Push notifications for my toy Q&amp;amp;A service &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;videah&#x2F;curiouswolf&quot;&gt;curiouswolf&lt;&#x2F;a&gt;
I ran into an issue that led to me being stumped for hours. I was successfully receiving notifications from my server
when using Chrome, but no matter what Safari was not playing ball.&lt;&#x2F;p&gt;
&lt;p&gt;Web Push requires the browser maintainers to run a notification endpoint. For example, when you use Google Chrome and you enable
notifications on a page, your &lt;em&gt;encrypted&lt;&#x2F;em&gt; notifications get funneled through a server Google controls. In the case of
Safari however, their endpoint was returning &lt;code&gt;BadJwtToken&lt;&#x2F;code&gt; for me despite it being considered valid by Google.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#the-solution&quot; aria-label=&quot;Anchor link for: the-solution&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;The Solution&lt;&#x2F;h2&gt;
&lt;p&gt;It turns out that Apple (and Mozilla apparently) require you to include a &lt;code&gt;sub&lt;&#x2F;code&gt; claim in your JWT with a
method of contact (such as an email) for them to consider it valid.&lt;&#x2F;p&gt;
&lt;p&gt;If you are providing an email, the &lt;code&gt;sub&lt;&#x2F;code&gt; claim should be prefixed with &lt;code&gt;mailto:&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;sub&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;mailto:admin@example.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#65737e;&quot;&gt;&#x2F;&#x2F; &amp;lt;-- The important part
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;aud&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;https:&#x2F;&#x2F;web.push.apple.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;exp&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1680135079&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The reasoning behind this is to provide the operator of the endpoint with a means of contacting you if there&#x27;s an issue.
However, this technically goes against the Web Push spec, and it&#x27;s frustrating that something like this isn&#x27;t spelled
out clearly in Apple or Mozilla&#x27;s technical documentation.&lt;&#x2F;p&gt;
&lt;figure &gt;
     &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;datatracker.ietf.org&amp;#x2F;doc&amp;#x2F;html&amp;#x2F;draft-thomson-webpush-vapid#section-2.1}&quot;&gt; 
        &lt;picture&gt;
            
            &lt;img decoding=&quot;async&quot; loading=&quot;lazy&quot; class=&quot;!mb-0&quot; src=&quot;rfc.png&quot;&#x2F;&gt;
        &lt;&#x2F;picture&gt;
     &lt;&#x2F;a&gt; 
    
    &lt;figcaption class=&quot;text-sm text-center&quot;&gt;
        Notice the emphasis on the word MAY
    &lt;&#x2F;figcaption&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Apple quite regularly leave important information out of their docs for web APIs like this, but it&#x27;s really messed
up that the only place Mozilla talk about this is in a &lt;a href=&quot;https:&#x2F;&#x2F;blog.mozilla.org&#x2F;services&#x2F;2016&#x2F;08&#x2F;23&#x2F;sending-vapid-identified-webpush-notifications-via-mozillas-push-service&#x2F;&quot;&gt;blog post from 2016.&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Howdy, Is This Thing On?</title>
          <pubDate>Mon, 14 Nov 2022 00:00:00 +0000</pubDate>
          <author>videah</author>
          <link>https://old.blog.videah.net/i-have-a-blog-now/</link>
          <guid>https://old.blog.videah.net/i-have-a-blog-now/</guid>
          <description xml:base="https://old.blog.videah.net/i-have-a-blog-now/">&lt;p&gt;Since things are uh... &lt;a href=&quot;https:&#x2F;&#x2F;www.theguardian.com&#x2F;technology&#x2F;2022&#x2F;nov&#x2F;12&#x2F;elon-musk-twitter-chaos-enleashed&quot;&gt;collapsing&lt;&#x2F;a&gt;?
I thought it&#x27;d be a good idea to finally get my blog up and running. Come in, get comfy and take a look around!
Cozy right?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;getting-started-again&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#getting-started-again&quot; aria-label=&quot;Anchor link for: getting-started-again&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Getting Started (Again)&lt;&#x2F;h3&gt;
&lt;p&gt;Ok admittedly, this is my 4th attempt at making a blog. This time I&#x27;m using &lt;a href=&quot;https:&#x2F;&#x2F;www.getzola.org&quot;&gt;Zola&lt;&#x2F;a&gt; which
is like &lt;a href=&quot;https:&#x2F;&#x2F;gohugo.io&quot;&gt;Hugo&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;jekyllrb.com&quot;&gt;Jekyll&lt;&#x2F;a&gt; but more Rust-y and less JavaScript-y. I can&#x27;t
make any comparisons beyond that because I haven&#x27;t used either, but my initial impressions of Zola are good! The theme
you&#x27;re looking at I made from scratch using &lt;a href=&quot;https:&#x2F;&#x2F;tailwindcss.com&quot;&gt;Tailwind&lt;&#x2F;a&gt; which is the only way I can do
frontend web stuff now.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to move away from what I had been using in the past (&lt;a href=&quot;https:&#x2F;&#x2F;ghost.org&quot;&gt;Ghost&lt;&#x2F;a&gt;) and have my blog sit in a
git repo in plain text instead. How I currently have things set up means when I push
any changes to the blog&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;videah&#x2F;blog&quot;&gt;GitHub&lt;&#x2F;a&gt; repo an action runner will automatically build my
site (in about 17ms!), compile &lt;a href=&quot;https:&#x2F;&#x2F;caddyserver.com&quot;&gt;Caddy&lt;&#x2F;a&gt;, embed the site into the binary
using &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mholt&#x2F;caddy-embed&quot;&gt;caddy-embed&lt;&#x2F;a&gt; (in... a lot more than 17ms!), then finally push it as an
image to DockerHub. My server will then see this new image, hot-swap it, and start serving my blog straight from memory!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;little-gremlin&quot;&gt;&lt;div class=&quot;absolute w-full h-full pointer-events-none&quot;&gt;
    &lt;a href=&quot;#little-gremlin&quot; aria-label=&quot;Anchor link for: little-gremlin&quot; class=&quot;pointer-events-auto&quot;&gt;
        &lt;svg xmlns=&quot;http:&#x2F;&#x2F;www.w3.org&#x2F;2000&#x2F;svg&quot; fill=&quot;none&quot; viewBox=&quot;0 0 24 24&quot; stroke-width=&quot;1.5&quot; stroke=&quot;currentColor&quot; class=&quot;!inline w-6 h-full ml-0 mr-0 md:-ml-10 md:mr-2 opacity-10 hover:opacity-100 transition hover:text-red-500 float-right md:float-left&quot;&gt;
            &lt;path stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; d=&quot;M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244&quot; &#x2F;&gt;
        &lt;&#x2F;svg&gt;
    &lt;&#x2F;a&gt;
&lt;&#x2F;div&gt;Little Gremlin&lt;&#x2F;h3&gt;
&lt;div class=&quot;child:!mt-0 hidden more-lg:inline&quot;&gt;
  &lt;p&gt;I hope you like my little &lt;a href=&quot;https:&#x2F;&#x2F;knowyourmeme.com&#x2F;memes&#x2F;rantsona&quot;&gt;rantsona&lt;&#x2F;a&gt; in the sidebar! He took the longest
to get working out of everything if you can believe it. I can disable him on a per-article basis, you don&#x27;t have to
worry about him 🤔-ing the more serious posts.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;&lt;div class=&quot;child:!mt-0 more-lg:hidden&quot;&gt;
  &lt;p&gt;You can&#x27;t see him unfortunately (try looking at this page on a larger screen) but I hope you like my little
&lt;a href=&quot;https:&#x2F;&#x2F;knowyourmeme.com&#x2F;memes&#x2F;rantsona&quot;&gt;rantsona&lt;&#x2F;a&gt; in the sidebar! He took the longest to get working out of
everything if you can believe it. I can disable him on a per-article basis, you don&#x27;t have to worry about him 🤔-ing
the more serious posts.&lt;&#x2F;p&gt;

&lt;&#x2F;div&gt;</description>
      </item>
    </channel>
</rss>
