jetLinks协议开发对接真实设备方式

jetLinks协议开发对接真实设备方式

拿到设备

首先拿到设备,确认设备型号
在这里插入图片描述
然后登入海康威视官网,下载 https://www.hikvision.com/cn/support/tools/hitools/
在这里插入图片描述
在这里插入图片描述
连接设备修改其对应的IP地址使得本机电脑与设备网络互通。
初始访问该设备Ip对应的网页时会出现提示下载插件的信息在这里插入图片描述
这时候按照提示下载插件,下载完成后用Microsoft Edge打开该网址
在这里插入图片描述
在这里插入图片描述
然后选择在internet模式下加载该网址,进入后则预览成功。
在这里插入图片描述

确定设备的SDK

设备拿到并配置完成后,那么下一步则需要确定设备sdk,进入海康SDK下载对应的页面,
https://open.hikvision.com/download/5cda567cf47ae80dd41a54b3?type=10,下载对应操作系统适配的SDK工具包,这里是windows操作系统。
在这里插入图片描述
,下载完成后找到对应设备的开发文档,看当前拿到的设备是否支持SDK二次开发。在这里插入图片描述
我这里用到的是IPC设备,则打开IPC设备对应的开发文档,根据上面设备的型号去开发文档上面去找。
在这里插入图片描述
确认SDK调用的主要流程
在这里插入图片描述

找到一个模块的功能
在这里插入图片描述

然后确认其SDK函数调用流程
在这里插入图片描述

SDK调用流程梳理

在这里插入图片描述
找到对应功能的Demo示例,修改Demo,此处直接将这个Demo集成到jetlinks协议包里面,
在这里插入图片描述
为了打包方便此处直接将依赖的两个jar包放在Maven对应的仓库里面去在这里插入图片描述
在这里插入图片描述
然后通过<dependency方式引入
在这里插入图片描述

package org.jetlinks.protocol.official;

import com.sun.jna.Pointer;
import com.sun.jna.ptr.ByteByReference;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;

import static org.jetlinks.protocol.official.ClientDemo.hCNetSDK;

/**
 * @ClassName VideoDemo
 * @Description
 * @Author SD.LIU
 * @Date 2023/6/6 16:12
 * @Version 1.0
 **/
public class VideoDemo implements Runnable {
    Timer Downloadtimer;//下载用定时器
    Timer Playbacktimer;//回放用定时器
    static FRealDataCallBack fRealDataCallBack;//预览回调函数实现
    //定义流的map集合
    static Map<Integer, FileOutputStream> outputStreamMap = new HashMap();
    static int lPlay = -1;  //预览句柄
    static File file;


    private Integer userId;

    private Integer iChannelNo;

    public VideoDemo(Integer userId, Integer iChannelNo) {
        this.userId = userId;
        this.iChannelNo = iChannelNo;
    }

    @Override
    public void run() {
        fRealDataCallBack = null;
        if (userId == -1) {
            System.out.println("请先注册");
            return;
        }
        HCNetSDK.NET_DVR_PREVIEWINFO strClientInfo = new HCNetSDK.NET_DVR_PREVIEWINFO();
        strClientInfo.read();
        strClientInfo.hPlayWnd = 0;  //窗口句柄,从回调取流不显示一般设置为空
        strClientInfo.lChannel = iChannelNo;  //通道号
        strClientInfo.dwStreamType = 0; //0-主码流,1-子码流,2-三码流,3-虚拟码流,以此类推
        strClientInfo.dwLinkMode = 0; //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4- RTP/RTSP,5- RTP/HTTP,6- HRUDP(可靠传输) ,7- RTSP/HTTPS,8- NPQ
        strClientInfo.bBlocked = 1;
        strClientInfo.write();

        if (fRealDataCallBack == null) {
            fRealDataCallBack = new FRealDataCallBack();
        }
        //开启预览
        lPlay = hCNetSDK.NET_DVR_RealPlay_V40(userId, strClientInfo, fRealDataCallBack, null);
        if (lPlay == -1) {
            int iErr = hCNetSDK.NET_DVR_GetLastError();
            System.out.println("取流失败" + iErr);
            return;
        }
        System.out.println("取流成功");
    }


    //创建文件

