diff --git a/.gitignore b/.gitignore
index e699ba2..d1edc6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,5 @@ target/
src/test/java/com/github/realzimboguy/ewelink/api/TestAppPrivate.java
src/test/java/com/github/realzimboguy/ewelink/api/TestApp.java
+
+.idea/
diff --git a/README.md b/README.md
index 43612e8..8ad2533 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,8 @@ You must perform a login before calling any other methods, the methods exposed a
public Status setDeviceStatusByName(String name, String status) throws Exception
public Status setDeviceStatus(String deviceId, String status) throws Exception
+
+ public void getWebSocket(WssResponse wssResponse) throws Exception
sample
@@ -64,6 +66,48 @@ sample
System.out.println(eweLink.getDevice("10009ce53b"));
System.out.println(eweLink.setDeviceStatusByName("Pool Tank","off"));
+
+ eweLink.getWebSocket(new WssResponse() {
+
+ @Override
+ public void onMessage(String s) {
+ //if you want the raw json data
+ System.out.println("on message in test raw:" + s);
+
+ }
+
+ @Override
+ public void onMessageParsed(WssRspMsg rsp) {
+
+ if (rsp.getError() == null) {
+
+ //normal scenario
+ StringBuilder sb = new StringBuilder();
+ sb.append("Device:").append(rsp.getDeviceid()).append(" - ");
+ if (rsp.getParams() != null) {
+ sb.append("Switch:").append(rsp.getParams().getSwitch()).append(" - ");
+ sb.append("Voltage:").append(rsp.getParams().getVoltage()).append(" - ");
+ sb.append("Power:").append(rsp.getParams().getPower()).append(" - ");
+ sb.append("Current:").append(rsp.getParams().getCurrent()).append(" - ");
+ }
+
+ System.out.println(sb.toString());
+
+ } else if (rsp.getError() == 0) {
+ //this is from a login response
+ System.out.println("login success");
+ } else if (rsp.getError() > 0) {
+ System.out.println("login error:" + rsp.toString());
+ }
+ }
+
+ @Override
+ public void onError(String error) {
+ System.out.println("onError in test, this should never be called");
+ System.out.println(error);
+
+ }
+ });
} catch (Exception e) {
diff --git a/pom.xml b/pom.xml
index 991683e..0cfc069 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.github.realzimboguy.ewelink.api
ewelink-api-java
- 2.0.1-RELEASE
+ 2.1.0-RELEASE
jar
ewelink-api-java
@@ -78,6 +78,11 @@
log4j-slf4j-impl
2.7
+
+ org.java-websocket
+ Java-WebSocket
+ 1.5.1
+
@@ -120,6 +125,7 @@
+
org.codehaus.mojo
build-helper-maven-plugin
diff --git a/src/main/java/com/github/realzimboguy/ewelink/api/EweLink.java b/src/main/java/com/github/realzimboguy/ewelink/api/EweLink.java
index 5944dcf..0ad0367 100644
--- a/src/main/java/com/github/realzimboguy/ewelink/api/EweLink.java
+++ b/src/main/java/com/github/realzimboguy/ewelink/api/EweLink.java
@@ -6,6 +6,8 @@
import com.github.realzimboguy.ewelink.api.model.StatusChange;
import com.github.realzimboguy.ewelink.api.model.login.LoginRequest;
import com.github.realzimboguy.ewelink.api.model.login.LoginResponse;
+import com.github.realzimboguy.ewelink.api.wss.WssLogin;
+import com.github.realzimboguy.ewelink.api.wss.WssResponse;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,6 +16,7 @@
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HttpsURLConnection;
import java.io.*;
+import java.net.URI;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@@ -25,12 +28,12 @@ public class EweLink {
Logger logger = LoggerFactory.getLogger(EweLink.class);
- private String region;
+ private static String region;
private String email;
private String password;
private int activityTimer;
private String baseUrl = "https://eu-api.coolkit.cc:8080/api/";
- private static final String APP_ID = "YzfeftUVcZ6twZw1OoVKPRFYTrGEg01Q";
+ public static final String APP_ID = "YzfeftUVcZ6twZw1OoVKPRFYTrGEg01Q";
private static final String APP_SECRET = "4G91qSoboqYO4Y0XJ0LPPKIsq8reHdfa";
private static boolean isLoggedIn = false;
private static long lastActivity = 0L;
@@ -39,8 +42,10 @@ public class EweLink {
private static String accessToken;
private static String apiKey;
+ private static WssResponse clientWssResponse;
-
+ private static EweLinkWebSocketClient eweLinkWebSocketClient = null;
+ private static Thread webSocketMonitorThread = null;
Gson gson = new Gson();
public EweLink(String region,String email, String password, int activityTimer) {
@@ -50,8 +55,8 @@ public EweLink(String region,String email, String password, int activityTimer) {
if (region!= null) {
baseUrl = "https://" + region + "-api.coolkit.cc:8080/api/";
}
- if (activityTimer == 0) {
- activityTimer = 1;
+ if (activityTimer < 30) {
+ activityTimer = 30;
}
this.activityTimer = activityTimer;
@@ -133,6 +138,25 @@ public void login() throws Exception{
}
+ public void getWebSocket(WssResponse wssResponse) throws Exception {
+ if (!isLoggedIn){
+ throw new Exception("Not Logged In, please call login Method");
+ }
+
+ eweLinkWebSocketClient = new EweLinkWebSocketClient(new URI("wss://"+ region+"-pconnect3.coolkit.cc:8080/api/ws"));
+ clientWssResponse = wssResponse;
+ eweLinkWebSocketClient.setWssResponse(clientWssResponse);
+ eweLinkWebSocketClient.setWssLogin(gson.toJson(new WssLogin(accessToken,apiKey,APP_ID,Util.getNonce())));
+ eweLinkWebSocketClient.connect();
+
+ if(webSocketMonitorThread == null) {
+ webSocketMonitorThread = new Thread(new WebSocketMonitor());
+ webSocketMonitorThread.start();
+ }
+
+
+ }
+
public Devices getDevices() throws Exception {
if (!isLoggedIn){
@@ -442,6 +466,42 @@ private static String getAuthMac (String data) throws UnsupportedEncodingExcepti
}
+ public class WebSocketMonitor implements Runnable
+ {
+
+ Logger logger = LoggerFactory.getLogger(WebSocketMonitor.class);
+ Gson gson = new Gson();
+
+
+ @Override
+ public void run() {
+
+ logger.info("Websocket Monitor Thread start");
+
+ while (true) {
+ try {
+ Thread.sleep(30000);
+ logger.debug("send websocket ping");
+ eweLinkWebSocketClient.send("ping");
+
+ } catch (Exception e) {
+ logger.error("Error in sening websocket ping:",e);
+ logger.info("Try reconnect to websocket");
+ try {
+ eweLinkWebSocketClient = new EweLinkWebSocketClient(new URI("wss://"+ region+"-pconnect3.coolkit.cc:8080/api/ws"));
+ eweLinkWebSocketClient.setWssResponse(clientWssResponse);
+ eweLinkWebSocketClient.setWssLogin(gson.toJson(new WssLogin(accessToken,apiKey,APP_ID,Util.getNonce())));
+ eweLinkWebSocketClient.connect();
+
+ }catch (Exception c) {
+ logger.error("Error trying to reconnect:",c);
+ }
+ }
+ }
+ }
+ }
+
+
}
diff --git a/src/main/java/com/github/realzimboguy/ewelink/api/EweLinkWebSocketClient.java b/src/main/java/com/github/realzimboguy/ewelink/api/EweLinkWebSocketClient.java
new file mode 100644
index 0000000..6821ce9
--- /dev/null
+++ b/src/main/java/com/github/realzimboguy/ewelink/api/EweLinkWebSocketClient.java
@@ -0,0 +1,59 @@
+package com.github.realzimboguy.ewelink.api;
+
+import com.github.realzimboguy.ewelink.api.wss.WssLogin;
+import com.github.realzimboguy.ewelink.api.wss.WssResponse;
+import com.github.realzimboguy.ewelink.api.wss.wssrsp.WssRspMsg;
+import com.google.gson.Gson;
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.handshake.ServerHandshake;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+
+public class EweLinkWebSocketClient extends WebSocketClient {
+
+ Logger logger = LoggerFactory.getLogger(EweLinkWebSocketClient.class);
+
+ private WssResponse wssResponse;
+ private String wssLogin;
+ Gson gson = new Gson();
+
+ public void setWssResponse(WssResponse wssResponse) {
+ this.wssResponse = wssResponse;
+ }
+
+ public void setWssLogin(String wssLogin) {
+ this.wssLogin = wssLogin;
+ }
+
+ public EweLinkWebSocketClient(URI serverUri) {
+ super(serverUri);
+ }
+
+ @Override
+ public void onOpen(ServerHandshake serverHandshake) {
+ send(wssLogin);
+ }
+
+ @Override
+ public void onMessage(String s) {
+ if (s!= null && s.equalsIgnoreCase("pong")){
+ //swallow this as its just a ping/pong
+ logger.debug(s);
+ }else {
+ wssResponse.onMessage(s);
+ wssResponse.onMessageParsed(gson.fromJson(s, WssRspMsg.class));
+ }
+ }
+
+ @Override
+ public void onClose(int i, String s, boolean b) {
+ logger.warn("WS onCloseCalled, system will self-recover {} {} {}",i,s,b);
+ }
+
+ @Override
+ public void onError(Exception e) {
+ wssResponse.onError(e.getMessage());
+ }
+}
diff --git a/src/main/java/com/github/realzimboguy/ewelink/api/model/devices/Params.java b/src/main/java/com/github/realzimboguy/ewelink/api/model/devices/Params.java
index b2a9135..53fc1ca 100644
--- a/src/main/java/com/github/realzimboguy/ewelink/api/model/devices/Params.java
+++ b/src/main/java/com/github/realzimboguy/ewelink/api/model/devices/Params.java
@@ -1,6 +1,8 @@
package com.github.realzimboguy.ewelink.api.model.devices;
+import com.google.gson.annotations.SerializedName;
+
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -9,6 +11,7 @@ public class Params {
private BindInfos bindInfos;
private String sledOnline;
+ @SerializedName("switch")
private String _switch;
private String power;
private String voltage;
@@ -269,4 +272,38 @@ public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
+ @Override
+ public String toString() {
+ return "Params{" +
+ "bindInfos=" + bindInfos +
+ ", sledOnline='" + sledOnline + '\'' +
+ ", _switch='" + _switch + '\'' +
+ ", power='" + power + '\'' +
+ ", voltage='" + voltage + '\'' +
+ ", current='" + current + '\'' +
+ ", fwVersion='" + fwVersion + '\'' +
+ ", staMac='" + staMac + '\'' +
+ ", rssi=" + rssi +
+ ", init=" + init +
+ ", alarmType='" + alarmType + '\'' +
+ ", alarmVValue=" + alarmVValue +
+ ", alarmCValue=" + alarmCValue +
+ ", alarmPValue=" + alarmPValue +
+ ", oneKwh='" + oneKwh + '\'' +
+ ", uiActive=" + uiActive +
+ ", timeZone=" + timeZone +
+ ", version=" + version +
+ ", startup='" + startup + '\'' +
+ ", pulse='" + pulse + '\'' +
+ ", pulseWidth=" + pulseWidth +
+ ", timers=" + timers +
+ ", hundredDaysKwh='" + hundredDaysKwh + '\'' +
+ ", onlyDevice=" + onlyDevice +
+ ", ssid='" + ssid + '\'' +
+ ", bssid='" + bssid + '\'' +
+ ", endTime='" + endTime + '\'' +
+ ", startTime='" + startTime + '\'' +
+ ", additionalProperties=" + additionalProperties +
+ '}';
+ }
}
diff --git a/src/main/java/com/github/realzimboguy/ewelink/api/wss/WssLogin.java b/src/main/java/com/github/realzimboguy/ewelink/api/wss/WssLogin.java
new file mode 100644
index 0000000..c1c16db
--- /dev/null
+++ b/src/main/java/com/github/realzimboguy/ewelink/api/wss/WssLogin.java
@@ -0,0 +1,112 @@
+package com.github.realzimboguy.ewelink.api.wss;
+
+import java.util.Date;
+
+public class WssLogin {
+
+ private String action = "userOnline";
+ private String at;
+ private String apikey;
+ private String appid;
+ private String nonce;
+ private Long ts;
+ private String userAgent = "app";
+ private Long sequence;
+ private int version = 8;
+
+ public WssLogin(String at, String apikey, String appid,String nonce) {
+ this.at = at;
+ this.apikey = apikey;
+ this.appid = appid;
+ this.nonce = nonce;
+ ts = new Date().getTime() / 1000;
+ sequence = new Date().getTime();
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ public String getAt() {
+ return at;
+ }
+
+ public void setAt(String at) {
+ this.at = at;
+ }
+
+ public String getApikey() {
+ return apikey;
+ }
+
+ public void setApikey(String apikey) {
+ this.apikey = apikey;
+ }
+
+ public String getAppid() {
+ return appid;
+ }
+
+ public void setAppid(String appid) {
+ this.appid = appid;
+ }
+
+ public String getNonce() {
+ return nonce;
+ }
+
+ public void setNonce(String nonce) {
+ this.nonce = nonce;
+ }
+
+ public Long getTs() {
+ return ts;
+ }
+
+ public void setTs(Long ts) {
+ this.ts = ts;
+ }
+
+ public String getUserAgent() {
+ return userAgent;
+ }
+
+ public void setUserAgent(String userAgent) {
+ this.userAgent = userAgent;
+ }
+
+ public Long getSequence() {
+ return sequence;
+ }
+
+ public void setSequence(Long sequence) {
+ this.sequence = sequence;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ @Override
+ public String toString() {
+ return "WssLogin{" +
+ "action='" + action + '\'' +
+ ", at='" + at + '\'' +
+ ", apikey='" + apikey + '\'' +
+ ", appid='" + appid + '\'' +
+ ", nonce='" + nonce + '\'' +
+ ", ts=" + ts +
+ ", userAgent='" + userAgent + '\'' +
+ ", sequence=" + sequence +
+ ", version=" + version +
+ '}';
+ }
+}
diff --git a/src/main/java/com/github/realzimboguy/ewelink/api/wss/WssResponse.java b/src/main/java/com/github/realzimboguy/ewelink/api/wss/WssResponse.java
new file mode 100644
index 0000000..e808389
--- /dev/null
+++ b/src/main/java/com/github/realzimboguy/ewelink/api/wss/WssResponse.java
@@ -0,0 +1,12 @@
+package com.github.realzimboguy.ewelink.api.wss;
+
+import com.github.realzimboguy.ewelink.api.wss.wssrsp.WssRspMsg;
+
+public interface WssResponse {
+
+ void onMessage(String s);
+
+ void onMessageParsed(WssRspMsg rsp);
+
+ void onError(String error);
+}
diff --git a/src/main/java/com/github/realzimboguy/ewelink/api/wss/wssrsp/Config.java b/src/main/java/com/github/realzimboguy/ewelink/api/wss/wssrsp/Config.java
new file mode 100644
index 0000000..8d7c421
--- /dev/null
+++ b/src/main/java/com/github/realzimboguy/ewelink/api/wss/wssrsp/Config.java
@@ -0,0 +1,45 @@
+
+package com.github.realzimboguy.ewelink.api.wss.wssrsp;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Config {
+
+ private Integer hb;
+ private Integer hbInterval;
+ private Map additionalProperties = new HashMap();
+
+ public Integer getHb() {
+ return hb;
+ }
+
+ public void setHb(Integer hb) {
+ this.hb = hb;
+ }
+
+ public Integer getHbInterval() {
+ return hbInterval;
+ }
+
+ public void setHbInterval(Integer hbInterval) {
+ this.hbInterval = hbInterval;
+ }
+
+ public Map getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+ @Override
+ public String toString() {
+ return "Config{" +
+ "hb=" + hb +
+ ", hbInterval=" + hbInterval +
+ ", additionalProperties=" + additionalProperties +
+ '}';
+ }
+}
diff --git a/src/main/java/com/github/realzimboguy/ewelink/api/wss/wssrsp/WssRspMsg.java b/src/main/java/com/github/realzimboguy/ewelink/api/wss/wssrsp/WssRspMsg.java
new file mode 100644
index 0000000..d02378f
--- /dev/null
+++ b/src/main/java/com/github/realzimboguy/ewelink/api/wss/wssrsp/WssRspMsg.java
@@ -0,0 +1,127 @@
+
+package com.github.realzimboguy.ewelink.api.wss.wssrsp;
+
+import com.github.realzimboguy.ewelink.api.model.devices.Params;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class WssRspMsg {
+
+ private Integer error;
+ private String action;
+ private String deviceid;
+ private String apikey;
+ private String userAgent;
+ private Params params;
+ private String from;
+ private Config config;
+ private String seq;
+ private String sequence;
+ private Map additionalProperties = new HashMap();
+
+ public Integer getError() {
+ return error;
+ }
+
+ public void setError(Integer error) {
+ this.error = error;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ public String getDeviceid() {
+ return deviceid;
+ }
+
+ public void setDeviceid(String deviceid) {
+ this.deviceid = deviceid;
+ }
+
+ public String getApikey() {
+ return apikey;
+ }
+
+ public void setApikey(String apikey) {
+ this.apikey = apikey;
+ }
+
+ public String getUserAgent() {
+ return userAgent;
+ }
+
+ public void setUserAgent(String userAgent) {
+ this.userAgent = userAgent;
+ }
+
+ public Params getParams() {
+ return params;
+ }
+
+ public void setParams(Params params) {
+ this.params = params;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public void setFrom(String from) {
+ this.from = from;
+ }
+
+ public Config getConfig() {
+ return config;
+ }
+
+ public void setConfig(Config config) {
+ this.config = config;
+ }
+
+ public String getSeq() {
+ return seq;
+ }
+
+ public void setSeq(String seq) {
+ this.seq = seq;
+ }
+
+ public String getSequence() {
+ return sequence;
+ }
+
+ public void setSequence(String sequence) {
+ this.sequence = sequence;
+ }
+
+ public Map getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ public void setAdditionalProperty(String name, Object value) {
+ this.additionalProperties.put(name, value);
+ }
+
+ @Override
+ public String toString() {
+ return "WssRspMsg{" +
+ "error=" + error +
+ ", action='" + action + '\'' +
+ ", deviceid='" + deviceid + '\'' +
+ ", apikey='" + apikey + '\'' +
+ ", userAgent='" + userAgent + '\'' +
+ ", params=" + params +
+ ", from='" + from + '\'' +
+ ", config=" + config +
+ ", seq='" + seq + '\'' +
+ ", sequence='" + sequence + '\'' +
+ ", additionalProperties=" + additionalProperties +
+ '}';
+ }
+}
diff --git a/src/test/java/com/github/realzimboguy/ewelink/api/TestCode.java b/src/test/java/com/github/realzimboguy/ewelink/api/TestCode.java
new file mode 100644
index 0000000..c266257
--- /dev/null
+++ b/src/test/java/com/github/realzimboguy/ewelink/api/TestCode.java
@@ -0,0 +1,82 @@
+package com.github.realzimboguy.ewelink.api;
+
+import com.github.realzimboguy.ewelink.api.model.devices.DeviceItem;
+import com.github.realzimboguy.ewelink.api.model.devices.Devices;
+import com.github.realzimboguy.ewelink.api.wss.WssResponse;
+import com.github.realzimboguy.ewelink.api.wss.wssrsp.WssRspMsg;
+
+public class TestCode {
+
+ public static void main(String[] args) {
+
+
+ EweLink eweLink = new EweLink("eu", "asdf@gmail.com", "asdf", 60);
+
+ try {
+ eweLink.login();
+
+ Devices getDevices = eweLink.getDevices();
+
+ for (DeviceItem devicelist : getDevices.getDevicelist()) {
+ System.out.println(devicelist.getDeviceid());
+ System.out.println(devicelist.getName());
+
+ System.out.println(eweLink.getDeviceStatus(devicelist.getDeviceid()));
+
+ }
+
+ eweLink.getWebSocket(new WssResponse() {
+
+ @Override
+ public void onMessage(String s) {
+ //if you want the raw json data
+ System.out.println("on message in test raw:" + s);
+
+ }
+
+ @Override
+ public void onMessageParsed(WssRspMsg rsp) {
+
+ if (rsp.getError() == null) {
+
+ //normal scenario
+ StringBuilder sb = new StringBuilder();
+ sb.append("Device:").append(rsp.getDeviceid()).append(" - ");
+ if (rsp.getParams() != null) {
+ sb.append("Switch:").append(rsp.getParams().getSwitch()).append(" - ");
+ sb.append("Voltage:").append(rsp.getParams().getVoltage()).append(" - ");
+ sb.append("Power:").append(rsp.getParams().getPower()).append(" - ");
+ sb.append("Current:").append(rsp.getParams().getCurrent()).append(" - ");
+ }
+
+ System.out.println(sb.toString());
+
+ } else if (rsp.getError() == 0) {
+ //this is from a login response
+ System.out.println("login success");
+ } else if (rsp.getError() > 0) {
+ System.out.println("login error:" + rsp.toString());
+ }
+ }
+
+ @Override
+ public void onError(String error) {
+ System.out.println("onError in test, this should never be called");
+ System.out.println(error);
+
+ }
+ });
+
+
+// System.out.println(eweLink.getDevice("10009ce53b"));
+
+// System.out.println(eweLink.setDeviceStatusByName("Pool Tank","off"));
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+}
diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..2820c0c
--- /dev/null
+++ b/src/test/resources/log4j2.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+