Thermostat with Arduino and touchscreen

..Hi, dear techno frieds (obviously male and female)!
My holidays unfortunately ended some day ago, and now it’s time to restart the work in my garret (and in the Garretlabs). It seems that your visits to my little blog during August increased…so many many many (many) thanks to you all! 🙂
Once returned from my vacation, my dear friend Luka Cekka (it isn’t his real name, so he isn’t a Russian guy, but a real Italian guy, and he is a “spitting image” of Tim Robbins in “Antitrust”…have you seen the movie? 😉 ) asked to me to realize a thermostat with touch screen for his new house thermo installation.

LukaCekka

My friend Tim Robbins… ehmm Luka Cekka! 😉

So… I realized the first prototype using my old friend Arduino UNO, a temperature and humidity DHT22 sensor and the well known Adafruit TFT 2.8” touchscreen. (http://www.adafruit.com/products/1651). As usual, I bought the touchscreen from Robot Italy, my preferred italian store!
Well, in order to extract the necessary pins for DHT22 and a led (used as alarm monitor for the thermostat), I inserted between Arduino and the TFT screen a cheap proto shield (from Sparkfun) modified and transformed in a very useful “breakout shield”.

Once created the “sandwich” with Arduino, the breakout shield and the TFT, I connected to Arduino the DHT22 and the alarm led on the breadboard.
This is the Fritzing diagram (please, see the note and pay attention to the use of Arduino pins in order to drive the Adafruit TFT):

Cekka_controller_v1(one temp sensor)_bb
Regarding the software, I started using the following ad-hoc DHT22 library (and one very useful example found on internet) and verifying that the sensor was OK (and the alarm led ON/FF strategy).
Secondly, I added the code to manage the visualization of the temp on TFT, starting from the well coded examples from Adafruit libraries.
I decided to have two software modes: in the “temps” mode you can see the actual temperature acquired from DHT22. In this mode you can touch the software button “SETUP” on the touchescreen in order to enter “setup” mode. In “setup” mode you can adjust the alarm temperature using two software buttons on the touchscreen (one “+” button and one “-” button). You can return to “temps” mode touching the “TEMPS”software button. …All simple! 😉

This is the complete Arduino code for my application:

#include "DHT.h"
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_ILI9341.h>
#include <Adafruit_STMPE610.h>

//Adafruit screen data
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 130
#define TS_MAXX 3800
#define TS_MAXY 4000

//define screen and touch screen plus control signals
#define STMPE_CS 8
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
#define TFT_CS 10
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

//temperatures frame
#define FRAME_X_T 80
#define FRAME_Y_T 6
#define FRAME_W_T 150
#define FRAME_H_T 150
//button frame
#define FRAME_X_B 210
#define FRAME_Y_B 180
#define FRAME_W_B 100
#define FRAME_H_B 50

//declare temp sensor
DHT dht;

//declare inital default max temp (setpoint) in order to signal an alarm
float max_temp=27.0;

//display modes--->used to define the menu (in the right-low corner) button text and behaviour
 #define MODE_TEMPS 1
 #define MODE_SETUP 2
 int current_display_mode=MODE_TEMPS;//at startup we see the temps..
 //coords and dimension for the + and - buttons, used to set max temps...
 #define X_PLUS_B 224
 #define X_MINUS_B 270
 #define Y_PLUS_B 3
 #define BUTTON_W 40
 #define BUTTON_H 35

void setup()
 {
   //serial
   Serial.begin(9600);
   Serial.println();
   Serial.println("Status\tHumidity (%)\tTemperature (C)\t(F)");
   //Use pin D2 to read temp/hum from DHT22
   dht.setup(2);
   //set pin D5 to output (alarm pin)
   pinMode(5,OUTPUT);
   
   //initialize touch screen
   tft.begin();
   if (!ts.begin()) {
      Serial.println("Unable to start touchscreen.");
   }
   else {
      Serial.println("Touchscreen started.");
   }
   tft.fillScreen(ILI9341_BLUE);
   // origin = left,top landscape (USB left upper)
   tft.setRotation(1);
   
   //draw button TS
   drawMenuButton(current_display_mode);
 }

void loop()
 {
   //set delay
   delay(dht.getMinimumSamplingPeriod());

   //get values from DHT22
   float humidity = dht.getHumidity();
   float temperature = dht.getTemperature();
   
   //debug: print value on serial
   Serial.print(dht.getStatusString());
   Serial.print("\t");
   Serial.print(humidity, 1);
   Serial.print("\t\t");
   Serial.print(temperature, 1);
   Serial.print("\t\t");
   Serial.println(dht.toFahrenheit(temperature), 1);
   
   //print value on Adafruit screen
   if (current_display_mode==MODE_TEMPS)
   {
      drawFrameT();
      RefreshTemp1Value(temperature);
   }
   else if (current_display_mode==MODE_SETUP)
   {
      //nothing
   }
   
   //Management of max temp in order to activate the alarm (led)
   if (temperature>=max_temp)
   {
      //set HIGH alarm pin (D5)
      digitalWrite(5,HIGH);
   }
   else
   {
      digitalWrite(5,LOW);
   }
 
   //Management of Adafruit touchscreen
   // See if there's any touch data for us
   if (!ts.bufferEmpty())
   {
       // Retrieve a point
       TS_Point p = ts.getPoint();
       // Scale using the calibration #'s
       // and rotate coordinate system
       p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height());
       p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width());
       int y = tft.height() - p.x;
       int x = p.y;

       //check if the Menu button is pressed
       if((x > FRAME_X_B) && (x < (FRAME_X_B + FRAME_W_B)))
       {
          if ((y > FRAME_Y_B) && (y <= (FRAME_Y_B + FRAME_H_B)))
          {
              if (current_display_mode==MODE_TEMPS)
              {
                  current_display_mode=MODE_SETUP;
                  tft.fillScreen(ILI9341_BLACK);
                  drawMenuButton(current_display_mode);
                  
                  //draw the Temp max set points controls
                  drawCurrentMaxTemp1(max_temp);
              }
              else
              {
                  current_display_mode=MODE_TEMPS;
                  tft.fillScreen(ILI9341_BLUE);
                  drawMenuButton(current_display_mode);
              }
          }
      }

      //check if + or - buttons are pressed and adjust max temp
      if((x > X_PLUS_B) && (x < (X_PLUS_B + 40)))
      {
          if ((y > Y_PLUS_B) && (y <= (Y_PLUS_B + 35)))
          {
             if (current_display_mode==MODE_SETUP)
             {
                max_temp=max_temp+0.5;
                tft.fillRect(6,6,X_PLUS_B-3,Y_PLUS_B+BUTTON_H,ILI9341_BLACK);
                drawCurrentMaxTemp1(max_temp);
             }
          }
      }
      
      if((x > X_MINUS_B) && (x < (X_MINUS_B + 40)))
      {
         if ((y > Y_PLUS_B) && (y <= (Y_PLUS_B + 35)))
         {
            if (current_display_mode==MODE_SETUP)
            {
                max_temp=max_temp-0.5;
                tft.fillRect(6,6,X_PLUS_B-3,Y_PLUS_B+BUTTON_H,ILI9341_BLACK);
                drawCurrentMaxTemp1(max_temp);
            }
         }
      }
   }
 }
 

