Simulation configuration file
As mentioned in the description of the FIWARE Device Simulator command line tool, a simulation is described by a simulation configuration file (which is passed to the command line tool using the -c
option).
The simulation configuration file is a JSON-formatted text file detailing the characteristics of the simulation to run.
This simulation configuration file can use environment variables, as described in a specific section.
An example simulation configuration file is shown next to give you a glimpse of its shape. After it, the accepted properties and options are properly detailed.
{
"domain": {
"service": "theService",
"subservice": "/theSubService"
},
"contextBroker": {
"protocol": "https",
"host": "localhost",
"port": 1026,
"ngsiVersion": "1.0"
},
"authentication": {
"provider": "keystone",
"protocol": "https",
"host": "localhost",
"port": 5001,
"user": "theUser",
"password": "thePassword",
"retry": {
"times": 10,
"interval": 1000
}
},
"iota": {
"ultralight": {
"api_key": "1ifhm6o0kp4ew7fi377mpyc3c",
"http": {
"protocol": "http",
"host": "localhost",
"port": 8085
},
"mqtt": {
"protocol": "mqtt",
"host": "localhost",
"port": 1883,
"user": "mqttUser",
"password": "mqttPassword"
}
},
"json": {
"api_key": "83ut64ib3gzs6km6izubjyenu",
"http": {
"protocol": "http",
"host": "localhost",
"port": 8185
},
"mqtt": {
"protocol": "mqtt",
"host": "localhost",
"port": 1883,
"user": "mqttUser",
"password": "mqttPassword"
}
}
},
"entities": [{
"schedule": "once",
"entity_name": "EntityName1",
"entity_type": "EntityType1",
"active": [{
"name": "active1",
"type": "date",
"value": "date-increment-interpolator({\"origin\": \"now\", \"increment\": 3600})"
}],
"staticAttributes": [{
"name": "static1",
"type": "string",
"value": "Value of static1"
}]
}, {
"schedule": {
"start": "2016-10-19T10:00:00Z",
"end": "2016-10-19T11:00:00Z",
"rule": "*/5 * * * * *"
},
"entity_name": "EntityName2",
"entity_type": "EntityType2",
"active": [{
"name": "active1",
"type": "geo:json",
"value": "multiline-position-interpolator({\"coordinates\": [[-6.2683868408203125,36.48948933214638],[-6.257915496826172,36.46478162030615],[-6.252079010009766,36.461744374732085],[-6.2162017822265625,36.456774079889286]],\"speed\": {\"value\": 30,\"units\": \"km/h\"},\"time\": {\"from\": 10,\"to\": 22}})"
}, {
"schedule": "*/1 * * * * *",
"name": "active2",
"type": "number",
"value": "time-linear-interpolator({\"spec\": [[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]], \"return\": {\"type\": \"float\"}})"
}],
"staticAttributes": [{
"name": "static1",
"type": "string",
"value": "Value of static1"
}]
}, {
"count": "3",
"entity_type": "EntityType3",
"schedule": "*/1 * * * * *",
"active": [{
"name": "active1",
"type": "number",
"value": "time-random-linear-interpolator({\"spec\": [[0,0],[20,random(25,45)],[21,random(50,75)],[22,100],[24,0]], \"return\": {\"type\": \"float\"}})"
}, {
"schedule": "*/5 * * * * *",
"name": "active2",
"type": "number",
"value": "time-step-after-interpolator([[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]])"
}],
"staticAttributes": [{
"name": "static1",
"type": "percentage",
"value": "time-step-before-interpolator([[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]])"
}, {
"name": "static2",
"type": "status",
"value": "text-rotation-interpolator({\"units\": \"seconds\", \"text\": [[0,\"PENDING\"],[15,\"REQUESTED\"],[30,[[50,\"COMPLETED\"],[50,\"ERROR\"]]],[45,\"REMOVED\"]]})"
}]
}],
"devices": [{
"schedule": "once",
"protocol": "UltraLight::HTTP",
"device_id": "DeviceId1",
"attributes": [{
"object_id": "a1",
"value": "date-increment-interpolator({\"origin\": \"now\", \"increment\": 3600})"
}]
}, {
"schedule": "*/5 * * * * *",
"protocol": "UltraLight::JSON",
"device_id": "DeviceId2",
"api_key": "1ifdjdo0kkd7w77du77mpjd78",
"attributes": [{
"object_id": "a1",
"value": "multiline-bearing-interpolator({\"coordinates\": [[-6.2683868408203125,36.48948933214638],[-6.257915496826172,36.46478162030615],[-6.252079010009766,36.461744374732085],[-6.2162017822265625,36.456774079889286]],\"speed\": {\"value\": 30,\"units\": \"km/h\"},\"time\": {\"from\": 10,\"to\": 22}})"
}, {
"schedule": "*/1 * * * * *",
"object_id": "a2",
"value": "time-linear-interpolator({\"spec\": [[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]], \"return\": {\"type\": \"integer\", \"rounding\": \"ceil\"}})"
}]
}, {
"count": "5",
"schedule": "*/1 * * * * *",
"entity_type": "DeviceType3",
"protocol": "UltraLight::MQTT",
"api_key": "ag235jdo0kkhd367du77mpgs54",
"attributes": [{
"object_id": "a1",
"value": "time-random-linear-interpolator({\"spec\": [[0,0],[20,random(25,45)],[21,random(50,75)],[22,100],[24,0]], \"return\": {\"type\": \"integer\", \"rounding\": \"ceil\"}})"
}, {
"schedule": "*/5 * * * * *",
"object_id": "a2",
"value": "time-step-after-interpolator([[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]])"
}]
}]
}
The simulation configuration file accepts the following JSON properties or entries:
- exports: The FIWARE Device Simulation provides a templating mechanism to avoid repeating text into simulation configuration files as well as to facilitate the edition of these files. More information about this templating mechanism just after the description of the rest of the properties which may be used in a simulation configuration file.
- globals: An object including the global state variables and their initial values to be shared amongst executions of the
attribute-function-interpolator
no matter their specification. This property is related to theattribute-function-interpolator
detailed below and it will become much clearer once the reader reaches that section. - require: An array of names and/or paths of NPM packages to be required before running the simulation. This property is related to the
attribute-function-interpolator
interpolator as well as to thecollector
entry inside theexternal
property detailed below. It makes it possible torequire()
these NPM packages directly in the code associated to theseattribute-function-interpolator
interpolators and collectors. - domain: Includes information about the service and subservice (i.e., service path) to use in the requests. It is mandatory in case any
entities
are included in the simulation configuration (see below).- service: The service to use in the requests.
- subservice: The subservice (i.e., service path) to use in the requests.
- contextBroker: Includes information about the context broker where the data will be stored. It is mandatory in case any
entities
are included in the simulation configuration (see below) and nosubscriber
configuration information is included (see below).- protocol: The protocol the Context Broker is expecting the requests to be sent by (or more concretely of the PEP protecting the access to the Context Broker API).
- host: The host machine name or IP address where the Context Broker is running (or more concretely of the PEP protecting the access to the Context Broker API).
- port: The port where the Context Broker host machine is listening for API requests (or more concretely of the PEP protecting the access to the Context Broker API).
- ngsiVersion: The NGSI version to be used in the requests sent to the Context Broker. Currently, versions
1.0
and2.0
are supported.
- subscriber: Includes information about the subscriber where the data will be notified. It is mandatory in case any
entities
are included in the simulation configuration (see below) and nocontextBroker
configuration information is included. Note that in case of includingcontextBroker
andsubscriber
configuration information, thecontextBroker
will prevail over thesubscriber
one and no notifications will be sent to the configured subscriber.- protocol: The protocol the subscriber is expecting the notification requests to be sent to.
- host: The host machine name or IP address where the subscriber is running.
- port: The port where the subscriber host machine is listening for notification requests.
- path: The path where the subscriber host machine is listening for notification requests.
- ngsiVersion: The NGSI version to be used in the notification requests sent to the subscriber. Currently, only version
1.0
is supported.
- authentication: Includes information about the Identity Service to get tokens to be included in the Context Broker requests. Optional (authentication tokens will only be requested if the
authentication
information is included).- provider: The Identity Service provider from which the authorization tokens will be requested. Accepted values are:
keystone
(to request tokens for the Telefónica IoT Platform) andfiware-lab
(to request tokens for the FIWARE Lab cloud infrastructure). - protocol: The protocol the Identity Service is expecting the requests to be sent by.
- host: The host machine or IP where the Identity Service is running.
- port: The port where the Identity Service is listening for requests.
- user: The user to be used in the authorization token requests for the provided service and subservice.
- password: The password to be used in the authorization token requests for the provided service and subservice.
- retry: Retry mechanism in case an error occurs when requesting the authentication token. It is based on the
async.retry()
function. It is an object including the following properties:- times: The number of attempts to make before giving up and ending the simulation. Mandatory if the
retry
property is included. - interval: The time to wait between retries, in milliseconds. Mandatory if the
retry
property is included.
- times: The number of attempts to make before giving up and ending the simulation. Mandatory if the
- provider: The Identity Service provider from which the authorization tokens will be requested. Accepted values are:
- iota: Includes information about the IoT Agents which will be used for the devices updates. It is mandatory if a
devices
property describing devices is included in the simulation configuration.- ultralight: Includes information about the configuration of the UltraLight IoT Agents. It is mandatory if a
devices
property describing UltraLight devices (protocol
property starting withUltraLight::
) is included in the simulation configuration).- api_key: The API key to be used when updating UltraLight devices whose API key is not specified at a local level (see below). Mandatory if at least one UltraLight device is included whose API key is not specified at a local level.
- http: Includes information about the configuration of the HTTP binding for the UltraLight protocol. It is mandatory if a
devices
property describing UltraLight HTTP devices (protocol
property equal toUltraLight::HTTP
) or UltraLight JSON devices ((protocol
property equal toUltraLight::JSON
)) is included in the simulation configuration).- protocol: The protocol the UltraLight HTTP IoT Agent is expecting the requests to be sent by.
- host: The host machine where the UltraLight HTTP IoT Agent will be listening for requests.
- port: The port where the UltraLight HTTP IoT Agent will be listening for requests.
- mqtt: Includes information about the configuration of the MQTT binding for the UltraLight protocol. It is mandatory if a
devices
property describing UltraLight MQTT devices (protocol
property equal toUltraLight::MQTT
) is included in the simulation configuration).- protocol: The transport protocol used. Possible values include:
mqtt
,mqtts
,tcp
,tls
,ws
,wss
. - host: The host machine where the UltraLight MQTT IoT Agent will be listening for requests.
- port: The port where the UltraLight MQTT IoT Agent will be listening for requests.
- user: The user to use for MQTT authenticated communications. Optional.
- password: The password to use for MQTT authenticated communications. Optional.
- protocol: The transport protocol used. Possible values include:
- json: Includes information about the configuration of the JSON IoT Agents. It is mandatory if a
devices
property describing UltraLight devices (protocol
property starting withJSON::
) is included in the simulation configuration).- api_key: The API key to be used when updating JSON devices whose API key is not specified at a local level (see below). Mandatory if at least one JSON device is included whose API key is not specified at a local level.
- http: Includes information about the configuration of the HTTP binding for the JSON protocol. It is mandatory if a
devices
property describing JSON HTTP devices (protocol
property equal toJSON::HTTP
) is included in the simulation configuration).- protocol: The protocol the JSON HTTP IoT Agent is expecting the requests to be sent by.
- host: The host machine where the JSON HTTP IoT Agent will be listening for requests.
- port: The port where the JSON HTTP IoT Agent will be listening for requests.
- mqtt: Includes information about the configuration of the MQTT binding for the JSON protocol. It is mandatory if a
devices
property describing JSON MQTT devices (protocol
property equal toJSON::MQTT
) is included in the simulation configuration).- protocol: The transport protocol used. Possible values include:
mqtt
,mqtts
,tcp
,tls
,ws
,wss
.- host: The host machine where the JSON MQTT IoT Agent will be listening for requests.
- port: The port where the JSON MQTT IoT Agent will be listening for requests.
- user: The user to use for MQTT authenticated communications. Optional.
- password: The password to use for MQTT authenticated communications. Optional.
- protocol: The transport protocol used. Possible values include:
- ultralight: Includes information about the configuration of the UltraLight IoT Agents. It is mandatory if a
- entities: Information about the entities to be updated during this concrete simulation.
- schedule: Cron-style schedule (according to https://www.npmjs.com/package/node-schedule#cron-style-scheduling) to schedule the updates of the entity. For example:
*/5 * * * * *
will update the attributes of the entity for which there is noschedule
information, see below, every 5 seconds, whereas0 0 0 * * *
will update the attributes of the entity for which there is noschedule
information, see below, at 00:00 of every first day of each month. A very useful tool for dealing with cron-style schedules can be found at http://crontab.guru/. An additional accepted valueonce
is included to force the update of the entity only once at the beginning of the simulation. Theschedule
property also accepts an object including starting and ending dates for the schedule such as:"schedule": {"start": "2016-10-19T10:47:00Z", "end": "2016-10-19T11:47:00Z", "rule": "*/5 * * * * *"}
. The previousschedule
will only be effective from2016-10-19T10:47:00Z
to2016-10-19T11:47:00Z
. - entity_name: The name of the entity. The
entity_name
should not be provided if thecount
is provided. - count: The number of entities to simulate and update. For example, if a value of 3 is provided as the
count
property, 3 entities with names<entity_type>:1
,<entity_type>:2
and<entity_type>:3
will be created and updated accordingly substituting the<entity_type>
by its provided value (see just below) and according to its active and static attribute simulation specification (see below). - entity_type: The type of the entity.
- active: List of attributes which will be updated according to their
schedule
s or the main entityschedule
and the providedvalue
(see just below).- schedule: The schedule by which this attribute should be updated. See the
schedule
property at the entity level above. It is an optional property. In case it is not specified, the entity levelschedule
property will be used. - name: The name of the attribute.
- type: The type of the attribute.
- value: The value of the attribute. This is the property which provides flexibility and realism to the FIWARE Device Simulator tool. It accepts static values (such as numbers (i.e.,
123
), text (i.e.,the attribute value
), arrays (i.e.,[1, 2, 3]
), JSON objects (i.e.,{"key": "value"}
), etc.) as well as interpolator function specifications which the FIWARE Device Simulator tool will use to generate the final values. The supported interpolator function specifications are:date-increment-interpolator
: It returns dates in UTC format. On the other hand, it accepts a JSON object including 2 properties: 1)origin
(the date from when the date will be incremented ornow
for the current date when the value is interpolated) and 2)increment
(the number of seconds the origin should incremented by. For example, a date increment interpolator specification such as:{\"origin\": \"now\", \"increment\": 86400}
will return the current hour incremented in86400
seconds, this is, 1 day, when the interpolated value is requested to be updated. For instance, an example attribute value using thedate-increment-interpolator
is:date-increment-interpolator({\"origin\": \"now\", \"increment\": 2592000})
.multiline-position-interpolator
: It returns the current position of a mobile object for the current decimal hour by default as a GeoJSON geometry of typePoint
including itscoordinates
. The return value can also be obtained as ageo:point
setting thereturn
property togeo:point
(see below). To this regard, it takes an object including the following properties:coordinates
: an array of points, this is, an array of 2 element arrays corresponding to the longitude and the latitude of the points. The connection between this points determine the line or route the mobile object will be traveling. It can be a circular or not circular route (in this case the mobile object will start the route from the beginning once the end is reached).speed
: an object including the following properties:value
: a number corresponding to the speed at which the mobile object will be movingunits
: a string corresponding to the speed units. Valid values arekm/h
(kilometers per hour) andmi/h
(miles per hour).
time
: an object including the following properties:from
: a number corresponding to the decimal hours from which the mobile object will be moving. If the current decimal hours is before thefrom
one, the interpolated position will be the starting point.to
: a number corresponding to the decimal hours until which the mobile object will be moving. If the current decimal hours is after theto
one, the traveled distance will be calculated until this one.
return
: a string including any of the following values:geo:json
(to get the interpolated value as a GeoJSON point, this is the default behaviour) orgeo:point
(to get the interpolated value as ageo:point
, this is the coordinates array of the GeoJSON point value as a string).- An example attribute value using the
multiline-position-interpolator
is:"multiline-position-interpolator({\"coordinates\": [[-6.2683868408203125,36.48948933214638],[-6.257915496826172,36.46478162030615],[-6.252079010009766,36.461744374732085],[-6.2162017822265625,36.456774079889286]],\"speed\": {\"value\": 30,\"units\": \"km/h\"},\"time\": {\"from\": 10,\"to\": 22}})"
.
multiline-bearing-interpolator
: It returns the bearing of the position of a mobile object for the current decimal hour by default as a GeoJSON geometry of typePoint
including itscoordinates
. To this regard, it takes an object including the following properties:coordinates
: an array of points, this is, an array of 2 element arrays corresponding to the longitude and the latitude of the points. The connection between this points determine the line or route the mobile object will be traveling. It can be a circular or not circular route (in this case the mobile object will start the route from the beginning once the end is reached).speed
: an object including the following properties:value
: a number corresponding to the speed at which the mobile object will be movingunits
: a string corresponding to the speed units. Valid values arekm/h
(kilometers per hour) andmi/h
(miles per hour).
time
: an object including the following properties:from
: a number corresponding to the decimal hours from which the mobile object will be moving. If the current decimal hours is before thefrom
one, the interpolated position will be the starting point.to
: a number corresponding to the decimal hours until which the mobile object will be moving. If the current decimal hours is after theto
one, the traveled distance will be calculated until this one.
- For instance, an example attribute value using the
multiline-bearing-interpolator
is:"multiline-bearing-interpolator({\"coordinates\": [[-6.2683868408203125,36.48948933214638],[-6.257915496826172,36.46478162030615],[-6.252079010009766,36.461744374732085],[-6.2162017822265625,36.456774079889286]],\"speed\": {\"value\": 30,\"units\": \"km/h\"},\"time\": {\"from\": 10,\"to\": 22}})"
.
time-linear-interpolator
: It returns float or integer values depending on the configuration. On the other hand, it accepts an object including the following properties:spec
: An array of 2 elements arrays corresponding to the decimal hours of the day and its specified value. For example, a time linear interpolator specification such as:[[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]]
will return0
if the interpolated value is requested at the00:00
hours,0.25
if the interpolated value is requested at the20:00
hours and0.125
if the interpolated value is requested at the10:00
hours according to a linear interpolation between0
and20
as the decimal hours in the x-axis. This is the reason why atime-linear-interpolator
is typically specified providing values for the0
and24
values in the x-axis according to the available decimal hours in any day.return
: It is an object including the following properties:type
: The interpolator return type. It can take any of the following values:float
orinteger
.rounding
: If the type is equal tointeger
, the rounding mechanism must also be specified. It can take any of the following values:ceil
,floor
orround
.
- A possible attribute value using the
time-linear-interpolator
is:"time-linear-interpolator({\"spec\": [[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]], \"return\": {\"type\": \"integer\", \"rounding\": \"ceil\"}})"
. - It is important to note that since this interpolator is a linear one (more concretely it leans on the
linear-interpolator
package), if some of the entries for the starting (0, 1, 2, etc.) or ending hours (22, 23, 24) are missing, the behavior may not be the one expected. Let's see it with a concrete example:time-linear-interpolator({\"spec\": [[8,0],[12,100],[22,0]], \"return\": {\"type\": \"float\"}})
, in this case and due to its linear nature values for decimal hours from 0 to 8 will be negative (linearly), values for decimal hours from 8 to 12 will be between 0 and 100 (linearly), values for decimal hours from 12 to 22 will be between 100 and 0 (linearly), and again values for decimal hours from 22 to 24 will be negative (linearly).
time-random-linear-interpolator
: It returns float or integer values depending on the configuration. On the other hand, it accepts an object including the following properties:spec
: An array of 2 elements arrays corresponding to the decimal hours of the day and its specified value.- The first element of the array or decimal hours may include the
random()
directive. For example, a random time linear interpolator specification such as:[[random(0,1),0],[random(23,24),100]]
will behave as atime-linear-interpolator
where the random part will be substituted for a concrete random decimal hours value each time this interpolator is invoked. For example, subsequent invocations of the previous interpolator may end up behaving such as the followingtime-linear-interpolator
s:[0.410237338161096,0],[23.268972319317982,100]]
,[0.192138821585104,0],[23.442964296089485,100]]
,[0.223540030419827,0],[23.614114402793348,100]]
, etc.- An example attribute value using the
time-random-linear-interpolator
is:"random-time-linear-interpolator({\"spec\": [[random(12,13),0],[random(20,21),100]], \"return\": {\"type\": \"integer\", \"rounding\": \"ceil\"}})"
. - It is important to note that since this interpolator is a linear one (more concretely it leans on the
linear-interpolator
package), if some of the entries for the starting (0, 1, 2, etc.) or ending hours (22, 23, 24) are missing, the behavior may not be the one expected. Let's see it with a concrete example:random-time-linear-interpolator({\"spec\": [[random(12,13),10],[random(20,21),100]], \"return\": {\"type\": \"float\"}})
, in this case and due to its linear nature values for decimal hours from 0 to 12 will be below 10 (linearly, including the randomness factor it may go beyond the 12 decimal hour) including negative values, values for decimal hours from the 13 to the 20 will be between 0 and 100 (linearly and according to the randomness factor it may go before the 13 and beyond the 20 decimal hours), values for decimal hours from 21 to 24 will be greater than 100 (linearly and according to the randomness factor it may be before the 21 decimal hour).
- An example attribute value using the
- The second element of the array or specified value may include the
random()
directive. For example, a time random linear interpolator specification such as:[[0,0],[20,random(0.25,0.50)],[24,1]]
will return0
if the interpolated value is requested at the00:00
hours, a random number bigger than0.25
and smaller than0.50
if the interpolated value is requested at the20:00
hours and the corresponding interpolated value between the previous y-axis values if it is requested at a time between the00:00
hours and the20:00
hours. This is the reason why atime-random-linear-interpolator
is typically specified providing values for the0
and24
values in the x-axis according to the available decimal hours in any day.- A possible attribute value using the
time-random-linear-interpolator
is:"time-random-linear-interpolator({\"spec\": [[0,0],[20,random(25,45)],[21,random(50,75)],[22,100],[24,0]], \"return\": {\"type\": \"integer\", \"rounding\": \"ceil\"}})"
. - It is important to note that since this interpolator is a linear one (more concretely it leans on the
linear-interpolator
package), if some of the entries for the starting (0, 1, 2, etc.) or ending hours (22, 23, 24) are missing, the behavior may not be the one expected. Let's see it with a concrete example:"time-random-linear-interpolator({\"spec\": [[8,random(0,10)],[12,random(90,100)],[22,random(0,10)]], \"return\": {\"type\": \"float\"}})"
, in this case and due to its linear nature values for decimal hours from 0 to 8 will be below 10 (linearly including the randomness factor) including negative values, values for decimal hours from 8 to 12 will be between 0 and 100 (linearly and according to the randomness factor), values for decimal hours from 12 to 22 will be between 100 and 0 (linearly and according to the randomness factor), and again values for decimal hours from 22 to 24 will be below 10 (linearly and according to the randomness factor) including negative values.
- A possible attribute value using the
- The
random()
directive can be used in the first element of the array specification, in the second one or in both in which case the behavior is the combined one. Consequently,"time-random-linear-interpolator({\"spec\": [[random(0,1),0],[20,random(25,45)],[random(21,22),random(50,75)],[22,100],[24,0]], \"return\": {\"type\": \"integer\", \"rounding\": \"ceil\"}})"
is a perfectly validtime-random-linear-interpolator
.
- The first element of the array or decimal hours may include the
return
: It is an object including the following properties:type
: The interpolator return type. It can take any of the following values:float
orinteger
.rounding
: If the type is equal tointeger
, the rounding mechanism must also be specified. It can take any of the following values:ceil
,floor
orround
.
time-step-after-interpolator
: It returns float values. On the other hand, it accepts an array of 2 elements arrays corresponding to the decimal hours of the day and its specified value. For example, a time step after interpolator specification such as:[[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]]
will return0
if the interpolated value is requested at the00:00
hours,0.25
if the interpolated value is requested at the20:00
hours and0
if the interpolated value is requested at any time between the00:00
hours and the20:00
hours (notice it is called "step-after"). This is the reason why atime-step-after-interpolator
is typically specified providing values for the0
and24
values in the x-axis according to the available decimal hours in any day. An accepted attribute value using thetime-step-after-interpolator
is:time-step-before-interpolator([[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]])
.time-step-before-interpolator
: It returns float values. On the other hand, it accepts an array of 2 elements arrays corresponding to the decimal hours of the day and its specified value. For example, a time step before interpolator specification such as:[[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]]
will return0
if the interpolated value is requested at the00:00
hours,0.25
if the interpolated value is requested at the20:00
hours and0.25
if the interpolated value is requested at any time between the00:00
hours and the20:00
hours (notice it is called "step-before"). This is the reason why atime-step-before-interpolator
is typically specified providing values for the0
and24
values in the x-axis according to the available decimal hours in any day. An example attribute value using thetime-step-before-interpolator
is:time-step-before-interpolator([[0,0],[20,0.25],[21,0.50],[22,0.75],[23,1],[24,1]])
.text-rotation-interpolator
: It returns a string from a set of possible values with support for probabilistic occurrences of them. On the other hand, it accepts an object including the following properties:units
: It is a string which affects thetext
property detailed below. It accepts the following values:seconds
,minutes
,hours
,days
(day of the week),dates
(day of the month),months
andyears
.text
: It is an array of 2 elements arrays. The first element is the number ofseconds
(from 0 to 59),minutes
(from 0 to 59),hours
(from 0 to 23),days
(from 0 to 6),dates
(from 1 to 31),months
(from 0 to 11) andyears
(full year) (according to theunits
property) from which the specified text will be returned for the current date and time. The second element can be a string corresponding to the text to be returned or an array of 2 elements arrays. The first element of this second 2 elements array is the probability (from 0 to 100) of the occurrence of the text specified as the second element of the array. The addition of the first elements array must be 100.- A possible attribute value using the
text-rotation-interpolator
is:"text-rotation-interpolator({\"units\": \"seconds\", \"text\": [[0,\"PENDING\"],[15,\"REQUESTED\"],[30,[[50,\"COMPLETED\"],[50,\"ERROR\"]]],[45,\"REMOVED\"]]})"
. For example, according to this text rotation interpolation specification, if the current time seconds is between 0 and 15 it will return the valuePENDING
, if it is between 15 and 30 it will return the valueREQUESTED
, if it is between 30 and 45 it will return the valueCOMPLETED
with a probability of 50% andERROR
with a probability of 50%.
attribute-function-interpolator
: It returns the result of the evaluation of some Javascript code. This code may include references to any entity's attributes values stored in the Context Broker. This interpolator accepts a string (properly escaped) with the Javascript code to evaluate. In this Javascript code, references to entity's attribute values may be included using the notation:${{<entity-id>:#:<entity-type>}{<attribute-name>}}
, substituting the<entity-id>
,<entity-type>
and<attribute-name}
by their concrete values. Take into consideration that the type specification of the entity (i.e.,:#:<entity-type>
, including the:#:
separator) is optional and can be omitted, in which case the entity type will not be considered when retrieving the entity and the corresponding attribute value from the Context Broker.- An example attribute value using the
attribute-function-interpolator
is:"attribute-function-interpolator(${{Entity:001}{active:001}} + Math.pow(${{Entity:002}{active:001}},2))"
. - An advanced feature incorporated to the
attribute-function-interpolator
is the possibility torequire
packages directly in the Javascript code to be evaluated. Obviously, all the capabilities related to referencing entity attributes are supported too in this case. To use it, please follow the next steps:- Include a
require
property in your simulation configuration file setting its value to an array including the names and/or paths of the NPM packages you will be using in any of yourattribute-function-interpolator
interpolators. These packages will be required before proceding with the simulation and made available to yourattribute-function-interpolator
code which uses them. For example:"require": ["postfix-calculate"]
. - The result of the evaluation of your code should be assigned to the
module.exports
property (this is due to the fact that this functionality leans on theeval
NPM package which imposes this restriction).
- Include a
- An accepted attribute value using this advanced mode of the
attribute-function-interpolator
is:"attribute-function-interpolator(var postfixCalculate = require('postfix-calculate'); module.exports = postfixCalculate('${{Entity:001}{active:001}} 1 +');)"
, where the result of the evaluation (this is, the value assigned tomodule.exports
) will be the result of adding 1 to the value of theactive:001
attribute of theEntity:001
entity, according to thepostfix-calculate
NPM functionality. - Sometimes it is useful to have access to the simulation date (mainly in case of fast-forward simulations (more information about fast-forward simulations below)), for that we inject into the Javascript code of
attribute-function-interpolator
s an object SimulationDate which behaves such as the JavascriptDate
object but "points" to the simulation time and date, this isnew SimulationDate()
returns the currentDate
for the current simulation. It is important to note that theSimulationDate
object will only be available if you assign the result of your code evaluation to themodule.exports
property. - A possible attribute value using the possibility to access the current simulation time is:
"attribute-function-interpolator(module.exports = new SimulationDate())"
, where the result of the evaluation (this is, the value assigned tomodule.exports
) will be the current simulation date. - In case you want to maintain state amongst executions of
attribute-function-interpolator
with the same specification (this is, with the same Javascript code to be evaluated), you can do it following the next guidelines:- Include a comment in your
attribute-function-interpolator
Javascript code such as:/* state: statefulVariable1 = 5, statefulVariable2 = {\"prop1\": \"value1\"}, statefulVariable3 */
, this is astate:
tag followed by the list of variables you would like the interpolator to maintain as the state. This list is used to inject into your code these variables with the value included after the=
character ornull
if no value is assigned for the first execution of your Javascript code. - Return the result the evaluation setting it as the value for the
module.exports.result
property. - Return the variables whose state should be maintained between executions of the interpolator as properties of an object assigned to the
module.exports.state
property.
- Include a comment in your
- It is important to note that all the
attribute-function-interpolator
sharing the same specification (this is, your Javascript code) will share the same state. If you do not want this, just slightly change the specification somehow withouth affecting the execution of your code such adding an additional;
or including a comment. - An example attribute value using the possibility to maintain state amongst
attribute-function-interpolator
interpolator executions is:"attribute-function-interpolator(/* state: counter = 1 */ module.exports = { result: ${{Entity:001}{active:001}} + counter, state: { counter: ++counter }};)"
, where the result of the evaluation (this is, the value assigned tomodule.exports.result
) will be the result of adding to the value of theactive:001
attribute of theEntity:001
entity an increment equal to the times the interpolator has been run. - Last but not least, we have also incorporated the possibility to share state between distint
attribute-function-interpolator
s, this is,attribute-function-interpolator
s with distinct associated Javascript code (since if it is the same, the state can be shared "locally" amongs all the instances of the sameattribute-function-interpolator
as previously described). To share state between distinctattribute-function-interpolator
s no matter their specification or associated Javascript code, follow the next steps:- Assign initial values to the global state variables in the
globals
property of the simulation configuration. For example:"globals": { "globalVar1": 1, "globalVar2": 2}
. This step is optional and its necessity depends on your specificattribute-function-interpolator
Javascript code where, obviously, you should not access any non-declared variable. - The variables will be available to be used in all the
attribute-function-interpolator
instances of the simulation. Take into consideration that in case of using not valid variable names in the step 1 above (such as:global-var-1
), you have to access the variables via theglobal
variable, this is, instead of the not validglobal-var-1
variable name, useglobal.global-var-1
. - Return the result the evaluation setting it as the value for the
module.exports.result
property. - Return the global state variables whose values you would like to update as properties of the object assigned to
module.exports.state.globals
. The global variables will be updated accordingly and passed to the nextattribute-function-interpolator
being executed.
- Assign initial values to the global state variables in the
- A possible attribute value using the possibility to maintain global state between
attribute-function-interpolator
instances (no matter the Javascript code included in them):"attribute-function-interpolator(module.exports = { result: ${{Entity:001}{active:001}} + globalVar1, state: { globals: { globalVar1: ++globalVar1 } }};)"
, where the result of the evaluation (this is, the value assigned tomodule.exports.result
) will be the result of adding to the value of theactive:001
attribute of theEntity:001
entity an increment equal to the value of theglobalVar1
global state variable, which will be incremented in 1 and passed as incremented to the next execution of anattribute-function-interpolator
interpolator. - It is important to note that global state variables (this is, amongst
attribute-function-interpolator
instances no matter their specification or associated Javascript code) and local state variables (this is, amongstattribute-function-interpolator
instances with the same specification or associated Javascript code) can be combined following the guidelines detailed above. Notice that local state variables will impose over global state variables. This is, if aattribute-function-interpolator
uses a local state variable with the same name as a global state variable, the local one will preserve and apply. - An accepted attribute value using the possibility to maintain local and global state amongst
attribute-function-interpolator
interpolator executions is:"attribute-function-interpolator(/* state: counter = 1 */ module.exports = { result: ${{Entity:001}{active:001}} + counter + globalVar1, state: { counter: ++counter, globals: { globalVar1: ++globalVar1 } } };)"
, where the result of the evaluation (this is, the value assigned tomodule.exports.result
) will be the result of adding to the value of theactive:001
attribute of theEntity:001
entity an increment equal to the times the interpolator has been run plus the value of theglobalVar1
state variable (which, on the other hand, is incremented globally in 1 before exiting the evaluation of the Javascript code). - NOTE: There is an issue in the
deasync
Node package which seems to break fast-forward simulations which make use of theattribute-function-interpolator
in combination with entity attribute references (this is,${{<entityId>}{<attributeName>}}
provoking a segmentation fault error. A workaround to avoid this issue is the use of global state variables updating the value of the attributes which need to be referenced and assigning their value to global state variables which make it possible to access them from any otherattribute-function-interpolator
instance.
- An example attribute value using the
- metadata: Array of metadata information to be associated to the attribute on the update. Each metadata array entry is an object including 3 properties:
- name: The metadata name.
- type: The metadata type.
- value: The metadata value. As the value of any metadata, all the possible accepted values for attributes (detailed above) can be used including the interpolators.
- schedule: The schedule by which this attribute should be updated. See the
- staticAttributes: List of attributes which will be included in every update of the entity. Static attributes are just like the active attributes previously described with 1 main remarks: they do not include a
schedule
property since the schedule of the updates of the entity and its attributes is determined by theschedule
property at the active attributes level or the one specified at the entity level. Although staticAttributes may use any of the available interpolators as theirvalue
property, they typically include fixed values and no any type of interpolation. - external: Information about an external source from which to load, to transform and to register data into a Context Broker instance. The
external
property includes the following sub-properties:- body: Optional. The body to be included into the requests sent to the external source to get the data.
- collector: Mandatory. The
collector
property includes Javascript code used to transform the data loaded from an external source into an array of arrays, each of them including Javascript objects corresponding to the attributes to be updated or notified. This is, in case only one entity including a textual attribute calledattr-001
wants to be updated or notified, thecollector
code should return an array of arrays such as[[{name: 'attr-001', type: "Text", value: "Some text value"}]]
. If more than 1 array of attributes are returned, a sequence of requests will be sent, each one of them including the attributes returned in each one of the returned arrays. Thecollector
mayrequire()
NPM packages (previously declaring them in therequire
property) just as in theattribute-function-interpolator
interpolator and should return its result (i.e., the array of arrays) assigning it to themodule.exports
variable. Anexternal
variable is injected into thecollector
property Javascript code including the simulation configurationexternal
property contents of the concrete entity augmented with an additionalresponse
sub-property with the result of the request made to the external endpoint. An example value for thecollector
property is the following:"var csvParse = require('csv-parse/lib/sync'); var data = external.response.body; var csvDataIndex = data.indexOf('\"Fecha y hora oficial'); var csvData = data.substring(csvDataIndex); var parsedCSVData = csvParse(csvData, {columns: true}); function getDate(dateString) { return new Date(dateString.substring(6,10), dateString.substring(3,5), dateString.substring(0,2), dateString.substring(11,13), dateString.substring(14));} var dateObserved = getDate(parsedCSVData[0]['Fecha y hora oficial']); module.exports = [[{name: 'dateObserved', type: 'DateTime', value: dateObserved}, {name: 'dateModified', type: 'DateTime', value: dateObserved}, {name: 'temperatura', type: 'Number', value: parsedCSVData[0]['Temperatura (�C)']}, {name: 'vientoVelocidad', type: 'Number', value: parsedCSVData[0]['Velocidad del viento (km/h)']}]];"
. - headers: Optional. An object including the headers to be added to the external source requests. A possible
headers
property is the following:"headers": { "Cache-Control": "no-cache", "Content-Type": "application/json", "Accept": "application/json" }
. - json: Optional. A boolean with the same semantics as used in the
request
NPM package. This is: iftrue
, 1)body
must be a JSON-serializable object, 2) theContent-type: application/json
header is automatically added to the requests and 3) the response body is parsed as JSON. - method: Mandatory. The HTTP method to be used in the request made to the external source endpoint. Accepted values:
GET
andPOST
. - retry: Optional. Retry politics to be applied in case an error happens when requesting the data from the external source. It is an object including a
times
(with a default default value of 5) property to set the number of retries and an additionalinterval
property (with a default default value of 0) to set the delay in milliseconds between the retries. - url: Mandatory. The URL where the requests for the external data should be sent to. The
url
entry accepts date templates so the final URLs can be composed dynamically. An acceptedurl
property is the following:"url": "http://www.aemet.es/es/eltiempo/observacion/ultimosdatos_6156X_datos-horarios.csv?k=and&l=6156X&datos=det&w=0&f=temperatura&x=h24"
. The supported date templates include (obviously these templates can be combined in one concreteurl
):{YY}
: This template is substituted by the final 2 digits of the current year. For example, in 2017 theurl
with value"http://www.example.com/{YY}"
will be finally generated as"http://www.example.com/17"
.{YYYY}
: This template is substituted by all the digits which corresponds to the current year. For example, in 2017 theurl
with value"http://www.example.com/{YYYY}"
will be finally generated as"http://www.example.com/2017"
.{MM}
: This template is substituted by the 2 digits corresponding to the current month including a0
at the beginning when appropriate. For example, in June theurl
with value"http://www.example.com/{MM}"
will be finally generated as"http://www.example.com/06"
.{M*}@en
: This template is subsituted by the whole name of the current month in uppercase in English. For example, in June theurl
with value"http://www.example.com/{M*}@en"
will be finally generated as"http://www.example.com/JUNE"
.{M*}@es
: This template is substituted by the whole name of the current month in uppercase in Spanish. For example, in June theurl
with value"http://www.example.com/{M*}@es"
will be finally generated as"http://www.example.com/JUNIO"
.{m*}@en
: This template is substituted by the whole name of the current month in lowercase in English. For example, in June theurl
with value"http://www.example.com/{m*}@en"
will be finally generated as"http://www.example.com/june"
.{m*}@es
: This template is substituted by the whole name of the current month in lowercase in Spanish. For example, in June theurl
with value"http://www.example.com/{M*}@es"
will be finally generated as"http://www.example.com/junio"
.{MMM}@en
: This template is substituted by the first 3 characters of the current month in uppercase in English. For example, in June theurl
with value"http://www.example.com/{MMM}@en"
will be finally generated as"http://www.example.com/JUN"
.{MMM}@es
: This template is substituted by the first 3 characters of the current month in uppercase in Spanish. For example, in June theurl
with value"http://www.example.com/{MMM}@es"
will be finally generated as"http://www.example.com/JUN"
.{mmm}@en
: This template is substituted by the first 3 characters of the current month in lowercase in English. For example, in June theurl
with value"http://www.example.com/{mmm}@en"
will be finally generated as"http://www.example.com/jun"
.{mmm}@es
: This template is substituted by the first 3 characters of the current month in lowercase in Spanish. For example, in June theurl
with value"http://www.example.com/{mmm}@es"
will be finally generated as"http://www.example.com/jun"
.{DD}
: This template is substituted by the current day of the month including a0
at the beginning when appropriate. For example, on the 5th, theurl
with value"http://www.example.com/{DD}"
will be finally generated as"http://www.example.com/05"
.{DD-1}
: This template is substituted by the day before of the current day of the month, including a0
at the beginning when appropriate. For example, on the 5th, theurl
with value"http://www.example.com/{DD}"
will be finally generated as"http://www.example.com/04"
.{D*}@en
: This template is substituted by the whole name of the current day of the week in English. For example, on Wednesday, theurl
with value"http://www.example.com/{D*}@en"
will be finally generated as"http://www.example.com/WEDNESDAY"
.{D*}@es
: This template is substituted by the whole name of the current day of the week in Spanish. For example, on Wednesday, theurl
with value"http://www.example.com/{D*}@es"
will be finally generated as"http://www.example.com/MIÉRCOLES"
.{DDD}@en
: This template is substituted by the first letters of the name of the current day of the week in uppercase in English. For example, on Wednesday, theurl
with value"http://www.example.com/{DDD}@en"
will be finally generated as"http://www.example.com/WED"
.{DDD}@es
: This template is substituted by the first letters of the name of the current day of the week in uppercase in Spanish. For example, on Wednesday, theurl
with value"http://www.example.com/{DDD}@es"
will be finally generated as"http://www.example.com/MIÉ"
.{ddd}@en
: This template is substituted by the first letters of the name of the current day of the week in lowercase in English. For example, on Wednesday, theurl
with value"http://www.example.com/{ddd}@en"
will be finally generated as"http://www.example.com/wed"
.{ddd}@es
: This template is substituted by the first letters of the name of the current day of the week in lowercase in Spanish. For example, on Wednesday, theurl
with value"http://www.example.com/{ddd}@es"
will be finally generated as"http://www.example.com/mié"
.{hh}
: This template is substituted by the current hour in 24-hours format including a0
at the beginning when appropriate. For example, at 10 PM, theurl
with value"http://www.example.com/{hh}"
will be finally generated as"http://www.example.com/22"
.{mm}
: This template is substituted by the current minutes including a0
at the beginning when appropriate. For example, at 10:05 PM, theurl
with value"http://www.example.com/{mm}"
will be finally generated as"http://www.example.com/05"
.{hh}
: This template is substituted by the current seconds including a0
at the beginning when appropriate. For example, at 10:05:09 PM, theurl
with value"http://www.example.com/{ss}"
will be finally generated as"http://www.example.com/09"
.
- schedule: Cron-style schedule (according to https://www.npmjs.com/package/node-schedule#cron-style-scheduling) to schedule the updates of the entity. For example:
- devices: Information about the devices to be updated during this concrete simulation. The
devices
entries are just like the previousentities
entries described above with the following modifications:- Instead of the
entity_name
, adevice_id
has to be specified (in case thecount
property is used, thedevice_id
property is set just like theentity_name
as describe above in thecount
property description). - A
protocol
property has to be set specifying the device protocol. Accepted values are:UltraLight::HTTP
,UltraLight::MQTT
,JSON::HTTP
andJSON::MQTT
. - No
entity_type
property has to be specified. - An
api_key
property has to be set specifying the API key to be used when updating the device attributes. - Instead of the
active
andstaticAttributes
property, anattributes
properties has to be included specifying the array of attributes to be updated. At theattributes
level:- No
name
property has to be specified. Instead theobject_id
has to be set specifying the attribute object (short) identifier. - No
type
property has to be specified. - All the previously describe interpolators can be used in the
value
.
- No
- Instead of the
To avoid repeating over and over again the same text in the simulation configuration files and, mainly, to facilitate editing them, a templating mechanism has been included. This templating mechanism makes it posible to use the imports()
directive as the value of any property of a simulation configuration JSON file. As a preliminary process before starting the simulation all these imports()
directives will be resolved and substituted by their concrete values.
Let's see this imports()
directive mechanism with an example. The next one is a valid simulation configuration file using the templating mechanism:
{
"exports": {
"contextBroker_NGSIv1": {
"protocol": "https",
"host": "1.2.3.4",
"port": 1026,
"ngsiVersion": "1.0"
},
"every 5 seconds": "*/5 * * * * *",
"autoincrement_1": "attribute-function-interpolator(${{Entity:001}{active:001}} + 1)",
},
"domain": {
"service": "service",
"subservice": "subservice"
},
"contextBroker": "import(contextBroker_NGSIv1)",
"authentication": "import(authentication)",
"entities": [
{
"schedule": "import(every 5 seconds)",
"entity_name": "Entity:001",
"entity_type": "Entity",
"active": [
{
"name": "active:001",
"type": "Number",
"value": "import(autoincrement_1)"
}
]
}
]
}
For example, the import directives: import(contextBroker_NGSIv1)
, import(every 5 seconds)
and import(autoincrement_1)
will be substituted by the corresponding values declared in the exports
property of the simulation configuration file, whereas the import(authentication)
(since it is not declared in the exports
) property will be require
d as the file authentication.json
from the root of the FIWARE Device Simulator application (this is, it is equivalent to require(${FIWARE_Device_Simulator_Root_Path}/authentication.json))
.
The previous and preliminary support for importing content into specific parts of the simulation configuration files has been recently extended to support conditional imports. In this case, it is possible to impose conditions which must be satisfied for the import to take place. The format of the conditional imports is the following one:
"<template-name>": [
{
"condition": "${{<entity-property-1>==<regular-expression-1>}}",
"content": "the-content-to-import-a-string-in-this-case"
},
{
"condition": "${{<entity-property-2>==<regular-expression-2>}{<attribute-property-2>==<regular-expression-2>}}",
"content": "the-content-to-import-a-string-in-this-case"
}
]
As you can see, the templates can now be an array of objects including a condition
and a content
properties in which case the import will only take place if the import()
directive appears inside an entity which satisfies the <entity-property-1>==<regular-expression-1>
condition (this is, the <entity-property1->
value satisfies the <regular-expression-1>
) OR appears inside an attribute which satisfies the <attribute-property-2>==<regular-expression-2>
condition (this is, the <attribute-property-2>
value satisfies the <regular-expression-2>
) inside an entity which satisfies the <entity-property-2>==<regular-expression-2>
condition (this is, the <entity-property-2>
value satisfies the <regular-expression-2>
).
Let's see it in a concrete example. Considering a simulation configuration file such as the following one:
{
"exports": {
"every 5 seconds": "*/5 * * * * *",
"parking from 6 to 22": "text-rotation-interpolator({\"units\": \"hours\", \"text\": [[0,\"closed\"],[6,[[40,\"free\"],[60,\"occupied\"]]],[19,[[80,\"free\"],[20,\"occupied\"]]],[22,\"closed\"]]})",
"now": "date-increment-interpolator({\"origin\": \"now\", \"increment\": 0})",
"entity-type": [
{
"content": "ParkingSpot",
"condition": "${{entity_name==pe-moraleja-01-group-0[0-9]:0[0-9]}}"
}
],
"attribute-type-1": [
{
"content": "Text",
"condition": "${{entity_name==pe-moraleja-01-group-02:0[0-9]}}"
},
{
"content": "DateTime",
"condition": "${{entity_name==pe-moraleja-01-group-01:0[0-9]}{name==dateModifie[a-z]}}"
}
]
},
...
"entities": [
{
"schedule": "import(every 5 seconds)",
"entity_name": "pe-moraleja-01-group-01:01",
"entity_type": "import(entity-type)",
"active": [
{
"name": "status",
"type": "Text",
"value": "import(parking from 6 to 22)"
},
{
"name": "dateModified",
"type": "import(attribute-type-1)",
"value": "import(now)"
}
]
},
{
"schedule": "import(every 5 seconds)",
"entity_name": "pe-moraleja-01-group-02:01",
"entity_type": "import(entity-type)",
"active": [
{
"name": "status",
"type": "import(attribute-type-1)",
"value": "import(parking from 6 to 22)"
},
{
"name": "dateModified",
"type": "DateTime",
"value": "import(now)"
}
]
}
]
...
}
After resolving the imports, the simulation configuration file will end up as the following one:
{
...
"entities": [
{
"schedule": "*/5 * * * * *", // -> IMPORTED
"entity_name": "pe-moraleja-01-group-01:01",
"entity_type": "ParkingSpot", // -> IMPORTED
"active": [
{
"name": "status",
"type": "Text",
"value": "text-rotation-interpolator({\"units\": \"hours\", \"text\": [[0,\"closed\"],[6,[[40,\"free\"],[60,\"occupied\"]]],[19,[[80,\"free\"],[20,\"occupied\"]]],[22,\"closed\"]]})" // -> IMPORTED
},
{
"name": "dateModified",
"type": "DateTime", // -> IMPORTED
"value": "date-increment-interpolator({\"origin\": \"now\", \"increment\": 0})" // -> IMPORTED
}
]
},
{
"schedule": "*/5 * * * * *", // -> IMPORTED
"entity_name": "pe-moraleja-01-group-02:01",
"entity_type": "ParkingSpot", // -> IMPORTED
"active": [
{
"name": "status",
"type": "Text", // -> IMPORTED
"value": "text-rotation-interpolator({\"units\": \"hours\", \"text\": [[0,\"closed\"],[6,[[40,\"free\"],[60,\"occupied\"]]],[19,[[80,\"free\"],[20,\"occupied\"]]],[22,\"closed\"]]})" // -> IMPORTED
},
{
"name": "dateModified",
"type": "DateTime",
"value": "date-increment-interpolator({\"origin\": \"now\", \"increment\": 0})" // -> IMPORTED
}
]
}
]
...
}
Just as in the case of the textual imports, the conditional imports can be declared in the exports
property of the simulation configuration file or in external JSON files which can be imported.
Obviously, if an import directive refers to a template not declared either in the exports
property or in an external JSON file, an error is thrown and the simulation is not run. On the other hand, if all the substitutions take place fine and the resulting simulation configuration file is valid, the simulation is run.
Although the FIWARE Device Simulator command line tool (i.e., fiwareDeviceSimulatorCLI
) includes support for the import mechanism just described, we have also included a specific command line tool for the import mechanism which transpiles an input simulation configuration file into an output configuration file including the resolved imports (i.e., fiwareDeviceSimulatorTranspilerCLI
). Check the Command line tools
section for further details on both command line tools.
Last but not least, the ./examples
directory includes some real examples of simulation configuration files used to simulate distinct scenarios.
Using environment variables in simulation file
The simulation configuration file may use an .env
file to set configuration in the form of environment variables. This can be used to avoid setting
sensitive information, and be executed in whatever environment, having different configurations and not been needed to change anything on code.
Note that the .env
file used by a given simulation file is the one that is located in the same directory where the simulation file is. For instance:
├── electricvehicle # Subservice directory (simulation has to have the same configuration)
│ ├── .env # Environment variables (just for the simulations in this directory)
│ ├── simulation1.json # simulation1.json tests
│ └── simulation2.json # simulation2.json tests
│ └── ...
├── bathwaters # Subservice directory (simulation has to have the same configuration)
│ ├── .env # Environment variables (just for the simulations in this directory)
│ ├── simulation1.json # simulation1.json tests
│ └── simulation2.json # simulation2.json tests
│ └── ...
└── ...
Here's an example of .env
file with the commonly environment variables used:
AUTH_PASS="pass"
AUTH_USER="user"
AUTH_PORT=5001
AUTH_HOST="localhost"
DOMAIN_SERVICE="service"
DOMAIN_SUBSERVICE="/subservice"
CB_HOST="localhost"
CB_PORT=1026
IOTA_ULTRALIGHT_API="1ifhm6o0kp4ew7fi377mpyc3c"
IOTA_ULTRALIGHT_HTTP_HOST="localhost"
IOTA_ULTRALIGHT_HTTP_PORT=8085
IOTA_ULTRALIGHT_MQTT_HOST="localhost"
IOTA_ULTRALIGHT_MQTT_PORT=1833
IOTA_ULTRALIGHT_MQTT_USER="mqttUser"
IOTA_ULTRALIGHT_MQTT_PASS="mqttPassword"
IOTA_JSON_API="83ut64ib3gzs6km6izubjyenu"
IOTA_JSON_HTTP_HOST="localhost"
IOTA_JSON_HTTP_PORT=8185
IOTA_JSON_MQTT_HOST="localhost"
IOTA_JSON_MQTT_PORT=1883
IOTA_JSON_MQTT_USER="mqttUser"
IOTA_JSON_MQTT_PASS="mqttPassword"
To use a environment variable on the configuration file, it's needed to be setted around ${}
having as result ${VARIABLE}
.
An example simulation configuration file using environment variables is shown next to give you a glimpse of its shape:
{
"domain": {
"service": "${DOMAIN_SERVICE}",
"subservice": "${DOMAIN_SUBSERVICE}"
},
"contextBroker": {
"protocol": "http",
"host": "${CB_HOST}",
"port": "${CB_PORT}",
"ngsiVersion": "2.0"
},
"authentication": {
"provider": "keystone",
"protocol": "http",
"host": "${AUTH_HOST}",
"port": "${AUTH_PORT}",
"user": "${AUTH_USER}",
"password": "${AUTH_PASS}",
"retry": {
"times": 10,
"interval": 1000
}
},
"iota": {
"ultralight": {
"api_key": "${IOTA_ULTRALIGHT_API}",
"http": {
"protocol": "http",
"host": "${IOTA_ULTRALIGHT_HTTP_HOST}",
"port": "${IOTA_ULTRALIGHT_HTTP_PORT}"
},
"mqtt": {
"protocol": "mqtt",
"host": "${IOTA_ULTRALIGHT_MQTT_HOST}",
"port": "${IOTA_ULTRALIGHT_MQTT_PORT}",
"user": "${IOTA_ULTRALIGHT_MQTT_USER}",
"password": "${IOTA_ULTRALIGHT_MQTT_PASS}"
}
},
"json": {
"api_key": "${IOTA_JSON_API",
"http": {
"protocol": "http",
"host": "${IOTA_JSON_HTTP_HOST}",
"port": "${IOTA_JSON_HTTP_PORT}"
},
"mqtt": {
"protocol": "mqtt",
"host": "${IOTA_JSON_MQTT_HOST}",
"port": "${IOTA_JSON_MQTT_PORT}",
"user": "${IOTA_JSON_MQTT_USER}",
"password": "${IOTA_JSON_MQTT_PASS}"
}
}
}
}