项目对接海康SDK

最近公司一个项目要对接海康的SDK, 落到了我手里, 折磨了我一个月, 写个博客来吐槽, 本篇只通过报警布防介绍对接海康SDK, 实时预览和视频回放下次一定。

一. 简介

设备网络SDK是基于设备私有网络通信协议开发的,为海康威视各类硬件产品服务的配套模块,用于远程访问和控制设备的软件二次开发。

二. 下载

下载地址: https://open.hikvision.com/download
从地址中选择硬件产品, 选择合适的版本下载即可。内含SDK动态库, 开发文档, Demo示例

三. 使用流程

接口调用主要流程

  1. 虚线指向为费必要操作;
  2. 功能模块可以单选多选不选;
  3. SDK资源和设备操作为必要操作, 否则会无法操作或者没有效果.

四. 对接Demo

本人使用Java开发报警预防相关, 则以此为例, 在Spring Boot项目中对接海康SDK.

1. 官方Demo

为方便理清思路, 将官方Demo的主要流程代码放置在此
官方Dmeo:
在使用之前请确保按照说明文档中的方法, 将相关文件和文件夹放置妥当

public static void main(String[] args) throws InterruptedException {
	// 加载SDK资源, 获取资源实例
	if (hCNetSDK == null) {
	    if (!CreateSDKInstance()) {
	        System.out.println("Load SDK fail");
	        return;
	    }
	}
	// 初始化
	hCNetSDK.NET_DVR_Init();
	// 加载日志
	hCNetSDK.NET_DVR_SetLogToFile(3, "../sdklog", false);
	//设置报警回调函数
	if (fMSFCallBack_V31 == null) {
	    fMSFCallBack_V31 = new FMSGCallBack_V31();
	    Pointer pUser = null;
	    if (!hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(fMSFCallBack_V31, pUser)) {
	        System.out.println("设置回调函数失败!");
	        return;
	    } else {
	        System.out.println("设置回调函数成功!");
	    }
	}
	/* 设备上传的报警信息是COMM_VCA_ALARM(0x4993)类型,
	 在SDK初始化之后增加调用NET_DVR_SetSDKLocalCfg(enumType为NET_DVR_LOCAL_CFG_TYPE_GENERAL)设置通用参数NET_DVR_LOCAL_GENERAL_CFG的byAlarmJsonPictureSeparate为1,
	 将Json数据和图片数据分离上传,这样设置之后,报警布防回调函数里面接收到的报警信息类型为COMM_ISAPI_ALARM(0x6009),
	 报警信息结构体为NET_DVR_ALARM_ISAPI_INFO(与设备无关,SDK封装的数据结构),更便于解析。*/
	HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struNET_DVR_LOCAL_GENERAL_CFG = new HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
	struNET_DVR_LOCAL_GENERAL_CFG.byAlarmJsonPictureSeparate = 1;   //设置JSON透传报警数据和图片分离
	struNET_DVR_LOCAL_GENERAL_CFG.write();
	Pointer pStrNET_DVR_LOCAL_GENERAL_CFG = struNET_DVR_LOCAL_GENERAL_CFG.getPointer();
	hCNetSDK.NET_DVR_SetSDKLocalCfg(17, pStrNET_DVR_LOCAL_GENERAL_CFG);
	// 设备登录
	Alarm.Login_V40(0, "10.17.35.41", (short) 8000, "admin", "abcd1234");
	// 设备布防
	Alarm.SetAlarm(0);
	while (true) {
	    //这里加入控制台输入控制,是为了保持连接状态,当输入Y表示布防结束
	    System.out.print("请选择是否撤出布防(Y/N):");
	    Scanner input = new Scanner(System.in);
	    String str = input.next();
	    if (str.equals("Y")) {
	        break;
	    }
	}
	Alarm.Logout(0);
}

此处注意官方Demo中的while(true), 下面会有使用和相关说明

2. 应用于SpringBoot项目中
(1) 配置

