Jim's Depository

this code is not yet written

This is mostly me talking to myself about how I use power4 for running the battery banks and generators in my shed.

Hardware

  • 48v battery bank with attached controllable DC propane generator and a provision for a manual AC gasoline generator.
  • 24v battery bank with a manual AC gasoline generator for charging.
  • DC/DC 48v -> 24v charger controlled by a relay.
  • 400w of solar panels on the 24v bank.
  • Each bank has an inverter which can be used to power the house, only one at a time.

Configuration

The power4/examples/shed.lua script is my actual configuration, so updating my configuration looks like this…

  • Check out power4 on my laptop
  • Have a chat with an AI about how I want to change my script, or just change it myself
  • Commit the change and push
  • Log in the shed.island.XXX.XXX
  • Check out the power4 repository
  • power4ctl stage examples/shed.lua
  • power4ctl policy accept
  • power4ctl show logs

Extending

If I have to make changes to the power controller's firmware or the power4ctl program, then it goes like this:

On the laptop:

$ # make the changes
$ make package && scp dist/power4-firmware.tar.gz shed.island.XXX.XXX:

On shed.island:

$ # Deploy the new firmware
$ rm -rf power4-firmware && tar -zxvf power4-firmware.tar.gz && ( cd power4-firmware && ./flash.sh && ./monitor.sh )
$
$ # If we need a new config or power4ctl then
$ cd ~/coding/power4
$ git pull
$ make deb && sudo dpkg -i power4ctl/power4ctl_1.0.0_arm64.deb && sudo systemctl restart power4ctl

