Don't get cheap $20 soldering irons for occasional soldering. I tried to use one to put together a beginner-appropriate kit and it took literally 120 seconds to heat up one lead of a small (through-hole) capacitor.

Upgrading OpenWRT 19.07.x to 21.02.x on a Linksys WRT3200ACM, plus Unbound DNSSEC configuration

I use OpenWRT wifi router firmware for my Linksys WRT3200ACM gigabit wifi router. OpenWRT released 21.07 just a few months ago, and I finally upgraded my installation.

Upgrading from 19.07.x to 21.02.x is a little less straightforward than I expected. 

  • You cannot retain configurations from your 19.07.x installation
  • You must force the firmware upgrade to go ahead
  • You must manually enable radios
  • You can only use WPA2-PSK for wifi security. Using WPA3 (only) or mixed WPA3/WPA2 will cause wifi to fail, though wired connectivity should continue working.

One last note before you begin: you perform all the upgrade tasks via a wired connection.

You should use the sysupgrade image. Download from the device page on the OpenWRT wiki. The filename is openwrt-21.02.1-mvebu-cortexa9-linksys_wrt3200acm-squashfs-sysupgrade.bin

Upon trying to apply the upgrade in Luci (OpenWRT’s web UI), you will see a warning/error message:

Device linksys,rango not supported by this image Supported devices: linksys,wrt3200acm armada-385-linksys-rango linksys,rango - Image version mismatch: image 1.1, device 1.0. Please wipe config during upgrade (force required) or reinstall. Reason: Config cannot be migrated from swconfig to DSA Image check failed. The uploaded image file does not contain a supported format. Make sure that you choose the generic image format for your platform.

You should look at one of your old backups for reference of how you configured OpenWRT as the configs cannot be retained in the upgrade from 19.07.x to 21.02.x. So, uncheck the “keep settings and retain current configuration” option, and go ahead with applying the upgrade.

After flashing the upgrade firmware, you will be able to continue with setup of what is effectively a fresh router. First thing to do is to set a root password. Then, once you set the router’s hostname, e.g. mywifi, you should be able to login using https://mywifi.lan/ 

One of the improvements in 21.02.x is that the default installation supports HTTPS off the bat, unlike 19.07.x where additional SSL packages had to be installed manually. To redirect http to https so all web connections are encrypted, follow the documented instructions. Do the following in an SSH session on the router:

uci set uhttpd.main.redirect_https=1 # 1 to enable redirect, 0 to disable redirect
uci commit uhttpd
service uhttpd reload

Next, you need to enable the radios. The WRT3200ACM has 3 radios:

  1. radio0 - Marvell 88W8964 802.11nac - enable this
  2. radio1 - Marvell 88W8964 802.11bgn - enable this
  3. radio2 - Marvell 88W8887 802.11nac - leave this disabled

This post and comment by u/BirbDoryx at Reddit explain what these are:

u/BirbDoryx - Wifi antennas are used the following way:

  • 88W8964 802.11nac -> main 5GHz n/ac
  • 88W8964 802.11bgn -> main 2.4Ghz n (legacy g)
  • 88W8887 802.11bgnac -> hidden by default, you shouldn't even see it in settings. It is used as radar interference detector for DFS 5GHz channels. Used as normal wifi connection is unstable, and this is why in the most updated mwlwifi driver it is hidden.

These next 2 settings are accessible by clicking the “Edit” button on the listing for the wlan. For both enabled wlan interfaces, select WPA2-PSK for their Wireless Security setting. I found that using WPA3-SAE, either by itself or in mixed mode with WPA2-PSK would cause wifi to malfunction after just a few minutes. I have been running on WPA2-PSK with no issues for a few days, now. You can also set the Country Code in Device Configuration → Advanced Settings.

You can leave the channel selection for both wlans to “auto” which should scan for wireless access points and pick the least crowded channel. Or you can look at Status → Channel Analysis to manually pick a channel.

One new thing I enabled is the use of Unbound secure DNS. This provides a new tab Services → Recursive DNS. This also allows for the use of DNS over TLS (DoT), which encrypts DNS queries. Setup instructions for using DoT with Unbound are in the documentation. You will probably also need to replace dnsmasq with odhcpd, which is what I did. One you remove dnsmasq, the Network → DCHP and DNS configuration page in LUCI becomes disabled (empty).

