Experimenting with reverse engineered TP-link API
authorJanus Varmarken <varmarken@gmail.com>
Fri, 6 Jul 2018 22:19:31 +0000 (15:19 -0700)
committerJanus Varmarken <varmarken@gmail.com>
Fri, 6 Jul 2018 22:37:26 +0000 (15:37 -0700)
16 files changed:
Code/Projects/TplinkPlugClient/.gitignore [new file with mode: 0644]
Code/Projects/TplinkPlugClient/.idea/compiler.xml [new file with mode: 0644]
Code/Projects/TplinkPlugClient/.idea/copyright/profiles_settings.xml [new file with mode: 0644]
Code/Projects/TplinkPlugClient/.idea/modules.xml [new file with mode: 0644]
Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient.iml [new file with mode: 0644]
Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_main.iml [new file with mode: 0644]
Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_test.iml [new file with mode: 0644]
Code/Projects/TplinkPlugClient/build.gradle [new file with mode: 0644]
Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.jar [new file with mode: 0644]
Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.properties [new file with mode: 0644]
Code/Projects/TplinkPlugClient/gradlew [new file with mode: 0755]
Code/Projects/TplinkPlugClient/gradlew.bat [new file with mode: 0644]
Code/Projects/TplinkPlugClient/settings.gradle [new file with mode: 0644]
Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Configuration.java [new file with mode: 0644]
Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Main.java [new file with mode: 0644]
Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/TplinkPlugWanClient.java [new file with mode: 0644]

