package com.hdl.sdk.connect.socket; import android.text.TextUtils; 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.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.util.ArrayList; import java.util.List; 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 response = GsonConvert.getGson().fromJson(data, new TypeToken>() { }.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> data = new BaseLocalResponse<>(); data.setId(IdUtils.getUUId()); data.setTime_stamp(time); List 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 request, CallBack callBack) { if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) { String time = String.valueOf(System.currentTimeMillis()); final BaseLocalResponse> 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 request, CallBack callBack) { if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) { String time = String.valueOf(System.currentTimeMillis()); final BaseLocalResponse> 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 request, CallBack callBack) { if (!TextUtils.isEmpty(getGatewayId()) && !TextUtils.isEmpty(getTcpIp())) { String time = String.valueOf(System.currentTimeMillis()); final BaseLocalResponse> 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("发送失败"); } } }); } } }