diff --git a/homeassistant/components/canary/alarm_control_panel.py b/homeassistant/components/canary/alarm_control_panel.py index 35fff8accbd..43290e9a345 100644 --- a/homeassistant/components/canary/alarm_control_panel.py +++ b/homeassistant/components/canary/alarm_control_panel.py @@ -24,10 +24,7 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Canary alarms.""" data = hass.data[DATA_CANARY] - devices = [] - - for location in data.locations: - devices.append(CanaryAlarm(data, location.location_id)) + devices = [CanaryAlarm(data, location.location_id) for location in data.locations] add_entities(devices, True) diff --git a/homeassistant/components/canary/camera.py b/homeassistant/components/canary/camera.py index 870256ffcff..3ba7f094da1 100644 --- a/homeassistant/components/canary/camera.py +++ b/homeassistant/components/canary/camera.py @@ -29,6 +29,9 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the Canary sensors.""" + if discovery_info is not None: + return + data = hass.data[DATA_CANARY] devices = [] diff --git a/homeassistant/components/hue/light.py b/homeassistant/components/hue/light.py index b808dd0594d..6157a7fde23 100644 --- a/homeassistant/components/hue/light.py +++ b/homeassistant/components/hue/light.py @@ -259,6 +259,9 @@ class HueLight(Light): else: bri = self.light.state.get("bri") + if bri is None: + return bri + return hue_brightness_to_hass(bri) @property diff --git a/homeassistant/components/icloud/account.py b/homeassistant/components/icloud/account.py index e0d9a608605..d039b270bb8 100644 --- a/homeassistant/components/icloud/account.py +++ b/homeassistant/components/icloud/account.py @@ -186,7 +186,7 @@ class IcloudAccount: DEVICE_STATUS_CODES.get(list(api_devices)[0][DEVICE_STATUS]) == "pending" and not self._retried_fetch ): - _LOGGER.warning("Pending devices, trying again in 15s") + _LOGGER.debug("Pending devices, trying again in 15s") self._fetch_interval = 0.25 self._retried_fetch = True else: diff --git a/homeassistant/components/icloud/manifest.json b/homeassistant/components/icloud/manifest.json index 2b8bc2fccae..40b58cbf2d0 100644 --- a/homeassistant/components/icloud/manifest.json +++ b/homeassistant/components/icloud/manifest.json @@ -3,6 +3,6 @@ "name": "Apple iCloud", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/icloud", - "requirements": ["pyicloud==0.9.6.1"], + "requirements": ["pyicloud==0.9.7"], "codeowners": ["@Quentame"] } diff --git a/homeassistant/components/roomba/__init__.py b/homeassistant/components/roomba/__init__.py index 28092f96477..9fb93211576 100644 --- a/homeassistant/components/roomba/__init__.py +++ b/homeassistant/components/roomba/__init__.py @@ -92,7 +92,6 @@ async def async_setup_entry(hass, config_entry): address=config_entry.data[CONF_HOST], blid=config_entry.data[CONF_BLID], password=config_entry.data[CONF_PASSWORD], - cert_name=config_entry.data[CONF_CERT], continuous=config_entry.options[CONF_CONTINUOUS], delay=config_entry.options[CONF_DELAY], ) diff --git a/homeassistant/components/roomba/config_flow.py b/homeassistant/components/roomba/config_flow.py index 3668984a41f..72ad6855d79 100644 --- a/homeassistant/components/roomba/config_flow.py +++ b/homeassistant/components/roomba/config_flow.py @@ -11,11 +11,9 @@ from homeassistant.core import callback from . import CannotConnect, async_connect_or_timeout, async_disconnect_or_timeout from .const import ( CONF_BLID, - CONF_CERT, CONF_CONTINUOUS, CONF_DELAY, CONF_NAME, - DEFAULT_CERT, DEFAULT_CONTINUOUS, DEFAULT_DELAY, ROOMBA_SESSION, @@ -27,7 +25,6 @@ DATA_SCHEMA = vol.Schema( vol.Required(CONF_HOST): str, vol.Required(CONF_BLID): str, vol.Required(CONF_PASSWORD): str, - vol.Optional(CONF_CERT, default=DEFAULT_CERT): str, vol.Optional(CONF_CONTINUOUS, default=DEFAULT_CONTINUOUS): bool, vol.Optional(CONF_DELAY, default=DEFAULT_DELAY): int, } @@ -45,7 +42,6 @@ async def validate_input(hass: core.HomeAssistant, data): address=data[CONF_HOST], blid=data[CONF_BLID], password=data[CONF_PASSWORD], - cert_name=data[CONF_CERT], continuous=data[CONF_CONTINUOUS], delay=data[CONF_DELAY], ) diff --git a/homeassistant/components/roomba/manifest.json b/homeassistant/components/roomba/manifest.json index b9e521ffc12..45fe9133bca 100644 --- a/homeassistant/components/roomba/manifest.json +++ b/homeassistant/components/roomba/manifest.json @@ -3,7 +3,7 @@ "name": "iRobot Roomba", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/roomba", - "requirements": ["roombapy==1.5.2"], + "requirements": ["roombapy==1.5.3"], "dependencies": [], "codeowners": ["@pschmitt", "@cyr-ius", "@shenxn"] } diff --git a/homeassistant/components/roomba/strings.json b/homeassistant/components/roomba/strings.json index a679b2fdbb5..b813f35883b 100644 --- a/homeassistant/components/roomba/strings.json +++ b/homeassistant/components/roomba/strings.json @@ -8,7 +8,6 @@ "host": "Hostname or IP Address", "blid": "BLID", "password": "Password", - "certificate": "Certificate", "continuous": "Continuous", "delay": "Delay" } diff --git a/homeassistant/components/synology_dsm/__init__.py b/homeassistant/components/synology_dsm/__init__.py index 3fbed6955d9..9431cb7b1c9 100644 --- a/homeassistant/components/synology_dsm/__init__.py +++ b/homeassistant/components/synology_dsm/__init__.py @@ -11,6 +11,7 @@ from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import ( CONF_DISKS, CONF_HOST, + CONF_MAC, CONF_PASSWORD, CONF_PORT, CONF_SSL, @@ -77,6 +78,13 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.unique_id] = api + # For SSDP compat + if not entry.data.get(CONF_MAC): + network = await hass.async_add_executor_job(getattr, api.dsm, "network") + hass.config_entries.async_update_entry( + entry, data={**entry.data, CONF_MAC: network.macs} + ) + hass.async_create_task( hass.config_entries.async_forward_entry_setup(entry, "sensor") ) @@ -115,7 +123,7 @@ class SynoApi: self._device_token = device_token self.temp_unit = temp_unit - self._dsm: SynologyDSM = None + self.dsm: SynologyDSM = None self.information: SynoDSMInformation = None self.utilisation: SynoCoreUtilization = None self.storage: SynoStorage = None @@ -129,7 +137,7 @@ class SynoApi: async def async_setup(self): """Start interacting with the NAS.""" - self._dsm = SynologyDSM( + self.dsm = SynologyDSM( self._host, self._port, self._username, @@ -147,9 +155,9 @@ class SynoApi: def _fetch_device_configuration(self): """Fetch initial device config.""" - self.information = self._dsm.information - self.utilisation = self._dsm.utilisation - self.storage = self._dsm.storage + self.information = self.dsm.information + self.utilisation = self.dsm.utilisation + self.storage = self.dsm.storage async def async_unload(self): """Stop interacting with the NAS and prepare for removal from hass.""" @@ -157,5 +165,5 @@ class SynoApi: async def update(self, now=None): """Update function for updating API information.""" - await self._hass.async_add_executor_job(self._dsm.update) + await self._hass.async_add_executor_job(self.dsm.update) async_dispatcher_send(self._hass, self.signal_sensor_update) diff --git a/homeassistant/components/synology_dsm/config_flow.py b/homeassistant/components/synology_dsm/config_flow.py index 4b09e516451..c3d15aff2fd 100644 --- a/homeassistant/components/synology_dsm/config_flow.py +++ b/homeassistant/components/synology_dsm/config_flow.py @@ -17,6 +17,7 @@ from homeassistant.components import ssdp from homeassistant.const import ( CONF_DISKS, CONF_HOST, + CONF_MAC, CONF_NAME, CONF_PASSWORD, CONF_PORT, @@ -145,6 +146,7 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): CONF_SSL: use_ssl, CONF_USERNAME: username, CONF_PASSWORD: password, + CONF_MAC: api.network.macs, } if otp_code: config_data["device_token"] = api.device_token @@ -162,16 +164,11 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): discovery_info[ssdp.ATTR_UPNP_FRIENDLY_NAME].split("(", 1)[0].strip() ) - if self._host_already_configured(parsed_url.hostname): + # Synology NAS can broadcast on multiple IP addresses, since they can be connected to multiple ethernets. + # The serial of the NAS is actually its MAC address. + if self._mac_already_configured(discovery_info[ssdp.ATTR_UPNP_SERIAL].upper()): return self.async_abort(reason="already_configured") - if ssdp.ATTR_UPNP_SERIAL in discovery_info: - # Synology can broadcast on multiple IP addresses - await self.async_set_unique_id( - discovery_info[ssdp.ATTR_UPNP_SERIAL].upper() - ) - self._abort_if_unique_id_configured() - self.discovered_conf = { CONF_NAME: friendly_name, CONF_HOST: parsed_url.hostname, @@ -205,12 +202,14 @@ class SynologyDSMFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): return await self.async_step_user(user_input) - def _host_already_configured(self, hostname): - """See if we already have a host matching user input configured.""" - existing_hosts = { - entry.data[CONF_HOST] for entry in self._async_current_entries() - } - return hostname in existing_hosts + def _mac_already_configured(self, mac): + """See if we already have configured a NAS with this MAC address.""" + existing_macs = [ + mac.replace("-", "") + for entry in self._async_current_entries() + for mac in entry.data.get(CONF_MAC, []) + ] + return mac in existing_macs def _login_and_fetch_syno_info(api, otp_code): @@ -221,10 +220,11 @@ def _login_and_fetch_syno_info(api, otp_code): storage = api.storage if ( - api.information.serial is None + not api.information.serial or utilisation.cpu_user_load is None - or storage.disks_ids is None - or storage.volumes_ids is None + or not storage.disks_ids + or not storage.volumes_ids + or not api.network.macs ): raise InvalidData diff --git a/homeassistant/components/synology_dsm/sensor.py b/homeassistant/components/synology_dsm/sensor.py index b6a88fe5a5a..8b5da35177e 100644 --- a/homeassistant/components/synology_dsm/sensor.py +++ b/homeassistant/components/synology_dsm/sensor.py @@ -152,7 +152,7 @@ class SynoNasUtilSensor(SynoNasSensor): attr = getattr(self._api.utilisation, self.sensor_type) if callable(attr): attr = attr() - if not attr: + if attr is None: return None # Data (RAM) @@ -173,7 +173,7 @@ class SynoNasStorageSensor(SynoNasSensor): def state(self): """Return the state.""" attr = getattr(self._api.storage, self.sensor_type)(self.monitored_device) - if not attr: + if attr is None: return None # Data (disk space) diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index c891c698cf6..c5b6e9a292c 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -95,7 +95,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= platform.async_register_entity_service( SERVICE_CALIBRATE_METER, - {vol.Required(ATTR_VALUE): vol.Coerce(float)}, + {vol.Required(ATTR_VALUE): vol.Coerce(Decimal)}, "async_calibrate", ) @@ -222,7 +222,7 @@ class UtilityMeterSensor(RestoreEntity): async def async_calibrate(self, value): """Calibrate the Utility Meter with a given value.""" _LOGGER.debug("Calibrate %s = %s", self._name, value) - self._state = Decimal(value) + self._state = value self.async_write_ha_state() async def async_added_to_hass(self): diff --git a/homeassistant/components/uvc/camera.py b/homeassistant/components/uvc/camera.py index 05937cc3ee9..5878023bf2e 100644 --- a/homeassistant/components/uvc/camera.py +++ b/homeassistant/components/uvc/camera.py @@ -192,11 +192,7 @@ class UnifiVideoCamera(Camera): def set_motion_detection(self, mode): """Set motion detection on or off.""" - - if mode is True: - set_mode = "motion" - else: - set_mode = "none" + set_mode = "motion" if mode is True else "none" try: self._nvr.set_recordmode(self._uuid, set_mode) @@ -215,9 +211,7 @@ class UnifiVideoCamera(Camera): async def stream_source(self): """Return the source of the stream.""" - caminfo = self._nvr.get_camera(self._uuid) - channels = caminfo["channels"] - for channel in channels: + for channel in self._caminfo["channels"]: if channel["isRtspEnabled"]: return channel["rtspUris"][0] diff --git a/homeassistant/components/websocket_api/manifest.json b/homeassistant/components/websocket_api/manifest.json index 76e2742b996..66dd76af769 100644 --- a/homeassistant/components/websocket_api/manifest.json +++ b/homeassistant/components/websocket_api/manifest.json @@ -1,6 +1,6 @@ { "domain": "websocket_api", - "name": "Home Asssitant WebSocket API", + "name": "Home Assistant WebSocket API", "documentation": "https://www.home-assistant.io/integrations/websocket_api", "dependencies": ["http"], "codeowners": ["@home-assistant/core"], diff --git a/homeassistant/const.py b/homeassistant/const.py index 91d6fe39921..b4b4041cdda 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 109 -PATCH_VERSION = "3" +PATCH_VERSION = "4" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) diff --git a/requirements_all.txt b/requirements_all.txt index 461f4d27d6d..34442550e13 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1342,7 +1342,7 @@ pyhomeworks==0.0.6 pyialarm==0.3 # homeassistant.components.icloud -pyicloud==0.9.6.1 +pyicloud==0.9.7 # homeassistant.components.intesishome pyintesishome==1.7.4 @@ -1825,7 +1825,7 @@ rocketchat-API==0.6.1 roku==4.1.0 # homeassistant.components.roomba -roombapy==1.5.2 +roombapy==1.5.3 # homeassistant.components.rova rova==0.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 56a3ac96310..5770d0562df 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -537,7 +537,7 @@ pyheos==0.6.0 pyhomematic==0.1.66 # homeassistant.components.icloud -pyicloud==0.9.6.1 +pyicloud==0.9.7 # homeassistant.components.ipma pyipma==2.0.5 @@ -701,7 +701,7 @@ ring_doorbell==0.6.0 roku==4.1.0 # homeassistant.components.roomba -roombapy==1.5.2 +roombapy==1.5.3 # homeassistant.components.yamaha rxv==0.6.0 diff --git a/tests/components/roomba/test_config_flow.py b/tests/components/roomba/test_config_flow.py index c9a0d8fde17..529b59dd8a6 100644 --- a/tests/components/roomba/test_config_flow.py +++ b/tests/components/roomba/test_config_flow.py @@ -5,7 +5,6 @@ from roomba import RoombaConnectionError from homeassistant import config_entries, data_entry_flow, setup from homeassistant.components.roomba.const import ( CONF_BLID, - CONF_CERT, CONF_CONTINUOUS, CONF_DELAY, DOMAIN, @@ -20,7 +19,6 @@ VALID_YAML_CONFIG = { CONF_HOST: "1.2.3.4", CONF_BLID: "blid", CONF_PASSWORD: "password", - CONF_CERT: "/etc/ssl/certs/ca-certificates.crt", CONF_CONTINUOUS: True, CONF_DELAY: 1, } @@ -69,7 +67,6 @@ async def test_form(hass): assert result2["result"].unique_id == "blid" assert result2["data"] == { CONF_BLID: "blid", - CONF_CERT: "/etc/ssl/certs/ca-certificates.crt", CONF_CONTINUOUS: True, CONF_DELAY: 1, CONF_HOST: "1.2.3.4", @@ -131,7 +128,6 @@ async def test_form_import(hass): assert result["title"] == "imported_roomba" assert result["data"] == { CONF_BLID: "blid", - CONF_CERT: "/etc/ssl/certs/ca-certificates.crt", CONF_CONTINUOUS: True, CONF_DELAY: 1, CONF_HOST: "1.2.3.4", diff --git a/tests/components/synology_dsm/test_config_flow.py b/tests/components/synology_dsm/test_config_flow.py index 66f752ffaf4..795348d900c 100644 --- a/tests/components/synology_dsm/test_config_flow.py +++ b/tests/components/synology_dsm/test_config_flow.py @@ -25,6 +25,7 @@ from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_SSDP, SOURCE_USER from homeassistant.const import ( CONF_DISKS, CONF_HOST, + CONF_MAC, CONF_PASSWORD, CONF_PORT, CONF_SSL, @@ -47,6 +48,8 @@ USERNAME = "Home_Assistant" PASSWORD = "password" DEVICE_TOKEN = "Dév!cè_T0k€ñ" +MACS = ["00-11-32-XX-XX-59", "00-11-32-XX-XX-5A"] + @pytest.fixture(name="service") def mock_controller_service(): @@ -56,8 +59,9 @@ def mock_controller_service(): ) as service_mock: service_mock.return_value.information.serial = SERIAL service_mock.return_value.utilisation.cpu_user_load = 1 - service_mock.return_value.storage.disks_ids = [] - service_mock.return_value.storage.volumes_ids = [] + service_mock.return_value.storage.disks_ids = ["sda", "sdb", "sdc"] + service_mock.return_value.storage.volumes_ids = ["volume_1"] + service_mock.return_value.network.macs = MACS yield service_mock @@ -72,8 +76,9 @@ def mock_controller_service_2sa(): ) service_mock.return_value.information.serial = SERIAL service_mock.return_value.utilisation.cpu_user_load = 1 - service_mock.return_value.storage.disks_ids = [] - service_mock.return_value.storage.volumes_ids = [] + service_mock.return_value.storage.disks_ids = ["sda", "sdb", "sdc"] + service_mock.return_value.storage.volumes_ids = ["volume_1"] + service_mock.return_value.network.macs = MACS yield service_mock @@ -85,8 +90,9 @@ def mock_controller_service_failed(): ) as service_mock: service_mock.return_value.information.serial = None service_mock.return_value.utilisation.cpu_user_load = None - service_mock.return_value.storage.disks_ids = None - service_mock.return_value.storage.volumes_ids = None + service_mock.return_value.storage.disks_ids = [] + service_mock.return_value.storage.volumes_ids = [] + service_mock.return_value.network.macs = [] yield service_mock @@ -118,6 +124,7 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD + assert result["data"][CONF_MAC] == MACS assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None @@ -142,6 +149,7 @@ async def test_user(hass: HomeAssistantType, service: MagicMock): assert not result["data"][CONF_SSL] assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD + assert result["data"][CONF_MAC] == MACS assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None @@ -183,6 +191,7 @@ async def test_user_2sa(hass: HomeAssistantType, service_2sa: MagicMock): assert result["data"][CONF_SSL] == DEFAULT_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD + assert result["data"][CONF_MAC] == MACS assert result["data"].get("device_token") == DEVICE_TOKEN assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None @@ -204,6 +213,7 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == DEFAULT_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD + assert result["data"][CONF_MAC] == MACS assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None @@ -231,6 +241,7 @@ async def test_import(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD + assert result["data"][CONF_MAC] == MACS assert result["data"].get("device_token") is None assert result["data"][CONF_DISKS] == ["sda", "sdb", "sdc"] assert result["data"][CONF_VOLUMES] == ["volume_1"] @@ -329,8 +340,13 @@ async def test_form_ssdp_already_configured( MockConfigEntry( domain=DOMAIN, - data={CONF_HOST: HOST, CONF_USERNAME: USERNAME, CONF_PASSWORD: PASSWORD}, - unique_id=SERIAL.upper(), + data={ + CONF_HOST: HOST, + CONF_USERNAME: USERNAME, + CONF_PASSWORD: PASSWORD, + CONF_MAC: MACS, + }, + unique_id=SERIAL, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( @@ -339,7 +355,7 @@ async def test_form_ssdp_already_configured( data={ ssdp.ATTR_SSDP_LOCATION: "http://192.168.1.5:5000", ssdp.ATTR_UPNP_FRIENDLY_NAME: "mydsm", - ssdp.ATTR_UPNP_SERIAL: SERIAL, + ssdp.ATTR_UPNP_SERIAL: "001132XXXX59", # Existing in MACS[0], but SSDP does not have `-` }, ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT @@ -355,7 +371,7 @@ async def test_form_ssdp(hass: HomeAssistantType, service: MagicMock): data={ ssdp.ATTR_SSDP_LOCATION: "http://192.168.1.5:5000", ssdp.ATTR_UPNP_FRIENDLY_NAME: "mydsm", - ssdp.ATTR_UPNP_SERIAL: SERIAL, + ssdp.ATTR_UPNP_SERIAL: "001132XXXX99", # MAC address, but SSDP does not have `-` }, ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM @@ -373,6 +389,7 @@ async def test_form_ssdp(hass: HomeAssistantType, service: MagicMock): assert result["data"][CONF_SSL] == DEFAULT_SSL assert result["data"][CONF_USERNAME] == USERNAME assert result["data"][CONF_PASSWORD] == PASSWORD + assert result["data"][CONF_MAC] == MACS assert result["data"].get("device_token") is None assert result["data"].get(CONF_DISKS) is None assert result["data"].get(CONF_VOLUMES) is None diff --git a/tests/components/utility_meter/test_sensor.py b/tests/components/utility_meter/test_sensor.py index 6118d74d0dd..b4ee618b54f 100644 --- a/tests/components/utility_meter/test_sensor.py +++ b/tests/components/utility_meter/test_sensor.py @@ -119,6 +119,17 @@ async def test_state(hass): assert state is not None assert state.state == "100" + await hass.services.async_call( + DOMAIN, + SERVICE_CALIBRATE_METER, + {ATTR_ENTITY_ID: "sensor.energy_bill_midpeak", ATTR_VALUE: "0.123"}, + blocking=True, + ) + await hass.async_block_till_done() + state = hass.states.get("sensor.energy_bill_midpeak") + assert state is not None + assert state.state == "0.123" + async def test_net_consumption(hass): """Test utility sensor state."""