IT441: Arduino Stoplight

Charles Christensen - Jun 13 - - Dev Community

Image description

Overview

The main purpose of this project was to optimize my previous distance stoplight by making network communication more lightweight and by adding power-saving functionality. Additional principles learned in this project are as follows.

  • Implemented an MQTT event hub for publish/subscribe notifications between devices.
  • Developed a communications protocol for devices across the event bus.
  • Established more complex conditions for the actuator involving multiple sensors.

Materials

The physical materials used in this project are as follows.

  • Personal Computer
  • Personal Cloud Server
  • (3) Arduino WEMOS D1 mini
  • (3) Breadboard
  • (1) LED Stoplight
  • (1) Ultrasonic Distance Sensor (HC-SR04)
  • (1) Magnetic Door Switch Sensor

Resources

The software, services, and code libraries used in this project are as follows.

  • Arduino IDE
  • C Libraries
  • ESP8266WiFi
  • WiFiManager
  • PubSubClient
  • NewPing
  • Mosquitto MQTT Broker

References

The following guides and references were very useful in the completion of this project.

  • Bald Engineer. Detailed instructions on writing better MQTT callback functions.
  • Instructables. Great explanation of using magnetic door sensors with Arduino. And nice overview of how to use the PubSub MQTT library with WifiManager on Arduino.
  • Randon Nerd Tutorials. Troubleshooting guide for testing MQTT communications from the broker itself.
  • Steve’s Internet Guide. Simple explanation of how to set up a MQTT server in the cloud.

Procedure

Part 1: Setup a MQTT Broker

My last project was a success, but using HTTP to communicate between devices was ridiculously slow. So, I used MQTT for this project. The main benefit of doing this was that it offloaded the complexity of managing the network connections to a more adept/powerful device.

Find a computer that you can use as your MQTT broker. The broker is basically the gateway for all your MQTT communications, so it will need to 1) have a semi-permanent network address and 2) be reachable by all the IoT devices that you might want to connect. In my project, I used the Moqsuitto MQTT broker, which also requires 3) a multi-threaded operating system.

Install your MQTT broker and integrate into your IoT devices. The exact “hows” of doing this depend a lot on the computer that you chose in step 1. In my case, I used a virtual Linux server in Microsoft Azure. The install process was fairly simple; it involved running a couple of commands and opening port 1883 to the public.

sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
sudo apt-get update
sudo apt-get install mosquitto
sudo apt-get install mosquitto-clients

Installing MQTT on Arduino. You need to take note of the network address with which your broker can be reached. The easiest way to do this is by creating a public DNS record that will point to your broker, regardless of where it is. (In my case, this was easy because Azure provides a customizable public DNS record.) If that’s not feasible for you, try setting an assigned/static IP that will be easy for you to remember.

Part 2: Create a Door Sensor

Here’s another improvement on my last project. If my distance stoplight was actually used in a garage, it wouldn’t need to be doing anything most of the time; it would only be needed for a few minutes while someone is parking their car. So, in an attempt to save power, this project also includes a door sensor that will put the other devices to sleep when it reports that the garage door has been closed.

  1. Wire the door sensor to interface with Arduino. Most door sensors are very simple; they take voltage from one end and allow/don’t allow it to pass to the other end. Therefore, one wire from the sensor needs to be connected to a known, constant signal and other end to an input pin. (In my case, I used D8/GPIO15 and the 3.3 voltage pin, so as to avoid complications from using ground and needing a pull-down resistor.)
  2. Code the door sensor functionality. This device is relatively simple to use, but for the inter-device communication you’ll need to add quite a few more components. Functionality-wise, this is the order of how you’ll want to stand-up the various functionalities in your code.
  3. Serial console connectivity. Absolutely essential for development troubleshooting. The commands are Serial.begin(FREQ) to set it up and Serial.println("text") to print text to the console. Door sensor functionality. Before you get into all the network connection mumbo-jumbo, get the main functionality of this device figured out. Instructables has a great guide on using door sensors with Arduino.
  4. WiFi connectivity. A Google search will find you tons of guides on how to do this. If you want, you can also reference my guide on doing this for the WEMOS D1 mini as part of my simple stoplight project.
  5. MQTT connectivity. Again, this is very common and can readily be found online; Instructables has a great explanation of how to do this.. Basically, you’ll need to have two basic functions for this specific device: a connection/reconnection function that will handle connecting to your broker (Remember that semi-permanent network address? You’ll need to use that here.) and a publish function that will transmit changes in the door sensor’s state.

Part 3: Create a Distance Sensor