For DHCP setup, I had to change some settings so that the local domain (.lan) is still known so that I can use https://mywifi.lan to connect to LUCI rather that specifying the IP address.

Screen Shot 2022-02-13 at 17.44.29

Further, you can use CloudFlare’s public DNS servers for better response. I set this as “enabled” and use Google as fallback. I also clicked the “Up” button on to put it higher in the list.

Screen Shot 2022-02-13 at 17.21.16

Finally, you will need to test the DNSSEC setup. To do so, on OpenWRT install the bind-dig package, which provides the “dig” utility. Then, following the instructions here, on the router command line run these two commands: the first should return an A record, while the second should return SERVFAIL.

root@mywifi# dig @

; <<>> DiG 9.18.0 <<>> @
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41914
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
; EDNS: version: 0, flags:; udp: 1232
; IN A
;; Query time: 199 msec
;; WHEN: Sun Feb 13 22:10:52 UTC 2022
;; MSG SIZE  rcvd: 71

root@mywifi# dig @

; <<>> DiG 9.18.0 <<>> @
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 7543
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
; EDNS: version: 0, flags:; udp: 1232
; IN A
;; Query time: 389 msec
;; WHEN: Sun Feb 13 22:11:02 UTC 2022
;; MSG SIZE  rcvd: 57
Then, to test your PC, you will need to first flush your DNS cache. On macOS Catalina 10.15.7, the command is: sudo killall -HUP mDNSResponder Once that is done, visit this the test webpage and click the “Start test” button. It may take a few seconds. I found that Firefox returned a result quickest, followed by Chrome. Safari returned a result the first time I tried it, but on subsequent visits (even after clearing browser cache), the test would run and not complete.
Much more information about using Unbound as a DNS resolver for your home network is given in the Unbound documentation. The example they give is using a Raspberry Pi to run the resolver; in our case, we use our wifi router.

UPDATE 2022-02-21: Running the OpenConnect (ocserv) VPN service seems to randomly cause 5GHz wifi to fail. Nothing definitive, but once I removed ocserv and related packages, none of the wifi clients would randomly drop connection.

macOS Quick Action - Convert HEIC to JPG in place

This Automator action combines converts an HEIC image file to a JPG image file in the same folder as the original HEIC. It combines this Automator action with this tip.

  1. Receive image files in any application
  2. Duplicate Finder Item
  3. Change Types of Image to JPEG
  4. Rename Finder Items: Replace Text “ copy” (note the single space at the start) with nothing.

Screen Shot 2021-10-23 at 4.25.19 PM

Converting an EOL Chromebook to Linux (GalliumOS or Xubuntu)

I have a Toshiba Chromebook 2 (2015) GANDOF that has just reached its end of life (EOL): Google will no longer provide ChromeOS updates to it. Since all I really need for the device to be useful is a terminal to run SSH, and a web browser that can play YouTube and maybe Netflix videos, and Zoom, I decided to convert the Chromebook to a “normal” laptop running a lightweight Linux distro called GalliumOS. It’s a perfectly fine cheap laptop: it has an Intel Broadwell Core i3-5015U 2-core CPU, and 4 GB RAM. The times I have used it for Zoom, it has been useable.

The primary source for all this is and GalliumOS.

Materials needed: two USB drives, one 16 GB for ChromeOS, and the other at least 4 GB for GalliumOS. Please see the embedded Flickr album for pictures of the process, including how to disable write-protect.


  1. Create a ChromeOS recovery USB drive. This will also tell you the Chromebook hardware ID.
  2. Check for GalliumOS compatibility based on the hardware ID. Decide if you want to proceed.
  3. Create bootable/live USB drive for GalliumOS.
  4. Update SSD from the original 16 GB to 256 GB. 
  5. Reinstall ChromeOS.
  6. If recommended, get new firmware matching your Chromebook hardware. (Or just leave the old firmware alone.)
