Final Project

Objective

Apply the principles you have learned in this class by designing your own IoT system that solves a real-life need. These don’t have to be massive, world-changing needs, but should be useful in your personal life.

Some examples are:

“In my apartment complex, I never know when my clothes are done in the dryer in the laundry room. I want to build a small device that recognized when the dryer finishes, and then flashes LEDs in a few rooms in my apartment.”

“I worry about packages being stolen from my front porch. I want to design a large box for packages that can be physically attached to my porch. When empty, the box is unlocked. When a package is placed inside and the box is closed, it takes a picture and sends me a message then locks itself until I come home and click a button on my phone to unlock it.”

It could be a system to monitor your pet’s food or water. It could be something to show if the dishwasher is clean or dirty. It could check the temperature in a room and turn on or off a fan or outlet.

Requirements

For the project, you will need to build a system that meets the following minimum technical requirements:

  • Utilize at least 3 physical devices (one sensor and two actuators, or two sensors and one actuator)
  • Utilize at least 2 wireless communication protocols (wifi, BLE, RFID, LoRa, etc)
  • Utilize restful API
  • Utilize event hub or cloud IoT service
  • Utilize a non-web page interface (voice, IFTTT, chat)

Materials

The items used to complete this project were:

  • 3x ESP8266
  • 3x Micro USB Cable for power and data transfer + power brick
  • Raspberry Pi 3
  • Green LED + Resistor
  • 3x Breadboard
  • Small hinged box
  • Generic pushbutton
  • Solenoid lock
  • MOSFET
  • BJT
  • Rectifier Diode
  • 12V Power Supply
  • 10K & 1K Resistors
  • Barrel Jack
  • Reed Switch
  • Buzzer
  • User’s Bluetooth-enabled device

References

The following references were used in the completion of this project. Please note that in some cases, large chunks of code were used as the basis / foundation upon which I could build my particular use case, and can therefore be attributed to their developers:

Procedure

These procedures assume you have already soldered all the pins on your ESP8266’s, and have already completed the procedures from previous labs. Most importantly, it assumes you have set up the RPi as a wireless hotspot and MQTT broker, as outlined in the “Event Bus” and “Security” labs.

Our EPS8266’s will be completely rewired for this project, but we will still need three separate ones, each attached to its own individual breadboard.

Device 1: Lock Solenoid

  1. Plug the barrel jack into the breadboard near the very edge, with the opening facing left.
  2. Viewed from the side still, opening left, plug the positive lead (the left pin) into the positive rail on the side of the board. Plug the negative (right pin) into the negative rail.
  3. Plug the BJT into the breadboard, notch facing upper-left towards the divide in the board.
  4. Plug the MOSFET into the breadboard, black piece facing toward you, a few rows to the side of the BJT. All of this should be done while you are still viewing the barrel jack from the side with the opening facing left.
  5. Run a jumper from the negative rail to the left leg of the BJT.
  6. Run a jumper from the middle leg of the BJT to a free row on the breadboard.
  7. Run a jumper from pin D3 to the same row as step 6, but across the divide in the board.
  8. Bridge #6 and #7 with a 1k resistor.
  9. Run a jumper from the right leg of the BJT to the left leg of the MOSFET.
  10. Run a jumper from the middle leg of the MOSFET to a free row on the breadboard.
  11. Run a jumper from the same row as #10 and leave the other end hanging. This is the positive lead to the lock solenoid.
  12. Run a jumper from the right leg of the MOSFET to the negative rail.
  13. Run a jumper from the ESP’s 5V to a free row near the right leg of the BJT.
  14. Use a 10k resistor to bridge #13 to the same row as the right leg of the BJT, but not between the jumper running to the MOSFET.
  15. Run a jumper from the positive lead to a free row.
  16. Run another jumper from that same row and leave the end hanging. This is the other lead for the solenoid.
  17. Bridge the two rows made in steps 10 & 11 and 15 & 16 with a rectifier diode, stripe facing right. One end of the diode MUST be between the connections made in 10 and 11, and the other end BETWEEN the connections made in 15 & 16.
  18. Run a jumper from the ESP’s ground to the negative rail, and consult the picture for confirmation of the steps.

Device 2: Button & LED

  1. Wire one end of the button to pin D4, and the other to the negative rail.
  2. Use a jumper to connect the ESP’s ground to the negative rail.
  3. Use a jumper to connect the negative rail to a free row.
  4. Use a 330 Ohm resistor to bridge across the previous row and over the break in the board. This is for the negative connection on the LED.
  5. Use a jumper to connect pin D7 to a a row adjacent to the previous row. This is for the positive LED connection.
  6. Insert the LED accordingly. You may want to use wires to extend it away from the breadboard for mounting.

Device 3: Buzzer & Reed Switch

  1. Run a jumper from the ESP ground to the negative rail.
  2. Plug the reed switch into pin D6 and the negative rail.
  3. Run a jumper from pin D4 to a free row.
  4. Run a jumper from the negative rail to a space exactly three rows to the side of the previous.
  5. #3 and #4 are the leads to your buzzer. Insert it into the breadboard.

Raspberry Pi

  1. Copy the files “lockbox.py” and “boxapi.py” to the Pi. Run both of these to make the API and MQTT functional.

Diagram

The entire system runs on a private network created by the Raspberry Pi. The API is served up via Flash on the Pi, as well as the MQTT broker and a script which handles Bluetooth-related functionality. Each ESP sends out a signal with its status every four seconds, which helps to protect against accidental states if a single node loses connectivity for a minute and misses the message via MQTT. All MQTT traffic is password-protected and over SSL.

Algorithm and System Codes

This is the exact document I used when developing the system, which explains the way the system works.


At system idle, box is locked, no bluetooth scanning, LED off.
Press button to begin bluetooth scan. LED flashes.
When phone found, unlock box and stop scan. LED off.
When box is open and closed again, box locks with LED ON.
To open box, press button.
When it opens and closes again, box locks with LED off. Cycle repeats.


EACH PIECE
—Lock—
Listen for all traffic, assign states to variables regardless.
At startup, lock and send locked signal.
If a “bluetooth confirmed” ‘B’ signal received:
unlock the box and send unlocked signal.
If a “bluetooth rejected” ‘X’ signal received:
keep the box locked and send locked signal.
If an “open” ‘A’ signal received:
Note in bool format box was opened.
If a “closed” signal was received AND the box was just previously opened:
set “opened” to 0 again.
lock the box again.
set variable for “next button press unlocks”.



—Buzzer/Reed—
If reed switch is opened, send ‘A’.
If reed switch is closed, send ‘Z’.
If box is locked and reed switch is opened, start buzzer.
If box is closed, stop buzzer.

—Button—
If the button is pressed and the box “next button press” is false:
send signal to start bluetooth scan.
If the button is pressed and the box “next button press” is true:
open the box.
set opened to 0.
lock box and send locked signal.
clear next button press variable.


SIGNAL INDEX:
A – Box opened (ack)
B – Bluetooth accepted (acknowledgement)
C – Bluetooth device check
D – Discovery start (command)
F – Discovery finished (acknowledgement)
L – Box locked. (ack)
N – Not ready for package
P – Button pressed
R – Ready for package drop
U – Box unlocked.
X – Bluetooth rejected
Z – Box closed

Who determines what:
int validPhonePresent: Rpi
int boxLocked: lock
int buttonPressed: button
int lidOpen: reedswitch
int addBTDeviceRunning: rpi
int readyForPackageDrop: reedswitch

Thought Questions

  • What was the biggest challenge you overcame in this project?
    • There were a lot of little problems which came up, but one of the most time-consuming was trying to get the Pi to correctly match a Bluetooth scan with the list of approved devices. There were simply some formatting issues. Other than that, Bluetooth and random MQTT dropouts were also problematic due to inefficient code.
  • Please estimate the total time you spent on this project and report.
    • ~25 Hours

Appendix

Buzz.ino

#include <PubSubClient.h>

#include <ESP8266WiFi.h>

#include <WiFiClientSecure.h>

//#include <ESP8266mDNS.h>

//#include <WiFiUdp.h>

const char* ssid = “”;           

const char* password = “”;

const char* mqtt_server = “”;

const char* mqtt_topic = “LOCKBOX”;

const char* clientID = “ReedBuzz”;

const char* fingerprint = “”;

//WiFiServer server(80);

WiFiClientSecure client;

PubSubClient pubcli(mqtt_server, 8883, client); // 1883 is the listener port for the Broker

int reedPin = D6;

int buzzPin = D4;

int validPhonePresent = 0;

int boxLocked = 0;

int buttonPressed = 0;

int lidOpen = 0;

int addBTDeviceRunning = 0;

int readyForPackageDrop = 0;

int checkBTRunning = 0;

int closedCount = 0;

int waitForClose = 0;

int stepOneDone = 0;

int masterTimer = 0;

int rp = 0;

String mostRecent = “Q”;

char codeToPublish[2];

int gar = LOW;

String initial = “A”;

void setup() {

 pinMode(reedPin,INPUT_PULLUP);

 pinMode(buzzPin,OUTPUT);

 Serial.begin(115200);

 int startup = digitalRead(reedPin);

 if(startup == HIGH) initial = “A”;

 else initial = “Z”;

 attachInterrupt(reedPin, onSwitchChange, CHANGE);

WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

//  server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

if (client.verify(fingerprint,”:8883″)) {

   Serial.println(“certificate matches”);

 } else {

   Serial.println(“certificate doesn’t match”);

 }

//set callback function, connect to broker

 pubcli.setCallback(ReceivedMessage);

   if (pubcli.connect(clientID,””,””)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   while(!pubcli.connect(clientID,””,””)){

   Serial.println(“Connection to MQTT Broker failed…”);

   }

 }

 pubcli.subscribe(mqtt_topic);

 sendM(initial);

 masterTimer = millis();

}

//the receivedmessage function here is for later, in case. Not needed by reed switch

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 Serial.println((char)payload[0]);

 char commd = (char)payload[0];

 switch(commd) {

   case ‘A’:

     lidOpen = 1;

     break;

   case ‘B’:

     validPhonePresent = 1;

     break;

   case ‘C’:

     checkBTRunning = 1;

     break;

   case ‘D’:

     addBTDeviceRunning = 1;

     break;

   case ‘F’:

     addBTDeviceRunning = 0;

     break;

   case ‘G’:

     checkBTRunning = 0;

     break;

   case ‘L’:

     boxLocked = 1;

     break;

   case ‘N’:

     readyForPackageDrop = 0;

     break;

   case ‘P’:

     buttonPressed = 1;

     break;

   case ‘R’:

     readyForPackageDrop = 1;

     break;

   case ‘U’:

     boxLocked = 0;

     break;

   case ‘X’:

     validPhonePresent = 0;

     break;

   case ‘Z’:

     lidOpen = 0;

     break;

 }

}

void onSwitchChange(){

 rp = digitalRead(reedPin);

//generic signals for open and closed

if(rp){

 sendM(“A”);

}

else if(!rp){

 closedCount++;

 if(closedCount==3)closedCount=1;

 sendM(“Z”);

}

}

void sendM(String c){

 c.toCharArray(codeToPublish,2);

 if(pubcli.publish(mqtt_topic,codeToPublish)) Serial.println(“Sent “+c);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,codeToPublish);

 }

 mostRecent = c;

 masterTimer = millis();

}

void waitTime(){

if(millis()-masterTimer < 4000) return;

sendM(mostRecent);

masterTimer = millis();

}

void loop() {

 //if the reed is closed but the garage variable is open, set to closed. Do opposite for open.

 if(boxLocked && rp) {

   digitalWrite(buzzPin,HIGH);

   closedCount = 0;

 }

else if (!rp) digitalWrite(buzzPin,LOW);

if(lidOpen && !boxLocked && !readyForPackageDrop && !waitForClose)

{

 //if the lid is open and the package drop ready variable is 0, the owner is opening for init. Set drop to 1.

 sendM(“R”);

 waitForClose = 1;

}

else if (lidOpen && !boxLocked && readyForPackageDrop && !waitForClose)

{

 sendM(“N”);

 waitForClose = 1;

}

if(!lidOpen) waitForClose = 0;

else waitForClose = 1;

waitTime();

pubcli.loop();

}

Lock.ino

#include <ESP8266WebServer.h>

#include <ESP8266WebServerSecure.h>

#include <ESP8266WebServerSecureAxTLS.h>

#include <ESP8266WebServerSecureBearSSL.h>

#include <PubSubClient.h>

#include <WiFiClientSecure.h>

const char* ssid = “”;           

const char* password = “”;              

const char* mqtt_server = “”;

const char* mqtt_topic = “LOCKBOX”;

const char* clientID = “Lock”;

