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;
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;
29 //import iotchecker.qual.*;
31 /** Class BlossomSprinkler for the Blossom Sprinkler.
33 * @author Ali Younis <ayounis @ uci.edu>
37 public class BlossomSprinkler implements Sprinkler {
39 /*******************************************************************************************************************************************
41 *******************************************************************************************************************************************/
42 //public static final int NUMBER_OF_ZONES = 12;
43 public static final int NUMBER_OF_ZONES = 1;
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;
64 public BlossomSprinkler(String _channelId, IoTSet<IoTDeviceAddress> _blossomSprAddressSet, IoTSet<IoTDeviceAddress> _localAddressSet) {
66 blossomSprAddressSet = _blossomSprAddressSet;
67 localAddressSet = _localAddressSet;
70 public BlossomSprinkler(String _channelId) {
71 channelId = _channelId;
75 if (didInit.compareAndSet(false, true) == false) {
76 return; // already init
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());
85 itr = localAddressSet.iterator();
86 localAddress = (IoTDeviceAddress)itr.next();
87 System.out.println("Local address: " + localAddress.getAddress() + ":" + localAddress.getSourcePortNumber() + ":" +
88 localAddress.getDestinationPortNumber());
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();
96 zTmp.onOffState = false;
101 // Launch the worker function in a separate thread.
102 workerThread = new Thread(new Runnable() {
107 workerThread.start();
110 // Launch the http monitor function in a separate thread.
111 httpMonitorThread = new Thread(new Runnable() {
116 httpMonitorThread.start();
119 public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) {
121 zoneStateMutex.acquire();
122 for (ZoneState z : zoneStates) {
124 // We replaced methods with fields
125 //z.zoneNumber, z.onOffState z.duration
126 //if (z.getZoneNumber() == _zone) {
127 if (z.zoneNumber == _zone) {
129 // turn on or off the valve
130 if (z.onOffState != _onOff) {
131 z.onOffState = _onOff;
140 // update the duration if needed
141 if (z.duration != _onDurationSeconds) {
142 z.duration = _onDurationSeconds;
145 // we found our sprinkler
150 } catch (Exception e) {
154 // never forget to unlock
155 zoneStateMutex.release();
158 public List<ZoneState> getZoneStates() {
160 // make a copy so that they cannot mess with our list
161 List<ZoneState> retList = new ArrayList<ZoneState>();
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;
172 } catch (Exception e) {
176 // Never forget to release!
177 zoneStateMutex.release();
182 public int getNumberOfZones() {
183 return NUMBER_OF_ZONES;
186 public boolean doesHaveZoneTimers() {
190 public void finalize() {
196 /*******************************************************************************************************************************************
200 *******************************************************************************************************************************************/
202 private void workerMethod() {
203 System.out.println("Get into worker!");
204 while (didEnd.get() == false) {
205 //System.out.println("While not end");
207 zoneStateMutex.acquire();
208 for (ZoneState z : zoneStates) {
209 //System.out.println("Iterating on zone: " + z.zoneNumber);
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) {
216 // turn off and reset the zone to the off state parameters
217 closeValue(z.zoneNumber);
218 z.onOffState = false;
220 } else if (z.duration > 0) {
222 // decrement the time
223 z.duration = z.duration - 1;
227 } catch (Exception e) {
230 zoneStateMutex.release();
236 } catch (Exception e) {
243 private void httpMonitorMethod() {
247 // setup server socket
248 IoTServerSocket serverSock = new IoTServerSocket(localAddress);
249 serverSock.setReuseAddress(true);
252 while (didEnd.get() == false) {
254 // wait for someone to connect
255 IoTTCP recSock = serverSock.accept();
256 recSock.setReuseAddress(true);
257 System.out.println("got new connection");
259 // open in and out streams
260 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(recSock.getInputStream()));
261 PrintWriter tcpOut = new PrintWriter(recSock.getOutputStream());
263 System.out.println("Waiting For Data");
264 // wait for data to be ready
265 while (!tcpIn.ready()) {
268 // wait a bit longer to get the whole packet
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();
278 System.out.println("---------------------------------------------------------------------");
279 System.out.println("---------------------------------------------------------------------");
280 for (String s : sList) {
281 System.out.println(s);
284 // get first line and check that it is a GET request
285 String line = sList.get(0);
286 if (line.startsWith("GET")) {
288 if (!line.contains("firmware-check")) {
289 // this is an important request to take care of
291 // get the date formatters
292 DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
293 DateFormat df2 = new SimpleDateFormat("HH:mm:ss");
296 Date today = Calendar.getInstance().getTime();
297 String reportDate = df1.format(today);
299 reportDate += df2.format(today);
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}";
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";
322 tcpOut.print(response);
325 // System.out.println(response);
328 // not a request we want to take care of
331 String response = "HTTP/1.1 404 Not Found\r\n\r\n";
332 tcpOut.print(response);
337 // close the connection
343 } catch (Exception e) {
348 private void openValue(int _valveNum) {
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";
358 IoTTCP connection = new IoTTCP(deviceAddress);
359 connection.setReuseAddress(true);
361 // Get in and out communication
362 PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
363 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
365 tcpOut.print(postMessage);
367 System.out.println("Sent POST message: " + postMessage);
370 while (!tcpIn.ready()) {
373 // Wait a bit longer for data
377 while (tcpIn.ready()) {
378 String answer = tcpIn.readLine();
379 System.out.println(answer);
383 } catch (Exception e) {
388 private void closeValue(int _valveNum) {
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";
399 IoTTCP connection = new IoTTCP(deviceAddress);
400 connection.setReuseAddress(true);
402 // Get in and out communication
403 PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
404 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
406 tcpOut.print(postMessage);
410 while (!tcpIn.ready()) {
413 // Wait a bit longer for data
417 while (tcpIn.ready()) {
418 String answer = tcpIn.readLine();
419 System.out.println(answer);
423 } catch (Exception e) {
428 private void endDriver() {
434 httpMonitorThread.join();
435 } catch (Exception e) {
440 /* TODO: Uncomment this part to do sprinkler test
441 public static void main(String[] args) throws Exception {
443 System.out.println("Executing main function!");
444 //IoTDeviceAddress iotDevAdd1 = new IoTDeviceAddress("192.168.0.129", 10009, 80, false, false);
445 //IoTDeviceAddress iotDevAdd2 = new IoTDeviceAddress("192.168.0.84", 10010, 80, false, false);
446 IoTDeviceAddress iotDevAdd1 = new IoTDeviceAddress(args[0], 10009, 80, false, false);
447 IoTDeviceAddress iotDevAdd2 = new IoTDeviceAddress(args[1], 10010, 80, false, false);
448 Set<IoTDeviceAddress> setBlossom = new HashSet<IoTDeviceAddress>();
449 Set<IoTDeviceAddress> setLocal = new HashSet<IoTDeviceAddress>();
450 setBlossom.add(iotDevAdd1);
451 setLocal.add(iotDevAdd2);
452 IoTSet<IoTDeviceAddress> iotsetBlossom = new IoTSet<IoTDeviceAddress>(setBlossom);
453 IoTSet<IoTDeviceAddress> iotsetLocal = new IoTSet<IoTDeviceAddress>(setLocal);
454 String channelID = "1bd60b0c-2a99-4c83-8a7d-f97bd3f77a51";
455 BlossomSprinkler bs = new BlossomSprinkler(channelID, iotsetBlossom, iotsetLocal);
457 System.out.println("Finished init()");
458 bs.setZone(0, true, 60);
459 System.out.println("Finished setZone!");