Step 1: You will need a 16 GB USB drive to create a ChromeOS recovery drive. (It should be possible to use an SD card, but I get the impression that is more prone to bugs.) Follow instructions here. In the Chromebook, install the Chromebook Recovery Utility (Chrome Extension). Once installed, the icon for the utility should show up in the extensions menu of the Chromebook browser. Click on it to run: it will guide you through the steps needed. It will also tell you the device ID in the “Identify Your Chromebook” step. Make a note of the device ID. For my Chromebook, it was GANDOF XXX-XXX-XXX-XXX where the X’s were some random-looking characters.
Step 2: The non-random part of that device ID, GANDOF in my case, identifies the hardware type. Look it up in the GalliumOS compatibility table.
Step 3: Download a GalliumOS ISO file appropriate for your device, and create a bootable/live USB drive. I had trouble with Balena Etcher, though that’s never happened in the past. (I did this on macOS; instructions will be different for Windows or Linux.) The direct method of copying the ISO file to the raw device under macOS worked for me. To determine which disk device corresponds to the USB drive, do “diskutil list > disks.txt”. Then, plug in the drive (it does not have to be readable by macOS), and do “diskutil list > disks2.txt”. Compare the files disks.txt and disks2.txt. You should find one entry like /dev/diskNN for the USB drive. Look at the listed size as a check. Then, cd to the directory containing the GalliumOS ISO file, and do:
sudo cp -X ./galliumos-3.1-broadwell.iso /dev/rdiskNN
NOTE: The destination is /dev/rdiskNN -- the “r” is very important.
Step 4: Replace the original 16 GB SSD with a 256 GB (or other size) SSD. The GANDOF has a SATA M.2 2242 SSD, so this replacement from Transcend worked great.
Step 5: While the Chromebook is opened up, remove the write-protect screw and jumper.
Step 6: Close it up, the power the device back on. It should complain about not being able to boot, and prompt for a recovery USB disk. Insert the ChromeOS recovery disk you created earlier, and follow the prompts.
Step 7: Prep the device for GalliumOS install: enable developer mode, and optionally update device firmware to a UEFI-capable firmware. If unable to sudo, do it as root: Hit Ctrl-Alt-ForwardArrow (not the normal cursor right arrow), and you will get the console as root. N.B. if something goes wrong, this may brick the device, though it can be recoverable by re-flashing the old firmware with an EEPROM writer. (I did update the firmware with no trouble.) After the firmware has been updated, toggle power, and plug in the GalliumOS installer USB drive when prompted.
Step 8: I followed the “Traditional ISO Install” instructions. Launch the GalliumOS installer application from the desktop, and follow the prompts. You can even set up an encrypted drive so the data is secure even if you lose your device. I was even able to run GIMP for simple image editing.


The only hiccup is if you want to install software that is distributed for Ubuntu, and which may rely on Ubuntu-specific packages. In that case, Xubuntu could be used instead of GalliumOS: it’s an Ubuntu distro that uses the lightweight XFCE desktop environment that is also used by GalliumOS.


Chromebook disable write-protect and install Linux

Update: I just updated to Xubuntu 21.04 using ZFS. One issue: the special Chromebook keys (screen brightness, volume control) will have to be manually re-mapped: they are not recognized by default.
UPDATE 2021-10-23 Well, after a few days of living with XFCE, I decided to ditch it. XFCE does not seem to have been designed with trackpads in mind: the handles to resize windows seem to be 1 pixel wide, so it was impossible to resize windows using the trackpad. I converted to standard Ubuntu, which then updated itself to 21.10 Impish Indri, and it works decently well. Will have to wait to see how it handles a Zoom call. The camera, speakers, and microphones seem to work fine without any tweaking. I did apply some tweaks to change the function keys to Chromebook-like control keys (volume, brightness, etc.) using the keymap file from fascinatingcaptain. (I did not apply any of the other tweaks from there.)

New bicycle - Priority Continuum Onyx

