Packages
grizzly
8.6.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/unsolicited_server/connection_handler.ex
defmodule Grizzly.UnsolicitedServer.ConnectionHandler do
@moduledoc false
use ThousandIsland.Handler
alias Grizzly.Report
alias Grizzly.SeqNumber
alias Grizzly.UnsolicitedServer.Messages
alias Grizzly.UnsolicitedServer.ResponseHandler
alias Grizzly.ZIPGateway
alias Grizzly.ZWave
alias Grizzly.ZWave.{Command, Commands.ZIPPacket}
alias ThousandIsland.Socket
require Logger
@impl ThousandIsland.Handler
def handle_connection(socket, _state) do
case Socket.peername(socket) do
{:ok, {ip, _port}} ->
node_id = ZIPGateway.node_id_from_ip(ip)
Logger.metadata(node_id: node_id)
Logger.debug("[Grizzly.UnsolicitedServer] New connection from node #{node_id}")
{:continue, %{node_id: node_id}}
{:error, reason} ->
{:error, reason, %{}}
end
end
@impl ThousandIsland.Handler
def handle_data(data, socket, %{node_id: node_id} = state) do
Grizzly.Trace.log(data, src: node_id, dest: :grizzly)
case Grizzly.ZWave.from_binary(data) do
{:ok, zip_packet} ->
actions = ResponseHandler.handle_response(zip_packet)
Enum.each(actions, &run_response_action(&1, socket, zip_packet, state))
{:continue, state}
{:error, reason} ->
Logger.error("""
[Grizzly.UnsolicitedServer] Error parsing Z-Wave packet: #{inspect(reason)}
binary: #{inspect(data, pretty: true, base: :hex, limit: 1024)}
""")
{:continue, state}
end
end
@impl ThousandIsland.Handler
def handle_close(_socket, state) do
Logger.debug("[Grizzly.UnsolicitedServer] Socket closed for node #{state.node_id}")
end
defp run_response_action(:ack, socket, zip_packet, state) do
header_extensions = Command.param!(zip_packet, :header_extensions)
seq = Command.param!(zip_packet, :seq_number)
ack_bin =
seq
|> ZIPPacket.make_ack_response(header_extensions: header_extensions)
|> ZWave.to_binary()
send_cmd(socket, ack_bin, state.node_id)
end
defp run_response_action({:send, command}, socket, zip_packet, state) do
# We have to preserve the header extensions to ensure command encapsulation
# is correct when sending the response back to the Z-Wave PAN.
header_extensions = Command.param!(zip_packet, :header_extensions)
{:ok, zip_packet} =
ZIPPacket.with_zwave_command(command, SeqNumber.get_and_inc(),
flag: :ack_request,
header_extensions: header_extensions
)
binary = ZWave.to_binary(zip_packet)
send_cmd(socket, binary, state.node_id)
end
defp run_response_action({:send_raw, command}, socket, _zip_packet, state) do
binary = ZWave.to_binary(command)
send_cmd(socket, binary, state.node_id)
end
defp run_response_action({:notify, command}, _socket, _zip_packet, state) do
:ok = Messages.broadcast(state.node_id, command)
end
defp run_response_action({:forward_to_controller, command}, socket, _zip_packet, state) do
case Grizzly.send_command(:gateway, command.name, command.params) do
{:ok, report} ->
handle_grizzly_report(report, socket, state)
error ->
error
end
end
defp handle_grizzly_report(%Report{type: :ack_response}, socket, state) do
zip_packet = ZIPPacket.make_ack_response(SeqNumber.get_and_inc())
binary = ZWave.to_binary(zip_packet)
send_cmd(socket, binary, state.node_id)
end
defp handle_grizzly_report(%Report{type: :command, command: command}, socket, state) do
{:ok, zip_packet} = ZIPPacket.with_zwave_command(command, SeqNumber.get_and_inc(), flag: nil)
binary = ZWave.to_binary(zip_packet)
send_cmd(socket, binary, state.node_id)
end
defp send_cmd(socket, binary, node_id) do
Grizzly.Trace.log(binary, src: :grizzly, dest: node_id)
Socket.send(socket, binary)
end
end