Summary
Somfy Digital Network (SDN) is a half-duplex RS-485 protocol used by Somfy motorised shading products (e.g. RS485 RTS transmitter, Glydea, Ø30 DC, Ø50 AC/DC, Ø40 AC). The Tahoma hub acts as a MASTER on the bus, addressing SLAVE motor nodes by 3-byte NodeID. This spec covers the device management, configuration, control, and status messages described in the SDN Protocol Integration Guide (revision covering GET_NODE_ADDR through GET_MOTOR_STATUS).
Transport
protocols:
- serial
serial:
baud_rate: 4800
data_bits: 8
parity: odd
stop_bits: 1
flow_control: none
electrical: rs485
half_duplex: true
auth:
type: none # inferred: no auth procedure in source
Notes on framing:
- All data bits must be inverted before transmission (NOT applied per byte); example: byte 58h on the wire = A7h.
- Character coding: NRZ. Least significant bit first.
- No sync byte; messages delimited by bus inactivity (Tfree = 3 ms min).
- Tc ≤ 1 ms between consecutive characters; Treq ≥ 10 ms before MASTER transmits; Trep = 5–255 ms randomized before SLAVE replies.
Traits
- routable # inferred: group/broadcast addressing
- queryable # inferred: GET_xxx / POST_xxx queries
Actions
# SDN messages follow the framing:
# MSG | ACK/LEN | NODE_TYPE | SRC@(3) | DST@(3) | DATA[...] | CHECKSUM
# CHECKSUM = sum of Byte1..Byte(n-2).
# SET_xxx = configuration, CTRL_xxx = control, GET_xxx = query (POST_xxx is the response).
# Below, commands are listed by their MSG opcode and DATA structure. Variable fields shown in {curly}.
# Source: SOMFY SDN Protocol Integration Guide §6.
- id: get_node_addr
label: Get Node Address (discover)
kind: query
command: "MSG=40h"
params: []
# DATA length 0. Replies arrive as POST_NODE_ADDR (60h) with node address in message header.
- id: set_group_addr
label: Set Group Address
kind: action
command: "MSG=51h DATA[4]={GroupIndex}{GroupID_3bytes}"
params:
- name: GroupIndex
type: integer
description: Group table entry 0-15
- name: GroupID
type: integer
description: 24-bit group address (LSB first)
- id: get_group_addr
label: Get Group Address
kind: query
command: "MSG=41h DATA[1]={GroupIndex}"
params:
- name: GroupIndex
type: integer
description: Group table entry 0-15
- id: set_node_label
label: Set Node Label (user-defined text)
kind: action
command: "MSG=55h DATA[16]={Label_16chars}"
params:
- name: Label
type: string
description: 16 ASCII characters; pad shorter strings with spaces
- id: get_node_label
label: Get Node Label
kind: query
command: "MSG=45h"
- id: set_local_ui
label: Set Local UI (HMI enable/lock)
kind: action
command: "MSG=17h DATA[3]={Function}{UI_Index}{Priority}"
params:
- name: Function
type: integer
description: "00h=Enable/Unlock, 01h=Disable/Lock"
- name: UI_Index
type: integer
description: "00h=All, 01h=DCT, 02h=Local stimuli, 03h=Local Radio, 04h=Touch Motion, 05h=LEDs"
- name: Priority
type: integer
description: "0-255; higher = higher priority"
- id: get_local_ui
label: Get Local UI Status
kind: query
command: "MSG=27h DATA[1]={UI_Index}"
params:
- name: UI_Index
type: integer
description: "01h-UI_MAX"
- id: set_motor_ip
label: Set Intermediate Position
kind: action
command: "MSG=15h DATA[4]={Function}{IP_Index}{Value_2bytes}"
params:
- name: Function
type: integer
description: "00h=Delete IP, 01h=Set IP at current position, 03h=Set IP at % position, 04h=Divide range (IP_Index ignored)"
- name: IP_Index
type: integer
description: "1-16 (ignored when Function=04h)"
- name: Value
type: integer
description: "16-bit; % position for Function=03h, IP count for Function=04h"
- id: get_motor_ip
label: Get Intermediate Position
kind: query
command: "MSG=25h DATA[1]={IP_Index}"
params:
- name: IP_Index
type: integer
description: "1-16"
- id: set_motor_rolling_speed
label: Set Motor Rolling Speed (DC motors only)
kind: action
command: "MSG=13h DATA[3]={UP_Speed}{DOWN_Speed}{Slow_Speed}"
params:
- name: UP_Speed
type: integer
description: UP speed in rpm; range per device datasheet
- name: DOWN_Speed
type: integer
description: DOWN speed in rpm; range per device datasheet
- name: Slow_Speed
type: integer
description: Slow speed in rpm; range per device datasheet
- id: get_motor_rolling_speed
label: Get Motor Rolling Speed
kind: query
command: "MSG=23h"
- id: set_network_lock
label: Set Network Lock
kind: action
command: "MSG=16h DATA[2]={Function}{Priority}"
params:
- name: Function
type: integer
description: "00h=Unlock, 01h=Lock, 03h=Save lock across power cycle, 04h=Do not save"
- name: Priority
type: integer
description: "0-255 (ignored for Functions 03h/04h)"
- id: get_network_lock
label: Get Network Lock Status
kind: query
command: "MSG=26h"
- id: ctrl_moveto
label: Move To Position
kind: action
command: "MSG=03h DATA[4]={Function}{Position_2bytes}{Reserved}"
params:
- name: Function
type: integer
description: "00h=DOWN limit, 01h=UP limit, 02h=Intermediate Position, 04h=Position in %"
- name: Position
type: integer
description: "16-bit; IP index (0-15) for Function=02h, % (0-100) for Function=04h; ignored for 00h/01h"
- name: Reserved
type: integer
description: 8-bit; set to 00h or FFh
- id: ctrl_stop
label: Stop Motor
kind: action
command: "MSG=02h DATA[1]={Reserved}"
params:
- name: Reserved
type: integer
description: 8-bit; set to 00h or FFh
- id: get_motor_position
label: Get Motor Position
kind: query
command: "MSG=0Ch"
- id: get_motor_status
label: Get Motor Status
kind: query
command: "MSG=0Eh"
- id: get_node_app_version
label: Get Firmware Revision
kind: query
command: "MSG=74h"
Feedbacks
- id: post_node_addr
label: Node Address Report
type: integer
values: []
notes: "MSG=60h, no DATA; address carried in header."
- id: post_group_addr
label: Group Address Report
type: integer
values: []
notes: "MSG=61h, DATA[4]={GroupIndex}{GroupID}."
- id: post_node_label
label: Node Label Report
type: string
values: []
notes: "MSG=65h, 16-char ASCII."
- id: post_local_ui
label: Local UI Status Report
type: integer
values: []
notes: "MSG=37h, DATA[5]: UI_Index, Status (00h=enabled, 01h=disabled), Source_Addr (3B), Priority."
- id: post_motor_ip
label: Intermediate Position Report
type: integer
values: []
notes: "MSG=35h, DATA[4]: IP_index, Reserved (16-bit), Position_percentage (0-100, FFh=not set)."
- id: post_motor_rolling_speed
label: Motor Rolling Speed Report
type: integer
values: []
notes: "MSG=33h, DATA[3]: UP/DOWN/Slow rpm."
- id: post_network_lock
label: Network Lock Status Report
type: integer
values: []
notes: "MSG=36h, DATA[6]: Status (00h=unlocked, 01h=locked), Source_Addr (3B), Priority, Saved (00h/01h)."
- id: post_motor_position
label: Motor Position Report
type: integer
values: []
notes: "MSG=0Dh, DATA[5]: Position_pulse (16-bit, UP_LIMIT..DOWN_LIMIT), Position_percentage (0-100), Reserved, IP (01h..IP_MAX, FFh=none)."
- id: post_motor_status
label: Motor Status Report
type: integer
values: []
notes: "MSG=0Fh, DATA[4]: Status (00h=Stopped, 01h=Running, 02h=Blocked, 03h=Locked), Direction (00h=DOWN, 01h=UP, FFh=Unknown), Source (00h=Internal, 01h=Network, 02h=Local UI), Cause (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)."
- id: post_node_app_version
label: Firmware Revision Report
type: string
values: []
notes: "MSG=75h, DATA[6]: App_Reference (3B), App_IndexLetter (1B ASCII), App_IndexNumber, Reserved."
- id: ack
label: Acknowledgement
type: integer
values: []
notes: "MSG=7Fh, DATA length 0. Sent only when ACK bit=1 in request."
- id: nack
label: Negative Acknowledgement / Error
type: integer
values:
- 01h # Data out of range
- 10h # Unknown message
- 11h # Message length error
- FFh # Busy - cannot process
notes: "MSG=6Fh, DATA[1]=ErrorCode. Additional NACK codes (NODE_IS_LOCKED, LOW_PRIORITY, IP_NOT_SET, DATA_ERROR) referenced in §6 but not enumerated here - UNRESOLVED until §6.1.3 expanded in source."
Variables
- id: motor_position_pulse
label: Motor Position (pulses)
type: integer
description: 16-bit; range = UP_LIMIT..DOWN_LIMIT per motor
- id: motor_position_percentage
label: Motor Position (%)
type: integer
description: 0-100
- id: intermediate_position
label: Intermediate Position (IP)
type: integer
description: 1-16 slots; position reported as % (FFh = not set)
- id: rolling_speed
label: Rolling Speed (rpm)
type: integer
description: Three slots: UP, DOWN, Slow. Valid ranges defined per-motor in the device technical datasheet - UNRESOLVED in this source.
- id: network_lock_status
label: Network Lock Status
type: enum
values: [unlocked, locked]
- id: network_lock_saved
label: Network Lock Persists Across Power Cycle
type: enum
values: [no, yes]
Events
# UNRESOLVED: source does not describe unsolicited push notifications distinct from POST_xxx replies.
Macros
# UNRESOLVED: source does not describe compound/multi-step sequences.
Safety
confirmation_required_for:
- ctrl_moveto # moves blind load; lock/network-lock interactions exist
interlocks:
- id: network_lock
description: "When SET_NETWORK_LOCK Status=01h, all CTRL_xxx movement commands and SET_MOTOR_LIMITS/SET_TILT_LIMITS are rejected with NACK(NODE_IS_LOCKED) unless they carry equal-or-higher priority than the lock."
- id: motor_status_thermal
description: "POST_MOTOR_STATUS Cause=22h indicates thermal protection has tripped (Status=Blocked)."
- id: motor_status_obstacle
description: "POST_MOTOR_STATUS Cause=20h indicates obstacle detection (Status=Blocked)."
Notes
- Known-protocol mismatch: input prompt said "TCP/IP"; this refined source is the RS-485 Somfy Digital Network (SDN) bus spec. No IP/Ethernet layer is described.
- Bus collisions: avoid requesting feedback (POST/ACK) in group or broadcast mode to lower collision risk on the half-duplex bus.
- Retry strategy: the source recommends implementing a retry when NACK is received or no ACK after a timeout, since collisions are possible.
- Radio inversion: every data byte is bitwise-NOTed on the wire (LSB first) for backward compatibility with early protocol revisions.
- Addressing formats: NodeID and GroupID are 3 bytes; on the wire they are LSB-first.
Broadcast DEST@ = FFFFFFh. Empty groupDEST@ = 000000h. - NodeType table (from §3.2.2): 02h=Ø30 DC, 05h=RS485 RTS transmitter, 06h=Glydea, 07h=Ø50 AC, 08h=Ø50 DC, 09h=Ø40 AC (not yet available at time of doc).
- Unsaved settings: per §6.3.1, DCT input and Local Stimuli UI state are NOT saved across power cycles; all other UI items are.
- Intermediate Position Function 04h: sets the first
xIPs evenly across the travel range (e.g. 2 IPs → 33% / 66%; 3 IPs → 25% / 50% / 75%). - NACK codes beyond §6.1.3 table (DATA_ERROR, LOW_PRIORITY, IP_NOT_SET, NODE_IS_LOCKED) are referenced in body text but not enumerated in the source excerpt.
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:23:35.364Z
last_checked_at: 2026-07-22T01:14:01.302Z
Verification Summary
verdict: verified
checked_at: 2026-07-22T01:14:01.302Z
matched_actions: 18
action_count: 18
confidence: medium
summary: "All 18 spec actions matched MSG opcodes verbatim; data shapes correct; transport parameters verified. (4 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "Known protocol \"TCP/IP\" from prompt is wrong — source describes RS-485 SDN bus (asynchronous serial). No Ethernet/Wi-Fi/IP control layer documented in this refined excerpt."
- "source does not describe unsolicited push notifications distinct from POST_xxx replies."
- "source does not describe compound/multi-step sequences."
- "power-on sequencing requirements, fault recovery, and exact voltage/current specs not stated in this excerpt."
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0