I have the dubious distinction of being an essential worker, due to being an IT person. Anyway, once work allowed essential workers back on site in April, I started cycling to avoid public transit. The bike is an 8-year old steel-frame Windsor Kensington from 8-speed Shimano Nexus internal gear hub, set up for “utility” cycling around town. I upgraded the brakes to Tektro R559 with FL750 levers, to retain a vintage-ish look; along with it, the brake cables were upgraded to Jagwyre Road Elite Sealed. That was a huge improvement: no more sponginess, and I could actually stop in the rain (with the normal precautions). I also upgraded the shifter cable to Jagwyre Road Elite Sealed: see this old post. And upgraded the rack, too, since the original one worked loose, and I wasn't too satisfied with its sturdiness. Not to mention the Pletscher Twin center kickstand, which was one of the first changes I made.


Anyway, my commute is only 4 miles. But I was still noticing the bike was pretty heavy. Fortunately, I can store it on the ground floor, currently, so I don’t have to schlep it up two floors to my apartment. And there were other minor annoyances, like a cheap steel chainring which rusted (it had been painted), some unexplained rattling in the Nexus hub (which did resolve itself after a couple of weeks of normal riding). 

More importantly, I had an idea of my ideal commuter bike. But pricing the parts put it way over my budget, not to mention my skill set in building a bike. Pre-built ones were also pretty pricy. I wanted an internal gear hub (without needing a massive gear range), belt drive, hydraulic disc brakes, and maybe a dynamo hub wheel.

Finally, after some months of cursory browsing, I found the Priority Continuum Onyx. It checked all the boxes, plus it added an aluminum frame, and a Nuvinci Enviolo (manual) continuously variable internal “gear” hub. Reviews from regular bike commuters on YouTube and in Reddit were favorable: these were people who put many more miles per day on their bikes, and rode in much rougher weather than I would. All those factors fell in place at the right time, and I bought one. I paid the nice people at Firth & Wilson Transport Cycles to assemble it for me.

The first thing I switched out was the seat/saddle: put in a Fabric Cell Radius Elite.


I took it for a 6-mile ride, and it’s pretty nice. Light compared to the old bike. Larger gear range: much faster on the high end. No sticking on the low end, which is an issue on my Shimano Nexus. Brakes are decent: honestly they did not feel much better than the Tektro rim brakes on my old bike. I expect they will be much better in wet weather. The ones on the Priority are low-end Tektro hydraulic disc brakes. It felt pretty nimble, and lively. The belt drive was very quiet. The Nuvinci continuously variable hub was nice: shift while stopped, find the “in-between gear ratios”. 

Of course, I have some gripes: the flat-straight handlebars are pretty uncomfortable for me. I find myself pitched further forward than I like, and the grips don’t sit in my palms well: my hands were tingling even after the 20-minute ride. The grips are not very comfortable, either: they are pretty hard, and just felt like two hard slightly tacky cylinders in my hands.

The Fabric Cell saddle was kind of disappointing: it was a lot harsher than I expected, despite the reviews I read or watched. (I think those were comparing against normal road racing saddles.) I’ll give it some more time, and maybe re-adjust the positioning.

Future upgrades: I definitely need a rear rack. Topeak make the same rack I have on my old bike, but which accomodates disc brakes. I use the bike for shopping errands, and picking up or dropping off packages. Definitely need more comfortable handlebars, something with a bit of a sweep back. Almost definitely more comfortable grips. Maybe a QuadLock mount for my phone.

Hackintosh USB mapping - attempt to fix broken Bluetooth

UPDATE 2: My attempts at “fixing” USB mapping broke all the USB 3.x ports. None of the USB 3.x ports work. I did set them to “Type 3” which is “USB 3 Standard-A connector”. Undoing all the USB mapping stuff fixed my non-functioning USB ports. Everything works OK, including Bluetooth. No idea why: everything about OpenCore is still kind of a mystery to me.

UPDATE: Bluetooth fixed itself. What I did: booted into Windows (installed on a separate SSD), used Windows to connect to the speaker, quit Windows to boot into Hackintosh, and Bluetooth works again. Quick way to see that Bluetooth is OK is that System Information on the Bluetooth device should show a non-trivial address. If it were broken, the address would be 00-00-00-00-00-00.

Screen_Shot_2020-07-12_at_10_38_26_PM edited

tl;dr This did NOT fix my Bluetooth issue. I had also cleared the CMOS and re-set all the BIOS settings before I went through all of this. So, this may be of some use as a summary of USB port mapping in OpenCore, but of no use at all for fixing Bluetooth issues.