//Adafruit screen functions
void RefreshTemp1Value(float value)
{
 //drawFrameT1();
 //tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE);
 tft.setCursor(6 , 6);
 tft.setTextColor(ILI9341_WHITE);
 tft.setTextSize(4);
 tft.print("T1= ");
 tft.println(value);
}

void drawFrameT()
{
 tft.fillRect(FRAME_X_T, FRAME_Y_T, FRAME_W_T, FRAME_H_T, ILI9341_BLUE);
}

void drawMenuButton(int current_mode)
{
 tft.fillRect(FRAME_X_B, FRAME_Y_B, FRAME_W_B, FRAME_H_B, ILI9341_BLUE);
 tft.drawRect(FRAME_X_B, FRAME_Y_B, FRAME_W_B, FRAME_H_B, ILI9341_BLACK);
 tft.setCursor(FRAME_X_B+ 6 , FRAME_Y_B + 15);
 tft.setTextColor(ILI9341_RED);
 tft.setTextSize(3);
 if (current_mode==MODE_TEMPS)
      tft.println("SETUP");
 else if (current_mode==MODE_SETUP)
      tft.println("TEMPS");
}
void drawCurrentMaxTemp1(float value)
{
 tft.setCursor(6 , 6);
 tft.setTextColor(ILI9341_WHITE);
 tft.setTextSize(3);
 tft.print("MAX T1=");
 tft.println(value);
 drawPlusButton(X_PLUS_B/*224*/,Y_PLUS_B/*3*/);
 drawMinusButton(X_MINUS_B/*270*/,Y_PLUS_B/*3*/);
}

void drawPlusButton(int x, int y)
{
 tft.fillRect(x, y, BUTTON_W, BUTTON_H, ILI9341_BLUE);
 tft.setCursor(x+10 , y+5);
 tft.setTextColor(ILI9341_WHITE);
 tft.setTextSize(4);
 tft.print("+");
}

void drawMinusButton(int x, int y)
{
 tft.fillRect(x, y, BUTTON_W, BUTTON_H, ILI9341_BLUE);
 tft.setCursor(x+10 , y+5);
 tft.setTextColor(ILI9341_WHITE);
 tft.setTextSize(4);
 tft.println("-");
}

Ok, these are the photos of the complete project.

wpid-storageemulated0DCIMCamera2014-09-15-17.08.25.png.png

wpid-storageemulated0DCIMCamera2014-09-10-06.39.30.png.png

Note that on the screen there are four temperature values: I’m now working on a more powerful application in order to match Luka request (he wants to use four DHT22 sensors in his house… I think I will use a input multiplexer with the Arduino UNO, or more simply an Arduino Mega! 😉 ).
But you can use this project in order to add the powerful Adafruit TFT touchscreen to your application.
Only two notes on the Adafruit TFT:
1. the screen refresh is slow (very slow in my opinion), but it’s an acceptable issue in embedded projects
2. the touchscreen is natively very sensitive to human touch, so if your touch is “too long” it will be detected as a multiple touch. You could implement some “low-pass software filter” (i.e. you could manage the touch only after a multiple touch).

Well boys and girls, now you have a thermostat with a touch screen for your hi-tech house. I hope Luka will be happy with his new toy (but I’m not sure..he is a very perfectionist guy! 😉 ).
…But attention friends, the touchscreen will record your fingerprints ;-), so clean it with attention…especially if you don’t like CSI! 🙂

Bye bye!

Advertisements

The GL holidays post: a multifunction anti-intrusion system using Arduino!

….Thanks God it’s holidays time, my dear geeks! 🙂

Well… during these days it isn’t a good idea to remain in a dark and little microelectronics laboratory, it’s a better solution to close your laboratory in order to go in a good house/hotel by the sea (or at the mountains)! 😉

So, today Garretlabs wants to propose you a very simple (but) all-in one solution of house anti-intrusion alarm system, based on Arduino UNO.

This basic idea is very compact (but you can add all the subsystem you invent/want):

  • we will monitoring a set of house internal doors via a “wired connection”, using the digital in/out Arduino pins in order to detect a door openting (…I confess: this is inspired from a old joke which I knew 😦 during a high school week at the mountains … as we say in Italy literally “White Week” that is “Settimana bianca”)
  • we will also manage a ultrasonic sensor in order to monitoring tha opening of another house internal door
  • in case of door opening detection, we will send an alarm email using the well known Arduino Ethernet Shield

This is, as usual, my hand-made design of the system 🙂 :

2014-07-22 09.17.29

The part list is (as usual) very short, because my goal is to use (when possible) only the parts present at the moment in my …garret! 😉

  • One Arduino UNO
  • One Arduino Ethernet shield
  • One ultrasonic sensor
  • Assorted cables (never too many! ;-))

This is the Fritzing circuit (click on the image to see it bigger):

Ultrasonic alarm v1_bb

Well, remember to the Arduino place in a safe and fixed position in the house (for exaple fixed on the roof or fixed inside a electrical box on the wall) because if someone will open one of the doors connected by wire, our goal is that the wire will be disconnected from one of the two used Arduino digital pins (in order to open the controlled signal circuit).

Now, let’s go to code some line. The ultrasonic sensor is managed by the excellent newPing library, and the code to send email using the Arduino Ethernet shield is took from the my preferred site about Arduino resources (the only and one Arduino.cc …”made in Italy” rules! :-)), and modified by myself. The specific link is the following: http://playground.arduino.cc/Code/Email.

So, this is the code.

#include <SPI.h>
#include <Ethernet.h>
#include <NewPing.h>

#define TRIGGER_PIN 6 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 7 // Arduino pin tied to echo pin on the ultrasonic sensor.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

// choose the MAC!
byte mac[] = { 0x90, 0xAA, 0xAA, 0x00, 0x59, 0x67 };

// change network settings
IPAddress ip( 192, 168, 0, 30 );
IPAddress gateway( 192, 168, 0, 1 );
IPAddress subnet( 255, 255, 255, 0 );

// change to your server SMTP
char server[] = "out.alice.it"; //note I used my italian ISP provider server to send emails... :-)
EthernetClient client;
unsigned int initial_distance;
bool ULTRASONIC_ALARM_ARMED=true;
bool PERIMETRAL_ALARM_ARMED=true;
void setup()
{   
   //start ehternet and serial
   Serial.begin(9600);
   pinMode(13,OUTPUT);
   digitalWrite(13,HIGH);
   Ethernet.begin(mac, ip, gateway, gateway, subnet);
   delay(2000);
   //calibration of ultrasonic sensor
   Serial.print("Calibrating....");
   for (int i=0;i<100;i++)
   {
      delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
      unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
      initial_distance+=uS / US_ROUNDTRIP_CM;
   }
   
   initial_distance=initial_distance/100;
   Serial.print("Initial distance:");
   Serial.print(initial_distance);
   Serial.println("cm");
   digitalWrite(13,LOW);
   //setup the perimetral cable
   pinMode(10,OUTPUT);
   pinMode(11,INPUT);
   digitalWrite(10,HIGH);
}