    /**
     * @param userId:登陆返回的用户句柄
     * @date 2022/8/31 23:37
     */
    public static void setFile(int userId) {
        file = new File("X:xxxx\\Download\\" + System.currentTimeMillis() + "(" + userId + ")" + ".mp4");  //保存回调函数的音频数据

        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
//            FileOutputStream outputStream=new FileOutputStream(file);
        try {

            outputStreamMap.put(userId, new FileOutputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }


    static class FRealDataCallBack implements HCNetSDK.FRealDataCallBack_V30 {
        //预览回调
        @Override
        public void invoke(int lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, Pointer pUser) {
            long offset = 0;
            ByteBuffer buffers = pBuffer.getPointer().getByteBuffer(offset, dwBufSize);
            byte[] bytes = new byte[dwBufSize];
            buffers.rewind();
            buffers.get(bytes);
            try {
                //从map中取出对应的流读取数据
                outputStreamMap.get(lRealHandle).write(bytes);
            } catch (Exception e) {
                e.printStackTrace();
            }


        }
    }


}

package org.jetlinks.protocol.official;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import org.jetlinks.protocol.official.common.osSelect;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @ClassName ClientDemo
 * @Description
 * @Author SD.LIU
 * @Date 2023/6/6 16:07
 * @Version 1.0
 **/
public class ClientDemo {



    public static HCNetSDK hCNetSDK = null;
    static PlayCtrl playControl = null;
    static int lUserID = 0;//用户句柄
    public static List<Integer> lUserIDList = new ArrayList<>();//用户句柄

    static FExceptionCallBack_Imp fExceptionCallBack;


    static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack {
        @Override
        public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {
            System.out.println("异常事件类型:" + dwType);
            return;
        }
    }

    public static void call() throws InterruptedException {

        if (hCNetSDK == null && playControl == null) {
            if (!CreateSDKInstance()) {
                System.out.println("Load SDK fail");
                return;
            }
            if (!CreatePlayInstance()) {
                System.out.println("Load PlayCtrl fail");
                return;
            }
        }
        String  strDllPath="";
        //linux系统建议调用以下接口加载组件库
        if (osSelect.isLinux()) {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限
            String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1";
            String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1";

            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
            ptrByteArray1.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());

            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
            ptrByteArray2.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());

            String strPathCom = System.getProperty("user.dir") + "/lib";
            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
            struComPath.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
        }

        //初始化
        init();

        //登陆
        login();


        // 创建线程池对象指定线程数量
        ExecutorService tp = Executors.newFixedThreadPool(2);

        VideoDemo video1 = new VideoDemo(lUserIDList.get(0), 1);

        tp.submit(video1);
    }


    //登陆
    private static void login() {

        //存储登陆设备集合
        List<Device> list = new ArrayList<>();
        Device device = new Device();
        device.setIp("169.254.194.72");
        device.setUserName("admin");
        device.setPassWord("abcd1234");

        list.add(device);
//        list.add(device1);

        //登录设备,每一台设备分别登录; 登录句柄是唯一的,可以区分设备
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo;//设备登录信息
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo;//设备信息

        for (Device d : list) {
            m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息
            m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息
            String m_sDeviceIP = d.getIp();//设备ip地址
            m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
            System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());

            String m_sUsername = d.getUserName();//设备用户名
            m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
            System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());

