- Fix state machine start timing: don't call start() in startStateMachine, let the CPE's first empty body trigger the state machine via continue(). This ensures GPN is sent at the correct point in the TR-069 session. - Add unit tests for reclassifyDeviceFromCatalog (10 tests) - Add unit tests for MainStateMachine transitions and GPN callbacks (11 tests) - Test both scenarios: Huawei (GPN supported) and Livebox (GPN unsupported + fallback) - Fix tr069_trace_service test path assertion (config/ → data/) - Update steering doc with Livebox bootstrap command
6.6 KiB
Debug: Reclassification Properties → Parameters
Contexte du problème
Les paramètres Device.ManagementServer.PeriodicInformInterval et Device.DeviceInfo.ProvisioningCode apparaissent comme properties (read-only) dans l'interface alors qu'ils devraient être des parameters (writable).
Le catalogue config/tr181-catalog.json les marque bien comme writable: true.
La fonction reclassifyDeviceFromCatalog() dans app/services/parameter_writability.ts est censée les déplacer de properties vers parameters quand gpnStatus === 'unsupported'.
Le dernier log de debug montre : [Reclassify] properties=9, reclassified=0, catalogSize=2953 — la fonction est appelée mais ne reclassifie rien malgré les paths présents dans le catalogue.
Fichiers impliqués
app/services/parameter_writability.ts— contientreclassifyDeviceFromCatalog()etnormalizePath()app/services/cwmp/device_action_executor.ts— appelle la reclassification quand GPN échoueapp/services/cwmp/main_state_machine.ts—CompletedStateappelle aussi la reclassificationapp/controllers/cwmp_controller.ts—handleInform()appelle la reclassification sigpnStatus === 'unsupported'app/domain/device/device.ts—updateFromValues()stocke les nouveaux params comme properties par défautconfig/tr181-catalog.json— référentiel de writabilité TR-181
Procédure de test complète
1. Faire la modification de code
Modifier le fichier concerné, puis vérifier la compilation :
npx tsc --noEmit
2. Build et relance Docker
docker compose build app
docker compose up -d app
Attendre que l'app soit healthy :
docker compose logs app --tail 5
3. Supprimer le device Sagemcom de l'ACS
curl -s -X DELETE http://localhost:8080/api/v1/devices/2e933565b8fc09f34f42531e
4. Supprimer le device du simulateur (home-device-simulator)
curl -s -X DELETE "http://localhost:9898/api/v1/device-simulator/delete-devices" \
-H 'Content-Type: application/json' \
-d '["F8:B7:FF:00:11:22"]'
5. Recréer le device dans le simulateur
curl -s -X PUT "http://localhost:9898/api/v1/device-simulator/create-devices?noOfDevices=1&autoGenerate=false&ipAddressType=ipv4" \
-H 'Content-Type: application/json' \
-d '{
"manufacturer": "Sagemcom",
"oui": "F8B7FF",
"productClass": "Livebox 4",
"serialNumber": "LB4-TEST-001",
"macaddress": "F8:B7:FF:00:11:22",
"parameters": [
{"type": "Manufacturer", "model": "Device.DeviceInfo.Manufacturer", "value": "Sagemcom"},
{"type": "ManufacturerOUI", "model": "Device.DeviceInfo.ManufacturerOUI", "value": "F8B7FF"},
{"type": "ModelName", "model": "Device.DeviceInfo.ModelName", "value": "Livebox 4"},
{"type": "ProductClass", "model": "Device.DeviceInfo.ProductClass", "value": "Livebox 4"},
{"type": "SerialNumber", "model": "Device.DeviceInfo.SerialNumber", "value": "LB4-TEST-001"},
{"type": "HardwareVersion", "model": "Device.DeviceInfo.HardwareVersion", "value": "SR40_sip-fr-4.62.0"},
{"type": "SoftwareVersion", "model": "Device.DeviceInfo.SoftwareVersion", "value": "SR40_sip-fr-4.62.0"}
]
}'
6. Déclencher le bootstrap Inform
Le simulateur ne fait PAS d'Inform automatiquement après la création. Il faut le déclencher manuellement :
sleep 3
curl -s -X POST "http://localhost:9898/api/v1/device-simulator/device-request" \
-H 'Content-Type: application/json' \
-d '{"actions":[{"macaddress":"F8:B7:FF:00:11:22","event":{"0":"BOOTSTRAP"}}]}'
7. Attendre l'Inform (30s max) puis vérifier
sleep 30
Vérifier la classification :
curl -s "http://localhost:8080/api/v1/devices/2e933565b8fc09f34f42531e" | \
python3 -c "
import sys,json
d=json.load(sys.stdin)
print('gpnStatus:', d.get('gpnStatus'))
props = [p['name'] for p in d.get('properties',[]) if 'PeriodicInform' in p['name'] or 'ProvisioningCode' in p['name']]
params = [p['name'] for p in d.get('parameters',[]) if 'PeriodicInform' in p['name'] or 'ProvisioningCode' in p['name']]
print('Dans properties (MAUVAIS):', props)
print('Dans parameters (BON):', params)
"
8. Regarder les logs de reclassification
docker compose logs app --tail 50 2>&1 | grep -i "reclassify\|Reclassify"
Résultat attendu
Sagemcom Livebox 4 (GPN unsupported, reclassification via catalogue) :
gpnStatus: unsupported
properties: 7
parameters: 2 (PeriodicInformInterval + ProvisioningCode)
Huawei BM632w (GPN supported, classification via GPN response) :
gpnStatus: supported
properties: 16
parameters: 15
compliance: compliant
Identifiants du device de test
| Champ | Valeur |
|---|---|
| ACS identifier | 2e933565b8fc09f34f42531e |
| Manufacturer | Sagemcom |
| OUI | F8B7FF |
| Product Class | Livebox 4 |
| Serial Number | LB4-TEST-001 |
| MAC (simulateur) | F8:B7:FF:00:11:22 |
| Data Model | tr-181 |
Device Huawei (genieacs-sim)
| Champ | Valeur |
|---|---|
| ACS identifier | f9747826c5545b0e49db7967 |
| Manufacturer | Huawei Technologies Co., Ltd. |
| OUI | 202BC1 |
| Product Class | BM632w |
| Serial Number | 000000 |
| Data Model | tr-098 (InternetGatewayDevice.*) |
| Container | adam-acs-genieacs-sim-1 |
Procédure de test Huawei
Le Huawei est simulé par le container genieacs-sim (défini dans docker-compose.yml avec le profile test). Il se crée automatiquement au démarrage du container.
Supprimer le device :
docker stop adam-acs-genieacs-sim-1 && docker rm adam-acs-genieacs-sim-1
curl -s -X DELETE http://localhost:8080/api/v1/devices/f9747826c5545b0e49db7967
Recréer le device (relancer le container) :
docker compose --profile test up -d genieacs-sim
Le container fait un Inform automatiquement au démarrage vers http://app:8080/cwmp10.
Vérifier :
sleep 15
curl -s "http://localhost:8080/api/v1/devices/f9747826c5545b0e49db7967" | python3 -c "
import sys,json
d=json.load(sys.stdin)
print('gpnStatus:', d.get('gpnStatus'))
print('dataModel:', d.get('dataModel'))
print('Properties:', len(d.get('properties',[])))
print('Parameters:', len(d.get('parameters',[])))
"
- Base URL :
http://localhost:9898/api/v1/device-simulator - Swagger :
http://localhost:9898/swagger/ - Suppression par MAC :
DELETE /delete-devicesbody["MAC"] - Création :
PUT /create-devices?noOfDevices=1&autoGenerate=false&ipAddressType=ipv4
Trace TR-069
Le device est déjà dans la config de trace (data/tr069-trace.json dans le volume Docker app_tr069_data). Les logs SOAP sont visibles sur http://localhost:8080/tr069-trace.