Summary

Spec covers the SOMFY Digital Network (SDN) protocol used by Somfy RS-485 products (Animeo-compatible motor controllers and transmitters: Ø30 DC, Glydea, Ø50 AC/DC series, RS485 RTS transmitter). Transport is half-duplex asynchronous serial on an RS-485 bus at 4800 baud, 8 data bits, odd parity, NRZ with bit-inversion for backward compatibility. The protocol carries SET (configuration), CTRL (control), GET (request), POST (response), and ACK/NACK messages between a single MASTER and one or more SLAVEs.

Transport

protocols:
  - serial
serial:
  baud_rate: 4800
  data_bits: 8
  parity: odd
  stop_bits: 1
  flow_control: none
  # UNRESOLVED: physical layer details (cable type, termination, max bus length) not stated in this source.
auth:
  type: none  # inferred: no auth procedure in source

Traits

- queryable  # inferred from GET_xxx command catalogue
- levelable  # inferred from MOVETO position-in-% control and intermediate-position (IP) presets

Actions

# SDN frame layout (all messages, verbatim from §5 of source):
#   Byte 1       : MSG          (message identifier)
#   Byte 2       : ACK/LEN      (ACK bit + 5-bit LEN, 0..31)
#   Byte 3       : NODE TYPE    (4-bit SRC NodeType | 4-bit DEST NodeType; SRC=0h for MASTER)
#   Bytes 4..6   : SOURCE @     (3 bytes NodeID, LSBF)
#   Bytes 7..9   : DEST @       (3 bytes NodeID, LSBF; FFFFFFh for broadcast)
#   Bytes 10..n-2: DATA         (per-message payload, see §6)
#   Bytes n-1,n  : CHECKSUM     (two copies of NOT(Σ bytes 1..n-2))
# All data bits are transmitted inverted (NOT of intended byte) on the wire.
# `{ack}` = ACK/LEN byte; `{nodetype}` = NODE TYPE byte; `{src3}` = 3 SRC @ bytes;
# `{dest3}` = 3 DEST @ bytes; `{checksum}` = 2-byte CHECKSUM; `LSBF` = least-significant
# byte first within multi-byte fields.

# ---------------- Device Management ----------------

- id: get_node_addr
  label: Get Node Address
  kind: query
  command: "40 {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 40h, DATA length 0. SLAVE replies with POST_NODE_ADDR (60h).

- id: set_group_addr
  label: Set Group Address
  kind: action
  command: "51 {ack} {nodetype} {src3} {dest3} {groupindex} {groupid3} {checksum}"
  params:
    - name: groupindex
      type: integer
      description: Group table entry index (0..15)
    - name: groupid
      type: string
      description: 24-bit GroupID (3 bytes, LSBF). Any NodeID not used by another device on the bus.
  notes: MSG 51h, DATA length 4. See §6.1.2.

- id: get_group_addr
  label: Get Group Address
  kind: query
  command: "41 {ack} {nodetype} {src3} {dest3} {groupindex} {checksum}"
  params:
    - name: groupindex
      type: integer
      description: Group table entry index (0..15)
  notes: MSG 41h, DATA length 1. SLAVE replies with POST_GROUP_ADDR (61h).

- id: ack
  label: Acknowledge
  kind: feedback
  command: "7F {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 7Fh, DATA length 0. Only sent by SLAVE when ACK bit was 1 in the originating request. Sent on successful Settings save or Control execution start. §6.1.3.

- id: nack
  label: Negative Acknowledge
  kind: feedback
  command: "6F {ack} {nodetype} {src3} {dest3} {errorcode} {checksum}"
  params:
    - name: errorcode
      type: integer
      description: "01h Data out of range | 10h Unknown message | 11h Message length error | FFh Busy"
  notes: MSG 6Fh, DATA length 1. §6.1.3.

# ---------------- Device Information ----------------

- id: get_node_app_version
  label: Get Firmware Revision
  kind: query
  command: "74 {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 74h, DATA length 0. SLAVE replies with POST_NODE_APP_VERSION (75h). §6.2.1.

- id: set_node_label
  label: Set User Label
  kind: action
  command: "55 {ack} {nodetype} {src3} {dest3} {label16} {checksum}"
  params:
    - name: label
      type: string
      description: 16 ASCII characters; pad with spaces if shorter.
  notes: MSG 55h, DATA length 16. §6.2.2.

