mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Merge pull request #62882 from home-assistant/rc
This commit is contained in:
commit
dfe193b277
@ -3,7 +3,7 @@
|
||||
"name": "Home Assistant Frontend",
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"requirements": [
|
||||
"home-assistant-frontend==20211220.0"
|
||||
"home-assistant-frontend==20211227.0"
|
||||
],
|
||||
"dependencies": [
|
||||
"api",
|
||||
|
@ -641,6 +641,8 @@ class EnergyStorageTrait(_Trait):
|
||||
def query_attributes(self):
|
||||
"""Return EnergyStorage query attributes."""
|
||||
battery_level = self.state.attributes.get(ATTR_BATTERY_LEVEL)
|
||||
if battery_level is None:
|
||||
return {}
|
||||
if battery_level == 100:
|
||||
descriptive_capacity_remaining = "FULL"
|
||||
elif 75 <= battery_level < 100:
|
||||
|
@ -145,6 +145,7 @@ class HueBaseEntity(Entity):
|
||||
if self.device.product_data.certified:
|
||||
# certified products report their state correctly
|
||||
self._ignore_availability = False
|
||||
return
|
||||
# some (3th party) Hue lights report their connection status incorrectly
|
||||
# causing the zigbee availability to report as disconnected while in fact
|
||||
# it can be controlled. Although this is in fact something the device manufacturer
|
||||
|
@ -3,11 +3,13 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Any, Literal
|
||||
|
||||
from homeassistant.components.sensor import SensorEntityDescription
|
||||
from homeassistant.const import CURRENCY_EURO, DEVICE_CLASS_TIMESTAMP
|
||||
from homeassistant.helpers.typing import StateType
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
DOMAIN = "picnic"
|
||||
|
||||
@ -42,7 +44,7 @@ class PicnicRequiredKeysMixin:
|
||||
"""Mixin for required keys."""
|
||||
|
||||
data_type: Literal["cart_data", "slot_data", "last_order_data"]
|
||||
value_fn: Callable[[Any], StateType]
|
||||
value_fn: Callable[[Any], StateType | datetime]
|
||||
|
||||
|
||||
@dataclass
|
||||
@ -73,7 +75,7 @@ SENSOR_TYPES: tuple[PicnicSensorEntityDescription, ...] = (
|
||||
icon="mdi:calendar-start",
|
||||
entity_registry_enabled_default=True,
|
||||
data_type="slot_data",
|
||||
value_fn=lambda slot: slot.get("window_start"),
|
||||
value_fn=lambda slot: dt_util.parse_datetime(str(slot.get("window_start"))),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_SELECTED_SLOT_END,
|
||||
@ -81,7 +83,7 @@ SENSOR_TYPES: tuple[PicnicSensorEntityDescription, ...] = (
|
||||
icon="mdi:calendar-end",
|
||||
entity_registry_enabled_default=True,
|
||||
data_type="slot_data",
|
||||
value_fn=lambda slot: slot.get("window_end"),
|
||||
value_fn=lambda slot: dt_util.parse_datetime(str(slot.get("window_end"))),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_SELECTED_SLOT_MAX_ORDER_TIME,
|
||||
@ -89,7 +91,7 @@ SENSOR_TYPES: tuple[PicnicSensorEntityDescription, ...] = (
|
||||
icon="mdi:clock-alert-outline",
|
||||
entity_registry_enabled_default=True,
|
||||
data_type="slot_data",
|
||||
value_fn=lambda slot: slot.get("cut_off_time"),
|
||||
value_fn=lambda slot: dt_util.parse_datetime(str(slot.get("cut_off_time"))),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_SELECTED_SLOT_MIN_ORDER_VALUE,
|
||||
@ -108,14 +110,18 @@ SENSOR_TYPES: tuple[PicnicSensorEntityDescription, ...] = (
|
||||
device_class=DEVICE_CLASS_TIMESTAMP,
|
||||
icon="mdi:calendar-start",
|
||||
data_type="last_order_data",
|
||||
value_fn=lambda last_order: last_order.get("slot", {}).get("window_start"),
|
||||
value_fn=lambda last_order: dt_util.parse_datetime(
|
||||
str(last_order.get("slot", {}).get("window_start"))
|
||||
),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_LAST_ORDER_SLOT_END,
|
||||
device_class=DEVICE_CLASS_TIMESTAMP,
|
||||
icon="mdi:calendar-end",
|
||||
data_type="last_order_data",
|
||||
value_fn=lambda last_order: last_order.get("slot", {}).get("window_end"),
|
||||
value_fn=lambda last_order: dt_util.parse_datetime(
|
||||
str(last_order.get("slot", {}).get("window_end"))
|
||||
),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_LAST_ORDER_STATUS,
|
||||
@ -129,7 +135,9 @@ SENSOR_TYPES: tuple[PicnicSensorEntityDescription, ...] = (
|
||||
icon="mdi:clock-start",
|
||||
entity_registry_enabled_default=True,
|
||||
data_type="last_order_data",
|
||||
value_fn=lambda last_order: last_order.get("eta", {}).get("start"),
|
||||
value_fn=lambda last_order: dt_util.parse_datetime(
|
||||
str(last_order.get("eta", {}).get("start"))
|
||||
),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_LAST_ORDER_ETA_END,
|
||||
@ -137,7 +145,9 @@ SENSOR_TYPES: tuple[PicnicSensorEntityDescription, ...] = (
|
||||
icon="mdi:clock-end",
|
||||
entity_registry_enabled_default=True,
|
||||
data_type="last_order_data",
|
||||
value_fn=lambda last_order: last_order.get("eta", {}).get("end"),
|
||||
value_fn=lambda last_order: dt_util.parse_datetime(
|
||||
str(last_order.get("eta", {}).get("end"))
|
||||
),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_LAST_ORDER_DELIVERY_TIME,
|
||||
@ -145,7 +155,9 @@ SENSOR_TYPES: tuple[PicnicSensorEntityDescription, ...] = (
|
||||
icon="mdi:timeline-clock",
|
||||
entity_registry_enabled_default=True,
|
||||
data_type="last_order_data",
|
||||
value_fn=lambda last_order: last_order.get("delivery_time", {}).get("start"),
|
||||
value_fn=lambda last_order: dt_util.parse_datetime(
|
||||
str(last_order.get("delivery_time", {}).get("start"))
|
||||
),
|
||||
),
|
||||
PicnicSensorEntityDescription(
|
||||
key=SENSOR_LAST_ORDER_TOTAL_PRICE,
|
||||
|
@ -60,11 +60,11 @@ class PicnicUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""Fetch the data from the Picnic API and return a flat dict with only needed sensor data."""
|
||||
# Fetch from the API and pre-process the data
|
||||
cart = self.picnic_api_client.get_cart()
|
||||
last_order = self._get_last_order()
|
||||
|
||||
if not cart or not last_order:
|
||||
if not cart:
|
||||
raise UpdateFailed("API response doesn't contain expected data.")
|
||||
|
||||
last_order = self._get_last_order()
|
||||
slot_data = self._get_slot_data(cart)
|
||||
|
||||
return {
|
||||
@ -102,11 +102,12 @@ class PicnicUpdateCoordinator(DataUpdateCoordinator):
|
||||
"""Get data of the last order from the list of deliveries."""
|
||||
# Get the deliveries
|
||||
deliveries = self.picnic_api_client.get_deliveries(summary=True)
|
||||
if not deliveries:
|
||||
return {}
|
||||
|
||||
# Determine the last order
|
||||
last_order = copy.deepcopy(deliveries[0])
|
||||
# Determine the last order and return an empty dict if there is none
|
||||
try:
|
||||
last_order = copy.deepcopy(deliveries[0])
|
||||
except KeyError:
|
||||
return {}
|
||||
|
||||
# Get the position details if the order is not delivered yet
|
||||
delivery_position = {}
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Definition of Picnic sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, cast
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
@ -62,8 +63,8 @@ class PicnicSensor(SensorEntity, CoordinatorEntity):
|
||||
self._attr_unique_id = f"{config_entry.unique_id}.{description.key}"
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the state of the entity."""
|
||||
def native_value(self) -> StateType | datetime:
|
||||
"""Return the value reported by the sensor."""
|
||||
data_set = (
|
||||
self.coordinator.data.get(self.entity_description.data_type, {})
|
||||
if self.coordinator.data is not None
|
||||
@ -73,8 +74,8 @@ class PicnicSensor(SensorEntity, CoordinatorEntity):
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return True if entity is available."""
|
||||
return self.coordinator.last_update_success and self.state is not None
|
||||
"""Return True if last update was successful."""
|
||||
return self.coordinator.last_update_success
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "iRobot Roomba and Braava",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/roomba",
|
||||
"requirements": ["roombapy==1.6.4"],
|
||||
"requirements": ["roombapy==1.6.5"],
|
||||
"codeowners": ["@pschmitt", "@cyr-ius", "@shenxn"],
|
||||
"dhcp": [
|
||||
{
|
||||
|
@ -283,6 +283,7 @@ RPC_SENSORS: Final = {
|
||||
device_class=sensor.DEVICE_CLASS_TEMPERATURE,
|
||||
state_class=sensor.STATE_CLASS_MEASUREMENT,
|
||||
default_enabled=False,
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
),
|
||||
"rssi": RpcAttributeDescription(
|
||||
key="wifi",
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "Sonos",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/sonos",
|
||||
"requirements": ["soco==0.25.1"],
|
||||
"requirements": ["soco==0.25.2"],
|
||||
"dependencies": ["ssdp"],
|
||||
"after_dependencies": ["plex", "zeroconf"],
|
||||
"zeroconf": ["_sonos._tcp.local."],
|
||||
|
@ -482,7 +482,7 @@ class SonosSpeaker:
|
||||
|
||||
for bool_var in (
|
||||
"dialog_level",
|
||||
"night_mode",
|
||||
"night_level",
|
||||
"sub_enabled",
|
||||
"surround_enabled",
|
||||
):
|
||||
@ -965,7 +965,7 @@ class SonosSpeaker:
|
||||
self.volume = self.soco.volume
|
||||
self.muted = self.soco.mute
|
||||
self.night_mode = self.soco.night_mode
|
||||
self.dialog_level = self.soco.dialog_mode
|
||||
self.dialog_level = self.soco.dialog_level
|
||||
self.bass = self.soco.bass
|
||||
self.treble = self.soco.treble
|
||||
|
||||
|
@ -36,7 +36,7 @@ ATTR_INCLUDE_LINKED_ZONES = "include_linked_zones"
|
||||
|
||||
ATTR_CROSSFADE = "cross_fade"
|
||||
ATTR_NIGHT_SOUND = "night_mode"
|
||||
ATTR_SPEECH_ENHANCEMENT = "dialog_mode"
|
||||
ATTR_SPEECH_ENHANCEMENT = "dialog_level"
|
||||
ATTR_STATUS_LIGHT = "status_light"
|
||||
ATTR_SUB_ENABLED = "sub_enabled"
|
||||
ATTR_SURROUND_ENABLED = "surround_enabled"
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "tuya",
|
||||
"name": "Tuya",
|
||||
"documentation": "https://www.home-assistant.io/integrations/tuya",
|
||||
"requirements": ["tuya-iot-py-sdk==0.6.3"],
|
||||
"requirements": ["tuya-iot-py-sdk==0.6.6"],
|
||||
"dependencies": ["ffmpeg"],
|
||||
"codeowners": ["@Tuya", "@zlinoliver", "@METISU", "@frenck"],
|
||||
"config_flow": true,
|
||||
|
@ -3,7 +3,7 @@
|
||||
"name": "YouLess",
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/youless",
|
||||
"requirements": ["youless-api==0.15"],
|
||||
"requirements": ["youless-api==0.16"],
|
||||
"codeowners": ["@gjong"],
|
||||
"iot_class": "local_polling"
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"domain": "zeroconf",
|
||||
"name": "Zero-configuration networking (zeroconf)",
|
||||
"documentation": "https://www.home-assistant.io/integrations/zeroconf",
|
||||
"requirements": ["zeroconf==0.37.0"],
|
||||
"requirements": ["zeroconf==0.38.1"],
|
||||
"dependencies": ["network", "api"],
|
||||
"codeowners": ["@bdraco"],
|
||||
"quality_scale": "internal",
|
||||
|
@ -7,7 +7,7 @@ from homeassistant.backports.enum import StrEnum
|
||||
|
||||
MAJOR_VERSION: Final = 2021
|
||||
MINOR_VERSION: Final = 12
|
||||
PATCH_VERSION: Final = "5"
|
||||
PATCH_VERSION: Final = "6"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 8, 0)
|
||||
|
@ -16,7 +16,7 @@ ciso8601==2.2.0
|
||||
cryptography==35.0.0
|
||||
emoji==1.5.0
|
||||
hass-nabucasa==0.50.0
|
||||
home-assistant-frontend==20211220.0
|
||||
home-assistant-frontend==20211227.0
|
||||
httpx==0.21.0
|
||||
ifaddr==0.1.7
|
||||
jinja2==3.0.3
|
||||
@ -33,7 +33,7 @@ sqlalchemy==1.4.27
|
||||
voluptuous-serialize==2.5.0
|
||||
voluptuous==0.12.2
|
||||
yarl==1.6.3
|
||||
zeroconf==0.37.0
|
||||
zeroconf==0.38.1
|
||||
|
||||
pycryptodome>=3.6.6
|
||||
|
||||
|
@ -820,7 +820,7 @@ hole==0.7.0
|
||||
holidays==0.11.3.1
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20211220.0
|
||||
home-assistant-frontend==20211227.0
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.10
|
||||
@ -2074,7 +2074,7 @@ rocketchat-API==0.6.1
|
||||
rokuecp==0.8.4
|
||||
|
||||
# homeassistant.components.roomba
|
||||
roombapy==1.6.4
|
||||
roombapy==1.6.5
|
||||
|
||||
# homeassistant.components.roon
|
||||
roonapi==0.0.38
|
||||
@ -2185,7 +2185,7 @@ smhi-pkg==1.0.15
|
||||
snapcast==2.1.3
|
||||
|
||||
# homeassistant.components.sonos
|
||||
soco==0.25.1
|
||||
soco==0.25.2
|
||||
|
||||
# homeassistant.components.solaredge_local
|
||||
solaredge-local==0.2.0
|
||||
@ -2339,7 +2339,7 @@ tp-connected==0.0.4
|
||||
transmissionrpc==0.11
|
||||
|
||||
# homeassistant.components.tuya
|
||||
tuya-iot-py-sdk==0.6.3
|
||||
tuya-iot-py-sdk==0.6.6
|
||||
|
||||
# homeassistant.components.twentemilieu
|
||||
twentemilieu==0.5.0
|
||||
@ -2475,7 +2475,7 @@ yeelight==0.7.8
|
||||
yeelightsunflower==0.0.10
|
||||
|
||||
# homeassistant.components.youless
|
||||
youless-api==0.15
|
||||
youless-api==0.16
|
||||
|
||||
# homeassistant.components.media_extractor
|
||||
youtube_dl==2021.06.06
|
||||
@ -2484,7 +2484,7 @@ youtube_dl==2021.06.06
|
||||
zengge==0.2
|
||||
|
||||
# homeassistant.components.zeroconf
|
||||
zeroconf==0.37.0
|
||||
zeroconf==0.38.1
|
||||
|
||||
# homeassistant.components.zha
|
||||
zha-quirks==0.0.65
|
||||
|
@ -515,7 +515,7 @@ hole==0.7.0
|
||||
holidays==0.11.3.1
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20211220.0
|
||||
home-assistant-frontend==20211227.0
|
||||
|
||||
# homeassistant.components.zwave
|
||||
homeassistant-pyozw==0.1.10
|
||||
@ -1236,7 +1236,7 @@ ring_doorbell==0.7.2
|
||||
rokuecp==0.8.4
|
||||
|
||||
# homeassistant.components.roomba
|
||||
roombapy==1.6.4
|
||||
roombapy==1.6.5
|
||||
|
||||
# homeassistant.components.roon
|
||||
roonapi==0.0.38
|
||||
@ -1291,7 +1291,7 @@ smarthab==0.21
|
||||
smhi-pkg==1.0.15
|
||||
|
||||
# homeassistant.components.sonos
|
||||
soco==0.25.1
|
||||
soco==0.25.2
|
||||
|
||||
# homeassistant.components.solaredge
|
||||
solaredge==0.0.2
|
||||
@ -1376,7 +1376,7 @@ total_connect_client==2021.12
|
||||
transmissionrpc==0.11
|
||||
|
||||
# homeassistant.components.tuya
|
||||
tuya-iot-py-sdk==0.6.3
|
||||
tuya-iot-py-sdk==0.6.6
|
||||
|
||||
# homeassistant.components.twentemilieu
|
||||
twentemilieu==0.5.0
|
||||
@ -1470,10 +1470,10 @@ yalexs==1.1.13
|
||||
yeelight==0.7.8
|
||||
|
||||
# homeassistant.components.youless
|
||||
youless-api==0.15
|
||||
youless-api==0.16
|
||||
|
||||
# homeassistant.components.zeroconf
|
||||
zeroconf==0.37.0
|
||||
zeroconf==0.38.1
|
||||
|
||||
# homeassistant.components.zha
|
||||
zha-quirks==0.0.65
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""The tests for the Picnic sensor platform."""
|
||||
import copy
|
||||
from datetime import timedelta
|
||||
from typing import Dict
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
@ -15,6 +16,7 @@ from homeassistant.const import (
|
||||
CURRENCY_EURO,
|
||||
DEVICE_CLASS_TIMESTAMP,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
from homeassistant.util import dt
|
||||
@ -103,6 +105,7 @@ class TestPicnicSensor(unittest.IsolatedAsyncioTestCase):
|
||||
# Patch the api client
|
||||
self.picnic_patcher = patch("homeassistant.components.picnic.PicnicAPI")
|
||||
self.picnic_mock = self.picnic_patcher.start()
|
||||
self.picnic_mock().session.auth_token = "3q29fpwhulzes"
|
||||
|
||||
# Add a config entry and setup the integration
|
||||
config_data = {
|
||||
@ -281,13 +284,11 @@ class TestPicnicSensor(unittest.IsolatedAsyncioTestCase):
|
||||
await self._setup_platform()
|
||||
|
||||
# Assert sensors are unknown
|
||||
self._assert_sensor("sensor.picnic_selected_slot_start", STATE_UNAVAILABLE)
|
||||
self._assert_sensor("sensor.picnic_selected_slot_end", STATE_UNAVAILABLE)
|
||||
self._assert_sensor("sensor.picnic_selected_slot_start", STATE_UNKNOWN)
|
||||
self._assert_sensor("sensor.picnic_selected_slot_end", STATE_UNKNOWN)
|
||||
self._assert_sensor("sensor.picnic_selected_slot_max_order_time", STATE_UNKNOWN)
|
||||
self._assert_sensor(
|
||||
"sensor.picnic_selected_slot_max_order_time", STATE_UNAVAILABLE
|
||||
)
|
||||
self._assert_sensor(
|
||||
"sensor.picnic_selected_slot_min_order_value", STATE_UNAVAILABLE
|
||||
"sensor.picnic_selected_slot_min_order_value", STATE_UNKNOWN
|
||||
)
|
||||
|
||||
async def test_sensors_last_order_in_future(self):
|
||||
@ -304,7 +305,7 @@ class TestPicnicSensor(unittest.IsolatedAsyncioTestCase):
|
||||
await self._setup_platform()
|
||||
|
||||
# Assert delivery time is not available, but eta is
|
||||
self._assert_sensor("sensor.picnic_last_order_delivery_time", STATE_UNAVAILABLE)
|
||||
self._assert_sensor("sensor.picnic_last_order_delivery_time", STATE_UNKNOWN)
|
||||
self._assert_sensor(
|
||||
"sensor.picnic_last_order_eta_start", "2021-02-26T19:54:00+00:00"
|
||||
)
|
||||
@ -312,6 +313,25 @@ class TestPicnicSensor(unittest.IsolatedAsyncioTestCase):
|
||||
"sensor.picnic_last_order_eta_end", "2021-02-26T20:14:00+00:00"
|
||||
)
|
||||
|
||||
async def test_sensors_eta_date_malformed(self):
|
||||
"""Test sensor states when last order eta dates are malformed."""
|
||||
# Set-up platform with default mock responses
|
||||
await self._setup_platform(use_default_responses=True)
|
||||
|
||||
# Set non-datetime strings as eta
|
||||
eta_dates: Dict[str, str] = {
|
||||
"start": "wrong-time",
|
||||
"end": "other-malformed-datetime",
|
||||
}
|
||||
delivery_response = copy.deepcopy(DEFAULT_DELIVERY_RESPONSE)
|
||||
delivery_response["eta2"] = eta_dates
|
||||
self.picnic_mock().get_deliveries.return_value = [delivery_response]
|
||||
await self._coordinator.async_refresh()
|
||||
|
||||
# Assert eta times are not available due to malformed date strings
|
||||
self._assert_sensor("sensor.picnic_last_order_eta_start", STATE_UNKNOWN)
|
||||
self._assert_sensor("sensor.picnic_last_order_eta_end", STATE_UNKNOWN)
|
||||
|
||||
async def test_sensors_use_detailed_eta_if_available(self):
|
||||
"""Test sensor states when last order is not yet delivered."""
|
||||
# Set-up platform with default mock responses
|
||||
@ -367,6 +387,21 @@ class TestPicnicSensor(unittest.IsolatedAsyncioTestCase):
|
||||
self._assert_sensor("sensor.picnic_last_order_eta_end", STATE_UNAVAILABLE)
|
||||
self._assert_sensor("sensor.picnic_last_order_delivery_time", STATE_UNAVAILABLE)
|
||||
|
||||
async def test_sensors_malformed_delivery_data(self):
|
||||
"""Test sensor states when the delivery api returns not a list."""
|
||||
# Setup platform with default responses
|
||||
await self._setup_platform(use_default_responses=True)
|
||||
|
||||
# Change mock responses to empty data and refresh the coordinator
|
||||
self.picnic_mock().get_deliveries.return_value = {"error": "message"}
|
||||
await self._coordinator.async_refresh()
|
||||
|
||||
# Assert all last-order sensors have STATE_UNAVAILABLE because the delivery info fetch failed
|
||||
assert self._coordinator.last_update_success is True
|
||||
self._assert_sensor("sensor.picnic_last_order_eta_start", STATE_UNKNOWN)
|
||||
self._assert_sensor("sensor.picnic_last_order_eta_end", STATE_UNKNOWN)
|
||||
self._assert_sensor("sensor.picnic_last_order_delivery_time", STATE_UNKNOWN)
|
||||
|
||||
async def test_sensors_malformed_response(self):
|
||||
"""Test coordinator update fails when API yields ValueError."""
|
||||
# Setup platform with default responses
|
||||
|
@ -68,7 +68,7 @@ def soco_fixture(music_library, speaker_info, battery_info, alarm_clock):
|
||||
mock_soco.alarmClock = alarm_clock
|
||||
mock_soco.mute = False
|
||||
mock_soco.night_mode = True
|
||||
mock_soco.dialog_mode = True
|
||||
mock_soco.dialog_level = True
|
||||
mock_soco.volume = 19
|
||||
mock_soco.bass = 1
|
||||
mock_soco.treble = -1
|
||||
|
Loading…
x
Reference in New Issue
Block a user