Summary

Somfy Digital Network (SDN) RS485 control protocol for Somfy motorized window covering products, including the RS485 RTS transmitter (NodeType 05h) and associated motor product families. Spec covers serial framing, addressing modes (point-to-point, group, broadcast), device management, configuration, motor control, and status query messages.

Transport

protocols:
  - serial
serial:
  baud_rate: 4800
  data_bits: 8
  parity: odd
  stop_bits: 1
  flow_control: none
  bus: rs485
  notes: |
    Character coding NRZ. Least significant bit sent first.
    All data bits MUST be inverted (bitwise NOT) before transmission
    for backward compatibility with earliest protocol versions.
    Example: byte 58h on the wire is transmitted as A7h.
    Timing requirements:
      Tc   = max 1 ms between consecutive characters in a message
      Tfree = min 3 ms bus free timeout
      Trep = 5 ms typ, 255 ms max - slave reply delay (partially randomized)
      Treq = min 10 ms - master inactivity before sending a new request
auth:
  type: none  # inferred: no auth procedure in source

Traits

- queryable        # inferred from GET_* query commands present
- levelable        # inferred from CTRL_MOVETO with Function 04h (move to % of travel)

Actions

# All SDN messages share the common frame:
#   [MSG][ACK/LEN][NODE TYPE][SOURCE@(3)][DEST@(3)][DATA...][CHECKSUM]
# CHECKSUM = sum of the complements of every byte from MSG through last DATA byte.
# Minimum frame length 11 bytes (no DATA); maximum 32 bytes (21 DATA bytes).
# `command:` below holds the MSG opcode byte verbatim from §6 of the source;
# the full frame is constructed by the controller per the addressing rules in §5.

- id: get_node_addr
  label: Get Node Address (GET_NODE_ADDR)
  kind: query
  command: "40h"
  params: []
  notes: |
    Used to discover devices on the bus. With many devices present, replies
    from all devices are not guaranteed.

- id: set_group_addr
  label: Set Group Address (SET_GROUP_ADDR)
  kind: action
  command: "51h"
  params:
    - name: group_index
      type: integer
      description: Entry in the group table (0..15)
    - name: group_id
      type: integer
      description: 24-bit associated group NodeID

- id: get_group_addr
  label: Get Group Address (GET_GROUP_ADDR)
  kind: query
  command: "41h"
  params:
    - name: group_index
      type: integer
      description: Entry in the group table (0..15)

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

- id: set_node_label
  label: Set User-Defined Text Label (SET_NODE_LABEL)
  kind: action
  command: "55h"
  params:
    - name: label
      type: string
      description: 16-character ASCII label; pad short strings with spaces.

- id: get_node_label
  label: Get User-Defined Text Label (GET_NODE_LABEL)
  kind: query
  command: "45h"
  params: []

- id: set_local_ui
  label: Set HMI/Local UI Lock (SET_LOCAL_UI)
  kind: action
  command: "17h"
  params:
    - name: function
      type: enum
      description: |
        00h = Enable/Unlock
        01h = Disable/Lock
    - name: ui_index
      type: enum
      description: |
        00h = All local controls and feedbacks
        01h = DCT input
        02h = Local stimuli (e.g. radio pairing pushbutton)
        03h = Local Radio access (e.g. Bluetooth)
        04h = Touch Motion feature
        05h = LEDs
    - name: priority
      type: integer
      description: 0..255; higher value = higher priority

- id: get_local_ui
  label: Get HMI/Local UI Status (GET_LOCAL_UI)
  kind: query
  command: "27h"
  params:
    - name: ui_index
      type: integer
      description: UI item index (01h..UI_MAX); see set_local_ui enum.