- id: get_node_label
  label: Get User Label
  kind: query
  command: "45 {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 45h, DATA length 0. SLAVE replies with POST_NODE_LABEL (65h) carrying the 16-char label. §6.2.2.

# ---------------- Device Configuration ----------------

- id: set_local_ui
  label: Set Local UI Lock
  kind: action
  command: "17 {ack} {nodetype} {src3} {dest3} {function} {ui_index} {priority} {checksum}"
  params:
    - name: function
      type: integer
      description: "00h Enable/Unlock | 01h Disable/Lock"
    - name: ui_index
      type: integer
      description: "00h All local controls & feedbacks | 01h DCT input | 02h Local stimuli (e.g. radio pairing) | 03h Local radio (e.g. Bluetooth) | 04h Touch Motion | 05h LEDs"
    - name: priority
      type: integer
      description: 0..255; greater number = higher priority. Must be >= current lock level for that UI, else NACK(LOW_PRIORITY).
  notes: MSG 17h, DATA length 3. §6.3.1.

- id: get_local_ui
  label: Get Local UI Lock
  kind: query
  command: "27 {ack} {nodetype} {src3} {dest3} {ui_index} {checksum}"
  params:
    - name: ui_index
      type: integer
      description: "01h..UI_MAX (see SET_LOCAL_UI UI_Index table)"
  notes: MSG 27h, DATA length 1. SLAVE replies with POST_LOCAL_UI (37h). §6.3.1.

- id: set_motor_ip
  label: Set Intermediate Position
  kind: action
  command: "15 {ack} {nodetype} {src3} {dest3} {function} {ip_index} {value2} {checksum}"
  params:
    - name: function
      type: integer
      description: "00h Delete IP | 01h Set IP at current position | 03h Set IP at given % | 04h Divide full range into N equally-spaced IPs"
    - name: ip_index
      type: integer
      description: 1..16; ignored when function=04h.
    - name: value
      type: integer
      description: 16-bit; position in % (function 03h) or IP count (function 04h). Ignored for functions 00h/01h.
  notes: MSG 15h, DATA length 4. §6.3.2.

- id: get_motor_ip
  label: Get Intermediate Position
  kind: query
  command: "25 {ack} {nodetype} {src3} {dest3} {ip_index} {checksum}"
  params:
    - name: ip_index
      type: integer
      description: 1..16
  notes: MSG 25h, DATA length 1. SLAVE replies with POST_MOTOR_IP (35h). §6.3.2.

- id: set_motor_rolling_speed
  label: Set Motor Rolling Speed
  kind: action
  command: "13 {ack} {nodetype} {src3} {dest3} {up_speed} {down_speed} {slow_speed} {checksum}"
  params:
    - name: up_speed
      type: integer
      description: UP-movement speed in rpm; see device technical datasheet for valid range.
    - name: down_speed
      type: integer
      description: DOWN-movement speed in rpm; see device technical datasheet.
    - name: slow_speed
      type: integer
      description: Adjustment-movement speed in rpm; see device technical datasheet.
  notes: MSG 13h, DATA length 3. DC motors only. §6.3.3.

- id: get_motor_rolling_speed
  label: Get Motor Rolling Speed
  kind: query
  command: "23 {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 23h, DATA length 0. SLAVE replies with POST_MOTOR_ROLLING_SPEED (33h). §6.3.3.

- id: set_network_lock
  label: Set Network Lock
  kind: action
  command: "16 {ack} {nodetype} {src3} {dest3} {function} {priority} {checksum}"
  params:
    - name: function
      type: integer
      description: "00h Unlock | 01h Lock at current position | 03h Save NETWORK_LOCK across power cycle | 04h Do not save across power cycle"
    - name: priority
      type: integer
      description: 0..255; greater = higher priority. Ignored for functions 03h/04h.
  notes: MSG 16h, DATA length 2. When locked, only CTRL messages with equal/higher priority are accepted. §6.3.4.

- id: get_network_lock
  label: Get Network Lock
  kind: query
  command: "26 {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 26h, DATA length 0. SLAVE replies with POST_NETWORK_LOCK (36h). §6.3.4.

# ---------------- Device Control ----------------

- id: ctrl_moveto
  label: Move To Position
  kind: action
  command: "03 {ack} {nodetype} {src3} {dest3} {function} {position2} {reserved} {checksum}"
  params:
    - name: function
      type: integer
      description: "00h Move to DOWN limit | 01h Move to UP limit | 02h Move to Intermediate Position (IP index in Position) | 04h Move to % of full range"
    - name: position
      type: integer
      description: 16-bit. IP index 0..15 for function 02h; % value 0..100 for function 04h; ignored for 00h/01h.
  notes: MSG 03h, DATA length 4. §6.4.1.

