Triple Axis Compass Sensor for mailbox?



  • I know this question has been discussed before but would a Triple Axis Compass Sensor be a good alternative for a battery powered mailbox-sensor. I have a type of mailbox that is common in sweden where the lid gets lifted and I would place the sensor under the lid in that case.

    Or would a PIR that is placed in the lid be any better/worse from a battery conserving standpoint?


  • Mod

    @Cliff-Karlsson Can't you use a simple reed switch & magnet (like a door sensor)?
    These can be tied to an interrupt input of your Arduino and wake it when opening is detected.
    Power usage will be minimal and implementation is simple.

    When using a compass sensor you either have to monitor the signal continuously to detect movement (which consumes 'a lot' of power) or select one which can generate a trigger when a certain displacement is detected (don't know if these event exist -- acceleration sensors which gererate a trigger do exist). The trigger has to be tied to an interrupt pin of your Arduino, and your back at the reed switch suggestion...



  • Yes, a magnet-switch would probably work. But my main concern regarding the magnet-switch is that I sometimes receives rather large parcels witch are jammed down the mailbox and would possible break of any magnet-switch that are placed inside the mailbox. The lid is where any sensor would be most protected. I might go with the simple magnet switch method to try out the durability but I would like to know if there are any options.

    Would the Triple Axis Accelerometer from the mysensors-shop link work with just waking up when lid is moved? Or could a PIR be able to use interrupt to wake up?


  • Admin

    I've mounted mine like this:

    0_1461511346700_20130804_205852.jpg

    It's been sitting there for almost 3 years now.



  • My mailbox kid of looks like this: 0_1461511903532_binary-590546-277725.jpg


  • Mod

    @Cliff-Karlsson Could you post a real picture and draw where you would mount the compass sensor?
    I expect the compass sensor is even more fragile than a door sensor and wont last very long...



  • @Yveaux said:

    @Cliff-Karlsson Could you post a real picture and draw where you would mount the compass sensor?

    It looks similar to this one and I would place everything inside a sealed plastic box glued to the top of the lid if that kind of sensor is a good idea battery-wise.

    0_1461518850285_brevlåda.jpg


  • Mod

    @Cliff-Karlsson I would expect you can find a place to firmly glue a small magnet (neodimium) to the bottom part (the one with 'POST' on it) that will survive even your most extreme AliExpress deliveries 😉



  • Ahhh, that idea did not strike me that I could use a different neodymium magnet instead of the one that was shipped with the magnet-switch. I guess that I just can place a strong magnet on the side of the mailbox. No glue needed as I almost break my nails of when trying to get those 20x3(?)mm magnets of my refridgerator


  • Mod

    @Cliff-Karlsson They come in all sizes. The door-sensor part without wires contains just a magnet, nothing more.



  • I want to try to build simple sensor using the door/window/button sketch:

    
    #include <MySensor.h>
    #include <SPI.h>
    #include <Bounce2.h>
    
    #define CHILD_ID 3
    #define BUTTON_PIN  3  // Arduino Digital I/O pin for button/reed switch
    
    MySensor gw;
    Bounce debouncer = Bounce(); 
    int oldValue=-1;
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(CHILD_ID,V_TRIPPED);
    
    void setup()  
    {  
      gw.begin();
    
     // Setup the button
      pinMode(BUTTON_PIN,INPUT);
      // Activate internal pull-up
      digitalWrite(BUTTON_PIN,HIGH);
      
      // After setting up the button, setup debouncer
      debouncer.attach(BUTTON_PIN);
      debouncer.interval(5);
      
      // Register binary input sensor to gw (they will be created as child devices)
      // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage. 
      // If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
      gw.present(CHILD_ID, S_DOOR);  
    }
    
    
    //  Check if digital input has changed and send in new value
    void loop() 
    {
      debouncer.update();
      // Get the update value
      int value = debouncer.read();
     
      if (value != oldValue) {
         // Send in the new value
         gw.send(msg.set(value==HIGH ? 1 : 0));
         oldValue = value;
      }
    } 
    

    And also add the battery masuring from :

    #include <SPI.h>
    #include <MySensor.h>
    
    #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
    #define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
    
    #define CHILD_ID_MOISTURE 0
    #define CHILD_ID_BATTERY 1
    #define SLEEP_TIME 1800000 // Sleep time between reads (in milliseconds)
    #define THRESHOLD 1.1 // Only make a new reading with reverse polarity if the change is larger than 10%.
    #define STABILIZATION_TIME 1000 // Let the sensor stabilize before reading
    #define BATTERY_FULL 3143 // 2xAA usually give 3.143V when full
    #define BATTERY_ZERO 2340 // 2.34V limit for 328p at 8MHz. 1.9V, limit for nrf24l01 without step-up. 2.8V limit for Atmega328 with default BOD settings.
    const int SENSOR_ANALOG_PINS[] = {A0, A1}; // Sensor is connected to these two pins. Avoid A3 if using ATSHA204. A6 and A7 cannot be used because they don't have pullups.
    
    MySensor gw;
    MyMessage msg(CHILD_ID_MOISTURE, V_HUM);
    MyMessage voltage_msg(CHILD_ID_BATTERY, V_VOLTAGE);
    long oldvoltage = 0;
    byte direction = 0;
    int oldMoistureLevel = -1;
    
    void setup()
    {
      gw.begin();
    
      gw.sendSketchInfo("Plant moisture w bat", "1.5");
    
      gw.present(CHILD_ID_MOISTURE, S_HUM);
      delay(250);
      gw.present(CHILD_ID_BATTERY, S_CUSTOM);
      for (int i = 0; i < N_ELEMENTS(SENSOR_ANALOG_PINS); i++) {
        pinMode(SENSOR_ANALOG_PINS[i], OUTPUT);
        digitalWrite(SENSOR_ANALOG_PINS[i], LOW);
      }
    }
    
    void loop()
    {
      int moistureLevel = readMoisture();
    
      // Send rolling average of 2 samples to get rid of the "ripple" produced by different resistance in the internal pull-up resistors
      // See http://forum.mysensors.org/topic/2147/office-plant-monitoring/55 for more information
      if (oldMoistureLevel == -1) { // First reading, save current value as old
        oldMoistureLevel = moistureLevel;
      }
      if (moistureLevel > (oldMoistureLevel * THRESHOLD) || moistureLevel < (oldMoistureLevel / THRESHOLD)) {
        // The change was large, so it was probably not caused by the difference in internal pull-ups.
        // Measure again, this time with reversed polarity.
        moistureLevel = readMoisture();
      }
      gw.send(msg.set((moistureLevel + oldMoistureLevel) / 2.0 / 10.23, 1));
      oldMoistureLevel = moistureLevel;
      long voltage = readVcc();
      if (oldvoltage != voltage) { // Only send battery information if voltage has changed, to conserve battery.
        gw.send(voltage_msg.set(voltage / 1000.0, 3)); // redVcc returns millivolts. Set wants volts and how many decimals (3 in our case)
        gw.sendBatteryLevel(round((voltage - BATTERY_ZERO) * 100.0 / (BATTERY_FULL - BATTERY_ZERO)));
        oldvoltage = voltage;
      }
      gw.sleep(SLEEP_TIME);
    }
    
    int readMoisture() {
      pinMode(SENSOR_ANALOG_PINS[direction], INPUT_PULLUP); // Power on the sensor
      analogRead(SENSOR_ANALOG_PINS[direction]);// Read once to let the ADC capacitor start charging
      gw.sleep(STABILIZATION_TIME);
      int moistureLevel = (1023 - analogRead(SENSOR_ANALOG_PINS[direction]));
    
      // Turn off the sensor to conserve battery and minimize corrosion
      pinMode(SENSOR_ANALOG_PINS[direction], OUTPUT);
      digitalWrite(SENSOR_ANALOG_PINS[direction], LOW);
    
      direction = (direction + 1) % 2; // Make direction alternate between 0 and 1 to reverse polarity which reduces corrosion
      return moistureLevel;
    }
    
    long readVcc() {
      // From http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
      // Read 1.1V reference against AVcc
      // set the reference to Vcc and the measurement to the internal 1.1V reference
    #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
      ADMUX = _BV(MUX5) | _BV(MUX0);
    #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
      ADMUX = _BV(MUX3) | _BV(MUX2);
    #else
      ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #endif
    
      delay(2); // Wait for Vref to settle
      ADCSRA |= _BV(ADSC); // Start conversion
      while (bit_is_set(ADCSRA, ADSC)); // measuring
    
      uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
      uint8_t high = ADCH; // unlocks both
    
      long result = (high << 8) | low;
    
      result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
      return result; // Vcc in millivolts
    }
    

    Do I "just" add these parts to the first sketch to have battery measuring working:

    #define CHILD_ID_BATTERY 1
    
    #define BATTERY_FULL 3143 // 2xAA usually give 3.143V when full
    #define BATTERY_ZERO 2340
    
    MyMessage voltage_msg(CHILD_ID_BATTERY, V_VOLTAGE);
    long oldvoltage = 0;
    
    gw.present(CHILD_ID_BATTERY, S_CUSTOM);
    
    long voltage = readVcc();
      if (oldvoltage != voltage) { // Only send battery information if voltage has changed, to conserve battery.
        gw.send(voltage_msg.set(voltage / 1000.0, 3)); // redVcc returns millivolts. Set wants volts and how many decimals (3 in our case)
        gw.sendBatteryLevel(round((voltage - BATTERY_ZERO) * 100.0 / (BATTERY_FULL - BATTERY_ZERO)));
        oldvoltage = voltage;
    	
    	
    long readVcc() {
      // From http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
      // Read 1.1V reference against AVcc
      // set the reference to Vcc and the measurement to the internal 1.1V reference
    #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
      ADMUX = _BV(MUX5) | _BV(MUX0);
    #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
      ADMUX = _BV(MUX3) | _BV(MUX2);
    #else
      ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #endif
    
      delay(2); // Wait for Vref to settle
      ADCSRA |= _BV(ADSC); // Start conversion
      while (bit_is_set(ADCSRA, ADSC)); // measuring
    
      uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
      uint8_t high = ADCH; // unlocks both
    
      long result = (high << 8) | low;
    
      result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
      return result; // Vcc in millivolts
    }
    


  • I used the BinarySwitchSleepSensor sketch and tried adding the battery measuring info. Does this look ok If I only want the sensor to sleep until the magnetswitch attached to PIN 2 is opened and every 6h it reports battery?

    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    #define SLEEP_TIME 21600000 // Sleep time between reads (in milliseconds)
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    
    #include <SPI.h>
    #include <MySensor.h>
    
    #define SKETCH_NAME "Mailbox +Battery"
    #define SKETCH_MAJOR_VER "1"
    #define SKETCH_MINOR_VER "0"
    
    #define PRIMARY_CHILD_ID 3
    #define CHILD_ID_BATTERY 1
    
    #define BATTERY_FULL 3143 // 2xAA usually give 3.143V when full
    #define BATTERY_ZERO 2340
    
    #define PRIMARY_BUTTON_PIN 2   // Arduino Digital I/O pin for button/reed switch
    
    
    
    
    // Change to V_LIGHT if you use S_LIGHT in presentation below
    MyMessage msg(PRIMARY_CHILD_ID, V_TRIPPED);
    MyMessage voltage_msg(CHILD_ID_BATTERY, V_VOLTAGE);
    long oldvoltage = 0;
    
    void setup()  
    {  
      // Setup the buttons
      pinMode(PRIMARY_BUTTON_PIN, INPUT);
     
    
      // Activate internal pull-ups
      digitalWrite(PRIMARY_BUTTON_PIN, HIGH);
    
    }
    
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER "." SKETCH_MINOR_VER);
    
      // Register binary input sensor to sensor_node (they will be created as child devices)
      // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage. 
      // If S_LIGHT is used, remember to update variable type you send in. See "msg" above.
      present(PRIMARY_CHILD_ID, S_DOOR);  
      delay(250);
      present(CHILD_ID_BATTERY, S_CUSTOM); 
    }
    
    // Loop will iterate on changes on the BUTTON_PINs
    void loop() 
    {
      uint8_t value;
      static uint8_t sentValue=2;
    
      // Short delay to allow buttons to properly settle
      sleep(5);
      
      value = digitalRead(PRIMARY_BUTTON_PIN);
      
      if (value != sentValue) {
         // Value has changed from last transmission, send the updated value
         send(msg.set(value==HIGH ? 1 : 0));
         sentValue = value;
      }
    long voltage = readVcc();
      if (oldvoltage != voltage) { // Only send battery information if voltage has changed, to conserve battery.
        send(voltage_msg.set(voltage / 1000.0, 3)); // redVcc returns millivolts. Set wants volts and how many decimals (3 in our case)
        sendBatteryLevel(round((voltage - BATTERY_ZERO) * 100.0 / (BATTERY_FULL - BATTERY_ZERO)));
        oldvoltage = voltage;
      }
      
    
      // Sleep until something happens with the sensor
      sleep(PRIMARY_BUTTON_PIN-2, CHANGE, SLEEP_TIME);
    } 
    
    long readVcc() {
      // From http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
      // Read 1.1V reference against AVcc
      // set the reference to Vcc and the measurement to the internal 1.1V reference
    #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
      ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
      ADMUX = _BV(MUX5) | _BV(MUX0);
    #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
      ADMUX = _BV(MUX3) | _BV(MUX2);
    #else
      ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    #endif
    
      delay(2); // Wait for Vref to settle
      ADCSRA |= _BV(ADSC); // Start conversion
      while (bit_is_set(ADCSRA, ADSC)); // measuring
    
      uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
      uint8_t high = ADCH; // unlocks both
    
      long result = (high << 8) | low;
    
      result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
      return result; // Vcc in millivolts
    }
    

 

429
Online

7.8k
Users

8.7k
Topics

93.0k
Posts