Tuesday, March 1, 2016

Somfy Wire (RS-485) Protocol

Somfy uses a very simple protocol for controlling the motors over RS-485, and it has been fairly easy to reverse engineer, so far. Somfy even provides the "ILT Command Calculator" utility (available at https://www.somfypro.com/downloads), which will show the raw bytes of every control command for a given motor or group address. I have provided information on all the control commands that are covered by Somfy's command calculator. There are also a number of other messages, and I have decoded a couple of those, too.

Overall Message Format

All messages that I've decoded so far follow the same basic format:

  • Byte 0: Message ID
  • Byte 1: Message length, subtracted from 0xFF
  • Byte 2: Unknown
  • Bytes 3..N: Payload
  • Bytes N..N+1: Checksum

Length

The length is the overall length of the message, including the ID, length field, payload, and checksum. It is encoded by subtractin from 0xFF. For example, a length of 14 bytes would be encoded as F1.

Checksum

The checksum bytes simply contains the lower two bytes of the summation of all the previous bytes of the message, in big-endian order.

Control Commands

The control command message used a message ID of 0xAB. The entire message contains these fields:
  • Byte 0: Message ID (AB)
  • Byte 1: Message length (F1, decoded to 14)
  • Byte 2: Unknown (observed to be FF)
  • Bytes 3..5: Group address
  • Bytes 6..8: Motor address
  • Byte 9: Command
  • Bytes 10..11: Parameters
  • Bytes 12..13: Checksum

 

Addresses

The command either addresses a motor or a group, but not both at once. The unused address field is set to FF FF FF.

The motor address is the real address of the motor, not the ST30 address that is printed on the motor label (assuming it's an ST30 motor). I can't figure out why Somfy just doesn't print the real address on the motor label! Anyway, the conversion formula is very simple: reverse the order of the bytes and flip every bit. So, for instance:

Label Address: 06091F (00000110 00001001 00011111‬)
Real Address: E0F6F9 (11100000 11110110 11111001‬)

 

Command Byte

The command byte is one of the following:
  • FE: Up
  • FD: Down
  • FC: Stop
  • FA: Next IP UP
  • F9: Next IP DOWN
  • FB: Go to IP
  • EF: Go to %
  • F5: Jog Up 10 ms
  • F4: Jog Down 10 ms
IPs are preset positions which are configured into the motor via the configuration utility at the above link. There are also some lock commands visible in the calculator tool, but I haven't documented them, because I haven't really looked into what they do.

Parameters

The parameter bytes are only used for some commands. For commands that don't take parameters,  these bytes should be FF. If a parameter byte is used, it's encoded by subtracting from FF. So 10 is encoded as F5. Of the above commands, the following take one parameter in the first parameter byte (values shown without encoding):

  • Down: 0 or 10-255 (I'm not sure what this parameter is used for. The default seems to be 0, encoded as FF.)
  • Go to IP: IP index (1-16)
  • Go to %: Position (0-255)
  • Jog Up/Down 10 ms: 1-255 (I'm not sure what this is used for. Number of 10 ms increments?)

 


Examples

Here are some examples of complete commands:
Tell motor with address ABCDEF to go up: AB F1 FF FF FF FF AB CD EF FE FF FF 0A FB
Tell group with address FEDCBA to go up: AB F1 FF FE DC BA FF FF FF FE FF FF 0B 28
Tell motor with address ABCDEF to go to 50%: AB F1 FF FF FF FF AB CD EF EF 80 FF 0A 6D

 

Other Messages


There are a number of other messages that are not shown in the ILT Command Calculator. These are are used for things like configuration (setting limits, group addresses, preset positions, etc.) as well as querying information from the motors (position, configuration). These are used by the "ILT2-ST30 Configuration Tool" (see Somfy link above). I was interested in being able to query the positions of my shades, so I decoded those messages. I haven't looked into any other messages.

Position Query

To query the position of the motor, the tool sends a message like this:
BB F4 FF 80 80 80 E0 F6 F9 6 FD
This contains the following fields:
  • Byte 0: Message ID (BB)
  • Byte 1: Message length (F1, decodes to 14)
  • Byte 2: Unknown (observed to be FF)
  • Bytes 3..5: Group address
  • Bytes 6..8: Motor address
  • Bytes 9..10: Checksum
The fields are used just like in the command messages above, except I've noticed the tool sets the group address to 80 80 80 instead of FF FF FF. In my experimentation, it doesn't seem to matter as long as a motor address is supplied.

You can send a position query to a group of motors by setting the motor address field to FF FF FF while setting the group address appropriately, and all the motors in that group will reply. I'm not sure this is a good idea, because the motors might try to talk over each other, but in practice, I haven't had this be an issue.

Position Reply

The motor replies with a message like this:
9B F1 DF E0 F6 F9 80 80 80 38 FB 60 08 4D
This contains the following fields:
  • Byte 0: Message ID (9B)
  • Byte 1: Message length (F1)
  • Byte 2: Unknown (observed to be DF)
  • Bytes 3..5: Motor address
  • Bytes 6..8: Group address, always the same as in the query message
  • Bytes 9..10: Position in pulses from top (encoded)
  • Byte 11: Relative position (0 is bottom limit, FF is top limit)
  • Bytes 12..13: Checksum
The position in pulses is encoded in little-endian, unlike the checksum (go figure!) and subtracted from 0xFFFF (as Somfy seems to like to do).

25 comments:

  1. This is amazing. Thanks so much for doing this. The Sonesse 30 RS485 manual is seriously lacking - and it seems completely different from your findings. Any ideas as to why?

    ReplyDelete
    Replies
    1. Hmm... actually I didn't know there was any documentation publicly available for the protocol. Maybe it didn't exist when I started this project.

      Here's what I found: http://solarshadingsystems.com/index.php?option=com_k2&view=item&layout=item&id=110&Itemid=292&jsmallfib=1&dir=JSROOT/Motors/Lutron&download_file=JSROOT/Motors/Lutron/st30_rs485_installation_instructions.pdf

      Is that the same document you're looking at? You're right, it seems the message IDs are completely different. I have no idea why that is. I'll have to study it some more.

      Delete
    2. Yes that is the document I am referring to. I was trying to send commands to the motors following that documentation and couldn't get it to work. Then I came across your blog post and it worked like a charm. The trick was the addressing part. How did you figure out that you need to swap the bytes and flip the bits to get the real address?

      Also, I had to convert hex to dec to get the commands to actually work.

      Delete
    3. The Somfy ILT2/ST30 Configuration Utility had a function to covert the addresses, so I just plugged in a bunch of addresses and recorded the results. Once I converted everything to binary, the pattern was pretty easy to figure out. This pattern actually applies across the protocol. Other fields also have their bits flipped, and if the field is multiple bytes, it's generally in little-endian byte order (the byte order is reversed).

      Note that it looks like the ILT2/ST30 utility has now been replaced with the SDN Motor Configuration Utility. I don't see a way to convert the addresses in the new utility.

      Hexadecimal and decimal are just just ways to represent numbers to humans. What you use would depend on the software or programming language you are using, as well as the notation you use. It's all binary under the hood.

      Delete
  2. I wonder if you could use an IP to serial converter, like https://www.amazon.com/USR-TCP232-310-Serial-Ethernet-Server-Webpage/dp/B009F7XZQK/ref=sr_1_9?s=electronics&ie=UTF8&qid=1470967111&sr=1-9&keywords=ip+to+serial

    If so, it would be nice to incorporate a binding into Openhab.

    ReplyDelete
    Replies
    1. It looks like that should work.

      What I've done it take my IR-to-RS485 bridge (see my blog post after this one), and attached it to a Raspberry Pi. I could use this combination as an IP-to-RS485 bridge, but what I'm currently doing is running homebridge on the RPi. Surely it could run OpenHAB, as well.

      Delete
  3. Mark, I have placed Somfy SDN protocol documents here: https://github.com/bhlarson/CurtainControl/tree/master/Documents.

    If your are interested, I am implemented a node.js Somfy curtain controller here: https://github.com/bhlarson/CurtainControl

    ReplyDelete
  4. Hi Mark! Thanks for documenting all of this. Going to try and debug my Somfy network using some of this information. Given what you know about how the communications work, any ideas on this:

    Have had a 7-blind Somfy ILT network hooked up for about 7 years now with an HAI OmniPro II controlling them. Completely flawless up until a few weeks ago when all of the blinds started going down randomly and they wouldn't go back up. Oddly, if I hooked my laptop up to the ILT tap in the closet via a USB-to-RS485 adapter, I was able to control them again. It's like a little resistance in the network seemed to help things. After a bunch more debugging, I found that disconnecting one cat5 cable that goes from the master tap to two blinds completely eliminates the problem. As soon as I punch that cable back onto my 66-block and wait a few hours, the blinds drop again.

    Any idea what could be going on here? I'm thinking it's some sort of wear-and-tear on the taps outside but they are almost impossible to get to. It's just weird that the blinds could get an "all down" signal out of nowhere.

    Thanks,

    Mike

    ReplyDelete
    Replies
    1. I don't know much about ILT. Is it RS-485-based?

      Anyway, RS-485 is designed to run on a bus, where every device sits somewhere on a linear bus, and each end of the bus is terminated with a resistor. A typical Somfy setup is star-shaped, though, and unterminated. This usually works because the data rate is very low, but it can break down if the distance is too long. Adding a resistor across A/B or +/- (whichever way it's labeled) somewhere in the network might help. The terminating resistance is supposed to match the characteristic impedance of the cable, and there are two of these resistors. To give you and idea of what resistance to use, the impedance of true RS-485 cable is 120 ohms, while the impedance of CAT5E is 100 ohms.

      Here's some good info on proper RS-485 wiring:

      https://www.maximintegrated.com/en/app-notes/index.mvp/id/763

      Delete
    2. Interesting. And yep, it's RS-485 based. I did place a 120ohm resistor between the master tap in the A/V closet and that definitely helped, but didn't seem to totally eliminate the problem (it made the blinds operational again so they wouldn't close every few minutes... but they still closed every day or two at random times).

      It's doesn't seem weird to me that there would be some sort of noise in the lines, but it just seems so weird that the blinds could receive the exact command that would send them all down (FFFFFF is the "all" group, I believe).

      Delete
    3. Yeah, that is strange. If there's interference, the checksum ought to fail, and nothing should happen. But maybe there is some bug where a badly-formed packet causes the firmware to go haywire.

      All I can suggest is maybe halving that resistance (since two identical resistors in parallel is equivalent to half, and there are two resistors in a proper RS-485 network), or place a second 120 ohm resistor as far away from the first as you can, for something that better resembles a properly-terminated network.

      Since you said you can disconnect one cable and everything else starts working correctly, if all else fails, you could split your network at that point. Build (or buy if such a thing is made) an RS-485 bridge.

      Delete
  5. Ok, I tried using a 100 ohm resistor and the problem seems to have vanished. Could have gone away on its own (wet component dried out or something) but this seems to have done the trick for now!

    ReplyDelete
  6. Thanks Mark, went back to a job from 5 years ago and found your blog with all the answers

    ReplyDelete
  7. Hello ! The insignificant zero as in 0x09 must be added? my program only returns "chk = 1 23" instead of "chk = 01 23".
    Thanks you very much !

    ReplyDelete
    Replies
    1. Without seeing the code, it's hard to say for sure. But it sounds like your program is simply displaying it differently. If each space-separated number is a byte, then 0 is the same at 00. It's what actually goes over the wire that's important.

      Delete

    2. the bytes of the command are stored in an array of unsigned long, each box of the array contains a bit of the command and the last contains all the checksum. The boxes are sent one by one on the bus by a loop. Sounds good to you?

      Delete
    3. I'm having a little bit of trouble following. A code snippet would make it easier. By "box" ("each box of the array"), do you mean element? And are you really storing one bit per element? That would be an unusual way to do it. A more normal way would be to store one byte per element, especially since this protocol is byte-oriented. But perhaps that's what you mean?

      Then there's the question of how are you actually sending the bytes to the bus?

      Delete
  8. Hi Mark! Very useful information!!!. Thank you !!. I am working on an old ILT network and I need to integrate the old system to a new Lutron HomeWorks system. I have tried to get a copy of the "ILT Command Calculator" with no success. At https://www.somfypro.ca/ there is a download page but you need a somfy account (which I don't have). Do you have any link were I can download a copy of the software. Thank you.

    ReplyDelete
    Replies
    1. I think it's now listed as "SDN String Calculator" on this page: https://www.somfypro.com/services-support/software

      And it looks like the Wayback Machine has the old version: http://web.archive.org/web/20150331100809/https://www.somfypro.com/downloads

      I don't really remember if the ILT protocol is different than the SDN protocol, other than the address order. But it appears they've removed all mention of ILT from the current version of the utility.

      Delete
    2. Hi Mark,
      Thank you very much!! You made my day!!
      I got the old version from to the Wayback Machine. The new “SDN String Calculator” is not compatible with the old ILT network I am working on. The old ILT Command calculator is going to save me A LOT of time.
      Just one detail, my antivirus was looking the “ILT Command Calc.exe” installation file as a malware. I’d to deactivate my antivirus and then install the software. After I installed the software everything was fine.

      Delete
    3. Note that I have decoded a good amount (most?) of the ILT2 protocol (along with much more than is documented of the ST30 protocol). My code is at https://github.com/ccutrer/somfy_sdn

      Delete
  9. HI, thanks for your blog Did you ever get to the bottom of the answer regarding the sdn protocol documentation? I have 30 RS485 Rev H motors and have been toying with automation using the somfy doc to no avail. My frames look just like what comes out of the frame builder software but there is no feedback from the device itself on any command. The code exceprt from 2016 referenced above also does not seem to match the specs. What rev motors did you use for your research? Thanks

    ReplyDelete
    Replies
    1. I'm not really sure which revision I have. (I think I'd have to take apart the shades to find out.) It's whatever they were making in 2011, though.

      Was the motor address converted correctly? (Reverse the order of the bits and invert every bit.) That's first thing that comes to mind.

      Delete
  10. Note that I have decoded a good amount (most?) of the ILT2 protocol, as well as more of the ST30 protocol than is documented. My code is at https://github.com/ccutrer/somfy_sdn

    ReplyDelete