DIY category

MyPart, An Open Source Portable Air Particle Counter

One of the most harmful airborne pollutants with respect to human health is particulate matter. Air particle counters are used to determine the air quality by counting and sizing the number of particles in the air. This information is useful in determining the amount of particles inside a building or in the ambient air. It is also useful in understanding the cleanliness level in a controlled environment.

Airborne particles with a diameter of less than 10 microns pose a large risk, they can travel deeply into the respiratory system, causing a variety of cardiovascular and respiratory diseases. Combustion (e.g. burning wood; automobiles) can generate particles less than 2.5 microns in diameter. Between 2.5 and 10 microns are particles such as dust, pollen, and mold. (More information about particulate matter can be found here.)

Four members of the Hybrid Ecologies Lab at UC Berkeley, Rundong Tian, Sarah Sterman, Chris Myers, and Eric Paulos, developed “MyPart”, a device that attempts to measure air particulate matter.

MyPart’s design focuses on four goals; accuracy, size and portability, cost, and open source.

Accuracy

In the test chamber, smoke concentration was allowed to decay naturally over about 2 hours. Three prototypes of MyPart gave similar accuracy results to an expensive instrument results ($5000 MetOne HHPC-6).

Additional experiments conducted with calibration particles of known sizes and in outdoor ambient environments, and more information about the tests can be found here.

Size & Portability

The overall size of the inner sensing chamber is 18mmx38mmx45mm. These dimensions include an onboard 400mAh battery. The components related to the sensing are completely separated from the outer casing, which allows various form factors to easily be explored, developed, and shared.

MyPart sensor consumes about 2 mA while sleeping, and about 70mA during sampling.

Cost

The total cost for the bill of materials is around $75 without the cost of the digital fabrication tools required to make the components (3D printer and CNC mill). This BOM prices are for electrical components in quantities of 1 or 2, which will drop dramatically when purchased in bulk.

Open Source

MyPart’s original design files and source codes are all open source in order to give people the base form which to make and modify their own sensors, to set up sensing in their own communities, and to generate reliable air quality data.

The full BOM can be found here. The fabrication files, as well as the original design files can be found here.

MyPart’s Parts

  • Top air channel, Contains the main flow channel, a light trap for the laser light, and the air inlet.
  • Bottom air channel, Contains features to hold the fan, and the air outlet
  • Analog cap, shields the sensitive analog circuitry from ambient light
  • Fan, pulls air through the channel
  • Laser, focused light source to illuminate particles in the airstream
  • Laser holder, aligns the laser to the photodiode

Limitations

Optical scattering: The quantity and direction of light scattered by a particle is dependent on the size, composition, and shape of the particle, as well as where it strikes the laser beam. Because of these factors, accurate sizing of particles tends to be difficult with optical scattering sensors. However, rough size cutoff bins can still be produced by using the amplitude of signal peaks.

Full documentation, technical details, and how to build guide are reachable at this seeedstudio article and this instructable.

TP4056 3V3 Load Share Upgrade

A lot of project are battery powered and some of them need dual battery links. Robert on hackaday.io had shared his new project that shed light on this issue. He built an load sharing addon board with the ability to charge the battery while the project is operating.

Many Chinese charger boards are out there based on TP4056, but these boards don’t have the load sharing or voltage regulator features.

Load sharing means that you can power your circuit in two ways, from battery and from Vcc if a charger is connected. Once the charger is connected the battery will start charging and the load will be powered directly from Vcc. Robert added this feature to a recent design and also he added voltage regulation by using MCP1252.

The Components needed to build this project:

  • 1x  MCP1252-33X50/MS Power: Management IC / Switching Regulators
  • 1x  FDN304P: Discrete Semiconductors / Diode-Transistor Modules
  • 1x  SGL1-40-DIO: Schottky diode
  • 2x  100k 1206 resistor
  • 3x  10uF 1206 capacitor X7R
  • 1x  2.2uF 0805 capacitor X7R
  • 1x  ON/OFF switch (optional)
  • 2x  2 pin pcb connector
  • 1x  PCB from OSHpark

This schematic was inspired by multiple designs and modified by Robert.

“The advantage of MCP1252 is automatic buck/boost feature, it will maintain the regulated output voltage whether the input voltage is above or below the output voltage (2.1 to 5.0 V input range) so it is ideal for the lithium battery voltage. If you read the datasheet for the MCP1252-33X50I/MS there is clearly specified what type of MLCC capacitor should be used.”

The maximum output current of this board is 120mA and the output voltage is 3.3 V. It may sound not that suitable for your projects if you want to power an ESP8266, but still you can build your own board with different components to achieve the outputs you need. For example, by using MCP1253, which is identical to MCP1252, you will get  higher switching frequency (1MHz). Robert’s plan is to use this board with CO2 sensor (about 30 mA) and other low power sensors, some MCU and LCD, which can be powered using 120 mA.

Some measurements will be done to test the functionality of this board. To keep updated with the news of this project, you can follow the project on hackaday.io. You can also check other projects by Robert here.

Alarm System Powered By Arduino

Dejan Nedelkovski had built an Arduino security and alarm system project that uses an ultrasonic sensor for detecting objects and a buzzer for notification.

