FIWARE IoT Agent Framework: How to define a device with nested attributes in IoT Agent e.g geo:json? - fiware

I can't find how to define a device where its entity contains nested attributes.
The need is to pass gps coordinates from a device to an entity having geo:json (like urn:ngsi-ld:Shelf:unit001 in tutorial https://github.com/FIWARE/tutorials.Entity-Relationships)
Following the https://fiware-tutorials.readthedocs.io/en/latest/iot-over-mqtt/index.html the below
curl -iX POST \
'http://localhost:4041/iot/devices' \
...
-d '{
"devices": [
{
"device_id": "motion001",
"entity_name": "urn:ngsi-ld:Motion:001",
{ "object_id": "c", "name": "count", "type": "Integer" }
],
"static_attributes": [
...
creates the count attribute
{
"id": "Motion:001",
"type": "Motion",
"TimeInstant": {
"type": "DateTime",
"value": "2020-04-04T07:52:29.00Z",
"metadata": {}
},
...
"count": {
"type": "Integer",
"value": "12",
"metadata": {
"TimeInstant": {
"type": "DateTime",
"value": "2020-04-04T07:52:29.00Z"
}
}
},
How to replace the count above in order to get the below outcome ?
"type": "geo:json",
"value": {
"type": "Point",
"coordinates": [13.3986,52.5547]
},
In all examples and documentation the attributes are defined in one level (not nested) https://iotagent-node-lib.readthedocs.io/en/latest/api/index.html.
Tses

Device measures are usually just numbers so for structured elements you either use the expression library or pass data as structured JSON using the IoT Agent for JSON.
That being said, improved GeoJSON support has recently been added to the IoT Agent library, so the following will work on *:latest IoT Agent docker images. According to the Documentation various input formats are now possible.
The defined type of any GeoJSON attribute can be any set to any of
the standard NGSI-v2 GeoJSON types - (e.g. geo:json, geo:point).
NGSI-LD formats such as GeoProperty, Point and LineString are
also accepted type values. If the latitude and longitude are
received as separate measures, the expression
language can be used to concatenate them.
"entity_type": "GPS",
"resource": "/iot/d",
"protocol": "PDI-IoTA-JSON", ..etc
"attributes": [
{
"name": "location",
"type": "geo:json",
"expression": "${#lng}, ${#lat}"
}
] }
For attributes and static_attributes which need to be formatted as
GeoJSON values, three separate input formats are accepted. Provided
the type is provisioned correctly, the value may be defined using
any of the following formats:
a comma delimited string
{ "name": "location", "value": "23, 12.5" }
an array of numbers
"name": "location",
"value": [23, 12.5]
}
an fully formatted GeoJSON object
{
"name": "location",
"value": {
"type": "Point",
"coordinates": [23, 12.5]
}
}
So if your device can send a comma separated long/lat string you should be fine.

Related

jmeter: I want to extract 2 values from 2 different json objects where 1 json object will validate my condition & other value I want to extract

My JSON Response is :
{
"results": [
{
"attributes": [
{
"format": "internal",
"name": "resourceid",
"type": "STRING",
"value": "56B15190000015E85E57923F0000033B"
},
{
"format": "attribute",
"name": "ds6w:identifier",
"type": "string",
"value": "ald7_al"
}
]
},
{
"attributes": [
{
"format": "internal",
"name": "resourceid",
"type": "STRING",
"value": "56B15190000015E85E578B1F000001B6"
},
{
"format": "attribute",
"name": "ds6w:identifier",
"type": "string",
"value": "fbh1"
}
]
},
{
"attributes": [
{
"format": "internal",
"name": "resourceid",
"type": "STRING",
"value": "56B15190000015E85E578F7800000211"
},
{
"format": "attribute",
"name": "ds6w:identifier",
"type": "string",
"value": "u89cf"
}
]
}
]
}
I want to get '56B15190000015E85E57923F0000033B' where value='ald7_al'
So basically within a jsonarray I have jsonobjects, and for single jsonobject I have two jsonobjects where secong jsonobject will validate my condition param and I want value from first jsonobject
For getting result to solve condition check I have used
JSON extractor expression as -> $..attributes[?(#.value==ald7_al)] which is giving me second json block but I want value from first json block.
Please help me if you have any inputs.
Thanking you in advance for your help!
As of JMeter 5.2.1 this it not possible with built-in JMeter components
JSON Extractor cannot do this due to underlying Jayway JsonPath issue 287
JSON JMESPath Extractor cannot do this due to underlying JMESPath issue 22
So you're left with JSR223 PostProcessor and Groovy language, example code which should resolve your issue would be something like:
def results = new groovy.json.JsonSlurper().parse(prev.getResponseData()).results
0.upto(results.size() - 1, { index ->
def attributes = results[index].attributes
if (attributes[1].get('value').equals('ald7_al')) {
vars.put('value', attributes[0].get('value'))
}
})
Add it as a child of the request which returns the above JSON and if everything goes well you will able to access the value you're looking for as ${value} where required.
More information:
Apache Groovy: Parsing and producing JSON
Apache Groovy - Why and How You Should Use It

filtering geoJSON data using JMESPath not working

I am trying to filter some data from the geoJSON data structure shown as below:
"features": [
{
"type": "Feature",
"properties": {
"#id": "node/7071544593",
"addr:city": "Joensuu",
"addr:housenumber": "12",
"addr:postcode": "80100",
"addr:street": "Siltakatu",
"addr:unit": "C 33",
"alt_name": "Crasman Oy Joensuu",
"alt_name_1": "Crasman Oy",
"name": "Crasman Joensuu",
"short_name": "Crasman",
"website": "https://www.crasman.fi"
},
"geometry": {
"type": "Point",
"coordinates": [
29.7621398,
62.6015236
]
},
"id": "node/7071544593"
},
{
"type": "Feature",
"properties": {
"#id": "node/7117872562",
"amenity": "car_rental",
"operator": "avis"
},
"geometry": {
"type": "Point",
"coordinates": [
29.7630643,
62.6036656
]
},
"id": "node/7117872562"
}
]
What I am trying to do is iterate through this array of features, look into the properties object to check if it contains website, if Yes, then I can print its coordinates from geometry object.
This is what I tried:
Features[*].properties[?contains(#,'website')=='true'].geometry.coordinates
It gives me null value
Try this:
features[?contains(keys(properties),'website')].geometry.coordinates
E.g.:
$ jp "features[?contains(keys(properties),'website')].geometry.coordinates" <input.json
[
[
29.7621398,
62.6015236
]
]
With regard to why your example didn't work:
Identifiers are case-sensitive, so you need features, not Features.
properties is an object, not an array, so you can't apply a filter expression to it.
Even if you could, it's not properties that you want to filter. You are trying to filter whole features.
contains tests if an array contains an item (or if a string contains a substring), not whether an object has a key. You can use keys() to get the keys of an object in an array.
You don't need to compare the result of contains() to true, it's already a boolean.
Even if you were trying to compare to true, you'd need to use backticks: `true`, not quotes 'true'.

Orion CB output regarding provisioned device

I have noticed that upon querying Orion CB, while it is working with provisioned devices and having IoT Agent receive HTTP and MQTT messages, it will always output all the values written in the quotation marks:
{
"id": "sensor_data",
"type": "Sensor",
"ActiveTime": {
"type": "Seconds",
"value": "17703",
"metadata": {
"TimeInstant": {
"type": "ISO8601",
"value": "2018-07-04T13:32:27.357Z"
}
}
},
"Distance": {
"type": "Number",
"value": "312",
"metadata": {
"TimeInstant": {
"type": "ISO8601",
"value": "2018-07-04T13:32:27.413Z"
}
}
}
}
However, if to work with only entities in Orion CB, it is possible to receive actual values (like in the example in the manual):
{
"id": "Room1",
"pressure": {
"metadata": {},
"type": "Integer",
"value": 720
},
"temperature": {
"metadata": {},
"type": "Float",
"value": 23
},
"type": "Room"
}
Sometimes, I need to receive the actual value from my sensor in order to format it and use in further applications, but they are in quotation marks, which makes it a little difficult.
Is it possible to somehow change?(maybe in device provisioning), or it really should be that way regarding devices?
Thanks in advance!
EDIT 1
This is the way I provisioned the device:
{
"devices": [
{
"device_id": "sensor_data",
"entity_name": "sensor_data",
"entity_type": "Sensor",
"transport": "MQTT",
"timezone": "Europe/Helsinki",
"attributes": [
{ "object_id": "act", "name": "ActiveTime", "type": "Seconds"},
{ "object_id": "dst", "name": "Distance", "type": "Number"}
]
}
]
}
And this is how the MQTT messages are sent from my sensor (I have set up the topics for IoT Agent to understand them)
/123456789/sensor_data/attrs/act 12
/123456789/sensor_data/attrs/dst 322
123456789 is the API Key I have set here.
This situation tipycally happens when IoT Agents uses NGSIv1 to push data to Context Broker, given that NGSIv1 always "string-fy" any attribute value. Recently, the ability to use NGSIv2 (which doesn't have this limitatino) was introduced in IoT Agents.
In order to solve your problem you have to:
Use a recent IOTA-UL version (the current one from master branch will work)
Enable NGSIv2 in configuration as explained in documentation. This is done in the config.js file:
config.iota = {
...
contextBroker: {
...
ngsiVersion: 'v2'
}
...
}
or using environament variable IOTA_CB_NGSI_VERSION=v2 for the IOTA-UL process.
Enable autocast as explained in documentation. This is done in config.js file:
config.iota = {
...
autocast: true,
...
}
or using environament variable IOTA_AUTOCAST=true for the IOTA-UL process.
Set the right type for each attribute at provision time. The documentation here) provides the right types:
Type "Number" for integer or float numbers
Type "Boolean" for boolean
Type "None" for null
Thus, in your case the provisioning for Distance is ok, but for ActiveTime you should use also Number as type.

Using Cygnus to write in mongo db with no string

I'm trying to use Orion CB and Cygnus to write information about water quality and water consume and I need to write in float type. However it is impossible to me to know if there is any possibility to write this with float or double format.
Could someone tell me if this possibility exists?
As stated at FIWARE Orion documentation, you are free to specify your entities attributes using JSON format.
So, you will have your entity in the following format:
{
"id": "entityID",
"type": "entityType",
"attr_1": <val_1>,
"attr_2": <val_2>,
...
"attr_N": <val_N>
}
In which each <val_n> will be in the following format:
{
"type": <...>,
"value": <...>,
"metadata": <...>
}
Thus, you can have some entity described, for example, as:
{
"id": "sensor_ID",
"type": "room_sensor",
"temperature": {
"type": "float",
"value": 23.2
},
"noise": {
"type": "integer",
"value": 35
}
}
Therefore, you can use float or double as you want.

Why does a numeric key in the JSON Structure always get displayed first

(Cannot summarize the problem in a single statement, hence the ambiguous title)
I create a JSON structure via Angular Typescript, wherein when a user interacts with certains parts of the component the JSON Structure gets updated.
Steps
Initially, the JSON under consideration is by default set to the following:
{
"keyword": {
"value": "product",
"type": "main"
}
}
For example, a user chooses some parameter Name. Once the user complies to certain steps in the UI, the JSON structure gets updated to the following:
{
"keyword": {
"value": "product",
"type": "main"
},
"Name": {
"value": " <hasProperty> Name",
"type": "dataprop"
}
}
Once the user selects a numeric value for a parameter like dryTime, the JSON gets updated to the following:
{
"20": { // WHY WOULD 20 be here?
"value": "<hasValue> 20",
"type": "fValue"
},
"keyword": {
"value": "Varnish",
"type": "main"
},
"Name": {
"value": " <hasProperty> Name",
"type": "dataprop"
},
"dryingTime": {
"value": " <hasProperty> dryingTime",
"type": "dataprop"
}
}
I understand that a JSON is an unordered data structure. But a previous implementation of something similar actually worked well, i.e., the value 20 here was 20.0 before and it was displayed after dryingTime in my JSON.
The order is critical for me as I parse all the Keys in the above mentioned JSON using a for loop and store it in an array. This array needs to show all the keys in the order of the User Interaction.
Where am I going wrong here if I decide to stay with JSON and not with an array to store such interactions?
Yes, JSON fields are unordered. JSON array is ordered.
If you want to keep the order of elements insterted, you could build your JSON like so:
{
"keyword": {
"value": "Varnish",
"type": "main"
},
"props": [
{
"name": "dryingTime",
"value": 20
},
{
"name": "anotherOrderedField",
"value": "fieldValue"
}
]
}