diff --git a/homeassistant/components/zwave_js/discovery.py b/homeassistant/components/zwave_js/discovery.py index 7ef8138b8a3e90..cacb987e120283 100644 --- a/homeassistant/components/zwave_js/discovery.py +++ b/homeassistant/components/zwave_js/discovery.py @@ -1282,19 +1282,19 @@ def async_discover_single_value( continue # check firmware_version_range - if schema.firmware_version_range is not None and ( - ( + if schema.firmware_version_range is not None: + # skip schema if device firmware version is unknown + if value.node.firmware_version is None: + continue + node_firmware = AwesomeVersion(value.node.firmware_version) + if ( schema.firmware_version_range.min is not None - and schema.firmware_version_range.min_ver - > AwesomeVersion(value.node.firmware_version) - ) - or ( + and schema.firmware_version_range.min_ver > node_firmware + ) or ( schema.firmware_version_range.max is not None - and schema.firmware_version_range.max_ver - < AwesomeVersion(value.node.firmware_version) - ) - ): - continue + and schema.firmware_version_range.max_ver < node_firmware + ): + continue # check device_class_generic # If the value has an endpoint but it is missing on the node diff --git a/tests/components/zwave_js/conftest.py b/tests/components/zwave_js/conftest.py index 084c965e38ad6d..39cd50021d164d 100644 --- a/tests/components/zwave_js/conftest.py +++ b/tests/components/zwave_js/conftest.py @@ -1513,3 +1513,15 @@ def fibaro_fgms001_v2_8_fixture( node = Node(client, fibaro_fgms001_v2_8_state) client.driver.controller.nodes[node.node_id] = node return node + + +@pytest.fixture(name="fibaro_fgms001_unknown_firmware") +def fibaro_fgms001_unknown_firmware_fixture( + client: MagicMock, fibaro_fgms001_v2_8_state: NodeDataType +) -> Node: + """Load FGMS001 node with no reported firmware version.""" + state = copy.deepcopy(fibaro_fgms001_v2_8_state) + state.pop("firmwareVersion", None) + node = Node(client, state) + client.driver.controller.nodes[node.node_id] = node + return node diff --git a/tests/components/zwave_js/test_discovery.py b/tests/components/zwave_js/test_discovery.py index f5ec08d569401e..e08b14760182df 100644 --- a/tests/components/zwave_js/test_discovery.py +++ b/tests/components/zwave_js/test_discovery.py @@ -33,7 +33,7 @@ DynamicCurrentTempClimateDataTemplate, ) from homeassistant.components.zwave_js.helpers import get_device_id -from homeassistant.config_entries import RELOAD_AFTER_UPDATE_DELAY +from homeassistant.config_entries import RELOAD_AFTER_UPDATE_DELAY, ConfigEntryState from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, @@ -666,6 +666,40 @@ async def test_nabu_casa_zwa2_legacy( ) +@pytest.mark.parametrize("platforms", [[Platform.BINARY_SENSOR, Platform.LIGHT]]) +async def test_fibaro_fgms001_unknown_firmware_setup( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + device_registry: dr.DeviceRegistry, + client: MagicMock, + fibaro_fgms001_unknown_firmware: Node, + integration: MockConfigEntry, +) -> None: + """Test setup completes when an FGMS001 node has no firmware version. + + Regression test for a crash where comparing AwesomeVersion(None) to a + schema's firmware_version_range raised AwesomeVersionCompareException + and aborted setup of the whole config entry. + """ + assert integration.state is ConfigEntryState.LOADED + + device = device_registry.async_get_device( + identifiers={get_device_id(client.driver, fibaro_fgms001_unknown_firmware)} + ) + assert device is not None + + entries = er.async_entries_for_device( + entity_registry, device.id, include_disabled_entities=True + ) + motion_entries = [ + entry + for entry in entries + if entry.domain == BINARY_SENSOR_DOMAIN + and entry.original_device_class == BinarySensorDeviceClass.MOTION + ] + assert motion_entries == [] + + @pytest.mark.parametrize("platforms", [[Platform.BINARY_SENSOR, Platform.LIGHT]]) async def test_fibaro_fgms001_v2_8_motion_discovery( hass: HomeAssistant,