void loop()
{  
   byte inChar;
   unsigned int distance=0;
   unsigned int medium_distance=0;
   //inChar = Serial.read();
   for (int i=0;i<20;i++)
   {
      delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
      unsigned int uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
      distance+=uS / US_ROUNDTRIP_CM;
   }
   medium_distance=distance/20;
   Serial.print (medium_distance);
   Serial.println (initial_distance);
   if(medium_distance<initial_distance && ULTRASONIC_ALARM_ARMED==true) //note that you can add a threshold in order to reduce false alarms
   { 
      if(sendEmail(1)) Serial.println(F("Email sent"));
      else Serial.println(F("Email failed"));
      ULTRASONIC_ALARM_ARMED=false; //the alarm should send only one email!
   }
   else
   {
      ULTRASONIC_ALARM_ARMED=true; //re-arm the alarm!
   }
   
   if(digitalRead(11)==LOW && PERIMETRAL_ALARM_ARMED)
   {
      if(sendEmail(2)) Serial.println(F("Email sent"));
      else Serial.println(F("Email failed"));
      PERIMETRAL_ALARM_ARMED=false; //the alarm should send only one email per violation!
   }
   else
   {
      //nothing to do: note that the perimetral wire alarm cannot be auto-rearmed! :-(
   }
}

//////////////////////////////////////////////////////////////////////////////
// Send email helper functions.
// Based on: http://playground.arduino.cc/Code/Email
//////////////////////////////////////////////////////////////////////////////

byte sendEmail(int type_alarm)
{
    byte thisByte = 0;
    byte respCode;
    if(client.connect(server,25)) {
        Serial.println(F("connected"));
    } else {
       Serial.println(F("connection failed"));
       return 0;
    }
    if(!eRcv()) return 0;
    Serial.println(F("Sending helo"));
    // change to your public ip
    client.println(F("helo 1.2.3.4"));
    if(!eRcv()) return 0;
    Serial.println(F("Sending From"));
    // change to your email address (sender)
    client.println(F("MAIL From: <your_email@alice.it>"));
    if(!eRcv()) return 0;

    // change to recipient address
    Serial.println(F("Sending To"));
    client.println(F("RCPT To: <your_recipient_address@your_provider.com>"));

    if(!eRcv()) return 0;
    Serial.println(F("Sending DATA"));
    client.println(F("DATA"));
    if(!eRcv()) return 0;
    Serial.println(F("Sending email"));
    // change to recipient address
   client.println(F("To: You <your_recipient_address@your_provider.com>"));

   // change to your address
   client.println(F("From: Me <your_email@alice.it>"));
   if(type_alarm==1) //ultrasonic alarm type
   {
      client.println(F("Subject: Arduino Ultrasonic alarm!\r\n"));
     client.println(F("The Arduino Ultrasonic alarm has been powered ON!"));
   }
   else if (type_alarm==2) //perimetral alarm type
   {
      client.println(F("Subject: Arduino Perimetral alarm!\r\n"));
      client.println(F("The Arduino Perimetral alarm has been powered ON!"));
   }
   client.println(F("."));
   if(!eRcv()) return 0;
   Serial.println(F("Sending QUIT"));
   client.println(F("QUIT"));
   if(!eRcv()) return 0;
   client.stop();
   Serial.println(F("disconnected"));
   return 1;
}

byte eRcv()
{
   byte respCode;
   byte thisByte;
   int loopCount = 0;
   while(!client.available()) {
      delay(1);
      loopCount++;
      // if nothing received for 10 seconds, timeout
      if(loopCount > 10000) {
          client.stop();
          Serial.println(F("\r\nTimeout"));
          return 0;
        }
     }
   respCode = client.peek();
   while(client.available())
   {
      thisByte = client.read();
      Serial.write(thisByte);
   }
   if(respCode >= '4')
   {
      efail();
      return 0;
   }
   return 1;
}

void efail()
{
   byte thisByte = 0;
   int loopCount = 0;
   client.println(F("QUIT"));
   while(!client.available()) {
      delay(1);
      loopCount++;
      // if nothing received for 10 seconds, timeout
      if(loopCount > 10000) {
          client.stop();
          Serial.println(F("\r\nTimeout"));
          return;
      }
   }

   while(client.available())
   {
      thisByte = client.read();
      Serial.write(thisByte);
   }
   client.stop();
   Serial.println(F("disconnected"));
}

Note that I used a SMTP email server which donesn’t use SSL access. In this case the SMTP sender library doesn’t work properly.

Well.. it’s very hot in Florence. I need a cold drink and a visit to a near pool. So, I think I will shutdown my computer now.;-)

But first…I hope you will have good vacation boys and girls. Your microelectronics worm should need a little time of relax, so see you soon at the end of August with other new open source ideas!

 

MIDin: a trasmitter/receiver sytem for MIDI messages using XBee and Arduino

Hi hi-tech friends (…with a prominent geek attitude 🙂 )!

This time I would like to talk about…MUSIC! Ta-daaaa!!

As you know I am also a musician, and I produce freely downloadable music from my music website www.marcolastri.net (only italian language, sorry!  ).

I have a large set of keyboards and synthesizers in my studio, and I have also a Roland AX-7, a “wearable” MIDI controller keyboard similar to a guitar (today these instruments are called “keytars” 😉 ). This keytar is used also by the mighty Herbie Hancock…. 😉

This keytar has also a great feature: it can be power by 6 AA batteries….but you will have always the midi cable in order to command your sound generator or expander (or software synth etc.). The midi cable is a limitation to your performance freedom on stage…so I want to cut it! 😉

There are some good wireless solution off-the-shelf, for example the Mid-Air product from M-Audio….and the price is not so low. 😦

…So I want to realize a DIY solution, using two Arduinos UNO, two XBee Shields and two XBee modules: this is the Garretlabs MIDin project! Ta-daaaa!

I bought from my preferred store (www.robot-italy.com) the following components:

Then I connected these components to two Arduino UNO boards in order to realize: one component working as MIDI Receiver-XBee Sender and one component working as MIDI Sender-XBee Receiver.

Thi is the system overview…design handmade by ML! 😉

20140711_093503

First step: program the XBee modules

This is the more complex step…I don’t love it but (unfortunately) it is necessary.

We must to setup the Series 2 modules in order to enable the “AT mode” communication (the Series 2 chips support also another -more complicated- configuration, in order to realize very complex networks of XBee modules). In other words, we must to program the devices in order to simulate a point-to-point-connection, a true serial wireless connection.

The best tutorial I’ve found on the internet is the following: http://tutorial.cytron.com.my/2012/03/08/xbee-series-2-point-to-point-communication/comment-page-1/. I used it step-by-step in order to configure my XBee modules…and it worked great! 😉

Firstly I downloaded  and installed the X-CTU utility (only for Windows… 😦 ) from Digi site.

