我有一个物联网设备,在运行时有一些可配置的参数。该参数可以由设备用户配置,也可以由设备配置(在某些情况下可以重新配置自身以优化功耗)。设备通过 HTTP 进行通信,并且没有配置端点,因此在发送测量结果时必须接收配置更新。
我正在使用 Orion LD 和 IOT 代理 JSON。为了解决这个场景,我决定使用双向属性,因为这些参数可以由设备和最终用户修改,并且不是真正的执行器。尽管如此,我在配置这个时遇到了一些问题。
我正在使用以下 docker compose 文件部署 Orion LD、IOT 代理 JSON 和上下文服务器:
version: "3.8"
services:
ngsi-ld-context-server:
image: nginx:latest
hostname: ngsi-ld-context-server
container_name: ngsi-ld-context-server
networks:
- fiware
ports:
- "9090:80"
volumes:
- ./ngsild-context.jsonld:/usr/share/nginx/html/ngsild-context.jsonld
fiware-mongo-db:
image: mongo:4.4
hostname: fiware-mongo-db
container_name: fiware-mongo-db
networks:
- fiware
ports:
- "27017:27017"
orion-ld:
platform: linux/amd64
image: quay.io/fiware/orion-ld:1.4.0
hostname: orion-ld
container_name: orion-ld
networks:
- fiware
depends_on:
- fiware-mongo-db
ports:
- "1026:1026"
command: -dbhost fiware-mongo-db -logLevel DEBUG -forwarding -experimental
iot-agent-json:
image: quay.io/fiware/iotagent-json:2.2.0
hostname: iot-agent-json
container_name: iot-agent-json
networks:
- fiware
depends_on:
- fiware-mongo-db
- orion-ld
ports:
- "4041:4041"
- "7896:7896"
environment:
- IOTA_CB_HOST=orion-ld
- IOTA_CB_PORT=1026
- IOTA_NORTH_PORT=4041
- IOTA_REGISTRY_TYPE=mongodb
- IOTA_LOG_LEVEL=DEBUG
- IOTA_TIMESTAMP=true
- IOTA_AUTOCAST=true
- IOTA_MONGO_HOST=fiware-mongo-db
- IOTA_MONGO_PORT=27017
- IOTA_MONGO_DB=iotagenjson
- IOTA_HTTP_PORT=7896
- IOTA_PROVIDER_URL=http://iot-agent-json:4041
- IOTA_DEFAULT_RESOURCE=/iot/json
- IOTA_CB_NGSI_VERSION=ld
- IOTA_JSON_LD_CONTEXT=http://ngsi-ld-context-server/ngsild-context.jsonld
- IOTA_FALLBACK_TENANT=openiot
networks:
fiware:
driver: bridge
首先,我为设备创建一个服务:
{
"services": [
{
"apikey": "4jggokgpepnvsb2uv4s40d59ov",
"cbroker": "http://orion-ld:1026",
"entity_type": "Device",
"resource": "/iot/json"
}
]
}
然后我尝试按照 IOT 代理 NGSILD 教程配置双向属性 (没有提供端点,因为我想轮询):
{
"devices": [
{
"device_id": "device001",
"entity_name": "urn:ngsi-ld:Device:device001",
"entity_type": "Device",
"attributes": [
{
"name": "sampleTime",
"type": "Property",
"reverse": [
{
"object_id": "sampleTime",
"type": "Property"
}
]
}
]
}
]
}
但我得到以下回复:
{
"name": "ENTITY_GENERIC_ERROR",
"message": "Error accesing entity data for device: urn:ngsi-ld:Device:device001 of type: Device"
}
查看 IOT 代理日志,我发现它正在尝试创建具有空属性的 Orion 订阅,这是不允许的:
time=2023-08-31T06:36:43.764Z | lvl=DEBUG | corr=1cfae922-438d-473a-9511-1f4fe7ad9f3e | trans=1cfae922-438d-473a-9511-1f4fe7ad9f3e | op=IoTAgentNGSI.BidirectionalPlugin | from=n/a | srv=n/a | subsrv=n/a | msg=Extracted variables: [] | comp=IoTAgent
time=2023-08-31T06:36:43.765Z | lvl=DEBUG | corr=1cfae922-438d-473a-9511-1f4fe7ad9f3e | trans=1cfae922-438d-473a-9511-1f4fe7ad9f3e | op=IoTAgentNGSI.RestUtils | from=n/a | srv=n/a | subsrv=n/a | msg=executeWithSecurity | comp=IoTAgent
time=2023-08-31T06:36:43.765Z | lvl=DEBUG | corr=1cfae922-438d-473a-9511-1f4fe7ad9f3e | trans=1cfae922-438d-473a-9511-1f4fe7ad9f3e | op=IoTAgentNGSI.MongoDBGroupRegister | from=n/a | srv=n/a | subsrv=n/a | msg=Looking for group params ["type"] with queryObj {"type":"Device"} | comp=IoTAgent
time=2023-08-31T06:36:43.768Z | lvl=DEBUG | corr=1cfae922-438d-473a-9511-1f4fe7ad9f3e | trans=1cfae922-438d-473a-9511-1f4fe7ad9f3e | op=IoTAgentNGSI.MongoDBGroupRegister | from=n/a | srv=openiot | subsrv=/ | msg=Device group data found: {"_id":"64f033436e41de0d07b70359","resource":"/iot/json","apikey":"4jggokgpepnvsb2uv4s40d59ov","type":"Device","service":"openiot","subservice":"/"} | comp=IoTAgent
time=2023-08-31T06:36:43.769Z | lvl=DEBUG | corr=1cfae922-438d-473a-9511-1f4fe7ad9f3e | trans=1cfae922-438d-473a-9511-1f4fe7ad9f3e | op=IoTAgentNGSI.Request | from=n/a | srv=openiot | subsrv=/ | msg=Options: {
"method": "POST",
"headers": {
"fiware-service": "openiot",
"fiware-servicepath": "/",
"NGSILD-Tenant": "openiot",
"NGSILD-Path": "/",
"Content-Type": "application/ld+json"
},
"json": {
"@context": "http://ngsi-ld-context-server/ngsild-context.jsonld",
"type": "Subscription",
"entities": [
{
"id": "urn:ngsi-ld:Device:device001",
"type": "Device"
}
],
"watchedAttributes": [
"sampleTime"
],
"notification": {
"endpoint": {
"uri": "http://iot-agent-json:4041/notify",
"accept": "application/json"
},
"attributes": [],
"format": "normalized"
}
},
"uri": "http://orion-ld:1026/ngsi-ld/v1/subscriptions/"
} | comp=IoTAgent
time=2023-08-31T06:36:43.786Z | lvl=DEBUG | corr=1cfae922-438d-473a-9511-1f4fe7ad9f3e | trans=1cfae922-438d-473a-9511-1f4fe7ad9f3e | op=IoTAgentNGSI.Request | from=n/a | srv=openiot | subsrv=/ | msg=Response {
"type": "https://uri.etsi.org/ngsi-ld/errors/BadRequestData",
"title": "Empty Array",
"detail": "Subscription::notification::attributes"
} | comp=IoTAgent
time=2023-08-31T06:36:43.786Z | lvl=DEBUG | corr=1cfae922-438d-473a-9511-1f4fe7ad9f3e | trans=1cfae922-438d-473a-9511-1f4fe7ad9f3e | op=IoTAgentNGSI.Subscription-LD | from=n/a | srv=openiot | subsrv=/ | msg=Unknown error subscribing device with id [400] to entity [%s]: $s | comp=IoTAgent
我在配置中遗漏了什么吗?
我继续寻找解决方案,发现如果我在配置中添加一个表达式,它就可以工作:
{
"devices": [
{
"device_id": "device001",
"entity_name": "urn:ngsi-ld:Device:device001",
"entity_type": "Device",
"attributes": [
{
"name": "sampleTime",
"type": "Property",
"reverse": [
{
"object_id": "sampleTime",
"type": "Property",
"expression": "sampleTime | tostring()"
}
]
}
]
}
]
}
但是当我尝试使用 getCmd 参数获取命令时,它会返回该命令两次,并且当我在将其检索到设备之前再次更新它时,它不会返回更新的命令。看起来它没有在 mongodb 上正确存储命令。
由于此解决方案似乎不起作用,是否有任何“标准”方法来处理设备和用户都可以修改的属性?
从 IoTAgents 的角度来看,我们不鼓励使用双向插件。您正在讨论的用例可以使用轮询命令(?getCmd = 1)来解决,因此具有新配置的命令将作为发送措施的响应返回。
双向插件以及所有复杂的插件已在 IoTAgents 库版本 3.3.0 中弃用,并将很快被删除(在下一个 IoTAgent 库版本,即 3.4.0 中)。
我们知道有一些与 NGSI 注册不兼容的代理,需要从 CB 向 IoTAgent 发出命令,这促使使用双向插件作为解决方法。在 IoTAgents 命令的未来版本中,将通过订阅而不是注册来支持,因此这种解决方法的需求会被削弱。