I wanted to be able to control my Somfy ST30 RS-485 shades via my universal infrared remote, so I built a simple project using an Arduino (aka a Genuino these days, if you live outside the USA) to do this. This could easily be adapted to control any serial device, either RS-232 or RS-485.
This also acts as a sniffer for my RS-485 network, which I used to observe and reverse engineer the Somfy protocol. Please see my previous post (Somfy Wire Protocol) for my documentation of this protocol.
I started with an Arduino Mega 2560, because it has four serial ports. I'm using only two at this time, one for debugging/setup over the built-in USB port, and a second for the RS-485 connection to control my shades. I plan to control addition devices later with the extra serial ports. If you only wan to control one thing, you could probably also use an ATmega32u4-based Arduino, like the Leonardo or Micro, since those have a separate USB port from the TX/RX pins.
You could mostly implement this functionality with a Raspberry Pi, but I feel a microcontroller is really the right thing, in this case. The ATmega2560 has four serial ports versus the Pi's one, and that's a problem for me, as stated above. I also prefer the simplicity of the microcontroller. The Raspberry Pi far more complex, which is necessary for some projects, but not for this one. The Arduino loses to the Pi in cost, though. The Arduino Mega goes for $46, while the top-of-the line Pi goes for $35. If I want to add the Arduino Ethernet Shield to my project, that's another $45, while the Pi has it built in. (In fact, if I want to add ethernet, it's cheaper to connect a Pi to my Arduino!) On the other hand, if I ever wanted mass-produce my project (admittedly not likely), it might be cheaper to go with the microcontroller design. (Hmm.. you can get ATmega2560 chips in bulk for about $10 a piece, which makes it a very expensive microcontroller. Haven't found the cost of the Pi's ARM1176JZF-S.)
Parts List
- Adruino Mega 2560
- IR LED (https://www.adafruit.com/products/387)
- IR Sensor (https://www.adafruit.com/products/157)
- MAX483 DIP RS-485 Transceiver Chip (datasheet)
- 2N2222 Transistor
- 300Ω Resistor
- 100Ω Resistor
- (optional) RJ45 Breakout Board (https://www.sparkfun.com/products/716)
- (optional) RJ45 Jack (https://www.sparkfun.com/products/643)
- Breadboard
- Breadboard connection wires
The RJ45 jack is specific to how my network is setup. I wired it up via Somfy's specifications, which matches the RJ45 jack on the back of the Somfy smart switches. You may want a different kind of connector for your project, or you may need the connector wired up differently. There's no wider standard that I'm aware of. You could even plug the wires from your RS-485 network directly into your breadboard.
Schematic
A few notes about this schematic:
The IR LED is switched via the 2N2222 transistor, so as to drive it at higher brightness than the AVR can drive directly. I'm not sure these are the optimal resistor values, but they work for me.
The IRremote library by default requires this to be connected to pin 9 on the Arduino Mega. There are several other options that can be chosen by modifying IRremoteInt.h in the library directory and recompiling. And if you are using a different Arduino, it's very important to consult this file to determine the proper pin. The library uses different pins for different AVRs!
The DE and RE pins of the MAX483 are connected together with pin 2 on the Arduino. This is possible because RE is inverted on the transceiver chip. Thus, when pin 2 is high, the transceiver is configured for sending but not receiving, and the opposite is true when pin 2 is low. This means the Arduino won't see the data it is putting on the RS-485 bus, but that's fine for my purposes.
Putting it Together
See the top of this post for what this project looks like put together on a breadboard.I added a second RJ45 jack, which is just split off the first. This gives me a port to hook up a USB-to-RS485 adapter, which allows me to use the Somfy software on the same network as my bridge. (This is how I logged protocol data, which I used to reverse engineer the protocol.) I could have simply used an RJ45 splitter, instead. Neither of these is necessary for the finished product.
In it's final home, I power the circuit by connecting the Arduino to my DVR via a USB cable. (For setup, it's powered off of my computer's USB port.)
Software
I used Ken Shirriff's IRremote libary, which is pretty awesome! One thing to note is that newer versions of the Arduino tools contain a bastardized version of this library. (Seriously, Arduino folks, what were you thinking?) You might want to remove the "RobotIRremote" directory from your Arduino installation to make sure there's no conflict. Unlike the original IRremote, RobotIRremote has limited receiving and no sending capabilities. No good!I've uploaded my Arduino sketch to GitHub:
https://github.com/baysinger/ir2rs485/tree/1.0
I plan to keep this git branch in sync with this blog post. The master branch may drift.
Build the sketch and upload it to the Arduino using the Arduino software suite.
Using It
Test the RS-485 Connection
With the project connected to the RS-485 network, and the USB port on the Arduino connected to a computer running the Arduino software, it's time to test things out. Open the Arduino serial monitor and set the line ending to carriage return.Find out your motor address. If the label on the motor says the address is AB C1 23, you can convert this to network format by reversing the byte order (23 C1 AB) and then flipping every bit (DC 3E 54). I'll use DC3E54 in this example.
Try lowering the shade by issuing this command in the serial monitor:
mffffffdc3e54fdffff (substitute your motor address, in network format, for dc3e54)
Note that it is important for all letters to be lowercase. I didn't bother to write the code to process uppercase letters.
Now to raise the shade again:
mffffffdc3e54feffff
Programming the Remote
You should pick a 16-bit IR code for each command you wish to issue with the remote. I wrote the code to partition the 16 bits into a high order byte to specify the motor or group, and a low order byte to specify the command. So, for instance, I have these motors and groups (in hexadecimal):10: All shades
20: Most shades (a group the contains all but one of my shades)
30: All the dining room shades
01: Sliding door
02: Dining room left
03: Dining room middle
04: Dining room right
05: Living room
06: Stairs
And these commands:
01: Up
02: Down
04: Stop
So, for example, the IR command for all shades up is 1001. The command for living room down is 0502.
To program the remote, you need to tell the Arduino to send an IR signal, and then you can have the remote learn that signal. To tell the Arduino to send the IR code for all shades up, enter this command into the serial monitor:
i1001You'll also need to modify the Arduino sketch to recognize these codes when the remote sends them. (You can do this before or after programming the remote.) Open the sketch and find this switch statement:
switch (results.value >> 8) {This section maps the high order byte received via IR to a motor or group address. You'll need to modify the case labels below that. For instance, this case label maps the value 10 to the group address 323456:
case 0x10:And this one maps the value 01 to the motor address DBF6F9:
Serial.print("all ");
uGrp = 0x323456;
break;
case 0x1:Modify this switch statement to match your setup.
Serial.print("sliding door ");
uAddr = 0xDBF6F9;
break;