Difference between revisions of "Nest Model"

From ESE205 Wiki
Jump to navigation Jump to search
m (Protected "Nest Model" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)))
 
(6 intermediate revisions by 2 users not shown)
Line 65: Line 65:
  
 
==== Website ====
 
==== Website ====
The website uses websockets to communicate with the raspberry pi hardware. The html buttons on the website will run a script on the pi to turn on/off the smart outlet.  
+
The website uses websockets to communicate with the raspberry pi hardware. The html buttons on the website will run a script on the pi to turn on/off the smart outlet. <br>
 
+
[[File: Communicationflow.png|400px]]
<br>
+
Figure 1. Communication depicted between the AWS web interface and the user, the database with user data, and the pi module.<br>
 
+
The websocket client-server connection in this project creates a handshake connection as an http request from the EC2 instance to the running server script on the RasPi. It is essential to the project to establish a connection through some sort of method between the Raspberry Pi and the web interface because we needed two way communication to display information from sensors on the Pi on the website as well as be able to control the outlet's status (on/off) from buttons on the website. Websockets were a good way of creating this connection because it established easy connection between the Javascript incorporated into the website and the Python server script running on the Pi. Potential problems: Not all browsers support websockets, but most of those in which they don't work are obsolete (see [[https://blog.teamtreehouse.com/an-introduction-to-websockets Introduction to Websockets]] for more specific information).<br>
The websocket client-server connection in this project creates a handshake connection as an http request from the EC2 instance to the running server script on the RasPi. It is essential to the project to establish a connection through some sort of method between the Raspberry Pi and the web interface because we needed two way communication to display information from sensors on the Pi on the website as well as be able to control the outlet's status (on/off) from buttons on the website. Websockets were a good way of creating this connection because it established easy connection between the Javascript incorporated into the website and the Python server script running on the Pi. Potential problems: Not all browsers support websockets, but most of those in which they don't work are obsolete (see [[https://blog.teamtreehouse.com/an-introduction-to-websockets Introduction to Websockets]] for more specific information).
+
[[File: FSM.png|400px]]
 
+
Figure 2. Original plan for configuration of the website pages and link paths<br>
<br>
 
 
On boot, the pi should run the server side websocket code(works on pi3 but not pi0, pi0 requires manual start, debugging). This starts the server that listens for emissions that are communicating with the IP address of the pi. The EC2 instance (continually running) connects to the server through a javascript script embedded in the website's html. This is kept track of by the Websocket Status shown at the bottom of the page. When connected, the client side (EC2) will send input from buttons on the page as messages to the pi, which interprets the incoming messages and converts them into instructions for its GPIO pins.  
 
On boot, the pi should run the server side websocket code(works on pi3 but not pi0, pi0 requires manual start, debugging). This starts the server that listens for emissions that are communicating with the IP address of the pi. The EC2 instance (continually running) connects to the server through a javascript script embedded in the website's html. This is kept track of by the Websocket Status shown at the bottom of the page. When connected, the client side (EC2) will send input from buttons on the page as messages to the pi, which interprets the incoming messages and converts them into instructions for its GPIO pins.  
 +
[[File: 2-16-19Indexpage.png|400px]]
 +
Figure 3. Rough design of website home page <br>
  
<source lang='python'>
+
==== Sensors & Hardware ====
#SERVER SIDE SCRIPT server.py on Raspberry Pi
+
<br>Sensors to Transmit Data: We decided to add sensors to collect data that can be displayed on the main web page. For our project, we were only able to add a temperature and light sensor, but many more features could be added in the future as the MCP3008 that we used has 8 channels available total. We had to wire an AD converter into the Raspberry Pi because it does not have one built in. The AD converter reads a voltage from the device and runs voltage through a conversion equation in the code to output a meaningful value. The AD converter sends that signal to one of the I/O pins on the pi so that it can constantly be reading a stream of data which we can display on the website.  
#! /usr/bin/python
 
import os.path
 
import tornado.httpserver
 
import tornado.websocket
 
import tornado.ioloop
 
import tornado.web
 
import RPi.GPIO as GPIO
 
import subprocess
 
import Adafruit_GPIO.SPI as SPI
 
import Adafruit_MCP3008
 
  
print "mode: "
+
Below is our program for converting values. Inside the for loop is our equation for converting voltage to temperature. For the photo-resistor, we decided to leave the values read from the ADC and tested a range of what values were considered bright or dark.
print GPIO.getmode()
 
  
#GPIO.setmode(GPIO.BOARD)
 
  
#print "mode: "
+
# Main program loop.
#print GPIO.getmode()
+
while True:
 +
    # Read all the ADC channel values in a list.
 +
    values = [0]*2
 +
    for i in range(2):
 +
        # The read_adc function will get the value of the specified channel (0-7).
 +
        if i==1:
 +
            millivolts = mcp.read_adc(i)*(3300/1024)
 +
            temp_C = ((millivolts-500.0)/10.0)
 +
            temp_F = (temp_C*9.0/5.0)+32
 +
            temp_C = "%.1f" % temp_C
 +
            temp_F = "%1.f" % temp_F
 +
            values[i] = temp_F
 +
        else:
 +
            values[i] = mcp.read_adc(i)
  
#software box configuration:
+
<gallery>
OUT1 = 24
+
Wiring.jpg|Pi3 with ADC and sensors in a breadboard
LED1 = 23
+
</gallery>
 
 
#software SPI configuration:
 
CLK = 23
 
MISO = 21
 
MOSI = 19
 
CS = 24
 
mcp = Adafruit_MCP3008.MCP3008(clk=CLK, cs=CS, miso=MISO, mosi=MOSI)
 
print "mode: "
 
print GPIO.getmode()
 
 
 
# Hardware SPI configuration:
 
SPI_PORT = 0
 
SPI_DEVICE = 0
 
mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))
 
 
 
#Define Variables
 
delay = 0.5
 
ldr_channel = 0
 
 
 
def readadc(i):
 
  # read SPI data from the MCP3008, channel 1 is temp channel 0 is light
 
  if i == 1:
 
millivolts = mcp.read_adc(i)*(3300/1024)
 
temp_C = ((millivolts-500.0)/10.0)
 
temp_F = (temp_C*9.0/5.0)+32
 
temp_C = "%.1f" % temp_C
 
temp_F = "%1.f" % temp_F
 
return temp_F
 
  else:
 
return (mcp.read_adc(i))/160
 
 
 
#Initialize Raspberry PI GPIO
 
GPIO.setup(LED1, GPIO.OUT)
 
GPIO.setup(OUT1, GPIO.OUT)
 
GPIO.output(LED1, False)
 
GPIO.output(OUT1, True)
 
 
 
#Tornado Folder Paths
 
settings = dict(
 
template_path = os.path.join(os.path.dirname(__file__), "templates"),
 
static_path = os.path.join(os.path.dirname(__file__), "static")
 
)
 
#Tornado server port
 
PORT = 8888
 
class MainHandler(tornado.web.RequestHandler):
 
  def get(self):
 
    print "[HTTP](MainHandler) User Connected."
 
    self.render("index.html")
 
 
class WSHandler(tornado.websocket.WebSocketHandler):
 
  def check_origin(self, origin):
 
    print origin
 
    return origin == "http://ec2-3-85-217-77.compute-1.amazonaws.com"
 
 
 
  def open(self):
 
    print '[WS] Connection was opened.'
 
 
  def on_message(self, message):
 
    print '[WS] Incoming message:', message
 
    if message == "on_outlet1":
 
      GPIO.output(OUT1, False)
 
      GPIO.output(LED1, True)
 
    if message == "off_outlet1":
 
      GPIO.output(OUT1, True)
 
      GPIO.output(LED1, False)
 
    if message == "refresh_lum":
 
      self.write_message(str(readadc(0))+ " LUM")
 
    if message == "refresh_temp":
 
      self.write_message(str(readadc(1))+ " TEMP")
 
  def on_close(self):
 
    print '[WS] Connection was closed.'
 
 
 
application = tornado.web.Application([
 
  (r'/', MainHandler),
 
  (r'/ws', WSHandler),
 
  ])
 
if __name__ == "__main__":
 
    try:
 
        http_server = tornado.httpserver.HTTPServer(application)
 
        http_server.listen(PORT)
 
        main_loop = tornado.ioloop.IOLoop.instance()
 
        print "Tornado Server started"
 
        main_loop.start()
 
    except:
 
        print "Exception triggered - Tornado Server stopped."
 
        GPIO.cleanup()
 
#End of Program
 
</source>
 
 
 
<source lang='js'>
 
//CLIENT SIDE SCRIPT ws-client.js on EC2 instance
 
$(document).ready(function(){
 
 
 
        var WEBSOCKET_ROUTE = ":8888/ws";
 
var piIP3 = "172.27.8.108";
 
var piIP0 = "172.27.178.159";
 
 
 
        if(window.location.protocol == "http:"){
 
            //localhost
 
            var ws = new WebSocket("ws://" + piIP0 +  WEBSOCKET_ROUTE);
 
    console.log("http case");
 
            }
 
        else if(window.location.protocol == "https:"){
 
            //Dataplicity
 
    console.log("in the https state");
 
            var ws = new WebSocket("wss://" + piIP0 + WEBSOCKET_ROUTE);
 
            }
 
 
 
        ws.onopen = function(evt) {
 
            $("#ws-status").html("Connected");
 
            };
 
 
 
        ws.onmessage = function(evt) {
 
    //console.log(evt.data);
 
    if(evt.data.includes("LUM")){
 
$("#lumin").html(parseInt(evt.data,10));
 
    }
 
    if(evt.data.includes("TEMP")){
 
$("#temp").html((parseInt(evt.data,10)));
 
    }
 
            };
 
 
 
        ws.onclose = function(evt) {
 
            $("#ws-status").html("Disconnected. If you were unable to connect, please restart your outlet.");
 
            };
 
 
 
        /*$("#outlet2_on").click(function(){
 
            ws.send("on_outlet2");
 
    if(ws.readyState === ws.OPEN){
 
            $("#outlet2-status").html("OUTLET ON");
 
    }
 
            });
 
        $("#outlet2_off").click(function(){
 
            ws.send("off_outlet2");
 
            $("#outlet2-status").html("OUTLET OFF");
 
            });*/
 
 
 
        $("#outlet1_on").click(function(){
 
            ws.send("on_outlet1");
 
    if(ws.readyState === ws.OPEN){
 
            $("#outlet1-status").html("OUTLET ON");
 
    }
 
            });
 
 
 
        $("#outlet1_off").click(function(){
 
            ws.send("off_outlet1");
 
            $("#outlet1-status").html("OUTLET OFF");
 
            });
 
 
 
        $("#check_lumin").click(function(){
 
            ws.send("refresh_lum");
 
            });
 
 
 
        $("#check_tem").click(function(){
 
            ws.send("refresh_temp");
 
            });
 
 
 
      });
 
</source>
 
 
 
[[File: 2-16-19Indexpage.png|400px]]
 
Figure 1. Rough design of website home page
 
 
 
[[File: Communicationflow.png|400px]]
 
Figure 2. Communication depicted between the AWS web interface and the user, the database with user data, and the pi module.
 
 
 
[[File: FSM.png|400px]]
 
Figure 3. Original plan for configuration of the website pages and link paths
 
 
 
==== Sensors & Hardware ====
 
<br>Sensors to Transmit Data: We decided to add sensors to collect data that can be displayed on the main web page. For our project, we were only able to add a temperature and light sensor, but many more features could be added in the future as the MCP3008 that we used has 8 channels available total. We had to wire an AD converter into the Raspberry Pi because it does not have one built in. The AD converter reads a voltage from the device and runs voltage through a conversion equation in the code to output a meaningful value. The AD converter sends that signal to one of the I/O pins on the pi so that it can constantly be reading a stream of data which we can display on the website.
 
  
 
<br>Power Supply and Relay: Our device plugs directly into the wall, however a typical outlet supplies 120 volts. The Raspberry Pi can only handle 5 volts at a time so we had to include a relay to the module in order to separate the pi from the wall outlet voltage unless the device needs to be turned on. A signal is sent from our pi to tell the relay when to flip the switch closed and allow mains voltage to turn the module on and supply wall voltage to the outlets on the front plate for any device to be plugged into. We also decided to add a small LED beside the outlets that automatically turns on when the relay closes so that the user can always know when the outlets have power even if nothing is plugged in.
 
<br>Power Supply and Relay: Our device plugs directly into the wall, however a typical outlet supplies 120 volts. The Raspberry Pi can only handle 5 volts at a time so we had to include a relay to the module in order to separate the pi from the wall outlet voltage unless the device needs to be turned on. A signal is sent from our pi to tell the relay when to flip the switch closed and allow mains voltage to turn the module on and supply wall voltage to the outlets on the front plate for any device to be plugged into. We also decided to add a small LED beside the outlets that automatically turns on when the relay closes so that the user can always know when the outlets have power even if nothing is plugged in.
Line 274: Line 105:
 
<gallery>
 
<gallery>
 
Relay_diagram_picture.png | Schematic diagram of relay wiring to pi0
 
Relay_diagram_picture.png | Schematic diagram of relay wiring to pi0
 +
</gallery>
 +
 +
<gallery>
 +
Diagram of system.png|Overall diagram of connectivity in module
 
</gallery>
 
</gallery>
  

Latest revision as of 14:43, 4 May 2019

Overview

Our project is to create a smart outlet consisting of a raspberry pi zero, a relay, and a container that works between an AC outlet and a device. We'd like to be able to communicate between a web interface and the outlet to be able to turn the device on and off. We would also like to add timing control features through the web interface. If we are successful with the initial project, we will add additional modules to the web interface to be able to control multiple devices.

Team Members

Amanda Hua
Tricia Brown
TA: Keith Kamons
Professor: James Feher

Links

[View Project Log]
[View Github]
[View Preliminary Presentation]
[Tutorial]
[Poster]

Objectives and Goals

Build a module that can relay between an AC outlet and device that we want to control
Build a web interface that successfully communicates with the built module in at least a binary fashion
Set up a server to host the web interface

Challenges

  • A majority of our programming expertise is in Java, and learning more about web development languages, especially Python, will be time consuming.
  • We have minimal background in hardware and circuitry, so a big challenge will be ensuring that we will account for all of the details necessary for our module.
  • We have no background in web security, so we need to be very careful in allowing access to the devices and files that we will be using.
  • We have never worked with Raspberry Pi before.
  • Linux is an unfamiliar operating system.


Budget

Total: -----needs to be updated ----

Useful Resources

RasPi Resources

GPIO Diagram
Blink Code

Temp Sensor Resources

132 Assignment (More Context)
Spec Sheet

DevOps and Server Side Resources

Websockets Tutorial

Project Results

Gantt Chart

https://docs.google.com/spreadsheets/d/10Ftzdzjh8UOGXznYvhBb2OvnZ2Exib2vUMbfKiH339s/edit?usp=sharing
Media:GanttChart2-16.png

Design and Solution

Website

The website uses websockets to communicate with the raspberry pi hardware. The html buttons on the website will run a script on the pi to turn on/off the smart outlet.
Communicationflow.png Figure 1. Communication depicted between the AWS web interface and the user, the database with user data, and the pi module.
The websocket client-server connection in this project creates a handshake connection as an http request from the EC2 instance to the running server script on the RasPi. It is essential to the project to establish a connection through some sort of method between the Raspberry Pi and the web interface because we needed two way communication to display information from sensors on the Pi on the website as well as be able to control the outlet's status (on/off) from buttons on the website. Websockets were a good way of creating this connection because it established easy connection between the Javascript incorporated into the website and the Python server script running on the Pi. Potential problems: Not all browsers support websockets, but most of those in which they don't work are obsolete (see [Introduction to Websockets] for more specific information).
FSM.png Figure 2. Original plan for configuration of the website pages and link paths
On boot, the pi should run the server side websocket code(works on pi3 but not pi0, pi0 requires manual start, debugging). This starts the server that listens for emissions that are communicating with the IP address of the pi. The EC2 instance (continually running) connects to the server through a javascript script embedded in the website's html. This is kept track of by the Websocket Status shown at the bottom of the page. When connected, the client side (EC2) will send input from buttons on the page as messages to the pi, which interprets the incoming messages and converts them into instructions for its GPIO pins. 2-16-19Indexpage.png Figure 3. Rough design of website home page

Sensors & Hardware


Sensors to Transmit Data: We decided to add sensors to collect data that can be displayed on the main web page. For our project, we were only able to add a temperature and light sensor, but many more features could be added in the future as the MCP3008 that we used has 8 channels available total. We had to wire an AD converter into the Raspberry Pi because it does not have one built in. The AD converter reads a voltage from the device and runs voltage through a conversion equation in the code to output a meaningful value. The AD converter sends that signal to one of the I/O pins on the pi so that it can constantly be reading a stream of data which we can display on the website.

Below is our program for converting values. Inside the for loop is our equation for converting voltage to temperature. For the photo-resistor, we decided to leave the values read from the ADC and tested a range of what values were considered bright or dark.


  1. Main program loop.

while True:

   # Read all the ADC channel values in a list.
   values = [0]*2
   for i in range(2):
       # The read_adc function will get the value of the specified channel (0-7).
       if i==1:
           millivolts = mcp.read_adc(i)*(3300/1024)
           temp_C = ((millivolts-500.0)/10.0)
           temp_F = (temp_C*9.0/5.0)+32
           temp_C = "%.1f" % temp_C
           temp_F = "%1.f" % temp_F
           values[i] = temp_F
       else:
           values[i] = mcp.read_adc(i)


Power Supply and Relay: Our device plugs directly into the wall, however a typical outlet supplies 120 volts. The Raspberry Pi can only handle 5 volts at a time so we had to include a relay to the module in order to separate the pi from the wall outlet voltage unless the device needs to be turned on. A signal is sent from our pi to tell the relay when to flip the switch closed and allow mains voltage to turn the module on and supply wall voltage to the outlets on the front plate for any device to be plugged into. We also decided to add a small LED beside the outlets that automatically turns on when the relay closes so that the user can always know when the outlets have power even if nothing is plugged in.

Results and Solution

Software

Goals: Create a working website that allows us to interact remotely with a physical device consisting of a relay, raspberry pi, and sensors to be able to turn a connected outlet on and off, with a timing setting.

Actual: The website is able to interact remotely with the physical device and turn the outlet on and off. The server script works pretty consistently to open a websocket connection between the pi and website, and the website is hosted publicly as of right now so that anyone with the QR code or link have access to the outlet.

Problems: The server script on the pi zero does not turn on automatically on boot. Next steps would be to get crontab working so that both the IP Address emailer for the pi (currently have a smtp problem with accessing gmail, although curiously the emailer works on boot when the pi is attached to an HDMI cable) and the automatic server start work. This could be solved in several ways. First, because websockets can be created in a way that allows you to send messages knowing only the server IP address, whether or not the RasPi IP address is consistent, it can be sent as a variable to the EC2 acting as a server to be used to connect to the Pi's server script. This would be helpful if we use this device in an environment like WashU where the wifi makes the IP address of the Pi inconsistent, so the script can be changed dynamically. Otherwise, we can continue to use the email system and change the scripts only when necessary, which might be easier in a more stable internet environment. This would require debugging the gmail bug, which would allow us to obtain the email on boot - there may also be a crontab problem, because the server script is not running on boot.

Hardware

Goals: Build a module that can contain the pi and its power supply, relay, ADC and other sensors as well as be safely wired to mains voltage.

Actual: A module that contains the pi 0, relay, ADC and sensors, and has two outlet plugs available for safe usage.

Problems: We were only able to have one electrical outlet on the box due to spacing issues inside when we had originally envisioned having four plugs available. Also, there was not enough room in the box itself to contain the power supply for the pi so we had to have a separate external battery. A next step would be to that entirely self contained so there is no need to plug into anything externally but a wall outlet. However, the box was built successfully and safely, and all the components work the way they should.

Next Steps

  • Create a database of users that would improve security so that people don't have access to each others' outlets (password protected)
  • Fix the crontab commands
  • Add different features
    • Outlets on timers (allow setting lights to come on at night, or if we have a motion sensor and there's no signal after 5 min, etc.)
    • Outlets changing status depending on sensor input (turn outlet off if it's indicated as a light outlet above a certain brightness, use temp sensor to turn on fan outlet above a certain temp, etc.)
    • Outlets with different statuses (light outlets, fan outlets, etc. as demonstrated in above examples)