I Don't Understand Docker Volumes

I really don't get Docker volumes over bind mounts.

Docker says they're easier to backup/migrate over bind mounts1, but I don't understand how rsyncing a single directory that contains everything is supposed to be harder than doing whatever this series of commands are in their documentation.

To me, Docker volumes make sense when you're dealing with temporary data, such as a cache. Or when you're needing to process data before making it permanent. Something like a /tmp.

docker compose down should remove volumes by default. I imagine Docker intends docker compose down -v as a full reset, but a single additional small (-v) flag is so easy to inadvertently lose data. Instead they should force the sysadmin to manually delete the data by specifying the volume name after an rm -rf. And by "volume name", I, of course, mean the bind mount.

docker compose down to remove all volumes. docker compose down --keep-temp-volumes to keep the (should be temporary) volumes.

Anyways. I use bind mounts. I prefer them over volumes. If volumes died tomorrow, I would feel nothing but elation.2


  1. "Volumes"

  2. This whole piece came about because I was dealing with a 1TB server that was low on disk space, and I figured I would try docker volume prune to see if it cleared anything up. Reader, even after I brought every container down via -v, I cleared out 700GB+. That shouldn't be possible!!!

Docker Login with Sonatype's Nexus

Sonatype's Nexus is an artifact repository for a variety of formats (e.g., Maven, npm, Nuget, etc.), but I use it primarily for Docker. I cache all the images that I use1 not only for speed but also to keep a copy that I can control the life of. Once it's set up, it usually enters into that "forget it" step. However for dumb-dumb reasons of my own doing, I needed to re-configure my install.

I ran into this last time, and I ran into it again this time. For a hot minute, I could not login to the repository from via docker login; I kept getting a 401 Unauthorized. From the last time I set it up, I remembered there was something completely unintuitive that I needed to do. I figured it out again, and it takes less than 30 seconds to fix. Why Sonatype doesn't set this up automatically when you add a Docker repo, I don't know.

Anyways, for both you and future!me:

You have to mark the Docker Bearer Token Realm as Active.

To do so,

  1. Login as an administrator.
  2. Click Settings, then expand the Security section. Click Realms.
  3. Click the ➕ next to "Docker Bearer Token Realm". It should move to the "Active" column.
  4. Click Save, then try to docker login again.

And that's it.


  1. Maybe not all the images, but everything from Dockerhub (including, and especially, the library), ghcr.io, and lscr.io.

🔗 Encyclopædia Britannica, 11th Edition →

The Age of the Encyclopedia began in 1751, with the first volume of the first edition of Denis Diderot's Encyclopedie, and ended in 1911, with the 11th edition of the Encyclopedia Britannica, shortly before the world went mad. An encyclopedia is a compilation of the world's knowledge; an encyclopedic age requires the twin beliefs that such a compilation is possible, and that it is worthwhile. By 1911 it was no longer quite possible, in truth, but the dream lived on. The advertisements for the 11th declared that it was "Everything Explained That Is Explainable." In any case, the firm conviction of the worth of such a project allayed any fears about its possibility.

Underlying these two beliefs, though not following them in strict logic, is the idea of progress, indeed of continuous progress. Compilation implies rational understanding, the purpose of which is to make further understanding, if not inevitable, at least possible. With further understanding we may expect further improvement of the human condition. The encyclopedic outlook is fundamentally Whig. However else Diderot's philosophes and the editors of the 11th might have differed, on this they were agreed. As J.B. Bury, a contributor, pointed out in The Idea of Progress, the very concept of continuous historical progress did not exist before the 18th century. After 1911, it could no longer be believed in.

Setting Up and Using Tuya Zigbee IR Remote (TS1201) in ZHA

With Home Assistant announcing that infrared is now "becoming a first-class citizen", this guide may become defunct quickly. I personally wouldn't mind that because this required more setup than I would've liked.

I've been doing home automation stuff since at least 2012, cutting my teeth with X10 devices. Home automation has come a long way since then, and I've been happily using a Home Assistant Yellow (RIP) since around September 2024. The Yellow supports Zigbee and Bluetooth out-of-the-box, and I was able to easily install a GPIO module to support Z-Wave devices as well. With networking being a prerequisite to access the device—and thus WiFi devices being supported—I'm able to support a fairly large ecosystem.1

