Skip to content

Commit

Permalink
Merge pull request #102 from mdeweerd/dev
Browse files Browse the repository at this point in the history
Fix neighbours_and_routes services #101
  • Loading branch information
mdeweerd authored Oct 30, 2022
2 parents b366a8b + 08d4686 commit bbe3fbd
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 83 deletions.
147 changes: 65 additions & 82 deletions custom_components/zha_toolkit/neighbours.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async def routes_and_neighbours(

LOGGER.debug("Getting routes and neighbours: %s", service)
device = app.get_device(ieee=ieee)
await _routes_and_neighbours(device, listener)
event_data["result"] = await _routes_and_neighbours(device, listener)


async def _routes_and_neighbours(device, listener):
Expand Down Expand Up @@ -60,6 +60,7 @@ async def _routes_and_neighbours(device, listener):
LOGGER.debug(
"Wrote scan results to '%s' and '%s'", routes_name, neighbours_name
)
return {"routes": routes, "neighbours": nbns}


async def all_routes_and_neighbours(
Expand All @@ -69,106 +70,76 @@ async def all_routes_and_neighbours(

counter = 1
devs = [d for d in app.devices.values() if not d.node_desc.is_end_device]
all_routes = {}
for device in devs:
LOGGER.debug(
"%s: Querying routes and neighbours: %s out of %s",
device.ieee,
counter,
len(devs),
)
await _routes_and_neighbours(device, listener)
all_routes[str(device.ieee)] = await _routes_and_neighbours(
device, listener
)
LOGGER.debug("%s: Got %s out of %s", device.ieee, counter, len(devs))
counter += 1

event_data["result"] = all_routes

async def async_get_neighbours(device):
"""Pull neighbor table from a device."""

def _process_neighbor(nbg):
"""Return dict of a neighbor entry."""

class NeighbourType(enum.IntEnum):
Coordinator = 0x0
Router = 0x1
End_Device = 0x2
Unknown = 0x3

class RxOnIdle(enum.IntEnum):
Off = 0x0
On = 0x1
Unknown = 0x2

class Relation(enum.IntEnum):
Parent = 0x0
Child = 0x1
Sibling = 0x2
None_of_the_above = 0x3
Previous_Child = 0x4

class PermitJoins(enum.IntEnum):
Not_Accepting = 0x0
Accepting = 0x1
Unknown = 0x2

res = {}

res["pan_id"] = str(nbg.PanId)
res["ieee"] = str(nbg.IEEEAddr)

raw = nbg.NeighborType & 0x03
try:
nei_type = NeighbourType(raw).name
except ValueError:
nei_type = f"undefined_0x{raw:02x}"
res["device_type"] = nei_type

raw = (nbg.NeighborType >> 2) & 0x03
try:
rx_on = RxOnIdle(raw).name
except ValueError:
rx_on = f"undefined_0x{raw:02x}"
res["rx_on_when_idle"] = rx_on
all_routes_name = os.path.join(
listener._hass.config.config_dir,
"scans",
"all_routes_and_neighbours.json",
)
save_json(all_routes_name, all_routes)

raw = (nbg.NeighborType >> 4) & 0x07
try:
relation = Relation(raw).name
except ValueError:
relation = f"undefined_0x{raw:02x}"
res["relationship"] = relation

raw = nbg.PermitJoining & 0x02
try:
joins = PermitJoins(raw).name
except ValueError:
joins = f"undefined_0x{raw:02x}"
res["new_joins_accepted"] = joins
async def async_get_neighbours(device):
"""Pull neighbour table from a device."""

res["depth"] = nbg.Depth
res["lqi"] = nbg.LQI
def _process_neighbour(nbg):
"""Return dict of a neighbour entry."""

# LOGGER.debug(f"NEIGHBOR: {nbg!r}")
res = {}
res["pan_id"] = str(nbg.extended_pan_id)
res["ieee"] = str(nbg.ieee)
res["device_type"] = nbg.device_type.name
res["rx_on_when_idle"] = nbg.rx_on_when_idle.name
res["relationship"] = nbg.relationship.name
res["permit_joining"] = nbg.permit_joining.name
res["depth"] = nbg.depth
res["lqi"] = nbg.lqi
return res

result = []
idx = 0
while True:
status, val = await device.zdo.request(zdo_t.ZDOCmd.Mgmt_Lqi_req, idx)
LOGGER.debug(
"%s: neighbor request Status: %s. Response: %r",
device.ieee,
status,
val,
)
if zdo_t.Status.SUCCESS != status:
try:
status, val = await device.zdo.request(
zdo_t.ZDOCmd.Mgmt_Lqi_req, idx
)
LOGGER.debug(
"%s: device oes not support 'Mgmt_Lqi_req'", device.ieee
"%s: neighbour request Status: %s. Response: %r",
device.ieee,
status,
val,
)
if zdo_t.Status.SUCCESS != status:
LOGGER.debug(
"%s: device does not support 'Mgmt_Lqi_req'", device.ieee
)
break
except DeliveryError:
LOGGER.debug("%s: Could not deliver 'Mgmt_Lqi_req'", device.ieee)
break

neighbors = val.NeighborTableList
for neighbor in neighbors:
result.append(_process_neighbor(neighbor))
# LOGGER.debug(f"NEIGHBORS: {val!r}")
neighbours = val.neighbor_table_list
for neighbour in neighbours:
result.append(_process_neighbour(neighbour))
idx += 1
if idx >= val.Entries:
if idx >= val.entries:
break
await asyncio.sleep(uniform(1.0, 1.5))

Expand Down Expand Up @@ -205,16 +176,28 @@ class RouteStatus(enum.IntEnum):
routes = []
idx = 0
while True:
status, val = await device.zdo.request(zdo_t.ZDOCmd.Mgmt_Rtg_req, idx)
LOGGER.debug(
"%s: route request Status:%s. Routes: %r", device.ieee, status, val
)
if zdo_t.Status.SUCCESS != status:
try:
status, val = await device.zdo.request(
zdo_t.ZDOCmd.Mgmt_Rtg_req, idx
)
LOGGER.debug(
"%s: Does not support 'Mgmt_rtg_req': %s", device.ieee, status
"%s: route request Status:%s. Routes: %r",
device.ieee,
status,
val,
)
if zdo_t.Status.SUCCESS != status:
LOGGER.debug(
"%s: Does not support 'Mgmt_rtg_req': %s",
device.ieee,
status,
)
break
except DeliveryError:
LOGGER.debug("%s: Could not deliver 'Mgmt_rtg_req'", device.ieee)
break

LOGGER.debug(f"Mgmt_Rtg_rsp: {val!r}")
for route in val.RoutingTableList:
routes.append(_process_route(route))
idx += 1
Expand Down
67 changes: 66 additions & 1 deletion custom_components/zha_toolkit/services.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
---
# Describes the format for available zha services
execute:
description: >-
Expand Down Expand Up @@ -342,6 +341,35 @@ add_to_group:
Throw exception when success==False, useful to stop scripts, automations
selector:
boolean:
all_routes_and_neigbours:
description: Scan for all routes and neighbours, results saved to config/scans/...
fields:
event_success:
description: Event name in case of success
example: my_read_success_trigger_event
selector:
text:
event_fail:
description: Event name in case of failure
example: my_read_fail_trigger_event
selector:
text:
event_done:
description: >-
Event name when the service call did all its work (either success
or failure). Has event data with relevant attributes.
example: my_read_done_trigger_event
selector:
text:
fail_exception:
description: >-
Throw exception when success==False, useful to stop scripts, automations
selector:
boolean:
expect_reply:
description: Wait for/expect a reply (not used yet)
selector:
boolean:
attr_read:
description: Read Attribute (ZHA-Toolkit)
fields:
Expand Down Expand Up @@ -1123,6 +1151,43 @@ get_groups:
Throw exception when success==False, useful to stop scripts, automations
selector:
boolean:
get_routes_and_neigbours:
description: Scan for all routes and neighbours, results saved to config/scans/...
fields:
ieee:
description: >-
Entity name,\ndevice name, or\nIEEE address of the node
example: 00:0d:6f:00:05:7d:2d:34
required: true
selector:
entity:
integration: zha
event_success:
description: Event name in case of success
example: my_read_success_trigger_event
selector:
text:
event_fail:
description: Event name in case of failure
example: my_read_fail_trigger_event
selector:
text:
event_done:
description: >-
Event name when the service call did all its work (either success
or failure). Has event data with relevant attributes.
example: my_read_done_trigger_event
selector:
text:
fail_exception:
description: >-
Throw exception when success==False, useful to stop scripts, automations
selector:
boolean:
expect_reply:
description: Wait for/expect a reply (not used yet)
selector:
boolean:
get_zll_groups:
description: Get groups for zll_cluster (if present)
fields:
Expand Down

0 comments on commit bbe3fbd

Please sign in to comment.