Components needed to build this simple system are: Arduino board, LCD display, 4×4 keypad, ultrasonic sensor and buzzer. The circuit can be connected as shown in the schematics below.

In order to build the project, you have to connect the buzzer with a PWM pin and the keypad pins where 4 of the 8 pins are for rows and the rest are for columns.

“The 4×4 keypad has 8 pins, 4 of them are for the rows and 4 of them for the columns of the keypad. Each button is actually a push button switch which makes a short between one row and column when pressed. So, for example, if we set the row 1 line low, and all column lines high, when we will press, for example, the button 3, due to the short between the two lines, the column 3 line will drop to low so in such a case we can register that the button 3 has been pressed.”

For connecting the LCD display and ultrasonic sensor you can check this detailed video tutorial by Dejan Nedelkovski and to see the project in action:

We want to activate the alarm by setting the A button to activate it. B button is used to change the password, and you need to enter the preset password “1234” to be able to change it.
After activating the alarm by pressing A, a 200 milliseconds sound will be produced from the buzzer showing that the alarm is now active. A message on the LCD display will appear to saying “Alarm will be activated in” and a countdown will be running afterwards until the alarm is completely active. At the end of the countdown a ” Alarm Activated” is on the display and the sensor will start working. Comparing with the initial distance at the start, the sensor will measure the distance is smaller than the initial distance, corrected by a value of 10 cms. The buzzer will  produce a sound if an object is observed as per the condition.

Here’s the complete source code of the Arduino alarm system:

/*
* Arduino Security and Alarm System
*
* by Dejan Nedelkovski,
* www.HowToMechatronics.com
*
*/
#include <LiquidCrystal.h> // includes the LiquidCrystal Library 
#include <Keypad.h>
#define buzzer 8
#define trigPin 9
#define echoPin 10
long duration;
int distance, initialDistance, currentDistance, i;
int screenOffMsg =0;
String password="1234";
String tempPassword;
boolean activated = false; // State of the alarm
boolean isActivated;
boolean activateAlarm = false;
boolean alarmActivated = false;
boolean enteredPassword; // State of the entered password to stop the alarm
boolean passChangeMode = false;
boolean passChanged = false;
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keypressed;
//define the cymbols on the buttons of the keypads
char keyMap[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {14, 15, 16, 17}; //Row pinouts of the keypad
byte colPins[COLS] = {18, 19, 20, 21}; //Column pinouts of the keypad
Keypad myKeypad = Keypad( makeKeymap(keyMap), rowPins, colPins, ROWS, COLS); 
LiquidCrystal lcd(1, 2, 4, 5, 6, 7); // Creates an LC object. Parameters: (rs, enable, d4, d5, d6, d7) 
void setup() { 
  lcd.begin(16,2); 
  pinMode(buzzer, OUTPUT); // Set buzzer as an output
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
}
void loop() {
  if (activateAlarm) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Alarm will be");
    lcd.setCursor(0,1);
    lcd.print("activated in");
   
    int countdown = 9; // 9 seconds count down before activating the alarm
    while (countdown != 0) {
      lcd.setCursor(13,1);
      lcd.print(countdown);
      countdown--;
      tone(buzzer, 700, 100);
      delay(1000);
    }
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Alarm Activated!");
    initialDistance = getDistance();
    activateAlarm = false;
    alarmActivated = true;
  }
  if (alarmActivated == true){
      currentDistance = getDistance() + 10;
      if ( currentDistance < initialDistance) {
        tone(buzzer, 1000); // Send 1KHz sound signal 
        lcd.clear();
        enterPassword();
      }
    }
  if (!alarmActivated) {
    if (screenOffMsg == 0 ){
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("A - Activate");
      lcd.setCursor(0,1);
      lcd.print("B - Change Pass");
      screenOffMsg = 1;
    }
    keypressed = myKeypad.getKey();
     if (keypressed =='A'){        //If A is pressed, activate the alarm
      tone(buzzer, 1000, 200);
      activateAlarm = true;            
    }
    else if (keypressed =='B') {
      lcd.clear();
      int i=1;
      tone(buzzer, 2000, 100);
      tempPassword = "";
      lcd.setCursor(0,0);
      lcd.print("Current Password");
      lcd.setCursor(0,1);
      lcd.print(">");
      passChangeMode = true;
      passChanged = true;   
      while(passChanged) {      
      keypressed = myKeypad.getKey();
      if (keypressed != NO_KEY){
        if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
            keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
            keypressed == '8' || keypressed == '9' ) {
         tempPassword += keypressed;
         lcd.setCursor(i,1);
         lcd.print("*");
         i++;
         tone(buzzer, 2000, 100);
        }
      }
      if (i > 5 || keypressed == '#') {
        tempPassword = "";
        i=1;
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Current Password");
        lcd.setCursor(0,1);
        lcd.print(">"); 
      }
      if ( keypressed == '*') {
        i=1;
        tone(buzzer, 2000, 100);
        if (password == tempPassword) {
          tempPassword="";
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("Set New Password");
          lcd.setCursor(0,1);
          lcd.print(">");
          while(passChangeMode) {
            keypressed = myKeypad.getKey();
            if (keypressed != NO_KEY){
              if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
                  keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
                  keypressed == '8' || keypressed == '9' ) {
                tempPassword += keypressed;
                lcd.setCursor(i,1);
                lcd.print("*");
                i++;
                tone(buzzer, 2000, 100);
              }
            }
            if (i > 5 || keypressed == '#') {
              tempPassword = "";
              i=1;
              tone(buzzer, 2000, 100);
              lcd.clear();
              lcd.setCursor(0,0);
              lcd.print("Set New Password");
              lcd.setCursor(0,1);
              lcd.print(">");
            }
            if ( keypressed == '*') {
              i=1;
              tone(buzzer, 2000, 100);
              password = tempPassword;
              passChangeMode = false;
              passChanged = false;
              screenOffMsg = 0;
            }            
          }
        }
      }
    }
   }
 }
}
void enterPassword() {
  int k=5;
  tempPassword = "";
  activated = true;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(" *** ALARM *** ");
  lcd.setCursor(0,1);
  lcd.print("Pass>");
      while(activated) {
      keypressed = myKeypad.getKey();
      if (keypressed != NO_KEY){
        if (keypressed == '0' || keypressed == '1' || keypressed == '2' || keypressed == '3' ||
            keypressed == '4' || keypressed == '5' || keypressed == '6' || keypressed == '7' ||
            keypressed == '8' || keypressed == '9' ) {
          tempPassword += keypressed;
          lcd.setCursor(k,1);
          lcd.print("*");
          k++;
        }
      }
      if (k > 9 || keypressed == '#') {
        tempPassword = "";
        k=5;
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(" *** ALARM *** ");
        lcd.setCursor(0,1);
        lcd.print("Pass>");
      }
      if ( keypressed == '*') {
        if ( tempPassword == password ) {
          activated = false;
          alarmActivated = false;
          noTone(buzzer);
          screenOffMsg = 0; 
        }
        else if (tempPassword != password) {
          lcd.setCursor(0,1);
          lcd.print("Wrong! Try Again");
          delay(2000);
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print(" *** ALARM *** ");
          lcd.setCursor(0,1);
          lcd.print("Pass>");
        }
      }    
    }
}
// Custom function for the Ultrasonic sensor
long getDistance(){
  //int i=10;
  
  //while( i<=10 ) {
  // Clears the trigPin
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH);
  // Calculating the distance
  distance = duration*0.034/2;
  //sumDistance += distance;
  //}
  //int averageDistance= sumDistance/10;
  return distance;
}

