Summary

Spec covers Somfy SDN (SOMFY Digital Network) RS485 bus protocol for the Somesse 30/50 motor family. Half-duplex MASTER/SLAVE bus, 4800 baud, 8N1-Odd, all data bits inverted on the wire. NodeType 08h identifies the Ø50 DC Serie RS485 family.

Transport

protocols:
  - serial
serial:
  baud_rate: 4800
  data_bits: 8
  parity: odd
  stop_bits: 1
  flow_control: none
  wiring:
    bus: RS485
    electrical:
      data_inversion: true  # source: "all data bits need to be inverted before transmission"
      bit_order: LSB_first
      start_bit_level: 0
      stop_bit_level: 1
      character_coding: NRZ
    half_duplex: true
auth:
  type: none  # inferred: no login/password/auth procedure in source
timings_ms:
  Tc_max: 1         # max gap between two consecutive characters
  Tfree_typical: 3  # bus free timeout
  Trep_min: 5       # slave reply delay min
  Trep_max: 255     # slave reply delay max (randomized within range)
  Treq_min: 10      # master must wait at least Treq after last bus activity

Message Framing

# Generic SDN frame on the wire. Minimum 11 bytes, max 32 bytes (max 21 bytes DATA).
# Every byte transmitted on the wire = logical_byte XOR 0xFF (i.e. inverted).
frame:
  layout:
    - byte1: MSG
    - byte2: ACK_LEN  # bit7=ACK request, bit6=EXT(0), bits4-0=LEN (0-31)
    - byte3: NODE_TYPE  # hi nibble=SOURCE NodeType (0h for MASTER), lo nibble=DEST NodeType
    - bytes4-6: SOURCE_ADDR  # 3 bytes, LSB first
    - bytes7-9: DEST_ADDR    # 3 bytes, LSB first; FFFFFFh = broadcast
    - bytes10..n-2: DATA     # see per-action payload spec
    - bytes_n-1_n: CHECKSUM  # 2 bytes; CHECKSUM = (Byte1 + ... + Byte n-2)
  addressing_modes:
    - point_to_point: SRC=NodeID, DEST=NodeID
    - group: SRC=GroupID, DEST=000000h
    - broadcast: SRC=NodeID, DEST=FFFFFFh
  acknowledgment:
    ack: 7Fh  # positive ack, no data
    nack: 6Fh # 1 byte ErrorCode (01h=out_of_range, 10h=unknown_msg, 11h=length_error, FFh=busy)

Traits

- queryable   # 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   # CTRL_MOVETO position-in-% (0..100) and intermediate-position control

Actions

# Each SDN message = one action. All bytes must be bit-inverted on the wire per §4.2.

# ---------- Device management ----------
- id: get_node_addr
  label: Get Node Address (discover)
  kind: query
  command: "40h"   # MSG byte
  params: []
  notes: "Sent broadcast. SLAVE replies POST_NODE_ADDR (60h) with no data - its address is in the message header."

- id: set_group_addr
  label: Set Group Address
  kind: action
  command: "51h {GroupIndex} {GroupID_3_bytes_LSBF}"
  params:
    - name: GroupIndex
      type: integer
      min: 0
      max: 15
      description: Entry in the group table (0..15)
    - name: GroupID
      type: bytes
      length: 3
      description: 24-bit group address, LSB first

- id: get_group_addr
  label: Get Group Address
  kind: query
  command: "41h {GroupIndex}"
  params:
    - name: GroupIndex
      type: integer
      min: 0
      max: 15

- id: set_node_label
  label: Set Node Text Label
  kind: action
  command: "55h {Label_padded_to_16_chars}"
  params:
    - name: Label
      type: string
      max_length: 16
      description: "DATA length always 16 chars; pad with spaces if shorter."

- id: get_node_label
  label: Get Node Text Label
  kind: query
  command: "45h"
  params: []

- id: get_node_app_version
  label: Get Firmware Revision
  kind: query
  command: "74h"
  params: []

# ---------- Device configuration ----------
- id: set_local_ui
  label: Set HMI Lock/Enable
  kind: action
  command: "17h {Function} {UI_Index} {Priority}"
  params:
    - name: Function
      type: enum
      values: [00h, 01h]
      description: "00h=Enable/Unlock, 01h=Disable/Lock"
    - name: UI_Index
      type: enum
      values: [00h, 01h, 02h, 03h, 04h, 05h]
      description: "00h=All, 01h=DCT input, 02h=Local stimuli, 03h=Local Radio (BT), 04h=Touch Motion, 05h=LEDs"
    - name: Priority
      type: integer
      min: 0
      max: 255
      description: "Greater = higher priority. Locking 00h requires priority >= highest existing lock."

- id: get_local_ui
  label: Get HMI Lock/Enable Status
  kind: query
  command: "27h {UI_Index}"
  params:
    - name: UI_Index
      type: integer
      min: 1
      description: "Refer to UI list in SET_LOCAL_UI. Source table shows min=01h, max=UI_MAX (not stated in this guide)."

- id: set_motor_ip
  label: Set Intermediate Position
  kind: action
  command: "15h {Function} {IP_Index} {Value_2_bytes}"
  params:
    - name: Function
      type: enum
      values: [00h, 01h, 03h, 04h]
      description: "00h=Delete IP, 01h=Set IP at current position, 03h=Set IP at given % position, 04h=Divide full range into N equal IPs"
    - name: IP_Index
      type: integer
      min: 1
      max: 16
    - name: Value
      type: integer
      description: "16-bit; meaning depends on Function (ignored for 00h/01h; % for 03h; IP count for 04h)"

- id: get_motor_ip
  label: Get Intermediate Position
  kind: query
  command: "25h {IP_Index}"
  params:
    - name: IP_Index
      type: integer
      min: 1
      max: 16

- id: set_motor_rolling_speed
  label: Set Motor Rolling Speed (DC motors only)
  kind: action
  command: "13h {UP_Speed} {DOWN_Speed} {Slow_Speed}"
  params:
    - name: UP_Speed
      type: integer
      description: "rpm during UP movement. Range per Technical Datasheet (not in this guide)."
    - name: DOWN_Speed
      type: integer
      description: "rpm during DOWN movement. Range per Technical Datasheet."
    - name: Slow_Speed
      type: integer
      description: "rpm for adjustment movements. Range per Technical Datasheet."

- id: get_motor_rolling_speed
  label: Get Motor Rolling Speed
  kind: query
  command: "23h"
  params: []

- id: set_network_lock
  label: Set Network Lock
  kind: action
  command: "16h {Function} {Priority}"
  params:
    - name: Function
      type: enum
      values: [00h, 01h, 03h, 04h]
      description: "00h=Unlock, 01h=Lock at current position, 03h=Save lock on power cycle, 04h=Do not save lock on power cycle"
    - name: Priority
      type: integer
      min: 0
      max: 255
      description: "Greater = higher priority. Ignored for Function 03h/04h."

- id: get_network_lock
  label: Get Network Lock Status
  kind: query
  command: "26h"
  params: []

# ---------- Device control ----------
- id: ctrl_moveto
  label: Move to Position
  kind: action
  command: "03h {Function} {Position_2_bytes} {Reserved}"
  params:
    - name: Function
      type: enum
      values: [00h, 01h, 02h, 04h]
      description: "00h=DOWN limit, 01h=UP limit, 02h=Intermediate Position, 04h=Position in % of full travel"
    - 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 reserved. Per source: set to 00h or FFh."

- id: ctrl_stop
  label: Stop Motor
  kind: action
  command: "02h {Reserved}"
  params:
    - name: Reserved
      type: integer
      description: "8-bit reserved. Per source: set to 00h or FFh."
  notes: "Motor stops immediately without speed ramp-down."

# ---------- Device status ----------
- id: get_motor_position
  label: Get Motor Position
  kind: query
  command: "0Ch"
  params: []

