- 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
157 lines
5.4 KiB
Python
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")
|