Re-testing Blossom driver and enabling driver with sudo to be able to use system...
[iot2.git] / benchmarks / drivers / Java / BlossomSprinkler / BlossomSprinkler.java
1 package iotcode.BlossomSprinkler;
2
3 // Java Standard Packages
4 import java.util.concurrent.Semaphore;
5 import java.io.InputStreamReader;
6 import java.io.BufferedReader;
7 import java.io.PrintWriter;
8 import java.io.ByteArrayInputStream;
9 import java.util.List;
10 import java.util.ArrayList;
11 import java.util.Iterator;
12 import java.util.Date;
13 import java.util.Calendar;
14 import java.text.DateFormat;
15 import java.text.SimpleDateFormat;
16 import java.util.concurrent.atomic.AtomicBoolean;
17 import java.util.Set;
18 import java.util.HashSet;
19
20 // IoT Packages
21 import iotruntime.IoTTCP;
22 import iotruntime.IoTServerSocket;
23 import iotruntime.slave.IoTDeviceAddress;
24 import iotruntime.slave.IoTSet;
25 import iotcode.annotation.*;
26 import iotcode.interfaces.ZoneState;
27 import iotcode.interfaces.Sprinkler;
28
29 //import iotchecker.qual.*;
30
31 /** Class BlossomSprinkler for the Blossom Sprinkler.
32  *
33  * @author      Ali Younis <ayounis @ uci.edu>
34  * @version     1.0
35  * @since       2016-05-2
36  */
37 public class BlossomSprinkler implements Sprinkler {
38
39     /*******************************************************************************************************************************************
40     **  Constants
41     *******************************************************************************************************************************************/
42     //public static final int NUMBER_OF_ZONES = 12;
43         public static final int NUMBER_OF_ZONES = 1;
44
45     @config IoTSet<IoTDeviceAddress> blossomSprAddressSet;
46     @config IoTSet<IoTDeviceAddress> localAddressSet;
47
48     private IoTDeviceAddress deviceAddress = null;
49     private IoTDeviceAddress localAddress = null;
50     private String channelId = "";
51     private Semaphore zoneStateMutex = new Semaphore(1);
52     private List<ZoneState> zoneStates = new ArrayList<ZoneState>();
53     private AtomicBoolean didEnd = new AtomicBoolean();
54     private boolean didClose = false;
55     private AtomicBoolean didInit = new AtomicBoolean(false);
56
57
58     /*******************************************************************************************************************************************
59     **  Threads
60     *******************************************************************************************************************************************/
61     private Thread workerThread = null;
62     private Thread httpMonitorThread = null;
63
64     public BlossomSprinkler(String _channelId, IoTSet<IoTDeviceAddress> _blossomSprAddressSet, IoTSet<IoTDeviceAddress> _localAddressSet) {
65         this(_channelId);
66                 blossomSprAddressSet = _blossomSprAddressSet;
67                 localAddressSet = _localAddressSet;             
68     }
69
70     public BlossomSprinkler(String _channelId) {
71         channelId = _channelId;
72     }
73
74     public void init() {
75         if (didInit.compareAndSet(false, true) == false) {
76             return; // already init
77         }
78
79         // Get the address from the IoTSet
80         Iterator itr = blossomSprAddressSet.iterator();
81         deviceAddress = (IoTDeviceAddress)itr.next();
82         System.out.println("Device address: " + deviceAddress.getAddress() + ":" + deviceAddress.getSourcePortNumber() + ":" +
83                            deviceAddress.getDestinationPortNumber());
84
85         itr = localAddressSet.iterator();
86         localAddress = (IoTDeviceAddress)itr.next();
87         System.out.println("Local address: " + localAddress.getAddress() + ":" + localAddress.getSourcePortNumber() + ":" +
88                            localAddress.getDestinationPortNumber());
89
90
91         // create the correct number of zones for this controller
92         for (int i = 0; i < NUMBER_OF_ZONES; i++) {
93             //zoneStates.add(new ZoneState(i, false, 0));
94                         ZoneState zTmp = new ZoneState();
95                         zTmp.zoneNumber = i;
96                         zTmp.onOffState = false;
97                         zTmp.duration = 0;
98             zoneStates.add(zTmp);
99         }
100
101         // Launch the worker function in a separate thread.
102         workerThread = new Thread(new Runnable() {
103             public void run() {
104                 workerMethod();
105             }
106         });
107         workerThread.start();
108
109
110         // Launch the http monitor function in a separate thread.
111         httpMonitorThread = new Thread(new Runnable() {
112             public void run() {
113                 httpMonitorMethod();
114             }
115         });
116         httpMonitorThread.start();
117     }
118
119     public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) {
120         try {
121             zoneStateMutex.acquire();
122             for (ZoneState z : zoneStates) {
123                 {
124                     // We replaced methods with fields
125                                 //z.zoneNumber, z.onOffState z.duration
126                     //if (z.getZoneNumber() == _zone) {
127                     if (z.zoneNumber == _zone) {
128
129                         // turn on or off the valve
130                         if (z.onOffState != _onOff) {
131                             z.onOffState = _onOff;
132
133                             if (_onOff) {
134                                 openValue(_zone);
135                             } else {
136                                 closeValue(_zone);
137                             }
138                         }
139
140                         // update the duration if needed
141                         if (z.duration != _onDurationSeconds) {
142                             z.duration = _onDurationSeconds;
143                         }
144
145                         // we found our sprinkler
146                         break;
147                     }
148                 }
149             }
150         } catch (Exception e) {
151             e.printStackTrace();
152         }
153
154         // never forget to unlock
155         zoneStateMutex.release();
156     }
157
158     public List<ZoneState> getZoneStates() {
159
160         // make a copy so that they cannot mess with our list
161         List<ZoneState> retList = new ArrayList<ZoneState>();
162
163         try {
164             zoneStateMutex.acquire();
165             for (ZoneState z : zoneStates) {
166                 ZoneState n = new ZoneState();
167                 n.zoneNumber = z.zoneNumber;
168                 n.onOffState = z.onOffState;
169                 n.duration = z.duration;
170                 retList.add(n);
171             }
172         } catch (Exception e) {
173             e.printStackTrace();
174         }
175
176         // Never forget to release!
177         zoneStateMutex.release();
178         return retList;
179     }
180
181
182     public int getNumberOfZones() {
183         return NUMBER_OF_ZONES;
184     }
185
186     public boolean doesHaveZoneTimers() {
187         return true;
188     }
189
190     public void finalize() {
191         if (!didClose) {
192             endDriver();
193         }
194     }
195
196     /*******************************************************************************************************************************************
197     **
198     **  Helper Methods
199     **
200     *******************************************************************************************************************************************/
201
202     private void workerMethod() {
203                 System.out.println("Get into worker!");
204                 while (didEnd.get() == false) {
205                         //System.out.println("While not end");
206             try {
207                 zoneStateMutex.acquire();
208                 for (ZoneState z : zoneStates) {
209                                         //System.out.println("Iterating on zone: " + z.zoneNumber);
210                     if (z.onOffState) {
211                                                 //System.out.println("Turning on zone: " + z.zoneNumber);
212                                                 //System.out.println("Duration: " + z.duration);
213                         // if on and time has expired then turn off
214                         if (z.duration == 0) {
215
216                             // turn off and reset the zone to the off state parameters
217                             closeValue(z.zoneNumber);
218                             z.onOffState = false;
219                             z.duration = 0;
220                         } else if (z.duration > 0) {
221
222                             // decrement the time
223                             z.duration = z.duration - 1;
224                         }
225                     }
226                 }
227             } catch (Exception e) {
228                 e.printStackTrace();
229             }
230             zoneStateMutex.release();
231
232
233
234             try {
235                 Thread.sleep(1000);
236             } catch (Exception e) {
237                 e.printStackTrace();
238             }
239         }
240     }
241
242
243     private void httpMonitorMethod() {
244
245         try {
246
247             // setup server socket
248             IoTServerSocket serverSock = new IoTServerSocket(localAddress);
249             serverSock.setReuseAddress(true);
250
251
252             while (didEnd.get() == false) {
253
254                 // wait for someone to connect
255                 IoTTCP recSock = serverSock.accept();
256                 recSock.setReuseAddress(true);
257                 System.out.println("got new connection");
258
259                 // open in and out streams
260                 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(recSock.getInputStream()));
261                 PrintWriter tcpOut = new PrintWriter(recSock.getOutputStream());
262
263                 System.out.println("Waiting For Data");
264                 // wait for data to be ready
265                 while (!tcpIn.ready()) {
266                 }
267
268                 // wait a bit longer to get the whole packet
269                 Thread.sleep(10);
270
271                 // put all the lines read into a list so we can read them 1 at a time
272                 List<String> sList = new ArrayList<String>();
273                 while (tcpIn.ready()) {
274                     String s = tcpIn.readLine();
275                     sList.add(s);
276                 }
277
278                 System.out.println("---------------------------------------------------------------------");
279                 System.out.println("---------------------------------------------------------------------");
280                 for (String s : sList) {
281                     System.out.println(s);
282                 }
283
284                 // get first line and check that it is a GET request
285                 String line = sList.get(0);
286                 if (line.startsWith("GET")) {
287
288                     if (!line.contains("firmware-check")) {
289                         // this is an important request to take care of
290
291                         // get the date formatters
292                         DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
293                         DateFormat df2 = new SimpleDateFormat("HH:mm:ss");
294
295                         // make the date
296                         Date today = Calendar.getInstance().getTime();
297                         String reportDate = df1.format(today);
298                         reportDate += "T";
299                         reportDate += df2.format(today);
300
301                         String body = "";
302
303                         // parse the packet and build the body
304                         if (line.contains("/device/v1/server/")) {
305                             body = "{\"stats_freq\": 3600, \"pn_keepalive\": 1, \"uap_debug\": 1, \"wave_boost\": 1, \"ota_freq\": 3600, \"current_time\":\"" + reportDate + "\", \"build\": 1042, \"opn_trip\": 40}";
306                         } else if (line.contains("api") && line.contains("device") && line.contains(channelId)) {
307                             body = "{\"channel\": \"channel_" + channelId + "\", \"current_time\": \"" + reportDate + "\", \"tz_offset\": -8.0, \"tz_seconds\": -28800, \"sch_load_time\": 24900, \"fetch_lead\": 3600}";
308                         }
309
310                         // make the header and send
311                         String response = "HTTP/1.1 200 OK\r\n";
312                         response += "Allow: GET, HEAD, OPTIONS\r\n";
313                         response += "Content-Type: application/json\r\n";
314                         response += "Date: Sun, 08 May 2016 04:20:35 GMT\r\n";
315                         response += "Server: nginx/1.4.6 (Ubuntu)\r\n";
316                         response += "Vary: Accept, Cookie\r\n";
317                         response += "Content-Length: " + body.length() + "\r\n";
318                         // response += "Connection: keep-alive\r\n";
319                         response += "Connection: Close\r\n";
320                         response += "\r\n";
321                         response += body;
322                         tcpOut.print(response);
323                         tcpOut.flush();
324
325                         // System.out.println(response);
326
327                     } else {
328                         // not a request we want to take care of
329
330                         // send 404 error
331                         String response = "HTTP/1.1 404 Not Found\r\n\r\n";
332                         tcpOut.print(response);
333                         tcpOut.flush();
334                     }
335                 }
336
337                 // close the connection
338                 recSock.close();
339             }
340
341             // close the socket
342             serverSock.close();
343         } catch (Exception e) {
344             e.printStackTrace();
345         }
346     }
347
348     private void openValue(int _valveNum) {
349
350         try {
351             String body = "{\"valve\":" + Integer.toString(_valveNum) + ",\"inverter\":1}";
352             String postMessage = "POST /bloom/valve HTTP/1.1\r\n";
353             postMessage += "Content-Type: application/json; charset=utf-8\r\n";
354             postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n";
355             postMessage += "\r\n";
356             postMessage += body;
357
358             IoTTCP connection = new IoTTCP(deviceAddress);
359             connection.setReuseAddress(true);
360
361             // Get in and out communication
362             PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
363             BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
364
365             tcpOut.print(postMessage);
366             tcpOut.flush();
367                         System.out.println("Sent POST message: " + postMessage);
368
369             // wait for data
370             while (!tcpIn.ready()) {
371             }
372
373             // Wait a bit longer for data
374             Thread.sleep(10);
375
376             // get the response
377             while (tcpIn.ready()) {
378                 String answer = tcpIn.readLine();
379                 System.out.println(answer);
380             }
381
382             connection.close();
383         } catch (Exception e) {
384             e.printStackTrace();
385         }
386     }
387
388     private void closeValue(int _valveNum) {
389
390         try {
391             String body = "{\"valve\":" + Integer.toString(_valveNum) + ",\"inverter\":0}";
392             String postMessage = "POST /bloom/valve HTTP/1.1\r\n";
393             postMessage += "Content-Type: application/json; charset=utf-8\r\n";
394             postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n";
395             postMessage += "\r\n";
396             postMessage += body;
397
398
399             IoTTCP connection = new IoTTCP(deviceAddress);
400             connection.setReuseAddress(true);
401
402             // Get in and out communication
403             PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
404             BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
405
406             tcpOut.print(postMessage);
407             tcpOut.flush();
408
409             // wait for data
410             while (!tcpIn.ready()) {
411             }
412
413             // Wait a bit longer for data
414             Thread.sleep(10);
415
416             // get the response
417             while (tcpIn.ready()) {
418                 String answer = tcpIn.readLine();
419                 System.out.println(answer);
420             }
421
422             connection.close();
423         } catch (Exception e) {
424             e.printStackTrace();
425         }
426     }
427
428     private void endDriver() {
429         didClose = true;
430         didEnd.set(true);
431
432         try {
433             workerThread.join();
434             httpMonitorThread.join();
435         } catch (Exception e) {
436             e.printStackTrace();
437         }
438     }
439         
440         /*public static void main(String[] args) throws Exception {
441
442                 System.out.println("Executing main function!");
443                 IoTDeviceAddress iotDevAdd1 = new IoTDeviceAddress("192.168.0.129", 10009, 80, false, false);
444                 IoTDeviceAddress iotDevAdd2 = new IoTDeviceAddress("192.168.0.84", 10010, 80, false, false);
445                 Set<IoTDeviceAddress> setBlossom = new HashSet<IoTDeviceAddress>();
446                 Set<IoTDeviceAddress> setLocal = new HashSet<IoTDeviceAddress>();
447                 setBlossom.add(iotDevAdd1);
448                 setLocal.add(iotDevAdd2);
449                 IoTSet<IoTDeviceAddress> iotsetBlossom = new IoTSet<IoTDeviceAddress>(setBlossom);
450                 IoTSet<IoTDeviceAddress> iotsetLocal = new IoTSet<IoTDeviceAddress>(setLocal);
451                 String channelID = "1bd60b0c-2a99-4c83-8a7d-f97bd3f77a51";
452                 BlossomSprinkler bs = new BlossomSprinkler(channelID, iotsetBlossom, iotsetLocal);
453                 bs.init();
454                 System.out.println("Finished init()");
455                 Thread.sleep(30000);
456                 bs.setZone(0, true, 120);
457                 System.out.println("Finished setZone!");
458
459         }*/
460 }
461
462