After this, I attached a wire to the RESET pin of the Arduino and I connected it to GND. Then I connected the XBee Shield with the XBee module onboard (remember to set his jumper on “USB”): this is the way to directly access the XBee modules for programming them using Arduino board USB connection. In other words, to program the XBee modules it’necessary to disable the ATMEGA chip, so…or you remove it, or you connect to GND the RST Arduino pin. 😉

So, I used as network ID the suggested number (1234), then I configured one module as Coordinator AT (setting in the values SH/SL of  serial number of Router module), and I configured the other module as Router AT (setting in the values SH/SL of Serial Number of Coordinator module).

Well, once configured, the two modules start to “talk” each other, and the leds on shields start to blink. To test the correct configuration you can use the procedure well explained in the  http://tutorial.cytron.com.my/2012/03/08/xbee-series-2-point-to-point-communication/comment-page-1/.

IMPORTANT NOTE: I used the default speed of serial connection (9600 bps) for XBee modules, since I noticed that if I change the data speed, the USB connection from Arduino IDE to Arduino in order to download applications should fatally fail.

 

Second step: the MIDI receiver-XBee sender

The difficult step is passed…so, one moment of relax now! 😉

Ok, let’s start with the secdond step.

This MIDI receiver/XBee Sender has one MIDI connector in order to receive MIDI signals from a synthesizer, the software collect them, then it uses the XBee serial link to send MIDI signals to the other system component (see the third step).

The circuit is very simple…. and it is based on the standard MIDI-IN circuit. See http://www.midi.org/techspecs/electrispec.php to see the details. I modified it a little (especially the optocoupler)…in order to match the parts I had in the “Garret” at the moment 😉 !

The components are:

  • 1x Optocoupler 4N35
  • 1x Diode 4148
  • 1x 100KOhm resistor
  • 1x 220Ohm resistor
  • 1x 3.3KOhm resistor

Note that in the schema I added the XBee module and the XBee shield on the right side of Arduino, in order to better explain the connections, but OBVIOUSLY their must be mounted ON the Arduino! 🙂

XBEE_sender+MIDI_receiver_Garretlabs_bb

The software is simply a MIDI messages collector and re-sender.

Note that I used a buffer to memorize a certain number of MIDI message before to send them, because if wen I receive a message I resend it immediately, I could loose another MIDI message incoming in the meantime. So, I used a “buffering approach”. I verified -as musician 🙂 – that the latency due to buffering is very (very) low, so this approach is acceptable. 😉

Note also that I use the Software Serial (the RX is on pin 10)  to receive MIDI messages, because XBee must use the Serial port.

 #include <SoftwareSerial.h>

SoftwareSerial MidiSerial(10, 11); // RX, TX

byte in_buffer[1024]; //maximum number of bytes arrived in one cpu cycle
unsigned int received_bytes;

void setup()
{
  Serial.begin(9600); //XBEE transmission
  MidiSerial.begin (31250); //MIDI transmission
  
  //led 13 used for debug
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  
  received_bytes=0;

}

void loop()
{
  if(MidiSerial.available()>0)
  {
      received_bytes=MidiSerial.available();
      for (int i=0;i<received_bytes;i++)
        in_buffer[i]=MidiSerial.read();  //save in the buffer all bytes arrived from MIDI port
      
      //write all bytes arrived in the present cycle (so, the input is decoupled from the output)
      digitalWrite(13, HIGH);
      for (int i=0;i<received_bytes;i++)
      {
        Serial.write(in_buffer[i]);
      }
      digitalWrite(13, LOW);
      
      //reset the counter of received bytes in the cycle
      received_bytes=0;
  }
}

In order to write the program on Arduino, you must set the XBee jumper on “USB” position (and obviously you must to remove the cable to ground connected to the RST pin…see step one!). After programming, you should set the jumper on “XBee” position.

 

Third step: the MIDI sender-XBee receiver

Well, this component is more simple than the previous: it receives the MIDI messages from Xbee serial wireless link and it resend them to the MIDI Out port, in order to command a sound generator, a expander or another synth.

Only one component in this case:

  • 1x 220Ohm resistor

This is the (simple) circuit. As you can note, the MIDI In and Out circuits are NOT mirrored (this is the standard)! ….What a strange design choice!!! 🙂

XBEE_receiver+MIDI_sender_Garretlabs_bb

 

