Sensor reporting after External Interrupt



  • It looks like battery readings and all attached sensors readings are sent when an external interrupt occurs (e.g. when the door contact changes). Is it possible to disable them being sent? I only want the door contact event to get reported upon that interrupt.

    Thanks!



  • I should have stated that I am using NodeManager.



  • Yes that is possible. Please post your sketch so someone can advise what to change



  • That's great @electrik. Here is my NodeManager sketch:

    /**********************************
     * MySensors node configuration
     */
    
    // General settings
    #define SKETCH_NAME "SensorV1"
    #define SKETCH_VERSION "1.0"
    //#define MY_DEBUG
    
    // Nodes IDs (if not defined then uses auto node ID assignment from controller)
    #define NODE_TEST              5
    #define MY_NODE_ID NODE_TEST
    
    // NRF24 radio settings
    #define MY_RADIO_NRF24
    #define MY_RF24_PA_LEVEL RF24_PA_HIGH
    
    // Advanced settings
    #define MY_BAUD_RATE 57600
    #define MY_SPLASH_SCREEN_DISABLED
    
    /***********************************
     * NodeManager modules for supported sensors
     */
    
    #define USE_BATTERY
    #define USE_INTERRUPT
    #define USE_BME280
    
    /***********************************
     * NodeManager built-in features
     */
    
    // Enable/disable NodeManager's features
    #define FEATURE_DEBUG ON
    #define FEATURE_POWER_MANAGER OFF
    #define FEATURE_INTERRUPTS ON
    #define FEATURE_CONDITIONAL_REPORT OFF
    #define FEATURE_EEPROM OFF
    #define FEATURE_SLEEP ON
    #define FEATURE_RECEIVE ON
    #define FEATURE_TIME OFF
    #define FEATURE_RTC OFF
    #define FEATURE_SD OFF
    #define FEATURE_HOOKING OFF
    
    /***********************************
     * Load NodeManager Library
     */
    
    #include "NodeManagerLibrary.h"
    NodeManager node;
    
    #define PRODUCTION ON
    
    // Application constants
    const int CONTACT_PIN = 3;
    const int DEBOUNCE_MS = 500;
    const float BAT_MIN = 1.8;
    const float BAT_MAX = 3.2;
    
    #if PRODUCTION == ON
      const int SLEEP_INTERVAL_SEC = 60*60;   // 1 hour
      const int BME280_RPT_INTERVAL = 1 * SLEEP_INTERVAL_SEC;
      const int BAT_RPT_INTERVAL = 12 * SLEEP_INTERVAL_SEC;
    #else
      // testing
      const int SLEEP_INTERVAL_SEC = 10;
      const int BME280_RPT_INTERVAL = 1 * SLEEP_INTERVAL_SEC;
      const int BAT_RPT_INTERVAL = 6 * SLEEP_INTERVAL_SEC;
    #endif
    
    /***********************************
     * Add your sensors below
     */
    
    // built-in sensors
    SensorBattery battery(node);
    
    // Attached sensors
    SensorDoor door(node,CONTACT_PIN);
    SensorBME280 bme280(node);
    
    /***********************************
     * Main Sketch
     */
    
    // before
    void before() {
      // setup the serial port baud rate
      Serial.begin(MY_BAUD_RATE);
      
      /* Configure sensors */
    
      // debounce interrupts
      node.setInterruptDebounce(DEBOUNCE_MS);
      node.setIsMetric(false);
      
      // report battery level, set min/max voltages for % avail
      battery.setReportIntervalSeconds(BAT_RPT_INTERVAL);
      battery.setMinVoltage(BAT_MIN);
      battery.setMaxVoltage(BAT_MAX);
    
      // BME280 reporting
      bme280.setReportIntervalSeconds(BME280_RPT_INTERVAL);
    
      // set the node to sleep
      node.setSleepSeconds(SLEEP_INTERVAL_SEC);
    
      /* End configure sensors */
    
      node.before();
    }
    
    // presentation
    void presentation() {
      // call NodeManager presentation routine
      node.presentation();
    }
    
    // setup
    void setup() {
      // call NodeManager setup routine
      node.setup();
    }
    
    // loop
    void loop() {
      // call NodeManager loop routine
      node.loop();
    }
    
    #if FEATURE_RECEIVE == ON
    // receive
    void receive(const MyMessage &message) {
      // call NodeManager receive routine
      node.receive(message);
    }
    #endif
    
    #if FEATURE_TIME == ON
    // receiveTime
    void receiveTime(unsigned long ts) {
      // call NodeManager receiveTime routine
      node.receiveTime(ts);
    }
    #endif
    

    I would expect the following:

    • Reporting of BME sensors once per hour
    • Reporting of Battery once every 12 hours
    • Reporting of contact closure/opening asynchronously via external interrupt.

    What I actually see:

    • Every hour I get the battery and the BME sensor readings.
    • When a contact closure/opening occurs, I get the BME sensors and the contact change sensor event.

    Thanks for your help!



  • I have no experience with Nodemanager but I would suggest to use unsigned int for your constants. The battery time doesn't fit now



  • @electrik
    Your on the right track however the function setReportIntervalSeconds only accepts int

    for longer time periods the function should be setReportIntervalMinutes or setReportIntervalHours, or even setReportIntervalDays

    If the Sleep and report times are the same then you get the BME and the Contact sensor event. if the Sleep time and report time is different then you will get the contact event separately.



  • First, thanks @electrik and @hard-shovel for your input.

    Indeed, using the const int to hold the BAT_RPT_INTERVAL in seconds was wrong - good find @electrik.

    I fixed (changed all intervals to minutes) and the sketch continued to behave as before.

    I then changed the intervals:

      const int SLEEP_INTERVAL_MIN = 1;
      const int BME280_RPT_INTERVAL = 2 * SLEEP_INTERVAL_MIN;
      const int BAT_RPT_INTERVAL = 3 * SLEEP_INTERVAL_MIN;
    

    This apparently fixed the battery reporting, but I was still getting the BME280 sensor readings with each sleep cycle.

    I then decided to comment out bme280.setReportIntervalMinutes(2 * SLEEP_INTERVAL_MIN) and added node.setReportIntervalMinutes(2 * SLEEP_INTERVAL_MIN) .

    After this, it appeared to be operating as expected (at least as far as synchronous timed reporting).

    This led me to think that perhaps the default for node.setReportIntervalMinutes() was the same as the sleep interval.

    I then tried setting bme280.setReportIntervalMinutes(2 * SLEEP_INTERVAL_MIN) and added node.setReportIntervalMinutes(0) . My thought was that this might effectively disable node wide child sensor reporting. Indeed, it looks like that is what it did.

    So far so good.

    I then went to look at the asynchronous reporting when an external interrupt gets generated. Sometimes it would only send the change event and other times it would also send the BME280 sensor values. I noticed a pattern and believe that interrupts are being treated like sleep intervals so that 2 interrupts (e.g. in quick succession) would result in the BME280 sensor values getting sent.

    I guess I better study the code.



  • Having looked at the code, I am fairly certain that without FEATURE_TIME enabled (and supporting RTC or controller reporting time) that an external interrupt is treated as the end of the sleep cycle and the sleep cycle period is assumed to have passed.



  • Without Nodemanager it is very easy task.
    You can send messages when you want.
    If interrupt occurs - send contact status.
    When is right time - send BME data or battery.
    Why Nodemanager for this?



  • @kimot, thanks for your input.

    I have previously coded directly with the MySensors API quite successfully. What I like about NodeManager is that the developers have identified some common patterns in programming for MySensors and created an easier to use programming experience. NodeManager does a lot of the heavy lifting. For the most part I agree with the developer's design decisions.

    This simply comes down to the perennial question of whether to build something yourself or leverage the work of others. I am at a point where I prefer to rely on the work of others (if it is of good quality) so that I can get the most done.


  • Contest Winner

    @john-oliva sorry for the delayed answer first of all, I got no notification of this thread unfortunately. Regarding the signed/unsigned int, you hit unfortunately a bug we are working on it right now in the development version (https://github.com/mysensors/NodeManager/pull/391); whether you use setReportIntervalMinutes() or setReportIntervalDays() in v1.7, still the underlying variable which stores the value is a signed int hence your input would not fit, sorry for that.

    Let me also clarify the difference between sensor.setReportIntervalMinutes() and node.setReportIntervalMinutes(). The latter would act as a sort of default value: if no report interval has been set by the user, this default value will be used. This is why it would not apply when already called to the sensor instance.

    As for the issue with reporting and external interrupt, if NodeManager is not time-aware it thinks when the interrupt occurred the entire sleep timeframe has elapsed and the timer is updated accordingly, even if only one second has passed by. Unfortunately I think there is no alternative, with or without NodeManager (MySensors' sleep() doesn't know and hence return the time actually slept). Only with a RTC attached NodeManager can know how much time has really elapsed and then the calculations are correct and put the node to sleep for the remainder timeframe.

    If the issue persists, would be great if you can share NodeManager's logs here so ti dig a bit more into it. Thanks!


 

269
Online

7.8k
Users

8.7k
Topics

93.0k
Posts