unifi-network-maps 1.4.9__py3-none-any.whl → 1.4.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- __version__ = "1.4.9"
1
+ __version__ = "1.4.10"
@@ -37,6 +37,8 @@ class Edge:
37
37
  label: str | None = None
38
38
  poe: bool = False
39
39
  wireless: bool = False
40
+ speed: int | None = None
41
+ channel: int | None = None
40
42
 
41
43
 
42
44
  type DeviceSource = object
@@ -64,6 +66,7 @@ class PortInfo:
64
66
 
65
67
  type PortMap = dict[tuple[str, str], str]
66
68
  type PoeMap = dict[tuple[str, str], bool]
69
+ type SpeedMap = dict[tuple[str, str], int]
67
70
  type ClientPortMap = dict[str, list[tuple[int, str]]]
68
71
 
69
72
 
@@ -421,7 +424,15 @@ def _tree_edges_from_parent(
421
424
  tree_edges.append(Edge(left=parent_name, right=child))
422
425
  else:
423
426
  tree_edges.append(
424
- Edge(left=parent_name, right=child, label=original.label, poe=original.poe)
427
+ Edge(
428
+ left=parent_name,
429
+ right=child,
430
+ label=original.label,
431
+ poe=original.poe,
432
+ wireless=original.wireless,
433
+ speed=original.speed,
434
+ channel=original.channel,
435
+ )
425
436
  )
426
437
  return tree_edges
427
438
 
@@ -492,6 +503,16 @@ def _client_is_wired(client: object) -> bool:
492
503
  return bool(_client_field(client, "is_wired"))
493
504
 
494
505
 
506
+ def _client_channel(client: object) -> int | None:
507
+ for key in ("channel", "radio_channel", "wifi_channel"):
508
+ value = _client_field(client, key)
509
+ if isinstance(value, int):
510
+ return value
511
+ if isinstance(value, str) and value.isdigit():
512
+ return int(value)
513
+ return None
514
+
515
+
495
516
  def _client_matches_mode(client: object, mode: str) -> bool:
496
517
  wired = _client_is_wired(client)
497
518
  if mode == "all":
@@ -528,12 +549,15 @@ def build_client_edges(
528
549
  key = (device_name, name)
529
550
  if key in seen:
530
551
  continue
552
+ is_wireless = not _client_is_wired(client)
553
+ channel = _client_channel(client) if is_wireless else None
531
554
  edges.append(
532
555
  Edge(
533
556
  left=device_name,
534
557
  right=name,
535
558
  label=label,
536
- wireless=not _client_is_wired(client),
559
+ wireless=is_wireless,
560
+ channel=channel,
537
561
  )
538
562
  )
539
563
  seen.add(key)
@@ -572,12 +596,14 @@ def build_edges(
572
596
  seen: set[frozenset[str]] = set()
573
597
  port_map: PortMap = {}
574
598
  poe_map: PoeMap = {}
599
+ speed_map: SpeedMap = {}
575
600
 
576
601
  devices_with_lldp_edges = _collect_lldp_links(
577
602
  ordered_devices,
578
603
  index,
579
604
  port_map,
580
605
  poe_map,
606
+ speed_map,
581
607
  raw_links,
582
608
  seen,
583
609
  only_unifi=only_unifi,
@@ -597,6 +623,7 @@ def build_edges(
597
623
  raw_links,
598
624
  port_map,
599
625
  poe_map,
626
+ speed_map,
600
627
  device_by_name,
601
628
  include_ports=include_ports,
602
629
  )
@@ -614,12 +641,14 @@ def build_port_map(devices: Iterable[Device], *, only_unifi: bool = True) -> Por
614
641
  seen: set[frozenset[str]] = set()
615
642
  port_map: PortMap = {}
616
643
  poe_map: PoeMap = {}
644
+ speed_map: SpeedMap = {}
617
645
 
618
646
  devices_with_lldp_edges = _collect_lldp_links(
619
647
  ordered_devices,
620
648
  index,
621
649
  port_map,
622
650
  poe_map,
651
+ speed_map,
623
652
  raw_links,
624
653
  seen,
625
654
  only_unifi=only_unifi,
@@ -661,11 +690,19 @@ def build_client_port_map(
661
690
  return port_map
662
691
 
663
692
 
693
+ def _port_speed_by_idx(port_table: list[PortInfo], port_idx: int) -> int | None:
694
+ for port in port_table:
695
+ if port.port_idx == port_idx:
696
+ return port.speed
697
+ return None
698
+
699
+
664
700
  def _collect_lldp_links(
665
701
  devices: list[Device],
666
702
  index: dict[str, str],
667
703
  port_map: PortMap,
668
704
  poe_map: PoeMap,
705
+ speed_map: SpeedMap,
669
706
  raw_links: list[tuple[str, str]],
670
707
  seen: set[frozenset[str]],
671
708
  *,
@@ -704,8 +741,12 @@ def _collect_lldp_links(
704
741
  label = local_port_label(entry_for_label)
705
742
  if label:
706
743
  port_map[(device.name, peer_name)] = label
707
- if resolved_port_idx is not None and resolved_port_idx in poe_ports:
708
- poe_map[(device.name, peer_name)] = poe_ports[resolved_port_idx]
744
+ if resolved_port_idx is not None:
745
+ if resolved_port_idx in poe_ports:
746
+ poe_map[(device.name, peer_name)] = poe_ports[resolved_port_idx]
747
+ port_speed = _port_speed_by_idx(device.port_table, resolved_port_idx)
748
+ if port_speed is not None:
749
+ speed_map[(device.name, peer_name)] = port_speed
709
750
 
710
751
  key = frozenset({device.name, peer_name})
711
752
  if key in seen:
@@ -794,6 +835,7 @@ def _build_ordered_edges(
794
835
  raw_links: list[tuple[str, str]],
795
836
  port_map: PortMap,
796
837
  poe_map: PoeMap,
838
+ speed_map: SpeedMap,
797
839
  device_by_name: dict[str, Device],
798
840
  *,
799
841
  include_ports: bool,
@@ -820,8 +862,9 @@ def _build_ordered_edges(
820
862
  poe = poe_map.get((left_name, right_name), False) or poe_map.get(
821
863
  (right_name, left_name), False
822
864
  )
865
+ speed = speed_map.get((left_name, right_name)) or speed_map.get((right_name, left_name))
823
866
  label = compose_port_label(left_name, right_name, port_map) if include_ports else None
824
- edges.append(Edge(left=left_name, right=right_name, label=label, poe=poe))
867
+ edges.append(Edge(left=left_name, right=right_name, label=label, poe=poe, speed=speed))
825
868
  return edges
826
869
 
827
870
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unifi-network-maps
3
- Version: 1.4.9
3
+ Version: 1.4.10
4
4
  Summary: Dynamic UniFi -> network maps in mermaid or svg
5
5
  Author: Merlijn
6
6
  License-Expression: MIT
@@ -32,7 +32,7 @@ Requires-Dist: pre-commit==4.5.1; extra == "dev"
32
32
  Requires-Dist: pytest==9.0.2; extra == "dev"
33
33
  Requires-Dist: pytest-cov==7.0.0; extra == "dev"
34
34
  Requires-Dist: pyright==1.1.408; extra == "dev"
35
- Requires-Dist: ruff==0.14.11; extra == "dev"
35
+ Requires-Dist: ruff==0.14.13; extra == "dev"
36
36
  Dynamic: license-file
37
37
 
38
38
  # unifi-network-maps
@@ -1,4 +1,4 @@
1
- unifi_network_maps/__init__.py,sha256=A4qmsE8vvj9H09qZTlxxGLwgABGRSkAJASAcIbNUgt4,22
1
+ unifi_network_maps/__init__.py,sha256=WCR-6aXXvi4kHlaMAYnHT-VzLSifo-1Btos9idb9SM8,23
2
2
  unifi_network_maps/__main__.py,sha256=XsOjaqslAVgyVlOTokjVddZ2iT8apZXpJ_OB-9WEEe4,179
3
3
  unifi_network_maps/adapters/__init__.py,sha256=nzx1KsiYalL_YuXKE6acW8Dj5flmMg0-i4gyYO0gV54,22
4
4
  unifi_network_maps/adapters/config.py,sha256=Bx9JDZxxY7Gjxyb8FDT0dxiKfgXt_TmzTDbgvpwB53s,1548
@@ -67,7 +67,7 @@ unifi_network_maps/model/labels.py,sha256=m_k8mbzWtOSDOjjHhLUqwIw93pg98HAtGtHkiE
67
67
  unifi_network_maps/model/lldp.py,sha256=SrPW5XC2lfJgaGeVx-KnSFNltyok7gIWWQNg1SkOaj4,3300
68
68
  unifi_network_maps/model/mock.py,sha256=kd1MSiIn-7KKu_nMVmheYPfTyAN5DHt4dzRrBifF_lI,8706
69
69
  unifi_network_maps/model/ports.py,sha256=o3NBlXcC5VV5iPWJsO4Ll1mRKJZC0f8zTHdlkkE34GU,609
70
- unifi_network_maps/model/topology.py,sha256=JfpY6Pam_pgqnnmsBmzy3oDv4OCi4Ezc8msxvp5Z5NQ,26784
70
+ unifi_network_maps/model/topology.py,sha256=Rq69wcJ5toXz4ZZPHahc2Jiuw-3CXiOiIrZp1fupaUU,28262
71
71
  unifi_network_maps/render/__init__.py,sha256=nzx1KsiYalL_YuXKE6acW8Dj5flmMg0-i4gyYO0gV54,22
72
72
  unifi_network_maps/render/device_ports_md.py,sha256=vt5kGFSIAabMbcSxIuVVLSzdb_i58NHGi4hJM2ZLZR4,15975
73
73
  unifi_network_maps/render/legend.py,sha256=TmZsxgCVOM2CZImI9zgRVyzrcg01HZFDj9F715d4CGo,772
@@ -91,9 +91,9 @@ unifi_network_maps/render/templates/mkdocs_html_block.html.j2,sha256=5l5-BbNujOc
91
91
  unifi_network_maps/render/templates/mkdocs_legend.css.j2,sha256=tkTI-RagBSgdjUygVenlTsQFenU09ePbXOfDt_Q7YRM,612
92
92
  unifi_network_maps/render/templates/mkdocs_legend.js.j2,sha256=qMYyCKsJ84uXf1wGgzbc7Bc49RU4oyuaGK9KrgQDQEI,685
93
93
  unifi_network_maps/render/templates/mkdocs_mermaid_block.md.j2,sha256=9IncllWQpoI8BN3A7b2zOQ5cksj97ddsjHJ-aBhpw7o,66
94
- unifi_network_maps-1.4.9.dist-info/licenses/LICENSE,sha256=mYo1siIIfIwyfdOuK2-Zt0ij2xBTii2hnpeTu79nD80,1074
95
- unifi_network_maps-1.4.9.dist-info/METADATA,sha256=8-wqtJhL46qhE6O56rNBkKpBJ_lAOqvwki6zxJSlRnY,9850
96
- unifi_network_maps-1.4.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
97
- unifi_network_maps-1.4.9.dist-info/entry_points.txt,sha256=cdJ7jsBgNgHxSflYUOqgz5BbvuM0Nnh-x8_Hbyh_LFg,67
98
- unifi_network_maps-1.4.9.dist-info/top_level.txt,sha256=G0rUX1PNfVCn1u-KtB6QjFQHopCOVLnPMczvPOoraHg,19
99
- unifi_network_maps-1.4.9.dist-info/RECORD,,
94
+ unifi_network_maps-1.4.10.dist-info/licenses/LICENSE,sha256=mYo1siIIfIwyfdOuK2-Zt0ij2xBTii2hnpeTu79nD80,1074
95
+ unifi_network_maps-1.4.10.dist-info/METADATA,sha256=hLv77auAYEJIxkk_vslu8qvQnI975Oud_AqsC3THRoE,9851
96
+ unifi_network_maps-1.4.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
97
+ unifi_network_maps-1.4.10.dist-info/entry_points.txt,sha256=cdJ7jsBgNgHxSflYUOqgz5BbvuM0Nnh-x8_Hbyh_LFg,67
98
+ unifi_network_maps-1.4.10.dist-info/top_level.txt,sha256=G0rUX1PNfVCn1u-KtB6QjFQHopCOVLnPMczvPOoraHg,19
99
+ unifi_network_maps-1.4.10.dist-info/RECORD,,