            String m_sPassword = d.getPassWord();//设备密码
            m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
            System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());

            m_strLoginInfo.wPort = 8000; //SDK端口
            m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是
            m_strLoginInfo.write();
            lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);

            //将登陆返回的用户句柄保存!(这里很重要 是原先官网没有的,这里保存句柄是为了预览使用)
            lUserIDList.add(lUserID);

            if (lUserID == -1) {
                System.out.println("登录失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
            } else {
                System.out.println("设备登录成功! " + "设备序列号:" + new String(m_strDeviceInfo.struDeviceV30.sSerialNumber).trim());
                m_strDeviceInfo.read();
            }
            //保存回调函数的音频数据
            VideoDemo.setFile(lUserID);

        }
    }


    //初始化
    private static void init() {

        //SDK初始化,一个程序只需要调用一次
        boolean initSuc = hCNetSDK.NET_DVR_Init();

        if (initSuc != true) {
            System.out.println("初始化失败");
        }

        //异常消息回调
        if (fExceptionCallBack == null) {
            fExceptionCallBack = new FExceptionCallBack_Imp();
        }

        Pointer pUser = null;
        if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) {
            return;
        }
        System.out.println("设置异常消息回调成功");

        //启动SDK写日志
        hCNetSDK.NET_DVR_SetLogToFile(3, "..\\sdkLog\\", false);

    }

    /**
     * 动态库加载
     *
     * @return
     */
    private static boolean CreateSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (osSelect.isWindows()) {
                        //win系统加载库路径
                        //strDllPath = System.getProperty("user.dir") + "\\lib\\HCNetSDK.dll";
                        strDllPath = "C:\\xxx\HCNetSDK.dll";
                    } else if (osSelect.isLinux()) {
                        //Linux系统加载库路径
                        //  strDllPath = System.getProperty("user.dir") + "/lib/libhcnetsdk.so";
                        strDllPath = "/usr/local/lib/libhcnetsdk.so";
                    }
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);


                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 播放库加载
     *
     * @return
     */
    private static boolean CreatePlayInstance() {
        if (playControl == null) {
            synchronized (PlayCtrl.class) {
                String strPlayPath = "";
                try {
                    if (osSelect.isWindows()) {
                        //win系统加载库路径
                        strPlayPath = System.getProperty("user.dir") + "\\lib\\PlayCtrl.dll";
                    } else if (osSelect.isLinux()) {
                        //Linux系统加载库路径
                        strPlayPath = System.getProperty("user.dir") + "/lib/libPlayCtrl.so";
                        playControl = (PlayCtrl) Native.loadLibrary("E:\\eclipse2019work\\ClientDemo-NetBeansPro\\PlayCtrl.dll", PlayCtrl.class);
                    }

                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strPlayPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    //注销设备
    public void videoWrite() {


        //退出程序时调用,每一台设备分别注销

        for (int id : lUserIDList) {
            if (hCNetSDK.NET_DVR_Logout(id)) {
                System.out.println("注销成功");
            }
        }


        lUserIDList.clear();


        //SDK反初始化,释放资源,只需要退出时调用一次
        hCNetSDK.NET_DVR_Cleanup();


        VideoDemo.outputStreamMap.clear();
    }


}

为了实验开发的协议的正确性将ClientDemo中的call方法修改一下:

    public static void main(String[] args) {

        if (hCNetSDK == null && playControl == null) {
            if (!CreateSDKInstance()) {
                System.out.println("Load SDK fail");
                return;
            }
            if (!CreatePlayInstance()) {
                System.out.println("Load PlayCtrl fail");
                return;
            }
        }
        String  strDllPath="";
        //linux系统建议调用以下接口加载组件库
        if (osSelect.isLinux()) {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限
            String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1";
            String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1";

            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
            ptrByteArray1.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());

            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
            ptrByteArray2.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());

            String strPathCom = System.getProperty("user.dir") + "/lib";
            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
            struComPath.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
        }

        //初始化
        init();

        //登陆
        login();


        // 创建线程池对象指定线程数量
        ExecutorService tp = Executors.newFixedThreadPool(2);

        VideoDemo video1 = new VideoDemo(lUserIDList.get(0), 1);

        tp.submit(video1);
    }

通过挂载的线程拉流,实现视频的预览功能:

在这里插入图片描述
视频下载工具获取地址:
https://www.hikvision.com/cn/support/tools/hitools/
在这里插入图片描述
如上图根据自己的开发环境选择合适VSPlayer播放器。

SDK集成JetLinks

这里只是一个小Demo,做初学的过程中尝试用,具体的集成流程根据实际的情况做实际的处理:
为了调试可以将jetlinks的协议包拖入到jetlinks-community-master项目里面,建立一个文件夹并把协议包拖进去,再鼠标选中协议包的pom.xml文件右键add as Maven project即完成项目的添加
在这里插入图片描述
再分析官方文档:
在如下这个链接中可以找到如下调用流程图:
https://doc.v1.jetlinks.cn/protocol/start.html#%E8%B0%83%E7%94%A8%E6%B5%81%E7%A8%8B
在这里插入图片描述
找一个最简单的方式实现真实设备的调用,这里选的是http调用下发的过程中实现设备的实时预览功能【这里的设备登录方法调用等都写在call方法里面的】:
在这里插入图片描述
然后启动项目,调用下发:
这里用的是Http模拟的,
具体Http设备配置流程可以参照如下链接:
https://hanta.yuque.com/px7kg1/yfac2l/qlr6nz5btr5rwrgk
先让模拟的设备上线,然后再调用下发,实现真实设备的调用:
在这里插入图片描述
点击获取最新属性
在这里插入图片描述
由于公司内网的原因,只演示到实际调用设备处,由下图可以看出已经去加载协议包对应的dll文件了,则jetlinks和协议包所写的设备代码已经可以实现联动调用了,调研结束。
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
JetLinks开源物联网平台基于Java8、Spring Boot 2.x、WebFlux、Netty、Vert.x、Reactor等开发,是一个开箱即用,可二次开发的企业级物联网基础平台。平台实现了物联网相关的众多基础功能,能帮助你快速建立物联网相关业务系统。 JetLinks开源物联网平台核心特性: 支持统一物模型管理,多种设备,多种厂家,统一管理。 统一设备连接管理,多协议适配(TCP、MQTT、UDP、CoAP、HTTP等),屏蔽网络编程复杂性,灵活接入不同厂家不同协议设备。 灵活的规则引擎,设备告警,消息通知,数据转发。可基于SQL进行复杂的数据处理逻辑。 地理位置:统一管理地理位置信息,支持区域搜索。 数据可视化:实现拖拽配置数据图表,设备组态等。 JetLinks开源物联网平台技术栈: Spring Boot 2.2.x Spring WebFlux 响应式Web支持 R2DBC 响应式关系型数据库驱动 Project Reactor 响应式编程框架 Netty、Vert.x 高性能网络编程框架 ElasticSearch 全文检索,日志,时序数据存储 PostgreSQL 业务功能数据管理 hsweb framework 4 业务功能基础框架     JetLinks开源物联网平台 更新日志: v1.9 1、增加设备独立物模型支持,可给单独的设备配置物模型. 2、基本实现GB28181国标视频设备接入,支持直播,云台控制,级联操作.(选配模块) 3、RabbitMQ增加routeKey配置,可在配置文件中指定device.message.writer.rabbitmq.consumer-route-key和device.message.writer.rabbitmq.producer-route-key.(Pro) 4、当设置了device.message.writer.rabbitmq.consumer=false时,不创建MQ消费者.(Pro) 5、设备支持独立物模型,可单独配置设备的物模型. 6、适配tdengine 2.0.16.0,优化sql长度策略. (pro) 7、优化规则引擎编辑器,实现组件模块化动态加载.(Pro) 8、修复启动服务时,如果某个产品物模型发布失败,导致后面的产品终止发布的问题. 9、增加ignoreLatest消息头,message.addHeader("ignoreLatest",true) 忽略记录最新数据到数据库. 10、修复租户下操作设备告警提示无权限.(Pro) 11、优化租户在解绑成员时,同时解绑成员的资产信息.(Pro) 12、优化子设备消息回复处理 13、物模型属性增加存储方式功能,可配置部分属性不存储. 14、增加虚拟属性功能,可通过规则来计算出虚拟属性值.(Pro) 15、增加租户成员绑定(TenantMemberBindEvent),解绑(TenantMemberUnBindEvent)事件.可通过spring-event订阅处理此事件.(Pro) 16、优化子设备状态检查,当检查子设备状态时,将会尝试发送ChildDeviceMessage<DeviceStateCheckMessage>给网关,处理后返回ChildDeviceMessageReply<DeviceStateCheckMessageReply>. 17、增加ClickHouse设备数据存储策略支持.(Pro) 18、增加权限过滤功能,可配置禁止赋予自己没有的权限给其他用户.hsweb.permission.filter相关配置 19、设备和产品的租户绑定逻辑优化: 绑定设备时,自动绑定产品.解绑产品时,自动解绑设备.(Pro) 20、用户管理增加租户权限控制.(Pro) 21、当向keepOnline的设备发送消息时,如果原始连接已断开,将返回CONNECTION_LOST错误. 22、设置keepOnline的会话将被持久化,重启服务后自动恢复.(Pro) 23、默认关闭设备最新数据存储,通过jetlinks.device.storage.enable-last-data-in-db=true开启.(Pro) 24、属性物模型增加属性值来源,配置为手动时,在发送修改属性指令(WritePropertyMessage)时,将直接生效,不会发送到设备. 25、优化租户资产解绑逻辑,当删除数据时,解绑资产全部的绑定关系.(Pro) 26、用户管理,机构管理增加租户端支持,租户可以自己管理自己的用户和机构.(Pro)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值