Search documentation of grizzly

# View Source Grizzly.Inclusions (grizzly v7.4.2)

Module for adding and removing Z-Wave nodes

In Z-Wave the term "inclusions" means two things:

1. Adding a new Z-Wave device to the Z-Wave Network
2. Removing a Z-Wave device to the Z-Wave Network

In practice though it is more common to speak about adding a Z-Wave node in the context of "including" and removing an Z-Wave mode in the context of "excluding." This module provides functionality for working will all contexts of inclusion, both adding and removing.

## Adding a Z-Wave Node (including)

When adding a device that does not required any security authentication is as simple as calling `Grizzly.Inclusions.add_node/0`.

    iex> Grizzly.Inclusions.add_node()
    :ok

After starting the inclusion on the controller, which the above function does, you can then put your device into inclusion as well. From here the new device and your controller will communicate and if all goes well you should receive a message in the form of `{:grizzly, :inclusion, NodeAddStatus}` where the the `NodeAddStatus` is a Z-Wave command the contains information about the inclusion status (status, node id, supported command classes, security levels, etc.). See `Grizzly.ZWave.Commands.NodeAddStatus` for more information about the values in that command. For example:

    defmodule MyInclusionServer do
      use GenServer

      require Logger

      alias Grizzly.Inclusions
      alias Grizzly.ZWave.Command

      def start_link(_) do
        GenServer.start_link(__MODULE__, nil)
      end

      def add_node(pid) do
        GenServer.call(pid, :add_node)
      end

      def init(_) do
        {:ok, nil}
      end

      def handle_call(:add_node, _from, state) do
        :ok = Inclusions.add_node()
        {:reply, :ok, state}
      end

      def handle_info({:grizzly, :inclusion, report}, state) do
        case Command.param!(report.command, :status) do
          :done ->
            node_id = Command.param!(report.command, :node_id)
            Logger.info("Node added with id: " <> node_id)

          :failed ->
            Logger.warning("Adding node failed :(")

          :security_failed ->
            node_id = Command.param!(report.command, :node_id)
            Logger.warning("Node added with id: " <> node_id <> "but the security failed")
        end

        {:noreply, state}
      end
    end

### Stop Adding a Node

If you need you need to stop trying to add a node to the Z-Wave network you can use the `Grizzly.Inclusions.remove_node/0` function.

This should stop the controller from trying to add a node and return it to a normal functions state.

### Security

There are five security levels in Z-Wave: unsecured, S0, S2 unauthenticated, S2 authenticated, and S2 access control. The first 2 requires nothing special from the calling process to able to use, as the controller and the including node will figure out which security scheme to use.

#### S2

The process of adding an S2 device is a little more involved. The process is the same up until right after you put the including node into the inclusion mode. At that point including will request security keys, which really means it tells you which S2 security scheme it supports. You then use the `Grizzly.Inclusions.grant_keys/1` function to pass a list of allowed security schemes.

After that the node will response with a `NodeAddDSKReport` where it reports the DSK and something called the `:dsk_input_length`. If the input length is `0`, that means it is trying to do S2 unauthenticated inclusion. You can just call `Grizzly.Inclusions.set_input_dsk/0` function and the rest of the inclusion process should continue until complete.

If the `:dsk_input_length` has number, normally will be `2` that means the including device is requesting a 5 digit digit pin that is normally found on a label somewhere on the physical device it.

From here you can call `Grizzly.Inclusions.set_input_dsk/1` with the 5 digit integer as the argument. The inclusion process should continue until complete.

## Removing a Z-Wave Node (excluding)

To remove a Z-Wave node from the network the `Grizzly.Inclusions.remove_node/0` will start an inclusion process for removing a Z-Wave node. After calling this function you can place your device into the inclusion (normally the same way you included the device is the way the device is excluded) mode. At the end of the exclusion the `NodeRemoveStatus` command is received and can be inspected for success of failure.

### Removed Node ID 0?

Any Z-Wave controller can excluded a device from another controller. In practice this means your Z-Wave controller can make a device "forget" the controller it is currently attached to. Most the time Z-Wave products will have you excluded your device and then included just to make sure the including node isn't connected to another Z-Wave controller.

When this happens you will a successful `NodeRemoveStatusReport` but the node id will be `0`. This is consider successful and most the time intend.

## Stopping Remove Node Process

To stop the removal inclusion process on your controller you can call the `Grizzly.Inclusions.remove_node_stop/0` function.

## Inclusion Handler

To tie into the inclusion process we default to sending messages to the calling process. However, there is a better way to tie into this system.

