Introducing Particle.io’s Generation3 Internet of Things devices

The Internet is a wonderful thing. Check the weather, cat videos, message a friend, cat videos. There is this whole Internet of Things (IoT) which is the notion of connecting cat videos to the physical world. The information on the internet can affect (oh gawd, affect or effect) and also be updated by the physical world.

There are a range of projects that can be solved by this.

  • The weather is changing and you left your laundry out.
  • Where did you leave your bike
  • Worried about your cat while you are at work (and it’s not bring your cat to work day)

Endless!

Being an electronics engineer this is something I’ve done for a while though thanks to Particle.io this has become accessible to programmers and makers with minimal emphasis on knowing electronics and hitting your head against brick walls.

What I want to share here is how to get your ideas into internet connected reality.

The Good, The Bad, and The Ugly.

That probably isn’t a good analogy.

Particle.io recently released their Generation 3 hardware which are a bag of goodies to connect your projects to the internet in various ways.

Meet Xenon, Argon, Boron

Yes, my friends are elements of the Periodic Table. Geeky+

Common to each is that Particle.io gives you easy ways to hook the physical world into internet data sources (weather, maps, tweets, cat videos) and to update the devices remotely (code online, press button, presto) which is referred to as Over The Air (OTA) updates.

They are different because each give you different connectivity options. You select them based on your projects needs.

Xenon – Mesh

Argon – Mesh + WiFi

Boron – Mesh + Cellular

WiFi and Cellular are familiar as your phone does this. Mesh however is the new kid on the block.

Mesh allows for local communication between devices but also for it to ‘hop’ between devices extending their range.

Here is Zach, Particle.io CEO in a flattering pose.

Each person is representing a node, having a conversation with the person next to them. From there information is passed on, you get the picture, mesh for the local win.

Now that we have an idea of each device super power, we will not start making things with them! To Be Continued.

Saving water when it rains

With the recent rain I noticed that my sprinkler system continued to do its job, even when the garden had more than enough water. Why not automatically disable the sprinkler when it’s raining.

Rain sensor + Processor + H Bridge Driver + Solenoid = Fixed!

The red rain sensor feeds into the processor (Adafruit 32u4 feather, overkill) which drives a H Bridge that accepts 9V to drive a latching solenoid
ItemDetail
ProcessorAdafruit 32u4 feather
Rain sensorJaycar Rain Sensor XC-4603
9V batteryEnergizer 9V
Latching SolenoidSunshoweronline IVL-NYMV75620DCL
H BridgeAdafruit DRV8871

Reading the rain sensor

Below code reads an analog value then re-maps it. We then use a switch/case to determine 3 broad actions to return.

int readRainSensor(){
  // read the sensor on analog A0:
  int sensorReading = analogRead(A0);
  Serial.print("Reading rain sensor, currently:"+String(sensorReading)+", re-maps to:");
  // map the sensor range (four options):
  // ex: 'long int map(long int, long int, long int, long int, long int)'
  int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
  Serial.println(String(range));
  // range value:
  switch (range) {
 case 0:    // Sensor getting wet
    Serial.println("WET");
    break;
 case 1:    // Sensor getting wet
    Serial.println("MEDIUM");
    break;
 case 2:    // Sensor dry - To shut this up delete the " Serial.println("Not Raining"); " below.
    Serial.println("DRY");
    break;
  }
  
  return range;
  
  }

Driving the solenoid

I’ve chosen a ‘Latching’ solenoid for this application. This is to conserve the battery. A normal solenoid will down juice whenever you activate it while a latching only does to transition. The complication here is that a latching needs to recieve reverse polarity to ‘unlatch’. Ie drive it forward to open, and reverse voltage to close. As a result we cant use a relay, we will use a H-Bridge.

The below code sets up the two inputs of the H-Bridge then we can send it a valve request of OPEN or CLOSE. The latching solenoid needs power for a moment (I chose 300mS / 0.3 seconds) and then you can release to conserve battery.

This driver accepts:

Input 1Input 2Output
LowLowNothing / Coast
HighLowForward
LowHighReverse
HighHighBreak / Stop

I only mention the High + High out of interest. If this was a motor then we could apply the breaks with this mode.

#define MOTOR_IN1 9
#define MOTOR_IN2 10

#define OPEN 1
#define CLOSE 0

pinMode(MOTOR_IN1, OUTPUT);
pinMode(MOTOR_IN2, OUTPUT);

int valveControl(int request){
  int holdTime = 300;
  
  Serial.println("Setting valve to:"+String(request));
  digitalWrite(MOTOR_IN1, request);
  digitalWrite(MOTOR_IN2, !request);
  delay(holdTime);   
  //Stop power
  Serial.println("Releasing power");
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);

  return request;
  
  }

All together now

#define MOTOR_IN1 9
#define MOTOR_IN2 10

#define OPEN 1
#define CLOSE 0

#define RAINING 0
#define WET 1
#define DRY 2

// lowest and highest sensor readings:
const int sensorMin = 0;     // sensor minimum
const int sensorMax = 1024;  // sensor maximum
int stateOfValve = 0;

void setup() {
  pinMode(MOTOR_IN1, OUTPUT);
  pinMode(MOTOR_IN2, OUTPUT);
  stateOfValve = valveControl(CLOSE); //Initalise valve
  Serial.begin(9600);
  Serial.println("Sentinel");
}

