From: Janus Varmarken Date: Fri, 6 Jul 2018 22:19:31 +0000 (-0700) Subject: Experimenting with reverse engineered TP-link API X-Git-Url: http://plrg.eecs.uci.edu/git/?p=pingpong.git;a=commitdiff_plain;h=d369572f402f46667ea04a5f46aa1927de4ecf9f Experimenting with reverse engineered TP-link API --- diff --git a/Code/Projects/TplinkPlugClient/.gitignore b/Code/Projects/TplinkPlugClient/.gitignore new file mode 100644 index 0000000..4336e49 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/.gitignore @@ -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 index 0000000..05e1e3d --- /dev/null +++ b/Code/Projects/TplinkPlugClient/.idea/compiler.xml @@ -0,0 +1,27 @@ + + + + + \ 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 index 0000000..e7bedf3 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ 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 index 0000000..b57a14e --- /dev/null +++ b/Code/Projects/TplinkPlugClient/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ 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 index 0000000..39928b5 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ 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 index 0000000..cf8382a --- /dev/null +++ b/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_main.iml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 index 0000000..9a19c02 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/.idea/modules/TplinkPlugClient_test.iml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Code/Projects/TplinkPlugClient/build.gradle b/Code/Projects/TplinkPlugClient/build.gradle new file mode 100644 index 0000000..f92f811 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/build.gradle @@ -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 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 index 0000000..7a51471 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/gradle/wrapper/gradle-wrapper.properties @@ -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 index 0000000..9d82f78 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/gradlew @@ -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 index 0000000..aec9973 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Code/Projects/TplinkPlugClient/settings.gradle b/Code/Projects/TplinkPlugClient/settings.gradle new file mode 100644 index 0000000..8a4dc83 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/settings.gradle @@ -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 index 0000000..ba9baa2 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Configuration.java @@ -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 index 0000000..7109a41 --- /dev/null +++ b/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/Main.java @@ -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 index 0000000..2bf1c6c --- /dev/null +++ b/Code/Projects/TplinkPlugClient/src/main/java/edu/uci/iotproject/tplinkplug/TplinkPlugWanClient.java @@ -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 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