Linux spinning drive failure

My backup disk on my Linux box failed.

[    6.006233] kernel: sd 1:0:0:0: [sdb] tag#26 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
[    6.006302] kernel: sd 1:0:0:0: [sdb] tag#26 Sense Key : Medium Error [current]
[    6.006358] kernel: sd 1:0:0:0: [sdb] tag#26 Add. Sense: Unrecovered read error - auto reallocate failed
[    6.006428] kernel: sd 1:0:0:0: [sdb] tag#26 CDB: Read(10) 28 00 00 00 0b b8 00 00 08 00
[    6.006496] kernel: blk_update_request: I/O error, dev sdb, sector 3000 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[    6.006568] kernel: Buffer I/O error on dev sdb1, logical block 119, async page read

That’s read errors, I think during fsck. I think it can’t read anything at all; badblocks just returns a list of integers from 1 to whenever I hit Ctrl-C. Higher level tools complain they can’t find a superblock, so that’s bad. Fortunately it’s just a backup volume so I don’t need to read the data off of it.

It’s a 2TB Western Digital Drive I bought back in 2015, six+ years is not too bad. (Confused it shows only 31313 hours = 3.5 years of power on time). I didn’t notice it failing; the errors from the backup script were going to root mail which I never read. Also I don’t have proper SMART alerting. Oops.

I’m replacing it with a WD Red Plus drive, 4TB. Spinning drives are basically a dead end product category. Except for server storage, so now there’s a lot of marketing around these “NAS drives”. The Seagate Ironwolf brand also gets recommended for NAS storage but Seagate drives tend to be noisier so I stuck with WD.

In theory drives will map around a few bad blocks but Linux has a long-standing thing where this process doesn’t (always?) happen automatically and I’ve never found a good tool to force it. There’s some instructions in a FAQ somewhere for an elaborate procedure of mapping that “logical block” to a physical sector on the disk and forcing a write to the sector, which causes a remap. But it’s scary. Meanwhile you already know the disc is beginning to fail; is it really worth trying to recover it? If you need the data ddrescue is probably the safer bet.

vs.code: playing well with others

I very much like my idiosyncratic coding setup with proportional fonts and automatic code formatting in VS.Code. But it doesn’t play well with others. Every time I save a file it completely reformats it in my preferred way. Not popular at pull request parties.

Making per-workspace settings that are more collaboration friendly is very easy thanks to VS.Code’s flexible settings. It basically boils down to creating a .vscode/settings.json file in the project workspace with a few settings to override the weird ones I have. By far the most important is “format on save”; the others just make my display fixed width like most people’s so I see what they’re seeing. Here’s the overrides I have in my workspace settings:

{
        "editor.fontFamily": "Consolas",
        "editor.letterSpacing": 0.0,
        "editor.tabSize": 4,
        "editor.formatOnSave": false,
}

WSL copy/paste clipboard

Useful command line pipeline tools for WSL, similar to MacOS pbcopy and pbpaste.

To paste the contents of the Windows clipboard into a WSL shell pipeline

powershell.exe Get-Clipboard | wc

To put the outputs of a command into the clipboard

echo foo | clip.exe

That’s the basic version. There’s a nicer version described here or packaged here suitable for installing. It uses sed to strip the DOS newlines and extra newline out of the clipboard content. Also uses tee in front of clip.exe, I think so that it will echo the output back to stdout as well.

Pretty clumsy having to invoke this code! But I believe WSL 2 has no API for accessing the Windows clipboard. It’d be simple enough to imagine in WSL 1’s emulator, but since WSL 2 is more of a VM approach it’d be more work. And then it’d be some weird WSL system call no other Linux understood, anyway. Although… WSL-G must have clipboard support, I wonder if there’s an alternate approach.

My custom solar monitoring system (PVS6)

I’ve been tinkering with monitoring my solar system and have come to a fairly nice useful setup. Time for a post documenting where I am. The details on how I did all this are in previous blog posts but I’m summarizing here. Some code in this gist.

The Display

Daily view

The daily view is focused on giving me a basic picture of my electricity usage. Green is production for the day, black is the PVS6 measurement of net (ie: production – consumption). Yellow is PG&E’s own view of net. I suspect PG&E’s data may be more correct; I’m not sure if the PVS6 CT sensors measure reactive loads correctly. Doesn’t much matter anyway; PG&E is the authority whether they are right or wrong. Mostly I just care that they are close. (Jan 7 is a data measurement anomaly.)