- id: ctrl_stop
  label: Stop
  kind: action
  command: "02 {ack} {nodetype} {src3} {dest3} {reserved} {checksum}"
  params:
    - name: reserved
      type: integer
      description: Set to 00h; ignored by device.
  notes: MSG 02h, DATA length 1. Motor stops immediately without ramp-down. §6.4.2.

# ---------------- Device Status ----------------

- id: get_motor_position
  label: Get Motor Position
  kind: query
  command: "0C {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 0Ch, DATA length 0. SLAVE replies with POST_MOTOR_POSITION (0Dh). §6.5.1.

- id: get_motor_status
  label: Get Motor Status
  kind: query
  command: "0E {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 0Eh, DATA length 0. SLAVE replies with POST_MOTOR_STATUS (0Fh). §6.5.2.

Feedbacks

- id: post_node_addr
  label: Node Address Report
  type: bytes
  command: "60 {ack} {nodetype} {src3} {dest3} {checksum}"
  notes: MSG 60h, DATA length 0. SLAVE-side reply to GET_NODE_ADDR (40h). Address carried in SRC@ header bytes.

- id: post_group_addr
  label: Group Address Report
  type: bytes
  command: "61 {ack} {nodetype} {src3} {dest3} {groupindex} {groupid3} {checksum}"
  notes: MSG 61h, DATA length 4. Reply to GET_GROUP_ADDR (41h).

- id: post_node_app_version
  label: Firmware Revision Report
  type: bytes
  command: "75 {ack} {nodetype} {src3} {dest3} {app_reference3} {app_indexletter} {app_indexnumber} {reserved} {checksum}"
  notes: MSG 75h, DATA length 6. App_Reference 24-bit part number, App_IndexLetter ASCII major (41h..5Ah), App_IndexNumber 8-bit revision, 8-bit reserved. Example: 5063486A02 → 4Dh 43h 3Eh 41h 02h.

- id: post_node_label
  label: User Label Report
  type: bytes
  command: "65 {ack} {nodetype} {src3} {dest3} {label16} {checksum}"
  notes: MSG 65h, DATA length 16. Reply to GET_NODE_LABEL (45h).

- id: post_local_ui
  label: Local UI Lock Report
  type: bytes
  command: "37 {ack} {nodetype} {src3} {dest3} {status} {source_addr3} {priority} {checksum}"
  notes: MSG 37h, DATA length 5. Status: 00h Enabled/Unlocked, 01h Disabled/Locked. Source_Addr/Priority reset to 0 when unlocked.

- id: post_motor_ip
  label: Intermediate Position Report
  type: bytes
  command: "35 {ack} {nodetype} {src3} {dest3} {ip_index} {reserved2} {ip_position_percentage} {checksum}"
  notes: MSG 35h, DATA length 4. IP_position_percentage: 0..100, or FFh if IP not set.

- id: post_motor_rolling_speed
  label: Motor Rolling Speed Report
  type: bytes
  command: "33 {ack} {nodetype} {src3} {dest3} {up_speed} {down_speed} {slow_speed} {checksum}"
  notes: MSG 33h, DATA length 3. Reply to GET_MOTOR_ROLLING_SPEED (23h). DC motors only.

- id: post_network_lock
  label: Network Lock Report
  type: bytes
  command: "36 {ack} {nodetype} {src3} {dest3} {status} {source_addr3} {priority} {saved} {checksum}"
  notes: MSG 36h, DATA length 6. Status: 00h Unlocked | 01h Locked. Saved: 00h not restored on power cycle | 01h restored on power cycle. Source_Addr/Priority reset when unlocked.

- id: post_motor_position
  label: Motor Position Report
  type: bytes
  command: "0D {ack} {nodetype} {src3} {dest3} {position_pulse2} {position_percentage} {reserved} {ip} {checksum}"
  notes: MSG 0Dh, DATA length 5. Position_pulse 16-bit between UP_LIMIT and DOWN_LIMIT. Position_percentage 0..100. IP byte 01h..IP_MAX, or FFh if no IP matches.

- id: post_motor_status
  label: Motor Status Report
  type: bytes
  command: "0F {ack} {nodetype} {src3} {dest3} {status} {direction} {source} {cause} {checksum}"
  notes: MSG 0Fh, DATA length 4. See §6.5.2 for enumerations.