Check the project post to know more information and to find detailed tutorial. You can also check other posts by Dejan using this link.

RELATED POSTS

Dintervalometer, A Custom Made Intervalometer For DSLR Cameras

If you want to take a timelapse with your camera, it may be helpful to use an intervalometer. It is an attachment or facility on a camera that operates the shutter regularly at set intervals over a period, in order to take timelapse series or take pictures after a set delay.

Daniel Knezevic had developed a custom made intervalometer for DSLR cameras. Dintervalometer (Deni’s intervalometer) enables cameras to shoot time lapses and allows shutter speeds longer than the 30s.

The Dintervalometer is built with an Atmega328P clocked at 10MHz, a PCD8544 84×48 pixel monochrome LCD display with a backlight, a 3.5mm male jack connector, and two tactile push buttons all combined together on a small PCB.

Dintervalometer Features

  • Intervalometer: It is used for time-lapse photography. It controls how often, how long and how many shots are taken.
  • Bulb mode: It allows to take time exposures longer than 30s.
  • Backlight
  • Charging via USB

The Display & Backlight

The PCD8544 LCD display can be powered using 3V3 and it draws very small amounts of power (around 200uA) making it extremely good for use in battery powered devices. It is typically used in Nokia 5110/3310 phones, and it interfaces to microcontrollers through a serial bus interface (SPI).

A custom made backlight were designed to allow using the Dintervalometer in the dark without an additional lamp. It operates like a backlight of a cell phone: it is active for 10 seconds when the user presses a button or the Dintervalometer finishes some job.

The backlight consists of these materials:

  • A sheet of white paper
  • A piece of transparent plastic
  • A double-sided tape

The first layer of the backlight is a sheet of white paper. Its main function is to reflect the light of the LEDs. Then it comes the piece of transparent plastic. The top of the plastic is sanded with a fine sandpaper to diffuse the light. Finally, the LCD comes on the top. The layers are glued together with a double-sided tape.

Powering & Charging

Dintervalometer’s circuit is powered using a LiPo battery and a very low drop 3V3 voltage regulator (TPS79933). A MAX1555 Li+ battery charger IC is used to charge the battery, which also can be powered via USB.

To prevent the over-discharge of the LiPo battery, Dintervalometer monitors and measures the battery voltage every 60 seconds. The user can always see the current status of the battery on the LCD. When the battery reaches the critical voltage, a “Low battery” notification will be shown, then the device will turn off.

The voltage measuring process is done using a voltage divider and AVRs internal 1V1 voltage reference.

The following equation is used to measure the battery voltage in mV, with the known values R2=10k, R3=3k3, Vref=1100mV, ADCres=1024.

Controlling The Camera

Using the 3.5mm male jack connector, the Dintervalometer will trigger the camera to focus and to take a picture. The jack consists of three wires: ground, focus and shutter.