Minute-by-minute view

This view gives a lot of detail minute by minute. The top panel is a detailed view of production and consumption, what is a single bar in the daily graph. The second graph compares production to a forecast. Below that are details of individual panel production. The individual sparklines towards the bottom are fun; the panel in the upper left goes to 0 in the morning in the shadow of the chimney on my roof. At the bottom is a simple sparkline of lifetime net production, I had a little party when it passed 1MWh.

Implementation

The data import code is all in this gist. The Grafana panels are not shared anywhere, sorry.

Here’s all the places I’m pulling data.

  • PVS6: the Sunpower solar monitoring system
  • PG&E: manual downloads via their “Big Green Button”
  • Predictions: forecast.solar

The whole system is built with Telegraf collecting the data into an Influx database and a Grafana dashboard to visualize it. What a great set of tools those are! A real pleasure to learn and work with.

The PVS6 stuff is the bulk of it. Turns out Sunpower has a JSON endpoint on a web server in your PVS6 and folks have worked out how to interpret the data. It’s pretty hacky; I’m using a Raspberry Pi to proxy the data onto the rest of the network. I’ve written a ~200 line Python script to collect the JSON data from the PVS6 every minute and emit it in Influx wire format for import. It also does a little analysis within the minute’s dataset to facilitate easier graphing.

The PG&E import is a very simple bit of Python code that converts PG&E’s data into Influx. I have to do this download by hand in the website right now. They do have an API but it requires some sort of signup I haven’t tried to do yet. I should add that PG&E’s Big Green Button CSV export is really quite good. The CSV data is clean and simple. And they have history! I was able to get 9 years of this house’s electricity usage. Nicely done.

The forecast.solar import is also very simple. They have a easy-to-use API where you tell them your location and the size and orientation of your solar system. Then they give predictions for power generated, including weather-corrected. The free version of the API is fine for this use; I download a new prediction every six hours.

Next steps

I plan to keep tinkering with the data display. I suspect as time goes on I’ll be more interested in the daily summaries than the per minute view, so I’ll probably pay more attention to that.

It’d be nice to automate the PG&E data download.

I’ve had some thought about packaging this all up as a Raspberry Pi image. I think the whole thing could run on pretty much any flavor of RPi, it’d be like an add-on to the PVS6 with a nice local web dashboard. But that’s a lot of work and I have zero interest in offering a product that uses an unauthorized Sunpower interface. Sunpower has a fairly decent monitoring website with something much like my daily summary view. They also have tools for installers showing per-minute data. Those aren’t available to end consumers, I think on purpose, and I suspect they would not be thrilled by me offering a competing product.

Solar sparklines

Look at all this free electricity! Time scale is 6 hours. These are 410W panels which in practice seem to max out about 320W AC, or 350W DC before the inverter takes its share. This is from Jan 13; maybe I’ll get more in summer.

Installing Oculus on a PC: “Not Enough Space”

The Oculus Windows app installer has a bug; you can’t install it on an NTFS dynamic partition. If you try it reports there’s not enough space, despite there being plenty. Dynamic partitions are extremely common on Windows machines.

The workaround I used was to run OculusSetup.exe /drive=D. I happened to have a D drive that was a basic partition and while there’s no GUI option for choosing the install drive, there is this command line switch. If you’re not so lucky, there’s a lot of advice online suggesting making a 20GB virtual disk and installing there.

This bug is six years old. I always wonder how bugs like this happen; do the developers just not give a shit? Sometimes I think it’s incompetence but Oculus is a very impressive piece of tech in general. The linked Reddit discussion suggests this is some ham-handed attempt to avoid installing to removable media, so maybe it’s deliberate. Maybe it’s a DRM thing? What a stupid decision if so.

Debugging a WiFi problem

Still tinkering with Raspberry Pis and my Sunpower PVS6 solar controller. I had it all set up with a new RPi Zero 2 W when I had a new problem; the WiFi was flaky. It kinda sorta mostly worked well enough, I could get the HTTP requests through to it usually. But ping was showing 40% or more packet loss with a latency of 200+ms. I have a very clean WiFi environment, that should be 0% loss and 2ms latency.

A whole lot of testing later and I established that the problem is some sort of interference on 2.4GHz Channel 1, but only in my garage near the Sunpower box. That corner also has all my other ethernet equipment, is where the generator and solar feeds come in, and where the utility power and electrical panel are. So a lot of wires. None of that stuff should interfere with 2401-2423Mhz and there are a lot of mysteries still.