以下配置是本人项目中进行相关配置
配置类:

@Data
@Configuration
@ConfigurationProperties(prefix = "hik")
public class HCNetSDKConfig {

    public static HCNetSDKConfig HC_NET_SDK_CONFIG;

    /**
     * 登录的设备
     */
    public static List<DeviceApp> devices = new LinkedList<>();

    /**
     * SDK资源路径
     */
    private String sdkPath;

    /**
     * 日志文件路径
     */
    private String logPath;

    /**
     * 是否自动登录
     */
    private boolean deviceAutoLogin;

    /**
     * 设备用户名
     */
    private String username;

    /**
     * 设备密码
     */
    private String password;

    /**
     * 超脑ip
     */
    private String superBrainIp;

    @PostConstruct
    public void postConstruct() {
        HC_NET_SDK_CONFIG = this;
    }

}
  1. 项目的设备较少, 在配置类中用一个List作为设备存档, 具体存档方式应以具体项目具体选择.
  2. 项目中的所有设备用户名和密码一致, 所以此处使用配置作为数据项, 具体数据来源应以具体项目为准

配置文件:

hik:
  sdk-path: D:\\workspace\\idea\\hazard-chemical-web\\sdk
  device-auto-login: true
  super-brain-ip: 192.168.1.45
  username: admin
  password: 123456
(2) 应用

此处寡人是将此资源比作了一个应用, 所以代码中会有App字样
设备相关:
设备信息类:

@Data
@Accessors(chain = true)
public class Device {

    private String ip;

    private short port;

    private String username;

    private String password;

    private boolean userAsync;

    private String deviceName;

    private String id;

}

设备应用类:

@Data
public class DeviceApp {

    private static Logger log = LoggerFactory.getLogger(DeviceApp.class);

    private HCNetSDK hCNetSDK;

    /**
     * 设备信息
     */
    private Device device;

    private int lUserID = -1; //用户句柄

    private int lDChannel = -1; //IP通道号

    private int lAlarmHandle = -1; // 报警布防句柄

    /**
     * 注销标记
     */
    private boolean logout;

    public DeviceApp(HCNetSDK hcNetSDK, Device device){
        this.hCNetSDK = hcNetSDK;
        this.device = device;
    }

    /**
     * 设备登录
     * @return
     */
    public boolean deviceLogin() {
        if (!this.logout) {
            return true;
        }
        log.info(device.getIp() + ": 设备登录!");
        //登录设备,每一台设备分别登录; 登录句柄是唯一的,可以区分设备
        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();//设备信息

        String m_sDeviceIP = device.getIp();//设备ip地址
        m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
        System.arraycopy(m_sDeviceIP.getBytes(StandardCharsets.UTF_8), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());

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

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

        m_strLoginInfo.wPort = device.getPort(); //SDK端口
        m_strLoginInfo.bUseAsynLogin = device.isUserAsync(); //是否异步登录:0- 否,1- 是
        m_strLoginInfo.write();

        this.lUserID = this.hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
        if (this.lUserID == -1) {
            log.error("登录失败,错误码为" + this.hCNetSDK.NET_DVR_GetLastError());
            this.logout = true;
            return false;
        } else {
            log.info(m_sDeviceIP + ":设备登录成功! " + "设备序列号:" + new String(m_strDeviceInfo.struDeviceV30.sSerialNumber).trim());
            this.logout = false;
            m_strDeviceInfo.read();
        }
        //byStartDChan为IP通道起始通道号, 预览回放NVR的IP通道时需要根据起始通道号进行取值
        this.lDChannel = m_strDeviceInfo.struDeviceV30.byStartDChan;
        return true;
    }

    /**
     * 设备注销
     * @return
     */
    public boolean deviceLogout() {
        log.info("设备注销!");
        this.logout = hCNetSDK.NET_DVR_Logout(lUserID);
        return this.logout;
    }