And this is the Arduino software (the MIDI management functions are taken from http://arduino.cc/en/Tutorial/Midi?from=Tutorial.MIDI):

#include <SoftwareSerial.h>

SoftwareSerial MidiSerial(10, 11); // RX, TX

void setup()
{
  Serial.begin(9600); //XBEE transmission
  MidiSerial.begin (31250); //MIDI transmission
  
  //led 13 used for debug
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

}

void loop()
{
  
  if(Serial.available() > 0)
  {
    digitalWrite(13, HIGH);
    MidiSerial.write(Serial.read()); //receives the midi messages via XBEE...and send it to Synth
    digitalWrite(13, LOW);
  }
  //Test function
  //SendAllNotes();
}
////////////////////////////////////////////////////////////////////////////////////////////
//
// MIDI HELPER FUNCTIONS (taken from http://arduino.cc/en/Tutorial/Midi?from=Tutorial.MIDI)
//
////////////////////////////////////////////////////////////////////////////////////////////

void SendAllNotes() {
  // play notes from F#-0 (0x1E) to F#-5 (0x5A):
  for (int note = 0x1E; note < 0x5A; note ++) {
    //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
    digitalWrite(13, HIGH);
    MIDICommand(0x90, note, 0x45);
    delay(100);
    digitalWrite(13, LOW);
    //Note on channel 1 (0x90), some note value (note), silent velocity (0x00):
    MIDICommand(0x90, note, 0x00);   
    delay(100);
    
  }
}

//  Send a midi command.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:
void MIDICommand(int cmd, int pitch, int velocity) {
  MidiSerial.write(cmd);
  MidiSerial.write(pitch);
  MidiSerial.write(velocity);
}

Now you can write the software on Arduino,

And…well… that’s done! 🙂

To test the system you can connect a master keyboard (better if it is a keytar! 😉 ) to Midi Receiver-XBee Sender and a sound generator to Xbee Receiver-Midi Sender…. and you can try to emulate Sandy Marton’s (one of my 80’s Italo Disco heroes) performances with their faboulous keytars!

This is the mighty Sandy in one of his mighty performances:

sandy_marton

Well… it seems a DIY keytar!

 

Bye bye people, now I go to play some note with my AX7…I need a music overdose (I think today I will write an italo-disco song)! 😉

And…remember tio visit my music site www.marcolastri.net!

 

Arduino + Raspberry= Weather station with webcam (Part Four: the internet connection…. and the conclusion!)

…Gooooood morning Vietnam!!!!

Ehmmm…good morning my dear geeks! 😉

A little lapsus is acceptable today, since today we finish the Weather Station project based on Raspberry and Arduino! 🙂 🙂

First thing: if you lost my previous three post on this marvelous project, please, read them: One, two, three! They contain not only the steps to build the weather station, but also general concepts about data acquisition, I2C connection, webcam integration and so on… 😉

Ok, today firstly we connect our weather station to internet. In order to do it we must use a 3G dongle (or a 3G expansion card for Raspberry). Note that the well known SIM900 Raspberry Addon (see my posts on it) is not suitable since it is a GPRS card.

 

The internet connection

For this purpose I used an old 3G dongle by Vodafone (with a SIM card by TIM inside). This dongle is a HUAWEI K3715 (a.k.a E 180).  With an infinite luck 🙂 I noticed that this dongle is automatically recognized as USB modem by Raspbian…. this is not the case of (for example) the HUAWEI E1820 (another dongle that I have at home).

So, the dongle is mapped by Raspbian at /dev/ttyUSB0 (you can verify it with dmesg or lsusb commands).

Let’s go on.

Firstly we must install screen (the AT commands wrapper) and wvdial (the PPP dialer) applications.

#sudo apt-get install screen
#sudo apt-get install wvdial

After this you must modify the /etc/wvdial.conf in order to match your 3G dongle.

In my case (TIM service provider, with HUAWEI K3715 dongle) the file is:

[Dialer defaults]
Init = AT
Init4 = AT0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CGDCONT=1,"IP","ibox.tim.it"
Phone = *99***1#
ISDN = 1
Username = a
Password = a
Modem = /dev/ttyUSB0
Baud = 460800
Stupid Mode = on

Some mysterious initialization is created ” by default” by wvdial. 🙂

Anyway, note that important lines for your configuration are: Init3 (where I placed my access point ibox.tim.it),  Username and Password (mandatory for wvdial, but with TIM you can insert a dummy user, I placed “a” in both cases), the Modem path and the Phone number (also *99# can work well with  my dongle).

After having saved the configuration file you can launch:

#sudo wvdial

…If all works well you will see the PPP connection steps, the IP address assignment etc. So, opening the browser you could surf on Internet! 🙂

 

The Dynamic DNS

Well, at this point you can surf the Internet, but it’s important to access to your Weather Station FROM Internet.

Since you have a dynamic IP assignment, you must use a service called Dynamic DNS in order to access to your Raspberry using always the same name (for example: mystation.dyndns.org).

In order to do it, firstly you must register to a Dynamic DNS site (I use always http://dyn.com/dns/). Note that Dyn.com is a pay service (but you have 30 days to try it)… and the price is effordable  (25 $ for year, and you can register up to 30 domains).

After this you must install on Raspberry a dynamic DNS client application. I used ddlclient.

#sudo apt-get install ddlclient

The configuration of the app is done launching:

#sudo dpkg-reconfigure ddlclient

You should insert the following parameters:

  • Name of service: http://www.dyndns.com
  • User: the username with wich you registered on Dyn.com (i.e. myuser)
  • Password: the password with wich you registered on Dyn.com (i.e. mypassword)
  • Interface on wich activate the client: ppp0 (it is the PPP on the USB 3G dongle)
  • activate ddlclient when ppp0 starts: Yes
  • Domain: the domain you registered on Dyn.com (i.e. mystation.dyndns.org)

Ok, at this point add to /ect/rc.local the following line, in order to automatically start the internet connection at Raspbian boot:

sudo wvdial &

Weeeeeelllll… this was a ordeal! 🙂

 

The web access from Internet

Do you remember that in my previous post I added the mjpg-streamer web server in rc.local?

So, if all works well, now you will see what your webcam images opening a browser from you Internet connected tablet, phone or pc and writing on the address bar:

http://mystation.dyndns.org:8090

But….what happens if the internet connection goes down? You should try to automatically relauch wvdial (or reboot), or you cannot (NEVERMORE) access to your station.

In order to do it I wrote a little .sh script that checks the internet connectivity.

This is the script:

#! /bin/bash
# Sending the output of the wget in a variable and not what wget fetches
RESULT=`wget --spider http://www.google.it 2>&1`
FLAG=0

# Traverse the string considering it as an array of words
for x in $RESULT; do
    if [ "$x" = '200' ]; then
        FLAG=1 # This means all good
        echo  "Internet OK, Google responded!"
    fi
done

if [ $FLAG -eq '0' ]; then
    # Probably internet key TIM is down...
    echo "Internet down"
    #....triyng to reconnect TIM key
    sudo reboot
fi

It checks if Google is accesible (using wget) from your station, and if not, it forces a reboot. This script must be lauched every X minutes in order to reboot the system if the Internet connection is down (so, to retry the PPP connection process). So, I added it to the crontab:

#sudo crontab -e

And at the end of crontab I added the following line (then I rebooted the board):

*/5 * * * * /home/pi/internet_conn_check/internet_check_daemon_v1.sh

The script is launched every 5 minutes. If the Internet is down, a reboot of the station is commanded. 🙂

 

Mixing meteo data with webcam video

We are at the final steps, boys and girls, so you must do the last effort! 😉

In order to “see” the Arduino meteo data mixed with the webcam images, we must now modify:

  • The Raspberry acquisition application
  • A webpage using Javascript

In the step TWO of my Weather Station project I created on Raspberry a C application to acquire data from Arduino. It was printing the meteo data as output on the shell.

Well, this time I modify the program in order to save the meteo data in a text file. This is the way to communicate to the Weather Station webpage the actual meteo data (i.e. the webpage will read this file and it will display the meteo data mixed with the ).

I know this is a “rough” method, but it is only an idea: you can use your preferred approach. 😉

This is the modified C acquisition program for Raspberry.

 #include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
 
// The PiWeather board i2c address
#define ADDRESS 0x04

//commands
#define TEMP 1
#define HUMI 2
#define PRES 3
#define DEW 4

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-1";
 
int main(int argc, char** argv) {
 
  printf("I2C: Connecting\n");
  int file;
 
  if ((file = open(devName, O_RDWR))< 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }
 
  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);
 
  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }
 
  int command;
  FILE* meteo_data_file;

while (1)
{
  //open file for web page display
  meteo_data_file=fopen("../mjpg-streamer/www/meteo_data_file.txt","w");
  time_t mytime;
  mytime = time(NULL);
  fprintf(meteo_data_file,"%s\n<br>",ctime(&mytime));

  for (command= 1; command<=4; command++) {
    int val;
    unsigned char cmd[16];
 
    //printf("Sending %d\n", val);
 
    cmd[0] = command;
    if (write(file, cmd, 1) == 1) {
 
      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);
 
      char buf[5];
      if (read(file, buf, 4) == 4) { //read 4 byte from i2c (a float)
        float value_received;
    
    //convert 4 bytes received into a float
    memcpy((char*)&value_received,buf,4);
/*disable printf on shell... 
     if (command==TEMP)   
        printf("Temperature (°C)= %f\n", value_received );
    if (command==HUMI)   
        printf("Humidity (%)= %f\n", value_received );
    if (command==PRES)   
        printf("Pressure (hPa)= %f\n", value_received );
    if (command==DEW)   
        printf("Dew Point (°C)= %f\n", value_received );
*/
        //write the file used to display values on the webpage
          if (command==TEMP)   
                fprintf(meteo_data_file,"Temperature (C)= %f\n<br>", value_received );
        if (command==HUMI)   
                fprintf(meteo_data_file,"Humidity (perc)= %f\n<br>", value_received );
        if (command==PRES)   
                fprintf(meteo_data_file,"Pressure (hPa)= %f\n<br>", value_received );
        if (command==DEW)   
                fprintf(meteo_data_file,"Dew Point (C)= %f\n<br>", value_received );
      }
    }
 
    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }
 //close meteo data file
 fclose(meteo_data_file); 
//one sensors reading every 5 seconds
 usleep (5000000);
} 
  close(file);
  return (EXIT_SUCCESS);
}

FIRST NOTE: I placed the executable as you see from the code, I placed the acquisition executable in /home/pi/ and mjpg-streamer in /home/pi/mjpg-streamer.

SECOND NOTE: I save the meteo_data_file.txt in the /mjpg-streamer/www folder, since I found some difficulty to access other directories from inside the webpage javascript.

Compile with the old command:

gcc -o acquisition_task acquisition_task.c

Then add it to the /etc/rc.local in order to autostart it at boot time.

sudo /home/pi/acquisition_task &

Now, the final step: the webpage meteo.html, which mixes the webcam output with the meteo data.

NOTE: This file must be placed in the /mjpg-streamer/www folder!

Note that I modified one of example provided by mjpg-streamer in order to read and display (using a refresh button) the file containing the actual meteo data. 😉

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  <head>
    <title>MJPG-streamer</title>
    <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
    <link rel="stylesheet" href="style.css" type="text/css" />
    <script type="text/javascript" src="jquery.js"></script>    
    <script type="text/javascript" src="jquery.rotate.js"></script>
    <!--[if IE 6]>
    <link rel="stylesheet" href="fix.css" type="text/css" />
    <![endif]-->
    <script type="text/javascript">
    
    var phi = 0, flipped = 0, mirrored = 0;

    function setXformClass () {
        $('.xform').each(function(idx,el) {
            el.className = "xform x" +(flipped ? "-flipped":"") + (mirrored ? "-mirrored" : "") + "-rotated-" + phi;
        });
    }
    $(document).ready(function() {
        // set rotation angle phi and toggle rotate class
        $('#rotate').click(function() {
            phi = (phi + 90) % 360;
            setXformClass();
            if (phi % 180) {
                $('.xform-p').addClass('rotated');
            } else {
                $('.xform-p').removeClass('rotated');
            }
        });
        // toggle mirror class component
        $('#mirror').click(function() {
            mirrored = ! mirrored;
            setXformClass();
        });
        // toggle flip class component
        $('#flip').click(function() {
            flipped = ! flipped;
            setXformClass();
        });

//ML:::::when I click on refresh_meteo_data...I print the values of the file!    
$("#refresh_meteo_data").click(function() {
        $.ajax({
            url : "meteo_data_file.txt",
            dataType: "text",
            success : function (data) {
                $(".text").html(data);
            }
        });
    });
    });
    </script>
  </head>

  <body>

    <div id="sidebar">
    <br><br>
    <div class="button" align="center">
            <input type="button" id="refresh_meteo_data" value="Refresh Meteo Data!!" />
    </div>
    <br>
    <div class="text" align="center">
            ...No meteo data acquired at the moment! <br />
    </div>

    </div>

    <div id="content">
      <h1>Garretlabs Meteo Lab</h1>
      <h2>version 1.0 (released by Marco Lastri)</h2>
      <h2>https://garretlabs.wordpress.com</h2>

    <p id="xform">
        <button id="rotate"><div class="btnface"></div></button>
        <button id="mirror"><div class="btnface"></div></button>
        <button id="flip"><div class="btnface"></div></button>
    </p>
    <p class="xform-p"></p>
    <p id="streamwrap" class="xform-p">
        <img id="streamimage" class="xform" src="/?action=stream" />
    </p>

    <p>&copy; The <a href="http://mjpg-streamer.sf.net">MJPG-streamer team</a> | Design by <a href="http://andreasviklund.com">Andreas Viklund</a></p>

</body>
</html>

Ok, I simply added a button “Refresh meteo data” in the sidebar, and I added  a callback which, on each button click, reads the file “meteo_data_file.txt” and prints it on the sidebar of the webpage. I didn’t modify the final line, which reports the original team of mjpg-streamer….it’s a beautiful software and I want to remember once again!

….The final goal!!!

Well, the Garretlabs Weather Station is now ready.

When you open from your tablet, pc etc. the page:

http://mydomain.dyndns.org/meteo.html

you would see (if all works correctly) the following page:

Well...the meteo data on the left of frame will be argument of the next posts! ;-)

Then you can click the button “Refresh Meteo Data” you should see the last acquired meteo data values.

Well… it has been a very long and hard work, but now I can place my final Weather Station at Montecchio, a beautiful place near Firenzuola (in the country of Florence, but it is a very special mountain site).

wpid-20140618_182808.jpg

wpid-20140618_182751.jpg

wpid-20140618_183520.jpg

So…. now I can take my grappa, listening a good progressive rock album (or viewing a  70’s italian horror movie).

I think to deserve a little piece of relax, and you? 🙂

Bye bye babes! 😉

 

The dark side of porting Arduino sketches on Intel Galileo (part three: comparing Galileo and Arduino on realtime performances)

Hi dear geeks and Intel Galileo lovers!

I’m sorry if I abandoned for a while your preferred board…but as you know Garretlabs (and I) have many other interests (Raspberry based projects, music and so on…).

Today I want to front one of “dearest” problems of my life: the realtime behavior and characteristics of  boards.

I know, it is one of my preffered psychiatric problems: I want ALWAYS to know the realtime performaces of a board (and of his operating system, if present)  😉

So, this time I want to compare the realtime performances of Arduino UNO and Intel Galileo.

In order to do it, I used the most simple circuit that I know (and that YOU know): one blinking led.

Well, the circuit in Fritzing is:

test_realtime_Galileo_vs_UNO_bbAnd the software is the same (obviously) for both boards:

void setup() 
{
    pinMode (2,OUTPUT);
}
void loop() 
{
   digitalWrite(2,HIGH);
   delay(10);
   digitalWrite(2,LOW);
   delay(10);
}

So, the behavior of code should be very very (very) simple: 10 milliseconds the led is ON and 10 milliseconds it is OFF. So the GPIO2 output is a 5V square wave, with a period of 20 milliseconds  and a duty cycle of 50%.

I connected the channel 1 of my oscilloscope to TestPoint1 and the channel 2 to TestPoint2.

As you see the behavior of the two boards are very different: since the square wave of Arduino UNO (TestPoint 1) is fixed on the timeline with a period of 20 milliseconds, the square wave of Galileo is moving on the timeline and it has more long period than 20 milliseconds. It means that the period is not exactly 20 milliseconds, and it is variable.

This is the trace for Arduino UNO:

Oscill_arduino

As you see, the square wave is perfect (…note that the horizontal scale is 10 milliseconds for division)!

This is the trace for Intel Galileo (stopped in a certain moment, since the trace is continously shifting right):