Switching my access point to channel 3 (2411-2433Mhz) seems to solve the problem. Part of the root cause of my troubles is I’d pinned the WiFi channel in the garage to 1 a year or more ago, I forget why. I’ve now set it to auto. I’ve had experiences where it seemed to be working for a few hours at a time before, so I don’t fully trust it yet. Edit: after rebooting the AP went back from channel 3 to 1. So I’ve configured it to hardcode channel 3 instead of “auto”. Whatever the interference is, the Ubiquiti hardware isn’t detecting it.

The most useful thing I did in the end was get 2 access points and 3 clients and try moving them around every few hours to see what triggered the problem. I used telegraf to ping them once a minute or so (but see below) for long term monitoring, and then occasional command line pings once a second for short term testing. Over two days I was able to narrow the problem down to the one channel in the one location, but it’s not related specifically to any particular hardware.

Some things I learned:

  • wavemon is a helpful tool on Linux for showing WiFi status. so is /proc/net/status and learning all the arcane options to the iw command.
  • The UniFi dashboard has some decent stats of its own hidden away under “Air Stats” for each individual access point device.
  • WiFi has its own link layer retransmit; lots of those might account for higher latency. But I don’t know what timescale it is on: 1 ms? 500ms? You can see WiFi retransmits in wavemon as “failed” and in Air Stats as “retry”.
  • Despite all these diagnostics none of them really showed me evidence the link was bad. All the basic link quality reports were 90% or better. No ridiculous number of retries (although it is 16% at the access point.)
  • Linux machines, including RPis, need to be configured for the country for wifi to work at its best. Particularly important for 5GHz.
  • Even with a perfectly good 5GHz channel available an RPi4 might still choose 2.4GHz. I could not find a way to reliably coerce it to use 5GHz.
  • Raspberry Pis have a variety of low power optimizations that mean they may not respond well to a ping every minute when otherwise idle. My RPi4 regularly takes 100ms to answer the first ping, then is a solid 2ms after. My original RPi Rev B just misses pings entirely if nothing else is happening on it. The RPi Zero 2 W seems pretty solid but then I’ve got it doing other real computation. Anyway my once-a-minute ping was showing phantom errors where there were none. A once-a-second ping test worked better.
  • There’s a power saving mode in the RPi radio hardware itself you can turn off with iw.
  • Raspberry Pis may in general just not be very good at wifi.
  • Don’t use mDNS names for ping testing. The mDNS query itself may get lost to a flaky / low power Pi and you never find the host.
  • TCP retransmits hide a lot of sins. But it only works right until it doesn’t. When my WiFi link was bad about 5% of my requests wouldn’t get through at all.

WiFi on Linux: country registration (Raspberry Pi)

My Raspberry Pi 4 would not talk via 5GHz to my Ubiquiti Access Point. Turns out the problem is the AP was running on channel 157 (5785MHz, 80MHz wide) which is not a globally allowed WiFi channel. It is allowed in the United States. Ubuntu on RPi4 has no country configuration for the WiFi unless you set it explicitly. Setting it for US jurisdiction should fix it.

On Ubuntu the config file /etc/default/crda is where to set it. Note you have to set it to “US”; “us” does not work. On Raspberry PI OS it’s in raspi-config under Localisation options. It’s also configurable in the wpa_supplicant.conf file you create when setting up a headless RPi.

Once the system is running you can inspect the state of your current wifi config with the commands iw reg get and iw phy phy0 channels, see output below. There’s documentation on how this works here, here. The apt packages crda and wireless-regdb are also of interest, as is /lib/crda.

$ iw reg get
global
country 00: DFS-UNSET
        (2402 - 2472 @ 40), (N/A, 20), (N/A)
        (2457 - 2482 @ 20), (N/A, 20), (N/A), AUTO-BW, PASSIVE-SCAN
        (2474 - 2494 @ 20), (N/A, 20), (N/A), NO-OFDM, PASSIVE-SCAN
        (5170 - 5250 @ 80), (N/A, 20), (N/A), AUTO-BW, PASSIVE-SCAN
        (5250 - 5330 @ 80), (N/A, 20), (0 ms), DFS, AUTO-BW, PASSIVE-SCAN
        (5490 - 5730 @ 160), (N/A, 20), (0 ms), DFS, PASSIVE-SCAN
        (5735 - 5835 @ 80), (N/A, 20), (N/A), PASSIVE-SCAN
        (57240 - 63720 @ 2160), (N/A, 0), (N/A)

