springboot 海康SDK 客流统计分析

347 阅读7分钟

通过springboot集成海康SDK-告警布防,在告警回调中获取客流类型的告警数据,对周期性统计客流数据进行存储,定时对客流进行统计汇总

海康网络设备SDK下载地址:open.hikvision.com/download/5c…

在线开放文档地址:open.hikvision.com/docs/docId?…

海康SDK客流统计文档:open.hikvision.com/docs/docId?…

海康SDK接口调用流程图:open.hikvision.com/imgs/%E5%AE…

下载SDK后,文件夹下有不同语言demo和开发文档,由于海康网络设备sdk是使用c++开放的,所以在Java中需要使用JNA框架:

JNA(Java Native Access)框架是SUN公司主导开发的开源java框架,是建立在JNI的基础上的一个框架,JNA框架提供了一组java工具类用于在运行期间动态访问动态链接库(native library:如Window的dll、Linux的so),实现在java语言中调用C/C++语言封装的接口,java开发人员只需要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射,而不需要编写任何Native/JNI代码,大大降低了Java调用动态链接库的开发难度。

JNA官网:github.com/java-native…

告警布防步骤

  1. 配置动态加载链接库路径,win下dll文件,linux下so文件
  2. 结构体、接口重定义,HCNetSDK.java 对应 HCNetSDK.h中的结构体、接口
  3. 加载Library Native.loadLibrary(OSUtils.getLoadLibrary(path), HCNetSDK.class)
  4. 初始化sdk资源 NET_DVR_Init
  5. 设置全局告警回调 NET_DVR_SetDVRMessageCallBack_V50 多台设备对接时也只需要调用一次设置一个回调函数
  6. 登录设备 NET_DVR_Login_V40
  7. 告警布防 NET_DVR_SetupAlarmChan_V41
  8. 告警撤防 NET_DVR_CloseAlarmChan_V30
  9. 登出设备 NET_DVR_Logout
  10. 释放sdk资源 NET_DVR_Cleanup

获取客流

在全局告警回调中接收 HCNetSDK.COMM_ALARM_PDC 客流告警事件,解析客流告警信息。 分为两种客流统计:

  1. “实时统计结果”是计数发生变化时上传的实时统计结果(变化频繁的情况下每秒更新一次),自上次清零动作后开始计算的实时数量
  2. “周期统计结果”是设定统计周期内增加的数量,更新频率即为设定的统计周期(默认15分钟,最小1分钟,最大60分钟)

demo中提供对周期性统计进行异步数据处理存储,防止超时导致,告警数据未正常接收到。并定时计算每小时,每天客流量

主要代码

源码地址

主入口配置类

/**
 * @author LGC
 */
@Data
@Component
@ConfigurationProperties(prefix = "hikvision") // 配置 文件的前缀
public class HikvisionProperties {

    private String path;
    private boolean enabled;
    private List<Device> devices;

    @Data
    public static class Device {
        private String id;
        private String name;
        private String ip;
        private String port;
        private String username;
        private String password;
    }

}

/**
 * 条件是否加载sdk
 *
 * @author LGC
 */
@Slf4j
@Configuration
@ConditionalOnProperty(name = {"hikvision.enabled"}, havingValue = "true")
public class HikvisionConfig implements ApplicationRunner, DisposableBean {

    private final HikvisionProperties hikvisionProperties;
    private final HikvisionSdkService hikvisionSdkService;
    private final TjsldFlowDeviceDOService tjsldFlowDeviceDOService;
    @Getter
    public static CopyOnWriteArrayList<HikLoginDevice> hikLoginDevices;

