This example shows the use Geo:Point special attributes within Cepheus-CEP.

Let's demonstrate a Geofencing alert that is triggered when a Tracker enters or exists a geofenced zone.

Setup

Let us suppose the trackers have location and time attributes: They will send updateContext requests of this type:

 {
     "id": "Tracker1",
     "type":"Tracker",
     "attributes": [
        { "name":"time", "type":"date", "value":"2015-10-26T22:47:09Z" },
        { "name":"location", "type":"geo:point", "value":"45.2334, 1.4233" }
     ]
 }

The goal is to have the CEP trigger an updateContext request like this one:

 {
     "id": "Tracker1", // Id of the tracker that triggered the alert
     "type":"Alert",
     "attributes": [
        { "name":"time", "type":"date", "value":"2015-10-26T22:47:09Z" },
        { "name":"location", "type":"geo:point", "value":"45.2334, 1.4233" }
        { "name":"inside", "type":"boolean", "value":"true" }
     ]
 }

each time a tracker enters or exit the geofenced zone.

Configuring the CEP

Translated to the configuration format of the Cepheus-CEP, we get the following "in" section for accepting Tracker as input :

"in":[ { "id":"Tracker1", "type":"Tracker", "attributes":[ { "name":"time", "type":"date" }, { "name":"location", "type":"geo:point" } ] } ]

The "out" section is also similar to the NGSI Context Entity of the given Alert definition:

"out":[
       {
         "id":"Fence1",
         "type":"Alert",
         "attributes":[
           { "name":"time", "type":"date" },
           { "name":"location", "type":"geo:point" },
           { "name":"inside", "type":"boolean" }
         ]
       }
]

We first need to define the fence (our geofenced zone) using a polygon:

CREATE VARIABLE Geometry fence = polygon({point(0, 0), point(0,50), point(50,50), point(50, 0), point(0, 0)})

Then we create a window that will keep the state of each Tracker modelled after the event type Alert:

CREATE WINDOW TrackerState.std:unique(id) as Alert

We then define a new Event Type to compute if the tracker is in the fence each time a tracker updates its location:

INSERT INTO TrackerInside SELECT *, fence.contains(location) as inside FROM Tracker

Then we define an FenceCross event when a tracker is detected in (or out) the zone and that no other opposite update occured during a given period:

INSERT INTO FenceCross SELECT a.* FROM pattern [ every a=TrackerInside -> (timer:interval(4 sec) and not TrackerInside(id=a.id, inside!=a.inside)) ]

This allows us to handle cases where a tracker can stay on the edge for a given time.

Then the TrackerState is updated only if the state is different (or that not state is yet defined):

ON FenceCross fc MERGE TrackerState ts
WHERE fc.id = ts.id
   WHEN NOT MATCHED THEN INSERT SELECT id, time, location, inside
   WHEN MATCHED AND fc.inside != ts.inside THEN UPDATE SET inside = fc.inside

Finaly, all events of the TrackerState window are sent as Alert:

INSERT INTO Alert SELECT * FROM TrackerState"

The config.json has the complete configuration setup.

Testing the setup

You can run the run.sh file in a terminal while checking the logs of Cepheus CEP to see the Rooms temperature sent to the CEP and the CEP reacting to the events.

In a first terminal, launch Cepheus-CEP:

cd cepheus-cep
mvn spring-boot:run

Default configuration should launch it on port :8080 on your machine.

Now in another terminal, trigger the run.sh script:

cd doc/examples/8_DateAndGeoPoint
sh run.sh

The script first sends the config.json file to Cepheus-CEP, then it starts sending location updates.

Go back to the terminal where you launched the CEP. You should see location as "EventIn" being logged and some Alert "EventOut" beeing fired 3 times:

  • the initial alert where the tracker is defined as outside of the zone,
  • the next alert where the tracker is define as inside the zone,
  • a final alert where the tracker exists the zone.