Introduction: Smart&Social Lamp

Project Description: Lamp with RGB LED strip inside, controlled via webpage in local network. It can check facebook inbox and notify you by light that there are some unread messages. Also lamp has "Alert" functionality that allows you send alert signal to it (just for fun!). Name and ip address of person who requested alert is sendig to Watson IoT service.

What you need:

  • Raspberry Pi (and power supply for it)
  • Transistors IRFZ34N or 2N2222A (which transistors to use depends on how much RGB LED strip you want to use)
  • RGB LED Strip
  • Power Supply (12V 2Amp) - for RGB LED Strip
  • Power Jack
  • Breadboard
  • Wires
  • Case for your lamp
  • Monitor, mouse, keyboard for Raspberry Pi (optionally)

Overview:

This project may seem a bit trivial, but I want to show how to combine different technologies in one project and get much more than just controlling RGB LED strip.

As I said, we will controll RGB LED strip that attached to Raspberry Pi via webpage in local network. On the diagram above I show interconnection between all elements (It is better to look at it in full size). Main program (box with "Main Lamp Controller", "Facebook Listener" and "Python Server" is written on Python and has three threads: one main thread and two threads for communicating with user and facebook api. I will tell about each thread in the following steps. "Python Server" communicates with Apache Server launched on the Raspberry Pi, and Apache Server communicates with users in local network. Also on Apache Server we have file "alert.php" that sends data to IBM Bluemix cloud with name and ip address of person who requested alert on your lamp. "Facebook listener" just check my inbox in facebook and send a signal when there are some unread messages.

Why do we need two servers: Python Server and Apache Server? Python Server is a simple program that listens only on one port. To make our project more secure we need to use Apache Server - program that is much more reliable that our implementation.

Why do we need threads? Threads is like programs that run independently of main process. In our project we have three different functionaly: control lamp, listen for data from user and listen for data from facebook. Each functionality by itself needs much time to work. If we implement all these functionalities in one program (one-thread program), program will work very slowly. More about threads in python you can read here.

Which transistors to use: IRFZ34N or 2N2222A? It depends on how much of your RBG LED strip you plan to use. My stip consumes 7.2W for one meter. It has 10 segments in one meter, so one segment consumes 0.72W = > current that flows through this segment: 0.72 = 12V * I => I = 0.06 amps. I used two segments => current in them 0.12 Amps. About electrical power you can read in wikipedia. 2N2222A allows max current around 500 mAmps, so for my lamp these transistors are good enough. If you wanna use 1 m and more you have to use IRFZ34N or counterparts.

Note: I used Raspberry Pi 3, which has wifi module, if you want to use Raspberry Pi 2, you have connect it to internet via Ethernet.

Step 1: Hardware

Step Description: On this step we will assembly our lamp and download special software.

Firstly, we have to configure Raspberry Pi. If you have brand new Raspberry Pi and have no experience with it you can use this tutorials (video, pdf) how to start with it. The main idea of this tutorials:

  1. Download Raspbian OS Image from offical web-site: raspberrypi.org
  2. Download program for formatting and burning data to flash-cards
  3. Format and then burn Raspbian OS Image to your flash-card
  4. Insert your flash-card to your raspberry pi and turn power on.

There two ways for control Raspberry Pi: attach monitor, mouse and keyboard to it - use it as standalone device, or control it via SSH from your own computer. If you want to control it via SSH - here is a good instruction how to set up this.

Now we have fully worked and configured Raspberry Pi.

Step 1. Take RGB LED strip, cut off elements what you need, solder wires to stip.
Step 2. Take breadboard, wires, power supply, transistors and strip that you cut and solder on previous step and assembly how it is showed on picture above. (I also attached Fritzing diagram)
Step 3. Attach wires for RED, GREEN, BLUE and Ground to Raspberry Pi to GPIO17, GPIO27, GPIO22 and ground respectively.

Attention! RGB LED Strip Ground and Raspberry Pi Ground have to be connected!

Note: GPIO pins on Raspberry Pi are shown on this picture.

Now we have to instal special software for controlling LEDs (actually you can use python module, but for me, pigpio library seems more stable). Open terminal on Raspberry Pi and type in the following commands:

wget abyz.co.uk/rpi/pigpio/pigpio.zip
unzip pigpio.zip
cd PIGPIO
make -j4
sudo make install

More about pigpio library here.

We just installed special library that we use to set PWM on needed pins. What is PWM and how it is used to to conrtol RGB LED read here and here.

Step 2: Lamp Controller

Step Description: In this step we will write functions for setting state and color, alert function, function that will signal that we have unread message in facebook. If you have some experience in Python you can skip this step and just download and test attached file.

So, let's start to write our program! Create a file with extension .py ("mainApp.py" in my case) on your Raspberry Pi and open it. This file will contain Python source code.
Note: If you control Raspberry via SSH you have to create file on your computer and when all work will be done put this file to Raspberry.

First thing we need to to do is import pigpio library, that we installed in previous step. Then we define pins which we will use and make them global so we can access them from any function.

import pigpio
global red
global green
global blue
red = 17
green = 27
blue = 22

Now we have to create pigpio object, so we can access pins.

global pi
pi = pigpio.pi()

First function that we are going to create is function for setting color. This function also will be used in other function. In Python when we want to use global variables inside function we have to declare that these variables are global, after that we can use them.

def setColor(hex_color):
global red
global green
global blue
global pi r = int(hex_color[0:2], 16)
g = int(hex_color[2:4], 16)
b = int(hex_color[4:6], 16) pi.set_PWM_dutycycle(red, r)
pi.set_PWM_dutycycle(green, g)
pi.set_PWM_dutycycle(blue, b) return

Function that we just wrote expects color string in hex form, e.g. "ffa9ce". We split this color string to values for each color( ff for red, a9 for green, ce for blue). Then convert this substrings to numbers with built-in functions "int" (second argument 16 - means "expect number in hexademical representation").

Now we need to add two more variables to our program to store current state and current color.

global lamp_color
global lamp_state
lamp_color = "ffffff" #initialize lamp color to white
lamp_state = "off" #initial state is off

Because we want that our lamp remember last entered color we will set color using lamp_color variable when we turn lamp on, i.e. setting state "on".

def changeState(state):
global red
global green
global blue
global pi
global lamp_color
global lamp_state if state == "off":
pi.set_PWM_dutycycle(red, 0)
pi.set_PWM_dutycycle(green, 0)
pi.set_PWM_dutycycle(blue, 0)
lamp_state = "off"
else:
lamp_state = "on"
setColor(lamp_color) return

So, now we have two basic functions that we need! You can play around with them!

Let's create two signalling functions: for alert and for unread facebook messages. Alert function is a little simpler. We need to turn on red for 0.5 sec, then turn it off, repeat some times (10 in my case).

import time
def alert():
	global lamp_color
	for i in range(10):
setColor("ff0000")
time.sleep(0.5)
setColor("000000")
time.sleep(0.5)
setColor(lamp_color) return

Implementing function for signalling about unread messages in facebook is actually depends on you - which signal you wanna see. My implementation of this function with all function above are in the attached file.

Note: file with code attached to this step is not final version, it just for play around with functions created in this step. To get final version of all files go to the end of this instruction.

Step 3: Python Server

Step description: In this step we will implement our own Python Server that will listen on specified port. You can skip this step if you don't want to go deep about how this element works and just download files at the end of this step.

As I said before we will implement Python Server in thread, with which main programm will communicate via Queue objects. Queue object in python is like real life queue - a line of people waiting for something. So you can put some data into queue object in one thread and then retrieve it in the other thread. More about queues in python you can read here. Also look at image in this step.

In communication between threads we will use the following queue objects:

  • color_queue, state_queue - python server sends information to main program: which color to set or turn on/off the lamp;
  • status_queue - main thread will put information about lamp: current state (on/off), current color;
  • alert_queue - python server will put alert request here.

Here we will not go deep about how to write Python server and how server works (read this articles about implementing server: article1, article2, articel3, article4 ), instead we will look at implementation breifly.

First thing we have to do is define HOST and PORT on which our server will listen. I used port 9090. Host we will leave empty so our server can be accessable for all interfaces.

import socket
global HOST
global PORT
HOST = ""
PORT = 9090

Then we need to create socket, tell him that he have to listen on specified host and port.

sock = socket.socket()
sock.bind( (HOST, PORT) )
sock.listen(5) # 5 - is max number of connections in queue

So, now we are waiting for connections. When we have new connection we accept it, parse it and respond. For parsing and responding we will make 2 separate functions. In parsing function we will analize what is requested and then send back suitable answer. We will configure answer only to the following HTTP requests:

/getdata - send information back to user about state and color of the lamp
/alert - user requested "alert", signal to main thread
/setdata?state=on (or off) - user want to turn lamp off/on, signal about that to main thread
/setdata?color=ffffff - user want to set lamp color to ffffff, signal to main thread

If we get other request that is not mentioned above, we will respond with message: "404 Not Found".

To make work main program with this Python Thread you have to add the file with Python thread and start thread.

Here I attach file with my implementation of Python Server in separate thread.

Note: To make work attached file with program on previous step you have to create Python thread with 4 queue objects: color_queue, state_queue, status_queue, alert_queue; and then start thread. OR download full project at the end of instruction.

Step 4: Apache & Graphical User Interface

Step Description: In this step we will create web page that provides GUI for our smart lamp and configure Apache web server on Raspberry Pi

Apache is a web server software, similar to out Python Server, but much powerfull and secure (read this article). We need to run it on our Raspberry Pi, so it can provide users with GUI web page. To install Apache to Raspberry Pi open terminal and type in:

sudo apt-get install apache2 -y

Wait some time. And Done! Apache installed!

Now, we can create GUI on web page for our lamp. Create file "MySmartLamp.html". To create empty file in linux you can type:

touch MySmartLamp.html

About HTML you can read here.

Every web page has minimum 2 pieces: head and body. Head countains title of page (that you see on tab in browser), links to other sources, some meta information for search engines, etc. Content of head is not visible for user. All stuff that you put in the body is visible to user and is essentially what you see in your browser.

So, we need the following functionality:

  • Button to turn on/off lamp
  • Form for setting new color
  • Form for requesting alert request.

But using just html makes page look ugly. So, let's add CSS!! CSS - helps html page look awesome. More about CSS you can read here. BUT! we will not go deep configuring web page so it looks good, instead we will use special css library called Bootstrap with minor chages. To do that we have to add the following tag inside head tag of our html page:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

Now, we add some styles to page, so it looks like picture in the header of this step.

Note: I attached final version of such web page, but Instructables blocks me to download file with .html extension, so after downloading you have to rename it to: "MySmartLamp.html".

Web page is created! It's time to put it to Apache server! In directory with your web page open terminal and type:

sudo mv MySmartLamp.html /var/www/html/

This command moves html page to web server folder. Now you can type on your Raspberry:

http://localhost/MySmartLamp.html

And you'll have see your web page. Or from from any other device on your local network type:

http://raspberry_pi_ip_address/MySmartLamp.html

To know ip address of your Raspberry type in terminal:

ifconfig

Or use this instruction.

Step 5: Communication Between User and Python Program

Step Description: In this step we add functionality to our web page to request data from lamp and send data to it.

How communication works: user sends request from web page to apache server, apache call PHP to help him to handle requests. PHP handles request and give Apache answer, then Apache sends this answer back to user. See image above.

Before we start working on such request handlers, we have to install php on Raspberry. Type in the terminal the following command:

sudo apt-get install php5 libapache2-mod-php5 -y

To handle requests from user we create file data.php. Basically in this file we check that we get valid request and everything is ok, then ask our python server and give its answer back to apache. File data.php is attached to this step with explaining comments inside. You can download it and put to /var/www/html/ folder.

Note: Instructubles blocks files with extension .php, so after downloading file "data", you have to change its name to "data.php".

Now we add some javascript to our web page. There is a good javascrip library jQuerry, that makes work with javascript really easy. On step 4, MySmartLamp web page was attached with added js functionality. Here brief overview.

After page is downloaded anonymous function is called. This function makes request to data.php and ask to provide data about lamp state. Then we use functions to set text on "turn of/off" button (setStateLabel function) and "current color" label (setCurrentColorLabel function) base on data what we got.

The following two functions: changeState and changeColor. First is called when user press "turn on/off" button, the second one is called when user press "change color" button. These two functions send requests to data.php that say: "Turn lamp off" or "Change color to ffaa99", etc.

The last function alert is called when you click on alert button and send request to alert.php. About alert functionality we will talk in the next step.

Step 6: IBM Bluemix, Watson IoT and Alert.php

Step Description: In this step we will add alert functionality to our project, also we will create and confugire IBM Bluemix account so we could send information about each alert request.

Alert is serious stuff and all who use it have to be tracked = ) That is why I added "name" field. Entered name and ip address of user who requested alert will be sent to IBM and at any time you can see who requested alerts =)