To focus the camera, the focus wire has to be connected to the ground. To release the camera both wires have to be connected to the ground. Dintervalometer is tested with Canon EOS 700D. It has a jack plug for remote shuttering.

The Software

The software is written in C and compiled with avr-gcc. It is divided into 6 logical modules:

  • TIMER: Initializes Timer1 and provides an interrupt based delay function.
  • BATTERY: Initializes ADC to read the battery voltage.
  • BACKLIGHT: Functions are used to control the backlight (initialize and update).
  • GPIO: Initializes IO ports for buttons, camera output, battery charger status indication, auto cut off control output.
  • LCD: It represents the pcd8544 LCD driver, it is reusable code for other projects. The driver provides the API to initialize, control, and print text on the LCD.
  • STATE: The state machine is implemented by using function pointers. Each menu state has three basic operations; show data on LCD, wait for user input, update backlight and battery status, and handle button presses/holds.
State Machine Diagram

Dintervalometer Sources

This project is published on hackady.io. Daniel had shared all the source designs and scripts online, so you can get it on its Github repository.

 

Arduino-Based Two-Way Pager

This Arduino-based pager by  Mike Schaus will allow you to send and receive real SMS text messages. This messaging device has its own SIM card and phone number.

In order to build this project you need the following parts:

And you will need to use this software to run the project: Hologram Data Router.

This project was made possible as part of Hologram’s Hacker-In-Residence program, The Hologram Global SIM Card allows you to connect you IoT device everywhere. Paired with a powerful device management platform and API. It provides a cellular data service that works with any device that accepts a SIM card. In addition it is totally inexpensive.

GSM shield, the Hologram things, and Arduino stacked on top of each other made a good combination to build such a project. For powering the project, Mike had used a 9V battery as an option, and still, powering from USB is possible.

Mike had designed this project so it could be used by children instead of a real cell phone, or it could be used as an “SOS” button for someone working alone outdoors or even exercising.

Check this video to know how this project works:

The amazing thing about Adafruit LCD shield that it only uses 2 pins of Arduino since it works over the I2C bus, which results with many places left for future features.

This is the schematics of the project: It is super easy, the wires mean putting the pieces on top of each other.

And here is the Arduino code used:

#include <GSM.h>

#define PINNUMBER ""

// include the LCD library code:
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>

// The shield uses the I2C SCL and SDA pins. On classic Arduinos
// this is Analog 4 and 5 so you can't use those for analogRead() anymore
// However, you can connect other I2C sensors to the I2C bus and share
// the I2C bus.
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

// These #defines make it easy to set the backlight color
#define OFF 0x0
#define ON 0x1

// make the arrow special character on the LCD
const byte arrow[8] =
{
 B00000, B00000, B01000, B01100, B01110, B01100, B01000, B00000
};

// initialize the GSM library instance
GSM gsmAccess(false); // include a 'true' parameter for debug enabled
GSM_SMS sms;

// char array of the telephone number to send SMS
// change the number 12125551212 to a number
// you have access to
char remoteNumber[20]= "12125551212";

// Array to hold the number a SMS is retreived from
char senderNumber[20];

// char array of the possible outgoing messages to choose from the menu
char* responses[]={"Mike=Awesome!", "Yes", "No", "Howdy!"};
//#define NUMRESPONSES 4 // if someone knows how to calculate this instead, I'm all ears
#define NUMRESPONSES (sizeof(responses)/sizeof(char *)) // thanks to Steve Kemp's comment!

int position=-1; // this way the first button press will always show first option of the menu

int inByte = 0; // incoming serial byte for keyboard interface

boolean backlight = true; // track backlight status for toggling

unsigned long previousMillis = 0; // will store last time messages were checked
#define CHECKINTERVAL 1500 // how often to check for text messages

void setup() {
  // put your setup code here, to run once:

  // initialize serial communications
  Serial.begin(9600);
  Serial.println(F("SMS Message Sender -- starting up..."));

  // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);

  // Print a message to the LCD
  lcd.print(F("Hello, Hologram!"));
  lcd.setCursor(0, 1);
  lcd.print(F("Starting up..."));
  lcd.setBacklight(ON);

  // set up the arrow character for display
  lcd.createChar(0, arrow);

  // connection state
  boolean notConnected = true;

  // Start GSM shield
  // If your SIM has PIN, pass it as a parameter of begin() in quotes
  while(notConnected)
  {
    if(gsmAccess.begin(PINNUMBER)==GSM_READY) {
      notConnected = false;
      Serial.println(F("GSM is connected because you are so awesome"));
      Serial.println(F("Waiting for messages, or send with \"s\""));
      Serial.println();

      lcd.clear();
      lcd.setCursor(0,0);
      homeScreen();

    }
    else
    {
      Serial.println(F("Not connected"));
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print(F("Not connected"));
      delay(1000);
    }
  }
}

// this is the menu system function
void showResponses() {
//  Serial.println(position); // only for debugging menu system

  lcd.clear();
  lcd.setCursor(0,0);
  
  // make sure cursor position is legal
  if (position<0) position=0;
  if (position>NUMRESPONSES-1) position = NUMRESPONSES-1;

  // write current selection and next option if there is another option
  lcd.write(0); //arrow character
  lcd.print(position+1);
  lcd.print("-");
  lcd.print(responses[position]);
  if (position < NUMRESPONSES-1) {
    lcd.setCursor(0,1);
    lcd.print(" ");
    lcd.print(position+2);
    lcd.print("-");
    lcd.print(responses[position+1]);
  }
}


