Skip to content

Commit

Permalink
OSDOptions and GetOSDOptions (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloo authored Aug 5, 2024
1 parent d17dcb1 commit 4a939dc
Show file tree
Hide file tree
Showing 4 changed files with 443 additions and 0 deletions.
35 changes: 35 additions & 0 deletions lib/media/ver10/get_osd_options.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Onvif.Media.Ver10.GetOSDOptions do
import SweetXml
import XmlBuilder

alias Onvif.Device
alias Onvif.Media.Ver10.OSDOptions

@spec soap_action :: String.t()
def soap_action, do: "http://www.onvif.org/ver10/media/wsdl/GetOSDOptions"

@spec request(Device.t(), list) :: {:ok, any} | {:error, map()}
def request(device, args),
do: Onvif.Media.Ver10.Media.request(device, args, __MODULE__)

def request_body(token) do
element(:"s:Body", [
element(:"trt:GetOSDOptions", [
element(:"trt:ConfigurationToken", token)
])
])
end

def response(xml_response_body) do
xml_response_body
|> parse(namespace_conformant: true, quiet: true)
|> xpath(
~x"//s:Envelope/s:Body/trt:GetOSDOptionsResponse/trt:OSDOptions"e
|> add_namespace("s", "http://www.w3.org/2003/05/soap-envelope")
|> add_namespace("trt", "http://www.onvif.org/ver10/media/wsdl")
|> add_namespace("tt", "http://www.onvif.org/ver10/schema")
)
|> OSDOptions.parse()
|> OSDOptions.to_struct()
end
end
271 changes: 271 additions & 0 deletions lib/media/ver10/osd_options.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
defmodule Onvif.Media.Ver10.OSDOptions do
@moduledoc """
OSD (On-Screen Display) Options specification.
"""

use Ecto.Schema
import Ecto.Changeset
import SweetXml

@primary_key false
@derive Jason.Encoder
@required [:type, :position_option]
@optional []

embedded_schema do
field(:type, {:array, :string})
field(:position_option, {:array, :string})
embeds_one :maximum_number_of_osds, MaximumNumberOfOSDs, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:total, :integer)
field(:image, :integer)
field(:plaintext, :integer)
field(:date, :integer)
field(:time, :integer)
field(:date_and_time, :integer)
end
embeds_one :text_option, TextOption, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:type , {:array, :string})
embeds_one :font_size_range, FontSizeRange, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
field(:date_format, {:array, :string})
field(:time_format, {:array, :string})
embeds_one :font_color, FontColor, primary_key: false, on_replace: :update do
@derive Jason.Encoder
embeds_one :color, Color, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:color_list, {:array, :string})
embeds_one :color_space_range, ColorSpaceRange, primary_key: false, on_replace: :update do
@derive Jason.Encoder
embeds_one :x , X, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
embeds_one :y , Y, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
embeds_one :z , Z, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
field(:color_space, {:array, :string})
end
end
embeds_one :transparent, Transparent, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
end
embeds_one :background_color, BackgroundColor, primary_key: false, on_replace: :update do
@derive Jason.Encoder
embeds_one :color, Color, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:color_list, {:array, :string})
embeds_one :color_space_range, ColorSpaceRange, primary_key: false, on_replace: :update do
@derive Jason.Encoder
embeds_one :x , X, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
embeds_one :y , Y, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
embeds_one :z , Z, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
field(:color_space, {:array, :string})
end
end
embeds_one :transparent, Transparent, primary_key: false, on_replace: :update do
@derive Jason.Encoder
field(:min, :integer)
field(:max, :integer)
end
end
end
embeds_one :image_option, ImageOption, primary_key: false, on_replace: :update do
field(:formats_supported, {:array, :string})
field(:max_size, :integer)
field(:max_width, :integer)
field(:max_height, :integer)
field(:image_path, :string)
end
end

def parse(nil), do: nil
def parse([]), do: nil
def parse(doc) do
xmap(
doc,
type: ~x"./tt:Type/text()"slo,
position_option: ~x"./tt:PositionOption/text()"slo,
maximum_number_of_osds: ~x"./tt:MaximumNumberOfOSDs"eo |> transform_by(&parse_maximum_number_of_osds/1),
text_option: ~x"./tt:TextOption"eo |> transform_by(&parse_text_option/1),
image_option: ~x"./tt:ImageOption"eo |> transform_by(&parse_image_option/1)
)
end

