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