void homeScreen() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("SMS Messenger!");
  lcd.setCursor(0,1);
  lcd.print("Ready; up/dn snd");

  position=-1; //reset response selection
}


void receiveSMS(){
  
  char c;

  // If there are any SMSs available()
  if (sms.available()) {
    Serial.println("Message received from:");

    // Get remote number
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);

    lcd.clear();
    lcd.setCursor(0,0);
    backlight = true;
    lcd.setBacklight(ON);

    // An example of message disposal
    // Any messages starting with # should be discarded
    if (sms.peek() == '#') {
      Serial.println("Discarded SMS");
      sms.flush();
    }

    // Read message bytes and print them
    // because sms.read only returns one character at a time
    int i=0;
    while (c = sms.read()) {
      i++;
      Serial.print(c);
      if (i==17) lcd.setCursor(0, 1); // move to next line if needed
      if (i<33) lcd.print(c); // don't try to print more than 32 chars just in case
    }

    Serial.println("\nEND OF MESSAGE");

    // Delete message from modem memory
    sms.flush();
    Serial.println("MESSAGE DELETED");
    Serial.println();

    // wait for right button to acknowlege before letting program continue
    boolean acknowledged = false;
    while(!acknowledged) {
      uint8_t buttons = lcd.readButtons();
      if (buttons & BUTTON_RIGHT) acknowledged = true;
      delay(50); //short delay for troubleshooting -- without this it behaves strangely
    }
    homeScreen();
    delay(400); // prevent multiple presses in a row
  }
}

// function to show message options in the serial monitor
void printResponseOptions(){
  for(int i=0; i<NUMRESPONSES; i++){
    Serial.print(i);
    Serial.print("-");
    Serial.println(responses[i]);
  }
  Serial.println();
}


void sendSMS(const char* txtMsg){

  Serial.print("Message to mobile number: ");
  Serial.println(remoteNumber);

  // print sms text info
  Serial.println("SENDING");
  Serial.println("Message:");
  Serial.println(txtMsg);

  // send the message
  sms.beginSMS(remoteNumber);
  sms.print(txtMsg);
  // next, add a signature to the chosen message
  sms.print(" --Be sure to connect with me on my blog http://mschausprojects.blogspot.com");
  // call endSMS function to finish sending; it will return 1 if successful
  if (sms.endSMS()==1) {
    Serial.println("\nCOMPLETE!\n");
    homeScreen();
  }
  else {
    Serial.println("\nERROR\n");
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("error");
  }
  Serial.println();
}



void loop() {
  // put your main code here, to run repeatedly:

  uint8_t buttons = lcd.readButtons();

  if (buttons) {
    if (buttons & BUTTON_UP) {
      position--;
      showResponses();
      backlight = true;
      lcd.setBacklight(ON);
    }
    if (buttons & BUTTON_DOWN) {
      position++;
      showResponses();
      backlight = true;
      lcd.setBacklight(ON);
    }
    if (buttons & BUTTON_LEFT) {
      homeScreen();
      backlight = true;
      lcd.setBacklight(ON);
    }
    if (buttons & BUTTON_RIGHT) {
      backlight = !backlight; // toggle the backlight state
      if (backlight) lcd.setBacklight(ON);
      else lcd.setBacklight(OFF);
      homeScreen(); // have to write to screen after turning light off, otherwise it goes blank
    }
    if (buttons & BUTTON_SELECT) {
      // make sure cursor selected position is legal
      if (position<0) position=0;
      
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Sending...");
      lcd.setCursor(0,1);
      lcd.print(responses[position]);
      backlight = true;
      lcd.setBacklight(ON);
      sendSMS(responses[position]);
    }
    delay(200); // prevent multiple presses in a row
  }


  // this is for serial interface only, not related to LCD and buttons
  // send a message when I type "s" in serial monitor
  // then wait for my selection of the response number
  if (Serial.available() > 0) {
    inByte = Serial.read(); // get incoming byte
    if (inByte == 's') {
      printResponseOptions();

      while (Serial.available() > 0) {  // clear the keyboard buffer just in case
        char junk = Serial.read();
      }
  
      while (Serial.available() == 0) ;  // Wait here until input buffer has a character
      inByte = Serial.parseInt();
      // would want to check for valid choice here to be more robust
      sendSMS(responses[inByte]);
    }
  }

  // check for new messages only once every few seconds to keep interface more responsive
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= CHECKINTERVAL) {
    previousMillis = currentMillis;
    receiveSMS(); // takes about 26ms when there are no messages
  }
}
CREDITS

R3tkcxkom1pu38aqb0bh

More details about this project are available on hackster.io and Mike’s own blog post. You can learn more about his projects on the same blog.

Dual Screen Netatmo Weather Station

Netatmo Weather Station is a module that measures your indoor comfort by providing vital information such as temperature, humidity, air quality, and CO2, alerting you when you need to air out your home to bring down its pollution levels.

