Add further admin commands and fixes.

This commit is contained in:
oscgonfer 2025-08-04 14:55:56 +02:00
parent 8a4f5c15e7
commit 2609f45550
2 changed files with 299 additions and 105 deletions

View File

@ -11,15 +11,19 @@
SCD4XSensor::SCD4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SCD4X, "SCD4X") {} SCD4XSensor::SCD4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SCD4X, "SCD4X") {}
bool SCD4XSensor::restoreClock(uint32_t currentClock){
#ifdef SCD4X_I2C_CLOCK_SPEED #ifdef SCD4X_I2C_CLOCK_SPEED
if (currentClock != SCD4X_I2C_CLOCK_SPEED){ uint32_t SCD4XSensor::setI2CClock(uint32_t desiredClock){
// LOG_DEBUG("Restoring I2C clock to %uHz", currentClock); uint32_t currentClock;
return bus->setClock(currentClock); currentClock = bus->getClock();
LOG_DEBUG("Current I2C clock: %uHz", currentClock);
if (currentClock != desiredClock){
LOG_DEBUG("Setting I2C clock to: %uHz", desiredClock);
bus->setClock(desiredClock);
return currentClock;
} }
return true; return 0;
#endif
} }
#endif
int32_t SCD4XSensor::runOnce() int32_t SCD4XSensor::runOnce()
{ {
@ -28,58 +32,60 @@ int32_t SCD4XSensor::runOnce()
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
uint16_t error;
bus = nodeTelemetrySensorsMap[sensorType].second; bus = nodeTelemetrySensorsMap[sensorType].second;
address = (uint8_t)nodeTelemetrySensorsMap[sensorType].first; address = (uint8_t)nodeTelemetrySensorsMap[sensorType].first;
#ifdef SCD4X_I2C_CLOCK_SPEED #ifdef SCD4X_I2C_CLOCK_SPEED
uint32_t currentClock; uint32_t currentClock;
currentClock = bus->getClock(); currentClock = setI2CClock(SCD4X_I2C_CLOCK_SPEED);
if (currentClock != SCD4X_I2C_CLOCK_SPEED){
// LOG_DEBUG("Changing I2C clock to %u", SCD4X_I2C_CLOCK_SPEED);
bus->setClock(SCD4X_I2C_CLOCK_SPEED);
}
#endif #endif
// FIXME - This should be based on bus and address from above // FIXME - This should be based on bus and address from above
scd4x.begin(*nodeTelemetrySensorsMap[sensorType].second, scd4x.begin(*nodeTelemetrySensorsMap[sensorType].second,
(uint8_t)nodeTelemetrySensorsMap[sensorType].first); address);
// SCD4X library
delay(30); delay(30);
// Ensure sensor is in clean state // Stop periodic measurement
error = scd4x.wakeUp(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Error trying to execute wakeUp()");
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
// Stop periodic measurement // Get sensor variant
error = scd4x.stopPeriodicMeasurement(); scd4x.getSensorVariant(sensorVariant);
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Error trying to stopPeriodicMeasurement()"); if (sensorVariant == SCD4X_SENSOR_VARIANT_SCD41){
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; LOG_INFO("SCD4X: Found SCD41");
if (!wakeUp()) {
LOG_ERROR("SCD4X: Error trying to execute wakeUp()");
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
} }
if (!getASC(ascActive)){ if (!getASC(ascActive)){
LOG_ERROR("SCD4X: Unable to check if ASC is enabled"); LOG_ERROR("SCD4X: Unable to check if ASC is enabled");
return false; return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
if (!ascActive){ // Start measurement in selected power mode (low power by default)
LOG_INFO("SCD4X: ASC is not active"); if (!startMeasurement()){
} else { LOG_ERROR("SCD4X: Couldn't start measurement");
LOG_INFO("SCD4X: ASC is active"); return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
} }
if (!scd4x.startLowPowerPeriodicMeasurement()) { #ifdef SCD4X_I2C_CLOCK_SPEED
if (currentClock){
setI2CClock(currentClock);
}
#endif
if (state == SCD4X_MEASUREMENT){
status = 1; status = 1;
} else { } else {
status = 0; status = 0;
} }
restoreClock(currentClock);
return initI2CSensor(); return initI2CSensor();
} }
@ -87,26 +93,41 @@ void SCD4XSensor::setup() {}
bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement) bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
{ {
if (state != SCD4X_MEASUREMENT) {
LOG_ERROR("SCD4X: Not in measurement mode");
return false;
}
uint16_t co2, error; uint16_t co2, error;
float temperature; float temperature, humidity;
float humidity;
#ifdef SCD4X_I2C_CLOCK_SPEED #ifdef SCD4X_I2C_CLOCK_SPEED
uint32_t currentClock; uint32_t currentClock;
currentClock = bus->getClock(); currentClock = setI2CClock(SCD4X_I2C_CLOCK_SPEED);
if (currentClock != SCD4X_I2C_CLOCK_SPEED){
// LOG_DEBUG("Changing I2C clock to %u", SCD4X_I2C_CLOCK_SPEED);
bus->setClock(SCD4X_I2C_CLOCK_SPEED);
}
#endif #endif
bool dataReady;
error = scd4x.getDataReadyStatus(dataReady);
if (!dataReady) {
LOG_ERROR("SCD4X: Data is not ready");
return false;
}
error = scd4x.readMeasurement(co2, temperature, humidity); error = scd4x.readMeasurement(co2, temperature, humidity);
restoreClock(currentClock); #ifdef SCD4X_I2C_CLOCK_SPEED
LOG_DEBUG("SCD4X: Error while getting measurements: %u", error); if (currentClock){
LOG_DEBUG("SCD4X readings: %u, %.2f, %.2f", co2, temperature, humidity); setI2CClock(currentClock);
if (error != SCD4X_NO_ERROR || co2 == 0) { }
LOG_ERROR("SCD4X: Skipping invalid measurement."); #endif
LOG_DEBUG("SCD4X readings: %u ppm, %.2f degC, %.2f %rh", co2, temperature, humidity);
if (error != SCD4X_NO_ERROR) {
LOG_DEBUG("SCD4X: Error while getting measurements: %u", error);
if (co2 == 0) {
LOG_ERROR("SCD4X: Skipping invalid measurement.");
}
return false; return false;
} else { } else {
measurement->variant.air_quality_metrics.has_co2_temperature = true; measurement->variant.air_quality_metrics.has_co2_temperature = true;
@ -132,19 +153,20 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
* command. 3. Issue the perform_forced_recalibration command. * command. 3. Issue the perform_forced_recalibration command.
*/ */
bool SCD4XSensor::performFRC(uint32_t targetCO2) { bool SCD4XSensor::performFRC(uint32_t targetCO2) {
uint16_t error; uint16_t error, frcCorr;
uint16_t frcCorr;
LOG_INFO("SCD4X: Issuing FRC. Ensure device has been working at least 3 minutes in stable target environment"); LOG_INFO("SCD4X: Issuing FRC. Ensure device has been working at least 3 minutes in stable target environment");
error = scd4x.stopPeriodicMeasurement(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false; return false;
} }
LOG_INFO("SCD4X: Target CO2: %u ppm", targetCO2);
error = scd4x.performForcedRecalibration((uint16_t)targetCO2, frcCorr); error = scd4x.performForcedRecalibration((uint16_t)targetCO2, frcCorr);
// SCD4X Sensirion datasheet
delay(400);
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to perform forced recalibration."); LOG_ERROR("SCD4X: Unable to perform forced recalibration.");
return false; return false;
@ -155,6 +177,67 @@ bool SCD4XSensor::performFRC(uint32_t targetCO2) {
return false; return false;
} }
LOG_INFO("SCD4X: FRC Correction successful. Correction output: %u", (uint16_t)(frcCorr-0x8000));
return true;
}
bool SCD4XSensor::startMeasurement() {
uint16_t error;
if (state == SCD4X_MEASUREMENT){
LOG_DEBUG("SCD4X: Already in measurement mode");
return true;
}
if (lowPower) {
error = scd4x.startLowPowerPeriodicMeasurement();
} else {
error = scd4x.startPeriodicMeasurement();
}
if (error == SCD4X_NO_ERROR) {
LOG_INFO("SCD4X: Started measurement mode");
if (lowPower) {
LOG_INFO("SCD4X: Low power mode");
} else {
LOG_INFO("SCD4X: Normal power mode");
}
state = SCD4X_MEASUREMENT;
return true;
} else {
LOG_ERROR("SCD4X: Couldn't start measurement mode");
return false;
}
}
bool SCD4XSensor::stopMeasurement(){
uint16_t error;
error = scd4x.stopPeriodicMeasurement();
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false;
}
state = SCD4X_IDLE;
return true;
}
bool SCD4XSensor::setPowerMode(bool _lowPower) {
lowPower = _lowPower;
if (!stopMeasurement()) {
return false;
}
if (lowPower) {
LOG_DEBUG("SCD4X: Set low power mode");
} else {
LOG_DEBUG("SCD4X: Set normal power mode");
}
return true; return true;
} }
@ -163,22 +246,26 @@ bool SCD4XSensor::performFRC(uint32_t targetCO2) {
* From Sensirion SCD4X I2C Library * From Sensirion SCD4X I2C Library
*/ */
bool SCD4XSensor::getASC(uint16_t &ascEnabled) { bool SCD4XSensor::getASC(uint16_t &_ascActive) {
uint16_t error; uint16_t error;
LOG_INFO("SCD4X: Getting ASC"); LOG_INFO("SCD4X: Getting ASC");
error = scd4x.stopPeriodicMeasurement(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false; return false;
} }
error = scd4x.getAutomaticSelfCalibrationEnabled(_ascActive);
error = scd4x.getAutomaticSelfCalibrationEnabled(ascEnabled);
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to send command."); LOG_ERROR("SCD4X: Unable to send command.");
return false; return false;
} }
if (_ascActive){
LOG_INFO("SCD4X: ASC is enabled");
} else {
LOG_INFO("SCD4X: FRC is enabled");
}
return true; return true;
} }
@ -199,9 +286,7 @@ bool SCD4XSensor::setASC(bool ascEnabled){
LOG_INFO("SCD4X: Disabling ASC"); LOG_INFO("SCD4X: Disabling ASC");
} }
error = scd4x.stopPeriodicMeasurement(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false; return false;
} }
@ -245,18 +330,18 @@ bool SCD4XSensor::setASC(bool ascEnabled){
* ppm. * ppm.
*/ */
bool SCD4XSensor::setASCBaseline(uint32_t targetCO2){ bool SCD4XSensor::setASCBaseline(uint32_t targetCO2){
// TODO - Remove?
// Available in library, but not described in datasheet.
uint16_t error; uint16_t error;
LOG_INFO("SCD4X: Setting ASC baseline"); LOG_INFO("SCD4X: Setting ASC baseline to: %u", targetCO2);
getASC(ascActive); getASC(ascActive);
if (!ascActive){ if (!ascActive){
LOG_ERROR("SCD4X: ASC is not active"); LOG_ERROR("SCD4X: Can't set ASC baseline. ASC is not active");
return false; return false;
} }
error = scd4x.stopPeriodicMeasurement(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false; return false;
} }
@ -273,6 +358,8 @@ bool SCD4XSensor::setASCBaseline(uint32_t targetCO2){
return false; return false;
} }
LOG_INFO("SCD4X: Setting ASC baseline successful");
return true; return true;
} }
@ -283,7 +370,8 @@ bool SCD4XSensor::setASCBaseline(uint32_t targetCO2){
* From Sensirion SCD4X I2C Library. * From Sensirion SCD4X I2C Library.
* *
* Setting the temperature offset of the SCD4x inside the customer device * Setting the temperature offset of the SCD4x inside the customer device
* allows the user to optimize the RH and T output signal. By default, the temperature offset is set to 4 °C. To save * allows the user to optimize the RH and T output signal.
* By default, the temperature offset is set to 4 °C. To save
* the setting to the EEPROM, the persist_settings command may be issued. * the setting to the EEPROM, the persist_settings command may be issued.
* Equation (1) details how the characteristic temperature offset can be * Equation (1) details how the characteristic temperature offset can be
* calculated using the current temperature output of the sensor (TSCD4x), a * calculated using the current temperature output of the sensor (TSCD4x), a
@ -299,50 +387,59 @@ bool SCD4XSensor::setASCBaseline(uint32_t targetCO2){
bool SCD4XSensor::setTemperature(float tempReference){ bool SCD4XSensor::setTemperature(float tempReference){
uint16_t error; uint16_t error;
float prevTempOffset; float prevTempOffset;
float updatedTempOffset;
float tempOffset; float tempOffset;
bool dataReady;
uint16_t co2; uint16_t co2;
float temperature; float temperature;
float humidity; float humidity;
LOG_INFO("SCD4X: Setting reference temperature at: %.2f". temperature);
LOG_INFO("SCD4X: Setting reference temperature at: %.2f", tempReference);
error = scd4x.getDataReadyStatus(dataReady);
if (!dataReady) {
LOG_ERROR("SCD4X: Data is not ready");
return false;
}
error = scd4x.readMeasurement(co2, temperature, humidity); error = scd4x.readMeasurement(co2, temperature, humidity);
if (error != SCD4X_NO_ERROR) { if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable read current temperature."); LOG_ERROR("SCD4X: Unable to read current temperature. Error code: %u", error);
return false; return false;
} }
LOG_INFO("SCD4X: Current sensor temperature: %.2f", temperature); LOG_INFO("SCD4X: Current sensor temperature: %.2f", temperature);
error = scd4x.stopPeriodicMeasurement(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false; return false;
} }
error = scd4x.getTemperatureOffset(prevTempOffset); error = scd4x.getTemperatureOffset(prevTempOffset);
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to get temperature offset."); LOG_ERROR("SCD4X: Unable to get temperature offset. Error code: %u", error);
return false; return false;
} }
LOG_INFO("SCD4X: Sensor temperature offset: %.2f", prevTempOffset); LOG_INFO("SCD4X: Current sensor temperature offset: %.2f", prevTempOffset);
tempOffset = temperature - tempReference + prevTempOffset; tempOffset = temperature - tempReference + prevTempOffset;
LOG_INFO("SCD4X: Setting temperature offset: %.2f", tempOffset); LOG_INFO("SCD4X: Setting temperature offset: %.2f", tempOffset);
error = scd4x.setTemperatureOffset(tempOffset); error = scd4x.setTemperatureOffset(tempOffset);
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to set temperature offset."); LOG_ERROR("SCD4X: Unable to set temperature offset. Error code: %u", error);
return false; return false;
} }
error = scd4x.persistSettings(); error = scd4x.persistSettings();
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to make settings persistent."); LOG_ERROR("SCD4X: Unable to make settings persistent. Error code: %u", error);
return false; return false;
} }
scd4x.getTemperatureOffset(updatedTempOffset);
LOG_INFO("SCD4X: Updated sensor temperature offset: %.2f", updatedTempOffset);
return true; return true;
} }
@ -358,16 +455,14 @@ bool SCD4XSensor::getAltitude(uint16_t &altitude){
uint16_t error; uint16_t error;
LOG_INFO("SCD4X: Requesting sensor altitude"); LOG_INFO("SCD4X: Requesting sensor altitude");
error = scd4x.stopPeriodicMeasurement(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false; return false;
} }
error = scd4x.getSensorAltitude(altitude); error = scd4x.getSensorAltitude(altitude);
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to get altitude."); LOG_ERROR("SCD4X: Unable to get altitude. Error code: %u", error);
return false; return false;
} }
LOG_INFO("SCD4X: Sensor altitude: %u", altitude); LOG_INFO("SCD4X: Sensor altitude: %u", altitude);
@ -375,6 +470,28 @@ bool SCD4XSensor::getAltitude(uint16_t &altitude){
return true; return true;
} }
/**
* @brief Get the ambient pressure around the sensor.
*
* From Sensirion SCD4X I2C Library.
*
* Gets the ambient pressure in Pa.
*/
bool SCD4XSensor::getAmbientPressure(uint32_t &ambientPressure){
uint16_t error;
LOG_INFO("SCD4X: Requesting sensor ambient pressure");
error = scd4x.getAmbientPressure(ambientPressure);
if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to get altitude. Error code: %u", error);
return false;
}
LOG_INFO("SCD4X: Sensor ambient pressure: %u", ambientPressure);
return true;
}
/** /**
* @brief Set the sensor altitude. * @brief Set the sensor altitude.
* *
@ -386,22 +503,20 @@ bool SCD4XSensor::getAltitude(uint16_t &altitude){
bool SCD4XSensor::setAltitude(uint32_t altitude){ bool SCD4XSensor::setAltitude(uint32_t altitude){
uint16_t error; uint16_t error;
error = scd4x.stopPeriodicMeasurement(); if (!stopMeasurement()) {
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X.");
return false; return false;
} }
error = scd4x.setSensorAltitude(altitude); error = scd4x.setSensorAltitude(altitude);
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to set altitude."); LOG_ERROR("SCD4X: Unable to set altitude. Error code: %u", error);
return false; return false;
} }
error = scd4x.persistSettings(); error = scd4x.persistSettings();
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to make settings persistent."); LOG_ERROR("SCD4X: Unable to make settings persistent. Error code: %u", error);
return false; return false;
} }
@ -427,14 +542,14 @@ bool SCD4XSensor::setAmbientPressure(uint32_t ambientPressure) {
error = scd4x.setAmbientPressure(ambientPressure); error = scd4x.setAmbientPressure(ambientPressure);
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to set altitude."); LOG_ERROR("SCD4X: Unable to set altitude. Error code: %u", error);
return false; return false;
} }
// Sensirion doesn't indicate if this is necessary. We send it anyway // Sensirion doesn't indicate if this is necessary. We send it anyway
error = scd4x.persistSettings(); error = scd4x.persistSettings();
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to make settings persistent."); LOG_ERROR("SCD4X: Unable to make settings persistent. Error code: %u", error);
return false; return false;
} }
@ -449,52 +564,106 @@ bool SCD4XSensor::setAmbientPressure(uint32_t ambientPressure) {
* The perform_factory_reset command resets all configuration settings * The perform_factory_reset command resets all configuration settings
* stored in the EEPROM and erases the FRC and ASC algorithm history. * stored in the EEPROM and erases the FRC and ASC algorithm history.
*/ */
bool SCD4XSensor::factoryReset() { bool SCD4XSensor::factoryReset() {
uint16_t error; uint16_t error;
error = scd4x.stopPeriodicMeasurement(); LOG_INFO("SCD4X: Requesting factory reset");
if (error != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Unable to set idle mode on SCD4X."); if (!stopMeasurement()) {
return false; return false;
} }
error = scd4x.performFactoryReset(); error = scd4x.performFactoryReset();
if (error != SCD4X_NO_ERROR){ if (error != SCD4X_NO_ERROR){
LOG_ERROR("SCD4X: Unable to do factory reset."); LOG_ERROR("SCD4X: Unable to do factory reset. Error code: %u", error);
return false; return false;
} }
LOG_INFO("SCD4X: Factory reset successful");
return true; return true;
} }
/**
* @brief Put the sensor into sleep mode from idle mode.
*
* From Sensirion SCD4X I2C Library.
*
* Put the sensor from idle to sleep to reduce power consumption. Can be
* used to power down when operating the sensor in power-cycled single shot
* mode.
*
* @note This command is only available in idle mode. Only for SCD41.
*/
bool SCD4XSensor::sleep() {
LOG_INFO("SCD4X: Powering down");
if (sensorVariant != SCD4X_SENSOR_VARIANT_SCD41) {
LOG_WARN("SCD4X: Can't send sensor to sleep. Incorrect variant. Ignoring");
return true;
}
if (!stopMeasurement()) {
return false;
}
if (scd4x.powerDown() != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Error trying to execute wakeUp()");
return false;
}
state = SCD4X_OFF;
return true;
}
/**
* @brief Wake up sensor from sleep mode to idle mode.
*
* From Sensirion SCD4X I2C Library.
*
* Wake up the sensor from sleep mode into idle mode. Note that the SCD4x
* does not acknowledge the wake_up command. The sensor's idle state after
* wake up can be verified by reading out the serial number.
*
* @note This command is only available for SCD41.
*/
bool SCD4XSensor::wakeUp(){
LOG_INFO("SCD4X: Waking up");
if (scd4x.wakeUp() != SCD4X_NO_ERROR) {
LOG_ERROR("SCD4X: Error trying to execute wakeUp()");
return false;
}
state = SCD4X_IDLE;
return true;
}
AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response) meshtastic_AdminMessage *response)
{ {
AdminMessageHandleResult result; AdminMessageHandleResult result;
// TODO: potentially add selftest command?
switch (request->which_payload_variant) { switch (request->which_payload_variant) {
case meshtastic_AdminMessage_sensor_config_tag: case meshtastic_AdminMessage_sensor_config_tag:
// Check for ASC-FRC request first // Check for ASC-FRC request first
if (!request->sensor_config.has_scdxx_config) { if (!request->sensor_config.has_scd4x_config) {
result = AdminMessageHandleResult::NOT_HANDLED; result = AdminMessageHandleResult::NOT_HANDLED;
break; break;
} }
if (request->sensor_config.scdxx_config.has_factory_reset) { if (request->sensor_config.scd4x_config.has_factory_reset) {
LOG_DEBUG("SCD4X: Requested factory reset"); LOG_DEBUG("SCD4X: Requested factory reset");
this->factoryReset(); this->factoryReset();
} else { } else {
if (request->sensor_config.scdxx_config.has_set_asc) { if (request->sensor_config.scd4x_config.has_set_asc) {
this->setASC(request->sensor_config.scdxx_config.set_asc); this->setASC(request->sensor_config.scd4x_config.set_asc);
if (request->sensor_config.scdxx_config.set_asc == false) { if (request->sensor_config.scd4x_config.set_asc == false) {
LOG_DEBUG("SCD4X: Request for FRC"); LOG_DEBUG("SCD4X: Request for FRC");
if (request->sensor_config.scdxx_config.has_target_co2_conc) { if (request->sensor_config.scd4x_config.has_set_target_co2_conc) {
this->performFRC(request->sensor_config.scdxx_config.target_co2_conc); this->performFRC(request->sensor_config.scd4x_config.set_target_co2_conc);
} else { } else {
// FRC requested but no target CO2 provided // FRC requested but no target CO2 provided
LOG_ERROR("SCD4X: target CO2 not provided"); LOG_ERROR("SCD4X: target CO2 not provided");
@ -503,9 +672,10 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa
} }
} else { } else {
LOG_DEBUG("SCD4X: Request for ASC"); LOG_DEBUG("SCD4X: Request for ASC");
if (request->sensor_config.scdxx_config.has_target_co2_conc) { if (request->sensor_config.scd4x_config.has_set_target_co2_conc) {
LOG_DEBUG("SCD4X: Request has target CO2"); LOG_DEBUG("SCD4X: Request has target CO2");
this->setASCBaseline(request->sensor_config.scdxx_config.target_co2_conc); // TODO - Remove? see setASCBaseline function
this->setASCBaseline(request->sensor_config.scd4x_config.set_target_co2_conc);
} else { } else {
LOG_DEBUG("SCD4X: Request doesn't have target CO2"); LOG_DEBUG("SCD4X: Request doesn't have target CO2");
} }
@ -513,19 +683,31 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa
} }
// Check for temperature offset // Check for temperature offset
if (request->sensor_config.scdxx_config.has_temperature) { // NOTE: this requires to have a sensor working on stable environment
this->setTemperature(request->sensor_config.scdxx_config.temperature); // And to make it between readings
if (request->sensor_config.scd4x_config.has_set_temperature) {
this->setTemperature(request->sensor_config.scd4x_config.set_temperature);
} }
// Check for altitude or pressure offset // Check for altitude or pressure offset
if (request->sensor_config.scdxx_config.has_altitude) { if (request->sensor_config.scd4x_config.has_set_altitude) {
this->setAltitude(request->sensor_config.scdxx_config.altitude); this->setAltitude(request->sensor_config.scd4x_config.set_altitude);
} else if (request->sensor_config.scdxx_config.has_ambient_pressure){ } else if (request->sensor_config.scd4x_config.has_set_ambient_pressure){
this->setAmbientPressure(request->sensor_config.scdxx_config.ambient_pressure); this->setAmbientPressure(request->sensor_config.scd4x_config.set_ambient_pressure);
}
// Check for low power mode
// NOTE: to switch from one mode to another do:
// setPowerMode -> startMeasurement
if (request->sensor_config.scd4x_config.has_set_power_mode) {
this->setPowerMode(request->sensor_config.scd4x_config.set_power_mode);
} }
} }
// Start measurement mode
this->startMeasurement();
result = AdminMessageHandleResult::HANDLED; result = AdminMessageHandleResult::HANDLED;
break; break;

View File

@ -22,18 +22,30 @@ class SCD4XSensor : public TelemetrySensor
bool setTemperature(float tempReference); bool setTemperature(float tempReference);
bool getAltitude(uint16_t &altitude); bool getAltitude(uint16_t &altitude);
bool setAltitude(uint32_t altitude); bool setAltitude(uint32_t altitude);
bool getAmbientPressure(uint32_t &ambientPressure);
bool setAmbientPressure(uint32_t ambientPressure); bool setAmbientPressure(uint32_t ambientPressure);
bool restoreClock(uint32_t currentClock); #ifdef SCD4X_I2C_CLOCK_SPEED
uint32_t setI2CClock(uint32_t currentClock);
#endif
bool factoryReset(); bool factoryReset();
bool setPowerMode(bool _lowPower);
bool startMeasurement();
bool stopMeasurement();
// Parameters // Parameters
uint16_t ascActive; uint16_t ascActive;
bool lowPower = true;
protected: protected:
virtual void setup() override; virtual void setup() override;
public: public:
SCD4XSensor(); SCD4XSensor();
enum SCD4XState { SCD4X_OFF, SCD4X_IDLE, SCD4X_MEASUREMENT };
SCD4XState state = SCD4X_OFF;
SCD4xSensorVariant sensorVariant;
bool sleep();
bool wakeUp();
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
virtual bool getMetrics(meshtastic_Telemetry *measurement) override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,