@@ -493,7 +493,7 @@ def generate_network_map_mermaid(network_map: Dict[str, Any]) -> str:
493493
494494 summary = network_map .get ("summary" , {})
495495 configured_devices = network_map .get ("configured_devices" , {})
496-
496+
497497 # Extract visualization options
498498 viz_options = network_map .get ("visualization_options" , {})
499499 layout = viz_options .get ("layout" , "lr" )
@@ -535,12 +535,11 @@ def get_latency_color_class(latency_ms: Optional[float]) -> str:
535535 return "online" # Default
536536 if latency_ms < 10 :
537537 return "latency_excellent" # Green
538- elif latency_ms < 50 :
538+ if latency_ms < 50 :
539539 return "latency_good" # Yellow
540- elif latency_ms < 100 :
540+ if latency_ms < 100 :
541541 return "latency_fair" # Orange
542- else :
543- return "latency_poor" # Red
542+ return "latency_poor" # Red
544543
545544 # Helper function to get alert indicators
546545 def get_alert_indicators (device : Dict [str , Any ]) -> List [str ]:
@@ -550,7 +549,7 @@ def get_alert_indicators(device: Dict[str, Any]) -> List[str]:
550549 ssh_error_type = device .get ("ssh_error_type" )
551550 last_seen = device .get ("last_seen" )
552551 power_watts = device .get ("tasmota_power_watts" )
553-
552+
554553 # SSH errors
555554 if ssh_error :
556555 if ssh_error_type == "timeout" :
@@ -561,15 +560,16 @@ def get_alert_indicators(device: Dict[str, Any]) -> List[str]:
561560 alerts .append ("🔐 Auth Failed" )
562561 else :
563562 alerts .append ("⚠️ SSH Error" )
564-
563+
565564 # High power consumption warning (for Tasmota devices)
566565 if power_watts is not None and power_watts > 50 :
567566 alerts .append ("⚡ High Power" )
568-
567+
569568 # Device not seen recently (if show_history enabled)
570569 if show_history and last_seen :
571570 # Parse last_seen timestamp if it's a string
572571 import datetime
572+
573573 try :
574574 if isinstance (last_seen , str ):
575575 # Try parsing ISO format or relative time
@@ -578,31 +578,38 @@ def get_alert_indicators(device: Dict[str, Any]) -> List[str]:
578578 alerts .append (f"🕐 { last_seen } " )
579579 else :
580580 # ISO timestamp
581- last_seen_dt = datetime .datetime .fromisoformat (last_seen .replace ("Z" , "+00:00" ))
581+ last_seen_dt = datetime .datetime .fromisoformat (
582+ last_seen .replace ("Z" , "+00:00" )
583+ )
582584 now = datetime .datetime .now (datetime .timezone .utc )
583585 age = now - last_seen_dt
584586 if age .total_seconds () > 3600 : # More than 1 hour
585587 alerts .append (f"🕐 { int (age .total_seconds () / 3600 )} h ago" )
586588 except Exception :
587589 pass
588-
590+
589591 return alerts
590592
591593 # Helper function to build enhanced device label
592- def build_device_label (device : Dict [str , Any ], device_type : str , hostname : str , ip : str ,
593- is_gateway : bool = False ) -> Tuple [str , str ]:
594+ def build_device_label (
595+ device : Dict [str , Any ],
596+ device_type : str ,
597+ hostname : str ,
598+ ip : str ,
599+ is_gateway : bool = False ,
600+ ) -> Tuple [str , str ]:
594601 """Build device label with optional details, alerts, and metrics
595-
602+
596603 Returns:
597604 Tuple of (label_string, css_class)
598605 """
599606 icon = get_icon (device_type )
600607 label_parts = [f"{ icon } { hostname } " , ip ]
601-
608+
602609 # Add gateway indicator
603610 if is_gateway :
604611 label_parts .insert (1 , "🌐 Gateway" )
605-
612+
606613 # Add device details if requested
607614 if show_details :
608615 # Manufacturer/model
@@ -612,29 +619,31 @@ def build_device_label(device: Dict[str, Any], device_type: str, hostname: str,
612619 label_parts .append (f"Mfr: { manufacturer } " )
613620 if model :
614621 label_parts .append (f"Model: { model } " )
615-
622+
616623 # Firmware version
617624 firmware = device .get ("firmware" )
618625 if firmware :
619626 if isinstance (firmware , dict ):
620- fw_version = firmware .get ("version_id" ) or firmware .get ("version" , "Unknown" )
627+ fw_version = firmware .get ("version_id" ) or firmware .get (
628+ "version" , "Unknown"
629+ )
621630 else :
622631 fw_version = str (firmware )
623632 label_parts .append (f"FW: { fw_version [:20 ]} " )
624-
633+
625634 # MAC address (if available)
626635 mac = device .get ("mac_address" ) or device .get ("mac" )
627636 if mac :
628637 label_parts .append (f"MAC: { mac [:17 ]} " )
629-
638+
630639 # Add performance metrics if requested
631640 latency_ms = device .get ("latency_ms" )
632641 css_class = "online" # Default
633-
642+
634643 if show_metrics and latency_ms is not None :
635644 label_parts .append (f"Ping: { latency_ms } ms" )
636645 css_class = get_latency_color_class (latency_ms )
637-
646+
638647 # Add alert indicators if requested
639648 if show_alerts :
640649 alerts = get_alert_indicators (device )
@@ -643,7 +652,7 @@ def build_device_label(device: Dict[str, Any], device_type: str, hostname: str,
643652 # Override CSS class for devices with alerts
644653 if ssh_error := device .get ("ssh_error" ):
645654 css_class = "alert_device"
646-
655+
647656 # Add SSH status
648657 ssh_error = device .get ("ssh_error" )
649658 ssh_status = device .get ("ssh_status" )
@@ -653,7 +662,7 @@ def build_device_label(device: Dict[str, Any], device_type: str, hostname: str,
653662 label_parts .append ("SSH: ✓" )
654663 else :
655664 label_parts .append ("SSH: ✗" )
656-
665+
657666 # Join parts and wrap in quotes
658667 label = f'"{ "<br/>" .join (label_parts )} "'
659668 return label , css_class
@@ -862,6 +871,8 @@ def get_icon(device_type):
862871 tasmota_name = switch_info .get ("friendly_name" ) or switch_info .get (
863872 "name" , power_switch_id
864873 )
874+ # Define tasmota_node_id before checking if it exists
875+ tasmota_node_id = f"T_{ power_switch_id .replace ('-' , '_' ).replace ('.' , '_' ).replace ('/' , '_' )} "
865876 if tasmota_node_id not in tasmota_nodes :
866877 tasmota_clean_name = (
867878 tasmota_name .replace ('"' , "'" )
@@ -905,7 +916,9 @@ def get_icon(device_type):
905916 clean_hostname = hostname .replace ('"' , "'" ).replace ("\n " , " " ).replace ("\r " , " " )
906917
907918 # Use helper function to build enhanced label
908- node_label , css_class = build_device_label (device , device_type , clean_hostname , ip , is_gateway )
919+ node_label , css_class = build_device_label (
920+ device , device_type , clean_hostname , ip , is_gateway
921+ )
909922
910923 node_id = f"D_{ device_id .replace ('-' , '_' ).replace ('.' , '_' ).replace ('/' , '_' )} "
911924 device_nodes [node_id ] = {"type" : device_type , "device_id" : device_id }
@@ -937,6 +950,8 @@ def get_icon(device_type):
937950 tasmota_name = switch_info .get ("friendly_name" ) or switch_info .get (
938951 "name" , power_switch_id
939952 )
953+ # Define tasmota_node_id before checking if it exists
954+ tasmota_node_id = f"T_{ power_switch_id .replace ('-' , '_' ).replace ('.' , '_' ).replace ('/' , '_' )} "
940955 # Add Tasmota node if not already added
941956 if tasmota_node_id not in tasmota_nodes :
942957 tasmota_clean_name = (
@@ -1051,6 +1066,8 @@ def get_icon(device_type):
10511066 tasmota_name = switch_info .get ("friendly_name" ) or switch_info .get (
10521067 "name" , power_switch_id
10531068 )
1069+ # Define tasmota_node_id before checking if it exists
1070+ tasmota_node_id = f"T_{ power_switch_id .replace ('-' , '_' ).replace ('.' , '_' ).replace ('/' , '_' )} "
10541071 if tasmota_node_id not in tasmota_nodes :
10551072 tasmota_clean_name = (
10561073 tasmota_name .replace ('"' , "'" )
@@ -1116,6 +1133,8 @@ def get_icon(device_type):
11161133 tasmota_name = switch_info .get ("friendly_name" ) or switch_info .get (
11171134 "name" , power_switch_id
11181135 )
1136+ # Define tasmota_node_id before checking if it exists
1137+ tasmota_node_id = f"T_{ power_switch_id .replace ('-' , '_' ).replace ('.' , '_' ).replace ('/' , '_' )} "
11191138 if tasmota_node_id not in tasmota_nodes :
11201139 tasmota_clean_name = (
11211140 tasmota_name .replace ('"' , "'" )
@@ -1201,17 +1220,27 @@ def get_icon(device_type):
12011220 " classDef offline fill:#FFB6B6,stroke:#FF0000,stroke-width:2px,stroke-dasharray: 5 5,color:#000"
12021221 )
12031222 lines .append (" classDef power_line stroke:#FFD700,stroke-width:4px" )
1204-
1223+
12051224 # Add latency-based performance metric classes (if show_metrics enabled)
12061225 if show_metrics :
1207- lines .append (" classDef latency_excellent fill:#90EE90,stroke:#228B22,stroke-width:3px,color:#000" )
1208- lines .append (" classDef latency_good fill:#FFD700,stroke:#FFA500,stroke-width:3px,color:#000" )
1209- lines .append (" classDef latency_fair fill:#FFA07A,stroke:#FF6347,stroke-width:3px,color:#000" )
1210- lines .append (" classDef latency_poor fill:#FF6B6B,stroke:#CC0000,stroke-width:3px,color:#FFF" )
1211-
1226+ lines .append (
1227+ " classDef latency_excellent fill:#90EE90,stroke:#228B22,stroke-width:3px,color:#000"
1228+ )
1229+ lines .append (
1230+ " classDef latency_good fill:#FFD700,stroke:#FFA500,stroke-width:3px,color:#000"
1231+ )
1232+ lines .append (
1233+ " classDef latency_fair fill:#FFA07A,stroke:#FF6347,stroke-width:3px,color:#000"
1234+ )
1235+ lines .append (
1236+ " classDef latency_poor fill:#FF6B6B,stroke:#CC0000,stroke-width:3px,color:#FFF"
1237+ )
1238+
12121239 # Add alert device class (if show_alerts enabled)
12131240 if show_alerts :
1214- lines .append (" classDef alert_device fill:#FFB6B6,stroke:#FF0000,stroke-width:4px,color:#000" )
1241+ lines .append (
1242+ " classDef alert_device fill:#FFB6B6,stroke:#FF0000,stroke-width:4px,color:#000"
1243+ )
12151244
12161245 # Add link styling for power connections (thicker, golden color)
12171246 lines .append (" linkStyle default stroke:#FFD700,stroke-width:3px" )
0 commit comments