fr8fd78ivcvqdh7-medium

One of the Netatmo limitations is that you need to use a smartphone to view the collected information by the station. To solve this, Barzok had developed an Arduino-based screen to display the weather data remotely, and published a full guide to build it in this instructable.

Barzok’s first attempt was a stand-alone device inside weather station using an Arduino UNO, a real time clock, a temperature and pressure sensor, and a 2.8” screen. It displays the time, pressure history over the past 6 days, and temperature as digits and as a gauge bar.

flxlafbivcvqchz-medium

The next experiment was connecting the Arduino UNO with Netatmo API through an Ethernet shield and displaying the data on the screen. The connection was the difficult part as the Arduino was not powerful enough to establish an HTTPS connection and receive valuable information from Netatmo servers.

The solution uses a PHP client on a web server, which connects with Netatmo servers, and then the Arduino retrieves the data using the standard HTTP.

f4bjzi3ivcvqcwg-medium-1

The final version of the station consists of an Arduino Mega, two 2.8” inches screens, and an ESP8266 Wifi module. There is no limit of the Arduino type and screen size, you can use your model with minor changes of the code. Barzok also made a custom circuit that transforms the 9V input voltage into a 5V to power the Arduino and 3.3V to power the ESP8266.

fdd0p87iva4yibz-medium

The diagram presents the process, the Netatmo module gathers the weather information and uploads them to the Netatmo servers. Then a PHP application runs on remote server and retrieves the information from the Netatmo servers and turns it into simple text data. Finally the Arduino receives the simple texts with the ESP8266 module and displays them on the two screens.

The two screens displays different information, the left one provides the real time data received from the Netatmo sensors about temperature, pressure, humidity, rain and CO2. The other screen shows the time and date, pressure history, and 3 days weather forecast.

f03ni4miva4yiem-medium

fyodjj4iva4yif3-medium

You can find more instructions to build this project with detailed description about the code, schematics, box design at the project page.

DIY Home Energy Meter

A new tutorial by The DIY Life is for building a home energy meter that provides information about power consumption and cost estimates for the month.

Using Arduino and some other components you can build your own energy meter that measure the supply current to your home through a CT (current transformer), current, power, maximum power and kilowatt hours consumed. The cost of electricity used to date can be added and displayed easily.

arduino-energy-meter-high-consumption

Electronics you need to build this project:

  • Arduino Uno
  • LCD Shield / LCD Screen
  • CT – Talema AC1030
  • 56Ω Burden Resistor
  • 10µF Capacitor
  • 2 x 100K Divider Resistors

If you are not familiar with Arduino or LCDs you can check these articles by The DIY Life to learn more: getting started with Arduino, connect an LCD screen

First you have to build the current sensor by connecting the CT to the Arduino and setting a right voltage reference due to the Arduino 0-5V input range. As shown below, this is the way you should connect the CT to the Arduino.

energy-meter-wiring-diagram

This code should be uploaded to your Arduino to run the project. It already has a scaling factor that can be adjusted due to the components you choose in your circuit.If you don’t want to use or don’t have an LCD screen, you can also modify the sketch to output to the Arduino IDE’s serial window as described in this code.

For more information on how to choose different components, how to calibrate them, and to learn more details about wiring and coding, you should check this tutorial out.

The first number displayed is the instantaneous current followed by the instantaneous power. On the bottom line, the kilowatt hours used since reset and then the maximum recorded power since reset. Check the meter in action:

DIY Pixel Art Frame Using Raspberry Pi Zero

Have you ever wanted to get an interesting art frame? That can display and flip photos, scroll text, show the weather or display social media notifications?

Frederick Vandenbosch’s new tutorial is for building an art frame using 32×32 LED matrix and Raspberry Pi Zero.

newimage-132

Electronics used in this project

You can watch a detailed step-by-step tutorial for assembling the frame in this video:


You can use the Adafruit RGB Matrix HAT like the tutorial to control the matrix and to make wiring simpler. But it is not mandatory, you can also wire the LED matrix directly to Pi’s GPIO. A USB Wifi adapter or dongle plugs into one of your desktop or laptop’s USB ports, allowing you to connect to a wireless network in the home, office, or a public place. You can use this connection to access shared files, devices, and documents, or to connect to the Internet. To connect this dongle with your Pi Zero you need a OTG USB cable. Connecting this dongle with your projects will open up for you doors of innovation, and that what made this frame cool!

The wiring is as described in this picture.

img_2833-1

Frederick used Raspbian Jessie “lite edition” for his Zero since the application is time-critical. Because it has more improvements, he preferred using Henner Zeller’s rpi-rgb-led-matrix library instead of the regular Adafruit library – which lately seemed an old version of the same series. He wrote a code to display and scroll ppm images, you can check it out here.

You can also use Raspberry Pi 3 in order to build this project, no need to change anything in software, and no need for the Wifi dongle since you can use the onboard Wifi. Things can be displayed on the matrix are unlimited. Since you have it connected with internet, this project could be your next IoT hack!

More details about this project and other amazing tutorials can be found at Frederick website.

Arduino Ouija Board

