I had an interesting correspondence recently with Wim Bruyn from Holland who was using my SerialSend program to implement a remote-controlled relay system for switching appliances on and off automatically. The relays Wim is using (ETH002) are actually controlled via TCP/IP, so he ended up abandoning SerialSend in favour of a custom Python script. It struck me as a great example of using Python to do automation really easily and I think others will find it useful. Wim has kindly given me permission to reproduce it here. I made some tiny modifications, but Wim did all the work.
Python is available for Windows, Linux, Mac OS and various other platforms. It can be downloaded for free from python.org and only takes a couple of minutes to install. All modules used in the examples below (socket, smtplib, argparse, time) are part of the standard library, so they shouldn’t require separate installation.
I’ll present this example in two stages. The first is very pared back version which demonstrates the basic process of sending a short byte sequence via TCP/IP and then sending a short report via email.
# # simple_rc.py - Written by Wim Bruyn (slightly modified by Ted Burke) # # This short Python program sends a three byte command to a remote # controlled relay device via TCP/IP. It receives a response indicating # whether the command was carried out. A report is then sent via email. # import socket # used for TCP/IP communication import smtplib # used to send email report import time # used to insert current date in email report # Prepare 3-byte control message for transmission TCP_IP = '192.168.2.115' TCP_PORT = 17494 BUFFER_SIZE = 80 MESSAGE = '\x21\x01\x00' # Relays 1 permanent off # Open socket, send message, close socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) s.send(MESSAGE) data = s.recv(BUFFER_SIZE) s.close() # Create report and send as email sender = 'joe.bloggs@email.com' receivers = ['joe.bloggs@email.com'] if data == '\x00': msg = 'Device powered off on date: ' + time.strftime(“%c”) else: msg = 'Error: Device not powered off on date: ' + time.strftime(“%c”) smtpObj = smtplib.SMTP('mailhost.email.com', 25) smtpObj.sendmail(sender, receivers, msg) smtpObj.quit()
The second example, shown below, is Wim’s final program. It parses command line arguments, allowing eight relay modules to be switched on or off individually. Wim uses this program in conjunction with the Windows Task Scheduler to automate on/off switching of appliances.
# # SwitchETH002.py - Written by Wim Bruyn # # Platform: python33, Windows 7 # # Purpose: # Switching ETH002 or ETH008 TCP/IP relays on and off and send an # e-mail when done. Windows task scheduler can be used to activate # the relays (optional). # # Command line arguments required for: # Relays number (1-8), # Mode (on/off), # e-mail report ID (free format text). # # Example usage: # # c:\python33\python.exe SwitchETH002.py 2 off "External WD USB disk" # import socket import time import argparse import smtplib def SendCommandToRelays (MESSAGE): #Value of MESSAGE is command to be send to relays TCP_IP = '192.168.2.115' #IP address of the relays TCP_PORT = 17494 #Port number of the relays BUFFER_SIZE = 80 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((TCP_IP, TCP_PORT)) s.send(MESSAGE) data = s.recv(BUFFER_SIZE) #Response from Relays s.close() if data == b'\x00': SendMailMessage ( (args.Device + ' is powered ' + args.Function + ', on date: ' + time.strftime("%c") ) ) else: SendMailMessage ( ('Error:' + args.Device + ' is not powered ' + args.Function + ', on date: ' + time.strftime("%c")) ) def SendMailMessage (Mtext): #Value of Mtext is action report send to mail recipient sender = 'joe.bloggs@email.com' #mail address of the sender receivers = ['joe.bloggs@email.com'] #mail address of the receiver smtpObj = smtplib.SMTP(‘mailhost.email.com’, 25) smtpObj.sendmail(sender, receivers, Mtext) smtpObj.quit() parser = argparse.ArgumentParser() parser.add_argument ("Number", help = "Relays number 1 – 8", type=int, choices = [1, 2, 3, 4, 5, 6, 7, 8]) parser.add_argument ("Function", help = "on is relays on, off is relays off", choices = ["on", "off"]) parser.add_argument ("Device", help = "Device id for e-mail message") args = parser.parse_args() if args.Number == 1 : if args.Function == 'on' : print ('Relays 1 on'), SendCommandToRelays ( b'\x21\x01\x00' ) #Relays 1 permanent on elif args.Function == 'off' : print ('Relays 1 off'), SendCommandToRelays ( b'\x20\x01\x00' ) #Relays 1 permanent off if args.Number == 2 : if args.Function == 'on' : print ('Relays 2 on'), SendCommandToRelays ( b'\x21\x02\x00' ) #Relays 2 permanent on elif args.Function == 'off' : print ('Relays 2 off'), SendCommandToRelays ( b'\x20\x02\x00' ) #Relays 2 permanent off if args.Number == 3 : if args.Function == 'on' : print ('Relays 3 on'), SendCommandToRelays ( b'\x21\x03\x00' ) #Relays 3 permanent on elif args.Function == 'off' : print ('Relays 3 off'), SendCommandToRelays ( b'\x20\x03\x00' ) #Relays 3 permanent off if args.Number == 4 : if args.Function == 'on' : print ('Relays 4 on'), SendCommandToRelays ( b'\x21\x04\x00' ) #Relays 4 permanent on elif args.Function == 'off' : print ('Relays 4 off'), SendCommandToRelays ( b'\x20\x04\x00' ) #Relays 4 permanent off if args.Number == 5 : if args.Function == 'on' : print ('Relays 5 on'), SendCommandToRelays ( b'\x21\x05\x00' ) #Relays 5 permanent on elif args.Function == 'off' : print ('Relays 5 off'), SendCommandToRelays ( b'\x20\x05\x00' ) #Relays 5 permanent off if args.Number == 6 : if args.Function == 'on' : print ('Relays 6 on'), SendCommandToRelays ( b'\x21\x06\x00' ) #Relays 6 permanent on elif args.Function == 'off' : print ('Relays 6 off'), SendCommandToRelays ( b'\x20\x06\x00' ) #Relays 6 permanent off if args.Number == 7 : if args.Function == 'on' : print ('Relays 7 on'), SendCommandToRelays ( b'\x21\x07\x00' ) #Relays 7 permanent on elif args.Function == 'off' : print ('Relays 7 off'), SendCommandToRelays ( b'\x20\x07\x00' ) #Relays 7 permanent off if args.Number == 8 : if args.Function == 'on' : print ('Relays 8 on'), SendCommandToRelays ( b'\x21\x08\x00' ) #Relays 8 permanent on elif args.Function == 'off' : print ('Relays 8 off'), SendCommandToRelays ( b'\x20\x08\x00' ) #Relays 8 permanent off
Thank You…I will try it.
Brad
Thank you very much for uploading this information.
I am trying to control a RelayPro board of 16 Realys via Ethernet. I found your code and try to apply it.but I haven’t been able to make it work.
I truly belueve that the IP adress and the port number are properly assigned. I do not know if the buffer size it corrects because I do not know what it represents.
I was wondering if you could get in contact with me and help me figure it out.
Thank you in advance,
Mercedes.
Hi Mercedes,
The buffer size is just the maximum number of characters that the device might send back over ethernet in response to each command you send. In the example above, it’s set to 80, but actually I think that’s much longer than required since only a few bytes are normally sent back.
Is this the exact device that you’re using?
http://www.relaypros.com/Relay/Relay/CAT_RELAY16_ETHERNET#.VSKLvOpb–8
If not, please specify exactly what device you’re using.
The exact device you’re using is critically important because devices from different manufacturers are controlled using completely different command sets and they respond in different ways too – i.e. the bytes that are sent back in response to each command will be different for different manufacturers’ devices.
For example, “\x21\x01\x00” was the 3-byte command sequence to switch on relay 1 on the exact board that Wim was using, but that command could be totally different for different ethernet relay boards, so it would be necessary to study the manual for the exact device.
Ted
From what I can see here…
http://www.relaypros.com/Relay/Device/A0010#.VSKOz-pb–8
…it looks like the command to turn on Relay 0 in bank 0 consists of the following three bytes: 254, 108, 0. The command to turn the same relay off seems to be 254, 100, 0. Converting these commands into hexadecimal:
In the first Python example above, you might change line 17 from this…
to one of the following:
…or…
Ted
Hello Ted,
Thank you very much for your help, I will change the uffer size to smaller number. About the Relay board, it was the one on the link.
I am sorry I didnt update my comment by I already figure out that the problem was in the way I sent the message.
It is required to use the struct package and convert the message to this type.
MESSAGE = struct.pack(“BBB”, 254, 108, 1)
Thanks again for your help and your time!
Mercedes.
Hi Mercedes,
Ok, thanks for the update. Glad to hear you got it working.
I think the result of…
…is probably more or less the same as writing the equivalent hex byte values directly in a string literal…
Anyway, the main thing is that you have it working. Best of luck with the rest of whatever you’re working on!
Ted
This is just what I needed to see after searching the internet all day! Thank you so much!
You’re very welcome!
Ted
I just recently purchased this device and I am looking to implement it into my companies systems by: http://gridconnect.com/serial-ethernet-converter.html
We have TV’s that are always located far from our PCs+switch (running Ubuntu). We would like to run CAT6 cabling to this device that will be located next to the TV’s. This would allow us to control the TV’s from our PC’s using TCP/IP, remotely. We would assign a specific IP to the device and then connect it to the TV. With my limited python knowledge, I am having trouble trying to figure out how to “translate” the serial command of: ka 01 01 (turns tv on) to a packet that could be sent through TCP/IP. This program is a great building block and I am now trying to transform is to meet my needs and I appreciate you sharing this. Would you have any recommendations or help you could provide me with?
Thanks
Hi Ed,
You could try something like this:
That’s assuming you want to do it from Python?
The above code also assumes that you’ve configured the ATC-1000 in TCP server mode, assigned it a fixed IP address of 192.168.2.7, and left its port number set to the default value of 23. You’ll find more about that in the user manual:
http://gridconnect.com/media/documentation/atc/ATC-1000-UM.pdf
TCP server mode is described (kind of) in Section 5.3.
I’m also assuming that you’re running Windows at the PC end? If you happen to be running Linux instead, then you don’t even need to create anything like the above program. I think you can just type this in at the command line:
An even better option might be to use netcat, but you can read more about here if you’re interested:
https://stackoverflow.com/questions/3010507/linux-tool-to-send-raw-data-to-a-tcp-server
Hope that helps!
Ted
PS Of course, I should have mentioned that I’ve never used an ATC-1000, so my suggestion above is based on of a quick read of its user manual. I think this is how it works, but I could be wrong! You’d definitely need to try it out in practice to be sure. Also, it definitely won’t work until you’ve configured the ATC-1000 as described in its documentation. The Python code I wrote above assumes that the ATC-1000 will be waiting to receive an incoming TCP connection – hence it’s essential that it’s configured in “TCP server” mode. There are several other ways it can be configured and I’m not sure which is the default.
Best of luck with it!
Ted
I really appreciate you taking the time to answer my question. This is a project I am working on that would greatly help the company I work for. Let me start by explaining a little bit more of what I am trying to do. Basically, we are trying to remotely control and monitor over 300 televisions in the field through their RS232 port. We have to use a Ethernet -> SerialRS232 device (ATC1000) because of the distance between our PC’s and our TV’s. Our PC’s in the field are all running Ubuntu and are all monitored remotely over here at our office. The goal is to have a python script that we could trigger remotely using our internal tools that would turn the TV on. The first step is to try to get the device to work using some command line or python script.
I first tested the device on windows just to see if I had the correct ASCII code to actually turn the TV on. On windows, I used the VCOM software that they suggested to create a virtual COM port and then used Putty to type in ‘ka 01 01’. This worked and it even sent back commands for status that looked like:
“a 01 OK01x” -> when the tv was turned on
So I know that the device is compatible with the TV and I know that I have the correct codes to control the various settings of my TV.
As for the ATC1000. I have it set to TCP Server mode with a data port number of 23. There is a setting under it for the control protocol. By default it is just set to “Port Number 6000”. Should I set it to RFC2217?
Here is a screenshot of the TCP settings: http://imgur.com/a/dvsg3
Now I have my test PC with Ubuntu 16.04 LTS set up and I am trying to figure out how to get it to work. I have tried the following command:
echo ‘ka 01 01’ > /dev/tcp/192.168.2.7/23
No success. However, I do see the “ACT” LED light up quickly on the device when I try to echo the command through so we are at least sending it something. I will try to connect to it through telnet but ultimately I would like to use python. Let me know if you think I should try or use any other method.
Thanks!
Hi Ed,
The fact that the ACT light is blinking when you send the message is encouraging at least. I’m not sure about the RFC2217 thing – my (limited) understanding of that is that it’s to do with creating a virtual COM port on the PC that you can talk to, which indirectly talks to whatever device is plugged into the remote serial port. Do you think that could be what that dialog box is configuring?
Did you try running the short python script I suggested in the first of my two posts above? If you did (and assuming it didn’t work), did you notice whether the ACT LED lit up or not?
All in all, if you seeing that ACT light blink when you send the command using echo and you’ve already been able to turn on the TV using putty, then I’d say you’re within a couple of configuration changes of getting the whole thing working.
Ted
Hi Ed,
Just checking – did you make any progress with your problem?
Ted
Hi Ted,
Some other stuff came up at the office so I have been super busy with that. I have no been able to communicate with the TV in the same way that I did on Windows by creating a VCOM port and then through the Putty command line. I have read a little on opening serial ports and listening as well. I tried using the socket code you suggested and get a quick flashing light on the ACT on the ATC1000 but can not get it to turn on the TV.
The way I would want the program to work is work it send the signal to the TV and to listen to the response and then to close the socket. I will be taking the device home with me this weekend to try to get it work and will post a more in depth explanation of what I am trying out. If you have any suggestions on things I might want to try this weekend please let me know!
Once again, I appreciate the help.
sir I have
$ ffmpeg -f alsa -i hw:0,0 -af astats=metadata=1:reset=1,ametadata=print:key=lavfi.astats.Overall.RMS_level -f null – 2> log.fifo
as input and
$ tail -f log.fifo |grep -i RMS_level
as output I need to program this code in C language to measure the RMS level can You please help me out.
Hi Everyone
how can i access the eth008 module through Ethernet by using c programming