Skip to content

Commit 4a76e0f

Browse files
committed
fix(energy): don't let a None-valued owned key clobber cloud in merge_local_into_cloud
PowerwallEnergySite.live_status() returns None for keys the gateway can't serve; the presence-only overlay check was letting that None win over a good cloud value. Claude-Session: https://claude.ai/code/session_01NJqvy4EqPJQwZbb2SGEHLh
1 parent b93c7ff commit 4a76e0f

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

tesla_fleet_api/router/energysite.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,17 @@ def merge_local_into_cloud(
3333
ownership test — a fixed owned-key set lets a caller overlay local
3434
readings without clobbering cloud values, and lets a local outage fall
3535
back to the cloud value instead of an unavailable one.
36+
37+
A key overlays only when it is owned, present in ``local``, and
38+
``local[key] is not None``; ``None`` means "not served this tick" and the
39+
cloud value is kept, while any other falsy value (``0``, ``False``, ``""``)
40+
still overlays.
3641
"""
3742
merged = dict(cloud)
3843
if local is None:
3944
return merged
4045
for key in owned_keys:
41-
if key in local:
46+
if key in local and local[key] is not None:
4247
merged[key] = local[key]
4348
return merged
4449

tests/test_energysite_merge_contract.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ def test_falsy_but_present_local_value_is_overlaid(self) -> None:
4040
result = merge_local_into_cloud(cloud, local, LOCAL_LIVE_STATUS_KEYS)
4141
self.assertEqual(result["grid_power"], 0)
4242

43+
def test_falsy_bool_local_value_is_overlaid(self) -> None:
44+
cloud = {"island_status": "on_grid"}
45+
local = {"island_status": False}
46+
result = merge_local_into_cloud(cloud, local, LOCAL_LIVE_STATUS_KEYS)
47+
self.assertEqual(result["island_status"], False)
48+
49+
def test_owned_key_present_with_none_keeps_cloud_value(self) -> None:
50+
cloud = {"solar_power": 100, "grid_power": 50}
51+
local = {"solar_power": None, "grid_power": 75}
52+
result = merge_local_into_cloud(cloud, local, LOCAL_LIVE_STATUS_KEYS)
53+
self.assertEqual(result["solar_power"], 100)
54+
self.assertEqual(result["grid_power"], 75)
55+
4356
def test_local_keys_outside_owned_set_are_ignored(self) -> None:
4457
cloud = {"solar_power": 100}
4558
local = {"solar_power": 200, "some_unowned_field": "surprise"}

0 commit comments

Comments
 (0)