Packages
grizzly
5.2.2
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/unsolicited_server.ex
defmodule Grizzly.UnsolicitedServer do
@moduledoc false
use GenServer
require Logger
alias Grizzly.{Options, Report, SeqNumber, Transport, ZWave}
alias Grizzly.ZWave.Commands.ZIPPacket
alias Grizzly.UnsolicitedServer.{SocketSupervisor, ResponseHandler, Messages}
defmodule State do
@moduledoc false
defstruct transport: nil
end
@doc """
Start the unsolicited server
"""
@spec start_link(Options.t()) :: GenServer.on_start()
def start_link(grizzly_opts) do
GenServer.start_link(__MODULE__, grizzly_opts, name: __MODULE__)
end
@impl GenServer
def init(%Options{} = grizzly_opts) do
{ip, port} = grizzly_opts.unsolicited_destination
transport =
Transport.new(grizzly_opts.transport, %{
ip_address: ip,
port: port
})
{:ok, %State{transport: transport}, {:continue, :listen}}
end
@impl GenServer
def handle_continue(:listen, state) do
%State{transport: transport} = state
case listen(transport) do
{:ok, listening_transport, listen_opts} ->
maybe_start_accept_sockets(listening_transport, listen_opts)
{:noreply, %State{state | transport: listening_transport}}
_error ->
# wait 2 seconds to try again
Logger.warn("[Grizzly]: Unsolicited server unable to listen")
:timer.sleep(2000)
{:noreply, state, {:continue, :listen}}
end
end
@impl GenServer
def handle_info(message, state) do
%State{transport: transport} = state
case Transport.parse_response(transport, message) do
{:ok, transport_response} ->
case ResponseHandler.handle_response(transport_response) do
[] ->
:ok
actions ->
Enum.each(actions, &run_response_action(transport, transport_response, &1))
end
{:noreply, state}
end
end
defp run_response_action(transport, response, {:send, command}) do
%Transport.Response{ip_address: ip_address, port: port} = response
{:ok, zip_packet} = ZIPPacket.with_zwave_command(command, SeqNumber.get_and_inc(), flag: nil)
binary = ZWave.to_binary(zip_packet)
Transport.send(transport, binary, to: {ip_address, port})
end
defp run_response_action(_transport, response, {:notify, command}) do
:ok = Messages.broadcast(response.ip_address, command)
end
defp run_response_action(transport, response, {:forward_to_controller, command}) do
case Grizzly.send_command(1, command.name, command.params) do
{:ok, report} ->
handle_grizzly_report(report, transport, response)
error ->
error
end
end
defp handle_grizzly_report(%Report{type: :ack_response}, transport, response) do
%Transport.Response{ip_address: ip_address, port: port} = response
zip_packet = ZIPPacket.make_ack_response(SeqNumber.get_and_inc())
binary = ZWave.to_binary(zip_packet)
Transport.send(transport, binary, to: {ip_address, port})
end
defp handle_grizzly_report(%Report{type: :command, command: command}, transport, response) do
%Transport.Response{ip_address: ip_address, port: port} = response
{:ok, zip_packet} = ZIPPacket.with_zwave_command(command, SeqNumber.get_and_inc(), flag: nil)
binary = ZWave.to_binary(zip_packet)
Transport.send(transport, binary, to: {ip_address, port})
end
def listen(transport) do
try do
Transport.listen(transport)
rescue
error -> error
end
end
def maybe_start_accept_sockets(listening_transport, listen_opts) do
case Keyword.get(listen_opts, :strategy) do
:accept ->
Enum.each(1..10, fn _ ->
SocketSupervisor.start_socket(listening_transport)
end)
:none ->
:ok
end
end
end