mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 19:06:34 +00:00
feat(cameras): sync entity name on rename + ONVIF device name from GetDeviceInformation
Two fixes: 1. When admin renames a camera, the linked entity's name now syncs automatically so the entity list doesn't drift from the camera list. 2. ONVIF discovery now calls GetDeviceInformation before GetProfiles (best-effort, catches auth-gated devices). Pulls Manufacturer + Model and uses the combined string as the camera's proposed name instead of the raw IP. E.g. "Hikvision DS-2CD2146G2" instead of "192.168.74.8". Falls back to host IP when the device omits the info.
This commit is contained in:
parent
5edf9d4b0b
commit
9129613920
2 changed files with 36 additions and 4 deletions
|
|
@ -1317,6 +1317,14 @@ export function registerAdminRoutes(app: H3, deps: AdminDeps): void {
|
|||
});
|
||||
}
|
||||
}
|
||||
// Sync entity name when camera name changes.
|
||||
if (patch["name"]) {
|
||||
const ent = deps.repo.getEntityForCamera(id);
|
||||
if (ent && ent.name !== patch["name"]) {
|
||||
deps.repo.updateEntity(ent.id, { name: patch["name"] } as any);
|
||||
}
|
||||
}
|
||||
|
||||
notifyKiosks();
|
||||
deps.nodered.forward("camera.changed", { camera_id: id, event: "updated", source: "server" });
|
||||
|
||||
|
|
|
|||
|
|
@ -278,20 +278,21 @@ function profileGroupKey(profileName: string, sourceToken: string | null, stream
|
|||
return match?.[1] ? `channel:${match[1]}` : "source:default";
|
||||
}
|
||||
|
||||
function groupProfiles(host: string, profiles: DiscoveredProfile[]): DiscoveredCamera[] {
|
||||
function groupProfiles(host: string, deviceName: string | null, profiles: DiscoveredProfile[]): DiscoveredCamera[] {
|
||||
const groups = new Map<string, DiscoveredProfile[]>();
|
||||
for (const profile of profiles) {
|
||||
const key = profileGroupKey(profile.profile_name, profile.source_token, profile.stream_uri);
|
||||
groups.set(key, [...(groups.get(key) ?? []), profile]);
|
||||
}
|
||||
|
||||
const base = deviceName || host;
|
||||
const out: DiscoveredCamera[] = [];
|
||||
let i = 1;
|
||||
for (const [key, group] of groups) {
|
||||
const sourceToken = group.find((p) => p.source_token)?.source_token ?? null;
|
||||
const name = groups.size === 1
|
||||
? host
|
||||
: sourceToken ? `${host} ${sourceToken}` : `${host} camera ${String(i)}`;
|
||||
? base
|
||||
: sourceToken ? `${base} ${sourceToken}` : `${base} camera ${String(i)}`;
|
||||
out.push({
|
||||
name,
|
||||
source_token: sourceToken ?? (key.startsWith("channel:") ? key.slice("channel:".length) : null),
|
||||
|
|
@ -316,6 +317,29 @@ export async function discover(input: DiscoverInput): Promise<DiscoveredCamera[]
|
|||
|
||||
const header = wsseHeader(input.username, input.password);
|
||||
|
||||
// ---- GetDeviceInformation (best-effort, for friendly device name) ---------
|
||||
let deviceName: string | null = null;
|
||||
try {
|
||||
const devInfoEnv = buildEnvelope(header, `<tds:GetDeviceInformation xmlns:tds="http://www.onvif.org/ver10/device/wsdl"/>`);
|
||||
const devInfoXml = await soap(
|
||||
endpoint.deviceUrl,
|
||||
"http://www.onvif.org/ver10/device/wsdl/GetDeviceInformation",
|
||||
devInfoEnv,
|
||||
timeoutMs,
|
||||
input.soapTransport,
|
||||
);
|
||||
// Try Manufacturer + Model as combined name (e.g. "Hikvision DS-2CD2146G2")
|
||||
const manufacturer = pickAll(devInfoXml, "Manufacturer")[0]?.trim() ?? null;
|
||||
const model = pickAll(devInfoXml, "Model")[0]?.trim() ?? null;
|
||||
if (manufacturer && model) {
|
||||
deviceName = `${manufacturer} ${model}`;
|
||||
} else {
|
||||
deviceName = manufacturer ?? model ?? null;
|
||||
}
|
||||
} catch {
|
||||
// Device info is optional — some cameras gate it behind auth or omit it.
|
||||
}
|
||||
|
||||
// ---- GetProfiles -----------------------------------------------------------
|
||||
const profilesEnv = buildEnvelope(header, `<trt:GetProfiles/>`);
|
||||
const profilesXml = await soap(
|
||||
|
|
@ -403,5 +427,5 @@ export async function discover(input: DiscoverInput): Promise<DiscoveredCamera[]
|
|||
});
|
||||
}
|
||||
|
||||
return groupProfiles(input.host, out);
|
||||
return groupProfiles(input.host, deviceName, out);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue