Add a Thread network status sensor to homekit_controller (#76209)

This commit is contained in:
Jc2k 2022-08-04 11:55:29 +01:00 committed by GitHub
parent d5695a2d86
commit aa3097a3be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 94 additions and 2 deletions

View File

@ -5,7 +5,7 @@ from collections.abc import Callable
from dataclasses import dataclass
from aiohomekit.model.characteristics import Characteristic, CharacteristicsTypes
from aiohomekit.model.characteristics.const import ThreadNodeCapabilities
from aiohomekit.model.characteristics.const import ThreadNodeCapabilities, ThreadStatus
from aiohomekit.model.services import Service, ServicesTypes
from homeassistant.components.sensor import (
@ -83,6 +83,54 @@ def thread_node_capability_to_str(char: Characteristic) -> str:
return "none"
def thread_status_to_str(char: Characteristic) -> str:
"""
Return the thread status as a string.
The underlying value is a bitmask, but we want to turn that to
a human readable string. So we check the flags in order. E.g. BORDER_ROUTER implies
ROUTER, so its more important to show that value.
"""
val = ThreadStatus(char.value)
if val & ThreadStatus.BORDER_ROUTER:
# Device has joined the Thread network and is participating
# in routing between mesh nodes.
# It's also the border router - bridging the thread network
# to WiFI/Ethernet/etc
return "border_router"
if val & ThreadStatus.LEADER:
# Device has joined the Thread network and is participating
# in routing between mesh nodes.
# It's also the leader. There's only one leader and it manages
# which nodes are routers.
return "leader"
if val & ThreadStatus.ROUTER:
# Device has joined the Thread network and is participating
# in routing between mesh nodes.
return "router"
if val & ThreadStatus.CHILD:
# Device has joined the Thread network as a child
# It's not participating in routing between mesh nodes
return "child"
if val & ThreadStatus.JOINING:
# Device is currently joining its Thread network
return "joining"
if val & ThreadStatus.DETACHED:
# Device is currently unable to reach its Thread network
return "detached"
# Must be ThreadStatus.DISABLED
# Device is not currently connected to Thread and will not try to.
return "disabled"
SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = {
CharacteristicsTypes.VENDOR_CONNECTSENSE_ENERGY_WATT: HomeKitSensorEntityDescription(
key=CharacteristicsTypes.VENDOR_CONNECTSENSE_ENERGY_WATT,
@ -243,6 +291,13 @@ SIMPLE_SENSOR: dict[str, HomeKitSensorEntityDescription] = {
entity_category=EntityCategory.DIAGNOSTIC,
format=thread_node_capability_to_str,
),
CharacteristicsTypes.THREAD_STATUS: HomeKitSensorEntityDescription(
key=CharacteristicsTypes.THREAD_STATUS,
name="Thread Status",
device_class="homekit_controller__thread_status",
entity_category=EntityCategory.DIAGNOSTIC,
format=thread_status_to_str,
),
}

View File

@ -7,6 +7,15 @@
"minimal": "Minimal End Device",
"sleepy": "Sleepy End Device",
"none": "None"
},
"homekit_controller__thread_status": {
"border_router": "Border Router",
"leader": "Leader",
"router": "Router",
"child": "Child",
"joining": "Joining",
"detached": "Detached",
"disabled": "Disabled"
}
}
}

View File

@ -7,6 +7,15 @@
"none": "None",
"router_eligible": "Router Eligible End Device",
"sleepy": "Sleepy End Device"
},
"homekit_controller__thread_status": {
"border_router": "Border Router",
"child": "Child",
"detached": "Detached",
"disabled": "Disabled",
"joining": "Joining",
"leader": "Leader",
"router": "Router"
}
}
}

View File

@ -57,6 +57,13 @@ async def test_nanoleaf_nl55_setup(hass):
entity_category=EntityCategory.DIAGNOSTIC,
state="border_router_capable",
),
EntityTestInfo(
entity_id="sensor.nanoleaf_strip_3b32_thread_status",
friendly_name="Nanoleaf Strip 3B32 Thread Status",
unique_id="homekit-AAAA011111111111-aid:1-sid:31-cid:117",
entity_category=EntityCategory.DIAGNOSTIC,
state="border_router",
),
],
),
)

View File

@ -1,11 +1,12 @@
"""Basic checks for HomeKit sensor."""
from aiohomekit.model.characteristics import CharacteristicsTypes
from aiohomekit.model.characteristics.const import ThreadNodeCapabilities
from aiohomekit.model.characteristics.const import ThreadNodeCapabilities, ThreadStatus
from aiohomekit.model.services import ServicesTypes
from aiohomekit.protocol.statuscodes import HapStatusCode
from homeassistant.components.homekit_controller.sensor import (
thread_node_capability_to_str,
thread_status_to_str,
)
from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass
@ -337,3 +338,14 @@ def test_thread_node_caps_to_str():
assert thread_node_capability_to_str(ThreadNodeCapabilities.MINIMAL) == "minimal"
assert thread_node_capability_to_str(ThreadNodeCapabilities.SLEEPY) == "sleepy"
assert thread_node_capability_to_str(ThreadNodeCapabilities(128)) == "none"
def test_thread_status_to_str():
"""Test all values of this enum get a translatable string."""
assert thread_status_to_str(ThreadStatus.BORDER_ROUTER) == "border_router"
assert thread_status_to_str(ThreadStatus.LEADER) == "leader"
assert thread_status_to_str(ThreadStatus.ROUTER) == "router"
assert thread_status_to_str(ThreadStatus.CHILD) == "child"
assert thread_status_to_str(ThreadStatus.JOINING) == "joining"
assert thread_status_to_str(ThreadStatus.DETACHED) == "detached"
assert thread_status_to_str(ThreadStatus.DISABLED) == "disabled"