Introduction: Intel Galileo Weather-Station

Picture of Intel Galileo Weather-Station

The Project

We are a group of students from the RWTH Aachen University. Our project is part of a practical course at the Multi Modal Media Madness Lab from the Media Computing Group.

This project is an introduction to the possibilites with the Intel Galileo 2 Board, including networking and the use of python scripts. Connected via Ethernet, this weather-station displays the local temperature, cloudiness and precipitation on three LEDs, using three different color scales.

What you will need:

  • Intel Galileo Gen. 2 Board (Including a Linux Image* on the SD-Card)
  • 1 Button
  • 3 RGB-Leds**
  • 4 Resistors (220 Ohm)
  • Ethernet cable
  • Some wires and other hardware to build up the circuit (breadboard etc.)

* The Linux SD-Card image and the current Arduino IDE that works best with the Intel Galileo 2 Board can be found here.

** We used Common Anode LEDs for this project. If you use Common Cathode LEDs, changes in code and circuit have to be made, which includes inverting the Pin output and using the Arduinos GND PIN instead of 5V..

Step 1: Wiring

Picture of Wiring
  1. Make sure that the Galileo board is turned off (no LEDs blinking etc)
  2. Now connect the LEDs*, the button and the resistors with your Galileo Board as it is shown in the wiring diagram
  3. The odd port numbers are chosen due to the PWM needed for the color transitions

*Which LED color is controlled by which lead depends on the lead length, with the longest lead being the common anode

Step 2: Print the Shield

Picture of Print the Shield
  1. The LED Cover has to be printed according to the wiring and hardware positioning you made before. We cut holes into a scrap of cardboard so that the LEDs can fit through.
  2. This cardboard piece can be scanned afterwards to figure out the positioning and size of the icons.
  3. The attached gimp file can be used to easily costumize the cover.

Step 3: Upload Files

1. Find out Galileos IP-Adress

  • Upload the getIP.ino file with the Arduino IDE onto the Galileo and execute it
  • Don't forget to plug in the Ethernet cable ;)
  • Open the "Serial Monitor" [STRG + SHIFT + M] and set the baud rate to 9600

2. Uploading the files

Windows:

  • Download and install Winscp
  • Upload the weather.py file to /home/root/ onto the Galileo
  • Do the same with the config.txt and mail.py

Linux:

  • Type
scp /path/to/your/file/weather.py root@IP-adress-you-found-out:/home/root/</p><p>scp /path/to/your/file/config.txt root@IP-adress-you-found-out:/home/root/

into your console

weather.py:

#!/bin/python2.7
import sys import urllib2 import xml.etree.ElementTree as ET

if (len(sys.argv) <= 1): # No arguments given. So we use Aachen as default place city = "Aachen" else: # Otherwise the given city city = sys.argv[1]

# Download from openweathermap the current weather as xml try: response = urllib2.urlopen('http://api.openweathermap.org/data/2.5/weather?q='+city+'&mode=xml&units=metric&lang=de', timeout = 10) except urllib2.URLError: # On timeout stop script and return error sys.exit(-1)

# Init the xml parser with our downloaded text root = ET.fromstring(response.read())

# Find out some intresting values temp = root.find('temperature').get('value') clouds = root.find('clouds').get('value')

# precipitation is a bit dificult. Either it is set to no ... if (root.find('precipitation').get('mode') == "no"): rain = 0 else: # ... ore a value is given rain = root.find('precipitation').get('value')

# Now we pint our parsed values, so it is posible to read them out of # the Arduino sketch print temp print clouds print rain

mail.py

#!/bin/python2.7
import sys import smtplib

# Do some config here SMTPServerUrl = 'www.host.com' SMTPServerPort = 25 SMTPUsername = 'username' SMTPPassword = 'password' EmailAddress = 'your.mail@host.com' SUBJECT = 'Weather information'

# Check given parameters if (len(sys.argv) <= 2): print "Usage: [target mail addr.] [message]" sys.exit(-1)