Oscill_galileo

Well...in this case the square wave  has a period major than 20 milliseconds (because each half wave has a duration major than 10 milliseconds).

Plus, if we measure two random periods, they havent the same duration (the continuous shift of the trace is depending on this).

These are both waveforms:

Oscill_arduino+galileo

So, for me the result is clear: since Arduino UNO commands GPIOs using a very strict realtime, Galileo does not command GPIOs with a realtime scheduling politics.

The motivation can be probably tied to the fact that Galileo launches Arduino scripts as Linux user processes (as I noticed in my prevoius post), so without realtime characteristics.

My conclusion is that, at the moment, we can’t use Galileo as hard realtime controller for particular hardware (ie. safety critical mechanisms and so on). 😦 …

And what are your thinkings about this behaviour of Galileo? Have you found my same results?

Obviously, possible solutions and workarounds are welcome (I thinked to modify the Intel Galileo native Linux in order to add some realtime extension, i.e. RT-PREEMPT or Xenomai).

So, the discussion is open! Let me know what you think! 🙂

…Bye bye electro-babes!

Arduino + Raspberry= Weather station with webcam (Part Three: the webcam)

Well boys and girls!

Here we are again…and this time we will SEE something with our project.:-)

I know that finally your voyeuristic tendencies (I know…I know) will be satisfied! 😉

Ok, do you remember the previous posts about meteo station? If not, go to the PART ONE and PART TWO!

Now, it’s time to connect ….the webcam! TA-DA!

I chose a very popular webcam by Logitech (…why? simply because it is cheap and it is natively supported by Debian and Raspbian!): the model is the well known C170, and I bought it on Amazon.it for approx. 19 euros.

The famous :-) Logitech C170

The famous 🙂 Logitech C170

The connection to Raspberry is very simple: connect it to one USB port of Raspi before the board power on, then after the Raspi boot sequence  it should be automatically mapped on /dev/video0 device.

I will use mjpg-streamer to remotely view the webcam stream, so we must to execute some preliminary (but necessary) step.

Firstly we must install SVN client, since mjpg-streamer is not in the Raspbian repository.

#sudo apt-get install subversion

Secondly we must download the mjpg-streamer sources in the Raspberry disk.

#svn co https://mjpg-streamer.svn.sourceforge.net/svnroot/mjpg-streamer mjpg-streamer

The last argument is the local folder where the sources will be saved.

IMPORTANT NOTE: some day ago the svn repository for mjpg-stream should be changed, so svn command should return an error reporting also the NEW svn repository path. You should relaunch svn command using the new/right svn repository path.

After this we must also install libjpeg8-dev and imagemagick.

#sudo apt-get install libjpeg8-dev
#sudo apt-get install imagemagick

After this, we must compile mjpg-streamer entering the folder /home/pi/mjpg-streamer (the sources location) and launch the old (very old 🙂 ) make command.

Cross the fingers ;-)….. and voilà, les jeux sont faits! 🙂

In order to remotely view (i.e. inside Firefox or IE) we must now activate the webserver provided by mjpg-streamer.

The command line (a little difficult to read but it works very well in my case) is:

# ./home/pi/mjpg-streamer/mjpg_streamer -i "/home/pi/mjpg-streamer/input_uvc.so -d /dev/video0 -r 320x240 -f 28" -o "/home/pi/mjpg-streamer/output_http.so -p 8090 -w /home/pi/mjpg-streamer/www" &

Well, only some clarification:

-i defines the input stream string

-d defines the video device (as mentioned, we use /dev/video0)

-r defines the video resolution (320 x 240)

-f defines the frame rate (28 frames/minute)

-o defines the output mode configuration (in this case the http is used)

-p defines the http port (in my case 8090)

-w defines the root for the webserver (where the webpages are placed)

Finally, note that the command should be launched in background (using the “&”).

Note also that some error will appear at command launch because C170 webcam doesn’t support all mjpg-streamer features (i.e. zoom), but NO PANIC. It should work correctly (I hope 😉 ).

Now…the test: type in your browser the following address http://192.168.0.x:8090 (where x is the address of your Raspberry) and you should see the demo page of mjpg-streamer with inside the stream image of your webcam. The live stream can be viewed in the subpages “Stream” or “Javascript”. For my meteo station I modified one of the demo pages in order to add the refresh of meteo data arriving from Arduino….but you will see this in the next episodes! 😉

This is rear garden of my house using mjpg-streamer…it’s a very strange view (from the ground) for my C170:

Well...the meteo data on the left of frame will be argument of the next posts! ;-)

Well…the meteo data on the left of frame will be argument of the next posts! 😉

What’s Montecchio? Ehmmm…that’s the name of the place where I will install the meteo station when it will be ready! 😉

OK, last recommendation: if you want to start automatically the mjpg-streamer webserver, you have to add the above command line to /etc/rc.local, as usual.

…Wellllll! 🙂

All good today, without pain. Strange, very strange…. 😉

So, the work on meteo station is more or less terminated: the only things to activate  for full functionalities are

  • the web page containg at the same time the webcam stream asnd the meteo data took from Arduino via I2C
  • the internet access of Raspberry using a 3G dongle with the aid of a Dynamic DNS service.

…But I ensure you that the difficult parts are already passed without (so high) difficulties.

So, see you soon geeks…keep always in touch with Garretlabs! 🙂

 

Raspberry and the remote controlled relay: a low-level approach (a.k.a. “AT modem commands: the usual suspects”).

Hi my dear microelectronics F&M (female & male) friends! 😉
Here we are again with the remote controlled 220V relay using a Raspberry PI. In my previous post I used a Huawei 3G dongle with the famous gammu daemon as SMS receiver.
But… do you remember the end of the post? I was talking about a thriller/horror movie by the great Lucio Fulci.
So, the horror turned to real, since gammu-smsd, after 20-25 minutes of correct activity, decided to die himself, without any clear cause. Or better, it continued running in background but when a SMS arrived, the daemon did nothing.
I tried to “reanimate” it in several ways, removing the screensaver and the blank screen from the Raspberry, writing a script which stop/restart the daemon every 5 minutes etc. But nothing changed. 😦
I noticed also after the above mentioned 20-25 minutes, the daemon start/restart (using sudo /etc/init.d/gammu-smsd start/restart) fails.
Only a reboot works in this case….but NO PANIC please! 🙂

I think there is some problem in gammu-smsd (related to Raspbian memory management? Hmmmm…I dont want investigate it because I want to live again 😉 ).
So….I decided to try another approach, using a more simple hardware and writing myself a more simple (= with a simple maintance and debug phases) software.
I bought the ITEAD GSM Sim900 module for Raspberry PI from my usual store (Robot Italy). Price: 37 euros. I think it is a good price for a GSM/GPRS phone without keys and display! 😉
I placed my SIM in the module, then I placed the module on the Raspberry.
The module reports the unused GPIOs on the higher side, so I connected the three wires used to command the relay (Vcc, GND and command) directly to the SIM900 module.
Note that the Vcc available on the SIM900 module is 3.3V , but I noticed that my relay module works well also using 3.3V instead the requested 5V. 🙂
Note also that GPIO18 used to command the relay in my previous post, is used now by SIM900 module as software reset, so I modified my relay ON/OFF scripts in order to use GPIO22.

