(#14) Esper Example Continued - The Event Pojo
The more time I spend with Esper, the more impressed I am at the low barrier to entry. In other words, getting a CEP platform up and running is easy. The previous post displayed the code I came up with that instantiates the Esper CEP engine.The second line of that code:
cepConfig.addEventType( "HHBStatusEvent", HHBStatusEvent.class.getName() );
shows us informing Esper about the class we'll create to represent an event, HHBStatusEvent.
Now, where's more than one way to represent an event, from your stream, to Esper but I chose what I felt was the most simple, a Plain Old Java Object (POJO).
Without further ado,
HHBStatusEvent.java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author patrick.conroy
*/
public class HHBStatusEvent
{
java.util.Calendar dateTime; // date/time event was created
int deviceType; // HHB device type (eg. 23 = Motion Sensor)
String deviceTypeString; // String of type (eg. "MOTION SENSOR")
String deviceName; // Sensor name (eg. "FRONT DOOR")
String deviceStatus; // Sensor state (eg. "OPEN", "CLOSED", "MOTION", "NO MOTION")
int statusDuration; // How long (seconds) the sensor has been in this state
String alarmOnSetting1; // See Note 1
String alarmOnSetting2; // See Note 1
String callOnSetting1; // See Note 2
String callOnSetting2; // See Note 2
boolean deviceOnline; // True or False
boolean batteryOK; // False if low or empty
boolean triggered; // True if sensor is in ALARM state
String macAddress; // MAC Address of this sensor
// ------------
// Note 1: The HHB System can be set to 'alarm' the Key FOB based on the sensor type and state/
// Eg. You can configure the System to alarm when a Door Sensor is 'OPEN' and you could
// configure the System to alarm when a Door Sensor is 'CLOSED'. A motion sensor could alarm
// on 'MOTION', a Tilt Sensor could alarm on 'TILT' and a power sensor could alarm on 'OFF'
// alarmSetting1 will be similar to "ALARM ON OPEN" and alarmSetting2 could be "NO ALARM ON CLOSED"
//
// Note 2: The system had (past tense) the capability to do the above but call into the Eaton
// servers and, in turn, call you or send a text message. So everything said above if copied
// to these attributes, just replace 'ALARM' with 'CALL'. For example the Tilt Sensor could be
// "CALL ON NO-TILT" for callOnSetting1 and "NO CALL ON TILT" for callOnSetting2
//--------------------------------------------------------------------------
@Override
public String toString()
{
return "HHBStatusEvent(" +
getDateTimeString() + "|" +
this.deviceTypeString + "|" +
this.deviceName + "|" +
this.deviceStatus + "|" +
this.statusDuration + "|" +
this.triggered + "|" +
this.macAddress +
")";
}
//--------------------------------------------------------------------------
public String getDateTimeString()
{
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss z" );
return sdf.format( this.dateTime.getTime() );
}
//--------------------------------------------------------------------------
public void fromEventString (String eventString)
{
/*
* Here are some some examples
HHB/STATUS | 2014-05-15 11:31:50 -0600 | 03 | OPEN-CLOSE SENSOR | Front Door | CLOSED | 14400 | ALARM ON OPEN | NO ALARM ON CLOSE | DO NOT CALL ON OPEN | DO NOT CALL ON CLOSE | ONLINE | BATTERY OK | CLEARED | 0000010228 |
HHB/STATUS | 2014-05-15 11:31:50 -0600 | 05 | WATER LEAK SENSOR | Basement Floor | DRY | 950400 | ALARM ON WET | NO ALARM ON DRY | DO NOT CALL ON WET | DO NOT CALL ON DRY | ONLINE | BATTERY OK | CLEARED | 0000011957 |
HHB/STATUS | 2014-05-15 11:31:50 -0600 | 23 | MOTION SENSOR | Motion Sensor | NO MOTION | 3600 | ALARM ON MOTION | NO ALARM ON NO MOTION | DO NOT CALL ON MOTION | DO NOT CALL ON NO MOTION | ONLINE | BATTERY OK | CLEARED | 000007AAAF |
HHB/STATUS | 2014-05-15 11:31:50 -0600 | 24 | TILT SENSOR | Garage Door Sensor | CLOSED | 3600 | ALARM ON OPEN | NO ALARM ON CLOSE | DO NOT CALL ON OPEN | DO NOT CALL ON CLOSE | ONLINE | BATTERY OK | CLEARED | 000000B357 |
*/
String regexDelimiters = "\\|";
String[] tokens = eventString.split( regexDelimiters );
String topic = tokens[ 0 ];
this.dateTime = createDateTime( tokens[ 1 ].trim() );
this.deviceType = Integer.parseInt( tokens[ 2 ].trim() );
this.deviceTypeString = tokens[ 3 ].trim();
this.deviceName = tokens[ 4 ].trim();
this.deviceStatus = tokens[ 5 ].trim();
this.statusDuration = Integer.parseInt( tokens[ 6 ].trim() );
this.alarmOnSetting1 = tokens[ 7 ].trim();
this.alarmOnSetting2 = tokens[ 8 ].trim();
this.callOnSetting1 = tokens[ 9 ].trim();
this.callOnSetting2 = tokens[ 10 ].trim();
this.deviceOnline = (tokens[ 11 ].trim().equalsIgnoreCase( "ONLINE" ) );
this.batteryOK = (tokens[ 12 ].trim().equalsIgnoreCase( "BATTERY OK" ) );
this.triggered = (tokens[ 13 ].trim().equalsIgnoreCase( "TRIGGERED" ) );
this.macAddress = tokens[ 14 ].trim();
}
//--------------------------------------------------------------------------
private java.util.Calendar createDateTime (String dateTimeStr)
{
Calendar aCal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss z" );
try {
aCal.setTime( sdf.parse( dateTimeStr ) );
} catch (ParseException ex) {
//
// In the event of an error - lets just set the event time to "now"
aCal.setTimeInMillis( System.currentTimeMillis() );
}
return aCal;
}
//--------------------------------------------------------------------------
public Calendar getDateTime() {
return dateTime;
}
public void setDateTime (Calendar dateTime) {
this.dateTime = dateTime;
}
public int getDeviceType() {
return deviceType;
}
public void setDeviceType (int deviceType) {
this.deviceType = deviceType;
}
public String getDeviceTypeString() {
return deviceTypeString;
}
public void setDeviceTypeString (String deviceTypeString) {
this.deviceTypeString = deviceTypeString;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public String getDeviceStatus() {
return deviceStatus;
}
public void setDeviceStatus(String deviceStatus) {
this.deviceStatus = deviceStatus;
}
public int getStatusDuration() {
return statusDuration;
}
public void setStatusDuration(int statusDuration) {
this.statusDuration = statusDuration;
}
public String getAlarmOnSetting1() {
return alarmOnSetting1;
}
public void setAlarmOnSetting1(String alarmOnSetting1) {
this.alarmOnSetting1 = alarmOnSetting1;
}
public String getAlarmOnSetting2() {
return alarmOnSetting2;
}
public void setAlarmOnSetting2(String alarmOnSetting2) {
this.alarmOnSetting2 = alarmOnSetting2;
}
public String getCallOnSetting1() {
return callOnSetting1;
}
public void setCallOnSetting1(String callOnSetting1) {
this.callOnSetting1 = callOnSetting1;
}
public String getCallOnSetting2() {
return callOnSetting2;
}
public void setCallOnSetting2(String callOnSetting2) {
this.callOnSetting2 = callOnSetting2;
}
public boolean isDeviceOnline() {
return deviceOnline;
}
public void setDeviceOnline(boolean deviceOnline) {
this.deviceOnline = deviceOnline;
}
public boolean isBatteryOK() {
return batteryOK;
}
public void setBatteryOK(boolean batteryOK) {
this.batteryOK = batteryOK;
}
public boolean isTriggered() {
return triggered;
}
public void setTriggered(boolean triggered) {
this.triggered = triggered;
}
public String getMacAddress() {
return macAddress;
}
public void setmacAddress(String macAddress) {
this.macAddress = macAddress;
}
}
Digging In
Starting right at the top of the class, there's a direct mapping between a field in the MQTT message that represent an event and an attribute in this class.Here's the first few fields from an HHB/STATUS event from MQTT:
HHB/STATUS | 2014-05-15 11:31:50 -0600 | 03 | OPEN-CLOSE SENSOR | Front Door | CLOSED | 14400 | <snip>
And the first few attributes in the Java class:
public class HHBStatusEvent
{
java.util.Calendar dateTime; // date/time event was created
int deviceType; // HHB device type (eg. 23 = Motion Sensor)
String deviceTypeString; // String of type (eg. "MOTION SENSOR")
String deviceName; // Sensor name (eg. "FRONT DOOR")
String deviceStatus; // Sensor state (eg. "OPEN", "CLOSED", "MOTION", "NO MOTION")
int statusDuration; // How long (seconds) the sensor has been in this state
<snip!>
Only the getter and setter methods are required. The toString() and createDateTime() methods are there to help me out.
The other not-essential-to-Esper method, fromEventString() is an easy way for me to create an instance of an HHBStatusEvent object from the payload of an MQTT message.
That's enough for now.
We'll look at the Listener class next. This class has the method that Esper will call when it finds a match for your events in the event stream.