mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-06 11:39:32 +00:00
Working implementation on VOCState
* Adds initial timer for SEN55 to not sleep if VOCstate is not stable (1h) * Adds conditions for stability and sensor state
This commit is contained in:
parent
d583991248
commit
1038765219
@ -79,13 +79,16 @@ int32_t AirQualityTelemetryModule::runOnce()
|
||||
}
|
||||
|
||||
// Wake up the sensors that need it, before we need to take telemetry data
|
||||
if ((lastSentToMesh == 0) ||
|
||||
// TODO - Do it for SENSOR ROLE too?
|
||||
if (((lastSentToMesh == 0) ||
|
||||
(sen5xSensor.hasSensor() && !Throttle::isWithinTimespanMs(lastSentToMesh - SEN5X_WARMUP_MS_1, Default::getConfiguredOrDefaultMsScaled(
|
||||
moduleConfig.telemetry.air_quality_interval,
|
||||
default_telemetry_broadcast_interval_secs, numOnlineNodes))) ||
|
||||
(pmsa003iSensor.hasSensor() && !Throttle::isWithinTimespanMs(lastSentToMesh - PMSA003I_WARMUP_MS, Default::getConfiguredOrDefaultMsScaled(
|
||||
moduleConfig.telemetry.air_quality_interval,
|
||||
default_telemetry_broadcast_interval_secs, numOnlineNodes)))) {
|
||||
default_telemetry_broadcast_interval_secs, numOnlineNodes)))) &&
|
||||
airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
|
||||
airTime->isTxAllowedAirUtil()) {
|
||||
|
||||
if (sen5xSensor.hasSensor() && !sen5xSensor.isActive())
|
||||
return sen5xSensor.wakeUp();
|
||||
@ -100,10 +103,11 @@ int32_t AirQualityTelemetryModule::runOnce()
|
||||
if (sen5xSensor.hasSensor() && sen5xSensor.isActive()) {
|
||||
sen5xPendingForReady = sen5xSensor.pendingForReady();
|
||||
LOG_DEBUG("SEN5X: Pending for ready %ums", sen5xPendingForReady);
|
||||
if (sen5xPendingForReady) {
|
||||
if (sen5xPendingForReady > 0) {
|
||||
return sen5xPendingForReady;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("Checking if sending telemetry");
|
||||
|
||||
if (((lastSentToMesh == 0) ||
|
||||
!Throttle::isWithinTimespanMs(lastSentToMesh, Default::getConfiguredOrDefaultMsScaled(
|
||||
@ -122,6 +126,7 @@ int32_t AirQualityTelemetryModule::runOnce()
|
||||
}
|
||||
|
||||
// Send the sensor to idle ONLY if there is enough time to wake it up before the next reading cycle
|
||||
// TODO - include conditions here for module timing
|
||||
#ifdef PMSA003I_ENABLE_PIN
|
||||
if (pmsa003iSensor.hasSensor() && pmsa003iSensor.isActive()) {
|
||||
if (PMSA003I_WARMUP_MS < Default::getConfiguredOrDefaultMsScaled(
|
||||
@ -322,8 +327,10 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||
m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
|
||||
m.time = getTime();
|
||||
|
||||
// TODO - if one sensor fails here, we will stop taking measurements from everything
|
||||
// Can we do this in a smarter way, for instance checking the nodeTelemetrySensor map and making it dynamic?
|
||||
|
||||
if (getAirQualityTelemetry(&m)) {
|
||||
LOG_INFO("Send: pm10_standard=%u, pm25_standard=%u, pm100_standard=%u",
|
||||
m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard,
|
||||
|
@ -218,25 +218,36 @@ bool SEN5XSensor::I2Cdetect(TwoWire *_Wire, uint8_t address)
|
||||
|
||||
bool SEN5XSensor::idle()
|
||||
{
|
||||
// From the datasheet:
|
||||
// By default, the VOC algorithm resets its state to initial
|
||||
// values each time a measurement is started,
|
||||
// even if the measurement was stopped only for a short
|
||||
// time. So, the VOC index output value needs a long time
|
||||
// until it is stable again. This can be avoided by
|
||||
// restoring the previously memorized algorithm state before
|
||||
// starting the measure mode
|
||||
|
||||
|
||||
// Get VOC state before going to idle mode
|
||||
if (vocStateFromSensor()) {
|
||||
// TODO Should this be saved with saveState()?
|
||||
// It so, we can consider not saving it when rebooting as
|
||||
// we would have likely saved it recently
|
||||
|
||||
// Check if we have time, and store it
|
||||
uint32_t now; // If time is RTCQualityNone, it will return zero
|
||||
now = getValidTime(RTCQuality::RTCQualityDevice);
|
||||
|
||||
if (now) {
|
||||
vocTime = now;
|
||||
vocValid = true;
|
||||
// saveState();
|
||||
}
|
||||
} else {
|
||||
// If the stabilisation period is not passed for SEN55, don't go to idle
|
||||
if (model == SEN55) {
|
||||
// Get VOC state before going to idle mode
|
||||
vocValid = false;
|
||||
if (vocStateFromSensor()) {
|
||||
vocValid = vocStateValid();
|
||||
// Check if we have time, and store it
|
||||
uint32_t now; // If time is RTCQualityNone, it will return zero
|
||||
now = getValidTime(RTCQuality::RTCQualityDevice);
|
||||
if (now) {
|
||||
// Check if state is valid (non-zero)
|
||||
vocTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
if (vocStateStable() && vocValid) {
|
||||
saveState();
|
||||
} else {
|
||||
LOG_INFO("SEN5X: Not stopping measurement, vocState is not stable yet!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!oneShotMode) {
|
||||
@ -248,8 +259,8 @@ bool SEN5XSensor::idle()
|
||||
LOG_ERROR("SEN5X: Error stoping measurement");
|
||||
return false;
|
||||
}
|
||||
delay(200); // From Sensirion Datasheet
|
||||
|
||||
delay(200); // From Sensirion Datasheet
|
||||
LOG_INFO("SEN5X: Stop measurement mode");
|
||||
|
||||
state = SEN5X_IDLE;
|
||||
@ -257,12 +268,40 @@ bool SEN5XSensor::idle()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SEN5XSensor::vocStateRecent(uint32_t now){
|
||||
if (now) {
|
||||
uint32_t passed = now - vocTime; //in seconds
|
||||
|
||||
// Check if state is recent, less than 10 minutes (600 seconds)
|
||||
if (passed < SEN5X_VOC_VALID_TIME && (now > SEN5X_VOC_VALID_DATE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SEN5XSensor::vocStateValid() {
|
||||
if (!vocState[0] && !vocState[1] && !vocState[2] && !vocState[3] &&
|
||||
!vocState[4] && !vocState[5] && !vocState[6] && !vocState[7]) {
|
||||
LOG_DEBUG("SEN5X: VOC state is all 0, invalid");
|
||||
return false;
|
||||
} else {
|
||||
LOG_DEBUG("SEN5X: VOC state is valid");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SEN5XSensor::vocStateToSensor()
|
||||
{
|
||||
if (model != SEN55){
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!vocStateValid()) {
|
||||
LOG_INFO("SEN5X: VOC state is invalid, not sending");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!sendCommand(SEN5X_STOP_MEASUREMENT)) {
|
||||
LOG_ERROR("SEN5X: Error stoping measurement");
|
||||
return false;
|
||||
@ -320,8 +359,7 @@ bool SEN5XSensor::vocStateFromSensor()
|
||||
vocState[7] = vocBuffer[10];
|
||||
|
||||
// Print the state (if debug is on)
|
||||
LOG_DEBUG("SEN5X: VOC state retrieved from sensor");
|
||||
LOG_DEBUG("[%u, %u, %u, %u, %u, %u, %u, %u]",
|
||||
LOG_DEBUG("SEN5X: VOC state retrieved from sensor: [%u, %u, %u, %u, %u, %u, %u, %u]",
|
||||
vocState[0],vocState[1], vocState[2], vocState[3],
|
||||
vocState[4],vocState[5], vocState[6], vocState[7]);
|
||||
|
||||
@ -337,24 +375,36 @@ bool SEN5XSensor::loadState()
|
||||
if (file) {
|
||||
LOG_INFO("%s state read from %s", sensorName, sen5XStateFileName);
|
||||
pb_istream_t stream = {&readcb, &file, meshtastic_SEN5XState_size};
|
||||
|
||||
if (!pb_decode(&stream, &meshtastic_SEN5XState_msg, &sen5xstate)) {
|
||||
LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream));
|
||||
} else {
|
||||
lastCleaning = sen5xstate.last_cleaning_time;
|
||||
lastCleaningValid = sen5xstate.last_cleaning_valid;
|
||||
oneShotMode = sen5xstate.one_shot_mode;
|
||||
// Unpack state
|
||||
vocState[7] = (uint8_t)(sen5xstate.voc_state >> 56);
|
||||
vocState[6] = (uint8_t)(sen5xstate.voc_state >> 48);
|
||||
vocState[5] = (uint8_t)(sen5xstate.voc_state >> 40);
|
||||
vocState[4] = (uint8_t)(sen5xstate.voc_state >> 32);
|
||||
vocState[3] = (uint8_t)(sen5xstate.voc_state >> 24);
|
||||
vocState[2] = (uint8_t)(sen5xstate.voc_state >> 16);
|
||||
vocState[1] = (uint8_t)(sen5xstate.voc_state >> 8);
|
||||
vocState[0] = (uint8_t)sen5xstate.voc_state;
|
||||
|
||||
vocTime = sen5xstate.voc_time;
|
||||
vocValid = sen5xstate.voc_valid;
|
||||
if (model == SEN55) {
|
||||
vocTime = sen5xstate.voc_state_time;
|
||||
vocValid = sen5xstate.voc_state_valid;
|
||||
// Unpack state
|
||||
vocState[7] = (uint8_t)(sen5xstate.voc_state_array >> 56);
|
||||
vocState[6] = (uint8_t)(sen5xstate.voc_state_array >> 48);
|
||||
vocState[5] = (uint8_t)(sen5xstate.voc_state_array >> 40);
|
||||
vocState[4] = (uint8_t)(sen5xstate.voc_state_array >> 32);
|
||||
vocState[3] = (uint8_t)(sen5xstate.voc_state_array >> 24);
|
||||
vocState[2] = (uint8_t)(sen5xstate.voc_state_array >> 16);
|
||||
vocState[1] = (uint8_t)(sen5xstate.voc_state_array >> 8);
|
||||
vocState[0] = (uint8_t) sen5xstate.voc_state_array;
|
||||
}
|
||||
|
||||
// LOG_DEBUG("Loaded lastCleaning %u", lastCleaning);
|
||||
// LOG_DEBUG("Loaded lastCleaningValid %u", lastCleaningValid);
|
||||
// LOG_DEBUG("Loaded oneShotMode %s", oneShotMode ? "true" : "false");
|
||||
// LOG_DEBUG("Loaded vocTime %u", vocTime);
|
||||
// LOG_DEBUG("Loaded [%u, %u, %u, %u, %u, %u, %u, %u]",
|
||||
// vocState[7], vocState[6], vocState[5], vocState[4], vocState[3], vocState[2], vocState[1], vocState[0]);
|
||||
// LOG_DEBUG("Loaded %svalid VOC state", vocValid ? "" : "in");
|
||||
|
||||
okay = true;
|
||||
}
|
||||
file.close();
|
||||
@ -370,7 +420,7 @@ bool SEN5XSensor::loadState()
|
||||
|
||||
bool SEN5XSensor::saveState()
|
||||
{
|
||||
// TODO - This should be called before a reboot
|
||||
// TODO - This should be called before a reboot for VOC index storage
|
||||
// is there a way to get notified?
|
||||
#ifdef FSCom
|
||||
auto file = SafeFile(sen5XStateFileName);
|
||||
@ -379,20 +429,23 @@ bool SEN5XSensor::saveState()
|
||||
sen5xstate.last_cleaning_valid = lastCleaningValid;
|
||||
sen5xstate.one_shot_mode = oneShotMode;
|
||||
|
||||
// Unpack state (12 bytes in two parts)
|
||||
sen5xstate.voc_state = ((uint64_t) vocState[7] << 56) |
|
||||
((uint64_t) vocState[6] << 48) |
|
||||
((uint64_t) vocState[5] << 40) |
|
||||
((uint64_t) vocState[4] << 32) |
|
||||
((uint32_t) vocState[3] << 24) |
|
||||
((uint32_t) vocState[2] << 16) |
|
||||
((uint32_t) vocState[1] << 8) |
|
||||
vocState[0];
|
||||
if (model == SEN55) {
|
||||
sen5xstate.has_voc_state_time = true;
|
||||
sen5xstate.has_voc_state_valid = true;
|
||||
sen5xstate.has_voc_state_array = true;
|
||||
|
||||
LOG_INFO("sen5xstate.voc_state %i", sen5xstate.voc_state);
|
||||
|
||||
sen5xstate.voc_time = vocTime;
|
||||
sen5xstate.voc_valid = vocValid;
|
||||
sen5xstate.voc_state_time = vocTime;
|
||||
sen5xstate.voc_state_valid = vocValid;
|
||||
// Unpack state (8 bytes)
|
||||
sen5xstate.voc_state_array = (((uint64_t) vocState[7]) << 56) |
|
||||
((uint64_t) vocState[6] << 48) |
|
||||
((uint64_t) vocState[5] << 40) |
|
||||
((uint64_t) vocState[4] << 32) |
|
||||
((uint64_t) vocState[3] << 24) |
|
||||
((uint64_t) vocState[2] << 16) |
|
||||
((uint64_t) vocState[1] << 8) |
|
||||
((uint64_t) vocState[0]);
|
||||
}
|
||||
|
||||
bool okay = false;
|
||||
|
||||
@ -421,42 +474,26 @@ bool SEN5XSensor::isActive(){
|
||||
}
|
||||
|
||||
uint32_t SEN5XSensor::wakeUp(){
|
||||
// LOG_INFO("SEN5X: Attempting to wakeUp sensor");
|
||||
uint32_t now;
|
||||
now = getValidTime(RTCQuality::RTCQualityDevice);
|
||||
LOG_DEBUG("SEN5X: Waking up sensor");
|
||||
|
||||
// From the datasheet
|
||||
// By default, the VOC algorithm resets its state to initial
|
||||
// values each time a measurement is started,
|
||||
// even if the measurement was stopped only for a short
|
||||
// time. So, the VOC index output value needs a long time
|
||||
// until it is stable again. This can be avoided by
|
||||
// restoring the previously memorized algorithm state before
|
||||
// starting the measure mode
|
||||
|
||||
// TODO - This needs to be tested
|
||||
// In SC, the sensor is operated in contionuous mode if
|
||||
// VOCs are present, increasing battery consumption
|
||||
// A different approach should be possible as stated on the
|
||||
// datasheet (see above)
|
||||
// uint32_t now, passed;
|
||||
// now = getValidTime(RTCQuality::RTCQualityDevice);
|
||||
// passed = now - vocTime; //in seconds
|
||||
// // Check if state is recent, less than 10 minutes (600 seconds)
|
||||
// if ((passed < SEN5X_VOC_VALID_TIME) && (now > SEN5X_VOC_VALID_DATE) && vocValid) {
|
||||
// if (!vocStateToSensor()){
|
||||
// LOG_ERROR("SEN5X: Sending VOC state to sensor failed");
|
||||
// }
|
||||
// } else {
|
||||
// LOG_DEBUG("SEN5X: No valid VOC state found. Ignoring");
|
||||
// }
|
||||
// Check if state is recent, less than 10 minutes (600 seconds)
|
||||
if (vocStateRecent(now) && vocStateValid()) {
|
||||
if (!vocStateToSensor()){
|
||||
LOG_ERROR("SEN5X: Sending VOC state to sensor failed");
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG("SEN5X: No valid VOC state found. Ignoring");
|
||||
}
|
||||
|
||||
if (!sendCommand(SEN5X_START_MEASUREMENT)) {
|
||||
LOG_ERROR("SEN5X: Error starting measurement");
|
||||
// TODO - what should this return??
|
||||
// TODO - what should this return?? Something actually on the default interval
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
delay(50); // From Sensirion Datasheet
|
||||
|
||||
// LOG_INFO("SEN5X: Setting measurement mode");
|
||||
// TODO - This is currently "problematic"
|
||||
// If time is updated in between reads, there is no way to
|
||||
// keep track of how long it has passed
|
||||
@ -467,6 +504,15 @@ uint32_t SEN5XSensor::wakeUp(){
|
||||
return SEN5X_WARMUP_MS_1;
|
||||
}
|
||||
|
||||
bool SEN5XSensor::vocStateStable()
|
||||
{
|
||||
uint32_t now;
|
||||
now = getTime();
|
||||
uint32_t sinceFirstMeasureStarted = (now - firstMeasureStarted);
|
||||
LOG_DEBUG("sinceFirstMeasureStarted: %us", sinceFirstMeasureStarted);
|
||||
return sinceFirstMeasureStarted > SEN55_VOC_STATE_WARMUP_S;
|
||||
}
|
||||
|
||||
bool SEN5XSensor::startCleaning()
|
||||
{
|
||||
// Note: we only should enter here if we have a valid RTC with at least
|
||||
@ -532,7 +578,7 @@ int32_t SEN5XSensor::runOnce()
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
// Check if firmware version allows The direct switch between Measurement and RHT/Gas-Only Measurement mode
|
||||
// Check the firmware version
|
||||
if (!getVersion()) return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
if (firmwareVer < 2) {
|
||||
LOG_ERROR("SEN5X: error firmware is too old and will not work with this implementation");
|
||||
@ -551,8 +597,8 @@ int32_t SEN5XSensor::runOnce()
|
||||
uint32_t now;
|
||||
int32_t passed;
|
||||
now = getValidTime(RTCQuality::RTCQualityDevice);
|
||||
// If time is not RTCQualityNone, it will return non-zero
|
||||
|
||||
// If time is not RTCQualityNone, it will return non-zero
|
||||
if (now) {
|
||||
if (lastCleaningValid) {
|
||||
|
||||
@ -566,36 +612,35 @@ int32_t SEN5XSensor::runOnce()
|
||||
LOG_INFO("SEN5X: Cleaning not needed (%ds passed). Last cleaning date (in epoch): %us", passed, lastCleaning);
|
||||
}
|
||||
} else {
|
||||
// We assume the device has just been updated or it is new, so no need to trigger a cleaning.
|
||||
// We assume the device has just been updated or it is new,
|
||||
// so no need to trigger a cleaning.
|
||||
// Just save the timestamp to do a cleaning one week from now.
|
||||
// TODO - could we trigger this after getting time?
|
||||
// Otherwise, we will never trigger cleaning in some cases
|
||||
lastCleaning = now;
|
||||
lastCleaningValid = true;
|
||||
LOG_INFO("SEN5X: No valid last cleaning date found, saving it now: %us", lastCleaning);
|
||||
saveState();
|
||||
}
|
||||
|
||||
if (model == SEN55) {
|
||||
if (!vocValid) {
|
||||
LOG_INFO("SEN5X: No valid VOC's state found");
|
||||
} else {
|
||||
passed = now - vocTime; //in seconds
|
||||
|
||||
// Check if state is recent, less than 10 minutes (600 seconds)
|
||||
if (passed < SEN5X_VOC_VALID_TIME && (now > SEN5X_VOC_VALID_DATE)) {
|
||||
// Check if state is recent
|
||||
if (vocStateRecent(now)) {
|
||||
// If current date greater than 01/01/2018 (validity check)
|
||||
// Send it to the sensor
|
||||
LOG_INFO("SEN5X: VOC state is valid and recent");
|
||||
vocStateToSensor();
|
||||
} else {
|
||||
LOG_INFO("SEN5X VOC state is to old or date is invalid");
|
||||
LOG_INFO("SEN5X: VOC state is too old or date is invalid");
|
||||
LOG_DEBUG("SEN5X: vocTime %u, Passed %u, and now %u", vocTime, passed, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// TODO - Should this actually ignore? We could end up never cleaning...
|
||||
LOG_INFO("SEN5X: Not enough RTCQuality, ignoring saved state");
|
||||
LOG_INFO("SEN5X: Not enough RTCQuality, ignoring saved state. Trying again later");
|
||||
}
|
||||
|
||||
return initI2CSensor();
|
||||
@ -645,6 +690,17 @@ bool SEN5XSensor::readValues()
|
||||
sen5xmeasurement.pM1p0, sen5xmeasurement.pM2p5,
|
||||
sen5xmeasurement.pM4p0, sen5xmeasurement.pM10p0);
|
||||
|
||||
if (model == SEN54 || model == SEN55) {
|
||||
LOG_DEBUG("Got: humidity=%.2f, temperature=%.2f, noxIndex=%.2f",
|
||||
sen5xmeasurement.humidity, sen5xmeasurement.temperature,
|
||||
sen5xmeasurement.noxIndex);
|
||||
}
|
||||
|
||||
if (model == SEN55) {
|
||||
LOG_DEBUG("Got: vocIndex=%.2f",
|
||||
sen5xmeasurement.vocIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -783,6 +839,10 @@ int32_t SEN5XSensor::pendingForReady(){
|
||||
return SEN5X_WARMUP_MS_1 - sinceMeasureStarted;
|
||||
}
|
||||
|
||||
if (!firstMeasureStarted) {
|
||||
firstMeasureStarted = now;
|
||||
}
|
||||
|
||||
// Get PN values to check if we are above or below threshold
|
||||
readPnValues(true);
|
||||
|
||||
@ -883,6 +943,7 @@ bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
} else if (response == 1) {
|
||||
// TODO return because data was not ready yet
|
||||
|
@ -20,6 +20,16 @@
|
||||
#define SEN5X_I2C_CLOCK_SPEED 100000
|
||||
#endif
|
||||
|
||||
/*
|
||||
Time after which the sensor can go to sleep, as the warmup period has passed
|
||||
and the VOCs sensor will is allowed to stop (although needs to recover the state
|
||||
each time)
|
||||
*/
|
||||
#ifndef SEN55_VOC_STATE_WARMUP_S
|
||||
// TODO for Testing 5' - Sensirion recommends 1h. We can try to test a smaller value
|
||||
#define SEN55_VOC_STATE_WARMUP_S 3600
|
||||
#endif
|
||||
|
||||
#define ONE_WEEK_IN_SECONDS 604800
|
||||
|
||||
struct _SEN5XMeasurements {
|
||||
@ -77,6 +87,7 @@ class SEN5XSensor : public TelemetrySensor
|
||||
// Flag to work on one-shot (read and sleep), or continuous mode
|
||||
bool oneShotMode = true;
|
||||
void setMode(bool setOneShot);
|
||||
bool vocStateValid();
|
||||
|
||||
bool sendCommand(uint16_t command);
|
||||
bool sendCommand(uint16_t command, uint8_t* buffer, uint8_t byteNumber=0);
|
||||
@ -91,6 +102,7 @@ class SEN5XSensor : public TelemetrySensor
|
||||
bool readValues();
|
||||
|
||||
uint32_t measureStarted = 0;
|
||||
uint32_t firstMeasureStarted = 0;
|
||||
_SEN5XMeasurements sen5xmeasurement;
|
||||
|
||||
protected:
|
||||
@ -108,10 +120,13 @@ class SEN5XSensor : public TelemetrySensor
|
||||
// VOC State
|
||||
#define SEN5X_VOC_STATE_BUFFER_SIZE 8
|
||||
uint8_t vocState[SEN5X_VOC_STATE_BUFFER_SIZE];
|
||||
uint32_t vocTime;
|
||||
bool vocValid = true;
|
||||
uint32_t vocTime = 0;
|
||||
bool vocValid = false;
|
||||
|
||||
bool vocStateFromSensor();
|
||||
bool vocStateToSensor();
|
||||
bool vocStateStable();
|
||||
bool vocStateRecent(uint32_t now);
|
||||
|
||||
virtual void setup() override;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user