New file |
| | |
| | | package com.hdl.sdk.link.zigbee; |
| | | |
| | | import com.google.gson.JsonArray; |
| | | import com.google.gson.JsonObject; |
| | | import com.google.gson.reflect.TypeToken; |
| | | import com.hdl.sdk.link.common.event.EventListener; |
| | | import com.hdl.sdk.link.common.exception.HDLLinkCode; |
| | | import com.hdl.sdk.link.common.exception.HDLLinkException; |
| | | import com.hdl.sdk.link.common.utils.LogUtils; |
| | | import com.hdl.sdk.link.common.utils.ThreadToolUtils; |
| | | import com.hdl.sdk.link.common.utils.gson.GsonConvert; |
| | | import com.hdl.sdk.link.core.bean.ZigbeeResponse; |
| | | import com.hdl.sdk.link.core.callback.ZigbeeCallBack; |
| | | import com.hdl.sdk.link.core.connect.HDLZigbeeConnect; |
| | | import com.hdl.sdk.link.zigbee.bean.PanelVibrationBean; |
| | | import com.hdl.sdk.link.zigbee.bean.TimeDataBean; |
| | | import com.hdl.sdk.link.zigbee.bean.ZBBaseSendBean; |
| | | import com.hdl.sdk.link.zigbee.bean.ZBDeviceBean; |
| | | import com.hdl.sdk.link.zigbee.callback.ZBDeviceListCallBack; |
| | | import com.hdl.sdk.link.zigbee.config.ZigBee; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.concurrent.ScheduledExecutorService; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | |
| | | /** |
| | | * Created by jlchen on 12/16/21. |
| | | * ZigBee原生协议相关 |
| | | */ |
| | | public class HDLLinkLocalZigBee { |
| | | private static final String TAG = "HDLLinkLocalZigBee"; |
| | | private static final String Cluster_ID = "Cluster_ID"; |
| | | private static final String Command = "Command"; |
| | | //instance |
| | | private volatile static HDLLinkLocalZigBee instance; |
| | | |
| | | //getInstance |
| | | public static synchronized HDLLinkLocalZigBee getInstance() { |
| | | if (instance == null) { |
| | | synchronized (HDLLinkLocalZigBee.class) { |
| | | if (instance == null) { |
| | | instance = new HDLLinkLocalZigBee(); |
| | | } |
| | | } |
| | | } |
| | | return instance; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 发送消息给网关 |
| | | * |
| | | * @param gatewayOid |
| | | * @param replyTopic 回复主题 |
| | | * @param payload |
| | | * @param callback |
| | | */ |
| | | public void sendData(String gatewayOid, String replyTopic, String payload, ZigbeeCallBack callback) { |
| | | //注意 gatewayId是填要连接的网关,可以是主网关的Id,也可以是从网关的Id |
| | | HDLZigbeeConnect.getInstance().Send(gatewayOid, replyTopic, payload, callback); |
| | | } |
| | | |
| | | /********************************网关相关********************************/ |
| | | /** |
| | | * 发送指令到网关进行定位(网关LED闪烁识别) |
| | | * |
| | | * @param gatewayOid 网关id |
| | | * @param callback |
| | | */ |
| | | public void locationGateway(String gatewayOid, ZigbeeCallBack callback) { |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty(Cluster_ID, 0); |
| | | jObject.addProperty(Command, ZigBee.CommandType.GwLinuxLocate); |
| | | sendData(gatewayOid, ZigBee.ReplyTopicType.GwLinuxLocate, jObject.toString(), callback); |
| | | } |
| | | |
| | | /********************************设备相关********************************/ |
| | | /** |
| | | * 设置设备入网方式 |
| | | * 设置1次之后保持设置的方式 |
| | | * 重启恢复默认方式 |
| | | * |
| | | * @param gatewayOid 网关oid |
| | | * @param deviceJoiningMode 0:默认;1:新方式(快速入网) |
| | | */ |
| | | public void setDeviceJoiningMode(String gatewayOid, int deviceJoiningMode, ZigbeeCallBack callback) { |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty("Cluster_ID", 0); |
| | | jObject.addProperty("Command", 180); |
| | | JsonObject data = new JsonObject(); |
| | | data.addProperty("mode", deviceJoiningMode); |
| | | jObject.add("Data", data); |
| | | sendData(gatewayOid, ZigBee.ReplyTopicType.SetJoiningModeRespon, jObject.toString(), callback); |
| | | } |
| | | |
| | | /** |
| | | * 设置搜索新设备开启或者关闭 |
| | | * |
| | | * @param gatewayOid 网关oid |
| | | * @param time 开启搜索设备的时间(单位:秒) 0:关闭搜索 255:一直开启 |
| | | * @param callback |
| | | */ |
| | | public void sendSearchDevice(String gatewayOid, int time, ZigbeeCallBack callback) { |
| | | ZBBaseSendBean<TimeDataBean> baseSendBean = new ZBBaseSendBean(0, ZigBee.CommandType.SearchNewDevice, new TimeDataBean(time)); |
| | | sendData(gatewayOid, ZigBee.ReplyTopicType.SearchNewDevice, GsonConvert.getGson().toJson(baseSendBean), callback); |
| | | } |
| | | |
| | | /** |
| | | * 搜索设备 |
| | | * |
| | | * @param gatewayOid |
| | | * @param callback |
| | | */ |
| | | public void startSearchDevice(String gatewayOid, ZigbeeCallBack callback) { |
| | | sendSearchDevice(gatewayOid, 255, callback); |
| | | } |
| | | |
| | | /** |
| | | * 暂停搜索设备 |
| | | * |
| | | * @param gatewayOid |
| | | * @param callback |
| | | */ |
| | | public void stopSearchDevice(String gatewayOid, ZigbeeCallBack callback) { |
| | | sendSearchDevice(gatewayOid, 0, callback); |
| | | } |
| | | |
| | | /** |
| | | * 定位设备 闪烁5秒 |
| | | * 该条指令设备不回复,所有没callBack |
| | | * 发送该命令,设备指示灯将闪烁。cluster 列表中支持 Identify 功能,即包含 cluster=3 的设 备可以使用该接口。 |
| | | * |
| | | * @param gatewayOid |
| | | * @param deviceAddr 单播时为设备节点的 mac 地 址 类型是字符(16 个字符) 组播时为组 id 类型是数值 广播时为 null |
| | | * @param epoint 设备端口号 和 mac 地址共同标识唯一的 zigbee 设备 数值范围 0-255 |
| | | */ |
| | | public void locationDevice(String gatewayOid, String deviceAddr, int epoint) { |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty("DeviceAddr", deviceAddr); |
| | | jObject.addProperty("Epoint", epoint); |
| | | jObject.addProperty(Cluster_ID, 3); |
| | | jObject.addProperty(Command, 0); |
| | | jObject.addProperty("SendMode", 2);//发送模式 组播: 1 单播: 2 广播: 15 |
| | | JsonObject data = new JsonObject(); |
| | | data.addProperty("Time", 5);//闪烁时间(秒) |
| | | jObject.add("Data", data); |
| | | sendData(gatewayOid, ZigBee.ReplyTopicType.Identify, jObject.toString(), null); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 设备列表-设备删除(使设备离网) |
| | | * 通过该指令可以使设备脱离当前 zigbee 网络,该设备信息也将会在网关上删除。 |
| | | * 注意:将会删除同一 MAC 地址下所有不同端口的设备,如一个 2 路按键设备,它具有两个 按键,在设备列表上这两个按键具有相同的 mac,但端口号是不同的。使用该指令让任意 一个按键离网,另一个也会离网。 |
| | | * |
| | | * @param gatewayOid |
| | | * @param compelClear 0:不强制清除。需要节点设备 反馈离网确认信息后才能删除设 备信息。 |
| | | * 1:强制清除。不需要节点设备 反馈离网确认信息,直接删除设 备信息。 |
| | | */ |
| | | public void removeDevice(String gatewayOid, int compelClear, List<String> deviceAddrList, ZigbeeCallBack callback) { |
| | | if (deviceAddrList == null || deviceAddrList.size() == 0) { |
| | | LogUtils.e("没有要删除到数据"); |
| | | return; |
| | | } |
| | | JsonArray addrList = new JsonArray(); |
| | | for (String addr : deviceAddrList) { |
| | | JsonObject aObject = new JsonObject(); |
| | | aObject.addProperty("DeviceAddr", addr); |
| | | addrList.add(aObject); |
| | | } |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty(Cluster_ID, 0); |
| | | jObject.addProperty(Command, ZigBee.CommandType.RemoveDevice); |
| | | JsonObject data = new JsonObject(); |
| | | data.addProperty("CompelClear", compelClear); |
| | | data.add("DeviceAddrList", addrList); |
| | | jObject.add("Data", data); |
| | | sendData(gatewayOid, ZigBee.ReplyTopicType.RemoveDevice, jObject.toString(), callback); |
| | | } |
| | | |
| | | /** |
| | | * 设备列表-获取本地网关设备 EPDeviceId 列表 |
| | | * (网关一个一个返回端点设备详细信息) |
| | | * |
| | | * @param gatewayOid |
| | | * @param callback |
| | | */ |
| | | public void getZigBeeDeviceList(String gatewayOid, ZBDeviceListCallBack callback) { |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty(Cluster_ID, 0); |
| | | jObject.addProperty(Command, ZigBee.CommandType.GetDeviceInfo); |
| | | //是否获取列表成功标记 |
| | | AtomicBoolean isSuccess = new AtomicBoolean(false); |
| | | //搜索5s等待标记 |
| | | AtomicInteger timeOut = new AtomicInteger(0); |
| | | //设备列表 |
| | | List<ZBDeviceBean> list = new ArrayList<>(); |
| | | //注册监听事件 |
| | | EventListener zigBeeEventListener = new EventListener() { |
| | | @Override |
| | | public synchronized void onMessage(Object msg) { |
| | | if (msg instanceof ZigbeeResponse) { |
| | | ZigbeeResponse zigbeeResponse = (ZigbeeResponse) msg; |
| | | try { |
| | | if (zigbeeResponse.getTopic().equals(ZigBee.ReplyTopicType.GetDeviceInfo)) { |
| | | final ZBDeviceBean bean = GsonConvert.getGson().fromJson(zigbeeResponse.getData(), new TypeToken<ZBDeviceBean>() { |
| | | }.getType()); |
| | | |
| | | |
| | | if (bean == null) { |
| | | LogUtils.i("获取到的Zigbee设备列表反系列化失败:\r\n" + zigbeeResponse.getData()); |
| | | } else { |
| | | bean.setGatewayMac(zigbeeResponse.getOid()); |
| | | LogUtils.i("zigbeeResponse ZBDeviceBean:" + bean.getDeviceAddr() + ":" + bean.getEpoint()); |
| | | if (bean.getData().getTotalNum() == 0) { |
| | | //回复空的设备列表 |
| | | list.clear(); |
| | | if (callback != null) { |
| | | callback.onSuccess(list); |
| | | } |
| | | HDLZigbeeConnect.getInstance().removeListener(this); |
| | | isSuccess.set(true); |
| | | } else { |
| | | list.add(bean); |
| | | // LogUtils.i("getZigBeeDeviceList 重置时间为0"); |
| | | timeOut.set(0);//收到一个设备则重置时间 |
| | | //如果当前序号等于总数,代表是最后一个设备了,回调成功 |
| | | if (bean.getData().getDeviceNum() == bean.getData().getTotalNum()) { |
| | | if (callback != null) { |
| | | callback.onSuccess(list); |
| | | } |
| | | HDLZigbeeConnect.getInstance().removeListener(this); |
| | | isSuccess.set(true); |
| | | LogUtils.i("getZigBeeDeviceList读取完成"); |
| | | timeOut.set(6);//计时结束标记 |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | LogUtils.e(TAG, "接收的数据内容:" + zigbeeResponse.getData() + " 异常信息:" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | HDLZigbeeConnect.getInstance().registerListener(zigBeeEventListener); |
| | | //发送数据 |
| | | sendData(gatewayOid, "", jObject.toString(), null); |
| | | //5秒后还没有接收到数据,就回调失败 |
| | | ScheduledExecutorService scheduledExecutorService = ThreadToolUtils.getInstance().newScheduledThreadPool(1); |
| | | scheduledExecutorService.schedule(new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | while (timeOut.get() < 5) { |
| | | try { |
| | | timeOut.set(timeOut.get() + 1); |
| | | LogUtils.i("getZigBeeDeviceList 计时:" + timeOut.get() + "s"); |
| | | Thread.sleep(1000); |
| | | } catch (InterruptedException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | //移除监听事件 |
| | | HDLZigbeeConnect.getInstance().removeListener(zigBeeEventListener); |
| | | if (!isSuccess.get()) { |
| | | if (null != callback) { |
| | | callback.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_GET_Zigbee_DEVICE_LIST_FAILURE_ERROR)); |
| | | } |
| | | } |
| | | LogUtils.i("getZigBeeDeviceList 5s倒计时结束"); |
| | | scheduledExecutorService.shutdownNow(); |
| | | } |
| | | }, 1, TimeUnit.SECONDS); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 修改设备端口(按键)名称 |
| | | * |
| | | * @param gatewayOid |
| | | * @param deviceAddr |
| | | * @param epoint |
| | | * @param deviceName |
| | | * @param callback |
| | | */ |
| | | public void renameDeviceName(String gatewayOid, String deviceAddr, int epoint, String deviceName, ZigbeeCallBack callback) { |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty("DeviceAddr", deviceAddr); |
| | | jObject.addProperty("Epoint", epoint); |
| | | jObject.addProperty(Cluster_ID, 0); |
| | | jObject.addProperty(Command, ZigBee.CommandType.DeviceRename); |
| | | JsonObject data = new JsonObject(); |
| | | data.addProperty("DeviceName", deviceName); |
| | | jObject.add("Data", data); |
| | | sendData(gatewayOid, ZigBee.ReplyTopicType.DeviceRename, jObject.toString(), callback); |
| | | } |
| | | |
| | | /** |
| | | * 对端点回路设备功能类型进行设置如 onoffoutput 回路,进行设置为普通开关或插座或灯光 |
| | | * |
| | | * @param gatewayOid |
| | | * @param deviceAddr 设备节点的 mac 地址 (最大 16 个字符) |
| | | * @param epoint 设备端口号 和 mac 地址共同标识唯一的 zigbee 设备 数值范围 0-255 |
| | | * @param functionType 用来表示实际回路用于什么 功能,可扩展 0-继电器接普通开关 1-继电器接灯光 2-插座 |
| | | * @param callback |
| | | */ |
| | | public void setEPDeviceFunctionType(String gatewayOid, String deviceAddr, int epoint, int functionType, ZigbeeCallBack callback) { |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty("DeviceAddr", deviceAddr); |
| | | jObject.addProperty("Epoint", epoint); |
| | | jObject.addProperty(Cluster_ID, 0); |
| | | jObject.addProperty(Command, ZigBee.CommandType.SetEPDeviceFunctionType); |
| | | JsonObject data = new JsonObject(); |
| | | data.addProperty("FunctionType", functionType); |
| | | jObject.add("Data", data); |
| | | sendData(gatewayOid, ZigBee.ReplyTopicType.SetEPDeviceFunctionType, jObject.toString(), callback); |
| | | } |
| | | |
| | | |
| | | /********面板震动功能********/ |
| | | /** |
| | | * 获取简约面板震动功能的信息 |
| | | */ |
| | | public void getPanelVibrationInfo(String gatewayOid, String deviceAddr, int epoint, String passData, ZigbeeCallBack callback) { |
| | | // //组装发送数据 |
| | | // JsonObject jObject = new JsonObject(); |
| | | // jObject.addProperty("DeviceAddr", deviceAddr); |
| | | // jObject.addProperty("Epoint", 200); |
| | | // jObject.addProperty(Cluster_ID, 64513); |
| | | // jObject.addProperty(Command, 0); |
| | | // JsonObject data = new JsonObject(); |
| | | // data.addProperty("PassData", "050108110101"); |
| | | // jObject.add("Data", data); |
| | | // sendClientDataPassthrough(device, jObject.toString(), "0802", 18, 6, null, callback); |
| | | // sendClientDataPassthrough(gatewayOid,deviceAddr,epoint,passData,callback); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 设置简约面板震动功能的信息 |
| | | * |
| | | * @param device |
| | | * @param deviceAddr |
| | | * @param panelVibrationBean |
| | | * @param callback |
| | | */ |
| | | public void setPanelVibrationInfo(String device, String deviceAddr, PanelVibrationBean panelVibrationBean, ZigbeeCallBack callback) { |
| | | // String passData = "0800081104"; |
| | | // passData += panelVibrationBean.getIsEnable() ? "01" : "00"; |
| | | //// passData += Convert.ToString(panelVibrationBean.getStrength(), 16).PadLeft(2, '0'); |
| | | //// String time = Convert.ToString(panelVibrationBean.getTime(), 16).PadLeft(4, '0'); |
| | | //// //低位在前,高位在后 |
| | | //// passData += time.Substring(2, 2); |
| | | //// passData += time.Substring(0, 2); |
| | | // |
| | | //// var jObject = new Newtonsoft.Json.Linq.JObject { { "DeviceAddr", DeviceAddr }, { "Epoint", 200 }, { "Cluster_ID", 64513 }, { "Command", 0 } }; |
| | | //// var data = new Newtonsoft.Json.Linq.JObject { { "PassData", passData } }; |
| | | //// jObject.Add("Data", data); |
| | | // |
| | | // JsonObject jObject = new JsonObject(); |
| | | // jObject.addProperty("DeviceAddr", deviceAddr); |
| | | // jObject.addProperty("Epoint", 200); |
| | | // jObject.addProperty(Cluster_ID, 64513); |
| | | // jObject.addProperty(Command, 0); |
| | | // JsonObject data = new JsonObject(); |
| | | // data.addProperty("PassData", passData); |
| | | // jObject.add("Data", data); |
| | | // |
| | | // sendClientDataPassthrough(device, jObject.toString(), "0002", 16, 6, null, callback); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 开关控制(仅用于cluster=6的设备) 设备支持cluster=6的设备才能调用该接口 |
| | | * |
| | | * @param command 0:关闭 1:打开 2:取反 |
| | | */ |
| | | public void switchControl(String gatewayOid, int command, ZBDeviceBean deviceBean) { |
| | | JsonObject jObject = new JsonObject(); |
| | | jObject.addProperty("DeviceAddr", deviceBean.getDeviceAddr()); |
| | | jObject.addProperty("Epoint", deviceBean.getEpoint()); |
| | | jObject.addProperty(Cluster_ID, 6); |
| | | jObject.addProperty(Command, command); |
| | | jObject.addProperty("SendMode", 2); |
| | | sendData(gatewayOid, "", jObject.toString(), null); |
| | | } |
| | | |
| | | } |