如标题中所述,我正在与 FIWARE 合作,特别是与 NGSI-LD 合作。为此,我使用 Docker Compose 部署了一系列容器:ld-context(这是为 Context Broker 提供上下文的容器)、orion-ld(我正在使用的 Context Broker)、quantumleap、mongo- db、crate-db 和 redis-db。
此外,我还部署了IoT Agent(我使用此 GitHub 存储库作为参考:https://github.com/telefonicaid/iotagent-json)。
我一直在通过在 IoT 代理中创建不同的设备和在 Context Broker 中创建不同的实体进行测试,没有遇到任何问题。这是我创建它们的方法。对于这些测试,我一直在使用 Bruno。
Service Group Creation:
POST: http://localhost:4041/iot/services
Headers:
Content-Type: application/json
fiware-service: openiot_device
fiware-servicepath: /
Body:
{
"services": [
{
"apikey": "openiot_device",
"cbroker": "http://localhost:1026",
"entity_type": "Device",
"resource": "/iot/json"
}
]
}
Device Creation:
POST: http://localhost:4041/iot/devices
Headers:
Content-Type: application/json
fiware-service: openiot_device
fiware-servicepath: /
Body:
{
"devices": [
{
"device_id": "device004",
"entity_name": "urn:ngsi-ld:Device:004",
"entity_type": "Device",
"timezone": "Europe/Berlin",
"attributes": [
{
"object_id": "t",
"name": "temperature",
"type": "Property",
"metadata": {
"unitCode": {
"type": "Text",
"value": "CEL"
}
}
}
],
"static_attributes": []
}
]
}
Entity Creation:
POST: http://localhost:1026/ngsi-ld/v1/entities/
Headers:
Content-Type: application/ld+json
fiware-service: openiot_device
fiware-servicepath: /
Body:
{
"id": "urn:ngsi-ld:Device:002",
"type": "Device",
"temperature": {
"type": "Property",
"value": 22
},
"@context": "http://context/user-context.jsonld"
}
我能够毫无问题地创建这些项目。我访问了 mongo-db 容器并验证了所有三个项目均已成功创建,并且我能够毫无问题地更新实体值。
当我尝试创建执行器时出现问题,因为我希望能够向它发送命令。为此,我遵循了类似的方法。
首先,为了启用命令发送,我修改了config.js文件:
var config = {};
config.http = {
port: 7896
};
config.iota = {
logLevel: 'DEBUG',
timestamp: true,
contextBroker: {
host: 'localhost',
port: '1026',
ngsiVersion: 'ld',
jsonLdContext: ['http://context/ngsi-context.jsonld',
'http://context/json-context.jsonld'],
fallbackTenant: 'openiot',
fallbackPath: '/'
},
server: {
port: 4041,
ldSupport: {
null: true,
datasetId: true,
merge: false
}
},
deviceRegistry: {
type: 'mongodb'
},
mongodb: {
host: 'localhost',
port: '27017',
db: 'iotagentjson'
},
types: {
/*Added type actuator with the command I want to use*/
Actuator: {
commands: ['download_json_data']
}
},
service: 'openiot',
subservice: '/',
providerUrl: 'http://localhost:4041',
deviceRegistrationDuration: 'P20Y',
defaultType: 'mtoolkit',
defaultResource: '/iot/json',
explicitAttrs: true,
contextBrokerUpdate: true
};
config.jexlTransformations = {};
config.configRetrieval = false;
config.defaultKey = 'mtoolkit1234';
config.defaultTransport = 'HTTP';
module.exports = config;
我将“download_json_data”命令添加到执行器类型中。我尝试以两种不同的方式创建执行器(我为这种类型的设备创建了一个带有固件服务的组:openiot_actuator):
1)直接使用命令创建设备:
帖子:
http://localhost:4041/iot/devices
标题:
Content-Type: application/json
fiware-service: openiot_actuator
fiware-servicepath: /
身体:
{
"devices": [
{
"device_id": "actuator005",
"entity_name": "urn:ngsi-ld:Actuator:005",
"entity_type": "Actuator",
"timezone": "Europe/Berlin",
"transport": "HTTP",
"commands": [
{
"name": "download_json_data",
"type": "command"
}
],
"static_attributes": [
{
"name": "base_url",
"type": "URL",
"value": "https://..."
}
]
}
]
}
我收到以下错误:
{
"name": "BAD_REQUEST",
"message": "Request error connecting to the Context Broker: 400"
}
这个错误没有多大意义,因为我能够以相同的方式创建设备类型而没有任何问题。
2)无需传递命令即可创建设备,因为它是在 config.js 中定义的:
帖子:
http://localhost:4041/iot/devices
标题:
Content-Type: application/json
fiware-service: openiot_actuator
fiware-servicepath: /
身体:
{
"devices": [
{
"device_id": "actuator004",
"entity_name": "urn:ngsi-ld:Actuator:004",
"entity_type": "Actuator",
"timezone": "Europe/Berlin",
"transport": "HTTP",
"static_attributes": [
{
"name": "base_url",
"type": "URL",
"value": "https://..."
}
]
}
]
}
这样,执行器设备就创建成功了,但是还没有分配命令。这是我在数据库中看到的:
{
_id: ObjectId('672375b3d05e4d4395dcd078'),
lazy: [],
commands: [],
staticAttributes: [
{
name: 'base_url',
type: 'URL',
value: 'https://...'
}
],
creationDate: ISODate('2024-10-31T12:18:59.467Z'),
id: 'actuator004',
type: 'Actuator',
name: 'urn:ngsi-ld:Actuator:004',
service: 'openiot_actuator',
subservice: '/',
internalId: null,
transport: 'HTTP',
polling: true,
__v: 0
}
更新:
在这里,我在尝试 POST 执行器时添加来自 IoT 代理的日志:
time=2024-11-04T11:57:02.827Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.GenericMiddlewares | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Request for path [/iot/devices] query [{}] from [localhost:4041] | comp=IoTAgent
time=2024-11-04T11:57:02.827Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.GenericMiddlewares | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Body:
{
"devices": [
{
"device_id": "actuator005",
"entity_name": "urn:ngsi-ld:Actuator:005",
"entity_type": "Actuator",
"timezone": "Europe/Berlin",
"transport": "HTTP",
"static_attributes": [
{
"name": "base_url",
"type": "URL",
"value": "https://..."
}
]
}
]
}
| comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.DeviceProvisioning | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Handling device provisioning request. | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentJSON.Agent | from=n/a | srv=openiot_actuator | subsrv=/ | msg=deviceProvisioningHandler for device {"id":"actuator005","type":"Actuator","name":"urn:ngsi-ld:Actuator:005","service":"openiot_actuator","subservice":"/","staticAttributes":[{"name":"base_url","type":"URL","value":"https://datosabiertos.castro-urdiales.net/transdat.aspx"}],"timezone":"Europe/Berlin","transport":"HTTP","internalId":null} | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.RestUtils | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Looking for bindings for the function deviceProvisioningHandler and protocol null | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.RestUtils | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Creating execution for function deviceProvisioningHandler and protocol null | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.RestUtils | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Binding found for function deviceProvisioningHandler and protocol null | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.RestUtils | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Binding found for function deviceProvisioningHandler and protocol null | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.RestUtils | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Binding found for function deviceProvisioningHandler and protocol null | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.RestUtils | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Binding found for function deviceProvisioningHandler and protocol null | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IOTAJSON.HTTP.Binding | from=n/a | srv=openiot_actuator | subsrv=/ | msg=httpbinding.deviceProvisioningHandler device {"id":"actuator005","type":"Actuator","name":"urn:ngsi-ld:Actuator:005","service":"openiot_actuator","subservice":"/","staticAttributes":[{"name":"base_url","type":"URL","value":"https://datosabiertos.castro-urdiales.net/transdat.aspx"}],"timezone":"Europe/Berlin","transport":"HTTP","internalId":null} | comp=IoTAgent
time=2024-11-04T11:57:02.828Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.MongoDBGroupRegister | from=n/a | srv=n/a | subsrv=n/a | msg=Looking for group params ["resource","apikey"] with queryObj {"resource":"/iot/json"} | comp=IoTAgent
time=2024-11-04T11:57:02.830Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.MongoDBGroupRegister | from=n/a | srv=openiot_device | subsrv=/ | msg=Device group data found: {"_id":"6720f8ce6dd0222e8d9057a4","resource":"/iot/json","apikey":"openiot_device","type":"Device","service":"openiot_device","subservice":"/"} | comp=IoTAgent
time=2024-11-04T11:57:02.831Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IOTAJSON.HTTP.Binding | from=n/a | srv=openiot_actuator | subsrv=/ | msg=httpbinding.deviceProvisioningHandler group {"_id":"6720f8ce6dd0222e8d9057a4","resource":"/iot/json","apikey":"openiot_device","type":"Device","service":"openiot_device","subservice":"/"} | comp=IoTAgent
time=2024-11-04T11:57:02.831Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IOTAJSON.HTTP.Binding | from=n/a | srv=openiot_actuator | subsrv=/ | msg=httpbinding.setPollingAndDefaultTransport device {"id":"actuator005","type":"Actuator","name":"urn:ngsi-ld:Actuator:005","service":"openiot_actuator","subservice":"/","staticAttributes":[{"name":"base_url","type":"URL","value":"https://datosabiertos.castro-urdiales.net/transdat.aspx"}],"timezone":"Europe/Berlin","transport":"HTTP","internalId":null} group {"_id":"6720f8ce6dd0222e8d9057a4","resource":"/iot/json","apikey":"openiot_device","type":"Device","service":"openiot_device","subservice":"/"} | comp=IoTAgent
time=2024-11-04T11:57:02.831Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.MongoDBDeviceRegister | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Looking for device with id [actuator005] and queryParams [{"id":"actuator005","service":"openiot_actuator","subservice":"/"}]. | comp=IoTAgent
time=2024-11-04T11:57:02.832Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.MongoDBDeviceRegister | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Device [actuator005] not found. | comp=IoTAgent
time=2024-11-04T11:57:02.833Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.MongoDBGroupRegister | from=n/a | srv=n/a | subsrv=n/a | msg=Looking for group params ["service","subservice","type","apikey"] with queryObj {"service":"openiot_actuator","subservice":"/","type":"Actuator"} | comp=IoTAgent
time=2024-11-04T11:57:02.835Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.MongoDBGroupRegister | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Device group data found: {"_id":"67233c6c390fec5139030d86","resource":"/iot/json","apikey":"openiot_actuator","type":"Actuator","service":"openiot_actuator","subservice":"/"} | comp=IoTAgent
time=2024-11-04T11:57:02.835Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.DeviceService | from=n/a | srv=openiot_device | subsrv=/ | msg=Prepare device data:
{
"id": "actuator005",
"type": "Actuator",
"name": "urn:ngsi-ld:Actuator:005",
"service": "openiot_actuator",
"subservice": "/",
"staticAttributes": [
{
"name": "base_url",
"type": "URL",
"value": "https://..."
}
],
"timezone": "Europe/Berlin",
"transport": "HTTP",
"internalId": null,
"polling": true
} | comp=IoTAgent
time=2024-11-04T11:57:02.835Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.DeviceService | from=n/a | srv=openiot_device | subsrv=/ | msg=deviceData before merge with conf: {"id":"actuator005","type":"Actuator","name":"urn:ngsi-ld:Actuator:005","service":"openiot_actuator","subservice":"/","staticAttributes":[{"name":"base_url","type":"URL","value":"https://datosabiertos.castro-urdiales.net/transdat.aspx"}],"timezone":"Europe/Berlin","transport":"HTTP","internalId":null,"explicitAttrs":true,"polling":true} defaults: [null,null,[],[],[],[],[]] fields: ["lazy","active","staticAttributes","commands","subscriptions"] configuration {"_id":"67233c6c390fec5139030d86","resource":"/iot/json","apikey":"openiot_actuator","type":"Actuator","service":"openiot_actuator","subservice":"/"} | comp=IoTAgent
time=2024-11-04T11:57:02.835Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.DeviceService | from=n/a | srv=openiot_device | subsrv=/ | msg=deviceData after merge with conf: {"id":"actuator005","type":"Actuator","name":"urn:ngsi-ld:Actuator:005","service":"openiot_actuator","subservice":"/","active":null,"staticAttributes":[{"name":"base_url","type":"URL","value":"https://datosabiertos.castro-urdiales.net/transdat.aspx"}],"lazy":null,"commands":[],"timezone":"Europe/Berlin","transport":"HTTP","internalId":null,"explicitAttrs":true,"polling":true,"subscriptions":[]} | comp=IoTAgent
time=2024-11-04T11:57:02.835Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.DeviceService | from=n/a | srv=openiot_device | subsrv=/ | msg=Registering device into NGSI Service:
{
"id": "actuator005",
"type": "Actuator",
"name": "urn:ngsi-ld:Actuator:005",
"service": "openiot_actuator",
"subservice": "/",
"active": null,
"staticAttributes": [
{
"name": "base_url",
"type": "URL",
"value": "https://..."
}
],
"lazy": null,
"commands": [],
"timezone": "Europe/Berlin",
"transport": "HTTP",
"internalId": null,
"explicitAttrs": true,
"polling": true,
"subscriptions": []
} | comp=IoTAgent
time=2024-11-04T11:57:02.835Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.Registration | from=n/a | srv=openiot_device | subsrv=/ | msg=Registration with Context Provider is not needed. Device without lazy atts or commands | comp=IoTAgent
time=2024-11-04T11:57:02.835Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.DeviceService | from=n/a | srv=openiot_device | subsrv=/ | msg=Storing device :
{
"id": "actuator005",
"type": "Actuator",
"name": "urn:ngsi-ld:Actuator:005",
"service": "openiot_actuator",
"subservice": "/",
"staticAttributes": [
{
"name": "base_url",
"type": "URL",
"value": "https://..."
}
],
"lazy": [],
"commands": [],
"timezone": "Europe/Berlin",
"transport": "HTTP",
"internalId": null,
"polling": true
} | comp=IoTAgent
time=2024-11-04T11:57:02.841Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.MongoDBDeviceRegister | from=n/a | srv=openiot_actuator | subsrv=/ | msg=Storing device with id [actuator005] and type [Actuator] | comp=IoTAgent
time=2024-11-04T11:57:02.852Z | lvl=DEBUG | corr=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | trans=33d4e532-a2e3-4bb2-a4ad-43c0d1d01db4 | op=IoTAgentNGSI.DeviceProvisioning | from=n/a | srv=openiot_device | subsrv=/ | msg=Device provisioning request succeeded | comp=IoTAgent
time=2024-11-04T11:57:02.852Z | lvl=DEBUG | corr=4a1a766f-41d6-42fb-94cb-2109155f9b9b | trans=4a1a766f-41d6-42fb-94cb-2109155f9b9b | op=IoTAgentNGSI.DomainControl | from=n/a | srv=openiot_actuator | subsrv=/ | msg=response-time: 26 | comp=IoTAgent
配置执行器与配置传感器类似。 对于 HTTP 传输,您需要包含一个
endpoint
属性来保存 IoT 代理需要发送命令的位置,并且 commands
数组包含可以调用的每个命令的列表。下面的示例使用 device_id=water001
提供水,它在上下文代理中称为 urn:ngsi-ld:Device:water001
。我注意到您对传感器和执行器使用不同的租户,这不是常见的做法,但我已将您的 openiot_actuator
租户包括在内。 HTTP 端点是 http://iot-sensors:3001/iot/water001
,它可以接受 on
和 off
命令。 Transport=HTTP 属性定义要使用的通信协议。
curl -L -X POST 'http://localhost:4041/iot/devices' \
-H 'fiware-service: openiot_actuator' \
-H 'fiware-servicepath: /' \
-H 'Content-Type: application/json' \
--data-raw '{
"devices": [
{
"device_id": "water001",
"entity_name": "urn:ngsi-ld:Device:water001",
"entity_type": "Device",
"apikey": "4jggokgpepnvsb2uv4s40d59ov",
"protocol": "PDI-IoTA-UltraLight",
"transport": "HTTP",
"endpoint": "http://iot-sensors:3001/iot/water001",
"commands": [
{
"name": "on",
"type": "Property"
},
{
"name": "off",
"type": "Property"
}
]
}
]
}'
使用 MQTT 传输执行相同的操作略有不同,不需要端点:
curl -iX POST \
'http://localhost:4041/iot/devices' \
-H 'Content-Type: application/json' \
-H 'fiware-service: openiot' \
-H 'fiware-servicepath: /' \
-d '{
"devices": [
{
"device_id": "bell001",
"entity_name": "urn:ngsi-ld:Bell:001",
"entity_type": "Bell",
"protocol": "PDI-IoTA-UltraLight",
"transport": "MQTT",
"commands": [
{ "name": "ring", "type": "Property" }
]
}
]
}'
发送上下文代理请求会将消息推送到
/<apikey>/<deviceid>/cmd
主题进行收集。