const char* fingerprint = “”;

int lockPin = D3;

int validPhonePresent = 0;

int boxLocked = 0;

int buttonPressed = 0;

int lidOpen = 0;

int addBTDeviceRunning = 0;

int readyForPackageDrop = 0;

int checkBTRunning = 0;

int waitForOpen = 0;

int masterTimer = 0;

char lastSent = ‘Q’;

String mostRecent = “Q”;

char codeToPublish[2];

//ESP8266WebServer server(80);

WiFiClientSecure client;

PubSubClient pubcli(mqtt_server, 8883, client); // 1883 is the listener port for the Broker

void setup() {

 Serial.begin(115200);

 delay(10);

 //set pins

 pinMode(lockPin, OUTPUT);

 digitalWrite(lockPin, HIGH);

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 //server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

if (client.verify(fingerprint,”:8883″)) {

   Serial.println(“certificate matches”);

 } else {

   Serial.println(“certificate doesn’t match”);

 }

 //set the message callback function, connect to MQTT broker, subscribe

 pubcli.setCallback(ReceivedMessage);

 if (pubcli.connect(clientID,””,””)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   while(!pubcli.connect(clientID,””,””)){

   Serial.println(“Connection to MQTT Broker failed…”);

   }

 }

 pubcli.subscribe(mqtt_topic);

 boxLocked = 1;

 sendM(“L”);

   masterTimer = millis();

}

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 char commd = (char)payload[0];

 switch(commd) {

   case ‘A’:

     lidOpen = 1;

     break;

   case ‘B’:

     validPhonePresent = 1;

     break;

   case ‘C’:

     checkBTRunning = 1;

     break;

   case ‘D’:

     addBTDeviceRunning = 1;

     break;

   case ‘F’:

     addBTDeviceRunning = 0;

     break;

   case ‘G’:

     checkBTRunning = 0;

     break;

   case ‘L’:

     boxLocked = 1;

     break;

   case ‘N’:

     readyForPackageDrop = 0;

     break;

   case ‘P’:

     buttonPressed = 1;

     break;

   case ‘R’:

     readyForPackageDrop = 1;

     break;

   case ‘U’:

     boxLocked = 0;

     break;

   case ‘X’:

     validPhonePresent = 0;

     break;

   case ‘Z’:

     lidOpen = 0;

     break;

 }

}

void sendM(String c){

 c.toCharArray(codeToPublish,2);

 if(pubcli.publish(mqtt_topic,codeToPublish)) Serial.println(“Sent “+c);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,codeToPublish);

 }

 mostRecent = c;

 masterTimer = millis();

}

void waitTime(){

if(millis()-masterTimer < 4000) return;

sendM(mostRecent);

masterTimer = millis();

}

void loop() {

   if(buttonPressed && readyForPackageDrop)

   {

     buttonPressed = 0;

     digitalWrite(lockPin,LOW);

     boxLocked = 0;

     sendM(“U”);

     lastSent = ‘U’;

     waitForOpen = 1;   

   }

   if(validPhonePresent && buttonPressed){

     buttonPressed = 0;

     digitalWrite(lockPin,LOW);

     boxLocked = 1;

     sendM(“U”);

    lastSent = ‘U’;

    waitForOpen = 1;

   }

   if(!lidOpen && lastSent != ‘L’ && !waitForOpen){

     digitalWrite(lockPin,HIGH);

     boxLocked = 1;

     sendM(“L”);

     lastSent = ‘L’;

   }

   if(lidOpen) waitForOpen = 0;

   waitTime();

   pubcli.loop();

}

Switch.ino

#include <PubSubClient.h>

#include <ESP8266WiFi.h>

#include <WiFiClientSecure.h>

const char* ssid = “”;           

const char* password = “”;

const char* mqtt_server = “”;

const char* mqtt_topic = “LOCKBOX”;

const char* clientID = “Button”;

const char* fingerprint = “”;

WiFiClientSecure client;

PubSubClient pubcli(mqtt_server, 8883, client); // 1883 is the listener port for the Broker

int pushButton = D3;

int led = D7;

int flashy = 0;

int masterTimer = 0;

int validPhonePresent = 0;

int boxLocked = 0;

int buttonPressed = 0;

int lidOpen = 0;

int addBTDeviceRunning = 0;

int readyForPackageDrop = 0;

int checkBTRunning = 0;

char codeToPublish[2];

char lastButtonReading = ‘A’;

char last = ‘Q’;

// Holds the current button state.

volatile int state;

// Holds the last time debounce was evaluated (in millis).

volatile long lastDebounceTime = 0;

// The delay threshold for debounce checking.

const int debounceDelay = 200;

void setup() {

 pinMode(pushButton,INPUT);

 pinMode(led,OUTPUT);

 Serial.begin(115200);

 attachInterrupt(pushButton, onButtonPress, CHANGE);

WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

//  server.begin();

// Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

if (client.verify(fingerprint,”:8883″)) {

   Serial.println(“certificate matches”);

 } else {

   Serial.println(“certificate doesn’t match”);

 }

//set callback function, connect to broker

 pubcli.setCallback(ReceivedMessage);

   if (pubcli.connect(clientID,””,””)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   while(!pubcli.connect(clientID,””,””)){

   Serial.println(“Connection to MQTT Broker failed…”);

   }

 }

 pubcli.subscribe(mqtt_topic);

masterTimer = millis();

int lastButtonReading = digitalRead(pushButton);

}

void onButtonPress() {

 // Get the pin reading.

 int reading = digitalRead(pushButton);

 // Ignore dupe readings.

 if(reading == state) return;

 boolean debounce = false;

 // Check to see if the change is within a debounce delay threshold.

 if((millis() – lastDebounceTime) <= debounceDelay) {

   debounce = true;

 }

 // This update to the last debounce check is necessary regardless of debounce state.

 lastDebounceTime = millis();

 // Ignore reads within a debounce delay threshold.

 if(debounce) return;  

 // All is good, persist the reading as the state.

 state = reading;

 // Work with the value now.

 Serial.println(“button: ” + String(reading));

 lastButtonReading = !lastButtonReading;

 flashy = 0;

 sendM(“P”);

 /*if(lidOpen && !readyForPackageDrop){

   //if the lid is opened by the user and the button is pressed

   flashy = 1;

   sendM(“D”);

 }*/

 if (!lidOpen && !readyForPackageDrop){

   //if the button is pressed after a package has been dropped

   sendM(“C”);

 }

}

//the receivedmessage function here is for later, in case. Not needed by reed switch

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 Serial.println((char)payload[0]);

 char commd = (char)payload[0];

 switch(commd) {

   case ‘A’:

     lidOpen = 1;

     break;

   case ‘B’:

     validPhonePresent = 1;

     break;

   case ‘C’:

     checkBTRunning = 1;

     break;

   case ‘D’:

     addBTDeviceRunning = 1;

     break;

   case ‘F’:

     addBTDeviceRunning = 0;

     break;

   case ‘G’:

     checkBTRunning = 0;

     break;

   case ‘L’:

     boxLocked = 1;

     break;

   case ‘N’:

     readyForPackageDrop = 0;

     break;

   case ‘P’:

     buttonPressed = 1;

     break;

   case ‘R’:

     readyForPackageDrop = 1;

     break;

   case ‘U’:

     boxLocked = 0;

     break;

   case ‘X’:

     validPhonePresent = 0;

     break;

   case ‘Z’:

     lidOpen = 0;

     break;

 }

}

void sendM(String c){

 c.toCharArray(codeToPublish,2);

 if(pubcli.publish(mqtt_topic,codeToPublish)) Serial.println(“Sent “+c);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,codeToPublish);

 }

}

void loop() {

if(flashy){

 flashTime();

}

if(lidOpen){

 digitalWrite(led,LOW);

}

else if (readyForPackageDrop){

   //if the box is awaiting a package

   flashy = 0;

   digitalWrite(led, HIGH);

}

if(checkBTRunning) flashy = 1;

else {

 flashy = 0;

 digitalWrite(led,LOW);

}

pubcli.loop();

}

void flashTime(){

if(millis()-masterTimer < 500) return;

digitalWrite(led,!digitalRead(led));

masterTimer = millis();

}

Lab 6: Security

 

Objective

  • Implement a simple RESTful API for the back-end garage actuators (distance sensor, garage door control)  
  • Implement a full-featured user interface for the garage door opener  
  • Utilize a non-web interface for the garage door opener

Requirements

For this lab, you will study Don Borthwick’s story in Case Study 6. While the specific requirements set forth in the narrative should be met, your objective in this lab is to maintain a safe and secure garage door opener, while providing one or more interfaces to the system. One interface must be full-featured, allowing Don to check the state of his garage, see if a car is parked in the garage. Don also needs a non-web interface for controlling his garage door as he arrives home each evening.

Materials

The items used to complete this lab were:

  • 3x Arduino D1 Mini
  • 3x Micro USB Cable for power and data transfer
  • 5v Relay Switch
  • Raspberry Pi
  • Ultrasonic sensor
  • Red LED
  • Yellow LED
  • Green LED
  • Blue LED
  • 4x 330 Ohm resistors
  • Assorted male-male jumper wires for breadboard
  • 3x Breadboard

 

References

The following references were used in the completion of this lab. Please note that large chunks of code were used as the basis / foundation upon which I could build my particular use case, and can therefore be attributed to their developers:

 

 

Command to listen: mosquitto_sub -u node -P connectM3 -t GARAGE -p 8883 -h 10.3.141.1 –cafile ca.crt

 

Procedure

These instructions assume you have already completed all the tasks outlined in all previous labs, and continues where those left off. If not, complete all of that first.

 

Raspberry Pi: Create the API

  1. Install the following packages using pip:
    1. flask flask-jsonpify flask-restful
    2. Copy the script found in the appendix, which listens for endpoints on /garage, /garage/door, and /garage/sonic.
    3. Copy over the new code found in the Appendix to the D3 Mini running the relay and stoplights.
    4. Run the python script on the Pi, which will start listening on port 5002.
    5. Using Postman or another API-testing software, perform GET requests on all endpoints and note that the status matches the status of the garage door reed switch.
    6. Perform a PUT request containing {status:open} or {status:closed} and note that the relay switches appropriately and the status changes.

 

IFTTT

  1. Log on to ifttt.com and create four new applets for Google Assistant: one for opening the garage, one for shutting, one for checking the status of the garage door, and one for hearing how to proceed to the garage (based on distance).
  2. Have the “then” portion be a Webhooks call to match each of these, which should mirror the testing you did in Postman.

 

Diagram and Reasoning

General Devices

A user issues a voice command to Google Assistant, which then communicates with IFTTT. IFTTT informs the assistant how to respond, then uses Webhooks to issue an API call to a public-facing web server. The web server receives the call, then reverse-proxies it to the MQTT broker, which is set to only receive commands from the proxy. The Flask API then receives the API call, which will either return the array of statuses or make a modification to the state of the garage door.

The MQTT broker sits and waits for all incoming messages. While the reed switch is closed, no signals are sent aside from the signal that the switch is closed, and the LED is turned on. When the switch is closed, a new message is sent indicating the switch is closed, which is then broadcast to the other two devices. The Ultrasonic sensor reads this message and then begins pinging for distance. It sends the appropriate message back to the MQTT topic depending on this distance. The stoplight then reads in this message alongside the open/closed information to light the correct LEDs. If it receives a “Closed” message, all LEDs turn off. The relay is activated via the web page, and received the “Open/Closed” messages sent so that it can display the status of the garage on the web page.

The system was designed in this way because it seemed like the most efficient method for directing traffic. No receiving needs to be done by the reed switch, as it is the “catalyst” for the rest of the system. The ultrasonic sensor needs to know when to operate, but also needs to instruct the stoplight, so two-way communication is necessary. The stoplight only needs to be told what to do, so no transmissions are necessary.

 

Security

The Raspberry Pi was configured to run its own, isolated WiFi network, to which the nodes could all connect. It was also configured as a certificate authority, issuing certificates which are then used by Mosquitto to secure communications. Of course, a WPA2 pass code was set on the wireless network itself, and credentials were also added to the MQTT credentials for further security, especially considering the communications are now encrypted with TLS. For further security against most vectors, SSH should be disabled on the Pi, and the root password should be changed to something very obscure.

As far as the external access goes, the Pi is limited to listen only to the address of the public-facing web server, which reverse-proxies all calls. This helps to obscure and secure the actual endpoints, and control which users are allowed to issue calls. The system could be further secured by restricting things like MAC addresses or IP ranges.

 