    public HikvisionConfig(HikvisionProperties hikvisionProperties, HikvisionSdkService hikvisionSdkService, TjsldFlowDeviceDOService tjsldFlowDeviceDOService) {
        this.hikvisionProperties = hikvisionProperties;
        this.hikvisionSdkService = hikvisionSdkService;
        this.tjsldFlowDeviceDOService = tjsldFlowDeviceDOService;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //0. 加载设备
        List<HikvisionProperties.Device> devices = hikvisionProperties.getDevices();
        if (CollUtil.isEmpty(devices)) {
            devices = BeanUtil.copyToList(tjsldFlowDeviceDOService.list(), HikvisionProperties.Device.class);
            if (CollUtil.isEmpty(devices)) {
                return;
            }
        }
        hikLoginDevices = new CopyOnWriteArrayList<>();
        // 1.加载初始化sdk资源
        hikvisionSdkService.initSdk();
        // 2.设置全局告警回调 多台设备对接时也只需要调用一次设置一个回调函数
        hikvisionSdkService.setFMSGCallBack_V31();
        for (HikvisionProperties.Device device : devices) {
            // 3.登录设备
            HikLoginDevice hikLoginDevice = HikVisionAuthService.login(device.getIp(), device.getPort(), device.getUsername(), device.getPassword());
            hikLoginDevices.add(hikLoginDevice);
            // 4.告警布防
            AlarmHandler.setupAlarmChan(hikLoginDevice);
        }

    }

    @Override
    public void destroy() {
        if (CollUtil.isNotEmpty(hikLoginDevices)) {
            for (HikLoginDevice hikLoginDevice : hikLoginDevices) {
                // 5.告警撤防
                AlarmHandler.closeAlarmChan(hikLoginDevice);
                // 6.登出设备
                HikVisionAuthService.logout(hikLoginDevice.getUserId());
            }
        }
        // 7.释放sdk资源
        hikvisionSdkService.destroySdk();
    }

}

海康SDK相关封装

/**
 * @author LGC
 */
@Slf4j
@Configuration
@ConditionalOnProperty(name = {"hikvision.enabled"}, havingValue = "true")
public class HikvisionSdkService {

    public static HCNetSDK hCNetSDK = null;
    private final String path;
    private final FMSGCallBack_V31Impl fMSFCallBack_V31;

    public HikvisionSdkService(HikvisionProperties hikvisionProperties, FMSGCallBack_V31Impl fMSFCallBack_V31) {
        this.path = hikvisionProperties.getPath();
        this.fMSFCallBack_V31 = fMSFCallBack_V31;
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                try {
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(OSUtils.getLoadLibrary(path), HCNetSDK.class);
                } catch (Exception ex) {
                    log.error("SdkInitService-init-hCNetSDK-error", ex);
                }
            }
        }
    }

    public void initSdk() {
        try {
//            String userDir = System.getProperty("user.dir");
            if (OSUtils.getOsName().equals("linux")) {
                log.info("InitSdk-is-linux");
                String osPrefix = OSUtils.getOsPrefix();
                if (osPrefix.toLowerCase().startsWith("linux-i386")) {
                    HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
                    HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
                    String strPath1 = path + "libcrypto.so.1.1";
                    String strPath2 = path + "libssl.so.1.1";
//                    String strPath1 =userDir + "linux32/libcrypto.so.1.1";
//                    String strPath2 = userDir + "linux32/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 = path + "linux32/HCNetSDKCom/";
//                    String strPathCom =userDir + "linux32/HCNetSDKCom/";
                    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());
                } else if (osPrefix.toLowerCase().startsWith("linux-amd64")) {
                    HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
                    HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
                    String strPath1 = path + "libcrypto.so.1.1";
                    String strPath2 = path + "libssl.so.1.1";
//                    String strPath1 = userDir + "linux64/libcrypto.so.1.1";
//                    String strPath2 = userDir+ "linux64/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 = path + "linux64/HCNetSDKCom/";
//                    String strPathCom = userDir+ "linux64/HCNetSDKCom/";
                    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());
                } else {
                    log.info("osPrefix={}", osPrefix);
                }
            }
            //初始化sdk
            boolean isOk = hCNetSDK.NET_DVR_Init();
            hCNetSDK.NET_DVR_SetConnectTime(2000, 1);
            hCNetSDK.NET_DVR_SetReconnect(10000, true);
            if (!isOk) {
                log.error("=================== InitSDK init fail ===================");
            } else {
                log.info("============== InitSDK init success ====================");
            }

        } catch (Exception e) {
            log.error("InitSDK-error", e);
        }
    }

    public void setFMSGCallBack_V31() {
        // 设置报警回调函数
        if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V50(0, fMSFCallBack_V31, Pointer.NULL)) {
            log.info("设置报警回调函数失败:{}", HikvisionSdkService.hCNetSDK.NET_DVR_GetLastError());
        }
    }

    public void destroySdk() {
        hCNetSDK.NET_DVR_Cleanup();
    }


}