Firstly, we have to create IBM Bluemix account and configure it.

  1. Go to https://console.ng.bluemix.net/registration/ and register an account.
  2. Go to https://console.ng.bluemix.net/catalog/
  3. In appeared window make all steps that needed, i.e. "set up environment"
  4. Then, in left side bar click "Internet of Things", after that click on "Internet of things Platform"
  5. Choose your pricing plan (I choose free), click create.
  6. Click Launch dashboard, new tab will be opened.
  7. Select Devices
  8. Click "Add Device"
  9. Click "create device type"
  10. One more time click "Create device type"
  11. Enter "SmartLamp"
  12. Click "Next" three times
  13. Click "Create"
  14. Now you have to see window with "Add Device" and SmartLamp chosen, click next
  15. Enter device id, such as "lamp1", click "next"
  16. skip Metadata section
  17. On page with security, also click next (authorization token will be generated automatically)
  18. In the end click "add"
  19. Now you see your device, copy device credentials:
    • Organization IF
    • Device Type
    • Device ID
    • Authentication Method
    • Authentication Token

So, now our device can send data IBM cloud. But! Data is sent via MQTT protocol that is not the same as HTTP (via which we download pages from the internet). About how it works you ca read here.

It's time create alert.php file that will process alert requests: It will send name and ip address of person that requested alert and signalize our Python Server that "alert" is needed.

PHP does not have buit in function to send MQTT requests, so we need to download special library from here or use zip file attached to this step. After downloading unzip this archive and move it to /var/www/html/ folder. Do not forget to use sudo command. Now, you can create your own alert.php file or use my that I attached here.

Note: If you use my file do not forget to change its name after downloading to alert.php

Basically in alert.php we do the following: check that request has name parameter, get users's ip address, send name and ip address to IBM Cloud, make GET request to our Python Server to signalize, that we need alert.

Main thing we have to do here is to form payload and send data to IBM, so:

1. Create an assosiative array

$msg = array( "d" => array("name" => $_GET['name'], "ip" => $_SERVER['REMOTE_ADDR']));

2. Encode array as json

$json_msg = json_encode($msg , JSON_FORCE_OBJECT );

3. Create MQTT object

$host = "YYY.messaging.internetofthings.ibmcloud.com";
$port = 1883; $username = "use-token-auth"; $password = "XXXX"; // create class for sending mqtt requests $mqtt = new phpMQTT($host, $port, "d:YYY:SmartLamp:lamp1");

Here you have to use credentials that we got when created lamp1 object. If you did not copied them and closed that page, you can just create new object.
YYY in first and last lines change to "Organization ID"
XXXX change to Authentication Token
In last line "SmartLamp" is Device Type and "lamp1" is Device ID.

4. Try to connect. If ok, send data close connection. Signal to Python Server.

if ($mqtt->connect(true,NULL,$username,$password)) {
// send data to IBM
$mqtt->publish("iot-2/evt/alert/fmt/json", $json_msg, 0);
$mqtt->close(); // request alert request to our Python Server
$data = file_get_contents("http://localhost:9090/alert");
if($data == "Ok"){ echo "Ok"; }else{ echo "Error"; } }else { echo "Fail or time out"; }

on the third line, when we make "publish" word "alert" in url is event type, actually you can change it and name this type of event as you want.

Put alert.php to /var/www/html/ folder, open your browser and open the following url:

http://localhost/alert.php?name=MyName

If you make all stuff right you have to see "Ok" message. Done! Test data is sent!

Now go Back to your Watson IoT Platform dashboard, where we created device. Navigate to "Boards", click "Add new Board". Name it. (I name it Smart Lamp). And open newly created board. So, now we create a card to visually represent data about alert requests.

  1. Click "Add new card"
  2. Select "Value"
  3. Select "lamp1", click "Next"
  4. Click "connect data set"
  5. Click on "Event" fiels and you have to see "aler" event, select it
  6. Select property "ip"
  7. Click "Connect new data set"
  8. Select "alert" event, and property "name"
  9. Click Next
  10. "Select "L", click "Next"
  11. Type in name for this card (Alert Requests?) and choose color, click "Submit"

