diff --git a/homeassistant/components/template/cover.py b/homeassistant/components/template/cover.py index a61b9cb5e60e..787a6d63b29c 100644 --- a/homeassistant/components/template/cover.py +++ b/homeassistant/components/template/cover.py @@ -175,14 +175,17 @@ class CoverExtraStoredData(ExtraStoredData): return asdict(self) @classmethod - def from_dict(cls, restored: dict[str, Any]) -> Self: + def from_dict(cls, restored: dict[str, Any]) -> Self | None: """Initialize a stored cover state from a dict.""" - return cls( - current_cover_position=restored["current_cover_position"], - current_cover_tilt_position=restored["current_cover_tilt_position"], - is_opening=restored["is_opening"], - is_closing=restored["is_closing"], - ) + try: + return cls( + current_cover_position=restored["current_cover_position"], + current_cover_tilt_position=restored["current_cover_tilt_position"], + is_opening=restored["is_opening"], + is_closing=restored["is_closing"], + ) + except KeyError: + return None class AbstractTemplateCover(AbstractTemplateEntity, CoverEntity, RestoreEntity): diff --git a/homeassistant/components/template/device_tracker.py b/homeassistant/components/template/device_tracker.py index e0103fdf92ca..702b9fa24f2f 100644 --- a/homeassistant/components/template/device_tracker.py +++ b/homeassistant/components/template/device_tracker.py @@ -191,14 +191,17 @@ class TrackerExtraStoredData(ExtraStoredData): return asdict(self) @classmethod - def from_dict(cls, restored: dict[str, Any]) -> Self: + def from_dict(cls, restored: dict[str, Any]) -> Self | None: """Initialize a stored tracker state from a dict.""" - return cls( - in_zones=restored["in_zones"], - latitude=restored["latitude"], - longitude=restored["longitude"], - location_accuracy=restored["location_accuracy"], - ) + try: + return cls( + in_zones=restored["in_zones"], + latitude=restored["latitude"], + longitude=restored["longitude"], + location_accuracy=restored["location_accuracy"], + ) + except KeyError: + return None class AbstractTemplateTracker(AbstractTemplateEntity, TrackerEntity, RestoreEntity): diff --git a/homeassistant/components/template/fan.py b/homeassistant/components/template/fan.py index 5a8f221ae98a..ff87cc830057 100644 --- a/homeassistant/components/template/fan.py +++ b/homeassistant/components/template/fan.py @@ -175,28 +175,16 @@ class FanExtraStoredData(ExtraStoredData): @classmethod def from_dict(cls, restored: dict[str, Any]) -> Self | None: """Initialize a stored fan data from a dict.""" - is_on = restored.get("is_on") - percentage = restored.get("percentage") - preset_mode = restored.get("preset_mode") - oscillating = restored.get("oscillating") - direction = restored.get("direction") - if is_on is not None and not isinstance(is_on, bool): + try: + return cls( + is_on=restored["is_on"], + percentage=restored["percentage"], + preset_mode=restored["preset_mode"], + oscillating=restored["oscillating"], + direction=restored["direction"], + ) + except KeyError: return None - if percentage is not None and not isinstance(percentage, int): - return None - if preset_mode is not None and not isinstance(preset_mode, str): - return None - if oscillating is not None and not isinstance(oscillating, bool): - return None - if direction is not None and not isinstance(direction, str): - return None - return cls( - is_on=is_on, - percentage=percentage, - preset_mode=preset_mode, - oscillating=oscillating, - direction=direction, - ) class AbstractTemplateFan(AbstractTemplateEntity, FanEntity, RestoreEntity): diff --git a/tests/components/template/test_cover.py b/tests/components/template/test_cover.py index 9fe566ed877f..e28284904118 100644 --- a/tests/components/template/test_cover.py +++ b/tests/components/template/test_cover.py @@ -1192,6 +1192,21 @@ async def test_flow_preview( }, CoverState.OPEN, ), + ( + # Missing Key + CoverState.OPEN, + { + "current_cover_position": 0, + "current_cover_tilt_position": 10, + "is_closing": False, + }, + STATE_UNKNOWN, + { + "current_position": None, + "current_tilt_position": None, + }, + CoverState.OPEN, + ), ( STATE_UNAVAILABLE, { diff --git a/tests/components/template/test_device_tracker.py b/tests/components/template/test_device_tracker.py index 1eb3d54b490d..30ff477c20ad 100644 --- a/tests/components/template/test_device_tracker.py +++ b/tests/components/template/test_device_tracker.py @@ -684,6 +684,21 @@ async def test_flow_preview( "gps_accuracy": 10.0, }, ), + ( + # Missing Key + STATE_HOME, + { + "in_zones": [], + "location_accuracy": 10.0, + }, + STATE_UNKNOWN, + { + "in_zones": [], + "latitude": None, + "longitude": None, + "gps_accuracy": None, + }, + ), ( STATE_UNAVAILABLE, { diff --git a/tests/components/template/test_fan.py b/tests/components/template/test_fan.py index 1c2ad479f9bb..61b812ebe40e 100644 --- a/tests/components/template/test_fan.py +++ b/tests/components/template/test_fan.py @@ -1435,6 +1435,21 @@ async def test_flow_preview( "direction": DIRECTION_FORWARD, }, ), + ( + # Missing Key + STATE_ON, + { + "is_on": True, + "percentage": 0, + }, + STATE_UNKNOWN, + { + "percentage": None, + "preset_mode": None, + "oscillating": None, + "direction": None, + }, + ), ( STATE_UNAVAILABLE, {