Reference
This document specifies all data shapes used by clj-artnet. It is intended as a precise technical reference, not a tutorial.
Configuration
clj-artnet uses two related but distinct address configurations:
| Configuration | Purpose | Example |
|---|---|---|
:node :ip | Identity advertised in ArtPollReply | {:node {:ip [192 168 1 50]}} |
:bind :host | Local socket binding address | {:bind {:host "0.0.0.0" :port 6454}} |
Most users only need :bind configuration. The :node :ip is auto-detected and only needs explicit configuration when:
- You have multiple network interfaces, and auto-detection selects the wrong one.
- You want to advertise a specific IP address for NAT or proxy scenarios.
Node configuration
The :node key in the configuration map corresponds to ArtPollReply fields:
| Key | Type | Default | Description |
|---|---|---|---|
:short-name | string | "clj-artnet" | 17-character node name |
:long-name | string | "clj-artnet Art-Net 4 Node" | 63-character description |
:ip | [int int int int] | Auto-detected | IPv4 address (ArtPollReply) |
:port | int | 6454 | UDP port (ArtPollReply) |
:mac | [int int int int int int] | [0 0 0 0 0 0] | MAC address |
:ports | vector | [] | Port definitions |
:style | keyword | :st-node | Node type |
:oem | int | 0xFFFF | OEM code |
:esta-man | int | 0x7FF0 | ESTA manufacturer code |
:version-hi | int | 0 | Firmware version high byte |
:version-lo | int | 1 | Firmware version low byte |
:status1 | int | Auto | Status register 1 |
:status2 | int | Auto | Status register 2 |
:status3 | int | Auto | Status register 3 |
!IMPORTANT The default
:esta-manvalue0x7FF0is the ESTA prototype range manufacturer ID, reserved for testing. Production deployments require a registered ESTA manufacturer ID.
Port configuration
Each entry in :ports:
| Key | Type | Default | Range | Description |
|---|---|---|---|---|
:direction | keyword | :output | :input, :output | Port direction |
:universe | int | Index | 0–15 | Universe address |
:type | keyword | :dmx512 | — | Protocol type |
Sync configuration
The :sync key:
| Key | Type | Default | Description |
|---|---|---|---|
:mode | keyword | :immediate | :immediate or :art-sync |
:buffer-ttl-ms | int | 200 | Buffer expiry in milliseconds |
:buffer-ttl-ns | long | 200000000 | Buffer expiry in nanoseconds |
Failsafe configuration
The :failsafe key:
| Key | Type | Default | Description |
|---|---|---|---|
:enabled? | boolean | true | Enable failsafe detection |
:idle-timeout-ms | int | 6000 | Timeout before failsafe engages |
:idle-timeout-ns | long | 6000000000 | Timeout in nanoseconds |
:tick-interval-ms | int | 100 | Failsafe check interval |
Network configuration
The :bind key controls the local socket address:
| Key | Type | Default | Description |
|---|---|---|---|
:host | string | "0.0.0.0" | Local IP address to bind to |
:port | int | 6454 | Local UDP port to bind |
Note: The
:bindkey controls where the node listens for packets. The library automatically resolves the advertised identity from bind configuration unless explicitly overridden.
IP address resolution
The node’s advertised IP address (in ArtPollReply) is resolved with this precedence:
| Priority | Source | Example | Use Case |
|---|---|---|---|
| 1 | :node :ip | {:node {:ip [10 0 0 99]}} | Explicit identity override |
| 2 | :bind :host | {:bind {:host "192.168.1.50"}} | Non-wildcard binding |
| 3 | Auto-detected | NetworkInterface enumeration | Wildcard bind (0.0.0.0) |
| 4 | Fallback | [2 0 0 1] | Detection failed (WARNING) |
Auto-detection prefers Art-Net standard IP ranges (2.x.x.x, 10.x.x.x) per the specification.
Important: Auto-detection only determines the IP address, not the assignment method (static vs. DHCP). If your environment uses DHCP, you must explicitly set
:network {:dhcp? true}to ensure the node correctly reports itself as “DHCP Configured” in theArtPollReplypacket (status register 2 bit 1).
UDP port resolution
The node’s advertised UDP port is resolved with this precedence:
| Priority | Source | Example | Use Case |
|---|---|---|---|
| 1 | :node :port | {:node {:port 6455}} | Explicit override |
| 2 | :bind :port | {:bind {:port 6455}} | Non-standard port |
| 3 | Default | 6454 (0x1936) | Standard Art-Net |
Warning: Non-standard UDP ports trigger a WARN log. Standard Art-Net UDP port is 6454 (0x1936). Custom ports enable local testing with multiple node instances on the same host.
Buffer pool configuration
| Key | Type | Default | Description |
|---|---|---|---|
:rx-buffer | map | {:count 256 :size 2048} | Receive buffer pool |
:tx-buffer | map | {:count 128 :size 2048} | Transmit buffer pool |
:max-packet | int | 2048 | Maximum packet size |
Buffer pool map:
| Key | Type | Description |
|---|---|---|
:count | int | Number of buffers in pool |
:size | int | Size of each buffer in bytes |
Callback payloads
DMX callback
{:packet {:data ByteBuffer ; Read-only channel data
:length int ; Number of channels (1–512)
:port-address int ; 15-bit Port-Address
:sequence int ; Sequence number (0–255)
:physical int ; Physical port number
:failsafe? boolean ; True if failsafe playback
:failsafe-mode keyword} ; :zero, :full, :scene, :hold
:sender {:host string ; Sender IP address
:port int} ; Sender port
:node {...}} ; Current node configuration
Sync callback
{:sender {:host string :port int} ; Sender address
:timestamp long ; System nanosecond timestamp
:node {...}} ; Current node configuration
RDM callback
{:packet {:rdm-packet ByteBuffer ; RDM PDU data
:port-address int ; Port-Address
:net int ; Network (0–127)
:command keyword} ; RDM command class
:sender {:host string :port int}
:node {...}}
Trigger callback
{:packet {:key int ; Trigger key (0=ASCII, 1=Macro, 2=Soft, 3=Show)
:sub-key int ; Trigger sub-key
:payload ByteBuffer ; Trigger payload data
:oem int} ; OEM code
:sender {:host string :port int}
:node {...}}
Command callback
{:packet {:text string ; Command text (ASCII)
:esta-man int ; ESTA manufacturer code
:length int} ; Command length
:sender {:host string :port int}
:node {...}}
Timecode callback
{:packet {:hours int ; Hours (0–23)
:minutes int ; Minutes (0–59)
:seconds int ; Seconds (0–59)
:frames int ; Frames
:type keyword ; :film, :ebu, :df, :smpte
:stream-id int} ; Stream ID (0–255)
:sender {:host string :port int}
:node {...}}
Runtime state
State snapshot keys
The state function accepts :keys to select which state sections to return:
| Key | Description |
|---|---|
:node | Node configuration (ArtPollReply fields) |
:network | Network binding information |
:peers | Discovered nodes |
:stats | Statistics (packets sent/received) |
:dmx | DMX state per port-address |
:sync | Sync buffer state |
:failsafe | Failsafe timing state |
Diagnostics snapshot
{:diagnostics {:subscribers [{:host string :priority keyword}]
:broadcast? boolean
:last-sent-at long}}
Protocol constants
OpCodes
| OpCode | Name | Direction |
|---|---|---|
0x2000 | OpPoll | RX/TX |
0x2100 | OpPollReply | RX/TX |
0x2300 | OpDiagData | RX/TX |
0x2400 | OpCommand | RX/TX |
0x2700 | OpDataRequest | RX |
0x2800 | OpDataReply | TX |
0x5000 | OpDmx | RX/TX |
0x5100 | OpNzs | RX |
0x5200 | OpSync | RX/TX |
0x6000 | OpAddress | RX |
0x7000 | OpInput | RX |
0x8000 | OpTodRequest | RX |
0x8100 | OpTodData | TX |
0x8200 | OpTodControl | RX |
0x8300 | OpRdm | RX/TX |
0x8400 | OpRdmSub | RX/TX |
0x9700 | OpTimeCode | RX |
0x9900 | OpTrigger | RX |
0xF200 | OpFirmwareMaster | RX |
0xF300 | OpFirmwareReply | TX |
0xF800 | OpIpProg | RX |
0xF900 | OpIpProgReply | TX |
Style codes
| Keyword | Value | Description |
|---|---|---|
:st-node | 0x00 | DMX to/from Art-Net device |
:st-controller | 0x01 | Lighting console |
:st-media | 0x02 | Media server |
:st-route | 0x03 | Network routing device |
:st-backup | 0x04 | Backup device |
:st-config | 0x05 | Configuration tool |
:st-visual | 0x06 | Visualizer |
Priority levels
| Keyword | Value | Description |
|---|---|---|
:dp-low | 0x10 | Low priority |
:dp-med | 0x40 | Medium priority |
:dp-high | 0x80 | High priority |
:dp-critical | 0xE0 | Critical priority |
:dp-volatile | 0xF0 | Volatile (temporary) |
Timecode types
| Keyword | Description |
|---|---|
:film | 24 fps |
:ebu | 25 fps |
:df | 29.97 fps drop-frame |
:smpte | 30 fps |
Protocol support matrix
Implemented OpCodes
| OpCode | Name | Direction | Status |
|---|---|---|---|
0x2000 | OpPoll | RX/TX | ✅ Full |
0x2100 | OpPollReply | RX/TX | ✅ Full |
0x2300 | OpDiagData | RX/TX | ✅ Full |
0x2400 | OpCommand | RX/TX | ✅ Full |
0x2700 | OpDataRequest | RX | ✅ Full |
0x2800 | OpDataReply | TX | ✅ Full |
0x5000 | OpDmx | RX/TX | ✅ Full |
0x5100 | OpNzs | RX | ✅ Full |
0x5200 | OpSync | RX/TX | ✅ Full |
0x6000 | OpAddress | RX | ✅ Full |
0x7000 | OpInput | RX | ✅ Full |
0x8000 | OpTodRequest | RX | ✅ Full |
0x8100 | OpTodData | TX | ✅ Full |
0x8200 | OpTodControl | RX | ✅ Full |
0x8300 | OpRdm | RX/TX | ✅ Full |
0x8400 | OpRdmSub | RX/TX | ✅ Full |
0x9700 | OpTimeCode | RX | ✅ Full |
0x9900 | OpTrigger | RX | ✅ Full |
0xF200 | OpFirmwareMaster | RX | ✅ Codec only |
0xF300 | OpFirmwareReply | TX | ✅ Codec only |
0xF800 | OpIpProg | RX | ✅ Full |
0xF900 | OpIpProgReply | TX | ✅ Full |
Not implemented (deprecated)
| OpCode | Name | Reason |
|---|---|---|
0xF000 | OpMacMaster | Deprecated in Art-Net 4 |
0xF100 | OpMacSlave | Deprecated in Art-Net 4 |
Edge cases and limits
Packet size limits
| Packet | Minimum | Maximum |
|---|---|---|
| ArtPoll | 14 bytes | 14 bytes |
| ArtPollReply | 207 bytes | 239 bytes |
| ArtDmx | 18 bytes (header) | 530 bytes (header + 512) |
| ArtRdm | 24 bytes (header) | varies |
Port-address range
- Minimum: 0 (deprecated in Art-Net 4 Rev DP for sACN compatibility)
- Maximum: 32,767
- Recommended start: 1 (for sACN compatibility)
Sequence number handling
| Value | Meaning |
|---|---|
0 | Sequence checking disabled |
1–255 | Active sequence number |
Receivers discard packets with sequence numbers lower than the last received (accounting for wraparound from 255 to 1).
Reply-on-change limits
{:discovery {:reply-on-change-limit 10
:reply-on-change-policy :prefer-existing}}
| Policy | Behavior |
|---|---|
:prefer-existing | Evict newest subscribers when limit exceeded |
:prefer-latest | Evict oldest subscribers when limit exceeded |
BindIndex pagination
For gateways with more than four ports, responses are paginated using BindIndex (0–255). Each ArtPollReply contains up to four ports.
Data length constraints
| Constraint | Value | Reason |
|---|---|---|
| Minimum DMX | 2 bytes | Art-Net specification |
| Maximum DMX | 512 bytes | DMX512 universe size |
| DMX Padding | Even length | Per Art-Net specification |
Error states
Timeout exceptions
;; ExceptionInfo with :type :timeout
{:type :timeout
:timeout-ms 1000
:operation :state-snapshot}
Network binding failures
;; ExceptionInfo with :type :bind-failed
{:type :bind-failed
:host "0.0.0.0"
:port 6454
:cause IOException}
Invalid configuration
;; ExceptionInfo with :type :invalid-config
{:type :invalid-config
:key :ports
:value "invalid"
:message "Ports must be a vector"}
Internal data shapes
Effect types
Effects are data structures returned by the state machine:
;; Transmit packet
{:effect :tx-packet
:packet ByteBuffer
:target {:host string :port int}}
;; Invoke callback
{:effect :callback
:callback keyword ; :dmx, :sync, :rdm, etc.
:payload map}
;; Schedule delayed action
{:effect :schedule
:action keyword
:delay-ms int
:target {:host string :port int}}
;; Log event
{:effect :log
:level keyword ; :info, :warn, :error
:message string}
Event types
Events are inputs to the state machine:
;; Received packet
{:type :rx-packet
:packet map ; Decoded packet
:source {:host string :port int}
:buffer ByteBuffer}
;; Timer tick
{:type :tick
:timestamp long} ; System.nanoTime
;; User command
{:type :command
:command keyword ; :send-dmx, :send-rdm, :send-sync, etc.
:data map} ; Command-specific data
;; State snapshot request
{:type :snapshot
:keys vector} ; Keys to include