Packages
grizzly
0.15.9
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/commands/command_runner.ex
defmodule Grizzly.Commands.CommandRunner do
@moduledoc false
# TODO: document ownership and timeouts
use GenServer
alias Grizzly.Report
alias Grizzly.Commands.Command
alias Grizzly.ZWave.Command, as: ZWaveCommand
def child_spec([_command, _node_id, _opts] = args) do
# Don't restart the command if there is a failure
# TODO: type out opts correctly!!
%{id: __MODULE__, start: {__MODULE__, :start_link, args}, restart: :temporary}
end
@spec start_link(Command.t(), [Grizzly.command_opt()]) :: GenServer.on_start()
def start_link(command, node_id, opts \\ []) do
opts = Keyword.merge([owner: self(), timeout: 5_000], opts)
GenServer.start_link(__MODULE__, [command, node_id, opts])
end
@spec handle_zip_command(pid(), ZWaveCommand.t()) ::
Report.t()
| :continue
| {:error, :nack_response}
| :retry
def handle_zip_command(runner, zip_packet) do
GenServer.call(runner, {:handle_zip_command, zip_packet})
end
@spec encode_command(pid()) :: binary()
def encode_command(runner) do
GenServer.call(runner, :encode)
end
@spec seq_number(pid()) :: Grizzly.seq_number()
def seq_number(runner) do
GenServer.call(runner, :seq_number)
end
@spec reference(pid()) :: reference()
def reference(runner) do
GenServer.call(runner, :reference)
end
def stop(runner), do: GenServer.stop(runner, :normal)
@impl true
def init([command, node_id, opts]) do
owner = Keyword.fetch!(opts, :owner)
timeout = Keyword.fetch!(opts, :timeout)
timeout_ref = start_timeout_counter(timeout)
opts = Keyword.merge(opts, timeout_ref: timeout_ref)
{:ok, Command.from_zwave_command(command, node_id, owner, opts)}
end
@impl true
def handle_call(:seq_number, _from, command), do: {:reply, command.seq_number, command}
def handle_call({:handle_zip_command, zip_packet}, _from, command) do
case Command.handle_zip_command(command, zip_packet) do
{%Report{status: :inflight} = report, new_command} ->
new_command = update_timeout(new_command, report.queued_delay)
{:reply, report, new_command}
{%Report{status: :complete} = report, new_command} ->
{:stop, :normal, report, new_command}
{:continue, new_command} ->
{:reply, :continue, new_command}
{:error, :nack_response, new_command} ->
{:stop, :normal, {:error, :nack_response}, new_command}
{:retry, new_command} ->
{:reply, :retry, new_command}
end
end
def handle_call(:reference, _from, command) do
{:reply, command.ref, command}
end
def handle_call(:encode, _from, command) do
{:reply, Command.to_binary(command), command}
end
@impl true
def handle_info(:timeout, command) do
send(command.owner, {:grizzly, :command_timeout, self(), command})
{:stop, :normal, command}
end
defp update_timeout(command, time_in_seconds) do
_ = Process.cancel_timer(command.timeout_ref)
new_timeout_ref = start_timeout_counter(time_in_seconds * 1000 + 500)
%Command{command | timeout_ref: new_timeout_ref}
end
defp start_timeout_counter(timeout), do: Process.send_after(self(), :timeout, timeout)
end