Now you have to see a card with ip address and name. Done!

Note: On Screen above ip address is ::1 because I made request from the computer on which apache is running,

Step 7: Facebook API

Step Description: In this step we will add one more thread to our main program that will check facebook inbox and signal to main thread that there are some unread messages.

Go to facebook.com and login to your account. Then go to https://developers.facebook.com/tools/explorer/.

  1. Click to "Get Token" -> "Get User Access Token"
  2. Select v2.3 (instead of 2.8) in header of opened window.
  3. In Section "Other" mark checkbox "read_mailbox"
  4. Click "Get Access Token"

Copy "Access Token" (long-long string with cryptic symbols).

Create file fbThread.py. Now we are going to write code for thread that will check your facebook inbox.

Create class with initialization method:

class FBthread(threading.Thread):
	def __init__(self, unread_messages):
		super().__init__()
		self.unread_messages = unread_messages
		self.access_token = "<paste access token that you copied from facebook developer page>"

self.access_token variable we will use when we acces data from facebook. Parameter unread_messages is a queue object that we will use to communicate with main thread.

Now we add method "run" that will run forever requesting data from FB.

def run(self):
	while True: 
		# get our all inbox messages.
		response = request.urlopen("https://graph.facebook.com/me/inbox?fields=unread&access_token="+self.access_token).read()
		response = response.decode("utf-8")

		# convert it to dictionary 
		data = json.loads(response) 
		# clear queue in case is not empty
		self.unread_messages.queue.clear()

		# send number of unread messages to main thread 
		self.unread_messages.put(data["summary"]["unread_count"])
		#wait some time and repeat
		time.sleep(3)

Now, add the following lines to file with main thread:

import fbThread
unread_msgs = queue.Queue()
FB = fbThread.FBthread(unread_msgs)
FB.start()

These lines will start new thread when you start your program and now you can check for availability of new messages and signal to user by light if needed:

if not unread_msgs.empty():
	if unread_msgs.get() > 0:
		fbUnreadMsg()

Note: Access token that we generated is valid for small amount of time, for permanent using you have to implement login functionality that is described on this page.

Step 8: Final

Step Description: Here attached full project file.

If you did not do instruction step by step you can download here my project, BUT:

  1. Content of folder "files for apache" move to /var/www/html/ folder on your raspberry pi
  2. Do not forget to change file alert.php (See step 6)
  3. Move content of folder "main program" to any place on your Raspberry Pi
  4. Generate facebook access token and paste it to fbThread.py file
  5. Run command sudo pigpiod
  6. Run file mainApp.py

Now you can type in any device in your local network:

http://raspberry_pi_ip/MySmartLamp.html

Note: to figure out ip address of Raspberry Pi type in terminal "sufo ifconfig" or see this instruction.

So now you have a smart lamp!

If you have something to say, do not hesistate to leave comments = )
I hope you enjoyed my Instructable!

Thank you!

Comments

author
Nematic! (author)2016-11-17

nice !

author
chuldmitry (author)Nematic!2016-11-19

Thank you!

author
Swansong (author)2016-11-17

This is a great instructable :)

author
chuldmitry (author)Swansong2016-11-17

Thank you very much! It's nice to hear it!