Thought Questions

  • How did you overcome the need for a full-featured interface, as well as the need for an accurate and easy to use interface?
    • I opted to use Google Assistant, a voice-driven application easy accessible or built-in to all Android phones, and available for iOS. This eliminated the need for a visual interface altogether, or any kind of touch interaction whatsoever. A user would simply need to use the wake words (Okay, Google) and issue a command. If speaking isn’t really easy, then I don’t know what is. This option is also valuable as it is hands-free, which is needed for a user to issue garage commands while still in the car.
  • What was the biggest challenge you overcame in this lab?
    • Figuring out how to get the PUT requests to work correctly in the Flask API.
  • Please estimate the total time you spent on this lab and report.
    • ~5 Hours

 

Appendix (New Code Only)

Api.py

 

from flask import Flask, request

from flask_restful import Resource, Api, reqparse

from sqlalchemy import create_engine

from json import dumps

from flask.ext.jsonpify import jsonify

import paho.mqtt.client as mqtt

import paho.mqtt.publish as publish

 

Broker = “localhost”

Port = 8883

 

topic = “GARAGE”

 

app = Flask(__name__)

api = Api(app)

 

parser = reqparse.RequestParser()

parser.add_argument(‘status’)

 

GARAGE = {

       ‘door’ : {‘status’: ‘closed’},

       ‘sonic’ : {‘distance’: ‘APPROACH’}

}

 

#BEGIN MQTT STUFF

def on_connect(client,userdata,flags,rc):

       print(“Connected”)

       client.subscribe(topic)

 

def on_message(client,userdata,msg):

       message = str(msg.payload)

       if(message == “O”):

               GARAGE[‘door’] = {‘status’:’open’}

       elif(message == “C”):

               GARAGE[‘door’] = {‘status’:’closed’}

       elif(message == “G”):

               GARAGE[‘sonic’] = {‘distance’:’APPROACH’}

       elif(message == “Y”):

               GARAGE[‘sonic’] = {‘distance’:’SLOW’}

       elif(message == “R”):

               GARAGE[‘sonic’] = {‘distance’:’STOP’}

       elif(message == “F”):

               GARAGE[‘sonic’] = {‘distance’:’REVERSE’}

       print(msg.payload)

 

def on_publish(mosq,obj,mid):

       print(“mid: ” + str(mid))

 

client = mqtt.Client()

client.on_connect = on_connect

client.on_message = on_message

client.username_pw_set(”,password=”)

client.tls_set(‘/home/pi/ca.crt’,tls_version=2)

client.connect(Broker,Port,60)

client.loop_start()

 

#BEGIN API STUFF

 

class Door(Resource):

       def get(self):

               return GARAGE[‘door’]

 

       def put(self):

               args = parser.parse_args()

               silly = {‘status’:args[‘status’]}

               GARAGE[‘door’] = silly

               client.publish(topic,silly[‘status’])

               return silly,201

 

class Sonic(Resource):

       def get(self):

               return GARAGE[‘sonic’]

 

class Garage(Resource):

       def get(self):

               return GARAGE

 

api.add_resource(Garage,’/garage’)

api.add_resource(Door,’/garage/door’)

api.add_resource(Sonic,’/garage/sonic’)

 

if __name__ == ‘__main__’:

       app.run(port=’5002′,host=’x.x.x.x’)

 

Stoplight.ino

#include <ESP8266WebServer.h>

#include <ESP8266WebServerSecure.h>

#include <ESP8266WebServerSecureAxTLS.h>

#include <ESP8266WebServerSecureBearSSL.h>

 

#include <PubSubClient.h>

#include <WiFiClientSecure.h>

//#include <ESP8266WiFi.h>

//#include <ESP8266mDNS.h>

//#include <WiFiUdp.h>

//#include <TimedAction.h>

 

const char* ssid = “”;           

const char* password = “”;              

const char* mqtt_server = “”;

const char* mqtt_topic = “GARAGE”;

const char* clientID = “Stoplight”;

const char* fingerprint = “”;

 

int redPin = D5;

int yellowPin = D6;

int greenPin = D7;          

int relayPin = D3;

 

int freaky = LOW;

 

int garOpen = LOW;

 

int timediff = 0;

 

unsigned long lastiter = 0;

int redstate = 0;

 

String garry = “CLOSED”;

 

ESP8266WebServer server(80);

WiFiClientSecure client;

 

PubSubClient pubcli(mqtt_server, 8883, client); // 1883 is the listener port for the Broker

 

void setup() {

 Serial.begin(115200);

 delay(10);

 //set pins

 pinMode(greenPin, OUTPUT);

 pinMode(yellowPin, OUTPUT);

 pinMode(redPin, OUTPUT);

 pinMode(relayPin, OUTPUT);

 digitalWrite(greenPin, LOW);

 digitalWrite(yellowPin, LOW);

 digitalWrite(redPin, LOW);

 digitalWrite(relayPin, LOW);

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 

server.on(“/GARAGE=OPEN”,opened);

 server.on(“/GARAGE=CLOSE”,closed);

 server.on(“/”,render);  

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

if (client.verify(fingerprint,””)) {

   Serial.println(“certificate matches”);

 } else {

   Serial.println(“certificate doesn’t match”);

 }

 

 //set the message callback function, connect to MQTT broker, subscribe

 pubcli.setCallback(ReceivedMessage);

 if (pubcli.connect(clientID,””,””)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   while(!pubcli.connect(clientID,””,””)){

   Serial.println(“Connection to MQTT Broker failed…”);

   }

 }

 pubcli.subscribe(mqtt_topic);

 

 

}

 

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 

 char commd = (char)payload[0];

 

 //set the garage open variable

 if (commd == ‘O’) {

   garOpen = HIGH;

   garry = “OPEN”;

 }

 else if (commd == ‘C’) {

   garry = “CLOSED”;

   garOpen = LOW;

 }

 else if (commd == ‘o’ && garOpen == LOW) {

   digitalWrite(relayPin,HIGH);

   delay(300);

   digitalWrite(relayPin,LOW);

   garOpen == HIGH;

 }open

 else if (commd == ‘o’ && garOpen == HIGH) {

   digitalWrite(relayPin,HIGH);

   delay(300);

   digitalWrite(relayPin,LOW);

   garOpen == LOW;

 }

 

 //if the garage is open, operate lights. If not, blackout

 if(garOpen == HIGH) {

 

   switch(commd){

     case ‘R’:

       digitalWrite(redPin,HIGH);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,LOW);

       break;

     case ‘Y’:

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,HIGH);

       digitalWrite(greenPin,LOW);

       break;

     case ‘G’:

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,HIGH);

       break;

     case ‘F’:

       freakout();

       break;

   }

 

 

 }

 else {

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,LOW);    

 }

 

}

 

void opened(){

digitalWrite(relayPin,HIGH);

String page = “<h1>GARAGE:”+garry+”</h1><a href=\”/GARAGE=OPEN\”><button>OPEN GARAGE</button></a><br><a href=\”/GARAGE=CLOSE\”><button>CLOSE GARAGE</button></a>”;

server.send(200,”text/html”,page);

delay(300);

digitalWrite(relayPin,LOW);

}

 

void closed(){

digitalWrite(relayPin, HIGH);

String page = “<h1>GARAGE:”+garry+”</h1><a href=\”/GARAGE=OPEN\”><button>OPEN GARAGE</button></a><br><a href=\”/GARAGE=CLOSE\”><button>CLOSE GARAGE</button></a>”;

server.send(200,”text/html”,page);

delay(300);

digitalWrite(relayPin,LOW);

}

 

void render(){

String page = “<h1>GARAGE:”+garry+”</h1><a href=\”/GARAGE=OPEN\”><button>OPEN GARAGE</button></a><br><a href=\”/GARAGE=CLOSE\”><button>CLOSE GARAGE</button></a>”;

server.send(200,”text/html”,page);

}

 

void loop() {    

   pubcli.loop();

   server.handleClient();

}

 

void freakout(){

 if (millis() > lastiter) {

   digitalWrite(redPin, (redstate) ? HIGH : LOW);

   digitalWrite(yellowPin, (redstate) ? HIGH : LOW);

   digitalWrite(greenPin, (redstate) ? HIGH : LOW);

   redstate = !redstate;

   lastiter = millis()+500UL;

 }

}

 

Lab 5: Security

 

Objective

  • Design a security architecture for your garage door system  
  • Extend the event hub architecture to accommodate another device  
  • Establish more complex conditions an additional sensor.

Requirements

For this lab, you will study Don Borthwick’s story in Case Study 5. While the specific requirements set forth in the narrative should be met, your objective in this lab is to shift from focusing on developing the individual devices, to designing the system as a whole. You should think through the security ramifications of this system and present a system security architecture, with appropriate diagrams and descriptions.

Materials

The items used to complete this lab were:

  • 3x Arduino D1 Mini
  • 3x Micro USB Cable for power and data transfer
  • 5v Relay Switch
  • Raspberry Pi
  • Ultrasonic sensor
  • Red LED
  • Yellow LED
  • Green LED
  • Blue LED
  • 4x 330 Ohm resistors
  • Assorted male-male jumper wires for breadboard
  • 3x Breadboard

 

References

The following references were used in the completion of this lab. Please note that large chunks of code were used as the basis / foundation upon which I could build my particular use case, and can therefore be attributed to their developers:

 

Procedure

These instructions assume you have already soldered the pins to your D1 Mini. If not, complete that task first.

 

First D1 Mini: Stoplight

 

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.    
  2. Take a jumper cable and connect it from a ground (G) output of the Mini to one of the negative rails running along the sides of the breadboard. This will send the ground along the entire row of that breadboard.
  3. Connect three jumper cables to three GPIO pin outputs of your choice. In this example, we will be using D5, D6, and D7.
  4. Connect the other ends of those jumper cables on rows 23, 25, and 27 of your breadboard, as close to the side as possible. These are the positive leads for your LEDs.
  5. Insert the long end of each LED into a hole which is on the same row as a jumper cable from the previous step. You’ll note that there is conveniently an extra hole between each jumper cable from step 4; this is for the ground.
  6. Insert one end of each resistor into the negative rail you established in step 2. Insert the other end along a row where you placed the negative leg of an LED. Once this is done, you should have a positive and negative connection for each LED. See the picture for confirmation.
  7. Plug the micro USB cable into the D1 Mini and insert it into the USB port on your machine. Your system should begin a basic driver installation. Take special note when the OS reports it is done installing; it should inform you of the COM Port the Mini is on.
  8. Obtain the Arduino IDE from https://www.arduino.cc/en/Main/Software, making sure to select your operating system and the latest software version. Install the IDE.
  9. Begin the process of adding the necessary modules for the board by navigating to File > Preferences in the IDE.
  10. Under “Additional Board URLs”, paste in http://arduino.esp8266.com/stable/package_esp8266com_index.json and press OK.
  11. Navigate to Tools > Board > Board Manager and locate “esp8266” from the list. Press install.
  12. Under Tools > Board, select “D1 & D1 Mini”.
  13. Under Tools > Port, select the COM port as reported by the OS in step 7.
  14. You should now be ready to load code. Copy and paste the code as found in the appendix of this document into the IDE. Modify the network SSID and password fields found near the beginning of the code accordingly.
  15. Verify that the code compiles by pressing the “checkmark” button in the upper-left.
  16. Once it has compiled, press the “upload” button (located next to the checkmark) to begin the upload process.
  17. Whenever the D1 mini has power and the specified network is available, it awaits signals from the ultrasonic sensor and responds accordingly.

 

Second D1 Mini: Ultrasonic Sensor

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.
  2. Mount the ultrasonic sensor across four rows (not columns) of pins.
  3. Connect the ground pin of the D1 to the ground pin of the sensor.
  4. Connect the VCC pin of the sensor to the 5V pin of the D1.
  5. Choose two GPIO pins for use with the pulse and echo pins of the sensor and connect them. Here, D4 and D3 were chosen.
  1. Follow steps 7-16 of the previous D1 mini to upload the corresponding code to it.
  2. Whenever the D1 mini has power and the specified network is available, it will send signals to the stoplight.

Third D1 Mini: Reed Switch

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.
  2. Connect an LED across two rows of the breadboard.
  3. Connect a jumper from the positive lead of the LED to a GPIO pin. We use D7 here.
  4. Connect a resistor from the negative lead of the LED to the negative side rail of the breadboard.
  5. Connect a jumper from the ground pin of the D1 mini to the ground rail.
  6. Connect one end of the reed switch to a GPIO pin. We use D5 here.
  7. Connect the other end to the ground rail of the breadboard.
  8. Follow steps 7-16 of the first D1 mini to upload the corresponding code to it.
  9. Whenever the reed switch is open, it will send a message via MQTT to the other devices indicating the garage door is “open” and turn off the LED. When it is closed, it will send a “closed” message and turn on the LED.

 