Ouija Board is a flat board marked with the letters of the alphabet, the numbers 0–9, the words “yes”, “no”, along with various symbols and graphics. It uses a small heart-shaped piece of wood or plastic called a planchette. Participants place their fingers on the planchette, and it is moved about the board to spell out words. The Ouija board is also called the spirit board and the talking board.

It was regarded as a parlor game unrelated to the occult until American spiritualist Pearl Curran popularized its use as a divining tool during World War I.

This board seems spooky! But how about combining it with Arduino? This project will introduce Arduino as the mind of this board with the planchette vibrating when it approaches certain letters plus opening a lock!

3c0hisxvd8f18esqyvsq

This project uses Radio-frequency identification (RFID) technology that uses electromagnetic fields to automatically identify and track tags attached to objects. The board has some RFID tags on its back at the exact positions of the letters and the planchette has RFID reader to be able to open the lock while choosing letters the same as the pre-configured password. Thanks to wireless technology used in this project, a radio receiver will control the lock when a password match happens!

In order to build this project you need to get a Ouija board or make one by yourself. Plus you need the following parts and materials:

You have to use Arduino IDE to program the Arduino mini.

seyvcjp8ai2mbt3f2fvy

The RFID reader is located within the planchette and it is attached to an Arduino and a battery, keeping in mind providing a place for the antenna in the planchette design. In the other side, the receiver is attached to the actuator and it contains an Arduino Pro Mini, a relay module, an NRF24L01 with a 1117-3.3 regulator attached, a separate 7805 linear regulator with some capacitors and LEDs.

zybml80obzwaptaz9h9b

You can check this board in action, the password here is “ Rose”

The sky’s the limit when it comes to choosing an actuator and the lock here in this project is just an example. You can check designs, code snippets, schematics and more detailed information about designing and programming this haunted Ouija board at the project’s page.

DIY Spectrum Analyser

Alan X has been working on a spectrum analyser project that can show the spectrum visually! He started working with ATTiny85 and kept on updating the project over time.

1952321477553334016

Alan X used Goertzel’s algorithm with a Hamming window, this algorithm can be used to detect a frequency from sampled data. Here is the preliminary code for a spectrum analyzer:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// Uses Daniil Guitelson's BGI library
#include "graphics.h" // -lBGI -lgdi32


#define SampleFreq 125000


int main(void)
{
  int N=250;
  double data[N];
  double samples[N];
  double freq;
  double s;
  double s_prev;
  double s_prev2;
  double coeff;
  double magn;
  int i;


  int gd=CUSTOM, gm=CUSTOM_MODE(700,700);
  initgraph(&gd, &gm, "");
  setcolor(WHITE);


  int X1,Y1,X2,Y2;
  double scale,xmin,ymin,xmax,ymax;


  // Find the maximum and minimum data range
  xmin=0;
  ymin=0;
  xmax=50000;
  ymax=N;
  scale=1.1*(xmax-xmin>ymax-ymin?xmax-xmin:ymax-ymin);


  // Generate samples
  for (i=0;i<N;i++) {
    samples[i]=(50*sin(2*M_PI*i*3300/SampleFreq)+50*sin(2*M_PI*i*5700/SampleFreq)+50*sin(2*M_PI*i*25700/SampleFreq)+100);
    // Window the data
    // data[i]=samples[i]; // Straight Goertzel - not great
    // data[i]=samples[i]*(0.5-0.25*cos(2*M_PI*i/N)); // Hanning Window
    data[i]=samples[i]*(0.54-0.46*cos(2*M_PI*i/N)); // Hamming Window
    // data[i]=samples[i]*(0.426551-0.496561*cos(2*M_PI*i/N)+0.076848*cos(4*M_PI*i/N)); // Exact Blackman Window
  }


  // Scan frequencies
  for (freq=100;freq<=50000;freq+=100) {
    coeff=2*cos(2*M_PI*freq/SampleFreq);
    s_prev=0.0;
    s_prev2=0.0;
    for (i=0;i<N;i++) {
      // Goertzel
      s=data[i]+coeff*s_prev-s_prev2;
      s_prev2=s_prev;
      s_prev=s;


    }


    // Get magnitude
    magn=2*sqrt(s_prev2*s_prev2+s_prev*s_prev-coeff*s_prev*s_prev2)/N;
    printf("Freq: %6f Mag: %6.4f\n",freq,magn);


    // Plot data
    X1=(int)((freq-(xmin+xmax)/2)*700/scale+350);
    Y1=(int)((0+(ymin+ymax)/2)*700/scale+650);
    X2=(int)((freq-(xmin+xmax)/2)*700/scale+350);
    Y2=(int)((-magn*700/2+(ymin+ymax)/2)*700/scale+650);
    line(X1,Y1,X2,Y2);


  }
  getchar();
  closegraph();


  return 0;
}

Daniil Guitelson’s BGI library was also used for the graphics.

Output

Here is the output showing the DC, 3300 Hz, 5700 Hz and 25700 Hz signals:

8398261477186172386

 

The next step is to port the code to a suitable Arduino board and to show the results physically. Thus, he used a MicroView OLED display and here it is listening to a 3v 1kHz square wave:

68801477279127568

 

#include <MicroView.h>