This is the schema of SIM900 module used GPIOs:Mappatura RasPi GPIO-ITEAD SIM900
Ok, let’s go powering the Raspberry board (with a 2A minimum power supplier, since the SIM900 can use also peaks of current of 1A).
But firstly I needed the right soundtrack for this activity, and the right soundtrack in this case is “The City Sleeps”, a powerful and aggressive crossover-progressive rock cd, in my opinion the best work of Touchstone, the band of my friend Kim Seviour.

Let’s return to us… now the Raspberry boots up but the SIM900 module is powered off (no green led is ON on the surface).
There are two ways to power it on:

  • the first approach is to simply press the power on button :-). Too simple for me.;-)
  • the second way is to set the GPIO17 high….well, you know this is my preferred solution. 😉

The python code (remember you must before install python extensions devoted to GPIO commanding, following my previous post!) is the following:

#poweron the RPI GSM SIM900 module
def PowerON_SIM900_module():
    GPIO.setup(17,GPIO.OUT)
    GPIO.output(17,GPIO.HIGH)
    return;

Raspberry talks with SIM900 module via a serial link mapped on /dev/ttyAMA0, but Raspberry locks this port at startup. The document reporting the correct actions to free the serial port (before to try to talk with the module) are in ITEAD provided C library…but they are written in chinese! 😦
So I googled aroud a lot before to find the solution to this problem, damn! 😦
This is the correct procedure in order to “unlock” /dev/ttyAMA0 port (application note taken from ITEAD blog, related to another ITEAD product):

In /etc/bootline.txt change:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p6 rootfstype=ext4 elevator=deadline rootwait

to:

dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p6 rootfstype=ext4 elevator=deadline rootwait

and in /etc/inittab comment out or delete the following line (in my case it is the last line):

# T0: 23: respawn :/ sbin / getty-L ttyAMA0 115200 vt100

Well…after this, a reboot is necessary.

The Itead GSM module...with "The City Sleeps" of Touchstone!

The Itead GSM module…with “The City Sleeps” of Touchstone!

Now, I tried using the examples provided in the official C library from ITEAD, but I encountered some error (very strange errors, such as “SIM not registered, some unpredictable error code and so on…), so I decided to talk directly to SIM900 module using AT commands.

Firstly I installed the old, well known minicom software then I connected minicom to SIM900 module with the following (the “old style values”) parameters: port: /dev/ttyAMA0, speed: 9600 bps, no flow control, no parity, 8 bit per word, 1 stop bit.

I sent some famous AT commands, such as “AT” (in order to verify if the momdem is responding), “AT+CMGS” (in order to send to my phone a text SMS), etc. and I verified that all worked well.

Quasi-incredible! 🙂

At this point I decided to implement (in Python, of course) the main code, which: receives the SMS message (many thanks to this tutorial for inspiration of this part), parses them and, if a valid command is received, it powers ON/OFF the relay. Plus, the script can send to my phone  a SMS reporting the action (Power ON/OFF) executed.

I used only three AT simple commands:

  • AT (in order to verify if the communication between module and Raspberry is OK)
  • AT+CMGS (used to send SMS messages)
  • AT+CMGL= “REC UNREAD” (used to read received unread messages)

Note that I added some delay, since I noticed that in some case the modem is a little slow to execute the AT commmands and to reply. This is the complete Python code.

But first don’t forget to install the python extension for serial communication using sudo apt-get install python-serial.

#! /usr/bin/env python

import serial
import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)

#poweron the RPI GSM SIM900 module
def PowerON_SIM900_module():
    GPIO.setup(17,GPIO.OUT)
    GPIO.output(17,GPIO.HIGH)
    return;

def PowerONRelay():
    GPIO.setup(22,GPIO.OUT);
    GPIO.output(22,GPIO.HIGH);
    #send message to my phone that Relay is ON
    SendSMS(1);
    return;

def PowerOFFRelay():
    GPIO.setup(22,GPIO.OUT);
    GPIO.output(22,GPIO.LOW);
    #send message to my phone that Relay is OFF
    SendSMS(0);
    return;


def SendSMS(value):
   #send SMS about the action
   ser=serial.Serial('/dev/ttyAMA0',9600,timeout=1);
   ser.open();
   ser.write("at\r");
   time.sleep(3);
   line=ser.read(size=64);
   print line;
   ser.write('AT+CMGS="+39123456"\r');
   time.sleep(3);
   if (value==1):
       ser.write('Relay powered ON!\r');
   elif (value==0):
       ser.write('Relay powered OFF!\r');
   time.sleep(3);
   ser.write(chr(26));
   ser.close();
   return;

def CheckNewUnreadMessage():
   print "Check for new messages..\n";
   ser=serial.Serial('/dev/ttyAMA0',9600,timeout=1);
   ser.open();
   ser.write("at\r");
   time.sleep(3);
   line=ser.read(size=64);
   #print line;
   ser.write('AT+CMGL="REC UNREAD"\r')
   time.sleep(3);
   response=ser.read(size=200);
   print response;
   ser.close();
   return response;

#main loop
   PowerON_SIM900_module();
   print "Registering the sim...\n";
   time.sleep(15); #wait for sim to resgister to the net
   print "Started main loop\n";
   while True:
      message=CheckNewUnreadMessage();
      if(message.find("poweron")<>-1):
          PowerONRelay();
          print "PowerON commanded\n";
      elif (message.find("poweroff")<>-1):
          PowerOFFRelay();
          print "PowerOFF commanded\n";
     time.sleep(5);

As you see from the code, the new, unread SMS messages are checked every 5 seconds.

If a new message is found, it is copied in the message variable. If the message contains the poweron keyword the relay is powered ON. Else,  if it contains the poweroff keyword, the relay is powered OFF.

In both cases a SMS is sent to my phone (well… this is not my real number, also if I know you would like to know it! 😉 )

In order to auto-start the script after the Raspberry boot, you should add this command to /etc/rc.local (prior, remember to “executabilize” 😀  your script using the old chmod +x name_of_your_script.py ):

sudo /home/pi/name_of_your_script.py &

IMPORTANT NOTE: Add the “&” in order to launch in background the Python script, or you won’t be able to stop it neither using CTRL+C or swithcing shell . I will re-take the control of your Raspberry only via remote connection (using ssh)! 🙂

Now, rebooting the Raspberry, you will be able to receive/send SMS message using AT commands, power ON/OFF a 220V relay…and the most important thing: I tested the system for 3+ hours, and it worked well all time!!!

So ….I think we executed today another litlle step in my and in your “knowledge database system” called BRAIN. 🙂

Now I will take a relax time with the aid of the new Touchstone cd: “Oceans of Time”. It’s an kick-ass prog-rock album, of highest level guaranteed (as we say in Italy, it’s “Lemon guaranteed”, that is “Garantito al limone”).

Bye bye Raspberry freaks, it’s rock time for me! 😉