Fourth Device: Relay Switch

  1. Taking the stoplight board from earlier, mount the relay switch onto it. You may need to relocate some LEDs and wiring to make room.
  2. Connect a line from the 8266’s ground to the relay ground.
  3. Connect 5V from the 8266 to the relay.
  4. Connect a GPIO pin from the 8266 to pin D1 of the relay.

Raspberry Pi: Initial Mosquitto Configuration

  1. Start up the Pi and connect it to the same wireless network the D1 minis will be on.
  2. Install the MQTT client with these commands:
    1. sudo apt-get install mosquitto -y
    2. sudo apt-get install mosquitto-clients -y
  3. Open the file /etc/mosquitto/mosquitto.conf for editing.
  4. Add the following line to the bottom of the file and save:
    1. listener 1883
  5. Restart the service with the following command:
    1. sudo service mosquitto restart
  6. Subscribe the Pi to the topic with the following command:
    1. mosquitto_sub -d -t GARAGE
  7. The Pi is now set to listen.

 

Raspberry Pi: Certificate Generation and MQTT SSL

  1. On the Pi, download a certificate generation script with
    1. wget https://github.com/owntracks/tools/raw/master/TLS/generate-CA.sh
  2. Allow it to be executed with
    1. Chmod +x generate-CA.sh
  3. Run the script. It will generate six files, three starting with “CA” and three starting with (likely) raspberrypi, or whatever your Pi’s hostname is.
  4. Run the following commands to copy the certificates to your Mosquitto directory:
    1. sudo cp CA.csr /etc/mosquitto/certs
    2. sudo cp rasberrypi.* /etc/mosquitto/certs
  5. Generate a mosquitto password file with the following command:
    1. cd /etc/mosquitto
    2. mosquitto_passwd -c <desired name of output file> <desired username>
      1. It will then prompt you for a password and finish.
  6. Open /etc/mosquitto/mosquitto.conf for editing and do the following:
    1. Comment out the “listener 1883” line.
    2. Add “listener 8883” to the bottom.
    3. Add “allow_anonymous false” below that.
    4. Add “password_file /etc/mosquitto/<what you named the file in 5b>”
    5. Add “cafile /etc/mosquitto/certs/ca.crt”
    6. Add “certfile /etc/mosquitto/certs/raspberrypi.crt”
    7. Add “keyfile /etc/mosquitto/certs/raspberrypi.key”
  7. Restart mosquitto with
    1. sudo service mosquitto restart
  8. Set up the Pi as its own network hotspot by running
    1. wget -q https://git.io/voEUQ -O /tmp/raspap && bash /tmp/raspap
  9. Restart the pi.
  10. Once it’s back, open a web browser and point it to localhost.
    1. The default username is “admin” and password is “secret”.
    2. Go to “configure hotspot”
    3. Change the SSID if desired.
    4. Go to the “security” tab in the same section and change the password. This will need to match what is in the code on each node.
    5. Save the settings, then press “Stop hotspot” and “Start hotspot”.
    6. The Pi should now be independent and broadcasting an SSID. No Internet connections are necessary, and the nodes can all connect.

Diagram and Reasoning

General Devices

The MQTT broker sits and waits for all incoming messages. While the reed switch is closed, no signals are sent aside from the signal that the switch is closed, and the LED is turned on. When the switch is closed, a new message is sent indicating the switch is closed, which is then broadcast to the other two devices. The Ultrasonic sensor reads this message and then begins pinging for distance. It sends the appropriate message back to the MQTT topic depending on this distance. The stoplight then reads in this message alongside the open/closed information to light the correct LEDs. If it receives a “Closed” message, all LEDs turn off. The relay is activated via the web page, and received the “Open/Closed” messages sent so that it can display the status of the garage on the web page.

The system was designed in this way because it seemed like the most efficient method for directing traffic. No receiving needs to be done by the reed switch, as it is the “catalyst” for the rest of the system. The ultrasonic sensor needs to know when to operate, but also needs to instruct the stoplight, so two-way communication is necessary. The stoplight only needs to be told what to do, so no transmissions are necessary.

 

Security

The Raspberry Pi was configured to run its own, isolated WiFi network, to which the nodes could all connect. It was also configured as a certificate authority, issuing certificates which are then used by Mosquitto to secure communications. Of course, a WPA2 pass code was set on the wireless network itself, and credentials were also added to the MQTT credentials for further security, especially considering the communications are now encrypted with TLS. For further security against most vectors, SSH should be disabled on the Pi, and the root password should be changed to something very obscure.

Thought Questions

  • How did you secure devices that are not inherently secure devices? How does layering security approaches help?
    • I had to utilize the RPi’s ability to act as a CA and host certificates, then create secure connections between it (as an MQTT broker) and the other devices. The 8266s can then connect using WiFiClientSecure. I also added password protection for further security, especially since it is now encrypted. Lastly, I created an entirely isolated network which could be accessed separately from the home network to reduce risks.
  • What was the biggest challenge you overcame in this lab?
    • Figuring out how to make PubSubClient and a Server play along together on one ESP8266. Turns out there was a much better library, ESP8266WebServer, which can handle requests much more quickly and won’t interfere with MQTT’s loop() function.
  • Please estimate the total time you spent on this lab and report.
    • About 7-8 hours. I made the mistake of not eating enough one night before working on this, and my brain pretty much shuts down when I do that.

Appendix

Figure 1: Picture of garage page

Figure 2: Useful Pinout Diagram

 

Lab5Stoplight.ino

#include <ESP8266WebServer.h>

#include <ESP8266WebServerSecure.h>

#include <ESP8266WebServerSecureAxTLS.h>

#include <ESP8266WebServerSecureBearSSL.h>

 

#include <PubSubClient.h>

#include <WiFiClientSecure.h>

//#include <ESP8266WiFi.h>

//#include <ESP8266mDNS.h>

//#include <WiFiUdp.h>

//#include <TimedAction.h>

 

const char* ssid = “”;           

const char* password = “”;              

const char* mqtt_server = “”;

const char* mqtt_topic = “GARAGE”;

const char* clientID = “Stoplight”;

const char* fingerprint = “3B 39 AD D0 7A F1 7F 83 4C 0F 68 D4 C7 08 B5 3F 35 BD 4D 36”;

 

int redPin = D5;

int yellowPin = D6;

int greenPin = D7;          

int relayPin = D3;

 

int freaky = LOW;

 

int garOpen = LOW;

 

int timediff = 0;

 

unsigned long lastiter = 0;

int redstate = 0;

 

String garry = “CLOSED”;

 

ESP8266WebServer server(80);

WiFiClientSecure client;

 

PubSubClient pubcli(mqtt_server, 8883, client); // 1883 is the listener port for the Broker

 

void setup() {

 Serial.begin(115200);

 delay(10);

 //set pins

 pinMode(greenPin, OUTPUT);

 pinMode(yellowPin, OUTPUT);

 pinMode(redPin, OUTPUT);

 pinMode(relayPin, OUTPUT);

 digitalWrite(greenPin, LOW);

 digitalWrite(yellowPin, LOW);

 digitalWrite(redPin, LOW);

 digitalWrite(relayPin, LOW);

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 

server.on(“/GARAGE=OPEN”,opened);

 server.on(“/GARAGE=CLOSE”,closed);

 server.on(“/”,render);  

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

if (client.verify(fingerprint,”hostname”)) {

   Serial.println(“certificate matches”);

 } else {

   Serial.println(“certificate doesn’t match”);

 }

 

 //set the message callback function, connect to MQTT broker, subscribe

 pubcli.setCallback(ReceivedMessage);

 if (pubcli.connect(clientID,”user”,”password”)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   while(!pubcli.connect(clientID,”user”,”password”)){

   Serial.println(“Connection to MQTT Broker failed…”);

   }

 }

 pubcli.subscribe(mqtt_topic);

 

 

}

 

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 

 char commd = (char)payload[0];

 

 //set the garage open variable

 if (commd == ‘O’) {

   garOpen = HIGH;

   garry = “OPEN”;

 }

 else if (commd == ‘C’) {

   garry = “CLOSED”;

   garOpen = LOW;

 }

 

 //if the garage is open, operate lights. If not, blackout

 if(garOpen == HIGH) {

 

   switch(commd){

     case ‘R’:

       digitalWrite(redPin,HIGH);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,LOW);

       break;

     case ‘Y’:

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,HIGH);

       digitalWrite(greenPin,LOW);

       break;

     case ‘G’:

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,HIGH);

       break;

     case ‘F’:

       freakout();

       break;

   }

 

 

 }

 else {

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,LOW);    

 }

 

}

 

void opened(){

digitalWrite(relayPin,HIGH);

String page = “<h1>GARAGE:”+garry+”</h1><a href=\”/GARAGE=OPEN\”><button>OPEN GARAGE</button></a><br><a href=\”/GARAGE=CLOSE\”><button>CLOSE GARAGE</button></a>”;

server.send(200,”text/html”,page);

}

 

void closed(){

digitalWrite(relayPin, LOW);

String page = “<h1>GARAGE:”+garry+”</h1><a href=\”/GARAGE=OPEN\”><button>OPEN GARAGE</button></a><br><a href=\”/GARAGE=CLOSE\”><button>CLOSE GARAGE</button></a>”;

server.send(200,”text/html”,page);

}

 

void render(){

String page = “<h1>GARAGE:”+garry+”</h1><a href=\”/GARAGE=OPEN\”><button>OPEN GARAGE</button></a><br><a href=\”/GARAGE=CLOSE\”><button>CLOSE GARAGE</button></a>”;

server.send(200,”text/html”,page);

}

 

void loop() {    

   pubcli.loop();

   server.handleClient();

}

 

void freakout(){

 if (millis() > lastiter) {

   digitalWrite(redPin, (redstate) ? HIGH : LOW);

   digitalWrite(yellowPin, (redstate) ? HIGH : LOW);

   digitalWrite(greenPin, (redstate) ? HIGH : LOW);

   redstate = !redstate;

   lastiter = millis()+500UL;

 }

}

 

Lab5Reed.ino

 

#include <PubSubClient.h>

#include <ESP8266WiFi.h>

#include <WiFiClientSecure.h>

//#include <ESP8266mDNS.h>

//#include <WiFiUdp.h>

 

const char* ssid = “”;           

const char* password = “”;

const char* mqtt_server = “”;

const char* mqtt_topic = “GARAGE”;

const char* clientID = “GarSense”;

const char* fingerprint = “3B 39 AD D0 7A F1 7F 83 4C 0F 68 D4 C7 08 B5 3F 35 BD 4D 36”;

 

//WiFiServer server(80);

WiFiClientSecure client;

 

PubSubClient pubcli(mqtt_server, 8883, client); // 1883 is the listener port for the Broker

 

int sensorPin = D5;

int cute = D7;

 

int gar = LOW;

 

void setup() {

 pinMode(sensorPin,INPUT_PULLUP);

 pinMode(cute,OUTPUT);

 Serial.begin(115200);

 

WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

//  server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

if (client.verify(fingerprint,”hostname”)) {

   Serial.println(“certificate matches”);

 } else {

   Serial.println(“certificate doesn’t match”);

 }

 

//set callback function, connect to broker

 pubcli.setCallback(ReceivedMessage);

   if (pubcli.connect(clientID,”user”,”password”)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   while(!pubcli.connect(clientID,”user”,”password”)){

   Serial.println(“Connection to MQTT Broker failed…”);

   }

 }

 

}

 

//the receivedmessage function here is for later, in case. Not needed by reed switch

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 

 // Handle the message we received

 // Here, we are only looking at the first character of the received message (payload[0])

 // If it is 0, turn the led off.

 // If it is 1, turn the led on.

 if ((char)payload[0] == ‘0’) {

   digitalWrite(cute, HIGH); // Notice for the HUZZAH Pin 0, HIGH is OFF and LOW is ON. Normally it is the other way around.

 }

 if ((char)payload[0] == ‘1’) {

   digitalWrite(cute, LOW);

 }

}

 

void loop() {

 //if the reed is closed but the garage variable is open, set to closed. Do opposite for open.

if(digitalRead(sensorPin)== LOW && gar == HIGH){

 if(pubcli.publish(mqtt_topic,”C”)) Serial.println(“Sent C”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”C”);

 }

 digitalWrite(cute, HIGH);

 gar = LOW;

}

else if(digitalRead(sensorPin) == HIGH && gar == LOW) {

 if(pubcli.publish(mqtt_topic,”O”)) Serial.println(“Sent O”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”O”);

 }

 digitalWrite(cute, LOW);

 gar = HIGH;

}

pubcli.loop();

}

 

Lab5Sonic.ino

 

#include <PubSubClient.h>

