import { createRequire } from 'node:module' import type { DeviceSnapshot } from '../domain/device/device.js' import type { Device } from '../domain/device/device.js' import { DeviceParameter } from '../domain/device/device_parameter.js' const require = createRequire(import.meta.url) const tr181Catalog: Array<{ path: string; writable: boolean; deviceClass: string }> = require('../../config/tr181-catalog.json') // Index chargé une fois au démarrage — O(1) lookup const catalogIndex = new Map(tr181Catalog.map((e) => [e.path, e.writable])) const catalogWritableIndex = new Set( tr181Catalog.filter((e) => e.writable).map((e) => e.path) ) /** Remplace les segments numériques par {i} pour matcher les entrées du catalogue */ export function normalizePath(path: string): string { return path.replace(/\.\d+\./g, '.{i}.').replace(/\.\d+$/, '.{i}') } export type WritabilitySource = 'live' | 'catalog' | 'default' | 'unknown' export interface WritabilityResult { writable: boolean | null source: WritabilitySource } /** * Résout la writabilité d'un paramètre à partir de l'état persisté du device. * * Logique : * 1. gpnStatus = 'supported' → parameters[] = writable, properties[] = RO (source fiable) * 2. gpnStatus = 'unsupported' → catalogue TR-181 → absent = writable=true (défaut R/W) * 3. gpnStatus = 'unknown' → catalogue TR-181 → absent = writable=null (genuinement inconnu) */ export function resolveWritability(snapshot: DeviceSnapshot, paramPath: string): WritabilityResult { const { gpnStatus, parameters, properties } = snapshot if (gpnStatus === 'supported') { if (parameters.some((p) => p.name === paramPath)) return { writable: true, source: 'live' } if (properties.some((p) => p.name === paramPath)) return { writable: false, source: 'live' } } // gpnStatus = 'unsupported' ou 'unknown' → consulter le catalogue const normalized = normalizePath(paramPath) if (catalogIndex.has(normalized)) { return { writable: catalogIndex.get(normalized)!, source: 'catalog' } } // Absent du catalogue if (gpnStatus === 'unsupported') return { writable: true, source: 'default' } return { writable: null, source: 'unknown' } } /** * Reclassify device properties as parameters using the TR-181 catalog. * Properties that are writable per the catalog are moved to parameters. * Should be called after updateFromValues when gpnStatus is 'unsupported'. */ export function reclassifyDeviceFromCatalog(device: Device): number { const properties = device.getProperties() let reclassified = 0 for (const prop of properties) { const normalized = normalizePath(prop.name) if (catalogWritableIndex.has(normalized)) { const snap = prop.toSnapshot() device.setParameter( new DeviceParameter(snap.name, snap.value, snap.type, snap.createdAt, snap.updatedAt, snap.notification, snap.accessList) ) ;(device as any)._properties.delete(prop.name) reclassified++ } } return reclassified }