    /**
     * 布防
     * @param device
     */
    public static void setAlarm(DeviceApp device) {
        log.info("布放!");
        //尚未布防,需要布防
        if (device.getLAlarmHandle() < 0) {
            //报警布防参数设置
            HCNetSDK.NET_DVR_SETUPALARM_PARAM_V50 m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM_V50();
            m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
            m_strAlarmInfo.byLevel = 1;  //布防等级
            m_strAlarmInfo.byAlarmInfoType = 1;   // 智能交通报警信息上传类型:0- 老报警信息(NET_DVR_PLATE_RESULT),1- 新报警信息(NET_ITS_PLATE_RESULT)
            m_strAlarmInfo.byDeployType = 1;   //布防类型:0-客户端布防,1-实时布防
            m_strAlarmInfo.write();
            String s = xmlData();
            log.info("xml 参数: {}", s);
            Pointer mode = new Memory(s.length() + 1);
            byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
            mode.write(0, bytes, 0, bytes.length);
            int lAlarmHandle = device.getHCNetSDK().NET_DVR_SetupAlarmChan_V50(device.getLUserID(), m_strAlarmInfo, mode, s.length() + 1);
//            int lAlarmHandle = device.getHCNetSDK().NET_DVR_SetupAlarmChan_V41(device.getLUserID(), m_strAlarmInfo);
            device.setLAlarmHandle(lAlarmHandle);
            log.info("lAlarmHandle: " + lAlarmHandle);
            if (lAlarmHandle == -1) {
                log.error("布防失败,错误码为" + device.getHCNetSDK().NET_DVR_GetLastError());
            } else {
                log.info("布防成功");

            }
        }
        else {
            log.info("设备已经布防,请先撤防!");
        }
    }
    
    @PreDestroy
    public void destroy() {
        log.info("设备销毁!");
        if (this.logout) {
            return;
        }
        for (int i = 0;!this.logout && i < 3 ; i++) {
            this.logout = deviceLogout();
        }
    }

    /**
     * 设备xml配置
     * @return
     */
    private static String xmlData() {
        return "<SubscribeEvent version=\"2.0\" xmlns=\"http://www.isapi.org/ver20/XMLSchema\">" +
                "<eventMode>list</eventMode>" +
                "<EventList>" +
                "<Event>" +
                "<type>fielddetection,</type>" +
                "<pictureURLType>binary</pictureURLType>" +
                "</Event>" +
                "<Event>" +
                "<type>linedetection</type>" +
                "<pictureURLType>binary</pictureURLType>" +
                "</Event>" +
                "<Event>" +
                "<type>group</type>" +
                "<pictureURLType>binary</pictureURLType>" +
                "</Event>" +
                "</EventList>" +
                "<channels>" +
                "</channels>" +
                "<identityKey>" +
                "</identityKey>" +
                "</SubscribeEvent>";
    }
}

资源应用:

@Data
@Component
public class HCNetSDKApp {

    private static Logger log = LoggerFactory.getLogger(HCNetSDKApp.class);
    @Autowired
    private HCNetSDKConfig hcNetSDKConfig;
    @Autowired
    private IVideoService videoService;

    /**
     * 释放资源标记
     */
    private boolean cleanup = true;

    private HCNetSDK hCNetSDK;

    private FExceptionCallBack_Imp fExceptionCallBack;