#include <NewPing.h>

#include <WiFiClientSecure.h>

#include <ESP8266WiFi.h>

//#include <ESP8266mDNS.h>

//#include <WiFiUdp.h>

 

const char* ssid = “”;           

const char* password = “”;

const char* host = “192.168.43.5”;  

const int httpPort = 80;

const char* mqtt_server = “”;

const char* mqtt_topic = “GARAGE”;

const char* clientID = “Sonic”;

const char* fingerprint = “3B 39 AD D0 7A F1 7F 83 4C 0F 68 D4 C7 08 B5 3F 35 BD 4D 36”;

 

int trigPin = D4;    // Trigger

int echoPin = D3;    // Echo

long duration, cm, inches;

 

int garOpen = LOW;

 

int red = 0;

int yellow = 0;

int green = 0;

int freak = 0;

 

int iters = 1;

int realinches = 0;

NewPing sonar(trigPin, echoPin, 360);

//WiFiServer server(80);

WiFiClientSecure client;

 

PubSubClient pubcli(mqtt_server, 8883, client); // 1883 is the listener port for the Broker

 

void setup() {

 //Serial Port begin

 Serial.begin (115200);

 //Define inputs and outputs

 pinMode(trigPin, OUTPUT);

 pinMode(echoPin, INPUT);

 

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 //server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

if (client.verify(fingerprint,”hostname”)) {

   Serial.println(“certificate matches”);

 } else {

   Serial.println(“certificate doesn’t match”);

 }

 

 //set mqtt callback, connect to broker and subscribe

   pubcli.setCallback(ReceivedMessage);

 if (pubcli.connect(clientID,”user”,”password”)) {

   Serial.println(“Connected to MQTT Broker!”);

   

 }

 else {

   while(!pubcli.connect(clientID,”user”,”password”)){

   Serial.println(“Connection to MQTT Broker failed…”);

   delay(1000);

   //pubcli.connect(clientID);

 }

 }

 pubcli.subscribe(mqtt_topic);

}

 

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 Serial.println(“received!”);

 

 //set garage open or closed variable

 if ((char)payload[0] == ‘O’) {

   garOpen = HIGH;

 }

 if ((char)payload[0] == ‘C’) {

   garOpen = LOW;

 }

}

 

void loop() {

 pubcli.loop();

 //if garage is open, operate distance measurement

 if (garOpen == HIGH){

 inches = sonar.convert_in(sonar.ping_median(10));

 

 Serial.print(inches);

 Serial.print(“in, “);

 Serial.print(cm);

 Serial.print(“cm”);

 Serial.println();

 

String url = “”;

 

if(inches > 24){

 if(pubcli.publish(mqtt_topic,”G”)) Serial.println(“Sent G”);

 else{

   pubcli.connect(clientID,”user”,”password”);

   delay(10);

   pubcli.publish(mqtt_topic,”G”);

 }

 green = 1;

}

else if (inches > 12){

 if(pubcli.publish(mqtt_topic,”Y”)) Serial.println(“Sent Y”);

 else{

   pubcli.connect(clientID,”user”,”password”);

   delay(10);

   pubcli.publish(mqtt_topic,”Y”);

 }

 yellow = 1;

}

else if (inches > 6) {

 if(pubcli.publish(mqtt_topic,”R”)) Serial.println(“Sent R”);

 else{

   pubcli.connect(clientID,”user”,”password”);

   delay(10);

   pubcli.publish(mqtt_topic,”G”);

 }

 red = 1;

}

else {

 if(pubcli.publish(mqtt_topic,”F”)) Serial.println(“Sent F”);

 else{

   pubcli.connect(clientID,”user”,”password”);

   delay(10);

   pubcli.publish(mqtt_topic,”F”);

 }

 freak = 1;

}

 

 }

 

}

Lab 4: Event Bus

Objective

  • Implement an Event Hub for publish/subscribe notifications between devices  
  • Develop a communications protocol for devices across the event bus  
  • Establish more complex conditions for the actuator involving multiple sensors

Requirements

For this lab, you will study Don Borthwick’s story in Case Study 4. While the specific requirements set forth in the narrative should be met, your objective in this lab is to shift from a system of two intercommunicating devices to a framework that could grow exponentially. This lab will require you to create a new device, and to make modifications to your devices from Labs 2 and 3.

Materials

The items used to complete this lab were:

  • 3x Arduino D1 Mini
  • 3x Micro USB Cable for power and data transfer
  • Raspberry Pi
  • Ultrasonic sensor
  • Red LED
  • Yellow LED
  • Green LED
  • Blue LED
  • 4x 330 Ohm resistors
  • Assorted male-male jumper wires for breadboard
  • 3x Breadboard

References

The following references were used in the completion of this lab. Please note that large chunks of code were used as the basis / foundation upon which I could build my particular use case, and can therefore be attributed to their developers:

 

Procedure

These instructions assume you have already soldered the pins to your D1 Mini. If not, complete that task first.

 

First D1 Mini: Stoplight

 

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.    
  2. Take a jumper cable and connect it from a ground (G) output of the Mini to one of the negative rails running along the sides of the breadboard. This will send the ground along the entire row of that breadboard.
  3. Connect three jumper cables to three GPIO pin outputs of your choice. In this example, we will be using D5, D6, and D7.
  4. Connect the other ends of those jumper cables on rows 23, 25, and 27 of your breadboard, as close to the side as possible. These are the positive leads for your LEDs.
  5. Insert the long end of each LED into a hole which is on the same row as a jumper cable from the previous step. You’ll note that there is conveniently an extra hole between each jumper cable from step 4; this is for the ground.
  6. Insert one end of each resistor into the negative rail you established in step 2. Insert the other end along a row where you placed the negative leg of an LED. Once this is done, you should have a positive and negative connection for each LED. 
  7. Plug the micro USB cable into the D1 Mini and insert it into the USB port on your machine. Your system should begin a basic driver installation. Take special note when the OS reports it is done installing; it should inform you of the COM Port the Mini is on.
  8. Obtain the Arduino IDE from https://www.arduino.cc/en/Main/Software, making sure to select your operating system and the latest software version. Install the IDE.
  9. Begin the process of adding the necessary modules for the board by navigating to File > Preferences in the IDE.
  10. Under “Additional Board URLs”, paste in http://arduino.esp8266.com/stable/package_esp8266com_index.json and press OK.
  11. Navigate to Tools > Board > Board Manager and locate “esp8266” from the list. Press install.
  12. Under Tools > Board, select “D1 & D1 Mini”.
  13. Under Tools > Port, select the COM port as reported by the OS in step 7.
  14. You should now be ready to load code. Copy and paste the code as found in the appendix of this document into the IDE. Modify the network SSID and password fields found near the beginning of the code accordingly.
  15. Verify that the code compiles by pressing the “checkmark” button in the upper-left.
  16. Once it has compiled, press the “upload” button (located next to the checkmark) to begin the upload process.
  17. Whenever the D1 mini has power and the specified network is available, it awaits signals from the ultrasonic sensor and responds accordingly.

 

Second D1 Mini: Ultrasonic Sensor

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.
  2. Mount the ultrasonic sensor across four rows (not columns) of pins.
  3. Connect the ground pin of the D1 to the ground pin of the sensor.
  4. Connect the VCC pin of the sensor to the 5V pin of the D1.
  5. Choose two GPIO pins for use with the pulse and echo pins of the sensor and connect them. Here, D4 and D3 were chosen.
  6. Follow steps 7-16 of the previous D1 mini to upload the corresponding code to it.
  7. Whenever the D1 mini has power and the specified network is available, it will send signals to the stoplight.

Third D1 Mini: Reed Switch

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.
  2. Connect an LED across two rows of the breadboard.
  3. Connect a jumper from the positive lead of the LED to a GPIO pin. We use D7 here.
  4. Connect a resistor from the negative lead of the LED to the negative side rail of the breadboard.
  5. Connect a jumper from the ground pin of the D1 mini to the ground rail.
  6. Connect one end of the reed switch to a GPIO pin. We use D5 here.
  7. Connect the other end to the ground rail of the breadboard.
  8. Follow steps 7-16 of the first D1 mini to upload the corresponding code to it.
  9. Whenever the reed switch is open, it will send a message via MQTT to the other devices indicating the garage door is “open” and turn off the LED. When it is closed, it will send a “closed” message and turn on the LED.

 

Raspberry Pi

  1. Start up the Pi and connect it to the same wireless network the D1 minis will be on.
  2. Install the MQTT client with these commands:
    1. sudo apt-get install mosquitto -y
    2. sudo apt-get install mosquitto-clients -y
  3. Open the file /etc/mosquitto/mosquitto.conf for editing.
  4. Add the following line to the bottom of the file and save:
    1. listener 1883
  5. Restart the service with the following command:
    1. sudo service mosquitto restart
  6. Subscribe the Pi to the topic with the following command:
    1. mosquitto_sub -d -t GARAGE
  7. The Pi is now set to listen.

 

Overall Picture

The MQTT broker sits and waits for all incoming messages. While the reed switch is closed, no signals are sent aside from the signal that the switch is closed, and the LED is turned on. When the switch is closed, a new message is sent indicating the switch is closed, which is then broadcast to the other two devices. The Ultrasonic sensor reads this message and then begins pinging for distance. It sends the appropriate message back to the MQTT topic depending on this distance. The stoplight then reads in this message alongside the open/closed information to light the correct LEDs. If it receives a “Closed” message, all LEDs turn off.

The system was designed in this way because it seemed like the most efficient method for directing traffic. No receiving needs to be done by the reed switch, as it is the “catalyst” for the rest of the system. The ultrasonic sensor needs to know when to operate, but also needs to instruct the stoplight, so two-way communication is necessary. The stoplight only needs to be told what to do, so no transmissions are necessary.

 

Thought Questions

  • How does the communication between devices change with the shift to using an event hub? How does this facilitate greater scalability?
    • It changes greatly; this type of communication is so much more simple. There is no need for HTTP calls or servers; each device simply acts as a wifi client and subscribes to a channel. Adding devices is as simple as subscribing to this MQTT channel, which makes it infinitely scalable without any major adjustment to backend code.
  • 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?
    • Direct communication does not have to rely on any sort of network or wireless protocol; it runs indefinitely so long as there is power. However, this limits the distance signals can be traveled by the length of cable or wire run between the two. The event hub has the downside of relying on a network and its uptime, but carries a huge advantage of being able to separate sensors and actuators by great distances so long as there is a network connection. In this particular garage situation, either would work since it’s a small room, but the most convenient solution is without question the event hub.
  • What was the biggest challenge you overcame in this lab?
    • Remembering that a device needs to subscribe to a topic and not just to the broker for it to, you know, actually work.
  • Please estimate the total time you spent on this lab and report.
    • Around three hours.

 

Appendix

Figure 1: Useful Pinout Diagram

 

Lab4Stoplight.ino

 

#include <PubSubClient.h>

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

//#include <TimedAction.h>

 

const char* ssid = “x”;           

const char* password = “x”;              

const char* mqtt_server = “192.168.43.3”;

const char* mqtt_topic = “GARAGE”;

const char* clientID = “Stoplight”;

 

int redPin = D5;

int yellowPin = D6;

int greenPin = D7;          

 

int freaky = LOW;

 

int garOpen = LOW;

 

int timediff = 0;

 

unsigned long lastiter = 0;

int redstate = 0;

 

WiFiServer server(80);

WiFiClient client;

 

PubSubClient pubcli(mqtt_server, 1883, client); // 1883 is the listener port for the Broker

 

void setup() {

 Serial.begin(115200);

 delay(10);

 //set pins

 pinMode(greenPin, OUTPUT);

 pinMode(yellowPin, OUTPUT);

 pinMode(redPin, OUTPUT);

 digitalWrite(greenPin, LOW);

 digitalWrite(yellowPin, LOW);

 digitalWrite(redPin, LOW);

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

 //set the message callback function, connect to MQTT broker, subscribe

 pubcli.setCallback(ReceivedMessage);

 if (pubcli.connect(clientID)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   while(!pubcli.connect(clientID)){

   Serial.println(“Connection to MQTT Broker failed…”);

   }

 }

 pubcli.subscribe(mqtt_topic);

}

 

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 

 char commd = (char)payload[0];

 

 //set the garage open variable

 if (commd == ‘O’) {

   garOpen = HIGH;

 }

 else if (commd == ‘C’) {

   garOpen = LOW;

 }

 

 //if the garage is open, operate lights. If not, blackout

 if(garOpen == HIGH) {

 

   switch(commd){

     case ‘R’:

       digitalWrite(redPin,HIGH);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,LOW);

       break;

     case ‘Y’:

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,HIGH);

       digitalWrite(greenPin,LOW);

       break;

     case ‘G’:

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,HIGH);

       break;

     case ‘F’:

       freakout();

       break;

   }

 

 

 }

 else {

       digitalWrite(redPin,LOW);

       digitalWrite(yellowPin,LOW);

       digitalWrite(greenPin,LOW);    

 }

 

}

