Home Assistant: configurable charge status values (BC) - #32136
Merged
Conversation
Drop the guessed vendor states from the built-in charge status mapping and keep only the unambiguous ones (a/b/c, disconnected, connected, charging). Vendor-specific states are now configured per device via statusA/statusB/ statusC as comma-separated, case-insensitive lists.
Contributor
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="util/homeassistant/connection_test.go" line_range="49-55" />
<code_context>
}
}
+func TestGetChargeStatus(t *testing.T) {
+ states, err := NewStatusMap("not_plugged", "Charging_Stopped, charging_error", "instant_charging")
+ require.NoError(t, err)
+
+ tests := []struct {
+ state string
+ want api.ChargeStatus
+ }{
+ {"A", api.StatusA},
+ {"connected", api.StatusB},
+ {" charging ", api.StatusC},
+ {"not_plugged", api.StatusA},
+ {"CHARGING_STOPPED", api.StatusB},
+ {"charging_error", api.StatusB},
+ {"instant_charging", api.StatusC},
+ {"paused", api.StatusNone}, // no longer built-in
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.state, func(t *testing.T) {
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, `{"entity_id":"sensor.foo","state":%q}`, tc.state)
+ }))
+ defer srv.Close()
+
+ status, err := newTestConnection(srv.URL).GetChargeStatus("sensor.foo", states)
+ assert.Equal(t, tc.want, status)
+ if tc.want == api.StatusNone {
</code_context>
<issue_to_address>
**suggestion (testing):** Add assertions on the error message content for unknown states to fully pin down the new behaviour
For the `paused` case we only assert that `err` is non-nil. Given `GetChargeStatus` now formats errors as `unknown charge status '%s' for entity %s`, please also assert that the error string includes the raw state (`paused`) and the entity ID. This will exercise the new diagnostics behaviour and protect against regressions in the error formatting.
```suggestion
status, err := newTestConnection(srv.URL).GetChargeStatus("sensor.foo", states)
assert.Equal(t, tc.want, status)
if tc.want == api.StatusNone {
assert.Error(t, err)
// exercise diagnostics for unknown states (e.g. "paused")
assert.Contains(t, err.Error(), tc.state)
assert.Contains(t, err.Error(), "sensor.foo")
} else {
assert.NoError(t, err)
}
```
</issue_to_address>
### Comment 2
<location path="util/homeassistant/connection_test.go" line_range="60-62" />
<code_context>
+ }
+}
+
+func TestNewStatusMapDuplicate(t *testing.T) {
+ _, err := NewStatusMap("foo", "foo", "")
+ assert.Error(t, err)
+}
+
</code_context>
<issue_to_address>
**suggestion (testing):** Extend NewStatusMap tests to cover duplicates within a single list and the happy-path mapping
Currently, duplicates are only tested across different lists. Please also add a case for duplicates within a single list (e.g. `NewStatusMap(
Suggested implementation:
```golang
func TestNewStatusMapDuplicate(t *testing.T) {
t.Run("duplicate across lists", func(t *testing.T) {
_, err := NewStatusMap("foo", "foo", "")
assert.Error(t, err)
})
t.Run("duplicate within single list", func(t *testing.T) {
_, err := NewStatusMap("foo,foo", "", "")
assert.Error(t, err)
})
}
func TestNewStatusMapMapping(t *testing.T) {
statusMap, err := NewStatusMap("none", "charging", "disconnected")
assert.NoError(t, err)
assert.Equal(t, api.StatusNone, statusMap["none"])
assert.Equal(t, api.StatusC, statusMap["charging"])
assert.Equal(t, api.StatusB, statusMap["disconnected"])
}
```
1. Adjust the arguments to `NewStatusMap` in `TestNewStatusMapMapping` (`"none"`, `"charging"`, `"disconnected"`) to match the actual Home Assistant status strings used in your implementation.
2. Update the expected `api.Status*` values (`StatusNone`, `StatusC`, `StatusB`) so they reflect the real mapping that `NewStatusMap` is supposed to produce.
3. If `assert` from `testify` is not yet imported in this file, add `github.com/stretchr/testify/assert` to the import block; if you prefer using `require` for the `NoError` check, import `github.com/stretchr/testify/require` and swap `assert.NoError` for `require.NoError`.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #32115.
Instead of growing the built-in Home Assistant charge status mapping with every vendor's wording, the mapping keeps only the states whose meaning is unambiguous and vendor-specific states become a per-device config option.
Built-in mapping (
util/homeassistant):a,disconnected,not_pluggedb,connected,plugged,starting,stopped,paused,complete,charging_completedc,chargingRemoved (BC):
on,true,active,1,2,0,off,none,ready,initialising,preparing,no_power,notreadyforcharging.unknown/unavailablewere dead entries sinceGetStatealready returnsapi.ErrNotAvailablefor them.New per-device option for charger and vehicle, comma-separated and case-insensitive. It extends the built-in mapping and overrides it only for the states it explicitly redefines:
Templates get
statusA/statusB/statusCas advanced params. Duplicate states across the three lists are rejected at config time, and an unmapped state now reports the raw value and entity so users know what to put into the lists.One thing to decide: since
on/off/true/false/1/0are gone, abinary_sensorused as status entity now needsstatusA: off+statusC: on. The charger template still offersbinary_sensorin the status entity picker. Happy to keepon/offbuilt-in if that is too sharp an edge.ioBroker is not affected: its charger template renders a
customcharger, so status goes throughapi.ChargeStatusStringand only ever accepted A/B/C.🤖 Generated with Claude Code