phy#0
country 99: DFS-UNSET
        (2402 - 2482 @ 40), (6, 20), (N/A)
        (2474 - 2494 @ 20), (6, 20), (N/A)
        (5140 - 5360 @ 160), (6, 20), (N/A)
        (5460 - 5860 @ 160), (6, 20), (N/A)

$ iw phy phy0 channels
Band 1:
        * 2412 MHz [1]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40+
        * 2417 MHz [2]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40+
        * 2422 MHz [3]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40+
        * 2427 MHz [4]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40+
        * 2432 MHz [5]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40- HT40+
        * 2437 MHz [6]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40- HT40+
        * 2442 MHz [7]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40- HT40+
        * 2447 MHz [8]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40- HT40+
        * 2452 MHz [9]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40- HT40+
        * 2457 MHz [10]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40-
        * 2462 MHz [11]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40-
        * 2467 MHz [12]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40-
        * 2472 MHz [13]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40-
        * 2484 MHz [14] (disabled)
Band 2:
        * 5170 MHz [34] (disabled)
        * 5180 MHz [36]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40+
        * 5190 MHz [38] (disabled)
        * 5200 MHz [40]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40-
        * 5210 MHz [42] (disabled)
        * 5220 MHz [44]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40+
        * 5230 MHz [46] (disabled)
        * 5240 MHz [48]
          Maximum TX power: 20.0 dBm
          Channel widths: 20MHz HT40-
        * 5260 MHz [52]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40+
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5280 MHz [56]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40-
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5300 MHz [60]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40+
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5320 MHz [64]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40-
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5500 MHz [100]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40+
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5520 MHz [104]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40-
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5540 MHz [108]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40+
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5560 MHz [112]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40-
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5580 MHz [116]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40+
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5600 MHz [120]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40-
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5620 MHz [124]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40+
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5640 MHz [128]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40-
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5660 MHz [132]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40+
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5680 MHz [136]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz HT40-
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5700 MHz [140]
          Maximum TX power: 20.0 dBm
          No IR
          Radar detection
          Channel widths: 20MHz
          DFS state: usable (for 726 sec)
          DFS CAC time: 0 ms
        * 5720 MHz [144] (disabled)
        * 5745 MHz [149] (disabled)
        * 5765 MHz [153] (disabled)
        * 5785 MHz [157] (disabled)
        * 5805 MHz [161] (disabled)
        * 5825 MHz [165] (disabled)

mDNS, hostname.local, and WSL2

Modern computers can often be reached by the DNS name hostname.local. This is implemented via Multicast DNS, mDNS, which originated in the early 2000s as part of the zeroconf work to make networked computers usable without manual configuration. Apple’s Bonjour was the first implementation of it I saw working widely. Linux machines tend to use Avahi. For Debain and Ubuntu systems apt install avahi-daemon is generally enough to get the system announcing its name.

The magic of multicast

It works via multicast. mDNS-aware name resolvers know that if a domain name ends in .local, the way to resolve it is to send a UDP multicast request to 224.0.0.251:5353 or and see if anyone answers. (There’s an IPv6 equivalent). Multicast generally propagates across your whole LAN; if a host sees a query for their own name it answers back to 224.0.0.251 (not the requester directly) with a DNS record. It’s not exactly standard DNS packets, some slight modifications in place, but the basics are the same.

It works great! As long as you have a reliable LAN. I’m using it on some Raspberry Pi devices with a flaky WiFi connection and that’s not a good experience.

As an aside, can I say how much I love multicast? Ethernet broadcast too, and even the less common anycast. Being able to send a packet to the local network without being exactly sure who the recipient is can be very useful in all sorts of applications. A lot of stuff we do like NTP would work better if it regularly used multicast. Unfortunately multicast over the routed public Internet is pretty much a dead-end technology; no one has ever figured out how to manage it scalably.

mDNS services

I mostly use mDNS myself for .local domain name resolution. But mDNS is a full service discovery framework. You can use it to ask for things like “is there a printer on the network?”

Avahi comes with a discovery tool to get a quick dump of services on the network.
avahi-browse --all --ignore-local --resolve --terminate
Here’s an example of the services my printer offers

