TasmotaManager/unknown_device_patterns_analysis.md
Mike Geppert 126cd39555 Major code improvements and bug fixes:
1. Restructured configuration: Moved config_other and console to top level
2. Added common _match_pattern function for regex pattern matching
3. Implemented Unifi Hostname bug fix in is_hostname_unknown
4. Created common get_device_hostname function to eliminate code duplication
5. Added comprehensive test scripts for all new functionality
6. Added detailed documentation for all changes
2025-08-08 19:04:33 -05:00

6.9 KiB

Analysis of unknown_device_patterns Checks in TasmotaManager.py

This document identifies and analyzes all places in the TasmotaManager.py script where checks against unknown_device_patterns are performed.

Summary

The script performs checks against unknown_device_patterns in 4 distinct places:

  1. In the get_tasmota_devices function during device discovery
  2. In the get_unknown_devices function when identifying unknown devices for processing
  3. In the process_single_device function when processing a single device
  4. In the process_devices function when filtering devices for MQTT configuration

Detailed Analysis

1. In get_tasmota_devices function (lines 235-244 and 269-276)

Purpose: During device discovery, this function checks if devices match unknown patterns in two ways:

  • First, it checks if the device's name or hostname as reported by UniFi matches any unknown patterns
  • Second, if there's a match, it checks if the device's self-reported hostname also matches unknown patterns

Context: This is part of the initial device discovery process when scanning the network. The function sets a flag unifi_hostname_bug_detected if the UniFi-reported name matches unknown patterns but the device's self-reported hostname doesn't (indicating a possible UniFi OS bug).

Code snippet:

# Check if device name or hostname matches unknown patterns
unifi_name_matches_unknown = False
for pattern in unknown_patterns:
    pattern_lower = pattern.lower()
    pattern_regex = pattern_lower.replace('.', r'\.').replace('*', '.*')
    if (re.match(f"^{pattern_regex}", device_name.lower()) or 
        re.match(f"^{pattern_regex}", device_hostname.lower())):
        unifi_name_matches_unknown = True
        self.logger.debug(f"Device {device_name} matches unknown device pattern: {pattern}")
        break

# If the name matches unknown patterns, check the device's self-reported hostname
if unifi_name_matches_unknown and device_ip:
    # ... [code to get device's self-reported hostname] ...
    
    # Check if the self-reported hostname also matches unknown patterns
    device_hostname_matches_unknown = False
    for pattern in unknown_patterns:
        pattern_lower = pattern.lower()
        pattern_regex = pattern_lower.replace('.', r'\.').replace('*', '.*')
        if re.match(f"^{pattern_regex}", device_reported_hostname.lower()):
            device_hostname_matches_unknown = True
            self.logger.debug(f"Device's self-reported hostname '{device_reported_hostname}' matches unknown pattern: {pattern}")
            break

2. In get_unknown_devices function (lines 500-506)

Purpose: Specifically identifies devices that match unknown_device_patterns from current.json.

Context: This function is used when processing unknown devices to set them up with proper names and MQTT settings. It's called by the process_unknown_devices function, which is triggered by the --process-unknown command-line argument.

Code snippet:

for device in all_devices:
    name = device.get('name', '').lower()
    hostname = device.get('hostname', '').lower()
    
    for pattern in unknown_patterns:
        pattern = pattern.lower()
        pattern = pattern.replace('.', r'\.').replace('*', '.*')
        if re.match(f"^{pattern}", name) or re.match(f"^{pattern}", hostname):
            self.logger.debug(f"Found unknown device: {name} ({hostname})")
            unknown_devices.append(device)
            break

3. In process_single_device function (lines 1526-1533 and 1559-1567)

Purpose: When processing a single device by IP or hostname, this function checks if it matches unknown patterns in two ways:

  • First, it checks if the device's name or hostname as reported by UniFi matches any unknown patterns
  • Second, if there's a match, it checks if the device's self-reported hostname also matches unknown patterns

Context: This function is used in Device mode (triggered by the --Device command-line argument) to determine if a specific device should be treated as unknown. If both the UniFi-reported name and the device's self-reported hostname match unknown patterns, the device is declared as unknown.

Code snippet:

# Initialize variables for hostname bug detection
unifi_name_matches_unknown = False
device_hostname_matches_unknown = False
for pattern in unknown_patterns:
    pattern_lower = pattern.lower()
    pattern_regex = pattern_lower.replace('.', r'\.').replace('*', '.*')
    if (re.match(f"^{pattern_regex}", device_name.lower()) or 
        re.match(f"^{pattern_regex}", device_hostname.lower())):
        unifi_name_matches_unknown = True
        self.logger.info(f"Device {device_name} matches unknown device pattern: {pattern}")
        break

# If the name matches unknown patterns, check the device's self-reported hostname
if unifi_name_matches_unknown:
    # ... [code to get device's self-reported hostname] ...
    
    # Check if the self-reported hostname also matches unknown patterns
    device_hostname_matches_unknown = False
    for pattern in unknown_patterns:
        pattern_lower = pattern.lower()
        pattern_regex = pattern_lower.replace('.', r'\.').replace('*', '.*')
        if re.match(f"^{pattern_regex}", device_reported_hostname.lower()):
            device_hostname_matches_unknown = True
            self.logger.info(f"Device's self-reported hostname '{device_reported_hostname}' matches unknown pattern: {pattern}")
            break

4. In process_devices function (lines 1760-1766)

Purpose: Filters out devices matching unknown_device_patterns during normal processing.

Context: This function is used to skip unknown devices when configuring MQTT for known devices. If a device matches an unknown_device_pattern, it's skipped unless the skip_unknown_filter parameter is True (which happens in Device mode).

Code snippet:

for device in all_devices:
    name = device.get('name', '').lower()
    hostname = device.get('hostname', '').lower()
    
    is_unknown = False
    for pattern in unknown_patterns:
        pattern = pattern.lower()
        pattern = pattern.replace('.', r'\.').replace('*', '.*')
        if re.match(f"^{pattern}", name) or re.match(f"^{pattern}", hostname):
            self.logger.debug(f"Skipping unknown device: {name} ({hostname})")
            is_unknown = True
            break
    
    if not is_unknown:
        devices.append(device)

Conclusion

The TasmotaManager.py script performs checks against unknown_device_patterns in 4 distinct places, each with a specific purpose:

  1. During device discovery to identify unknown devices and detect the UniFi OS hostname bug
  2. When specifically looking for unknown devices to process them
  3. When processing a single device to determine if it should be treated as unknown
  4. When filtering devices for MQTT configuration to skip unknown devices

These checks are an important part of the script's functionality, allowing it to handle unknown devices appropriately in different contexts.