Add error handling for all zwave_js service calls (#93846)

* Add error handling for all service calls

* Switch siren to use internal function

* Remove failing checks

* Revert change to poll service, add comments, and add additional error handling

* Add error handling for ping and refresh + review comment + add tests

* Add test for statistics entity refresh
This commit is contained in:
Raman Gupta 2023-05-31 11:09:01 -04:00 committed by GitHub
parent 927b59fe5a
commit bd8c88f51b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 191 additions and 69 deletions

View file

@ -5,6 +5,7 @@ from zwave_js_server.const.command_class.thermostat import (
THERMOSTAT_OPERATING_STATE_PROPERTY,
)
from zwave_js_server.event import Event
from zwave_js_server.exceptions import FailedZWaveCommand
from zwave_js_server.model.node import Node
from homeassistant.components.climate import (
@ -30,6 +31,7 @@ from homeassistant.components.climate import (
HVACMode,
)
from homeassistant.components.zwave_js.climate import ATTR_FAN_STATE
from homeassistant.components.zwave_js.const import DOMAIN, SERVICE_REFRESH_VALUE
from homeassistant.components.zwave_js.helpers import ZwaveValueMatcher
from homeassistant.const import (
ATTR_ENTITY_ID,
@ -49,7 +51,11 @@ from .common import (
async def test_thermostat_v2(
hass: HomeAssistant, client, climate_radio_thermostat_ct100_plus, integration
hass: HomeAssistant,
client,
climate_radio_thermostat_ct100_plus,
integration,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test a thermostat v2 command class entity."""
node = climate_radio_thermostat_ct100_plus
@ -280,6 +286,20 @@ async def test_thermostat_v2(
blocking=True,
)
# Refresh value should log an error when there is an issue
client.async_send_command.reset_mock()
client.async_send_command.side_effect = FailedZWaveCommand("test", 1, "test")
await hass.services.async_call(
DOMAIN,
SERVICE_REFRESH_VALUE,
{
ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
},
blocking=True,
)
assert "Error while refreshing value" in caplog.text
async def test_thermostat_different_endpoints(
hass: HomeAssistant,

View file

@ -1,4 +1,5 @@
"""Test the Z-Wave JS lock platform."""
import pytest
from zwave_js_server.const import CommandClass
from zwave_js_server.const.command_class.lock import (
ATTR_CODE_SLOT,
@ -6,6 +7,7 @@ from zwave_js_server.const.command_class.lock import (
CURRENT_MODE_PROPERTY,
)
from zwave_js_server.event import Event
from zwave_js_server.exceptions import FailedZWaveCommand
from zwave_js_server.model.node import Node, NodeStatus
from homeassistant.components.lock import (
@ -27,6 +29,7 @@ from homeassistant.const import (
STATE_UNLOCKED,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from .common import SCHLAGE_BE469_LOCK_ENTITY, replace_value_of_zwave_value
@ -153,6 +156,33 @@ async def test_door_lock(
}
assert args["value"] == 0
client.async_send_command.reset_mock()
client.async_send_command.side_effect = FailedZWaveCommand("test", 1, "test")
# Test set usercode service error handling
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
ZWAVE_JS_DOMAIN,
SERVICE_SET_LOCK_USERCODE,
{
ATTR_ENTITY_ID: SCHLAGE_BE469_LOCK_ENTITY,
ATTR_CODE_SLOT: 1,
ATTR_USERCODE: "1234",
},
blocking=True,
)
# Test clear usercode service error handling
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
ZWAVE_JS_DOMAIN,
SERVICE_CLEAR_LOCK_USERCODE,
{ATTR_ENTITY_ID: SCHLAGE_BE469_LOCK_ENTITY, ATTR_CODE_SLOT: 1},
blocking=True,
)
client.async_send_command.reset_mock()
event = Event(
type="dead",
data={

View file

@ -4,6 +4,7 @@ import copy
import pytest
from zwave_js_server.const.command_class.meter import MeterType
from zwave_js_server.event import Event
from zwave_js_server.exceptions import FailedZWaveCommand
from zwave_js_server.model.node import Node
from homeassistant.components.sensor import (
@ -39,6 +40,7 @@ from homeassistant.const import (
UnitOfTime,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity_registry as er
from .common import (
@ -420,6 +422,18 @@ async def test_reset_meter(
client.async_send_command_no_wait.reset_mock()
client.async_send_command_no_wait.side_effect = FailedZWaveCommand(
"test", 1, "test"
)
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
DOMAIN,
SERVICE_RESET_METER,
{ATTR_ENTITY_ID: METER_ENERGY_SENSOR},
blocking=True,
)
async def test_meter_attributes(
hass: HomeAssistant,
@ -609,7 +623,7 @@ NODE_STATISTICS_SUFFIXES_UNKNOWN = {
async def test_statistics_sensors(
hass: HomeAssistant, zp3111, client, integration
hass: HomeAssistant, zp3111, client, integration, caplog: pytest.LogCaptureFixture
) -> None:
"""Test statistics sensors."""
ent_reg = er.async_get(hass)
@ -730,10 +744,27 @@ async def test_statistics_sensors(
(NODE_STATISTICS_ENTITY_PREFIX, NODE_STATISTICS_SUFFIXES_UNKNOWN),
):
for suffix_key, val in suffixes.items():
state = hass.states.get(f"{prefix}{suffix_key}")
entity_id = f"{prefix}{suffix_key}"
state = hass.states.get(entity_id)
assert state
assert state.state == str(val)
await hass.services.async_call(
DOMAIN,
SERVICE_REFRESH_VALUE,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
assert caplog.text.count("There is no value to refresh for this entity") == len(
[
*CONTROLLER_STATISTICS_SUFFIXES,
*CONTROLLER_STATISTICS_SUFFIXES_UNKNOWN,
*NODE_STATISTICS_SUFFIXES,
*NODE_STATISTICS_SUFFIXES_UNKNOWN,
]
)
ENERGY_PRODUCTION_ENTITY_MAP = {
"energy_production_power": {

View file

@ -1539,6 +1539,18 @@ async def test_ping(
blocking=True,
)
client.async_send_command.reset_mock()
client.async_send_command.side_effect = FailedZWaveCommand("test", 1, "test")
with pytest.raises(HomeAssistantError):
await hass.services.async_call(
DOMAIN,
SERVICE_PING,
{
ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
},
blocking=True,
)
async def test_invoke_cc_api(
hass: HomeAssistant,