Packages
grizzly
0.22.2
9.1.4
9.1.2
9.1.1
9.1.0
9.0.0
8.15.3
8.15.2
8.15.1
8.15.0
8.14.0
8.13.0
8.12.0
8.11.3
8.11.2
8.11.1
8.11.0
8.10.0
8.9.0
8.8.1
8.8.0
8.7.1
8.7.0
8.6.12
8.6.11
8.6.10
8.6.9
8.6.8
8.6.7
retired
8.6.6
8.6.5
8.6.4
8.6.3
8.6.2
8.6.1
8.6.0
8.5.3
8.5.2
8.5.1
8.5.0
8.4.0
8.3.0
8.2.3
8.2.2
8.2.1
8.2.0
8.1.0
8.0.1
8.0.0
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.0
7.1.4
7.1.3
7.1.2
7.1.1
7.1.0
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.8.8
6.8.7
6.8.6
6.8.5
6.8.4
6.8.3
6.8.2
6.8.1
6.8.0
6.7.1
6.7.0
6.6.1
6.6.0
6.5.1
6.5.0
6.4.0
6.3.0
6.2.0
6.1.1
6.1.0
6.0.1
6.0.0
5.4.1
5.4.0
5.3.0
5.2.8
5.2.7
5.2.6
5.2.5
5.2.4
5.2.3
5.2.2
5.2.1
5.2.0
5.1.2
5.1.1
5.1.0
5.0.2
5.0.1
5.0.0
4.0.1
4.0.0
3.0.0
2.1.0
2.0.0
1.0.1
1.0.0
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.9.0-rc.4
0.9.0-rc.3
0.9.0-rc.2
0.9.0-rc.1
0.9.0-rc.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
Elixir Z-Wave library
Current section
Files
Jump to
Current section
Files
lib/grizzly/zwave/commands/extended_node_add_status.ex
defmodule Grizzly.ZWave.Commands.ExtendedNodeAddStatus do
@moduledoc """
ExtendedNodeAddStatus
This command is used to report the result of a node inclusion of an a node
with an extended node id, normally a long range node.
Params:
* `:seq_number` - the sequence number of the inclusion command
* `:status` - the status of the inclusion
* `:node_id` - the new id of the new Z-Wave node
* `:listening?` - if the node is a listening node or not
* `:basic_device_class` - the Z-Wave basic device class
* `:generic_device_class` - the Z-Wave generic device class
* `:specific_device_class` - the Z-Wave specific device class
* `:command_classes` - a list of the command class the device supports, tagged by their security level
used only if the device was included securely
* `:granted_keys` - the security keys granted during S2 inclusion
* `:kex_fail_type` - the error that occurred in the S2 bootstrapping
"""
@behaviour Grizzly.ZWave.Command
alias Grizzly.ZWave.{Command, CommandClasses, Security}
alias Grizzly.ZWave.CommandClasses.NetworkManagementInclusion
@type tagged_command_classes() ::
{:non_secure_supported, [CommandClasses.command_class()]}
| {:non_secure_controlled, [CommandClasses.command_class()]}
| {:secure_supported, [CommandClasses.command_class()]}
| {:secure_controlled, [CommandClasses.command_class()]}
@type param() ::
{:node_id, Grizzly.node_id()}
| {:status, NetworkManagementInclusion.node_add_status()}
| {:seq_number, Grizzly.seq_number()}
| {:listening?, boolean()}
| {:basic_device_class, byte()}
| {:generic_device_class, byte()}
| {:specific_device_class, byte()}
| {:command_classes, [tagged_command_classes()]}
| {:granted_keys, [Security.key()]}
| {:kex_fail_type, Security.key_exchange_fail_type()}
@impl Grizzly.ZWave.Command
@spec new([param()]) :: {:ok, Command.t()}
def new(params \\ []) do
# TODO: validate params
command = %Command{
name: :extended_node_add_status,
command_byte: 0x16,
command_class: NetworkManagementInclusion,
params: params,
impl: __MODULE__
}
{:ok, command}
end
@impl Grizzly.ZWave.Command
def encode_params(command) do
node_id = Command.param!(command, :node_id)
status = Command.param!(command, :status)
seq_number = Command.param!(command, :seq_number)
status_byte = NetworkManagementInclusion.node_add_status_to_byte(status)
if status == :failed do
<<seq_number, status_byte, node_id::16, 0x01>>
else
listening? = Command.param!(command, :listening?)
basic_device_class = Command.param!(command, :basic_device_class)
generic_device_class = Command.param!(command, :generic_device_class)
specific_device_class = Command.param!(command, :specific_device_class)
command_classes = Command.param!(command, :command_classes)
# We add 6 to the length of the command classes to account for the 3 device
# classes 2 Z-Wave protocol bytes and the node info length byte.
# Also add the number of command classes plus 4 bytes for the separators
# See SDS13784 4.4.8.2 for more details
node_info_length = 6 + cc_count(command_classes)
listening_bit = if listening?, do: 1, else: 0
# TODO: fix opt func bit (after the listening bit)
<<seq_number, status_byte, node_id::16, node_info_length, listening_bit::size(1),
0x00::size(7), 0x00, basic_device_class, generic_device_class,
specific_device_class>> <>
CommandClasses.command_class_list_to_binary(command_classes) <>
add_keys_granted_and_fail_type(command)
end
end
@impl Grizzly.ZWave.Command
def decode_params(<<seq_number, status_byte, node_id::16, node_info_bin::binary>>) do
node_info = NetworkManagementInclusion.parse_node_info(node_info_bin)
params =
%{
status: NetworkManagementInclusion.parse_node_add_status(status_byte),
seq_number: seq_number,
node_id: node_id
}
|> Map.merge(node_info)
|> Enum.into([])
{:ok, params}
end
def decode_params(<<seq_number, status_byte, node_id::16, 0x01>>) do
{:ok,
[
status: NetworkManagementInclusion.parse_node_add_status(status_byte),
seq_number: seq_number,
node_id: node_id,
listening?: false,
basic_device_class: :unknown,
generic_device_class: :unknown,
specific_device_class: :unknown,
command_classes: []
]}
end
defp add_keys_granted_and_fail_type(command) do
keys = Command.param!(command, :keys_granted)
kex_failed_type = Command.param!(command, :kex_fail_type)
<<Security.keys_to_byte(keys), Security.failed_type_to_byte(kex_failed_type)>>
end
defp cc_count(tagged_command_classes) do
padding = get_padding(tagged_command_classes)
cc_length = tagged_command_classes |> Keyword.values() |> List.flatten() |> length()
cc_length + padding
end
defp get_padding(tagged_command_classes) do
Enum.reduce(tagged_command_classes, 0, fn
{_, []}, padding ->
padding
{:secure_supported, _}, padding ->
padding + 2
{other, _}, padding when other in [:non_secure_controlled, :secure_controlled] ->
padding + 1
_, padding ->
padding
end)
end
end