# Next try to connect to the server try: server = smtplib.SMTP(SMTPServerUrl, SMTPServerPort) server.login(SMTPUsername, SMTPPassword) except: # Print some error messages print "Error Connecting" sys.exit(-1)

# Now try to send our given Message try: message = "Subject: " + SUBJECT + "\n" + sys.argv[2] server.sendmail(EmailAddress, sys.argv[1], message) except: # Print some error messages print "Error Sending" sys.exit(-1)

# Finally disconnect server.quit()

config.txt:

Aachen
Aachen;0;30;0;100;1;100;It is raining. Take a umbrella with you.;your.mail@host.com; Aachen;18;30;0;33;0;0;The weather is sunny. You can leave your jacket at home.;your.mail@host.com;

getIP.ino:

void setup() {
  // Set the baud rate
  Serial.begin(9600);
}

void loop() {
  // Execute ifconfig and pipe everything to the serial output
  system("ifconfig &> /dev/ttyGS0");
  
  // Wait some time
  sleep(5); 
}

Step 4: Upload and Configure Code

  1. Open the weather_to_led.ino in your Arduino IDE and configure following things
    • LED ports (The PWM Ports of your board are marked with an [ ~ ])
    • Button port
    • Sleep time
    • Maybe change script and config file path
  2. Open mail.py via ssh. Then change the 6 variables defined on top of the script
    • SMTPServerUrl is the address of your SMTP server
    • SMTPServerPort is the port number of the SMTP server
    • SMTPUsername is the username of your mail account
    • SMTPPassword is the password to your mail account
    • EmailAddress is the mail address to your mail account
    • SUBJECT is the subject of the mail sent by this script
    • NOTE: The connection is not sequre. Informations are not encrypted
  3. Open config.txt via ssh. The config scheme is explained in the following codeblock:
CITY_NAME_LED
CITY_NAME1;MIN_TEMP;MAX_TEMP;MIN_CLOUDS;MAX_CLOUDS;MIN_RAIN;MAX_RAIN;MESSAGE;E-MAIL;
CITY_NAME2;...
[...]
[EMPTY LINE]
  • CITY_NAME_LED is the name of the city whose weather data should be displayed via LEDs.
  • Every following Line defines one Message that should be sent to the E-Mail if the given conditions are met* according to the weather data fetched from the city defined at the lines beginning. (CITY_NAME1 in the code block)
  • Temperatures are measured in Celsius, clouds in percent (0% = blue sky) and rain is measured in mm per square meter, fallen in the last 3 hours.

*That means, that for every measured value x should be MIN_VALUE <= x and x <= MAX_VALUE.

weather_to_led.ino:

#define MAX_MESSAGE_LENGTH 128
#define MAX_CITY_LENGTH 20 #define MAX_COMMAND_LENGTH (MAX_CITY_LENGTH + 30) #define MAX_MAILADDR_LENGTH 30

#define SLEEP_TIME 3600 #define LOOP_DELAY 250 #define BUTTON_PIN 2 char SCRIPT_FILE[] = "/home/root/weather.py"; char CONFIG_FILE[] = "/home/root/config.txt"; char MAIL_FILE[] = "/home/root/mail.py";

/* * Contains the IO port numbers for one RGB-LED. We use ports with * PWM to mix the colours. * Port 0 means, this LED is not used or connected. */ struct RGB_LED { int red; int green; int blue; };

/* * Declaration of our 3 used led's. Each uses only two ports. So we * are able to connect three led's to 6 PWM ports. */ struct RGB_LED temp = {3, 0, 5}; struct RGB_LED rain = {0, 6, 9}; struct RGB_LED clouds = {0, 10, 11};

struct weather { float temp; float clouds; float rain; };

