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

144 lines
6.9 KiB
Markdown

# 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**:
```python
# 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**:
```python
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**:
```python
# 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**:
```python
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.