Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/components/i2c/WipperSnapper_I2C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1032,7 +1032,7 @@ bool WipperSnapper_Component_I2C::initI2CDevice(
_drivers_out.push_back(_ssd1306);
WS_DEBUG_PRINTLN("SSD1306 display initialized Successfully!");
} else {
WS_DEBUG_PRINTLN("ERROR: I2C device type not found!")
WS_DEBUG_PRINTLN("ERROR: I2C device type not found!");
_busStatusResponse =
wippersnapper_i2c_v1_BusResponse_BUS_RESPONSE_UNSUPPORTED_SENSOR;
return false;
Expand Down Expand Up @@ -1347,13 +1347,20 @@ void WipperSnapper_Component_I2C::update() {
msgi2cResponse.which_payload =
wippersnapper_signal_v1_I2CResponse_resp_i2c_device_event_tag;

// one fast pass for all drivers every update() call
for (auto *drv : drivers) {
if (drv)
drv->fastTick();
}

long curTime;
bool sensorsReturningFalse = true;
int retries = 3;

while (sensorsReturningFalse && retries > 0) {
sensorsReturningFalse = false;
retries--;
curTime = millis();

std::vector<WipperSnapper_I2C_Driver *>::iterator iter, end;
for (iter = drivers.begin(), end = drivers.end(); iter != end; ++iter) {
Expand Down
18 changes: 16 additions & 2 deletions src/components/i2c/drivers/WipperSnapper_I2C_Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class WipperSnapper_I2C_Driver {
public:
/*******************************************************************************/
/*!
@brief Instanciates an I2C sensor.
@brief Instanctiates an I2C sensor.
@param i2c
The I2C hardware interface, default is Wire.
@param sensorAddress
Expand All @@ -53,6 +53,20 @@ class WipperSnapper_I2C_Driver {
/*******************************************************************************/
virtual ~WipperSnapper_I2C_Driver() {}

/*******************************************************************************/
/*!
@brief Per-update background hook for drivers that need faster internal
sampling than the user publish interval.
Default is a no-op; override in concrete drivers (e.g.,
SGP30/40) to maintain required ~1 Hz reads and accumulate/condition values
for later publish.
@note Call site: WipperSnapper_Component_I2C::update() will invoke
this once per loop for each driver. Implementations must be
non-blocking (do not delay); use millis()-based timing.
*/
/*******************************************************************************/
virtual void fastTick() {}

/*******************************************************************************/
/*!
@brief Initializes the I2C sensor and begins I2C.
Expand Down Expand Up @@ -1312,7 +1326,7 @@ class WipperSnapper_I2C_Driver {
@brief Updates the properties of a proximity sensor.
@param period
The time interval at which to return new data from the
proimity sensor.
proximity sensor.
*/
/*******************************************************************************/
virtual void updateSensorProximity(float period) {
Expand Down
97 changes: 82 additions & 15 deletions src/components/i2c/drivers/WipperSnapper_I2C_Driver_SGP30.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ class WipperSnapper_I2C_Driver_SGP30 : public WipperSnapper_I2C_Driver {
: WipperSnapper_I2C_Driver(i2c, sensorAddress) {
_i2c = i2c;
_sensorAddress = sensorAddress;
_sgp30 = nullptr;
}

/*******************************************************************************/
/*!
@brief Destructor for an SGP30 sensor.
*/
/*******************************************************************************/
~WipperSnapper_I2C_Driver_SGP30() {
~WipperSnapper_I2C_Driver_SGP30() override {
// Called when a SGP30 component is deleted.
delete _sgp30;
if (_sgp30) {
delete _sgp30;
_sgp30 = nullptr;
}
}

/*******************************************************************************/
Expand All @@ -44,27 +48,90 @@ class WipperSnapper_I2C_Driver_SGP30 : public WipperSnapper_I2C_Driver {
/*******************************************************************************/
bool begin() {
_sgp30 = new Adafruit_SGP30();
return _sgp30->begin(_i2c);
if (!_sgp30->begin(_i2c)) {
delete _sgp30; // avoid leak on init failure
_sgp30 = nullptr;
return false;
}
_sgp30->IAQinit(); // start IAQ algorithm
_lastFastMs = millis(); // reset fast sampler
_n = _eco2Sum = _tvocSum = 0; // clear accumulators
return true;
}

bool getEventECO2(sensors_event_t *senseEvent) {
bool result = _sgp30->IAQmeasure();
if (result) {
senseEvent->eCO2 = _sgp30->eCO2;
bool getEventECO2(sensors_event_t *senseEvent) override {
if (!_sgp30)
return false;
if (_n > 0) {
senseEvent->eCO2 = (uint16_t)(_eco2Sum / _n);
_eco2Sum = 0;
_tvocSum = 0;
_n = 0;
return true;
}
if (_sgp30->IAQmeasure()) {
senseEvent->eCO2 = (uint16_t)_sgp30->eCO2;
return true;
}
return result;
return false;
}

bool getEventTVOC(sensors_event_t *senseEvent) {
bool result = _sgp30->IAQmeasure();
if (result) {
senseEvent->tvoc = _sgp30->TVOC;
bool getEventTVOC(sensors_event_t *senseEvent) override {
if (!_sgp30)
return false;
if (_n > 0) {
senseEvent->tvoc = (uint16_t)(_tvocSum / _n);
_eco2Sum = 0;
_tvocSum = 0;
_n = 0;
return true;
}
if (_sgp30->IAQmeasure()) {
senseEvent->tvoc = (uint16_t)_sgp30->TVOC;
return true;
}
return false;
}

void fastTick() override {
if (!iaqEnabled())
return; // nothing enabled, save cycles
uint32_t now = millis();
if (now - _lastFastMs >= 1000) { // ~1 Hz cadence
if (_sgp30 && _sgp30->IAQmeasure()) {
_eco2Sum += _sgp30->eCO2; // uint16_t in library
_tvocSum += _sgp30->TVOC; // uint16_t in library
_n++;
}
_lastFastMs = now;
}
return result;
}

protected:
Adafruit_SGP30 *_sgp30; ///< Pointer to SGP30 temperature sensor object
Adafruit_SGP30 *_sgp30; ///< Pointer to SGP30 sensor object

/** Millis timestamp of last 1 Hz background read. */
uint32_t _lastFastMs = 0;

/** Number of samples accumulated since last publish. */
uint32_t _n = 0;

/** Running sum of eCO2 samples for averaging. */
uint32_t _eco2Sum = 0;

/** Running sum of TVOC samples for averaging. */
uint32_t _tvocSum = 0;

/*******************************************************************************/
/*!
@brief Returns whether IAQ background sampling should be active.
@return True if either eCO2 or TVOC metrics are configured to publish.
*/
/*******************************************************************************/
inline bool iaqEnabled() {
// Enable IAQ background reads if either metric is requested
return (getSensorECO2Period() > 0) || (getSensorTVOCPeriod() > 0);
}
};

#endif // WipperSnapper_I2C_Driver_SGP30
#endif // WipperSnapper_I2C_Driver_SGP30
100 changes: 90 additions & 10 deletions src/components/i2c/drivers/WipperSnapper_I2C_Driver_SGP40.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,21 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
: WipperSnapper_I2C_Driver(i2c, sensorAddress) {
_i2c = i2c;
_sensorAddress = sensorAddress;
_sgp40 = nullptr;
}

/*******************************************************************************/
/*!
@brief Destructor for an SGP40 sensor driver.
Cleans up and deallocates the underlying Adafruit_SGP40 object
when the driver is destroyed.
*/
/*******************************************************************************/
~WipperSnapper_I2C_Driver_SGP40() override {
if (_sgp40) {
delete _sgp40;
_sgp40 = nullptr;
}
}

/*******************************************************************************/
Expand All @@ -50,12 +65,15 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
/*******************************************************************************/
bool begin() {
_sgp40 = new Adafruit_SGP40();
if (!_sgp40->begin(_i2c)) {
if (!_sgp40 || !_sgp40->begin(_i2c)) {
delete _sgp40;
_sgp40 = nullptr;
return false;
}

// TODO: update to use setCalibration() and pass in temp/humidity

_lastFastMs = millis();
_n = 0;
_vocSum = 0.0f;
_rawSum = 0;
return true;
}

Expand All @@ -64,11 +82,20 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
@brief Gets the sensor's current raw unprocessed value.
@param rawEvent
Pointer to an Adafruit_Sensor event.
@returns True if the temperature was obtained successfully, False
@returns True if the raw value was obtained successfully, False
otherwise.
*/
/*******************************************************************************/
bool getEventRaw(sensors_event_t *rawEvent) {
bool getEventRaw(sensors_event_t *rawEvent) override {
if (!_sgp40)
return false;
if (_n > 0) {
rawEvent->data[0] = (float)_rawSum / (float)_n;
_rawSum = 0;
_vocSum = 0.0f;
_n = 0;
return true;
}
rawEvent->data[0] = (float)_sgp40->measureRaw();
return true;
}
Expand All @@ -82,13 +109,66 @@ class WipperSnapper_I2C_Driver_SGP40 : public WipperSnapper_I2C_Driver {
otherwise.
*/
/*******************************************************************************/
bool getEventVOCIndex(sensors_event_t *vocIndexEvent) {
vocIndexEvent->voc_index = (float)_sgp40->measureVocIndex();
bool getEventVOCIndex(sensors_event_t *vocIndexEvent) override {
if (!_sgp40)
return false;
if (_n > 0) {
vocIndexEvent->voc_index = (uint16_t)(_vocSum / (float)_n);
_rawSum = 0;
_vocSum = 0.0f;
_n = 0;
return true;
}
vocIndexEvent->voc_index = (uint16_t)_sgp40->measureVocIndex();
return true;
}

/*******************************************************************************/
/*!
@brief Performs background sampling for the SGP40.
Runs once per second to accumulate raw and VOC index values
for later averaging in getEventRaw() and getEventVOCIndex().
*/
/*******************************************************************************/
void fastTick() override {
if (!_sgp40)
return;
if (!vocEnabled())
return;

uint32_t now = millis();
if (now - _lastFastMs >= 1000) {
_rawSum += _sgp40->measureRaw();
_vocSum += _sgp40->measureVocIndex();
_n++;
_lastFastMs = now;
}
}

protected:
Adafruit_SGP40 *_sgp40; ///< SEN5X driver object
Adafruit_SGP40 *_sgp40; ///< SGP40

/** Millis timestamp of last 1 Hz background read. */
uint32_t _lastFastMs = 0;

/** Number of samples accumulated since last publish. */
uint32_t _n = 0;

/** Running sum of VOC index samples for averaging. */
float _vocSum = 0.0f;

/** Running sum of raw samples for averaging. */
uint32_t _rawSum = 0;

/*******************************************************************************/
/*!
@brief Returns whether VOC background sampling should be active.
@return True if either VOC Index or raw value is configured to publish.
*/
/*******************************************************************************/
inline bool vocEnabled() {
return (getSensorVOCIndexPeriod() > 0) || (getSensorRawPeriod() > 0);
}
};

#endif // WipperSnapper_I2C_Driver_SEN5X
#endif // WipperSnapper_I2C_Driver_SGP40_H
Loading