Packages
grizzly
0.8.4
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.ex
defmodule Grizzly do
@moduledoc """
Grizzly functions for controlling Z-Wave devices and the
Z-Wave network.
## Sending commands to Z-Wave
The most fundamental function in `Grizzly` is `Grizzly.send_command/3`.
There are two ways of using this function.
First, by passing in a node id for a node on the network:
```elixir
Grizzly.send_command(10, Grizzly.CommandClass.SwitchBinary.Get)
{:ok, :on}
Grizzly.send_command(10, Grizzly.CommandClass.SwitchBinary.Set, value: :off)
```
This is useful for short lived deterministic communication like `iex`
and scripts. This is because there is the overhead of connecting and
disconnecting to the node for each call.
For long lived applications that have non-deterministic sending of
messages (some type of automated commands) and user expectations on
device action we recommend using this function by passing in a
`Grizzly.Node`, `Grizzly.Conn`, or `Grizzly.Controller`.
```elixir
{:ok, zw_node} = Grizzly.get_node(10)
{:ok, zw_node} = Grizzly.Node.connect(zw_node)
{:ok, :on} = Grizzly.send_command(zw_node, Grizzly.CommandClass.SwitchBinary.Get)
:ok = Grizzly.send_command(zw_node, Grizzly.CommandClass.SwitchBinary.Set, value: :on)
```
This is useful because we maintain a heart beat with the node and overhead
of establishing the connection is removed from `send_command`.
In order for the consumer of Grizzly to use this in a long running application they
will need to hold on to a reference to the connected Z-Wave Node.
To know more commands and their arguments see the modules under the
`Grizzly.CommandClass` name space.
## Subscribing to Z-Wave messages
`Grizzly` has a pubsub module (`Grizzly.Notifications`) which is used for
sending or receiving notifications to and from `Grizzly`.
You can subscribe to notifications using:
```elixir
Grizzly.subscribe(topic)
```
This will subscribe the calling process to the supplied topic. So, if you
are using `iex` you can see recevied messages with `flush`, although it would
be most useful from a `GenServer` where you can use `handle_info` to handle
the notifications.
The available topics are:
:controller_connected,
:connection_established,
:unsolicited_message,
:node_added,
:node_removed,
:node_updated
You can also `Grizzly.Notifications` directly, where there are additional and
more useful functions available.
"""
alias Grizzly.{Conn, Command, Node, Controller, Notifications}
alias Grizzly.Conn.Config
alias Grizzly.Client.DTLS
@type seq_number :: 0..255
@typedoc """
A type the repersents things the have/can establish connections
to the Z/IP network.
1. `Conn.t` - A Connection struct
2. `Grizzly.Controller` - The controller process, this is a global, started on
application start process
3. `Node.t` - This is a Z-Wave Node that has been connected to the network
"""
@type connected :: Conn.t() | Controller | Node.t()
@conn_opts [:owner]
@spec config() :: Config.t()
def config() do
case Application.get_env(:grizzly, Grizzly.Controller) do
nil ->
Config.new(
ip: {0xFD00, 0xAAAA, 0, 0, 0, 0, 0, 1},
port: 41230,
client: DTLS
)
opts ->
Config.new(opts)
end
end
@doc """
Send a command to the Z-Wave device, first checking if in inclusion/exclusion state.
See individual command modules for information about what options it takes.
"""
@spec send_command(
connected | Node.node_id(),
command_module :: module,
command_opts :: keyword
) ::
:ok | {:ok, any} | {:error, any}
def send_command(connected, command_module, command_opts \\ [])
def send_command(%Conn{} = conn, command_module, opts) do
# an option in opts is either a command or connection option
command_opts = Keyword.drop(opts, @conn_opts)
conn_opts = opts -- command_opts
with {:ok, command} <- Command.start(command_module, command_opts) do
Conn.send_command(conn, command, conn_opts)
else
{:error, reason} ->
{:error, reason}
end
end
def send_command(Controller, command_module, command_opts) do
send_command(Controller.conn(), command_module, command_opts)
end
def send_command(%Node{conn: nil, id: 1}, command_module, command_opts) do
send_command(Controller, command_module, command_opts)
end
def send_command(%Node{conn: conn}, command_module, command_opts) do
send_command(conn, command_module, command_opts)
end
def send_command(node_id, command_module, command_opts) when is_integer(node_id) do
with {:ok, zw_node} <- Grizzly.get_node(node_id),
{:ok, zw_node} <- Node.connect(zw_node) do
response = send_command(zw_node, command_module, command_opts)
:ok = Node.disconnect(zw_node)
response
else
error -> error
end
end
@doc """
Close a connection
"""
@spec close_connection(Conn.t()) :: :ok
def close_connection(%Conn{} = conn) do
Conn.close(conn)
end
@doc """
Get a node from the network
This does not make a DTLS connection to the `Node.t()`
and if you want to connect to the node use `Grizzly.Node.connect/1`.
"""
@spec get_node(Node.node_id()) :: {:ok, Node.t()} | {:error, :node_not_found}
defdelegate get_node(node_id), to: Grizzly.Network
@doc """
Reset the Z-Wave Module to a clean state
"""
@spec reset_controller() :: :ok | {:error, :network_busy}
defdelegate reset_controller(), to: Grizzly.Network, as: :reset
@doc """
List the nodes on the Z-Wave network
"""
@spec get_nodes() :: {:ok, [Node.t()]} | {:error, :unable_to_get_nodes}
defdelegate get_nodes(), to: Grizzly.Network
@doc """
Check to see if the network is busy
"""
@spec network_busy?() :: boolean()
defdelegate network_busy?(), to: Grizzly.Network, as: :busy?
@doc """
Check to see if the network is ready
"""
@spec network_ready?() :: boolean()
defdelegate network_ready?(), to: Grizzly.Network, as: :ready?
@doc """
Put network in inclusion mode
"""
@spec add_node([Grizzly.Inclusion.opt()]) ::
:ok | {:error, {:invalid_option, Grizzly.Inclusion.invalid_opts_reason()}}
defdelegate add_node(opts \\ []), to: Grizzly.Inclusion
@doc """
Put network in exclusion mode
"""
@spec remove_node([Grizzly.Inclusion.opt()]) :: :ok
defdelegate remove_node(opts \\ []), to: Grizzly.Inclusion
@doc """
Put network out of inclusion mode
"""
@spec add_node_stop() :: :ok
defdelegate add_node_stop(), to: Grizzly.Inclusion
@doc """
Put network out of exclusion mode
"""
@spec remove_node() :: :ok
defdelegate remove_node_stop(), to: Grizzly.Inclusion
@doc """
Whether the node's command class versions are known
"""
@spec command_class_versions_known?(Node.t()) :: boolean
defdelegate command_class_versions_known?(zw_node), to: Grizzly.Node
@doc """
Update the command class version of a node
"""
@spec update_command_class_versions(Node.t()) :: Node.t()
defdelegate update_command_class_versions(zw_node), to: Node
@doc """
Put the controller in learn mode for a few seconds
"""
@spec start_learn_mode([Grizzly.Inclusion.opt()]) :: :ok
defdelegate start_learn_mode(opts \\ []), to: Grizzly.Inclusion
@doc """
Get the version of a node's command class, if the node does not have a version for
this command class this function will try to get it from the Z-Wave network.
"""
@spec get_command_class_version(Node.t(), atom) ::
{:ok, non_neg_integer} | {:error, atom}
defdelegate get_command_class_version(node, command_class_name), to: Node
@doc """
Whether a node has a given command class
"""
@spec has_command_class?(Node.t(), atom) :: boolean
defdelegate has_command_class?(node, command_class_name), to: Node
@doc """
Whether a node is connected.
"""
@spec connected?(Node.t()) :: boolean
defdelegate connected?(node), to: Node
@doc """
Get the command classes supported by a node.
"""
@spec command_class_names(Node.t()) :: [atom()]
defdelegate command_class_names(node), to: Node
@doc """
Subscribe to notifications about a topic
See `Grizzly.Notifications` for more information
"""
@spec subscribe(Notifications.topic()) :: :ok | {:error, :already_subscribed}
defdelegate subscribe(topic), to: Notifications
end