Skip to content

Commit

Permalink
Return old data if not ready upto some interval (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
dk307 committed Jul 29, 2023
1 parent 37b0cf1 commit 7f36b78
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 91 deletions.
2 changes: 1 addition & 1 deletion main/hardware/hardware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void hardware::sensor_task_ftn()
#endif
read_sps30_sensor();

vTaskDelay(pdMS_TO_TICKS(sensor_history::sensor_interval / 20));
vTaskDelay(pdMS_TO_TICKS(sensor_history::sensor_interval / 10));
} while (true);
}
catch (const std::exception &ex)
Expand Down
5 changes: 2 additions & 3 deletions main/hardware/hardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,12 @@ class hardware final : public esp32::singleton<hardware>

#ifdef CONFIG_SCD30_SENSOR_ENABLE
// SCD30
scd30_sensor_device &scd30_sensor_{
scd30_sensor_device::create_instance(static_cast<uint16_t>(sensor_history::sensor_interval / 1000), sensor_history::sensor_interval / 30)};
scd30_sensor_device &scd30_sensor_{scd30_sensor_device::create_instance()};
uint64_t scd30_sensor_last_read_ = 0;
#endif

// SPS 30
sps30_sensor_device &sps30_sensor_{sps30_sensor_device::create_instance(sensor_history::sensor_interval / 30)};
sps30_sensor_device &sps30_sensor_{sps30_sensor_device::create_instance()};
uint64_t sps30_sensor_last_read_ = 0;

// BH1750
Expand Down
36 changes: 36 additions & 0 deletions main/hardware/sensors/last_measurement_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include "util/misc.h"
#include <optional>
#include <type_traits>

template <class T, unsigned long max_interval_ms>
requires std::is_copy_assignable_v<T>
class last_measurement_helper
{
public:
constexpr static unsigned long max_value_interval_ms = max_interval_ms;

void store(const T &value)
{
last_measurement_value_ = value;
last_measurement_value_taken_ = esp32::millis();
}

bool update(T &value)
{
if ((esp32::millis() - last_measurement_value_taken_) <= max_interval_ms)
{
if (last_measurement_value_.has_value())
{
value = last_measurement_value_.value();
return true;
}
}
return false;
}

private:
std::optional<T> last_measurement_value_;
uint64_t last_measurement_value_taken_;
};
67 changes: 27 additions & 40 deletions main/hardware/sensors/scd30_sensor_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
void scd30_sensor_device::init()
{
CHECK_THROW_ESP(scd30_init_desc(&scd30_sensor_, I2C_NUM_1, SDAWire, SCLWire));
CHECK_THROW_ESP(scd30_set_measurement_interval(&scd30_sensor_, sensor_interval_s_ - 1));
CHECK_THROW_ESP(scd30_set_measurement_interval(&scd30_sensor_, (decltype(last_measurement_value_)::max_value_interval_ms / 1000) / 2));
CHECK_THROW_ESP(scd30_set_automatic_self_calibration(&scd30_sensor_, true));
}

Expand All @@ -24,60 +24,47 @@ std::array<std::tuple<sensor_id_index, float>, 4> scd30_sensor_device::read()
float temperatureC = NAN;
float temperatureF = NAN;
float humidity = NAN;
const bool data_ready = wait_till_data_ready();

if (data_ready)
{
auto err = scd30_read_measurement(&scd30_sensor_, &co2, &temperatureC, &humidity);
if (err == ESP_OK)
{
#ifdef CONFIG_SCD30_SENSOR_TEMPERATURE_OFFSET
temperatureC -= CONFIG_SCD30_SENSOR_TEMPERATURE_OFFSET / 100; // offset for the heat generated by sensor itself.
#endif
temperatureF = (temperatureC * 1.8) + 32;
ESP_LOGI(SENSOR_SCD30_TAG, "Read SCD30 sensor values:%g ppm %g F, %g C %g %%", co2, temperatureF, temperatureC, humidity);
}
else
{
ESP_LOGE(SENSOR_SCD30_TAG, "Failed to read from SCD30 sensor with error:%s", esp_err_to_name(err));
}
}

return {std::tuple<sensor_id_index, float>{sensor_id_index::temperatureC, esp32::round_with_precision(temperatureC, 0.01)},
std::tuple<sensor_id_index, float>{sensor_id_index::temperatureF, esp32::round_with_precision(temperatureF, 0.1)},
std::tuple<sensor_id_index, float>{sensor_id_index::CO2, esp32::round_with_precision(co2, 1)},
std::tuple<sensor_id_index, float>{sensor_id_index::humidity, esp32::round_with_precision(humidity, 1)}};
}