void loop() {

  int currentWetness = readRainSensor();
  Serial.println("currentWetness:"+String(currentWetness));
  
  if(currentWetness == RAINING && stateOfValve == OPEN){
    stateOfValve = valveControl(CLOSE);
    Serial.println("Valve Request: CLOSE");
  }else if(currentWetness == DRY && stateOfValve == CLOSE){
    stateOfValve = valveControl(OPEN);
    Serial.println("Valve Request: OPEN");
  }

  Serial.println("Valve State:"+returnValveState(stateOfValve));
  
  Serial.println("");
  delay(1000);  // delay between reads
}



int readRainSensor(){
  // read the sensor on analog A0:
  int sensorReading = analogRead(A0);
  Serial.print("Reading rain sensor, currently:"+String(sensorReading)+", re-maps to:");
  // map the sensor range (four options):
  // ex: 'long int map(long int, long int, long int, long int, long int)'
  int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
  Serial.println(String(range));
  // range value:
  switch (range) {
 case 0:    // Sensor getting wet
    Serial.println("WET");
    break;
 case 1:    // Sensor getting wet
    Serial.println("MEDIUM");
    break;
 case 2:    // Sensor dry - To shut this up delete the " Serial.println("Not Raining"); " below.
    Serial.println("DRY");
    break;
  }
  return range;
  }

String returnValveState(int stateOfValve){
  switch (stateOfValve) {
    case 0:    // Sensor getting wet
      return "CLOSED";
      break;
    case 1:    // Sensor getting wet
      return "OPEN";
      break;
    }
  return "ERROR";
  }

int valveControl(int request){
  int holdTime = 300;
  
  Serial.println("Setting valve to:"+String(request));
  digitalWrite(MOTOR_IN1, request);
  digitalWrite(MOTOR_IN2, !request);
  delay(holdTime);   
  //Stop power
  Serial.println("Releasing power");
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, LOW);

  return request;
  }

Items for improvement

  1. Run from Solar. For this we need a boost controller and capacitor as we need a higher voltage as the common LiPo input is 3.2V. The capacitor will allow the solenoid’s inrush to be satisfied.
  2. Adapt for low power consumption – could be done either by implementing sleep mode or adding external watchdog.

LED Matrix – Getting Started with the Feather Wing

LEDs are AWESOME. What’s even better is a MATRIX of them. A matrix allows you to display pictures, text, and animate them. It can display what the weather will be for that day, your agenda for the day or entertaining emojis.

This post will explore getting started with the Matrix panel. You can run them from an Arduino Uno (slower re-fresh), Adafruit M0 (good for animations), Raspberry Pi (multiple matrix panels + internet connection).

We will explore the M0 feather route in this tutorial:

Things you will need:

  1. Matrix of LEDs
  2. Adafruit M0 feather
  3. Adafruit Matrix Backpack
  4. 5V power supply capable of 2 or more amps
  5. Computer with Arduino installed

Preparing Arduino:

Ensure Adafruit libraries are available

Arduino > Tools > Manage Libraries

Search for and install the Adafruit libraries by looking up: “gfx” and “RGB Matrix Panel”

Load an Example

Arduino > File > Examples > RGB matrix Panel > colorwheel_32x32 or which ever dimension your display is.

Adjust for your connections

Because each panel is wired differently we need to adjust for that. We are using the M0 Feather with the Matrix Wing we we need to adjust the following:

Add below code

// FeatherWing pinouts for M0 and M4
#define CLK  13
#define OE   1  // TX
#define LAT  0  // RX
#define A   A5
#define B   A4
#define C   A3
#define D   A2
// the RGB data pins on featherwing, must be on same PORT as CLK
uint8_t rgbpins[] = { 6,5,9,11,10,12 };
 
// Create a 32-pixel tall matrix with the defined pins
RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, false, 32, rgbpins);

Ensure you have the M0 board installed

Install both Arduino SAMD and Adafruit SAMD

Ensure your board is selected

Connect your board physically and then ensure your port is selected

Tools > Port > Select your USB connected device

Now, upload to your board!

Sketch > Upload

Lets explore what the code is doing:

#include <RGBmatrixPanel.h>

This is including the library that gives us access to all the good stuff. It allows us to create a panel easily later on and enumerates it as an object.

// FeatherWing pinouts for M0 and M4
#define CLK  13
#define OE   1  // TX
#define LAT  0  // RX
#define A   A5
#define B   A4
#define C   A3
#define D   A2
// the RGB data pins on featherwing, must be on same PORT as CLK
uint8_t rgbpins[] = { 6,5,9,11,10,12 };

This is the pinout for our specific model.

// Create a 32-pixel tall matrix with the defined pins
RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, false, 32, rgbpins);

This enumerates an instance of “RGBmatrixPanel” and calls it “matrix”, we pass in the parameters (pin configuration) of the panel. After this is done we can easily address the panel!

matrix.begin();

This kicks off the matrix, it needs to be run before we access any aspect as seen below

matrix.width();
matrix.height();

We can access parameters of the matrix so that we dont need to hard code anything ie we can dynamically do things. This basically passes back the parameters we setup the matrix with. In this case, 32 for both Width and Height

c = matrix.ColorHSV(hue, sat, val, true);

This creates a value that represents a pixels Hue, Satuation and Value. This still needs to be written to the screen.

matrix.drawPixel(x, y, c);

After we know the value we want, we need to write it to the pixel. The above code does this. For a specific X and Y location, write the pixel value C. In this instance, we are writing one pixel at a time, in a loop. This is why it progressively scans onto the matrix. Explore the other example scripts for more features of the library.