- id: motor_status_state
  label: Motor State (Status field of POST_MOTOR_STATUS)
  type: enum
  values:
    - stopped
    - running
    - blocked
    - locked

- id: motor_status_direction
  label: Last Direction (Direction field of POST_MOTOR_STATUS)
  type: enum
  values:
    - down
    - up
    - unknown

- id: motor_status_source
  label: Command Origin (Source field of POST_MOTOR_STATUS)
  type: enum
  values:
    - internal
    - network
    - local_ui

- id: motor_status_cause
  label: Cause (Cause field of POST_MOTOR_STATUS)
  type: enum
  values:
    - target_reached
    - explicit_command
    - wink
    - obstacle_detection
    - over_current
    - thermal_protection
    - runtime_exceeded
    - timeout_exceeded
    - reset_powerup

Variables

# UNRESOLVED: settable parameters that are not discrete action mnemonics: only the
# variable-bearing action params (groupindex, groupid, ui_index, priority, ip_index,
# function, position, up/down/slow_speed) exist; they are encoded inside the action
# commands above. No standalone "Variables" entries apply.

Events

# UNRESOLVED: the protocol has no unsolicited event channel. Every SLAVE response
# (POST_xxx, ACK, NACK) is a reply to a MASTER GET/SET/CTRL. No spontaneous
# notifications are documented in the source.

Macros

# UNRESOLVED: source does not describe multi-step sequences. Power-on
# sequencing and lock priority overrides are application-layer concerns.

Safety

confirmation_required_for: []
interlocks: []
# UNRESOLVED: source contains no operator-facing safety warnings, lockout
# procedures, or mandatory confirmation rules beyond the priority-based
# network-lock mechanism (which is captured in SET_NETWORK_LOCK above). Per
# §3.6 the source itself recommends ACK-with-retry, but that is a bus
# reliability recommendation, not a safety interlock.

Notes

Half-duplex RS-485, MASTER/SLAVE. Only one MASTER may drive the bus at a time. Slave response delay Trep is partially randomized 5–255 ms; master must wait Treq ≥ 10 ms after last bus activity before transmitting; inter-character gap Tc ≤ 1 ms. All payload bytes are sent bit-inverted (e.g. 58h → A7h on wire) for backward compatibility with earliest SDN revisions. Frame is delimited by bus inactivity — there is no sync byte — so Tc discipline is mandatory. Checksum is the byte-wise NOT of all preceding frame bytes (issued twice as two checksum bytes). All multi-byte fields (NodeID, GroupID, position) are LSB first.

Broadcast (DEST@ = FFFFFFh) and group addressing are supported, but ACK/feedback should not be requested in those modes (high collision risk; §3.7).

Set priority on SET_NETWORK_LOCK to a value at least equal to the highest currently-held lock, otherwise the SLAVE returns NACK with cause consistent with NODE_IS_LOCKED (§6.3.4). The lock blocks all movement and limit-changing commands, not just network MOVETO.

For SET_MOTOR_IP function 04h, the IP count is in value and ip_index is ignored. Example: value=2 → IP1 at 33%, IP2 at 66%. Existing IPs are overwritten.

NodeType filtering (§3.2.2) lets a MASTER address a single product family by setting the DEST NodeType nibble in byte 3 — e.g. 02h for Ø30 DC, 06h for Glydea, 07h for Ø50 AC.

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.493Z
last_checked_at: 2026-06-02T05:46:14.717Z

Verification Summary

verdict: verified
checked_at: 2026-06-02T05:46:14.717Z
matched_actions: 20
action_count: 20
confidence: medium
summary: "All 20 spec actions matched literally to source MSG codes and parameters; transport parameters verified against serial config (4800 baud, 8 data bits, odd parity); full bidirectional coverage of source command catalogue. (7 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "per-model behavior (e.g. Glydea vs. Ø50) is governed by NodeType filtering but the source does not document which commands a specific model implements."
- "physical layer details (cable type, termination, max bus length) not stated in this source."
- "settable parameters that are not discrete action mnemonics: only the"
- "the protocol has no unsolicited event channel. Every SLAVE response"
- "source does not describe multi-step sequences. Power-on"
- "source contains no operator-facing safety warnings, lockout"
- "per-product capability matrix (which MSG identifiers each NodeType implements) is not in this protocol guide; the matrix lives in each product's technical datasheet."

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