Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. General Discussion
  3. 6/8 Buttons battery remote node

6/8 Buttons battery remote node

Scheduled Pinned Locked Moved General Discussion
53 Posts 7 Posters 6.9k Views 8 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • NeverDieN NeverDie

    Here it is notionally for 4 buttons:
    0_1517019196870_keypad.jpg
    It's a voltage divider. Structured like this, it could trigger the IRQ pin when a button is pushed, and the analog pin could read the voltage to determine which button it was.

    NeverDieN Offline
    NeverDieN Offline
    NeverDie
    Hero Member
    wrote on last edited by
    #17

    @neverdie said in 6/8 Buttons battery remote node:

    Here it is notionally for 4 buttons:
    0_1517019196870_keypad.jpg
    It's a voltage divider. Structured like this, it could trigger the IRQ pin when a button is pushed, and the analog pin could read the voltage to determine which button it was.

    I made a custom PCB to test the concept:
    0_1517086906817_test_keyboard.jpg

    1 Reply Last reply
    0
    • gohanG Offline
      gohanG Offline
      gohan
      Mod
      wrote on last edited by
      #18

      Tomorrow I'll try to bring out the arduino numeric keypad and an old sketch I used with it and see what I can do

      NeverDieN 1 Reply Last reply
      0
      • gohanG gohan

        Tomorrow I'll try to bring out the arduino numeric keypad and an old sketch I used with it and see what I can do

        NeverDieN Offline
        NeverDieN Offline
        NeverDie
        Hero Member
        wrote on last edited by
        #19

        @gohan said in 6/8 Buttons battery remote node:

        Tomorrow I'll try to bring out the arduino numeric keypad and an old sketch I used with it and see what I can do

        Cool! I didn't know there was an official Arduino keypad.

        Here's mine:

        0_1517105000210_4button_keyboard.jpg

        1 Reply Last reply
        1
        • NeverDieN Offline
          NeverDieN Offline
          NeverDie
          Hero Member
          wrote on last edited by NeverDie
          #20

          It works. Connecting the output wires to A0 and D3, and running this script:

          #include <avr/sleep.h>
          
          void wake ()
          {
            // cancel sleep as a precaution
            sleep_disable();
            // precautionary while we do other stuff
            detachInterrupt (1);
          }  // end of wake
          
          void setup() {
            pinMode(A0,INPUT);
            Serial.begin(115200);
            Serial.println("Starting...");
            Serial.flush();
          
          }
          
          void loop() {
            uint16_t voltage;
          
            set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
            sleep_enable();
          
            // Do not interrupt before we go to sleep, or the
            // ISR will detach interrupts and we won't wake.
            noInterrupts ();
            
            // will be called when pin D2 goes low  
            attachInterrupt (1, wake, RISING);  //pin D3
           
            EIFR = bit (INTF1);  // clear flag for interrupt 1
            
            // turn off brown-out enable in software
            // BODS must be set to one and BODSE must be set to zero within four clock cycles
            MCUCR = bit (BODS) | bit (BODSE);
            // The BODS bit is automatically cleared after three clock cycles
            MCUCR = bit (BODS); 
            
            // We are guaranteed that the sleep_cpu call will be done
            // as the processor executes the next instruction after
            // interrupts are turned on.
            interrupts ();  // one cycle
            sleep_cpu ();   // one cycle
          
            delay(100);  //debounce the button
            voltage=analogRead(A0);
            if (voltage>0) {
              Serial.println(voltage);
              Serial.flush();
            }
          }
          

          on a 3.3v Arduino pro mini yields these values for each of the four buttons:

          Starting...
          1023
          930
          852
          787
          

          The pro mini sleeps until one of the buttons gets pressed, then it wakes up, reads the value, displays the value, and then goes back to sleep. :)

          1 Reply Last reply
          1
          • NeverDieN Offline
            NeverDieN Offline
            NeverDie
            Hero Member
            wrote on last edited by NeverDie
            #21

            It * might* get a little hairy though if running at 1.8v and you've got a lot of buttons to disambiguate and you still want to wake up on any button press. According to Table 32-2 of the atmega328p datasheet, the minimum threshold for input HIGH if running at vcc=1.8v-2.4v is 0.7Vcc. So, at the limit, that is 0.7*1.8v=1.26v. So, if n is the number of buttons, you need to disambiguate, then in a perfect world 0.54/(n-1) volts separates each button press. So, if say 12 buttons, that is 0.54/11=0.049 volts. Well, let's see: resolution is 1.8v/1023=0.0018v.

            Hmm... Again, in a perfect world, that's 27 analog read units separating each button press. In an imperfect world, that's not a lot of headroom for disambiguation. I guess in the worst case you might have to run a one-time calibration for each button and store it in EEPROM. I would hope to avoid such a calibration step, but it might come to that.

            zboblamontZ 1 Reply Last reply
            1
            • gohanG Offline
              gohanG Offline
              gohan
              Mod
              wrote on last edited by
              #22

              I am planning to use a LiFePO4 3.4V battery anyway, so it will be difficult to go even below 2.8V as that would mean battery almost empty.

              1 Reply Last reply
              1
              • NeverDieN NeverDie

                It * might* get a little hairy though if running at 1.8v and you've got a lot of buttons to disambiguate and you still want to wake up on any button press. According to Table 32-2 of the atmega328p datasheet, the minimum threshold for input HIGH if running at vcc=1.8v-2.4v is 0.7Vcc. So, at the limit, that is 0.7*1.8v=1.26v. So, if n is the number of buttons, you need to disambiguate, then in a perfect world 0.54/(n-1) volts separates each button press. So, if say 12 buttons, that is 0.54/11=0.049 volts. Well, let's see: resolution is 1.8v/1023=0.0018v.

                Hmm... Again, in a perfect world, that's 27 analog read units separating each button press. In an imperfect world, that's not a lot of headroom for disambiguation. I guess in the worst case you might have to run a one-time calibration for each button and store it in EEPROM. I would hope to avoid such a calibration step, but it might come to that.

                zboblamontZ Offline
                zboblamontZ Offline
                zboblamont
                wrote on last edited by
                #23

                @neverdie Is this not an instance where a high efficiency low dropout booster supply would null this particular issue?

                NeverDieN 1 Reply Last reply
                0
                • zboblamontZ zboblamont

                  @neverdie Is this not an instance where a high efficiency low dropout booster supply would null this particular issue?

                  NeverDieN Offline
                  NeverDieN Offline
                  NeverDie
                  Hero Member
                  wrote on last edited by
                  #24

                  @zboblamont said in 6/8 Buttons battery remote node:

                  @neverdie Is this not an instance where a high efficiency low dropout booster supply would null this particular issue?

                  Yes, that trade-off would relax the constraints.

                  But so does a one-time calibration. Since writing the above, I've warmed up to the idea. At least for my purposes, it's not that big a deal.

                  Nca78N 1 Reply Last reply
                  0
                  • NeverDieN NeverDie

                    @zboblamont said in 6/8 Buttons battery remote node:

                    @neverdie Is this not an instance where a high efficiency low dropout booster supply would null this particular issue?

                    Yes, that trade-off would relax the constraints.

                    But so does a one-time calibration. Since writing the above, I've warmed up to the idea. At least for my purposes, it's not that big a deal.

                    Nca78N Offline
                    Nca78N Offline
                    Nca78
                    Hardware Contributor
                    wrote on last edited by
                    #25

                    @neverdie said in 6/8 Buttons battery remote node:

                    But so does a one-time calibration. Since writing the above, I've warmed up to the idea. At least for my purposes, it's not that big a deal.

                    What about resistance variation due to temperature changes ? :)

                    NeverDieN 1 Reply Last reply
                    0
                    • Nca78N Nca78

                      @neverdie said in 6/8 Buttons battery remote node:

                      But so does a one-time calibration. Since writing the above, I've warmed up to the idea. At least for my purposes, it's not that big a deal.

                      What about resistance variation due to temperature changes ? :)

                      NeverDieN Offline
                      NeverDieN Offline
                      NeverDie
                      Hero Member
                      wrote on last edited by
                      #26

                      @nca78 said in 6/8 Buttons battery remote node:

                      @neverdie said in 6/8 Buttons battery remote node:

                      But so does a one-time calibration. Since writing the above, I've warmed up to the idea. At least for my purposes, it's not that big a deal.

                      What about resistance variation due to temperature changes ? :)

                      I hadn't really thought about that. Should I? In my case (12 buttons on a remote control) I'm assuming the resistors stay more or less room temperature.

                      Nca78N 1 Reply Last reply
                      0
                      • NeverDieN NeverDie

                        @nca78 said in 6/8 Buttons battery remote node:

                        @neverdie said in 6/8 Buttons battery remote node:

                        But so does a one-time calibration. Since writing the above, I've warmed up to the idea. At least for my purposes, it's not that big a deal.

                        What about resistance variation due to temperature changes ? :)

                        I hadn't really thought about that. Should I? In my case (12 buttons on a remote control) I'm assuming the resistors stay more or less room temperature.

                        Nca78N Offline
                        Nca78N Offline
                        Nca78
                        Hardware Contributor
                        wrote on last edited by
                        #27

                        @neverdie said in 6/8 Buttons battery remote node:

                        I hadn't really thought about that. Should I? In my case (12 buttons on a remote control) I'm assuming the resistors stay more or less room temperature.

                        It would depend on the quality of your resistors, and if your room temperature varies. Cheap carbon film resistors can have relatively wide temperature coefficient variation range, I see over 1000ppm/°C between min and max of range for some "branded" resistors on Arrow.com so it could be worse with cheap aliexpress versions. So if you're unlucky you could get resistors in the two opposite parts of the range. With 27 units on average on a 1024 max value you have an average 27000ppm margin, so you should be ok if your keyboard stays inside, but it could become a problem if it's outside, a 30°C variation between summer and winter could in theory give your wrong results.

                        But I suppose I'm really nitpicking here, you would need to be really unlucky with your resistors :D

                        1 Reply Last reply
                        2
                        • gohanG Offline
                          gohanG Offline
                          gohan
                          Mod
                          wrote on last edited by
                          #28

                          Since values are a bit far apart, I could make a range of values to be considered a specific key pressed.

                          NeverDieN 1 Reply Last reply
                          0
                          • gohanG gohan

                            Since values are a bit far apart, I could make a range of values to be considered a specific key pressed.

                            NeverDieN Offline
                            NeverDieN Offline
                            NeverDie
                            Hero Member
                            wrote on last edited by NeverDie
                            #29

                            @gohan Exactly right.

                            @gohan Does the Arduino keypad that you already have work on the same principle?

                            Presently I'm doing the layout on a 3x4 matrix keypad that uses fewer resistors (using the design I referenced earlier), but which works on the same voltage dividing principle.

                            gohanG 1 Reply Last reply
                            0
                            • NeverDieN NeverDie

                              @gohan Exactly right.

                              @gohan Does the Arduino keypad that you already have work on the same principle?

                              Presently I'm doing the layout on a 3x4 matrix keypad that uses fewer resistors (using the design I referenced earlier), but which works on the same voltage dividing principle.

                              gohanG Offline
                              gohanG Offline
                              gohan
                              Mod
                              wrote on last edited by
                              #30

                              @neverdie this is the one I'm talking about http://www.circuitstoday.com/interfacing-hex-keypad-to-arduino

                              1 Reply Last reply
                              0
                              • wesW Offline
                                wesW Offline
                                wes
                                wrote on last edited by
                                #31

                                I have the same use case (remote control with buttons to control lights/scenes).

                                I'm planning to use some cheap RF remotes and connect a RF receiver to my RPI, which hosts both my gateway and controller.

                                Not sure if I'll receive the codes via MySensors, or write something that talks directly to the controller (thoughts on pros/cons of each approach welcome).

                                Of course this won't be as reliable or flexible as buttons connected to a MySensors node, but it should be enough for my needs.

                                Further thoughts welcome :-)

                                Blog: https://www.wes.id.au/
                                Nodes: Arduino Pro Mini ATMega328P 3.3V 8MHz, RFM69 433MHz, Canton Power CE024 0.8-3.3V regulator & single AA battery
                                Gateway & Controller: Raspberry Pi 3 + Home Assistant

                                Nca78N 1 Reply Last reply
                                0
                                • wesW wes

                                  I have the same use case (remote control with buttons to control lights/scenes).

                                  I'm planning to use some cheap RF remotes and connect a RF receiver to my RPI, which hosts both my gateway and controller.

                                  Not sure if I'll receive the codes via MySensors, or write something that talks directly to the controller (thoughts on pros/cons of each approach welcome).

                                  Of course this won't be as reliable or flexible as buttons connected to a MySensors node, but it should be enough for my needs.

                                  Further thoughts welcome :-)

                                  Nca78N Offline
                                  Nca78N Offline
                                  Nca78
                                  Hardware Contributor
                                  wrote on last edited by
                                  #32

                                  @wes said in 6/8 Buttons battery remote node:

                                  I have the same use case (remote control with buttons to control lights/scenes).

                                  I'm planning to use some cheap RF remotes and connect a RF receiver to my RPI, which hosts both my gateway and controller.

                                  Not sure if I'll receive the codes via MySensors, or write something that talks directly to the controller (thoughts on pros/cons of each approach welcome).

                                  Of course this won't be as reliable or flexible as buttons connected to a MySensors node, but it should be enough for my needs.

                                  Further thoughts welcome :-)

                                  I think you should change the remote controls into MySensors nodes. A bit more work at the beginning but you'll probably save a lot of hair pulling, reliability etc in the long term.

                                  1 Reply Last reply
                                  0
                                  • CarywinC Offline
                                    CarywinC Offline
                                    Carywin
                                    wrote on last edited by
                                    #33

                                    You can use pin change interrupts with MySensors sleep loops with an easy hack. Here's the code I use for 4 button battery powered nodes that also report temperature and humidity using DHT a sensor. I run them from 2 AA and so far they've been running for more than 6 months without showing signs of discharge. This could be easily modified for 6 or 8 buttons.

                                    // MySensors EnviroButtons
                                    // Temperature and Humidity Sensor with 4 Push Buttons
                                    // Battery Powered Node
                                    // Don't forget to change buttons and VCC_CAL for each node
                                    
                                    // Cary Wintle - July 2017
                                    
                                    // MySensors configuration
                                    // -----------------------
                                    #define SN "EnviroButtons"  // Software name
                                    #define SV "0.4"            // Version number
                                    //#define MY_DEBUG
                                    #define MY_NODE_ID 6
                                    #define MY_RADIO_RFM69
                                    #define MY_RFM69_NETWORKID 137
                                    #define MY_RFM69_ENABLE_ENCRYPTION
                                    #define MY_RFM69_NEW_DRIVER
                                    #define MY_RFM69_FREQUENCY RFM69_433MHZ
                                    #define MY_IS_RFM69HW
                                    #include <MySensors.h>
                                    
                                    #include <SPI.h>
                                    #include <DHT.h>
                                    
                                    #define EI_NOTEXTERNAL // External interrupts managed by built-in routines
                                    #include <EnableInterrupt.h> // Pin-change interrupts
                                    
                                    // Set this to the pin you connected the DHT's data pin to
                                    #define DHT_DATA_PIN 8
                                    
                                    // Buttons
                                    #define BUTTON1_PIN A1 // 5: A1 - 6: A1
                                    #define BUTTON2_PIN A2 // 5: A3 - 6: A2
                                    #define BUTTON3_PIN A3 // 5: A2 - 6: A3
                                    #define BUTTON4_PIN A0 // 5: A0 - 6: A0
                                    
                                    // Set this offset if the sensor has a permanent small offset to the real temperatures
                                    #define SENSOR_TEMP_OFFSET 0
                                    
                                    // Sleep time between sensor updates (in milliseconds)
                                    // Must be >1000ms for DHT22 and >2000ms for DHT11
                                    static const uint64_t UPDATE_INTERVAL = 120000;
                                    #define BAT_UPDATE_INTERVAL 720 // 24 hrs - Interval between battery updates (multiples of UPDATE_INTERVAL)
                                    // VCC Calibration Values
                                    // Node 5: 1128953L
                                    // Node 6: 1125300L
                                    #define VCC_CAL 1125300L
                                    
                                    // Force sending an update of the temperature after n sensor reads, so a controller showing the
                                    // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
                                    // the value didn't change since;
                                    // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
                                    static const uint8_t FORCE_UPDATE_N_READS = 30; // After an hour
                                    
                                    float lastTemp;
                                    float lastHum;
                                    uint8_t nNoUpdatesTemp;
                                    uint8_t nNoUpdatesHum;
                                    int cycleCount = BAT_UPDATE_INTERVAL; // Send battery update immediately
                                    volatile byte B1Int = 0, B2Int = 0, B3Int = 0, B4Int = 0; // Interrupt button flags
                                    uint32_t now;
                                    
                                    MyMessage msgHum(0, V_HUM);
                                    MyMessage msgTemp(0, V_TEMP);
                                    MyMessage msgButtons(0, V_SCENE_ON);
                                    MyMessage msgBattV(0, V_VOLTAGE);
                                    DHT dht;
                                    
                                    void presentation()  
                                    { 
                                      // Send the sketch version information to the gateway
                                      sendSketchInfo(SN,SV);
                                      // Present the sensor
                                      present(0, S_CUSTOM, "Temp/Humid/Buttons");
                                    }
                                    
                                    void setup()
                                    {
                                      // Setup pins the DHT sensor is on
                                      digitalWrite(6, LOW);
                                      pinMode(6, OUTPUT);
                                      digitalWrite(7, LOW);
                                      pinMode(7, OUTPUT);
                                      digitalWrite(9, HIGH);
                                      pinMode(9, OUTPUT);
                                    
                                      sleep(2000);
                                    
                                      dht.setup(DHT_DATA_PIN); // Setup the DHT sensor
                                    
                                      pinMode(BUTTON1_PIN,INPUT_PULLUP);
                                      pinMode(BUTTON2_PIN,INPUT_PULLUP);
                                      pinMode(BUTTON3_PIN,INPUT_PULLUP);
                                      pinMode(BUTTON4_PIN,INPUT_PULLUP);
                                      enableInterrupt(BUTTON1_PIN,Button1,FALLING);
                                      enableInterrupt(BUTTON2_PIN,Button2,FALLING);
                                      enableInterrupt(BUTTON3_PIN,Button3,FALLING);
                                      enableInterrupt(BUTTON4_PIN,Button4,FALLING);
                                    }
                                    
                                    void Button1() {
                                      B1Int++;
                                      _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                    }
                                    
                                    void Button2() {
                                      B2Int++;
                                      _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                    }
                                    
                                    void Button3() {
                                      B3Int++;
                                      _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                    }
                                    
                                    void Button4() {
                                      B4Int++;
                                      _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                    }
                                    
                                    
                                    void loop() {
                                      _wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
                                      // Power up the DHT sensor
                                      digitalWrite(9, HIGH);
                                    
                                      // Process buttons
                                      if(B1Int > 0) {
                                        send(msgButtons.set(1));
                                        B1Int = 0;
                                      } else if(B2Int > 0) {
                                        send(msgButtons.set(2));
                                        B2Int = 0;
                                      } else if(B3Int > 0) {
                                        send(msgButtons.set(3));
                                        B3Int = 0;
                                      } else if(B4Int > 0) {
                                        send(msgButtons.set(4));
                                        B4Int = 0;
                                      }
                                    
                                      // Wait for the DHT sensor to init
                                      sleep(2000);
                                      
                                      // Force reading sensor, so it works also after sleep()
                                      dht.readSensor(true);
                                      
                                      // Get temperature from DHT library
                                      float temperature = dht.getTemperature();
                                      if (isnan(temperature)) {
                                        Serial.println("Failed reading temperature from DHT!");
                                      } else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
                                        // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
                                        lastTemp = temperature;
                                        // Reset no updates counter
                                        nNoUpdatesTemp = 0;
                                        temperature += SENSOR_TEMP_OFFSET;
                                        send(msgTemp.set(temperature, 1));
                                    
                                        #ifdef MY_DEBUG
                                        Serial.print("T: ");
                                        Serial.println(temperature);
                                        #endif
                                      } else {
                                        // Increase no update counter if the temperature stayed the same
                                        nNoUpdatesTemp++;
                                      }
                                    
                                      // Get humidity from DHT library
                                      byte humidity = (byte)dht.getHumidity();
                                      if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
                                        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
                                        lastHum = humidity;
                                        // Reset no updates counter
                                        nNoUpdatesHum = 0;
                                        send(msgHum.set(humidity, 1));
                                        
                                        #ifdef MY_DEBUG
                                        Serial.print("H: ");
                                        Serial.println(humidity);
                                        #endif
                                      } else {
                                        // Increase no update counter if the humidity stayed the same
                                        nNoUpdatesHum++;
                                      }
                                    
                                      if (cycleCount >= BAT_UPDATE_INTERVAL) {
                                        cycleCount = 0;
                                        int BatV = readVCC();
                                        #ifdef MY_DEBUG
                                        Serial.print("BatVR: ");
                                        Serial.println(BatV);
                                        #endif
                                        float BatVolts = BatV / 1000.0;
                                        #ifdef MY_DEBUG
                                        Serial.print("BatV: ");
                                        Serial.println(BatVolts);
                                        #endif
                                        send(msgBattV.set(BatVolts, 2));
                                        float BatPercent = (BatVolts - 2.8) / 0.6 * 100;
                                        if(BatPercent > 100) BatPercent = 100;
                                        #ifdef MY_DEBUG
                                        Serial.print("Bat%: ");
                                        Serial.println(BatPercent);
                                        #endif
                                        sendBatteryLevel((int)BatPercent);
                                      }
                                      cycleCount++;
                                    
                                      // Power down the DHT sensor
                                      digitalWrite(9, LOW);
                                      
                                      // Sleep for a while to save energy
                                      sleep(UPDATE_INTERVAL); 
                                    }
                                    
                                    int readVCC() {
                                      // Read 1.1V reference against AVcc
                                      // set the reference to Vcc and the measurement to the internal 1.1V reference
                                        ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
                                    
                                      wait(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
                                    
                                      int result = (high<<8) | low;
                                    
                                      #ifdef MY_DEBUG
                                      Serial.print("R: ");
                                      Serial.println(result);
                                      #endif
                                    
                                      result = VCC_CAL / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
                                      return result; // Vcc in millivolts
                                    }
                                    
                                    dbemowskD gohanG 2 Replies Last reply
                                    0
                                    • CarywinC Carywin

                                      You can use pin change interrupts with MySensors sleep loops with an easy hack. Here's the code I use for 4 button battery powered nodes that also report temperature and humidity using DHT a sensor. I run them from 2 AA and so far they've been running for more than 6 months without showing signs of discharge. This could be easily modified for 6 or 8 buttons.

                                      // MySensors EnviroButtons
                                      // Temperature and Humidity Sensor with 4 Push Buttons
                                      // Battery Powered Node
                                      // Don't forget to change buttons and VCC_CAL for each node
                                      
                                      // Cary Wintle - July 2017
                                      
                                      // MySensors configuration
                                      // -----------------------
                                      #define SN "EnviroButtons"  // Software name
                                      #define SV "0.4"            // Version number
                                      //#define MY_DEBUG
                                      #define MY_NODE_ID 6
                                      #define MY_RADIO_RFM69
                                      #define MY_RFM69_NETWORKID 137
                                      #define MY_RFM69_ENABLE_ENCRYPTION
                                      #define MY_RFM69_NEW_DRIVER
                                      #define MY_RFM69_FREQUENCY RFM69_433MHZ
                                      #define MY_IS_RFM69HW
                                      #include <MySensors.h>
                                      
                                      #include <SPI.h>
                                      #include <DHT.h>
                                      
                                      #define EI_NOTEXTERNAL // External interrupts managed by built-in routines
                                      #include <EnableInterrupt.h> // Pin-change interrupts
                                      
                                      // Set this to the pin you connected the DHT's data pin to
                                      #define DHT_DATA_PIN 8
                                      
                                      // Buttons
                                      #define BUTTON1_PIN A1 // 5: A1 - 6: A1
                                      #define BUTTON2_PIN A2 // 5: A3 - 6: A2
                                      #define BUTTON3_PIN A3 // 5: A2 - 6: A3
                                      #define BUTTON4_PIN A0 // 5: A0 - 6: A0
                                      
                                      // Set this offset if the sensor has a permanent small offset to the real temperatures
                                      #define SENSOR_TEMP_OFFSET 0
                                      
                                      // Sleep time between sensor updates (in milliseconds)
                                      // Must be >1000ms for DHT22 and >2000ms for DHT11
                                      static const uint64_t UPDATE_INTERVAL = 120000;
                                      #define BAT_UPDATE_INTERVAL 720 // 24 hrs - Interval between battery updates (multiples of UPDATE_INTERVAL)
                                      // VCC Calibration Values
                                      // Node 5: 1128953L
                                      // Node 6: 1125300L
                                      #define VCC_CAL 1125300L
                                      
                                      // Force sending an update of the temperature after n sensor reads, so a controller showing the
                                      // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
                                      // the value didn't change since;
                                      // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
                                      static const uint8_t FORCE_UPDATE_N_READS = 30; // After an hour
                                      
                                      float lastTemp;
                                      float lastHum;
                                      uint8_t nNoUpdatesTemp;
                                      uint8_t nNoUpdatesHum;
                                      int cycleCount = BAT_UPDATE_INTERVAL; // Send battery update immediately
                                      volatile byte B1Int = 0, B2Int = 0, B3Int = 0, B4Int = 0; // Interrupt button flags
                                      uint32_t now;
                                      
                                      MyMessage msgHum(0, V_HUM);
                                      MyMessage msgTemp(0, V_TEMP);
                                      MyMessage msgButtons(0, V_SCENE_ON);
                                      MyMessage msgBattV(0, V_VOLTAGE);
                                      DHT dht;
                                      
                                      void presentation()  
                                      { 
                                        // Send the sketch version information to the gateway
                                        sendSketchInfo(SN,SV);
                                        // Present the sensor
                                        present(0, S_CUSTOM, "Temp/Humid/Buttons");
                                      }
                                      
                                      void setup()
                                      {
                                        // Setup pins the DHT sensor is on
                                        digitalWrite(6, LOW);
                                        pinMode(6, OUTPUT);
                                        digitalWrite(7, LOW);
                                        pinMode(7, OUTPUT);
                                        digitalWrite(9, HIGH);
                                        pinMode(9, OUTPUT);
                                      
                                        sleep(2000);
                                      
                                        dht.setup(DHT_DATA_PIN); // Setup the DHT sensor
                                      
                                        pinMode(BUTTON1_PIN,INPUT_PULLUP);
                                        pinMode(BUTTON2_PIN,INPUT_PULLUP);
                                        pinMode(BUTTON3_PIN,INPUT_PULLUP);
                                        pinMode(BUTTON4_PIN,INPUT_PULLUP);
                                        enableInterrupt(BUTTON1_PIN,Button1,FALLING);
                                        enableInterrupt(BUTTON2_PIN,Button2,FALLING);
                                        enableInterrupt(BUTTON3_PIN,Button3,FALLING);
                                        enableInterrupt(BUTTON4_PIN,Button4,FALLING);
                                      }
                                      
                                      void Button1() {
                                        B1Int++;
                                        _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                      }
                                      
                                      void Button2() {
                                        B2Int++;
                                        _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                      }
                                      
                                      void Button3() {
                                        B3Int++;
                                        _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                      }
                                      
                                      void Button4() {
                                        B4Int++;
                                        _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                      }
                                      
                                      
                                      void loop() {
                                        _wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
                                        // Power up the DHT sensor
                                        digitalWrite(9, HIGH);
                                      
                                        // Process buttons
                                        if(B1Int > 0) {
                                          send(msgButtons.set(1));
                                          B1Int = 0;
                                        } else if(B2Int > 0) {
                                          send(msgButtons.set(2));
                                          B2Int = 0;
                                        } else if(B3Int > 0) {
                                          send(msgButtons.set(3));
                                          B3Int = 0;
                                        } else if(B4Int > 0) {
                                          send(msgButtons.set(4));
                                          B4Int = 0;
                                        }
                                      
                                        // Wait for the DHT sensor to init
                                        sleep(2000);
                                        
                                        // Force reading sensor, so it works also after sleep()
                                        dht.readSensor(true);
                                        
                                        // Get temperature from DHT library
                                        float temperature = dht.getTemperature();
                                        if (isnan(temperature)) {
                                          Serial.println("Failed reading temperature from DHT!");
                                        } else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
                                          // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
                                          lastTemp = temperature;
                                          // Reset no updates counter
                                          nNoUpdatesTemp = 0;
                                          temperature += SENSOR_TEMP_OFFSET;
                                          send(msgTemp.set(temperature, 1));
                                      
                                          #ifdef MY_DEBUG
                                          Serial.print("T: ");
                                          Serial.println(temperature);
                                          #endif
                                        } else {
                                          // Increase no update counter if the temperature stayed the same
                                          nNoUpdatesTemp++;
                                        }
                                      
                                        // Get humidity from DHT library
                                        byte humidity = (byte)dht.getHumidity();
                                        if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
                                          // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
                                          lastHum = humidity;
                                          // Reset no updates counter
                                          nNoUpdatesHum = 0;
                                          send(msgHum.set(humidity, 1));
                                          
                                          #ifdef MY_DEBUG
                                          Serial.print("H: ");
                                          Serial.println(humidity);
                                          #endif
                                        } else {
                                          // Increase no update counter if the humidity stayed the same
                                          nNoUpdatesHum++;
                                        }
                                      
                                        if (cycleCount >= BAT_UPDATE_INTERVAL) {
                                          cycleCount = 0;
                                          int BatV = readVCC();
                                          #ifdef MY_DEBUG
                                          Serial.print("BatVR: ");
                                          Serial.println(BatV);
                                          #endif
                                          float BatVolts = BatV / 1000.0;
                                          #ifdef MY_DEBUG
                                          Serial.print("BatV: ");
                                          Serial.println(BatVolts);
                                          #endif
                                          send(msgBattV.set(BatVolts, 2));
                                          float BatPercent = (BatVolts - 2.8) / 0.6 * 100;
                                          if(BatPercent > 100) BatPercent = 100;
                                          #ifdef MY_DEBUG
                                          Serial.print("Bat%: ");
                                          Serial.println(BatPercent);
                                          #endif
                                          sendBatteryLevel((int)BatPercent);
                                        }
                                        cycleCount++;
                                      
                                        // Power down the DHT sensor
                                        digitalWrite(9, LOW);
                                        
                                        // Sleep for a while to save energy
                                        sleep(UPDATE_INTERVAL); 
                                      }
                                      
                                      int readVCC() {
                                        // Read 1.1V reference against AVcc
                                        // set the reference to Vcc and the measurement to the internal 1.1V reference
                                          ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
                                      
                                        wait(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
                                      
                                        int result = (high<<8) | low;
                                      
                                        #ifdef MY_DEBUG
                                        Serial.print("R: ");
                                        Serial.println(result);
                                        #endif
                                      
                                        result = VCC_CAL / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
                                        return result; // Vcc in millivolts
                                      }
                                      
                                      dbemowskD Offline
                                      dbemowskD Offline
                                      dbemowsk
                                      wrote on last edited by
                                      #34

                                      @carywin Certain arduinos such as the pro minis can ONLY do interrupts on pins 2 or 3 from my understanding.

                                      Vera Plus running UI7 with MySensors, Sonoffs and 1-Wire devices
                                      Visit my website for more Bits, Bytes and Ramblings from me: http://dan.bemowski.info/

                                      NeverDieN CarywinC 2 Replies Last reply
                                      0
                                      • CarywinC Carywin

                                        You can use pin change interrupts with MySensors sleep loops with an easy hack. Here's the code I use for 4 button battery powered nodes that also report temperature and humidity using DHT a sensor. I run them from 2 AA and so far they've been running for more than 6 months without showing signs of discharge. This could be easily modified for 6 or 8 buttons.

                                        // MySensors EnviroButtons
                                        // Temperature and Humidity Sensor with 4 Push Buttons
                                        // Battery Powered Node
                                        // Don't forget to change buttons and VCC_CAL for each node
                                        
                                        // Cary Wintle - July 2017
                                        
                                        // MySensors configuration
                                        // -----------------------
                                        #define SN "EnviroButtons"  // Software name
                                        #define SV "0.4"            // Version number
                                        //#define MY_DEBUG
                                        #define MY_NODE_ID 6
                                        #define MY_RADIO_RFM69
                                        #define MY_RFM69_NETWORKID 137
                                        #define MY_RFM69_ENABLE_ENCRYPTION
                                        #define MY_RFM69_NEW_DRIVER
                                        #define MY_RFM69_FREQUENCY RFM69_433MHZ
                                        #define MY_IS_RFM69HW
                                        #include <MySensors.h>
                                        
                                        #include <SPI.h>
                                        #include <DHT.h>
                                        
                                        #define EI_NOTEXTERNAL // External interrupts managed by built-in routines
                                        #include <EnableInterrupt.h> // Pin-change interrupts
                                        
                                        // Set this to the pin you connected the DHT's data pin to
                                        #define DHT_DATA_PIN 8
                                        
                                        // Buttons
                                        #define BUTTON1_PIN A1 // 5: A1 - 6: A1
                                        #define BUTTON2_PIN A2 // 5: A3 - 6: A2
                                        #define BUTTON3_PIN A3 // 5: A2 - 6: A3
                                        #define BUTTON4_PIN A0 // 5: A0 - 6: A0
                                        
                                        // Set this offset if the sensor has a permanent small offset to the real temperatures
                                        #define SENSOR_TEMP_OFFSET 0
                                        
                                        // Sleep time between sensor updates (in milliseconds)
                                        // Must be >1000ms for DHT22 and >2000ms for DHT11
                                        static const uint64_t UPDATE_INTERVAL = 120000;
                                        #define BAT_UPDATE_INTERVAL 720 // 24 hrs - Interval between battery updates (multiples of UPDATE_INTERVAL)
                                        // VCC Calibration Values
                                        // Node 5: 1128953L
                                        // Node 6: 1125300L
                                        #define VCC_CAL 1125300L
                                        
                                        // Force sending an update of the temperature after n sensor reads, so a controller showing the
                                        // timestamp of the last update doesn't show something like 3 hours in the unlikely case, that
                                        // the value didn't change since;
                                        // i.e. the sensor would force sending an update every UPDATE_INTERVAL*FORCE_UPDATE_N_READS [ms]
                                        static const uint8_t FORCE_UPDATE_N_READS = 30; // After an hour
                                        
                                        float lastTemp;
                                        float lastHum;
                                        uint8_t nNoUpdatesTemp;
                                        uint8_t nNoUpdatesHum;
                                        int cycleCount = BAT_UPDATE_INTERVAL; // Send battery update immediately
                                        volatile byte B1Int = 0, B2Int = 0, B3Int = 0, B4Int = 0; // Interrupt button flags
                                        uint32_t now;
                                        
                                        MyMessage msgHum(0, V_HUM);
                                        MyMessage msgTemp(0, V_TEMP);
                                        MyMessage msgButtons(0, V_SCENE_ON);
                                        MyMessage msgBattV(0, V_VOLTAGE);
                                        DHT dht;
                                        
                                        void presentation()  
                                        { 
                                          // Send the sketch version information to the gateway
                                          sendSketchInfo(SN,SV);
                                          // Present the sensor
                                          present(0, S_CUSTOM, "Temp/Humid/Buttons");
                                        }
                                        
                                        void setup()
                                        {
                                          // Setup pins the DHT sensor is on
                                          digitalWrite(6, LOW);
                                          pinMode(6, OUTPUT);
                                          digitalWrite(7, LOW);
                                          pinMode(7, OUTPUT);
                                          digitalWrite(9, HIGH);
                                          pinMode(9, OUTPUT);
                                        
                                          sleep(2000);
                                        
                                          dht.setup(DHT_DATA_PIN); // Setup the DHT sensor
                                        
                                          pinMode(BUTTON1_PIN,INPUT_PULLUP);
                                          pinMode(BUTTON2_PIN,INPUT_PULLUP);
                                          pinMode(BUTTON3_PIN,INPUT_PULLUP);
                                          pinMode(BUTTON4_PIN,INPUT_PULLUP);
                                          enableInterrupt(BUTTON1_PIN,Button1,FALLING);
                                          enableInterrupt(BUTTON2_PIN,Button2,FALLING);
                                          enableInterrupt(BUTTON3_PIN,Button3,FALLING);
                                          enableInterrupt(BUTTON4_PIN,Button4,FALLING);
                                        }
                                        
                                        void Button1() {
                                          B1Int++;
                                          _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                        }
                                        
                                        void Button2() {
                                          B2Int++;
                                          _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                        }
                                        
                                        void Button3() {
                                          B3Int++;
                                          _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                        }
                                        
                                        void Button4() {
                                          B4Int++;
                                          _wokeUpByInterrupt = 0xFE; // Dirty hack to get out of MySensors sleep loop
                                        }
                                        
                                        
                                        void loop() {
                                          _wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
                                          // Power up the DHT sensor
                                          digitalWrite(9, HIGH);
                                        
                                          // Process buttons
                                          if(B1Int > 0) {
                                            send(msgButtons.set(1));
                                            B1Int = 0;
                                          } else if(B2Int > 0) {
                                            send(msgButtons.set(2));
                                            B2Int = 0;
                                          } else if(B3Int > 0) {
                                            send(msgButtons.set(3));
                                            B3Int = 0;
                                          } else if(B4Int > 0) {
                                            send(msgButtons.set(4));
                                            B4Int = 0;
                                          }
                                        
                                          // Wait for the DHT sensor to init
                                          sleep(2000);
                                          
                                          // Force reading sensor, so it works also after sleep()
                                          dht.readSensor(true);
                                          
                                          // Get temperature from DHT library
                                          float temperature = dht.getTemperature();
                                          if (isnan(temperature)) {
                                            Serial.println("Failed reading temperature from DHT!");
                                          } else if (temperature != lastTemp || nNoUpdatesTemp == FORCE_UPDATE_N_READS) {
                                            // Only send temperature if it changed since the last measurement or if we didn't send an update for n times
                                            lastTemp = temperature;
                                            // Reset no updates counter
                                            nNoUpdatesTemp = 0;
                                            temperature += SENSOR_TEMP_OFFSET;
                                            send(msgTemp.set(temperature, 1));
                                        
                                            #ifdef MY_DEBUG
                                            Serial.print("T: ");
                                            Serial.println(temperature);
                                            #endif
                                          } else {
                                            // Increase no update counter if the temperature stayed the same
                                            nNoUpdatesTemp++;
                                          }
                                        
                                          // Get humidity from DHT library
                                          byte humidity = (byte)dht.getHumidity();
                                          if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
                                            // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
                                            lastHum = humidity;
                                            // Reset no updates counter
                                            nNoUpdatesHum = 0;
                                            send(msgHum.set(humidity, 1));
                                            
                                            #ifdef MY_DEBUG
                                            Serial.print("H: ");
                                            Serial.println(humidity);
                                            #endif
                                          } else {
                                            // Increase no update counter if the humidity stayed the same
                                            nNoUpdatesHum++;
                                          }
                                        
                                          if (cycleCount >= BAT_UPDATE_INTERVAL) {
                                            cycleCount = 0;
                                            int BatV = readVCC();
                                            #ifdef MY_DEBUG
                                            Serial.print("BatVR: ");
                                            Serial.println(BatV);
                                            #endif
                                            float BatVolts = BatV / 1000.0;
                                            #ifdef MY_DEBUG
                                            Serial.print("BatV: ");
                                            Serial.println(BatVolts);
                                            #endif
                                            send(msgBattV.set(BatVolts, 2));
                                            float BatPercent = (BatVolts - 2.8) / 0.6 * 100;
                                            if(BatPercent > 100) BatPercent = 100;
                                            #ifdef MY_DEBUG
                                            Serial.print("Bat%: ");
                                            Serial.println(BatPercent);
                                            #endif
                                            sendBatteryLevel((int)BatPercent);
                                          }
                                          cycleCount++;
                                        
                                          // Power down the DHT sensor
                                          digitalWrite(9, LOW);
                                          
                                          // Sleep for a while to save energy
                                          sleep(UPDATE_INTERVAL); 
                                        }
                                        
                                        int readVCC() {
                                          // Read 1.1V reference against AVcc
                                          // set the reference to Vcc and the measurement to the internal 1.1V reference
                                            ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
                                        
                                          wait(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
                                        
                                          int result = (high<<8) | low;
                                        
                                          #ifdef MY_DEBUG
                                          Serial.print("R: ");
                                          Serial.println(result);
                                          #endif
                                        
                                          result = VCC_CAL / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
                                          return result; // Vcc in millivolts
                                        }
                                        
                                        gohanG Offline
                                        gohanG Offline
                                        gohan
                                        Mod
                                        wrote on last edited by
                                        #35

                                        @carywin what is the sleep current of your node with this "interrupt hack"?

                                        CarywinC 1 Reply Last reply
                                        0
                                        • NeverDieN Offline
                                          NeverDieN Offline
                                          NeverDie
                                          Hero Member
                                          wrote on last edited by
                                          #36

                                          Here's the PCB I made for the matrix keypad:
                                          0_1517266378834_matrix_keypad.jpg
                                          The whole thing fits on a single sided PCB. :)

                                          1 Reply Last reply
                                          1
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          17

                                          Online

                                          11.7k

                                          Users

                                          11.2k

                                          Topics

                                          113.0k

                                          Posts


                                          Copyright 2019 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • MySensors
                                          • OpenHardware.io
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular