This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Somfy RS-485 Protocol
#1
Dear All,

We have a project that we will integrate with Somfy blinds and shutter.
We will communicate and control with some extra transmitter/gateway device which is converting RS485 commands to RF signals.
All blinds and shutters get RF commands from this transmitter/gateway device.

It has a special for RS485 protocol and commands for communication & control.
We need to implement this protocol commands to LM.
I attached RS485 protocol guide &  transmitter/gateway device documentation below.




What we need ?
We need to communicate with transmitter/gateway  to send basic blinds & shutter commands. such as open/close,up/down etc.


Can you help us ?
BR
Ceyhan

Attached Files
.pdf   SOMFY RS485 Protocol_User's guide.pdf (Size: 583.5 KB / Downloads: 231)
.pdf   rs485-rts-transmitter_manual.pdf (Size: 5.09 MB / Downloads: 159)
.pdf   rs485-rts-transmitter_profile1.pdf (Size: 549.91 KB / Downloads: 157)
Reply
#2
You can do this in such way:
1. prepare a user.somfy library with:
- a table with every commands for every channel (up, down, +, -, program, set) e.g.
Code:
Somfy = {
ch01 = {
 up = string.char(0x7F,0xF2,0xFA,0xB8,0x43,0xFA,0x00,0x00,0x00,0xFF,0xFE,0x06,0x5D),}}

- communication function
Code:
-- Send to Somfy transmitter
somfy_send(cmd)
port = require('serial').open('/dev/RS485', {
baudrate = 4800,
parity = 'odd',
duplex = 'half',
databits = 8,
stopbits = 1
})
port:write(cmd)
end


2. Use it in event-based script.
Code:
somfy_send(Somfy.ch01.up)


3. You can also improve this with a function of buffering based on UDP because somfy transmitter is very slow. E.g. for sending step command 0,4s; up/down 0,6s; program 6s. So when you will send some command too fast(too soon after last command), it will not work.

Please check:
http://forum.logicmachine.net/showthread...ight=somfy
Reply
#3
Thank you for your support. buuuudzik it will help me so much.
If i will find good solution i will share from there.

BR
Ceyhan
Reply
#4
You're welcome. The best would be if there will some command generator, because when you change device to new one you must update all commands.
Reply
#5
Dear buuuudzik,

I started workout on programming it.

Can you help me about messages ? I'm so new about that Smile
For example can you share with me your correct example messages (up/down +/- )

or write basic (up) message for me like your example ?
( RTS transmitter  node ID : 05B8E1,  channel : 2 , MSG 80h, function : 01h <up>)


Somfy = {
 ch01 = {
  up = string.char(0x7F,0xF2,0xFA,0xB8,0x43,0xFA,0x00,0x00,0x00,0xFF,0xFE,0x06,0x5D),}}


note: I did UDP Buffer script.

BR
Ceyhan
Reply
#6
To prepare commands you can use a special tool from Somfy: SOMFY_rs485_frame_builder.

I've attached the manual for this app.

Attached Files
.pdf   rs485_frame_builder_quick_guide_0.04.11.pdf (Size: 450.35 KB / Downloads: 156)
Reply
#7
Hi

i have created this in user.somfey in liberary


Somfy = {
ch01 = {
 up = string.char(0x7F,0xF2,0xFA,0xB8,0x43,0xFA,0x00,0x00,0x00,0xFF,0xFE,0x06,0x5D),}}


and in event communication function also i have done this code also

- Send to Somfy transmitter
somfy_send(cmd)
port = require('serial').open('/dev/RS485', {
baudrate = 4800,
parity = 'odd',
duplex = 'half',
databits = 8,
stopbits = 1
})
port:write(cmd)
end

but the last end i given the error so i have removed end also

In event base script i have done the
omfy_send(cmd)
port = require('serial').open('/dev/RS485', {
baudrate = 4800,
parity = 'odd',
duplex = 'half',
databits = 8,
stopbits = 1
})
string.char(0x7F,0xF2,0xFA,0xB8,0x43,0xFA,0x00,0x00,0x00,0xFF,0xFE,0x06,0x5D),}}
this with the hexacode given by somfy vendor

but the contoller is not working


so please tell the procedure todo because i am doing it first time


Thanks
Reply
#8
You must have:
- id of your Somfy RS-485 transmitter,
- path to your RS-485 port from Logic Machine (often LM has more than one),
- use frame builder to prepare apropriate command e.g. up or down
- you can log the response from serial
Done is better than perfect
Reply
#9
(17.09.2020, 18:17)buuuudzik Wrote: You must have:
- id of your Somfy RS-485 transmitter,
- path to your RS-485 port from Logic Machine (often LM has more than one),
- use frame builder to prepare apropriate command e.g. up or down
- you can log the response from serial
Hi

- yes i have id of the transmitter but where i have to write
- i have connected to the RS485-3 means port 3
- using the frame builder only i have all hexa codes
 so this is the code i have write in event based script but it is not working

-- for curtain up

if not port then
require('serial')
port = serial.open('/dev/RS485-3', {
      baudrate = 4800,
      parity = 'odd',
      databits = 8,
      stopbits = 1,
      duplex = 'half'
    })
port:flush()
end
if port then
  ch01=up
  char = string.char(0x7F, 0xF2, 0xFA, 0x01, 0x00, 0x00, 0xB5, 0x2B, 0xFA, 0xFF, 0xFE, 0x06, 0x43)
  -- wait for 1.5 seconds
os.sleep(0.1)
  char = string.char(0x7F, 0xF2, 0xFA, 0x01, 0x00, 0x00, 0xB5, 0x2B, 0xFA, 0xFF, 0xFE, 0x06, 0x43)
  alert(char)
  port:write(char) 
end


-- For curtain down
if not port then
require('serial')
port = serial.open('/dev/RS485-3', {
      baudrate = 4800,
      parity = 'odd',
      databits = 8,
      stopbits = 1,
      duplex = 'half'
    })
port:flush()
end
if port then
  char = string.char(0x7F, 0xF2, 0xFA, 0x01, 0x00, 0x00, 0xB5, 0x2B, 0xFA, 0xFF, 0xFE, 0x06, 0x42)
  -- wait for 1.5 seconds
os.sleep(0.1)
  char = string.char(0x7F, 0xF2, 0xFA, 0x01, 0x00, 0x00, 0xB5, 0x2B, 0xFA, 0xFF, 0xFE, 0x06, 0x42)
  alert(char)
  port:write(char) 
end

pls do needfull todo work
Reply
#10
Another thing is that this is wireless so sometimes length is too much, the best is testing when transmitter see the blind.

Today unfortunately I dont have enough time to do such tutorial maybe someone else.
Done is better than perfect
Reply
#11
FWIW, I have shutters/blinds RF integration based on Sonoff RF bridge flashed with custom firmware, it connects to MQTT that's running on LM, but it also needs WiFi to run. It's super cheap and easy to program, and you can issue simple MQTT commands to operate.
Reply
#12
(17.09.2020, 18:17)buuuudzik Wrote: You must have:
- id of your Somfy RS-485 transmitter,
- path to your RS-485 port from Logic Machine (often LM has more than one),
- use frame builder to prepare apropriate command e.g. up or down
- you can log the response from serial

Hi Buuuudzik,

Have you had experience with reading the response from the nodes?
I.e. if you use the broadcast message 'get node address'??

The returned message from the node appears as symbols when logged?

BW

Attached Files Thumbnail(s)
   
Reply
#13
With the script below i now can control one motor. But that motor was already programmed by a remote control. Now my question is if someone can tell me if and how it's possible to program a new motor from scratch on please as i totaly don't understand the protocol and all of its functions. There is no manuel explaining the RTS protocol so i'm really confused..

value = event.getvalue()

require('serial')
port = serial.open('/dev/RS485', {
baudrate = 4800,
databits = 8,
stopbits = 1,
parity = 'odd',
duplex = 'half'
})

if value == false then
res, err = port:write(string.char(0x7F,0xF2,0xFA,0xC9,0x7B,0xFA,0x00,0x00,0x00,0xFE,0xFE,0x06,0xA5))
else
res, err = port:write(string.char(0x7F,0xF2,0xFA,0xC9,0x7B,0xFA,0x00,0x00,0x00,0xFE,0xFD,0x06,0xA4))
end

log(res, err)
Reply
#14
(14.09.2023, 13:41)Joep Wrote: With the script below i now can control one motor. But that motor was already programmed by a remote control. Now my question is if someone can tell me if and how it's possible to program a new motor from scratch on please as i totaly don't understand the protocol and all of its functions. There is no manuel explaining the RTS protocol so i'm really confused..

value = event.getvalue()

require('serial')
port = serial.open('/dev/RS485', {
  baudrate = 4800,
  databits = 8,
  stopbits = 1,
  parity = 'odd',
  duplex = 'half'
})

if value == false then
res, err = port:write(string.char(0x7F,0xF2,0xFA,0xC9,0x7B,0xFA,0x00,0x00,0x00,0xFE,0xFE,0x06,0xA5))
else
  res, err = port:write(string.char(0x7F,0xF2,0xFA,0xC9,0x7B,0xFA,0x00,0x00,0x00,0xFE,0xFD,0x06,0xA4))
end

log(res, err)

You should know address of motors and implement your sendRS485 function with your connection parameters. 
Check code below it would be great if it works you, but I can't be responsible for it. 
It work with my motors.
Code:
-- 1/0 up/down
function rs485windowControl(value, address)
  msg = bit.bxor(0x80, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address

    local da2
    if value then
      da2 = bit.bxor(0x01, 0xFF)
    else
        da2 = bit.bxor(0x02, 0xFF)
    end

    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end


function rs485windowStop(address)
  msg = bit.bxor(0x80, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address

    da2 = bit.bxor(0x03, 0xFF)
    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end

function rs485windowSetChannel(address)
  msg = bit.bxor(0x97, 0xFF)
    len = bit.bxor(0x0C, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address



    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1, sum2, sum1))
end

function rs485windowMy(address)
  msg = bit.bxor(0x80, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address

    da2 = bit.bxor(0x04, 0xFF)
    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end

function rs485windowHeight(value, address)
  local tilt = 1
  if value <= 127 then
    value = 128 - value
  else
    tilt = 0
    value = 256 - value + 127
  end
  msg = bit.bxor(0x81, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address
  da2 = value

    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end

function Int16ToBytes(num, endian)
  if num < 0 then
      num = bit.band(num, 0xFFFF)
  end

  highByte = bit.rshift(bit.band(num, 0xFF00), 8)
  lowByte  = bit.band(num, 0xFF)

  if endian == "little" then
      lowByte, highByte = highByte, lowByte
  end

  return highByte,lowByte
end
Reply
#15
(14.09.2023, 20:37)Bitver Wrote:
(14.09.2023, 13:41)Joep Wrote: With the script below i now can control one motor. But that motor was already programmed by a remote control. Now my question is if someone can tell me if and how it's possible to program a new motor from scratch on please as i totaly don't understand the protocol and all of its functions. There is no manuel explaining the RTS protocol so i'm really confused..

value = event.getvalue()

require('serial')
port = serial.open('/dev/RS485', {
  baudrate = 4800,
  databits = 8,
  stopbits = 1,
  parity = 'odd',
  duplex = 'half'
})

if value == false then
res, err = port:write(string.char(0x7F,0xF2,0xFA,0xC9,0x7B,0xFA,0x00,0x00,0x00,0xFE,0xFE,0x06,0xA5))
else
  res, err = port:write(string.char(0x7F,0xF2,0xFA,0xC9,0x7B,0xFA,0x00,0x00,0x00,0xFE,0xFD,0x06,0xA4))
end

log(res, err)

You should know address of motors and implement your sendRS485 function with your connection parameters. 
Check code below it would be great if it works you, but I can't be responsible for it. 
It work with my motors.
Code:
-- 1/0 up/down
function rs485windowControl(value, address)
  msg = bit.bxor(0x80, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address

    local da2
    if value then
      da2 = bit.bxor(0x01, 0xFF)
    else
        da2 = bit.bxor(0x02, 0xFF)
    end

    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end


function rs485windowStop(address)
  msg = bit.bxor(0x80, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address

    da2 = bit.bxor(0x03, 0xFF)
    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end

function rs485windowSetChannel(address)
  msg = bit.bxor(0x97, 0xFF)
    len = bit.bxor(0x0C, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address



    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1, sum2, sum1))
end

function rs485windowMy(address)
  msg = bit.bxor(0x80, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address

    da2 = bit.bxor(0x04, 0xFF)
    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end

function rs485windowHeight(value, address)
  local tilt = 1
  if value <= 127 then
    value = 128 - value
  else
    tilt = 0
    value = 256 - value + 127
  end
  msg = bit.bxor(0x81, 0xFF)
    len = bit.bxor(0x0D, 0xFF)
    con = bit.bxor(0x05, 0xFF)
    sr1 = bit.bxor(0xFE, 0xFF)
    sr2 = bit.bxor(0xFF, 0xFF)
    sr3 = bit.bxor(0xFF, 0xFF)
    de1 = bit.bxor(0x72, 0xFF)
    de2 = bit.bxor(0xBB, 0xFF)
    de3 = bit.bxor(0x05, 0xFF)
    da1 = bit.bxor(address, 0xFF) -- address
  da2 = value

    sum = msg + len + con + sr1 + sr2 + sr3 + de1 + de2 + de3 + da1 + da2
    sum1, sum2 = Int16ToBytes(sum, 'little')

    sendRS485(string.char(msg, len, con, sr1, sr2, sr3, de1, de2, de3, da1,da2, sum2, sum1))
end

function Int16ToBytes(num, endian)
  if num < 0 then
      num = bit.band(num, 0xFFFF)
  end

  highByte = bit.rshift(bit.band(num, 0xFF00), 8)
  lowByte  = bit.band(num, 0xFF)

  if endian == "little" then
      lowByte, highByte = highByte, lowByte
  end

  return highByte,lowByte
end

Thanks for your answer and sharing your code. My biggest issue is how to set the correct channel? How is this done? First with a Somfy remote and once paired you can also control it by the script or how does it work?
Reply
#16
(15.09.2023, 12:04)Joep Wrote: Thanks for your answer and sharing your code. My biggest issue is how to set the correct channel? How is this done? First with a Somfy remote and once paired you can also control it by the script or how does it work?
Only address is needed for control by script. If you need RTS channels check rs485windowSetChannel function or remote controller.
Also I think you should check your motors documentation first for proper initial installation.
Reply
#17
(15.09.2023, 19:47)Bitver Wrote:
(15.09.2023, 12:04)Joep Wrote: Thanks for your answer and sharing your code. My biggest issue is how to set the correct channel? How is this done? First with a Somfy remote and once paired you can also control it by the script or how does it work?
Only address is needed for control by script. If you need RTS channels check rs485windowSetChannel function or remote controller.
Also I think you should check your motors documentation first for proper initial installation.

Thanks Bitver. That helped me.
Reply


Forum Jump: