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 ZoneState zTmp = new ZoneState();
95 zTmp.onOffState = false;
100 // Launch the worker function in a separate thread.
101 workerThread = new Thread(new Runnable() {
106 workerThread.start();
109 // Launch the http monitor function in a separate thread.
110 httpMonitorThread = new Thread(new Runnable() {
115 httpMonitorThread.start();
118 public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) {
120 zoneStateMutex.acquire();
121 for (ZoneState z : zoneStates) {
123 // We replaced methods with fields
124 //z.zoneNumber, z.onOffState z.duration
125 if (z.zoneNumber == _zone) {
127 // turn on or off the valve
128 if (z.onOffState != _onOff) {
129 z.onOffState = _onOff;
138 // update the duration if needed
139 if (z.duration != _onDurationSeconds) {
140 z.duration = _onDurationSeconds;
143 // we found our sprinkler
148 } catch (Exception e) {
152 // never forget to unlock
153 zoneStateMutex.release();
156 public List<ZoneState> getZoneStates() {
158 // make a copy so that they cannot mess with our list
159 List<ZoneState> retList = new ArrayList<ZoneState>();
162 zoneStateMutex.acquire();
163 for (ZoneState z : zoneStates) {
164 ZoneState n = new ZoneState();
165 n.zoneNumber = z.zoneNumber;
166 n.onOffState = z.onOffState;
167 n.duration = z.duration;
170 } catch (Exception e) {
174 // Never forget to release!
175 zoneStateMutex.release();
180 public int getNumberOfZones() {
181 return NUMBER_OF_ZONES;
184 public boolean doesHaveZoneTimers() {
188 public void finalize() {
194 /*******************************************************************************************************************************************
198 *******************************************************************************************************************************************/
200 private void workerMethod() {
201 System.out.println("Get into worker!");
202 while (didEnd.get() == false) {
203 //System.out.println("While not end");
205 zoneStateMutex.acquire();
206 for (ZoneState z : zoneStates) {
208 // if on and time has expired then turn off
209 if (z.duration == 0) {
211 // turn off and reset the zone to the off state parameters
212 closeValue(z.zoneNumber);
213 z.onOffState = false;
215 } else if (z.duration > 0) {
217 // decrement the time
218 z.duration = z.duration - 1;
222 } catch (Exception e) {
225 zoneStateMutex.release();
231 } catch (Exception e) {
238 private void httpMonitorMethod() {
242 // setup server socket
243 IoTServerSocket serverSock = new IoTServerSocket(localAddress);
244 serverSock.setReuseAddress(true);
247 while (didEnd.get() == false) {
249 // wait for someone to connect
250 IoTTCP recSock = serverSock.accept();
251 recSock.setReuseAddress(true);
252 System.out.println("got new connection");
254 // open in and out streams
255 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(recSock.getInputStream()));
256 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);
279 // get first line and check that it is a GET request
280 String line = sList.get(0);
281 if (line.startsWith("GET")) {
283 if (!line.contains("firmware-check")) {
284 // this is an important request to take care of
286 // get the date formatters
287 DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
288 DateFormat df2 = new SimpleDateFormat("HH:mm:ss");
291 Date today = Calendar.getInstance().getTime();
292 String reportDate = df1.format(today);
294 reportDate += df2.format(today);
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}";
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";
317 tcpOut.print(response);
320 // System.out.println(response);
323 // not a request we want to take care of
326 String response = "HTTP/1.1 404 Not Found\r\n\r\n";
327 tcpOut.print(response);
332 // close the connection
338 } catch (Exception e) {
343 private void openValue(int _valveNum) {
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";
353 IoTTCP connection = new IoTTCP(deviceAddress);
354 connection.setReuseAddress(true);
356 // Get in and out communication
357 PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
358 BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
360 tcpOut.print(postMessage);
362 System.out.println("Sent POST message: " + 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) {
435 /* TODO: Uncomment this part to do sprinkler test
436 public static void main(String[] args) throws Exception {
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);
452 System.out.println("Finished init()");
453 bs.setZone(0, true, 60);
454 System.out.println("Finished setZone!");