Art-Net Sample
View SourceMix.install([
{:art_net, "~> 0.1.0"}
])Create an Art-Net Dmx Packet
Art-Net Dmx packet is created using the ArtDmx struct.
dmx_packet = %ArtNet.Packet.ArtDmx{sequence: 1, physical: 0, sub_universe: 0, net: 0, length: 1, data: [255]}%ArtNet.Packet.ArtDmx{sequence: 1, physical: 0, sub_universe: 0, net: 0, length: 1, data: [255]}Encode the message
The ArtNet.encode!/1 function is used to encode the ArtDmx struct into a binary message.
If the encoding is successful, the function returns the encoded message. Otherwise, it raises an error.
ArtNet.encode/1 is also available, which returns {:ok, encoded_message} or {:error, reason}.
dmx_message = ArtNet.encode!(dmx_packet)<<65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 1, 0, 0, 0, 0, 1, 255>>The encoded message is a binary that can be sent over the network via UDP.
Send an encoded message
To send the encoded message, you need to open a UDP port and send the message to the target IP address and port number.
To open a UDP port, use the :gen_udp.open/2 function.
:gen_udp is a built-in erlang library that provides UDP socket functionality.
Send a UDP packet to the specified IP address and port number. Art-Net uses port 6454 for communication.
ip_address = ~c"127.0.0.1"
port_number = 6454
# Open a port
{:ok, port} = :gen_udp.open(0, [:binary, {:active, true}]){:ok, #Port<0.8>}Use :gen_udp.send/4 to send the encoded message.
:gen_udp.send(port, ip_address, port_number, dmx_message):okIf the message is successfully sent, the function returns :ok.
WireShark can be used to verify that the message is sent correctly. If the message is sent successfully, it will be displayed in WireShark as shown below.
Send an ArtPoll message
ArtPoll is used to discover Art-Net nodes(devices) on the network. When an ArtPoll message is sent, Art-Net nodes respond with an ArtPollReply message. The ArtPollReply message contains information about the node, such as its IP address, port number, and other details.
Create an ArtPoll message
Create an ArtPoll message using the ArtPoll struct.
The ArtPoll struct contains talk_to_me field, which is a TalkToMe struct.
alias ArtNet.Packet.ArtPoll
alias ArtNet.Packet.BitField.TalkToMe
talk_to_me = %TalkToMe{reply_on_change: false, diagnostics: false, diag_unicast: false, vlc: false}
poll_packet = %ArtPoll{talk_to_me: talk_to_me, priority: :dp_all}%ArtNet.Packet.ArtPoll{
talk_to_me: %ArtNet.Packet.BitField.TalkToMe{
reply_on_change: false,
diagnostics: false,
diag_unicast: false,
vlc: false
},
priority: :dp_all
}Encode and send the ArtPoll message
Encode the ArtPoll message using the ArtNet.encode!/1 function.
ArtNet.encode!1 encodes the packet appropriately based on the packet type.
poll_message = ArtNet.encode!(poll_packet)<<65, 114, 116, 45, 78, 101, 116, 0, 0, 32, 0, 14, 0, 0>>Send the ArtPoll message using the :gen_udp.send/4 function.
:gen_udp.send(port, ip_address, port_number, poll_message):okIf the message is successfully sent, the function returns :ok.
And, WireShark will display the sent message as shown below.
If an Art-Net node receives the ArtPoll message, it will respond with an ArtPollReply message. The ArtPollReply message contains information about the node, such as its IP address, port number, and other details.
Below is a screenshot from WireShark showing QLC+ enabled for Art-Net input, receiving an ArtPoll message and sending an ArtPollReply.
Receive Art-Net messages
To receive Art-Net messages, you need to open a UDP port and listen for incoming messages.
Create a GenServer module to receive Art-Net messages.
The handle_info/2 callback is used to handle incoming messages.
defmodule ReceiveSample do
use GenServer
@impl true
def init(port) do
{:ok, socket} = :gen_udp.open(port, [:binary])
{:ok, port} = :inet.port(socket)
IO.puts("Listening on port: #{port}")
{:ok, socket}
end
@impl true
def handle_info(msg, state) do
case msg do
{:udp, _process_port, _ip_addr, _port_num, res} ->
IO.inspect(res, label: "Binary message received")
artnet_packet = ArtNet.decode!(res)
IO.inspect(artnet_packet, label: "ArtNet packet received")
state
_ ->
state
end
{:noreply, state}
end
def start_link(port) do
GenServer.start_link(ReceiveSample, port)
end
end
{:module, ReceiveSample, <<70, 79, 82, 49, 0, 0, 21, ...>>, {:start_link, 1}}Start the GenServer and prepare to receive messages.
{:ok, receiver_pid} = ReceiveSample.start_link(port_number)Listening on port: 6454{:ok, #PID<0.206.0>}GenServer is now listening messages.
Send an ArtDmx message to the GenServer listening on the port.
:gen_udp.send(port, ip_address, port_number, dmx_message):okBinary message received: <<65, 114, 116, 45, 78, 101, 116, 0, 0, 80, 0, 14, 1, 0, 0, 0, 0, 1, 255>>
ArtNet packet received: %ArtNet.Packet.ArtDmx{
sequence: 1,
physical: 0,
sub_universe: 0,
net: 0,
length: 1,
data: [255]
}The GenServer receives the ArtDmx message and decodes it into an ArtDmx struct.
Stop the GenServer
if you want to stop the GenServer, you can use the GenServer.stop/1 function.
GenServer.stop(receiver_pid):ok