bool scd30_sensor_device::wait_till_data_ready()
{
uint8_t retries = 0;
bool ready = false;
auto error = scd30_get_data_ready_status(&scd30_sensor_, &ready);

do
if ((error == ESP_OK))
{
auto error = scd30_get_data_ready_status(&scd30_sensor_, &ready);

if ((error == ESP_OK))
if (ready)
{
if (ready)
auto err = scd30_read_measurement(&scd30_sensor_, &co2, &temperatureC, &humidity);
if (err == ESP_OK)
{
return true;
#ifdef CONFIG_SCD30_SENSOR_TEMPERATURE_OFFSET
temperatureC -= CONFIG_SCD30_SENSOR_TEMPERATURE_OFFSET / 100; // offset for the heat generated by sensor itself.
#endif
temperatureF = (temperatureC * 1.8) + 32;
ESP_LOGI(SENSOR_SCD30_TAG, "Read SCD30 sensor values:%g ppm %g F, %g C %g %%", co2, temperatureF, temperatureC, humidity);
}
else
{
vTaskDelay(max_wait_ticks_ / 5);
retries++;
ESP_LOGE(SENSOR_SCD30_TAG, "Failed to read from SCD30 sensor with error:%s", esp_err_to_name(err));
}
last_measurement_value_.store(std::tie(co2, temperatureC, temperatureF, humidity));
}
else
{
ESP_LOGE(SENSOR_SPS30_TAG, "Failed to read from SPS30 sensor with failed to read measurement error:0x%x", error);
return false;
std::tuple<float, float, float, float> old_values;
if (last_measurement_value_.update(old_values))
{
std::tie(co2, temperatureC, temperatureF, humidity) = old_values;
}
}
}
else
{
ESP_LOGE(SENSOR_SCD30_TAG, "Failed to read from SCD30 sensor with failed to read measurement error:0x%x", error);
}

} while (retries < 5);
return false;
return {std::tuple<sensor_id_index, float>{sensor_id_index::temperatureC, esp32::round_with_precision(temperatureC, 0.01)},
std::tuple<sensor_id_index, float>{sensor_id_index::temperatureF, esp32::round_with_precision(temperatureF, 0.1)},
std::tuple<sensor_id_index, float>{sensor_id_index::CO2, esp32::round_with_precision(co2, 1)},
std::tuple<sensor_id_index, float>{sensor_id_index::humidity, esp32::round_with_precision(humidity, 1)}};
}

uint8_t scd30_sensor_device::get_initial_delay()
Expand Down
11 changes: 3 additions & 8 deletions main/hardware/sensors/scd30_sensor_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "sdkconfig.h"

#ifdef CONFIG_SCD30_SENSOR_ENABLE
#include "hardware/sensors/last_measurement_helper.h"
#include "hardware/sensors/sensor_id.h"
#include "util/singleton.h"
#include <array>
Expand All @@ -19,15 +20,9 @@ class scd30_sensor_device final : public esp32::singleton<scd30_sensor_device>

private:
i2c_dev_t scd30_sensor_{};
last_measurement_helper<std::tuple<float, float, float, float>, 20000> last_measurement_value_;

const uint16_t sensor_interval_s_;
const TickType_t max_wait_ticks_;

scd30_sensor_device(uint16_t sensor_interval_s, uint32_t max_wait_ms)
: sensor_interval_s_(sensor_interval_s), max_wait_ticks_(pdMS_TO_TICKS(max_wait_ms))
{
}
bool wait_till_data_ready();
scd30_sensor_device() = default;
friend class esp32::singleton<scd30_sensor_device>;
};
#endif
50 changes: 17 additions & 33 deletions main/hardware/sensors/sps30_sensor_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "logging/logging_tags.h"
#include "sps30/sps30.h"
#include "util/exceptions.h"
#include "util/misc.h"
#include "util/noncopyable.h"
#include <esp_log.h>
#include <i2cdev.h>
Expand Down Expand Up @@ -39,51 +38,36 @@ void sps30_sensor_device::init()
}
}

