CLI Reference
sitsolar-dongle reads the read-only registers of a SiNeng / FuturaPulse
inverter through its WiFi dongle on TCP port 7078.
sitsolar-dongle <host> --sn <SERIAL> [options]
sitsolar-dongle --list
A host is required for every mode except --list, and --sn is required for
every mode except --list. Both are validated before any socket is opened.
Connection
Slave address selects the target device
The 64 07 00 02 00 05 frame prefix is a constant. The device actually
queried is chosen by the slave address byte inside the inner Modbus RTU
frame: 0x00 is the dongle, 0x01 is the inverter. See
Protocol.
What to read
--read takes precedence: when present, --section and --key are ignored and
the output is a list of {address, count, hex | error} entries rather than a
decoded register map.
sitsolar-dongle 192.168.1.50 --sn ... --read 31002:2 --read 30100:1
Filtering by section or key still reads the full coalesced blocks that contain those registers, then discards the unwanted values locally — the dongle is never asked for a narrower range.
Output
--errors skip (the default) records refused ranges under
_unreadable_ranges and carries on, because firmwares differ in which optional
blocks they implement. --errors raise makes any refusal fatal.
--raw adds the un-scaled integer, plus a signed interpretation in
parentheses when it differs — for example raw=65535 (-1) for a two's
complement -1.
JSON shape
A decoded poll produces an object keyed by register key, plus underscore-prefixed metadata entries:
{
"grid_frequency": {
"address": "31002~31003",
"name": "Grid frequency",
"section": "AC_side",
"raw": 50010,
"value": 50.01,
"unit": "Hz"
},
"battery_soc": {
"address": "32064",
"name": "Battery SOC",
"section": "battery_parameters",
"raw": 87,
"value": 87,
"unit": "%"
},
"_unreadable_ranges": [
{ "range": "32001~32026", "error": "…64 07 01 stub…" }
],
"_dongle": {
"factory": "SiNeng", "model": "Si-Dongle-L",
"serial": "…", "version": 0, "time": 1718000000
}
}
Underscore-prefixed entries — _unreadable_ranges, _devices, _dongle — are
metadata, not registers.
Sampling
With --interval unset or 0, the tool performs exactly one poll and exits.
Any positive value loops until interrupted.
sitsolar-dongle 192.168.1.50 --sn ... --interval 15 --json
Other
Exit codes
Examples
Poll once, human readable:
sitsolar-dongle 192.168.1.50 --sn <DONGLE_SERIAL>
Emit JSON and include device identity:
sitsolar-dongle 192.168.1.50 --sn ... --json --include-device-info
Follow forever for a Home Assistant or MQTT bridge:
sitsolar-dongle 192.168.1.50 --sn ... --interval 15 --json
Inspect one section with raw words shown:
sitsolar-dongle 192.168.1.50 --sn ... --section AC_side --raw
Watch a couple of specific keys:
sitsolar-dongle 192.168.1.50 --sn ... --key grid_frequency --key battery_soc
Probe undocumented registers, tolerating refusals:
sitsolar-dongle 192.168.1.50 --sn ... --read 31002:2 --read 34101:4
Read holding registers instead of input registers:
sitsolar-dongle 192.168.1.50 --sn ... --fc 03 --read 46056:1
Browse the register map offline:
sitsolar-dongle --list