Maintaining

  • shed.island.XXX.XXX, use the power4ctl program. It has some native commands, but power4ctl help will tell you all the pass through commands.
  • power4ctl daemon mode is snapshotting to /run/power4/*.json, one of those files is logs.json. See how things are going.
  • You can connect with picocom, but unless you want real time logs you can just use power4ctl and the pass through commands.

I polished my various SQLite wrappers into their own public Swift package: minimal-sqlite.

The repository is here:

https://github.com/jimstudt/minimal-sqlite

And the DocC documentation, because apparently I am susceptible to fancy modern trappings, is here:

https://jimstudt.github.io/minimal-sqlite/documentation/minimalsqlite/

This came out of work on the latest Femtoblogger rewrite. I had a tiny local sqlite.swift wrapper which was doing the job, but it was just barely doing the job. The database layer in Femtoblogger was getting harder to read than it needed to be, mostly because every query had too much low-level SQLite plumbing showing through.

minimal-sqlite is not an ORM. That is an important non-feature. You still write SQL. You still know what tables you have. You still get to make your own indexing mistakes in the traditional manner.

What it does provide is a small, safe, Swift Concurrency-friendly shell around SQLite:

  • an SQLDatabase actor which owns the connections
  • one writer connection and a pool of read-only connections
  • explicit readwrite and readonly transaction APIs
  • prepared statement binding and typed tuple row decoding
  • convenience execute, query, lookup, and queryDict calls
  • a RowID type for hidden SQLite row IDs
  • support for lastInsertRowID, changes, and totalChanges
  • a formatted text-date wrapper for legacy SQLite timestamp columns

The transaction model is the bit I care about most. A write transaction uses BEGIN IMMEDIATE; a read transaction uses BEGIN DEFERRED; read-only transactions do not expose an execute API. If SQLite reports BUSY or LOCKED, the transaction body can be retried, so the usual warning applies: do not put non-idempotent side effects in there unless you enjoy mysterious little duplicate behaviors.

Femtoblogger is now using the public 0.1.0 release, so I suppose that makes it real enough for now.

The package is intentionally small. No migrations framework. No query builder. No magic model layer. Just enough SQLite glue to make the code above it easier to read without hiding what SQLite is doing.

I have a Sungold SPH5048P All-in-one inverter. It has an RS-485 port and a USB port where you can get information, though it isn't documented how you might do that.

I wrote a program I call sungold which interfaces to the USB port on the Sungold, extracts the information, and reports it in a giant JSON file of mostly correctly interpreted data.

I tried to turn the inverter section on and off, and failed miserably. But I have succeeded in setting and clearing power saver mode, which is good enough for me. How power saving mode works is poorly documented, but without grid/generator power and no load, my inverter eventually shuts off, and when load appears, it eventually comes back on.

The device presents as a serial port where you do Modbus commands to pull blocks of register values. Most values cannot be written, but some can. It's hit or miss.

You can run in daemon mode where it will hang around and periodically write a new .json file, or you can run it as a one-shot command and get a JSON output.

This may work with many different brands of inverters: Many companies use the SRNE internals, which is what this targets. Good luck there.

This program just makes the JSON, I grind it up, and put it into a web page to monitor things. That ends up looking like this:

alt text

Attachments

sungold.jpg 61058 bytes

While working with those horrible battery management system BLE interfaces, I wanted to probe my various BLE devices and see what services and characteristics they have. I suspect there is a way to do it with the standard-ish bluetooth tools, but they also looked overcomplicated and apparently they also hate humans.

So I did what any civilized program would do, I "wrote" my own in a programming language I do not know. The AIs assured me that Rust's zbus interface was the friendliest API to work with. I've never written Rust, or used D-bus, but why let that stop me.

So I sat down with Claude and told him my wishes for a bluetooth low energy scanning program, and after a false start and a bunch of refinement, and then some locating of catastrophic bugs and maybe getting rid of them I now have the BLE scanner of my dreams.

I still don't know Rust, I kind of meant to learn it, but I haven't really read any of the code. I made it move some things around and structure things a little different, but Claude didn't need me for my coding skills.

Anyway, you too can have blescan. There is a Raspberry Pi Debian package in the release prebuilt, or you can build it yourself.

With no arguments it lists the devices it sees advertising. With a MAC as an argument it maps out the services and characteristics of the device.

$ blescan
Scanning for BLE devices... (5s)
Found 2 device(s):
  AA:BB:CC:DD:EE:FF - My Sensor (-72 dBm)
  11:22:33:44:55:66 - Unknown (-85 dBm)

$ blescan AA:BB:CC:DD:EE:FF
Connecting to AA:BB:CC:DD:EE:FF...
Waiting for GATT services...

GATT profile for AA:BB:CC:DD:EE:FF:

Service: 0x1800 - Generic Access
  Characteristic: 0x2A00 - Device Name [read]
    Value: "My Sensor"
  Characteristic: 0x2A01 - Appearance [read]
    Value: 00 00

Service: 0x180A - Device Information
  Characteristic: 0x2A29 - Manufacturer Name String [read]
    Value: "ACME Corp"
  Characteristic: 0x2A26 - Firmware Revision String [read]
    Value: "1.2.3"

Service: 0x180F - Battery Service
  Characteristic: 0x2A19 - Battery Level [read, notify]
    Value: 64

There's a man page if you want to know more.

I've got 8 Vatrer 12v 100Ah LiFePO4 batteries in two banks powering a remote installation. The absolute #1 selling point of these batteries is that their BMS (battery management system) will look to see if it is too cold to charge the batteries and run a little heater until the cells warm up enough to charge without destroying them.

The #2 selling point is that the BMS units report the battery state of charge, voltage, current, and such over BLE (Bluetooth Low Energy). That lets me better track their state when unattended for months and decide when to cut power off to less critical systems or attempt to start a backup generator.

After much jiggery-pokery, I have this integrated in the control systems, but those little BMS controllers are really nasty to work with.

Woes

  • No sane BLE implementation. They sort of implement a RS-485 interface with a write-only string characteristic and a notify-only string characteristic. Listen to the one and shout in the other.

  • No sane protocol. I'm pretty sure that is some ancient Modbus controller protocol wrapped in the Bluetooth.

  • No documentation of the protocol. I get it, I'd be ashamed to admit to that too.

  • GIANT DANGER: If a device connects to the BMS, in the BLE sense, then the battery will stop advertising itself, and it appears the battery has vanished. If there is a timeout, it is more than 12 hours. Lest you think,“well, I won't do that then"… there are a lot of sneaky paths for BlueZ and NimBLE that will leave connection stuck on without you knowing it. I found several.

  • You apparently can't reset the BMS. I mean, it's not like you can take the batteries out or disconnect the power.

Moral

If one of your batteries drops off Bluetooth, then reboot all the devices that were talking to it, and it may well come back.

more articles