+   eno1 IPv4 Samsung M267x 287x Series (SEC...)   _privet._tcp         local
+   eno1 IPv4 Samsung M267x 287x Series (SEC...)   _scanner._tcp        local
+   eno1 IPv4 Samsung M267x 287x Series (SEC...)   UNIX Printer         local
+   eno1 IPv4 Samsung M267x 287x Series (SEC...)   PDL Printer          local
+   eno1 IPv4 Samsung M267x 287x Series (SEC...)   Internet Printer     local
+   eno1 IPv4 Samsung M267x 287x Series (SEC...)   Web Site             local

On my LAN I have services for Sonos, Roku Airplay, the printer, my Samba fileshare, and some things Home Assistant has published.

I believe the service discovery is all implemented via mDNS queries, with some extra information placed in TXT records. It all looks fairly elaborate, RFC 6763 is one reference for how it works. Now I’m curious how carefully specified the metadata for things like printers are. Is there a clear standard or is it all freeform and customary publication?

WSL and mDNS

WSL2, Microsoft’s Linux VM for Windows, also supports .local domain names. It’s a little weird. My windows machine is named “Nelson-Win10”. On the rest of my network nelson-win10.local resolves to 192.168.3.114, the DHCP-assigned address for the host Windows system. Just like you’d expect. But inside a WSL2 shell it resolves to Nelson-Win10.mshome.net (172.27.48.1). That’s a private-use address and the domain name is something Microsoft has been doing for years as part of their Internet connection sharing stuff. This address is reachable from the host Windows system. It’s not accessible on the rest of my LAN because I don’t have routes for that subnet, I wonder if it would work if I added one? Anyway this is all a workaround for the fact that localhost doesn’t work very well (or at all) across the host Windows and WSL2). Honestly all the networking in WSL2 to the outside world is kind of confusing and maybe buggy. But hostname.local works on the Windows machine itself.

(Note that in a command shell on Windows itself, nelson-win10.local also works. It resolves to an IPv6 link local address in the fe80::/10 block.)

Customizing a Raspberry PI Zero 2 W for PVS6

Awhile back I set up a Raspberry Pi to be a gateway to get access to my SunPower PVS6 monitoring system. That’s going great; the extra status info is really helpful and interesting. (Bonus screenshot below). I just bought a Raspberry Pi Zero 2 W to be the new computer for this. It’s so tiny it’ll fit entirely in the PVS6 box, powered by the USB that’s in there.

It works! The wifi is pretty flaky, despite me getting an amazing -30dB signal. It seems to be a problem with one specific access point, need to tinker some more. (Update: it may be wifi power saving.) The cable mess is pretty janky but it’s going to be shut inside a box, not sure I care. A smaller ethernet adapter would sure be nice.

Here’s my detailed software notes on setting this up.

  1. Mostly I’m just following this guide
  2. Use the RPi image installer to burn RPi OS Lite to a new SD card. Note this is a 32 bit OS.
  3. Create and configure a wpa_supplicant.conf file on the DOS partition of the SD card
  4. Create an empty ssh file on the DOS partition
  5. Boot the RPi, find its IP address via my DHCP server. (The name raspberrypi.local might also work.)
  6. Log in with ssh as pi/raspberry. Ignore locale complaints.
  7. Change the password for pi
  8. Become root
  9. apt update; apt upgrade. (This takes awhile!)
  10. Enable console autologin using raspi-config
  11. Fix locale using raspi-config
  12. Change the hostname to “pvspi0” using raspi-config
  13. Edit /etc/dhcpcd.conf so the ethernet is not used as a gateway
  14. apt install chrony
  15. apt install avahi-daemon
  16. Disable wifi power saving
  17. Reboot the pi
  18. Log in to pvspi0.local using pi/newpassword.
    Note mDNS takes awhile to start working, a minute or two after the RPi starts up
  19. Install haproxy
  20. Configure /etc/haproxy/haproxy.cfg. I did not include stats.

A brief note on power consumption. Idle the RPi Zero 2 W seems to use about 165mA (at 5W). Running stress-ng -c 4 peaked at 570 mA. The magic number here is 500 mA, that’s the minimum power for a USB port. I expect the system to basically be idle all the time so I think I’m safe with no extra measures. But some ideas on reducing power consumption.

  • Turn off HDMI. Instructions don’t work.
  • Turn off LEDs
  • Use fewer than 4 cores
  • Turn off unnecessary daemons. bluetoothd, hciattach (the serial console)

Here’s the bonus snapshot of some of my Grafana config. Not running on the RPi; all its doing is proxying requests. These graphs are centered on showing the status of all 28 separate panels, something you can only do by accessing the PVS6 data directly.