Summary
The Somfy UAI+ v1.6 is an RS-485 motor controller on the Somfy Digital Network (SDN) used to operate window-covering motors (shades, blinds, awnings). This spec covers the SDN serial control protocol: device addressing, configuration, motion control, and status reporting over an RS-485 bus at 4800 baud.
Transport
protocols:
- serial
serial:
baud_rate: 4800
data_bits: 8
parity: odd
stop_bits: 1
flow_control: none # UNRESOLVED: source does not document flow control explicitly
character_coding: NRZ
bit_order: LSB_first
inversion: true # all data bits are bitwise-inverted before transmission (NOT of every byte)
auth:
type: none # inferred: no auth procedure in source
Frame layout (RS-485, bitwise-inverted, 11–32 bytes):
- Byte 1: MSG (message identifier)
- Byte 2: ACK/LEN — bit7=ACK request, bit6=EXT (reserved, 0), bits5:0=LEN (0..31)
- Byte 3: NODE TYPE (source/destination)
- Bytes 4–6: SOURCE@ (3-byte NodeID, LSB first)
- Bytes 7–9: DEST@ (3-byte NodeID, LSB first; FFFFFFh = broadcast, 000000h = group)
- Bytes 10..n-2: DATA (0–21 bytes)
- Byte n-1: CHECKSUM = (Byte1 + Byte2 + … + Byte n-2), each byte itself bitwise-inverted
- Bus-inactivity framing (no sync byte); MASTER must wait Treq before sending, SLAVE waits Trep before replying.
Traits
- powerable # inferred from NETWORK_LOCK save/restore and power-cycle behavior
- routable # inferred from group addressing / MOTOR_IP intermediate positions
- queryable # inferred from GET_xxx query messages (GET_NODE_ADDR, GET_GROUP_ADDR, GET_NODE_APP_VERSION, GET_NODE_LABEL, GET_LOCAL_UI, GET_MOTOR_IP, GET_MOTOR_ROLLING_SPEED, GET_NETWORK_LOCK, GET_MOTOR_POSITION, GET_MOTOR_STATUS)
- levelable # inferred from MOTOR_ROLLING_SPEED (UP/DOWN/Slow speed)
Actions
- id: get_node_addr
label: Get Device NodeID
kind: query
command: "MSG=40h (GET_NODE_ADDR), DATA Length=0; reply POST_NODE_ADDR 60h"
params: []
- id: post_node_addr
label: Report Device NodeID
kind: event
command: "MSG=60h (POST_NODE_ADDR), DATA Length=0"
params: []
- id: set_group_addr
label: Set Group Address
kind: action
command: "MSG=51h (SET_GROUP_ADDR), DATA Length=4"
params:
- name: GroupIndex
type: integer
description: Entry in the group table (0..15)
- name: GroupID
type: integer
description: 24-bit group address (NodeID format)
- id: get_group_addr
label: Get Group Address
kind: query
command: "MSG=41h (GET_GROUP_ADDR), DATA Length=1"
params:
- name: GroupIndex
type: integer
description: Entry in the group table (0..15)
- id: post_group_addr
label: Report Group Address
kind: event
command: "MSG=61h (POST_GROUP_ADDR), DATA Length=4"
params:
- name: GroupIndex
type: integer
description: Entry in the group table (0..15)
- name: GroupID
type: integer
description: 24-bit group address
- id: ack
label: Acknowledgement
kind: event
command: "MSG=7Fh (ACK), DATA Length=0"
params: []
- id: nack
label: Negative Acknowledgement / Error
kind: event
command: "MSG=6Fh (NACK), DATA Length=1"
params:
- name: ErrorCode
type: integer
description: "01h Data out of range, 10h Unknown message, 11h Message length error, FFh Busy"
- id: get_node_app_version
label: Get Firmware Revision
kind: query
command: "MSG=74h (GET_NODE_APP_VERSION), DATA Length=0"
params: []
- id: post_node_app_version
label: Report Firmware Revision
kind: event
command: "MSG=75h (POST_NODE_APP_VERSION), DATA Length=6"
params:
- name: App_Reference
type: integer
description: 24-bit firmware part number
- name: App_IndexLetter
type: integer
description: 8-bit ASCII firmware major revision (41h..5Ah)
- name: App_IndexNumber
type: integer
description: 8-bit firmware revision number
- name: Reserved
type: integer
description: 8-bit reserved (00h or FFh)
- id: set_node_label
label: Set User-defined Text Label
kind: action
command: "MSG=55h (SET_NODE_LABEL), DATA Length=16"
params:
- name: Label
type: string
description: 16-character string, space-padded
- id: get_node_label
label: Get User-defined Text Label
kind: query
command: "MSG=45h (GET_NODE_LABEL), DATA Length=0"
params: []
- id: post_node_label
label: Report User-defined Text Label
kind: event
command: "MSG=65h (POST_NODE_LABEL), DATA Length=16"
params:
- name: Label
type: string
description: 16-character string
- id: set_local_ui
label: HMI Management - Enable/Disable UI Feature
kind: action
command: "MSG=17h (SET_LOCAL_UI), DATA Length=3"
params:
- name: Function
type: integer
description: "00h Enable/Unlock, 01h Disable/Lock"
- name: UI_Index
type: integer
description: "00h All controls+feedbacks, 01h DCT input, 02h Local stimuli, 03h Local Radio (Bluetooth), 04h Touch Motion, 05h LEDs"
- name: Priority
type: integer
description: 8-bit priority (00h..FFh, higher = greater)
- id: get_local_ui
label: HMI Management - Query UI Lock State
kind: query
command: "MSG=27h (GET_LOCAL_UI), DATA Length=1"
params:
- name: UI_Index
type: integer
description: UI index (01h..UI_MAX)
- id: post_local_ui
label: HMI Management - Report UI Lock State
kind: event
command: "MSG=37h (POST_LOCAL_UI), DATA Length=5"
params:
- name: UI_Index
type: integer
description: UI index (01h..UI_MAX)
- name: Status
type: integer
description: "00h Enabled/Unlocked, 01h Disabled/Locked"
- name: Source_Addr
type: integer
description: 24-bit NodeID of lock originator
- name: Priority
type: integer
description: 8-bit priority
- id: set_motor_ip
label: Configure Intermediate Position
kind: action
command: "MSG=15h (SET_MOTOR_IP), DATA Length=4"
params:
- name: Function
type: integer
description: "00h Delete IP, 01h Set IP at current position, 03h Set IP at % position, 04h Divide range into N IPs"
- name: IP_Index
type: integer
description: IP index (1..16)
- name: Value
type: integer
description: 16-bit value (position % or IP count depending on Function)
- id: get_motor_ip
label: Get Intermediate Position
kind: query
command: "MSG=25h (GET_MOTOR_IP), DATA Length=1"
params:
- name: IP_Index
type: integer
description: IP index (1..16)
- id: post_motor_ip
label: Report Intermediate Position
kind: event
command: "MSG=35h (POST_MOTOR_IP), DATA Length=4"
params:
- name: IP_index
type: integer
description: IP index (1..16)
- name: Reserved
type: integer
description: 16-bit reserved
- name: IP_position_percentage
type: integer
description: 8-bit position % (0..100, FFh if not set)
- id: set_motor_rolling_speed
label: Set Motor Speed (DC motors only)
kind: action
command: "MSG=13h (SET_MOTOR_ROLLING_SPEED), DATA Length=3"
params:
- name: UP_Speed
type: integer
description: UP movement speed in rpm (range per device datasheet)
- name: DOWN_Speed
type: integer
description: DOWN movement speed in rpm (range per device datasheet)
- name: Slow_Speed
type: integer
description: Adjustment speed in rpm (range per device datasheet)
- id: get_motor_rolling_speed
label: Get Motor Speed
kind: query
command: "MSG=23h (GET_MOTOR_ROLLING_SPEED), DATA Length=0"
params: []
- id: post_motor_rolling_speed
label: Report Motor Speed
kind: event
command: "MSG=33h (POST_MOTOR_ROLLING_SPEED), DATA Length=3"
params:
- 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: set_network_lock
label: Network Lock
kind: action
command: "MSG=16h (SET_NETWORK_LOCK), DATA Length=2"
params:
- name: Function
type: integer
description: "00h Unlock, 01h Lock, 03h Save lock across power cycle, 04h Do not save lock across power cycle"
- name: Priority
type: integer
description: 8-bit priority (00h..FFh, higher = greater; ignored for Function 03h/04h)
- id: get_network_lock
label: Get Network Lock State
kind: query
command: "MSG=26h (GET_NETWORK_LOCK), DATA Length=0"
params: []
- id: post_network_lock
label: Report Network Lock State
kind: event
command: "MSG=36h (POST_NETWORK_LOCK), DATA Length=6"
params:
- name: Status
type: integer
description: "00h Unlocked, 01h Locked"
- name: Source_Addr
type: integer
description: 24-bit NodeID of lock originator
- name: Priority
type: integer
description: 8-bit priority
- name: Saved
type: integer
description: "00h Lock not restored on power cycle, 01h Lock restored on power cycle"
- id: ctrl_moveto_down
label: Move to DOWN Limit
kind: action
command: "MSG=03h (CTRL_MOVETO), DATA Length=4"
params:
- name: Function
type: integer
description: "00h Move to DOWN limit"
- name: Position
type: integer
description: 16-bit position (ignored for this function)
- name: Reserved
type: integer
description: 8-bit reserved
- id: ctrl_moveto_up
label: Move to UP Limit
kind: action
command: "MSG=03h (CTRL_MOVETO), DATA Length=4"
params:
- name: Function
type: integer
description: "01h Move to UP limit"
- name: Position
type: integer
description: 16-bit position (ignored for this function)
- name: Reserved
type: integer
description: 8-bit reserved
- id: ctrl_moveto_ip
label: Move to Intermediate Position
kind: action
command: "MSG=03h (CTRL_MOVETO), DATA Length=4"
params:
- name: Function
type: integer
description: "02h Move to Intermediate Position"
- name: Position
type: integer
description: 16-bit IP index (0..15)
- name: Reserved
type: integer
description: 8-bit reserved
- id: ctrl_moveto_percent
label: Move to Position (% of full range)
kind: action
command: "MSG=03h (CTRL_MOVETO), DATA Length=4"
params:
- name: Function
type: integer
description: "04h Move to % of full travel range"
- name: Position
type: integer
description: 16-bit percent value (0..100)
- name: Reserved
type: integer
description: 8-bit reserved
- id: ctrl_stop
label: Stop Motor
kind: action
command: "MSG=02h (CTRL_STOP), DATA Length=1"
params:
- name: Reserved
type: integer
description: 8-bit reserved
- id: get_motor_position
label: Get Motor Position
kind: query
command: "MSG=0Ch (GET_MOTOR_POSITION), DATA Length=0"
params: []
- id: get_motor_status
label: Get Motor Status
kind: query
command: "MSG=0Eh (GET_MOTOR_STATUS), DATA Length=0"
params: []
Feedbacks
- id: motor_position
label: Motor Position
type: object
fields:
- name: Position_pulse
type: integer
description: 16-bit pulse count within UP_LIMIT..DOWN_LIMIT
- name: Position_percentage
type: integer
description: 8-bit percentage (0..100)
- name: Reserved
type: integer
description: 8-bit reserved
- name: IP
type: integer
description: "8-bit current IP index (01h..IP_MAX); FFh if no IP matched"
- id: motor_status
label: Motor Status
type: object
fields:
- name: Status
type: enum
values: [stopped, running, blocked, locked]
description: "00h Stopped, 01h Running, 02h Blocked (thermal/obstacle), 03h Locked (NETWORK_LOCK)"
- name: Direction
type: enum
values: [going_down, going_up, unknown]
description: "00h Going DOWN, 01h Going UP, FFh Unknown"
- name: Source
type: enum
values: [internal, network, local_ui]
description: "00h Internal, 01h Network message, 02h Local UI"
- name: Cause
type: enum
values: [target_reached, explicit_command, wink, obstacle_detection, over_current, thermal_protection, run_time_exceeded, timeout_exceeded, reset_powerup]
description: "00h Target reached, 01h Explicit command, 02h Wink, 20h Obstacle, 21h Over-current, 22h Thermal, 30h Run time, 32h Timeout, FFh Reset/PowerUp"
- id: nack_error
label: NACK Error Code
type: enum
values: [data_out_of_range, unknown_message, message_length_error, busy]
description: "01h Data out of range, 10h Unknown message, 11h Message length error, FFh Busy"
Variables
# UNRESOLVED: speed ranges (UP/DOWN/Slow) are not in the source - refer to per-device technical datasheet.
Events
- id: post_node_addr
description: Unsolicited NodeID report (MSG=60h, no DATA) - address carried in message header.
- id: post_node_app_version
description: Unsolicited firmware version report (MSG=75h, 6-byte DATA).
- id: post_node_label
description: Unsolicited 16-character label report (MSG=65h).
- id: post_local_ui
description: UI lock state report (MSG=37h, 5-byte DATA).
- id: post_motor_ip
description: Intermediate position report (MSG=35h, 4-byte DATA).
- id: post_motor_rolling_speed
description: Motor speed report (MSG=33h, 3-byte DATA).
- id: post_network_lock
description: Network lock state report (MSG=36h, 6-byte DATA).
- id: ack
description: Positive acknowledgement (MSG=7Fh, no DATA) sent only when ACK bit is set in request.
- id: nack
description: Negative acknowledgement / error (MSG=6Fh, 1-byte ErrorCode).
Macros
# UNRESOLVED: source does not describe multi-step macro sequences.
Safety
confirmation_required_for:
- network_lock # SET_NETWORK_LOCK with Function=01h prevents any other controller from operating the device.
interlocks:
- "When NETWORK_LOCK is active, CTRL_xxx and SET_MOTOR_LIMITS / SET_TILT_LIMITS are rejected with NACK(NODE_IS_LOCKED) unless CTRL_NETWORK_LOCK is sent with equal-or-higher priority."
- "When SET_LOCAL_UI disables a feature, all actions/feedback for that item are ignored or switched off until re-enabled."
- "SET_NETWORK_LOCK Function 03h causes the highest lock to be persisted across power cycles; Function 04h clears this persistence."
# UNRESOLVED: electrical safety, motor thermal protection thresholds, and run-time limits are not documented in the protocol manual and must be sourced from the device's technical datasheet.
Notes
- Bit inversion: every data byte on the bus is bitwise-inverted (NOT) before transmission, including the checksum. Example: byte 58h is transmitted as A7h. This applies to MSG, ACK/LEN, NODE TYPE, SOURCE@, DEST@, DATA, and CHECKSUM.
- Checksum: sum of all bytes in the frame excluding the checksum byte itself (each byte is its post-inversion bus value). No error correction — detection only.
- Addressing modes: Point-to-Point (specific NodeID), Group (DEST@=000000h, requires GroupID in recipient group table), Broadcast (DEST@=FFFFFFh). Group/broadcast requests with ACK or feedback requested risk bus collisions and are discouraged.
- Message categories: SET_xxx (configuration), CTRL_xxx (commands), GET_xxx (status requests, replied to by POST_xxx from SLAVE), POST_xxx (status reports). ACK/NACK are separate.
- Timings: Tc ≤ 1ms between consecutive characters; Tfree ≥ 3ms bus free; Trep 5–255ms SLAVE reply delay (partially randomized); Treq ≥ 10ms MASTER pre-send delay.
- MOTOR_IP Function 04h sets the first N IPs to evenly spaced positions between top and bottom limits, overwriting any existing IPs.
- POST_MOTOR_POSITION IP field returns FFh when position does not match any IP; tolerance around an IP point is motor-dependent.
- POST_MOTOR_STATUS Cause=32h indicates CTRL_MOVE was canceled because more than 2 minutes elapsed (adjustment timeout).
Provenance
source_domains:
- service.somfy.com
source_urls:
- https://service.somfy.com/downloads/bui_v4/sdn-integration-guide--preliminary.pdf
retrieved_at: 2026-07-21T23:49:16.319Z
last_checked_at: 2026-07-22T01:19:22.514Z
Verification Summary
verdict: verified
checked_at: 2026-07-22T01:19:22.514Z
matched_actions: 31
action_count: 31
confidence: medium
summary: "All 31 spec actions matched to distinct MSG codes and verified against source; CTRL_MOVETO correctly expands to its 4 Function variants; transport parameters all found in source. (6 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "voltage, current, and power specifications are not documented in the source protocol manual and are intentionally omitted."
- "source does not document flow control explicitly"
- "speed ranges (UP/DOWN/Slow) are not in the source - refer to per-device technical datasheet."
- "source does not describe multi-step macro sequences."
- "electrical safety, motor thermal protection thresholds, and run-time limits are not documented in the protocol manual and must be sourced from the device's technical datasheet."
- "motor-specific defaults, limits (UP_LIMIT/DOWN_LIMIT/UI_MAX/IP_MAX), and per-motor speed ranges are not in the protocol manual and must come from each motor's technical datasheet."
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0