Summary
The Somfy Connect UAI+ participates in the Somfy Digital Network (SDN), an RS-485 multi-drop bus on which a MASTER device exchanges framed messages with RS-485 motor and transmitter nodes (Glydea, Ø30 DC, Ø50 AC/DC, RS485 RTS transmitter, etc.). This spec covers the bus transport, the full message frame, and every SET/CTRL/GET/POST message documented in the SDN protocol reference, including device management, configuration, motor control, and status reporting.
Transport
protocols:
- serial
serial:
baud_rate: 4800
data_bits: 8
parity: odd
stop_bits: 1
flow_control: none
# Physical layer: RS-485 multi-drop bus.
# Character coding: NRZ.
# Bit order: LSB first.
# All data bits are inverted before transmission (backward compatibility with earliest protocol versions).
# Example from source: transmitted byte 58h appears on the bus as NOT(58h) = A7h.
auth:
type: none # inferred: no auth procedure in source
Traits
- powerable # inferred from stop / move-to commands driving motor power
- levelable # inferred from move-to-position (percent and IP) commands
- queryable # inferred from GET_xxx query commands
Actions
# SDN message frame layout (per source §5):
# Byte 1 : MSG (1 byte, message identifier - literal below)
# Byte 2 : ACK/LEN (1 byte - high bit = ACK request, lower bits = DATA length 0-31)
# Byte 3 : NODE TYPE (1 byte - DEST NodeType used for NodeType filtering;
# SOURCE NodeType is always 00h for a MASTER)
# Bytes 4..6 : SOURCE@ (3 bytes, LSBF)
# Bytes 7..9 : DEST@ (3 bytes, LSBF)
# Bytes 10..n-2 : DATA (length is the LEN value in byte 2)
# Bytes n-1..n : CHECKSUM (2 bytes; sum of bitwise-NOT of every preceding byte)
#
# Minimum frame: 11 bytes (no DATA). Maximum: 32 bytes (21 bytes of DATA).
# Every byte on the wire is the bitwise inverse of the value above (per source §4.2).
# SOURCE@ and DEST@ are LSB first (per source §5.4).
# No synchronization byte - messages are delimited by bus inactivity (per source §4.3).
# Placeholders used:
# {ack_len} = byte 2, ACK bit + LEN value combined
# {filter_nodetype}= byte 3, DEST NodeType filter (00h = no filter, e.g. 06h = Glydea)
# {src_addr} = 3 bytes SOURCE@, LSBF
# {dst_addr} = 3 bytes DEST@, LSBF
# {checksum} = 2 bytes, computed by controller
- id: ctrl_moveto
label: Move to Position
kind: action
command: "03h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {function} {position:2byte} {reserved} {checksum:2byte}"
params:
- name: function
type: enum
description: |
Movement function (1 byte):
00h = Move to DOWN limit (position ignored)
01h = Move to UP limit (position ignored)
02h = Move to Intermediate Position (position = IP index 0-15)
04h = Move to Position in % of full travel range (position = 0-100)
- name: position
type: integer
description: 16-bit value. Meaning depends on function (IP index 0-15 or percent 0-100).
- name: reserved
type: integer
description: 1 byte. Reserved - set to 00h or FFh (per source §5.5).
- id: ctrl_stop
label: Stop
kind: action
command: "02h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {reserved} {checksum:2byte}"
params:
- name: reserved
type: integer
description: 1 byte. Reserved - set to 00h or FFh (per source §5.5). Motor stops immediately with no speed ramp-down (per source §6.4.2).
- id: set_group_addr
label: Set Group Address
kind: action
command: "51h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {group_index} {group_id:3byte} {checksum:2byte}"
params:
- name: group_index
type: integer
description: Group table entry 0-15.
- name: group_id
type: string
description: 24-bit GroupID (3 bytes, LSBF). Same format as a NodeID.
- id: set_node_label
label: Set Node Text Label
kind: action
command: "55h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {label:16char} {checksum:2byte}"
params:
- name: label
type: string
description: 16-character ASCII label, space-padded if shorter (DATA length is always 16).
- id: set_local_ui
label: Set Local UI Lock State
kind: action
command: "17h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {function} {ui_index} {priority} {checksum:2byte}"
params:
- name: function
type: enum
values: [00, 01]
description: "00h = Enable/Unlock, 01h = Disable/Lock"
- name: ui_index
type: enum
values: [00, 01, 02, 03, 04, 05]
description: |
UI element (1 byte):
00h = All local controls and feedbacks
01h = DCT input
02h = Local stimuli (radio pairing pushbutton)
03h = Local Radio access (Bluetooth)
04h = Touch Motion feature
05h = LEDs
- name: priority
type: integer
description: Lock priority 00h-FFh. Higher number = higher priority.
- id: set_motor_ip
label: Set Intermediate Position
kind: action
command: "15h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {function} {ip_index} {value:2byte} {checksum:2byte}"
params:
- name: function
type: enum
values: [00, 01, 03, 04]
description: |
IP operation (1 byte):
00h = Delete IP at ip_index (value ignored; NACK(IP_NOT_SET) if not set)
01h = Set IP at the current position (value ignored)
03h = Set IP at the specified position (value = position in %)
04h = Divide full range into N IPs (value = IP count, ip_index ignored;
first N IPs are equally spaced from top to bottom)
- name: ip_index
type: integer
description: IP table index 1-16.
- name: value
type: integer
description: 16-bit value. Meaning depends on function (percent 0-100, or IP count for 04h).
- id: set_motor_rolling_speed
label: Set Motor Rolling Speed (DC motors only)
kind: action
command: "13h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {up_speed} {down_speed} {slow_speed} {checksum:2byte}"
params:
- name: up_speed
type: integer
description: UP movement speed (rpm). Range per device technical datasheet.
- name: down_speed
type: integer
description: DOWN movement speed (rpm). Range per device technical datasheet.
- name: slow_speed
type: integer
description: Adjustment movement speed (rpm). Range per device technical datasheet.
- id: set_network_lock
label: Set Network Lock
kind: action
command: "16h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {function} {priority} {checksum:2byte}"
params:
- name: function
type: enum
values: [00, 01, 03, 04]
description: |
Lock operation (1 byte):
00h = Unlock (priority applies)
01h = Lock at current position (priority applies)
03h = Save NETWORK_LOCK across power cycle (priority ignored)
04h = Do not save NETWORK_LOCK across power cycle (priority ignored;
default factory state)
- name: priority
type: integer
description: Lock priority 00h-FFh. Higher = higher priority. When locked, only CTRL messages with equal or higher priority execute.
- id: get_node_addr
label: Get Node Address
kind: query
command: "40h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {checksum:2byte}"
params: []
- id: get_group_addr
label: Get Group Address
kind: query
command: "41h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {group_index} {checksum:2byte}"
params:
- name: group_index
type: integer
description: Group table entry 0-15 to query.
- id: get_node_app_version
label: Get Node Application (Firmware) Version
kind: query
command: "74h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {checksum:2byte}"
params: []
- id: get_node_label
label: Get Node Text Label
kind: query
command: "45h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {checksum:2byte}"
params: []
- id: get_local_ui
label: Get Local UI Status
kind: query
command: "27h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {ui_index} {checksum:2byte}"
params:
- name: ui_index
type: integer
description: UI element index 01h-UI_MAX (per device).
- id: get_motor_ip
label: Get Motor Intermediate Position
kind: query
command: "25h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {ip_index} {checksum:2byte}"
params:
- name: ip_index
type: integer
description: IP table index 1-16 to query.
- id: get_motor_rolling_speed
label: Get Motor Rolling Speed
kind: query
command: "23h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {checksum:2byte}"
params: []
- id: get_network_lock
label: Get Network Lock Status
kind: query
command: "26h {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {checksum:2byte}"
params: []
- id: get_motor_position
label: Get Motor Position
kind: query
command: "0Ch {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {checksum:2byte}"
params: []
- id: get_motor_status
label: Get Motor Status
kind: query
command: "0Eh {ack_len} {filter_nodetype} {src_addr:3byte LSBF} {dst_addr:3byte LSBF} {checksum:2byte}"
params: []
Feedbacks
# POST_xxx are SLAVE responses to GET_xxx queries. They share the same frame
# structure as Actions but originate at the controlled device. Decoded payload
# is described below; the wire bytes are bitwise-inverted versions of these.
- id: post_node_addr
type: signal
description: "POST_NODE_ADDR (60h). 0 bytes DATA. The address is in the response frame's SOURCE@ field (no DATA payload)."
- id: post_group_addr
type: object
description: "POST_GROUP_ADDR (61h). 4 bytes DATA."
fields:
- name: group_index
type: integer
description: Group table entry 0-15.
- name: group_id
type: string
description: 24-bit GroupID (3 bytes, LSBF).
- id: post_node_app_version
type: object
description: "POST_NODE_APP_VERSION (75h). 6 bytes DATA."
fields:
- name: app_reference
type: string
description: 24-bit firmware part number (3 bytes).
- name: app_index_letter
type: char
description: Firmware major revision letter, ASCII 41h-5Ah (A-Z).
- name: app_index_number
type: integer
description: Firmware revision number (1 byte).
- name: reserved
type: integer
description: Reserved (1 byte).
- id: post_node_label
type: string
description: "POST_NODE_LABEL (65h). 16 bytes DATA - space-padded ASCII label."
- id: post_local_ui
type: object
description: "POST_LOCAL_UI (37h). 5 bytes DATA."
fields:
- name: ui_index
type: integer
description: UI element index queried.
- name: status
type: enum
values: [00, 01]
description: "00h = Enabled/Unlocked, 01h = Disabled/Locked."
- name: source_addr
type: string
description: NodeID of the device that sent the lock command (3 bytes, LSBF); 000000h when unlocked.
- name: priority
type: integer
description: Lock priority 00h-FFh. Reset to 0x00 when unlocked.
- id: post_motor_ip
type: object
description: "POST_MOTOR_IP (35h). 4 bytes DATA."
fields:
- name: ip_index
type: integer
description: IP table index 1-16.
- name: reserved
type: integer
description: 16-bit reserved field.
- name: ip_position_percentage
type: integer
description: "0-100, or FFh if IP not set at this index."
- id: post_motor_rolling_speed
type: object
description: "POST_MOTOR_ROLLING_SPEED (33h). 3 bytes DATA."
fields:
- name: up_speed
type: integer
description: UP movement speed.
- name: down_speed
type: integer
description: DOWN movement speed.
- name: slow_speed
type: integer
description: Adjustment movement speed.
- id: post_network_lock
type: object
description: "POST_NETWORK_LOCK (36h). 6 bytes DATA."
fields:
- name: status
type: enum
values: [00, 01]
description: "00h = Unlocked, 01h = Locked."
- name: source_addr
type: string
description: NodeID of the device that sent the lock command.
- name: priority
type: integer
description: Lock priority 00h-FFh.
- name: saved
type: enum
values: [00, 01]
description: "00h = Lock will not be restored on power cycle, 01h = Lock will be restored on power cycle."
- id: post_motor_position
type: object
description: "POST_MOTOR_POSITION (0Dh). 5 bytes DATA. Sent even while the motor is running."
fields:
- name: position_pulse
type: integer
description: 16-bit pulse count between UP_LIMIT and DOWN_LIMIT.
- name: position_percentage
type: integer
description: Position 0-100 percent.
- name: reserved
type: integer
description: 8-bit reserved.
- name: ip
type: integer
description: "01h-IP_MAX if at an IP; FFh otherwise. If multiple IPs match, first matching index is returned."
- id: post_motor_status
type: object
description: "POST_MOTOR_STATUS (0Fh). 4 bytes DATA."
fields:
- name: status
type: enum
values: [00, 01, 02, 03]
description: |
Motor state:
00h = Stopped
01h = Running
02h = Blocked (thermal protection, obstacle)
03h = Locked (by NETWORK_LOCK)
- name: direction
type: enum
values: [00, 01, FF]
description: |
Direction:
00h = Going DOWN
01h = Going UP (or last movement direction if stopped)
FFh = Unknown
- name: source
type: enum
values: [00, 01, 02]
description: |
Origin of last command:
00h = Internal (limit/IP reached, over-current, obstacle, thermal)
01h = Network message
02h = Local UI (DCT, local stimulus, local wireless)
- name: cause
type: enum
values: [00, 01, 02, 20, 21, 22, 30, 32, FF]
description: |
Additional information:
00h = Target reached
01h = Explicit command (network or Local UI)
02h = Wink
20h = Obstacle detection
21h = Over-current protection
22h = Thermal protection
30h = Run time exceeded
32h = Timeout exceeded (CTRL_MOVE > 2 minutes => adjustment canceled)
FFh = Reset / PowerUp
- id: ack
type: signal
description: "ACK (7Fh). 0 bytes DATA. Sent by a SLAVE in response to a CTRL/SET/GET message that had its ACK bit set, when the message was processed successfully."
- id: nack
type: object
description: "NACK (6Fh). 1 byte DATA: ErrorCode."
fields:
- name: error_code
type: enum
values: [01, 10, 11, FF]
description: |
Implemented across all products:
01h = Data out of range
10h = Unknown message
11h = Message Length Error
FFh = Busy - cannot process message
Additional product-specific NACK codes may exist beyond those listed in source §6.1.3.
Safety
confirmation_required_for: []
interlocks: []
# UNRESOLVED: this source is a bus-protocol reference and contains no installer-facing
# safety procedures, lockout/tagout steps, or power-on sequencing requirements.
# SET_NETWORK_LOCK is a control lock that blocks CTRL/SET messages, not a safety interlock.
# CTRL_STOP halts the motor immediately with no speed ramp-down (per source §6.4.2).
Notes
Bus and timing constraints (per source §4.3):
Tc(max time between consecutive characters in a frame): 1 ms max.Tfree(bus-free timeout): 3 ms.Trep(slave reply delay): 5-255 ms, partially randomized within range.Treq(master minimum gap before next request): 10 ms.- No synchronization byte — frames are delimited by bus inactivity. Collisions are possible; source §3.7 recommends ACK + retry on NACK or timeout.
Collision-avoidance guidance from source §3.7:
- Do not request feedback in group or broadcast addressing mode.
- Do not request ACK in group or broadcast mode.
Addressing modes (per source §3.4 and §5.4):
- Point-to-point:
SOURCE@= NodeID,DEST@= NodeID. - Group:
SOURCE@= GroupID,DEST@=000000h(every node with this GroupID responds). - Broadcast:
SOURCE@= NodeID,DEST@=FFFFFFh(every node on the bus responds). - NodeType filtering via byte 3 (e.g.
02hØ30 DC,05hRS485 RTS,06hGlydea,07hØ50 AC,08hØ50 DC) limits which product family responds.
Byte 3 (NODE TYPE) interpretation: Source §5.3 states "SOURCE NodeType = NodeType of the transmitter — Always 0h for MASTER devices" and "DEST NodeType = NodeType of the receiver(s) — Used to implement NodeType filtering". In practice the field carries the destination NodeType for filtering, since a MASTER's source nodetype is always 00h.
Reserved fields: Per source §5.5, fields marked "Reserved" must be present in the message and set to 00h or FFh.
Bit inversion on the wire: Per source §4.2, every data byte is bitwise-inverted before transmission for backward compatibility with the earliest protocol version. Source example: logical 58h is transmitted on the bus as A7h. The implementer must apply this inversion to both transmit and receive paths.
Byte order: SOURCE@ and DEST@ are LSB first (per source §5.4). The byte order of multi-byte DATA fields (e.g. Position 16-bit, GroupID 24-bit, App_Reference 24-bit) is not explicitly stated; treat as UNRESOLVED and verify against a real device.
Action coverage rationale: Every distinct MSG identifier in source §6 is enumerated as a separate Action or Query, including all parameter-bearing sub-commands (CTRL_MOVETO function variants, SET_MOTOR_IP function variants, SET_LOCAL_UI function/ui_index variants, SET_NETWORK_LOCK function variants, SET_MOTOR_ROLLING_SPEED speed triplet), per-IP queries, firmware/app version queries, label queries, and motor status/position queries. The full set of POST_xxx slave responses is enumerated as Feedbacks.
Operational notes from source:
- Per §6.3.1, factory default is all UI enabled; DCT/Local Stimuli lock state is not saved across power-up, all other UI lock states are.
- Per §6.3.4, factory default for NETWORK_LOCK is "Do Not Save" — no lock is restored at power-up.
- Per §6.5.2, if a CTRL_MOVE exceeds 2 minutes the motor cancels the adjustment and POST_MOTOR_STATUS reports
cause=32h.
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:14.307Z
last_checked_at: 2026-06-02T22:14:50.715Z
Verification Summary
verdict: verified
checked_at: 2026-06-02T22:14:50.715Z
matched_actions: 18
action_count: 18
confidence: medium
summary: "All 18 spec actions traced to source (dip-safe re-verify). (3 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "the source is a generic SDN protocol reference; per-motor capability ranges (speed limits, pulse ranges, IP_MAX, UI_MAX, etc.) are referenced as \"See Technical Datasheet\" and cannot be populated from this source alone. The IP-side / gateway-side of \"Somfy Connect UAI+\" is not described in this document."
- "this source is a bus-protocol reference and contains no installer-facing"
- "this spec is sourced from the generic SDN protocol reference; per-device firmware compatibility, per-device motor speed/pulse ranges, the IP_MAX and UI_MAX values, and any \"Somfy Connect UAI+\"-specific extension commands are not stated in the source and must be filled in from device-specific datasheets or a verified integration."
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0