/**
 * @author LGC
 */
@Slf4j
public class HikVisionAuthService {

    public static HikLoginDevice login(String m_sDeviceIP, String wPort, String m_sUsername, String m_sPassword) {
        log.info("m_sDeviceIP:{}wPort:{} m_sUsername:{} m_sPassword:{}", m_sDeviceIP, wPort, m_sUsername, m_sPassword);
        //注册
        HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息
        HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息

        //设备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());

        //设备用户名
        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());

        //设备密码
        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 = Short.parseShort(wPort);
        m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是
        m_strLoginInfo.byLoginMode = 0;  //ISAPI登录
        m_strLoginInfo.write();

        int lUserID = HikvisionSdkService.hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (lUserID == -1) {
            int errorCode = HikvisionSdkService.hCNetSDK.NET_DVR_GetLastError();
            IntByReference errorInt = new IntByReference(errorCode);
            log.error("[HK] login fail errorCode:{}, errMsg:{}", errorCode, HikvisionSdkService.hCNetSDK.NET_DVR_GetErrorMsg(errorInt));
        }
        HikLoginDevice hikLoginDevice = new HikLoginDevice();
        hikLoginDevice.setUserId(lUserID);
        hikLoginDevice.setIp(m_sDeviceIP);
        hikLoginDevice.setPort(wPort);
        hikLoginDevice.setUsername(m_sUsername);
        hikLoginDevice.setPassword(m_sPassword);
        return hikLoginDevice;

    }

    public static void logout(int lUserID) {
        if (lUserID > -1) {
            if (HikvisionSdkService.hCNetSDK.NET_DVR_Logout(lUserID)) {
                log.info("注销成功");
            }
        }
    }
}

全局告警回调

/**
 * 全局报警信息回调函数
 *
 * @author LGC
 */
@Slf4j
@Component
public class FMSGCallBack_V31Impl implements HCNetSDK.FMSGCallBack_V31 {

    @Resource
    private FlowAlarmEventPublisher flowAlarmEventPublisher;

