Add hostname resolution and fix UTF-8 encoding issues

This commit is contained in:
2025-12-30 23:51:53 +11:00
parent 44b6662507
commit 248d7b52fe

View File

@@ -6,6 +6,7 @@ Helps discover devices on the network and manage MAC-based internet blocking
import requests import requests
import json import json
import socket
from typing import List, Dict from typing import List, Dict
from urllib3.exceptions import InsecureRequestWarning from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning) requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
@@ -44,6 +45,15 @@ class OPNsenseDeviceManager:
print(f"Error making request to {endpoint}: {e}") print(f"Error making request to {endpoint}: {e}")
return None return None
def _get_hostname(self, ip: str) -> str:
"""Try to resolve hostname from IP address"""
try:
hostname, _, _ = socket.gethostbyaddr(ip)
return hostname
except (socket.herror, socket.gaierror, socket.timeout):
return ""
def discover_devices(self) -> List[Dict]: def discover_devices(self) -> List[Dict]:
"""Discover all devices from ARP table""" """Discover all devices from ARP table"""
result = self._make_request("diagnostics/interface/getArp") result = self._make_request("diagnostics/interface/getArp")
@@ -72,20 +82,30 @@ class OPNsenseDeviceManager:
seen_macs.add(mac) seen_macs.add(mac)
# Try to get hostname
hostname = self._get_hostname(ip)
device_info = { device_info = {
'mac': mac, 'mac': mac,
'ip': ip, 'ip': ip,
'hostname': hostname,
'manufacturer': manufacturer, 'manufacturer': manufacturer,
'intf_description': entry.get('intf_description', 'LAN'), 'intf_description': entry.get('intf_description', 'LAN'),
'suggested_name': self._suggest_device_name(manufacturer, ip) 'suggested_name': self._suggest_device_name(manufacturer, ip, hostname)
} }
devices.append(device_info) devices.append(device_info)
return sorted(devices, key=lambda x: x['ip']) return sorted(devices, key=lambda x: x['ip'])
def _suggest_device_name(self, manufacturer: str, ip: str) -> str: def _suggest_device_name(self, manufacturer: str, ip: str, hostname: str = "") -> str:
"""Suggest a device name based on manufacturer""" """Suggest a device name based on manufacturer and hostname"""
# If we have a hostname, use it
if hostname:
# Clean up hostname (remove domain suffix if present)
clean_hostname = hostname.split('.')[0]
return clean_hostname
manufacturer = manufacturer.lower() manufacturer = manufacturer.lower()
if 'apple' in manufacturer: if 'apple' in manufacturer:
@@ -215,6 +235,8 @@ class OPNsenseDeviceManager:
for device in device_list: for device in device_list:
report += f" MAC: {device['mac']}\n" report += f" MAC: {device['mac']}\n"
report += f" IP: {device['ip']}\n" report += f" IP: {device['ip']}\n"
if device['hostname']:
report += f" Hostname: {device['hostname']}\n"
report += f" Suggested Name: {device['suggested_name']}\n" report += f" Suggested Name: {device['suggested_name']}\n"
report += "\n" report += "\n"
@@ -225,14 +247,16 @@ class OPNsenseDeviceManager:
"""Export devices in a format easy to copy into Home Assistant""" """Export devices in a format easy to copy into Home Assistant"""
devices = self.discover_devices() devices = self.discover_devices()
with open(output_file, 'w') as f: with open(output_file, 'w', encoding='utf-8') as f:
f.write("# Copy these MAC addresses into your Home Assistant input_text entities\n") f.write("# Copy these MAC addresses into your Home Assistant input_text entities\n")
f.write("# Format: device_name | MAC Address | IP | Manufacturer\n\n") f.write("# Format: device_name | MAC Address | IP | Hostname | Manufacturer\n\n")
for device in devices: for device in devices:
hostname = device['hostname'] if device['hostname'] else "N/A"
f.write(f"{device['suggested_name']:<40} | " f.write(f"{device['suggested_name']:<40} | "
f"{device['mac']:<20} | " f"{device['mac']:<20} | "
f"{device['ip']:<15} | " f"{device['ip']:<15} | "
f"{hostname:<30} | "
f"{device['manufacturer']}\n") f"{device['manufacturer']}\n")
print(f"Device list exported to: {output_file}") print(f"Device list exported to: {output_file}")
@@ -272,6 +296,8 @@ def main():
print(f"{idx}. {device['suggested_name']}") print(f"{idx}. {device['suggested_name']}")
print(f" MAC: {device['mac']}") print(f" MAC: {device['mac']}")
print(f" IP: {device['ip']}") print(f" IP: {device['ip']}")
if device['hostname']:
print(f" Hostname: {device['hostname']}")
print(f" Manufacturer: {device['manufacturer']}") print(f" Manufacturer: {device['manufacturer']}")
print() print()
@@ -281,7 +307,7 @@ def main():
save = input("Save report to file? (y/n): ").strip().lower() save = input("Save report to file? (y/n): ").strip().lower()
if save == 'y': if save == 'y':
with open('device_report.txt', 'w') as f: with open('device_report.txt', 'w', encoding='utf-8') as f:
f.write(report) f.write(report)
print("Report saved to: device_report.txt") print("Report saved to: device_report.txt")