diff --git a/Code/Projects/TplinkPlugClient/.gitignore b/Code/Projects/TplinkPlugClient/.gitignore
new file mode 100644 (file)
index 0000000..4336e49
--- /dev/null
@@ -0,0 +1,70 @@
+# Borrowed from https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore
+
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+ # JetBrains says not to ignore this one, but it is often inhibitted by a lot of machine specific automatic changes
+.idea/misc.xml
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Janus: Exclude idea artifacts
+.idea/artifacts
+
+# Gradle: (combination of the JetBrains gitiginre and Gradle gitignore at )
+.idea/**/gradle.xml
+.idea/**/libraries
+.gradle
+/build/
+# Ignore Gradle GUI config
+gradle-app.setting
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+# Cache of project
+.gradletasknamecache
+# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
+# gradle/wrapper/gradle-wrapper.properties
+
+# CMake
+cmake-build-debug/
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+#ignore config files as they are user specific and hold login credentials
+src/main/resources/cfg/config.properties
diff --git a/Code/Projects/TplinkPlugClient/.idea/compiler.xml b/Code/Projects/TplinkPlugClient/.idea/compiler.xml
new file mode 100644 (file)
index 0000000..05e1e3d
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Javac" />
+    <resourceExtensions />
+    <wildcardResourcePatterns>
+      <entry name="!?*.java" />
+      <entry name="!?*.form" />
+      <entry name="!?*.class" />
+      <entry name="!?*.groovy" />
+      <entry name="!?*.scala" />
+      <entry name="!?*.flex" />
+      <entry name="!?*.kt" />
+      <entry name="!?*.clj" />
+      <entry name="!?*.aj" />
+    </wildcardResourcePatterns>
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="false">
+        <processorPath useClasspath="true" />
+      </profile>
+    </annotationProcessing>
+    <bytecodeTargetLevel>
+      <module name="TplinkPlugClient_main" target="1.8" />
+      <module name="TplinkPlugClient_test" target="1.8" />
+    </bytecodeTargetLevel>
+  </component>
+</project>
\ No newline at end of file
diff --git a/Code/Projects/TplinkPlugClient/.idea/copyright/profiles_settings.xml b/Code/Projects/TplinkPlugClient/.idea/copyright/profiles_settings.xml
new file mode 100644 (file)
index 0000000..e7bedf3
--- /dev/null
@@ -0,0 +1,3 @@
+<component name="CopyrightManager">
+  <settings default="" />
+</component>
\ No newline at end of file
diff --git a/Code/Projects/TplinkPlugClient/.idea/modules.xml b/Code/Projects/TplinkPlugClient/.idea/modules.xml
new file mode 100644 (file)
index 0000000..b57a14e
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/TplinkPlugClient.iml" filepath="$PROJECT_DIR$/.idea/modules/TplinkPlugClient.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/TplinkPlugClient_main.iml" filepath="$PROJECT_DIR$/.idea/modules/TplinkPlugClient_main.iml" group="TplinkPlugClient" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/modules/TplinkPlugClient_test.iml" filepath="$PROJECT_DIR$/.idea/modules/TplinkPlugClient_test.iml" group="TplinkPlugClient" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient.iml b/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient.iml
new file mode 100644 (file)
index 0000000..39928b5
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id="TplinkPlugClient" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="GRADLE" external.system.module.group="edu.uci.iotproject.tplinkplug" external.system.module.version="1.0-SNAPSHOT" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../..">
+      <excludeFolder url="file://$MODULE_DIR$/../../.gradle" />
+      <excludeFolder url="file://$MODULE_DIR$/../../build" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_main.iml b/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_main.iml
new file mode 100644 (file)
index 0000000..cf8382a
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id="TplinkPlugClient:main" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="GRADLE" external.system.module.group="edu.uci.iotproject.tplinkplug" external.system.module.type="sourceSet" external.system.module.version="1.0-SNAPSHOT" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
+    <output url="file://$MODULE_DIR$/../../build/classes/main" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../../src/main">
+      <sourceFolder url="file://$MODULE_DIR$/../../src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/../../src/main/resources" type="java-resource" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Gradle: com.mashape.unirest:unirest-java:1.4.9" level="project" />
+    <orderEntry type="library" name="Gradle: javax.ws.rs:javax.ws.rs-api:2.1" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpclient:4.5.2" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpasyncclient:4.1.1" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.jersey.core:jersey-client:2.27" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpmime:4.5.2" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.jersey.inject:jersey-hk2:2.27" level="project" />
+    <orderEntry type="library" name="Gradle: org.json:json:20160212" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore:4.4.4" level="project" />
+    <orderEntry type="library" name="Gradle: commons-logging:commons-logging:1.2" level="project" />
+    <orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.9" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore-nio:4.4.4" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.jersey.core:jersey-common:2.27" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2.external:javax.inject:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:hk2-locator:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: javax.annotation:javax.annotation-api:1.2" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:osgi-resource-locator:1.0.1" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:hk2-api:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:hk2-utils:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.javassist:javassist:3.22.0-CR2" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: javax.inject:javax.inject:1" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_test.iml b/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_test.iml
new file mode 100644 (file)
index 0000000..9a19c02
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id="TplinkPlugClient:test" external.linked.project.path="$MODULE_DIR$/../.." external.root.project.path="$MODULE_DIR$/../.." external.system.id="GRADLE" external.system.module.group="edu.uci.iotproject.tplinkplug" external.system.module.type="sourceSet" external.system.module.version="1.0-SNAPSHOT" type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
+    <output-test url="file://$MODULE_DIR$/../../build/classes/test" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/../../src/test">
+      <sourceFolder url="file://$MODULE_DIR$/../../src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/../../src/test/resources" type="java-test-resource" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="TplinkPlugClient_main" />
+    <orderEntry type="library" name="Gradle: com.mashape.unirest:unirest-java:1.4.9" level="project" />
+    <orderEntry type="library" name="Gradle: javax.ws.rs:javax.ws.rs-api:2.1" level="project" />
+    <orderEntry type="library" name="Gradle: junit:junit:4.11" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpclient:4.5.2" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpasyncclient:4.1.1" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.jersey.core:jersey-client:2.27" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpmime:4.5.2" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.jersey.inject:jersey-hk2:2.27" level="project" />
+    <orderEntry type="library" name="Gradle: org.json:json:20160212" level="project" />
+    <orderEntry type="library" name="Gradle: org.hamcrest:hamcrest-core:1.3" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore:4.4.4" level="project" />
+    <orderEntry type="library" name="Gradle: commons-logging:commons-logging:1.2" level="project" />
+    <orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.9" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.jersey.core:jersey-common:2.27" level="project" />
+    <orderEntry type="library" name="Gradle: org.apache.httpcomponents:httpcore-nio:4.4.4" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2.external:javax.inject:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:hk2-locator:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: javax.annotation:javax.annotation-api:1.2" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:osgi-resource-locator:1.0.1" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2.external:aopalliance-repackaged:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:hk2-api:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.glassfish.hk2:hk2-utils:2.5.0-b42" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: org.javassist:javassist:3.22.0-CR2" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Gradle: javax.inject:javax.inject:1" level="project" />
+  </component>
+  <component name="TestModuleProperties" production-module="TplinkPlugClient_main" />
+</module>
\ No newline at end of file
diff --git a/Code/Projects/TplinkPlugClient/build.gradle b/Code/Projects/TplinkPlugClient/build.gradle
new file mode 100644 (file)
index 0000000..f92f811
--- /dev/null
@@ -0,0 +1,24 @@
+group 'edu.uci.iotproject.tplinkplug'
+version '1.0-SNAPSHOT'
+
+apply plugin: 'java'
+apply plugin: 'application'
+
+mainClassName = 'edu.uci.iotproject.tplinkplug.Main'
+
+sourceCompatibility = 1.8
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+
+    compile group: 'com.mashape.unirest', name: 'unirest-java', version: '1.4.9'
+
+    compile group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.1'
+    runtime group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.27'
+    runtime group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27'
+
+    testCompile group: 'junit', name: 'junit', version: '4.11'
+}
diff --git a/Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.jar b/Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.jar
new file mode 100644 (file)
index 0000000..9411448
Binary files /dev/null and b/Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.properties b/Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.properties
new file mode 100644 (file)
index 0000000..7a51471
--- /dev/null
@@ -0,0 +1,6 @@
+#Thu May 31 18:44:49 PDT 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip
diff --git a/Code/Projects/TplinkPlugClient/gradlew b/Code/Projects/TplinkPlugClient/gradlew
new file mode 100755 (executable)
index 0000000..9d82f78
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/Code/Projects/TplinkPlugClient/gradlew.bat b/Code/Projects/TplinkPlugClient/gradlew.bat
new file mode 100644 (file)
index 0000000..aec9973
--- /dev/null
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off\r
+@rem ##########################################################################\r
+@rem\r
+@rem  Gradle startup script for Windows\r
+@rem\r
+@rem ##########################################################################\r
+\r
+@rem Set local scope for the variables with windows NT shell\r
+if "%OS%"=="Windows_NT" setlocal\r
+\r
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
+set DEFAULT_JVM_OPTS=\r
+\r
+set DIRNAME=%~dp0\r
+if "%DIRNAME%" == "" set DIRNAME=.\r
+set APP_BASE_NAME=%~n0\r
+set APP_HOME=%DIRNAME%\r
+\r
+@rem Find java.exe\r
+if defined JAVA_HOME goto findJavaFromJavaHome\r
+\r
+set JAVA_EXE=java.exe\r
+%JAVA_EXE% -version >NUL 2>&1\r
+if "%ERRORLEVEL%" == "0" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:findJavaFromJavaHome\r
+set JAVA_HOME=%JAVA_HOME:"=%\r
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
+\r
+if exist "%JAVA_EXE%" goto init\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:init\r
+@rem Get command-line arguments, handling Windowz variants\r
+\r
+if not "%OS%" == "Windows_NT" goto win9xME_args\r
+if "%@eval[2+2]" == "4" goto 4NT_args\r
+\r
+:win9xME_args\r
+@rem Slurp the command line arguments.\r
+set CMD_LINE_ARGS=\r
+set _SKIP=2\r
+\r
+:win9xME_args_slurp\r
+if "x%~1" == "x" goto execute\r
+\r
+set CMD_LINE_ARGS=%*\r
+goto execute\r
+\r
+:4NT_args\r
+@rem Get arguments from the 4NT Shell from JP Software\r
+set CMD_LINE_ARGS=%$\r
+\r
+:execute\r
+@rem Setup the command line\r
+\r
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
+\r
+@rem Execute Gradle\r
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\r
+\r
+:end\r
+@rem End local scope for the variables with windows NT shell\r
+if "%ERRORLEVEL%"=="0" goto mainEnd\r
+\r
+:fail\r
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
+rem the _cmd.exe /c_ return code!\r
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
+exit /b 1\r
+\r
+:mainEnd\r
+if "%OS%"=="Windows_NT" endlocal\r
+\r
+:omega\r
diff --git a/Code/Projects/TplinkPlugClient/settings.gradle b/Code/Projects/TplinkPlugClient/settings.gradle
new file mode 100644 (file)
index 0000000..8a4dc83
--- /dev/null
@@ -0,0 +1,2 @@
+rootProject.name = 'TplinkPlugClient'
+
diff --git a/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Configuration.java b/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Configuration.java
new file mode 100644 (file)
index 0000000..ba9baa2
--- /dev/null
@@ -0,0 +1,69 @@
+package edu.uci.iotproject.tplinkplug;
+
+import java.io.IOException;
+import java.util.MissingResourceException;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * TODO add class documentation.
+ *
+ * @author Janus Varmarken
+ */
+public class Configuration {
+
+    /**
+     * Name of the file in the resources folder that contains the configuration.
+     */
+    private static final String RESOURCE_FILENAME = "/cfg/config.properties";
+
+    private static final Properties PROPERTIES;
+
+    // ==== Begin keys used in properties file ====
+    private static final String APP_SERVER_URL_KEY = "appServerUrl";
+    private static final String LOGIN_TOKEN_KEY = "token";
+    private static final String DEVICE_ID_KEY = "deviceId";
+    // ===== End keys used in properties file =====
+
+    // ==== Begin cached values of PROPERTIES contents ====
+    private static final String APP_SERVER_URL;
+    private static final String LOGIN_TOKEN;
+    private static final String DEVICE_ID;
+    // ===== End cached values of PROPERTIES contents =====
+
+    static {
+        PROPERTIES = new Properties();
+        try {
+            PROPERTIES.load(Configuration.class.getResourceAsStream(RESOURCE_FILENAME));
+            APP_SERVER_URL = Objects.requireNonNull(PROPERTIES.getProperty(APP_SERVER_URL_KEY, null),
+                    String.format("No value for key '%s' in properties file '%s'", APP_SERVER_URL_KEY, RESOURCE_FILENAME));
+            LOGIN_TOKEN = Objects.requireNonNull(PROPERTIES.getProperty(LOGIN_TOKEN_KEY, null),
+                    String.format("No value for key '%s' in properties file '%s'", LOGIN_TOKEN_KEY, RESOURCE_FILENAME));
+            DEVICE_ID = Objects.requireNonNull(PROPERTIES.getProperty(DEVICE_ID_KEY, null),
+                    String.format("No value for key '%s' in properties file '%s'", DEVICE_ID_KEY, RESOURCE_FILENAME));
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new MissingResourceException(
+                    String.format("Configuration file not found in resources. Missing file: '%s'", RESOURCE_FILENAME),
+                    Configuration.class.getName(),
+                    RESOURCE_FILENAME
+            );
+        }
+    }
+
+    private Configuration() {
+
+    }
+
+    public static String getAppServerUrl() {
+        return APP_SERVER_URL;
+    }
+
+    public static String getLoginToken() {
+        return LOGIN_TOKEN;
+    }
+
+    public static final String getDeviceId() {
+        return DEVICE_ID;
+    }
+}
diff --git a/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Main.java b/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Main.java
new file mode 100644 (file)
index 0000000..7109a41
--- /dev/null
@@ -0,0 +1,63 @@
+package edu.uci.iotproject.tplinkplug;
+
+/**
+ * TODO add class documentation.
+ *
+ * @author Janus Varmarken
+ */
+public class Main {
+
+    public static void main(String[] args) throws InterruptedException {
+        TplinkPlugWanClient client = new TplinkPlugWanClient();
+        int c = 0;
+        while (c < 15) {
+            if (c % 2 == 0) {
+                client.powerOn();
+            }
+            else {
+                client.powerOff();
+            }
+            Thread.sleep(5_000);
+            c++;
+        }
+    }
+
+}
+
+
+// To login, POST following JSON to https://wap.tplinkcloud.com
+// The UUID is generated by the client - possibly used for tracking future logins from the same device?
+// {
+//     "method": "login",
+//     "params": {
+//     "appType": "Kasa_Android",
+//     "cloudUserName": "iotuser22@gmail.com",
+//     "cloudPassword": "Hqeas2tplink",
+//     "terminalUUID": "7e8691de-cf4b-4727-ab31-863b4d4919b4"
+//     }
+// }
+// Login output
+// {"error_code":0,"result":{"accountId":"1619813","regTime":"2017-08-06 06:28:38","email":"iotuser22@gmail.com","token":"a749210e-A9F3yu9IMYGWAepK0KCVNp0"}}
+
+// To get list of devices, POST following JSON to https://wap.tplinkcloud.com?token=TOKEN_FROM_LOGIN_RESPONSE_HERE
+// {"method":"getDeviceList"}
+// getDeviceList output (note that the appServerUrl points to the URL to send device control actions (on/off) to (in this case https://use1-wap.tplinkcloud.com)
+// {"error_code":0,"result":{"deviceList":[{"fwVer":"1.4.3 Build 170504 Rel.144921","deviceName":"Smart Wi-Fi LED Bulb with Color Changing","status":0,"alias":"My_TPLink_LightBulb","deviceType":"IOT.SMARTBULB","appServerUrl":"https://use1-wap.tplinkcloud.com","deviceModel":"LB130(US)","deviceMac":"50C7BF59D584","role":0,"isSameRegion":true,"hwId":"111E35908497A05512E259BB76801E10","fwId":"00000000000000000000000000000000","oemId":"05BF7B3BE1675C5A6867B7A7E4C9F6F7","deviceId":"8012CE834562C3304F4FD28FBFBA86E4185B6843","deviceHwVer":"1.0"},{"fwVer":"1.2.5 Build 171206 Rel.085954","deviceName":"Wi-Fi Smart Plug With Energy Monitoring","status":1,"alias":"My Smart Plug","deviceType":"IOT.SMARTPLUGSWITCH","appServerUrl":"https://use1-wap.tplinkcloud.com","deviceModel":"HS110(US)","deviceMac":"50C7BF331F09","role":0,"isSameRegion":true,"hwId":"60FF6B258734EA6880E186F8C96DDC61","fwId":"00000000000000000000000000000000","oemId":"FFF22CFF774A0B89F7624BFC6F50D5DE","deviceId":"800617CC047187F5251E5B88567ACC6D1819FDCF","deviceHwVer":"1.0"}]}}
+
+
+
+
+//    async set_relay_state(state){
+//        return await super.tplink_request( {"system":{"set_relay_state":{"state": state }}} )
+//    }
+
+// deviceId 800617CC047187F5251E5B88567ACC6D1819FDCF or alias "My Smart Plug" ?
+//    {
+//        "method":"passthrough",
+//        "params": {
+//            "deviceId": "My Smart Plug",
+//            "requestData": {"system":{"set_relay_state":{"state": 0 }}} // 0 for off, 1 for on
+//        }
+//    }
+
+// curl --request POST "https://use1-wap.tplinkcloud.com/?token=a749210e-A9F3yu9IMYGWAepK0KCVNp0 HTTP/1.1" --data '{"method":"passthrough", "params": {"deviceId": "800617CC047187F5251E5B88567ACC6D1819FDCF", "requestData": "{\"system\":{\"set_relay_state\":{\"state\":1}}}" }}' --header "Content-Type: application/json"
\ No newline at end of file
diff --git a/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/TplinkPlugWanClient.java b/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/TplinkPlugWanClient.java
new file mode 100644 (file)
index 0000000..2bf1c6c
--- /dev/null
@@ -0,0 +1,69 @@
+package edu.uci.iotproject.tplinkplug;
+
+import com.mashape.unirest.http.HttpResponse;
+import com.mashape.unirest.http.JsonNode;
+import com.mashape.unirest.http.Unirest;
+import com.mashape.unirest.http.exceptions.UnirestException;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * TODO add class documentation.
+ *
+ * @author Janus Varmarken
+ */
+public class TplinkPlugWanClient {
+
+//    private Client mRestClient = ClientBuilder.newClient();
+
+    public TplinkPlugWanClient() {
+
+    }
+
+    public void powerOn() {
+        System.out.println(String.format("%s.powerOn() invoked", getClass().getSimpleName()));
+        sendRequest(PlugCommand.ON);
+    }
+
+    public void powerOff() {
+        System.out.println(String.format("%s.powerOff() invoked", getClass().getSimpleName()));
+        sendRequest(PlugCommand.OFF);
+    }
+
+    private void sendRequest(PlugCommand plugCommand) {
+
+        String url = String.format("%s/?token=%s", Configuration.getAppServerUrl(), Configuration.getLoginToken());
+        String payload = buildSetRelayStatePayload(plugCommand);
+
+        try {
+            HttpResponse<JsonNode> response = Unirest.post(url).
+                    header("cache-control", "no-cache").
+                    header("Content-Type", MediaType.APPLICATION_JSON).
+                    body(payload).asJson();
+            String debug = null;
+        } catch (UnirestException e) {
+            e.printStackTrace();
+        }
+
+//        Response response = mRestClient.target(url).request(MediaType.APPLICATION_JSON).
+//                header("cache-control", "no-cache").
+//                header("Content-Type", MediaType.APPLICATION_JSON).
+//                post(Entity.text(payload));
+
+        // TODO actually parse the response.
+        String debugPoint = null;
+    }
+
+    private String buildSetRelayStatePayload(PlugCommand command) {
+        return String.format("{ \"method\":\"passthrough\", \"params\": { \"deviceId\": \"%s\", \"requestData\": \"{\\\"system\\\":{\\\"set_relay_state\\\":{\\\"state\\\":%d}}}\"}}",
+                Configuration.getDeviceId(), command.equals(PlugCommand.ON) ? 1 : 0);
+    }
+
+    private static enum PlugCommand {
+        ON, OFF
+    }
+}
\ No newline at end of file