def parse_maximum_number_of_osds([]), do: nil
def parse_maximum_number_of_osds(nil), do: nil
def parse_maximum_number_of_osds(doc) do
xmap(
doc,
total: ~x"//@Total"so,
image: ~x"//@Image"so,
plaintext: ~x"//@PlainText"so,
date: ~x"//@Date"so,
time: ~x"//@Time"so,
date_and_time: ~x"//@DateAndTime"so
)
end

def parse_text_option([]), do: nil
def parse_text_option(nil), do: nil
def parse_text_option(doc) do
xmap(
doc,
type: ~x"./tt:Type/text()"slo,
font_size_range: ~x"./tt:FontSizeRange"eo |> transform_by(&parse_int_range/1),
date_format: ~x"./tt:DateFormat/text()"slo,
time_format: ~x"./tt:TimeFormat/text()"slo,
font_color: ~x"./tt:FontColor"eo |> transform_by(&parse_text_color/1),
background_color: ~x"./tt:BackgroundColor"eo |> transform_by(&parse_text_color/1)
)
end

def parse_int_range([]), do: nil
def parse_int_range(nil), do: nil
def parse_int_range(doc) do
xmap(
doc,
min: ~x"./tt:Min/text()"so,
max: ~x"./tt:Max/text()"so
)
end

def parse_text_color([]), do: nil
def parse_text_color(nil), do: nil
def parse_text_color(doc) do
xmap(
doc,
color: ~x"./tt:Color"eo |> transform_by(&parse_color/1),
transparent: ~x"./tt:Transparent"eo |> transform_by(&parse_int_range/1)
)
end

def parse_color([]), do: nil
def parse_color(nil), do: nil
def parse_color(doc) do
xmap(
doc,
color_list: ~x"//@ColorList"so,
color_space_range: ~x"./tt:ColorSpaceRange"eo |> transform_by(&parse_color_space_range/1)
)
end

def parse_color_space_range([]), do: nil
def parse_color_space_range(nil), do: nil
def parse_color_space_range(doc) do
xmap(
doc,
x: ~x"./tt:X"eo |> transform_by(&parse_int_range/1),
y: ~x"./tt:Y"eo |> transform_by(&parse_int_range/1),
z: ~x"./tt:Z"eo |> transform_by(&parse_int_range/1),
color_space: ~x"//@ColorSpace"so
)
end

def parse_image_option([]), do: nil
def parse_image_option(nil), do: nil
def parse_image_option(doc) do
xmap(
doc,
formats_supported: ~x"./tt:FormatsSupported/text()"so,
max_size: ~x"//@MaxSize"so,
max_width: ~x"//@MaxWidth"so,
max_height: ~x"//@MaxHeight"so,
image_path: ~x"./tt:ImagePath/text()"so
)
end

def to_struct(parsed) do
%__MODULE__{}
|> changeset(parsed)
|> apply_action(:validate)
end

@spec to_json(%Onvif.Media.Ver10.OSDOptions{}) ::
{:error,
%{
:__exception__ => any,
:__struct__ => Jason.EncodeError | Protocol.UndefinedError,
optional(atom) => any
}}
| {:ok, binary}
def to_json(%__MODULE__{} = schema) do
Jason.encode(schema)
end

def changeset(osd_options, params \\ %{}) do
osd_options
|> cast(params, @required ++ @optional)
|> validate_required(@required)
|> cast_embed(:maximum_number_of_osds, with: &maximum_number_of_osds_changeset/2)
|> cast_embed(:text_option, with: &text_option_changeset/2)
|> cast_embed(:image_option, with: &image_option_changeset/2)
|> validate_subset(:type, ["Image", "Text", "Extended"])
|> validate_subset(:position_option, ["UpperLeft", "UpperRight", "LowerLeft", "LowerRight", "Custom"])
end

def maximum_number_of_osds_changeset(module, attrs) do
cast(module, attrs, [:total, :image, :plaintext, :date, :time, :date_and_time])
end

def text_option_changeset(module, attrs) do
cast(module, attrs, [:type, :date_format, :time_format])
|> cast_embed(:font_size_range, with: &int_range_changeset/2)
|> cast_embed(:font_color, with: &text_color_changeset/2)
|> cast_embed(:background_color, with: &text_color_changeset/2)
end

def int_range_changeset(module, attrs) do
cast(module, attrs, [:min, :max])
end

def text_color_changeset(module, attrs) do
cast(module, attrs, [])
|> cast_embed(:color, with: &color_changeset/2)
|> cast_embed(:transparent, with: &int_range_changeset/2)
end

