diff --git a/firmware/weather_station.ino b/firmware/weather_station.ino index 76ce878..329c2bd 100644 --- a/firmware/weather_station.ino +++ b/firmware/weather_station.ino @@ -10,7 +10,7 @@ * BLINK : I2C ERROR * FLASH : Heartbeat * - * Copyright (C) 2023 M.T. Konstapel https://meezenest.nl/mees + * Copyright (C) 2023, 2024 M.T. Konstapel https://meezenest.nl/mees * * This file is part of weather_station * @@ -42,6 +42,7 @@ SI7021 si7021; // Pressure sensor #include "i2c_BMP280.h" BMP280 bmp280; +float PRESSURE_OFFSET = 210; // Calibration of BMP280: offset in Pascal /**************************/ /* Configurable variables */ @@ -128,30 +129,33 @@ void ReadSi7021 (void) si7021.triggerMeasurement(); si7021.getHumidity(MeasuredData.Humidity); si7021.getTemperature(MeasuredData.Temperature); - // Scale for more decimal positions when converted to integer value for ModBus - MeasuredData.Humidity *= 100; - MeasuredData.Temperature *= 100; - //If humidity is larger than 80% switch on heater to get more acurate measurement - //Switch off when lower than 78% (hysteresis) - if (MeasuredData.Humidity > 80 && !MeasuredData.HeaterStatus) { + if (MeasuredData.Humidity>100 || MeasuredData.Humidity<0) + MeasuredData.Humidity = 100; + + //If humidity is larger than 96% switch on heater to get more acurate measurement and prevent memory offset + //Switch off when lower than 94% (hysteresis) + if (MeasuredData.Humidity > 96 && !MeasuredData.HeaterStatus) { Serial.print(F("Heater on.")); MeasuredData.HeaterStatus = 1; si7021.setHeater(MeasuredData.HeaterStatus); } - if (MeasuredData.Humidity < 78 && MeasuredData.HeaterStatus) { + if (MeasuredData.Humidity < 94 && MeasuredData.HeaterStatus) { Serial.print(F("Heater off.")); MeasuredData.HeaterStatus = 0; si7021.setHeater(MeasuredData.HeaterStatus); } - + + // Scale for more decimal positions when converted to integer value for ModBus + MeasuredData.Humidity *= 100; + MeasuredData.Temperature *= 100; } // Read BMP280 void ReadBMP280 (void) { - MeasuredData.Pressure=0; -/* +// MeasuredData.Pressure=0; + bmp280.awaitMeasurement(); float temperature; @@ -160,10 +164,20 @@ void ReadBMP280 (void) float pascal; bmp280.getPressure(pascal); + pascal = (pascal - PRESSURE_OFFSET) / 10; // Convert to hPa + MeasuredData.Pressure = pascal; bmp280.triggerMeasurement(); -*/ + + // When humidity is high, the heater of the Si7021 is on. This causes the temperature sensor of the humidity sensor to heat up. + // Use temperature sensor of BMP280 instead. + if (MeasuredData.HeaterStatus) { + bmp280.getTemperature(MeasuredData.Temperature); + // Scale for more decimal positions when converted to integer value for ModBus + MeasuredData.Temperature *= 100; + } + } int MaxOfArray (int array[], unsigned int length) @@ -329,7 +343,7 @@ void setup() { } } -/* // Initialize BMP280 pressure sensor + // Initialize BMP280 pressure sensor Serial.print(F("Pressure sensor BMP280 ")); if (bmp280.initialize()) Serial.println(F("found")); @@ -347,7 +361,7 @@ void setup() { // onetime-measure: bmp280.setEnabled(0); bmp280.triggerMeasurement(); -*/ + // Expected ADC values have been defined for various platforms in the // library, however your platform may not be included. This code will check // if that's the case @@ -358,6 +372,61 @@ void setup() { // resolution, so you'll need to specify it here: weatherMeterKit.setADCResolutionBits(10); #endif + + // Here we create a struct to hold all the calibration parameters + SFEWeatherMeterKitCalibrationParams calibrationParams = weatherMeterKit.getCalibrationParams(); + + // The wind vane has 8 switches, but 2 could close at the same time, which + // results in 16 possible positions. Each position has a resistor connected + // to GND, so this library assumes a voltage divider is created by adding + // another resistor to VCC. Some of the wind vane resistor values are + // fairly close to each other, meaning an accurate ADC is required. However + // some ADCs have a non-linear behavior that causes this measurement to be + // inaccurate. To account for this, the vane resistor values can be manually + // changed here to compensate for the non-linear behavior of the ADC + calibrationParams.vaneADCValues[WMK_ANGLE_0_0] = 943; + calibrationParams.vaneADCValues[WMK_ANGLE_22_5] = 828; + calibrationParams.vaneADCValues[WMK_ANGLE_45_0] = 885; + calibrationParams.vaneADCValues[WMK_ANGLE_67_5] = 702; + calibrationParams.vaneADCValues[WMK_ANGLE_90_0] = 785; + calibrationParams.vaneADCValues[WMK_ANGLE_112_5] = 404; + calibrationParams.vaneADCValues[WMK_ANGLE_135_0] = 460; + calibrationParams.vaneADCValues[WMK_ANGLE_157_5] = 82; + calibrationParams.vaneADCValues[WMK_ANGLE_180_0] = 91; + calibrationParams.vaneADCValues[WMK_ANGLE_202_5] = 64; + calibrationParams.vaneADCValues[WMK_ANGLE_225_0] = 185; + calibrationParams.vaneADCValues[WMK_ANGLE_247_5] = 125; + calibrationParams.vaneADCValues[WMK_ANGLE_270_0] = 285; + calibrationParams.vaneADCValues[WMK_ANGLE_292_5] = 242; + calibrationParams.vaneADCValues[WMK_ANGLE_315_0] = 628; + calibrationParams.vaneADCValues[WMK_ANGLE_337_5] = 598; + + // The rainfall detector contains a small cup that collects rain water. When + // the cup fills, the water is dumped and the total rainfall is incremented + // by some value. This value defaults to 0.2794mm of rain per count, as + // specified by the datasheet + calibrationParams.mmPerRainfallCount = 0.2794; + + // The rainfall detector switch can sometimes bounce, causing multiple extra + // triggers. This input is debounced by ignoring extra triggers within a + // time window, which defaults to 100ms + calibrationParams.minMillisPerRainfall = 100; + + // The anemometer contains a switch that opens and closes as it spins. The + // rate at which the switch closes depends on the wind speed. The datasheet + // states that a wind of 2.4kph causes the switch to close once per second + calibrationParams.kphPerCountPerSec = 2.4; + + // Because the anemometer generates discrete pulses as it rotates, it's not + // possible to measure the wind speed exactly at any point in time. A filter + // is implemented in the library that averages the wind speed over a certain + // time period, which defaults to 1 second. Longer intervals result in more + // accurate measurements, but cause delay in the measurement + calibrationParams.windSpeedMeasurementPeriodMillis = 1000; + + // Now we can set all the calibration parameters at once + weatherMeterKit.setCalibrationParams(calibrationParams); + // Begin weather meter kit weatherMeterKit.begin(); @@ -396,6 +465,10 @@ void loop() { mb.Ireg (SensorHumidityIreg, MeasuredData.Humidity); mb.Ireg (SensorPressureIreg, MeasuredData.Pressure); + // Debug wind vane + //Serial.print(F("\n Measured ADC: ")); + //Serial.print(analogRead(windDirectionPin)); + digitalWrite(LED_BUILTIN, LOW); // LED as heartbeat