When starting any inclusion process you can pass the `:handler` option which can be either another pid or a module that implements the `Grizzly.InclusionHandler` behaviour, or a tuple with the module and callback arguments.

A basic implementation might look like:

    defmodule MyApp.InclusionHandler do
      @behaviour Grizzly.InclusionHandler

      require Logger

      def handle_report(report, opts) do
        Logger.info("Got command: " <> report.command.name <> " with callback arguments " <> inspect opts)
        :ok
      end
    end

This is recommended for applications using Grizzly over a `GenServer` that wraps `Grizzly.Inclusions`.

# Summary

## Types

opt()

Options for inclusion

status()

Status of the inclusion server

## Functions

add_node(opts \\ [])

Start the process to add a Z-Wave node to the network

add_node_stop()

Stop an add node inclusion process

grant_keys(s2_keys)

Tell the inclusion process which keys to use during the inclusion process

inclusion_running?()

Check to see if there is an inclusion process running

learn_mode(opts \\ [])

Start learn mode on the controller

learn_mode_stop()

Stop learn mode on the controller

remove_node(opts \\ [])

Start the process to remove a Z-Wave node from the network

remove_node_stop()

Stop a remove node inclusion process

set_input_dsk(input_dsk \\ DSK.new(<<>>))

Tell the inclusion process what the input DSK is

status()

Get the current status of the inclusion process

stop() deprecated

Stop the inclusion runner

# Types

Link to this type

# opt()

View Source

    @type opt() ::
      {:controller_id, Grizzly.node_id()}
      | {:timeout, non_neg_integer()}
      | {:handler, pid() | module() | {module(), keyword()}}
      | {atom(), term()}

Options for inclusion

Link to this type

# status()

View Source

    @type status() ::
      :idle
      | :node_adding
      | :node_add_stopping
      | :node_removing
      | :node_remove_stopping
      | :waiting_dsk
      | :waiting_s2_keys
      | :s2_keys_granted
      | :dsk_input_set
      | :learn_mode
      | :learn_mode_stopping

Status of the inclusion server

# Functions

Link to this function

# add_node(opts \\ [])

View Source

    @spec add_node([opt()]) :: :ok | status()

Start the process to add a Z-Wave node to the network

Link to this function

# add_node_stop()

View Source

    @spec add_node_stop() :: :ok | status()

Stop an add node inclusion process

Link to this function

# grant_keys(s2_keys)

View Source

    @spec grant_keys([Grizzly.ZWave.Security.key()]) :: :ok | status()

Tell the inclusion process which keys to use during the inclusion process

During S2 inclusion the node being included with send a `DSKAddKeysReport` to request which keys it can use to included securely. This function is useful for passing back to the node which keys it is allowed to use and depending on that answer the including node might request more information.

Link to this function

# inclusion_running?()

View Source

    @spec inclusion_running?() :: boolean()

Check to see if there is an inclusion process running

Link to this function

# learn_mode(opts \\ [])

View Source

    @spec learn_mode([opt()]) :: :ok | status()

Start learn mode on the controller

Link to this function

# learn_mode_stop()

View Source

    @spec learn_mode_stop() :: :ok | status()

Stop learn mode on the controller

Link to this function

# remove_node(opts \\ [])

View Source

    @spec remove_node([opt()]) :: :ok | status()

Start the process to remove a Z-Wave node from the network

Link to this function

# remove_node_stop()

View Source

    @spec remove_node_stop() :: :ok | status()

Stop a remove node inclusion process

Link to this function

# set_input_dsk(input_dsk \\ DSK.new(<<>>))

View Source

    @spec set_input_dsk(Grizzly.ZWave.DSK.t()) :: :ok | status()

Tell the inclusion process what the input DSK is

If the `NodeAddDSKReport`'s `:input_dsk_length` is `0` you can just call this function without any arguments:

    Grizzly.Inclusions.set_input_dsk()

If you are doing `:s2_authenticated` or `:s2_access_control` the `NodeAddDSKReport` will probably ask for input DSK length of `2`. This means it is expecting a 2 byte (16 bit) number, which is normally a 5 digit pin located somewhere on the node that is being added. After locating the pin and you can pass it as an argument like so:

    {:ok, dsk} = Grizzly.ZWave.DSK.parse("12345")
    Grizzly.Inclusions.set_input_dsk(dsk)

Link to this function

# status()

View Source

    @spec status() :: status()

Get the current status of the inclusion process

Link to this function

# stop()

View Source
This function is deprecated. Use either remove_node_stop/0, add_node_stop/0, or learn_mode_stop/0.

    @spec stop() :: :ok

Stop the inclusion runner