Geraete-Aenderungen (Name/IP) jetzt auch nur als Vorschlag statt automatisch, klarere FritzBox-Zaehlung

This commit is contained in:
2026-07-22 16:53:38 +02:00
parent 5f150119b2
commit 54f224b650
5 changed files with 172 additions and 16 deletions

View File

@@ -28,7 +28,7 @@ export async function pluginRoutes(app: FastifyInstance): Promise<void> {
try {
const devices = await loaded.plugin.importDevices();
const imported = devices.map((d) =>
const results = devices.map((d) =>
deviceRepo.upsertDeviceFromScan({
hostname: d.hostname,
ip: d.ip,
@@ -39,14 +39,18 @@ export async function pluginRoutes(app: FastifyInstance): Promise<void> {
source: "plugin",
})
);
const imported = results.map((r) => r.device);
const deviceChanges = results.flatMap((r) =>
r.changes.map((c) => ({ deviceId: r.device.id, ...c }))
);
logRepo.logScan({
type: "device",
level: "info",
message: `Plugin "${name}": ${imported.length} Gerät(e) importiert`,
message: `Plugin "${name}": ${imported.length} Gerät(e) importiert${deviceChanges.length > 0 ? `, ${deviceChanges.length} Änderung(en) vorgeschlagen` : ""}`,
});
return { imported: imported.length, devices: imported };
return { imported: imported.length, devices: imported, deviceChanges };
} catch (err) {
const detail = err instanceof Error ? err.message : String(err);
logRepo.logScan({

View File

@@ -139,7 +139,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
const devicesBeforeScan = deviceRepo.listDevices().filter((d) => d.source === "fritzbox");
const hosts = await fetchFritzBoxHosts({ host, port, username, password });
const devices = hosts.map((h) =>
const results = hosts.map((h) =>
deviceRepo.upsertDeviceFromScan({
hostname: h.hostname,
ip: h.ip,
@@ -149,6 +149,26 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
})
);
// Mehrere TR-064-Einträge können auf dasselbe Gerät zusammengeführt
// werden (z. B. IPv4+IPv6 oder WLAN+Mesh-Eintrag desselben Geräts,
// abgeglichen über MAC/IP) - deshalb kann "gefundene Einträge" > Anzahl
// eindeutiger Geräte sein. Für die Rückgabe nach Geräte-ID dedupliziert.
const seenIds = new Set<string>();
const devices = results
.map((r) => r.device)
.filter((d) => {
if (seenIds.has(d.id)) return false;
seenIds.add(d.id);
return true;
});
// Vorschläge für abweichende Hostnamen/IPs bereits bekannter Geräte
// einsammeln (siehe upsertDeviceFromScan) - werden NICHT automatisch
// übernommen, nur zur Bestätigung zurückgegeben.
const deviceChanges = results.flatMap((r) =>
r.changes.map((c) => ({ deviceId: r.device.id, deviceHostname: r.device.hostname, ...c }))
);
// Geräte, die die FritzBox früher gemeldet hatte, diesmal aber nicht
// mehr in der Liste sind nicht automatisch gelöscht, nur zur
// manuellen Durchsicht zurückgegeben.
@@ -158,10 +178,16 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
logRepo.logScan({
type: "fritzbox",
level: "info",
message: `FritzBox-Scan: ${hosts.length} Gerät(e) gefunden${staleDevices.length > 0 ? `, ${staleDevices.length} nicht mehr gemeldet` : ""}`,
message: `FritzBox-Scan: ${hosts.length} Eintrag/Einträge (${devices.length} eindeutige Geräte)${staleDevices.length > 0 ? `, ${staleDevices.length} nicht mehr gemeldet` : ""}${deviceChanges.length > 0 ? `, ${deviceChanges.length} Änderung(en) vorgeschlagen` : ""}`,
});
return { found: hosts.length, devices, staleDevices };
return {
found: hosts.length,
uniqueDevices: devices.length,
devices,
staleDevices,
deviceChanges,
};
} catch (err) {
const detail = err instanceof Error ? err.message : String(err);
logRepo.logScan({