Bluetooth stopped working for unknown reasons. Discovered that Bluetooth is actually an internal USB device.

Suspicion: the breakage is due to the macOS 15 USB port limit. (Additional USB hubs get their own 15-port limit.)

Follow instructions:


Using the USBMap script, can see that there are 26 ports listed: HS01 - HS14, USR1 - USR2, SS01 - SS10. (This is the same as the list that corpnewt has on their system.)

The script allows you to disable all SSxx ports and all HSxx ports. Then, manually enable a specific set of HSxx ports. From this post at tonymacx86, someone has listed the USB ports for this motherboard: back panel, and internal headers. I have verified this is correct, for the ports that I can use. I have no USB Type-C devices, so I cannot check the two USB Type-C ports on the rear panel.

Designare Rear IO Layer v3_resize
Designare Rear IO Layer v3_resize

The case I am using has no front-panel USB Type-C ports, so I can leave HS01 disabled. I do not currently have any USB 3.1 Gen 2 Type C devices, but I am planning to get at least one: I will enable both HS08 and HS13. I will leave the internal Bluetooth (HS14) enabled. There is no HS02 shown in either diagram, and none of the ports I could test were HS02: so, disable that. There was no USR1, either, but the USBMap documentation does not say anything about enabling or disabling USR* ports, so leave that enabled.


  • Two disabled HS ports: HS01 and HS02

That leaves me with 12 HS ports, and 2 USR ports, bringing me up to 14 ports.

The boot-args option is:

debug=0x100 keepsyms=1 alcid=1 agdpmod=pikera -uia_exclude_ss -uia_exclude_hs uia_include=HS03,HS04,HS05,HS06,HS07,HS08,HS09,HS10,HS11,HS12,HS13,HS14,USR1,USR2

Back at the main menu of USBMap, pick “S. Build SSDT-UIAC”, which will generate two .aml files:

  • SSDT-UIAC.aml
  • SSDT-USBX.aml

Copy those to your EFI/OC/ACPI folder, edit your config.plist to add them to the ACPI section, and reboot.


  1. Disable all ports named “SS* - using USBMap script, select “S. Exclude SSxx Ports. This appends the boot option -uia_exclude_ss to NVRAM which will persist across reboots. NB this does not modify config.plist. In OpenCore 0.5.9, this step did not work for me. So, manually modify config.plist to add the boot option (NVRAM->Add->...long string of chars->boot-args). Manually trying to set boot-args using the nvram command gives an error: “nvram: Error setting variable - 'boot-args': (iokit/common) not permitted”. So, set it in config.plist, instead.
  2. Download SSDT-USBX.aml from USB-Map-Guide/extra-files
  3. Use SSDTTime to generate SSDT-EC.aml. (Had SSDT-PLUG.aml from initial install.)
  4. Copy the .aml files into EFI/OC/ACPI/
  5. Add entries for both SSDT-USBX.aml and SSDT-EC.aml into config.plist

Hackintosh update - WiFi card added

I wanted to have Handoff on my Hackintosh. That requires WiFi.

The built-in WiFi on the Gigabyte Z390 Designare motherboard does not work with macOS. But Dortania, the people who work on OpenCore, have a list of recommended WiFi devices. I got an ASUS PCE-AC68 AC1900 Dual-Band Wireless PCI-E Adapter. And it just worked. I did not have to add more kexts or munge my config.plist.

Another point for OpenCore.

However, Handoff does not work. It seems like I need a Bluetooth adapter with a particular chipset. The ones that are pretty certain to work are ripped out of actual Macs: they use the Broadcom BCM94360CS2 or BCM94360CS (one person had better luck with this) chipset, and combine WiFi with Bluetooth. There are also generic adapters: search eBay for that product string. These are M.2 form factor. Since I wanted the second M.2 slot on my motherboard for a Windows installation, I could not go this route.

Migrating from Aperture to Lightroom Classic

I built a new Hackintosh, and am now running macOS Catalina (10.15). Since Catalina only runs 64-bit applications, I am finally forced to migrate all my photos from Aperture to Lightroom Classic. 

