Skip to content
  • 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. Troubleshooting
  3. Is there a "standard" way to terminate a sleep time, after waking by an interrupt?
  • Getting Started
  • Controller
  • Build
  • Hardware
  • Download/API
  • Forum
  • Store

Is there a "standard" way to terminate a sleep time, after waking by an interrupt?

Scheduled Pinned Locked Moved Troubleshooting
15 Posts 3 Posters 118 Views 2 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.
  • N Offline
    N Offline
    Nigel31
    wrote on last edited by
    #1

    HI,

    I have a sleeping battery node, soil moisture sensor, to which I am adding a Rain tipping bucket sensor.
    The node sleeps for an hour, before waking, measuring soil, and reporting.
    I have added an interrupt to this to set a flag, to process counts, and report as necessary.
    The code however, due to I imagine the looping multiples of (probably) 8 sec WDT loops to enable a longer sleep function, simply goes back to sleep, untill either another interrupt, or the timeout of the sleep time, AFTER which the rest of the code executes as expected.
    So my question is this, is there a

    sleep(end);

    type function? (can't find one)

    I can do this by externally to the mysensors core by looping n times, and sleeping for say 8 sec, check for the flag from the interrupt, and break the loop, but is there a mysensors way to do this?

    Kind Regards,
    Nigel

    mfalkviddM 1 Reply Last reply
    0
    • N Nigel31

      HI,

      I have a sleeping battery node, soil moisture sensor, to which I am adding a Rain tipping bucket sensor.
      The node sleeps for an hour, before waking, measuring soil, and reporting.
      I have added an interrupt to this to set a flag, to process counts, and report as necessary.
      The code however, due to I imagine the looping multiples of (probably) 8 sec WDT loops to enable a longer sleep function, simply goes back to sleep, untill either another interrupt, or the timeout of the sleep time, AFTER which the rest of the code executes as expected.
      So my question is this, is there a

      sleep(end);

      type function? (can't find one)

      I can do this by externally to the mysensors core by looping n times, and sleeping for say 8 sec, check for the flag from the interrupt, and break the loop, but is there a mysensors way to do this?

      Kind Regards,
      Nigel

      mfalkviddM Offline
      mfalkviddM Offline
      mfalkvidd
      Mod
      wrote on last edited by
      #2

      @Njwyborn can't you use the MySensors sleep to waker from interrupt?

      N 1 Reply Last reply
      0
      • mfalkviddM mfalkvidd

        @Njwyborn can't you use the MySensors sleep to waker from interrupt?

        N Offline
        N Offline
        Nigel31
        wrote on last edited by
        #3

        @mfalkvidd
        Yes, that is exactly what I am doing, however, as I hopefully explained, AFTER the interrupt, the node returns to sleep and does not action the rest of the main loop.

        I am Calling

        sleep(RainPin, FALLING, MYsleepTime*3); 
        

        having already defined the pin and interrupt handler etc.

          pinMode(RainPin, INPUT_PULLUP);
            EIFR = (1<<INTF0) | (1<<INTF1);// prevent initial trigger, clear interrupt
            wait(100);
            EIFR = (1<<INTF0) | (1<<INTF1);
          attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
        

        all works perfectly, in that the interrupt executes.
        What I am asking is . Is there a way of stopping the sleep from continuing for the rest of the time defined by MYsleepTime? ( actually MYsleepTime = 3600000)
        I can, and am for the moment, performing the calculations, and sending data to the controller in the interrupt, but that is very poor programming in principal. What I wish to do is simply set a flag, and then have the main loop execute, where I can decide what to do, and then return to sleep, after I have done all I wish.

        Many thanks
        Nigel

        YveauxY 1 Reply Last reply
        0
        • N Nigel31

          @mfalkvidd
          Yes, that is exactly what I am doing, however, as I hopefully explained, AFTER the interrupt, the node returns to sleep and does not action the rest of the main loop.

          I am Calling

          sleep(RainPin, FALLING, MYsleepTime*3); 
          

          having already defined the pin and interrupt handler etc.

            pinMode(RainPin, INPUT_PULLUP);
              EIFR = (1<<INTF0) | (1<<INTF1);// prevent initial trigger, clear interrupt
              wait(100);
              EIFR = (1<<INTF0) | (1<<INTF1);
            attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
          

          all works perfectly, in that the interrupt executes.
          What I am asking is . Is there a way of stopping the sleep from continuing for the rest of the time defined by MYsleepTime? ( actually MYsleepTime = 3600000)
          I can, and am for the moment, performing the calculations, and sending data to the controller in the interrupt, but that is very poor programming in principal. What I wish to do is simply set a flag, and then have the main loop execute, where I can decide what to do, and then return to sleep, after I have done all I wish.

          Many thanks
          Nigel

          YveauxY Offline
          YveauxY Offline
          Yveaux
          Mod
          wrote on last edited by
          #4

          @Njwyborn post your full sketch please. You should not attach your own interrupt handler and let mysensors handle it instead.

          http://yveaux.blogspot.nl

          N 2 Replies Last reply
          1
          • YveauxY Yveaux

            @Njwyborn post your full sketch please. You should not attach your own interrupt handler and let mysensors handle it instead.

            N Offline
            N Offline
            Nigel31
            wrote on last edited by
            #5

            @Yveaux

            Full sketch as requested. the sketch includes some serial.prints in the interrupt handler for debug purposes.
            the vast majority of the interrupt code, was in the main loop, I have moved it in order to get "on demand" transmissions, so I can test Domoticz / setup the device. I HAD to include somthing for the rainrate, else donoticz wouldnt create the device, even though it showed up in hardware OK.

            // Enable debug prints
            //#define MY_DEBUG
            //#define MY_DEBUG_VERBOSE_SIGNING
            //#define MY_SIGNING_SOFT
            //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
            //#define MY_SIGNING_REQUEST_SIGNATURES
            #define   MY_SPLASH_SCREEN_DISABLED
            //#define   MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
            #define MY_TRANSPORT_WAIT_READY_MS 10000
            #define MY_RADIO_RFM69
            #define MY_RFM69_FREQUENCY RFM69_433MHZ // Set your frequency here
            //#define MY_RFM69_MAX_POWER_LEVEL_DBM (13)   // max. TX power 10dBm = 10mW
            #define   MY_RFM69_TX_POWER_DBM (13)
            #define MY_IS_RFM69HW // Omit if your RFM is not "H"
            
            #define MY_NODE_ID 32
            #include <MySensors.h>
            #include <SPI.h>
            #include <math.h>
            #include <TimeLib.h>
            #include <avr/wdt.h>
            #include <Vcc.h>
            
            #define CHILD_ID 32 // Id of the sensor child
            #define VCC_MIN 3.1
            #define VCC_MAX 4.1
            Vcc vcc;
            
            #define CHILD_ID_S_MOISTURE 1
            //#define CHILD_ID_RELAYSTATUS 2
            //#define CHILD_ID_SETPOINT 7
            //#define CHILD_ID_WATERTIME 9
            #define CHILD_ID_RX_RSSI 5
            #define CHILD_ID_BATVCC 6
            #define CHILD_ID_RAIN 11  // Indicates Tripped when rain detected
            #define CHILD_ID_RAINREPORT 10  // Indicates Tripped when rain detected
            
            // EEPROM LOCATIONS
            int SetpointADD = 1;
            int WaterTimeADD = 2;
            int WatermmADD = 8;
            // Pins
            int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
            int Soil_ip_pin = A1;
            int SoilPowerPin = 6;
            int RainPin = 3;
            
            float fullCounter = 0.0f;
            float bucketSize = 0.3f;//0.3mm rain per tip
            float Watermmtot = 0.0f;
            
            unsigned long previousMillis, previousrelayMillis, previouprescence = 0;
            
            volatile long currenttime = 0;
            int ScaledMoisture = 20;
            int oldBatteryPcnt = 0;
            int SoilSetPoint = loadState(SetpointADD) ;
            int WaterTime = loadState(WaterTimeADD) ;
            int RawSoil = 0;
            
            bool Slept = 0;
            bool RainInterrupt = 0;
            bool ValidWaterCount = 0;
            
            unsigned long MYsleepTime = 3600000;//SLEEP_SEC*1000 * SLEEP_MINS * 60  ; //period_t is an enum type defined in the LowPower library (LowPower.h)
            unsigned long lastTipTime = 0;
            
            // Initialize  message
            
            
            MyMessage msgSoil(CHILD_ID_S_MOISTURE, V_LEVEL);
            MyMessage msgRxRSSI(CHILD_ID_RX_RSSI, V_LEVEL);
            MyMessage msgVcc(CHILD_ID_BATVCC, V_VOLTAGE);
            MyMessage msgRain(CHILD_ID_RAINREPORT, V_RAIN);
            MyMessage lastCounterMsg(CHILD_ID_RAIN, V_TEXT);
            MyMessage msgRainRate(CHILD_ID_RAINREPORT, V_RAINRATE);
            
            
            
            
            
            // EEPROM
            //This function will write a 4 byte (32bit) long to the eeprom at
            //the specified address to address + 3.
            void EEPROMWritelong(int address, long value)
            {
              wdt_reset();
              //Decomposition from a long to 4 bytes by using bitshift.
              //One = Most significant -> Four = Least significant byte
              byte four = (value & 0xFF);
              byte three = ((value >> 8) & 0xFF);
              byte two = ((value >> 16) & 0xFF);
              byte one = ((value >> 24) & 0xFF);
            
              //Write the 4 bytes into the eeprom memory.
              saveState(address, four);
              saveState(address + 1, three);
              saveState(address + 2, two);
              saveState(address + 3, one);
            }// end eeprom write
            
            long EEPROMReadlong(long address)// long eeprom read
            {
              //Read the 4 bytes from the eeprom memory.
              long four = loadState(address);
              long three = loadState(address + 1);
              long two = loadState(address + 2);
              long one = loadState(address + 3);
            
              //Return the recomposed long by using bitshift.
              return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
            }
            
            // end EEPROM
            
            
            void setup() {  // put your setup code here, to run once:
              Serial.begin(115200);
              pinMode(SoilPowerPin, OUTPUT); // output
              pinMode(RainPin, INPUT_PULLUP);
              EIFR = (1 << INTF0) | (1 << INTF1); // prevent initial trigger, clear interrupt
              wait(100);
              EIFR = (1 << INTF0) | (1 << INTF1);
              attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
            
              request( CHILD_ID_RAIN, V_TEXT); // readback count
              wait(4000);
              if (ValidWaterCount == 0 ) { // of did not receive valid count
                request( CHILD_ID_RAIN, V_TEXT); // readback count
                wait(4000);
              }
              if (ValidWaterCount == 0 ) { // of did not receive valid count
                Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
              }
            
              // ReadEEprom();
            
            
              wdt_disable(); // Might be redundant as the bootloader should have done this already
              Serial.print("Rain & Soil Sensor RES 1.1.1");
            
              // use the 1.1 V internal reference
            #if defined(__AVR_ATmega2560__)
              analogReference(INTERNAL1V1);
            #else
              analogReference(INTERNAL);
            #endif
            
              // ReadEEprom();
            
              wdt_enable(WDTO_8S);
            }//end setup
            
            void presentation() {
              // Send the sketch version information to the gateway and Controller
              sendSketchInfo("Soil Moisture_R", "1.1.1");
            
            
              // Register all sensors to gw (they will be created as child devices)
              present(CHILD_ID_S_MOISTURE, S_MOISTURE, "Soil Moisture", false);
              wait(250);
              present(CHILD_ID_RX_RSSI, S_SOUND, "Soil & Rain Transmitter RX RSSI", true);
              wait(250);
              present(CHILD_ID_BATVCC, S_MULTIMETER, "Battery V", false);
              wait(250);
              present(CHILD_ID_RAINREPORT, S_RAIN, "Rain", true);
              wait(250);
              present(CHILD_ID_RAIN, S_INFO, "TxTCount", true);
            
            }//end presentation
            
            
            
            
            void loop() { // put your main code here, to run repeatedly:
              wdt_reset();
              getSoil();
              //unsigned long currentMillis = millis();
              // use the 1.1 V internal reference
            #if defined(__AVR_ATmega2560__)
              analogReference(INTERNAL1V1);
            #else
              analogReference(INTERNAL);
            #endif
            
              for (int i = 0; i <= 10; i++) {
                analogRead(BATTERY_SENSE_PIN);
                wait(5);
              }
            
            
              // get the battery Voltage
              int sensorValue = analogRead(BATTERY_SENSE_PIN);// * ((1e6 + 470e3) / 470e3);
            #ifdef MY_DEBUG
              Serial.print("sensorValue raw ");
              Serial.println(analogRead(BATTERY_SENSE_PIN));
              Serial.print("sensorValue V ");
              Serial.println(sensorValue);
            #endif
              wdt_reset();
              // 1M, 470K divider across battery and using internal ADC ref of 1.1V
              // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
              // ((1e6+360e3)/360e3)*1.1 = Vmax = 4.15 Volts
              // 3.44/1023 = Volts per bit = 0.004062127
            
            
              //long batteryVt  = map(sensorValue, 0 , 1023, 0, 43000); // get the target positionsensorValue * 0.003363075;
              float batteryV  = (sensorValue * (4.08 / 3.88)) * 0.004062127; // batteryVt/10000;
              int batteryPcnt = ((batteryV - VCC_MIN) / (VCC_MAX - VCC_MIN)) * 100;// sensorValue / 10;
            
              send(msgSoil.set(ScaledMoisture, 0)); // send moisture
              wait(100);
            
              wdt_reset();
            
              //float volts = vcc.Read_Volts();
              send(msgVcc.set(batteryV, 1));
            
              //#ifdef MY_DEBUG
            
              Serial.print("Soil Moisture : ");
              Serial.print(ScaledMoisture);
              Serial.println(" cb");
            
              Serial.print("Battery Voltage count: ");
              Serial.print(sensorValue);
              Serial.println(" int");
            
              Serial.print("Battery Voltage: ");
              Serial.print(batteryV);
              Serial.println(" V");
            
              Serial.print("Battery percent: ");
              Serial.print(batteryPcnt);
              Serial.println(" %");
              //#endif
              wdt_reset();
            
              if (oldBatteryPcnt != batteryPcnt) {
                //  sendBatteryReport();
                sendBatteryLevel(batteryPcnt);
                oldBatteryPcnt = batteryPcnt;
              }
            
              RX_SEND();
            
              if (batteryPcnt < 35) {
                //send(msgText.set("Sleep*10"), false);
                Serial.println("Sleep*10");
                wdt_reset();
                //sleep(MYsleepTime*5); // sleep(MYsleepTime);
                RainInterrupt = 0;
                sleep(RainPin, FALLING, MYsleepTime * 5);
            
                Slept = 1;
                wdt_reset();
                //requestTime();// get time
            
              }
              else if (batteryPcnt<75 and batteryPcnt>35) {
                //send(msgText.set("Sleep*3"), false);
                Serial.println("Sleep");
                wdt_reset();
                RainInterrupt = 0;
                //sleep(MYsleepTime*3); // sleep(MYsleepTime);
                sleep(RainPin, FALLING, MYsleepTime * 3);
                Slept = 1;
                wdt_reset();
                //requestTime();// get time
              }
              else {
                Serial.println("Sleep :");
                wdt_reset();
                RainInterrupt = 0;
                //sleep(MYsleepTime); // sleep(MYsleepTime)
                sleep(RainPin, FALLING, MYsleepTime);
                Slept = 1;
                wdt_reset();
              }
              wait(100);// need to wait otherwisee the debounce won't work
            
            
            
            
            }// end loop
            
            
            
            void receive(const MyMessage &message) {
              // We only expect one type of message from controller. But we better check anyway.
              wdt_reset();
              if (message.isAck()) {
            #ifdef MY_DEBUG
                Serial.println("+Ack FMGW");
            #endif
              }
            
            #ifdef MY_DEBUG
              Serial.print("*InMsgty :");
              Serial.print(message.type);
              Serial.print(" MsgComd:");
              Serial.print(message.getCommand());
              Serial.print(" childID:");
              Serial.print(message.sensor);
            
              Serial.print(" Switch:");
              Serial.println(message.getFloat());
            #endif
            
            
              if (message.type == V_STATUS || S_HEATER || V_LIGHT || V_TEXT || V_HVAC_SETPOINT_HEAT || V_PERCENTAGE || S_DIMMER) {
            
            
                if (message.getCommand() == 2) { // THIS PROCESSES THE CONTROLLERS EXPECTED STATE OF THE OUTPUT
                  // put code here to be executed when the message is from a request
            #ifdef MY_DEBUG
                  Serial.print("REQ_Msg :");
                  Serial.print(message.type);
                  Serial.print(" MsgCmd:");
                  Serial.print(message.getCommand());
                  Serial.print(" childID:");
                  Serial.print(message.sensor);
                  Serial.print(" Switch:");
                  Serial.println(message.getBool());
            #endif
            
                  switch (message.sensor) {// the child ID
            
                    case 11:
            
                      Watermmtot = message.getFloat();
                      //#ifdef MY_DEBUG
                      Serial.print(" Incoming Rain mm:");
                      Serial.println(Watermmtot);
                      //#endif
                      if (Watermmtot >= 0.3) {
                        EEPROMWritelong(WatermmADD, Watermmtot);
                      }
                      else {
                        Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                        ValidWaterCount = 1;
                      }
                      break;
            
                  } // end switch
            
            
            
            
                }// end msg=2
            
                if (message.getCommand() == 1) { // THIS PROCESSES DIRECTED COMMANDS
            
            
            #ifdef MY_DEBUG
                  Serial.print("*InMsgty :");
                  Serial.print(message.type);
                  Serial.print(" MsgComd:");
                  Serial.print(message.getCommand());
                  Serial.print(" childID:");
                  Serial.print(message.sensor);
            
                  Serial.print(" Switch:");
                  Serial.println(message.getBool());
            #endif
                  /*
                        switch (message.sensor) {// the child ID
            
                          case 2:
                            TempRELAY = message.getBool();
                            //#ifdef MY_DEBUG
                            Serial.print(" Incoming rELAY:");
                            Serial.println(TempRELAY);
                            //#endif
            
                            watering = TempRELAY;
            
                            send(msgRelay.set(watering, 0)); // send relay state
            
            
                            break;
            
                        } // end switch
            
                  */
            
            
                }// end if msg = 1
            
            
              }// end msg type function
            
            }// end void loop
            
            
            
            void RX_SEND()
            {
              wdt_reset();
              send(msgRxRSSI.set(transportGetSignalReport(SR_RX_RSSI)));
              wdt_reset();
            }
            
            
            void sendBatteryReport() {
              wdt_reset();
            
              float p = vcc.Read_Perc(VCC_MIN, VCC_MAX, true);
              int batteryPcnt = static_cast<int>(p);
            #ifdef MY_DEBUG
              Serial.print("Battery is: "); Serial.println(batteryPcnt);
            #endif
              sendBatteryLevel(batteryPcnt);
            }
            
            
            
            void ReadEEprom() {
              wdt_reset();
              //if (EEPROMReadlong(SetpointADD) > 0) SoilSetPoint = EEPROMReadlong(SetpointADD) ;
              //if (EEPROMReadlong(WaterTimeADD) > 0) WaterTime = EEPROMReadlong(WaterTimeADD) ;
            
              if (loadState(SetpointADD) > 0) SoilSetPoint = loadState(SetpointADD) ;
              if (loadState(WaterTimeADD) > 0) WaterTime = loadState(WaterTimeADD) ;
            
            }
            
            
            
            void getSoil() {
              wdt_reset();
            
              analogReference(DEFAULT);
              for (int i = 0; i <= 10; i++) {
                RawSoil = analogRead(Soil_ip_pin);
                wait(5);
              }
            
              int soilCount = 0;
              unsigned long soilAccum = 0;
              digitalWrite(SoilPowerPin, HIGH); // Power up sensor
              wait(1000);
            
              RawSoil = analogRead(Soil_ip_pin);
              soilAccum = RawSoil;
              while (soilCount < 50) {
                wait(20);
                RawSoil = analogRead(Soil_ip_pin);
                if (RawSoil > 0) {
                  soilAccum = soilAccum + RawSoil;
                }
                soilCount++;
              }
              Serial.print("SCount ");
              Serial.println(soilCount);
              RawSoil = soilAccum / soilCount;
              Serial.print("RawSoil ");
              Serial.println(RawSoil);
            
              wait(1);
              ScaledMoisture = map(RawSoil, 600 , 0, 0, 100); // get the target position
              digitalWrite(SoilPowerPin, LOW); // Power down sensor
            
              Serial.print("Scaled Moisture CB ");
              Serial.println(ScaledMoisture);
            
            }
            
            void RainINT() {
              unsigned long thisTipTime = millis();
              Serial.println("int");
              if (thisTipTime - lastTipTime > 20UL) {// debounce 100ms
                Watermmtot = Watermmtot + bucketSize;
                fullCounter = fullCounter + bucketSize;//Count so we send the counter for every 1mm
                Serial.println(Watermmtot);
                RainInterrupt = 1;
                lastTipTime = thisTipTime;
              }
              wait(21);// need to wait otherwisee the debounce won't work
            
              if (RainInterrupt == 1) {// of woken due to rain bucket actions
            
                Serial.print("Total Water = ");
                Serial.print(Watermmtot);
                Serial.println(" mm");
            
                if (fullCounter >= 1) {
                  resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                  if (resend(msgRain.set(Watermmtot, 1) , true, 5)) { // only reset if sending succeeded
                    resend(msgRainRate.set(100) , true, 5);
                    Serial.print("Total Water Transmitted = ");
                    Serial.print(Watermmtot);
                    Serial.println(" mm");
                    fullCounter = fullCounter - 1;
                    RainInterrupt = 0;
                    EEPROMWritelong(WatermmADD, Watermmtot);
                  }
                }
              }
            
            
            }
            
            
            bool resend(MyMessage & msg, bool ack, int repeats)
            {
              wdt_reset();
              int repeat = 1;
              int repeatdelay = 0;
              boolean sendOK = false;
            
              while ((sendOK == false) and (repeat < repeats)) {
                if (send(msg, ack)) {
                  sendOK = true;
                } else {
                  sendOK = false;
                  Serial.print("TX Error ");
                  Serial.println(repeat);
                  repeatdelay += 200;
                  if (repeatdelay >= 500) {
                    repeatdelay = 500;
                  }
                  wdt_reset();
                } repeat++; wait(repeatdelay);
              }
              return sendOK;
            }
            
            1 Reply Last reply
            0
            • YveauxY Yveaux

              @Njwyborn post your full sketch please. You should not attach your own interrupt handler and let mysensors handle it instead.

              N Offline
              N Offline
              Nigel31
              wrote on last edited by
              #6

              @Yveaux
              Could you elaborate a little please on the declaration of the interrupt?
              Are you saying that the sleep function

              sleep(RainPin, FALLING, MYsleepTime);
              

              Sets an interrupt handler, the same as

              attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
              

              If that's the case, how does it know what routeen to call?
              If I do not declare the interrupt, as usual, then surely, when code is in the middle of executing in the loop, or another function, how would the event be captured?

              many thanks
              Nigel

              YveauxY 1 Reply Last reply
              0
              • N Nigel31

                @Yveaux
                Could you elaborate a little please on the declaration of the interrupt?
                Are you saying that the sleep function

                sleep(RainPin, FALLING, MYsleepTime);
                

                Sets an interrupt handler, the same as

                attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                

                If that's the case, how does it know what routeen to call?
                If I do not declare the interrupt, as usual, then surely, when code is in the middle of executing in the loop, or another function, how would the event be captured?

                many thanks
                Nigel

                YveauxY Offline
                YveauxY Offline
                Yveaux
                Mod
                wrote on last edited by Yveaux
                #7

                @Njwyborn yes, the sleep() function which takes an interrupt will install an interrupt handler, enable interrupts for wakeup and then goes to sleep for the specified time, unless it wakes early from an interrupt.
                Its use and some example code is documented here: https://www.mysensors.org/download/sensor_api_20#sleeping

                If you're into low-level coding you can find the heart of the underlying library implementation for AVR here https://github.com/mysensors/MySensors/blob/b9d9cc339659f724aa94d4108fc5289a720d1bcd/hal/architecture/AVR/MyHwAVR.cpp#L175
                It takes care of some tricky corner-cases involving interrupts and sleeping the CPU.

                Note that you should call sleep() as

                sleep(digitalPinToInterrupt(RainPin), FALLING, MYsleepTime);
                

                so pass it an interrupt instead of the pin number

                http://yveaux.blogspot.nl

                N 1 Reply Last reply
                1
                • YveauxY Yveaux

                  @Njwyborn yes, the sleep() function which takes an interrupt will install an interrupt handler, enable interrupts for wakeup and then goes to sleep for the specified time, unless it wakes early from an interrupt.
                  Its use and some example code is documented here: https://www.mysensors.org/download/sensor_api_20#sleeping

                  If you're into low-level coding you can find the heart of the underlying library implementation for AVR here https://github.com/mysensors/MySensors/blob/b9d9cc339659f724aa94d4108fc5289a720d1bcd/hal/architecture/AVR/MyHwAVR.cpp#L175
                  It takes care of some tricky corner-cases involving interrupts and sleeping the CPU.

                  Note that you should call sleep() as

                  sleep(digitalPinToInterrupt(RainPin), FALLING, MYsleepTime);
                  

                  so pass it an interrupt instead of the pin number

                  N Offline
                  N Offline
                  Nigel31
                  wrote on last edited by
                  #8

                  @Yveaux
                  many thanks for the response.
                  So if I understand correctly, you are saying (in my code above) that I should call

                  sleep(digitalPinToInterrupt(RainINT), FALLING, MYsleepTime);
                  
                  

                  that is passing the interrupt handler RATHER than the PIN?

                  BUT still call

                  pinMode(RainPin, INPUT_PULLUP);
                  attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                  

                  in the setup?

                  From my reading of the code you reference above, any existing interrupt handler is disabled prior to the final sleeping, and re-attachment of the interrupt. However I don't see where it might reference the interrupt handler.
                  I see that a value is returned after waking, which is either the pin, or "0" dependant on wake cause, and this is utilised in the example you quote above.

                  Question, Is an existing interrupt handler re-instated anywhere after waking? or is it up to me to re-attech the IRQ handler? I ask, as if not then any "event" occurring whilst not sleeping will be missed. which in my case is quite likely during heavy rain.
                  Sorry if I am being a little thick. Might it be better for me to use just a short timed sleep (say 1 sec), loop for n sec to provide my ultimate sleep time, subject to breaking the loop if a interrupt occurs, by setting a flag in the IRQ handler.
                  I realise this is what is sort of being done in the example above, using Mysensors returned value from the sleep + interrupt function, but it won't (I think) address the case of an interrupt occuring whilst actioning the several seconds potentially utilised during the main loop, especially if there are re-transmit attempts.

                  Once again many thanks for the help.

                  regards Nigel

                  1 Reply Last reply
                  0
                  • N Offline
                    N Offline
                    Nigel31
                    wrote on last edited by
                    #9

                    Update.
                    If I called the sleep, passing the interrupt, rather than the pin

                    sleep(digitalPinToInterrupt(RainINT), FALLING, MYsleepTime);
                    

                    the compiler complained (unsurprisingly I thought), as it is expecting a uint8_t

                    int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,

                    If I passed the pin, but utilised the return value as in

                    wakeupReason = sleep(digitalPinToInterrupt(INT_PIN), CHANGE, sleepTime);
                    

                    ALL Iever got was "-1" as a return value, EVEN THOUGH the interrupt was firing (still having defined and attached the interrupt)

                    pinMode(RainPin, INPUT_PULLUP);
                      EIFR = (1 << INTF0) | (1 << INTF1); // prevent initial trigger, clear interrupt
                      wait(100);
                      EIFR = (1 << INTF0) | (1 << INTF1);
                      attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                    

                    If I detached the interrupt, before calling the sleep function with

                    
                      detachInterrupt(digitalPinToInterrupt(RainPin));
                    

                    then the Interrupt failed to execute, NOR did the return value from the sleep function deviate from -1
                    I was calling this for 1000ms, in a loop, checking the return value and executing the original RainInt() to do the counting/ incrementing.

                    In the end I have gone with my own looping sleep, and checking at the end of each sleep, for the interrupt having fired.

                    // Sleeping 
                     
                                while((SleepCnt < MYsleepTime) ){
                                  sleep(1000);
                                
                                      if(RainInterrupt == 1){
                                        break;
                                      }
                                      else{
                                        Slept = 1;
                                        wdt_reset();
                                      }
                                  SleepCnt=SleepCnt+1000; // count another 1000ms of sleep
                                  wdt_reset();
                                
                                }// end while
                    

                    This works fine, including actioning the interrupt if it occurs during the rest of the loop.

                    should anyone be interested, here is the whole sketch, no douby it can be much improved upon, but it is working.

                    // Enable debug prints
                    //#define MY_DEBUG
                    //#define MY_DEBUG_VERBOSE_SIGNING
                    //#define MY_SIGNING_SOFT
                    //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
                    //#define MY_SIGNING_REQUEST_SIGNATURES
                    #define   MY_SPLASH_SCREEN_DISABLED
                    //#define   MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
                    #define MY_TRANSPORT_WAIT_READY_MS 10000
                    #define MY_RADIO_RFM69
                    #define MY_RFM69_FREQUENCY RFM69_433MHZ // Set your frequency here
                    //#define MY_RFM69_MAX_POWER_LEVEL_DBM (13)   // max. TX power 10dBm = 10mW
                    #define   MY_RFM69_TX_POWER_DBM (13)
                    #define MY_IS_RFM69HW // Omit if your RFM is not "H"
                    
                    #define MY_NODE_ID 32
                    #include <MySensors.h>
                    #include <SPI.h>
                    #include <math.h>
                    //#include <TimeLib.h>
                    #include <avr/wdt.h>
                    #include <Vcc.h>
                    
                    #define CHILD_ID 32 // Id of the sensor child
                    #define VCC_MIN 3.1
                    #define VCC_MAX 4.16
                    Vcc vcc;
                    
                    #define CHILD_ID_S_MOISTURE 1
                    //#define CHILD_ID_RELAYSTATUS 2
                    //#define CHILD_ID_SETPOINT 7
                    //#define CHILD_ID_WATERTIME 9
                    #define CHILD_ID_RX_RSSI 5
                    #define CHILD_ID_BATVCC 6
                    #define CHILD_ID_RAIN 11  // Indicates Tripped when rain detected
                    #define CHILD_ID_RAINREPORT 10  // Indicates Tripped when rain detected
                    
                    // EEPROM LOCATIONS
                    int SetpointADD = 1;
                    int WaterTimeADD = 2;
                    int WatermmADD = 8;
                    // Pins
                    int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
                    int Soil_ip_pin = A1;
                    int SoilPowerPin = 6;
                    int RainPin = 3;
                    const int Debouncetime = 40;
                    int wakeupReason =0;
                    
                    float fullCounter = 0.0f;
                    float bucketSize = 0.3f;//0.3mm rain per tip
                    volatile float Watermmtot = 0.0f;
                    float prevWatermmtot = 0.0f;
                    float rainratenow  = 0.0f;
                    
                    unsigned long previousMillis, previousrelayMillis, previouprescence , SleepCnt , RemainSleep = 0;
                    
                    volatile long currenttime = 0;
                    int ScaledMoisture = 20;
                    int oldBatteryPcnt = 0;
                    int SoilSetPoint = loadState(SetpointADD) ;
                    int WaterTime = loadState(WaterTimeADD) ;
                    int RawSoil = 0;
                    
                    bool Slept = 0;
                    volatile bool RainInterrupt = 0;
                    bool ValidWaterCount = 0;
                    
                    float batteryV  = 3.70f;
                    int batteryPcnt = 50;
                    
                    
                    unsigned long MYsleepTime , BaseMYsleepTime = 900000;//SLEEP_SEC*1000 * SLEEP_MINS * 60  ; //period_t is an enum type defined in the LowPower library (LowPower.h) 900000
                    unsigned long lastTipTime = 0;
                    
                    // Initialize  message
                    
                    
                    MyMessage msgSoil(CHILD_ID_S_MOISTURE, V_LEVEL);
                    MyMessage msgRxRSSI(CHILD_ID_RX_RSSI, V_LEVEL);
                    MyMessage msgVcc(CHILD_ID_BATVCC, V_VOLTAGE);
                    MyMessage msgRain(CHILD_ID_RAINREPORT, V_RAIN);
                    MyMessage lastCounterMsg(CHILD_ID_RAIN, V_TEXT);
                    MyMessage msgRainRate(CHILD_ID_RAINREPORT, V_RAINRATE);
                    
                    
                    
                    
                    
                    // EEPROM
                    //This function will write a 4 byte (32bit) long to the eeprom at
                    //the specified address to address + 3.
                    void EEPROMWritelong(int address, long value)
                    {
                      wdt_reset();
                      //Decomposition from a long to 4 bytes by using bitshift.
                      //One = Most significant -> Four = Least significant byte
                      byte four = (value & 0xFF);
                      byte three = ((value >> 8) & 0xFF);
                      byte two = ((value >> 16) & 0xFF);
                      byte one = ((value >> 24) & 0xFF);
                    
                      //Write the 4 bytes into the eeprom memory.
                      saveState(address, four);
                      saveState(address + 1, three);
                      saveState(address + 2, two);
                      saveState(address + 3, one);
                    }// end eeprom write
                    
                    long EEPROMReadlong(long address)// long eeprom read
                    {
                      //Read the 4 bytes from the eeprom memory.
                      long four = loadState(address);
                      long three = loadState(address + 1);
                      long two = loadState(address + 2);
                      long one = loadState(address + 3);
                    
                      //Return the recomposed long by using bitshift.
                      return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
                    }
                    
                    // end EEPROM
                    
                    
                    void setup() {  // put your setup code here, to run once:
                      Serial.begin(115200);
                      pinMode(SoilPowerPin, OUTPUT); // output
                      pinMode(RainPin, INPUT_PULLUP);
                      EIFR = (1 << INTF0) | (1 << INTF1); // prevent initial trigger, clear interrupt
                      wait(100);
                      EIFR = (1 << INTF0) | (1 << INTF1);
                      attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                    
                      request( CHILD_ID_RAIN, V_TEXT); // readback count
                      wait(4000);
                      if (ValidWaterCount == 0 ) { // of did not receive valid count
                        request( CHILD_ID_RAIN, V_TEXT); // readback count
                        wait(4000);
                      }
                      if (ValidWaterCount == 0 ) { // of did not receive valid count
                        Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                        prevWatermmtot = Watermmtot;
                      }
                    
                      // ReadEEprom();
                    
                    
                      wdt_disable(); // Might be redundant as the bootloader should have done this already
                      Serial.print("Rain & Soil Sensor RES 1.1.2");
                    
                      // use the 1.1 V internal reference
                    #if defined(__AVR_ATmega2560__)
                      analogReference(INTERNAL1V1);
                    #else
                      analogReference(INTERNAL);
                    #endif
                    
                      // ReadEEprom();
                    
                      wdt_enable(WDTO_8S);
                    }//end setup
                    
                    void presentation() {
                      // Send the sketch version information to the gateway and Controller
                      sendSketchInfo("Soil Moisture_R", "1.1.2");
                    
                    
                      // Register all sensors to gw (they will be created as child devices)
                      present(CHILD_ID_S_MOISTURE, S_MOISTURE, "Soil Moisture", false);
                      wait(250);
                      present(CHILD_ID_RX_RSSI, S_SOUND, "Soil & Rain Transmitter RX RSSI", true);
                      wait(250);
                      present(CHILD_ID_BATVCC, S_MULTIMETER, "Battery V", false);
                      wait(250);
                      present(CHILD_ID_RAINREPORT, S_RAIN, "Rain", true);
                      wait(250);
                      present(CHILD_ID_RAIN, S_INFO, "TxTCount", true);
                    
                    }//end presentation
                    
                    
                    
                    
                    void loop() { // put your main code here, to run repeatedly:
                      
                      wdt_reset();
                    
                    if (RainInterrupt == 0) {
                      
                    
                            getSoil();
                            //unsigned long currentMillis = millis();
                            // use the 1.1 V internal reference
                          #if defined(__AVR_ATmega2560__)
                            analogReference(INTERNAL1V1);
                          #else
                            analogReference(INTERNAL);
                          #endif
                          
                            for (int i = 0; i <= 10; i++) {
                              analogRead(BATTERY_SENSE_PIN);
                              wait(5);
                            }
                          
                          
                            // get the battery Voltage
                            int sensorValue = analogRead(BATTERY_SENSE_PIN);// * ((1e6 + 470e3) / 470e3);
                          #ifdef MY_DEBUG
                            Serial.print("sensorValue raw ");
                            Serial.println(analogRead(BATTERY_SENSE_PIN));
                            Serial.print("sensorValue V ");
                            Serial.println(sensorValue);
                          #endif
                            wdt_reset();
                            // 1M, 470K divider across battery and using internal ADC ref of 1.1V
                            // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
                            // ((1e6+360e3)/360e3)*1.1 = Vmax = 4.15 Volts
                            // 3.44/1023 = Volts per bit = 0.004062127
                          
                          
                            //long batteryVt  = map(sensorValue, 0 , 1023, 0, 43000); // get the target positionsensorValue * 0.003363075;
                            batteryV  = (sensorValue * (4.08 / 3.88)) * 0.004062127; // batteryVt/10000;
                            batteryPcnt = ((batteryV - VCC_MIN) / (VCC_MAX - VCC_MIN)) * 100;// sensorValue / 10;
                          
                            send(msgSoil.set(ScaledMoisture, 0)); // send moisture
                            wait(100);
                          
                            wdt_reset();
                          
                            //float volts = vcc.Read_Volts();
                            send(msgVcc.set(batteryV, 1));
                          
                            //#ifdef MY_DEBUG
                          
                            Serial.print("Soil Moisture : ");
                            Serial.print(ScaledMoisture);
                            Serial.println(" cb");
                          
                            Serial.print("Battery Voltage count: ");
                            Serial.print(sensorValue);
                            Serial.println(" int");
                          
                            Serial.print("Battery Voltage: ");
                            Serial.print(batteryV);
                            Serial.println(" V");
                          
                            Serial.print("Battery percent: ");
                            Serial.print(batteryPcnt);
                            Serial.println(" %");
                            //#endif
                            wdt_reset();
                          
                            if (oldBatteryPcnt != batteryPcnt) {
                              //  sendBatteryReport();
                              sendBatteryLevel(batteryPcnt);
                              oldBatteryPcnt = batteryPcnt;
                            }
                          
                            RX_SEND();
                          
                          
                            if( Watermmtot == prevWatermmtot){
                              rainratenow = 0.0;
                            }
                            else{
                              rainratenow = ((Watermmtot - prevWatermmtot)*4) *100;
                            }
                          
                                resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                                resend(msgRain.set(Watermmtot, 1) , true, 5);
                                if(resend(msgRainRate.set(rainratenow,1) , true, 2)){
                                  prevWatermmtot = Watermmtot;
                                }
                       }// end if not rain interrupt   
                            
                            if (batteryPcnt < 35) {
                              //send(msgText.set("Sleep*10"), false);
                              Serial.println("Sleep*10");
                              MYsleepTime = (BaseMYsleepTime * 10);
                              wdt_reset();
                              //requestTime();// get time     
                            }
                            else if (batteryPcnt<75 and batteryPcnt>35) {
                              //send(msgText.set("Sleep*3"), false);
                              Serial.println("Sleep*3");
                              wdt_reset();
                              MYsleepTime = (BaseMYsleepTime * 3) ;
                              //requestTime();// get time
                            }
                            else {
                              Serial.println("Sleep :");
                              wdt_reset();
                              MYsleepTime = BaseMYsleepTime;
                            }
                        //    Serial.print("Sleepcount = ");Serial.println(SleepCnt);
                         //   Serial.print("Sleeptime = ");Serial.println(MYsleepTime);  
                            MYsleepTime = constrain((MYsleepTime - SleepCnt),1000,MYsleepTime);// calc how much left from last sleep
                         //   Serial.print("RemainSleep = ");Serial.println(MYsleepTime);
                    
                            SleepCnt=0;
                            RainInterrupt = 0;
                              
                    // Sleeping 
                     
                                while((SleepCnt < MYsleepTime) ){//or (wakeupReason != digitalPinToInterrupt(RainPin)) or (RainInterrupt != 1) 
                                  sleep(1000);
                                
                                      if(RainInterrupt == 1){
                                        break;
                                      }
                                      else{
                                        Slept = 1;
                                        wdt_reset();
                                      }
                                  SleepCnt=SleepCnt+1000; // count another 1000ms of sleep
                                  wdt_reset();
                                
                                }// end while
                                
                                if(SleepCnt>=(MYsleepTime - 10000)){
                                  SleepCnt=0;
                                }
                    
                              attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                              
                              wdt_reset();
                    
                      
                     wait(Debouncetime + 1);// need to wait otherwisee the debounce won't work because millis not updated in sleep
                    
                      if (RainInterrupt == 1) {// of woken due to rain bucket actions
                        //  Serial.println(F("RainInterrupt=1"));
                    
                          resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                          if (resend(msgRain.set(Watermmtot, 1) , true, 5)) { // only reset if sending succeeded
                            resend(msgRainRate.set(30) , true, 5);
                            fullCounter = fullCounter - 1;
                            //RainInterrupt = 0;
                            EEPROMWritelong(WatermmADD, Watermmtot);
                          }
                    
                      }
                    
                    }// end loop
                    
                    
                    
                    void receive(const MyMessage &message) {
                      // We only expect one type of message from controller. But we better check anyway.
                      wdt_reset();
                      if (message.isAck()) {
                    #ifdef MY_DEBUG
                        Serial.println("+Ack FMGW");
                    #endif
                      }
                    
                    #ifdef MY_DEBUG
                      Serial.print("*InMsgty :");
                      Serial.print(message.type);
                      Serial.print(" MsgComd:");
                      Serial.print(message.getCommand());
                      Serial.print(" childID:");
                      Serial.print(message.sensor);
                    
                      Serial.print(" Switch:");
                      Serial.println(message.getFloat());
                    #endif
                    
                    
                      if (message.type == V_STATUS || S_HEATER || V_LIGHT || V_TEXT || V_HVAC_SETPOINT_HEAT || V_PERCENTAGE || S_DIMMER) {
                    
                    
                        if (message.getCommand() == 2) { // THIS PROCESSES THE CONTROLLERS EXPECTED STATE OF THE OUTPUT
                          // put code here to be executed when the message is from a request
                    #ifdef MY_DEBUG
                          Serial.print("REQ_Msg :");
                          Serial.print(message.type);
                          Serial.print(" MsgCmd:");
                          Serial.print(message.getCommand());
                          Serial.print(" childID:");
                          Serial.print(message.sensor);
                          Serial.print(" Switch:");
                          Serial.println(message.getBool());
                    #endif
                    
                          switch (message.sensor) {// the child ID
                    
                            case 11:
                    
                              Watermmtot = message.getFloat();
                              //#ifdef MY_DEBUG
                              Serial.print(" Incoming Rain mm:");
                              Serial.println(Watermmtot);
                              //#endif
                              if (Watermmtot >= 0.3) {
                                EEPROMWritelong(WatermmADD, Watermmtot);
                              }
                              else {
                                Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                                ValidWaterCount = 1;
                              }
                              break;
                    
                          } // end switch
                    
                        }// end msg=2
                    
                        if (message.getCommand() == 1) { // THIS PROCESSES DIRECTED COMMANDS
                    
                    
                    #ifdef MY_DEBUG
                          Serial.print("*InMsgty :");
                          Serial.print(message.type);
                          Serial.print(" MsgComd:");
                          Serial.print(message.getCommand());
                          Serial.print(" childID:");
                          Serial.print(message.sensor);
                    
                          Serial.print(" Switch:");
                          Serial.println(message.getBool());
                    #endif
                      
                        }// end if msg = 1
                    
                      }// end msg type function
                    
                    }// end void loop
                    
                    
                    
                    void RX_SEND()
                    {
                      wdt_reset();
                      send(msgRxRSSI.set(transportGetSignalReport(SR_RX_RSSI)));
                      wdt_reset();
                    }
                    
                    
                    void sendBatteryReport() {
                      wdt_reset();
                    
                      float p = vcc.Read_Perc(VCC_MIN, VCC_MAX, true);
                      int batteryPcnt = static_cast<int>(p);
                    #ifdef MY_DEBUG
                      Serial.print("Battery is: "); Serial.println(batteryPcnt);
                    #endif
                      sendBatteryLevel(batteryPcnt);
                    }
                    
                    
                    
                    void ReadEEprom() {
                      wdt_reset();
                      //if (EEPROMReadlong(SetpointADD) > 0) SoilSetPoint = EEPROMReadlong(SetpointADD) ;
                      //if (EEPROMReadlong(WaterTimeADD) > 0) WaterTime = EEPROMReadlong(WaterTimeADD) ;
                    
                      if (loadState(SetpointADD) > 0) SoilSetPoint = loadState(SetpointADD) ;
                      if (loadState(WaterTimeADD) > 0) WaterTime = loadState(WaterTimeADD) ;
                    
                    }
                    
                    
                    
                    void getSoil() {
                      wdt_reset();
                    
                      analogReference(DEFAULT);
                      for (int i = 0; i <= 10; i++) {
                        RawSoil = analogRead(Soil_ip_pin);
                        wait(5);
                      }
                    
                      int soilCount = 0;
                      unsigned long soilAccum = 0;
                      digitalWrite(SoilPowerPin, HIGH); // Power up sensor
                      wait(1000);
                    
                      RawSoil = analogRead(Soil_ip_pin);
                      soilAccum = RawSoil;
                      while (soilCount < 50) {
                        wait(20);
                        RawSoil = analogRead(Soil_ip_pin);
                        if (RawSoil > 0) {
                          soilAccum = soilAccum + RawSoil;
                        }
                        soilCount++;
                      }
                      Serial.print("SCount ");
                      Serial.println(soilCount);
                      RawSoil = soilAccum / soilCount;
                      Serial.print("RawSoil ");
                      Serial.println(RawSoil);
                    
                      wait(1);
                      ScaledMoisture = map(RawSoil, 600 , 0, 0, 100); // get the target position
                      digitalWrite(SoilPowerPin, LOW); // Power down sensor
                    
                      Serial.print("Scaled Moisture CB ");
                      Serial.println(ScaledMoisture);
                    
                    }
                    
                    void RainINT() {
                      
                      unsigned long thisTipTime = millis();
                      if (thisTipTime - lastTipTime > (Debouncetime)) {// debounce 20ms
                        Watermmtot = Watermmtot + bucketSize;
                        fullCounter = fullCounter + bucketSize;//Count so we send the counter for every 1mm
                        RainInterrupt = 1;
                        lastTipTime = thisTipTime;
                      }
                    }
                    
                    
                    bool resend(MyMessage & msg, bool ack, int repeats)
                    {
                      wdt_reset();
                      int repeat = 1;
                      int repeatdelay = 0;
                      boolean sendOK = false;
                    
                      while ((sendOK == false) and (repeat < repeats)) {
                        if (send(msg, ack)) {
                          sendOK = true;
                        } else {
                          sendOK = false;
                          Serial.print("TX Error ");
                          Serial.println(repeat);
                          repeatdelay += 200;
                          if (repeatdelay >= 500) {
                            repeatdelay = 500;
                          }
                          wdt_reset();
                        } repeat++; wait(repeatdelay);
                      }
                      return sendOK;
                    }
                    
                    
                    

                    Many thanks for the input.

                    Regards
                    Nigel

                    YveauxY 1 Reply Last reply
                    0
                    • N Nigel31

                      Update.
                      If I called the sleep, passing the interrupt, rather than the pin

                      sleep(digitalPinToInterrupt(RainINT), FALLING, MYsleepTime);
                      

                      the compiler complained (unsurprisingly I thought), as it is expecting a uint8_t

                      int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,

                      If I passed the pin, but utilised the return value as in

                      wakeupReason = sleep(digitalPinToInterrupt(INT_PIN), CHANGE, sleepTime);
                      

                      ALL Iever got was "-1" as a return value, EVEN THOUGH the interrupt was firing (still having defined and attached the interrupt)

                      pinMode(RainPin, INPUT_PULLUP);
                        EIFR = (1 << INTF0) | (1 << INTF1); // prevent initial trigger, clear interrupt
                        wait(100);
                        EIFR = (1 << INTF0) | (1 << INTF1);
                        attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                      

                      If I detached the interrupt, before calling the sleep function with

                      
                        detachInterrupt(digitalPinToInterrupt(RainPin));
                      

                      then the Interrupt failed to execute, NOR did the return value from the sleep function deviate from -1
                      I was calling this for 1000ms, in a loop, checking the return value and executing the original RainInt() to do the counting/ incrementing.

                      In the end I have gone with my own looping sleep, and checking at the end of each sleep, for the interrupt having fired.

                      // Sleeping 
                       
                                  while((SleepCnt < MYsleepTime) ){
                                    sleep(1000);
                                  
                                        if(RainInterrupt == 1){
                                          break;
                                        }
                                        else{
                                          Slept = 1;
                                          wdt_reset();
                                        }
                                    SleepCnt=SleepCnt+1000; // count another 1000ms of sleep
                                    wdt_reset();
                                  
                                  }// end while
                      

                      This works fine, including actioning the interrupt if it occurs during the rest of the loop.

                      should anyone be interested, here is the whole sketch, no douby it can be much improved upon, but it is working.

                      // Enable debug prints
                      //#define MY_DEBUG
                      //#define MY_DEBUG_VERBOSE_SIGNING
                      //#define MY_SIGNING_SOFT
                      //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
                      //#define MY_SIGNING_REQUEST_SIGNATURES
                      #define   MY_SPLASH_SCREEN_DISABLED
                      //#define   MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
                      #define MY_TRANSPORT_WAIT_READY_MS 10000
                      #define MY_RADIO_RFM69
                      #define MY_RFM69_FREQUENCY RFM69_433MHZ // Set your frequency here
                      //#define MY_RFM69_MAX_POWER_LEVEL_DBM (13)   // max. TX power 10dBm = 10mW
                      #define   MY_RFM69_TX_POWER_DBM (13)
                      #define MY_IS_RFM69HW // Omit if your RFM is not "H"
                      
                      #define MY_NODE_ID 32
                      #include <MySensors.h>
                      #include <SPI.h>
                      #include <math.h>
                      //#include <TimeLib.h>
                      #include <avr/wdt.h>
                      #include <Vcc.h>
                      
                      #define CHILD_ID 32 // Id of the sensor child
                      #define VCC_MIN 3.1
                      #define VCC_MAX 4.16
                      Vcc vcc;
                      
                      #define CHILD_ID_S_MOISTURE 1
                      //#define CHILD_ID_RELAYSTATUS 2
                      //#define CHILD_ID_SETPOINT 7
                      //#define CHILD_ID_WATERTIME 9
                      #define CHILD_ID_RX_RSSI 5
                      #define CHILD_ID_BATVCC 6
                      #define CHILD_ID_RAIN 11  // Indicates Tripped when rain detected
                      #define CHILD_ID_RAINREPORT 10  // Indicates Tripped when rain detected
                      
                      // EEPROM LOCATIONS
                      int SetpointADD = 1;
                      int WaterTimeADD = 2;
                      int WatermmADD = 8;
                      // Pins
                      int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
                      int Soil_ip_pin = A1;
                      int SoilPowerPin = 6;
                      int RainPin = 3;
                      const int Debouncetime = 40;
                      int wakeupReason =0;
                      
                      float fullCounter = 0.0f;
                      float bucketSize = 0.3f;//0.3mm rain per tip
                      volatile float Watermmtot = 0.0f;
                      float prevWatermmtot = 0.0f;
                      float rainratenow  = 0.0f;
                      
                      unsigned long previousMillis, previousrelayMillis, previouprescence , SleepCnt , RemainSleep = 0;
                      
                      volatile long currenttime = 0;
                      int ScaledMoisture = 20;
                      int oldBatteryPcnt = 0;
                      int SoilSetPoint = loadState(SetpointADD) ;
                      int WaterTime = loadState(WaterTimeADD) ;
                      int RawSoil = 0;
                      
                      bool Slept = 0;
                      volatile bool RainInterrupt = 0;
                      bool ValidWaterCount = 0;
                      
                      float batteryV  = 3.70f;
                      int batteryPcnt = 50;
                      
                      
                      unsigned long MYsleepTime , BaseMYsleepTime = 900000;//SLEEP_SEC*1000 * SLEEP_MINS * 60  ; //period_t is an enum type defined in the LowPower library (LowPower.h) 900000
                      unsigned long lastTipTime = 0;
                      
                      // Initialize  message
                      
                      
                      MyMessage msgSoil(CHILD_ID_S_MOISTURE, V_LEVEL);
                      MyMessage msgRxRSSI(CHILD_ID_RX_RSSI, V_LEVEL);
                      MyMessage msgVcc(CHILD_ID_BATVCC, V_VOLTAGE);
                      MyMessage msgRain(CHILD_ID_RAINREPORT, V_RAIN);
                      MyMessage lastCounterMsg(CHILD_ID_RAIN, V_TEXT);
                      MyMessage msgRainRate(CHILD_ID_RAINREPORT, V_RAINRATE);
                      
                      
                      
                      
                      
                      // EEPROM
                      //This function will write a 4 byte (32bit) long to the eeprom at
                      //the specified address to address + 3.
                      void EEPROMWritelong(int address, long value)
                      {
                        wdt_reset();
                        //Decomposition from a long to 4 bytes by using bitshift.
                        //One = Most significant -> Four = Least significant byte
                        byte four = (value & 0xFF);
                        byte three = ((value >> 8) & 0xFF);
                        byte two = ((value >> 16) & 0xFF);
                        byte one = ((value >> 24) & 0xFF);
                      
                        //Write the 4 bytes into the eeprom memory.
                        saveState(address, four);
                        saveState(address + 1, three);
                        saveState(address + 2, two);
                        saveState(address + 3, one);
                      }// end eeprom write
                      
                      long EEPROMReadlong(long address)// long eeprom read
                      {
                        //Read the 4 bytes from the eeprom memory.
                        long four = loadState(address);
                        long three = loadState(address + 1);
                        long two = loadState(address + 2);
                        long one = loadState(address + 3);
                      
                        //Return the recomposed long by using bitshift.
                        return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
                      }
                      
                      // end EEPROM
                      
                      
                      void setup() {  // put your setup code here, to run once:
                        Serial.begin(115200);
                        pinMode(SoilPowerPin, OUTPUT); // output
                        pinMode(RainPin, INPUT_PULLUP);
                        EIFR = (1 << INTF0) | (1 << INTF1); // prevent initial trigger, clear interrupt
                        wait(100);
                        EIFR = (1 << INTF0) | (1 << INTF1);
                        attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                      
                        request( CHILD_ID_RAIN, V_TEXT); // readback count
                        wait(4000);
                        if (ValidWaterCount == 0 ) { // of did not receive valid count
                          request( CHILD_ID_RAIN, V_TEXT); // readback count
                          wait(4000);
                        }
                        if (ValidWaterCount == 0 ) { // of did not receive valid count
                          Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                          prevWatermmtot = Watermmtot;
                        }
                      
                        // ReadEEprom();
                      
                      
                        wdt_disable(); // Might be redundant as the bootloader should have done this already
                        Serial.print("Rain & Soil Sensor RES 1.1.2");
                      
                        // use the 1.1 V internal reference
                      #if defined(__AVR_ATmega2560__)
                        analogReference(INTERNAL1V1);
                      #else
                        analogReference(INTERNAL);
                      #endif
                      
                        // ReadEEprom();
                      
                        wdt_enable(WDTO_8S);
                      }//end setup
                      
                      void presentation() {
                        // Send the sketch version information to the gateway and Controller
                        sendSketchInfo("Soil Moisture_R", "1.1.2");
                      
                      
                        // Register all sensors to gw (they will be created as child devices)
                        present(CHILD_ID_S_MOISTURE, S_MOISTURE, "Soil Moisture", false);
                        wait(250);
                        present(CHILD_ID_RX_RSSI, S_SOUND, "Soil & Rain Transmitter RX RSSI", true);
                        wait(250);
                        present(CHILD_ID_BATVCC, S_MULTIMETER, "Battery V", false);
                        wait(250);
                        present(CHILD_ID_RAINREPORT, S_RAIN, "Rain", true);
                        wait(250);
                        present(CHILD_ID_RAIN, S_INFO, "TxTCount", true);
                      
                      }//end presentation
                      
                      
                      
                      
                      void loop() { // put your main code here, to run repeatedly:
                        
                        wdt_reset();
                      
                      if (RainInterrupt == 0) {
                        
                      
                              getSoil();
                              //unsigned long currentMillis = millis();
                              // use the 1.1 V internal reference
                            #if defined(__AVR_ATmega2560__)
                              analogReference(INTERNAL1V1);
                            #else
                              analogReference(INTERNAL);
                            #endif
                            
                              for (int i = 0; i <= 10; i++) {
                                analogRead(BATTERY_SENSE_PIN);
                                wait(5);
                              }
                            
                            
                              // get the battery Voltage
                              int sensorValue = analogRead(BATTERY_SENSE_PIN);// * ((1e6 + 470e3) / 470e3);
                            #ifdef MY_DEBUG
                              Serial.print("sensorValue raw ");
                              Serial.println(analogRead(BATTERY_SENSE_PIN));
                              Serial.print("sensorValue V ");
                              Serial.println(sensorValue);
                            #endif
                              wdt_reset();
                              // 1M, 470K divider across battery and using internal ADC ref of 1.1V
                              // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
                              // ((1e6+360e3)/360e3)*1.1 = Vmax = 4.15 Volts
                              // 3.44/1023 = Volts per bit = 0.004062127
                            
                            
                              //long batteryVt  = map(sensorValue, 0 , 1023, 0, 43000); // get the target positionsensorValue * 0.003363075;
                              batteryV  = (sensorValue * (4.08 / 3.88)) * 0.004062127; // batteryVt/10000;
                              batteryPcnt = ((batteryV - VCC_MIN) / (VCC_MAX - VCC_MIN)) * 100;// sensorValue / 10;
                            
                              send(msgSoil.set(ScaledMoisture, 0)); // send moisture
                              wait(100);
                            
                              wdt_reset();
                            
                              //float volts = vcc.Read_Volts();
                              send(msgVcc.set(batteryV, 1));
                            
                              //#ifdef MY_DEBUG
                            
                              Serial.print("Soil Moisture : ");
                              Serial.print(ScaledMoisture);
                              Serial.println(" cb");
                            
                              Serial.print("Battery Voltage count: ");
                              Serial.print(sensorValue);
                              Serial.println(" int");
                            
                              Serial.print("Battery Voltage: ");
                              Serial.print(batteryV);
                              Serial.println(" V");
                            
                              Serial.print("Battery percent: ");
                              Serial.print(batteryPcnt);
                              Serial.println(" %");
                              //#endif
                              wdt_reset();
                            
                              if (oldBatteryPcnt != batteryPcnt) {
                                //  sendBatteryReport();
                                sendBatteryLevel(batteryPcnt);
                                oldBatteryPcnt = batteryPcnt;
                              }
                            
                              RX_SEND();
                            
                            
                              if( Watermmtot == prevWatermmtot){
                                rainratenow = 0.0;
                              }
                              else{
                                rainratenow = ((Watermmtot - prevWatermmtot)*4) *100;
                              }
                            
                                  resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                                  resend(msgRain.set(Watermmtot, 1) , true, 5);
                                  if(resend(msgRainRate.set(rainratenow,1) , true, 2)){
                                    prevWatermmtot = Watermmtot;
                                  }
                         }// end if not rain interrupt   
                              
                              if (batteryPcnt < 35) {
                                //send(msgText.set("Sleep*10"), false);
                                Serial.println("Sleep*10");
                                MYsleepTime = (BaseMYsleepTime * 10);
                                wdt_reset();
                                //requestTime();// get time     
                              }
                              else if (batteryPcnt<75 and batteryPcnt>35) {
                                //send(msgText.set("Sleep*3"), false);
                                Serial.println("Sleep*3");
                                wdt_reset();
                                MYsleepTime = (BaseMYsleepTime * 3) ;
                                //requestTime();// get time
                              }
                              else {
                                Serial.println("Sleep :");
                                wdt_reset();
                                MYsleepTime = BaseMYsleepTime;
                              }
                          //    Serial.print("Sleepcount = ");Serial.println(SleepCnt);
                           //   Serial.print("Sleeptime = ");Serial.println(MYsleepTime);  
                              MYsleepTime = constrain((MYsleepTime - SleepCnt),1000,MYsleepTime);// calc how much left from last sleep
                           //   Serial.print("RemainSleep = ");Serial.println(MYsleepTime);
                      
                              SleepCnt=0;
                              RainInterrupt = 0;
                                
                      // Sleeping 
                       
                                  while((SleepCnt < MYsleepTime) ){//or (wakeupReason != digitalPinToInterrupt(RainPin)) or (RainInterrupt != 1) 
                                    sleep(1000);
                                  
                                        if(RainInterrupt == 1){
                                          break;
                                        }
                                        else{
                                          Slept = 1;
                                          wdt_reset();
                                        }
                                    SleepCnt=SleepCnt+1000; // count another 1000ms of sleep
                                    wdt_reset();
                                  
                                  }// end while
                                  
                                  if(SleepCnt>=(MYsleepTime - 10000)){
                                    SleepCnt=0;
                                  }
                      
                                attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                                
                                wdt_reset();
                      
                        
                       wait(Debouncetime + 1);// need to wait otherwisee the debounce won't work because millis not updated in sleep
                      
                        if (RainInterrupt == 1) {// of woken due to rain bucket actions
                          //  Serial.println(F("RainInterrupt=1"));
                      
                            resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                            if (resend(msgRain.set(Watermmtot, 1) , true, 5)) { // only reset if sending succeeded
                              resend(msgRainRate.set(30) , true, 5);
                              fullCounter = fullCounter - 1;
                              //RainInterrupt = 0;
                              EEPROMWritelong(WatermmADD, Watermmtot);
                            }
                      
                        }
                      
                      }// end loop
                      
                      
                      
                      void receive(const MyMessage &message) {
                        // We only expect one type of message from controller. But we better check anyway.
                        wdt_reset();
                        if (message.isAck()) {
                      #ifdef MY_DEBUG
                          Serial.println("+Ack FMGW");
                      #endif
                        }
                      
                      #ifdef MY_DEBUG
                        Serial.print("*InMsgty :");
                        Serial.print(message.type);
                        Serial.print(" MsgComd:");
                        Serial.print(message.getCommand());
                        Serial.print(" childID:");
                        Serial.print(message.sensor);
                      
                        Serial.print(" Switch:");
                        Serial.println(message.getFloat());
                      #endif
                      
                      
                        if (message.type == V_STATUS || S_HEATER || V_LIGHT || V_TEXT || V_HVAC_SETPOINT_HEAT || V_PERCENTAGE || S_DIMMER) {
                      
                      
                          if (message.getCommand() == 2) { // THIS PROCESSES THE CONTROLLERS EXPECTED STATE OF THE OUTPUT
                            // put code here to be executed when the message is from a request
                      #ifdef MY_DEBUG
                            Serial.print("REQ_Msg :");
                            Serial.print(message.type);
                            Serial.print(" MsgCmd:");
                            Serial.print(message.getCommand());
                            Serial.print(" childID:");
                            Serial.print(message.sensor);
                            Serial.print(" Switch:");
                            Serial.println(message.getBool());
                      #endif
                      
                            switch (message.sensor) {// the child ID
                      
                              case 11:
                      
                                Watermmtot = message.getFloat();
                                //#ifdef MY_DEBUG
                                Serial.print(" Incoming Rain mm:");
                                Serial.println(Watermmtot);
                                //#endif
                                if (Watermmtot >= 0.3) {
                                  EEPROMWritelong(WatermmADD, Watermmtot);
                                }
                                else {
                                  Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                                  ValidWaterCount = 1;
                                }
                                break;
                      
                            } // end switch
                      
                          }// end msg=2
                      
                          if (message.getCommand() == 1) { // THIS PROCESSES DIRECTED COMMANDS
                      
                      
                      #ifdef MY_DEBUG
                            Serial.print("*InMsgty :");
                            Serial.print(message.type);
                            Serial.print(" MsgComd:");
                            Serial.print(message.getCommand());
                            Serial.print(" childID:");
                            Serial.print(message.sensor);
                      
                            Serial.print(" Switch:");
                            Serial.println(message.getBool());
                      #endif
                        
                          }// end if msg = 1
                      
                        }// end msg type function
                      
                      }// end void loop
                      
                      
                      
                      void RX_SEND()
                      {
                        wdt_reset();
                        send(msgRxRSSI.set(transportGetSignalReport(SR_RX_RSSI)));
                        wdt_reset();
                      }
                      
                      
                      void sendBatteryReport() {
                        wdt_reset();
                      
                        float p = vcc.Read_Perc(VCC_MIN, VCC_MAX, true);
                        int batteryPcnt = static_cast<int>(p);
                      #ifdef MY_DEBUG
                        Serial.print("Battery is: "); Serial.println(batteryPcnt);
                      #endif
                        sendBatteryLevel(batteryPcnt);
                      }
                      
                      
                      
                      void ReadEEprom() {
                        wdt_reset();
                        //if (EEPROMReadlong(SetpointADD) > 0) SoilSetPoint = EEPROMReadlong(SetpointADD) ;
                        //if (EEPROMReadlong(WaterTimeADD) > 0) WaterTime = EEPROMReadlong(WaterTimeADD) ;
                      
                        if (loadState(SetpointADD) > 0) SoilSetPoint = loadState(SetpointADD) ;
                        if (loadState(WaterTimeADD) > 0) WaterTime = loadState(WaterTimeADD) ;
                      
                      }
                      
                      
                      
                      void getSoil() {
                        wdt_reset();
                      
                        analogReference(DEFAULT);
                        for (int i = 0; i <= 10; i++) {
                          RawSoil = analogRead(Soil_ip_pin);
                          wait(5);
                        }
                      
                        int soilCount = 0;
                        unsigned long soilAccum = 0;
                        digitalWrite(SoilPowerPin, HIGH); // Power up sensor
                        wait(1000);
                      
                        RawSoil = analogRead(Soil_ip_pin);
                        soilAccum = RawSoil;
                        while (soilCount < 50) {
                          wait(20);
                          RawSoil = analogRead(Soil_ip_pin);
                          if (RawSoil > 0) {
                            soilAccum = soilAccum + RawSoil;
                          }
                          soilCount++;
                        }
                        Serial.print("SCount ");
                        Serial.println(soilCount);
                        RawSoil = soilAccum / soilCount;
                        Serial.print("RawSoil ");
                        Serial.println(RawSoil);
                      
                        wait(1);
                        ScaledMoisture = map(RawSoil, 600 , 0, 0, 100); // get the target position
                        digitalWrite(SoilPowerPin, LOW); // Power down sensor
                      
                        Serial.print("Scaled Moisture CB ");
                        Serial.println(ScaledMoisture);
                      
                      }
                      
                      void RainINT() {
                        
                        unsigned long thisTipTime = millis();
                        if (thisTipTime - lastTipTime > (Debouncetime)) {// debounce 20ms
                          Watermmtot = Watermmtot + bucketSize;
                          fullCounter = fullCounter + bucketSize;//Count so we send the counter for every 1mm
                          RainInterrupt = 1;
                          lastTipTime = thisTipTime;
                        }
                      }
                      
                      
                      bool resend(MyMessage & msg, bool ack, int repeats)
                      {
                        wdt_reset();
                        int repeat = 1;
                        int repeatdelay = 0;
                        boolean sendOK = false;
                      
                        while ((sendOK == false) and (repeat < repeats)) {
                          if (send(msg, ack)) {
                            sendOK = true;
                          } else {
                            sendOK = false;
                            Serial.print("TX Error ");
                            Serial.println(repeat);
                            repeatdelay += 200;
                            if (repeatdelay >= 500) {
                              repeatdelay = 500;
                            }
                            wdt_reset();
                          } repeat++; wait(repeatdelay);
                        }
                        return sendOK;
                      }
                      
                      
                      

                      Many thanks for the input.

                      Regards
                      Nigel

                      YveauxY Offline
                      YveauxY Offline
                      Yveaux
                      Mod
                      wrote on last edited by
                      #10

                      @Njwyborn Good to see you how have a somewhat working solution.
                      Just configuring the pin for input, and passing the corresponding interrupt (not the pin) to the sleep() fuction as in my example does work.
                      I have many sleeping sensors that wake from either timer or interrupt and they all work correctly.

                      Others, please don't use this as an example, as the manual watchdog and interrupt handling will likely interfere with the MySensors AVR implementation.

                      I can only help when the exact compiler error is known (not "the compiler complained (unsurprisingly I thought), as it is expecting a uint8_t"), and if you provide a minimal sketch that exhibits the compiler error.

                      The hardware could also be a cause of errors; bouncing switches and sleeping nodes don't play together nicely, unless signals are debounced.

                      http://yveaux.blogspot.nl

                      N 1 Reply Last reply
                      0
                      • YveauxY Yveaux

                        @Njwyborn Good to see you how have a somewhat working solution.
                        Just configuring the pin for input, and passing the corresponding interrupt (not the pin) to the sleep() fuction as in my example does work.
                        I have many sleeping sensors that wake from either timer or interrupt and they all work correctly.

                        Others, please don't use this as an example, as the manual watchdog and interrupt handling will likely interfere with the MySensors AVR implementation.

                        I can only help when the exact compiler error is known (not "the compiler complained (unsurprisingly I thought), as it is expecting a uint8_t"), and if you provide a minimal sketch that exhibits the compiler error.

                        The hardware could also be a cause of errors; bouncing switches and sleeping nodes don't play together nicely, unless signals are debounced.

                        N Offline
                        N Offline
                        Nigel31
                        wrote on last edited by Nigel31
                        #11

                        @Yveaux
                        Many thanks for coming back.
                        Ok, so if I just define the pin as INPUT_PULLUP, and not attach a interrupt, when I call sleep, passing the interrupt handler, it WILL call the handler?

                        the compiler outputs:

                        N:\Home Automation\Arduino\MySensors\Solar_Soil_Sensor_and_Rain_Sensor\Solar_Soil_Sensor_and_Rain_Sensor.ino:298:40: warning: invalid conversion from 'void (*)()' to 'uint8_t {aka unsigned char}' [-fpermissive]
                             sleep(RainINT, FALLING, MYsleepTime);
                        
                        
                        

                        when I invoke the sleep, passing the interrupt handler.

                        How is it possible to utilise an interrupt on a otherwise sleeping node, WHEN it is awake?
                        This is one of the "issues" I mentioned above by not using / invoking the attachment of the interrupt at all, and why I tried to use the normal attachment of the interrupt, then detaching it, just prior to calling the sleep (albeit passing the pin, rather than the handler). devices that would suffer without being able to utilise interrupts when awake, would include among others, a rain sensor, a flow meter, even a pulse counter for say a water meter, if battery powered, and needing to sleep.

                        separately, what is wrong with my watchdog implementation?

                        many thanks and regards Nigel

                        YveauxY 1 Reply Last reply
                        0
                        • N Nigel31

                          @Yveaux
                          Many thanks for coming back.
                          Ok, so if I just define the pin as INPUT_PULLUP, and not attach a interrupt, when I call sleep, passing the interrupt handler, it WILL call the handler?

                          the compiler outputs:

                          N:\Home Automation\Arduino\MySensors\Solar_Soil_Sensor_and_Rain_Sensor\Solar_Soil_Sensor_and_Rain_Sensor.ino:298:40: warning: invalid conversion from 'void (*)()' to 'uint8_t {aka unsigned char}' [-fpermissive]
                               sleep(RainINT, FALLING, MYsleepTime);
                          
                          
                          

                          when I invoke the sleep, passing the interrupt handler.

                          How is it possible to utilise an interrupt on a otherwise sleeping node, WHEN it is awake?
                          This is one of the "issues" I mentioned above by not using / invoking the attachment of the interrupt at all, and why I tried to use the normal attachment of the interrupt, then detaching it, just prior to calling the sleep (albeit passing the pin, rather than the handler). devices that would suffer without being able to utilise interrupts when awake, would include among others, a rain sensor, a flow meter, even a pulse counter for say a water meter, if battery powered, and needing to sleep.

                          separately, what is wrong with my watchdog implementation?

                          many thanks and regards Nigel

                          YveauxY Offline
                          YveauxY Offline
                          Yveaux
                          Mod
                          wrote on last edited by Yveaux
                          #12

                          @Njwyborn said in Is there a "standard" way to terminate a sleep time, after waking by an interrupt?:

                          so if I just define the pin as INPUT_PULLUP, and not attach a interrupt, when I call sleep, passing the interrupt handler, it WILL call the handler?

                          You shall not pass the interrupt handler, but the interrupt number instead. Each pin that supports interrupts can trigger a certain interrupt. The interrupt number for a pin is returned when calling digitalPinToInterrupt(). You can read more on the topic here.
                          During the execution of the sleep() function, a new interrupt handler will be installed that is used to handle the wake-from-interrupt. It is detached again, before returning from sleep().

                          About the most minimalist implementation is the following, which compiles without errors:

                          #include <Arduino.h>
                          
                          #define MY_RADIO_RF24
                          #include <MySensors.h>
                          
                          #define MY_PIN         (3)
                          #define CHILD_ID       (0)
                          #define SLEEP_TIME_MS  (60000)
                          #define SKETCH_NAME    F("Test")
                          #define SKETCH_VERSION F("1.0")
                          
                          void presentation()
                          {
                              sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
                              present(CHILD_ID, S_RAIN, F("Rain"));
                          }
                          
                          void setup()
                          {
                              pinMode(CHILD_ID, INPUT_PULLUP);
                          }
                          
                          void loop()
                          {
                              auto result = sleep(digitalPinToInterrupt(MY_PIN), RISING, SLEEP_TIME_MS);
                              Serial.println(result);
                          }
                          

                          How is it possible to utilise an interrupt on a otherwise sleeping node, WHEN it is awake?

                          I did not relealize before that you wanted to install your own interrupt handler for the same pin when the node is awake.
                          To achieve this, you can just attach your own handler after returning from sleep(), something like:

                          // .. same code as above ..
                          void RainINT(void)
                          {
                            // .. handle the interrupt ..
                          }
                          
                          void loop()
                          {
                              auto result = sleep(digitalPinToInterrupt(MY_PIN), RISING, SLEEP_TIME_MS);
                              attachInterrupt(digitalPinToInterrupt(MY_PIN), RainINT, FALLING);
                              Serial.println(result);
                          }
                          

                          Just be aware that the call to sleep() will overwrite your installed interrupt handler, so you need to reinstall it after returning from sleep().

                          separately, what is wrong with my watchdog implementation?

                          MySensors on AVR uses the watchdog to wake a sleeping node after a certain amount of time.
                          To achieve this, it reprograms the watchdog just as it does with the interrupt handler.
                          In most cases you will be just fine if you reprogram the watchdog settings when returning from sleep(), just as when reattaching the interrupt handler.

                          However, as MySensors hides you from a lot of nastiness by taking over hardware specifics, you must understand its limitations.
                          That's why I do not suggest most users to follow your solution but instead, don't use the watchdog or try to share interrupts.

                          http://yveaux.blogspot.nl

                          N 1 Reply Last reply
                          0
                          • YveauxY Yveaux

                            @Njwyborn said in Is there a "standard" way to terminate a sleep time, after waking by an interrupt?:

                            so if I just define the pin as INPUT_PULLUP, and not attach a interrupt, when I call sleep, passing the interrupt handler, it WILL call the handler?

                            You shall not pass the interrupt handler, but the interrupt number instead. Each pin that supports interrupts can trigger a certain interrupt. The interrupt number for a pin is returned when calling digitalPinToInterrupt(). You can read more on the topic here.
                            During the execution of the sleep() function, a new interrupt handler will be installed that is used to handle the wake-from-interrupt. It is detached again, before returning from sleep().

                            About the most minimalist implementation is the following, which compiles without errors:

                            #include <Arduino.h>
                            
                            #define MY_RADIO_RF24
                            #include <MySensors.h>
                            
                            #define MY_PIN         (3)
                            #define CHILD_ID       (0)
                            #define SLEEP_TIME_MS  (60000)
                            #define SKETCH_NAME    F("Test")
                            #define SKETCH_VERSION F("1.0")
                            
                            void presentation()
                            {
                                sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
                                present(CHILD_ID, S_RAIN, F("Rain"));
                            }
                            
                            void setup()
                            {
                                pinMode(CHILD_ID, INPUT_PULLUP);
                            }
                            
                            void loop()
                            {
                                auto result = sleep(digitalPinToInterrupt(MY_PIN), RISING, SLEEP_TIME_MS);
                                Serial.println(result);
                            }
                            

                            How is it possible to utilise an interrupt on a otherwise sleeping node, WHEN it is awake?

                            I did not relealize before that you wanted to install your own interrupt handler for the same pin when the node is awake.
                            To achieve this, you can just attach your own handler after returning from sleep(), something like:

                            // .. same code as above ..
                            void RainINT(void)
                            {
                              // .. handle the interrupt ..
                            }
                            
                            void loop()
                            {
                                auto result = sleep(digitalPinToInterrupt(MY_PIN), RISING, SLEEP_TIME_MS);
                                attachInterrupt(digitalPinToInterrupt(MY_PIN), RainINT, FALLING);
                                Serial.println(result);
                            }
                            

                            Just be aware that the call to sleep() will overwrite your installed interrupt handler, so you need to reinstall it after returning from sleep().

                            separately, what is wrong with my watchdog implementation?

                            MySensors on AVR uses the watchdog to wake a sleeping node after a certain amount of time.
                            To achieve this, it reprograms the watchdog just as it does with the interrupt handler.
                            In most cases you will be just fine if you reprogram the watchdog settings when returning from sleep(), just as when reattaching the interrupt handler.

                            However, as MySensors hides you from a lot of nastiness by taking over hardware specifics, you must understand its limitations.
                            That's why I do not suggest most users to follow your solution but instead, don't use the watchdog or try to share interrupts.

                            N Offline
                            N Offline
                            Nigel31
                            wrote on last edited by
                            #13

                            @Yveaux

                            We seem to have been talking at a little crossed terminology.
                            When I refer to the IRQ handler I mean to reference the FUNCTION which is handling the Interrupt, when the interrupt PIN is in the required state. That's why I couldn't understand why the reference to passing the handler to the sleep function was likely to work.

                            This really brings us back to the point where I WAS using the MYSensors sleep with the interrupt pin, and interrogating as to the return (reason for waking), which in my case was "-1" even though it definitely had woken with the interrupt.
                            This implementation ( and I didn't try a minimal sketch) wasn't working for me, as I couldn't determine why it had woken.

                            This ultimately led me to my current solution, and calling in a loop, a 1000ms sleep, and breaking the loop if the interrupt had fired, having set a flag.

                            I always use a WDT on my sketches, knowing that MYSensors, stores the state before sleeping, (needing as it does the hardware timer on avr) and restores it after waking (having read this elsewhere)

                            this is the current and working sketch, , as I say I have tried using a "pure" mysensors solution, but I ONLY got "-1" for wakeupReason returned from the function.

                            wakeupReason = sleep(digitalPinToInterrupt(INT_PIN), CHANGE, sleepTime);
                            

                            this is the current working code.

                            // Enable debug prints
                            //#define MY_DEBUG
                            //#define MY_DEBUG_VERBOSE_SIGNING
                            //#define MY_SIGNING_SOFT
                            //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
                            //#define MY_SIGNING_REQUEST_SIGNATURES
                            #define   MY_SPLASH_SCREEN_DISABLED
                            //#define   MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
                            #define MY_TRANSPORT_WAIT_READY_MS 10000
                            #define MY_RADIO_RFM69
                            #define MY_RFM69_FREQUENCY RFM69_433MHZ // Set your frequency here
                            //#define MY_RFM69_MAX_POWER_LEVEL_DBM (13)   // max. TX power 10dBm = 10mW
                            #define   MY_RFM69_TX_POWER_DBM (13)
                            #define MY_IS_RFM69HW // Omit if your RFM is not "H"
                            
                            #define MY_NODE_ID 32
                            #include <MySensors.h>
                            #include <SPI.h>
                            #include <math.h>
                            //#include <TimeLib.h>
                            #include <avr/wdt.h>
                            #include <Vcc.h>
                            
                            #define CHILD_ID 32 // Id of the sensor child
                            #define VCC_MIN 3.1
                            #define VCC_MAX 4.16
                            Vcc vcc;
                            
                            #define CHILD_ID_S_MOISTURE 1
                            //#define CHILD_ID_RELAYSTATUS 2
                            //#define CHILD_ID_SETPOINT 7
                            //#define CHILD_ID_WATERTIME 9
                            #define CHILD_ID_RX_RSSI 5
                            #define CHILD_ID_BATVCC 6
                            #define CHILD_ID_RAIN 11  // Indicates Tripped when rain detected
                            #define CHILD_ID_RAINREPORT 10  // Indicates Tripped when rain detected
                            
                            // EEPROM LOCATIONS
                            int SetpointADD = 1;
                            int WaterTimeADD = 2;
                            int WatermmADD = 8;
                            // Pins
                            int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
                            int Soil_ip_pin = A1;
                            int SoilPowerPin = 6;
                            int RainPin = 3;
                            const int Debouncetime = 40;
                            int wakeupReason =0;
                            
                            float fullCounter = 0.0f;
                            float bucketSize = 0.3f;//0.3mm rain per tip
                            volatile float Watermmtot = 0.0f;
                            float prevWatermmtot = 0.0f;
                            float rainratenow  = 0.0f;
                            
                            unsigned long previousMillis, previousrelayMillis, previouprescence , SleepCnt , RemainSleep = 0;
                            
                            volatile long currenttime = 0;
                            int ScaledMoisture = 20;
                            int oldBatteryPcnt = 0;
                            int SoilSetPoint = loadState(SetpointADD) ;
                            int WaterTime = loadState(WaterTimeADD) ;
                            int RawSoil = 0;
                            
                            bool Slept = 0;
                            volatile bool RainInterrupt = 0;
                            bool ValidWaterCount = 0;
                            
                            float batteryV  = 3.70f;
                            int batteryPcnt = 50;
                            
                            
                            unsigned long MYsleepTime , BaseMYsleepTime = 900000;//SLEEP_SEC*1000 * SLEEP_MINS * 60  ; //period_t is an enum type defined in the LowPower library (LowPower.h) 900000
                            unsigned long lastTipTime = 0;
                            
                            // Initialize  message
                            
                            
                            MyMessage msgSoil(CHILD_ID_S_MOISTURE, V_LEVEL);
                            MyMessage msgRxRSSI(CHILD_ID_RX_RSSI, V_LEVEL);
                            MyMessage msgVcc(CHILD_ID_BATVCC, V_VOLTAGE);
                            MyMessage msgRain(CHILD_ID_RAINREPORT, V_RAIN);
                            MyMessage lastCounterMsg(CHILD_ID_RAIN, V_TEXT);
                            MyMessage msgRainRate(CHILD_ID_RAINREPORT, V_RAINRATE);
                            
                            
                            
                            
                            
                            // EEPROM
                            //This function will write a 4 byte (32bit) long to the eeprom at
                            //the specified address to address + 3.
                            void EEPROMWritelong(int address, long value)
                            {
                              wdt_reset();
                              //Decomposition from a long to 4 bytes by using bitshift.
                              //One = Most significant -> Four = Least significant byte
                              byte four = (value & 0xFF);
                              byte three = ((value >> 8) & 0xFF);
                              byte two = ((value >> 16) & 0xFF);
                              byte one = ((value >> 24) & 0xFF);
                            
                              //Write the 4 bytes into the eeprom memory.
                              saveState(address, four);
                              saveState(address + 1, three);
                              saveState(address + 2, two);
                              saveState(address + 3, one);
                            }// end eeprom write
                            
                            long EEPROMReadlong(long address)// long eeprom read
                            {
                              //Read the 4 bytes from the eeprom memory.
                              long four = loadState(address);
                              long three = loadState(address + 1);
                              long two = loadState(address + 2);
                              long one = loadState(address + 3);
                            
                              //Return the recomposed long by using bitshift.
                              return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
                            }
                            
                            // end EEPROM
                            
                            
                            void setup() {  // put your setup code here, to run once:
                              Serial.begin(115200);
                              pinMode(SoilPowerPin, OUTPUT); // output
                              pinMode(RainPin, INPUT_PULLUP);
                              EIFR = (1 << INTF0) | (1 << INTF1); // prevent initial trigger, clear interrupt
                              wait(100);
                              EIFR = (1 << INTF0) | (1 << INTF1);
                              attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                            
                              request( CHILD_ID_RAIN, V_TEXT); // readback count
                              wait(4000);
                              if (ValidWaterCount == 0 ) { // of did not receive valid count
                                request( CHILD_ID_RAIN, V_TEXT); // readback count
                                wait(4000);
                              }
                              if (ValidWaterCount == 0 ) { // of did not receive valid count
                                Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                                prevWatermmtot = Watermmtot;
                              }
                            
                              // ReadEEprom();
                            
                            
                              wdt_disable(); // Might be redundant as the bootloader should have done this already
                              Serial.print("Rain & Soil Sensor RES 1.1.2");
                            
                              // use the 1.1 V internal reference
                            #if defined(__AVR_ATmega2560__)
                              analogReference(INTERNAL1V1);
                            #else
                              analogReference(INTERNAL);
                            #endif
                            
                              // ReadEEprom();
                            
                              wdt_enable(WDTO_8S);
                            }//end setup
                            
                            void presentation() {
                              // Send the sketch version information to the gateway and Controller
                              sendSketchInfo("Soil Moisture_R", "1.1.2");
                            
                            
                              // Register all sensors to gw (they will be created as child devices)
                              present(CHILD_ID_S_MOISTURE, S_MOISTURE, "Soil Moisture", false);
                              wait(250);
                              present(CHILD_ID_RX_RSSI, S_SOUND, "Soil & Rain Transmitter RX RSSI", true);
                              wait(250);
                              present(CHILD_ID_BATVCC, S_MULTIMETER, "Battery V", false);
                              wait(250);
                              present(CHILD_ID_RAINREPORT, S_RAIN, "Rain", true);
                              wait(250);
                              present(CHILD_ID_RAIN, S_INFO, "TxTCount", true);
                            
                            }//end presentation
                            
                            
                            
                            
                            void loop() { // put your main code here, to run repeatedly:
                              
                              wdt_reset();
                            
                            if (RainInterrupt == 0) {
                              
                            
                                    getSoil();
                                    //unsigned long currentMillis = millis();
                                    // use the 1.1 V internal reference
                                  #if defined(__AVR_ATmega2560__)
                                    analogReference(INTERNAL1V1);
                                  #else
                                    analogReference(INTERNAL);
                                  #endif
                                  
                                    for (int i = 0; i <= 10; i++) {
                                      analogRead(BATTERY_SENSE_PIN);
                                      wait(5);
                                    }
                                  
                                  
                                    // get the battery Voltage
                                    int sensorValue = analogRead(BATTERY_SENSE_PIN);// * ((1e6 + 470e3) / 470e3);
                                  #ifdef MY_DEBUG
                                    Serial.print("sensorValue raw ");
                                    Serial.println(analogRead(BATTERY_SENSE_PIN));
                                    Serial.print("sensorValue V ");
                                    Serial.println(sensorValue);
                                  #endif
                                    wdt_reset();
                                    // 1M, 470K divider across battery and using internal ADC ref of 1.1V
                                    // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
                                    // ((1e6+360e3)/360e3)*1.1 = Vmax = 4.15 Volts
                                    // 3.44/1023 = Volts per bit = 0.004062127
                                  
                                  
                                    //long batteryVt  = map(sensorValue, 0 , 1023, 0, 43000); // get the target positionsensorValue * 0.003363075;
                                    batteryV  = (sensorValue * (4.08 / 3.88)) * 0.004062127; // batteryVt/10000;
                                    batteryPcnt = ((batteryV - VCC_MIN) / (VCC_MAX - VCC_MIN)) * 100;// sensorValue / 10;
                                  
                                    send(msgSoil.set(ScaledMoisture, 0)); // send moisture
                                    wait(100);
                                  
                                    wdt_reset();
                                  
                                    //float volts = vcc.Read_Volts();
                                    send(msgVcc.set(batteryV, 1));
                                  
                                    //#ifdef MY_DEBUG
                                  
                                    Serial.print("Soil Moisture : ");
                                    Serial.print(ScaledMoisture);
                                    Serial.println(" cb");
                                  
                                    Serial.print("Battery Voltage count: ");
                                    Serial.print(sensorValue);
                                    Serial.println(" int");
                                  
                                    Serial.print("Battery Voltage: ");
                                    Serial.print(batteryV);
                                    Serial.println(" V");
                                  
                                    Serial.print("Battery percent: ");
                                    Serial.print(batteryPcnt);
                                    Serial.println(" %");
                                    //#endif
                                    wdt_reset();
                                  
                                    if (oldBatteryPcnt != batteryPcnt) {
                                      //  sendBatteryReport();
                                      sendBatteryLevel(batteryPcnt);
                                      oldBatteryPcnt = batteryPcnt;
                                    }
                                  
                                    RX_SEND();
                                  
                                  
                                    if( Watermmtot == prevWatermmtot){
                                      rainratenow = 0.0;
                                    }
                                    else{
                                      rainratenow = ((Watermmtot - prevWatermmtot)*4) *100;
                                    }
                                  
                                        resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                                        resend(msgRain.set(Watermmtot, 1) , true, 5);
                                        if(resend(msgRainRate.set(rainratenow,1) , true, 2)){
                                          prevWatermmtot = Watermmtot;
                                        }
                               }// end if not rain interrupt   
                                    
                                    if (batteryPcnt < 35) {
                                      //send(msgText.set("Sleep*10"), false);
                                      Serial.println("Sleep*10");
                                      MYsleepTime = (BaseMYsleepTime * 10);
                                      wdt_reset();
                                      //requestTime();// get time     
                                    }
                                    else if (batteryPcnt<75 and batteryPcnt>35) {
                                      //send(msgText.set("Sleep*3"), false);
                                      Serial.println("Sleep*3");
                                      wdt_reset();
                                      MYsleepTime = (BaseMYsleepTime * 3) ;
                                      //requestTime();// get time
                                    }
                                    else {
                                      Serial.println("Sleep :");
                                      wdt_reset();
                                      MYsleepTime = BaseMYsleepTime;
                                    }
                                //    Serial.print("Sleepcount = ");Serial.println(SleepCnt);
                                 //   Serial.print("Sleeptime = ");Serial.println(MYsleepTime);  
                                    MYsleepTime = constrain((MYsleepTime - SleepCnt),1000,MYsleepTime);// calc how much left from last sleep
                                 //   Serial.print("RemainSleep = ");Serial.println(MYsleepTime);
                            
                                    SleepCnt=0;
                                    RainInterrupt = 0;
                                      
                            // Sleeping 
                             
                                        while((SleepCnt < MYsleepTime) ){//or (wakeupReason != digitalPinToInterrupt(RainPin)) or (RainInterrupt != 1) 
                                          sleep(1000);
                                        
                                              if(RainInterrupt == 1){
                                                break;
                                              }
                                              else{
                                                Slept = 1;
                                                wdt_reset();
                                              }
                                          SleepCnt=SleepCnt+1000; // count another 1000ms of sleep
                                          wdt_reset();
                                        
                                        }// end while
                                        
                                        if(SleepCnt>=(MYsleepTime - 10000)){
                                          SleepCnt=0;
                                        }
                            
                                      attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                                      
                                      wdt_reset();
                            
                              
                             wait(Debouncetime + 1);// need to wait otherwisee the debounce won't work because millis not updated in sleep
                            
                              if (RainInterrupt == 1) {// of woken due to rain bucket actions
                                //  Serial.println(F("RainInterrupt=1"));
                            
                                  resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                                  if (resend(msgRain.set(Watermmtot, 1) , true, 5)) { // only reset if sending succeeded
                                    resend(msgRainRate.set(30) , true, 5);
                                    fullCounter = fullCounter - 1;
                                    //RainInterrupt = 0;
                                    EEPROMWritelong(WatermmADD, Watermmtot);
                                  }
                            
                              }
                            
                            }// end loop
                            
                            
                            
                            void receive(const MyMessage &message) {
                              // We only expect one type of message from controller. But we better check anyway.
                              wdt_reset();
                              if (message.isAck()) {
                            #ifdef MY_DEBUG
                                Serial.println("+Ack FMGW");
                            #endif
                              }
                            
                            #ifdef MY_DEBUG
                              Serial.print("*InMsgty :");
                              Serial.print(message.type);
                              Serial.print(" MsgComd:");
                              Serial.print(message.getCommand());
                              Serial.print(" childID:");
                              Serial.print(message.sensor);
                            
                              Serial.print(" Switch:");
                              Serial.println(message.getFloat());
                            #endif
                            
                            
                              if (message.type == V_STATUS || S_HEATER || V_LIGHT || V_TEXT || V_HVAC_SETPOINT_HEAT || V_PERCENTAGE || S_DIMMER) {
                            
                            
                                if (message.getCommand() == 2) { // THIS PROCESSES THE CONTROLLERS EXPECTED STATE OF THE OUTPUT
                                  // put code here to be executed when the message is from a request
                            #ifdef MY_DEBUG
                                  Serial.print("REQ_Msg :");
                                  Serial.print(message.type);
                                  Serial.print(" MsgCmd:");
                                  Serial.print(message.getCommand());
                                  Serial.print(" childID:");
                                  Serial.print(message.sensor);
                                  Serial.print(" Switch:");
                                  Serial.println(message.getBool());
                            #endif
                            
                                  switch (message.sensor) {// the child ID
                            
                                    case 11:
                            
                                      Watermmtot = message.getFloat();
                                      //#ifdef MY_DEBUG
                                      Serial.print(" Incoming Rain mm:");
                                      Serial.println(Watermmtot);
                                      //#endif
                                      if (Watermmtot >= 0.3) {
                                        EEPROMWritelong(WatermmADD, Watermmtot);
                                      }
                                      else {
                                        Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                                        ValidWaterCount = 1;
                                      }
                                      break;
                            
                                  } // end switch
                            
                            
                            
                            
                                }// end msg=2
                            
                                if (message.getCommand() == 1) { // THIS PROCESSES DIRECTED COMMANDS
                            
                            
                            #ifdef MY_DEBUG
                                  Serial.print("*InMsgty :");
                                  Serial.print(message.type);
                                  Serial.print(" MsgComd:");
                                  Serial.print(message.getCommand());
                                  Serial.print(" childID:");
                                  Serial.print(message.sensor);
                            
                                  Serial.print(" Switch:");
                                  Serial.println(message.getBool());
                            #endif
                                  /*
                                        switch (message.sensor) {// the child ID
                            
                                          case 2:
                                            TempRELAY = message.getBool();
                                            //#ifdef MY_DEBUG
                                            Serial.print(" Incoming rELAY:");
                                            Serial.println(TempRELAY);
                                            //#endif
                            
                                            watering = TempRELAY;
                            
                                            send(msgRelay.set(watering, 0)); // send relay state
                            
                            
                                            break;
                            
                                        } // end switch
                            
                                  */
                            
                            
                                }// end if msg = 1
                            
                            
                              }// end msg type function
                            
                            }// end void loop
                            
                            
                            
                            void RX_SEND()
                            {
                              wdt_reset();
                              send(msgRxRSSI.set(transportGetSignalReport(SR_RX_RSSI)));
                              wdt_reset();
                            }
                            
                            
                            void sendBatteryReport() {
                              wdt_reset();
                            
                              float p = vcc.Read_Perc(VCC_MIN, VCC_MAX, true);
                              int batteryPcnt = static_cast<int>(p);
                            #ifdef MY_DEBUG
                              Serial.print("Battery is: "); Serial.println(batteryPcnt);
                            #endif
                              sendBatteryLevel(batteryPcnt);
                            }
                            
                            
                            
                            void ReadEEprom() {
                              wdt_reset();
                              //if (EEPROMReadlong(SetpointADD) > 0) SoilSetPoint = EEPROMReadlong(SetpointADD) ;
                              //if (EEPROMReadlong(WaterTimeADD) > 0) WaterTime = EEPROMReadlong(WaterTimeADD) ;
                            
                              if (loadState(SetpointADD) > 0) SoilSetPoint = loadState(SetpointADD) ;
                              if (loadState(WaterTimeADD) > 0) WaterTime = loadState(WaterTimeADD) ;
                            
                            }
                            
                            
                            
                            void getSoil() {
                              wdt_reset();
                            
                              analogReference(DEFAULT);
                              for (int i = 0; i <= 10; i++) {
                                RawSoil = analogRead(Soil_ip_pin);
                                wait(5);
                              }
                            
                              int soilCount = 0;
                              unsigned long soilAccum = 0;
                              digitalWrite(SoilPowerPin, HIGH); // Power up sensor
                              wait(1000);
                            
                              RawSoil = analogRead(Soil_ip_pin);
                              soilAccum = RawSoil;
                              while (soilCount < 50) {
                                wait(20);
                                RawSoil = analogRead(Soil_ip_pin);
                                if (RawSoil > 0) {
                                  soilAccum = soilAccum + RawSoil;
                                }
                                soilCount++;
                              }
                              Serial.print("SCount ");
                              Serial.println(soilCount);
                              RawSoil = soilAccum / soilCount;
                              Serial.print("RawSoil ");
                              Serial.println(RawSoil);
                            
                              wait(1);
                              ScaledMoisture = map(RawSoil, 600 , 0, 0, 100); // get the target position
                              digitalWrite(SoilPowerPin, LOW); // Power down sensor
                            
                              Serial.print("Scaled Moisture CB ");
                              Serial.println(ScaledMoisture);
                            
                            }
                            
                            void RainINT() {
                              
                              unsigned long thisTipTime = millis();
                              if (thisTipTime - lastTipTime > (Debouncetime)) {// debounce 20ms
                                Watermmtot = Watermmtot + bucketSize;
                                fullCounter = fullCounter + bucketSize;//Count so we send the counter for every 1mm
                                RainInterrupt = 1;
                                lastTipTime = thisTipTime;
                              }
                            }
                            
                            
                            bool resend(MyMessage & msg, bool ack, int repeats)
                            {
                              wdt_reset();
                              int repeat = 1;
                              int repeatdelay = 0;
                              boolean sendOK = false;
                            
                              while ((sendOK == false) and (repeat < repeats)) {
                                if (send(msg, ack)) {
                                  sendOK = true;
                                } else {
                                  sendOK = false;
                                  Serial.print("TX Error ");
                                  Serial.println(repeat);
                                  repeatdelay += 200;
                                  if (repeatdelay >= 500) {
                                    repeatdelay = 500;
                                  }
                                  wdt_reset();
                                } repeat++; wait(repeatdelay);
                              }
                              return sendOK;
                            }
                            

                            For my own education, I will build a new note to test the sleep and interrupt, and see where / how thing are not working, but that won't happen till later in the week.

                            Please note that I am still on V 2.2.0

                            YveauxY 1 Reply Last reply
                            0
                            • N Nigel31

                              @Yveaux

                              We seem to have been talking at a little crossed terminology.
                              When I refer to the IRQ handler I mean to reference the FUNCTION which is handling the Interrupt, when the interrupt PIN is in the required state. That's why I couldn't understand why the reference to passing the handler to the sleep function was likely to work.

                              This really brings us back to the point where I WAS using the MYSensors sleep with the interrupt pin, and interrogating as to the return (reason for waking), which in my case was "-1" even though it definitely had woken with the interrupt.
                              This implementation ( and I didn't try a minimal sketch) wasn't working for me, as I couldn't determine why it had woken.

                              This ultimately led me to my current solution, and calling in a loop, a 1000ms sleep, and breaking the loop if the interrupt had fired, having set a flag.

                              I always use a WDT on my sketches, knowing that MYSensors, stores the state before sleeping, (needing as it does the hardware timer on avr) and restores it after waking (having read this elsewhere)

                              this is the current and working sketch, , as I say I have tried using a "pure" mysensors solution, but I ONLY got "-1" for wakeupReason returned from the function.

                              wakeupReason = sleep(digitalPinToInterrupt(INT_PIN), CHANGE, sleepTime);
                              

                              this is the current working code.

                              // Enable debug prints
                              //#define MY_DEBUG
                              //#define MY_DEBUG_VERBOSE_SIGNING
                              //#define MY_SIGNING_SOFT
                              //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
                              //#define MY_SIGNING_REQUEST_SIGNATURES
                              #define   MY_SPLASH_SCREEN_DISABLED
                              //#define   MY_DISABLE_RAM_ROUTING_TABLE_FEATURE
                              #define MY_TRANSPORT_WAIT_READY_MS 10000
                              #define MY_RADIO_RFM69
                              #define MY_RFM69_FREQUENCY RFM69_433MHZ // Set your frequency here
                              //#define MY_RFM69_MAX_POWER_LEVEL_DBM (13)   // max. TX power 10dBm = 10mW
                              #define   MY_RFM69_TX_POWER_DBM (13)
                              #define MY_IS_RFM69HW // Omit if your RFM is not "H"
                              
                              #define MY_NODE_ID 32
                              #include <MySensors.h>
                              #include <SPI.h>
                              #include <math.h>
                              //#include <TimeLib.h>
                              #include <avr/wdt.h>
                              #include <Vcc.h>
                              
                              #define CHILD_ID 32 // Id of the sensor child
                              #define VCC_MIN 3.1
                              #define VCC_MAX 4.16
                              Vcc vcc;
                              
                              #define CHILD_ID_S_MOISTURE 1
                              //#define CHILD_ID_RELAYSTATUS 2
                              //#define CHILD_ID_SETPOINT 7
                              //#define CHILD_ID_WATERTIME 9
                              #define CHILD_ID_RX_RSSI 5
                              #define CHILD_ID_BATVCC 6
                              #define CHILD_ID_RAIN 11  // Indicates Tripped when rain detected
                              #define CHILD_ID_RAINREPORT 10  // Indicates Tripped when rain detected
                              
                              // EEPROM LOCATIONS
                              int SetpointADD = 1;
                              int WaterTimeADD = 2;
                              int WatermmADD = 8;
                              // Pins
                              int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
                              int Soil_ip_pin = A1;
                              int SoilPowerPin = 6;
                              int RainPin = 3;
                              const int Debouncetime = 40;
                              int wakeupReason =0;
                              
                              float fullCounter = 0.0f;
                              float bucketSize = 0.3f;//0.3mm rain per tip
                              volatile float Watermmtot = 0.0f;
                              float prevWatermmtot = 0.0f;
                              float rainratenow  = 0.0f;
                              
                              unsigned long previousMillis, previousrelayMillis, previouprescence , SleepCnt , RemainSleep = 0;
                              
                              volatile long currenttime = 0;
                              int ScaledMoisture = 20;
                              int oldBatteryPcnt = 0;
                              int SoilSetPoint = loadState(SetpointADD) ;
                              int WaterTime = loadState(WaterTimeADD) ;
                              int RawSoil = 0;
                              
                              bool Slept = 0;
                              volatile bool RainInterrupt = 0;
                              bool ValidWaterCount = 0;
                              
                              float batteryV  = 3.70f;
                              int batteryPcnt = 50;
                              
                              
                              unsigned long MYsleepTime , BaseMYsleepTime = 900000;//SLEEP_SEC*1000 * SLEEP_MINS * 60  ; //period_t is an enum type defined in the LowPower library (LowPower.h) 900000
                              unsigned long lastTipTime = 0;
                              
                              // Initialize  message
                              
                              
                              MyMessage msgSoil(CHILD_ID_S_MOISTURE, V_LEVEL);
                              MyMessage msgRxRSSI(CHILD_ID_RX_RSSI, V_LEVEL);
                              MyMessage msgVcc(CHILD_ID_BATVCC, V_VOLTAGE);
                              MyMessage msgRain(CHILD_ID_RAINREPORT, V_RAIN);
                              MyMessage lastCounterMsg(CHILD_ID_RAIN, V_TEXT);
                              MyMessage msgRainRate(CHILD_ID_RAINREPORT, V_RAINRATE);
                              
                              
                              
                              
                              
                              // EEPROM
                              //This function will write a 4 byte (32bit) long to the eeprom at
                              //the specified address to address + 3.
                              void EEPROMWritelong(int address, long value)
                              {
                                wdt_reset();
                                //Decomposition from a long to 4 bytes by using bitshift.
                                //One = Most significant -> Four = Least significant byte
                                byte four = (value & 0xFF);
                                byte three = ((value >> 8) & 0xFF);
                                byte two = ((value >> 16) & 0xFF);
                                byte one = ((value >> 24) & 0xFF);
                              
                                //Write the 4 bytes into the eeprom memory.
                                saveState(address, four);
                                saveState(address + 1, three);
                                saveState(address + 2, two);
                                saveState(address + 3, one);
                              }// end eeprom write
                              
                              long EEPROMReadlong(long address)// long eeprom read
                              {
                                //Read the 4 bytes from the eeprom memory.
                                long four = loadState(address);
                                long three = loadState(address + 1);
                                long two = loadState(address + 2);
                                long one = loadState(address + 3);
                              
                                //Return the recomposed long by using bitshift.
                                return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
                              }
                              
                              // end EEPROM
                              
                              
                              void setup() {  // put your setup code here, to run once:
                                Serial.begin(115200);
                                pinMode(SoilPowerPin, OUTPUT); // output
                                pinMode(RainPin, INPUT_PULLUP);
                                EIFR = (1 << INTF0) | (1 << INTF1); // prevent initial trigger, clear interrupt
                                wait(100);
                                EIFR = (1 << INTF0) | (1 << INTF1);
                                attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                              
                                request( CHILD_ID_RAIN, V_TEXT); // readback count
                                wait(4000);
                                if (ValidWaterCount == 0 ) { // of did not receive valid count
                                  request( CHILD_ID_RAIN, V_TEXT); // readback count
                                  wait(4000);
                                }
                                if (ValidWaterCount == 0 ) { // of did not receive valid count
                                  Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                                  prevWatermmtot = Watermmtot;
                                }
                              
                                // ReadEEprom();
                              
                              
                                wdt_disable(); // Might be redundant as the bootloader should have done this already
                                Serial.print("Rain & Soil Sensor RES 1.1.2");
                              
                                // use the 1.1 V internal reference
                              #if defined(__AVR_ATmega2560__)
                                analogReference(INTERNAL1V1);
                              #else
                                analogReference(INTERNAL);
                              #endif
                              
                                // ReadEEprom();
                              
                                wdt_enable(WDTO_8S);
                              }//end setup
                              
                              void presentation() {
                                // Send the sketch version information to the gateway and Controller
                                sendSketchInfo("Soil Moisture_R", "1.1.2");
                              
                              
                                // Register all sensors to gw (they will be created as child devices)
                                present(CHILD_ID_S_MOISTURE, S_MOISTURE, "Soil Moisture", false);
                                wait(250);
                                present(CHILD_ID_RX_RSSI, S_SOUND, "Soil & Rain Transmitter RX RSSI", true);
                                wait(250);
                                present(CHILD_ID_BATVCC, S_MULTIMETER, "Battery V", false);
                                wait(250);
                                present(CHILD_ID_RAINREPORT, S_RAIN, "Rain", true);
                                wait(250);
                                present(CHILD_ID_RAIN, S_INFO, "TxTCount", true);
                              
                              }//end presentation
                              
                              
                              
                              
                              void loop() { // put your main code here, to run repeatedly:
                                
                                wdt_reset();
                              
                              if (RainInterrupt == 0) {
                                
                              
                                      getSoil();
                                      //unsigned long currentMillis = millis();
                                      // use the 1.1 V internal reference
                                    #if defined(__AVR_ATmega2560__)
                                      analogReference(INTERNAL1V1);
                                    #else
                                      analogReference(INTERNAL);
                                    #endif
                                    
                                      for (int i = 0; i <= 10; i++) {
                                        analogRead(BATTERY_SENSE_PIN);
                                        wait(5);
                                      }
                                    
                                    
                                      // get the battery Voltage
                                      int sensorValue = analogRead(BATTERY_SENSE_PIN);// * ((1e6 + 470e3) / 470e3);
                                    #ifdef MY_DEBUG
                                      Serial.print("sensorValue raw ");
                                      Serial.println(analogRead(BATTERY_SENSE_PIN));
                                      Serial.print("sensorValue V ");
                                      Serial.println(sensorValue);
                                    #endif
                                      wdt_reset();
                                      // 1M, 470K divider across battery and using internal ADC ref of 1.1V
                                      // Sense point is bypassed with 0.1 uF cap to reduce noise at that point
                                      // ((1e6+360e3)/360e3)*1.1 = Vmax = 4.15 Volts
                                      // 3.44/1023 = Volts per bit = 0.004062127
                                    
                                    
                                      //long batteryVt  = map(sensorValue, 0 , 1023, 0, 43000); // get the target positionsensorValue * 0.003363075;
                                      batteryV  = (sensorValue * (4.08 / 3.88)) * 0.004062127; // batteryVt/10000;
                                      batteryPcnt = ((batteryV - VCC_MIN) / (VCC_MAX - VCC_MIN)) * 100;// sensorValue / 10;
                                    
                                      send(msgSoil.set(ScaledMoisture, 0)); // send moisture
                                      wait(100);
                                    
                                      wdt_reset();
                                    
                                      //float volts = vcc.Read_Volts();
                                      send(msgVcc.set(batteryV, 1));
                                    
                                      //#ifdef MY_DEBUG
                                    
                                      Serial.print("Soil Moisture : ");
                                      Serial.print(ScaledMoisture);
                                      Serial.println(" cb");
                                    
                                      Serial.print("Battery Voltage count: ");
                                      Serial.print(sensorValue);
                                      Serial.println(" int");
                                    
                                      Serial.print("Battery Voltage: ");
                                      Serial.print(batteryV);
                                      Serial.println(" V");
                                    
                                      Serial.print("Battery percent: ");
                                      Serial.print(batteryPcnt);
                                      Serial.println(" %");
                                      //#endif
                                      wdt_reset();
                                    
                                      if (oldBatteryPcnt != batteryPcnt) {
                                        //  sendBatteryReport();
                                        sendBatteryLevel(batteryPcnt);
                                        oldBatteryPcnt = batteryPcnt;
                                      }
                                    
                                      RX_SEND();
                                    
                                    
                                      if( Watermmtot == prevWatermmtot){
                                        rainratenow = 0.0;
                                      }
                                      else{
                                        rainratenow = ((Watermmtot - prevWatermmtot)*4) *100;
                                      }
                                    
                                          resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                                          resend(msgRain.set(Watermmtot, 1) , true, 5);
                                          if(resend(msgRainRate.set(rainratenow,1) , true, 2)){
                                            prevWatermmtot = Watermmtot;
                                          }
                                 }// end if not rain interrupt   
                                      
                                      if (batteryPcnt < 35) {
                                        //send(msgText.set("Sleep*10"), false);
                                        Serial.println("Sleep*10");
                                        MYsleepTime = (BaseMYsleepTime * 10);
                                        wdt_reset();
                                        //requestTime();// get time     
                                      }
                                      else if (batteryPcnt<75 and batteryPcnt>35) {
                                        //send(msgText.set("Sleep*3"), false);
                                        Serial.println("Sleep*3");
                                        wdt_reset();
                                        MYsleepTime = (BaseMYsleepTime * 3) ;
                                        //requestTime();// get time
                                      }
                                      else {
                                        Serial.println("Sleep :");
                                        wdt_reset();
                                        MYsleepTime = BaseMYsleepTime;
                                      }
                                  //    Serial.print("Sleepcount = ");Serial.println(SleepCnt);
                                   //   Serial.print("Sleeptime = ");Serial.println(MYsleepTime);  
                                      MYsleepTime = constrain((MYsleepTime - SleepCnt),1000,MYsleepTime);// calc how much left from last sleep
                                   //   Serial.print("RemainSleep = ");Serial.println(MYsleepTime);
                              
                                      SleepCnt=0;
                                      RainInterrupt = 0;
                                        
                              // Sleeping 
                               
                                          while((SleepCnt < MYsleepTime) ){//or (wakeupReason != digitalPinToInterrupt(RainPin)) or (RainInterrupt != 1) 
                                            sleep(1000);
                                          
                                                if(RainInterrupt == 1){
                                                  break;
                                                }
                                                else{
                                                  Slept = 1;
                                                  wdt_reset();
                                                }
                                            SleepCnt=SleepCnt+1000; // count another 1000ms of sleep
                                            wdt_reset();
                                          
                                          }// end while
                                          
                                          if(SleepCnt>=(MYsleepTime - 10000)){
                                            SleepCnt=0;
                                          }
                              
                                        attachInterrupt(digitalPinToInterrupt(RainPin), RainINT, FALLING);
                                        
                                        wdt_reset();
                              
                                
                               wait(Debouncetime + 1);// need to wait otherwisee the debounce won't work because millis not updated in sleep
                              
                                if (RainInterrupt == 1) {// of woken due to rain bucket actions
                                  //  Serial.println(F("RainInterrupt=1"));
                              
                                    resend(lastCounterMsg.set(Watermmtot, 1) , true, 5);
                                    if (resend(msgRain.set(Watermmtot, 1) , true, 5)) { // only reset if sending succeeded
                                      resend(msgRainRate.set(30) , true, 5);
                                      fullCounter = fullCounter - 1;
                                      //RainInterrupt = 0;
                                      EEPROMWritelong(WatermmADD, Watermmtot);
                                    }
                              
                                }
                              
                              }// end loop
                              
                              
                              
                              void receive(const MyMessage &message) {
                                // We only expect one type of message from controller. But we better check anyway.
                                wdt_reset();
                                if (message.isAck()) {
                              #ifdef MY_DEBUG
                                  Serial.println("+Ack FMGW");
                              #endif
                                }
                              
                              #ifdef MY_DEBUG
                                Serial.print("*InMsgty :");
                                Serial.print(message.type);
                                Serial.print(" MsgComd:");
                                Serial.print(message.getCommand());
                                Serial.print(" childID:");
                                Serial.print(message.sensor);
                              
                                Serial.print(" Switch:");
                                Serial.println(message.getFloat());
                              #endif
                              
                              
                                if (message.type == V_STATUS || S_HEATER || V_LIGHT || V_TEXT || V_HVAC_SETPOINT_HEAT || V_PERCENTAGE || S_DIMMER) {
                              
                              
                                  if (message.getCommand() == 2) { // THIS PROCESSES THE CONTROLLERS EXPECTED STATE OF THE OUTPUT
                                    // put code here to be executed when the message is from a request
                              #ifdef MY_DEBUG
                                    Serial.print("REQ_Msg :");
                                    Serial.print(message.type);
                                    Serial.print(" MsgCmd:");
                                    Serial.print(message.getCommand());
                                    Serial.print(" childID:");
                                    Serial.print(message.sensor);
                                    Serial.print(" Switch:");
                                    Serial.println(message.getBool());
                              #endif
                              
                                    switch (message.sensor) {// the child ID
                              
                                      case 11:
                              
                                        Watermmtot = message.getFloat();
                                        //#ifdef MY_DEBUG
                                        Serial.print(" Incoming Rain mm:");
                                        Serial.println(Watermmtot);
                                        //#endif
                                        if (Watermmtot >= 0.3) {
                                          EEPROMWritelong(WatermmADD, Watermmtot);
                                        }
                                        else {
                                          Watermmtot = EEPROMReadlong(WatermmADD); // long eeprom read
                                          ValidWaterCount = 1;
                                        }
                                        break;
                              
                                    } // end switch
                              
                              
                              
                              
                                  }// end msg=2
                              
                                  if (message.getCommand() == 1) { // THIS PROCESSES DIRECTED COMMANDS
                              
                              
                              #ifdef MY_DEBUG
                                    Serial.print("*InMsgty :");
                                    Serial.print(message.type);
                                    Serial.print(" MsgComd:");
                                    Serial.print(message.getCommand());
                                    Serial.print(" childID:");
                                    Serial.print(message.sensor);
                              
                                    Serial.print(" Switch:");
                                    Serial.println(message.getBool());
                              #endif
                                    /*
                                          switch (message.sensor) {// the child ID
                              
                                            case 2:
                                              TempRELAY = message.getBool();
                                              //#ifdef MY_DEBUG
                                              Serial.print(" Incoming rELAY:");
                                              Serial.println(TempRELAY);
                                              //#endif
                              
                                              watering = TempRELAY;
                              
                                              send(msgRelay.set(watering, 0)); // send relay state
                              
                              
                                              break;
                              
                                          } // end switch
                              
                                    */
                              
                              
                                  }// end if msg = 1
                              
                              
                                }// end msg type function
                              
                              }// end void loop
                              
                              
                              
                              void RX_SEND()
                              {
                                wdt_reset();
                                send(msgRxRSSI.set(transportGetSignalReport(SR_RX_RSSI)));
                                wdt_reset();
                              }
                              
                              
                              void sendBatteryReport() {
                                wdt_reset();
                              
                                float p = vcc.Read_Perc(VCC_MIN, VCC_MAX, true);
                                int batteryPcnt = static_cast<int>(p);
                              #ifdef MY_DEBUG
                                Serial.print("Battery is: "); Serial.println(batteryPcnt);
                              #endif
                                sendBatteryLevel(batteryPcnt);
                              }
                              
                              
                              
                              void ReadEEprom() {
                                wdt_reset();
                                //if (EEPROMReadlong(SetpointADD) > 0) SoilSetPoint = EEPROMReadlong(SetpointADD) ;
                                //if (EEPROMReadlong(WaterTimeADD) > 0) WaterTime = EEPROMReadlong(WaterTimeADD) ;
                              
                                if (loadState(SetpointADD) > 0) SoilSetPoint = loadState(SetpointADD) ;
                                if (loadState(WaterTimeADD) > 0) WaterTime = loadState(WaterTimeADD) ;
                              
                              }
                              
                              
                              
                              void getSoil() {
                                wdt_reset();
                              
                                analogReference(DEFAULT);
                                for (int i = 0; i <= 10; i++) {
                                  RawSoil = analogRead(Soil_ip_pin);
                                  wait(5);
                                }
                              
                                int soilCount = 0;
                                unsigned long soilAccum = 0;
                                digitalWrite(SoilPowerPin, HIGH); // Power up sensor
                                wait(1000);
                              
                                RawSoil = analogRead(Soil_ip_pin);
                                soilAccum = RawSoil;
                                while (soilCount < 50) {
                                  wait(20);
                                  RawSoil = analogRead(Soil_ip_pin);
                                  if (RawSoil > 0) {
                                    soilAccum = soilAccum + RawSoil;
                                  }
                                  soilCount++;
                                }
                                Serial.print("SCount ");
                                Serial.println(soilCount);
                                RawSoil = soilAccum / soilCount;
                                Serial.print("RawSoil ");
                                Serial.println(RawSoil);
                              
                                wait(1);
                                ScaledMoisture = map(RawSoil, 600 , 0, 0, 100); // get the target position
                                digitalWrite(SoilPowerPin, LOW); // Power down sensor
                              
                                Serial.print("Scaled Moisture CB ");
                                Serial.println(ScaledMoisture);
                              
                              }
                              
                              void RainINT() {
                                
                                unsigned long thisTipTime = millis();
                                if (thisTipTime - lastTipTime > (Debouncetime)) {// debounce 20ms
                                  Watermmtot = Watermmtot + bucketSize;
                                  fullCounter = fullCounter + bucketSize;//Count so we send the counter for every 1mm
                                  RainInterrupt = 1;
                                  lastTipTime = thisTipTime;
                                }
                              }
                              
                              
                              bool resend(MyMessage & msg, bool ack, int repeats)
                              {
                                wdt_reset();
                                int repeat = 1;
                                int repeatdelay = 0;
                                boolean sendOK = false;
                              
                                while ((sendOK == false) and (repeat < repeats)) {
                                  if (send(msg, ack)) {
                                    sendOK = true;
                                  } else {
                                    sendOK = false;
                                    Serial.print("TX Error ");
                                    Serial.println(repeat);
                                    repeatdelay += 200;
                                    if (repeatdelay >= 500) {
                                      repeatdelay = 500;
                                    }
                                    wdt_reset();
                                  } repeat++; wait(repeatdelay);
                                }
                                return sendOK;
                              }
                              

                              For my own education, I will build a new note to test the sleep and interrupt, and see where / how thing are not working, but that won't happen till later in the week.

                              Please note that I am still on V 2.2.0

                              YveauxY Offline
                              YveauxY Offline
                              Yveaux
                              Mod
                              wrote on last edited by
                              #14

                              @Njwyborn said in Is there a "standard" way to terminate a sleep time, after waking by an interrupt?:

                              Please note that I am still on V 2.2.0

                              You should have started there. I fixed some nasty race conditions in the sleep code, that iirc, were not included until 2.3.0.
                              Why don't you upgrade? These versions are on - air compatible anyway.

                              http://yveaux.blogspot.nl

                              N 1 Reply Last reply
                              0
                              • YveauxY Yveaux

                                @Njwyborn said in Is there a "standard" way to terminate a sleep time, after waking by an interrupt?:

                                Please note that I am still on V 2.2.0

                                You should have started there. I fixed some nasty race conditions in the sleep code, that iirc, were not included until 2.3.0.
                                Why don't you upgrade? These versions are on - air compatible anyway.

                                N Offline
                                N Offline
                                Nigel31
                                wrote on last edited by
                                #15

                                @Yveaux
                                Yes, that is what the sencebender gateway was for, so I could start with an easily swappable item, and the core of the network, however you might remember that I am having issues with sencebender gateway.. with no solution in sight.

                                link text

                                1 Reply Last reply
                                0
                                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
                                • OpenHardware.io
                                • Categories
                                • Recent
                                • Tags
                                • Popular