- id: get_motor_status
  label: Get Motor Status
  kind: query
  command: "0Eh"
  params: []

Feedbacks

- id: post_node_addr
  type: bytes
  description: "POST_NODE_ADDR (60h). 0 data bytes - address is in message header."

- id: post_group_addr
  type: bytes
  description: "POST_GROUP_ADDR (61h). DATA: GroupIndex (1 byte) + GroupID (3 bytes)."

- id: post_node_app_version
  type: bytes
  description: "POST_NODE_APP_VERSION (75h). 6 bytes: App_Reference (3) + App_IndexLetter (ASCII 41h..5Ah) + App_IndexNumber (1) + Reserved (1)."

- id: post_node_label
  type: string
  description: "POST_NODE_LABEL (65h). 16-char label, space-padded."

- id: post_local_ui
  type: bytes
  description: "POST_LOCAL_UI (37h). 5 bytes: Status (1: 00h=enabled, 01h=disabled) + Source_Addr (3) + Priority (1)."

- id: post_motor_ip
  type: bytes
  description: "POST_MOTOR_IP (35h). 4 bytes: IP_index (1) + Reserved (2) + IP_position_percentage (1, 0..100, FFh=not set)."

- id: post_motor_rolling_speed
  type: bytes
  description: "POST_MOTOR_ROLLING_SPEED (33h). 3 bytes: UP_Speed, DOWN_Speed, Slow_Speed."

- id: post_network_lock
  type: bytes
  description: "POST_NETWORK_LOCK (36h). 6 bytes: Status (00h=unlocked, 01h=locked) + Source_Addr (3) + Priority (1) + Saved (00h=no, 01h=yes)."

- id: post_motor_position
  type: bytes
  description: "POST_MOTOR_POSITION (0Dh). 5 bytes: Position_pulse (2) + Position_percentage (1, 0..100) + Reserved (1) + IP (1, 01h..IP_MAX, FFh=not at any IP)."

- id: post_motor_status
  type: bytes
  description: "POST_MOTOR_STATUS (0Fh). 4 bytes: Status, Direction, Source, Cause. See motor-status field tables."

- id: motor_status
  type: enum
  values: [stopped, running, blocked, locked]
  description: "POST_MOTOR_STATUS byte 1. 00h=Stopped, 01h=Running, 02h=Blocked (thermal/obstacle), 03h=Locked (NETWORK_LOCK)."

- id: motor_direction
  type: enum
  values: [down, up, unknown]
  description: "POST_MOTOR_STATUS byte 2. 00h=DOWN, 01h=UP, FFh=Unknown."

- id: motor_source
  type: enum
  values: [internal, network, local_ui]
  description: "POST_MOTOR_STATUS byte 3. 00h=Internal, 01h=Network message, 02h=Local UI."

- id: motor_cause
  type: enum
  values: [target_reached, explicit_command, wink, obstacle, over_current, thermal, run_time_exceeded, timeout, reset_power_up]
  description: "POST_MOTOR_STATUS byte 4. 00h=Target reached, 01h=Explicit command, 02h=Wink, 20h=Obstacle, 21h=Over-current, 22h=Thermal, 30h=Run time exceeded, 32h=Timeout, FFh=Reset/Power Up."

- id: nack_error
  type: enum
  values: [data_out_of_range, unknown_message, message_length_error, busy]
  description: "NACK (6Fh) ErrorCode. 01h=Data out of range, 10h=Unknown message, 11h=Length error, FFh=Busy."

Variables

- name: GroupID
  type: bytes
  length: 3
  description: "24-bit group address, LSB first. Up to 16 per device (GroupIndex 0..15)."
- name: NodeID
  type: bytes
  length: 3
  description: "3-byte built-in device address, LSB first. Factory-programmed, read-only."
- name: NodeType
  type: nibble
  description: "4-bit product family code. 08h = Ø50 DC Serie RS485 (this family)."
- name: MotorPosition_pct
  type: integer
  min: 0
  max: 100
  description: "Current position as % of full travel range, returned by GET_MOTOR_POSITION."
