Summary
This spec covers the binary control protocol for the Middle Atlantic UPX RLNK 2000R 2 rack power distribution unit (PDU), a RackLink Premium+ tier product. Two transports are supported: RS-232 (RackLink Premium only — not available on Premium+ UPX) and TCP/IP on port 60000. The protocol is a framed binary envelope of the form <0xFE><Length><Cmd><Subcommand>[Data][Checksum]><0xFF>, with a 7-bit masked additive checksum. The control protocol is disabled by default and must be enabled through the device web UI before any command set is accepted; a "SET" login command using user|password (or any admin account on Premium+) is required to authenticate every session, and the host must respond to periodic pings or be disconnected.
Transport
protocols:
- tcp
- serial
addressing:
port: 60000 # source: "TCP Port: 60000"
serial:
baud_rate: 9600
data_bits: 8
parity: none
stop_bits: 1
flow_control: none
auth:
type: credentials # source: "SET" login message required, default "user|password"
username_field: "Username|Password" # source: data envelope format
default_username: "user"
default_password: "password" # source: "Default: 'user|password'"
# UNRESOLVED: protocol-over-TLS not stated; assume plaintext framing
Traits
powerable: true # inferred: power outlet on/off/cycle commands present (0x20/0x30)
queryable: true # inferred: status query commands present (0x20/0x02, 0x50+, 0x70+)
Frame Encoding Reference
Every command and response shares the same envelope:
<0xFE> <Length> <Data Envelope> <Checksum> <0xFF>
- Header:
0xFE(1 byte) - Length: total length of the data envelope, 1 byte (range
0x03–0xFAper source example) - Data envelope:
Cmdbyte,Subcommandbyte, then optional data (3–250 bytes) - Checksum: sum of all bytes from
0xFEthrough end of data envelope, masked& 0x7F(low 7 bits; high bit cleared) - Tail:
0xFF(1 byte)
Escape: the protected values 0xFE, 0xFF, 0xFD in the data envelope MUST be escaped with a leading 0xFD and bit-inverted; escaped bytes are excluded from length and checksum calculations.
The {chk} placeholder in the command fields below denotes the computed 1-byte masked checksum. The {len} placeholder denotes the data envelope length byte. Concrete examples in the source are reproduced verbatim where possible.
Actions
# ============================================================================
# SESSION / LINK
# ============================================================================
- id: login
label: Login (authenticate control session)
kind: action
command: "FE 10 00 02 01 {creds:ascii} {chk:hex} FF"
# Source sample: 0xFE10000201757365727C70617373776F72643FFF (default "user|password")
params:
- name: creds
type: string
description: 'ASCII "Username|Password". Default on Select/Premium = "user|password". Premium+ may use any admin account with control protocol enabled.'
- id: respond_ping
label: Respond to device PING (Pong)
kind: action
command: "FE 03 00 01 10 12 FF"
# Source sample: 0xFE0300011012FF (Control System sending PING response)
params: []
notes: |
Required when device sends unsolicited PING (0xFE 03 00 01 01 03 FF).
Three missed pings = session terminated by device.
# ============================================================================
# POWER OUTLETS (0x20)
# ============================================================================
- id: read_outlet_state
label: Read Outlet State
kind: query
command: "FE 04 00 20 02 {outlet:hex} {chk:hex} FF"
# Source sample: 0xfe040020000325ff (Read Outlet 3 state)
params:
- name: outlet
type: integer
description: Outlet number 1-16 (0x01-0x10)
- id: write_outlet_state
label: Set Outlet State (on/off/cycle)
kind: action
command: "FE 09 00 20 01 {outlet:hex} {state:hex} 30 30 30 30 {chk:hex} FF"
# Source examples:
# 0xfe090020010101303030306aff Outlet 1 ON
# 0xfe090020010200303030306aff Outlet 2 OFF
# 0xfe0900200102023030303571ff Outlet 2 Cycle 5 s
# 0xfe0900200108023030303874ff Outlet 8 Cycle 8 s
params:
- name: outlet
type: integer
description: Outlet number 1-16 (0x01-0x10)
- name: state
type: enum
values: [0x00, 0x01, 0x02, 0x03]
description: 0x00=OFF, 0x01=ON, 0x02=Cycle, 0x03=Not Controllable (response only)
- name: cycle_time_seconds
type: integer
description: 0-3600 s, ASCII-encoded as 4 decimal digits (e.g. "0005" = 0x30303035). Required for Cycle; send "0000" (0x30303030) for on/off.
# ============================================================================
# DRY CONTACTS (0x30)
# ============================================================================
- id: read_dry_contact_state
label: Read Dry Contact State
kind: query
command: "FE 04 00 30 02 {contact:hex} {chk:hex} FF"
params:
- name: contact
type: integer
description: Contact number 1-8 (0x01-0x08)
- id: write_dry_contact_state
label: Set Dry Contact State
kind: action
command: "FE 09 00 30 01 {contact:hex} {state:hex} 30 30 30 30 {chk:hex} FF"
params:
- name: contact
type: integer
description: Contact number 1-8 (0x01-0x08)
- name: state
type: enum
values: [0x00, 0x01, 0x02, 0x03]
description: 0x00=OFF, 0x01=ON, 0x02=Cycle, 0x03=Not Controllable (response only)
- name: cycle_time_seconds
type: integer
description: 0-3600 s, ASCII-encoded 4 decimal digits
# ============================================================================
# OUTLET / CONTACT NAMES (0x21, 0x31)
# ============================================================================
- id: read_outlet_name
label: Read Outlet Name
kind: query
command: "FE 04 00 21 02 {outlet:hex} {chk:hex} FF"
# Source sample: 0xFE040021020126FF (Read Name of Outlet 1)
params:
- name: outlet
type: integer
description: Outlet number 1-16
- id: write_outlet_name
label: Set Outlet Name
kind: action
command: "FE 08 00 21 01 {outlet:hex} {name:ascii} {chk:hex} FF"
# Source sample: FE08002110016E616D6559FF (Set Outlet 1 name to "name"; note source uses 0x10 not 0x01 in the Subcommand slot - see notes)
params:
- name: outlet
type: integer
description: Outlet number 1-16
- name: name
type: string
description: ASCII outlet name
- id: read_dry_contact_name
label: Read Dry Contact Name
kind: query
command: "FE 04 00 31 02 {contact:hex} {chk:hex} FF"
params:
- name: contact
type: integer
description: Contact number 1-8
- id: write_dry_contact_name
label: Set Dry Contact Name
kind: action
command: "FE {len:hex} 00 31 01 {contact:hex} {name:ascii} {chk:hex} FF"
params:
- name: contact
type: integer
description: Contact number 1-8
- name: name
type: string
description: ASCII contact name
# ============================================================================
# OUTLET / CONTACT COUNT (0x22, 0x32)
# ============================================================================
- id: read_outlet_count
label: Read Outlet Count
kind: query
command: "FE 03 00 22 02 25 FF"
# Source sample: 0xFE0300220225FF; checksum is always 0x25 for outlet count
params: []
- id: read_dry_contact_count
label: Read Dry Contact Count
kind: query
command: "FE 03 00 32 02 35 FF"
# Source: checksum is always 0x35 for contact count
params: []
# ============================================================================
# POWER SEQUENCING (0x36)
# ============================================================================
- id: sequence_power
label: Power Sequencing (up/down with delay)
kind: action
command: "FE 08 00 36 01 {direction:hex} {delay:ascii} {chk:hex} FF"
# Source examples:
# 0xFE08003601013030303301FF Sequence up, 3 s delay
# 0xFE08003601033030303505FF Sequence down, 5 s delay
# 0xFE0800360101303030307EFF Sequence up, Premium+, use saved settings (delay "0000")
params:
- name: direction
type: enum
values: [0x01, 0x03]
description: 0x01=Sequence UP, 0x03=Sequence DOWN
- name: delay_seconds
type: integer
description: 0-999 s, ASCII-encoded 4 decimal digits. Use "0000" on Premium+ to apply configured saved delay.
# ============================================================================
# ENERGY MANAGEMENT STATE (0x23) - Premium / Premium+ only
# ============================================================================
- id: read_energy_management_state
label: Read Energy Management State
kind: query
command: "FE 04 00 23 02 {outlet:hex} {chk:hex} FF"
params:
- name: outlet
type: integer
description: Outlet number 1-16
- id: set_energy_management_state
label: Set Energy Management State
kind: action
command: "FE 05 00 23 01 {outlet:hex} {state:ascii} {chk:hex} FF"
params:
- name: outlet
type: integer
description: Outlet number 1-16
- name: state
type: enum
values: ["D", "S", "I", "O", "U"]
description: 'ASCII letter: "D"=Disconnected (0x44), "S"=Standby (0x53), "I"=ON (0x49), "O"=OFF (0x4F), "U"=Unknown (0x55)'
# ============================================================================
# EMERGENCY POWER OFF (0x37) - Premium / Premium+ only
# ============================================================================
- id: epo_initiate
label: Emergency Power Off - Initiate
kind: action
command: "FE 04 00 37 01 01 {chk:hex} FF"
params: []
notes: |
SAFETY-CRITICAL. Immediately removes downstream power.
Source: "0x37 - EPO", "0x01 - Set", "0x01 - EPO Initiate".
NACK 0x11 ("Access Denied(EPO)") is sent back if EPO already active.
- id: epo_recover
label: Emergency Power Off - Recover
kind: action
command: "FE 04 00 37 01 00 {chk:hex} FF"
params: []
# ============================================================================
# LOG ALERTS REGISTRATION (0x40) - Premium / Premium+ only
# ============================================================================
- id: set_log_alerts
label: Set Log Alert Registration Bits
kind: action
command: "FE 05 00 40 01 {byte1:hex} {byte2:hex} {chk:hex} FF"
params:
- name: byte1
type: integer
description: 'Bitmask - BIT1 Normal Log, BIT2 Over Voltage, BIT3 Under Voltage, BIT4 Over Temp, BIT5 Under Temp, BIT6 Surge Fault, BIT7 <Future>, BIT8 RESERVED'
- name: byte2
type: integer
description: 'Bitmask - BIT1 Auto Ping Timeout, BIT2 RS232 Ping Timeout, BIT3 Over Current, BIT4 Under Current, BIT5 EPO, BIT6/7 <Future>, BIT8 RESERVED'
- id: get_log_alerts
label: Get Log Alert Registration
kind: query
command: "FE 03 00 40 02 {chk:hex} FF"
params: []
# ============================================================================
# STATUS CHANGE REGISTRATION (0x41) - Premium / Premium+ only
# ============================================================================
- id: set_status_change
label: Set Status Change Registration
kind: action
command: "FE 06 00 41 01 {b1:hex} {b2:hex} {b3:hex} {b4:hex} {chk:hex} FF"
# NOTE: source data table has 6 bytes (B1-B7) but length field says "Always 0x06 for set subcommand"; carrying 4 bytes per the listed bytes
params:
- name: b1
type: integer
description: 'BIT1 Outlet Status, BIT2-7 <Future>, BIT8 RESERVED'
- name: b2
type: integer
description: 'BIT1 Dry Contact, BIT2 Input, BIT3 Sequence, BIT4 EPO, BIT5-7 <Future>, BIT8 RESERVED'
- name: b3
type: integer
description: 'BIT1 Low Volt Thresh, BIT2 High Volt Thresh, BIT4 Max Load, BIT5 Min Load, BIT7 Max Temp, BIT8 RESERVED'
- name: b4
type: integer
description: 'BIT1 Min Temp, others <Future>'
- id: get_status_change
label: Get Status Change Registration
kind: query
command: "FE 03 00 41 02 {chk:hex} FF"
params: []
# ============================================================================
# SENSOR VALUES (0x50 - 0x61) - Premium / Premium+ only
# Format note: each command is one byte. SET writes the sensor value (where
# applicable). GET is a query; length byte = 0x03.
# ============================================================================
- id: read_kilowatt_hours
label: Read Kilowatt Hours
kind: query
command: "FE 03 00 50 02 {chk:hex} FF"
notes: 'Format: ##########.# (11 ASCII chars incl. decimal)'
- id: set_kilowatt_hours
label: Set Kilowatt Hours Counter
kind: action
command: "FE 07 00 50 01 {value:ascii} {chk:hex} FF"
notes: 'Value in ASCII, format ##########.# (length 0x07 includes cmd+sub+4 decimal digits+dot)'
- id: read_peak_voltage
label: Read Peak Voltage
kind: query
command: "FE 03 00 51 02 {chk:hex} FF"
notes: 'Format: ### (3 ASCII digits)'
- id: set_peak_voltage
label: Set Peak Voltage
kind: action
command: "FE 06 00 51 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ###'
- id: read_rms_voltage
label: Read RMS Voltage
kind: query
command: "FE 03 00 52 02 {chk:hex} FF"
notes: 'Format: ###'
- id: set_rms_voltage
label: Set RMS Voltage
kind: action
command: "FE 06 00 52 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ###'
- id: read_peak_load
label: Read Peak Load
kind: query
command: "FE 03 00 53 02 {chk:hex} FF"
notes: 'Format: ##.#'
- id: set_peak_load
label: Set Peak Load
kind: action
command: "FE 07 00 53 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ##.#'
- id: read_rms_load
label: Read RMS Load
kind: query
command: "FE 03 00 54 02 {chk:hex} FF"
notes: 'Format: ##.#'
- id: set_rms_load
label: Set RMS Load
kind: action
command: "FE 07 00 54 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ##.#'
- id: read_temperature
label: Read Temperature
kind: query
command: "FE 03 00 55 02 {chk:hex} FF"
notes: 'Format: ### (Fahrenheit per source)'
- id: set_temperature
label: Set Temperature
kind: action
command: "FE 06 00 55 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ###'
- id: read_wattage
label: Read Wattage
kind: query
command: "FE 03 00 56 02 {chk:hex} FF"
notes: 'Format: ####'
- id: set_wattage
label: Set Wattage
kind: action
command: "FE 07 00 56 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ####'
- id: read_power_factor
label: Read Power Factor
kind: query
command: "FE 03 00 57 02 {chk:hex} FF"
notes: 'Format: #.#'
- id: set_power_factor
label: Set Power Factor
kind: action
command: "FE 06 00 57 01 {value:ascii} {chk:hex} FF"
notes: 'Format: #.#'
- id: read_thermal_load
label: Read Thermal Load (BTU)
kind: query
command: "FE 03 00 58 02 {chk:hex} FF"
notes: 'Format: ####.#'
- id: set_thermal_load
label: Set Thermal Load
kind: action
command: "FE 08 00 58 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ####.#'
- id: read_surge_protection_state
label: Read Surge Protection State
kind: query
command: "FE 03 00 59 02 {chk:hex} FF"
notes: 'Response: 0x00 n/a, 0x01 protected, 0x02 compromised'
- id: read_energy_mgmt_per_outlet
label: Read Energy Management State (all 16 outlets)
kind: query
command: "FE 03 00 60 02 {chk:hex} FF"
notes: 'Response: 16 ASCII bytes (one per outlet): D/S/I/O/U'
- id: read_occupancy_state
label: Read Occupancy State
kind: query
command: "FE 03 00 61 02 {chk:hex} FF"
notes: 'Response: "U"/0x55 Unoccupied, "O"/0x4F Occupied'
# ============================================================================
# THRESHOLDS (0x70 - 0x77) - Premium / Premium+ only
# 0x72 and 0x75 are not assigned in the source.
# ============================================================================
- id: read_low_voltage_threshold
label: Read Low Voltage Threshold
kind: query
command: "FE 03 00 70 02 {chk:hex} FF"
notes: 'Format: ###'
- id: set_low_voltage_threshold
label: Set Low Voltage Threshold
kind: action
command: "FE 06 00 70 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ###'
- id: read_high_voltage_threshold
label: Read High Voltage Threshold
kind: query
command: "FE 03 00 71 02 {chk:hex} FF"
notes: 'Format: ###'
- id: set_high_voltage_threshold
label: Set High Voltage Threshold
kind: action
command: "FE 06 00 71 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ###'
- id: read_max_load_current
label: Read Max Load Current
kind: query
command: "FE 03 00 73 02 {chk:hex} FF"
notes: 'Format: ##.#'
- id: set_max_load_current
label: Set Max Load Current
kind: action
command: "FE 07 00 73 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ##.#'
- id: read_min_load_current
label: Read Min Load Current
kind: query
command: "FE 03 00 74 02 {chk:hex} FF"
notes: 'Format: ##.#'
- id: set_min_load_current
label: Set Min Load Current
kind: action
command: "FE 07 00 74 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ##.#'
- id: read_max_temperature
label: Read Max Temperature
kind: query
command: "FE 03 00 76 02 {chk:hex} FF"
notes: 'Format: ###'
- id: set_max_temperature
label: Set Max Temperature
kind: action
command: "FE 06 00 76 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ###'
- id: read_min_temperature
label: Read Min Temperature
kind: query
command: "FE 03 00 77 02 {chk:hex} FF"
notes: 'Format: ###'
- id: set_min_temperature
label: Set Min Temperature
kind: action
command: "FE 06 00 77 01 {value:ascii} {chk:hex} FF"
notes: 'Format: ###'
# ============================================================================
# LOG ENTRY READ / COUNT / CLEAR (0x80, 0x81, 0x82)
# ============================================================================
- id: read_log_entries
label: Read Log Entries
kind: query
command: "FE 0A 00 80 02 {first_idx:ascii} 7C {count:ascii} {chk:hex} FF"
# Source: 1 byte Length always 0x0A, 0x80 cmd, 0x02 sub, ASCII first index 4 chars,
# separator 0x7C ('|'), ASCII count 2 chars
notes: 'First index e.g. "0002" (0x30303032). Count e.g. "10" (0x3130).'
params:
- name: first_idx
type: string
description: 'ASCII 4-digit starting index, e.g. "0002"'
- name: count
type: string
description: 'ASCII 2-digit count, e.g. "10"'
- id: get_log_count
label: Get Log Count
kind: query
command: "FE 03 00 81 02 {chk:hex} FF"
notes: 'Response carries 4 ASCII bytes, e.g. "0120" = 120 entries'
- id: clear_log
label: Clear Log
kind: action
command: "FE 03 00 82 01 {chk:hex} FF"
notes: 'Subcommand 0x01 = Set (Clear).'
# ============================================================================
# PRODUCT INFO (0x90, 0x91, 0x93, 0x94, 0x95)
# ============================================================================
- id: read_part_number
label: Read Product Part Number
kind: query
command: "FE 03 00 90 02 {chk:hex} FF"
notes: 'Response: ASCII string up to 50 chars'
- id: read_amp_hour_rating
label: Read Product Amp Hour Rating
kind: query
command: "FE 03 00 91 02 {chk:hex} FF"
notes: 'Response format: ###'
- id: read_surge_existence
label: Read Surge Protection Existence
kind: query
command: "FE 03 00 93 02 {chk:hex} FF"
notes: 'Response: "Y" or "N" (single ASCII byte)'
- id: read_ip_address
label: Read Current IP Address
kind: query
command: "FE 03 00 94 02 {chk:hex} FF"
notes: 'Response: ASCII "###.###.###.###" with no leading zeroes, variable length'
- id: read_mac_address
label: Read MAC Address
kind: query
command: "FE 03 00 95 02 {chk:hex} FF"
notes: 'Response: ASCII "##:##:##:##:##:##"'
Feedbacks
# Generic response envelope for many commands echoes the request with
# Subcommand byte 0x10 (response) or 0x12 (unsolicited status change) or
# 0x30 (log update). Decoders should match Cmd + Outlet/Index as appropriate.
- id: nack_error
label: NACK (error response)
type: object
fields:
cmd: 0x10
error_code:
type: enum
values: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x10, 0x11]
description: |
0x01 Bad CRC on previous command
0x02 Bad Length on previous command
0x03 Bad Escape sequence on previous command
0x04 Previous command invalid
0x05 Previous sub-command invalid
0x06 Previous command incorrect byte count
0x07 Invalid data bytes in previous command
0x08 Invalid Credentials (note: need to login again)
0x10 Unknown Error
0x11 Access Denied (EPO)
# Source sample: 0xFE040010100123FF (bad CRC on previous command)
- id: login_response
label: Login response
type: object
fields:
cmd: 0x02
response:
type: enum
values: [0x00, 0x01]
description: 0x00 Rejected, 0x01 Accepted
# Source sample: 0xFE040002100115FF (login accepted)
- id: outlet_state
label: Outlet state (response / unsolicited)
type: object
fields:
cmd: 0x20
subcommand:
type: enum
values: [0x10, 0x12, 0x30]
description: 0x10 response to command, 0x12 status update from local event, 0x30 log update
outlet: integer # 1-16
state:
type: enum
values: [0x00, 0x01]
description: 0x00 OFF, 0x01 ON
cycle_time_seconds: integer # ASCII 4-digit, 0-3600
# Source sample: 0xfe0900200100300303030357fff (Outlet 3 OFF, 5 s cycle)
- id: dry_contact_state
label: Dry contact state (response / unsolicited)
type: object
fields:
cmd: 0x30
subcommand: { type: enum, values: [0x10, 0x12, 0x30] }
contact: integer # 1-8
state: { type: enum, values: [0x00, 0x01] }
cycle_time_seconds: integer
- id: outlet_name
label: Outlet name
type: string
# Cmd 0x21, response echoes outlet number + ASCII name (e.g. 0x6E616D65 = "name")
# Source sample: FE08002101016E616D654AFF (Outlet 1 named "name")
- id: dry_contact_name
label: Dry contact name
type: string
# Cmd 0x31
- id: outlet_count_map
label: Outlet count / per-outlet controllability
type: string
# Cmd 0x22, 16 bytes: "C" controllable, "N" non-controllable, "X" does-not-exist
# 0x43 / 0x4E / 0x58
- id: dry_contact_count_map
label: Dry contact count / per-contact controllability
type: string
# Cmd 0x32, 8 bytes: C/N/X
- id: sequence_response
label: Power sequence response / status
type: object
fields:
cmd: 0x36
direction:
type: enum
values: [0x00, 0x01, 0x02, 0x03, 0x04]
description: 0x00 Not Sequencing (error fallback), 0x01 up, 0x02 up complete, 0x03 down, 0x04 down complete
delay_seconds: integer # ASCII 4 digits, 0-999
- id: energy_mgmt_state
label: Energy management state (single outlet)
type: string
# Cmd 0x23, single ASCII letter: D / S / I / O / U (0x44/0x53/0x49/0x4F/0x55)
- id: epo_response
label: EPO response / status change
type: object
fields:
cmd: 0x37
subcommand: { type: enum, values: [0x10, 0x12] }
state: { type: enum, values: [0x00, 0x01], description: "0x00 Normal, 0x01 EPO Mode" }
- id: log_alerts_registration
label: Log alert registration bitmask
type: object
fields:
cmd: 0x40
byte1_bits: integer
byte2_bits: integer
- id: status_change_registration
label: Status change registration bitmask
type: object
fields:
cmd: 0x41
bytes: array # six data bytes (set/get); see action notes
- id: sensor_value
label: Sensor reading
type: string
# Cmd 0x50-0x61, ASCII payload format depends on sensor (see actions notes)
# Subcommand 0x10 response or 0x12 unsolicited status change
- id: threshold_value
label: Threshold value
type: string
# Cmd 0x70-0x77, ASCII payload; sub 0x10/0x12
- id: log_entry
label: Log entry (one per record)
type: object
fields:
cmd: 0x80
log_request_number: string # 2 ASCII digits
entries_remaining: string # 2 ASCII digits
actual_log_entry_number: string # 4 ASCII digits
log_entry_type:
type: enum
values: ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11"]
description: |
00 Normal, 01 Over Voltage, 02 Under Voltage, 03 Over Current,
04 Under Current, 05 Over Temperature, 06 Under Temperature,
07 Surge Fault, 08 Auto Ping Fault, 09 RS-232 Ping Fail,
10 EPO Initiate, 11 EPO Recovery
log_date_time: string # "MM/DD/YYYY HH:MM:SS,"
log_sensors: string # "TTT,WWWW,F.F,VVR,CC.R,LLLL.L,O,"
energy_mgmt_states: string # "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16"
- id: log_count
label: Log count
type: string
# Cmd 0x81, 4 ASCII digits e.g. "0120" = 120
- id: part_number
label: Product part number
type: string
# Cmd 0x90, up to 50 ASCII chars
- id: amp_hour_rating
label: Amp hour rating
type: string
# Cmd 0x91, format ###
- id: surge_existence
label: Surge protection existence
type: string
# Cmd 0x93, "Y" or "N"
- id: ip_address
label: Current IP address
type: string
# Cmd 0x94, ASCII "###.###.###.###" no leading zeroes
- id: mac_address
label: MAC address
type: string
# Cmd 0x95, ASCII "##:##:##:##:##:##"
Events
# Unsolicited notifications from the device (host must handle, not request).
# All share the same envelope: <0xFE><Length><Cmd><Sub 0x12>[Data]<Checksum><0xFF>
# Per source: "if you have registered status changes updates, you will receive those unsolicited when items change."
- id: device_ping
label: Device-initiated PING
cmd: 0x01
subcommand: 0x01
command: "FE 03 00 01 01 03 FF"
notes: |
Source sample: 0xFE0300010103FF. Host must respond with pong
(0xFE 03 00 01 10 12 FF) within timeout. Three missed pings = session terminated.
- id: outlet_status_change
label: Outlet status change (unsolicited)
cmd: 0x20
subcommand: 0x12
notes: 'Same payload as response to outlet read (outlet, state, cycle time).'
- id: dry_contact_status_change
label: Dry contact status change (unsolicited)
cmd: 0x30
subcommand: 0x12
- id: outlet_log_update
label: Outlet scheduled log update
cmd: 0x20
subcommand: 0x30
- id: sensor_status_change
label: Sensor reading change (unsolicited)
cmd_range: [0x50, 0x61]
subcommand: 0x12
notes: 'Carries current sensor value when registered via 0x41 status-change registration.'
- id: threshold_status_change
label: Threshold value change (unsolicited)
cmd_range: [0x70, 0x77]
subcommand: 0x12
- id: epo_status_change
label: EPO state change (unsolicited)
cmd: 0x37
subcommand: 0x12
Macros
# UNRESOLVED: source does not define named multi-step macro sequences;
# Sequencing (0x36) is the only batch operation and is modeled as a single action.
Safety
confirmation_required_for:
- epo_initiate # source: "0x11 - Access Denied(EPO)" implies EPO has elevated privilege
interlocks:
- description: |
Emergency Power Off (0x37/0x01 with 0x01) immediately removes downstream power.
Per source, an active EPO state returns NACK 0x11 "Access Denied (EPO)" to other
commands until EPO Recover (0x37/0x01 with 0x00) is issued.
- description: |
Control protocol disabled by default on Premium+; must be enabled via
web UI (Device Setting → Network Services → Control Protocol) before
any TCP command is accepted. On Select/Premium it is enabled at first
webpage login. (source: "Enabling Control Protocol Access")
# UNRESOLVED: specific outlet/load current limits, voltage thresholds, and
# thermal limits are operator-configurable via 0x70-0x77 and were not
# enumerated as fixed safety values in the source.
Notes
- Tier 2 inference — auth type: the protocol clearly demands credentials (the source's "Login Command" with default "user|password" is explicit, not optional). Marked
type: credentialsrather thannone. Do not auto-filluser|passwordif the operator has changed defaults via the web UI. - Source typo in
write_outlet_namesample: the source's worked exampleFE08002110016E616D6559FFuses0x10in the Subcommand slot, but the table above it specifies0x01 - Set Name. The0x01value is taken from the table; the example byte appears to be a transcription error in the source PDF. Treat the table as authoritative. (UNRESOLVEDflagged in the action's notes via this comment.) - Source inconsistency in
set_status_changelength: the source's length field says "Always 0x06" but the data table defines 6 register bytes (B1–B7 listed, with B5 and B6 sometimes not numbered). Action above carries 4 bytes to match the stated length; full resolution requires operator to confirm against an actual device. - PING timing: the source does not specify the PING interval. Implementer must measure against a real device. Three missed pings closes the session.
- Checksum computation: only the low 7 bits of the byte sum are kept (
& 0x7F); the high bit is cleared. Escaped0xFDbytes are excluded from both length and checksum. - Cycling semantics:
state=0x02 (Cycle)on outlet/contact writes requires a 1–3600 s delay encoded as 4 ASCII decimal digits in the trailing 4 bytes. For pure on/off writes, those 4 bytes must be sent as0x30 0x30 0x30 0x30("0000") — the field is still present. - Premium-only commands: Energy Management (0x23), EPO (0x37), Log Alerts (0x40), Status Change (0x41), Sensors (0x50–0x61), Thresholds (0x70–0x77), and product info queries (0x90–0x95) are documented as "Premium/Premium+ only". The UPX RLNK 2000R 2 is a Premium+ product per the source's tier listing, so all of them apply.
- RS-232 vs TCP: source explicitly says RS-232 is "RackLink Premium Only". The 2000R 2 is Premium+, so RS-232 may not be populated. The serial block is included because the source documents it; verify physical connector on the actual device before using.
Provenance
source_domains:
- res.cloudinary.com
- digitalautomation.us
- manualslib.com
- markertek.com
source_urls:
- "https://res.cloudinary.com/avd/image/upload/v1598618818/Resources/Middle%20Atlantic/Power/Firmware/I-00472-Series-Protocol.pdf"
- https://res.cloudinary.com/legrandav/image/upload/v133936596/UPX-COMM-PROTOCOL-UM.pdf
- https://digitalautomation.us/wp-content/uploads/2023/09/MiddleAtlantic_RacklinkSelect_IP.pdf
- https://www.manualslib.com/manual/1839068/Middle-Atlantic-Products-Racklink.html
- "https://www.markertek.com/Attachments/Manuals/Middle%20Atlantic/RLNK-SW820R-SP-Manual.pdf"
retrieved_at: 2026-05-27T02:36:30.545Z
last_checked_at: 2026-06-02T17:23:32.993Z
Verification Summary
verdict: verified
checked_at: 2026-06-02T17:23:32.993Z
matched_actions: 62
action_count: 62
confidence: medium
summary: "All 62 spec actions matched verbatim in source; transport parameters verified; full command coverage. (9 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "firmware version compatibility not stated in source"
- "default baud-rate parity/data/stop values for Premium+ Ethernet-only operation do not apply; RS-232 is Premium only per source"
- "protocol-over-TLS not stated; assume plaintext framing"
- "source does not define named multi-step macro sequences;"
- "specific outlet/load current limits, voltage thresholds, and"
- "PING interval / timeout values not stated in source"
- "NACK 0x11 \"Access Denied(EPO)\" — source lists under NACK codes but does not describe which commands are denied during EPO; treat as global until operator confirms"
- "source's outlet-name sample uses subcommand 0x10 (response) where the table specifies 0x01 (set); flagged above"
- "source's status-change set-subcommand length (0x06) vs. described byte count (6+); flagged above"
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0