Introduction
I have been working with MQTT for some time now, especially after a demo by Benjamin Kabe of the Eclipse Foundation on Paho, LWM2M and the related. MQTT offers a light communication method for connected devices. In my project, I have an architecture where the Raspberry Pi acts as an aggregation point for all the local data. This has two advantages.
All the local traffic stays local. This means that my home automation system will never be responsible for excessive internet traffic. Additionally it will function if my Internet connection goes down.
Single point to be secured. The Internet is a bad place and Home automation needs security. The RPi will be behind a firewall or can have its own iptables if needed.
My intention was to have the RPi run a MQTT server and have all the devices connect to publish their info. OpenHAB has an MQTT binding which I have not gone through yet but I have a number of methods I can use to connect OpenHAB to MQTT(python script or Nodejs script). So what can I use it for? In a home automation system, I need to connect various devices to my system. Possible options are:
1. EnOcean Wireless modules -CHECK!
2. Wired Serial device- The EnOcean Pi already uses the UART. BUT the RPiSOC will change that... more on this later.
3. USB to Serial Conversion- I have an FTDI module and I also have Arduino Nanos AND a surprise for later but wired means nearby... Not yet
4. nRF modules- These are SPI devices and I will try to hook em up to the RPi's SPI directly OR the RPiSOC... later. I got these from elsewhere and will use em for a special purpose.
5. Wi-Fi Connectivity- The CC3200 is on it's way here... later.
6. Other RF- like 433MHz Too insecure. I have a couple of AM modules but these are prone to replay attacks. They are good for some local data transmission but I don't trust them for control unless there is some way to secure them.
7. XBEE- Not this time.... I think
8. Wired Ethernet- Aahhaa! This is unexplored. Ethernet is cheap(er) and is more secured. There are ways to secure a wireless connection as well but the additional security comes at the price of computational complexity which turns into hardware cost.
My goal here is to connect an Arduino to my Raspberry Pi using MQTT over a wired Ethernet. There are multiple reasons for using MQTT but the major ones are
1. Low network load. It is designed for M2M
2. Interoperability- Standard Protocol. I can write my own socket client server but what if I need to add another device? What if my devices change? Standard protocols have the advantage of interoperability between platforms.
With this lets see what we can put together.
About MQTT:
Simply put, MQTT is a lightweight protocol which is based on publish and subscribe methodology. This means there is a place where data/messages are posted which is called a broker and a client will subscribe to the service. The messages are organized by way of TOPICS which means you can have a single broker cater to a lot of devices which may or may not talk to all others.
For more info on mqtt visit www.mqtt.org
Preparing the RPi.
The first step is to setup a MQTT broker on the RPi. Mosquitto is the broker for linux and there is a client and python libraries to help test things. I install all three since I will want to test out things locally before moving to the Arduino. At the prompt, type
sudo apt-get install mosquitto mosquitto-clients python-mosquitto
Surprisingly, the install is also very light weight from 300Kb to 600Kb depending on version. The service is started immediately and there is no mention of username or passwords. We will talk about this later.
Now to test things, we need two terminals. If you have a monitor connected, start the gui by typing startx and open two terminals. If you ssh into the Pi, just get another session going. Now use the precompiled apps mosquitto-pub and mosquitto_sub. In the first terminal type
mosquitto_sub -d -t hello/world
hello/world is the topic.
In the next terminal, type
mosquitto_pub -d -t hello/world -m "Hello MQTT" mosquitto_pub -d -t hello/world -m "Your message"
They should show up like:
If everything goes as shown, you should have MQTT server ready... simple!
The Arduino Endpoint-
Now let me discuss the Arduino side of things.
Arduino and MQTT
Now lets look at the end point device-the arduino. The arduino has some processing capability but SSL/TLS are definitely not one of them. Fortunately for me, google did it's thing and I did not have to write the code for the MQTT client. There is MQTT library written for the Arduino at http://knolleary.net/arduino-client-for-mqtt/
The code is pretty straightforward. Just point towards your RPi and your static IP if you want. I use static IPs because that way I can use wireshark to peek into the network and see how data is going to and fro the RPi and devices. I used one of the examples and put up my own code and done. There is a lot of stuff you can do but I am pretty much done at this point for MQTT.
In order to observer the MQTT status, I use a chrome app by the name of MQTT lens which was recommended by Benjamin Cabe. A screenshot of the same is given below.
Arduino and Relays and IR
There is a flood of circuit descriptions for controlling a relay with an Arduino so I won't go into the details of this. I used a simple 2n2222 transistor to drive the relays and the circuit is given below.
The other thing of interest was to control the appliances with IR remotes- In particular the Air Conditioner. The idea is to be able to sense the room temperature using the EnOcean module and to be able to automate the switching OFF of the Air-Conditioner when we leave the house and ON preemptively before we reach back. Additionally I will be adding a PIR sensor to detect presence and switch ON the AC automatically and switch to manual control. Circuit vise we need to connect an IR LED to the Arduino board. This is gonna be simple.
The first thing I need to know is what the device is transmitting. So I hook up an IR receiver to a 5V supply and the output to an oscilloscope. Again the internet is filled with such images as:
The output on the scope looked like
WOW ! Thats a lot of data. If I start manually noting the timing, I will have grey hair sooner than I thought. So what is the solution? I have an idea.
There are a lot of people who will be thinking about libraries for arduino and all that stuff but I want something different. I will basically be designing an IR replay attach. The first thing is to capture this signal in the form of a csv file. The file can be opened in excel. I added two columns to the sheet. The second one is just sample no i.e. 1 2 3 and so on. The first column had a repeated formula such that
IF(E1>4,1,0) which means if the value of E1 is greater than 4 then produce a 1 else a zero. This is basic thresholding and allows me to convert voltages into bits. I copied and pasted the formula across the column and this is what I got.
This converts my captured signal into on and off data. Great! I can now use this as a lookup table and use the arduino to generate the required waveforms... but wait. This lookup data is still a lot of data and is saved at a very high sampling rate. I could try and reduce the sample rate at the scope level but why did I pay for Excel then? I will first try and visualize the data. Using the charts tool, I created a chart as follows:
Looks good. The real data starts from sample 469 something. The first thing I need to do is to understand the CSV. I have attached the CSV for reference. The CSV says that the sample period is 4.00E-05 which means 4*10^-5 or 40microSeconds. Hence between each sample is the mentioned delay. Now even though the Arduino can generate a delay of 2uS, I also need to generate the 38KHz carrier. I do this using the following function.
38KHz Carrier: Credit Limor Fried of Adafruit.
void pulseIR(long microsecs) { // we'll count down from the number of microseconds we are told to wait cli(); // this turns off any background interrupts while (microsecs > 0) { // 38 kHz is about 13 microseconds high and 13 microseconds low digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen delayMicroseconds(10); // hang out for 10 microseconds digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds delayMicroseconds(10); // hang out for 10 microseconds // so 26 microseconds altogether microsecs -= 26; } sei(); // this turns them back on }
Next I want to reduce the size of the table. What I actually need is the count of how long each signal, 0 or 1 is present. This is done using a simple formula. It is an array formula hence it it entered using CTRL+SHIFT+ENTER. The formula is then copied to the entire column and what we get is...
You can see that now we have the count like 42 samples of ones followed by 12 samples of zeros and so forth. This means that since each sample is spaced 40uSecs the 42 can be translated into a pulse width of 42*40uSec = appox 16.6 milliseconds and the 12 is a low pulse of 12*40uSecs = appox 4.8milliSeconds. Simple right? ehhh....
If we collect these numbers, we have a table of times when the signal is toggled. Actually this means that it is a table of values when the IR transmits and then the value of delay. Like actually, its 16.6 milliseconds of IR signal and 4.8 milliseconds of no signal.... right? More ehhh....
The receiver is actually producing an active Low signal which means that the 1 means no IR SIGNAL and 0 indicates the presence of the IR signal... wow that's complicated.!
So what do we do? Well we definitely need the counts and to do that I simply noted them down. I could have written a VB Script but I just felt it was not worth the effort. I added another column with the simple formula
=IF(H1=H2, "", H1)
This should cause the cell without data to be left blank and have the counts displayed where there is a toggle. Next to delete the blank spaces, use the Filter menu and select all the (blank) cells and delete them. This causes the cells to become really empty. Next use the Home> Find and Select > Go to Special > Blank and then delete the cells. If all goes as planned then you should have a single column of values. I recommend doing all this after converting the csv into an Excel Sheet. Here is a tutorial for the last step... its a doozy. http://www.extendoffice.com/documents/excel/525-excel-remove-blank-rows.html
Now we have a table but we need to verify that the values are in pairs of ON and OFF- Count em. I have a 130 count on the table. I need to convert this column into a row so that when I save as a CSV, we get something we can directly copy into the arduino .h file. Copy the cells, and in a different sheet, Paste Special> Values and Transpose. This will produce a row as:
now save as a CSV and open in something like notepad or my favourite Notepad++. It should look like:
We have a lookup table. Yay!
Now to use it. So my IRTransmit function takes 26microSeconds in one go. I also had a 40uSecond res on the scope and effectively my samples. I'm gonna take some liberties at this point. I am going to modify the function so that it takes 26+26 = 52microseconds. This is done as follows:
void pulseIR52(int cnt) { while(cnt>0){ cli(); // this turns off any background interrupts // 38 kHz is about 13 microseconds high and 13 microseconds low digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen delayMicroseconds(10); // hang out for 10 microseconds digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds delayMicroseconds(10); // hang out for 10 microseconds // repeat digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen delayMicroseconds(10); // hang out for 10 microseconds digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds delayMicroseconds(10); // hang out for 10 microseconds sei(); // this turns them back on cnt--; } }
This is what I am going to use as the function directly instead of the 40uS as it should be. The transmit function will call this to transmit the Signal. The above function will make sure I am transmitting 38KHz hence I wont tamper with it. I have stored the lookup table in the variable
const int pack1[] = { // data here} const int pack1Cnt = 130 // packet1 Pulse Count
Next to write the Packet Function. It looks like this.
void packet1Transmit(void){ int index=0; while(index < pack1Cnt ){ pulseIR52( pack1[index] ); // ON index++; delayMicroseconds(40*pack1[index]); // OFF index++; }
The routine simply goes through the pulse count and plays them out. Now for the testing. I put the code on an arduino, hooked up an LED and attached a scope. Success. It transmits and the output was...
Now for the Receiver...
On the same scale. Viola! It works... I have some more testing to do and will probably find a better way to do the calculation but right now this will have to do.
Humpty Dumpty
At the end both these are combined to get MQTT control over IR devices. I leave the final solution to the imagination of the reader. This finishes one of my modules for the project.
Thanks for reading.
Sincerely,
Inderpreet
Top Comments