Adding config file for sharing.
[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 /** Class BlossomSprinkler for the Blossom Sprinkler.
30  *
31  * @author      Ali Younis <ayounis @ uci.edu>
32  * @version     1.0
33  * @since       2016-05-2
34  */
35 public class BlossomSprinkler implements Sprinkler {
36
37     /*******************************************************************************************************************************************
38     **  Constants
39     *******************************************************************************************************************************************/
40     //public static final int NUMBER_OF_ZONES = 12;
41     // TODO: We stick to 1 zone for now
42     // Unfortunately Java has a problem of creating struct that it can only declare it as public static.
43     // So having more than 1 zone is not possible with a struct of static variables.
44         public static final int NUMBER_OF_ZONES = 1;
45
46     @config IoTSet<IoTDeviceAddress> blossomSprAddressSet;
47     @config IoTSet<IoTDeviceAddress> localAddressSet;
48
49     private IoTDeviceAddress deviceAddress = null;
50     private IoTDeviceAddress localAddress = null;
51     private String channelId = "";
52     private Semaphore zoneStateMutex = new Semaphore(1);
53     private List<ZoneState> zoneStates = new ArrayList<ZoneState>();
54     private AtomicBoolean didEnd = new AtomicBoolean();
55     private boolean didClose = false;
56     private AtomicBoolean didInit = new AtomicBoolean(false);
57
58
59     /*******************************************************************************************************************************************
60     **  Threads
61     *******************************************************************************************************************************************/
62     private Thread workerThread = null;
63     private Thread httpMonitorThread = null;
64
65     public BlossomSprinkler(String _channelId, IoTSet<IoTDeviceAddress> _blossomSprAddressSet, IoTSet<IoTDeviceAddress> _localAddressSet) {
66         this(_channelId);
67                 blossomSprAddressSet = _blossomSprAddressSet;
68                 localAddressSet = _localAddressSet;             
69     }
70
71     public BlossomSprinkler(String _channelId) {
72         channelId = _channelId;
73     }
74
75     public void init() {
76         if (didInit.compareAndSet(false, true) == false) {
77             return; // already init
78         }
79
80         // Get the address from the IoTSet
81         Iterator itr = blossomSprAddressSet.iterator();
82         deviceAddress = (IoTDeviceAddress)itr.next();
83         System.out.println("Device address: " + deviceAddress.getAddress() + ":" + deviceAddress.getSourcePortNumber() + ":" +
84                            deviceAddress.getDestinationPortNumber());
85
86         itr = localAddressSet.iterator();
87         localAddress = (IoTDeviceAddress)itr.next();
88         System.out.println("Local address: " + localAddress.getAddress() + ":" + localAddress.getSourcePortNumber() + ":" +
89                            localAddress.getDestinationPortNumber());
90
91
92         // create the correct number of zones for this controller
93         for (int i = 0; i < NUMBER_OF_ZONES; i++) {
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.zoneNumber == _zone) {
127
128                         // turn on or off the valve
129                         if (z.onOffState != _onOff) {
130                             z.onOffState = _onOff;
131
132                             if (_onOff) {
133                                 openValue(_zone);
134                             } else {
135                                 closeValue(_zone);
136                             }
137                         }
138
139                         // update the duration if needed
140                         if (z.duration != _onDurationSeconds) {
141                             z.duration = _onDurationSeconds;
142                         }
143
144                         // we found our sprinkler
145                         break;
146                     }
147                 }
148             }
149         } catch (Exception e) {
150             e.printStackTrace();
151         }
152
153         // never forget to unlock
154         zoneStateMutex.release();
155     }
156
157     public List<ZoneState> getZoneStates() {
158
159         // make a copy so that they cannot mess with our list
160         List<ZoneState> retList = new ArrayList<ZoneState>();
161
162         try {
163             zoneStateMutex.acquire();
164             for (ZoneState z : zoneStates) {
165                 ZoneState n = new ZoneState();
166                 n.zoneNumber = z.zoneNumber;
167                 n.onOffState = z.onOffState;
168                 n.duration = z.duration;
169                 retList.add(n);
170             }
171         } catch (Exception e) {
172             e.printStackTrace();
173         }
174
175         // Never forget to release!
176         zoneStateMutex.release();
177         return retList;
178     }
179
180
181     public int getNumberOfZones() {
182         return NUMBER_OF_ZONES;
183     }
184
185     public boolean doesHaveZoneTimers() {
186         return true;
187     }
188
189     public void finalize() {
190         if (!didClose) {
191             endDriver();
192         }
193     }
194
195     /*******************************************************************************************************************************************
196     **
197     **  Helper Methods
198     **
199     *******************************************************************************************************************************************/
200
201     private void workerMethod() {
202                 System.out.println("Get into worker!");
203                 while (didEnd.get() == false) {
204             try {
205                 zoneStateMutex.acquire();
206                 for (ZoneState z : zoneStates) {
207                     if (z.onOffState) {
208                         // if on and time has expired then turn off
209                         if (z.duration == 0) {
210
211                             // turn off and reset the zone to the off state parameters
212                             closeValue(z.zoneNumber);
213                             z.onOffState = false;
214                             z.duration = 0;
215                         } else if (z.duration > 0) {
216
217                             // decrement the time
218                             z.duration = z.duration - 1;
219                         }
220                     }
221                 }
222             } catch (Exception e) {
223                 e.printStackTrace();
224             }
225             zoneStateMutex.release();
226
227
228
229             try {
230                 Thread.sleep(1000);
231             } catch (Exception e) {
232                 e.printStackTrace();
233             }
234         }
235     }
236
237
238     private void httpMonitorMethod() {
239
240         try {
241
242             // setup server socket
243             IoTServerSocket serverSock = new IoTServerSocket(localAddress);
244             serverSock.setReuseAddress(true);
245
246
247             while (didEnd.get() == false) {
248
249                 // wait for someone to connect
250                 IoTTCP recSock = serverSock.accept();
251                 recSock.setReuseAddress(true);
252                 System.out.println("got new connection");
253
254                 // open in and out streams
255                 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(recSock.getInputStream()));
256                 PrintWriter tcpOut = new PrintWriter(recSock.getOutputStream());
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                 // get first line and check that it is a GET request
280                 String line = sList.get(0);
281                 if (line.startsWith("GET")) {
282
283                     if (!line.contains("firmware-check")) {
284                         // this is an important request to take care of
285
286                         // get the date formatters
287                         DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
288                         DateFormat df2 = new SimpleDateFormat("HH:mm:ss");
289
290                         // make the date
291                         Date today = Calendar.getInstance().getTime();
292                         String reportDate = df1.format(today);
293                         reportDate += "T";
294                         reportDate += df2.format(today);
295
296                         String body = "";
297
298                         // parse the packet and build the body
299                         if (line.contains("/device/v1/server/")) {
300                             body = "{\"stats_freq\": 3600, \"pn_keepalive\": 1, \"uap_debug\": 1, \"wave_boost\": 1, \"ota_freq\": 3600, \"current_time\":\"" + reportDate + "\", \"build\": 1042, \"opn_trip\": 40}";
301                         } else if (line.contains("api") && line.contains("device") && line.contains(channelId)) {
302                             body = "{\"channel\": \"channel_" + channelId + "\", \"current_time\": \"" + reportDate + "\", \"tz_offset\": -8.0, \"tz_seconds\": -28800, \"sch_load_time\": 24900, \"fetch_lead\": 3600}";
303                         }
304
305                         // make the header and send
306                         String response = "HTTP/1.1 200 OK\r\n";
307                         response += "Allow: GET, HEAD, OPTIONS\r\n";
308                         response += "Content-Type: application/json\r\n";
309                         response += "Date: Sun, 08 May 2016 04:20:35 GMT\r\n";
310                         response += "Server: nginx/1.4.6 (Ubuntu)\r\n";
311                         response += "Vary: Accept, Cookie\r\n";
312                         response += "Content-Length: " + body.length() + "\r\n";
313                         // response += "Connection: keep-alive\r\n";
314                         response += "Connection: Close\r\n";
315                         response += "\r\n";
316                         response += body;
317                         tcpOut.print(response);
318                         tcpOut.flush();
319
320                         // System.out.println(response);
321
322                     } else {
323                         // not a request we want to take care of
324
325                         // send 404 error
326                         String response = "HTTP/1.1 404 Not Found\r\n\r\n";
327                         tcpOut.print(response);
328                         tcpOut.flush();
329                     }
330                 }
331
332                 // close the connection
333                 recSock.close();
334             }
335
336             // close the socket
337             serverSock.close();
338         } catch (Exception e) {
339             e.printStackTrace();
340         }
341     }
342
343     private void openValue(int _valveNum) {
344
345         try {
346             String body = "{\"valve\":" + Integer.toString(_valveNum) + ",\"inverter\":1}";
347             String postMessage = "POST /bloom/valve HTTP/1.1\r\n";
348             postMessage += "Content-Type: application/json; charset=utf-8\r\n";
349             postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n";
350             postMessage += "\r\n";
351             postMessage += body;
352
353             IoTTCP connection = new IoTTCP(deviceAddress);
354             connection.setReuseAddress(true);
355
356             // Get in and out communication
357             PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
358             BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
359
360             tcpOut.print(postMessage);
361             tcpOut.flush();
362                         System.out.println("Sent POST message: " + postMessage);
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         /* TODO: Uncomment this part to do sprinkler test
436         public static void main(String[] args) throws Exception {
437
438                 System.out.println("Executing main function!");
439                 //IoTDeviceAddress iotDevAdd1 = new IoTDeviceAddress("192.168.0.129", 10009, 80, false, false);
440                 //IoTDeviceAddress iotDevAdd2 = new IoTDeviceAddress("192.168.0.84", 10010, 80, false, false);
441                 IoTDeviceAddress iotDevAdd1 = new IoTDeviceAddress(args[0], 10009, 80, false, false);
442                 IoTDeviceAddress iotDevAdd2 = new IoTDeviceAddress(args[1], 10010, 80, false, false);           
443                 Set<IoTDeviceAddress> setBlossom = new HashSet<IoTDeviceAddress>();
444                 Set<IoTDeviceAddress> setLocal = new HashSet<IoTDeviceAddress>();
445                 setBlossom.add(iotDevAdd1);
446                 setLocal.add(iotDevAdd2);
447                 IoTSet<IoTDeviceAddress> iotsetBlossom = new IoTSet<IoTDeviceAddress>(setBlossom);
448                 IoTSet<IoTDeviceAddress> iotsetLocal = new IoTSet<IoTDeviceAddress>(setLocal);
449                 String channelID = "1bd60b0c-2a99-4c83-8a7d-f97bd3f77a51";
450                 BlossomSprinkler bs = new BlossomSprinkler(channelID, iotsetBlossom, iotsetLocal);
451                 bs.init();
452                 System.out.println("Finished init()");
453                 bs.setZone(0, true, 60);
454                 System.out.println("Finished setZone!");
455
456         }*/
457 }
458
459