import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ConcurrentHashMap;
// IoT Runtime Packages
import iotruntime.slave.IoTSet;
import iotruntime.slave.IoTRelation;
+import iotruntime.slave.IoTAddress;
import iotcode.annotation.*;
// IoT Driver Packages
import iotcode.interfaces.*;
-// Checker annotations
-//import iotchecker.qual.*;
+// IoT Cloud
+import iotcloud.*;
/** Class Home Security Controller for the home security application benchmark
*
* @version 1.0
* @since 2016-12-14
*/
-public class HomeSecurityController implements SmartthingsSensorCallback {
+public class HomeSecurityController implements SmartthingsSensorCallback, SmartthingsActuatorCallback {
/*
* Constants
private static final int MOTION_TIME_THRESHOLD = 60; // in seconds
private static final int CAMERA_FPS = 15;
private static final int CHECK_TIME_WAIT = 1; // in seconds
- private static final int SECOND_TO_TURN_ON = 60; // in seconds
+ private static final int SECOND_TO_TURN_ON = -1; // in seconds
private static final int SECOND_TO_TURN_OFF = 1; // in seconds
-
+ private static final int LOCK_DOOR = 0;
+ private static final int UNLOCK_DOOR = 1;
+ // For IoTCloud
+ private static final String BASE_URL = "http://dc-6.calit2.uci.edu/test.iotcloud/";
+ private static final String PASSWORD = "reallysecret";
+ private static final int LOCAL_MACHINE_ID = 399;
+ private static final int LISTENING_PORT = -1; // We don't use any listening port for this application
+
/**
* IoT Sets and Relations
* <p>
* 4) Camera (detect motion)
* 5) Alarm (using ESP board) - assuming 1 house alarm
* 6) Room (object as place of device)
- *
- * Additionals (for more extensive home management)
* 7) Doorlock (detect open/locked)
- * 8) Power outlet (detect on/off, monitor watt)
*/
- // This comprises multipurpose, motion, and water leak sensors
- // TODO: Per 01/2017, doorlock and outlet are not ready, ESP board will be used for alarm
@config private IoTSet<SmartthingsSensorSmart> smartSensorsSet;
@config private IoTSet<CameraSmart> camSet;
@config private IoTSet<AlarmSmart> alarmSet;
@config private IoTSet<RoomSmart> roomSet;
- //@config private IoTSet<DoorLock> doorlockSet;
- //@config private IoTSet<Outlet> outletSet;
+ @config private IoTSet<SmartthingsActuatorSmart> doorlockSet;
+ // Set of addresses for Fidelius connection (dc-6.calit2.uci.edu) to give access
+ @config private IoTSet<IoTAddress> iotcloudServer;
@config private IoTRelation<RoomSmart, SmartthingsSensorSmart> roomSensorRelation;
@config private IoTRelation<RoomSmart, CameraSmart> roomCameraRelation;
//@config private IoTRelation<RoomSmart, DoorLock> roomDoorLockRelation;
- //@config private IoTRelation<RoomSmart, Outlet> roomOutletRelation;
/*******************************************************************************************************************************************
**
long lastTimeChecked = 0;
private static int sensorId = 0;
+ private static int doorlockId = 0;
+ // Initialize values 1 and 0 (for active and not active)
+ private final IoTString ACTIVE = new IoTString("1"); // ACTIVE can mean detecting or being locked for doorlock
+ private final IoTString NOT_ACTIVE = new IoTString("0"); // NOT_ACTIVE can mean not detecting or being unlocked for doorlock
+ private Table t1 = null;
/*******************************************************************************************************************************************
**
new ConcurrentHashMap<Integer, Boolean>();
// Camera (true = motion)
private Map<CameraSmart, Boolean> camDetectStatus =
- new HashMap<CameraSmart, Boolean>();
- // Doorlock (true = open - not locked)
- //private Map<DoorLock, Boolean> doorlockStatus =
- // new HashMap<DoorLock, Boolean>();
- // Outlet (true = on - outlet is used)
- //private Map<Outlet, Boolean> outletStatus =
- // new HashMap<Outlet, Boolean>();
+ new ConcurrentHashMap<CameraSmart, Boolean>();
+ // Doorlock (true = locked)
+ private Map<Integer, Boolean> doorlockStatus =
+ new ConcurrentHashMap<Integer, Boolean>();
// Alarm status
private Map<Integer, Boolean> alarmStatus =
**
*******************************************************************************************************************************************/
+ /** Method to initialize IoTCloud server (dc-6.calit2.uci.edu)
+ *
+ * @return [void] None.
+ */
+ private void initIoTCloudServer() {
+
+ try {
+ System.out.println("DEBUG: Initialize IoTCloud table!");
+ // Get and init the IoTCloud server address
+ // Setup table
+ t1 = new Table(BASE_URL, PASSWORD, LOCAL_MACHINE_ID, LISTENING_PORT);
+ t1.initTable();
+ System.out.println("DEBUG: Table initialized!");
+ // Initialize sensors!
+ int id = 0;
+ // Initialize alarms! One alarm for now
+ for(AlarmSmart alarm : alarmSet.values()) {
+ createKeyIoTCloud("alarm", NOT_ACTIVE);
+ System.out.println("DEBUG: Setting alarm to NOT-ACTIVE!");
+ }
+
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ System.out.println("DEBUG: Cloud server transactions committed successfully!");
+ }
+
+ /** Method to create key IoTCloud
+ *
+ * @param key [String] , encrypted key.
+ * @param val [IoTString] , encrypted value.
+ *
+ * @return [void] None.
+ */
+ private void createKeyIoTCloud(String key, IoTString val) {
+
+ try {
+ IoTString iotKey = new IoTString(key);
+ t1.update();
+ t1.createNewKey(iotKey, LOCAL_MACHINE_ID);
+ t1.startTransaction();
+ t1.addKV(iotKey, val);
+ t1.commitTransaction();
+ t1.update();
+ System.out.println("DEBUG: Successfully committed transaction for: " + key);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /** Method to update IoTCloud
+ *
+ * @param key [String] , encrypted key.
+ * @param val [IoTString] , encrypted value.
+ *
+ * @return [void] None.
+ */
+ private void updateIoTCloud(String key, IoTString val) {
+ // No key creation here!
+ try {
+ IoTString iotKey = new IoTString(key);
+ t1.update();
+ t1.startTransaction();
+ t1.addKV(iotKey, val);
+ t1.commitTransaction();
+ t1.update();
+ System.out.println("DEBUG: Successfully committed transaction for: " + key);
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /** Method to read IoTCloud
+ *
+ * @param key [String] , encrypted key.
+ * @param val [IoTString] , encrypted value.
+ *
+ * @return [boolean] Check if it is ACTIVE or NOT_ACTIVE (true or false).
+ */
+ private boolean readIoTCloud(String key, IoTString iotTestVal) {
+
+ t1.update();
+ IoTString iotKey = new IoTString(key);
+ IoTString iotVal = t1.getCommitted(iotKey);
+
+ // Matching value and test value
+ if ((iotVal != null) && (iotVal.equals(iotTestVal) == true))
+ return true;
+ // Mismatch between value and test value
+ return false;
+ }
/** Method to initialize Smartthings sensors
*
System.out.println("DEBUG: Initialized smartthings sensor! ID: " + sensorId + " Room ID: " + rm.getRoomID());
senDetectStatus.put(sensorId, false);
System.out.println("DEBUG: Initialized sensor detection to false!");
+ System.out.println("DEBUG: Now sensor ID is being set!");
+ // Initialize IoTCloud
sen.setId(sensorId++);
+ System.out.println("DEBUG: Set sensor ID to: " + sensorId + "!");
sen.registerCallback(this);
System.out.println("DEBUG: Registered sensor callback!");
} catch (Exception e) {
*
* @return [void] None.
*/
- private void initCameras(RoomSmart rm) {
+ private void initCameras() {
- // Get and init the IAS sensors for this specific room
- HashSet<CameraSmart> cameras = roomCameraRelation.get(rm);
// Setup the cameras, start them all and assign each one a motion detector
- for (CameraSmart cam : cameras) {
+ for (CameraSmart cam : camSet.values()) {
// Each camera will have a motion detector unique to it since the motion detection has state
MotionDetection mo = new MotionDetection(12, 0.5f, 10, 10);
// Get and init the alarm (this single alarm set can serve multiple zones / rooms)
Iterator alarmIt = alarmSet.iterator();
AlarmSmart alm = (AlarmSmart) alarmIt.next();
- // init the alarm controller, do it here since it only needs to be done once per controller
+ // Initialize the alarm controller, do it here since it only needs to be done once per controller
try {
alm.init();
System.out.println("DEBUG: Initialized alarm!");
- // TODO: Check that this initialization works for multiple times - might be that setZone() only works once!
- //for (RoomSmart room : roomSet.values()) {
- // turnOffAlarms(room.getRoomID());
- // System.out.println("DEBUG: Initialized alarm for room (turn off): " + room.getRoomID());
- //}
} catch (Exception e) {
e.printStackTrace();
}
*
* @return [void] None.
*/
- private void initDoorLocks(RoomSmart rm) {
+ private void initDoorLocks() {
- // Get and init the doorlocks for this specific room
- /*HashSet<DoorLock> doorlocks = roomDoorLockRelation.get(rm);
- for (DoorLock doorlock : doorlocks) {
+ // Get and init the doorlocks (we only assume 1 main doorlock)
+ Set<SmartthingsActuatorSmart> doorlocks = doorlockSet.values();
+ for (SmartthingsActuatorSmart doorlock : doorlocks) {
try {
// Initialize doorlocks
doorlock.init();
- System.out.println("DEBUG: Initialized doorlock!");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }*/
- }
-
-
- /** Method to initialize power outlets
- *
- * @return [void] None.
- */
- private void initOutlets(RoomSmart rm) {
-
- // Get and init the outlets for this specific room
- /*HashSet<Outlet> outlets = roomOutletRelation.get(rm);
- for (Outlet outlet : outlets) {
-
- try {
- // Initialize outlets
- outlet.init();
- System.out.println("DEBUG: Initialized outlet!");
+ System.out.println("DEBUG: Initialized doorlock! ID: " + doorlockId);
+ doorlockStatus.put(doorlockId, false);
+ System.out.println("DEBUG: Initialized doorlock status to false!");
+ doorlock.setId(doorlockId++);
+ doorlock.registerCallback(this);
+ System.out.println("DEBUG: Registered doorlock callback!");
} catch (Exception e) {
e.printStackTrace();
}
- }*/
+ }
}
public void newReadingAvailable(int _sensorId, int _value, boolean _activeValue) {
System.out.println("DEBUG: Sensor reading value: " + _value);
+
+ String sensor = "sensor" + Integer.toString(_sensorId);
if(_activeValue) {
- System.out.println("DEBUG: Sensor is detecting something: " + _activeValue);
+ System.out.println("DEBUG: Sensor " + sensorId + " is detecting something: " + _activeValue);
senDetectStatus.put(_sensorId, true);
-
} else {
- //System.out.println("DEBUG: Sensor is not detecting something: " + _activeValue);
+ System.out.println("DEBUG: Sensor " + sensorId + " is not detecting something: " + _activeValue);
senDetectStatus.put(_sensorId, false);
- }
- }
-
-
- /** Method to update state data structures for doorlocks
- *
- * @return [void] None.
- */
- private void updateDoorLockStatus(RoomSmart rm) {
-
- // Get and init the outlets for this specific room
- /*HashSet<DoorLock> doorlocks = roomDoorLockRelation.get(rm);
- for (DoorLock doorlock : doorlocks) {
-
- // Change is detected! Set to true for report...
- if(isChangeDetected()) {
-
- doorlockStatus.put(doorlock, true);
- } else {
-
- doorlockStatus.put(doorlock, false);
- }
- }*/
+ }
}
-
- /** Method to update state data structures for outlets
+ /** Method to update state data structures for Smartthings actuators
*
* @return [void] None.
*/
- private void updateOutletStatus(RoomSmart rm) {
+ public void newActuatorReadingAvailable(int _sensorId, int _value, boolean _activeValue) {
- // Get and init the outlets for this specific room
- /*HashSet<Outlet> outlets = roomOutletRelation.get(rm);
- for (Outlet outlet : outlets) {
-
- // Change is detected! Set to true for report...
- if(isChangeDetected()) {
+ System.out.println("DEBUG: Actuator " + _sensorId + " reading value: " + _value);
- outletStatus.put(outlet, true);
- } else {
-
- outletStatus.put(outlet, false);
- }
- }*/
+ // Update IoTCloud
+ String actuator = "doorlock" + Integer.toString(_sensorId);
+ if(_activeValue) {
+ System.out.println("DEBUG: Actuator " + _sensorId + " is detecting something: " + _activeValue);
+ doorlockStatus.put(_sensorId, true);
+ } else {
+ //System.out.println("DEBUG: Actuator " + _sensorId + " is not detecting something: " + _activeValue);
+ doorlockStatus.put(_sensorId, false);
+ }
}
// Update status of camera
updateCameraStatus(room);
- // Update status of doorlocks
- //updateDoorLockStatus(room);
-
- // Update status of outlets
- //updateOutletStatus(room);
+ // Update status of other devices if any
+ // ...
}
}
// Motion was detected
System.out.println("DEBUG: Camera detected something!");
- for(CameraSmart cam : cameras)
+ for(CameraSmart cam : cameras) {
camDetectStatus.put(cam, true);
+ }
} else {
// No motion was detected
- //System.out.println("DEBUG: Camera didn't detect anything!");
- for(CameraSmart cam : cameras)
+ System.out.println("DEBUG: Camera didn't detect anything!");
+ for(CameraSmart cam : cameras) {
camDetectStatus.put(cam, false);
+ }
}
}
// Get and init the alarm (this single alarm set can serve multiple zones / rooms)
Iterator alarmIt = alarmSet.iterator();
AlarmSmart alm = (AlarmSmart) alarmIt.next();
- alm.setZone(zoneId, true, SECOND_TO_TURN_OFF);
+ alm.setZone(zoneId, true, SECOND_TO_TURN_ON);
+ updateIoTCloud("alarm", ACTIVE);
}
Iterator alarmIt = alarmSet.iterator();
AlarmSmart alm = (AlarmSmart) alarmIt.next();
// Turn this alarm off indefinitely
- alm.setZone(zoneId, false, SECOND_TO_TURN_ON);
+ alm.setZone(zoneId, false, SECOND_TO_TURN_OFF);
+ updateIoTCloud("alarm", NOT_ACTIVE);
+ }
+
+
+ /** Method to lock doors
+ *
+ * @return [void] None.
+ */
+ private void lockDoors() {
+
+ // Get and lock the doorlocks (we only assume 1 main doorlock)
+ Set<SmartthingsActuatorSmart> doorlocks = doorlockSet.values();
+ for (SmartthingsActuatorSmart doorlock : doorlocks) {
+
+ doorlock.actuate(LOCK_DOOR);
+ int doorId = doorlock.getId();
+ System.out.println("DEBUG: Lock doorlock! ID: " + doorId);
+ doorlockStatus.put(doorId, true);
+ }
}
zoneId = room.getRoomID();
turnOnAlarms(zoneId);
System.out.println("DETECTION: Camera active in room: " + zoneId);
+ lockDoors();
+ while(readIoTCloud("alarm", ACTIVE)) {
+ System.out.println("DETECTION: Now alarm is on so wait here until turned off!");
+ try {
+ Thread.sleep(5000); // sleep for a tenth of the time
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } // Wait until turned off!
+ System.out.println("DETECTION: Now alarm is turned off!");
+ cleanUp();
+ return;
}
}
for (SmartthingsSensorSmart sensor : roomSensorRelation.get(room)) {
// Get the right sensor and the right detection status (true or false)
- //System.out.println("ABOUT TO DETECT: Reading sensor: " + sensor.getId());
if (senDetectStatus.get(sensor.getId())) {
zoneId = room.getRoomID();
turnOnAlarms(zoneId);
System.out.println("DETECTION: Sensor active in room: " + zoneId);
System.out.println("DETECTION: Detection by sensor: " + sensor.getId());
+ lockDoors();
+ while(readIoTCloud("alarm", ACTIVE)) {
+ System.out.println("DETECTION: Now alarm is on so wait here until turned off!");
+ try {
+ Thread.sleep(5000); // sleep for a tenth of the time
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } // Wait until turned off!
+ System.out.println("DETECTION: Now alarm is turned off!");
+ cleanUp();
+ return;
}
}
}
}
- /** Check status of devices and turn off alarm accordingly
+ /** Clean up all status booleans
* <p>
- * If everything (camera and sensors) is set back to normal
- * then the system will turn off the alarm
*
* @return [void] None.
*/
- // TODO: Need to fix this part later
- // TODO: Perhaps we should use a phone app to turn off the alarm
- /*private void decideToTurnOffAlarm() {
+ private void cleanUp() {
- // Check for motion in rooms and if there is motion then report
+ // Clear sensor status
+ for (Boolean senStatus : senDetectStatus.values()) {
+ senStatus = false;
+ }
+ // Clear camera status
+ for (Boolean camStatus : camDetectStatus.values()) {
+ camStatus = false;
+ }
+ // Clear doorlock status
+ for (Boolean doorStatus : doorlockStatus.values()) {
+ doorStatus = false;
+ }
+ // Clear alarm status
+ updateIoTCloud("alarm", NOT_ACTIVE);
+ // Turn off alaarms
for (RoomSmart room : roomSet.values()) {
-
int zoneId = room.getRoomID();
- // Loop through all the cameras in the room
- for (CameraSmart cam : roomCameraRelation.get(room)) {
-
- // Get the right camera and the right detection status (true or false)
- if (camDetectStatus.get(cam)) // Camera still active so alarm is still on, so false for off-alarm status
-
- alarmStatus.put(zoneId, false);
-
- else
-
- alarmStatus.put(zoneId, true);
-
- }
-
- // Loop through all the cameras in the room
- for (SmartthingsSensor sensor : roomSensorRelation.get(room)) {
-
- // Get the right sensor and the right detection status (true or false)
- if (senDetectStatus.get(sensor.getId())) // Sensor still active so alarm is still on, so false for off-alarm status
-
- alarmStatus.put(zoneId, false);
-
- else
-
- alarmStatus.put(zoneId, true);
- }
- }
-
- // Turn on alarm in the right zone
- for (Map.Entry<Integer, Boolean> alEnt : alarmStatus.entrySet()) {
- if (alEnt.getValue()) // if this zone is true, that means we need to turn off its alarm
- turnOffAlarms(alEnt.getKey());
+ turnOffAlarms(zoneId);
}
- }*/
+ }
/*******************************************************************************************************************************************
// Init all Smartthings sensors
initSmartthingsSensors(rm);
-
- // Init all cameras
- initCameras(rm);
-
- // Init all doorlocks
- //initDoorLocks();
-
- // Init all outlets
- //initOutlets();
}
+ // Init all doorlocks
+ initDoorLocks();
// Init all alarms
initAlarms();
+ // Init all cameras
+ initCameras();
+
+ // Initialize IoTCloud server
+ initIoTCloudServer();
+
System.out.println("DEBUG: Initialized all devices! Now starting detection loop!");
// Run the main loop that will keep checking the sensors and cameras periodically
// Decide to turn on alarm if any of the sensor/camera detects something unusual
decideToTurnOnAlarm();
- // Decide to turn off alarm if every sensor/camera goes back to normal
- //decideToTurnOffAlarm();
-
} else {
try {