I have an Back-UPS ES 700
A moment in 2018 with the ups out of use because it needed a new battery gives an opportuntiy to see what features are missing
Have a machine with libvirt and kvm, get a guest and licence a proprietary operating system
Using it virtualised is permitted inside a trusted hypervisor like kvm is permitted and adviseable.
Install powerchute for windows and notice that it can toggle energy management and change settings, that which neither apcupsd and nut do not seem to support. Update, latest nut in git ff860090 - ff860097
Energy management means that the controlled outlets will be on only if the master outlet draws more than a set number of watts.
Thus run powerchute in a windows guest under kvm and attach wireshark in usb debug mode to get the instructions issued to the ups...
Wireshark reveals ups gets sent urb control messages with a REPORT ID and some data, it is quickly noticed that the report id is present as the first octet of the "value"
We can compare apcupsd and powerchute
description | report id | value |
---|---|---|
with powerchute alarm on | 0x0378 | 0x7802 |
with powerchute alarm off | 0x0378 | 0x7801 |
with apcupsd alarm on | 0x0318 | 0x1802 |
with apcupsd alarm off | 0x0318 | 0x1801 |
line sensitivity high | 0x0335 | 0x3502 |
line sensitivity med | 0x0335 | 0x3501 |
line sensitivity low | 0x0335 | 0x3500 |
energy management enable first sets | 0x38f | 8f01 |
energy management enable second sets | 0x38d | 8d19 |
energy management disable first sets | 0x38f | 8f00 |
energy management disable then sets | 0x38d | 8d19 |
energy management set 10watts then sets | 0x38d | 8d0a |
energy management set 25watts then sets | 0x38d | 8d19 |
energy management set 60watts then sets | 0x38d | 8d3c |
energy management set custom min is 10watts then sets | 0x38d | 8d0a |
energy management set custom max is 80watts then sets | 0x38d | 8d50 |
for 0x1337 sent in decimal seconds as ontime | 0x0391 | 0x913713 |
for 0x55aa sent in decimal seconds as offtime | 0x0392 | 0x92aa55 |
turn power on now sends (presume sets ontime zero) | 0x0391 | 0x910000 |
turn power on now then sends (presume sets ontime back to gui setting of 0x1337 | 0x0391 | 0x913713 |
The powerchute gui lets user pick watts of between 10 and 80 inclusive and times of between 1 and 65535 seconds
Then found, when trying to set apctest to do energy management, "report id" is not hardcoded into apcupsd, instead we have to find a value called "usage":
The resolution was found by replugging the UPS usb cable, the ups dumps a mapping table of "report id" to "usage"
I firstly tried usbhid-dump --model=051d:0002 just a big block of hex
Then success, save a wireshark pcap of the device being plugged in, tshark -x -r plugin.pcap -T json usbhid | grep "usbhid.item.local.usage_raw\|usbhid.item.global.report_id_raw"
To correlate, the "usages" and reportids of features supported by both powerchute and apcupsd were compared.
When reading this, notice that the usage, that is the last octet in FF8600XX is preceeded by the corresponding report id, which is the operation code octet sent to the ups over usb hid protocol.
This is in addition to 008400XX and 008500XX with USB-IF defined values usage tables for power devices
"usbhid.item.global.report_id_raw": "8c", "usbhid.item.local.usage_raw": "91", "usbhid.item.global.report_id_raw": "8d", "usbhid.item.local.usage_raw": "92", "usbhid.item.global.report_id_raw": "8e", "usbhid.item.local.usage_raw": "93", "usbhid.item.global.report_id_raw": "8f", "usbhid.item.local.usage_raw": "94", "usbhid.item.global.report_id_raw": "90", "usbhid.item.local.usage_raw": "95", "usbhid.item.global.report_id_raw": "91", "usbhid.item.local.usage_raw": "96", "usbhid.item.global.report_id_raw": "92", "usbhid.item.local.usage_raw": "97",
We have at last some lines for src/drivers/usb/usb.c they are inserted into _known_info[]
The CI_ items are completely made up, they are internal to apcupsd, add them to the table in include/defines.h
I know CI_energy_master_enable is volatile as there is a button on the ups to enable or not energy management, also the threshold can be set by holding the button in until the ups beeps thrice.
At this point I copy the part of apctest.c that does the ups alarm and have it control the energy management.
It works, can theoretically let do everything that powerchute lets us, in powerchute seconds defaults to 4 and watts to 25.
Being adventurous, I notice that usages 90,91,93 and 95 are defined, though powerchute does not call them. 90 turns out to be unreadable, 91 and 95 return 1, and 93 return 0
I plug in an 18w rated soldering iron into the master port and notice that usage 93 returns 18. Great, this means 93 can be used to measure power draw on tha master outlet.
Doing the hold button until beep thrice reveals the ups adds 10 watts to usage 0xFF860093 and stores it in usage 0xFF860092
This led to ACPI virtual battery for QEMU KVM