diff --git a/.changeset/pixii-unknown-status.md b/.changeset/pixii-unknown-status.md new file mode 100644 index 00000000..862924ca --- /dev/null +++ b/.changeset/pixii-unknown-status.md @@ -0,0 +1,7 @@ +--- +"ftw": patch +--- + +Bundle Pixii 2.1.6 so an unsupported or unknown charge status cannot clear a +known calibration fault. Keep battery and meter readings available while +reporting the missing status. diff --git a/drivers/BUNDLED_SOURCE.json b/drivers/BUNDLED_SOURCE.json index 97b2c4c1..a01d7afe 100644 --- a/drivers/BUNDLED_SOURCE.json +++ b/drivers/BUNDLED_SOURCE.json @@ -16,7 +16,7 @@ "from the signed channel. Run scripts/sync-bundled-drivers.sh to update." ], "repository": "srcfl/device-drivers", - "commit": "92adaf074f54a20f872ab84ae34c2cac45528f04", + "commit": "7e572fb499dda7acf6f1212b8b0b78235b9d3ba9", "source_dir": "drivers/lua", "drivers": [ "ambibox_v2x", "ctek", "ctek_hybrid", "ctek_v2", "deye", "easee_cloud", diff --git a/go/internal/drivers/pixii_unknown_status_test.go b/go/internal/drivers/pixii_unknown_status_test.go new file mode 100644 index 00000000..9b645da8 --- /dev/null +++ b/go/internal/drivers/pixii_unknown_status_test.go @@ -0,0 +1,57 @@ +package drivers + +import ( + "context" + "encoding/json" + "path/filepath" + "testing" + + "github.com/srcfl/ftw/go/internal/telemetry" +) + +// Exercise the bundled Lua in FTW's host, including its persistent fault state. +func TestPixiiUnknownStatusPreservesCalibrationFault(t *testing.T) { + tel := telemetry.NewStore() + modbus := newPixiiTestModbus() + env := NewHostEnv("pixii", tel).WithModbus(modbus) + env.BatteryCapacityWh = 10000 + d, err := NewLuaDriver(filepath.Join("..", "..", "..", "drivers", "pixii.lua"), env) + if err != nil { + t.Fatal(err) + } + defer d.Cleanup() + if err := d.Init(context.Background(), nil); err != nil { + t.Fatal(err) + } + for _, step := range []struct { + code uint16 + fault bool + label string + }{ + {0xffff, false, "unknown"}, + {7, true, "testing"}, + {0xffff, true, "unknown"}, + {99, true, "unknown_99"}, + {4, false, "charging"}, + } { + modbus.regs[40137] = step.code + if _, err := d.Poll(context.Background()); err != nil { + t.Fatal(err) + } + health := tel.DriverHealth("pixii") + if health == nil || health.DeviceFault != step.fault || health.IsOnline() == step.fault { + t.Fatalf("charge status %d: health = %+v, want fault=%v", step.code, health, step.fault) + } + reading := tel.Get("pixii", telemetry.DerBattery) + if reading == nil || tel.Get("pixii", telemetry.DerMeter) == nil { + t.Fatal("lost battery or meter telemetry") + } + var data map[string]any + if err := json.Unmarshal(reading.Data, &data); err != nil { + t.Fatal(err) + } + if data["charge_status"] != step.label { + t.Fatalf("charge status %d: label=%v, want %s", step.code, data["charge_status"], step.label) + } + } +}