void loop() {  

   pubcli.loop();

}

 

void freakout(){

 if (millis() > lastiter) {

   digitalWrite(redPin, (redstate) ? HIGH : LOW);

   digitalWrite(yellowPin, (redstate) ? HIGH : LOW);

   digitalWrite(greenPin, (redstate) ? HIGH : LOW);

   redstate = !redstate;

   lastiter = millis()+500UL;

 }

}

 

Lab4Sonic.ino

 

#include <PubSubClient.h>

#include <NewPing.h>

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

 

const char* ssid = “x”;           

const char* password = “x”;

const char* host = “192.168.43.5”;  

const int httpPort = 80;

const char* mqtt_server = “192.168.43.3”;

const char* mqtt_topic = “GARAGE”;

const char* clientID = “Sonic”;

 

int trigPin = D4;    // Trigger

int echoPin = D3;    // Echo

long duration, cm, inches;

 

int garOpen = LOW;

 

int red = 0;

int yellow = 0;

int green = 0;

int freak = 0;

 

int iters = 1;

int realinches = 0;

NewPing sonar(trigPin, echoPin, 360);

WiFiServer server(80);

WiFiClient client;

 

PubSubClient pubcli(mqtt_server, 1883, client); // 1883 is the listener port for the Broker

 

void setup() {

 //Serial Port begin

 Serial.begin (115200);

 //Define inputs and outputs

 pinMode(trigPin, OUTPUT);

 pinMode(echoPin, INPUT);

 

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

 //set mqtt callback, connect to broker and subscribe

   pubcli.setCallback(ReceivedMessage);

 if (pubcli.connect(clientID)) {

   Serial.println(“Connected to MQTT Broker!”);

   

 }

 else {

   while(!pubcli.connect(clientID)){

   Serial.println(“Connection to MQTT Broker failed…”);

   delay(1000);

   //pubcli.connect(clientID);

 }

 }

 pubcli.subscribe(mqtt_topic);

}

 

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 Serial.println(“received!”);

 

 //set garage open or closed variable

 if ((char)payload[0] == ‘O’) {

   garOpen = HIGH;

 }

 if ((char)payload[0] == ‘C’) {

   garOpen = LOW;

 }

}

 

void loop() {

 pubcli.loop();

 //if garage is open, operate distance measurement

 if (garOpen == HIGH){

 inches = sonar.convert_in(sonar.ping_median(10));

 

 Serial.print(inches);

 Serial.print(“in, “);

 Serial.print(cm);

 Serial.print(“cm”);

 Serial.println();

 

String url = “”;

 

if(inches > 24){

 if(pubcli.publish(mqtt_topic,”G”)) Serial.println(“Sent G”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”G”);

 }

 green = 1;

}

else if (inches > 12){

 if(pubcli.publish(mqtt_topic,”Y”)) Serial.println(“Sent Y”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”Y”);

 }

 yellow = 1;

}

else if (inches > 6) {

 if(pubcli.publish(mqtt_topic,”R”)) Serial.println(“Sent R”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”G”);

 }

 red = 1;

}

else {

 if(pubcli.publish(mqtt_topic,”F”)) Serial.println(“Sent F”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”F”);

 }

 freak = 1;

}

 

 }

 

}

 

Lab4Reed.ino

 

#include <PubSubClient.h>

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

 

const char* ssid = “x”;           

const char* password = “x”;

const char* mqtt_server = “192.168.43.3”;

const char* mqtt_topic = “GARAGE”;

const char* clientID = “GarSense”;

 

WiFiServer server(80);

WiFiClient client;

 

PubSubClient pubcli(mqtt_server, 1883, client); // 1883 is the listener port for the Broker

 

int sensorPin = D5;

int cute = D7;

 

int gar = LOW;

 

void setup() {

 pinMode(sensorPin,INPUT_PULLUP);

 pinMode(cute,OUTPUT);

 Serial.begin(115200);

 

WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

//set callback function, connect to broker

 pubcli.setCallback(ReceivedMessage);

 if (pubcli.connect(clientID)) {

   Serial.println(“Connected to MQTT Broker!”);

 }

 else {

   Serial.println(“Connection to MQTT Broker failed…”);

 }

 

}

 

//the receivedmessage function here is for later, in case. Not needed by reed switch

void ReceivedMessage(char* topic, byte* payload, unsigned int length) {

 // Output the first character of the message to serial (debug)

 Serial.println((char)payload[0]);

 

 // Handle the message we received

 // Here, we are only looking at the first character of the received message (payload[0])

 // If it is 0, turn the led off.

 // If it is 1, turn the led on.

 if ((char)payload[0] == ‘0’) {

   digitalWrite(cute, HIGH); // Notice for the HUZZAH Pin 0, HIGH is OFF and LOW is ON. Normally it is the other way around.

 }

 if ((char)payload[0] == ‘1’) {

   digitalWrite(cute, LOW);

 }

}

 

void loop() {

 //if the reed is closed but the garage variable is open, set to closed. Do opposite for open.

if(digitalRead(sensorPin)== LOW && gar == HIGH){

 if(pubcli.publish(mqtt_topic,”C”)) Serial.println(“Sent C”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”C”);

 }

 digitalWrite(cute, HIGH);

 gar = LOW;

}

else if(digitalRead(sensorPin) == HIGH && gar == LOW) {

 if(pubcli.publish(mqtt_topic,”O”)) Serial.println(“Sent O”);

 else{

   pubcli.connect(clientID);

   delay(10);

   pubcli.publish(mqtt_topic,”O”);

 }

 digitalWrite(cute, LOW);

 gar = HIGH;

}

pubcli.loop();

}

 

Lab 3

Lab 3: Sensor

Code

The code and online version of this report can be found at http://www.b3audioproductions.com

Objective

The purposes of this lab are to:  Build an IoT sensor using GPIO pins for inputs  Establish a machine-to-machine (M2M) communication protocol  Design an IoT interaction between a sensor and an actuator.

Requirements

For this lab, you will study Don Borthwick’s story in Case Study 3. While the specific requirements set forth in the narrative should be met, your objective in this lab is to develop a system of two devices that communicate to accomplish the objective. This lab will require you to create a new device, and to make modifications to your device from Lab 2.

Materials

The items used to complete this lab were:

  • 2x Arduino D1 Mini
  • 2x Micro USB Cable for power and data transfer
  • Ultrasonic sensor
  • Red LED
  • Yellow LED
  • Green LED
  • Three 330 Ohm resistors
  • Assorted male-male jumper wires for breadboard
  • Breadboard

References

The following references were used in the completion of this lab. Please note that large chunks of code were used as the basis / foundation upon which I could build my particular use case, and can therefore be attributed to their developers:

 

Procedure

These instructions assume you have already soldered the pins to your D1 Mini. If not, complete that task first.

First D1 Mini: Stoplight

 

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.    
  2. Take a jumper cable and connect it from a ground (G) output of the Mini to one of the negative rails running along the sides of the breadboard. This will send the ground along the entire row of that breadboard.
  3. Connect three jumper cables to three GPIO pin outputs of your choice. In this example, we will be using D5, D6, and D7.
  4. Connect the other ends of those jumper cables on rows 23, 25, and 27 of your breadboard, as close to the side as possible. These are the positive leads for your LEDs.
  5. Insert the long end of each LED into a hole which is on the same row as a jumper cable from the previous step. You’ll note that there is conveniently an extra hole between each jumper cable from step 4; this is for the ground.
  6. Insert one end of each resistor into the negative rail you established in step 2. Insert the other end along a row where you placed the negative leg of an LED. Once this is done, you should have a positive and negative connection for each LED. 
  7. Plug the micro USB cable into the D1 Mini and insert it into the USB port on your machine. Your system should begin a basic driver installation. Take special note when the OS reports it is done installing; it should inform you of the COM Port the Mini is on.
  8. Obtain the Arduino IDE from https://www.arduino.cc/en/Main/Software, making sure to select your operating system and the latest software version. Install the IDE.
  9. Begin the process of adding the necessary modules for the board by navigating to File > Preferences in the IDE.
  10. Under “Additional Board URLs”, paste in http://arduino.esp8266.com/stable/package_esp8266com_index.json and press OK.
  11. Navigate to Tools > Board > Board Manager and locate “esp8266” from the list. Press install.
  12. Under Tools > Board, select “D1 & D1 Mini”.
  13. Under Tools > Port, select the COM port as reported by the OS in step 7.
  14. You should now be ready to load code. Copy and paste the code as found in the appendix of this document into the IDE. Modify the network SSID and password fields found near the beginning of the code accordingly.
  15. Verify that the code compiles by pressing the “checkmark” button in the upper-left.
  16. Once it has compiled, press the “upload” button (located next to the checkmark) to begin the upload process.
  17. Whenever the D1 mini has power and the specified network is available, it awaits signals from the ultrasonic sensor and responds accordingly.

 

Second D1 Mini: Ultrasonic Sensor

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.
  2. Mount the ultrasonic sensor across four rows (not columns) of pins.
  3. Connect the ground pin of the D1 to the ground pin of the sensor.
  4. Connect the VCC pin of the sensor to the 5V pin of the D1.
  5. Choose two GPIO pins for use with the pulse and echo pins of the sensor and connect them. Here, D4 and D3 were chosen.
  6. Follow steps 7-16 of the previous D1 mini to upload the corresponding code to it.
  7. Whenever the D1 mini has power and the specified network is available, it will send signals to the stoplight.

Thought Questions

 

  • Think of the interaction between your devices. How well would this scale to multiple devices? Is it easy to add another sensor? Another actuator?

 

      • This should scale rather well on both ends, since you’d really only have to specify additional addresses to send to or set up another listening address. My concern with adding more sensors would be the potential to overload the actuator with HTTP requests. Some sort of queue may need to be implemented to keep that under control.

 

  • What are strengths and weaknesses of the tennis-ball-on-a-string system that Don had originally? What are strengths and weaknesses of the IoT system that he developed? What enhancements would you suggest?

 

      • The tennis ball system was simple to both set up and troubleshoot, did not require any sort of electricity, and was inexpensive to implement. However, it was vulnerable to failure because of outside forces like kids with bats. The IoT system has more vulnerability against vandalism, though it’s still possible it could be destroyed. It also has much more precision and flexibility in measuring distance by offering distinct warnings. On the downside, it’s expensive, requires power, and is much more complex to set up and troubleshoot.

 

  • What was the biggest challenge you overcame in this lab?

 

      • The biggest was probably getting the response time trimmed down. Initially it would take a good 5-10 seconds for the stoplight to respond to readings, but I simplified the code down to cut out any unnecessary calls so that the server could spend more time listening for light requests.

 

  • Please estimate the total time you spent on this lab and report.

 

    • I’d say about 4.5 hours, with the majority of that working on speed of response as well as the consistency of the supersonic readings.

Appendix

Figure 1: Useful Pinout Diagram

 

Lab3.ino: Sensor code

 

#include <NewPing.h>

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

 

const char* ssid = “xxxxx”;           

const char* password = “xxxxx”;

const char* host = “192.168.43.5”;  

const int httpPort = 80;

 

int trigPin = D4;    // Trigger

int echoPin = D3;    // Echo

long duration, cm, inches;

 

int red = 0;

int yellow = 0;

int green = 0;

int freak = 0;

 

int iters = 1;

int realinches = 0;

NewPing sonar(trigPin, echoPin, 360);

WiFiServer server(80);

WiFiClient client;

void setup() {

 //Serial Port begin

 Serial.begin (115200);

 //Define inputs and outputs

 pinMode(trigPin, OUTPUT);

 pinMode(echoPin, INPUT);

 

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

 

}

void loop() {

 inches = sonar.convert_in(sonar.ping_median(10));

 

 Serial.print(inches);

 Serial.print(“in, “);

 Serial.print(cm);

 Serial.print(“cm”);

 Serial.println();

 

String url = “”;

 

if(inches > 24){

 url = “/GREEN=ON”;

 green = 1;

}

else if (inches > 12){

 url = “/YELLOW=ON”;

 yellow = 1;

}

else if (inches > 6) {

 url = “/RED=ON”;

 red = 1;

}

else {

 url = “/FREAKY=ON”;

 freak = 1;

}

 

Serial.print(“Requesting URL: “);

 Serial.println(url);

 

 // This will send the request to the server

 client.connect(host, httpPort);

 client.print(String(“GET “) + url + ” HTTP/1.1\r\n” +

              “Host: ” + host + “\r\n” +

              “Connection: close\r\n\r\n”);

}

 

