Christmas Tree watering node - seasonal greetings



  • How to make your Christmas tree to remain green for several weeks? Plenty of water!

    Here is a project that will take care of the watering for You. Of course it can run without radio or mysensors but is great for monitoring and remote control (And you han add some extra alarms and safety nets)

    But be careful! We are dealing with water on places where we don't want any spill or leaks!

    0_1545469851948_IMG_20181220_211036.jpg

    A simple water sensor to measure the level in the base of the christmas tree. Normally i use etape for working with water levels but i considered it to be a bit too pricy (range 40-60$) for this project.

    0_1545468736650_water_sensor.JPG

    The level is checked roughly every second but the current is only on for 10ms to decrease the corrosion of the sensor. I think it will last one christmas at least ☺

    To fill the base i use a Peristaltic Liquid Pump. You can pick one up from your local Adafruit dealer or from ebay for ~15$. The pump can move 100ml / minute (i.e. like dripping once every two seconds or so) which is a very nice speed for this type of project. The sound level is like a brand new sewing machine so it's not supernoisy but nut supersilent either. I use a 5liter bucket with lid and all tubes are connected under the lid so if one gets disconnected it should stay in the bucket. Then both the tube and the water sensor is striped or taped to the tree.

    In my setup the pump works for just above one minute so it has then filled up around 100ml (but that depends on the thresholds you set of course)

    You can see the sensor box below and it's pretty simple don't think there is a need for schematics. Use a diode and a TIP120 to control the DC motor like below (I have a step up circuit from 5V to 12V)

    0_1545478676207_IMG_20181220_211319.jpg
    0_1545478544563_tip120-solenoid.png

    #define MY_DEBUG
    #define MY_RADIO_RFM69
    #define MY_IS_RFM69HW
    #define MY_RFM69_FREQUENCY RFM69_433MHZ // RFM69_433MHZ for development branch, RF69_433MHZ for master
    #define MY_RFM69_NEW_DRIVER
    
    #define MY_REPEATER_FEATURE
    #define MY_NODE_ID 42
    
    #define MY_RFM69_NETWORKID (170)
    
    #define CHILD_ID_LEVEL 2        
    #define CHILD_ID_PUMP  3       
    
    #include <MySensors.h>
    
    MyMessage levelMsg(CHILD_ID_LEVEL,V_LEVEL);
    MyMessage pumpMsg(CHILD_ID_PUMP, V_TRIPPED);
    
    long double HEARTBEAT_TIME = 60000;
    long double last_heartbeat_time = millis();
    const int read = A0; //Sensor AO pin to Arduino pin A0
    const int sensor_enable = 6;
    
    int value = -1;
    int readValue;
    int prevSentValue = -1;
    
    #define FILL_PIN 8
    #define STATE_IDLE 0
    #define STATE_FILL 1
    int state = STATE_IDLE;
    
    void before()
    {
      pinMode(sensor_enable, OUTPUT);
      digitalWrite(sensor_enable, LOW);
      pinMode(FILL_PIN, OUTPUT);
      digitalWrite(FILL_PIN, LOW);
    }
    
    void setup()
    {
    
    }
    
    void presentation()
    {
        // Send the sketch version information to the gateway and Controller
        sendSketchInfo("Cristmas Tree", "1.0");
    
        present(CHILD_ID_PUMP, S_BINARY);
        // Register this device as dust sensor as that seems easiest to map
        // to whatever you want (we want adc value)
        present(CHILD_ID_LEVEL, S_DUST);
    }
    
    
    void loop()
    {
    
      // No need to update more frequently than every second (or some more)
      wait(1000);
    
      // Enable the current in the water (Reduce corrosion compared to
      // continous 3.3V)
      digitalWrite(sensor_enable, HIGH);
      wait(10);
      readValue = analogRead(read);
      digitalWrite(sensor_enable, LOW);
      Serial.print("readValue = ");
      Serial.print(readValue);
    
      // Do some simple averaging unless first sample
      if(value == -1) {
        value = readValue;
      } else {
          value = readValue + value;
          value = value / 2;
      }
      Serial.print(", value = ");
      Serial.println(value);
    
      if(state == STATE_IDLE) {
        // The adc reading goes from 0 to ~150 when first in contact with water
        // 150-200 is within the first millimeter. Then the values increase in
        // a more linear manner.
        if(value < 200) {
          state = STATE_FILL;
          digitalWrite(FILL_PIN, HIGH);
          // Send both the level and the on so we can monitor for how long we
          // fill and are idle
          send(pumpMsg.set(state==STATE_FILL));
          send(levelMsg.set(value));
          prevSentValue = value;
        }
      }
      else if(state == STATE_FILL) {
        // Threshold at 360 (which is roughly half way on the mm scale
        // on the sensor ~20mm from empty) 
        // Note that since we are taking an average it will take a few seconds  
        // until we stop and so the value will be higher ~420
        if(value > 360) {
          state = STATE_IDLE;
          digitalWrite(FILL_PIN, LOW);
          // Send both the level and the on so we can monitor for how long we
          // fill and are idle
          send(pumpMsg.set(state==STATE_FILL));
          send(levelMsg.set(value));
          prevSentValue = value;
        }
      }
    
      int diff = value - prevSentValue;
      // Allow some jitter
      if(diff < 15 && diff > -15) {
    
        // no change but send anyway
        long double temp = (millis() - last_heartbeat_time);
        if (temp > HEARTBEAT_TIME) {
          // If it exceeds the heartbeat time then send a level anyway
          last_heartbeat_time = millis();
          send(levelMsg.set(value));
          prevSentValue = value;
    
        }
      } else {
        send(levelMsg.set(value));
        prevSentValue = value;
      }
    
    
    }
    
    void receive(const MyMessage &message)
    {
      Serial.print("msg");
        // We only expect one type of message from controller. But we better check anyway.
        if (message.type==V_STATUS) {
           // pulse = true;
            Serial.print("Incoming change for sensor:");
        }
    }
    

    If you hook up the sensor to your Homeautomation you should be able to monitor the sensor in action. You can then also take measures if the fill state (on) is longer than expected and raise an alarm and possibly to stop the watering all together.

    0_1545484636146_63bd7c01-d29e-460c-b2d4-2f65387a12cb-image.png

    As you can see the "normal" periodicity for me is watering every 3-4 hours and it fills for 1 to 1½ minute.

    0_1545484452499_chart.jpeg

    Wrap everything up in a nice present and enjoy! 🤗

    0_1545478963716_IMG_20181220_211359.jpg



  • Great idea. I was thinking about an automatic tree watering system, but the water level sensing seemed complex, and where to hide the water tank. I see you have great answers for both problems : )
    It's on my project list for next year.



  • Great idea to hide the water reservoir in a christmas package
    I would recommend to use an old car 12V windshield washer reservoir, as it already have pump and hose, and some have a low level indicator so you can be notified when you need to add water 🙂



  • @bjacobse 🙂 That's a great idea! Do you know what kind of flow a windshield washer would give? I looked for other pumps which i rejected due to their high flow (I'd expect even 1-2 liters per minute would be a bit too agressive with lots of water on the floor)



  • Just a follow-up 2 years later... Still no water incidents and the simple watersensor still looks surprisingly good! A very satisfying feeling for the third year in a row to just fill the bucket with water and plug it in and it just works 🙂

    The biggest problem now is that it's become harder to argue with the kids that we need to get rid of the spruce tree as it loses very little needles...


Log in to reply
 

Suggested Topics

  • 8
  • 90
  • 1
  • 1
  • 1
  • 3

1
Online

11.4k
Users

11.1k
Topics

112.7k
Posts