Sketch problems.... I think



  • 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 🙂



  • 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.



  • Turns out i had a bad battery...... Must of shorted internally and was causing my arduino to go crazy 👻.
    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;
    }
    

  • Mod

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



  • 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 ?


Log in to reply
 

Suggested Topics

11
Online

11.4k
Users

11.1k
Topics

112.7k
Posts