- name: MotorPosition_pulse
  type: integer
  description: "Raw pulse count between UP_LIMIT and DOWN_LIMIT. Range per device Technical Datasheet (not in this guide)."
- name: LocalUI_Status
  type: enum
  values: [enabled, disabled]
  description: "Per-UI-Index lock state. 00h=Enabled, 01h=Disabled."
- name: NetworkLock_Status
  type: enum
  values: [unlocked, locked]
  description: "Network-wide command lock. 00h=Unlocked, 01h=Locked."

Events

# UNRESOLVED: source does not describe any unsolicited notifications. All device-side traffic
# is a POST_xxx reply to a GET_xxx, or ACK/NACK.

Macros

# UNRESOLVED: source does not describe multi-step macro sequences.

Safety

confirmation_required_for: []
interlocks:
  - description: "NETWORK_LOCK (SET_NETWORK_LOCK function 01h) blocks all CTRL_xxx and limit-changing SET messages from lower-priority callers. Source returns NACK(NODE_IS_LOCKED) on rejection."
    source_section: "6.3.4"
  - description: "SET_LOCAL_UI can disable local controls (DCT, BT, Touch Motion, LEDs). When UI_Index=00h (all), priority must be >= highest existing lock level, else NACK(LOW_PRIORITY)."
    source_section: "6.3.1"
  - description: "Obstacle / over-current / thermal protection events are reported via POST_MOTOR_STATUS with Status=02h (Blocked) and Cause=20h/21h/22h."
    source_section: "6.5.2"
  - description: "CTRL_STOP halts the motor immediately without a speed ramp-down. Source warns no deceleration."
    source_section: "6.4.2"

Notes

  • All data bits on the wire are bit-inverted (logical byte XOR 0xFF). Example from source: 58h on bus = A7h.
  • SOURCE@ and DEST@ are 3-byte LSB-first. Example: label address 05:04:03 is transmitted as 03h 04h 05h in the SOURCE@ field.
  • Minimum frame is 11 bytes (no DATA); maximum 32 bytes (21 bytes DATA).
  • No sync byte — frame end is detected by bus inactivity (>= Tfree).
  • One MASTER per bus; SLAVEs do not transmit except in response to a MASTER request. Some devices can broadcast their address on a local pushbutton action (out-of-band discovery).
  • Source recommends enabling ACK requests plus a controller-side retry strategy (on NACK or ACK timeout) to compensate for RS485 collision loss.
  • 3-year to 5-year NodeID recycling window: a given installation can treat NodeIDs as unique. Conflicting NodeIDs are not allowed on the same bus.
  • Speed ranges (UP/DOWN/Slow) and limit pulse counts are device-specific — refer to the per-product Technical Datasheet, not this integration guide.

Provenance

source_domains:
  - service.somfy.com
source_urls:
  - https://service.somfy.com/downloads/bui_v4/sdn-integration-guide--preliminary.pdf
retrieved_at: 2026-05-13T21:35:26.594Z
last_checked_at: 2026-06-02T06:13:09.385Z

Verification Summary

verdict: verified
checked_at: 2026-06-02T06:13:09.385Z
matched_actions: 18
action_count: 18
confidence: medium
summary: "All 18 spec actions matched literally in source; transport parameters (4800 baud, 8N1, data inversion, LSB-first) verified verbatim; full coverage. (4 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "source documents the whole SDN bus protocol — not a single device. Per-family speed ranges, IP limits, and limit-switch behavior are stated in the device Technical Datasheet, not this integration guide."
- "source does not describe any unsolicited notifications. All device-side traffic"
- "source does not describe multi-step macro sequences."
- "per-device speed ranges, IP count max (IP_MAX), UI_MAX, position pulse limits, exact Obstruction/thermal detection thresholds, and any Tilt/Slat control message details are documented in the device Technical Datasheet rather than this Integration Guide."

From the AI4AV catalog (https://ai4av.net) · ODbL-1.0