diff --git a/homeassistant/components/shelly/climate.py b/homeassistant/components/shelly/climate.py index 2027cf73d25..04c211a98cb 100644 --- a/homeassistant/components/shelly/climate.py +++ b/homeassistant/components/shelly/climate.py @@ -20,6 +20,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature from homeassistant.core import HomeAssistant, State, callback from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import issue_registry as ir from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -33,7 +34,12 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.util.unit_conversion import TemperatureConverter from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM -from .const import LOGGER, SHTRV_01_TEMPERATURE_SETTINGS +from .const import ( + DOMAIN, + LOGGER, + NOT_CALIBRATED_ISSUE_ID, + SHTRV_01_TEMPERATURE_SETTINGS, +) from .coordinator import ShellyBlockCoordinator, get_entry_data @@ -339,6 +345,27 @@ class BlockSleepingClimate( self.async_write_ha_state() return + if self.coordinator.device.status.get("calibrated") is False: + ir.async_create_issue( + self.hass, + DOMAIN, + NOT_CALIBRATED_ISSUE_ID.format(unique=self.coordinator.mac), + is_fixable=False, + is_persistent=False, + severity=ir.IssueSeverity.ERROR, + translation_key="device_not_calibrated", + translation_placeholders={ + "device_name": self.name, + "ip_address": self.coordinator.device.ip_address, + }, + ) + else: + ir.async_delete_issue( + self.hass, + DOMAIN, + NOT_CALIBRATED_ISSUE_ID.format(unique=self.coordinator.mac), + ) + assert self.coordinator.device.blocks for block in self.coordinator.device.blocks: diff --git a/homeassistant/components/shelly/const.py b/homeassistant/components/shelly/const.py index e678f92c480..608798976ba 100644 --- a/homeassistant/components/shelly/const.py +++ b/homeassistant/components/shelly/const.py @@ -178,3 +178,5 @@ class BLEScannerMode(StrEnum): MAX_PUSH_UPDATE_FAILURES = 5 PUSH_UPDATE_ISSUE_ID = "push_update_{unique}" + +NOT_CALIBRATED_ISSUE_ID = "not_calibrated_{unique}" diff --git a/homeassistant/components/shelly/strings.json b/homeassistant/components/shelly/strings.json index 7c3f6033d07..6ff48f5b85b 100644 --- a/homeassistant/components/shelly/strings.json +++ b/homeassistant/components/shelly/strings.json @@ -120,6 +120,10 @@ } }, "issues": { + "device_not_calibrated": { + "title": "Shelly device {device_name} is not calibrated", + "description": "Shelly device {device_name} with IP address {ip_address} requires calibration. To calibrate the device, it must be rebooted after proper installation on the valve. You can reboot the device in its web panel, go to 'Settings' > 'Device Reboot'." + }, "push_update_failure": { "title": "Shelly device {device_name} push update failure", "description": "Home Assistant is not receiving push updates from the Shelly device {device_name} with IP address {ip_address}. Check the CoIoT configuration in the web panel of the device and your network configuration." diff --git a/tests/components/shelly/test_climate.py b/tests/components/shelly/test_climate.py index 505d1d463e8..c806cb5e742 100644 --- a/tests/components/shelly/test_climate.py +++ b/tests/components/shelly/test_climate.py @@ -21,9 +21,11 @@ from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant, State from homeassistant.exceptions import HomeAssistantError +import homeassistant.helpers.issue_registry as ir from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM -from . import init_integration, register_device, register_entity +from . import MOCK_MAC, init_integration, register_device, register_entity +from .conftest import MOCK_STATUS_COAP from tests.common import mock_restore_cache, mock_restore_cache_with_extra_data @@ -486,3 +488,43 @@ async def test_block_restored_climate_auth_error( assert "context" in flow assert flow["context"].get("source") == SOURCE_REAUTH assert flow["context"].get("entry_id") == entry.entry_id + + +async def test_device_not_calibrated( + hass: HomeAssistant, mock_block_device, monkeypatch +) -> None: + """Test to create an issue when the device is not calibrated.""" + issue_registry: ir.IssueRegistry = ir.async_get(hass) + + await init_integration(hass, 1, sleep_period=1000, model="SHTRV-01") + + # Make device online + mock_block_device.mock_update() + await hass.async_block_till_done() + + mock_status = MOCK_STATUS_COAP.copy() + mock_status["calibrated"] = False + monkeypatch.setattr( + mock_block_device, + "status", + mock_status, + ) + mock_block_device.mock_update() + await hass.async_block_till_done() + + assert issue_registry.async_get_issue( + domain=DOMAIN, issue_id=f"not_calibrated_{MOCK_MAC}" + ) + + # The device has been calibrated + monkeypatch.setattr( + mock_block_device, + "status", + MOCK_STATUS_COAP, + ) + mock_block_device.mock_update() + await hass.async_block_till_done() + + assert not issue_registry.async_get_issue( + domain=DOMAIN, issue_id=f"not_calibrated_{MOCK_MAC}" + )