Lab3Stoplight.ino: Stoplight code

 

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

//#include <TimedAction.h>

 

const char* ssid = “xxxxxx”;           

const char* password = “xxxxxx”;              

 

int redPin = D5;

int yellowPin = D6;

int greenPin = D7;          

 

int freaky = LOW;

 

int timer;

 

int timediff = 0;

 

unsigned long lastiter = 0;

int redstate = 0;

 

WiFiServer server(80);

WiFiClient client;

String request;

 

void setup() {

 Serial.begin(115200);

 delay(10);

 pinMode(greenPin, OUTPUT);

 pinMode(yellowPin, OUTPUT);

 pinMode(redPin, OUTPUT);

 digitalWrite(greenPin, LOW);

 digitalWrite(yellowPin, LOW);

 digitalWrite(redPin, LOW);

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

}

 

void loop() {

 

timer = millis();   

 

// Check if a client has connected

 client = server.available();

 if (!client) {

   return;

 }

 

 // Wait until the client sends some data

 Serial.println(“new client”);

 while(!client.available()){

   delay(1);

 }

 

 // Read the first line of the request

 request = client.readStringUntil(‘\r’);

 Serial.println(request);

 client.flush();

 // Match the request

   //resetlights();

 

 if (request.indexOf(“/GREEN=ON”) != -1) {

   digitalWrite(greenPin, HIGH);

   digitalWrite(redPin, LOW);

   digitalWrite(yellowPin, LOW);

 }

 else if (request.indexOf(“/YELLOW=ON”) != -1){

   digitalWrite(yellowPin, HIGH);

   digitalWrite(redPin, LOW);

   digitalWrite(greenPin, LOW);

 }

 else if (request.indexOf(“/RED=ON”) != -1){

   digitalWrite(redPin, HIGH);

   digitalWrite(yellowPin, LOW);

   digitalWrite(greenPin, LOW);

 }

 else if (request.indexOf(“/FREAKY=ON”) != -1){

   freakout();

 }

 else {

   int silly = 0;

 }

 

 // Return the response

 client.println(“HTTP/1.1 200 OK”);

 client.println(“Content-Type: text/html”);

 client.println(“”);

 client.println(“<!DOCTYPE HTML>”);

 client.println(“<html>”);

 client.println(“</html>”);

 delay(1);

 Serial.println(“Client disconnected”);

 Serial.println(“”);

}

 

void freakout(){

 if (millis() > lastiter) {

   digitalWrite(redPin, (redstate) ? HIGH : LOW);

   digitalWrite(yellowPin, (redstate) ? HIGH : LOW);

   digitalWrite(greenPin, (redstate) ? HIGH : LOW);

   redstate = !redstate;

   lastiter = millis()+500UL;

 }

}

 

Stoplight v2

Objective

The purposes of this lab are to:  Reinforce enumerating requirements from use cases and user stories  Become familiar with the Arduino platform and its programming methodologies.  Program an Arduino-based microcontroller to use the GPIO pins to control LEDs.  Develop iteratively, beginning with a minimum viable product and add functionality until the requirements are met.

 

Requirements

For this lab, you will study Don Borthwick’s story in Case Study 2, and identify the requirements that he set forth for his prototype. You should then deliver a working project that meets those specifications. Part of your grade will be how well you enumerate the requirements, based on the limited information provided to you in the case study.

 

Materials

The items used to complete this lab were:

  • Arduino D1 Mini
  • Micro USB Cable for power and data transfer
  • Red LED
  • Yellow LED
  • Green LED
  • Three 330 Ohm resistors
  • Assorted male-male jumper wires for breadboard
  • Breadboard

 

References

The following references were used in the completion of this lab. Please note that large chunks of code were used as the basis / foundation upon which I could build my particular use case, and can therefore be attributed to their developers:

 

 

Procedure

These instructions assume you have already soldered the pins to your D1 Mini. If not, complete that task first.

 

  1. Mount the D1 Mini to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.    
  2. Take a jumper cable and connect it from a ground (G) output of the Mini to one of the negative rails running along the sides of the breadboard. This will send the ground along the entire row of that breadboard.
  3. Connect three jumper cables to three GPIO pin outputs of your choice. In this example, we will be using D5, D6, and D7.
  4. Connect the other ends of those jumper cables on rows 23, 25, and 27 of your breadboard, as close to the side as possible. These are the positive leads for your LEDs.
  5. Insert the long end of each LED into a hole which is on the same row as a jumper cable from the previous step. You’ll note that there is conveniently an extra hole between each jumper cable from step 4; this is for the ground.
  6. Insert one end of each resistor into the negative rail you established in step 2. Insert the other end along a row where you placed the negative leg of an LED. Once this is done, you should have a positive and negative connection for each LED. See the picture for confirmation.
  7. Plug the micro USB cable into the D1 Mini and insert it into the USB port on your machine. Your system should begin a basic driver installation. Take special note when the OS reports it is done installing; it should inform you of the COM Port the Mini is on.
  8. Obtain the Arduino IDE from https://www.arduino.cc/en/Main/Software, making sure to select your operating system and the latest software version. Install the IDE.
  9. Begin the process of adding the necessary modules for the board by navigating to File > Preferences in the IDE.
  10. Under “Additional Board URLs”, paste in http://arduino.esp8266.com/stable/package_esp8266com_index.json and press OK.
  11. Navigate to Tools > Board > Board Manager and locate “esp8266” from the list. Press install.
  12. Under Tools > Board, select “D1 & D1 Mini”.
  13. Under Tools > Port, select the COM port as reported by the OS in step 7.
  14. You should now be ready to load code. Copy and paste the code as found in the appendix of this document into the IDE. Modify the network SSID and password fields found near the beginning of the code accordingly.
  15. Verify that the code compiles by pressing the “checkmark” button in the upper-left.
  16. Once it has compiled, press the “upload” button (located next to the checkmark) to begin the upload process.
  17. Once that has happened, click the “View Serial Output” button, located in the upper-right of the IDE. This will open the serial output produced by the Mini and allow you to see the Mini’s IP address.
  18. Navigate to the IP address from a browser on the same network and utilize the buttons on the screen to operate the stoplight.

 

Thought Questions

 

  • What are some key differences between developing this lab on a Raspberry Pi, and developing on Arduino?

 

      • One of the most major differences is simplicity, so to speak. The Arduino simply turns off and on, has no OS, and just executes the code it has in its memory. This leads to very quick startups, as there are no frills. Along that same note, however, that simplicity can get rather frustrating. The D1 Mini is not capable of multiple threads or processes, so the developer is forced to get creative with running multiple tasks at once all inside the primary execution loop. Aside from these points, the wiring and voltages are essentially identical. From a more obvious standpoint, the Arduino allows for one coding language and nothing else: C. The RPi, however, allows a developer to use virtually any language in existence, so long as it is compatible with the Pi’s ARM architecture.

 

  • What are the strengths and trade-offs of each of these platforms?

 

      • I addressed many of these in the previous question, but the Arduino is excellent due to its low power usage, no frills, and straightforward execution. If you have a very direct process to complete, where A leads to B and no complex computations or threading needs to take place, then absolutely go for the Arduino. If you need more versatility, including onboard sound and video, threading and more, go for the Pi, but at the expense of complexity and startup times. So much more can go wrong with a Pi because of all it is capable of, whereas an Arduino has much less it needs to concern itself with.

 

  • How familiar were you with the Arduino platform prior to this lab?

 

      • I had worked with a handful of them before, so it really wasn’t anything new. Regardless, any level of familiarity with C/C++ is mostly what you need to get moving on the platform.

 

  • What was the biggest challenge you overcame in this lab?

 

      • The classic threading/multitasking issue. I spent multiple hours solely trying to figure out how to keep the stoplight function from blocking everything else, including the webserver. Executing the stoplight would prevent the server from listening to further requests, so the web page and function would end up in a permanent locked state until new code was loaded onto the board. I eventually solved this issue using millis and timers.

 

  • Please estimate the total time you spent on this lab and report.

 

    • Somewhere in the vicinity of five hours, with a little more than two of those spent solely on the blocking issue I just described.

 

Appendix

Figure 1: Useful Pinout Diagram

Code: Lab2.ino. Again, note that the foundational code here was written by its respective developers and (aside from the WiFi setup functions) was heavily modified and expanded upon for my use case.

 

#include <ESP8266WiFi.h>

#include <ESP8266mDNS.h>

#include <WiFiUdp.h>

 

const char* ssid = “<the ssid of my phone>”;           

const char* password = “<the password of my phone’s network>”;              

 

//set up pin numbers for each lights

int redPin = D5;

int yellowPin = D6;

int greenPin = D7;          

 

//these variables track the status of each light

int greenValue = LOW;

int yellowValue = LOW;

int redValue = LOW;

int stoplValue = LOW;

 

//set variables which track where the light currently is if on stoplight mode

int yellowcycle = 0;

int greencycle = 0;

int redcycle = 0;

 

//declare time variable to track millis

int timer;

 

//declare time variable to track time elapsed for stoplight function

int timediff = 0;

 

WiFiServer server(80);

WiFiClient client;

String request;

 

