- Introduction
- EPL text
- No signal conditions
- Actions
- Metadata and object values
- Location fields
- Time fields
- JSON and Array fields
There are two kind of rules:
- Esper-based rules, which include the final EPL statement used by the Esper engine inside perseo-core. In order to work with perseo (front-end) properly, the EPL statement must fulfill several conventions for the rule to be able to operate on the incoming events and trigger adequate actions. Example:
{
"name": "blood_rule_update",
"text": "select *, *, ev.BloodPressure? as Pressure, ev.id? as Meter from pattern [every ev=iotEvent(cast(cast(BloodPressure?,String),float)>1.5 and type=\"BloodMeter\")]",
"action": {
"type": "update",
"parameters": {
"attributes": [
{
"name": "abnormal",
"value": "true",
"type": "boolean"
}
]
}
}
}
- No signal rules. They are triggered when a given attribute is not updated in a given interval of time. They don't use Esper at persero-core (they are checked and triggered by perseo frontend). Example:
{
"name": "check_temp_no_signal",
"nosignal": {
"checkInterval": "1",
"attribute": "temperature",
"reportInterval": "5",
"id": null,
"idRegexp": "^value.*",
"type": null
},
"action": {
"type": "email",
"template": "No signal in temperature",
"parameters": {
"to": "[email protected]",
"from": "[email protected]",
"subject": "temperature no signal"
}
}
}
In both types of rules the following fields are mandatory:
- name: name of the rule, used as identifier
- action: action to be performed by perseo if the rule is fired from the core
For EPL-based rules the following field is mandatory:
- text: EPL statement for the rule engine in perseo-core.
For no signal rules the following field is mandatory:
- nosignal: a description of the no signal condition.
The rule name must consist of the ASCII characters from A to Z, from a to z, digits (0-9), underscore (_) and dash (-). It can have a maximum length of 50 characters.
The field action
can be also an array of "actions", objects with the same structure than the single action described
in the rest of the documentation. Each of those actions will be executed when the rule is fired, avoiding to duplicate a
rule only for getting several actions executed. For practical purposes, it is the same result that would be obtained
with multiple rules with the same condition.
The field text
of the rule must be a valid EPL statement and additionally must honor several restrictions to match
expectations of perseo and perseo-core.
EPL is documented in Esper site, in particular version 7.1.0.
A EPL statement to use with perseo could be:
select *, ev.BloodPressure? as Pressure, ev.id? as Meter
from pattern
[every ev=iotEvent(cast(cast(BloodPressure?,String),float)>1.5 and type="BloodMeter")]
- Include
*,
in EPL select clause - The from pattern must name the event as ev and the event stream from which take events must be iotEvent
- A type= condition must be concatenated for avoiding mixing different kinds of entities
- The variable 'ruleName' in automatically added to the action, even if it is not present in the EPL text. The ruleName automatically added this way is retrieved as part of the EPL text when the rule is recovered using GET /rules or GET /rules/{name}.
Backward compatibility note: since perseo-fe version 1.8.0 it is not mandatory to specify the name of the rule as part of the
EPL text. In fact, it is not recommendable to do that. However, for backward compatibility, it can be present as
ruleName alias (e.g: select *, "blood_rule_update" as ruleName...
) in the select clause. If present, it must be
equal to the ‘name’ field of the rule object.
The used entity's attributes must be cast to float
in case of being numeric (like in the example). Alphanumeric values
must be cast to String
. Nested cast to string and to float is something we are analyzing, and could be unnecessary in
a future version. Use it by now. All the attributes in the notification from Orion are available in the event object,
ev, like ev.BlodPressure? and ev.id?. A question mark is necessary for EPL referring ‘dynamic’ values.
Metadata is also available as explained in Metadata and object values.
Please, be carefull with using non-ascii characters in the EPL syntax. It will provoke an error. You can find information on how to scape characters at Esper site
The no signal condition is specified in the nosignal
configuration element, which is an object with the following
fields:
- checkInterval: mandatory, time in minutes for checking the attribute
- attribute: mandatory, attribute for watch
- reportInterval: mandatory, time in seconds to see an entity as silent
- id or idRegexp: mandatory (but not both at the same time), id or regex of the entity to watch
- type: optional, type of entities to watch
Is recommended to set checkInterval at least double of reportInterval. Howeer, note that a very demanding value of checkInterval could impact on performance.
When a rule is fired, the "complex event" generated by the select clause is sent to perseo (front-end) which executes the action using the generated event as parameter to the action.
There are a predefined set of actions: sending a SMS, sending a email, updating an attribute of the entity that fired the rule and making a HTTP POST to a provided URL.
The action must be provided in the action
field of rule. An example:
"action":{
"type":"update",
"parameters":{
"name":"abnormal",
"value":"true",
"type":"boolean"
},
"interval" : "30e3"
}
The type
field is mandatory and must be one of
update
: update an entity's attributesms
: send a SMSemail
: send an emailpost
: make an HTTP POSTtwitter
: send a twitter
An action can optionally have a field interval
for limiting the frequency of the action execution (for the rule and
entity which fired it). The value is expressed in milliseconds and is the minimum period between executions. Once the
action is executed successfully, it won't be executed again until that period has elapsed. All the request from core
to execute it are silently discarded. This way, the rate of executions for an entity and rule can be limited. (Strictly,
the minimum time between executions)
Some of the fields of an action
(see detailed list below) can include a reference to one of the fields of the
notification/event. This allows include information as the received "pressure" value, the ID of the device, etc. For
example, the actions sms
, email
, post
include a field template
used to build the body of message/request. This
text can include placeholders for attributes of the generated event. That placeholder has the form ${X}
where X
may
be:
id
for the ID of the entity that triggers the rule.type
for the type of the entity that triggers the rule- Any other value is interpreted as the name of an attribute in the entity which triggers the rule and the placeholder is substituted by the value of that attribute.
All alias for simple event attributes or "complex" calculated values can be directly used in the placeholder with their
name. And any of the original event attributes (with the special cases for id
and type
meaning entity ID and type,
respectively) can be referred too.
This substitution can be used in the following fields:
template
,from
,to
andsubject
foremail
actiontemplate
,url
,qs
,headers
,json
forpost
actiontemplate
forsms
actiontemplate
fortwitter
actionid
,type
,name
,value
,ìsPattern
forupdate
action
Attribute value of update
action and template of post
action are expanded to numerical, boolean or JSON stringyfied
values instead of string values when is possible. For example, if we have {"a": "${x}"}
:
- If the value of attribute
x
is42
then it will expand do{"a": 42}
and not to{"a": "42"}
- If the value of attribute
x
is{"hello": "world"}
then it will expand to{"a": "{\"hello\":\"world\"}"}
(expand to native JSON, i.e.{"a": {"hello": "world"}}
, is not supported)
Sends a SMS to a number set as an action parameter with the body of the message built from the template
"action": {
"type": "sms",
"template": "Meter ${Meter} has pressure ${Pressure}.",
"parameters": {
"to": "123456789"
}
}
The field parameters
include a field to
with the number, or numbers separated by whiestpace charaters, to send the
message to.
The template
and to
fields perform attribute substitution.
Sends an email to the recipient set in the action parameters, with the body mail build from the template
field. A
field to
in parameters
sets the recipient and a field from
sets the sender's email address. Also the subject of the
email can be set in the field subject
in parameters
.
"action": {
"type": "email",
"template": "Meter ${Meter} has pressure ${Pressure} (GEN RULE)",
"parameters": {
"to": "[email protected]",
"from": "[email protected]",
"subject": "It's The End Of The World As We Know It (And I Feel Fine)"
}
}
The template
, from
, to
and subject
fields perform string substitution.
Updates one or more attributes of a given entity or as a result of filter (in the Context Broker instance specified in
the Perseo configuration). The parameters
map includes the following fields:
- id: optional, the ID of the entity which attribute is to be updated (by default the ID of the entity that triggers
the rule is used, i.e.
${id}
) - type: optional, the type of the entity which attribute is to be updated (by default the type of the entity that
triggers the rule is usedi.e.
${type}
) - version: optional, The NGSI version for the update action. Set this attribute to
2
or"2"
if you want to use NGSv2 format.2
by default. - isPattern: optional,
false
by default. (Only for NGSIv1. Ifversion
is set to 2, this attribute will be ignored) - attributes: mandatory, array of target attributes to update. Each element of the array must contain the fields
- name: mandatory, attribute name to set
- value: mandatory, attribute value to set
- type: optional, type of the attribute to set. By default, not set (in which case, only the attribute value is changed).
- actionType: optional, type of CB action: APPEND, UPDATE or DELETE. By default is APPEND.
- APPEND: updated attributes (if previously exist in the entity) or append them to the entity (if previously doesn't exist in the entity)
- UPDATE: update attributes, asumming they exist (otherwise the update operation fails at CB)
- DELETE: delete attributes (or the entity itself if the attributes list is empty)
- trust: optional, trust token for getting an access token from Auth Server which can be used to get to a Context Broker behind a PEP.
- service: optional, service that will be used by updateAction rule instead of current event service, pep url will be used instead of contextbroker.
- subservice: optional, subservice that will be used by updateAction rule instead of current event service, pep url will be used instead of contextbroker.
- filter: optional, a NGSIv2 filter. If provided then updateAction is done over result of query. This overrides the
id
field (in other words, if you usefilter
thenid
field is ignored, in fact you should not useid
andfilter
in the same rule). Needsversion: 2
option (ifversion
is1
the filter is ignored).
NGSIv1 example:
"action":{
"type":"update",
"parameters":{
"id":"${id}_mirror",
"attributes": [
{
"name":"abnormal",
"type":"boolean",
"value":"true"
}
],
"actionType": "UPDATE"
}
}
The name
parameter cannot take id
or type
as a value, as that would refer to the entity's ID and the entity's type
(which are not updatable) and not to an attribute with any of those names. Trying to create such action will return an
error.
The id
, type
, name
, value
, ìsPattern
fields perform string substitution.
First time an update action using trust token is triggered, Perseo interacts with Keystone to get the temporal auth token corresponding to that trust token. This auth token is cached and used in every new update associated to the same action. Eventually, Perseo can receive a 401 Not Authorized due to auth token expiration. In that case, Perseo interacts again with Keystone to get a fresh auth token, then retries the update that causes the 401 (and the cache is refreshed with the new auth token for next updates).
It could happen (in theory) that a just got auth token also produce a 401 Not authorized, however this would be an abnormal situation: Perseo logs the problem with the update but doesn't try to get a new one from Keystone. Next time Perseo triggers the action, the process may repeat, i.e. first update attempt fails with 401, Perseo requests a fresh auth token to Keystone, the second update attempt fails with 401, Perseo logs the problem and doesn't retry again.
NGSIv2 example:
"action":{
"type":"update",
"parameters":{
"id":"${id}_mirror",
"version": 2,
"attributes": [
{
"name":"abnormal",
"type":"Number",
"value": 7
},
{
"name": "locationCopy",
"type": "MyCustomTypo",
"value": "{\"type\":\"Point\",\"coordinates\":[${Lat},${Lon}]}"
}
]
}
}
When using NGSIv2 in the update actions, the value field perform string substitution. If
value
is a String, Perseo will try cast value to number, boolean or null (without paying attention to the attribute
type). If the casting fails then String is used. Boolean
and None
types.
Data Types for NGSIv2:
With Number
type attributes, Perseo can be able to manage a int/float number or a String to parse in value field.
- Number from variable:
{
"name": "numberFromValue",
"type": "Number",
"value": "${NumberValue}"
}
If NumberValue
value is for example 32.12
, this attribute will take 32.12
as value.
- Literal Number:
{
"name": "numberLiteral",
"type": "Number",
"value": 12
}
This attribute will take 12
as value.
- Number as String from variable:
{
"name": "numberFromStringValue",
"type": "Number",
"value": "${NumberValueAsString}"
}
If NumberValueAsString
value is for example "4.67"
, this attribute will take 4.67
as value.
- Number as String:
{
"name": "numberStringLiteral",
"type": "Number",
"value": "67.8"
}
This attribute will take 67.8
as value.
With Text
type attributes, Perseo will put the value field parsed as string.
- Text as variable:
{
"name": "textFromValue",
"type": "Text",
"value": "${varValue}"
}
If varValue
value is for example "Good morning"
, this attribute will take "Good morning"
as value.
If varValue
value is for example 1234
, this attribute will take "1234"
as value.
- Literal Text:
{
"name": "textLiteral",
"type": "Text",
"value": "Hello world"
}
This attribute will take "Hello world"
as value.
- Literal Number:
{
"name": "textNumberLiteral",
"type": "Text",
"value": 67.8
}
This attribute will take "67.8"
as value.
- Literal Boolean:
{
"name": "textBoolLiteral",
"type": "Text",
"value": true
}
This attribute will take "true"
as value.
With DateTime
type attributes, Perseo will try to parse the value to DateTime format.
Date as String:
{
"name": "dateString",
"type": "DateTime",
"value": "2018-12-05T11:31:39.00Z"
}
This attribute will take "2018-12-05T11:31:39.000Z"
as value.
Date as Number in milliseconds:
{
"name": "dateString",
"type": "DateTime",
"value": 1548843229832
}
This attribute will take "2019-01-30T10:13:49.832Z"
as value.
Date from variable.
{
"name": "dateString",
"type": "DateTime",
"value": "${dateVar}"
}
If dateVar
value is for example 1548843229832
(as Number or String), this attribute will take
"2019-01-30T10:13:49.832Z"
as value.
You can use the __ts
field of a Perseo DateTime attribute to fill a DateTime attribute value without using any
cast()
. For example, if the var are defined as follow in the rule text, ev.timestamp__ts? as dateVar
, dateVar
will
be a String with the Date in milliseconds, for example "1548843060657"
and Perseo will parse this String with to a
valid DateTime as 2019-01-30T10:11:00.657Z
.
With None
type attributes, Perseo will set the value to null
in all cases.
None Attribute:
{
"name": "nullAttribute",
"type": "None",
"value": "It does not matter what you put here"
}
This attribute will take null
as value.
{
"name": "nullAttribute2",
"type": "None",
"value": null
}
This attribute will take null
as value.
Complete example using NGSv2 update action in a rule:
{
"name": "blood_rule_update",
"text": "select *,\"blood_rule_update\" as ruleName, *, ev.BloodPressure? as Pressure from pattern [every ev=iotEvent(BloodPressure? > 1.5 and type=\"BloodMeter\")]",
"action": {
"type": "update",
"parameters": {
"id": "${id}_example",
"version": 2,
"attributes": [
{
"name": "pressure",
"type": "Number",
"value": "${Pressure}"
}
]
}
}
}
Note that using NGSIv2 the BloodPressure attribute is a Number and therefore it is not necessary to use cast()
.
Complete example using NGSv2 update action with filter in a rule:
{
"name": "blood_rule_update",
"text": "select *,\"blood_rule_update\" as ruleName, *, ev.BloodPressure? as Pressure from pattern [every ev=iotEvent(BloodPressure? > 1.5 and type=\"BloodMeter\")]",
"action": {
"type": "update",
"parameters": {
"filter": {
"type": "SensorMetter",
"q": "status:on"
},
"version": 2,
"attributes": [
{
"name": "pressure",
"type": "Number",
"value": "${Pressure}"
}
]
}
}
}
Makes an HTTP request to an URL specified in url
inside parameters
, sending a body built from template
. The
parameters
field can specify
- method: optional, HTTP method to use, POST by default
- URL: mandatory, URL target of the HTTP method
- headers: optional, an object with fields and values for the HTTP header
- qs: optional, an object with fields and values to build the query string of the URL
- json: optional, an object that will be sent as JSON. String substitution will be performed in the keys and values
of the object's fields. If present, it overrides
template
fromaction
"action":{
"type":"post",
"template":"BloodPressure is ${BloodPressure}",
"parameters":{
"url": "http://localhost:9182/${type}/${id}",
"method": "PUT",
"headers": {
"Content-type": "text/plain",
"X-${type}-pressure": "${BloodPressure}"
},
"qs": {
"${id}": "${BloodPressure}"
}
}
}
Note that you can encode a JSON in the template
field:
"action": {
"type": "post",
"template": "{\"meter\":\"${Meter}\", \"pressure\": ${Pressure}}",
"parameters": {
"url": "http://${target_host}:${target_port}/myapp/${id}",
"headers": {
"Content-type": "application/json",
"X-${type}-pressure": "${BloodPressure}"
},
"qs": {
"${id}": "${BloodPressure}"
}
}
}
or use the json
parameter
"action": {
"type": "post",
"parameters": {
"url": "http://${target_host}:${target_port}/myapp/${id}",
"headers": {
"Content-type": "application/json",
"X-${type}-pressure": "${BloodPressure}"
},
"qs": {
"${id}": "${BloodPressure}"
},
"json": {
"meter": "${meter}",
"${id}": "${type}",
"pressure": "${pressure}"
}
}
}
The template
and url
fields and both the field names and the field values of qs
and headers
and json
perform
string substitution.
Updates the status of a twitter account, with the text build from the template
field. The field parameters
must
contain the values for the consumer key and secret and the access token key and access token secret of the
pre-provisioned application associated to the twitter user.
"action": {
"type": "twitter",
"template": "Meter ${Meter} has pressure ${Pressure} (GEN RULE)",
"parameters": {
"consumer_key": "xvz1evFS4wEEPTGEFPHBog",
"consumer_secret": "L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg",
"access_token_key": "xvz1evFS4wEEPTGEFPHBog",
"access_token_secret": "L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg"
}
}
The template
field performs string substitution.
Metadata values can be accessed by adding the suffix __metadata__x
to the attribute name, being x
the name of the
metadata attribute. This name can be used in the EPL text of the rule and in the parameters of the action which accept
string substitution. If the value of the metadata item is an object itself, nested fields can be referred by additional
suffixes beginning with double underscore and the hierarchy can be walked down by adding more suffixes, like
__metadata__x__subf1__subf12
.
For example: The metadata in an event/notice like
{
"subscriptionId": "51c04a21d714fb3b37d7d5a7",
"originator": "localhost",
"contextResponses": [
{
"contextElement": {
"attributes": [
{
"name": "BloodPressure",
"type": "centigrade",
"value": "2",
"metadatas": [
{
"crs": {
"value": { "system": "WGS84" }
}
}
]
},
{
"name": "TimeInstant",
"type": "urn:x-ogc:def:trs:IDAS:1.0:ISO8601",
"value": "2014-04-29T13:18:05Z"
}
],
"type": "BloodMeter",
"isPattern": "false",
"id": "bloodm1"
},
"statusCode": {
"code": "200",
"reasonPhrase": "OK"
}
}
]
}
could be used by a rule so
{
"name": "blood_rule_email_md",
"text": "select *, *,ev.BloodPressure? as Pression, ev.id? as Meter from pattern [every ev=iotEvent(cast(BloodPressure__metadata__crs__system?,String)=\"WGS84\" and type=\"BloodMeter\")]",
"action": {
"type": "email",
"template": "Meter ${Meter} has pression ${Pression} (GEN RULE) and system is ${BloodPressure__metadata__crs__system}",
"parameters": {
"to": "[email protected]",
"from": "[email protected]",
"subject": "MD VALUE: ${BloodPressure__metadata__crs__system}"
}
}
}
Generally, fields of attribute values which are objects themselves are accessible by adding to the name of the field a
double underscore prefix, so an attribute x
with fields a
, b
, c
, will allow these fields to be referred as
x__a
, x__b
and x__c
.
Note: be aware of the difference between the key metadatas
used in the context broker notificacions (v1), ending in
s
and the infix metadata
, without the final s
, used to access fields from EPL and actions.
Fields with geolocation info with the formats recognized by NGSI v1, are parsed and generate two pairs of
pseudo-attributes, the first pair is for the latitude and the longitude and the second pair is for the x and y UTMC
coordinates for the point. These pseudo-attributes ease the use of the position in the EPL sentence of the rule. These
derived attributes have the same name of the attribute with a suffix of __lat
and __lon
, and __x
and __y
respectively.
The formats are
- NGSIv1 deprecated format
- NGSIv2 current format, section "Geospatial properties of entities"
So, a notification in the deprecated format like
{
"subscriptionId": "57f73930e0e2c975a712b8fd",
"originator": "localhost",
"contextResponses": [
{
"contextElement": {
"type": "Vehicle",
"isPattern": "false",
"id": "Car1",
"attributes": [
{
"name": "position",
"type": "coords",
"value": "40.418889, -3.691944",
"metadatas": [
{
"name": "location",
"type": "string",
"value": "WGS84"
}
]
}
]
}
}
]
}
will propagate to the core, (and so making available to the EPL sentence) the fields position__lat
, position__lon
,
position__x
, position__y
{
"noticeId": "169b0920-8edb-11e6-838d-0b633312661c",
"id": "Car1",
"type": "Vehicle",
"isPattern": "false",
"subservice": "/",
"service": "unknownt",
"position": "40.418889, -3.691944",
"position__type": "coords",
"position__metadata__location": "WGS84",
"position__metadata__location__type": "string",
"position__lat": 40.418889,
"position__lon": -3.691944,
"position__x": 657577.4234800448,
"position__y": 9591797.935076647
}
Analogously, a notification in "geopoint" format, like
{
"subscriptionId": "57f73930e0e2c975a712b8fd",
"originator": "localhost",
"contextResponses": [
{
"contextElement": {
"type": "Vehicle",
"isPattern": "false",
"id": "Car1",
"attributes": [
{
"name": "position",
"type": "geo:point",
"value": "40.418889, -3.691944"
}
]
},
"statusCode": {
"code": "200",
"reasonPhrase": "OK"
}
}
]
}
will send to core an event with the fields position__lat
, position__lon
, position__x
, position__y
also
{
"noticeId":"7b8f1c50-8eda-11e6-838d-0b633312661c",
"id":"Car1",
"type":"Vehicle",
"isPattern":"false",
"subservice":"/",
"service":"unknownt",
"position":"40.418889, -3.691944",
"position__type":"geo:point",
"position__lat":40.418889,
"position__lon":-3.691944,
"position__x":657577.4234800448,
"position__y":9591797.935076647
An example of rule taking advantage of these derived attributes could be:
{
"name": "rule_distance",
"text": "select *, from pattern [every ev=iotEvent(Math.pow((cast(cast(position__x?,String),float) - 618618.8286057833), 2) + Math.pow((cast(cast(position__y?,String),float) - 9764160.736945232), 2) < Math.pow(5e3,2))]",
"action": {
"type": "email",
"template": "${id} (${type}) is at ${position__lat}, ${position__lon} (${position__x}, ${position__y})",
"parameters": {
"to": "[email protected]",
"from": "[email protected]",
"subject": "${id} is coming"
}
}
}
that will send an email when the entity with attribute position
is less than 5 km far away from Cuenca. It uses the
circle equation, (x - a)^2 + (y - b)^2 = d^2
, being (a, b)
618618.8286057833 and 9764160.736945232 the UTMC
coordinates of Cuenca and d
the distance of 5 000 m.
Notes:
- NGSIv2 allows several geo location formats (geo:point, geo:line, geo:box, geo:polygon and geo:json). At the present moment, Perseo only supports geo:point.
- For long distances the precision of the computations and the distortion of the projection can introduce some degree of inaccuracy.
Some attributes and metadata, supposed to contain a time in ISO8601 format, will generate a pseudo-attribute with the same name as the attribute (or metadata field) and a suffix "__ts", with the parsed value as milliseconds for Unix epoch. This value makes easier to write the EPL text which involves time comparisons. The fields (attribute or metadata) supposed to convey time information are
- Fields named
TimeInstant
- Fields of type
DateTime
- Fields of type
urn:x-ogc:def:trs:IDAS:1.0:ISO8601
Additionally, some derived pseudo-attributes are included also
x__day
: the day of the month (1-31) for the specified date according to local time.x__month
: the month (1-12) in the specified date according to local time.x__year
: the year (4 digits) of the specified date according to local time.x__hour
: the hour (0-23) in the specified date according to local time.x__minute
: the minutes (0-59) in the specified date according to local time.x__second
: the seconds (0-59) in the specified date according to local time.x__millisecond
: the milliseconds (0-999) in the specified date according to local time.x__dayUTC
: the day of the month (1-31) in the specified date according to universal time.x__monthUTC
: the month (1-12) in the specified date according to universal time.x__yearUTC
: the year (4 digits) of the specified date according to universal time.x__hourUTC
: the hour (0-23) in the specified date according to universal time.x__minuteUTC
: the minutes (0-59) in the specified date according to universal time.x__secondUTC
: the seconds (0-59) in the specified date according to universal time.x__millisecondUTC
: the milliseconds (0-999) in the specified date according to universal time.
So, an incoming notification like
{
"subscriptionId": "51c04a21d714fb3b37d7d5a7",
"originator": "localhost",
"contextResponses": [
{
"contextElement": {
"attributes": [
{
"name": "TimeInstant",
"value": "2014-04-29T13:18:05Z"
},
{
"name": "birthdate",
"type": "urn:x-ogc:def:trs:IDAS:1.0:ISO8601",
"value": "2014-04-29T13:18:05Z"
},
{
"name": "hire",
"type": "DateTime",
"value": "2016-10-13T12:10:44.149Z"
},
{
"name": "role",
"value": "benevolent dictator for life",
"metadatas": [
{
"name": "when",
"value": "2014-04-29T13:18:05Z",
"type": "DateTime"
}
]
}
],
"type": "employee",
"isPattern": "false",
"id": "John Doe"
},
"statusCode": {
"code": "200",
"reasonPhrase": "OK"
}
}
]
}
will send to core the "event"
{
"noticeId": "799635b0-914f-11e6-836b-bf1691c99768",
"noticeTS": 1476368120971,
"id": "John Doe",
"type": "employee",
"isPattern": "false",
"subservice": "/",
"service": "unknownt",
"TimeInstant": "2014-04-29T13:18:05Z",
"TimeInstant__ts": 1398777485000,
"TimeInstant__day": 29,
"TimeInstant__month": 4,
"TimeInstant__year": 2014,
"TimeInstant__hour": 15,
"TimeInstant__minute": 18,
"TimeInstant__second": 5,
"TimeInstant__millisecond": 0,
"TimeInstant__dayUTC": 29,
"TimeInstant__monthUTC": 4,
"TimeInstant__yearUTC": 2014,
"TimeInstant__hourUTC": 13,
"TimeInstant__minuteUTC": 18,
"TimeInstant__secondUTC": 5,
"TimeInstant__millisecondUTC": 0,
"birthdate": "2014-04-29T13:18:05Z",
"birthdate__type": "urn:x-ogc:def:trs:IDAS:1.0:ISO8601",
"birthdate__ts": 1398777485000,
"birthdate__day": 29,
"birthdate__month": 4,
"birthdate__year": 2014,
"birthdate__hour": 15,
"birthdate__minute": 18,
"birthdate__second": 5,
"birthdate__millisecond": 0,
"birthdate__dayUTC": 29,
"birthdate__monthUTC": 4,
"birthdate__yearUTC": 2014,
"birthdate__hourUTC": 13,
"birthdate__minuteUTC": 18,
"birthdate__secondUTC": 5,
"birthdate__millisecondUTC": 0,
"hire": "2014-04-29T13:18:05Z",
"hire__type": "DateTime",
"hire__ts": 1398777485000,
"hire__day": 29,
"hire__month": 4,
"hire__year": 2014,
"hire__hour": 15,
"hire__minute": 18,
"hire__second": 5,
"hire__millisecond": 0,
"hire__dayUTC": 29,
"hire__monthUTC": 4,
"hire__yearUTC": 2014,
"hire__hourUTC": 13,
"hire__minuteUTC": 18,
"hire__secondUTC": 5,
"hire__millisecondUTC": 0,
"role": "benevolent dictator for life",
"role__metadata__when": "2014-04-29T13:18:05Z",
"role__metadata__when__type": "DateTime",
"role__metadata__when__ts": 1398777485000,
"role__metadata__when__day": 29,
"role__metadata__when__month": 4,
"role__metadata__when__year": 2014,
"role__metadata__when__hour": 15,
"role__metadata__when__minute": 18,
"role__metadata__when__second": 5,
"role__metadata__when__millisecond": 0,
"role__metadata__when__dayUTC": 29,
"role__metadata__when__monthUTC": 4,
"role__metadata__when__yearUTC": 2014,
"role__metadata__when__hourUTC": 13,
"role__metadata__when__minuteUTC": 18,
"role__metadata__when__secondUTC": 5,
"role__metadata__when__millisecondUTC": 0
}
A rule that will check if the employee has been hired in the last half hour, could be
{
"name": "rule_time",
"text": "select *, from pattern [every ev=iotEvent(cast(cast(hire__ts?,String),float) > current_timestamp - 30*60*1000)]",
"action": {
"type": "email",
"template": "So glad with our new ${role}, ${id}!",
"parameters": {
"to": "[email protected]",
"from": "[email protected]",
"subject": "Welcome ${id}!"
}
}
}
Some attributes like JSON and Array based, will generate a pseudo-attribute with the same name as the attribute and a suffix "__" followed by element name (for the case of JSON) or the ordinal (for the case of arrays), with the parsed value. This value makes easier to write the EPL text which involves time comparisons.
So, an incoming notification like this:
{
"subscriptionId": "51c04a21d714fb3b37d7d5a7",
"data": [
{
"id": "John Doe",
"type": "employee",
"myJsonValue": {
"type": "myType1",
"value": { "color": "blue" }
},
"myArrayValue": {
"type": "myType2",
"value": ["green", "blue"]
}
}
]
}
will send to core the "event"
{
"noticeId": "799635b0-914f-11e6-836b-bf1691c99768",
"noticeTS": 1476368120971,
"id": "John Doe",
"type": "employee",
"isPattern": "false",
"subservice": "/",
"service": "unknownt",
"myJsonValue__color": "blue",
"myArrayValue__0": "green",
"myArrayValue__1": "black"
}
Additionally all attributes are also included in non flatten format in the event into the stripped
section:
{
"noticeId": "799635b0-914f-11e6-836b-bf1691c99768",
"noticeTS": 1476368120971,
"id": "John Doe",
"type": "employee",
"isPattern": "false",
"subservice": "/",
"service": "unknownt",
"myJsonValue__color": "blue",
"myArrayValue__0": "green",
"myArrayValue__1": "black",
"stripped": [
{
"myJsonValue": {
"type": "myType1",
"value": {
"color": "blue"
}
}
},
{
"myArrayValue": {
"type": "myType2",
"value": ["green", "black"]
}
}
]
}