Announcements

November 24, 2007
Reading for November 27th, are now posted. Enjoy!

October 2, 2007
To upload your thoughtless acts, create a new assignment page like any other lab. You'll see "Thoughtless Acts" listed as one of the assignment options.

May 24, 2008
This site has been archived and is no longer editable. Stay tuned for the next version, coming in the fall!


Breathe Easy

Project Members: 
Alana

Description

Controls the speed of the motor based upon local air quality, as retrieved from airnow.gov. Faster spinning means worse air quality.

Components Used

(1) transistor

(1) diode

(1) motor

Arduino Code

/*
Based on code from:
http://makezine.com/11/diycircuits_meter/
by:
Tom Igoe, 13 April 2006

This program takes the input from a PHP script that will
return the Air Quality Index (AQI), and spins a motor faster,
the worse the AQI. Still a work in progress, need to figure out
how to get the code to actually send the HTTP GET request.
*/

// Defines for the status (used for staus variable):
#define disconnected 0
#define connected 1
#define connecting 2
#define requesting 3
#define reading 4

// Defines for I/O pin:
#define motorPin 9 // I/O pin that the motor is on

// Define for clock tick interval, in ms:
#define interval 20

// variables:
int inByte= -1; // incoming byte from serial RX
char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
int kilobytes = 0; // number of kilobytes of mail

int status = 0; // connection status
int secs = 0; // second counter (used to sleep between checks)

// start serial port, 9600:
void setup() {
Serial.begin(9600);
}

void loop() {
int i = 0; // generic loop counter

// if you're connected to the server, make a HTTP call.
// If not, connect to the server:

if(status == disconnected) {
// attempt to connect to the server:
connect();
}

if (status == connecting) {
// read the serial port:
if (Serial.available()) {
inByte = Serial.read();
// Serial.print(inByte, DEC);
if (inByte == 67) { // 'C' in ascii
status = connected;
}
}

}
if (status == connected) {
// send HTTP GET request for CGI script:
httpRequest();
}

if (status == requesting) {
// wait for bytes from server:
// read the serial port:
if (Serial.available()) {
inByte = Serial.read();
// If you get a "<", what follows is the air quality index:
if (inByte == 60) {
stringPos = 0;
status = reading;
}
}
}

if (status == reading) {
if (Serial.available()) {
inByte = Serial.read();
// Keep reading until you get a ">":
if (inByte != 62) {
// save only ASCII numeric characters:
if ((inByte >= 48) && (inByte <= 57)){
inString[stringPos] = inByte;
stringPos++;
}
}
else {
// convert the string to a numeric value:
int airQuality = atoi(inString);
// set the motor appropriately:
setMotor(airQuality);
status = disconnected;

// wait 60 seconds before trying again:
for (secs = 0; secs < 60; secs++) {
delay(1000);
}

// reset Port before next request:
resetPort();
}
}
}
}

void connect() {
// send out the server address and
// wait for a "C" byte to come back.
// fill in your server's numerical address below:
Serial.print("C192.168.1.23/80\n");
status = connecting;
}

void httpRequest() {
int i = 0; // generic loop counter
inByte = -1;
stringPos = 0;
// Make HTTP GET request. Fill in the path to your version
// of the CGI script:
Serial.print("GET /~alana/scraper.php HTTP/1.1\n");
delay(250);
// Fill in your server's name:
Serial.print("HOST: www.ischool.berkeley.edu\n\n");
status = requesting;
}

void setMotor(int desiredValue) {
int airQualityValue = 0;
// AQI will be between 0 and 500, must convert to motor input (up to 255),
// so I'm taking the easy way out and just dividing by 2
airQualityValue = desiredValue/2;
analogWrite(motorPin, airQualityValue);
}

/*
void printResults() {
// this routine used in debugging only, to print out the results:
Serial.print(" I got ");
Serial.print(stringPos, DEC);
if (stringPos > 0) {
Serial.print(" bytes, total: ");
Serial.print(kilobytes, DEC);
Serial.print(" string: " );
for (int i = 0; i< howManyTimes; i++) {
digitalWrite(13, HIGH);
delay(200);
digitalWrite(13, LOW);
delay(200);
}
}
}
*/

 

PHP Code

<?php
/*
Scrape AQI Page

I can't write PHP code AT ALL, so this code was taken pretty much intact from code by: Tom Igoe, 13 April 2006

found at: http://makezine.com/11/diycircuits_meter/

This program reads the Air Quality index page for Oakland and removes everything but the values for particulate air quality and ozone level. It prints those two values in the following format:

< particulate > followed by a linefeed character (ASCII 10)

< ozone > followed by a linefeed character (ASCII 10)

null character (ASCII 0)

*/

// url of the page with the air quality index data for Oakland:
$url = 'http://airnow.gov/index.cfm?action=airnow.showlocal&CityID=171';

$readParticles = 0; // flag telling you the next line is the particle value
$readOzone = 0; // flag telling you the next line is the ozone value
$particles = -1; // the particles value
$ozone = -1; // the ozone value

// open the file at the URL for reading:
$filePath = fopen ($url, "r");

// as long as you haven't reached the end of the file
while (!feof($filePath))
{
// read one line at a time, and strip all HTML and PHP tags from the line:
$line = fgetss($filePath, 4096);

// if the previous line was the "observed at line" preceding
// the particle matter reading, then $readParticles = 1 and
// you should get this line, trim everything but the number,
// and save the result in $particles:
if ($readParticles == 1) {
$particles = trim($line);
echo "< AQI: $particles>";
$readParticles = 0;
}

// if the previous line was the "observed at line" preceding
// the ozone reading, then $readOzone = 1 and
// you should get this line, trim everything but the number,
// and save the result in $ozone:
if ($readOzone == 1) {
$ozone = trim($line);
//echo "<$ozone>";
$readOzone = 0;
}

// if the current line contains the substring "AQI observed at"
// then the line following it is either the particle reading
// or the ozone reading:
if (preg_match('/AQI observed at /', $line)) {
// if $particles == -1, you haven't gotten
// a value for it yet, so the next line
// till be the particle value:
if ($particles == -1) {
$readParticles = 1;
}

// if $particles > -1, you've gotten a value for it.
// that means that the next line will be the
// ozone reading, if you haven't already gotten
// a reading for ozone (i.e. if $ozone == -1):
if (($particles > -1) && ($ozone == -1)) {
$readOzone = 1;
}
}
}
// close the file at the URL, you're done:
fclose($filePath);
?>


Comments

Comments from TAs

Nice work! Scrapping websites is never an easy task, so good job getting the data offline and connected to the Arduino. I know the need to use a DC motor was a constraint for this lab, but it doesn't seem like the motor speed is a particularly natural mapping to air quality (e.g. faster motor means worse air quality). It would be worth thinking about other outputs might work well for this input data: maybe a simple color from red to green, or something that gets "hazy", etc?


Powered by Drupal - Design by Artinet