    /**
     * @param lCommand   上传消息类型
     * @param pAlarmer   报警设备信息
     * @param pAlarmInfo 报警信息
     * @param dwBufLen   报警信息缓存大小
     * @param pUser      用户数据
     * @return
     */
    @Override
    public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
        alarmDataHandle(lCommand, pAlarmer, pAlarmInfo, dwBufLen, pUser);
        return true;
    }

    //

    /**
     * 解析设备信息
     *
     * @param alarm
     * @return
     */
    public HikDeviceInfo resolveDeviceInfo(HCNetSDK.NET_DVR_ALARMER alarm) {
        HikDeviceInfo hikDeviceInfo = new HikDeviceInfo();
        if (alarm.byUserIDValid == 1) {
            hikDeviceInfo.setUserId(alarm.lUserID);
        }
        if (alarm.byDeviceIPValid == 1) {
            String deviceIp = new String(alarm.sDeviceIP).trim();
            hikDeviceInfo.setDeviceIp(deviceIp);
        }
        if (alarm.byDeviceNameValid == 1) {
            String deviceName = new String(alarm.sDeviceName).trim();
            hikDeviceInfo.setDeviceIp(deviceName);
        }
        if (alarm.bySerialValid == 1) {
            String serialNumber = new String(alarm.sSerialNumber).trim();
            hikDeviceInfo.setSerialNumber(serialNumber);
        }
        if (alarm.byMacAddrValid == 1) {
            String macAddr = new String(alarm.byMacAddr).trim();
            hikDeviceInfo.setDeviceMacAddr(macAddr);
        }
        alarm.toString();
        log.info("device info ====== {}", hikDeviceInfo);
        return hikDeviceInfo;
    }

    /**
     * 接收设备上传的报警信息
     *
     * @param lCommand   报警事件类型
     * @param pAlarmer   报警设备信息
     * @param pAlarmInfo 报警信息
     * @param dwBufLen   报警信息缓存大小
     * @param pUser      用户数据
     * @return
     */
    public void alarmDataHandle(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
//        log.info("报警事件类型: lCommand:{}", lCommand);
        switch (lCommand) {
            //客流统计
            case HCNetSDK.COMM_ALARM_PDC:
                HikDeviceInfo hikDeviceInfo = resolveDeviceInfo(pAlarmer);
                HCNetSDK.NET_DVR_PDC_ALRAM_INFO strPDCResult = new HCNetSDK.NET_DVR_PDC_ALRAM_INFO();
                strPDCResult.write();
                Pointer pPDCInfo = strPDCResult.getPointer();
                pPDCInfo.write(0, pAlarmInfo.getByteArray(0, strPDCResult.size()), 0, strPDCResult.size());
                strPDCResult.read();
                // byMode=0-实时统计结果(联合体中struStatFrame有效),
                if (strPDCResult.byMode == 0) {
                    strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATFRAME.class);
                    String sAlarmPDC0Info = "实时客流量统计,进入人数:" + strPDCResult.dwEnterNum + ",离开人数:" + strPDCResult.dwLeaveNum +
                            ", byMode:" + strPDCResult.byMode + ", dwRelativeTime:" + strPDCResult.uStatModeParam.struStatFrame.dwRelativeTime +
                            ", dwAbsTime:" + strPDCResult.uStatModeParam.struStatFrame.dwAbsTime +
                            ", dwAbsTime:" + CommonUtil.hikAbsTimeToStrDate(strPDCResult.uStatModeParam.struStatFrame.dwAbsTime);
                    log.info(sAlarmPDC0Info);
                }
                // byMode=1-周期统计结果(联合体中struStatTime有效),
                if (strPDCResult.byMode == 1) {
                    strPDCResult.uStatModeParam.setType(HCNetSDK.NET_DVR_STATTIME.class);
//                    String strtmStart = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwYear) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMonth) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwDay) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwHour) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwMinute) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmStart.dwSecond);

//                    String strtmEnd = "" + String.format("%04d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwYear) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMonth) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwDay) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwHour) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwMinute) +
//                            String.format("%02d", strPDCResult.uStatModeParam.struStatTime.tmEnd.dwSecond);
                    String strtmStart = strPDCResult.uStatModeParam.struStatTime.tmStart.toStringTime();
                    String strtmEnd = strPDCResult.uStatModeParam.struStatTime.tmEnd.toStringTime();
                    String info = "客流周期统计,进入人数:" + strPDCResult.dwEnterNum + ",离开人数:" + strPDCResult.dwLeaveNum +
                            ", byMode:" + strPDCResult.byMode + ", tmStart:" + strtmStart + ",tmEnd :" + strtmEnd;
//                    String sAlarmPDC0Info = "byChannel通道号:%s,dwPassingNum 经过人数:%s, dwChildLeaveNum小孩离开人数:%s, dwChildEnterNum小孩进入人数:%s, dwDuplicatePeople重复人数:%s";
//                    log.info(String.format(sAlarmPDC0Info, strPDCResult.byChannel, strPDCResult.dwPassingNum, strPDCResult.dwChildLeaveNum, strPDCResult.dwChildEnterNum, strPDCResult.dwDuplicatePeople));
                    log.info(info);
                    FlowAlarmDTO flowAlarmDTO = new FlowAlarmDTO(hikDeviceInfo, strtmStart, strtmEnd, strPDCResult.dwEnterNum, strPDCResult.dwLeaveNum);
                    flowAlarmDTO.setChannel(strPDCResult.byChannel);
                    flowAlarmDTO.setPassingValue(strPDCResult.dwPassingNum);
                    flowAlarmDTO.setChildInValue(strPDCResult.dwChildEnterNum);
                    flowAlarmDTO.setChildOutValue(strPDCResult.dwChildLeaveNum);
                    flowAlarmDTO.setDuplicateValue(strPDCResult.dwDuplicatePeople);
                    flowAlarmEventPublisher.publish(flowAlarmDTO);
                }
                break;
            default:
                log.info("其他报警信息==========");
                break;
        }
    }
}

