add service auto discovery
This commit is contained in:
4
.tf5_mixer_cache/mixer_ip.json
Normal file
4
.tf5_mixer_cache/mixer_ip.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"ip": "192.168.1.57",
|
||||||
|
"timestamp": 1770578444.177839
|
||||||
|
}
|
||||||
Binary file not shown.
249
config.py
249
config.py
@@ -1,13 +1,252 @@
|
|||||||
|
import socket
|
||||||
|
import ipaddress
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
import json
|
||||||
|
import threading
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
import time
|
||||||
|
|
||||||
# Configurazione mixer
|
# Configurazione mixer
|
||||||
DEFAULT_HOST = "192.168.1.57"
|
|
||||||
DEFAULT_PORT = 49280
|
DEFAULT_PORT = 49280
|
||||||
TF5_INPUT_CHANNELS = 40
|
TF5_INPUT_CHANNELS = 40
|
||||||
TF5_MIX_BUSSES = 20
|
TF5_MIX_BUSSES = 20
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
# Configurazione cache
|
# Configurazione cache
|
||||||
CACHE_DIR = Path(".tf5_mixer_cache")
|
CACHE_DIR = Path(".tf5_mixer_cache")
|
||||||
CACHE_FILE = CACHE_DIR / "channels_cache.json"
|
CACHE_FILE = CACHE_DIR / "channels_cache.json"
|
||||||
CACHE_DURATION = 3600 # 60 minuti in secondi
|
IP_CACHE_FILE = CACHE_DIR / "mixer_ip.json"
|
||||||
|
CACHE_DURATION = 3600 # 60 minuti in secondi
|
||||||
|
IP_CACHE_DURATION = 300 # 5 minuti per l'IP
|
||||||
|
|
||||||
|
def log(message: str, level: str = "INFO"):
|
||||||
|
"""Stampa log formattato con timestamp"""
|
||||||
|
timestamp = time.strftime("%H:%M:%S")
|
||||||
|
symbols = {
|
||||||
|
"INFO": "ℹ️",
|
||||||
|
"SUCCESS": "✅",
|
||||||
|
"ERROR": "❌",
|
||||||
|
"WARNING": "⚠️",
|
||||||
|
"SEARCH": "🔍",
|
||||||
|
"NETWORK": "🌐",
|
||||||
|
"CACHE": "📍",
|
||||||
|
"TIME": "⏱️"
|
||||||
|
}
|
||||||
|
symbol = symbols.get(level, "•")
|
||||||
|
print(f"[{timestamp}] {symbol} {message}")
|
||||||
|
|
||||||
|
def get_local_network() -> str:
|
||||||
|
"""Ottiene la rete locale del sistema"""
|
||||||
|
log("Rilevamento rete locale in corso...", "NETWORK")
|
||||||
|
try:
|
||||||
|
# Crea un socket per ottenere l'IP locale
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
s.connect(("8.8.8.8", 80))
|
||||||
|
local_ip = s.getsockname()[0]
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
# Converte in network (es: 192.168.1.0/24)
|
||||||
|
ip_parts = local_ip.split('.')
|
||||||
|
network = f"{ip_parts[0]}.{ip_parts[1]}.{ip_parts[2]}.0/24"
|
||||||
|
|
||||||
|
log(f"IP locale rilevato: {local_ip}", "INFO")
|
||||||
|
log(f"Rete da scansionare: {network}", "NETWORK")
|
||||||
|
return network
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Errore nel rilevare la rete locale: {e}", "ERROR")
|
||||||
|
network = "192.168.1.0/24"
|
||||||
|
log(f"Uso rete di fallback: {network}", "WARNING")
|
||||||
|
return network
|
||||||
|
|
||||||
|
def check_port(ip: str, port: int, timeout: float = 0.5) -> bool:
|
||||||
|
"""Controlla se una porta è aperta su un IP"""
|
||||||
|
try:
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
result = sock.connect_ex((ip, port))
|
||||||
|
sock.close()
|
||||||
|
return result == 0
|
||||||
|
except Exception as e:
|
||||||
|
# Log solo per debug, commentabile se troppo verbose
|
||||||
|
# log(f"Errore su {ip}: {e}", "ERROR")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def scan_network_for_mixer(port: int = DEFAULT_PORT, max_workers: int = 50) -> Optional[str]:
|
||||||
|
"""Scansiona la rete locale per trovare il mixer"""
|
||||||
|
log(f"Ricerca mixer sulla porta {port}...", "SEARCH")
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
network = get_local_network()
|
||||||
|
|
||||||
|
# Genera lista di IP da scansionare
|
||||||
|
ip_network = ipaddress.ip_network(network, strict=False)
|
||||||
|
total_hosts = sum(1 for _ in ip_network.hosts())
|
||||||
|
log(f"Indirizzi da scansionare: {total_hosts}", "INFO")
|
||||||
|
log(f"Thread paralleli: {max_workers}", "INFO")
|
||||||
|
|
||||||
|
found_ip = None
|
||||||
|
scanned = 0
|
||||||
|
|
||||||
|
# Scansione parallela per velocità
|
||||||
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
|
future_to_ip = {
|
||||||
|
executor.submit(check_port, str(ip), port): str(ip)
|
||||||
|
for ip in ip_network.hosts()
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Scansione in corso...", "SEARCH")
|
||||||
|
|
||||||
|
for future in as_completed(future_to_ip):
|
||||||
|
ip = future_to_ip[future]
|
||||||
|
scanned += 1
|
||||||
|
|
||||||
|
# Log di progresso ogni 50 IP
|
||||||
|
if scanned % 50 == 0:
|
||||||
|
log(f"Progresso: {scanned}/{total_hosts} IP scansionati", "INFO")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if future.result():
|
||||||
|
found_ip = ip
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
log(f"MIXER TROVATO su {ip}:{port}", "SUCCESS")
|
||||||
|
log(f"Tempo di scansione: {elapsed:.2f}s", "TIME")
|
||||||
|
log(f"IP scansionati: {scanned}/{total_hosts}", "INFO")
|
||||||
|
# Cancella i task rimanenti
|
||||||
|
executor.shutdown(wait=False, cancel_futures=True)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Errore durante scansione di {ip}: {e}", "ERROR")
|
||||||
|
|
||||||
|
if not found_ip:
|
||||||
|
elapsed = time.time() - start_time
|
||||||
|
log(f"Nessun mixer trovato sulla porta {port}", "ERROR")
|
||||||
|
log(f"Tempo totale di scansione: {elapsed:.2f}s", "TIME")
|
||||||
|
log(f"IP scansionati: {scanned}/{total_hosts}", "INFO")
|
||||||
|
|
||||||
|
return found_ip
|
||||||
|
|
||||||
|
def load_cached_ip() -> Optional[str]:
|
||||||
|
"""Carica l'IP dalla cache se valido"""
|
||||||
|
log("Controllo cache IP...", "CACHE")
|
||||||
|
|
||||||
|
if not IP_CACHE_FILE.exists():
|
||||||
|
log("Nessuna cache trovata", "INFO")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(IP_CACHE_FILE, 'r') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
cached_ip = data.get('ip')
|
||||||
|
cache_time = data.get('timestamp', 0)
|
||||||
|
age = time.time() - cache_time
|
||||||
|
|
||||||
|
log(f"Cache trovata: {cached_ip} (età: {int(age)}s)", "CACHE")
|
||||||
|
|
||||||
|
# Controlla se la cache è ancora valida
|
||||||
|
if age < IP_CACHE_DURATION:
|
||||||
|
log(f"Verifica raggiungibilità di {cached_ip}...", "CACHE")
|
||||||
|
# Verifica che l'IP sia ancora valido
|
||||||
|
if cached_ip and check_port(cached_ip, DEFAULT_PORT, timeout=1.0):
|
||||||
|
log(f"IP dalla cache valido: {cached_ip}", "SUCCESS")
|
||||||
|
return cached_ip
|
||||||
|
else:
|
||||||
|
log(f"IP dalla cache non raggiungibile", "WARNING")
|
||||||
|
else:
|
||||||
|
log(f"Cache scaduta (max {IP_CACHE_DURATION}s)", "WARNING")
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Errore nel leggere cache IP: {e}", "ERROR")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def save_ip_to_cache(ip: str):
|
||||||
|
"""Salva l'IP nella cache"""
|
||||||
|
log(f"Salvataggio IP in cache: {ip}", "CACHE")
|
||||||
|
CACHE_DIR.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(IP_CACHE_FILE, 'w') as f:
|
||||||
|
json.dump({
|
||||||
|
'ip': ip,
|
||||||
|
'timestamp': time.time()
|
||||||
|
}, f, indent=2)
|
||||||
|
log(f"Cache salvata: {IP_CACHE_FILE}", "SUCCESS")
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Errore nel salvare cache IP: {e}", "ERROR")
|
||||||
|
|
||||||
|
def get_mixer_ip() -> str:
|
||||||
|
"""
|
||||||
|
Ottiene l'IP del mixer con auto-discovery:
|
||||||
|
1. Controlla cache
|
||||||
|
2. Scansiona la rete
|
||||||
|
3. Fallback su IP predefinito
|
||||||
|
"""
|
||||||
|
log("=== INIZIO RICERCA MIXER ===", "INFO")
|
||||||
|
|
||||||
|
# Prova con la cache
|
||||||
|
cached_ip = load_cached_ip()
|
||||||
|
if cached_ip:
|
||||||
|
log("=== RICERCA COMPLETATA (CACHE) ===", "SUCCESS")
|
||||||
|
return cached_ip
|
||||||
|
|
||||||
|
# Scansiona la rete
|
||||||
|
log("Avvio scansione di rete...", "SEARCH")
|
||||||
|
discovered_ip = scan_network_for_mixer()
|
||||||
|
if discovered_ip:
|
||||||
|
save_ip_to_cache(discovered_ip)
|
||||||
|
log("=== RICERCA COMPLETATA (DISCOVERY) ===", "SUCCESS")
|
||||||
|
return discovered_ip
|
||||||
|
|
||||||
|
# Fallback
|
||||||
|
fallback_ip = "192.168.1.57"
|
||||||
|
log(f"Uso IP predefinito di fallback: {fallback_ip}", "WARNING")
|
||||||
|
log("=== RICERCA COMPLETATA (FALLBACK) ===", "WARNING")
|
||||||
|
return fallback_ip
|
||||||
|
|
||||||
|
# Variabile globale per l'host (si aggiorna automaticamente)
|
||||||
|
DEFAULT_HOST = None
|
||||||
|
|
||||||
|
def get_host() -> str:
|
||||||
|
"""Ottiene l'host del mixer (con lazy loading)"""
|
||||||
|
global DEFAULT_HOST
|
||||||
|
if DEFAULT_HOST is None:
|
||||||
|
log("Host mixer non inizializzato, avvio discovery...", "INFO")
|
||||||
|
DEFAULT_HOST = get_mixer_ip()
|
||||||
|
else:
|
||||||
|
log(f"Host mixer già inizializzato: {DEFAULT_HOST}", "INFO")
|
||||||
|
return DEFAULT_HOST
|
||||||
|
|
||||||
|
def refresh_mixer_ip():
|
||||||
|
"""Forza un refresh dell'IP del mixer"""
|
||||||
|
global DEFAULT_HOST
|
||||||
|
log("=== REFRESH FORZATO IP MIXER ===", "INFO")
|
||||||
|
log("Cancellazione cache esistente...", "CACHE")
|
||||||
|
|
||||||
|
# Rimuovi cache
|
||||||
|
if IP_CACHE_FILE.exists():
|
||||||
|
try:
|
||||||
|
IP_CACHE_FILE.unlink()
|
||||||
|
log("Cache rimossa", "SUCCESS")
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Errore rimozione cache: {e}", "ERROR")
|
||||||
|
|
||||||
|
# Nuova scansione
|
||||||
|
DEFAULT_HOST = scan_network_for_mixer()
|
||||||
|
if DEFAULT_HOST:
|
||||||
|
save_ip_to_cache(DEFAULT_HOST)
|
||||||
|
log(f"Nuovo IP impostato: {DEFAULT_HOST}", "SUCCESS")
|
||||||
|
else:
|
||||||
|
log("Refresh fallito, mantengo IP precedente", "ERROR")
|
||||||
|
|
||||||
|
log("=== REFRESH COMPLETATO ===", "INFO")
|
||||||
|
return DEFAULT_HOST
|
||||||
|
|
||||||
|
# Test rapido
|
||||||
|
if __name__ == "__main__":
|
||||||
|
log("=== TEST AUTO-DISCOVERY MIXER ===", "INFO")
|
||||||
|
host = get_host()
|
||||||
|
log(f"Host finale: {host}", "SUCCESS")
|
||||||
|
|
||||||
|
# Test refresh
|
||||||
|
# log("\n=== TEST REFRESH ===", "INFO")
|
||||||
|
# refresh_mixer_ip()
|
||||||
@@ -1,34 +1,10 @@
|
|||||||
{
|
{
|
||||||
"user_id": 4762864,
|
"user_id": 4762864,
|
||||||
"username": "unnikked",
|
"username": "unnikked",
|
||||||
"last_updated": 1770577997.6975403,
|
"last_updated": 1770578542.7348943,
|
||||||
"last_updated_str": "2026-02-08 19:13:17",
|
"last_updated_str": "2026-02-08 19:22:22",
|
||||||
"message_count": 21,
|
"message_count": 21,
|
||||||
"history": [
|
"history": [
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "Controlla canali mixer",
|
|
||||||
"timestamp": 1769455886.9095418,
|
|
||||||
"timestamp_str": "2026-01-26 19:31:26"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "Ok Nicola, ho controllato i canali del mixer! Ecco cosa vedo:\n\n**Canali Attivi e Nominati:**\n* **Gelato (Canale 2):** Acceso, volume a -11.7 dB\n* **Vox1 (Canale 5):** Acceso, volume a 0 dB\n* **Vox2 (Canale 6):** Acceso, volume a 6.3 dB\n* **Basso (Canale 7):** Acceso, volume a -2.15 dB\n* **Kick (Canale 9):** Acceso, volume a -0.35 dB\n* **Snare (Canale 10):** Acceso, volume a -1.6 dB\n* **Tom 1 (Canale 11):** Acceso, volume a -2.8 dB\n* **Tom 2 (Canale 12):** Acceso, volume a -0.8 dB\n* **Tom3 (Canale 13):** Acceso, volume a -3.05 dB\n* **Pan SX (Canale 14):** Acceso, volume a -3.85 dB\n* **Pan dx (Canale 15):** Acceso, volume a -4.3 dB\n* **Archetto (Canale 18):** Acceso, volume a 4.6 dB\n* **Vox 5 (Canale 19):** Acceso, volume a -4.65 dB\n* **Tast (Canale 20):** Acceso, volume a -1.6 dB\n* **Vox3 (Canale 23):** Acceso, volume a 3.05 dB\n* **Chit cnt (Canale 24):** Acceso, volume a -2.35 dB\n* **Chit dx (Canale 25):** Acceso, volume a -0.85 dB\n* **Vox 4 (Canale 27):** Acceso, volume a -120 dB (ma è acceso, strano, forse un errore o un volume bassissimo)\n* **PC (Canale 33 e 34):** Accesi, volume a -43.2 dB\n\n**Canali Spenti o Sconosciuti:**\n* **Canale 1:** Sconosciuto, spento, volume a 0.65 dB\n* **Talkback (Canale 3):** Spento, volume a -120 dB\n* **Canale 4:** Sconosciuto, spento, volume a -120 dB\n* **Canale 8:** Sconosciuto, spento, volume a -120 dB\n* **Canale 16:** Sconosciuto, spento, volume a -120 dB\n* **Canale 17:** Sconosciuto, spento, volume a -120 dB\n* **Canale 21:** Sconosciuto, spento, volume a -120 dB\n* **Canale 22:** Sconosciuto, spento, volume a -120 dB\n* **Canale 26:** Sconosciuto, spento, volume a -120 dB\n* **Canale 28:** Sconosciuto, spento, volume a -120 dB\n* **Pad (Canale 29):** Spento, volume a -120 dB\n* **Canali dal 30 al 32:** Sconosciuti, spenti, volume a -120 dB\n* **Canali dal 35 al 40:** Nominati \"chXX\", accesi ma con volume a -120 dB (praticamente muti)\n\nSembra che ci siano un bel po' di canali attivi con nomi, il che è un buon segno! Però, alcuni canali sono \"accesi\" ma con il volume a -120 dB, il che significa che non si sentiranno.\n\nFammi sapere se vuoi che faccia qualcosa in particolare! 🎛️🎤",
|
|
||||||
"timestamp": 1769455894.465047,
|
|
||||||
"timestamp_str": "2026-01-26 19:31:34"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "Refresh cache",
|
|
||||||
"timestamp": 1769455900.8138618,
|
|
||||||
"timestamp_str": "2026-01-26 19:31:40"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "✅ Fatto, Nicola! Ho ricaricato tutte le informazioni del mixer. Ora siamo pronti a ripartire con i dati freschi! 🎛️✨",
|
|
||||||
"timestamp": 1769455904.113328,
|
|
||||||
"timestamp_str": "2026-01-26 19:31:44"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"content": "Controlla ora",
|
"content": "Controlla ora",
|
||||||
@@ -130,6 +106,30 @@
|
|||||||
"content": "Ciao Nicola! Tutto bene? Dimmi pure se hai bisogno di qualcosa con il mixer! 🎛️🎤",
|
"content": "Ciao Nicola! Tutto bene? Dimmi pure se hai bisogno di qualcosa con il mixer! 🎛️🎤",
|
||||||
"timestamp": 1770577997.697525,
|
"timestamp": 1770577997.697525,
|
||||||
"timestamp_str": "2026-02-08 19:13:17"
|
"timestamp_str": "2026-02-08 19:13:17"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Ciao pupo",
|
||||||
|
"timestamp": 1770578526.691519,
|
||||||
|
"timestamp_str": "2026-02-08 19:22:06"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Ciao Nicola! Tutto bene? Dimmi pure se hai bisogno di qualcosa con il mixer! 🎛️🎤",
|
||||||
|
"timestamp": 1770578528.1236699,
|
||||||
|
"timestamp_str": "2026-02-08 19:22:08"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "Check canali",
|
||||||
|
"timestamp": 1770578537.6022112,
|
||||||
|
"timestamp_str": "2026-02-08 19:22:17"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": "Allora, Nicola, ho controllato tutti i canali! Ecco la situazione attuale:\n\n**Canali Attivi (o con volume udibile):**\n* **PC (Canale 33 e 34):** Accesi, volume a -17.5 dB\n\n**Canali che sono accesi ma con volume bassissimo (-120 dB), quindi praticamente muti:**\n* **Gelato (Canale 2)**\n* **Vox1 (Canale 5)**\n* **Vox2 (Canale 6)**\n* **Basso (Canale 7)**\n* **Kick (Canale 9)**\n* **Snare (Canale 10)**\n* **Tom 1 (Canale 11)**\n* **Tom 2 (Canale 12)**\n* **Tom3 (Canale 13)**\n* **Pan SX (Canale 14)**\n* **Pan dx (Canale 15)**\n* **Vox 5 (Canale 19)**\n* **Tast (Canale 20)**\n* **Vox3 (Canale 23)**\n* **Chit cnt (Canale 24)**\n* **Chit dx (Canale 25)**\n* **Vox 4 (Canale 27)**\n* **ch35 (Canale 35)**\n* **ch36 (Canale 36)**\n* **ch37 (Canale 37)**\n* **ch38 (Canale 38)**\n* **ch39 (Canale 39)**\n* **ch40 (Canale 40)**\n\n**Canali spenti o sconosciuti:**\n* **Canale 1:** Sconosciuto, spento, volume a 0.65 dB\n* **Talkback (Canale 3):** Spento, volume a -60 dB\n* **Canale 4:** Sconosciuto, spento, volume a -120 dB\n* **Canale 8:** Sconosciuto, spento, volume a -120 dB\n* **Canale 16:** Sconosciuto, spento, volume a -120 dB\n* **Canale 17:** Sconosciuto, spento, volume a -120 dB\n* **Archetto (Canale 18):** Spento, volume a -76 dB\n* **Canale 21:** Sconosciuto, spento, volume a -120 dB\n* **Canale 22:** Sconosciuto, spento, volume a -120 dB\n* **Canale 26:** Sconosciuto, spento, volume a -120 dB\n* **Canale 28:** Sconosciuto, spento, volume a -120 dB\n* **Pad (Canale 29):** Spento, volume a -120 dB\n* **Canali dal 30 al 32:** Sconosciuti, spenti, volume a -120 dB\n\nLa cache è stata aggiornata circa 10 minuti fa. Sembra che molti canali siano spenti o con volumi molto bassi. Fammi sapere se vuoi che accenda o alzi qualcosa! 🎛️🎤",
|
||||||
|
"timestamp": 1770578542.7348733,
|
||||||
|
"timestamp_str": "2026-02-08 19:22:22"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1083,7 +1083,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
bot = TF5TelegramBot(
|
bot = TF5TelegramBot(
|
||||||
telegram_token=telegram_token,
|
telegram_token=telegram_token,
|
||||||
mixer_host=args.mixer_host,
|
mixer_host=get_host(),
|
||||||
mixer_port=args.mixer_port,
|
mixer_port=args.mixer_port,
|
||||||
conversations_dir=args.conversations_dir,
|
conversations_dir=args.conversations_dir,
|
||||||
profiles_dir=args.profiles_dir
|
profiles_dir=args.profiles_dir
|
||||||
|
|||||||
Reference in New Issue
Block a user