Tuesday, February 10, 2015

Webify your Pi Projects

Would you like to control your pi projects from the internet?  Here is some simple instructions that will turn on and off an LED from anywhere in the world.

Supplies needed:
A Raspberry Pi
An LED
A resistor
A computer

First off, I'm going to assume that you have done a little work with your Pi already.  If you're not sure how to set up your Pi, Adafruit has excellent guides.

Next, we install the Apache web server.  Disclaimer: I am by no means a web security expert.  If you intend to make your Pi project public, you will want to secure it.

To install Apache, ssh into your Pi and type:

sudo apt-get install apache2 -y

Find your Pi's local IP address:

ifconfig | grep addr

And look for the inet addr that is not 127.0.0.1

wlan0       Link encap:Ethernet  HWaddr 00:0f:60:01:78:73                    
                 inet addr:192.168.1.4  Bcast:10.0.0.255  Mask:255.255.255.0

From a web browser you should be able to see the default webpage.  Browse to your Pi's IP address.

It works!

This is the default web page for this server.
The web server software is running but no content has been added, yet.


The default location for webpages is: /var/www

Now we need to add python capabilities to Apache.  From your shell type:

sudo apt-get install libapache2-mod-python

Next we need to modify Apache to execute your .py files. (substitute vi for your preferred text editor. Type:

sudo vi /etc/apache2/sites-enabled/000-default

Look for the line:  <Directory "/usr/lib/cgi-bin">
And somewhere below it add:

AddHandler cgi-script .py

Save your file and exit.  Restart Apache:

sudo /etc/init.d/apache2 restart

Let's create a simple python script.  Save this file to your /usr/lib/cgi-bin directory.

#hello.py
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# enable debugging
import cgitb

cgitb.enable()

print "Content-Type: text/plain;charset=utf-8""
print "Hello World!"



Make the file executable:

sudo chmod a+x hello.py

And browse to: http://your_pi_ip/cgi-bin/hello.py

If you see Hello World!  It worked!

Now let's get Apache talking to your GPIO pins with wiringPi.
First we will need to install 'git'

sudo apt-get install git-core
sudo apt-get update
sudo apt-get upgrade

Then we use git to get wiringPi:

git clone git://get.drogon.net/wiringPi

Once that finishes:

cd wiringPi
git pull origin
./build

Test out the new program:  Connect a resistor to pin 26 and an LED to the resistor.  Here's a great guide if you're not sure how to do that. Then type:

gpio -g mode 26 out
gpio -g write 26 1

Your LED should light up.  Sending a 0 (zero) to the pin will turn it off.

gpio -g write 26 0

We now have all the building blocks we need to control your Pi project from the web!

Change back to your /var/www directory and create a new file: light.html

<html>
<head>
<title>Light</title>
</head>
<body>

<form action="/cgi-bin/light.py" method="POST">
  <P>Light</P>
  <input type="submit" value="On" name="On">
  <input type="submit" value="Off" name="Off">
</form>
</body>
</html>


We're almost there, change to your /usr/lib/cgi-bin directory and create a new file: light.py

#!/usr/bin/env python

import cgi
import cgitb
import subprocess

cgitb.enable()

print "Content-type: text/html\n\n"
print "<html>"
print "<head>"
print "<title>Light</title>"
print '<meta http-equiv="refresh" content="4;url=/../light.html" />'
print '<link rel="stylesheet" type="text/css" href="/../light.css">'
print "</head>"
print "<body>"

form=cgi.FieldStorage()

print "<P>"
print "The light is now "
if "On" in form:
    subprocess.call(['gpio', '-g', 'write', '26', '1'])
    print "on"
elif "Off" in form:
    subprocess.call(['gpio', '-g', 'write', '26', '0'])
    print "off"
else:
    print "derp"
print "</P>"


Browse to http://your_pi_ip/light.html and you should be able to turn on and off with a click of the mouse!

To make your Pi accessible from the internet you will need to open and redirect a port on your router's firewall to the Pi.  This could be dangerous as it opens your Pi up to everyone on the internet, do so at your own risk.  It may also violate the terms of service with your ISP.

Saturday, January 17, 2015

Sunrise Alarm Clock

I'm not a morning person.  I wanted some way that would wake me up nice and gentle like instead of the blaring sound of an alarm cock.  Sure, companies sell sunlight alarm clocks, but why not build my own?  After some Google-fu, I found this page on how to make one.

Supplies:

A-Star 32U4 Micro
Adafruit DS1307 real time clock
NeoPixel LED ring
A micro USB cable
A few bits of wire
A computer - duh

Assembly (version 1):

A-Star Micro diagram
-Connect the 5V power from the Micro to the power pin of the LED ring and the 5V pin of the real time clock
-Connect the GND from the Micro to the GND or the LED ring and the GND of the real time clock
-Connect the SCA pin of the real time clock to pin 2 of the Micro
-Connect the SCL ping of the real time clock to pin 3 of the Micro
-Connect pin 4 of the Micro to the data pin of the LED ring

For adding an off button (version 2):

-Connect a button to pin 0 of the Micro (you'll need a resistor)

assembled version 2


Software:

Arduino IDE (I used version 1.0.5)
DS1307RTC.h library
Time.h library
TimeAlarms.h library
FastLED.h library

Setting up Arduino IDE:

Set the board to Arduino Leonardo
Set the programmer to AVR ISP

Setting the clock for the first time:

Run the example program 'SetTime' from the DS1307RTC library.
Run the other example 'ReadTest' to make sure the time is correct.

Code for version 1:

#include <DS1307RTC.h>
#include <Wire.h>
#include <Time.h>
#include <TimeAlarms.h>
#include <FastLED.h>

// Yet Another Sunrise Alarm Clock
// This alarm clock will wake you up with a simulated sunrise,
// just like nature intended.  There are a few variables that
// you need to set first.

// REQUIRED
// Alarm Time: When you want the sunrise to start.  You'll need
// to use maths to figure this out.  See LED_DELAY  Note, the
// clock is 24 hour for those getting up after noon.
#define ALARM_HOUR 6
#define ALARM_MIN 30
#define ALARM_SEC 0

// Alarm Off: Set this to how long you want the alarm to stay
// at full sunlight for.
#define ALARM_OFF_HOUR 1
#define ALARM_OFF_MIN 0
#define ALARM_OFF_SEC 0

// LED_DELAY: This controls how quickly the LEDs turn on.
// You'll need to do a little bit of math here.  I'm sorry.
// The sunrise will go through 3 different colors - red,
// orange, and white.  Each LED will be lit one at a time
// with a delay.  If each LED has a 1000ms delay, it will
// take 16000ms per color, or 48000ms (48 secs) for the
// whole sunrise.  37500 is for a half hour long sunrise.
#define LED_DELAY 37500

// NUM_LEDS: This is the number of LEDs of the NeoPixel LED
// ring.  You probably don't need to change this.
#define NUM_LEDS 16

// DATA_PIN: This is connected to the NeoPixel LED data pin.
#define DATA_PIN 4

// OPTIONALS
// LED_PIN: Use this for a power on indicator.  Note: On the
// smaller Arduinos, there is a built in LED that is connected
// to pin 13
//#define LED_PIN 13

CRGB leds[NUM_LEDS];

void setup()  
{
  // Setup the alarm.
  tmElements_t tm;
  tm.Hour = ALARM_HOUR;
  tm.Minute = ALARM_MIN;
  tm.Second = ALARM_SEC;
  
  setSyncProvider(RTC.get);
  
  // setup the lights
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  LightsOff();

  pinMode(DATA_PIN, OUTPUT);
  
  // Create an alarm for everyday
  Alarm.alarmRepeat(tm.Hour, tm.Minute, tm.Second, Sunrise);  
    
  // Create an alarm to turn the lights off again
  Alarm.alarmRepeat(tm.Hour + ALARM_OFF_HOUR, tm.Minute + ALARM_OFF_MIN, tm.Second + ALARM_OFF_SEC, LightsOff);
  
  // Optional power indicator
  //digitalWrite(LED_PIN, HIGH);
}

void loop()
{ 
  // Alarm.delay has to be called occasionally to make the alarms work
  Alarm.delay(500);
}

// turn on the leds like a sunrise red - orange - white (brightest)
void Sunrise()
{
  // sunrise
  CRGB SunColors[0];
  SunColors[0] = CRGB::Orange;
  SunColors[1] = CRGB::Red;
  SunColors[2] = CRGB::White;
  
  for(int c = 0; c<3; c++ )
  {
    for(int i = 0; i < NUM_LEDS; i++ )
    {  
      leds[i] = SunColors[c];
      FastLED.show();
      delay(LED_DELAY);
    }
  }
}

// turn off the leds
void LightsOff()
{
  for(int i = 0; i < NUM_LEDS; i++ )
  {
    leds[i] = CRGB::Black;
    FastLED.show();
  }
}


Code for version 2 - an off button:

#include <DS1307RTC.h>
#include <Wire.h>
#include <Time.h>
#include <TimeAlarms.h>
#include <FastLED.h>

// Yet Another Sunrise Alarm Clock v2
// This alarm clock will wake you up with a simulated sunrise,
// just like nature intended.  There are a few variables that
// you need to set first.

// REQUIRED
// Alarm Time: When you want the sunrise to start.  You'll need
// to use maths to figure this out.  See LED_DELAY  Note, the
// clock is 24 hour for those getting up after noon.
#define ALARM_HOUR 6
#define ALARM_MIN 45
#define ALARM_SEC 0

// Alarm Off: Set this to how long you want the alarm to stay
// at full sunlight for.
#define ALARM_OFF_HOUR 1
#define ALARM_OFF_MIN 0
#define ALARM_OFF_SEC 0

// LED_DELAY: This controls how quickly the LEDs turn on.
// You'll need to do a little bit of math here.  I'm sorry.
// The sunrise will go through 3 different colors - red,
// orange, and white.  Each LED will be lit one at a time
// with a delay.  If each LED has a 1000ms delay, it will
// take 16000ms per color, or 48000ms (48 secs) for the
// whole sunrise.  37500 is for a half hour long sunrise.
#define LED_DELAY 37500

// NUM_LEDS: This is the number of LEDs of the NeoPixel LED
// ring.  You probably don't need to change this.
#define NUM_LEDS 16

// DATA_PIN: This is connected to the NeoPixel LED data pin.
#define DATA_PIN 4

// OPTIONALS
// LED_PIN: Use this for a power on indicator.  Note: On the
// smaller Arduinos, there is a built in LED that is connected
// to pin 13
//#define LED_PIN 13

// OFF_BTN_PIN: If you are going to have an OFF button, you
// will need to set this.  If you are just going to pull the
// power plug, you can comment out everthing to do with this.
#define OFF_BTN_PIN 0

byte off_btnState = 0;

CRGB leds[NUM_LEDS];

void setup()  
{
  // Setup the alarm.
  tmElements_t tm;
  tm.Hour = ALARM_HOUR;
  tm.Minute = ALARM_MIN;
  tm.Second = ALARM_SEC;
  
  setSyncProvider(RTC.get);
  
  // setup the lights
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  LightsOff();

  pinMode(DATA_PIN, OUTPUT);
  pinMode(OFF_BTN_PIN, INPUT);
  
  // Create an alarm for everyday
  Alarm.alarmRepeat(tm.Hour, tm.Minute, tm.Second, Sunrise);  
    
  // Create an alarm to turn the lights off again
  Alarm.alarmRepeat(tm.Hour + ALARM_OFF_HOUR, tm.Minute + ALARM_OFF_MIN, tm.Second + ALARM_OFF_SEC, LightsOff);
  
  // Optional power indicator
  //digitalWrite(LED_PIN, HIGH);
}

void loop()
{
  // if you're not going to use an off button, comment this line
  off_btnState = digitalRead(OFF_BTN_PIN);
  
  // Alarm.delay has to be called occasionally to make the alarms work
  Alarm.delay(500);

  // if you're not going to use an off button, comment the next 4 lines
  if (off_btnState == HIGH)
  {
    LightsOff();
  }
}

// turn on the leds like a sunrise red - orange - white (brightest)
void Sunrise()
{
  // sunrise
  CRGB SunColors[0];
  SunColors[0] = CRGB::Orange;
  SunColors[1] = CRGB::Red;
  SunColors[2] = CRGB::White;
  
  for(int c = 0; c<3; c++ )
  {
    for(int i = 0; i < NUM_LEDS; i++ )
    {  
      leds[i] = SunColors[c];
      FastLED.show();
      // if you're not going to use an off button, comment the next 4 lines
      if (check_for_off() )
      {
        return;
      }
      // and uncomment the next line
      // delay(LED_DELAY);
    }
  }
}

// you can comment this if you're not using a button
byte check_for_off()
{
  for(int d = 0; d < (LED_DELAY / 10); d++ )
    {
      off_btnState = digitalRead(OFF_BTN_PIN);
      if (off_btnState == HIGH)
      {
        LightsOff();
        return 1;
      }
      else {
        delay(10);
      }
   }
   return 0;
}

// turn off the leds
void LightsOff()
{
  for(int i = 0; i < NUM_LEDS; i++ )
  {
    leds[i] = CRGB::Black;
    FastLED.show();
  }
}