working in production - not entirely validated. parallel mode working.
This commit is contained in:
39
LVX6048/2026-04-26-lvx6048_1-dump
Normal file
39
LVX6048/2026-04-26-lvx6048_1-dump
Normal file
@@ -0,0 +1,39 @@
|
||||
# LVX6048 settings profile. Edit freely; all keys are optional.
|
||||
# `flash.py diff` previews changes; `flash.py apply --confirm` writes.
|
||||
#
|
||||
# skipped (read-only or out of settable range):
|
||||
# max_charging_current=100 (max_charging_current=100 out of range [10, 80])
|
||||
|
||||
# enum: AGM | FLOODED | USER
|
||||
battery_type: AGM
|
||||
|
||||
# V 40.0..48.0 — hard shutdown; must be < stop_discharge_voltage. Only honored when battery_type=USER.
|
||||
cutoff_voltage: 40.8
|
||||
|
||||
# V 44.0..51.0 — switch battery→grid below this (pair: stop_charge_voltage). Only honored when battery_type=USER.
|
||||
stop_discharge_voltage: 46.0
|
||||
|
||||
# V 48.0..58.4 — CC→CV transition (pair: float_voltage; must be >= float_voltage). Only honored when battery_type=USER.
|
||||
bulk_voltage: 56.4
|
||||
|
||||
# A 2,10,20,30,40,50,60,70,80 — grid-side cap only
|
||||
max_utility_charging_current: 30
|
||||
|
||||
# enum: solar_utility_battery | solar_battery_utility
|
||||
output_source_priority: solar_battery_utility
|
||||
|
||||
# enum: solar_first | solar_and_utility | solar_only
|
||||
charger_priority: solar_first
|
||||
|
||||
# enum: battery_load_utility_ac | load_battery_utility
|
||||
solar_power_priority: battery_load_utility_ac
|
||||
|
||||
# enum: enabled | disabled (PEI/PDI)
|
||||
grid_tie: disabled
|
||||
|
||||
# V 0 (=Full) or 48.0..58.0 — switch grid→battery above this (pair: stop_discharge_voltage). Only honored when battery_type=USER.
|
||||
stop_charge_voltage: 54.0
|
||||
|
||||
# V 48.0..58.4 — held while on grid (pair: bulk_voltage; must be <= bulk_voltage). Only honored when battery_type=USER.
|
||||
float_voltage: 54.0
|
||||
|
||||
39
LVX6048/2026-04-26-lvx6048_2-dump
Normal file
39
LVX6048/2026-04-26-lvx6048_2-dump
Normal file
@@ -0,0 +1,39 @@
|
||||
# LVX6048 settings profile. Edit freely; all keys are optional.
|
||||
# `flash.py diff` previews changes; `flash.py apply --confirm` writes.
|
||||
|
||||
# enum: AGM | FLOODED | USER
|
||||
battery_type: AGM
|
||||
|
||||
# V 40.0..48.0 — hard shutdown; must be < stop_discharge_voltage. Only honored when battery_type=USER.
|
||||
cutoff_voltage: 40.8
|
||||
|
||||
# V 44.0..51.0 — switch battery→grid below this (pair: stop_charge_voltage). Only honored when battery_type=USER.
|
||||
stop_discharge_voltage: 46.0
|
||||
|
||||
# V 48.0..58.4 — CC→CV transition (pair: float_voltage; must be >= float_voltage). Only honored when battery_type=USER.
|
||||
bulk_voltage: 56.4
|
||||
|
||||
# A 2,10,20,30,40,50,60,70,80 — grid-side cap only
|
||||
max_utility_charging_current: 30
|
||||
|
||||
# A 10,20,30,40,50,60,70,80 — combined solar+AC cap
|
||||
max_charging_current: 60
|
||||
|
||||
# enum: solar_utility_battery | solar_battery_utility
|
||||
output_source_priority: solar_battery_utility
|
||||
|
||||
# enum: solar_first | solar_and_utility | solar_only
|
||||
charger_priority: solar_first
|
||||
|
||||
# enum: battery_load_utility_ac | load_battery_utility
|
||||
solar_power_priority: battery_load_utility_ac
|
||||
|
||||
# enum: enabled | disabled (PEI/PDI)
|
||||
grid_tie: disabled
|
||||
|
||||
# V 0 (=Full) or 48.0..58.0 — switch grid→battery above this (pair: stop_discharge_voltage). Only honored when battery_type=USER.
|
||||
stop_charge_voltage: 54.0
|
||||
|
||||
# V 48.0..58.4 — held while on grid (pair: bulk_voltage; must be <= bulk_voltage). Only honored when battery_type=USER.
|
||||
float_voltage: 54.0
|
||||
|
||||
139
LVX6048/2026-04-26-parallel.md
Normal file
139
LVX6048/2026-04-26-parallel.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# 2026-04-26 (afternoon) — LVX6048 parallel-mode commissioning
|
||||
|
||||
Got the two LVX6048 inverters operationally paralleled, sharing battery
|
||||
charge from the EG4 LP4 v2 bank symmetrically. Several discoveries about
|
||||
the firmware's parallel-state reporting along the way, plus a couple of
|
||||
small patches.
|
||||
|
||||
## What happened
|
||||
|
||||
1. **Firmware parity (main CPU): achieved.** Pre-flash main versions
|
||||
were 06303 (unit 1) and 06440 (unit 2). User flashed both to
|
||||
**06306** using the MPP Solar `InfiniVMasterCPU_Reflash` tool. Active
|
||||
fault 71 ("Parallel version different") cleared.
|
||||
|
||||
2. **Slave-CPU firmware: still skewed but benign.** Slaves remain
|
||||
06126 / 06021. The vendor's `LVX6048 FW63.06.zip` *does* include a
|
||||
`dsp.hex` slave bin, but the operational evidence (load-sharing,
|
||||
matched battery V, no faults, master/slave handshake completing)
|
||||
indicates the slave delta is not blocking parallel function on this
|
||||
firmware family. **Not flashing the DSPs** — filed for the record only.
|
||||
|
||||
3. **Battery wiring + commissioning.** Both inverters tied to the same
|
||||
3× EG4 LP4 v2 100 Ah bank (300 Ah at 51.2 V nominal). After fault 83
|
||||
("Parallel battery voltage detect different") cleared on first
|
||||
battery-connected boot, both inverters entered MOD `06` and began
|
||||
sharing the charge load (~55 A each, ~110 A combined ≈ 0.37 C).
|
||||
|
||||
4. **MCHGC mismatch (100 A vs 60 A) → fixed.** Unit 1 was at 100 A —
|
||||
above the PI18 `MCHGC` setter's 80 A ceiling, so it had to be set
|
||||
via the LCD (Program 02). User dropped unit 1 to 60 A so both
|
||||
match. Confirmed via `flash.py compare` (12/12 settings match).
|
||||
|
||||
5. **Patch (g) tweak — `outputformats/hass.py`** *(unrelated to parallel
|
||||
work but lives in the same patch tree).* No change here today; the
|
||||
morning's cleanup is in commit `f771ec2`.
|
||||
|
||||
6. **Patch (h) — `pi18.py` MOD decoder.** Inverter started reporting
|
||||
MOD code `06` after batteries connected; the existing decoder only
|
||||
knew 00..05 and crashed (`KeyError: '06'`). Added `"06": "Charge"`.
|
||||
The "Charge" label is an educated guess based on observed behavior
|
||||
(active charging, no AC out); revisit if it turns up in unrelated
|
||||
states.
|
||||
|
||||
7. **`parallel_instance_number` decoder fixed.** The GS/PGS field is
|
||||
the parallel-instance index per the PI18 spec (0 = master, 1+ =
|
||||
slaves), not a 2-value flag — but powermon upstream (and our patch)
|
||||
was decoding it as `["Not valid", "valid"]`, which made the master
|
||||
appear as "Not valid" in HA. Replaced with an `OPTION` decoder
|
||||
labeling each index ("instance 0 (master)", "instance 1", ...) in
|
||||
both GS field 27 and PGS field 0. `flash.py sync-check` updated
|
||||
accordingly: removed the false-positive "GS parallel_instance_number
|
||||
= Not valid" issue, replaced with index-collision and no-master
|
||||
checks.
|
||||
|
||||
8. **`lvx-resolve-links` now auto-runs on USB hot-plug.** Added an
|
||||
`ACTION=="add"` udev rule for vendor 0665 / product 5161 that
|
||||
`RUN+=`s `systemctl --no-block restart lvx-resolve-links.service
|
||||
powermon.service powermon2.service`. Powermon's `Requires=` /
|
||||
`After=` already serialize the chain. Added a retry loop to the
|
||||
resolver script (poll up to ~10 s for both expected serials) so a
|
||||
single hidraw appearing slightly before its sibling doesn't leave a
|
||||
symlink missing. Tested via `udevadm trigger --action=add
|
||||
--subsystem-match=hidraw`: all three services restarted in lock-step
|
||||
and symlinks rewrote cleanly.
|
||||
|
||||
9. **Battery profile YAML for the bank.** Created
|
||||
`lvx-flash/profiles/eg4-lp4-v2.yaml` capturing the conservative
|
||||
off-grid LFP policy (USER mode, bulk 56.4 V / float 54.0 V, cutoff
|
||||
48.0 V, stop-charge 54.0 V). Live state already matches — applying
|
||||
would be a no-op. Kept as the canonical record of the chosen policy.
|
||||
|
||||
10. **Sanity dumps** — `2026-04-26-lvx6048_{1,2}-dump` capture per-unit
|
||||
settings post-commissioning. Useful as a baseline for diff-on-suspect.
|
||||
|
||||
11. **Battery side: re-discovered that EG4 LP4 v2's inter-pack
|
||||
daisy-chain silences slave packs.** User had wired the inter-pack
|
||||
`Link-In/Link-Out` chain earlier in the day; it elects a master
|
||||
and demotes slaves on their independent RS485 ports. Pulling the
|
||||
chain restored all three packs to MQTT immediately (all reporting
|
||||
54.62 V agreement). Daemon needed no change. Memorized for next
|
||||
time.
|
||||
|
||||
## Net effect
|
||||
|
||||
| Metric | Before | After |
|
||||
|---|---|---|
|
||||
| Main-CPU firmware | 06303 / 06440 | **06306 / 06306** ✓ |
|
||||
| Slave-CPU firmware | 06126 / 06021 | unchanged (benign) |
|
||||
| Active fault 71 | yes | cleared |
|
||||
| Active fault 83 | n/a (no battery) | cleared |
|
||||
| MCHGC delta | 100 A vs 60 A | 60 A / 60 A ✓ |
|
||||
| Settings parity | mismatch | 12/12 match |
|
||||
| Charge-current sharing | n/a | 55 A / 57 A symmetric |
|
||||
| Battery V agreement | n/a | 55.1 V / 55.1 V identical |
|
||||
| `parallel_instance_number` | "Not valid" / "valid" (master mislabeled) | "instance 0 (master)" / "instance 1" |
|
||||
| MOD 06 crash on sync-check | yes | fixed |
|
||||
| Hot-plug symlink recovery | manual `systemctl restart` | automatic via udev `RUN+=` |
|
||||
|
||||
## Files touched
|
||||
|
||||
```
|
||||
M LVX6048/powermon-patches/pi18.py (MOD 06 -> "Charge"; parallel_instance_number decoder fix)
|
||||
M LVX6048/lvx-flash/flash.py (parallel_instance_number index semantics; new sync-check rules)
|
||||
M LVX6048/bin/lvx-resolve-links (retry loop for hot-plug race)
|
||||
M LVX6048/etc/udev/rules.d/99-lvx6048.rules (ACTION=="add" RUN+= cascade)
|
||||
A LVX6048/2026-04-26-lvx6048_1-dump (post-commissioning baseline)
|
||||
A LVX6048/2026-04-26-lvx6048_2-dump (post-commissioning baseline)
|
||||
A LVX6048/lvx-flash/profiles/eg4-lp4-v2.yaml (canonical battery profile)
|
||||
A LVX6048/2026-04-26-parallel.md (this file)
|
||||
```
|
||||
|
||||
## How to verify
|
||||
|
||||
```bash
|
||||
sudo systemctl stop powermon.service powermon2.service
|
||||
sudo systemctl restart lvx-resolve-links.service # always run after inverter power-cycle
|
||||
/home/noise/solar/LVX6048/lvx-flash/flash.py sync-check \
|
||||
--device-a /dev/lvx6048-1 --device-b /dev/lvx6048-2
|
||||
sudo systemctl start powermon.service powermon2.service
|
||||
```
|
||||
|
||||
Pass criteria post-commissioning:
|
||||
- main fw 06306 on both
|
||||
- `mode=06` (Charge) or `mode=03` (Battery) or `mode=05` (Hybrid) — i.e. healthy operating modes, no `04` (Fault)
|
||||
- `fault=No fault` on both
|
||||
- both `parallel_*` values present (one as master/0, one as slave/1)
|
||||
- battery V agreement within ~0.2 V
|
||||
- charge currents within ~5 A symmetric (when both are charging)
|
||||
|
||||
## Loose ends / next pass
|
||||
|
||||
1. update `LVX6048/README.md` "Next steps" section to reflect that
|
||||
parallel commissioning + decoder + hot-plug fixes are done, and
|
||||
the slave-firmware delta is intentionally unrepaired (benign)
|
||||
2. (optional) verify MOD 06 label by observing in different states
|
||||
3. (optional) decode remaining PGS fields now that values are meaningful
|
||||
4. (optional, longer horizon) closed-loop BMS comms via the dedicated
|
||||
pack→inverter CAN port; defer until open-loop has been stable for a
|
||||
week and we can baseline SoC accuracy
|
||||
@@ -63,19 +63,35 @@ def _relink(link: str, target: str) -> None:
|
||||
|
||||
|
||||
async def main() -> int:
|
||||
candidates = sorted(glob.glob("/dev/hidraw*"))
|
||||
if not candidates:
|
||||
print("no /dev/hidraw* devices present", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# Hot-plug case: udev fires this script as soon as one hidraw appears, but
|
||||
# a sibling inverter coming up at nearly the same moment may still be
|
||||
# enumerating. Retry-probe up to ~10 s waiting for all expected serials,
|
||||
# so a transient single-device sighting doesn't leave one symlink missing.
|
||||
expected = set(LINK_FOR_SERIAL.keys())
|
||||
deadline = asyncio.get_event_loop().time() + 10.0
|
||||
sn_to_path: dict[str, str] = {}
|
||||
seen_paths: set[str] = set()
|
||||
while True:
|
||||
candidates = sorted(glob.glob("/dev/hidraw*"))
|
||||
for p in candidates:
|
||||
if p in seen_paths:
|
||||
continue
|
||||
seen_paths.add(p)
|
||||
sn = await probe_serial(p)
|
||||
if sn:
|
||||
print(f"{p}: serial {sn}")
|
||||
sn_to_path[sn] = p
|
||||
else:
|
||||
print(f"{p}: no PI18 response (probably not an LVX6048)")
|
||||
if expected.issubset(sn_to_path):
|
||||
break
|
||||
if asyncio.get_event_loop().time() >= deadline:
|
||||
break
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
if not sn_to_path:
|
||||
print("no LVX6048 devices found on /dev/hidraw*", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
missing = []
|
||||
for sn, link in LINK_FOR_SERIAL.items():
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
# LVX6048 (MPP Solar / Voltronic) USB-HID — dialout access only.
|
||||
# Logical unit identification is done via PI18 `ID` query at powermon startup
|
||||
# (see powermon.yaml: path: /dev/hidraw*, serial_number: <SN>).
|
||||
# No SYMLINK here — powermon resolves the right /dev/hidrawN by inverter serial,
|
||||
# which survives cable moves / hub port changes.
|
||||
# Logical unit identification is done via the lvx-resolve-links oneshot, which
|
||||
# reads each inverter's PI18 serial and writes /dev/lvx6048-{1,2} symlinks.
|
||||
# powermon services have Requires=lvx-resolve-links so they wait for it at boot.
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0665", ATTRS{idProduct}=="5161", MODE="0660", GROUP="dialout"
|
||||
|
||||
# Hot-plug recovery: when an inverter re-enumerates (e.g. after a power cycle),
|
||||
# hidraw indices can shuffle, leaving /dev/lvx6048-{1,2} symlinks pointing at
|
||||
# the wrong physical unit. Re-run the resolver and bounce the powermon services
|
||||
# so HA stops receiving crossed-up entity data. Fires only on add (avoid double
|
||||
# restart on disconnect+reconnect).
|
||||
SUBSYSTEM=="hidraw", ACTION=="add", ATTRS{idVendor}=="0665", ATTRS{idProduct}=="5161", \
|
||||
RUN+="/bin/systemctl --no-block restart lvx-resolve-links.service powermon.service powermon2.service"
|
||||
|
||||
@@ -544,7 +544,7 @@ FAULT_NAMES = {
|
||||
# GS field indices (see powermon/protocols/pi18.py :: QUERY_COMMANDS["GS"])
|
||||
GS_AC_OUTPUT_V = 2
|
||||
GS_AC_OUTPUT_HZ = 3
|
||||
GS_PARALLEL_VALID = 27
|
||||
GS_PARALLEL_INDEX = 27 # 0 = master, 1+ = slaves; one unit per cluster reports 0
|
||||
|
||||
|
||||
async def _read_raw_parts(port: USBPort, code: str, retries: int = 3) -> list[str]:
|
||||
@@ -574,7 +574,7 @@ async def _snapshot_sync(path: str) -> dict[str, Any]:
|
||||
finally:
|
||||
await port.disconnect()
|
||||
return {
|
||||
"parallel_valid": gs[GS_PARALLEL_VALID] == "1",
|
||||
"parallel_index": int(gs[GS_PARALLEL_INDEX]),
|
||||
"ac_output_v": _tenths_to_v(gs[GS_AC_OUTPUT_V]),
|
||||
"ac_output_hz": int(gs[GS_AC_OUTPUT_HZ]) / 10.0,
|
||||
"fault_code": fws[0],
|
||||
@@ -593,9 +593,10 @@ async def cmd_sync_check(args) -> int:
|
||||
b = await _snapshot_sync(path_b)
|
||||
|
||||
def _row(label: str, s: dict) -> str:
|
||||
valid = "valid" if s["parallel_valid"] else "NOT VALID"
|
||||
idx = s["parallel_index"]
|
||||
role = f"instance {idx}{' (master)' if idx == 0 else ''}"
|
||||
return (f"{label}: fw={s['main_cpu']}/{s['slave_cpu']} mode={s['mode']} "
|
||||
f"parallel={valid} fault={s['fault_name']} "
|
||||
f"parallel={role} fault={s['fault_name']} "
|
||||
f"vac={s['ac_output_v']}V fac={s['ac_output_hz']}Hz")
|
||||
|
||||
print(_row(path_a, a))
|
||||
@@ -604,10 +605,10 @@ async def cmd_sync_check(args) -> int:
|
||||
issues: list[str] = []
|
||||
if a["main_cpu"] != b["main_cpu"] or a["slave_cpu"] != b["slave_cpu"]:
|
||||
issues.append(f"firmware mismatch: {a['main_cpu']}/{a['slave_cpu']} vs {b['main_cpu']}/{b['slave_cpu']} — parallel requires matching firmware on both units")
|
||||
if not a["parallel_valid"]:
|
||||
issues.append(f"{path_a}: GS parallel_instance_number = Not valid")
|
||||
if not b["parallel_valid"]:
|
||||
issues.append(f"{path_b}: GS parallel_instance_number = Not valid")
|
||||
if a["parallel_index"] == b["parallel_index"]:
|
||||
issues.append(f"both units report the same parallel instance index ({a['parallel_index']}); should differ — cluster handshake incomplete")
|
||||
if 0 not in (a["parallel_index"], b["parallel_index"]):
|
||||
issues.append(f"neither unit reports instance 0 — cluster has no elected master (got {a['parallel_index']}, {b['parallel_index']})")
|
||||
if a["fault_code"] != "00":
|
||||
issues.append(f"{path_a}: active fault {a['fault_code']} ({a['fault_name']})")
|
||||
if b["fault_code"] != "00":
|
||||
|
||||
59
LVX6048/lvx-flash/profiles/eg4-lp4-v2.yaml
Normal file
59
LVX6048/lvx-flash/profiles/eg4-lp4-v2.yaml
Normal file
@@ -0,0 +1,59 @@
|
||||
# LVX6048 settings profile — EG4 LifePower4 v2 LiFePO4 bank, open-loop.
|
||||
#
|
||||
# Designed for: 3× EG4 LP4 v2 100 Ah in parallel (300 Ah, ~15.4 kWh).
|
||||
# Apply identically to both inverters in a parallel pair:
|
||||
# sudo systemctl stop powermon.service powermon2.service
|
||||
# ./flash.py apply --device /dev/lvx6048-1 --profile profiles/eg4-lp4-v2.yaml --confirm
|
||||
# ./flash.py apply --device /dev/lvx6048-2 --profile profiles/eg4-lp4-v2.yaml --confirm
|
||||
# sudo systemctl start powermon.service powermon2.service
|
||||
# ./flash.py compare --device-a /dev/lvx6048-1 --device-b /dev/lvx6048-2
|
||||
# ./flash.py sync-check --device-a /dev/lvx6048-1 --device-b /dev/lvx6048-2
|
||||
#
|
||||
# Voltage rationale (16S LFP, 3.2 V/cell nominal = 51.2 V pack):
|
||||
# bulk 56.4 V = 3.525 V/cell — long-life sweet spot for LFP
|
||||
# float 54.0 V = 3.375 V/cell — rest near mid-knee, avoid sitting on the top
|
||||
# stop_charge 54.0 V — grid charges only to ~mid-knee; solar handles the bulk top-off
|
||||
# stop_dis 48.0 V = 3.000 V/cell — soft "switch to grid" point
|
||||
# cutoff 48.0 V = 3.000 V/cell — inverter hard shutdown floor (BMS still protects below)
|
||||
# Conservative off-grid policy: keep grid as a soft top-up, let solar do the bulk work.
|
||||
#
|
||||
# Current rationale (300 Ah bank):
|
||||
# 60 A/unit × 2 units = 120 A combined ≈ 0.4 C — well under bank's continuous spec
|
||||
# 30 A/unit MUCHGC keeps grid-charging conservative (60 A combined)
|
||||
|
||||
# enum: AGM | FLOODED | USER
|
||||
# USER required to enable the per-cell custom voltages below.
|
||||
battery_type: USER
|
||||
|
||||
# V 40.0..48.0 — hard shutdown; must be < stop_discharge_voltage.
|
||||
cutoff_voltage: 48.0
|
||||
|
||||
# V 44.0..51.0 — switch battery→grid below this (pair: stop_charge_voltage).
|
||||
stop_discharge_voltage: 48.0
|
||||
|
||||
# V 0 (=Full) or 48.0..58.0 — switch grid→battery above this. 0 = let bulk define.
|
||||
stop_charge_voltage: 54.0
|
||||
|
||||
# V 48.0..58.4 — CC→CV transition (pair: float_voltage; must be >= float_voltage).
|
||||
bulk_voltage: 56.4
|
||||
|
||||
# V 48.0..58.4 — held while on grid (pair: bulk_voltage; must be <= bulk_voltage).
|
||||
float_voltage: 54.0
|
||||
|
||||
# A 10,20,30,40,50,60,70,80 — combined solar+AC cap, per unit.
|
||||
max_charging_current: 60
|
||||
|
||||
# A 2,10,20,30,40,50,60,70,80 — grid-side cap, per unit.
|
||||
max_utility_charging_current: 30
|
||||
|
||||
# enum: solar_utility_battery | solar_battery_utility
|
||||
output_source_priority: solar_battery_utility
|
||||
|
||||
# enum: solar_first | solar_and_utility | solar_only
|
||||
charger_priority: solar_first
|
||||
|
||||
# enum: battery_load_utility_ac | load_battery_utility
|
||||
solar_power_priority: battery_load_utility_ac
|
||||
|
||||
# enum: enabled | disabled (PEI/PDI)
|
||||
grid_tie: disabled
|
||||
@@ -336,9 +336,23 @@ QUERY_COMMANDS = {
|
||||
"2": "output",
|
||||
},
|
||||
},
|
||||
# Parallel-cluster index. PI18 spec: 0 = master, 1+ = slaves.
|
||||
# Upstream powermon labels this as a 2-value flag ["Not valid", "valid"]
|
||||
# which is wrong — masters end up labeled "Not valid". Fixed to expose
|
||||
# the actual index. Range covers up to max_parallel_units (typ. 9).
|
||||
{"description": "Parallel instance number", "reading_type": ReadingType.MESSAGE,
|
||||
"response_type": ResponseType.LIST,
|
||||
"options": ["Not valid", "valid"],
|
||||
"response_type": ResponseType.OPTION,
|
||||
"options": {
|
||||
"0": "instance 0 (master)",
|
||||
"1": "instance 1",
|
||||
"2": "instance 2",
|
||||
"3": "instance 3",
|
||||
"4": "instance 4",
|
||||
"5": "instance 5",
|
||||
"6": "instance 6",
|
||||
"7": "instance 7",
|
||||
"8": "instance 8",
|
||||
},
|
||||
},
|
||||
|
||||
],
|
||||
@@ -362,6 +376,7 @@ QUERY_COMMANDS = {
|
||||
"03": "Battery",
|
||||
"04": "Fault",
|
||||
"05": "Hybrid mode(Line mode, Grid mode)",
|
||||
"06": "Charge",
|
||||
}
|
||||
},
|
||||
],
|
||||
@@ -523,8 +538,10 @@ QUERY_COMMANDS = {
|
||||
"command_type": CommandType.PI18_QUERY,
|
||||
"result_type": ResultType.COMMA_DELIMITED,
|
||||
"reading_definitions": [
|
||||
# See note on the matching field in GS — same fix here.
|
||||
{"description": "Parallel instance number", "reading_type": ReadingType.MESSAGE,
|
||||
"response_type": ResponseType.LIST, "options": ["Not valid", "valid"]},
|
||||
"response_type": ResponseType.OPTION,
|
||||
"options": {str(i): f"instance {i}{' (master)' if i == 0 else ''}" for i in range(9)}},
|
||||
{"description": "Parallel unit count", "reading_type": ReadingType.MESSAGE},
|
||||
{"description": "Fault code", "reading_type": ReadingType.MESSAGE},
|
||||
{"description": "Field 4 (raw)", "reading_type": ReadingType.MESSAGE},
|
||||
|
||||
Reference in New Issue
Block a user