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

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Troubleshooting
  3. Sketch problems.... I think

Sketch problems.... I think

Scheduled Pinned Locked Moved Troubleshooting
5 Posts 3 Posters 89 Views 3 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.
  • J Offline
    J Offline
    JCH
    wrote on last edited by JCH
    #1

    I am trying to create a outdoor weather station which runs on batterys.
    I am having issues with the light level readings.... they were working fine now all of a sudden they arent.
    I am pretty sure that it is an issue with my sketch but i cant find any problems?? Am i missing something??

    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * Version 1.0 - Henrik Ekblad
     * 
     * DESCRIPTION
     * Pressure sensor example using BMP085 module  
     * http://www.mysensors.org/build/pressure
     *
     */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    #define MY_NODE_ID 5
    
    #include <SPI.h>
    #include <MySensors.h>  
    #include <Wire.h>
    #include <Adafruit_BMP085.h>
    #include <DHT.h>
    
    #define DHT_DATA_PIN 2
    #define LIGHT_SENSOR_ANALOG_PIN 1
    #define LUX_ON 5
    
    #define POWER_ON 1  //  value to write to turn on sensor
    #define POWER_OFF 0 //  value to write to turn off sensor
    
    #define BARO_CHILD 0
    #define TEMP_CHILD 1
    #define VOLTAGE_CHILD_ID 3
    #define CHILD_ID_HUM 4
    #define CHILD_ID_LIGHT 5
    
    
    static const uint64_t UPDATE_INTERVAL = 30000;
    static const uint8_t FORCE_UPDATE_N_READS = 10;
    
    int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
    
    int oldBatteryPcnt = 0;
    
    const float ALTITUDE = 59; // <-- adapt this value to your own location's altitude.
    
    // Sleep time between reads (in seconds). Do not change this value as the forecast algorithm needs a sample every minute.
    const unsigned long SLEEP_TIME = 60000; 
    
    const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
    enum FORECAST
    {
      STABLE = 0,     // "Stable Weather Pattern"
      SUNNY = 1,      // "Slowly rising Good Weather", "Clear/Sunny "
      CLOUDY = 2,     // "Slowly falling L-Pressure ", "Cloudy/Rain "
      UNSTABLE = 3,   // "Quickly rising H-Press",     "Not Stable"
      THUNDERSTORM = 4, // "Quickly falling L-Press",    "Thunderstorm"
      UNKNOWN = 5     // "Unknown (More Time needed)
    };
    
    Adafruit_BMP085 bmp = Adafruit_BMP085();      // Digital Pressure Sensor 
    
    float lastPressure = -1;
    float lastTemp = -1;
    int lastForecast = -1;
    
    //float lastTemp;
    float lastHum;
    uint8_t nNoUpdatesTemp;
    uint8_t nNoUpdatesHum;
    //bool metric = true;
    
    const int LAST_SAMPLES_COUNT = 5;
    float lastPressureSamples[LAST_SAMPLES_COUNT];
    
    // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
    // get kPa/h be dividing hPa by 10 
    #define CONVERSION_FACTOR (1.0/10.0)
    
    int minuteCount = 0;
    bool firstRound = true;
    // average value is used in forecast algorithm.
    float pressureAvg;
    // average after 2 hours is used as reference value for the next iteration.
    float pressureAvg2;
    
    float dP_dt;
    bool metric;
    MyMessage tempMsg(TEMP_CHILD, V_TEMP);
    MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
    MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
    MyMessage voltageMsg(VOLTAGE_CHILD_ID, V_VOLTAGE);
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    DHT dht;
    MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
    int lastLightLevel;
    
    
    
    
    
    
    
    
    void setup() 
    {
    //Serial.println("Setting Pin Mode to Output");
    //pinMode(LUX_ON, OUTPUT);
        
    Serial.println("Setup Sensor");
      
      dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
      if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
        Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
      }
      // Sleep for the time of the minimum sampling period to give the sensor time to power up
      // (otherwise, timeout errors might occure for the first reading)
      sleep(dht.getMinimumSamplingPeriod());
      {
        // use the 1.1 V internal reference
    #if defined(__AVR_ATmega2560__)
        analogReference(INTERNAL1V1);
    #else
        analogReference(INTERNAL);
    #endif
    }
      
      if (!bmp.begin()) 
      {
        Serial.println("Could not find a valid BMP085 sensor, check wiring!");
        while (1) {}
      }
      metric = getConfig().isMetric;
    }
    
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Pressure Sensor", "1.1");
    Serial.println("Present sensors to gateway");
      // Register sensors to gw (they will be created as child devices)
      present(BARO_CHILD, S_BARO);
      present(TEMP_CHILD, S_TEMP);
      present(VOLTAGE_CHILD_ID, S_MULTIMETER, "Battery " );
      present(CHILD_ID_HUM, S_HUM);
      present(CHILD_ID_LIGHT, S_LIGHT_LEVEL);  
    
     // metric = getConfig().isMetric;
    
    
    }
    
    
    void loop() 
    
    {
        int16_t lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23;
            Serial.println("LUX:");
        Serial.println(lightLevel);
        if (lightLevel != lastLightLevel) {
            send(msg.set(lightLevel));
            lastLightLevel = lightLevel;
        }
        sleep(5000);
        
        Serial.println("Humidity");
      
      // Force reading sensor, so it works also after sleep()
      dht.readSensor(true);
      
    
      // Get humidity from DHT library
      float humidity = dht.getHumidity();
      if (isnan(humidity)) {
        Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
        // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
        lastHum = humidity;
        // Reset no updates counter
        nNoUpdatesHum = 0;
        send(msgHum.set(humidity, 1));
        
       #ifdef MY_DEBUG
        Serial.print("H: ");
        Serial.println(humidity);
       #endif
      } else {
        // Increase no update counter if the humidity stayed the same
        nNoUpdatesHum++;
      }
    
      // Sleep for a while to save energy
      //sleep(UPDATE_INTERVAL); 
     {
        // get the battery Voltage
        int sensorValue = analogRead(BATTERY_SENSE_PIN);
    #ifdef MY_DEBUG
        Serial.println(sensorValue);
    #endif
    
        // 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+470e3)/470e3)*1.1 = Vmax = 3.44 Volts
        // 3.44/1023 = Volts per bit = 0.003363075
    
        int batteryPcnt = sensorValue / 10;
    
    #ifdef MY_DEBUG
        float batteryV  = sensorValue * 0.003363075;
        float voltage = sensorValue * 0.003363075;
        Serial.print("Battery Voltage: ");
        Serial.print(batteryV);
        Serial.println(" V");
    
        Serial.print("Battery percent: ");
        Serial.print(batteryPcnt);
        Serial.println(" %");
    #endif
    
        if (oldBatteryPcnt != batteryPcnt) {
            // Power up radio after sleep
            sendBatteryLevel(batteryPcnt);
            oldBatteryPcnt = batteryPcnt;
            send(voltageMsg.set(voltage,2));
        }
    //    sleep(SLEEP_TIME);
    }
      
      float pressure = bmp.readSealevelPressure(ALTITUDE) / 100.0;
      float temperature = bmp.readTemperature();
    
      if (!metric) 
      {
        // Convert to fahrenheit
        temperature = temperature * 9.0 / 5.0 + 32.0;
      }
    
      int forecast = sample(pressure);
    
      Serial.print("Temperature = ");
      Serial.print(temperature);
      Serial.println(metric ? " *C" : " *F");
      Serial.print("Pressure = ");
      Serial.print(pressure);
      Serial.println(" hPa");
      Serial.print("Forecast = ");
      Serial.println(weather[forecast]);
    
    
      if (temperature != lastTemp) 
      {
        send(tempMsg.set(temperature, 1));
        lastTemp = temperature;
      }
    
      if (pressure != lastPressure) 
      {
        send(pressureMsg.set(pressure, 0));
        lastPressure = pressure;
      }
    
      if (forecast != lastForecast)
      {
        send(forecastMsg.set(weather[forecast]));
        lastForecast = forecast;
      }
    
      sleep(SLEEP_TIME);
    }
    
    float getLastPressureSamplesAverage()
    {
      float lastPressureSamplesAverage = 0;
      for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
      {
        lastPressureSamplesAverage += lastPressureSamples[i];
      }
      lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
    
      return lastPressureSamplesAverage;
    }
    
    
    
    // Algorithm found here
    // http://www.freescale.com/files/sensors/doc/app_note/AN3914.pdf
    // Pressure in hPa -->  forecast done by calculating kPa/h
    int sample(float pressure)
    {
      // Calculate the average of the last n minutes.
      int index = minuteCount % LAST_SAMPLES_COUNT;
      lastPressureSamples[index] = pressure;
    
      minuteCount++;
      if (minuteCount > 185)
      {
        minuteCount = 6;
      }
    
      if (minuteCount == 5)
      {
        pressureAvg = getLastPressureSamplesAverage();
      }
      else if (minuteCount == 35)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change * 2; // note this is for t = 0.5hour
        }
        else
        {
          dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
        }
      }
      else if (minuteCount == 65)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) //first time initial 3 hour
        {
          dP_dt = change; //note this is for t = 1 hour
        }
        else
        {
          dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 95)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 1.5; // note this is for t = 1.5 hour
        }
        else
        {
          dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 125)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        pressureAvg2 = lastPressureAvg; // store for later use.
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 2; // note this is for t = 2 hour
        }
        else
        {
          dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 155)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 2.5; // note this is for t = 2.5 hour
        }
        else
        {
          dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
        }
      }
      else if (minuteCount == 185)
      {
        float lastPressureAvg = getLastPressureSamplesAverage();
        float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
        if (firstRound) // first time initial 3 hour
        {
          dP_dt = change / 3; // note this is for t = 3 hour
        }
        else
        {
          dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
        }
        pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
        firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
      }
    
      int forecast = UNKNOWN;
      if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
      {
        forecast = UNKNOWN;
      }
      else if (dP_dt < (-0.25))
      {
        forecast = THUNDERSTORM;
      }
      else if (dP_dt > 0.25)
      {
        forecast = UNSTABLE;
      }
      else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
      {
        forecast = CLOUDY;
      }
      else if ((dP_dt > 0.05) && (dP_dt < 0.25))
      {
        forecast = SUNNY;
      }
      else if ((dP_dt >(-0.05)) && (dP_dt < 0.05))
      {
        forecast = STABLE;
      }
      else
      {
        forecast = UNKNOWN;
      }
    
      // uncomment when debugging
      Serial.print(F("Forecast at minute "));
      Serial.print(minuteCount);
      Serial.print(F(" dP/dt = "));
      Serial.print(dP_dt);
      Serial.print(F("kPa/h --> "));
      Serial.println(weather[forecast]);
    
      return forecast;
    }
    

    EDIT: ignore the commented out sections.. i was playing around with powering the sensor off an arduino pin so try and save on power :)

    1 Reply Last reply
    0
    • MasMatM Offline
      MasMatM Offline
      MasMat
      wrote on last edited by
      #2

      I dont know what controller you are using but I had similar problems with domoticz when presenting s_light_level and V_Level vs v_light_level. It had to do with domoticz update.

      Thats what came to mind. I didnt find a sketch problem if this wasn't part of your problem.

      1 Reply Last reply
      1
      • J Offline
        J Offline
        JCH
        wrote on last edited by
        #3

        Turns out i had a bad battery...... Must of shorted internally and was causing my arduino to go crazy :ghost:.
        Node is up and running and reporting perfectly. Power consumption is approx 220uA.
        Reporting temp, humidity, light level , barometer, forecast and battery level.
        Here is the code if anyone wants..................

        /**
        OUTDOOR WEATHER STATION SKETCH
        TEMP AND PRESSURE VIA BMP180
        HUMIDITY VIA DHT22
        LIGHT SENSOR VIA LM393
        SOIL MOISTURE VIA SOIL MOISTURE SENSOR
        
        CREATED BY J.H 4.3.2020
        
        REV 2
         *
         */
        
        // Enable debug prints to serial monitor
        #define MY_DEBUG 
        
        // Enable and select radio type attached
        #define MY_RADIO_NRF24
        
        // Define Node ID
        #define MY_NODE_ID 5
        
        // Includes
        #include <SPI.h>
        #include <MySensors.h>  
        #include <Wire.h>
        #include <Adafruit_BMP085.h>
        #include <DHT.h>
        
        // Pin Defines
        #define DHT_DATA_PIN 2
        #define LIGHT_SENSOR_ANALOG_PIN 1
        #define LUX_ON 5
        
        // Defines
        #define POWER_ON 1  //  value to write to turn on sensor
        #define POWER_OFF 0 //  value to write to turn off sensor
        
        #define BARO_CHILD 0
        #define TEMP_CHILD 1
        #define VOLTAGE_CHILD_ID 3
        #define CHILD_ID_HUM 4
        #define CHILD_ID_LIGHT 5
        
        
        static const uint64_t UPDATE_INTERVAL = 30000;
        static const uint8_t FORCE_UPDATE_N_READS = 10;
        
        int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
        
        int oldBatteryPcnt = 0;
        
        const float ALTITUDE = 59; // <-- adapt this value to your own location's altitude.
        
        // Sleep time between reads (in seconds). Do not change this value as the forecast algorithm needs a sample every minute.
        const unsigned long SLEEP_TIME = 60000; 
        
        const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
        enum FORECAST
        {
          STABLE = 0,     // "Stable Weather Pattern"
          SUNNY = 1,      // "Slowly rising Good Weather", "Clear/Sunny "
          CLOUDY = 2,     // "Slowly falling L-Pressure ", "Cloudy/Rain "
          UNSTABLE = 3,   // "Quickly rising H-Press",     "Not Stable"
          THUNDERSTORM = 4, // "Quickly falling L-Press",    "Thunderstorm"
          UNKNOWN = 5     // "Unknown (More Time needed)
        };
        
        Adafruit_BMP085 bmp = Adafruit_BMP085();      // Digital Pressure Sensor 
        
        float lastPressure = -1;
        float lastTemp = -1;
        int lastForecast = -1;
        
        //float lastTemp;
        float lastHum;
        uint8_t nNoUpdatesTemp;
        uint8_t nNoUpdatesHum;
        //bool metric = true;
        
        const int LAST_SAMPLES_COUNT = 5;
        float lastPressureSamples[LAST_SAMPLES_COUNT];
        
        // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
        // get kPa/h be dividing hPa by 10 
        #define CONVERSION_FACTOR (1.0/10.0)
        
        int minuteCount = 0;
        bool firstRound = true;
        // average value is used in forecast algorithm.
        float pressureAvg;
        // average after 2 hours is used as reference value for the next iteration.
        float pressureAvg2;
        
        float dP_dt;
        bool metric;
        MyMessage tempMsg(TEMP_CHILD, V_TEMP);
        MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
        MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
        MyMessage voltageMsg(VOLTAGE_CHILD_ID, V_VOLTAGE);
        MyMessage msgHum(CHILD_ID_HUM, V_HUM);
        DHT dht;
        MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
        int lastLightLevel;
        
        
        
        
        
        
        
        
        void setup() 
        {
        //Serial.println("Setting Pin Mode to Output");
        //pinMode(LUX_ON, OUTPUT);
            
        Serial.println("Setup Sensor");
          
          dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
          if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
            Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
          }
          // Sleep for the time of the minimum sampling period to give the sensor time to power up
          // (otherwise, timeout errors might occure for the first reading)
          sleep(dht.getMinimumSamplingPeriod());
          {
            // use the 1.1 V internal reference
        #if defined(__AVR_ATmega2560__)
            analogReference(INTERNAL1V1);
        #else
            analogReference(INTERNAL);
        #endif
        }
          
          if (!bmp.begin()) 
          {
            Serial.println("Could not find a valid BMP085 sensor, check wiring!");
            while (1) {}
          }
          metric = getConfig().isMetric;
        }
        
        void presentation()  {
          // Send the sketch version information to the gateway and Controller
          sendSketchInfo("Pressure Sensor", "1.1");
        Serial.println("Present sensors to gateway");
          // Register sensors to gw (they will be created as child devices)
          present(BARO_CHILD, S_BARO, "Pressure" );
          present(TEMP_CHILD, S_TEMP, "Temperature" );
          present(VOLTAGE_CHILD_ID, S_MULTIMETER, "Battery" );
          present(CHILD_ID_HUM, S_HUM, "Humidity" );
          present(CHILD_ID_LIGHT, S_LIGHT_LEVEL, "Lux" );  
        
         // metric = getConfig().isMetric; 
        
        
        }
        
        
        void loop() 
        
        {
          ////////////////////////////////////////
          ////////// Lux Sensor Code /////////////
          ////////////////////////////////////////
          
            digitalWrite(LUX_ON, POWER_ON); // Power the Lux sensor of Digital Pin to save power
            Serial.print("Sensor Power on pin "); Serial.print(LUX_ON); Serial.print(" is..."); Serial.println((POWER_ON));
            wait(1000); // Wait a second for sensor to power up before reading
            
            int16_t lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23;
                Serial.println("Light Lux Level:");
            Serial.println(lightLevel);
            if (lightLevel != lastLightLevel) {
                send(msg.set(lightLevel));
                lastLightLevel = lightLevel;
        
           digitalWrite(LUX_ON, POWER_OFF); // turn it off
           Serial.print("Sensor Power on pin "); Serial.print(LUX_ON); Serial.print(" is..."); Serial.println((POWER_OFF));
            }
            wait(1000);
        
          ////////////////////////////////////////
          ////////// DHT22 Sensor Code ///////////
          ////////////////////////////////////////
          
          // Force reading sensor, so it works also after sleep()
          dht.readSensor(true);
          
        
          // Get humidity from DHT library
          float humidity = dht.getHumidity();
          if (isnan(humidity)) {
            Serial.println("Failed reading humidity from DHT");
          } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
            // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
            lastHum = humidity;
            // Reset no updates counter
            nNoUpdatesHum = 0;
            send(msgHum.set(humidity, 1));
            
           #ifdef MY_DEBUG
            Serial.print("Humidity: ");
            Serial.println(humidity);
           #endif
          } else {
            // Increase no update counter if the humidity stayed the same
            nNoUpdatesHum++;
          }
        
          // Sleep for a while to save energy
          //sleep(UPDATE_INTERVAL); 
         {
          /////////////////////////////////////////////
          ////////// Battery Reporting Code ///////////
          /////////////////////////////////////////////
          
            // get the battery Voltage
            int sensorValue = analogRead(BATTERY_SENSE_PIN);
        #ifdef MY_DEBUG
            Serial.println(sensorValue);
        #endif
        
            // 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+470e3)/470e3)*1.1 = Vmax = 3.44 Volts
            // 3.44/1023 = Volts per bit = 0.003363075
        
            int batteryPcnt = sensorValue / 10;
        
        #ifdef MY_DEBUG
            float batteryV  = sensorValue * 0.003363075;
            float voltage = sensorValue * 0.003363075;
            Serial.print("Battery Voltage: ");
            Serial.print(batteryV);
            Serial.println(" V");
        
            Serial.print("Battery percent: ");
            Serial.print(batteryPcnt);
            Serial.println(" %");
        #endif
        
            if (oldBatteryPcnt != batteryPcnt) {
                // Power up radio after sleep
                sendBatteryLevel(batteryPcnt);
                oldBatteryPcnt = batteryPcnt;
                send(voltageMsg.set(voltage,2));
            }
        //    sleep(SLEEP_TIME);
        }
          //////////////////////////////////////////////////
          ////////// BMP180 Pressure Sensor Code ///////////
          //////////////////////////////////////////////////
          
          float pressure = bmp.readSealevelPressure(ALTITUDE) / 100.0;
          float temperature = bmp.readTemperature();
        
          if (!metric) 
          {
            // Convert to fahrenheit
            temperature = temperature * 9.0 / 5.0 + 32.0;
          }
        
          int forecast = sample(pressure);
        
          Serial.print("Temperature = ");
          Serial.print(temperature);
          Serial.println(metric ? " *C" : " *F");
          Serial.print("Pressure = ");
          Serial.print(pressure);
          Serial.println(" hPa");
          Serial.print("Forecast = ");
          Serial.println(weather[forecast]);
        
        
          if (temperature != lastTemp) 
          {
            send(tempMsg.set(temperature, 1));
            lastTemp = temperature;
          }
        
          if (pressure != lastPressure) 
          {
            send(pressureMsg.set(pressure, 0));
            lastPressure = pressure;
          }
        
          if (forecast != lastForecast)
          {
            send(forecastMsg.set(weather[forecast]));
            lastForecast = forecast;
          }
        
          sleep(SLEEP_TIME);
        }
        
        float getLastPressureSamplesAverage()
        {
          float lastPressureSamplesAverage = 0;
          for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
          {
            lastPressureSamplesAverage += lastPressureSamples[i];
          }
          lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
        
          return lastPressureSamplesAverage;
        }
        
        
        
          //////////////////////////////////////////
          ////////// Forecast Algorithm ///////////
          /////////////////////////////////////////
          
        int sample(float pressure)
        {
          // Calculate the average of the last n minutes.
          int index = minuteCount % LAST_SAMPLES_COUNT;
          lastPressureSamples[index] = pressure;
        
          minuteCount++;
          if (minuteCount > 185)
          {
            minuteCount = 6;
          }
        
          if (minuteCount == 5)
          {
            pressureAvg = getLastPressureSamplesAverage();
          }
          else if (minuteCount == 35)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change * 2; // note this is for t = 0.5hour
            }
            else
            {
              dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
            }
          }
          else if (minuteCount == 65)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) //first time initial 3 hour
            {
              dP_dt = change; //note this is for t = 1 hour
            }
            else
            {
              dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 95)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 1.5; // note this is for t = 1.5 hour
            }
            else
            {
              dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 125)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            pressureAvg2 = lastPressureAvg; // store for later use.
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 2; // note this is for t = 2 hour
            }
            else
            {
              dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 155)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 2.5; // note this is for t = 2.5 hour
            }
            else
            {
              dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
            }
          }
          else if (minuteCount == 185)
          {
            float lastPressureAvg = getLastPressureSamplesAverage();
            float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
            if (firstRound) // first time initial 3 hour
            {
              dP_dt = change / 3; // note this is for t = 3 hour
            }
            else
            {
              dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
            }
            pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
            firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
          }
        
          int forecast = UNKNOWN;
          if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
          {
            forecast = UNKNOWN;
          }
          else if (dP_dt < (-0.25))
          {
            forecast = THUNDERSTORM;
          }
          else if (dP_dt > 0.25)
          {
            forecast = UNSTABLE;
          }
          else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
          {
            forecast = CLOUDY;
          }
          else if ((dP_dt > 0.05) && (dP_dt < 0.25))
          {
            forecast = SUNNY;
          }
          else if ((dP_dt >(-0.05)) && (dP_dt < 0.05))
          {
            forecast = STABLE;
          }
          else
          {
            forecast = UNKNOWN;
          }
        
          // uncomment when debugging
          Serial.print(F("Forecast at minute "));
          Serial.print(minuteCount);
          Serial.print(F(" dP/dt = "));
          Serial.print(dP_dt);
          Serial.print(F("kPa/h --> "));
          Serial.println(weather[forecast]);
        
          return forecast;
        }
        
        mfalkviddM 1 Reply Last reply
        1
        • J JCH

          Turns out i had a bad battery...... Must of shorted internally and was causing my arduino to go crazy :ghost:.
          Node is up and running and reporting perfectly. Power consumption is approx 220uA.
          Reporting temp, humidity, light level , barometer, forecast and battery level.
          Here is the code if anyone wants..................

          /**
          OUTDOOR WEATHER STATION SKETCH
          TEMP AND PRESSURE VIA BMP180
          HUMIDITY VIA DHT22
          LIGHT SENSOR VIA LM393
          SOIL MOISTURE VIA SOIL MOISTURE SENSOR
          
          CREATED BY J.H 4.3.2020
          
          REV 2
           *
           */
          
          // Enable debug prints to serial monitor
          #define MY_DEBUG 
          
          // Enable and select radio type attached
          #define MY_RADIO_NRF24
          
          // Define Node ID
          #define MY_NODE_ID 5
          
          // Includes
          #include <SPI.h>
          #include <MySensors.h>  
          #include <Wire.h>
          #include <Adafruit_BMP085.h>
          #include <DHT.h>
          
          // Pin Defines
          #define DHT_DATA_PIN 2
          #define LIGHT_SENSOR_ANALOG_PIN 1
          #define LUX_ON 5
          
          // Defines
          #define POWER_ON 1  //  value to write to turn on sensor
          #define POWER_OFF 0 //  value to write to turn off sensor
          
          #define BARO_CHILD 0
          #define TEMP_CHILD 1
          #define VOLTAGE_CHILD_ID 3
          #define CHILD_ID_HUM 4
          #define CHILD_ID_LIGHT 5
          
          
          static const uint64_t UPDATE_INTERVAL = 30000;
          static const uint8_t FORCE_UPDATE_N_READS = 10;
          
          int BATTERY_SENSE_PIN = A0;  // select the input pin for the battery sense point
          
          int oldBatteryPcnt = 0;
          
          const float ALTITUDE = 59; // <-- adapt this value to your own location's altitude.
          
          // Sleep time between reads (in seconds). Do not change this value as the forecast algorithm needs a sample every minute.
          const unsigned long SLEEP_TIME = 60000; 
          
          const char *weather[] = { "stable", "sunny", "cloudy", "unstable", "thunderstorm", "unknown" };
          enum FORECAST
          {
            STABLE = 0,     // "Stable Weather Pattern"
            SUNNY = 1,      // "Slowly rising Good Weather", "Clear/Sunny "
            CLOUDY = 2,     // "Slowly falling L-Pressure ", "Cloudy/Rain "
            UNSTABLE = 3,   // "Quickly rising H-Press",     "Not Stable"
            THUNDERSTORM = 4, // "Quickly falling L-Press",    "Thunderstorm"
            UNKNOWN = 5     // "Unknown (More Time needed)
          };
          
          Adafruit_BMP085 bmp = Adafruit_BMP085();      // Digital Pressure Sensor 
          
          float lastPressure = -1;
          float lastTemp = -1;
          int lastForecast = -1;
          
          //float lastTemp;
          float lastHum;
          uint8_t nNoUpdatesTemp;
          uint8_t nNoUpdatesHum;
          //bool metric = true;
          
          const int LAST_SAMPLES_COUNT = 5;
          float lastPressureSamples[LAST_SAMPLES_COUNT];
          
          // this CONVERSION_FACTOR is used to convert from Pa to kPa in forecast algorithm
          // get kPa/h be dividing hPa by 10 
          #define CONVERSION_FACTOR (1.0/10.0)
          
          int minuteCount = 0;
          bool firstRound = true;
          // average value is used in forecast algorithm.
          float pressureAvg;
          // average after 2 hours is used as reference value for the next iteration.
          float pressureAvg2;
          
          float dP_dt;
          bool metric;
          MyMessage tempMsg(TEMP_CHILD, V_TEMP);
          MyMessage pressureMsg(BARO_CHILD, V_PRESSURE);
          MyMessage forecastMsg(BARO_CHILD, V_FORECAST);
          MyMessage voltageMsg(VOLTAGE_CHILD_ID, V_VOLTAGE);
          MyMessage msgHum(CHILD_ID_HUM, V_HUM);
          DHT dht;
          MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
          int lastLightLevel;
          
          
          
          
          
          
          
          
          void setup() 
          {
          //Serial.println("Setting Pin Mode to Output");
          //pinMode(LUX_ON, OUTPUT);
              
          Serial.println("Setup Sensor");
            
            dht.setup(DHT_DATA_PIN); // set data pin of DHT sensor
            if (UPDATE_INTERVAL <= dht.getMinimumSamplingPeriod()) {
              Serial.println("Warning: UPDATE_INTERVAL is smaller than supported by the sensor!");
            }
            // Sleep for the time of the minimum sampling period to give the sensor time to power up
            // (otherwise, timeout errors might occure for the first reading)
            sleep(dht.getMinimumSamplingPeriod());
            {
              // use the 1.1 V internal reference
          #if defined(__AVR_ATmega2560__)
              analogReference(INTERNAL1V1);
          #else
              analogReference(INTERNAL);
          #endif
          }
            
            if (!bmp.begin()) 
            {
              Serial.println("Could not find a valid BMP085 sensor, check wiring!");
              while (1) {}
            }
            metric = getConfig().isMetric;
          }
          
          void presentation()  {
            // Send the sketch version information to the gateway and Controller
            sendSketchInfo("Pressure Sensor", "1.1");
          Serial.println("Present sensors to gateway");
            // Register sensors to gw (they will be created as child devices)
            present(BARO_CHILD, S_BARO, "Pressure" );
            present(TEMP_CHILD, S_TEMP, "Temperature" );
            present(VOLTAGE_CHILD_ID, S_MULTIMETER, "Battery" );
            present(CHILD_ID_HUM, S_HUM, "Humidity" );
            present(CHILD_ID_LIGHT, S_LIGHT_LEVEL, "Lux" );  
          
           // metric = getConfig().isMetric; 
          
          
          }
          
          
          void loop() 
          
          {
            ////////////////////////////////////////
            ////////// Lux Sensor Code /////////////
            ////////////////////////////////////////
            
              digitalWrite(LUX_ON, POWER_ON); // Power the Lux sensor of Digital Pin to save power
              Serial.print("Sensor Power on pin "); Serial.print(LUX_ON); Serial.print(" is..."); Serial.println((POWER_ON));
              wait(1000); // Wait a second for sensor to power up before reading
              
              int16_t lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23;
                  Serial.println("Light Lux Level:");
              Serial.println(lightLevel);
              if (lightLevel != lastLightLevel) {
                  send(msg.set(lightLevel));
                  lastLightLevel = lightLevel;
          
             digitalWrite(LUX_ON, POWER_OFF); // turn it off
             Serial.print("Sensor Power on pin "); Serial.print(LUX_ON); Serial.print(" is..."); Serial.println((POWER_OFF));
              }
              wait(1000);
          
            ////////////////////////////////////////
            ////////// DHT22 Sensor Code ///////////
            ////////////////////////////////////////
            
            // Force reading sensor, so it works also after sleep()
            dht.readSensor(true);
            
          
            // Get humidity from DHT library
            float humidity = dht.getHumidity();
            if (isnan(humidity)) {
              Serial.println("Failed reading humidity from DHT");
            } else if (humidity != lastHum || nNoUpdatesHum == FORCE_UPDATE_N_READS) {
              // Only send humidity if it changed since the last measurement or if we didn't send an update for n times
              lastHum = humidity;
              // Reset no updates counter
              nNoUpdatesHum = 0;
              send(msgHum.set(humidity, 1));
              
             #ifdef MY_DEBUG
              Serial.print("Humidity: ");
              Serial.println(humidity);
             #endif
            } else {
              // Increase no update counter if the humidity stayed the same
              nNoUpdatesHum++;
            }
          
            // Sleep for a while to save energy
            //sleep(UPDATE_INTERVAL); 
           {
            /////////////////////////////////////////////
            ////////// Battery Reporting Code ///////////
            /////////////////////////////////////////////
            
              // get the battery Voltage
              int sensorValue = analogRead(BATTERY_SENSE_PIN);
          #ifdef MY_DEBUG
              Serial.println(sensorValue);
          #endif
          
              // 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+470e3)/470e3)*1.1 = Vmax = 3.44 Volts
              // 3.44/1023 = Volts per bit = 0.003363075
          
              int batteryPcnt = sensorValue / 10;
          
          #ifdef MY_DEBUG
              float batteryV  = sensorValue * 0.003363075;
              float voltage = sensorValue * 0.003363075;
              Serial.print("Battery Voltage: ");
              Serial.print(batteryV);
              Serial.println(" V");
          
              Serial.print("Battery percent: ");
              Serial.print(batteryPcnt);
              Serial.println(" %");
          #endif
          
              if (oldBatteryPcnt != batteryPcnt) {
                  // Power up radio after sleep
                  sendBatteryLevel(batteryPcnt);
                  oldBatteryPcnt = batteryPcnt;
                  send(voltageMsg.set(voltage,2));
              }
          //    sleep(SLEEP_TIME);
          }
            //////////////////////////////////////////////////
            ////////// BMP180 Pressure Sensor Code ///////////
            //////////////////////////////////////////////////
            
            float pressure = bmp.readSealevelPressure(ALTITUDE) / 100.0;
            float temperature = bmp.readTemperature();
          
            if (!metric) 
            {
              // Convert to fahrenheit
              temperature = temperature * 9.0 / 5.0 + 32.0;
            }
          
            int forecast = sample(pressure);
          
            Serial.print("Temperature = ");
            Serial.print(temperature);
            Serial.println(metric ? " *C" : " *F");
            Serial.print("Pressure = ");
            Serial.print(pressure);
            Serial.println(" hPa");
            Serial.print("Forecast = ");
            Serial.println(weather[forecast]);
          
          
            if (temperature != lastTemp) 
            {
              send(tempMsg.set(temperature, 1));
              lastTemp = temperature;
            }
          
            if (pressure != lastPressure) 
            {
              send(pressureMsg.set(pressure, 0));
              lastPressure = pressure;
            }
          
            if (forecast != lastForecast)
            {
              send(forecastMsg.set(weather[forecast]));
              lastForecast = forecast;
            }
          
            sleep(SLEEP_TIME);
          }
          
          float getLastPressureSamplesAverage()
          {
            float lastPressureSamplesAverage = 0;
            for (int i = 0; i < LAST_SAMPLES_COUNT; i++)
            {
              lastPressureSamplesAverage += lastPressureSamples[i];
            }
            lastPressureSamplesAverage /= LAST_SAMPLES_COUNT;
          
            return lastPressureSamplesAverage;
          }
          
          
          
            //////////////////////////////////////////
            ////////// Forecast Algorithm ///////////
            /////////////////////////////////////////
            
          int sample(float pressure)
          {
            // Calculate the average of the last n minutes.
            int index = minuteCount % LAST_SAMPLES_COUNT;
            lastPressureSamples[index] = pressure;
          
            minuteCount++;
            if (minuteCount > 185)
            {
              minuteCount = 6;
            }
          
            if (minuteCount == 5)
            {
              pressureAvg = getLastPressureSamplesAverage();
            }
            else if (minuteCount == 35)
            {
              float lastPressureAvg = getLastPressureSamplesAverage();
              float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
              if (firstRound) // first time initial 3 hour
              {
                dP_dt = change * 2; // note this is for t = 0.5hour
              }
              else
              {
                dP_dt = change / 1.5; // divide by 1.5 as this is the difference in time from 0 value.
              }
            }
            else if (minuteCount == 65)
            {
              float lastPressureAvg = getLastPressureSamplesAverage();
              float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
              if (firstRound) //first time initial 3 hour
              {
                dP_dt = change; //note this is for t = 1 hour
              }
              else
              {
                dP_dt = change / 2; //divide by 2 as this is the difference in time from 0 value
              }
            }
            else if (minuteCount == 95)
            {
              float lastPressureAvg = getLastPressureSamplesAverage();
              float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
              if (firstRound) // first time initial 3 hour
              {
                dP_dt = change / 1.5; // note this is for t = 1.5 hour
              }
              else
              {
                dP_dt = change / 2.5; // divide by 2.5 as this is the difference in time from 0 value
              }
            }
            else if (minuteCount == 125)
            {
              float lastPressureAvg = getLastPressureSamplesAverage();
              pressureAvg2 = lastPressureAvg; // store for later use.
              float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
              if (firstRound) // first time initial 3 hour
              {
                dP_dt = change / 2; // note this is for t = 2 hour
              }
              else
              {
                dP_dt = change / 3; // divide by 3 as this is the difference in time from 0 value
              }
            }
            else if (minuteCount == 155)
            {
              float lastPressureAvg = getLastPressureSamplesAverage();
              float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
              if (firstRound) // first time initial 3 hour
              {
                dP_dt = change / 2.5; // note this is for t = 2.5 hour
              }
              else
              {
                dP_dt = change / 3.5; // divide by 3.5 as this is the difference in time from 0 value
              }
            }
            else if (minuteCount == 185)
            {
              float lastPressureAvg = getLastPressureSamplesAverage();
              float change = (lastPressureAvg - pressureAvg) * CONVERSION_FACTOR;
              if (firstRound) // first time initial 3 hour
              {
                dP_dt = change / 3; // note this is for t = 3 hour
              }
              else
              {
                dP_dt = change / 4; // divide by 4 as this is the difference in time from 0 value
              }
              pressureAvg = pressureAvg2; // Equating the pressure at 0 to the pressure at 2 hour after 3 hours have past.
              firstRound = false; // flag to let you know that this is on the past 3 hour mark. Initialized to 0 outside main loop.
            }
          
            int forecast = UNKNOWN;
            if (minuteCount < 35 && firstRound) //if time is less than 35 min on the first 3 hour interval.
            {
              forecast = UNKNOWN;
            }
            else if (dP_dt < (-0.25))
            {
              forecast = THUNDERSTORM;
            }
            else if (dP_dt > 0.25)
            {
              forecast = UNSTABLE;
            }
            else if ((dP_dt > (-0.25)) && (dP_dt < (-0.05)))
            {
              forecast = CLOUDY;
            }
            else if ((dP_dt > 0.05) && (dP_dt < 0.25))
            {
              forecast = SUNNY;
            }
            else if ((dP_dt >(-0.05)) && (dP_dt < 0.05))
            {
              forecast = STABLE;
            }
            else
            {
              forecast = UNKNOWN;
            }
          
            // uncomment when debugging
            Serial.print(F("Forecast at minute "));
            Serial.print(minuteCount);
            Serial.print(F(" dP/dt = "));
            Serial.print(dP_dt);
            Serial.print(F("kPa/h --> "));
            Serial.println(weather[forecast]);
          
            return forecast;
          }
          
          mfalkviddM Offline
          mfalkviddM Offline
          mfalkvidd
          Mod
          wrote on last edited by
          #4

          Great work @JCH, thanks for reporting back and for sharing the sketch.

          1 Reply Last reply
          0
          • J Offline
            J Offline
            JCH
            wrote on last edited by
            #5

            So after running this weather station for a few weeks i decided to switch out the lux sensor for a soil moisture sensor without modifying the code....
            The readings are working but they are very up and down.... they are not a steady decline..... how are people measuring the analog values of soil moisture ?

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


            26

            Online

            11.7k

            Users

            11.2k

            Topics

            113.1k

            Posts


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

            • Don't have an account? Register

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