tl;dr Make Aperture store its masters as “referenced”. Split the library into smaller ones, no more than about 10,000 masters per library. (A 27,000-master library took > 24 hours to import.) Import into Lightroom, keeping Aperture masters in place, and copying Aperture-edited previews into the masters’ location to allow automatic stacking. 

The Aperture import plug-in that comes with Lightroom Classic is not great. If you have a very large library, it can get very slow. No one who has very large libraries seems to have waited. My library is about 700 GB, with about 560 projects and 81,500 images. I kept the library “managed” i.e. Aperture copied everything into its library package. I tried to import the full Aperture library into Lightroom Classic. After 5 full days (24 hours per day) of running, the import into Lightroom seemed to stall at 50%. From the start of the process, every additional percentage point seem to take longer and longer. (Felt like an N² algorithm or worse.) Others have had the same experience (Adobe support community forum post).

Without resorting to a manual import (aka “the Old Method”), as the person who posted that issue in the Adobe forum did, I figured I would try the latest suggestion posted there, i.e. to break up the single original library into multiple smaller libraries. That seems to be working pretty well. 

To export in Aperture: File ▶ Export ▶ Items as New Library… Then, in the options: 

For this to work, your Aperture masters folder must have the same absolute path on the old computer and the new computer. My old computer’s Aperture masters (originals) folder was at: /Volumes/Homes/Users/myname/Pictures/Masters
On my new computer, I needed to make sure that my home folder was on a separate volume, such that it ended up with the same absolute path /Volumes/Homes/Users/myname/Pictures/Masters. I had tried one iteration, where my new home folder was in a slightly different location /Volumes/Homes/myname and that did not work because Lightroom Classic complained that the folder /Volumes/Homes/Users/myname/Pictures/Masters was missing. It is not the fault of Lightroom Classic, since the absolute paths are encoded in the exported Aperture libraries.
You also want to make sure the previews are copied into the exported library. Otherwise, Lightroom Classic would not have access to those (edited) previews.
To import into Lightroom Classic: File ▶ Plug-in Extras ▶ Import from Aperture Library…. There is an Aperture Import Info… menu selection which gives some info about the import process. A window will pop up, showing four sections.
The first section is “Previews from Aperture”. There is only one option, “For images which have been adjusted in Aperture, import full size previews from the Aperture library (if they are available and up-to-date)”: check that ON.
The last one, is “Files referenced in Aperture”. Here, check ON “Leave referenced files in your Aperture library in their current location”. If you have checked on “import previews”, a second option should be available: “For referenced images left in their original location, place version previews in the same folder as the master image to allow for automatic stacking”. Check this ON, too.
In short: import previews ON, leave referenced files in current location ON, place version previews in same folder as masters ON. Really, ALL options are checked ON.
Screen Shot 2020-07-04 at 5.29.38 PM
Click “OK”. As a check, you should see that the “Disk space required” value should be small, indicating no additional space for the masters will be used. It should just be the additional space to accomodate the previews.
It will return you to the first window, where you can click “Import” to start the import. How long it takes seems to depend on the number of images in the library. I didn’t time any of the imports, but a few thousand masters with maybe a thousand previews took maybe 2 or 3 hours. Certainly not the multiple days that a naïve import took.

Setting user home directory in macOS via command line

My old Hackintosh was messed up: it mounted the separate drive holding the Home directories in "/Volumes/Homes 1" rather than "/Volumes/Homes". That meant I could not login normally.

But, I was still able to login via ssh. Since macOS is a Unix-ish system, it just drops you in the root directory. From there, do the following:

    sudo dscl . -change /Users/username NFSHomeDirectory old-path new-path

Replace username, old-path, and new-path with appropriate values.

Credit to this answer at Stack Overflow. Like any *nix, there is a man page.

Migrating from Aperture to Lightroom Classic drops non-destructive adjustments layer

Well, this sucks: according to Apple, migrating Aperture RAW files to Lightroom Classic does NOT migrate the non-destructive adjustment layer. Which means my 650 GB or so of photos are the unedited versions. 

The old Hackintosh is dead. So, I can’t go in and re-export edited JPGs. But even if I could, I wouldn’t do that: who’s got the time?