Handle Tailscale hosts without client connectivity details (#143505)

This commit is contained in:
Stefan Agner
2025-04-23 18:36:55 +02:00
committed by GitHub
parent 738e39413d
commit e41283a40a
7 changed files with 109 additions and 10 deletions

View File

@ -46,37 +46,61 @@ BINARY_SENSORS: tuple[TailscaleBinarySensorEntityDescription, ...] = (
key="client_supports_hair_pinning",
translation_key="client_supports_hair_pinning",
entity_category=EntityCategory.DIAGNOSTIC,
is_on_fn=lambda device: device.client_connectivity.client_supports.hair_pinning,
is_on_fn=lambda device: (
device.client_connectivity.client_supports.hair_pinning
if device.client_connectivity is not None
else None
),
),
TailscaleBinarySensorEntityDescription(
key="client_supports_ipv6",
translation_key="client_supports_ipv6",
entity_category=EntityCategory.DIAGNOSTIC,
is_on_fn=lambda device: device.client_connectivity.client_supports.ipv6,
is_on_fn=lambda device: (
device.client_connectivity.client_supports.ipv6
if device.client_connectivity is not None
else None
),
),
TailscaleBinarySensorEntityDescription(
key="client_supports_pcp",
translation_key="client_supports_pcp",
entity_category=EntityCategory.DIAGNOSTIC,
is_on_fn=lambda device: device.client_connectivity.client_supports.pcp,
is_on_fn=lambda device: (
device.client_connectivity.client_supports.pcp
if device.client_connectivity is not None
else None
),
),
TailscaleBinarySensorEntityDescription(
key="client_supports_pmp",
translation_key="client_supports_pmp",
entity_category=EntityCategory.DIAGNOSTIC,
is_on_fn=lambda device: device.client_connectivity.client_supports.pmp,
is_on_fn=lambda device: (
device.client_connectivity.client_supports.pmp
if device.client_connectivity is not None
else None
),
),
TailscaleBinarySensorEntityDescription(
key="client_supports_udp",
translation_key="client_supports_udp",
entity_category=EntityCategory.DIAGNOSTIC,
is_on_fn=lambda device: device.client_connectivity.client_supports.udp,
is_on_fn=lambda device: (
device.client_connectivity.client_supports.udp
if device.client_connectivity is not None
else None
),
),
TailscaleBinarySensorEntityDescription(
key="client_supports_upnp",
translation_key="client_supports_upnp",
entity_category=EntityCategory.DIAGNOSTIC,
is_on_fn=lambda device: device.client_connectivity.client_supports.upnp,
is_on_fn=lambda device: (
device.client_connectivity.client_supports.upnp
if device.client_connectivity is not None
else None
),
),
)

View File

@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/tailscale",
"integration_type": "hub",
"iot_class": "cloud_polling",
"requirements": ["tailscale==0.6.1"]
"requirements": ["tailscale==0.6.2"]
}

2
requirements_all.txt generated
View File

@ -2858,7 +2858,7 @@ systembridgeconnector==4.1.5
systembridgemodels==4.2.4
# homeassistant.components.tailscale
tailscale==0.6.1
tailscale==0.6.2
# homeassistant.components.tank_utility
tank-utility==1.5.0

View File

@ -2314,7 +2314,7 @@ systembridgeconnector==4.1.5
systembridgemodels==4.2.4
# homeassistant.components.tailscale
tailscale==0.6.1
tailscale==0.6.2
# homeassistant.components.tellduslive
tellduslive==0.10.12

View File

@ -104,6 +104,28 @@
"upnp": false
}
}
},
{
"addresses": ["100.11.11.113"],
"id": "123458",
"user": "frenck",
"name": "host-no-connectivity.homeassistant.github",
"hostname": "host-no-connectivity",
"clientVersion": "1.14.0-t5cff36945-g809e87bba",
"updateAvailable": true,
"os": "linux",
"created": "2021-08-29T09:49:06Z",
"lastSeen": "2021-11-15T20:37:03Z",
"keyExpiryDisabled": false,
"expires": "2022-02-25T09:49:06Z",
"authorized": true,
"isExternal": false,
"machineKey": "mkey:mock",
"nodeKey": "nodekey:mock",
"blocksIncomingConnections": false,
"enabledRoutes": ["0.0.0.0/0", "10.10.10.0/23", "::/0"],
"advertisedRoutes": ["0.0.0.0/0", "10.10.10.0/23", "::/0"],
"clientConnectivity": null
}
]
}

View File

@ -82,6 +82,38 @@
'update_available': True,
'user': '**REDACTED**',
}),
dict({
'addresses': '**REDACTED**',
'advertised_routes': list([
'0.0.0.0/0',
'10.10.10.0/23',
'::/0',
]),
'authorized': True,
'blocks_incoming_connections': False,
'client_connectivity': None,
'client_version': '1.14.0-t5cff36945-g809e87bba',
'created': '2021-08-29T09:49:06+00:00',
'device_id': '**REDACTED**',
'enabled_routes': list([
'0.0.0.0/0',
'10.10.10.0/23',
'::/0',
]),
'expires': '2022-02-25T09:49:06+00:00',
'hostname': '**REDACTED**',
'is_external': False,
'key_expiry_disabled': False,
'last_seen': '2021-11-15T20:37:03+00:00',
'machine_key': '**REDACTED**',
'name': '**REDACTED**',
'node_key': '**REDACTED**',
'os': 'linux',
'tags': list([
]),
'update_available': True,
'user': '**REDACTED**',
}),
]),
})
# ---

View File

@ -6,7 +6,12 @@ from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
)
from homeassistant.components.tailscale.const import DOMAIN
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_FRIENDLY_NAME, EntityCategory
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_FRIENDLY_NAME,
STATE_UNKNOWN,
EntityCategory,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
@ -122,3 +127,19 @@ async def test_tailscale_binary_sensors(
device_entry.configuration_url
== "https://login.tailscale.com/admin/machines/100.11.11.111"
)
# Check host without client connectivity attribute
state = hass.states.get("binary_sensor.host_no_connectivity_supports_hairpinning")
entry = entity_registry.async_get(
"binary_sensor.host_no_connectivity_supports_hairpinning"
)
assert entry
assert state
assert entry.unique_id == "123458_client_supports_hair_pinning"
assert entry.entity_category == EntityCategory.DIAGNOSTIC
assert state.state == STATE_UNKNOWN
assert (
state.attributes.get(ATTR_FRIENDLY_NAME)
== "host-no-connectivity Supports hairpinning"
)
assert ATTR_DEVICE_CLASS not in state.attributes