Summary
The Somfy UAI+ integrates RS-485 Somfy Digital Network (SDN) bus devices (tubular motors, etc.) into third-party control systems. This spec covers the SDN half-duplex MASTER/SLAVE protocol: message framing, node addressing, and the command catalogue exposed by SDN-compatible motor endpoints.
Transport
protocols:
- serial
serial:
baud_rate: 4800
data_bits: 8
parity: odd
stop_bits: 1
flow_control: none
electrical: rs485 # inferred: source states "RS485 device" / "RS485 bus" throughout
half_duplex: true # inferred from "half-duplex communication" statement
auth:
type: none # inferred: no auth procedure in source
Traits
# - powerable No explicit power on/off command in source
# - routable No input/output routing
# - queryable GET_xxx / POST_xxx query cycle present
# - levelable Position commands present (CTRL_MOVETO)
# - lockable SET_NETWORK_LOCK present
# - configurable SET_xxx settings messages present
Actions
# SDN message format reminder (see §5):
# Byte 1 MSG - message opcode
# Byte 2 ACK/LEN - ACK bit + LEN (data length 0..31)
# Byte 3 NODE TYPE - src(4b) | dst(4b)
# Bytes 4-6 SOURCE@ - 3-byte NodeID, LSBF
# Bytes 7-9 DEST@ - 3-byte NodeID (or group / 000000h / FFFFFFh), LSBF
# Bytes 10.. DATA - see per-message tables
# Last byte CHECKSUM - sum of all preceding bytes (no complement)
#
# All hex opcodes below are written VERBATIM from the source's "MSG" column.
# Variable DATA bytes are shown as {placeholders} with param descriptions.
# A sending implementation must also supply NodeType, Source@, Dest@, ACK bit,
# LEN byte, and the trailing CHECKSUM (sum of bytes 1..n-1).
# ===== Device Management =====
- id: get_node_addr
label: Get Node Address
kind: query
command: "MSG=40h, DATA length=0"
params: []
notes: "Broadcast request; slave replies with POST_NODE_ADDR (60h)."
- id: set_group_addr
label: Set Group Address
kind: action
command: "MSG=51h, DATA={group_index}{group_id_3bytes}"
params:
- name: group_index
type: integer
description: Entry in the group table (0..15)
- name: group_id
type: string
description: 24-bit GroupID, 3 bytes LSBF
notes: "DATA length = 4 bytes."
- id: get_group_addr
label: Get Group Address
kind: query
command: "MSG=41h, DATA={group_index}"
params:
- name: group_index
type: integer
description: Entry in the group table (0..15)
notes: "DATA length = 1 byte."
- id: post_group_addr
label: Group Address Report
kind: feedback
command: "MSG=61h, DATA={group_index}{group_id_3bytes}"
params:
- name: group_index
type: integer
description: Entry in the group table (0..15)
- name: group_id
type: string
description: 24-bit GroupID, 3 bytes LSBF
notes: "Posted by slave in reply to GET_GROUP_ADDR. DATA length = 4 bytes."
- id: ack
label: Acknowledgment
kind: feedback
command: "MSG=7Fh, DATA length=0"
params: []
notes: "Sent when ACK bit = 1 in the original request and processing succeeds."
- id: nack
label: Negative Acknowledgment
kind: feedback
command: "MSG=6Fh, DATA={error_code}"
params:
- name: error_code
type: string
description: 01h=data out of range, 10h=unknown message, 11h=length error, FFh=busy
notes: "DATA length = 1 byte."
# ===== Device Information =====
- id: get_node_app_version
label: Get Firmware Revision
kind: query
command: "MSG=74h, DATA length=0"
params: []
- id: post_node_app_version
label: Firmware Revision Report
kind: feedback
command: "MSG=75h, DATA={app_ref_3bytes}{index_letter}{index_number}{reserved}"
params:
- name: app_ref
type: string
description: 24-bit Firmware Part Number, 3 bytes
- name: index_letter
type: string
description: 8-bit ASCII firmware major revision (41h..5Ah)
- name: index_number
type: string
description: 8-bit firmware revision
- name: reserved
type: string
description: 8-bit reserved
notes: "DATA length = 6 bytes."
- id: set_node_label
label: Set User-Defined Text Label
kind: action
command: "MSG=55h, DATA={label_16chars}"
params:
- name: label
type: string
description: ASCII string, padded to exactly 16 characters with spaces
notes: "DATA length is always 16 bytes; pad with spaces if shorter."
- id: get_node_label
label: Get User-Defined Text Label
kind: query
command: "MSG=45h, DATA length=0"
params: []
- id: post_node_label
label: Text Label Report
kind: feedback
command: "MSG=65h, DATA={label_16chars}"
params:
- name: label
type: string
description: 16-character ASCII label
notes: "DATA length = 16 bytes."
# ===== Device Configuration =====
- id: set_local_ui
label: Lock/Unlock Local UI
kind: action
command: "MSG=17h, DATA={function}{ui_index}{priority}"
params:
- name: function
type: string
description: 00h=Enable/Unlock, 01h=Disable/Lock
- name: ui_index
type: string
description: 00h=All, 01h=DCT input, 02h=Local stimuli, 03h=Local Radio (BT), 04h=Touch Motion, 05h=LEDs
- name: priority
type: string
description: 8-bit; higher number = higher priority
notes: "DATA length = 3 bytes. UI_Index=00h priority must be >= highest existing lock level or NACK(LOW_PRIORITY)."
- id: get_local_ui
label: Get Local UI Status
kind: query
command: "MSG=27h, DATA={ui_index}"
params:
- name: ui_index
type: string
description: 01h..UI_MAX (see SET_LOCAL_UI list)
notes: "DATA length = 1 byte."
- id: post_local_ui
label: Local UI Status Report
kind: feedback
command: "MSG=37h, DATA={ui_index}{status}{source_addr_3bytes}{priority}"
params:
- name: ui_index
type: string
description: 01h..UI_MAX
- name: status
type: string
description: 00h=Enabled/Unlocked, 01h=Disabled/Locked
- name: source_addr
type: string
description: 24-bit NodeID of the device that issued the lock
- name: priority
type: string
description: 8-bit lock priority
notes: "DATA length = 5 bytes."
- id: set_motor_ip
label: Set Intermediate Position
kind: action
command: "MSG=15h, DATA={function}{ip_index}{value_2bytes}"
params:
- name: function
type: string
description: 00h=Delete IP, 01h=Set at current pos, 03h=Set at % pos, 04h=Divide full range (Value=count)
- name: ip_index
type: integer
description: 1..16 (ignored when function=04h)
- name: value
type: string
description: 16-bit; meaning depends on function (% for 03h, count for 04h)
notes: "DATA length = 4 bytes. Existing IPs are overwritten."
- id: get_motor_ip
label: Get Intermediate Position
kind: query
command: "MSG=25h, DATA={ip_index}"
params:
- name: ip_index
type: integer
description: 1..16
notes: "DATA length = 1 byte."
- id: post_motor_ip
label: Intermediate Position Report
kind: feedback
command: "MSG=35h, DATA={ip_index}{reserved_2bytes}{ip_position_percentage}"
params:
- name: ip_index
type: integer
description: 1..16
- name: reserved
type: string
description: 16-bit reserved
- name: ip_position_percentage
type: integer
description: 0..100; FFh if IP not set
notes: "DATA length = 4 bytes."
- id: set_motor_rolling_speed
label: Set Motor Rolling Speed
kind: action
command: "MSG=13h, DATA={up_speed}{down_speed}{slow_speed}"
params:
- name: up_speed
type: string
description: 8-bit; rpm during UP movement (range per device datasheet)
- name: down_speed
type: string
description: 8-bit; rpm during DOWN movement (range per device datasheet)
- name: slow_speed
type: string
description: 8-bit; rpm for adjustment movements (range per device datasheet)
notes: "DC motors only. DATA length = 3 bytes. Speed ranges per device technical datasheet."
- id: get_motor_rolling_speed
label: Get Motor Rolling Speed
kind: query
command: "MSG=23h, DATA length=0"
params: []
- id: post_motor_rolling_speed
label: Motor Rolling Speed Report
kind: feedback
command: "MSG=33h, DATA={up_speed}{down_speed}{slow_speed}"
params:
- name: up_speed
type: string
description: 8-bit
- name: down_speed
type: string
description: 8-bit
- name: slow_speed
type: string
description: 8-bit
notes: "DATA length = 3 bytes."
- id: set_network_lock
label: Set Network Lock
kind: action
command: "MSG=16h, DATA={function}{priority}"
params:
- name: function
type: string
description: 00h=Unlock, 01h=Lock, 03h=Save on power cycle, 04h=Do not save on power cycle
- name: priority
type: string
description: 8-bit; higher number = higher priority (ignored for functions 03h/04h)
notes: "DATA length = 2 bytes. When locked, only CTRL with >= priority accepted; others return NACK(NODE_IS_LOCKED)."
- id: get_network_lock
label: Get Network Lock
kind: query
command: "MSG=26h, DATA length=0"
params: []
- id: post_network_lock
label: Network Lock Report
kind: feedback
command: "MSG=36h, DATA={status}{source_addr_3bytes}{priority}{saved}"
params:
- name: status
type: string
description: 00h=Unlocked, 01h=Locked
- name: source_addr
type: string
description: 24-bit NodeID of lock source
- name: priority
type: string
description: 8-bit lock priority
- name: saved
type: string
description: 00h=not restored on power cycle, 01h=restored on power cycle
notes: "DATA length = 6 bytes."
# ===== Device Control =====
- id: ctrl_moveto
label: Move to Position
kind: action
command: "MSG=03h, DATA={function}{position_2bytes}{reserved}"
params:
- name: function
type: string
description: 00h=DOWN limit, 01h=UP limit, 02h=Intermediate Position (Position=IP index 0..15), 04h=Position in % (0..100)
- name: position
type: string
description: 16-bit; meaning depends on function
- name: reserved
type: string
description: 8-bit reserved
notes: "DATA length = 4 bytes."
- id: ctrl_stop
label: Stop
kind: action
command: "MSG=02h, DATA={reserved}"
params:
- name: reserved
type: string
description: 8-bit reserved
notes: "DATA length = 1 byte. Motor stops immediately without speed ramp-down."
# ===== Device Status =====
- id: get_motor_position
label: Get Motor Position
kind: query
command: "MSG=0Ch, DATA length=0"
params: []
- id: post_motor_position
label: Motor Position Report
kind: feedback
command: "MSG=0Dh, DATA={position_pulse_2bytes}{position_percentage}{reserved}{ip_index}"
params:
- name: position_pulse
type: string
description: 16-bit; UP_LIMIT..DOWN_LIMIT
- name: position_percentage
type: integer
description: 0..100
- name: reserved
type: string
description: 8-bit reserved
- name: ip_index
type: string
description: 01h..IP_MAX; FFh if no IP matches current position
notes: "DATA length = 5 bytes. Sent even while motor is running."
- id: get_motor_status
label: Get Motor Status
kind: query
command: "MSG=0Eh, DATA length=0"
params: []
- id: post_motor_status
label: Motor Status Report
kind: feedback
command: "MSG=0Fh, DATA={status}{direction}{source}{cause}"
params:
- name: status
type: string
description: 00h=Stopped, 01h=Running, 02h=Blocked, 03h=Locked
- name: direction
type: string
description: 00h=Going DOWN, 01h=Going UP, FFh=Unknown
- name: source
type: string
description: 00h=Internal, 01h=Network message, 02h=Local UI
- name: cause
type: string
description: 00h=Target reached, 01h=Explicit command, 02h=WINK, 20h=Obstacle, 21h=Over-current, 22h=Thermal, 30h=Run time exceeded, 32h=Timeout exceeded, FFh=Reset/Power up
notes: "DATA length = 4 bytes."
Feedbacks
- id: node_addr
type: object
description: 24-bit NodeID, LSBF, in DEST@ of POST_NODE_ADDR
- id: group_addr
type: object
description: GroupIndex (0..15) + 24-bit GroupID
- id: ack_status
type: enum
values: [ack, nack]
- id: nack_error_code
type: enum
values: [data_out_of_range, unknown_message, length_error, busy, low_priority, ip_not_set, node_is_locked]
- id: firmware_version
type: object
description: 24-bit App_Reference + 8-bit IndexLetter (ASCII) + 8-bit IndexNumber
- id: node_label
type: string
description: 16-character ASCII label
- id: local_ui_status
type: object
description: UI_Index, Status (enabled/disabled), Source_Addr, Priority
- id: motor_ip
type: object
description: IP_Index, IP_position_percentage (0..100, FFh=unset)
- id: motor_rolling_speed
type: object
description: UP_Speed, DOWN_Speed, Slow_Speed (each 8-bit rpm)
- id: network_lock_status
type: object
description: Status, Source_Addr, Priority, Saved
- id: motor_position
type: object
description: Position_pulse (16-bit), Position_percentage (0..100), IP index
- id: motor_status
type: object
description: Status (Stopped/Running/Blocked/Locked), Direction, Source, Cause
Variables
- id: intermediate_position_count
type: integer
description: Up to 16 IP slots per device (IP_Index 1..16)
range: [1, 16]
- id: group_membership_count
type: integer
description: Up to 16 GroupID entries per device (GroupIndex 0..15)
range: [0, 15]
- id: lock_priority
type: integer
description: 8-bit; higher = higher priority
range: [0, 255]
Events
# UNRESOLVED: source describes request/response (GET_xxx / POST_xxx) but no
# unsolicited push notifications from slave to master.
Macros
# UNRESOLVED: source documents no multi-step sequences.
Safety
confirmation_required_for: []
interlocks:
- description: "When SET_NETWORK_LOCK is active, all CTRL_xxx and limit-changing SET_xxx messages are rejected with NACK(NODE_IS_LOCKED) unless sender priority >= current lock priority."
# UNRESOLVED: no explicit high-voltage / mechanical hazard warnings in source excerpt.
Notes
- Bus is half-duplex RS-485; all data bits must be INVERTED before transmission for backward compatibility (NOT(58h) = A7h on the wire).
- Checksum = sum of all bytes from Byte 1 through Byte n-1 (no complement, per §5.6).
- SOURCE@ / DEST@ are 3 bytes LSBF; DEST@ = 000000h for group addressing, FFFFFFh for broadcast.
- Address bytes shown as e.g. "05:04:03" on device labels map to wire bytes 03h, 04h, 05h.
- Bus timing: Tc ≤ 1ms between characters, Treq ≥ 10ms before master transmits, Tfree = 3ms, Trep 5..255ms (randomized) for slave reply.
- Always set ACK bit and implement a retry strategy; NACK or timeout triggers retry.
- The user-supplied "Known protocol: TCP/IP" hint is overridden by source: SDN is RS-485 serial, not TCP/IP.
Provenance
source_domains:
- service.somfy.com
source_urls:
- https://service.somfy.com/downloads/bui_v4/sdn-integration-guide--preliminary.pdf
retrieved_at: 2026-04-29T08:47:16.319Z
last_checked_at: 2026-06-02T05:46:20.978Z
Verification Summary
verdict: verified
checked_at: 2026-06-02T05:46:20.978Z
matched_actions: 29
action_count: 29
confidence: medium
summary: "All 29 spec actions matched verbatim in source §6 command tables; transport parameters verified against §4.1 serial config. (5 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "UAI+ model-specific behaviour (firmware range, supported NodeType list, port) not stated in source."
- "source describes request/response (GET_xxx / POST_xxx) but no"
- "source documents no multi-step sequences."
- "no explicit high-voltage / mechanical hazard warnings in source excerpt."
- "UAI+-specific port number, supported NodeType list, firmware range, and DC-motor speed ranges not stated in source — they are device-specific (per technical datasheet)."
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0