One technology standard that's been missing, though, is infrared. With the purchase of a Tuya Zigbee IR Remote, I've now solved this. But since I wanted to do this within ZHA2, it took me more than a few minutes to set everything up. There are plenty of great guides for zigbee2mqtt, but nothing step-by-step for ZHA. So I'm writing this for both you and future me.

  1. Buy the device. My particular model is the TS1201. One of the aforelinked guides has a list of purchase options for AliExpress and Amazon US and NL. I paid a little over USD$30.
  2. Set up the device. The included manual suggests that it should come with two AAA batteries, but mine did not. After popping two in, you should see a subtle blue LED in one of the four corners on top of the device. To enter pairing mode, in the battery compartment press and hold the Reset button for ~5 seconds. That previously mentioned LED should now be blinking. Adopt the device into ZHA as normal.
  3. Learning codes. For each infrared device you want to control, you'll need to learn the codes being sent. You can use the Tuya blaster for this. However, if you go to the device details page, you'll see it's quite barren with nothing to indicate how you learn the codes.
    To learn them, click the three-dot menu beside the Reconfigure button on the left-hand pane. Then click Manage Zigbee Device.
    A new modal will appear with three top sections and will have Clusters selected by default. There'll be a dropdown menu and two more sections below it. From the dropdown, select "ZosungIRControl".3 Click the Commands subsection, then select IRLearn from the "Commands of the selected cluster" dropdown. In the "on_off" section, select "true".
    Then, with your infrared remote in one hand aimed at the blaster and your finger hovering over "Issue Zigbee Command", press the "Issue Zigbee Command" button then press the button on your remote.
    After doing so, you can navigate back to the attributes tab, select "last_learned_ir_code" from the "Attributes of the selected cluster" dropdown, then click "Read attribute". If all went well, you should have a base64-looking string in the Value box.
  4. Testing codes. You can now take that string, click back to the Commands tab, select "IRSend" from the dropdown, and paste the code into the "code" box. (You can ignore the "Manufacturer code override" box.) If all went well, your transmitter will send out the infrared command and your device should have done whatever you told it to! 4

But now that you have the codes, how do you use them in Home Assistant?

The easiest way I've found is to set up a template script and use that everywhere. I stole and parameterized this script from a GitHub comment on an issue request to have this device's ZHA quirk added:

alias: Send Infrared Signal
sequence:
  - data:
      cluster_type: in
      endpoint_id: 1
      command: 2
      command_type: server
      params:
        code: "{{ infrared_code }}"
      cluster_id: 57348
      ieee: >-
        {{ device_attr(infrared_blaster_device, 'identifiers') |
        selectattr(0,'eq','zha') | map(attribute=1) | first }}
    action: zha.issue_zigbee_cluster_command
mode: single
icon: mdi:remote
description: ""
fields:
  infrared_blaster_device:
    selector:
      device: null
    name: Infrared Blaster Device
    required: true
  infrared_code:
    selector:
      text: null
    required: true
    name: Infrared Code
    description: The base64 string to send to blaster

It creates a UI that looks like this:

However, I will rarely call that script directly; instead, I create other scripts that call it. Think of it as an abstract class being used in other concrete classes. For example, here's a script that uses that base script and turns some candle lights on:

sequence:
  - action: script.candles_on
    metadata: {}
    data:
      infrared_blaster_device: cca75c2d831612b6897906fcdf7bf5e3
      infrared_code: >-
        B2IjlRFaAhoC4AEDA3MGWgLgAw9AC0ATwAPgAw8AGiABQBcBGgLgCwNAAYAXQCPgEwMHIaBiI6YIWgI=
alias: "Candles: On"
description: Turn the candles on
icon: mdi:candle

If I ever need to correct a code or change the transmitter device, I can do it one place instead of (possibly) dozens of automations and dashboards, etc.

And now, I can control infrared devices in my smart home. All just in time for this to all be replaced with ESP32 blasters and, I'm sure, a more intuitive UI for learning codes. 🥲


  1. Though as a general rule, I don't allow Internet-connected devices in my home automation network if I can help it. I'd rather use something local, like Zigbee or Z-Wave. Heck, even Bluetooth for that matter.

  2. I know, I know. Literally everyone says to use zigbee2mqtt and for all very good reasons. But ZHA has supported everything I've needed so far, so I have no real reason that justifies all the hassle of switching over.

  3. There's also ZosungIRTransmit, but I have clue what that does; it wasn't used at all in my setup and subsequent use.

  4. In practice, I had to repeat Step 3 several times to make sure I had an accurate code. In my testing, it would sometimes pick up a different string than the one I should have gotten even though I was pressing the same button on the remote each time. I found having a virtual scratchpad handy where you can keep track of all of the codes it puts out quite helpful. It shouldn't take more than five minutes of doing an IRLearn and reading the attribute before a single string repeats itself often enough for you to feel confident that you have the right code. And you can always do an IRSend for reassurance.

🔗 Hank Green on the Humanity behind the Artemis II Photos →

It's kind of wonderful to me that the Earthrise photo was a bit of a mistake. And they had to scramble to get that color film into the camera. And, at the same time, the fact that we got to see this perfect eclipse from space, this sci-fi view of something that we've never seen anything like before. Also, was not, like- we didn't plan the mission to be able to take that photo or anything; that's just a thing we got lucky enough to get. But in all of these cases, I think it's really important to remember that photographs are art, that part of why the pictures are better from these things than they are when we send probes is because people make these decisions.

Bill Anders yelling to get that color film out. The Artemis crew trying to figure out a way to get Venus in that dark shot with the moon. Which is why some of my favorite pictures are the ones that include the interior of the spacecraft that show the juxtaposition between the foreground of the interior of the capsule, this thing that is made by humans, that is very small, just a submarine out in the ocean of everything. And then through that window, taking up much less space, the little ball where everything is from.

That's what you get when people are making decisions.