- id: set_motor_ip
  label: Set Intermediate Position (SET_MOTOR_IP)
  kind: action
  command: "15h"
  params:
    - name: function
      type: enum
      description: |
        00h = Delete IP (value ignored; NACK IP_NOT_SET if IP doesn't exist)
        01h = Set IP at the current position (value ignored)
        03h = Set IP at the specified position (value = percentage)
        04h = Divide full range into N equally spaced IPs (value = IP count; ip_index ignored)
    - name: ip_index
      type: integer
      description: Intermediate Position index (1..16)
    - name: value
      type: integer
      description: 16-bit function-dependent value (position % or IP count).

- id: get_motor_ip
  label: Get Intermediate Position (GET_MOTOR_IP)
  kind: query
  command: "25h"
  params:
    - name: ip_index
      type: integer
      description: IP index (1..16)

- id: set_motor_rolling_speed
  label: Set Motor Rolling Speed (SET_MOTOR_ROLLING_SPEED)
  kind: action
  command: "13h"
  params:
    - name: up_speed
      type: integer
      description: UP movement speed (rpm). DC motors only. Range per motor datasheet.
    - name: down_speed
      type: integer
      description: DOWN movement speed (rpm). DC motors only. Range per motor datasheet.
    - name: slow_speed
      type: integer
      description: Adjustment movement speed (rpm). DC motors only. Range per motor datasheet.
  notes: |
    Speed adjustment is only available on DC motors. Default speed and valid
    speed range are motor-specific; refer to the device technical datasheet.

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

- id: set_network_lock
  label: Set Network Lock (SET_NETWORK_LOCK)
  kind: action
  command: "16h"
  params:
    - name: function
      type: enum
      description: |
        00h = Unlock
        01h = Lock device at current position
        03h = Save NETWORK_LOCK upon power cycle (priority ignored)
        04h = Do not save NETWORK_LOCK upon power cycle (priority ignored)
    - name: priority
      type: integer
      description: 0..255; higher value = higher priority

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

- id: ctrl_moveto
  label: Move to Position (CTRL_MOVETO)
  kind: action
  command: "03h"
  params:
    - name: function
      type: enum
      description: |
        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 (position = 0..100)
    - name: position
      type: integer
      description: 16-bit function-dependent value (IP index or percentage).

- id: ctrl_stop
  label: Stop (CTRL_STOP)
  kind: action
  command: "02h"
  params: []
  notes: Motor stops immediately without speed ramp-down.

- id: get_motor_position
  label: Get Motor Position (GET_MOTOR_POSITION)
  kind: query
  command: "0Ch"
  params: []
  notes: Position is reported even while the motor is running.

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

Feedbacks

- id: post_node_addr
  label: Node Address Reply (POST_NODE_ADDR)
  command: "60h"
  type: response
  notes: |
    Reply to GET_NODE_ADDR. NodeID carried in frame header (SOURCE@); no DATA payload.

- id: post_group_addr
  label: Group Address Reply (POST_GROUP_ADDR)
  command: "61h"
  type: response
  fields:
    - name: group_index
      type: integer
      description: 8-bit entry in the group table (0..15)
    - name: group_id
      type: integer
      description: 24-bit associated group address

- id: ack
  label: Acknowledge (ACK)
  command: "7Fh"
  type: response
  notes: |
    Sent only when ACK bit was set to 1 in the originating CTRL/GET/SET request.
    Indicates: for SET, parameters saved; for CTRL, execution started (not necessarily finished).

- id: nack
  label: Negative Acknowledge (NACK)
  command: "6Fh"
  type: error
  fields:
    - name: error_code
      type: enum
      values:
        - "01h: Data out of range (DATA fields not within expected range)"
        - "10h: Unknown message (MSG identifier unknown)"
        - "11h: Message Length Error (frame below minimum length)"
        - "FFh: Busy - cannot process message"
  notes: |
    Additional NACK codes mentioned but not enumerated in this section:
    NACK(LOW_PRIORITY) - SET_LOCAL_UI / network lock with insufficient priority.
    NACK(NODE_IS_LOCKED) - CTRL/SET refused while network is locked.
    NACK(IP_NOT_SET) - SET_MOTOR_IP delete on non-existent IP.

- id: post_node_app_version
  label: Firmware Revision Reply (POST_NODE_APP_VERSION)
  command: "75h"
  type: response
  fields:
    - name: app_reference
      type: integer
      description: 24-bit firmware part number
    - name: app_index_letter
      type: string
      description: 8-bit ASCII A..Z (41h..5Ah), firmware major revision
    - name: app_index_number
      type: integer
      description: 8-bit firmware revision number
    - name: reserved
      type: integer
      description: 8-bit reserved

- id: post_node_label
  label: Node Label Reply (POST_NODE_LABEL)
  command: "65h"
  type: response
  fields:
    - name: label
      type: string
      description: 16-character ASCII string

- id: post_local_ui
  label: Local UI Status Reply (POST_LOCAL_UI)
  command: "37h"
  type: response
  fields:
    - name: ui_index
      type: integer
      description: UI item index (01h..UI_MAX)
    - name: status
      type: enum
      values:
        - "00h: Enabled/Unlocked"
        - "01h: Disabled/Locked"
    - name: source_addr
      type: integer
      description: 24-bit NodeID of the device that sent the lock command (zero when unlocked)
    - name: priority
      type: integer
      description: 0..255; higher value = higher priority (zero when unlocked)

- id: post_motor_ip
  label: Intermediate Position Reply (POST_MOTOR_IP)
  command: "35h"
  type: response
  fields:
    - 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: 0..100, or FFh when the IP is not set

- id: post_motor_rolling_speed
  label: Motor Rolling Speed Reply (POST_MOTOR_ROLLING_SPEED)
  command: "33h"
  type: response
  fields:
    - name: up_speed
      type: integer
      description: UP movement speed (per device datasheet)
    - name: down_speed
      type: integer
      description: DOWN movement speed (per device datasheet)
    - name: slow_speed
      type: integer
      description: Adjustment movement speed (per device datasheet)

- id: post_network_lock
  label: Network Lock Status Reply (POST_NETWORK_LOCK)
  command: "36h"
  type: response
  fields:
    - name: status
      type: enum
      values:
        - "00h: Unlocked"
        - "01h: Locked"
    - name: source_addr
      type: integer
      description: 24-bit NodeID of the device that sent the lock command
    - name: priority
      type: integer
      description: 0..255; higher value = higher priority
    - name: saved
      type: enum
      values:
        - "00h: Lock will not be restored on power cycle"
        - "01h: Lock will be restored on power cycle"

- id: post_motor_position
  label: Motor Position Reply (POST_MOTOR_POSITION)
  command: "0Dh"
  type: response
  fields:
    - name: position_pulse
      type: integer
      description: 16-bit pulse count between UP_LIMIT and DOWN_LIMIT
    - name: position_percentage
      type: integer
      description: 0..100
    - name: reserved
      type: integer
      description: 8-bit reserved
    - name: ip
      type: integer
      description: |
        Current IP (01h..IP_MAX), or FFh if the position does not correspond
        to any IP. If position corresponds to several IPs, the first matching
        IP on the list is returned.

- id: post_motor_status
  label: Motor Status Reply (POST_MOTOR_STATUS)
  command: "0Fh"
  type: response
  fields:
    - name: status
      type: enum
      values:
        - "00h: Stopped"
        - "01h: Running (during movement)"
        - "02h: Blocked (thermal protection, obstacle)"
        - "03h: Locked (NETWORK_LOCK by another device)"
    - name: direction
      type: enum
      values:
        - "00h: Going DOWN"
        - "01h: Going UP (if stopped, indicates last movement direction)"
        - "FFh: Unknown"
    - name: source
      type: enum
      values:
        - "00h: Internal (limit/IP/position reached, over-current, obstacle, thermal)"
        - "01h: Network message (any SDN bus message)"
        - "02h: Local UI (DCT, local stimulus, local wireless)"
    - name: cause
      type: enum
      values:
        - "00h: Target reached (limit or IP or already there)"
        - "01h: Explicit command (network or local UI)"
        - "02h: Wink"
        - "20h: Obstacle detection"
        - "21h: Over-current protection"
        - "22h: Thermal protection"
        - "30h: Run time exceeded (continuous runtime limit)"
        - "32h: Timeout exceeded (CTRL_MOVE > 2 min, adjustment canceled)"
        - "FFh: Reset / PowerUp (power recycled or no command after startup)"

Variables

# UNRESOLVED: settable parameters are exposed via SET_* actions above
# (node label, group table entries, intermediate positions, rolling speeds,
# local UI lock state, network lock state). No separate variable-style
# polling interface is documented in the source.

Events

# UNRESOLVED: source documents no unsolicited event/notification messages.
# All device-originated messages (POST_*, ACK, NACK) are responses to master
# requests, not asynchronous events.

Macros

# UNRESOLVED: no multi-step macro sequences are documented in the source.

Safety

confirmation_required_for: []
interlocks:
  - id: network_lock
    description: |
      SET_NETWORK_LOCK / CTRL_NETWORK_LOCK locks the device against network
      commands at a configurable priority level. While locked, only
      CTRL_NETWORK_LOCK messages with equal or higher priority are accepted;
      all other CTRL_xxx and SET_MOTOR_LIMITS / SET_TILT_LIMITS messages are
      rejected with NACK(NODE_IS_LOCKED).
  - id: motor_blocked
    description: |
      Motor reports POST_MOTOR_STATUS status=02h (Blocked) when it cannot move
      due to thermal protection or obstacle detection. Cause field indicates
      the specific protection event (20h obstacle, 21h over-current,
      22h thermal, 30h run-time exceeded).
  - id: ctrl_move_timeout
    description: |
      Continuous adjustment movement is canceled if more than 2 minutes
      elapse without a new command (cause 32h Timeout exceeded).
# UNRESOLVED: voltage/current/power specifications are not stated in this
# source and must be taken from per-motor technical datasheets.

Notes

  • Source: SDN RS485 protocol specification (§3–§6 covered).
  • Addressing modes available on every message: point-to-point (DEST@ = device NodeID), group (DEST@ = 000000h, SOURCE@ = GroupID, device must have GroupID in its group table), broadcast (DEST@ = FFFFFFh). NodeType filtering is available via the NODE TYPE byte (byte 3): SOURCE NodeType = 0h for masters; DEST NodeType used to address a product family (02h Ø30 DC RS485, 05h RS485 RTS transmitter, 06h Glydea RS485, 07h Ø50 AC RS485, 08h Ø50 DC RS485, 09h Ø40 AC RS485 reserved).
  • SOURCE@ and DEST@ are transmitted LSBF: a device labelled NodeID 05:04:03 appears in bytes 4..6 as 03 04 05.
  • Acknowledgements: ACK bit in byte 2 of any CTRL/SET/GET request opts in to ACK/NACK feedback. Recommended for reliability; group/broadcast addressing should NOT request ACK or feedback to reduce bus collisions.
  • DATA length in §6 tables is the minimum DATA length; received messages may carry additional trailing bytes.
  • Reserved DATA fields must be present in transmitted messages and set to 00h or FFh.

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:07.519Z
last_checked_at: 2026-06-02T22:14:43.071Z

Verification Summary

verdict: verified
checked_at: 2026-06-02T22:14:43.071Z
matched_actions: 18
action_count: 18
confidence: medium
summary: "All 18 spec actions traced to source (dip-safe re-verify). (6 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "source describes the SDN RS485 protocol generically; per-product limits (speed ranges, IP count maxima) are deferred to per-motor technical datasheets that are not in this source."
- "settable parameters are exposed via SET_* actions above"
- "source documents no unsolicited event/notification messages."
- "no multi-step macro sequences are documented in the source."
- "voltage/current/power specifications are not stated in this"
- "- Motor-specific speed ranges and IP_MAX / UI_MAX limits depend on per-motor datasheets not included in this source."

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