Wire the ultrasonic distance sensor to interface with Arduino. If you need more information on this, take a quick peek at how I did it in my distance stoplight project. Remember, the sensor performs best when it is connected to 5 volts, instead of 3.3 volts.
Code the distance sensor functionality. This will also be a lot like the code in my distance stoplight project. Since this project uses MQTT, the distance sensor device will need to handle the state changes between distance ranges itself, instead of providing distance information upon request from other devices. In general, this is how you’ll want to build/rebuild your distance sensor functionality.

  1. Serial console connectivity.
  2. Distance sensor functionality. As mentioned above, this functionality not only needs to read distance information from the sensor, but also move the sensor between the different distance distance range states to indicate green, yellow, red, or too close.
  3. WiFi connectivity.
  4. MQTT connectivity. On this device, you’ll need three functions for MQTT communications: a connection/reconnection function, a state publish function, and a callback/”message received” function to change the sensor sleep state based on information from the door sensor. Bald Engineer has a great tutorial on how to use and respond to MQTT callbacks. Power-saving functionality. Basically, all that needs to be done here is to build a option in your infinite loop that will stop the ultrasonic sensor from sampling distances until the door sensor reports that it is open again.

Part 4: Create the Stoplight

Wire the stoplight to interface with Arduino. The best way to do this is probably to wire each specific light and ground. (In my case, I took the lazy route and connected it in a spot on the board where the the pins were already lined up in the order I needed. The only caveat to this was that changing the stoplight’s colors also changed built-in LED’s state.)

  1. Code the stoplight functionality. Here’s a overview of what you’ll need to do to get this functionality up and running. (In my case, I just trimmed down my stoplight code from previous projects since I off-loaded a lot of the functions to MQTT and the distance sensor itself.)
  2. Serial console connectivity.
  3. WiFi connectivity.
  4. MQTT connectivity. You’ll only need two functions for MQTT communications: a connection/reconnection function and a callback function to change the stoplight state and the sleep state. Stoplight functionality. Unlike the previous two devices, the stoplight’s functionality can only come after implementing MQTT because it relies on the state information that it gets there in order to change the lights. Power-saving functionality.

Appendix

FAQ

  • I installed Mosquitto, but none of my devices are able to connect to it. First, verify that Mosquitto is running. On Linux, the following commands will report the status of the Mosquitto broker and enable it to automatically run on system startup, if wanted. Next, test the network connection to your broker; try pinging it. (You may need to open your firewall to ICMP requests in order for this to work.) If neither of those suggestions finds the problem, it is most likely in your code. Time to pull out your bug-finding glasses!

sudo service mosquitto status
sudo systemctl enable mosquitto.service

  • The code inside my infinite loop function is getting ridiculously complicated. Help! One of the main differences between programming for Arduino and other types of coding is that the code we are writing is essentially for a single-function state machine. Therefore, the common advice about not using global variables goes out the window; global variables are your states! To avoid complicated code, define all the states that you’ll need to keep track of as global variables. Then, write seperate functions that will update your global variables or respond to updates. Put as little in you infinite loop function as possible, and instead call your functions as needed.

Thought Questions

  • How does the communication between devices change with the shift to using an MQTT event hub? How does this facilitate greater scalability? Using an MQTT event hub has a huge impact on the overall scalability of IoT projects. As mentioned before, using MQTT offloads all of the details of device communication to a single computer. Each individual device no longer needs to keep track of other IP addresses, serialize/deserialize data, or implement network timeout conditions; the MQTT broker handles all of that and does its best to guarantee that messages are delivered. Therefore, it is much easier to scale projects because each device’s functionality doesn’t need to change or improve. Communication limits can be reduced simply by modifying the broker.
  • What things did you do to learn to use MQTT? The most useful thing to me in learning MQTT was a live demonstration I saw. In the demonstration, several Arduinos turned on/off their LEDs based on the messages sent to them from the command line of the MQTT topic publisher. Having no previous MQTT experience, just simply watching the MQTT traffic and the responses to it was an excellent way for me to learn how to incorporate MQTT into IoT devices.
  • What are strengths and weaknesses of the direct communication between the sensor and actuator? What are strengths and weaknesses of the event hub? Which do you feel is better for this application? The strengths and weaknesses of MQTT versus direct communication can be summarized in the pros/cons of star versus mesh networks. MQTT event hubs are good because they reduce complexity and allow for a single point of upgrade, but on the downside they require an extra device and inherently have an single point of failure. Direct communication, however, is more complex but doesn’t have a single point of failure or require extra devices. (In my opinion, choosing the best option for an application like this rides on whether or not there are outside devices that I also want to hook into my MQTT broker. If there are, building/maintaining an MQTT broker would probably be worth it. Otherwise, it would be way to much overhead for this very simple task.)
  • What was the biggest challenge you overcame in this project? Completing this project required me to really dive down and figure out how to use char array like I never have before. Due to my C++ background, I am used to an easier way of managing strings, but the data provided by the MQTT functions was all char arrays. Thanks to MQTT tutorials mentioned above, I eventually got it figured out with the strcmp() and String.indexOf() functions.
  • How much time did it take you to complete this project? I was able to adapt a fair amount of code from my previous projects for use in this project, so it only took me about 4 hours to complete. After that, I spent an additional 4 hours writing this report.

Code

All code for this project can be found in my repo on GitHub.

. . .