package com.hdl.sdk.connect;
|
|
import android.text.TextUtils;
|
import android.util.ArrayMap;
|
import android.util.Log;
|
|
import com.google.gson.Gson;
|
import com.google.gson.JsonArray;
|
import com.google.gson.JsonObject;
|
import com.google.gson.reflect.TypeToken;
|
import com.hdl.sdk.common.config.TopicConstant;
|
import com.hdl.sdk.common.event.EventDispatcher;
|
import com.hdl.sdk.common.event.EventListener;
|
import com.hdl.sdk.common.utils.IdUtils;
|
import com.hdl.sdk.common.utils.IpUtils;
|
import com.hdl.sdk.common.utils.SPUtils;
|
import com.hdl.sdk.common.utils.ThreadToolUtils;
|
import com.hdl.sdk.common.utils.gson.GsonConvert;
|
import com.hdl.sdk.connect.bean.AuthenticateRequest;
|
import com.hdl.sdk.connect.bean.BaseLocalRequest;
|
import com.hdl.sdk.connect.bean.BaseLocalResponse;
|
import com.hdl.sdk.connect.bean.DeviceControlRequest;
|
import com.hdl.sdk.connect.bean.FunctionAttributeRequest;
|
import com.hdl.sdk.connect.bean.GatewaySearchBean;
|
import com.hdl.sdk.connect.bean.LinkRequest;
|
import com.hdl.sdk.connect.bean.LinkResponse;
|
import com.hdl.sdk.connect.bean.PropertyReadRequest;
|
import com.hdl.sdk.connect.bean.PropertyUpRequest;
|
import com.hdl.sdk.connect.protocol.LinkMessageDecoder;
|
import com.hdl.sdk.connect.protocol.LinkMessageEncoder;
|
import com.hdl.sdk.socket.SocketBoot;
|
import com.hdl.sdk.socket.SocketOptions;
|
import com.hdl.sdk.socket.client.TcpClient;
|
import com.hdl.sdk.socket.client.UdpClient;
|
import com.hdl.sdk.socket.codec.MessagePipeLine;
|
import com.hdl.sdk.socket.listener.ConnectStatusListener;
|
import com.hdl.sdk.socket.listener.SendListener;
|
|
import java.io.UnsupportedEncodingException;
|
import java.lang.reflect.ParameterizedType;
|
import java.nio.charset.StandardCharsets;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
/**
|
* Created by Tong on 2021/9/26.
|
* 1、通过Udp 组播或者广播搜索网关
|
* 2、通过Udp 获取Tcp ip 端口统一8586
|
*/
|
public class HDLSocket {
|
|
private static final String GATEWAY_KEY = "gateway_key";
|
private static final String TCP_IP_KEY = "tcp_ip_key";
|
private String gatewayId;
|
|
public interface CallBack {
|
|
void onError(String error);
|
|
void onResponse(String data);
|
|
}
|
|
/**
|
* udp默认组播ip
|
*/
|
private static final String UDP_GROUP_IP = "239.0.168.188";
|
|
/**
|
* udp默认端口
|
*/
|
private static final int UDP_PORT = 8585;
|
|
/**
|
* tcp默认端口
|
*/
|
private static final int TCP_PORT = 8586;
|
|
private String tcpIp;
|
private int tcpPort;
|
|
private int udpPort;
|
private String udpIp;
|
|
private static SocketBoot updBoot;
|
private SocketBoot tcpBoot;
|
|
private ConnectStatusListener statusListener;
|
|
private EventListener searchEvent;
|
private CallBack searchCallBack;
|
private ScheduledExecutorService searchGatewayThread;
|
private final AtomicInteger searchCount = new AtomicInteger(0);
|
|
private HDLSocket() {
|
statusListener = new ConnectStatusListener() {
|
@Override
|
public void onConnecting() {
|
|
}
|
|
@Override
|
public void onConnected() {
|
|
}
|
|
@Override
|
public void onConnectFailed() {
|
|
}
|
};
|
searchEvent = new EventListener() {
|
@Override
|
public void onMessage(Object msg) {
|
try {
|
if (msg instanceof LinkResponse) {
|
LinkResponse linkResponse = (LinkResponse) msg;
|
String data = linkResponse.getData();
|
if (!TextUtils.isEmpty(data)) {
|
final BaseLocalResponse<GatewaySearchBean> response = GsonConvert.getGson().fromJson(data, new TypeToken<BaseLocalResponse<GatewaySearchBean>>() {
|
}.getType());
|
GatewaySearchBean searchBean = response.getObjects();
|
if (searchBean != null) {
|
gatewayId = searchBean.getGatewayId();
|
if (!TextUtils.isEmpty(gatewayId)) {
|
SPUtils.put(GATEWAY_KEY, gatewayId);
|
}
|
tcpIp = searchBean.getIp_address();
|
if (!TextUtils.isEmpty(tcpIp)) {
|
SPUtils.put(TCP_IP_KEY, tcpIp);
|
}
|
}
|
|
if (searchCallBack != null) {
|
searchCallBack.onResponse(linkResponse.toString());
|
}
|
}
|
|
}
|
} catch (Exception e) {
|
if (searchCallBack != null) {
|
searchCallBack.onError("解析失败");
|
}
|
}
|
|
|
}
|
};
|
}
|
|
private static class SingletonInstance {
|
private static final HDLSocket INSTANCE = new HDLSocket();
|
}
|
|
public static HDLSocket getInstance() {
|
return SingletonInstance.INSTANCE;
|
}
|
|
|
private SocketOptions getUdpOptions() {
|
final SocketOptions options = new SocketOptions();
|
final MessagePipeLine pipeLine = new MessagePipeLine();
|
pipeLine.add(new LinkMessageDecoder());
|
pipeLine.add(new LinkMessageEncoder());
|
options.setHandleMessage(pipeLine);
|
options.setEnabledHeartbeat(false);
|
return options;
|
}
|
|
private SocketOptions getTcpOptions() {
|
final SocketOptions options = new SocketOptions();
|
final MessagePipeLine pipeLine = new MessagePipeLine();
|
pipeLine.add(new LinkMessageDecoder());
|
pipeLine.add(new LinkMessageEncoder());
|
options.setHandleMessage(pipeLine);
|
options.setEnabledHeartbeat(false);
|
return options;
|
}
|
|
private int getUdpPort() {
|
return UDP_PORT;
|
}
|
|
public int getTcpPort() {
|
return TCP_PORT;
|
}
|
|
public String getTcpIp() {
|
if (!TextUtils.isEmpty(tcpIp)) {
|
return tcpIp;
|
}
|
return SPUtils.getString(TCP_IP_KEY, "");
|
}
|
|
public String getGatewayId() {
|
if (!TextUtils.isEmpty(gatewayId)) {
|
return gatewayId;
|
}
|
return SPUtils.getString(GATEWAY_KEY, "");
|
}
|
|
|
private String getUdpIp() {
|
if (TextUtils.isEmpty(udpIp)) {
|
udpIp = UDP_GROUP_IP;
|
}
|
return udpIp;
|
}
|
|
public void searchGateway() {
|
searchGateway(null);
|
}
|
|
/**
|
* 组播搜索
|
*/
|
public void searchGateway(CallBack callBack) {
|
gatewayId = "";//重置网关ID
|
this.searchCallBack = callBack;
|
|
if (searchGatewayThread != null) {
|
searchGatewayThread.shutdownNow();
|
}
|
|
|
new Thread(new Runnable() {
|
@Override
|
public void run() {
|
while (TextUtils.isEmpty(gatewayId)) {
|
//搜索网关
|
searchGateway(IdUtils.getUUId(), searchEvent);
|
try {
|
Thread.sleep(1000L);
|
} catch (InterruptedException e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
}).start();
|
}
|
|
|
/**
|
* 通过组播搜索网关
|
*/
|
public void searchGateway(String msgId, EventListener eventListener) {
|
searchGateway(getUdpIp(), getUdpPort(), msgId, eventListener);
|
}
|
|
/**
|
* 通过广播搜索网关
|
*/
|
public void searchGatewayByBroadcast(String msgId, EventListener eventListener) {
|
searchGateway(IpUtils.getBroadcastAddress(), getUdpPort(), msgId, eventListener);
|
}
|
|
/**
|
* 默认是组播搜索网关
|
*/
|
public void searchGateway(String ip, int port, String msgId, EventListener eventListener) {
|
|
if (updBoot == null) {
|
updBoot = UdpClient.init(ip, port, getUdpOptions());
|
updBoot.connect();
|
}
|
|
|
String time = String.valueOf(System.currentTimeMillis());
|
JsonObject jsonObject = new JsonObject();
|
jsonObject.addProperty("id", msgId);
|
jsonObject.addProperty("time_stamp", time);
|
|
EventDispatcher.getInstance().registerIo(TopicConstant.GATEWAY_SEARCH_REPLY, eventListener);
|
LinkRequest message = new LinkRequest(TopicConstant.GATEWAY_SEARCH,
|
jsonObject.toString());
|
|
try {
|
updBoot.sendMsg(message.toString().getBytes("utf-8"));
|
} catch (UnsupportedEncodingException e) {
|
e.printStackTrace();
|
}
|
|
}
|
|
|
/**
|
* 获取设备列表
|
*/
|
public void getDeviceList(CallBack callBack) {
|
if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
|
String time = String.valueOf(System.currentTimeMillis());
|
JsonObject jsonObject = new JsonObject();
|
jsonObject.addProperty("id", IdUtils.getUUId());
|
jsonObject.addProperty("time_stamp", time);
|
|
String topic = String.format(TopicConstant.GET_DEVICE_LIST, getGatewayId());
|
|
LinkRequest message = new LinkRequest(topic,
|
jsonObject.toString());
|
|
String replyTopic = String.format(TopicConstant.GET_DEVICE_LIST_REPLY, getGatewayId());
|
try {
|
sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
|
@Override
|
public void onSucceed() {
|
|
}
|
|
@Override
|
public void onError() {
|
if (callBack != null) {
|
callBack.onError("获取设备列表失败");
|
}
|
}
|
});
|
} catch (UnsupportedEncodingException e) {
|
if (callBack != null) {
|
callBack.onError("获取设备列表失败");
|
}
|
}
|
} else {
|
if (callBack != null) {
|
callBack.onError("ip地址丢失");
|
}
|
}
|
}
|
|
|
/**
|
* 获取功能列表
|
*/
|
public void getFunctionList(CallBack callBack) {
|
if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
|
String time = String.valueOf(System.currentTimeMillis());
|
JsonObject jsonObject = new JsonObject();
|
jsonObject.addProperty("id", IdUtils.getUUId());
|
jsonObject.addProperty("time_stamp", time);
|
|
String topic = String.format(TopicConstant.GET_FUNCTION_LIST, getGatewayId());
|
|
LinkRequest message = new LinkRequest(topic,
|
jsonObject.toString());
|
|
String replyTopic = String.format(TopicConstant.GET_FUNCTION_LIST_REPLY, getGatewayId());
|
try {
|
sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
|
@Override
|
public void onSucceed() {
|
|
}
|
|
@Override
|
public void onError() {
|
if (callBack != null) {
|
callBack.onError("获取功能列表失败");
|
}
|
}
|
});
|
} catch (UnsupportedEncodingException e) {
|
if (callBack != null) {
|
callBack.onError("获取功能列表失败");
|
}
|
}
|
} else {
|
if (callBack != null) {
|
callBack.onError("ip地址丢失");
|
}
|
}
|
}
|
|
|
/**
|
* 获取功能属性
|
*
|
* @param callBack
|
* @param sid
|
*/
|
public void getFunctionAttribute(CallBack callBack, String... sid) {
|
if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
|
String time = String.valueOf(System.currentTimeMillis());
|
|
final BaseLocalResponse<List<FunctionAttributeRequest>> data = new BaseLocalResponse<>();
|
data.setId(IdUtils.getUUId());
|
data.setTime_stamp(time);
|
List<FunctionAttributeRequest> list = new ArrayList<>();
|
for (String s : sid) {
|
list.add(new FunctionAttributeRequest(s));
|
}
|
data.setObjects(list);
|
|
String topic = String.format(TopicConstant.GET_FUNCTION_ATTRIBUTE, getGatewayId());
|
LinkRequest message = new LinkRequest(topic,
|
GsonConvert.getGson().toJson(data));
|
|
String replyTopic = String.format(TopicConstant.GET_FUNCTION_ATTRIBUTE_REPLY, getGatewayId());
|
try {
|
sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
|
@Override
|
public void onSucceed() {
|
|
}
|
|
@Override
|
public void onError() {
|
if (callBack != null) {
|
callBack.onError("获取功能属性失败");
|
}
|
}
|
});
|
} catch (UnsupportedEncodingException e) {
|
if (callBack != null) {
|
callBack.onError("获取功能属性失败");
|
}
|
}
|
} else {
|
if (callBack != null) {
|
callBack.onError("ip地址丢失");
|
}
|
}
|
}
|
|
/**
|
* 设备控制
|
*/
|
public void propertyDown(List<DeviceControlRequest> request, CallBack callBack) {
|
|
if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
|
String time = String.valueOf(System.currentTimeMillis());
|
|
final BaseLocalResponse<List<DeviceControlRequest>> data = new BaseLocalResponse<>();
|
data.setId(IdUtils.getUUId());
|
data.setTime_stamp(time);
|
data.setObjects(request);
|
|
|
String topic = String.format(TopicConstant.PROPERTY_DOWN, getGatewayId());
|
LinkRequest message = new LinkRequest(topic,
|
GsonConvert.getGson().toJson(request));
|
|
String replyTopic = String.format(TopicConstant.PROPERTY_DOWN_REPLY, getGatewayId());
|
try {
|
sendMsg(message.getSendBytes(), replyTopic, callBack, new SendListener() {
|
@Override
|
public void onSucceed() {
|
|
}
|
|
@Override
|
public void onError() {
|
if (callBack != null) {
|
callBack.onError("控制指令发送失败");
|
}
|
}
|
});
|
} catch (Exception e) {
|
if (callBack != null) {
|
callBack.onError("控制指令发送失败");
|
}
|
}
|
} else {
|
if (callBack != null) {
|
callBack.onError("控制指令发送失败");
|
}
|
}
|
|
}
|
|
/**
|
* 状态上报
|
*/
|
public void propertyUp(List<PropertyUpRequest> request, CallBack callBack) {
|
if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
|
String time = String.valueOf(System.currentTimeMillis());
|
|
final BaseLocalResponse<List<PropertyUpRequest>> data = new BaseLocalResponse<>();
|
data.setId(IdUtils.getUUId());
|
data.setTime_stamp(time);
|
data.setObjects(request);
|
|
|
String topic = String.format(TopicConstant.PROPERTY_UP, getGatewayId());
|
LinkRequest message = new LinkRequest(topic,
|
GsonConvert.getGson().toJson(request));
|
|
String replyTopic = String.format(TopicConstant.PROPERTY_UP_REPLY, getGatewayId());
|
try {
|
sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
|
@Override
|
public void onSucceed() {
|
|
}
|
|
@Override
|
public void onError() {
|
if (callBack != null) {
|
callBack.onError("指令发送失败");
|
}
|
}
|
});
|
} catch (UnsupportedEncodingException e) {
|
if (callBack != null) {
|
callBack.onError("指令发送失败");
|
}
|
}
|
} else {
|
if (callBack != null) {
|
callBack.onError("指令发送失败");
|
}
|
}
|
}
|
|
/**
|
* 读取状态
|
*/
|
public void propertyRead(List<PropertyReadRequest> request, CallBack callBack) {
|
if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) {
|
String time = String.valueOf(System.currentTimeMillis());
|
|
final BaseLocalResponse<List<PropertyReadRequest>> data = new BaseLocalResponse<>();
|
data.setId(IdUtils.getUUId());
|
data.setTime_stamp(time);
|
data.setObjects(request);
|
|
|
String topic = String.format(TopicConstant.PROPERTY_READ, getGatewayId());
|
LinkRequest message = new LinkRequest(topic,
|
GsonConvert.getGson().toJson(request));
|
|
String replyTopic = String.format(TopicConstant.PROPERTY_READ_REPLY, getGatewayId());
|
try {
|
sendMsg(message.toString().getBytes("utf-8"), replyTopic, callBack, new SendListener() {
|
@Override
|
public void onSucceed() {
|
|
}
|
|
@Override
|
public void onError() {
|
if (callBack != null) {
|
callBack.onError("指令发送失败");
|
}
|
}
|
});
|
} catch (UnsupportedEncodingException e) {
|
if (callBack != null) {
|
callBack.onError("指令发送失败");
|
}
|
}
|
} else {
|
if (callBack != null) {
|
callBack.onError("指令发送失败");
|
}
|
}
|
}
|
|
public SocketBoot getTcp() throws RuntimeException {
|
if (TextUtils.isEmpty(getTcpIp())) {
|
throw new RuntimeException("请搜索网关");
|
}
|
if (tcpBoot == null) {
|
tcpBoot = TcpClient.init(getTcpIp(), getTcpPort(), getTcpOptions());
|
}
|
return tcpBoot;
|
}
|
|
/**
|
* 清空缓存
|
*/
|
public void clearCache() {
|
SPUtils.remove(TCP_IP_KEY);
|
SPUtils.remove(GATEWAY_KEY);
|
}
|
|
|
/**
|
* 发送指令
|
* 1秒没响应就让他重新发送,重试3次
|
*/
|
public void sendMsg(byte[] data, String eventTag, CallBack callBack, SendListener sendListener) {
|
|
try {
|
final AtomicInteger sendCount = new AtomicInteger(0);
|
|
final ScheduledExecutorService threadPool = ThreadToolUtils.getInstance().newScheduledThreadPool(1);
|
final EventListener eventListener = new EventListener() {
|
@Override
|
public void onMessage(Object msg) {
|
if (msg instanceof LinkResponse) {
|
|
if (callBack != null) {
|
callBack.onResponse(msg.toString());
|
}
|
threadPool.shutdownNow();
|
}
|
}
|
};
|
|
threadPool.scheduleWithFixedDelay(new Runnable() {
|
@Override
|
public void run() {
|
if (sendCount.get() < 3) {
|
sendCount.set(sendCount.get() + 1);
|
getTcp().sendMsg(data);
|
} else {
|
threadPool.shutdownNow();
|
EventDispatcher.getInstance().remove(eventTag, eventListener);
|
ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
|
@Override
|
public void run() {
|
if (callBack != null) {
|
callBack.onError("发送失败");
|
}
|
}
|
});
|
}
|
}
|
}, 1000, 500, TimeUnit.MILLISECONDS);
|
EventDispatcher.getInstance().register(eventTag, eventListener);
|
getTcp().sendMsg(data, new SendListener() {
|
@Override
|
public void onSucceed() {
|
if (sendListener != null) {
|
sendListener.onSucceed();
|
}
|
}
|
|
@Override
|
public void onError() {
|
if (sendListener != null) {
|
sendListener.onError();
|
}
|
}
|
});
|
} catch (Exception e) {
|
e.printStackTrace();
|
ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
|
@Override
|
public void run() {
|
if (callBack != null) {
|
callBack.onError("发送失败");
|
}
|
}
|
});
|
}
|
|
}
|
|
}
|