2222RULE_TYPE_LEGACY_FIREWALL_RULE = "legacy_firewall_rules"
2323RULE_TYPE_TRAFFIC_RULE = "traffic_rules"
2424RULE_TYPE_WLAN = "wlans"
25+ RULE_TYPE_DEVICES = "devices"
2526
2627# Trigger types
2728TRIGGER_RULE_ENABLED = "rule_enabled"
5152 RULE_TYPE_LEGACY_FIREWALL_RULE : ["firewallrule" , "legacy" , "accept" , "reject" ],
5253 RULE_TYPE_TRAFFIC_RULE : ["trafficrule" , "traffic_rule" ],
5354 RULE_TYPE_WLAN : ["wlan" , "wireless" , "wifi" , "ssid" ],
55+ RULE_TYPE_DEVICES : ["device" , "led" , "led_override" , "access_point" , "uap" ],
5456}
5557
5658# Configuration schema for platform triggers
7476 RULE_TYPE_LEGACY_FIREWALL_RULE ,
7577 RULE_TYPE_TRAFFIC_RULE ,
7678 RULE_TYPE_WLAN ,
79+ RULE_TYPE_DEVICES ,
7780 ]),
7881 vol .Optional ("name_filter" ): cv .string ,
7982 }
@@ -131,6 +134,15 @@ def get_rule_name_from_data(rule_data: Dict[str, Any], rule_id: str, rule_type:
131134 if "ssid" in rule_data :
132135 return f"WLAN: { rule_data ['ssid' ]} "
133136
137+ elif rule_type == RULE_TYPE_DEVICES :
138+ # For device LED changes, construct a meaningful name
139+ device_name = rule_data .get ('name' , rule_data .get ('device_id' , 'Unknown' ))
140+ device_model = rule_data .get ('model' , '' )
141+ if device_model :
142+ return f"{ device_name } LED ({ device_model } )"
143+ else :
144+ return f"{ device_name } LED"
145+
134146 # For device configuration changes (cfgversion events), extract device info
135147 if rule_id .startswith ("device_config_" ):
136148 device_part = rule_id .replace ("device_config_" , "" )
@@ -250,11 +262,16 @@ def _handle_websocket_msg(msg: Dict[str, Any]) -> None:
250262 elif isinstance (msg_data , dict ):
251263 LOGGER .info ("📋 RULE DATA: keys=%s" , list (msg_data .keys ()))
252264 LOGGER .info ("📄 RULE CONTENT: %s" , str (msg )[:300 ] + "..." if len (str (msg )) > 300 else str (msg ))
253- elif msg_type == "device:update" and isinstance (msg_data , list ):
265+ elif msg_type in [ "device:update" , "device:sync" ] and isinstance (msg_data , list ):
254266 # Very limited logging for device updates to avoid spam
255267 first_item = msg_data [0 ] if msg_data else {}
256268 if isinstance (first_item , dict ) and "cfgversion" in first_item :
257269 LOGGER .debug ("📱 CFGVERSION UPDATE: %s" , first_item .get ("cfgversion" ))
270+ # Check for LED changes in device:sync messages
271+ elif isinstance (first_item , dict ) and any (led_field in first_item for led_field in ["led_override" , "led_override_color" , "led_override_color_brightness" ]):
272+ led_state = first_item .get ("led_override" , "unknown" )
273+ device_mac = first_item .get ("mac" , msg .get ("meta" , {}).get ("mac" , "unknown" ))
274+ LOGGER .info ("🔴 TRIGGER LED DETECTION: %s led=%s, device=%s" , msg_type , led_state , device_mac )
258275 try :
259276 # Extract message type and data from UniFi OS websocket structure
260277 meta = msg .get ("meta" , {})
@@ -283,7 +300,7 @@ def _handle_websocket_msg(msg: Dict[str, Any]) -> None:
283300 # Check for cfgversion changes (but only refresh if we have active rule triggers)
284301 has_cfgversion_change = False
285302 cfgversion = None
286- if msg_type == "device:update" and isinstance (msg_data , list ):
303+ if msg_type in [ "device:update" , "device:sync" ] and isinstance (msg_data , list ):
287304 for item in msg_data :
288305 if isinstance (item , dict ) and "cfgversion" in item :
289306 cfgversion = item .get ("cfgversion" )
@@ -344,6 +361,9 @@ def _handle_websocket_msg(msg: Dict[str, Any]) -> None:
344361 detected_rule_type = RULE_TYPE_TRAFFIC_ROUTE
345362 elif "ssid" in rule_data :
346363 detected_rule_type = RULE_TYPE_WLAN
364+ elif "led_override" in rule_data or ("type" in rule_data and rule_data .get ("type" ) == "uap" ) or "mac" in rule_data :
365+ # Device LED detection - check for LED override field, UAP device type, or MAC address (device identifier)
366+ detected_rule_type = RULE_TYPE_DEVICES
347367
348368 # Fallback: Keyword matching with SPECIFIC order (most specific first)
349369 if not detected_rule_type :
@@ -365,6 +385,8 @@ def _handle_websocket_msg(msg: Dict[str, Any]) -> None:
365385 detected_rule_type = RULE_TYPE_TRAFFIC_ROUTE
366386 elif any (keyword in rule_data_str for keyword in ["wlan" , "ssid" ]):
367387 detected_rule_type = RULE_TYPE_WLAN
388+ elif any (keyword in rule_data_str for keyword in ["led_override" , "device" , "access_point" , "uap" ]):
389+ detected_rule_type = RULE_TYPE_DEVICES
368390
369391 if not detected_rule_type :
370392 if LOG_TRIGGERS :
0 commit comments