TasmotaManager/reporting.py
Mike Geppert 9c22168f79 Refactor: Split TasmotaManager into modular structure
- Created modular Python files (main, utils, discovery, configuration, console_settings, unknown_devices, reporting, unifi_client)
- Moved documentation files to docs/
- Moved data files to data/
- Removed old monolithic TasmotaManager.py and TasmotaManager_fixed.py
- Updated .gitignore and pyproject.toml
- All functionality preserved, command-line interface unchanged
Version: 2.0.0
2025-10-29 16:38:03 +00:00

157 lines
5.4 KiB
Python

"""Report generation for Tasmota devices."""
import logging
from typing import List, Dict, Optional
from datetime import datetime
from utils import get_data_file_path, save_json_file, format_device_info
from discovery import TasmotaDiscovery
class ReportGenerator:
"""Generates various reports for Tasmota devices."""
def __init__(self, config: dict, discovery: TasmotaDiscovery,
logger: Optional[logging.Logger] = None):
"""
Initialize report generator.
Args:
config: Configuration dictionary
discovery: Discovery handler instance
logger: Optional logger instance
"""
self.config = config
self.discovery = discovery
self.logger = logger or logging.getLogger(__name__)
def generate_unifi_hostname_report(self) -> Dict:
"""
Generate a report comparing UniFi and Tasmota hostnames.
Returns:
dict: Report data
"""
self.logger.info("Generating UniFi hostname report")
devices = self.discovery.get_tasmota_devices()
report = {
'generated_at': datetime.now().isoformat(),
'total_devices': len(devices),
'devices': []
}
for device in devices:
device_ip = device.get('ip', '')
device_name = device.get('name', 'Unknown')
unifi_hostname = device.get('hostname', '')
# Get self-reported hostname
tasmota_hostname, success = self.discovery.get_device_hostname(
device_ip, device_name, timeout=5
)
device_report = {
'name': device_name,
'ip': device_ip,
'mac': device.get('mac', ''),
'unifi_hostname': unifi_hostname,
'tasmota_hostname': tasmota_hostname if success else 'N/A',
'hostnames_match': tasmota_hostname == unifi_hostname if success else False,
'connection': device.get('connection', 'Unknown'),
'bug_detected': device.get('unifi_hostname_bug_detected', False)
}
report['devices'].append(device_report)
# Save report
report_file = get_data_file_path('TasmotaHostnameReport.json')
save_json_file(report_file, report, self.logger)
# Print summary
self._print_hostname_report_summary(report)
return report
def _print_hostname_report_summary(self, report: Dict):
"""
Print a summary of the hostname report.
Args:
report: Report data dictionary
"""
print(f"\n{'='*70}")
print("UniFi vs Tasmota Hostname Report")
print(f"{'='*70}")
print(f"Total devices: {report['total_devices']}")
print(f"Generated: {report['generated_at']}")
print(f"{'='*70}\n")
mismatches = 0
bug_detected = 0
for device in report['devices']:
if not device['hostnames_match']:
mismatches += 1
if device['bug_detected']:
bug_detected += 1
print(f"Hostname mismatches: {mismatches}")
print(f"UniFi bug detected: {bug_detected}")
print(f"\n{'='*70}")
if mismatches > 0:
print("\nDevices with hostname mismatches:")
print(f"{'Device':<25} {'UniFi Hostname':<25} {'Tasmota Hostname':<25}")
print("-" * 75)
for device in report['devices']:
if not device['hostnames_match']:
name = device['name'][:24]
unifi = device['unifi_hostname'][:24]
tasmota = device['tasmota_hostname'][:24]
bug = " [BUG]" if device['bug_detected'] else ""
print(f"{name:<25} {unifi:<25} {tasmota:<25}{bug}")
print(f"\n{'='*70}\n")
def save_device_details(self, device_details: List[Dict]):
"""
Save detailed device information to file.
Args:
device_details: List of detailed device info dictionaries
"""
output_file = get_data_file_path('TasmotaDevices.json')
# Add metadata
output = {
'generated_at': datetime.now().isoformat(),
'total_devices': len(device_details),
'devices': device_details
}
save_json_file(output_file, output, self.logger)
self.logger.info(f"Saved details for {len(device_details)} devices")
def print_processing_summary(self, processed: int, mqtt_updated: int,
console_updated: int, failed: int):
"""
Print summary of processing results.
Args:
processed: Number of devices processed
mqtt_updated: Number with MQTT updates
console_updated: Number with console updates
failed: Number that failed
"""
print(f"\n{'='*60}")
print("Processing Summary")
print(f"{'='*60}")
print(f"Total devices processed: {processed}")
print(f"MQTT settings updated: {mqtt_updated}")
print(f"Console settings applied: {console_updated}")
print(f"Failed: {failed}")
print(f"{'='*60}\n")