// Audio Spectrum Analyser
#define SampleInput A0   // Name the sample input pin
#define BandWidth  500   // BandWidth
#define MaxFreq   4000   // Max analysis frequency
#define Trigger     10   // Trigger to synchronise the sampler 2vpp at 1kHz = 32

// Define various ADC prescaler
const unsigned char PS_16=(1<<ADPS2);
const unsigned char PS_32=(1<<ADPS2)|(1<<ADPS0);
const unsigned char PS_64=(1<<ADPS2)|(1<<ADPS1);
const unsigned char PS_128=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

// Setup the serial port and pin 2
void setup() {
// Setup the ADC
pinMode(SampleInput,INPUT);
ADCSRA&=~PS_128; // Remove bits set by Arduino library
// Set prescaler
// ADCSRA|=PS_64; // 64 prescaler (250 kHz assuming a 16MHz clock)
// ADCSRA|=PS_32; // 32 prescaler (500 kHz assuming a 16MHz clock)
ADCSRA|=PS_16; // 16 prescaler (1 MHz assuming a 16MHz clock)

uView.begin();// Start MicroView
uView.clear(PAGE); // Clear page
uView.println("Spectrum  Analyser"); // Project
uView.println("0-20 kHz"); // Range
uView.println();
uView.println("agp.cooper@gmail.com"); // Author
uView.display(); // Display
uView.clear(PAGE); // Clear page
delay(2000);// Wait
}

void loop() {
static byte *samples; // Sample array pointer
static byte *window; // Window array pointer
static int N=0; // Number of samples for BandWidth
static long sampleFreq; // Sample frequency
long freq; // Frequency of interest
float s; // Goertzel variables
float s_prev;
float s_prev2;
float coeff;
float magn;
int i;

if (N==0) {
// Check sample frequency and set number of samples
samples=(byte *)malloc(100);
unsigned long ts=micros();
for (i=0;i<100;i++) samples[i]=(byte)(analogRead(SampleInput)>>2);
unsigned long tf=micros();
free(samples);
sampleFreq=100000000/(tf-ts);
N=2*sampleFreq/BandWidth+1;

uView.setCursor(0,0); // Set cursor to beginning
uView.print("SI: A"); // Sample input pin
uView.println(SampleInput-14);
uView.print("SF: "); // Sample frequency
uView.println(sampleFreq);
uView.print("MF: "); // Max frequency
uView.println(MaxFreq);
uView.print("BW: ");// andWidth
uView.println(MaxFreq);
uView.print("SN: ");// Number of samples
uView.println(N);
uView.display(); // Display
uView.clear(PAGE);// Clear page
delay(2000);

// Create arrays
samples=(byte *)malloc(N);
window=(byte *)malloc(N);

// Modified Hamming Window
for (i=0;i<N;i++) window[i]=(byte)((0.54-0.46*cos(2*M_PI*i/(N-1)))*255);

// Generate test samples
for (i=0;i<N;i++) {
samples[i]=(byte)(30*(sin(2*M_PI*i*5000/sampleFreq)+sin(2*M_PI*i*2500/sampleFreq)+sin(2*M_PI*i*7500/sampleFreq)+sin(2*M_PI*i*10000/sampleFreq))+127);
}
}

if (true) {
// Sychronise the start of sampling with data slicer
int a0,a1;
a0=1023;
for (i=0;i<N;i+=2) {
a1=analogRead(SampleInput);
a0=(a0*13+a1*3)/16;
if (a1>a0+3) break;
}
for (i=0;i<N;i++) samples[i]=(byte)(analogRead(SampleInput)>>2);
}

// Scan frequencies
for (freq=0;freq<=MaxFreq;freq+=(MaxFreq/40)) {
// Goertzel (https://en.wikipedia.org/wiki/Goertzel_algorithm)
coeff=2*cos(2*M_PI*freq/sampleFreq);
s_prev=0;
s_prev2=0;
for (i=0;i<N;i++) {
s=0.0000768935*window[i]*samples[i]+s_prev*coeff-s_prev2;
s_prev2=s_prev;
s_prev=s;
}
// Get magnitude
magn=2*sqrt(s_prev2*s_prev2+s_prev*s_prev-coeff*s_prev*s_prev2)/N;
// Display on MicroView
uView.line(freq*40/MaxFreq,47,freq*40/MaxFreq,10-(int)(20*log10(magn+0.0001)));
}
// Frequency graduations
uView.setCursor(47,0);
uView.print(MaxFreq/1000);
uView.print("k");
uView.line(0,0,0,5);
uView.line(10,0,10,2);
uView.line(20,0,20,5);
uView.line(30,0,30,2);
uView.line(40,0,40,5);
// Voltage graduations
uView.line(0,40,40,40);
uView.setCursor(47,38);
uView.print("-30");
uView.line(0,20,40,20);
uView.setCursor(47,18);
uView.print("-10");
uView.line(0,10,40,10);
uView.setCursor(47,8);
uView.print("  0");
//Display
uView.display();
uView.clear(PAGE);
}

He then updated the project to work with Nokia LCD, here it is showing the 0-3v 1 kHz square wave signal:

3095781477395166324

Amazing ideas and projects can be inspired by this project. You can download these files to start your own spectrum analyser!

The full project and detailed information are available at the project page on Hackaday. You can follow it to keep updates with the latest versions.