告警布防

/**
 * 告警布防
 *
 * @author LGC
 */
@Slf4j
public class AlarmHandler {

    /**
     * 报警布防
     */
    public static int setupAlarmChan(HikLoginDevice hikLoginDevice) {
        int lUserID = hikLoginDevice.getUserId();
        if (lUserID == -1) {
            log.info("请先注册");
            return lUserID;
        }
        int lAlarmHandle = hikLoginDevice.getSetupAlarmHandle();
        if (lAlarmHandle < 0) {
            HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
            m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
            //智能交通布防优先级:0- 一等级(高),1- 二等级(中),2- 三等级(低)
            m_strAlarmInfo.byLevel = 1;
            //智能交通报警信息上传类型:0- 老报警信息(NET_DVR_PLATE_RESULT), 1- 新报警信息(NET_ITS_PLATE_RESULT)
            m_strAlarmInfo.byAlarmInfoType = 1;
            //布防类型(仅针对门禁主机、人证设备):0-客户端布防(会断网续传),1-实时布防(只上传实时数据)
            m_strAlarmInfo.byDeployType = 1;
            m_strAlarmInfo.write();
            lAlarmHandle = HikvisionSdkService.hCNetSDK.NET_DVR_SetupAlarmChan_V41(lUserID, m_strAlarmInfo);
            if (lAlarmHandle == -1) {
                int errorCode = HikvisionSdkService.hCNetSDK.NET_DVR_GetLastError();
                log.info("布防失败errorCode:{}, errMsg:{}", errorCode, HikvisionSdkService.hCNetSDK.NET_DVR_GetErrorMsg(new IntByReference(errorCode)));
                return lAlarmHandle;
            } else {
                log.info("报警布防成功");
            }
        }
        hikLoginDevice.setSetupAlarmHandle(lAlarmHandle);
        boolean setExceptionResult = HikvisionSdkService.hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, lAlarmHandle, new DeviceExceptionCallback(), null);
        if (!setExceptionResult) {
            int errorCode = HikvisionSdkService.hCNetSDK.NET_DVR_GetLastError();
            log.info("报警布防,设置异常回调 失败 errorCode:{}, errMsg:{}", errorCode, HikvisionSdkService.hCNetSDK.NET_DVR_GetErrorMsg(new IntByReference(errorCode)));
            closeAlarmChan(hikLoginDevice);
        }
        hikLoginDevice.setSetupAlarmHandle(lAlarmHandle);
        return lAlarmHandle;
    }

    /**
     * 报警撤防
     */
    public static void closeAlarmChan(HikLoginDevice hikLoginDevice) {
        int lAlarmHandle = hikLoginDevice.getSetupAlarmHandle();
        if (lAlarmHandle > -1) {
            if (HikvisionSdkService.hCNetSDK.NET_DVR_CloseAlarmChan_V30(lAlarmHandle)) {
                log.info("报警撤防 成功");
            }
            hikLoginDevice.setSetupAlarmHandle(-1);
        }
    }

    /**
     * 布防告警异常回调处理
     *
     * @author LGC
     */
    @Slf4j
    public static class DeviceExceptionCallback implements HCNetSDK.FExceptionCallBack {

        public static final DeviceExceptionCallback INSTANCE = new DeviceExceptionCallback();

        @Override
        public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {
            log.info("布防告警异常回调 异常事件类型dwType:{},lUserID:{},lHandle:{}", dwType, lUserID, lHandle);
        }
    }
}