bool sps30_sensor_device::wait_till_data_ready()
std::array<std::tuple<sensor_id_index, float>, 5> sps30_sensor_device::read()
{
uint16_t ready = 0;
uint8_t retries = 0;

do
uint16_t ready{0};
sps30_measurement measurement{NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN};
auto error = sps30_read_data_ready(&ready);
if (error == NO_ERROR)
{
auto error = sps30_read_data_ready(&ready);

if ((error == NO_ERROR))
if (ready)
{
if (ready)
const auto error = sps30_read_measurement(&measurement);
if (error == NO_ERROR)
{
return true;
ESP_LOGI(SENSOR_SPS30_TAG, "Read SPS30 sensor values PM2.5:%g, PM1:%g, PM4:%g, PM10:%g, Particle Size:%g", measurement.mc_2p5,
measurement.mc_1p0, measurement.mc_4p0, measurement.mc_10p0, measurement.typical_particle_size);
}
else
{
vTaskDelay(max_wait_ticks_ / 5);
ESP_LOGE(SENSOR_SPS30_TAG, "Failed to read from SPS30 sensor with failed to read measurement error:0x%x", error);
}
last_measurement_value_.store(measurement);
}
else
{
ESP_LOGE(SENSOR_SPS30_TAG, "Failed to read from SPS30 sensor with failed to read measurement error:0x%x", error);
return false;
ESP_LOGI(SENSOR_SPS30_TAG, "Returning last stored values");
last_measurement_value_.update(measurement);
}
} while (retries < 5);
return false;
}

std::array<std::tuple<sensor_id_index, float>, 5> sps30_sensor_device::read()
{
const bool ready = wait_till_data_ready();
sps30_measurement measurement{NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN};
if (ready)
}
else
{
const auto error = sps30_read_measurement(&measurement);
if (error == NO_ERROR)
{
ESP_LOGI(SENSOR_SPS30_TAG, "Read SPS30 sensor values PM2.5:%g, PM1:%g, PM4:%g, PM10:%g, Particle Size:%g", measurement.mc_2p5,
measurement.mc_1p0, measurement.mc_4p0, measurement.mc_10p0, measurement.typical_particle_size);
}
else
{
ESP_LOGE(SENSOR_SPS30_TAG, "Failed to read from SPS30 sensor with failed to read measurement error:0x%x", error);
}
ESP_LOGE(SENSOR_SPS30_TAG, "Failed to read from SPS30 sensor with failed to read measurement error:0x%x", error);
}

return {std::tuple<sensor_id_index, float>{sensor_id_index::pm_10, esp32::round_with_precision(measurement.mc_10p0, 1)},
Expand Down
9 changes: 5 additions & 4 deletions main/hardware/sensors/sps30_sensor_device.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "hardware/sensors/last_measurement_helper.h"
#include "hardware/sensors/sensor_id.h"
#include "hardware/sensors/sps30/sps30.h"
#include "util/singleton.h"
Expand All @@ -17,18 +18,18 @@ class sps30_sensor_device final : public esp32::singleton<sps30_sensor_device>
std::string get_error_register_status();
bool clean();

uint16_t get_initial_delay_ms();

private:
i2c_dev_t sps30_sensor_{};
const uint32_t max_wait_ticks_;
last_measurement_helper<sps30_measurement, 2000> last_measurement_value_;

esp_err_t sensirion_i2c_read(uint8_t address, uint8_t *data, uint16_t count);
esp_err_t sensirion_i2c_write(uint8_t address, const uint8_t *data, uint16_t count);

friend int8_t sensirion_i2c_write(uint8_t address, const uint8_t *data, uint16_t count);
friend int8_t sensirion_i2c_read(uint8_t address, uint8_t *data, uint16_t count);

sps30_sensor_device(uint32_t max_wait_ms): max_wait_ticks_(pdMS_TO_TICKS(max_wait_ms)) {};
bool wait_till_data_ready();

sps30_sensor_device() = default;
friend class esp32::singleton<sps30_sensor_device>;
};
1 change: 1 addition & 0 deletions main/util/misc.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <cmath>
#include <esp_timer.h>

namespace esp32
Expand Down
5 changes: 3 additions & 2 deletions sdkconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1612,8 +1612,9 @@ CONFIG_WPA_MBEDTLS_TLS_CLIENT=y
#
# Project
#
CONFIG_SHT3X_SENSOR_ENABLE=y
# CONFIG_SCD30_SENSOR_ENABLE is not set
# CONFIG_SHT3X_SENSOR_ENABLE is not set
CONFIG_SCD30_SENSOR_ENABLE=y
CONFIG_SCD30_SENSOR_TEMPERATURE_OFFSET=200
# CONFIG_ENABLE_SD_CARD_SUPPORT is not set
# end of Project

Expand Down

0 comments on commit 7f36b78

Please sign in to comment.