View Source Grizzly.Report (grizzly v8.5.3)

Reports from Z-Wave commands

When you send a command in Z-Wave you will receive a report back.

When Things Go Well

There are two primary reports that are returned when sending a command.

The first is :command report and the second is an :ack_response report. These both will have a status of :complete.

Normally, an :ack_response report is returned when you set a value on a device. This means the device received the command and is processing it, not that the device has already processed it. You might have to go read the value back after setting it if you want to make the device ran the set based command.

A :command report type is returned often after reading a value from a device. This report will have its :command field filled with a Z-Wave command.

case Grizzly.send_command(node_id, command, command_args, command_opts) do
  {:ok, %Grizzly.Report{status: :complete, type: :command} = report} ->
    # do something withe report.command
  {:ok, %Grizzly.Report{status: :complete, type: :ack_response}} ->
    # do whatever
end

Queued Commands

When sending a command to a device that sleeping, normally battery powered devices, the command will be queued internally. The command will still be considered :inflight as it has not reached the device yet. You know when a command has been queued when the report's :status field is :inflight and the :type field is :queued_delayed. Fields to help you manage queued commands are :command_ref, :queued_delay, and :node_id

During the command's queued lifetime the system sends pings back to the caller to ensure that the low level connection is still established. This also provides an updated delayed time before the device wakes up.

case Grizzly.send_command(node_id, command, command_args, command_opts) do
  {:ok, %Grizzly.Report{status: :inflight, type: :queued_delay}} ->
    # the command was just queued
end

Once the command has been queued the calling process will receive messages about the queued command like so:

{:grizzly, :report, %Report{}}

This report can take two forms. One for a completed queued command and one for a queued ping.

def handle_info({:grizzly, :report, report}, state) do
  case report do
    %Grizzly.Report{status: :inflight, type: :queued_ping} ->
      # handle the ping if you want
      # an updated queue delay will be found in the :queued_delay
      # field of the report
    %Grizzly.Report{status: :complete, type: :command, queued: true} ->
      # here if the :queued field is marked has true and the report is
      # complete that will indicate a command has made it to the sleeping
      # device and the device has received the command
    %Grizzly.Report{status: :complete, type: :timeout, queued: true} ->
      # The woke up and the controller sent the command but for reason
      # the command's processing timed out
  end
end

Timeouts

If sending the command times out you will get a command with the :type of :timeout

case Grizzly.send_command(node_id, command, command_args, command_opts) do
  {:ok, %Grizzly.Report{status: :complete, type: :timeout}} ->
    # handle the timeout
end

The reason why this is considered okay is because the command that was sent was valid and we were able to establish a connect to the desired device but it just did not provide any report back.

Full Example

The below example shows the various ways one might match after calling Grizzly.send_command/4.

case Grizzly.send_command(node_id, command, command_args, command_opts) do
  {:ok, %Grizzly.Report{status: :complete, type: :command} = report} ->
    handle_complete_report(report)
  {:ok, %Grizzly.Report{status: :complete, type: :ack_response} = report} ->
    handle_complete_report(report)
  {:ok, %Grizzly.Report{status: :complete, type: :timeout} = report} ->
    handle_timeout(report)
  {:ok, %Grizzly.Report{status: :inflight, type: :queued} = report} ->
    handle_queued_command(report)
end

note: the handle_* functions will need to implemented and are only used in the example for illustration purposes

Summary

Types

The RSSI value between each device that command had to route through to get to the destination node

t()

All the data for the status and type of a report.

The various transmission stats that are provide by the Z-Wave network when sending a command.

Types

@type opt() ::
  {:transmission_stats, [transmission_stat()]}
  | {:queued_delay, non_neg_integer()}
  | {:command, Grizzly.ZWave.Command.t()}
  | {:command_ref, reference()}
  | {:queued, boolean()}
  | {:acknowledged, boolean()}
@type rssi_value() :: integer() | :not_available

The RSSI value between each device that command had to route through to get to the destination node

If the value is :not_available that means data for that hop in not available or a hope did not take place. To see the nodes that the command was routed through see the :last_working_route field of the transmission stats.

@type status() :: :inflight | :complete
@type t() :: %Grizzly.Report{
  acknowledged: boolean(),
  command: Grizzly.ZWave.Command.t() | nil,
  command_ref: reference() | nil,
  node_id: Grizzly.ZWave.node_id() | Grizzly.VirtualDevices.id(),
  queued: boolean(),
  queued_delay: non_neg_integer(),
  status: status(),
  transmission_stats: [transmission_stat()],
  type: type()
}

All the data for the status and type of a report.

Fields

  • :status - this indicates if the report is complete, inflight, or timed out
  • :type - this indicates if the report is contains a command or information about being queued.
  • :command - if the status is :complete and the type is :command then this field will contain a Z-Wave command in the report.
  • :transmission_stats - provides transmission stats for the command that was sent
  • :queued_delay - the delay time remaining if the report type is :queued_delay or :queued_ping
  • :command_ref - a reference to the command. This is mostly useful for tracking queued commands
  • :node_id - the node the report is responding from
  • :queued - this flag marks if the command was ever queued before completing
  • :acknowledged - whether the destination node acknowledged the command. Only valid when the status is :complete. For commands using the AckResponse command handler, this field will be true if type is :ack_response and false if type is :nack_response. For other command handlers, it will be true if the original command was acknowledged by the destination node (i.e. we received an ACK Response from Z/IP Gateway). This is useful for differentiating report timeouts where the destination received the command but didn't send a report (e.g. it doesn't support the command or command version, it considered some or all of the payload invalid, etc.) from other causes. Other types of timeouts typically mean the timeout was too short and Grizzly had to return before Z/IP Gateway could send a response
@type transmission_stat() ::
  {:transmit_channel, non_neg_integer()}
  | {:ack_channel, non_neg_integer()}
  | {:rssi_hops, [rssi_value()]}
  | {:rssi_4bars, 0..4 | :unknown}
  | {:rssi_dbm, rssi_value()}
  | {:last_working_route, [Grizzly.ZWave.node_id()]}
  | {:transmit_speed, transmit_speed()}
  | {:transmission_time, non_neg_integer()}
  | {:route_changed, boolean()}

The various transmission stats that are provide by the Z-Wave network when sending a command.

  • :transmit_channel - the RF channel the command was transmitted on
  • :ack_channel - the RF channel the acknowledgement report was transmitted on
  • :rssi - a 5 tuple that contains RSSI values for each hop in the Z-Wave network
  • :last_working_route - this contains a 4 tuple that shows what nodes the Z-Wave command was routed through to the destination node. Also this contains the speed by which the Z-Wave command was transmitted to the destination
  • :transmission_time - the length of time until the reception of an acknowledgement in milliseconds
  • :route_changed - this indicates if the route was changed for the current transmission
@type transmit_speed() :: float() | non_neg_integer()
@type type() ::
  :ack_response
  | :nack_response
  | :queue_full
  | :command
  | :queued_ping
  | :unsolicited
  | :queued_delay
  | :timeout
  | :supervision_status

Functions

Link to this function

new(status, type, node_id, opts \\ [])

View Source
@spec new(status(), type(), Grizzly.ZWave.node_id() | Grizzly.VirtualDevices.id(), [
  opt()
]) :: t()

Make a new Grizzly.Report