Group Details Private

Contest Winner

 
  • RE: OpenHAB 2.3 and MQTT

    @martim I'm sorry myFriend. I've tried OpenHaB a couple of years ago. But in those days I couldn't get it to work. To complicated for me. That's why I've switched to Domoticz. That does what I need. You could give that - or another controller - a try. OpenHAB is overly complicated if you ask me.

    posted in OpenHAB
  • RE: Arduino minimum hw requirements (Nano problems)

    Hi, despite the continuous effort to make NodeManager small in size to fit into any board, when there are a few sensors registered and/or features enabled you can have issues to fit the board's memory. I'm running most of the tests on Pro Mini boards so with the same memory layout of your Nano to put myself in a worst case scenario but especially when using sensors requiring external libraries, the memory consumption could become an issue. Start by disabling NodeManager debug once you trust your code enough as a starting point but if you need all of those features all together you may also consider a board with more memory available. Thanks!

    posted in NodeManager
  • RE: 💬 Button size radionode with sensors swarm extension

    Hi @bjornhallberg.
    I've done many tests today with your code. All tested boards were the newer ones. So I completely had no ideas until I read your last message. Now all is clear for me. You have battery draining ~10-100ua, not 1-2mA. As I see your boards contain 107J capacitors. It was an absolutely failed batch of capacitors. We resoldered all of these capacitors on all the boards after we had found this problem with @alexsh1. Unfortunatelly some of these boards had been sent until we found this problem. We are so sorry you had to deal with these failed boards. I suggest I send you some new tested buttonsized v1 boards to you. Also I can send good capacitors to rework failed boards and some of my new interesting boards for free.

    posted in OpenHardware.io
  • RE: How do I push Notification within Arduino IDE sketch?

    @goddur I'm sorry my friend. I think this question is not related to MySensors. I've googled it for you. https://www.instructables.com/id/ESP8266-to-IFTTT-Using-Arduino-IDE/

    posted in My Project
  • Humidifier / Essence oil vaporize - anti dry-out monitor (WIP)

    First of all. I'm sorry I've been away for a really long time. Life was just very busy. But I graduated as a psycho therapist a couple of months ago. And finally had some time to build this project.

    So my better half bought a humidifier in which you can drop some drops of essence oil. It's suppose to be good when she's doing Yoga.

    https://nl.aliexpress.com/item/USB-Luchtbevochtiger-Essenti-le-Olie-Diffuser-Diffuseur-Huile-Essentiel-Humidificador-Ultrasonico-500-ml-10/32856306452.html?spm=a2g0s.9042311.0.0.1ec64c4dVkQqGE

    alt text

    It's really a simple system. There's a water tank and a sponge, which is spring held against a piezo element. So when there's power on the piezo element it vaporizes the water in the tank. I'm not sure, but I think the piezo element stimulates the capillary function of the sponge. But when there's no power on the piezo element for a couple of hours, the humidifier smells terrible when you turn it on again. You suppose to remove the sponge when you turn it off, but we forget that for most of the time.

    A couple of weeks ago, I was doing some meditation and turned on the humidifier. And it is actually very relaxing. I like the smell of Vata oil. So I put some drops in the humidifier. It was during that meditation that it came to me, that I needed to add a MySensors monitor.

    Design Goals:

    1. It must be possible to operate the humidifier manually all of the time.
    2. The monitor should turn on the humidifier on regular intervals for a set amount of time.
    3. When the humidifier has ran for more than 4 hours in total, the humidifier is not allowed to be turned on again. Until the user confirms a refill of the water tank.
    4. It would be awesome, if I can control the humidifier with an IR remote control - I'm gonna be honest. After a couple of years of doing Home Automation, I really don't like the fact that I have to use my mobile phone for controlling devices.
    5. It would be nice if I can get a visual on the water level in the tank. Without opening the humidifier.

    So after prototyping a lot. The design I have now is:

    • a one button operated monitor. Used to turn the humidifier on and off and to confirm to the monitor, that I have refilled the tank.
    • a WS28b12 which changes it's color to the calculated percentage of the water level. (Couldn't fit a distance sensor in the humidifier)
    • MySensorfied (still version 2.0.0 need to upgrade to 2.3.0 but that takes a lot of time)
    • I can control domoticz with a IR Remote Control project I'm working on.
      I like this setup, it's really basic but does what I need.

    The main sketch humidifierSystem.ino

    /*
      Sketch : humidifierSystem
      Author : by Theo
    
      Controls a USB powered connector. To which an USB powered humitifier is connected, which is also able to humiditfy esence oil.
    
      History:
      -  December 1st 2018 : Initial Version. 
    */
    
    /* Use static Node id. We'll use another Arduino for production version */
    #define MY_NODE_ID 5
    
    // Enable debug prints
    #define MY_DEBUG_OFF
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    
    
    /* Include used libraries */
    #include <Bounce2.h>
    #include "FastLED.h"
    #include "avr/power.h"
    #include "config.h" // Project specific settings and definitions.
    #include <SPI.h>
    #include <MySensors.h>
    
    #include "mysUtils.h"
    
    
    /* Needs to be declared prior to serialDebug inclussion. */
    HUMIDIFIER_STATES currentState = HS_INITIAL;
    unsigned long currentTime; // The current running time in millis since Arduino has been started. Is set in main loop
    unsigned long preventSmellStartlInterval = 3600; // Restart every hour. Is reset each time the humidifier is turnedOff
    unsigned long preventSmellRunDuration =  30; // Run 30 Secods. If we don't use it. It needs refill once every xx days....
    
    unsigned long humidifierRefillPeriod = 14400; // needs refill after 180 seconds (3 minutes = 10 runs)
    unsigned long totalRunningTime = humidifierRefillPeriod; // Indicates the amount of seconds the humidifier has been running 14400 is 4 hour. We start with an empty tank, because we have no idea what the state is.
    
    unsigned long lastActivationTime = 0 - ( preventSmellStartlInterval * 1000 );
    unsigned long currentStateRunningTime = 0;
    
    unsigned long maxUserRunDuration = 900; // meaning 15 minutes if 0 no maxDuration but I think that that's not a good idea. We control cheap Chinese crap, which shouldn't be powered on infinitly. It's up to the user.
    HUMIDIFIER_STATES oldState; // Used in set state, so that we can do something depending on previous state
    unsigned long stateStarted = 0; // Indicates the TS when the currentState has been set.
    
    
    #include "serialDebug.h"
    
    double currentTankPercentage = 100;
    double percentageCalculator = 0;
    
    CRGB leds[ WS28b12_NUM_LEDS ];
    Bounce toggleButtonDebouncer = Bounce();
    
    
    
    /* Declare outside of dispSecondsLeft function, to be more heap space friendly */
    unsigned long secondsLeft = 0;
    int days = 0;
    
    /*
      Calculate how much time is left before the tank is empty, Based upon the total time it takes for our tank to be empty if run contineously,
      the amount of time the humidifier alreada ran after last refill, the duration of a dry-out prevention run and the interval between dry-out preventions.
    */
    void dispSecondsLeft() {
      secondsLeft = ( ( humidifierRefillPeriod - totalRunningTime ) / (float)preventSmellRunDuration ) * (float)preventSmellStartlInterval; // amount of seconds left
    
      if ( secondsLeft >= SECONDS_IN_DAY) {
        days = secondsLeft / SECONDS_IN_DAY;
        secondsLeft -=  days * SECONDS_IN_DAY;
      }
    
      if ( secondsLeft >= SECONDS_IN_HOUR ) {
        hours = secondsLeft / SECONDS_IN_HOUR;
        secondsLeft -= hours * SECONDS_IN_HOUR;
      }
    
      if ( secondsLeft >= SECONDS_IN_MINUTES ) {
        minutes = secondsLeft / SECONDS_IN_MINUTES;
        secondsLeft -= minutes * SECONDS_IN_MINUTES;
      }
    
    #ifdef DEBUG_HUMIDIFIER
      Serial.print( "Tank left " ); Serial.print( days ); Serial.print( " days, " ); Serial.print( hours ); Serial.print( ":" ); Serial.print( minutes ); Serial.print( ":" ); Serial.print( secondsLeft ); Serial.println();
    #endif
      sendTimeLeft( days, hours, minutes, secondsLeft );
    }
    
    /*
      Turns off our visual indicator.
    */
    void turnOffVisualIndicator() {
      FastLED.clear();
      FastLED.show();
    }
    
    /*
      Shows the level of our tank. Until 10% it'll show a green color. Until 5% we'll show yellos. Until 2% we show orange and of we have 2 or less % available we show red
    */
    void showVisualTankPercentage() {
      if ( currentTankPercentage <= 2.0 ) {
        leds[0] = CRGB::Red;
      }
      else if ( currentTankPercentage <= 5.0 ) {
        leds[0] = CRGB::Orange;
      }
      else if ( currentTankPercentage <= 10.0 ) {
        leds[0] = CRGB::Yellow;
      }
      else {
        leds[0] = CRGB::Green;
      }
      FastLED.show();
    }
    
    /*
      MySensors before method. It's being called before Node tries to connect to the gateway.
    
      Since we want to visualize connecting to the gateway. We have to Initialize our WS28b12 led.
    */
    void before() {
      FastLED.addLeds<NEOPIXEL, WS28b12_INDICATOR_PIN>(leds, WS28b12_NUM_LEDS  );
    
      leds[0] = CRGB::Blue;
      FastLED.show();
    
    
    #ifdef DEBUG_HUMIDIFIER
      Serial.begin( 115200 );
      while (!Serial) { // Wait for the serial connection to be establised.
        delay( 50 );
      }
    #endif
    }
    
    /*
      Setup method of the sketch.
    */
    void setup() {
      /* Turn of peripherals we don't use for power savings */
      ADCSRA = 0;  // disable ADC to save power consumptione, we don't use Analog input.
    
      // Assign each pin and write low to it.
      for ( byte b = 2; b <= A5; b++ ) {
        pinMode( b, OUTPUT );
        digitalWrite( b, 0 );
      }
    
      pinMode( POWER_STATE_PIN, OUTPUT ); // It's binary we don't use PWM. So setting it to OUTPUT is good enough
    
      pinMode( TOGGLE_BUTTON_PIN, INPUT_PULLUP ); // Setup the button with an internal pull-up :
      toggleButtonDebouncer.attach( TOGGLE_BUTTON_PIN ); // After setting up the button, setup the Bounce instance
      toggleButtonDebouncer.interval( DEBOUNCE_DURATION ); // Set debounce interval
    
    #ifdef DEBUG_HUMIDIFIER
      Serial.println( "Starting humidifier monitor" );
    #endif
      setState( HS_IDLE );
    }
    
    /*
      MySensors presentation method. It's used to present out sensors to the gateway.
      Note: You can use a request, but had no luck with using a send cmd
    */
    void presentation() {
      sendSketchInfo(SN, SV);
      present( CHILD_ID_HUMIDIFIER_STATE_CHANGE_REQUEST, S_BINARY );
      wait( 50 );
      present(CHILD_ID_CONFIG, S_INFO );
      wait( 50 );
      present(CHILD_ID_TANK_EMPTY, S_MOTION );
      wait( 50 );
      present( CHILD_ID_NEW_CONFIG, S_BINARY );
      wait( 50 );
      present( CHILD_ID_TANKLEVEL_PERCENTAGE, S_INFO );
      wait( 50 );
      present( CHILD_ID_TANKLEVEL_TIMELEFT, S_INFO );
      wait( 50 );
      request( CHILD_ID_CONFIG, V_TEXT, 0 );
      wait( 50 );
      turnOffVisualIndicator();
    }
    
    /*
    
    */
    double getCalculatedTankLevel( long currentRunningtime ) {
      percentageCalculator = 100 - ( double( currentRunningtime )  / double( humidifierRefillPeriod ) * 100 );
      percentageCalculator = ( (double)(round( percentageCalculator * 10 ) / (double)10) );
      return percentageCalculator;
    }
    
    unsigned long toggleButtonLastPress = 0;
    bool buttonChanged = false;
    unsigned long refillAnimationLastIndicatorSet;
    bool refillBlyncOn;
    
    bool longPressDetectionSend = false;
    
    void loop() {
      currentTime = millis(); // Remember currentTime millis for other parts in sketch.
      buttonChanged = toggleButtonDebouncer.update();
    #ifdef DEBUG_HUMIDIFIER
      displayCurrentTime();
    #endif
      switch ( currentState ) {
        case HS_IDLE:
          if ( currentTime >= ( lastActivationTime + ( preventSmellStartlInterval * 1000 ) ) ) {
            lastActivationTime = currentTime; // The interval is based upon the last time the prevention has run
            setState( HS_RUNNING_PREVENTION );
          }
          else { // Check for user humidifier on request
            if ( buttonChanged ) {
              if ( toggleButtonDebouncer.read() == LOW ) { // Call code if Bounce fell (transition from HIGH to LOW) :
    #ifdef DEBUG_HUMIDIFIER
                Serial.println( "press detected...???" );
    #endif
                toggleButtonLastPress = currentTime;
                longPressDetectionSend = false;
              }
              else {
    #ifdef DEBUG_HUMIDIFIER
                Serial.println( "Released... " );
    #endif
                if ( currentTime <= toggleButtonLastPress + 500 ) {
    #ifdef DEBUG_HUMIDIFIER
                  Serial.println( "short press" );
    #endif
                  setState( HS_RUNNING_USER );
                }
                else {
                  turnOffVisualIndicator();
                  totalRunningTime = 0; // (unsigned long)( humidifierRefillPeriod * 0.898 ); // Note: This is for debug. Should actually be 0 meaning full tank
    #ifdef DEBUG_HUMIDIFIER
                  Serial.println( "User indicates inbetween refill" ); // totalRunningTime
                  Serial.println( totalRunningTime );
    #endif
                }
              }
            }
            else if ( toggleButtonDebouncer.read() == LOW && currentTime >= toggleButtonLastPress + 500 && longPressDetectionSend == false ) {
    #ifdef DEBUG_HUMIDIFIER
              Serial.println( "Long pressed detected" );
    #endif
              longPressDetectionSend = true;
              leds[0] = CRGB::Green;
              FastLED.show();
    
            }
          }
          break;
        case HS_RUNNING_PREVENTION:
          toggleButtonDebouncer.read(); // remove debounce change bool
          currentStateRunningTime = ( currentTime - stateStarted ) / 1000; // Interval is in seconds.
          if ( currentStateRunningTime + totalRunningTime >= humidifierRefillPeriod  ) {
            totalRunningTime += currentStateRunningTime;
            setState( HS_NEEDSREFILL );
            break;
          }
          else if (  currentStateRunningTime >= preventSmellRunDuration || ( totalRunningTime + currentStateRunningTime ) >= humidifierRefillPeriod ) {
            totalRunningTime += currentStateRunningTime;
            if ( totalRunningTime >= humidifierRefillPeriod ) {
              setState( HS_NEEDSREFILL );
            }
            else {
    #ifdef DEBUG_HUMIDIFIER
              Serial.print( "Next dry up prevention is at " ); Serial.println( lastActivationTime + ( preventSmellStartlInterval * 1000 ) );
    #endif
              setState( HS_IDLE );
            }
            break;
          }
          if ( getCalculatedTankLevel( totalRunningTime + currentStateRunningTime) != currentTankPercentage ) {
    #ifdef DEBUG_HUMIDIFIER
            Serial.print( currentTime  ); Serial.print( " - Humidifier tank percentage " ); Serial.print( percentageCalculator, 1 ); Serial.println( "%" );
    
    #endif
            currentTankPercentage = percentageCalculator;
            showVisualTankPercentage();
            sendTankLevelUpdate( currentTankPercentage );
          }
          break;
        case HS_RUNNING_USER:
          currentStateRunningTime = ( currentTime - stateStarted ) / 1000; // Interval is in seconds.
          if ( currentStateRunningTime + totalRunningTime >= humidifierRefillPeriod  ) {
            totalRunningTime += currentStateRunningTime;
            lastActivationTime = currentTime;
            setState( HS_NEEDSREFILL );
          }
          else {
            if ( getCalculatedTankLevel( totalRunningTime + currentStateRunningTime) != currentTankPercentage ) {
    #ifdef DEBUG_HUMIDIFIER
              Serial.print( currentTime  ); Serial.print( " - Humidifier tank percentage " ); Serial.print( percentageCalculator, 1 ); Serial.println( "%" );
    #endif
    
              currentTankPercentage = percentageCalculator;
              showVisualTankPercentage();
              sendTankLevelUpdate( currentTankPercentage );
            }
            if ( ( maxUserRunDuration > 0 && currentStateRunningTime >= maxUserRunDuration )  || ( buttonChanged && toggleButtonDebouncer.read() == HIGH ) ) {
    #ifdef DEBUG_HUMIDIFIER
              Serial.println( "(auto)shutdown user running" );
    #endif
              totalRunningTime += currentStateRunningTime;
              lastActivationTime = currentTime;
              setState( HS_IDLE );
            }
          }
          break;
        case HS_NEEDSREFILL:
          // Wait for user to press Refill button... Should we allow to do this via MySensors.???
          if ( buttonChanged && toggleButtonDebouncer.read() == HIGH ) { // Call code if Bounce fell (transition from HIGH to LOW) :
            totalRunningTime = 0;
    #ifdef DEBUG_HUMIDIFIER
            Serial.println( "User refilled tank" );
    #endif
            send( tankEmptyMsg.set( "0" ) );
    
            lastActivationTime = currentTime - ( preventSmellStartlInterval * 1000 ) - 500; // force a dry-out protection
            setState( HS_IDLE );
          }
          else {
            if ( currentTime >= refillAnimationLastIndicatorSet + refillBlyncDuration ) {
              refillBlyncOn = !refillBlyncOn;
              refillAnimationLastIndicatorSet = currentTime;
    
              if ( refillBlyncOn ) {
                leds[0] = CRGB::Red;
                FastLED.show();
              }
              else {
                turnOffVisualIndicator();
              }
            }
          }
          break;
      }
    }
    
    void setState( HUMIDIFIER_STATES newState ) {
      if ( newState != currentState ) {
        oldState = currentState;
        currentState = newState;
        stateStarted = currentTime;
    
    #ifdef DEBUG_HUMIDIFIER
        Serial.print( currentTime  ); Serial.print( " - State changed to " ); Serial.println( stateNames[ currentState ] );
        Serial.print( currentTime  ); Serial.print( " - Humidifier tank percentage " ); Serial.print( getCalculatedTankLevel( totalRunningTime ), 1 ); Serial.println( "%" );
    #endif
    
        currentTankPercentage = percentageCalculator;
    
    #ifdef DEBUG_HUMIDIFIER
        lastTimeDisplayed = currentTime;
        displayCurrentTime( true );
    #endif
    
        switch ( newState ) { // Turn on/off the power pin according the new state. Much easier to handle it here throughtout the Code.
          case HS_INITIAL:
            digitalWrite( POWER_STATE_PIN, LOW );
            break;
          case HS_IDLE:
            dispSecondsLeft();
            turnOffVisualIndicator();
    
            digitalWrite( POWER_STATE_PIN, LOW );
    
            send( humidifierRunningMsg.set( "0" ) ); // Let gateway know we humidifier is no longer running
            wait( 5 );
            sendTankLevelUpdate( currentTankPercentage );
    
            break;
          case HS_RUNNING_PREVENTION:
            showVisualTankPercentage();
            digitalWrite( POWER_STATE_PIN, HIGH );
    
            send( humidifierRunningMsg.set( "1" ) ); // Let gateway know we humidifier is longer running
            wait( 5 );
            sendTankLevelUpdate( currentTankPercentage );
            break;
          case HS_RUNNING_USER:
            showVisualTankPercentage();
            digitalWrite( POWER_STATE_PIN, HIGH );
    
            send( humidifierRunningMsg.set( "1" ) ); // Let gateway know we humidifier is longer running
            wait( 5 );
            sendTankLevelUpdate( currentTankPercentage );
            break;
          case HS_NEEDSREFILL:
            sendTankLevelUpdate( 0.0 );
            turnOffVisualIndicator(); // Should be red
            refillAnimationLastIndicatorSet = currentTime;
            refillBlyncOn = false;
    
            // Turn off humidifier powerrrrr!!! :p
            digitalWrite( POWER_STATE_PIN, LOW );
    
            send( humidifierRunningMsg.set( "0" ) ); // Let gateway know we humidifier is no longer running
            wait(5);
            send( tankEmptyMsg.set( "1" ) );
            break;
        }
      }
    }
    
    /*
      MySensors callback method for when a message from the gateway - or another Node - has been received.
    */
    void receive(const MyMessage &message) {
    #ifdef DEBUG_HUMIDIFIER
      Serial.println( "Message received:" );
      Serial.print( "\tType: " ); Serial.println( message.type );
      Serial.print( "\tSensor: " ); Serial.println( message.sensor);
      Serial.print( "\tString: '" ); Serial.print( message.getString() ); Serial.println( "'" );
    #endif
    
      if ( message.sensor == CHILD_ID_CONFIG ) {
        bufferTmp = message.getString();
    
        if ( getMysBufferSeparatorCount() == 3 ) {
          if ( updateHumidifierConfig() ) {
            preventSmellStartlInterval = tmpDryOutPreventionInterval;
            preventSmellRunDuration =  tmpDryOutPreventionRunTime;
            humidifierRefillPeriod = tmpTankStock;
            maxUserRunDuration = tmpMaxUserRunTimeDuration;
    
            if ( totalRunningTime > humidifierRefillPeriod ) {
              totalRunningTime = humidifierRefillPeriod;
            }
          }
        }
        else if ( strcmp( bufferTmp, "-" ) == 0 ) {
          sendCurrentConfiguration( humidifierRefillPeriod, preventSmellStartlInterval, preventSmellRunDuration, maxUserRunDuration );
        }
      }
      else if ( message.sensor == CHILD_ID_NEW_CONFIG ) {
        request( CHILD_ID_CONFIG, V_TEXT, 0 );
      }
      else if ( message.sensor == CHILD_ID_HUMIDIFIER_STATE_CHANGE_REQUEST ) {
        //    Serial.print( "Request received for Humidifier: " ); Serial.println( message.getBool() == true ? "on" : "off" );
        bool onStateRequested = message.getBool();
        switch ( currentState ) {
          case HS_IDLE:
            if ( onStateRequested == true ) {
              setState( HS_RUNNING_USER );
            }
            else {
              send( humidifierRunningMsg.set( "0" ) ); // Let gateway know we didn't accept the request
            }
            break;
          case HS_RUNNING_PREVENTION:
            send( humidifierRunningMsg.set( "1" ) ); // Let gateway know we didn't accept the request
            break;
          case HS_RUNNING_USER:
            if ( onStateRequested == false ) {
              totalRunningTime += currentStateRunningTime;
              lastActivationTime = currentTime;
              setState( HS_IDLE );
            }
            else {
              send( humidifierRunningMsg.set( "1" ) ); // Let gateway know we didn't accept the request
            }
            break;
          case HS_NEEDSREFILL:
            if ( onStateRequested == true ) {
              send( humidifierRunningMsg.set( "0" ) ); // Let gateway know we didn't accept the request
            }
            break;
          case HS_INITIAL: // Can't be in this state. Simply not possible
            break;
        }
      }
    }
    

    config.h

    /*
      file   : config.h
      author : by Theo
    
      description:
        contains settings and definitions for the humidifier monitor.
    */
    
    #define DEBUG_HUMIDIFIER_OFF // If defined DEBUG_HUMIDIFIER Serial debug is enabled. Just append _OFF if you don't need debug.
    
    
    #define DEBOUNCE_DURATION   5 // The amount of millis soft debouncing has to determine the value of a debounced switch
    #define TOGGLE_BUTTON_PIN   3 // The pin to wich the switch for manual operating is connected
    #define POWER_STATE_PIN     5 // The pin which connects to the USB terminal for controlling the power of the humidifier (will be connected to a mosfet controlling the USB terminal
    
    #define WS28b12_INDICATOR_PIN 6 // The pin to which the WS28b12 led is connected that we'll be using for a visual indicator
    #define WS28b12_NUM_LEDS 1      // The amount of leds. Can be more than one of chained more
    
    /* Constants used to calculate the total time left, before our tank is empty. Based upon the current settings. */
    #define SECONDS_IN_DAY 86400ul
    #define SECONDS_IN_HOUR 3600ul
    #define SECONDS_IN_MINUTES 60ul
    
    #define refillBlyncDuration 1000 // the duration between blync on and blync off, during refill animation
    
    /*
     State machines states for a humidifier monitorL
     - HS_INITIAL : Means we're in the setup part of the Sketch
     - HS_IDLE    : Means waiting for user required power on, or ant dry out time out
     - HS_RUNNING_PREVENTION : The anti dry-out timer went of and we're powering on the humidifier just long enough that it won't dry out
     - HS_RUNNING_USER : The user has requested a power on. Will run until user request a stop or when the max on duration timer has timed oud
     - HS_NEEDSREFILL  : Hold your horses. ank needs refilling. We don't allow any request to power on the humidifier
     */
    enum HUMIDIFIER_STATES { HS_INITIAL, HS_IDLE, HS_RUNNING_PREVENTION, HS_RUNNING_USER, HS_NEEDSREFILL };
    
    /* Contains the names of our states. Can be used for debug purposes */
    char stateNames[5][22] = { "HS_INITIAL", "HS_IDLE", "HS_RUNNING_PREVENTION", "HS_RUNNING_USER", "HS_NEEDSREFILL" };
    
    // Enable debug prints
    #define MY_DEBUG_OFF
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    

    mysUtils.h

    /*
    
    */
    
    #define SN "Dry-Out protector"
    #define SV "1.0"
    
    #define CHILD_ID_HUMIDIFIER_STATE_CHANGE_REQUEST  1
    #define CHILD_ID_CONFIG 2
    #define CHILD_ID_TANK_EMPTY 3
    #define CHILD_ID_NEW_CONFIG 4
    #define CHILD_ID_TANKLEVEL_PERCENTAGE 5
    #define CHILD_ID_TANKLEVEL_TIMELEFT 6
    
    MyMessage humidifierRunningMsg( CHILD_ID_HUMIDIFIER_STATE_CHANGE_REQUEST, V_LIGHT );
    MyMessage textMsg( CHILD_ID_CONFIG, V_TEXT);
    MyMessage tankEmptyMsg( CHILD_ID_TANK_EMPTY, V_TRIPPED);
    MyMessage tankLevelUpdatedMsg( CHILD_ID_TANKLEVEL_PERCENTAGE, V_TEXT );
    MyMessage tankLevelTimeLeftMsg( CHILD_ID_TANKLEVEL_TIMELEFT, V_TEXT );
    
    
    char *mysBufferHelper;
    char *bufferTmp;
    
    char *getMysBuffertNextSeparator() {
      return strchr( bufferTmp, '|' );
    }
    
    //bool mySensorsInitialized = false;
    
    
    int getMysBufferSeparatorCount() {
      int res = 0;
      char *cPtr = bufferTmp;
      char *sepPtr;
    
      sepPtr = strchr( cPtr, '|' ) ;
      while ( sepPtr != NULL ) {
        cPtr += ( sepPtr - cPtr ) + 1;
        res++;
        sepPtr = strchr( cPtr, '|' ) ;
      }
      return res;
    }
    
    unsigned long tmpTankStock;
    unsigned long tmpDryOutPreventionInterval;
    unsigned long tmpDryOutPreventionRunTime;
    unsigned long tmpMaxUserRunTimeDuration;
    
    bool updateHumidifierConfig() {
      mysBufferHelper = getMysBuffertNextSeparator();
      tmpTankStock = strtoul( bufferTmp, NULL, 10 );
      bufferTmp += ( mysBufferHelper - bufferTmp ) + 1;
      mysBufferHelper = getMysBuffertNextSeparator();
      tmpDryOutPreventionInterval = strtoul( bufferTmp, NULL, 10 );
      bufferTmp += ( mysBufferHelper - bufferTmp ) + 1;
      mysBufferHelper = getMysBuffertNextSeparator();
      tmpDryOutPreventionRunTime = strtoul( bufferTmp, NULL, 10 );
      bufferTmp += ( mysBufferHelper - bufferTmp ) + 1;
      tmpMaxUserRunTimeDuration = strtoul( bufferTmp, NULL, 10 );
    
      if ( tmpTankStock != 0 && tmpDryOutPreventionInterval != 0 && tmpDryOutPreventionRunTime != 0 ) {
        return true;
      }
      return false;
    }
    
    char mySensorsPayloadBuffer[ MAX_PAYLOAD ];
    void sendTankLevelUpdate( float newLevel ) {
      dtostrf( newLevel, 4, 1, mySensorsPayloadBuffer);
      send( tankLevelUpdatedMsg.set( mySensorsPayloadBuffer ) );
    }
    
    void sendTimeLeft( int days, int hours, int minutes, int seconds ) { // seconds is allways 0
      for ( int i = 0; i < MAX_PAYLOAD; i++ ) { // clearUp buffer
        mySensorsPayloadBuffer[ i ] = '\0';
      }
      char *hlpPtr;
      itoa ( days, mySensorsPayloadBuffer, 10 );
      hlpPtr = &mySensorsPayloadBuffer[0];
      hlpPtr += strlen( mySensorsPayloadBuffer );
      strcpy( hlpPtr, " days, " );
      hlpPtr = &mySensorsPayloadBuffer[0];
      hlpPtr += strlen( mySensorsPayloadBuffer );
      sprintf ( hlpPtr, "%02d:%02d:%02d", hours, minutes,  seconds );
      send( tankLevelTimeLeftMsg.set( mySensorsPayloadBuffer ) );
    }
    
    void sendCurrentConfiguration( unsigned long tankStock, unsigned long dryOutPreventionInterval, unsigned long dryOutPreventionRunTime, unsigned long maxUserRunTimeDuration ) {
      // //        send( textMsg.set( "14400|3600|30|900" ) );
      for ( int i = 0; i < MAX_PAYLOAD; i++ ) { // clearUp buffer
        mySensorsPayloadBuffer[ i ] = '\0';
      }
      sprintf ( mySensorsPayloadBuffer, "%lu|%lu|%lu|%lu", tankStock, dryOutPreventionInterval, dryOutPreventionRunTime,  maxUserRunTimeDuration );
      send( textMsg.set( mySensorsPayloadBuffer ) );
    }
    
    

    serialDebug.h

    /*
      file   : config.h
      author : by Theo
    
      description:
        contains methods used for serial debugging.
    */
    
    int minutes = 0;
    int hours = 0;
    
    
    #ifdef DEBUG_HUMIDIFIER
    /* vars for time display */
    unsigned long lastTimeDisplayed = 0;
    unsigned long elapsed = 0;
    int seconds = 0;
    
    /*
      Displays the given int value as a time. Meaning 00:00
    */
    void displayTime( int value ) {
      if ( value >= 3600 ) {
        hours = value / 3600;
        value -= ( hours * 3600 );
        if ( hours < 10 ) {
          Serial.print( "0" );
        }
        Serial.print( hours );
      }
      else {
         Serial.print( "00" );
      }
      Serial.print( ":" );
    
      minutes = value / 60;
      seconds = value % 60;
      if ( minutes < 10 ) {
        Serial.print( "0" );
      }
      Serial.print( minutes );
      Serial.print( ":" );
      if ( seconds < 10 ) {
        Serial.print( "0" );
      }
      Serial.println( seconds );
    }
    
    /*
      Displays the ellapsed time since a state has been set for each state
    */
    void displayCurrentTime( bool init = false) {
      // clear display...
      switch ( currentState ) {
        case HS_IDLE:
          elapsed = ( currentTime - lastTimeDisplayed  ) / 1000;
          if ( elapsed >= 1 || init ) {
            displayTime( preventSmellStartlInterval - ( ( currentTime - lastActivationTime ) / 1000 ) );
            lastTimeDisplayed = currentTime;
          }
          break;
        case HS_RUNNING_PREVENTION:
          elapsed = ( currentTime - lastTimeDisplayed  ) / 1000;
          if ( elapsed >= 1 || init ) {
            displayTime( preventSmellRunDuration - ( ( currentTime - stateStarted ) / 1000 ) );
            lastTimeDisplayed = currentTime;
          }
          break;
        case HS_RUNNING_USER:
          elapsed = ( currentTime - lastTimeDisplayed  ) / 1000;
          if ( elapsed >= 1 || init ) {
            displayTime( ( currentTime - stateStarted ) / 1000 );
            lastTimeDisplayed = currentTime;
          }
          break;
        case HS_NEEDSREFILL:
          elapsed = ( currentTime - lastTimeDisplayed  ) / 1000;
          if ( elapsed >= 1 || init ) {
            displayTime( ( currentTime - stateStarted ) / 1000 );
            lastTimeDisplayed = currentTime;
          }
          break;
        default:
          Serial.print( "Disp time: unsupported state" ); Serial.println( stateNames[ currentState ] );
      }
    }
    #endif
    

    The code is not completed yet. Lacks comments. The c code needs to be seperated from the .h files.

    But it works great. I has the following child nodes:

    1. Switch for controlling the power state through Domoticz
    2. Text node for configuring the monitor through Domoticz
    3. One update control switch. When pressed the current config is queried from Domoticz. Doesn't make sense to me, to poll it each and every while
    4. text node to which the tank level in percentages is written
    5. text node to which the remaining days en time is written after the humidifier has run
    6. Alarm node, for when the water tank is empty.

    0_1543788555926_Schermafbeelding 2018-12-02 om 23.08.07.png

    0_1543788579565_Schermafbeelding 2018-12-02 om 23.08.34.png

    Will post a schematic and some photo's soon. And put the code on my Github. Just wanted to share this one with you guys.

    If you don't use it for Yoga or meditation, you can use it as device that makes your house smell nice. You only need to refill it once every month. If you don't turn it on manually. You're better half is gonna love it.

    Currently deciding on whether I can use a 2n2222 transistor to control the USB. It says 500 mWa. It 5 Volt that should be sufficient to drive a 1 amp device??? As an alternative I can use a Mosfet. But the ones I have can drive up to 60 amps. Which is really overkill. I think I have some darlingtons laying around somewhere.

    As you can read. Still in prototyping phase. But the sketch is done.

    posted in My Project
  • RE: 💬 NodeManager

    Hello All, NodeManager v1.8 has just been released! I've opened up as usual a dedicated thread on the forum containing all the details of new release: https://forum.mysensors.org/topic/9944/nodemanager-v1-8-now-available

    posted in OpenHardware.io
  • NodeManager v1.8 now available!

    NodeManager v1.8 is finally here!

    With 8 months of development from 12 different contributors, the new NodeManager v1.8 ships now as an Arduino library to allow an easier integration, a more consistent upgrade process across the versions and a simpler way of using it.

    This version includes also a number of enhancements and bug fixes, a better integration with the MySensors library (including the capability to use the web-based Log Parser) and support for an additional 11 new sensors, with a grand total of 62 built-in sensors that can be added to your project by just a single line of code.

    NodeManager v1.8 can be downloaded directly from Github https://github.com/mysensors/NodeManager where detailed installation instructions are also provided.
    Please read the README file carefully before starting so to get a sense on how to use it or what has changed from the previous releases.

    The full release notes for this version are listed below:

    • Split NodeManager's core classes in individual files and each sensor code in its own dedicated header file
    • New Arduino-compatible library structure to allow easier integration and more consistent updates across version
    • Included a complete set of examples which can be loaded directly from the Arduino IDE
    • Simplified the template sketch with a global nodeManager object and sensors that can be imported directly from there
    • Debug output is now fully compatible with the one used by the MySensors library and integrated into MySensors LogParser
    • Better control on how often, if and when to sync the time with the controller for time-aware nodes
    • Added a Measure Timer so to allow splitting between taking measures and reporting
    • Added support for every sensor to keep track of the last value assigned to a child in EEPROM and restoring it upon a reboot
    • Introduced new capabilities for reporting every minute/hour/day or only at a given minute/hour/day
    • Added ability to read from the serial port at the end of each loop cycle, useful for debugging interactive sensors
    • Added support for pH sensor
    • Added support for PCA9685 as RGB/RGBW/W dimmer
    • Added support for DSM501A dust sensor
    • Added support for PN532 NFC RFID module
    • Added support for CCS811 CO2/VOC sensor
    • Added support for MPR121 Capacitive Touch Sensor
    • Added support for serial GSM/SMS device
    • Added support for FPM10A fingerprint sensor
    • Added support for SDS011 Air quality sensor
    • Added support for ESP32 devices
    • Added support for nRF52 radio
    • Improved SensorDigitalInput and NeoPixelSensor
    • Si7021 sensor is now using the library from the MySensors example
    • Reviewed the MQ Sensor implementation
    • Optimized memory utilization
    • Added Travis Continuous Integration tests
    • Fixed wrong battery report when using battery pin and SensorRain/SensorSoilMoisture
    • Fixed DigitalOutput safeguard not working as expected
    • Fixed radio signal level reporting wrong values
    • Fixed SensorLatchingRelay2Pins wrong pin selection
    • Other minor bug fixes
    posted in NodeManager
  • RE: 💬 NodeManager

    @maddinthebrain sorry for the huge delay...would you mind sharing the logs? Also feel free to open an issue on https://github.com/mysensors/NodeManager/issues with the logs. Thanks!

    posted in OpenHardware.io
  • RE: 💬 Security & Signing posted in Announcements
  • RE: 💬 Security & Signing

    @alowhum @hek we should perhaps retire that article or reduce it to a reference to the "actual" documentation instead to reduce the risk of confusion?

    posted in Announcements