--- /dev/null
+package iotcode.DlinkAlarm;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import iotrmi.Java.IoTRMIComm;
+import iotrmi.Java.IoTRMICommClient;
+import iotrmi.Java.IoTRMICommServer;
+import iotrmi.Java.IoTRMIUtil;
+
+import iotcode.interfaces.*;
+
+public class Alarm_Skeleton implements Alarm {
+
+ private Alarm mainObj;
+ private int objectId = 1;
+ // Communications and synchronizations
+ private IoTRMIComm rmiComm;
+ private AtomicBoolean didAlreadyInitWaitInvoke;
+ private AtomicBoolean methodReceived;
+ private byte[] methodBytes = null;
+ // Permissions
+ private static Integer[] object1Permission = { 4, 2, 0, 1, 3 };
+ private static List<Integer> set1Allowed;
+
+
+ public Alarm_Skeleton(Alarm _mainObj, int _portSend, int _portRecv) throws Exception {
+ mainObj = _mainObj;
+ rmiComm = new IoTRMICommServer(_portSend, _portRecv);
+ set1Allowed = new ArrayList<Integer>(Arrays.asList(object1Permission));
+ IoTRMIUtil.mapSkel.put(_mainObj, this);
+ IoTRMIUtil.mapSkelId.put(_mainObj, objectId);
+ didAlreadyInitWaitInvoke = new AtomicBoolean(false);
+ methodReceived = new AtomicBoolean(false);
+ rmiComm.registerSkeleton(objectId, methodReceived);
+ Thread thread1 = new Thread() {
+ public void run() {
+ try {
+ ___waitRequestInvokeMethod();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ };
+ thread1.start();
+ }
+
+ public Alarm_Skeleton(Alarm _mainObj, IoTRMIComm _rmiComm, int _objectId) throws Exception {
+ mainObj = _mainObj;
+ rmiComm = _rmiComm;
+ objectId = _objectId;
+ set1Allowed = new ArrayList<Integer>(Arrays.asList(object1Permission));
+ didAlreadyInitWaitInvoke = new AtomicBoolean(false);
+ methodReceived = new AtomicBoolean(false);
+ rmiComm.registerSkeleton(objectId, methodReceived);
+ }
+
+ public boolean didAlreadyInitWaitInvoke() {
+ return didAlreadyInitWaitInvoke.get();
+ }
+
+ public void init() {
+ mainObj.init();
+ }
+
+ public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) {
+ mainObj.setZone(_zone, _onOff, _onDurationSeconds);
+ }
+
+ public List<ZoneState> getZoneStates() {
+ return mainObj.getZoneStates();
+ }
+
+ public int getNumberOfZones() {
+ return mainObj.getNumberOfZones();
+ }
+
+ public boolean doesHaveZoneTimers() {
+ return mainObj.doesHaveZoneTimers();
+ }
+
+ public void ___init() {
+ byte[] localMethodBytes = methodBytes;
+ rmiComm.setGetMethodBytes();
+ Object[] paramObj = rmiComm.getMethodParams(new Class<?>[] { }, new Class<?>[] { }, localMethodBytes);
+ init();
+ }
+
+ public void ___setZone() {
+ byte[] localMethodBytes = methodBytes;
+ rmiComm.setGetMethodBytes();
+ Object[] paramObj = rmiComm.getMethodParams(new Class<?>[] { int.class, boolean.class, int.class }, new Class<?>[] { null, null, null }, localMethodBytes);
+ setZone((int) paramObj[0], (boolean) paramObj[1], (int) paramObj[2]);
+ }
+
+ public void ___getZoneStates() throws IOException {
+ byte[] localMethodBytes = methodBytes;
+ rmiComm.setGetMethodBytes();
+ Object[] paramObj = rmiComm.getMethodParams(new Class<?>[] { }, new Class<?>[] { }, localMethodBytes);
+ List<ZoneState> retStruct = getZoneStates();
+ int retLen = retStruct.size();
+ Object retLenObj = retLen;
+ rmiComm.sendReturnObj(retLenObj, localMethodBytes);
+ Class<?>[] retCls = new Class<?>[3*retLen];
+ Object[] retObj = new Object[3*retLen];
+ int retPos = 0;
+ for(int i = 0; i < retLen; i++) {
+ retCls[retPos] = int.class;
+ retObj[retPos++] = retStruct.get(i).zoneNumber;
+ retCls[retPos] = boolean.class;
+ retObj[retPos++] = retStruct.get(i).onOffState;
+ retCls[retPos] = int.class;
+ retObj[retPos++] = retStruct.get(i).duration;
+ }
+ rmiComm.sendReturnObj(retCls, retObj, localMethodBytes);
+ }
+
+ public void ___getNumberOfZones() throws IOException {
+ byte[] localMethodBytes = methodBytes;
+ rmiComm.setGetMethodBytes();
+ Object[] paramObj = rmiComm.getMethodParams(new Class<?>[] { }, new Class<?>[] { }, localMethodBytes);
+ Object retObj = getNumberOfZones();
+ rmiComm.sendReturnObj(retObj, localMethodBytes);
+ }
+
+ public void ___doesHaveZoneTimers() throws IOException {
+ byte[] localMethodBytes = methodBytes;
+ rmiComm.setGetMethodBytes();
+ Object[] paramObj = rmiComm.getMethodParams(new Class<?>[] { }, new Class<?>[] { }, localMethodBytes);
+ Object retObj = doesHaveZoneTimers();
+ rmiComm.sendReturnObj(retObj, localMethodBytes);
+ }
+
+ public void ___waitRequestInvokeMethod() throws IOException {
+ didAlreadyInitWaitInvoke.compareAndSet(false, true);
+ while (true) {
+ if (!methodReceived.get()) {
+ continue;
+ }
+ methodBytes = rmiComm.getMethodBytes();
+ methodReceived.set(false);
+ int _objectId = IoTRMIComm.getObjectId(methodBytes);
+ int methodId = IoTRMIComm.getMethodId(methodBytes);
+ if (_objectId == objectId) {
+ if (!set1Allowed.contains(methodId)) {
+ throw new Error("Object with object Id: " + _objectId + " is not allowed to access method: " + methodId);
+ }
+ }
+ else {
+ continue;
+ }
+ switch (methodId) {
+ case 0:
+ new Thread() {
+ public void run() {
+ try {
+ ___init();
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }.start();
+ break;
+ case 1:
+ new Thread() {
+ public void run() {
+ try {
+ ___setZone();
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }.start();
+ break;
+ case 2:
+ new Thread() {
+ public void run() {
+ try {
+ ___getZoneStates();
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }.start();
+ break;
+ case 3:
+ new Thread() {
+ public void run() {
+ try {
+ ___getNumberOfZones();
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }.start();
+ break;
+ case 4:
+ new Thread() {
+ public void run() {
+ try {
+ ___doesHaveZoneTimers();
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }.start();
+ break;
+ default:
+ throw new Error("Method Id " + methodId + " not recognized!");
+ }
+ }
+ }
+
+}
--- /dev/null
+package iotcode.DlinkAlarm;
+
+// Standard Java Packages
+import java.io.*;
+import java.net.*;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.security.InvalidParameterException;
+import java.util.Date;
+import java.util.Iterator;
+import java.nio.charset.StandardCharsets;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ArrayList;
+
+// HMAC digest packages
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+// IoT Packages
+import iotruntime.IoTTCP;
+import iotruntime.slave.IoTDeviceAddress;
+import iotruntime.slave.IoTSet;
+import iotcode.interfaces.ZoneState;
+import iotcode.interfaces.Alarm;
+
+//import iotchecker.qual.*;
+import iotcode.annotation.*;
+
+/** Class DlinkAlarm for the D-Link Alarm.
+ *
+ * @author Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version 1.0
+ * @since 2017-11-28
+ */
+
+public class DlinkAlarm implements Alarm {
+
+ /*******************************************************************************************************************************************
+ **
+ ** Variables
+ **
+ *******************************************************************************************************************************************/
+ private static final String STR_HMAC_ALGO = "HmacMD5";
+ private static final int INT_ALARM_SOUND_TYPE = 6;
+ private static final int INT_ALARM_VOLUME = 0;
+ private static final int INT_ALARM_MAX_DUR = 86400;
+
+ private String host = null;
+ private String head = null;
+ private String end = null;
+ private IoTDeviceAddress deviceAddress = null;
+ private String devicePin = null;
+ private String response = null;
+ // The following 3 are needed to send commands to the alarm/siren
+ private String cookie = null;
+ private String timeStamp = null;
+ private String privateKey = null;
+
+
+ /*******************************************************************************************************************************************
+ **
+ ** IoT Sets and Relations
+ **
+ *******************************************************************************************************************************************/
+
+ // IoTSet of Device Addresses.
+ // Will be filled with only 1 address.
+ @config private IoTSet<IoTDeviceAddress> alm_Addresses;
+
+ public DlinkAlarm(IoTSet<IoTDeviceAddress> _alm_addr, String _devicePin) {
+ alm_Addresses = _alm_addr;
+ devicePin = _devicePin;
+ }
+
+ public DlinkAlarm(String _devicePin) {
+ devicePin = _devicePin;
+ }
+
+
+ /*******************************************************************************************************************************************
+ **
+ ** Interface Methods
+ **
+ *******************************************************************************************************************************************/
+
+ /** Method to set the state of a specified zone. Interface implementation.
+ *
+ * @param _zone [int] : zone number to set.
+ * @param _onOff [boolean] : the state to set the zone to, on or off.
+ * @param _onDurationSeconds [int]: the duration to set the state on to, if -1 then infinite.
+ *
+ * @return [void] None.
+ */
+ public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) {
+
+ // We don't use zone at this point (for this alarm there is only 1 zone and 1 alarm)
+
+ // True means on
+ if (_onOff) {
+ if ((_onDurationSeconds == -1) || (_onDurationSeconds > 86400)) {
+ // Set alarm on to max duration
+ setSoundPlay(INT_ALARM_SOUND_TYPE, INT_ALARM_VOLUME, INT_ALARM_MAX_DUR);
+ } else {
+ setSoundPlay(INT_ALARM_SOUND_TYPE, INT_ALARM_VOLUME, _onDurationSeconds);
+ }
+ } else { // Else turn off
+ setAlarmDismissed();
+ }
+ }
+
+
+ /** Method to get the current state of all the zones. Interface implementation.
+ *
+ * @param None.
+ *
+ * @return [List<ZoneState>] list of the states for the zones.
+ */
+ public List<ZoneState> getZoneStates() {
+
+ return null;
+ }
+
+
+ /** Method to get the number of zones this alarm can control. Interface implementation.
+ *
+ * @param None.
+ *
+ * @return [int] number of zones that can be controlled.
+ */
+ public int getNumberOfZones() {
+ return 1;
+ }
+
+
+ /** Method to get whether or not this alarm can control durations. Interface implementation.
+ *
+ * @param None.
+ *
+ * @return [boolean] boolean if this sprinkler can do durations.
+ */
+ public boolean doesHaveZoneTimers() {
+ return true;
+ }
+
+
+ /** Method to initialize the alarm. Interface implementation.
+ *
+ * @param None.
+ *
+ * @return [void] None.
+ */
+ public void init() {
+
+ try {
+ Iterator itr = alm_Addresses.iterator();
+ deviceAddress = (IoTDeviceAddress)itr.next();
+ host = deviceAddress.getHostAddress();
+ System.out.println("Address: " + host);
+
+ // Add the head ...
+ head = "<?xml version=\"1.0\" encoding=\"utf-8" +
+ "\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance" +
+ "\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=" +
+ "\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>";
+ // End!
+ end = "</soap:Body></soap:Envelope>\r\n";
+ // Send login request first
+ sendLoginRequest();
+ // Send login info (challenge and HMAC encrypted message)
+ sendLoginInfo();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /*******************************************************************************************************************************************
+ **
+ ** Private Handlers
+ **
+ *******************************************************************************************************************************************/
+
+ private void sendLoginRequest() {
+
+ try {
+ // Message
+ String body = head + "<Login xmlns=\"http://purenetworks.com/HNAP1/" +
+ "\"><Action>request</Action><Username>admin</Username><LoginPassword></LoginPassword><Captcha/></Login>" + end;
+ String postMessage = "POST /HNAP1 HTTP/1.1\r\n";
+ postMessage += "User-Agent: Java/1.8.0_144\r\n";
+ postMessage += "Host: " + host + "\r\n";
+ postMessage += "Accept: */*\r\n";
+ postMessage += "Content-Type: text/xml; charset=utf-8\r\n";
+ postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/Login\"\r\n";
+ postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n";
+ postMessage += "\r\n";
+ postMessage += body;
+
+ // Create the communication channel
+ //IoTTCP connection = new IoTTCP(deviceAddress);
+ IoTTCP connection = new IoTTCP();
+ connection.setReuseAddress(true);
+ connection.bindAndConnect(deviceAddress, false);
+
+ // Get in and out communication
+ System.out.println(postMessage);
+ PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
+ BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+
+ tcpOut.print(postMessage);
+ tcpOut.flush();
+
+ // wait for data
+ while (!tcpIn.ready()) {
+ }
+
+ // Wait a bit longer for data
+ Thread.sleep(10);
+
+ // get the response
+ while (tcpIn.ready()) {
+ response = tcpIn.readLine();
+ System.out.println("Response to Login Request: " + response);
+ }
+ connection.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void sendLoginInfo() {
+
+ // Extract challenge, public key, and cookie
+ String challenge = getTagValue(response, "Challenge");
+ cookie = "Cookie: uid=" + getTagValue(response, "Cookie");
+ String publicKey = getTagValue(response, "PublicKey") + devicePin;
+
+ // Generate private key and password
+ privateKey = hmacDigest(challenge, publicKey, STR_HMAC_ALGO);
+ String password = hmacDigest(challenge, privateKey, STR_HMAC_ALGO);
+ timeStamp = Long.toString(getUnixEpochSeconds());
+ // HNAP authentication
+ String authStr = timeStamp + "\"http://purenetworks.com/HNAP1/Login\"";
+ String auth = hmacDigest(authStr, privateKey, STR_HMAC_ALGO);
+ String hnap_auth = "HNAP_AUTH: " + auth + " " + timeStamp;
+
+ try {
+ // Message
+ String body = head + "<Login xmlns=\"http://purenetworks.com/HNAP1/" +
+ "\"><Action>login</Action><Username>admin</Username><LoginPassword>" +
+ password + "</LoginPassword><Captcha/></Login>" + end;
+ String postMessage = "POST /HNAP1 HTTP/1.1\r\n";
+ postMessage += "User-Agent: Java/1.8.0_144\r\n";
+ postMessage += "Host: " + host + "\r\n";
+ postMessage += "Accept: */*\r\n";
+ postMessage += "Content-Type: text/xml; charset=utf-8\r\n";
+ postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/Login\"\r\n";
+ postMessage += hnap_auth + "\r\n";
+ postMessage += cookie + "\r\n";
+ postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n";
+ postMessage += "\r\n";
+ postMessage += body;
+
+ // Create the communication channel
+ //IoTTCP connection = new IoTTCP(deviceAddress);
+ IoTTCP connection = new IoTTCP();
+ connection.setReuseAddress(true);
+ connection.bindAndConnect(deviceAddress, false);
+
+ // Get in and out communication
+ System.out.println(postMessage);
+ PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
+ BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+
+ tcpOut.print(postMessage);
+ tcpOut.flush();
+
+ // wait for data
+ while (!tcpIn.ready()) {
+ }
+
+ // Wait a bit longer for data
+ //Thread.sleep(10);
+
+ // get the response
+ while (tcpIn.ready()) {
+ response = tcpIn.readLine();
+ System.out.println("Response to Login Info: " + response);
+ }
+ connection.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setSoundPlay(int soundType, int volume, int duration) {
+
+ try {
+ // Message
+ String method = "SetSoundPlay";
+ String body = head + "<" + method + " xmlns=\"http://purenetworks.com/HNAP1/\">" +
+ "<ModuleID>1</ModuleID><Controller>1</Controller><SoundType>" + Integer.toString(soundType) +
+ "</SoundType><Volume>" + Integer.toString(volume) + "</Volume><Duration>" + Integer.toString(duration) +
+ "</Duration></" + method + ">" + end;
+ String postMessage = "POST /HNAP1 HTTP/1.1\r\n";
+ postMessage += "User-Agent: Java/1.8.0_144\r\n";
+ postMessage += "Host: " + host + "\r\n";
+ postMessage += "Accept: */*\r\n";
+ postMessage += "Content-Type: text/xml; charset=utf-8\r\n";
+ postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/" + method + "\"\r\n";
+ // HNAP authentication
+ String authStr = timeStamp + "\"http://purenetworks.com/HNAP1/" + method + "\"";
+ String auth = hmacDigest(authStr, privateKey, STR_HMAC_ALGO);
+ String hnap_auth = "HNAP_AUTH: " + auth + " " + timeStamp;
+ postMessage += hnap_auth + "\r\n";
+ postMessage += cookie + "\r\n";
+ postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n";
+ postMessage += "\r\n";
+ postMessage += body;
+
+ System.out.println(postMessage);
+
+ // Create the communication channel
+ //IoTTCP connection = new IoTTCP(deviceAddress);
+ IoTTCP connection = new IoTTCP();
+ connection.setReuseAddress(true);
+ connection.bindAndConnect(deviceAddress, false);
+
+ // Get in and out communication
+ PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
+ BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+
+ tcpOut.print(postMessage);
+ tcpOut.flush();
+
+ // wait for data
+ while (!tcpIn.ready()) {
+ }
+
+ // Wait a bit longer for data
+ //Thread.sleep(10);
+
+ // get the response
+ while (tcpIn.ready()) {
+ response = tcpIn.readLine();
+ System.out.println("Response to SetSoundPlay: " + response);
+ }
+ connection.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setAlarmDismissed() {
+
+ try {
+ // Message
+ String method = "setAlarmDismissed";
+ String body = head + "<" + method + " xmlns=\"http://purenetworks.com/HNAP1/\">" +
+ "<ModuleID>1</ModuleID><Controller>1</Controller></" + method + ">" + end;
+ String postMessage = "POST /HNAP1 HTTP/1.1\r\n";
+ postMessage += "User-Agent: Java/1.8.0_144\r\n";
+ postMessage += "Host: " + host + "\r\n";
+ postMessage += "Accept: */*\r\n";
+ postMessage += "Content-Type: text/xml; charset=utf-8\r\n";
+ postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/" + method + "\"\r\n";
+ // HNAP authentication
+ String authStr = timeStamp + "\"http://purenetworks.com/HNAP1/" + method + "\"";
+ String auth = hmacDigest(authStr, privateKey, STR_HMAC_ALGO);
+ String hnap_auth = "HNAP_AUTH: " + auth + " " + timeStamp;
+ postMessage += hnap_auth + "\r\n";
+ postMessage += cookie + "\r\n";
+ postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n";
+ postMessage += "\r\n";
+ postMessage += body;
+
+ System.out.println(postMessage);
+
+ // Create the communication channel
+ //IoTTCP connection = new IoTTCP(deviceAddress);
+ IoTTCP connection = new IoTTCP();
+ connection.setReuseAddress(true);
+ connection.bindAndConnect(deviceAddress, false);
+
+ // Get in and out communication
+ PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true);
+ BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+
+ tcpOut.print(postMessage);
+ tcpOut.flush();
+
+ // wait for data
+ while (!tcpIn.ready()) {
+ }
+
+ // Wait a bit longer for data
+ //Thread.sleep(10);
+
+ // get the response
+ while (tcpIn.ready()) {
+ response = tcpIn.readLine();
+ System.out.println("Response to SetSoundPlay: " + response);
+ }
+ connection.close();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // Adapted from https://stackoverflow.com/questions/4076910/how-to-retrieve-element-value-of-xml-using-java
+ private String getTagValue(String xml, String tagName) {
+
+ return xml.split("<"+tagName+">")[1].split("</"+tagName+">")[0];
+ }
+
+ // Adapted from http://www.supermind.org/blog/1102/generating-hmac-md5-sha1-sha256-etc-in-java
+ private String hmacDigest(String message, String keyString, String algorithm) {
+ String digest = null;
+ try {
+ SecretKeySpec key = new SecretKeySpec((keyString).getBytes("UTF-8"), algorithm);
+ Mac mac = Mac.getInstance(algorithm);
+ mac.init(key);
+
+ byte[] bytes = mac.doFinal(message.getBytes("ASCII"));
+
+ // Create a StringBuffer and convert the bytes into a String
+ StringBuffer hash = new StringBuffer();
+ for (int i = 0; i < bytes.length; i++) {
+ String hex = Integer.toHexString(0xFF & bytes[i]);
+ if (hex.length() == 1) {
+ hash.append('0');
+ }
+ hash.append(hex);
+ }
+ // We need to convert the String to upper case
+ digest = hash.toString().toUpperCase();
+ } catch ( UnsupportedEncodingException |
+ InvalidKeyException |
+ NoSuchAlgorithmException e ) {
+ e.printStackTrace();
+ }
+ return digest;
+ }
+
+ private long getUnixEpochSeconds() {
+ // Return time since January 1, 1970 00:00:00 UTC in seconds
+ return System.currentTimeMillis()/1000;
+ }
+
+ /*public static void main(String[] args) throws Exception {
+
+ String ipAddress = "192.168.1.183";
+ String devicePin = "215530";
+ IoTDeviceAddress iotAddress = new IoTDeviceAddress(ipAddress, 12345, 80, false, false);
+ Set<IoTDeviceAddress> setAddress = new HashSet<IoTDeviceAddress>();
+ setAddress.add(iotAddress);
+ IoTSet<IoTDeviceAddress> iotSetAddress = new IoTSet<IoTDeviceAddress>(setAddress);
+
+ DlinkAlarm alarm = new DlinkAlarm(iotSetAddress, devicePin);
+ alarm.init();
+ // Set alarm
+ alarm.setZone(0, true, -1);
+ // Set alarm
+ alarm.setZone(0, false, 0);
+ // Set alarm
+ alarm.setZone(0, true, -1);
+ // Set alarm
+ alarm.setZone(0, false, 0);
+ }*/
+}
+
+
--- /dev/null
+#!/bin/bash
+# modify next two line for your DSP-W215
+IP="192.168.1.183"
+PIN="215530"
+# do not modify after this line if you don't know what you are doing
+
+function usage {
+ echo -e "\nUsage: $(basename $0) [OPTION]"
+ echo -e "\nOPTION:"
+ echo -e "\t--getstate"
+ echo -e "\t--stop"
+ echo -e "\t--noise SoundType(1-6) Volume(0-100) Duration(??)"
+}
+
+function hash_hmac {
+ data="$1"
+ key="$2"
+ echo -n "$data" | openssl dgst "-md5" -hmac "$key" -binary | xxd -ps -u
+}
+
+contentType="Content-Type: text/xml; charset=utf-8"
+soapLogin="SOAPAction: \"http://purenetworks.com/HNAP1/Login\""
+
+#Get Login data
+
+head="<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>"
+end="</soap:Body></soap:Envelope>"
+
+message="<Login xmlns=\"http://purenetworks.com/HNAP1/\"><Action>request</Action><Username>admin</Username><LoginPassword></LoginPassword><Captcha/></Login>"
+loginrequest="$head$message$end"
+#echo "Login request: $loginrequest"
+
+#ret=`curl -s -X POST -H "$contentType" -H "$soapLogin" --data-binary "$loginrequest" http://$IP/HNAP1`
+ret=`curl -v -X POST -H "$contentType" -H "$soapLogin" --data-binary "$loginrequest" http://$IP/HNAP1`
+echo -e "Returned value: $ret"
+
+function getResult {
+ opt=`echo -n "$ret" | grep -Po "(?<=<$1>).*(?=</$1>)"`
+ echo -n "$opt"
+}
+
+#echo -e "Challenge: "
+#echo -e `getResult Challenge`
+
+challenge=`getResult Challenge`
+cookie="Cookie: uid=`getResult Cookie`"
+publickey="`getResult PublicKey`$PIN"
+privatekey=`hash_hmac "$challenge" "$publickey"`
+password=`hash_hmac "$challenge" "$privatekey"`
+timestamp=`date +%s`
+auth_str="$timestamp\"http://purenetworks.com/HNAP1/Login\""
+auth=`hash_hmac "$auth_str" "$privatekey"`
+hnap_auth="HNAP_AUTH: $auth $timestamp"
+
+message="<Login xmlns=\"http://purenetworks.com/HNAP1/\"><Action>login</Action><Username>admin</Username><LoginPassword>$password</LoginPassword><Captcha/></Login>"
+
+login="$head$message$end"
+echo "Login info: $login"
+
+#Get Login Result
+#ret=`curl -s -X POST -H "$contentType" -H "$soapLogin" -H "$hnap_auth" -H "$cookie" --data-binary "$login" http://$IP/HNAP1`
+ret=`curl -v -X POST -H "$contentType" -H "$soapLogin" -H "$hnap_auth" -H "$cookie" --data-binary "$login" http://$IP/HNAP1`
+echo -e "Returned value: $ret"
+
+echo -e "\nUsage: $(basename $0) [OPTION]"
+
+case "$1" in
+--getstate )
+ #Next 2 rows to modify query
+ method="GetSirenAlarmSettings"
+ message="<$method xmlns=\"http://purenetworks.com/HNAP1/\"><ModuleID>1</ModuleID>><Controller>1</Controller></$method>"
+
+ #Do not modify after this line
+ soapAction="SOAPAction: \"http://purenetworks.com/HNAP1/$method\""
+ authStr="$timestamp\"http://purenetworks.com/HNAP1/$method\""
+ auth=`hash_hmac "$authStr" "$privatekey"`
+ hnap_auth="HNAP_AUTH: $auth $timestamp"
+ data="$head$message$end"
+
+ #Get Device state from GetSocketSettings
+ #ret=`curl -s -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1`
+ ret=`curl -v -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1`
+ echo -e "Timestamp=$timestamp\tSOAPAction=$soapAction\tAuthStr=$authStr\tAUTH=$auth\tHNAP=$hnap_auth\tRET = $ret" #This line is for debug purpose
+ ;;
+--noise )
+ #Next 2 rows to modify query
+ method="SetSoundPlay"
+ message="<$method xmlns=\"http://purenetworks.com/HNAP1/\"><ModuleID>1</ModuleID><Controller>1</Controller><SoundType>$2</SoundType><Volume>$3</Volume><Duration>$4</Duration></$method>"
+
+ #Do not modify after this line
+ soapAction="SOAPAction: \"http://purenetworks.com/HNAP1/$method\""
+ authStr="$timestamp\"http://purenetworks.com/HNAP1/$method\""
+ auth=`hash_hmac "$authStr" "$privatekey"`
+ hnap_auth="HNAP_AUTH: $auth $timestamp"
+ data="$head$message$end"
+ echo -e "Sound data: $data"
+
+ #Get Device state from GetSocketSettings
+ #ret=`curl -s -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1`
+ ret=`curl -v -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1`
+ echo -e "Return value: $ret"
+ ;;
+--stop )
+ #Next 2 rows to modify query
+ method="SetAlarmDismissed"
+ message="<$method xmlns=\"http://purenetworks.com/HNAP1/\"><ModuleID>1</ModuleID><Controller>1</Controller></$method>"
+
+ #Do not modify after this line
+ soapAction="SOAPAction: \"http://purenetworks.com/HNAP1/$method\""
+ authStr="$timestamp\"http://purenetworks.com/HNAP1/$method\""
+ auth=`hash_hmac "$authStr" "$privatekey"`
+ hnap_auth="HNAP_AUTH: $auth $timestamp"
+ data="$head$message$end"
+ echo -e "Stop data: $data"
+
+ #Get Device state from GetSocketSettings
+ #ret=`curl -s -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1`
+ ret=`curl -v -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1`
+ ;;
+* )
+ usage
+ ;;
+esac