def color_changeset(module, attrs) do
cast(module, attrs, [:color_list])
|> cast_embed(:color_space_range, with: &color_space_range_changeset/2)
end

def color_space_range_changeset(module, attrs) do
cast(module, attrs, [:color_space])
|> cast_embed(:x, with: &int_range_changeset/2)
|> cast_embed(:y, with: &int_range_changeset/2)
|> cast_embed(:z, with: &int_range_changeset/2)
end

def image_option_changeset(module, attrs) do
cast(module, attrs, [:formats_supported, :max_size, :max_width, :max_height, :image_path])
end

end
87 changes: 87 additions & 0 deletions test/media/ver10/fixtures/get_osd_options_valid.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope
xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:soapenc="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tt="http://www.onvif.org/ver10/schema"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl"
xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl"
xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl"
xmlns:tan="http://www.onvif.org/ver20/analytics/wsdl"
xmlns:tst="http://www.onvif.org/ver10/storage/wsdl"
xmlns:ter="http://www.onvif.org/ver10/error"
xmlns:dn="http://www.onvif.org/ver10/network/wsdl"
xmlns:tns1="http://www.onvif.org/ver10/topics"
xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl"
xmlns:wsoap12="http://schemas.xmlsoap.org/wsdl/soap12"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http"
xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery"
xmlns:wsadis="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
xmlns:wsrf-bf="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:wsntw="http://docs.oasis-open.org/wsn/bw-2"
xmlns:wsrf-rw="http://docs.oasis-open.org/wsrf/rw-2"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsrf-r="http://docs.oasis-open.org/wsrf/r-2"
xmlns:trc="http://www.onvif.org/ver10/recording/wsdl"
xmlns:tse="http://www.onvif.org/ver10/search/wsdl"
xmlns:trp="http://www.onvif.org/ver10/replay/wsdl"
xmlns:tnshik="http://www.hikvision.com/2011/event/topics"
xmlns:hikwsd="http://www.onvifext.com/onvif/ext/ver10/wsdl"
xmlns:hikxsd="http://www.onvifext.com/onvif/ext/ver10/schema"
xmlns:tas="http://www.onvif.org/ver10/advancedsecurity/wsdl"
xmlns:tr2="http://www.onvif.org/ver20/media/wsdl"
xmlns:axt="http://www.onvif.org/ver20/analytics">
<env:Body>
<trt:GetOSDOptionsResponse>
<trt:OSDOptions>
<tt:MaximumNumberOfOSDs Total="14" Image="4" PlainText="9" Date="1" Time="1" DateAndTime="1"></tt:MaximumNumberOfOSDs>
<tt:Type>Text</tt:Type>
<tt:PositionOption>UpperLeft</tt:PositionOption>
<tt:PositionOption>LowerLeft</tt:PositionOption>
<tt:PositionOption>Custom</tt:PositionOption>
<tt:TextOption>
<tt:Type>Plain</tt:Type>
<tt:Type>Date</tt:Type>
<tt:Type>Time</tt:Type>
<tt:Type>DateAndTime</tt:Type>
<tt:FontSizeRange>
<tt:Min>16</tt:Min>
<tt:Max>64</tt:Max>
</tt:FontSizeRange>
<tt:DateFormat>MM/dd/yyyy</tt:DateFormat>
<tt:DateFormat>dd/MM/yyyy</tt:DateFormat>
<tt:DateFormat>yyyy/MM/dd</tt:DateFormat>
<tt:DateFormat>yyyy-MM-dd</tt:DateFormat>
<tt:TimeFormat>hh:mm:ss tt</tt:TimeFormat>
<tt:TimeFormat>HH:mm:ss</tt:TimeFormat>
<tt:FontColor>
<tt:Color>
<tt:ColorspaceRange>
<tt:X>
<tt:Min>0.000000</tt:Min>
<tt:Max>255.000000</tt:Max>
</tt:X>
<tt:Y>
<tt:Min>0.000000</tt:Min>
<tt:Max>255.000000</tt:Max>
</tt:Y>
<tt:Z>
<tt:Min>0.000000</tt:Min>
<tt:Max>255.000000</tt:Max>
</tt:Z>
<tt:Colorspace>http://www.onvif.org/ver10/colorspace/YCbCr</tt:Colorspace>
</tt:ColorspaceRange>
</tt:Color>
</tt:FontColor>
</tt:TextOption>
</trt:OSDOptions>
</trt:GetOSDOptionsResponse>
</env:Body>
</env:Envelope>
Loading

0 comments on commit 4a939dc

Please sign in to comment.