diff --git a/homeassistant/components/dhcp/__init__.py b/homeassistant/components/dhcp/__init__.py index 5d0b31c8788..7003038593b 100644 --- a/homeassistant/components/dhcp/__init__.py +++ b/homeassistant/components/dhcp/__init__.py @@ -248,10 +248,10 @@ class DeviceTrackerWatcher(WatcherBase): return ip_address = attributes.get(ATTR_IP) - hostname = attributes.get(ATTR_HOST_NAME) + hostname = attributes.get(ATTR_HOST_NAME, "") mac_address = attributes.get(ATTR_MAC) - if ip_address is None or hostname is None or mac_address is None: + if ip_address is None or mac_address is None: return self.process_client(ip_address, hostname, _format_mac(mac_address)) @@ -328,10 +328,10 @@ class DHCPWatcher(WatcherBase): return ip_address = _decode_dhcp_option(options, REQUESTED_ADDR) or packet[IP].src - hostname = _decode_dhcp_option(options, HOSTNAME) + hostname = _decode_dhcp_option(options, HOSTNAME) or "" mac_address = _format_mac(packet[Ether].src) - if ip_address is None or hostname is None or mac_address is None: + if ip_address is None or mac_address is None: return self.process_client(ip_address, hostname, mac_address) diff --git a/tests/components/dhcp/test_init.py b/tests/components/dhcp/test_init.py index 122e81786c2..0da383c758a 100644 --- a/tests/components/dhcp/test_init.py +++ b/tests/components/dhcp/test_init.py @@ -81,6 +81,47 @@ RAW_DHCP_RENEWAL = ( b"\x43\x37\x08\x01\x21\x03\x06\x1c\x33\x3a\x3b\xff" ) +# 60:6b:bd:59:e4:b4 192.168.107.151 +RAW_DHCP_REQUEST_WITHOUT_HOSTNAME = ( + b"\xff\xff\xff\xff\xff\xff\x60\x6b\xbd\x59\xe4\xb4\x08\x00\x45\x00" + b"\x02\x40\x00\x00\x00\x00\x40\x11\x78\xae\x00\x00\x00\x00\xff\xff" + b"\xff\xff\x00\x44\x00\x43\x02\x2c\x02\x04\x01\x01\x06\x00\xff\x92" + b"\x7e\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x60\x6b\xbd\x59\xe4\xb4\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x63\x82\x53\x63\x35\x01\x03\x3d\x07\x01" + b"\x60\x6b\xbd\x59\xe4\xb4\x3c\x25\x75\x64\x68\x63\x70\x20\x31\x2e" + b"\x31\x34\x2e\x33\x2d\x56\x44\x20\x4c\x69\x6e\x75\x78\x20\x56\x44" + b"\x4c\x69\x6e\x75\x78\x2e\x31\x2e\x32\x2e\x31\x2e\x78\x32\x04\xc0" + b"\xa8\x6b\x97\x36\x04\xc0\xa8\x6b\x01\x37\x07\x01\x03\x06\x0c\x0f" + b"\x1c\x2a\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +) + async def test_dhcp_match_hostname_and_macaddress(hass): """Test matching based on hostname and macaddress.""" @@ -182,6 +223,29 @@ async def test_dhcp_match_macaddress(hass): } +async def test_dhcp_match_macaddress_without_hostname(hass): + """Test matching based on macaddress only.""" + dhcp_watcher = dhcp.DHCPWatcher( + hass, {}, [{"domain": "mock-domain", "macaddress": "606BBD*"}] + ) + + packet = Ether(RAW_DHCP_REQUEST_WITHOUT_HOSTNAME) + + with patch.object(hass.config_entries.flow, "async_init") as mock_init: + dhcp_watcher.handle_dhcp_packet(packet) + + assert len(mock_init.mock_calls) == 1 + assert mock_init.mock_calls[0][1][0] == "mock-domain" + assert mock_init.mock_calls[0][2]["context"] == { + "source": config_entries.SOURCE_DHCP + } + assert mock_init.mock_calls[0][2]["data"] == { + dhcp.IP_ADDRESS: "192.168.107.151", + dhcp.HOSTNAME: "", + dhcp.MAC_ADDRESS: "606bbd59e4b4", + } + + async def test_dhcp_nomatch(hass): """Test not matching based on macaddress only.""" dhcp_watcher = dhcp.DHCPWatcher(