Current section

Files

Jump to
grizzly lib grizzly virtual_devices reports.ex
Raw

lib/grizzly/virtual_devices/reports.ex

defmodule Grizzly.VirtualDevices.Reports do
@moduledoc false
# Helper module for building various general reports for a virtual device
alias Grizzly.Report
alias Grizzly.VirtualDevices
alias Grizzly.ZWave.Command
alias Grizzly.ZWave.Commands
alias Grizzly.ZWave.DeviceClass
alias Grizzly.ZWave.DSK
@doc """
Send the node add status message to the handler
"""
@spec send_node_add_status(VirtualDevices.device_entry(), Grizzly.handler()) :: :ok
def send_node_add_status(device_entry, handler) do
{handler, handler_opts} = ensure_handler_with_opts(handler)
{:ok, node_add_status} =
Commands.create(:node_add_status,
seq_number: 0x00,
node_id: device_entry.id,
status: :done,
listening?: true,
basic_device_class: device_entry.device_class.basic_device_class,
generic_device_class: device_entry.device_class.generic_device_class,
specific_device_class: device_entry.device_class.specific_device_class,
command_classes: command_classes_for_device(device_entry.device_class),
granted_keys: [],
kex_fail_type: :none,
input_dsk: DSK.new("")
)
report = Report.new(:complete, :command, device_entry.id, command: node_add_status)
handler.handle_report(report, handler_opts)
:ok
end
def send_node_remove_status(device_id, handler) do
{handler, handler_opts} = ensure_handler_with_opts(handler)
{:ok, node_remove_status} =
Commands.create(:node_remove_status, seq_number: 0x01, status: :done, node_id: device_id)
report = Report.new(:complete, :command, device_id, command: node_remove_status)
handler.handle_report(report, handler_opts)
:ok
end
defp ensure_handler_with_opts(handler_spec) when is_tuple(handler_spec), do: handler_spec
defp ensure_handler_with_opts(handler_module) when is_atom(handler_module),
do: {handler_module, []}
@doc """
Build a node info cached report based of a node info get command
"""
@spec build_node_info_cache_report(VirtualDevices.device_entry(), Command.t()) ::
Report.t()
def build_node_info_cache_report(entry, node_info_get) do
seq_number = Command.param!(node_info_get, :seq_number)
{:ok, node_info_report} =
Commands.create(:node_info_cached_report,
seq_number: seq_number,
status: :ok,
age: 1,
listening?: true,
command_classes: command_classes_for_device(entry.device_class),
basic_device_class: entry.device_class.basic_device_class,
specific_device_class: entry.device_class.specific_device_class,
generic_device_class: entry.device_class.generic_device_class
)
Report.new(:complete, :command, entry.id, command: node_info_report)
end
@doc """
Build manufacturer specific report for the device entry
"""
@spec build_manufacturer_specific_report(VirtualDevices.device_entry()) :: Report.t()
def build_manufacturer_specific_report(entry) do
{:ok, manufacturer_report} =
Commands.create(:manufacturer_specific_report,
manufacturer_id: entry.device_class.manufacturer_id,
product_id: entry.device_class.product_id,
product_type_id: entry.device_class.product_type_id
)
Report.new(:complete, :command, entry.id, command: manufacturer_report)
end
@doc """
Build version command class get for a command class in the entry's device
class
"""
@spec build_version_command_class_get_report(VirtualDevices.device_entry(), Command.t()) ::
Report.t()
def build_version_command_class_get_report(entry, version_command_class_get) do
command_class = Command.param!(version_command_class_get, :command_class)
case DeviceClass.get_command_class_version(entry.device_class, command_class) do
nil ->
build_timeout_report(entry.id)
version ->
{:ok, version_report} =
Commands.create(:version_command_class_report,
command_class: command_class,
version: version
)
build_report(entry, version_report)
end
end
@doc """
Build the association report from the association get command
"""
@spec build_association_report(VirtualDevices.device_entry()) :: Report.t()
def build_association_report(entry) do
{:ok, report} =
Commands.create(:association_report,
nodes: [1],
grouping_identifier: 1,
max_nodes_supported: 1,
reports_to_follow: 0
)
build_report(entry, report)
end
@doc """
Build a battery report for a battery get command
"""
@spec build_battery_report(VirtualDevices.device_entry()) :: Report.t()
def build_battery_report(entry) do
{:ok, report} = Commands.create(:battery_report, level: 100)
build_report(entry, report)
end
@doc """
Build a version report for a version get command
"""
@spec build_version_report(VirtualDevices.device_entry()) :: Report.t()
def build_version_report(entry) do
{:ok, report} =
Commands.create(:version_report,
library_type: entry.device_class.library_type,
protocol_version: "7.16",
firmware_version: "7.16",
hardware_version: 1,
other_firmware_versions: ["7.16"]
)
build_report(entry, report)
end
def build_manufacturer_specific_device_specific_report(entry, command) do
case Command.param!(command, :device_id_type) do
:serial_number ->
{:ok, report} =
Commands.create(:manufacturer_specific_device_specific_report,
device_id_type: :serial_number,
device_id: "0000"
)
build_report(entry, report)
_other ->
build_timeout_report(entry.id)
end
end
@doc """
Build a Grizzly Report for a timeout
"""
@spec build_timeout_report(VirtualDevices.id()) :: Report.t()
def build_timeout_report(device_id) do
Report.new(:complete, :timeout, device_id)
end
@doc """
Build an ack response report
"""
@spec build_ack_response(VirtualDevices.device_entry()) :: Report.t()
def build_ack_response(entry) do
Report.new(:complete, :ack_response, entry.id)
end
@doc """
Build a report that contains a command
"""
@spec build_report(VirtualDevices.device_entry(), Command.t()) :: Report.t()
def build_report(entry, command) do
Report.new(:complete, :command, entry.id, command: command)
end
defp command_classes_for_device(device_class) do
[
non_secure_supported: Map.keys(device_class.command_classes.support),
non_secure_controlled: Map.keys(device_class.command_classes.control)
]
end
end