In this tutorial we will build a basic Arduino sensor that will read the status of a switch and send the result via our NRFL01 wireless network to the RaspberryPi. We will use a reed switch which is activated by moving a magnet within 1″ of the switch. This sensor is good for recognizing when doors are open/closed. I have also used this for detecting when my mail box has been opened, alerting me that I have new mail. Below is the Fritzing diagram of the circuit and pictures of my actual installation with the reed switch attached to my yard gate. The Fritzing diagram shows the Arduino being powered through the VIN pin from a 12V DC supply. This is my usual method for powering sensors, and you can pick up inexpensive 12V power supplies on-line that work well. However in the pictures you will note that I have a USB cable connected the Arduino which in the case is supplying the power. I used this because I had some spare USB wall chargers that I wanted to use up. Either option works.

Here is the Arduino code (note that if you intend to copy this code and use in your Arduino IDE you will get a compile error on line 42. This is because the text \&\&amp should really be &&. This is an error in how the web page displays & characters in code listings.)

#define MY_NODE_ID 18
#define MY_DEBUG
#define MY_RADIO_NRF24
#define MY_RF24_PA_LEVEL RF24_PA_MAX
#include <MySensors.h>

// configure parameters for reed switch sensor
#define SWITCH_PIN          2       // Pin for reed switch
#define CHILD_ID_SWITCH     0       // Child-id for switch messages
MyMessage msgGateStatus(CHILD_ID_SWITCH, V_TRIPPED);

int val = LOW;                               // variable to store the switch value read from the input pin
int switchState = LOW;               // value of switch after filtering out any transient noise using debounce timer
bool timerRunning = false;       // status of debounce timer

unsigned long lastDebounceTime = 0;                   // the last time the switch sensor changed state
const unsigned long debounceDelay = 1000;       // the time switch has to have been in a changed state before we accept it as real.




void presentation()
{
  sendSketchInfo("SIDE GATE SENSOR", "1.0");
  present(CHILD_ID_SWITCH, S_DOOR);
}

void setup()
{
  pinMode(SWITCH_PIN, INPUT_PULLUP);

   switchState =  digitalRead(SWITCH_PIN);             // read the switch pin
   send(msgGateStatus.set(switchState));                // send initial status of switch to gateway
   
}

void loop() {


  val = digitalRead(SWITCH_PIN);   // read the switch pin

    if (val != switchState &amp;&amp; !timerRunning ) {             // if switch has changed state, start the debounce timer
      // reset the debouncing timer
      timerRunning = true;
      lastDebounceTime = millis();
      Serial.println("-------- TIMER STARTED-------");
    } 

  // debounce timer
    
  if(timerRunning){                        

       if( val == switchState){             // has switch returned to prior state before debounce timer expires ?
           timerRunning = false;   
            Serial.println(" ======= TIMER EXITED ========");          
       }
        
       if ((millis() - lastDebounceTime) > debounceDelay) {
             // switch has lasted longer than debounce time, thus this is a real reading
             switchState = val;
             timerRunning = false; 
             Serial.print(" Switch status  = ");  Serial.println( switchState);  
              send(msgGateStatus.set(switchState));          
       }
    
  }

}


Lines 1-5 Configure the core parameters and load the MySensors library. MY_NODE_ID needs to be unique for each Arduino on your wireless network. I have used a value of 18, but any value from 1-254 can be used. (Note that Node ID of 0 is reserved for the gateway).

A single Arduino is capable of reading multiple sensors. In our case we have just one sensor, a single reed switch wired to pin 2. Each sensor is uniquely identified by the mySensors software by creating a C++ object of type MyMessage with a unique Child ID parameter.

The diagram below shows how the object named msgGateStatus is create and used to store and transmit sensor values (the payload) to the gateway. The mySensors library has a send() method that packages up sensor object data in a predefined format and transmits the data via the nRF24L01 wireless transceiver. Each transmitted package is a single text string made up of object parameters delimited with a semicolon (e.g. “18;0;1;0;16;1”). Below is a description of how these object parameters are set, and how to transmit a package of data from the Sensor Arduino to the Gateway.

Message Format
Message Format

In line 10 we create one object that we have called msgGateStatus. The object needs two parameters, the first parameter is the unique Child ID. The second parameter is the Message Type. We have used a child ID of 0 and a message type of V_TRIPPED. V_TRIPPED is simply an integer that is defined in the mySensors library as 16. The full range of variables for message type are defined on the mySensors documentation (https://www.mysensors.org/download/serial_api_20) . If we had more than one sensor (e.g. multiple reed switches) we would create multiple objects each with a different name and unique Child ID parameter.

The node-id parameter is set by defining a mySensors parameter MY_NODE_ID in line 1. Each Arduino on your network must have a unique Node-id. In this example I have used 18, but if this is your first node then you would start with 1. (Note that 0 is reserved for the node-id of the gateway).

The parameters, command and ack are defined and used by the mySensors software to interpret the message. We don’t need to worry about these at this stage.

We use the msgGateStatus.set() method on Line 33 to set the payload parameter equal to the current status of our reed switch. In the same line we also use the mySensors library send() method to transmit the objects parameters to the gateway. The send() method first serializes the parameters into a text string, with each parameter separated by a semicolon (e.g. “18;0;1;0;16;1”). This text string is what is transmitted via our NRF24L01 wireless network to the Gateway Arduino. As we saw in the prior tutorial ‘setting up your system’, the gateway simply echos this text string to our Raspberry PI via the USB connection. Once we have received this string data in our Raspberry Pi we can decompose the message to identify which Arduino sent it (node-id), the specific sensor (child-id) and the value of the sensor (payload).

The mySensors library also defines a function named presentation be defined (see lines 22-26 of code, also shown below)

void presentation()
{
  sendSketchInfo("SIDE GATE SENSOR", "1.0");
  present(CHILD_ID_SWITCH, S_DOOR);
}

This function is not mandatory but can be useful when troubleshooting as it sends some basic information about the node. The function contains two mySensors methods. sendSkethInfo() has two string parameters that provide a simple description and version information that you can use to manage your code. The present() method is used for each sensor child object you defined previously. It has two parameters, the first is the child id and the second a MySensors variable that defines the type of sensor as defined in the documentation (https://www.mysensors.org/download/serial_api_20). The use of the present() method is not essential in our projects as we will be writing our own Node.js application on the Raspberry Pi rather than use a 3rd party application such as openHAB.

The core execution code for our sensor is in the loop() method lines 37-68. This code reads the current value of the limit switch (line 40). If the state has changed and remains in this changed state for a defined time (debounceDelay) then we recognize that the gate has been opened or closed and report the new switchState to the Gateway. The reason for including a delay is due to a phenomena called switch bounce. When mechanical switches such as reed switches open or close they don’t always do so cleanly. Often they are noisy any the contacts bounce together, opening and closing quickly for a few milliseconds before reaching their new open or closed state. The loop() method runs repeatedly and is very fast, meaning that this noisy signal could result in many state changes being sent to the controller.

To overcome this issue the first time we detect the reed switch state has changed we start a timer (timerRunning=true on line 44 and lastDebounceTime = millis() on line 45). Only when the sufficient time has elapsed (line 58) do we register the change in state of the reed switch and send the new status to the gateway (line 63).

That’s it. Your new Gate open/closed sensor is ready for deployment. In the next tutorial I will describe how to decode the text string from the sensor when it arrives at your Raspberry Pi.

Leave a Reply

Your email address will not be published. Required fields are marked *