    /**
     * 初始化SDK资源
     * @return
     * @throws CreateSDKException
     */
    public boolean initSDKInstance() throws CreateSDKException {
        if (!this.cleanup) {
             return true;
        }
        log.info("SDK初始化!");
        // 创建SDK实例
        boolean createSDK = CreateSDKInstance();
        if (!createSDK) {
            log.error("创建SDK实例失败!");
            throw new CreateSDKException("创建SDK实例失败!");
        } else {
            log.info("创建SDK实例成功!");
        }
        // SDK资源初始化
        boolean initSDK = hCNetSDK.NET_DVR_Init();
        if (!initSDK) {
            log.error("初始化SDK资源失败!");
            hCNetSDK.NET_DVR_Cleanup();
            throw new CreateSDKException("初始化SDK资源失败!");
        } else {
            this.cleanup = false;
            log.info("初始化SDK资源成功!");
        }
        fExceptionCallBack = new FExceptionCallBack_Imp();
        Pointer pUser = null;
        if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) {
            log.info("初始化异常消息回调失败!");
            // 初始化异常消息回调失败, 释放SDK资源
            hCNetSDK.NET_DVR_Cleanup();
            this.cleanup = true;
            throw new CreateSDKException("初始化异常消息回调失败!");
        } else {
            log.info("初始化异常消息回调成功!");
        }
        //启动SDK写日志
        hCNetSDK.NET_DVR_SetLogToFile(3, hcNetSDKConfig.getLogPath(), false);
        return true;
    }

    /**
     * 自动登录
     */
    public void autoDevicesLogin() {
        AtomicBoolean flag = new AtomicBoolean(false);
        QueryWrapper<VideoShowModel> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("IP");
        wrapper.ne("IP", "");
        List<Video> videos = videoService.getBaseMapper().selectList(wrapper);
        List<Device> devices = videos.stream().map(item -> {
            if (hcNetSDKConfig.getSuperBrainIp().equals(item.getIp())) {
                flag.set(true);
            }
            Device device = new Device();
            device.setIp(item.getIp());
            device.setId(item.getSheetId());
            return device;
        }).collect(Collectors.toList());
        if (!flag.get()) {
            Device device = new Device();
            device.setIp(hcNetSDKConfig.getSuperBrainIp());
            devices.add(device);
        }
        devicesLogin(devices);
    }

    /**
     * 设备登录
     */
    public void devicesLogin(List<Device> devices) {
        for (Device device : devices) {
            deviceLogin(device);
        }
    }

    /**
     * 设备登录
     * @param device
     * @return
     */
    public DeviceApp deviceLogin(Device device) {
        try {
            DeviceApp deviceApp = new DeviceApp(this.hCNetSDK, device);
            // 设备登录注册
            boolean deviceLogin = deviceApp.deviceLogin();
            if (!deviceLogin) {
                log.error("注册设备失败!");
                throw new CreateSDKException("注册设备失败!");
            } else {
                log.info("注册设备成功!");
            }
            HCNetSDKConfig.devices.add(deviceApp);
            log.info("已登录设备数量: {}", HCNetSDKConfig.devices.size());
            return deviceApp;
        } catch (CreateSDKException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 释放SDK资源
     *
     * @return
     */
    public boolean cleanup() {
        log.info("释放SDK资源!");
        this.cleanup = hCNetSDK.NET_DVR_Cleanup();
        return this.cleanup;
    }

    @PreDestroy
    public void destroy() {
        log.info("SDK实例销毁!");
        if (this.cleanup) {
            return;
        }
        for (int i = 0; !this.cleanup && i < 3; i++) {
            if (!HCNetSDKConfig.devices.isEmpty()) {
                HCNetSDKConfig.devices.forEach(item -> {
                    boolean b = item.deviceLogout();
                });
            }
        }
        HCNetSDKConfig.devices.clear();
        cleanup();
    }

    static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack {
        public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {
            log.error("异常事件类型: {}", dwType);
            log.error("异常用户主键: {}", lUserID);
            log.error("异常处理: {}", lHandle);
            log.error("异常Pointer: {}", pUser);
        }
    }


    /**
     * 动态库加载
     *
     * @return
     */
    private boolean CreateSDKInstance() {
        log.info("创建SDK实例!");
        String strDllPath = "";
        log.info("hc net sdk config: {}", hcNetSDKConfig);
        try {
            if (OSSelectUtil.isWindows())
                //win系统加载库路径
                strDllPath = hcNetSDKConfig.getSdkPath() + "\\windows\\HCNetSDK.dll";
            else if (OSSelectUtil.isLinux())
                //Linux系统加载库路径
                strDllPath = hcNetSDKConfig.getSdkPath() + "/linux/libhcnetsdk.so";
            this.hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
            this.cleanup = false;
            return true;
        } catch (Exception ex) {
            log.error("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
            return false;
        }
    }
}

说明:

  1. 资源应用使用了Spring的组件注解@Component, 因为改资源只需要加载一次即可, 可以引用Spring的单例模式
  2. 注意: 在之前的配置项中, sdk-path使用了\\作为目录分隔符, 本项目是在windows服务器上运行, 所以使用windows目录格式, 尝试过使用/\两种方式, 都失败了,具体原因,我知道不知道,你自己体会吧.
  3. 此处的设备登录相关内容是本人项目中查询相关设备,然后调用设备中的登录方法,不一定非要在此处,可将其作为相关案例使用, 需根据项目要求进行合理处理.
(3) 流程

流程启动类

@Service
public class AlarmListenerServiceImpl implements IAlarmListenerService {

    @Autowired
    private HCNetSDKApp hcNetSDKApp;

    @PostConstruct
    public void startListener() {
		AlarmListenerTask task = new AlarmListenerTask(hcNetSDKApp);
		Thread thread = new Thread(task);
		thread.setDaemon(true);
		thread.start();
    }
}
  1. 启动方式有很多, 可以选择手动启动, 也可以选择项目运行时启动, 此处项目中采用项目启动时启动
  2. 项目启动时执行某些方法的方式有多种, 可参照博文: Springboot启动后执行方法的四种方式
  3. 此处使用新建守护线程的方式启动报警布防功能, 下方代码展示后便会知晓.

流程任务类

public class AlarmListenerTask implements Runnable {

    private static Logger log = LoggerFactory.getLogger(AlarmListenerTask.class);

    private HCNetSDKApp hcNetSDKApp;

    public AlarmListenerTask(HCNetSDKApp hcNetSDKApp) {
        this.hcNetSDKApp = hcNetSDKApp;
    }

    @Override
    public void run() {
        try {
            if (hcNetSDKApp.getHCNetSDK() == null) {
                boolean b = hcNetSDKApp.initSDKInstance();
            }
        } catch (CreateSDKException e) {
            log.error("SDK实例创建失败!");
        }
        FMSGCallBack_V31 fMSFCallBack_V31 = new FMSGCallBack_V31();
        Pointer pUser = null;
        if (!hcNetSDKApp.getHCNetSDK().NET_DVR_SetDVRMessageCallBack_V50(0, fMSFCallBack_V31, pUser)) {
            log.error("设置回调函数失败!");
            return;
        } else {
            log.info("设置回调函数成功!");
        }
        /* 设备上传的报警信息是COMM_VCA_ALARM(0x4993)类型,
         在SDK初始化之后增加调用NET_DVR_SetSDKLocalCfg(enumType为NET_DVR_LOCAL_CFG_TYPE_GENERAL)设置通用参数NET_DVR_LOCAL_GENERAL_CFG的byAlarmJsonPictureSeparate为1,
         将Json数据和图片数据分离上传,这样设置之后,报警布防回调函数里面接收到的报警信息类型为COMM_ISAPI_ALARM(0x6009),
         报警信息结构体为NET_DVR_ALARM_ISAPI_INFO(与设备无关,SDK封装的数据结构),更便于解析。*/
        HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG struNET_DVR_LOCAL_GENERAL_CFG = new HCNetSDK.NET_DVR_LOCAL_GENERAL_CFG();
        struNET_DVR_LOCAL_GENERAL_CFG.byAlarmJsonPictureSeparate = 1;   //设置JSON透传报警数据和图片分离
        struNET_DVR_LOCAL_GENERAL_CFG.write();
        Pointer pStrNET_DVR_LOCAL_GENERAL_CFG = struNET_DVR_LOCAL_GENERAL_CFG.getPointer();
        hcNetSDKApp.getHCNetSDK().NET_DVR_SetSDKLocalCfg(17, pStrNET_DVR_LOCAL_GENERAL_CFG);
        // 设备登录
        hcNetSDKApp.autoDevicesLogin();
        log.info("布防设备数量: {}", HCNetSDKConfig.devices.size());
        // 设备布防
        HCNetSDKConfig.devices.forEach(DeviceApp::setAlarm);
        // 维持线程
        while (true) {}
    }
}
  1. 此任务类中的run方法中便是整个布防流程
  2. while(true){}这个位置的代码即是前面官方Demo中的while代码的修改

关于为什么新建一个守护线程处理流程:

  1. SDK的模块功能需要维持一条线程保持运转,官方Demo中的while就是为了维持线程, 即使它被卡在while处无法继续向下进行,
    猜测:SDK为当前线程创建了守护线程进行布防监听, 当前线程中断了,布防的守护线程就挂掉了.
  2. main线程在加载资源后就会结束, 本人在初次尝试时即使用main执行流程,结果是报警回调后续便不再触发,所以选择新建一条线程来进行流程操作.
  3. 使用守护线程是因为代码中有死循环代码, 守护线程在主线程结束后便会被杀死.但前两天看博文,好像spring项目在结束程序时会杀死所有线程,具体我不太了解,希望有大佬解答.

之前昨晚后主管要我写一篇对接文档给之后的开发人员作指导, 然后就被拿去批复了,我看了批注之后我表示想买个袋子把他装起来吊着打.
问题1: 设备注册需要将所有的设备都注册吗?
我丢,你爱注册多少注册多少,要不去搜罗一下全球有多少海康的摄像头,都注册进去吧!
问题2: 设备在注册登录之后就要注销吗?
我去,微信登录了就要退出吗?人出生了就要下葬吗?

如果有幸有人能看到这篇博文, 请转告身边的人, 不要为难开发人员了, 他们不是万能的, 劝大家善良

日 期 : 2022 − 07 − 01 \color{#00FF00}{日期:2022-07-01} 20220701

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,我可以为您提供一些基本的步骤供您参考: 1. 先要确定您要使用的海康设备的型号以及对应的ISAPI接口文档。可以在海康官网上下载相应的文档。 2. 安装Python的requests库,用来发送HTTP请求。 3. 根据接口文档,编写Python代码调用相应的接口,实现布防操作。 以下是一个简单的示例代码,用来实现海康设备的布防操作: ``` import requests def set_device_arm(ip, port, username, password): url = "http://{0}:{1}/ISAPI/ContentMgmt/DefenseTasks".format(ip, port) headers = {'Content-Type': 'application/xml'} auth = requests.auth.HTTPDigestAuth(username, password) data = ''' <DefenseTasks version="2.0" xmlns="http://www.hikvision.com/ver20/XMLSchema"> <DefenseTask> <id>1</id> <name>Task1</name> <taskType>1</taskType> <defenseAreaNum>1</defenseAreaNum> <defenseAreaList> <DefenseArea> <id>1</id> <name>Area1</name> <enabled>true</enabled> <timeTemplate>1</timeTemplate> <alarmInList> <alarmInId>1</alarmInId> </alarmInList> </DefenseArea> </defenseAreaList> </DefenseTask> </DefenseTasks> ''' response = requests.put(url, headers=headers, auth=auth, data=data) if response.status_code == 200: print("Device armed successfully") else: print("Failed to arm device") if __name__ == '__main__': set_device_arm('192.168.1.100', 80, 'admin', 'password') ``` 在上面的示例代码中,我们使用了requests库发送了一个PUT请求到海康设备的ISAPI接口,来实现布防操作。其中IP地址、端口号、用户名、密码等参数需要根据实际情况进行修改。同时,布防操作的参数也需要根据接口文档进行调整。 希望这个示例代码能够帮助您完成海康设备ISAPI的封装库。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值