Packages
grizzly
5.2.3
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/network.ex
defmodule Grizzly.Network do
@moduledoc """
Module for working with the Z-Wave network
"""
alias Grizzly.{Associations, Connections, Report, SeqNumber, VirtualDevices, ZWave}
alias Grizzly.ZWave.Command
@typedoc """
Options for when you want to reset the device
- `:notify` - if the flag is set to true this will try to notify any node that
is part of the lifeline association group (default `true`)
"""
@type reset_opt() :: {:notify, boolean()}
@type opt() :: {:node_id, ZWave.node_id()} | {:seq_number, integer()}
@doc """
Get a list of node ids from the Z-Wave network
Just because a node id might be in the list does not mean the node is on the
network. A device might have been reset or unpaired from the controller with
out the controller knowing. However, in most use cases this shouldn't be an
issue.
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec get_node_ids([opt()]) :: Grizzly.send_command_response()
def get_node_ids(opts \\ []) do
seq_number = opts[:seq_number] || SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
Grizzly.send_command(node_id, :node_list_get, seq_number: seq_number)
end
@doc """
Gets all the node ids both from the Z-Wave network and any virtual nodes
If everything is okay the response will be `{:ok, list_of_node_ids}` where the
list of node ids will be a combination of actual Z-Wave devices and virtual
device ids.
"""
@doc since: "3.0.0"
@spec get_all_node_ids([opt()]) ::
{:ok, [ZWave.node_id() | VirtualDevices.id()]} | {:error, :timeout | :nack_response}
def get_all_node_ids(opts \\ []) do
case get_node_ids(opts) do
{:ok, %Report{type: :command, status: :complete, command: node_id_list}} ->
zwave_node_ids = Command.param!(node_id_list, :node_ids)
virtual_node_ids = VirtualDevices.list_nodes()
{:ok, zwave_node_ids ++ virtual_node_ids}
{:ok, %Report{type: :timeout}} ->
{:error, :timeout}
{:error, :nack_response} = error ->
error
end
end
@doc """
Reset the Z-Wave controller
This command takes a few seconds to run.
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec reset_controller([reset_opt() | opt()]) :: Grizzly.send_command_response()
def reset_controller(opts \\ []) do
# close all the connections before resetting the controller. It's okay
# to blindly close all connections because when we send the command to
# the controller Grizzly will automatically reconnect to the controller
# at that point in time. We do this because the connections to the Z-Wave
# devices are still reachable after being removed and we will still be
# sending keep alive messages when we don't need to and will have
# unnecessary connections hanging out just taking up resources.
:ok = Connections.close_all()
seq_number = SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
case Grizzly.send_command(node_id, :default_set, [seq_number: seq_number], timeout: 10_000) do
{:ok, %Report{type: :command, status: :complete}} = response ->
maybe_notify_reset(response, opts)
other ->
other
end
end
@doc """
Delete a node from the network's provisioning list via the node's DSK
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec delete_node_provisioning(Grizzly.ZWave.DSK.t(), [opt()]) ::
Grizzly.send_command_response()
def delete_node_provisioning(dsk, opts \\ []) do
seq_number = SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
Grizzly.send_command(node_id, :node_provisioning_delete, seq_number: seq_number, dsk: dsk)
end
@doc """
Get the nodes provisioning list information via the node's DSK
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec get_node_provisioning(Grizzly.ZWave.DSK.t(), [opt()]) ::
Grizzly.send_command_response()
def get_node_provisioning(dsk, opts \\ []) do
seq_number = SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
Grizzly.send_command(node_id, :node_provisioning_get, seq_number: seq_number, dsk: dsk)
end
@doc """
A node to the network provisioning list
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec set_node_provisioning(
Grizzly.ZWave.DSK.t(),
[Grizzly.ZWave.SmartStart.MetaExtension.extension()],
[opt()]
) :: Grizzly.send_command_response()
def set_node_provisioning(dsk, meta_extensions, opts \\ []) do
seq_number = SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
Grizzly.send_command(
node_id,
:node_provisioning_set,
seq_number: seq_number,
dsk: dsk,
meta_extensions: meta_extensions
)
end
@doc """
Add a long range device to the provisioning list
"""
@spec add_long_range_device(Grizzly.ZWave.DSK.t(), [opt()]) :: Grizzly.send_command_response()
def add_long_range_device(dsk, opts \\ []) do
extensions = [
bootstrapping_mode: :long_range,
smart_start_inclusion_setting: :pending,
advanced_joining: [:s2_unauthenticated, :s2_authenticated]
]
set_node_provisioning(dsk, extensions, opts)
end
@doc """
List all the nodes on the provisioning list
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec list_node_provisionings(integer(), [opt()]) :: Grizzly.send_command_response()
def list_node_provisionings(remaining_counter, opts \\ []) do
seq_number = SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
Grizzly.send_command(
node_id,
:node_provisioning_list_iteration_get,
seq_number: seq_number,
remaining_counter: remaining_counter
)
end
@doc """
Remove a (presumably) failed node
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec remove_failed_node([opt()]) ::
Grizzly.send_command_response()
def remove_failed_node(opts \\ []) do
seq_number = SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
Grizzly.send_command(:gateway, :failed_node_remove, seq_number: seq_number, node_id: node_id)
end
@doc """
Get the list of ids of all failed nodes.
"""
@spec report_failed_node_ids() :: {:ok, [Grizzly.ZWave.node_id()]} | {:error, atom}
def report_failed_node_ids() do
seq_number = Grizzly.SeqNumber.get_and_inc()
case Grizzly.send_command(1, :failed_node_list_get, seq_number: seq_number) do
{:ok,
%Grizzly.Report{
command: %Grizzly.ZWave.Command{
name: :failed_node_list_report,
params: params
},
status: :complete
}} ->
{:ok, Keyword.fetch!(params, :node_ids)}
{:ok, %Grizzly.Report{type: :timeout}} ->
{:error, :timeout}
{:error, reason} ->
{:error, reason}
end
end
@doc """
Request a network update (network healing)
Options
* `:node_id` - If your controller is part of another controller's network
you might want to issue network commands to that controller. By default
this option will chose your controller.
"""
@spec request_network_update([opt()]) ::
Grizzly.send_command_response()
def request_network_update(opts \\ []) do
seq_number = SeqNumber.get_and_inc()
node_id = node_id_from_opts(opts)
Grizzly.send_command(node_id, :network_update_request, seq_number: seq_number)
end
defp node_id_from_opts(opts) do
Keyword.get(opts, :node_id, :gateway)
end
defp maybe_notify_reset(response, opts) do
{:ok, %Report{command: command}} = response
case Command.param!(command, :status) do
:done ->
maybe_notify_reset(opts)
response
:busy ->
response
end
end
defp maybe_notify_reset(opts) do
if Keyword.get(opts, :notify, true) do
notify_reset()
else
:ok
end
end
defp notify_reset() do
# get the nodes in the lifeline group
case Associations.get(1) do
nil ->
:ok
association ->
Enum.each(association.node_ids, fn node_id ->
Grizzly.send_command(node_id, :device_reset_locally_notification)
end)
end
end
end