/* * Enables one led. Therefor the pinmode ist set to * output. * @param led struct with port numbers */ void init_rgb_led(struct RGB_LED led) { // Set each led Port to output if (led.red != 0) pinMode(led.red, OUTPUT); if (led.green != 0) pinMode(led.green, OUTPUT); if (led.blue != 0) pinMode(led.blue, OUTPUT);

// Switch led's off set_rgb_led(led, 0, 0, 0); }

/* * Sets the color on a specific led. We use analogWrite and PWM to * mix the colors. * The led struct should have been initialized before. * @param led struct with port numbers and r,g,b values, which should be * set */ void set_rgb_led(struct RGB_LED led, int r, int g, int b) { // Writes the given values on our ports. The value must be inverted, // caused by our construction. if (led.red != 0) analogWrite(led.red, 255 - r); if (led.green != 0) analogWrite(led.green, 255 - g); if (led.blue != 0) analogWrite(led.blue, 255 - b); }

/* * Given a temperature in celsius this function shows the value * by mixing the right colors together. * @param degree from 0 to 25 */ void set_temp(int degree) { int value;

// Scale: 0 <= degree <= 25 if (degree > 25) degree = 25; if (degree < 0) degree = 0;

// Calculate the LED value. (25 * 1 value = degree * 10;

// Red led was to bright. So its value is divided by 2 set_rgb_led(temp, value / 2, 0, 255 - value); }

/* * Given a propability this function * shows the value by mixing the right colors together. * @param propability as value from 0 to 100 */ void set_rain(int percent) { int value;

// Accept only values between 0 and 100 degree if (percent > 100) percent = 100; if (percent < 0) percent = 0;

value = (percent * 255) / 100; set_rgb_led(rain, 0, 255 - value, value); }

/* * Given a propability this function * shows the value by mixing the right colors together. * @param propability as value from 0 to 100 */ void set_clouds(int percent) { int value;

if (percent > 100) percent = 100; if (percent < 0) percent = 0;

value = (percent * 255) / 100; set_rgb_led(clouds, value, value, 255 - value); // Rot durch Verdratung }

/* * This function uses a python script to send a message to a given mail address * including the current weather informations. * * @param message is a pointer to our message string * @param w is a weather struct containing the current informations * @param mailaddr is a pointer to our target mail string */ char send_weather_mail(char *message, struct weather w, char* mailaddr) { FILE *fp; char buf[1024];

// Prepare a big string, which contains the command if (snprintf(buf, 1024, "python2.7 %s '%s' 'New weather informations:\n%s\n\nCurrent Weather:\nTemperature: %.1fC\nRaining: %dmm (last 3h)\nClouds: %d%%'", MAIL_FILE, mailaddr, message, w.temp, w.rain, w.clouds) <= 0) { return 0; }

// Open a pipe and execute the command fp = popen(buf, "r"); if (fp == NULL) { return 0; }

// Next close it if (pclose(fp) != 0) { return 0; }

return 1; }

/* * Given a city and a weather struct, this method reads * the current weather values and fills the struct with these. * @param Name of a city as string * @param Pointer to a weather struct * * @return 0 on failure and otherwise it is a success */ int readWeather(char *city, struct weather *w) { FILE *fp; char buf[MAX_COMMAND_LENGTH + 1];

// Build the command string, by adding path and city together if (snprintf(buf, (MAX_COMMAND_LENGTH + 1) * sizeof(char), "python2.7 %s '%s'", SCRIPT_FILE, city) <= 0) { return 0; }

/* Execute the python script and write everything into a pipe * so we can read the result */ fp = popen(buf, "r");

if (fp == NULL) return 0;

// Read the current weather values int erg = fscanf(fp, "%f\n%f\n%f", &(w->temp), &(w->clouds), &(w->rain)) == 3;

// Close the pipe and check return value if (pclose(fp) != 0) { return 0; }

return erg; }

/* * Standard Arduino setup method */ void setup() { int i;

//Pullup resistors -> negated Logic pinMode(BUTTON_PIN, INPUT_PULLUP);

// Set baudrate for debugging Serial.begin(9600);

// Initialize our 3 RGB-LEDs init_rgb_led(temp); init_rgb_led(rain); init_rgb_led(clouds);

// Test our leds by showing an animation for (i = 0; i <= 100; i++) { set_temp(i / 4); delay(10); } for (i = 0; i <= 100; i++) { set_rain(i); delay(10); } for (i = 0; i <= 100; i++) { set_clouds(i); delay(10); } }

/* * Updates the weather infomation. * @param onlyLeds does what it sounds like ;) */ void updateEverything(bool onlyLeds) {

struct weather weather; FILE *fd; char city[MAX_CITY_LENGTH + 1]; char mailaddr[MAX_MAILADDR_LENGTH + 1]; char message[MAX_MESSAGE_LENGTH + 1]; int min_tmp, max_tmp, min_rain, max_rain, min_clouds, max_clouds;

// Open the config file fd = fopen(CONFIG_FILE, "r");

// Error handling if (fd == NULL) { Serial.println("Could not find/open config file!\n"); sleep(SLEEP_TIME); return; }

// First read the standart LED city name if (fscanf(fd, "%s\n", city) == 1) { // Print name for debugging Serial.println(city);

if (readWeather(city, &weather)) { // Print values for debugging Serial.println(weather.temp); Serial.println(weather.clouds); Serial.println(weather.rain);

// Refresh LED colors set_temp(weather.temp); set_clouds(weather.clouds); set_rain(weather.rain); } else { Serial.println("Error reading weather!\n"); }

} else { Serial.println("Konnte Stadt nicht lesen!\n"); }

// Read config file, until it ends while (!feof(fd) && !onlyLeds) { // Try to read one line and parse it if (fscanf(fd, "%[^;];%d;%d;%d;%d;%d;%d;%[^;];%[^;];\n", city, &min_tmp, &max_tmp, &min_clouds, &max_clouds, &min_rain, &max_rain, message, mailaddr) == 9) { // Print city for debugging Serial.println(city);

if (readWeather(city, &weather)) { // Print values for debugging Serial.println(weather.temp); Serial.println(weather.clouds); Serial.println(weather.rain);

// Check our conditions for giving a message if (min_tmp <= weather.temp && weather.temp <= max_tmp && min_clouds <= weather.clouds && weather.clouds <= max_clouds && min_rain <= weather.rain && weather.rain <= max_rain) { // Print the message Serial.println(message);

// Send a mail if (!send_weather_mail(message, weather, mailaddr)) { Serial.println("Error sending message!\n"); }

}

} else { Serial.println("Error reading weather!\n"); }

} else { Serial.println("Error reading config file!"); } }

// Close the file and wait for button press fclose(fd); }

void loop() { static int loop_count = 1000 * SLEEP_TIME; // So it is executet at beginning

if (loop_count >= 1000 * SLEEP_TIME) { updateEverything(0); loop_count = 0; }

if (digitalRead(BUTTON_PIN) == LOW) { // Switch led's off set_rgb_led(temp, 0, 0, 0); set_rgb_led(clouds, 0, 0, 0); set_rgb_led(rain, 0, 0, 0);

updateEverything(1); }

loop_count += LOOP_DELAY; delay(LOOP_DELAY); }

Step 5: The Weatherdata

Picture of The Weatherdata

The weather data is fetched from openweathermap.org
as an XML-file. Using this file we extracted the values needed for our weatherstation, allowing us to set the colors of our LEDs accordingly. As seen in the picture above, the file contains a lot more Information suitable for a full-fledged weather station with an description of the current weather.

Comments

SomePolishGuy (author)2015-11-28

Very nice! Cant wait to make something similar

sitinafiah1801 (author)2015-09-09

thanks for sharing :D

very good project :)

tomatoskins (author)2015-05-12

This is awesome! Thanks for sharing and welcome to the community!

About This Instructable

6,139views

20favorites

More by konnykonny50:Intel Galileo Weather-Station
Add instructable to: