1 package iotcode.BlossomSprinkler;
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;
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;
18 // import java.util.HashSet;
19 // import java.util.Set;
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;
30 //import iotchecker.qual.*;
32 /** Class BlossomSprinkler for the Blossom Sprinkler.
34 * @author Ali Younis <ayounis @ uci.edu>
38 public class BlossomSprinkler implements Sprinkler {
40 /*******************************************************************************************************************************************
42 *******************************************************************************************************************************************/
43 public static final int NUMBER_OF_ZONES = 12;
45 @config IoTSet<IoTDeviceAddress> blossomSprAddressSet;
46 @config IoTSet<IoTDeviceAddress> localAddressSet;
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);
58 /*******************************************************************************************************************************************
60 *******************************************************************************************************************************************/
61 private Thread workerThread = null;
62 private Thread httpMonitorThread = null;
65 public BlossomSprinkler(String _channelId) {
66 channelId = _channelId;
70 if (didInit.compareAndSet(false, true) == false) {
71 return; // already init
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());
80 itr = localAddressSet.iterator();
81 localAddress = (IoTDeviceAddress)itr.next();
82 System.out.println("Local address: " + localAddress.getAddress() + ":" + localAddress.getSourcePortNumber() + ":" +
83 localAddress.getDestinationPortNumber());
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();
91 zTmp.onOffState = false;
96 // Launch the worker function in a separate thread.
97 workerThread = new Thread(new Runnable() {
102 workerThread.start();
105 // Launch the http monitor function in a separate thread.
106 httpMonitorThread = new Thread(new Runnable() {
111 httpMonitorThread.start();
114 public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) {
116 zoneStateMutex.acquire();
117 for (ZoneState z : zoneStates) {
119 // We replaced methods with fields
120 //z.zoneNumber, z.onOffState z.duration
121 //if (z.getZoneNumber() == _zone) {
122 if (z.zoneNumber == _zone) {
124 // turn on or off the valve
125 if (z.onOffState != _onOff) {
126 z.onOffState = _onOff;
135 // update the duration if needed
136 if (z.duration != _onDurationSeconds) {
137 z.duration = _onDurationSeconds;
140 // we found our sprinkler
145 } catch (Exception e) {
149 // never forget to unlock
150 zoneStateMutex.release();
153 public List<ZoneState> getZoneStates() {
155 // make a copy so that they cannot mess with our list
156 List<ZoneState> retList = new ArrayList<ZoneState>();
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;
167 } catch (Exception e) {
171 // Never forget to release!
172 zoneStateMutex.release();
177 public int getNumberOfZones() {
178 return NUMBER_OF_ZONES;
181 public boolean doesHaveZoneTimers() {
185 public void finalize() {
191 /*******************************************************************************************************************************************
195 *******************************************************************************************************************************************/
197 private void workerMethod() {
198 while (didEnd.get() == false) {
201 zoneStateMutex.acquire();
202 for (ZoneState z : zoneStates) {
205 // if on and time has expired then turn off
206 if (z.duration == 0) {
208 // turn off and reset the zone to the off state parameters
209 closeValue(z.zoneNumber);
210 z.onOffState = false;
212 } else if (z.duration > 0) {
214 // decrement the time
215 z.duration = z.duration - 1;
219 } catch (Exception e) {
222 zoneStateMutex.release();
228 } catch (Exception e) {
235 private void httpMonitorMethod() {
239 // setup server socket
240 IoTServerSocket serverSock = new IoTServerSocket(localAddress);
241 serverSock.setReuseAddress(true);
244 while (didEnd.get() == false) {
246 // wait for someone to connect
247 IoTTCP recSock = serverSock.accept();
248 recSock.setReuseAddress(true);
249 System.out.println("got new connection");
251 // open in and out streams
252 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(recSock.getInputStream()));
253 PrintWriter tcpOut = new PrintWriter(recSock.getOutputStream());
258 System.out.println("Waiting For Data");
259 // wait for data to be ready
260 while (!tcpIn.ready()) {
263 // wait a bit longer to get the whole packet
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();
273 // System.out.println("---------------------------------------------------------------------");
274 // System.out.println("---------------------------------------------------------------------");
275 // for (String s : sList) {
276 // System.out.println(s);
280 // get first line and check that it is a GET request
281 String line = sList.get(0);
282 if (line.startsWith("GET")) {
284 if (!line.contains("firmware-check")) {
285 // this is an important request to take care of
287 // get the date formatters
288 DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
289 DateFormat df2 = new SimpleDateFormat("HH:mm:ss");
292 Date today = Calendar.getInstance().getTime();
293 String reportDate = df1.format(today);
295 reportDate += df2.format(today);
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}";
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";
318 tcpOut.print(response);
321 // System.out.println(response);
324 // not a request we want to take care of
327 String response = "HTTP/1.1 404 Not Found\r\n\r\n";
328 tcpOut.print(response);
333 // close the connection
339 } catch (Exception e) {
344 private void openValue(int _valveNum) {
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";
354 IoTTCP connection = new IoTTCP(deviceAddress);
355 connection.setReuseAddress(true);
357 // Get in and out communication
358 PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
359 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
361 tcpOut.print(postMessage);
365 while (!tcpIn.ready()) {
368 // Wait a bit longer for data
372 while (tcpIn.ready()) {
373 String answer = tcpIn.readLine();
374 System.out.println(answer);
378 } catch (Exception e) {
383 private void closeValue(int _valveNum) {
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";
394 IoTTCP connection = new IoTTCP(deviceAddress);
395 connection.setReuseAddress(true);
397 // Get in and out communication
398 PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
399 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
401 tcpOut.print(postMessage);
405 while (!tcpIn.ready()) {
408 // Wait a bit longer for data
412 while (tcpIn.ready()) {
413 String answer = tcpIn.readLine();
414 System.out.println(answer);
418 } catch (Exception e) {
423 private void endDriver() {
429 httpMonitorThread.join();
430 } catch (Exception e) {