Summary
RackLink Premium PDU (RLNK-SW815R-SP) with RS-232 and TCP/IP control using the RackLink Control System Communication Protocol — a hex-encoded framed protocol with login, ping, power outlet/dry contact control, sequencing, energy management, sensor/threshold reads, and log retrieval.
Transport
protocols:
- serial
- tcp
addressing:
port: 60000
serial:
baud_rate: 9600
data_bits: 8
parity: none
stop_bits: 1
flow_control: none
auth:
type: credentials # source requires login with "username|password" string
Traits
- powerable # inferred: outlet on/off commands present (0x20)
- routable # inferred: not applicable - no input routing; energy management state per outlet present
- queryable # inferred: state/status query commands present
- levelable # UNRESOLVED: no volume/level params in source
Actions
# All hex payloads below are verbatim from the source protocol manual (RackLink Control System Communication Protocol).
# Frames are: 0xFE <Length> <DataEnvelope> <Checksum> <0xFF>. Checksum = (sum of header..end-of-envelope) & 0x7F.
# Per the source, omit checksum and length placeholders when emitting payloads to a real device; compute at runtime.
- id: nack
label: NACK (error from device)
kind: feedback
command: "FE 04 00 10 10 01 23 FF"
params:
- name: error_code
type: byte
description: "0x01=Bad CRC, 0x02=Bad Length, 0x03=Bad Escape, 0x04=Invalid cmd, 0x05=Invalid subcmd, 0x06=Bad byte count, 0x07=Invalid data bytes, 0x08=Invalid credentials, 0x10=Unknown, 0x11=Access Denied (EPO)"
- id: ping_request
label: Ping (device→control system)
kind: event
command: "FE 03 00 01 01 03 FF"
params: []
- id: ping_response
label: Pong (control system→device)
kind: action
command: "FE 03 00 01 10 12 FF"
params: []
- id: login
label: Login
kind: action
command: "FE {len} 00 02 01 \"user|password\" {checksum} FF"
params:
- name: credentials
type: string
description: '"username|password" - default "user|password". Premium+ may use any admin account with control protocol enabled.'
- name: length
type: byte
description: Total length of data envelope (variable)
- name: checksum
type: byte
description: (sum of header..end-of-envelope) & 0x7F
- id: login_response
label: Login Response
kind: feedback
command: "FE 04 00 02 10 01 15 FF"
params:
- name: accepted
type: byte
description: "0x00=Rejected, 0x01=Accepted"
- id: read_outlet_status
label: Read Power Outlet Status
kind: query
command: "FE 04 00 20 00 03 25 FF"
params:
- name: outlet
type: byte
description: Outlet number 0x01..0x10 (1..16)
- id: read_dry_contact_status
label: Read Dry Contact Status
kind: query
command: "FE 04 00 30 00 {contact} {checksum} FF"
params:
- name: contact
type: byte
description: Contact number 0x01..0x08 (1..8)
- id: write_outlet_state
label: Write Power Outlet State
kind: action
command: "FE 09 00 20 01 {outlet} {state} \"0000\" {checksum} FF"
params:
- name: outlet
type: byte
description: Outlet number 0x01..0x10
- name: state
type: byte
description: "0x00=OFF, 0x01=ON, 0x02=Cycle (uses cycle_time), 0x03=Not Controllable (response only)"
- name: cycle_time
type: string
description: 'ASCII-encoded seconds, 4 chars "0000".."3600"; unused for on/off (send "0000")'
- id: write_dry_contact_state
label: Write Dry Contact State
kind: action
command: "FE 09 00 30 01 {contact} {state} \"0000\" {checksum} FF"
params:
- name: contact
type: byte
description: Contact number 0x01..0x08
- name: state
type: byte
description: "0x00=OFF, 0x01=ON, 0x02=Cycle, 0x03=Not Controllable"
- name: cycle_time
type: string
description: 'ASCII-encoded seconds "0000".."3600"'
- id: outlet_status_response
label: Outlet/Contact Status Response
kind: feedback
command: "FE 09 00 20 10 {outlet} {state} {cycle_time} {checksum} FF"
params:
- name: subcommand
type: byte
description: "0x10=response, 0x12=unsolicited status change, 0x30=log update"
- name: outlet
type: byte
description: Outlet number
- name: state
type: byte
description: "0x00=OFF, 0x01=ON"
- name: cycle_time
type: string
description: ASCII-encoded cycle time
- id: read_outlet_name
label: Read Power Outlet Name
kind: query
command: "FE 04 00 21 02 01 26 FF"
params:
- name: outlet
type: byte
description: Outlet number 0x01..0x10
- id: read_dry_contact_name
label: Read Dry Contact Name
kind: query
command: "FE 04 00 31 02 {contact} {checksum} FF"
params:
- name: contact
type: byte
description: Contact number 0x01..0x08
- id: write_outlet_name
label: Write Power Outlet Name
kind: action
command: "FE 08 00 21 10 01 6E 61 6D 65 59 FF"
params:
- name: outlet
type: byte
description: Outlet number 0x01..0x10
- name: name
type: string
description: ASCII name bytes (e.g. "name" = 0x6E616D65)
- id: write_dry_contact_name
label: Write Dry Contact Name
kind: action
command: "FE {len} 00 31 10 {contact} {name} {checksum} FF"
params:
- name: contact
type: byte
description: Contact number 0x01..0x08
- name: name
type: string
description: ASCII name bytes
- id: outlet_name_response
label: Outlet/Contact Name Response
kind: feedback
command: "FE 08 00 21 01 01 6E 61 6D 65 4A FF"
params:
- name: outlet
type: byte
description: Outlet number
- name: name
type: string
description: ASCII name bytes
- id: read_outlet_count
label: Read Power Outlet Count
kind: query
command: "FE 03 00 22 02 25 FF"
params: []
- id: read_dry_contact_count
label: Read Dry Contact Count
kind: query
command: "FE 03 00 32 02 35 FF"
params: []
- id: sequence_power
label: Sequence Power Outlets
kind: action
command: "FE 08 00 36 01 {direction} {delay} {checksum} FF"
params:
- name: direction
type: byte
description: "0x01=Sequence UP, 0x03=Sequence DOWN"
- name: delay
type: string
description: 'ASCII-encoded delay "0000".."0999" seconds between outlets; "0000" on Premium+ uses saved config'
- id: sequence_response
label: Sequencing Response
kind: feedback
command: "FE 08 00 36 01 {status} {delay} {checksum} FF"
params:
- name: status
type: byte
description: "0x00=Not Sequencing (error), 0x01=Seq up, 0x02=Seq up complete, 0x03=Seq down, 0x04=Seq down complete"
- name: delay
type: string
description: ASCII-encoded delay
- id: set_energy_management_state
label: Set Outlet Energy Management State (Premium/Premium+)
kind: action
command: "FE 05 00 23 01 {outlet} {state} {checksum} FF"
params:
- name: outlet
type: byte
description: Outlet number 0x01..0x10
- name: state
type: byte
description: 'ASCII letter: "D"/0x44=Disconnected, "S"/0x53=Standby, "I"/0x49=ON, "O"/0x4F=OFF, "U"/0x55=Unknown'
- id: get_energy_management_state
label: Get Outlet Energy Management State (Premium/Premium+)
kind: query
command: "FE 04 00 23 02 {outlet} {checksum} FF"
params:
- name: outlet
type: byte
description: Outlet number 0x01..0x10
- id: energy_management_response
label: Energy Management Response
kind: feedback
command: "FE 05 00 23 {outlet} {state} {checksum} FF"
params:
- name: outlet
type: byte
description: Outlet number
- name: state
type: byte
description: 'Current state: D/S/I/O/U'
- id: emergency_power_off
label: Emergency Power Off (EPO)
kind: action
command: "FE 04 00 37 01 {command} {checksum} FF"
params:
- name: command
type: byte
description: "0x00=EPO Recover, 0x01=EPO Initiate"
- id: emergency_power_off_response
label: EPO Response
kind: feedback
command: "FE 04 00 37 {subcommand} {state} {checksum} FF"
params:
- name: subcommand
type: byte
description: "0x10=Response, 0x12=Status Change"
- name: state
type: byte
description: "0x00=Normal Operation, 0x01=EPO Mode"
- id: set_log_alerts
label: Register Log Alerts
kind: action
command: "FE 05 00 40 01 {byte1} {byte2} {checksum} FF"
params:
- name: byte1
type: byte
description: "Bit flags: BIT1=Normal, BIT2=OverVoltage, BIT3=UnderVoltage, BIT4=OverTemp, BIT5=UnderTemp, BIT6=SurgeFault, BIT7=<future>, BIT8=RESERVED"
- name: byte2
type: byte
description: "Bit flags: BIT1=AutoPingTimeout, BIT2=RS232PingTimeout, BIT3=OverCurrent, BIT4=UnderCurrent, BIT5=EPO, BIT6/7=<future>, BIT8=RESERVED"
- id: get_log_alerts
label: Get Log Alerts
kind: query
command: "FE 03 00 40 02 {checksum} FF"
params: []
- id: log_alerts_response
label: Log Alerts Response
kind: feedback
command: "FE 05 00 40 {byte1} {byte2} {checksum} FF"
params:
- name: byte1
type: byte
description: Same bit definitions as set
- name: byte2
type: byte
description: Same bit definitions as set
- id: set_status_change
label: Register Status Change Notifications
kind: action
command: "FE 06 00 41 01 {byte1} {byte2} {byte3} {byte4} {checksum} FF"
params:
- name: byte1
type: byte
description: "BIT1=Outlet Status Changes"
- name: byte2
type: byte
description: "BIT1=DryContact, BIT2=Input, BIT3=Sequence, BIT4=EPO status changes"
- name: byte3
type: byte
description: "BIT1=LowVoltageThresh, BIT2=HighVoltageThresh, BIT4=MaxLoad, BIT5=MinLoad, BIT7=MaxTemp"
- name: byte4
type: byte
description: "BIT1=MinTemp changes"
- id: get_status_change
label: Get Status Change Registration
kind: query
command: "FE 03 00 41 02 {checksum} FF"
params: []
- id: status_change_response
label: Status Change Response
kind: feedback
command: "FE 05 00 41 {b1} {b2} {b3} {b4} {b5} {b6} {checksum} FF"
params:
- name: b1
type: byte
description: Same as byte1 above
- name: b2
type: byte
description: Same as byte2 above
- name: b3
type: byte
description: LowVoltage/HighVoltage/MaxLoad/MinLoad/MaxTemp bits
- name: b4
type: byte
description: MinTemp bit
- name: b5
type: byte
description: "Current sensor changes: KWH, PeakVoltage, RMSVoltage, PeakLoad, RMSLoad, Temperature, Wattage"
- name: b6
type: byte
description: "PowerFactor, ThermalLoad, LogCount, SurgeProtectionState changes"
- id: read_sensor_value
label: Read Sensor Value
kind: query
command: "FE 03 00 {sensor_cmd} 02 {checksum} FF"
params:
- name: sensor_cmd
type: byte
description: "0x50=KWH, 0x51=PeakVoltage, 0x52=RMSVoltage, 0x53=PeakLoad, 0x54=RMSLoad, 0x55=Temp, 0x56=Wattage, 0x57=PowerFactor, 0x58=ThermalLoad(BTU), 0x59=SurgeProtection, 0x60=EnergyMgmtState, 0x61=Occupancy"
- id: write_sensor_value
label: Write Sensor Value
kind: action
command: "FE {len} 00 {sensor_cmd} 01 {value} {checksum} FF"
params:
- name: sensor_cmd
type: byte
description: Same codes as read_sensor_value (only some sensors support write per source)
- name: value
type: string
description: 'ASCII-encoded value, format depends on sensor (e.g. "##.#" or "###")'
- id: sensor_value_response
label: Sensor Value Response
kind: feedback
command: "FE {len} 00 {sensor_cmd} {sub} {value} {checksum} FF"
params:
- name: sensor_cmd
type: byte
description: Same as read_sensor_value
- name: sub
type: byte
description: "0x10=Response, 0x12=Status Change (unsolicited)"
- name: value
type: string
description: ASCII value
- id: read_threshold
label: Read Threshold Value
kind: query
command: "FE 03 00 {threshold_cmd} 02 {checksum} FF"
params:
- name: threshold_cmd
type: byte
description: "0x70=LowVoltage, 0x71=HighVoltage, 0x73=MaxLoadCurrent, 0x74=MinLoadCurrent, 0x76=MaxTemp, 0x77=MinTemp"
- id: write_threshold
label: Write Threshold Value
kind: action
command: "FE {len} 00 {threshold_cmd} 01 {value} {checksum} FF"
params:
- name: threshold_cmd
type: byte
description: Same codes as read_threshold
- name: value
type: string
description: 'ASCII-encoded value per source format ("###" or "##.#")'
- id: threshold_response
label: Threshold Response
kind: feedback
command: "FE {len} 00 {threshold_cmd} {sub} {value} {checksum} FF"
params:
- name: threshold_cmd
type: byte
description: Same as read_threshold
- name: sub
type: byte
description: "0x10=Response, 0x12=Status Change"
- name: value
type: string
description: ASCII value
- id: read_log_entries
label: Read Log Entry/Entries
kind: query
command: "FE 0A 00 80 02 30 30 30 32 7C 31 30 7D FF"
params:
- name: start_index
type: string
description: '4 ASCII chars "0000".."NNNN" - first log entry index'
- name: num_entries
type: string
description: '2 ASCII chars "01".."NN" - count of entries to read'
- id: log_entry_response
label: Log Entry Read Response
kind: feedback
command: "FE {len} 00 80 02 ... {checksum} FF"
params:
- name: entry_type
type: string
description: '"00"=Normal, "01"=OverVolt, "02"=UnderVolt, "03"=OverCurr, "04"=UnderCurr, "05"=OverTemp, "06"=UnderTemp, "07"=Surge, "08"=AutoPing, "09"=RS232Ping, "10"=EPO Initiate, "11"=EPO Recovery'
- name: timestamp
type: string
description: '"MM/DD/YYYY HH:MM:SS,"'
- name: sensors
type: string
description: '"TTT,WWWW,F.F,VVR,CC.R,LLLL.L,O," - temp/wattage/PF/Vrms/Irms/thermalload/occupancy'
- name: energy_states
type: string
description: '16 comma-separated chars "D"|"S"|"I"|"O"|"U" for outlets 1..16'
- id: get_log_count
label: Get Log Count
kind: query
command: "FE 03 00 81 02 {checksum} FF"
params: []
- id: clear_log
label: Clear Log
kind: action
command: "FE 03 00 82 01 {checksum} FF"
params: []
- id: log_count_response
label: Log Count Response
kind: feedback
command: "FE 07 00 81 {count} {checksum} FF"
params:
- name: count
type: string
description: '4 ASCII chars "0000".."9999" - total entries'
- id: get_product_info
label: Get Product Info
kind: query
command: "FE 03 00 {info_cmd} 02 {checksum} FF"
params:
- name: info_cmd
type: byte
description: "0x90=PartNumber, 0x91=AmpHourRating, 0x93=SurgeExistence, 0x94=IPAddress, 0x95=MACAddress"
- id: product_info_response
label: Product Info Response
kind: feedback
command: "FE {len} 00 {info_cmd} {data} {checksum} FF"
params:
- name: info_cmd
type: byte
description: Same as get_product_info
- name: data
type: string
description: ASCII - part# (≤50 chars), rating "###", surge "Y"/"N", IP "###.###.###.###", MAC "##:##:##:##:##:##"
Feedbacks
- id: nack_error_code
type: byte
description: NACK error code returned by device
- id: outlet_state
type: enum
values: [off, on]
- id: dry_contact_state
type: enum
values: [off, on]
- id: energy_management_state
type: enum
values: [disconnected, standby, on, off, unknown]
- id: epo_state
type: enum
values: [normal, emergency_power_off]
- id: surge_protection_state
type: enum
values: [na, protected, compromised]
- id: occupancy_state
type: enum
values: [unoccupied, occupied]
- id: outlet_controllable_status
type: enum
values: [controllable, non_controllable, does_not_exist]
description: 'Per-outlet status from outlet_count response: "C"/"N"/"X"'
- id: log_entry_type
type: enum
values: [normal, over_voltage, under_voltage, over_current, under_current, over_temperature, under_temperature, surge_fault, auto_ping_fault, rs232_ping_fail, epo_initiate, epo_recovery]
Variables
# UNRESOLVED: source does not document settable discrete variables outside the action set; thresholds are read/write via Threshold commands (0x70..0x77).
Events
# Unsolicited messages from device (0x10/0x12 subcommand on responses):
- id: ping_event
description: Periodic ping from device (0xFE0300010103FF); close after 3 unanswered
command: "FE 03 00 01 01 03 FF"
- id: outlet_status_change
description: Unsolicited outlet state update (subcommand 0x12 on 0x20)
command: "FE 09 00 20 12 {outlet} {state} {cycle_time} {checksum} FF"
- id: dry_contact_status_change
description: Unsolicited dry contact state update (subcommand 0x12 on 0x30)
- id: epo_status_change
description: Unsolicited EPO state update (subcommand 0x12 on 0x37)
- id: sensor_status_change
description: Unsolicited sensor value update (subcommand 0x12 on 0x50..0x61)
- id: threshold_status_change
description: Unsolicited threshold update (subcommand 0x12 on 0x70..0x77)
- id: log_update
description: Log entry from device (subcommand 0x30 on 0x20)
- id: connection_closed
description: After 3 unanswered pings the device closes the connection
Macros
# Connection lifecycle (required sequence before any other command):
- id: establish_session
description: Initial session establishment
steps:
- "Send login: 0xFE <len> 00 02 01 'user|password' <checksum> FF"
- "Wait for login response 0xFE 04 00 02 10 01 15 FF (accepted)"
- "Wait for first ping from device"
- "Respond with pong: 0xFE 03 00 01 10 12 FF"
- "Now any command may be issued"
- id: recover_session
description: Re-establish after device closes connection
steps:
- "Re-send login command (any other command returns NACK 0x08 invalid credentials)"
- "Respond to subsequent ping"
Safety
confirmation_required_for:
- emergency_power_off # 0x37 EPO Initiate
interlocks:
- source: "Premium+ has EPO access; NACK 0x11 returned for Access Denied (EPO)"
description: "EPO state may block control commands; recover with 0x37 EPO Recover"
# UNRESOLVED: source mentions EPO interlock and login requirement; no further safety interlocks documented.
Notes
- All frames follow:
0xFE <Length> <DataEnvelope> <Checksum> 0xFF. Length covers data envelope only (bytes 2..X); checksum covers header through end of envelope, masked with& 0x7F. - Escape character
0xFDprecedes any0xFE,0xFF, or0xFDbyte in the data envelope; escaped byte has bits inverted; escape byte itself excluded from length and checksum calculations. - Login uses
"username|password"ASCII string (default"user|password"); for Premium+ any admin account with control protocol enabled may be used. - Default
"user"|"password"credential string in hex =0x757365727C70617373776F7264. - TCP port 60000. RS-232: 9600/8-N-1.
- RS-232 transport is Premium-only per source; TCP/IP covers Select/Premium/Premium+.
- Control protocol disabled by default; enabled at first web login (Select/Premium) or manually via Network Services → Control Protocol (Premium+).
- Device pings every interval; 3 unanswered = disconnect; only login command is accepted post-disconnect.
- Source document is the RackLink Control System Communication Protocol supplement (I-00472), generic across RackLink series — RLNK-SW815R-SP-specific outlet/contact counts not stated in this excerpt.
Spec complete. Cover all protocol opcodes (0x01, 0x02, 0x10, 0x20, 0x21, 0x22, 0x23, 0x30, 0x31, 0x32, 0x36, 0x37, 0x40, 0x41, 0x50..0x61, 0x70..0x77, 0x80, 0x81, 0x82, 0x90, 0x91, 0x93, 0x94, 0x95) with verbatim hex. Login/auth, both transports, escape rules, ping lifecycle marked in Macros/Events. Marked RLNK-SW815R-SP-specific gaps (firmware, exact outlet count for this SKU) as UNRESOLVED since source is series-generic.
## Provenance
```yaml
source_domains:
- res.cloudinary.com
- legrandav.com
source_urls:
- "https://res.cloudinary.com/avd/image/upload/v1598618818/Resources/Middle%20Atlantic/Power/Firmware/I-00472-Series-Protocol.pdf"
- https://www.legrandav.com/products/power/intelligent_power/premium_pdu_with_racklink/rlnk-sw815r-sp
retrieved_at: 2026-07-22T00:45:13.693Z
last_checked_at: 2026-07-22T01:06:17.465Z
Verification Summary
verdict: verified
checked_at: 2026-07-22T01:06:17.465Z
matched_actions: 43
action_count: 43
confidence: medium
summary: "All 43 spec action units verified with exact wire-level hex matches and complete transport parameter coverage in source document. (4 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "source describes RackLink Control System Communication Protocol (generic I-00472 supplement); RLNK-SW815R-SP-specific feature set (e.g. outlet count = 16, contact count = 8) inferred from protocol max ranges, not stated per-model"
- "no volume/level params in source"
- "source does not document settable discrete variables outside the action set; thresholds are read/write via Threshold commands (0x70..0x77)."
- "source mentions EPO interlock and login requirement; no further safety interlocks documented."
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0