Adjusting files in ZigbeeTest; preparing things for 4th benchmark, i.e. generating...
[iot2.git] / benchmarks / HomeSecurityController / HomeSecurityController.java
1 package HomeSecurityController;
2
3 // Standard Java Packages
4 import java.util.Date;
5 import java.util.Iterator;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import java.util.HashSet;
12 import java.util.concurrent.atomic.AtomicBoolean;
13 import java.util.concurrent.ConcurrentHashMap;
14
15 // RMI packages
16 import java.rmi.RemoteException;
17 import java.rmi.server.UnicastRemoteObject;
18
19 // IoT Runtime Packages
20 import iotruntime.slave.IoTSet;
21 import iotruntime.slave.IoTRelation;
22 import iotcode.annotation.*;
23
24 // IoT Driver Packages
25 import iotcode.interfaces.*;
26
27 // Checker annotations
28 //import iotchecker.qual.*;
29
30 /** Class Home Security Controller for the home security application benchmark
31  *
32  * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
33  * @version     1.0
34  * @since       2016-12-14
35  */
36 public class HomeSecurityController implements SmartthingsSensorCallback {
37
38         /*
39          *  Constants
40          */
41         private static final int MOTION_TIME_THRESHOLD = 60;    // in seconds
42         private static final int CAMERA_FPS = 15;
43         private static final int CHECK_TIME_WAIT = 1;                   // in seconds
44         private static final int SECOND_TO_TURN_ON = 60;                // in seconds
45
46         /**
47          *  IoT Sets and Relations
48          *  <p>
49          *  Devices involved:
50          *  1) Multipurpose sensor (detect windows open/close) - Smartthings sensor
51          *  2) Motion sensor (detect motion in certain radius) - Smartthings sensor
52          *  3) Water leak sensor (detect leakage) - Smartthings sensor
53          *  4) Camera (detect motion)
54          *  5) Alarm (using ESP board) - assuming 1 house alarm
55          *  6) Room (object as place of device)
56          *
57          *  Additionals (for more extensive home management)
58          *  7) Doorlock (detect open/locked)
59          *  8) Power outlet (detect on/off, monitor watt)
60          */
61         // This comprises multipurpose, motion, and water leak sensors
62         // TODO: Per 01/2017, doorlock and outlet are not ready, ESP board will be used for alarm
63         @config private IoTSet<SmartthingsSensorSmart> smartSensorsSet;
64         @config private IoTSet<CameraSmart> camSet;
65         @config private IoTSet<AlarmSmart> alarmSet;
66         @config private IoTSet<RoomSmart> roomSet;
67         //@config private IoTSet<DoorLock> doorlockSet;
68         //@config private IoTSet<Outlet> outletSet;
69
70         @config private IoTRelation<RoomSmart, SmartthingsSensorSmart> roomSensorRelation;
71         @config private IoTRelation<RoomSmart, CameraSmart> roomCameraRelation;
72         //@config private IoTRelation<RoomSmart, DoorLock> roomDoorLockRelation;
73         //@config private IoTRelation<RoomSmart, Outlet> roomOutletRelation;
74
75         /*******************************************************************************************************************************************
76         **
77         **  Variables
78         **
79         *******************************************************************************************************************************************/
80         long lastTimeChecked = 0;
81
82         private static int sensorId = 0;
83
84         /*******************************************************************************************************************************************
85         **
86         **  States data structures
87         **
88         *******************************************************************************************************************************************/
89         // Camera and motion detection
90         private Map<CameraSmart, MotionDetection> camMotionDetect =
91                 new HashMap<CameraSmart, MotionDetection>();
92         // Smartthings sensors (true = motion, leakage, etc.)
93         private Map<Integer, Boolean> senDetectStatus =
94                 new ConcurrentHashMap<Integer, Boolean>();
95         // Camera (true = motion)
96         private Map<CameraSmart, Boolean> camDetectStatus =
97                 new HashMap<CameraSmart, Boolean>();
98         // Doorlock (true = open - not locked)
99         //private Map<DoorLock, Boolean> doorlockStatus =
100         //      new HashMap<DoorLock, Boolean>();
101         // Outlet (true = on - outlet is used)
102         //private Map<Outlet, Boolean> outletStatus =
103         //      new HashMap<Outlet, Boolean>();
104
105         // Alarm status
106         private Map<Integer, Boolean> alarmStatus =
107                 new HashMap<Integer, Boolean>();
108
109         public HomeSecurityController() {
110
111         }
112
113
114         /*******************************************************************************************************************************************
115         **
116         **  Helper Methods
117         **
118         *******************************************************************************************************************************************/
119
120
121         /** Method to initialize Smartthings sensors
122          *
123          *   @return [void] None.
124          */
125         private void initSmartthingsSensors(RoomSmart rm) {
126
127                 // Get and init the IAS sensors for this specific room
128                 HashSet<SmartthingsSensorSmart> sensors = roomSensorRelation.get(rm);
129                 for (SmartthingsSensorSmart sen : sensors) {
130         
131                         try {
132                                 // Initialize sensors
133                                 sen.init();
134                                 sen.setId(sensorId++);
135                                 System.out.println("DEBUG: Initialized smartthings sensor!");
136                         } catch (Exception e) {
137                                 e.printStackTrace();
138                         }
139                 }
140         }
141
142
143         /** Method to initialize cameras
144          *
145          *   @return [void] None.
146          */
147         private void initCameras(RoomSmart rm) {
148
149                 // Get and init the cameras for this specific room
150                 HashSet<CameraSmart> cameras = roomCameraRelation.get(rm);
151                 // Setup the cameras, start them all and assign each one a motion detector
152                 for (CameraSmart cam : camSet.values()) {
153
154                         // Each camera will have a motion detector unique to it since the motion detection has state
155                         MotionDetection mo = new MotionDetection(12, 0.5f, 10, 10);
156
157                         // initialize the camera, might need to setup some stuff internally
158                         cam.init();
159
160                         // set the camera parameters.
161                         cam.setFPS(CAMERA_FPS);
162                         cam.setResolution(Resolution.RES_VGA);
163
164                         // camera will call the motion detector directly with data not this controller
165                         cam.registerCallback(mo);
166
167                         // Start the camera (example is start the HTTP stream if it is a network camera)
168                         cam.start();
169                         System.out.println("DEBUG: Initialized camera!");
170
171                         // Remember which motion detector is for what camera
172                         camMotionDetect.put(cam, mo);
173                 }
174         }
175
176
177         /** Method to initialize alarms
178          *
179          *   @return [void] None.
180          */
181         private void initAlarms() {
182
183                 // Get and init the alarm (this single alarm set can serve multiple zones / rooms)
184                 Iterator alarmIt = alarmSet.iterator();
185                 AlarmSmart alm = (AlarmSmart) alarmIt.next();
186                 // init the alarm controller, do it here since it only needs to be done once per controller
187                 try {
188                         alm.init();
189                         System.out.println("DEBUG: Initialized alarm!");
190                 } catch (Exception e) {
191                         e.printStackTrace();
192                 }
193         }
194
195
196         /** Method to initialize doorlocks
197          *
198          *   @return [void] None.
199          */
200         private void initDoorLocks(RoomSmart rm) {
201
202                 // Get and init the doorlocks for this specific room
203                 /*HashSet<DoorLock> doorlocks = roomDoorLockRelation.get(rm);
204                 for (DoorLock doorlock : doorlocks) {
205         
206                         try {
207                                 // Initialize doorlocks
208                                 doorlock.init();
209                                 System.out.println("DEBUG: Initialized doorlock!");
210                         } catch (Exception e) {
211                                 e.printStackTrace();
212                         }
213                 }*/
214         }
215
216
217         /** Method to initialize power outlets
218          *
219          *   @return [void] None.
220          */
221         private void initOutlets(RoomSmart rm) {
222
223                 // Get and init the outlets for this specific room
224                 /*HashSet<Outlet> outlets = roomOutletRelation.get(rm);
225                 for (Outlet outlet : outlets) {
226         
227                         try {
228                                 // Initialize outlets
229                                 outlet.init();
230                                 System.out.println("DEBUG: Initialized outlet!");
231                         } catch (Exception e) {
232                                 e.printStackTrace();
233                         }
234                 }*/
235         }
236
237
238         /** Method to detect if a room has seen motion within the last few seconds (time specified as parameter).
239          *   Checks all the motion detectors for the given room
240          *
241          *   @param _room            [RoomSmart] , Room of interest.
242          *   @param _numberOfSeconds [int]  , Number of seconds in the past that we consider recent.
243          *   @param _upperThreshold  [int]  , Number of seconds as an upper bound before we turn off.
244          *
245          *   @return [void] None.
246          */
247         private void updateCameraStatus(RoomSmart _room, int _numberOfSeconds) {
248                 long currentTimeSeconds = (new Date()).getTime() / 1000;
249
250                 // Loop through all the cameras in the room
251                 for (CameraSmart cam : roomCameraRelation.get(_room)) {
252                         long lastDetectedMotionSeconds = currentTimeSeconds;
253
254                         Date motionTime = ((MotionDetection)camMotionDetect.get(cam)).getTimestampOfLastMotion();
255
256                         // Motion was detected at least once
257                         if (motionTime != null) {
258                                 lastDetectedMotionSeconds = motionTime.getTime() / 1000;
259                         } else {
260                                 // motionTime == null means this is the initialization phase
261                                 // so we put false
262                                 camDetectStatus.put(cam, false);
263                         }
264
265                         // Did detect motion recently
266                         if (Math.abs(currentTimeSeconds - lastDetectedMotionSeconds) < _numberOfSeconds) {
267                                 camDetectStatus.put(cam, true);
268                         }
269                 }
270         }
271
272
273         /** Method to update state data structures for Smartthings sensors
274          *
275          *   @return [void] None.
276          */
277         public void newReadingAvailable(int _sensorId, int _value, boolean _activeValue) {
278
279                 System.out.println("DEBUG: Sensor reading value: " + _value);
280                 if(_activeValue) {
281
282                         senDetectStatus.put(_sensorId, true);
283
284                 } else {
285
286                         senDetectStatus.put(_sensorId, false);
287                 } 
288         }
289
290
291         /** Method to update state data structures for doorlocks
292          *
293          *   @return [void] None.
294          */
295         private void updateDoorLockStatus(RoomSmart rm) {
296
297                 // Get and init the outlets for this specific room
298                 /*HashSet<DoorLock> doorlocks = roomDoorLockRelation.get(rm);
299                 for (DoorLock doorlock : doorlocks) {
300         
301                         // Change is detected! Set to true for report...
302                         if(isChangeDetected()) {
303
304                                 doorlockStatus.put(doorlock, true);
305                         } else {
306
307                                 doorlockStatus.put(doorlock, false);
308                         }
309                 }*/
310         }
311
312
313         /** Method to update state data structures for outlets
314          *
315          *   @return [void] None.
316          */
317         private void updateOutletStatus(RoomSmart rm) {
318
319                 // Get and init the outlets for this specific room
320                 /*HashSet<Outlet> outlets = roomOutletRelation.get(rm);
321                 for (Outlet outlet : outlets) {
322         
323                         // Change is detected! Set to true for report...
324                         if(isChangeDetected()) {
325
326                                 outletStatus.put(outlet, true);
327                         } else {
328
329                                 outletStatus.put(outlet, false);
330                         }
331                 }*/
332         }
333
334
335         /** Update the status of all devices
336          *
337          *   @return [void] None.
338          */
339         private void updateUniversalStatus() {
340
341                 // Check for motion in rooms and if there is motion then report
342                 for (RoomSmart room : roomSet.values()) {
343
344                         // Update status of camera
345                         updateCameraStatus(room, MOTION_TIME_THRESHOLD);
346
347                         // Update status of doorlocks
348                         //updateDoorLockStatus(room);
349
350                         // Update status of outlets
351                         //updateOutletStatus(room);
352                 }
353         }
354
355
356         /** Method to turn on alarms
357          *
358          *   @return [void] None.
359          */
360         private void turnOnAlarms(int zoneId) {
361
362                 // Get and init the alarm (this single alarm set can serve multiple zones / rooms)
363                 Iterator alarmIt = alarmSet.iterator();
364                 AlarmSmart alm = (AlarmSmart) alarmIt.next();
365                 alm.setZone(zoneId, true, SECOND_TO_TURN_ON);
366         }
367
368
369         /** Method to turn off alarms
370          *
371          *   @return [void] None.
372          */
373         private void turnOffAlarms(int zoneId) {
374
375                 // Get and init the alarm (this single alarm set can serve multiple zones / rooms)
376                 Iterator alarmIt = alarmSet.iterator();
377                 AlarmSmart alm = (AlarmSmart) alarmIt.next();
378                 // Turn this alarm off indefinitely
379                 alm.setZone(zoneId, false, -1);
380         }
381
382
383         /** Check status of devices and turn on alarm accordingly
384          *  <p>
385          *  Simple rule is whenever any sensor or camera detect something unusual
386          *      (sensor/camera becomes active) then we sound the corresponding alarm.
387          *  This means we send the signal to the right zone in the EspAlarm
388          *
389          *   @return [void] None.
390          */
391         private void decideToTurnOnAlarm() {
392
393                 int zoneId = 0;
394
395                 // Check for motion in rooms and if there is motion then report
396                 for (RoomSmart room : roomSet.values()) {
397
398                         // Loop through all the cameras in the room
399                         for (CameraSmart cam : roomCameraRelation.get(room)) {
400
401                                 // Get the right camera and the right detection status (true or false)
402                                 if (camDetectStatus.get(cam)) {
403                                         zoneId = room.getRoomID();
404                                         turnOnAlarms(zoneId);
405                                         System.out.println("DETECTION: Camera active in room: " + zoneId);
406                                 }
407                         }
408
409                         // Loop through all the cameras in the room
410                         for (SmartthingsSensorSmart sensor : roomSensorRelation.get(room)) {
411
412                                 // Get the right sensor and the right detection status (true or false)
413                                 if (senDetectStatus.get(sensor.getId())) {
414                                         zoneId = room.getRoomID();
415                                         turnOnAlarms(zoneId);
416                                         System.out.println("DETECTION: Sensor active in room: " + zoneId);
417                                 }
418                         }
419                 }
420         }
421
422
423         /** Check status of devices and turn off alarm accordingly
424          *  <p>
425          *  If everything (camera and sensors) is set back to normal
426          *  then the system will turn off the alarm
427          *
428          *   @return [void] None.
429          */
430         // TODO: Need to fix this part later
431         // TODO: Perhaps we should use a phone app to turn off the alarm
432         /*private void decideToTurnOffAlarm() {
433
434                 // Check for motion in rooms and if there is motion then report
435                 for (RoomSmart room : roomSet.values()) {
436
437                         int zoneId = room.getRoomID();
438                         // Loop through all the cameras in the room
439                         for (CameraSmart cam : roomCameraRelation.get(room)) {
440
441                                 // Get the right camera and the right detection status (true or false)
442                                 if (camDetectStatus.get(cam))   // Camera still active so alarm is still on, so false for off-alarm status
443
444                                         alarmStatus.put(zoneId, false);
445
446                                 else
447
448                                         alarmStatus.put(zoneId, true);
449                                 
450                         }
451
452                         // Loop through all the cameras in the room
453                         for (SmartthingsSensor sensor : roomSensorRelation.get(room)) {
454
455                                 // Get the right sensor and the right detection status (true or false)
456                                 if (senDetectStatus.get(sensor.getId()))        // Sensor still active so alarm is still on, so false for off-alarm status
457
458                                         alarmStatus.put(zoneId, false);
459
460                                 else
461
462                                         alarmStatus.put(zoneId, true);
463                         }
464                 }
465
466                 // Turn on alarm in the right zone
467                 for (Map.Entry<Integer, Boolean> alEnt : alarmStatus.entrySet()) {
468                         if (alEnt.getValue())   // if this zone is true, that means we need to turn off its alarm
469                                 turnOffAlarms(alEnt.getKey());
470                 }
471         }*/
472
473
474         /*******************************************************************************************************************************************
475         **
476         **  Public Methods
477         **
478         *******************************************************************************************************************************************/
479
480         /** Initialization method, called by the runtime (effectively the main of the controller)
481          *   This method runs a continuous loop and is blocking
482          *
483          *   @return [void] None;
484          */
485         public void init() {
486
487                 // Iterate over the set of rooms
488                 for (RoomSmart rm : roomSet.values()) {
489
490                         // Init all Smartthings sensors
491                         initSmartthingsSensors(rm);
492
493                         // Init all cameras
494                         initCameras(rm);
495
496                         // Init all doorlocks
497                         //initDoorLocks(rm);
498
499                         // Init all outlets
500                         //initOutlets(rm);
501                 }
502
503                 // Init all alarms
504                 initAlarms();
505
506                 // Run the main loop that will keep checking the sensors and cameras periodically
507                 while (true) {
508
509                         // Run this code every <specified time>
510                         long currentTimeSeconds = (new Date()).getTime() / 1000;
511                         if ((currentTimeSeconds - lastTimeChecked) > CHECK_TIME_WAIT) {
512                                 lastTimeChecked = currentTimeSeconds;
513
514                                 // Update the status of all devices
515                                 updateUniversalStatus();
516
517                                 // Decide to turn on alarm if any of the sensor/camera detects something unusual
518                                 decideToTurnOnAlarm();
519
520                                 // Decide to turn off alarm if every sensor/camera goes back to normal
521                                 //decideToTurnOffAlarm();
522
523                         } else {
524
525                                 try {
526
527                                         Thread.sleep(CHECK_TIME_WAIT * 100); // sleep for a tenth of the time
528
529                                 } catch (Exception e) {
530
531                                         e.printStackTrace();
532                                 }
533                         }
534
535                 }
536         }
537 }
538
539