void setup() {

 Serial.begin(115200);

 delay(10);

//set pin modes and voltages initially

 pinMode(greenPin, OUTPUT);

 pinMode(yellowPin, OUTPUT);

 pinMode(redPin, OUTPUT);

 digitalWrite(greenPin, LOW);

 digitalWrite(yellowPin, LOW);

 digitalWrite(redPin, LOW);

 // Connect to WiFi network

 Serial.println();

 Serial.println();

 Serial.print(“Connecting to “);

 Serial.println(ssid);

 WiFi.mode(WIFI_STA);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {

   delay(500);

   Serial.print(“.”);

 }

 Serial.println(“”);

 Serial.println(“WiFi connected”);

 // Start the server

 server.begin();

 Serial.println(“Server started”);

 // Print the IP address

 Serial.print(“Use this URL : “);

 Serial.print(“http://”);

 Serial.print(WiFi.localIP());

 Serial.println(“/”);

}

 

void loop() {

 

//get current time for tracking with use of stoplight function

timer = millis();   

 

//make sure a client is connected, check the URL to know what to do, render the HTML page   

getServerStatus();

getRequest();

renderHTML();

 

//If stoplight mode is engaged, check the stoplight to see if it needs to change colors

if(stoplValue==HIGH){

  checkStoplight();

}

 

}

 

void checkStoplight(){

 

//get the time elapsed since the last change

int gettime = timer – timediff;

 

//check if each light color has executed or not, and act accordingly

if(redcycle = 0){

digitalWrite(redPin, HIGH);

redcycle = 1;

return;

}

else if(gettime > 5000 && greencycle == 0){

 digitalWrite(redPin, LOW);

 digitalWrite(greenPin, HIGH);

 greencycle = 1;

 timediff = timer;

 return;

}

else if(gettime > 10000 && yellowcycle == 0)

{

 digitalWrite(greenPin, LOW);

 digitalWrite(yellowPin, HIGH);

 yellowcycle = 1;

 timediff = timer;

 return;

}

else if (gettime > 3000 && yellowcycle == 1)

{

  digitalWrite(yellowPin, LOW);

  digitalWrite(redPin, HIGH);

  redcycle = 1;

  greencycle = 0;

  yellowcycle = 0;

  timediff = timer;

  return;

}

 

}

 

void resetlights(){

   digitalWrite(greenPin, LOW);

   digitalWrite(yellowPin, LOW);

   digitalWrite(redPin, LOW);

   greenValue = LOW;

   yellowValue = LOW;

   redValue = LOW;

   return;

}

 

void getServerStatus(){

 

 // Check if a client has connected

 client = server.available();

 if (!client) {

   return;

 }

 

 // Wait until the client sends some data

 Serial.println(“new client”);

 while(!client.available()){

   delay(1);

 }

}

 

void getRequest(){

// Read the first line of the request

 request = client.readStringUntil(‘\r’);

 Serial.println(request);

 client.flush();

 // Look at the requested page and act on the URL accordingly, changing lights or modes

 if (request.indexOf(“/GREEN=ON”) != -1) {

   if(stoplValue==HIGH){

     stoplValue=LOW;

     resetlights();

   }

   digitalWrite(greenPin, HIGH);

   greenValue = HIGH;

 }

 else if (request.indexOf(“/GREEN=OFF”) != -1){

   if(stoplValue==HIGH){

     stoplValue=LOW;

     resetlights();

   }

   digitalWrite(greenPin, LOW);

   greenValue = LOW;

 }

 else if (request.indexOf(“/YELLOW=ON”) != -1){

   if(stoplValue==HIGH){

     stoplValue=LOW;

     resetlights();

   }

   digitalWrite(yellowPin, HIGH);

   yellowValue = HIGH;

 }

 else if (request.indexOf(“/YELLOW=OFF”) != -1){

   if(stoplValue==HIGH){

     stoplValue=LOW;

     resetlights();

   }

   digitalWrite(yellowPin, LOW);

   yellowValue = LOW;

 }

 else if (request.indexOf(“/RED=ON”) != -1){

   if(stoplValue==HIGH){

     stoplValue=LOW;

     resetlights();

   }

   digitalWrite(redPin, HIGH);

   redValue = HIGH;

 }

 else if (request.indexOf(“/RED=OFF”) != -1){

   if(stoplValue==HIGH){

     stoplValue=LOW;

     resetlights();

   }

   digitalWrite(redPin, LOW);

   redValue = LOW;

 }

 else if (request.indexOf(“/STOPLIGHT=ON”) != -1){

   resetlights();

   stoplValue=HIGH;

 }

 else if (request.indexOf(“/STOPLIGHT=OFF”) != -1){

   resetlights();

   stoplValue=LOW;

 }

 else if (request.indexOf(“/ALL=OFF”) != -1){

   resetlights();

   stoplValue=LOW;

 }

 else {

   int silly = 0;

 }

}

 

void renderHTML(){

 // Return an HTML response and print the whole page out with buttons conditional on status, set URL

 client.println(“HTTP/1.1 200 OK”);

 client.println(“Content-Type: text/html”);

 client.println(“”);

 client.println(“<!DOCTYPE HTML>”);

 client.println(“<html>”);

 client.println(“<h1>SUPER STOPLIGHT TIME</h1>”);

 client.println(“<br><br>”);

 client.println(” <a href=\”/GREEN=”);

 if(greenValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“\”><button>TURN GREEN “);

 if(greenValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“</button></a><br>”);

 

 client.println(” <a href=\”/YELLOW=”);

 if(yellowValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“\”><button>TURN YELLOW “);

 if(yellowValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“</button></a><br>”);

 

 client.println(” <a href=\”/RED=”);

 if(redValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“\”><button>TURN RED “);

 if(redValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“</button></a><br>”);

 

 client.println(” <a href=\”/STOPLIGHT=”);

 if(stoplValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“\”><button>STOPLIGHT TIME “);

 if(stoplValue == HIGH) {

   client.print(“OFF”);  

 } else {

   client.print(“ON”);

 }

 client.println(“</button></a><br>”);

 

 client.println(” <a href=\”/ALL=OFF\”><button>ALL OFF</button></a><br>”);

 client.println(“</html>”);

 delay(1);

 Serial.println(“Client disconnected”);

 Serial.println(“”);

}

 

Web Page Screenshot

Lab 1

Objective

The purposes of this lab are to:

  • Learn to enumerate requirements from use cases and user stories
  • Learn to utilize the general purpose input/output (GPIO) pins on the Raspberry Pi to control LEDs.
  • Learn to develop a minimum viable product, and deliver new functionality through subsequent updates until the requirements are met, and all of the deliverables are acceptable.
  • Learn to use Github for progressive code commits and version tracking.

 

Materials

The items used to complete this lab were:

  • Raspberry Pi 3
  • Sparkfun Pi Wedge and ribbon cable
  • Red LED
  • Yellow LED
  • Green LED
  • Three 330 Ohm resistors
  • Assorted male-male jumper wires for breadboard
  • Breadboard

 

References

I used the following references in this lab. All of them concern smaller problems I was having with remembering specific syntax or how certain functions work.

Procedures

  • Connect the Sparkfun Pi Wedge to the Raspberry PI pins using the provided ribbon cable, and mount the T-shaped portion to the breadboard, straddling the break in the middle of the breadboard which indicates a break in the circuit of the board.
  • Take a jumper cable and connect it from a ground (GND) output of the Pi Wedge to one of the negative rails running along the sides of the breadboard. This will send the ground along the entire row of that breadboard.
  • Connect three jumper cables to three GPIO pin outputs of your choice. In this example, we will be using G17, 16, and 13.
  • Connect the other ends of those jumper cables on rows 23, 25, and 27 of your breadboard, as close to the side as possible. These are the positive leads for your LEDs.
  • Insert the long end of each LED into a hole which is on the same row as a jumper cable from the previous step. You’ll note that there is conveniently an extra hole between each jumper cable from step 4; this is for the ground.
  • Insert one end of each resistor into the negative rail you established in step 2. Insert the other end along a row where you placed the negative leg of an LED. Once this is done, you should have a positive and negative connection for each LED.
  • Power on your RPi. It is assumed you have already installed an operating system such as Raspbian.
  • Ensure that the pins are prepared for output by running the command gpio -g mode <pin number> out for each of the pins listed in step three.
  • Install the Apache web server by issuing the command sudo apt-get install apache2.
  • Enable CGI (the protocol necessary for running our light-controlling scripts from a browser) by running the command sudo a2enmod cgi
  • Create a directory for scripts by running the command sudo mkdir /var/www/html/cgi-bin
  • Navigate to the directory just created and create script files by issuing the command sudo touch <file name>, with these file names:
    • alloff.py
    • red.py
    • green.py
    • yellow.py
    • status.py
    • stoplight.py
    • stoppython.py
  • Open /var/www/html/index.html in a file editor (sudo nano <file name>) and erase its contents, replacing them with the code for index.html found in the appendix.
  • Fill each of the files mentioned in step 11 with their respective contents from the appendix.
  • Make each script from step 11 executable by navigating to the cgi-bin directory and running the command sudo chmod +x *
  • Navigate to the web page locally on the Pi by opening up a browser to localhost/
  • Press the buttons on the screen to operate the stoplight

 

Thought Questions

  • What language did you choose for implementing this project? Why?
    • For the web front-end, I used HTML and JS (jQuery). HTML is a necessary no-brainer, but I chose jQuery because it’s straightforward to get simple scripts stood up and run asynchronous commands (such as the buttons changing their status depending on the actual status of the LED as reported from the Pi). For the back end, I chose Python because of its ability to quickly and efficiently access GPIO pins as well as send JSON back to jQuery, which Is necessary for status reporting.
  • What is the purpose of the resistor in this simple circuit? What would happen if you omitted it?
    • The resistor is there to reduce the amount of electricity reaching the LED so that it doesn’t overload it and melt (or explode). Omitting this critical piece would eventually result in failure of the LED.
  • What are practical applications of this device? What enhancements or modifications would you make?
    • Honestly, this device isn’t particularly practical in its current state. Considering the premise of the lab was that Don Borthwick was simply wanting to refresh his skills, I’d say it accomplished its task. For a real stoplight, perhaps one which could be placed outside a bathroom or other office room (hey, I’m just being imaginative), some major aesthetic changes would need to be made, and it’d make more sense to allow the light to also be controlled by hardware. Additionally, measures would need to be taken so that multiple users could (or could not) control the stoplight as appropriate.
  • Please estimate the total time you spent on this lab and report.
    • I’d say somewhere in the vicinity of three to three-and-a-half hours.

 

Certification of Work

I certify that the solution presented in this lab represents my own work. In the case where I have borrowed code or ideas from another person, I have provided a link to the author’s work in the references and included a citation in the comments of my code.

 

 

Appendix

Web Page

Code

Index.html

<!DOCTYPE HTML>

 

<html>

<head>

<script src=”https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js”></script>

</head>

<body>

<h1>TRAFFIC LIGHT</h1>

<button id=”redbutt” type=”button” onclick=”red()”>HELLO</button>

<button id=”yellowbutt” type=”button” onclick=”yellow()”>HELLO</button>

<button id=”greenbutt” type=”button” onclick=”green()”>HELLO</button>

<button id=”offbutt” type=”button” onclick=”off()”>ALL OFF</button>

<button id=”stopbutt” type=”button” onclick=”stoplight()”>STOPLIGHT TIME</button>

<button id=”stopstopbutt” type=”button” onclick=”stopstoplight()”>STOP STOPLIGHT TIME</button>

</body>

<script>

$(document).ready(function(){

var green = “”;

var red = “”;

var yellow = “”;

$.getJSON(‘cgi-bin/status.py’,function(data){

data.Green==”Off” ? green=”On” : green=”Off”;

data.Yellow==”Off” ? yellow=”On” : yellow=”Off”;

data.Red==”Off” ? red=”On” : red=”Off”;

$(“#greenbutt”).html(“Turn Green “+green);

$(“#yellowbutt”).html(“Turn Yellow “+yellow);

$(“#redbutt”).html(“Turn Red “+red);

});

})

 

function green(){

$.getJSON(‘cgi-bin/green.py’,function(data){

localgreen = “”;

data.Status==”Off” ? localgreen=”On” : localgreen=”Off”;

$(“#greenbutt”).html(“Turn Green “+localgreen);

});

}

 

function yellow(){

$.getJSON(‘cgi-bin/yellow.py’,function(data){

localyellow = “”;

data.Status==”Off” ? localyellow=”On” : localyellow=”Off”;

$(“#yellowbutt”).html(“Turn Yellow “+localyellow);

});

}

 

function red(){

$.getJSON(‘cgi-bin/red.py’,function(data){

localred = “”;

data.Status==”Off” ? localred=”On” : localred=”Off”;

$(“#redbutt”).html(“Turn Red “+localred);

});

}

 

function off(){

fetch(‘cgi-bin/alloff.py’);

$(“#redbutt”).html(“Turn Red On”);

$(“#yellowbutt”).html(“Turn Yellow On”);

$(“#greenbutt”).html(“Turn Green On”);

}

 

function stoplight(){

off();

fetch(‘cgi-bin/stoplight.py’);

}

 

function stopstoplight(){

fetch(‘cgi-bin/stoppython.py’);

off();

}

 

 

</script>

</html>

 

Alloff.py

#!/usr/bin/python

 

import os

print(“Content-Type: text/plain”)

print

 

os.system(“gpio -g write 17 0”)

os.system(“gpio -g write 16 0”)

os.system(“gpio -g write 13 0”)

 

Green.py

#!/usr/bin/python

 

import os,json

print(“Content-Type: application/json”)

print

response = “”

 

results = os.popen(“gpio -g read 17”).read()

 

if(results==’1\n’):

os.system(“gpio -g write 17 0”)

response={‘Status’:’Off’}

else:

os.system(“gpio -g write 17 1”)

response={‘Status’:’On’}

 

print(json.JSONEncoder().encode(response))

 

Red.py

#!/usr/bin/python

 

import os,json

print(“Content-Type: application/json”)

print

response = “”

 

results = os.popen(“gpio -g read 13”).read()

 

if(results==’1\n’):

os.system(“gpio -g write 13 0”)

response={‘Status’:’Off’}

else:

os.system(“gpio -g write 13 1”)

response={‘Status’:’On’}

 

print(json.JSONEncoder().encode(response))

 

Status.py

#!/usr/bin/python

 

import os,json

print(“Content-Type: application/json”)

print

response = “”

 

green = os.popen(“gpio -g read 17”).read().replace(‘1\n’,’On’).replace(‘0\n’,’Off’)

yellow = os.popen(“gpio -g read 16”).read().replace(‘1\n’,’On’).replace(‘0\n’,’Off’)

red = os.popen(“gpio -g read 13”).read().replace(‘1\n’,’On’).replace(‘0\n’,’Off’)

response = {‘Green’:green,’Yellow’:yellow,’Red’:red}

print(json.JSONEncoder().encode(response))

 

Stoplight.py

#!/usr/bin/python

 

import os,json,time

print(“Content-Type: application/json”)

print

response = “”

 

while(1==1):

os.system(“gpio -g write 13 1”)

time.sleep(5)

os.system(“gpio -g write 13 0”)

os.system(“gpio -g write 17 1”)

time.sleep(7)

os.system(“gpio -g write 17 0”)

os.system(“gpio -g write 16 1”)

time.sleep(2)

os.system(“gpio -g write 16 0”)

 

Stoppython.py

#!/usr/bin/python

 

import os

 

print(“content-type: text/plain\n\n”)

 

os.system(“pkill -9 -f stoplight.py”)

 

Yellow.py

#!/usr/bin/python

 

import os,json

print(“Content-Type: application/json”)

print

response = “”

 

results = os.popen(“gpio -g read 16”).read()

 

if(results==’1\n’):

os.system(“gpio -g write 16 0”)

response={‘Status’:’Off’}

else:

os.system(“gpio -g write 16 1”)

response={‘Status’:’On’}

 

print(json.JSONEncoder().encode(response))