Elixir通过Onvif协议控制ip摄像机,扩展ExOnvif的获取预置位列表GetPresets

发布于:2025-09-05 ⋅ 阅读:(25) ⋅ 点赞:(0)

ExOnvif官方文档

扩展ExOnvif 调用指定预置位GotoPreset请参考此文章。

在使用 Elixir 进行 IPdome 控制时,可以使用 ExOnvif 库。
ExOnvif官方文档中未给出预置位调用命令,自己按照onvif协议 Onvif协议 扩展的此项功能;

Onvif协议获取预置位内容:
请添加图片描述
由以上协议可以看出,获取摄像机所有预置位,只需要一个参数 profile_token,返回值为:此摄像机已设置的所有预置位

步骤如下:

  • 初始化device设备
  • 获取device的profile_token
  • 获取设备的预置位表
  • 将返回值格式化
  # 初始化device设备
  defp get_device(uri) when not is_nil(uri) do
    %{host: host, userinfo: userinfo} =  URI.parse(uri)
    [user, pw] = String.split(userinfo, ":")
    Device.new("http://" <> host, user, pw);
  end

  defp get_device(uri) do
    :error
  end

  # 获取设备的 main streamprofile_token
  defp get_main_stream_profile_token(device) do
    profiles = Media2.get_profiles(device)
    case profiles do
      {:ok, list} -> {:ok, hd(list).reference_token}
      _ -> "something went wrong"
    end
  end

  # 获取设备所有的预置位
  defp get_presets(device, profile_token) do
    body = element("tptz:GetPresets", element("tptz:ProfileToken", profile_token))
    ptz_request(device, "GetPresets", body, fn _ -> :ok end)
  end

注意:提前导入需要的模块

完整文件onvif.action.ex文件

defmodule Onvif.Action do

  @moduledoc """
  自定义的Onvif的部分协议
  获取当前状态(exonvifabsolute move调用摄像头到指定位置,
  continuous move摄像头连续移动
  调用指定预置位
  停止运动
  """

  alias ExOnvif.Device
  alias ExOnvif.Media2
  import ExOnvif.Utils.ApiClient, only: [ptz_request: 4]

  defp get_device(uri) when not is_nil(uri) do
    %{host: host, userinfo: userinfo} =  URI.parse(uri)
    [user, pw] = String.split(userinfo, ":")
    Device.new("http://" <> host, user, pw);
  end

  defp get_device(uri) do
    :error
  end

  defp get_main_stream_profile_token(device) do
    profiles = Media2.get_profiles(device)
    case profiles do
      {:ok, list} -> {:ok, hd(list).reference_token}
      _ -> "something went wrong"
    end
  end

  # 获取设备所有的预置位
  defp get_presets(device, profile_token) do
    body = element("tptz:GetPresets", element("tptz:ProfileToken", profile_token))
    ptz_request(device, "GetPresets", body, fn _ -> :ok end)
    # 解析presets
    # end
  end

  # 获取所有预置位对外调用
  def get_presets(uri) do
    with {:ok, device} <- get_device(ip, username, password),
         {:ok, profile_token} <- get_main_stream_profile_token(device) do
    end
    get_presets(device, profile_token)
  end
获取预置位列表的标准xml文件: GetPresets
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
    xmlns:wsdl="http://www.onvif.org/ver20/ptz/wsdl"
    xmlns:sch="http://www.onvif.org/ver10/schema">
    
    <SOAP-ENV:Header>
        <!-- 安全认证头(根据设备要求) -->
        <Security SOAP-ENV:mustUnderstand="true"
            xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <UsernameToken>
                <Username>您的用户名</Username>
                <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
                    <!-- 密码需按ONVIF标准加密 -->
                </Password>
                <Nonce>随机数</Nonce>
                <Created>当前时间戳</Created>
            </UsernameToken>
        </Security>
    </SOAP-ENV:Header>
    
    <SOAP-ENV:Body>
        <wsdl:GetPresets>
            <!-- 必填参数:设备配置集Token -->
            <wsdl:ProfileToken>主码流配置Token</wsdl:ProfileToken>
        </wsdl:GetPresets>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>