mirror of
https://github.com/meshtastic/firmware.git
synced 2025-08-01 19:35:42 +00:00
add CO2 sensing with SCD4X
This commit is contained in:
parent
33eb073535
commit
8fa513ff1f
@ -149,6 +149,7 @@ lib_deps =
|
||||
ClosedCube OPT3001@^1.1.2
|
||||
emotibit/EmotiBit MLX90632@^1.0.8
|
||||
dfrobot/DFRobot_RTU@^1.0.3
|
||||
sensirion/Sensirion I2C SCD4x@^0.4.0
|
||||
|
||||
|
||||
https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502
|
||||
|
@ -139,6 +139,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MLX90632_ADDR 0x3A
|
||||
#define DFROBOT_LARK_ADDR 0x42
|
||||
#define NAU7802_ADDR 0x2A
|
||||
#define SCD4X_ADDR 0x62
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ACCELEROMETER
|
||||
|
@ -51,7 +51,8 @@ class ScanI2C
|
||||
AHT10,
|
||||
BMX160,
|
||||
DFROBOT_LARK,
|
||||
NAU7802
|
||||
NAU7802,
|
||||
SCD4X
|
||||
} DeviceType;
|
||||
|
||||
// typedef uint8_t DeviceAddress;
|
||||
|
@ -367,6 +367,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found\n");
|
||||
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found\n");
|
||||
|
||||
case SCD4X_ADDR:
|
||||
type = SCD4X;
|
||||
LOG_INFO("SCD4X CO2 sensor found\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address);
|
||||
}
|
||||
@ -404,4 +409,4 @@ size_t ScanI2CTwoWire::countDevices() const
|
||||
{
|
||||
return foundDevices.size();
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -583,6 +583,7 @@ void setup()
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK)
|
||||
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X)
|
||||
|
||||
i2cScanner.reset();
|
||||
#endif
|
||||
@ -1155,4 +1156,4 @@ void loop()
|
||||
}
|
||||
// if (didWake) LOG_DEBUG("wake!\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
@ -71,7 +71,9 @@ typedef enum _meshtastic_TelemetrySensorType {
|
||||
/* MAX17048 1S lipo battery sensor (voltage, state of charge, time to go) */
|
||||
meshtastic_TelemetrySensorType_MAX17048 = 28,
|
||||
/* Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor */
|
||||
meshtastic_TelemetrySensorType_CUSTOM_SENSOR = 29
|
||||
meshtastic_TelemetrySensorType_CUSTOM_SENSOR = 29,
|
||||
/* SCD40/SCD41 CO2 sensor */
|
||||
meshtastic_TelemetrySensorType_SCD4X = 30
|
||||
} meshtastic_TelemetrySensorType;
|
||||
|
||||
/* Struct definitions */
|
||||
@ -114,8 +116,8 @@ typedef struct _meshtastic_EnvironmentMetrics {
|
||||
/* Current measured (To be depreciated in favor of PowerMetrics in Meshtastic 3.x) */
|
||||
bool has_current;
|
||||
float current;
|
||||
/* relative scale IAQ value as measured by Bosch BME680 . value 0-500.
|
||||
Belongs to Air Quality but is not particle but VOC measurement. Other VOC values can also be put in here. */
|
||||
/* relative scale IAQ value as measured by Bosch BME680. value 0-500.
|
||||
Belongs to Air Quality but is not particle but VOC measurement. Other VOC values can also be put in here. */
|
||||
bool has_iaq;
|
||||
uint16_t iaq;
|
||||
/* RCWL9620 Doppler Radar Distance Sensor, used for water level detection. Float value in mm. */
|
||||
@ -134,7 +136,7 @@ typedef struct _meshtastic_EnvironmentMetrics {
|
||||
bool has_uv_lux;
|
||||
float uv_lux;
|
||||
/* Wind direction in degrees
|
||||
0 degrees = North, 90 = East, etc... */
|
||||
0 degrees = North, 90 = East, etc... */
|
||||
bool has_wind_direction;
|
||||
uint16_t wind_direction;
|
||||
/* Wind speed in m/s */
|
||||
@ -149,6 +151,9 @@ typedef struct _meshtastic_EnvironmentMetrics {
|
||||
/* Wind lull in m/s */
|
||||
bool has_wind_lull;
|
||||
float wind_lull;
|
||||
/* CO2 measured in ppm */
|
||||
bool has_co2;
|
||||
uint16_t co2;
|
||||
} meshtastic_EnvironmentMetrics;
|
||||
|
||||
/* Power Metrics (voltage / current / etc) */
|
||||
@ -267,8 +272,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_CUSTOM_SENSOR
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_CUSTOM_SENSOR+1))
|
||||
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SCD4X
|
||||
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SCD4X+1))
|
||||
|
||||
|
||||
|
||||
@ -280,14 +285,14 @@ extern "C" {
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
|
||||
#define meshtastic_Nau7802Config_init_default {0, 0}
|
||||
#define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||
#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
|
||||
@ -317,6 +322,7 @@ extern "C" {
|
||||
#define meshtastic_EnvironmentMetrics_weight_tag 15
|
||||
#define meshtastic_EnvironmentMetrics_wind_gust_tag 16
|
||||
#define meshtastic_EnvironmentMetrics_wind_lull_tag 17
|
||||
#define meshtastic_EnvironmentMetrics_co2_tag 18
|
||||
#define meshtastic_PowerMetrics_ch1_voltage_tag 1
|
||||
#define meshtastic_PowerMetrics_ch1_current_tag 2
|
||||
#define meshtastic_PowerMetrics_ch2_voltage_tag 3
|
||||
@ -379,7 +385,8 @@ X(a, STATIC, OPTIONAL, UINT32, wind_direction, 13) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, wind_speed, 14) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, weight, 15) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, wind_gust, 16) \
|
||||
X(a, STATIC, OPTIONAL, FLOAT, wind_lull, 17)
|
||||
X(a, STATIC, OPTIONAL, FLOAT, wind_lull, 17) \
|
||||
X(a, STATIC, OPTIONAL, UINT32, co2, 18)
|
||||
#define meshtastic_EnvironmentMetrics_CALLBACK NULL
|
||||
#define meshtastic_EnvironmentMetrics_DEFAULT NULL
|
||||
|
||||
@ -473,4 +480,4 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg;
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
@ -30,6 +30,7 @@
|
||||
#include "Sensor/NAU7802Sensor.h"
|
||||
#include "Sensor/OPT3001Sensor.h"
|
||||
#include "Sensor/RCWL9620Sensor.h"
|
||||
#include "Sensor/SCD4XSensor.h"
|
||||
#include "Sensor/SHT31Sensor.h"
|
||||
#include "Sensor/SHT4XSensor.h"
|
||||
#include "Sensor/SHTC3Sensor.h"
|
||||
@ -54,6 +55,7 @@ AHT10Sensor aht10Sensor;
|
||||
MLX90632Sensor mlx90632Sensor;
|
||||
DFRobotLarkSensor dfRobotLarkSensor;
|
||||
NAU7802Sensor nau7802Sensor;
|
||||
SCD4XSensor scd4xSensor;
|
||||
#ifdef T1000X_SENSOR_EN
|
||||
T1000xSensor t1000xSensor;
|
||||
#endif
|
||||
@ -139,6 +141,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
result = mlx90632Sensor.runOnce();
|
||||
if (nau7802Sensor.hasSensor())
|
||||
result = nau7802Sensor.runOnce();
|
||||
if (scd4xSensor.hasSensor())
|
||||
result = scd4xSensor.runOnce();
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
@ -252,6 +256,10 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
if (lastMeasurement.variant.environment_metrics.weight != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg");
|
||||
|
||||
if (lastMeasurement.variant.environment_metrics.co2 != 0)
|
||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||
"CO2: " + String(lastMeasurement.variant.environment_metrics.co2) + " ppm");
|
||||
}
|
||||
|
||||
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||
@ -268,9 +276,9 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
|
||||
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", sender, t->variant.environment_metrics.voltage,
|
||||
t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance, t->variant.environment_metrics.lux);
|
||||
|
||||
LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", sender,
|
||||
LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg, co2=%d ppm\n", sender,
|
||||
t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction,
|
||||
t->variant.environment_metrics.weight);
|
||||
t->variant.environment_metrics.weight, t->variant.environment_metrics.co2);
|
||||
|
||||
#endif
|
||||
// release previous packet before occupying a new spot
|
||||
@ -383,6 +391,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity;
|
||||
}
|
||||
}
|
||||
if (scd4xSensor.hasSensor()) {
|
||||
valid = valid && scd4xSensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
return valid && hasSensor;
|
||||
@ -433,8 +445,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
||||
LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", m.variant.environment_metrics.voltage,
|
||||
m.variant.environment_metrics.iaq, m.variant.environment_metrics.distance, m.variant.environment_metrics.lux);
|
||||
|
||||
LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", m.variant.environment_metrics.wind_speed,
|
||||
m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight);
|
||||
LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees, weight=%fkg, co2=%d ppm\n", m.variant.environment_metrics.wind_speed,
|
||||
m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight, m.variant.environment_metrics.co2);
|
||||
|
||||
sensor_read_error_count = 0;
|
||||
|
||||
@ -568,7 +580,12 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
if (scd4xSensor.hasSensor()) {
|
||||
result = scd4xSensor.handleAdminMessage(mp, request, response);
|
||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
57
src/modules/Telemetry/Sensor/SCD4XSensor.cpp
Normal file
57
src/modules/Telemetry/Sensor/SCD4XSensor.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "SCD4XSensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <SensirionI2CScd4x.h>
|
||||
|
||||
SCD4XSensor::SCD4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SCD4X, "SCD4X") {}
|
||||
|
||||
int32_t SCD4XSensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s\n", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
// scd4x = SensirionI2CScd4x(nodeTelemetrySensorsMap[sensorType].second);
|
||||
// status = scd4x.begin(nodeTelemetrySensorsMap[sensorType].first);
|
||||
scd4x.begin(*nodeTelemetrySensorsMap[sensorType].second);
|
||||
scd4x.stopPeriodicMeasurement();
|
||||
status = scd4x.startLowPowerPeriodicMeasurement();
|
||||
if (status == 0) {
|
||||
status = 1;
|
||||
} else {
|
||||
status = 0;
|
||||
}
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void SCD4XSensor::setup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
uint16_t co2, error;
|
||||
float temperature, humidity;
|
||||
error = scd4x.readMeasurement(
|
||||
co2, temperature, humidity
|
||||
);
|
||||
if (error || co2 == 0) {
|
||||
LOG_DEBUG("Skipping invalid SCD4X measurement.\n");
|
||||
return false;
|
||||
} else {
|
||||
measurement->variant.environment_metrics.has_temperature = true;
|
||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
||||
measurement->variant.environment_metrics.has_co2 = true;
|
||||
measurement->variant.environment_metrics.temperature = temperature;
|
||||
measurement->variant.environment_metrics.relative_humidity = humidity;
|
||||
measurement->variant.environment_metrics.co2 = co2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
23
src/modules/Telemetry/Sensor/SCD4XSensor.h
Normal file
23
src/modules/Telemetry/Sensor/SCD4XSensor.h
Normal file
@ -0,0 +1,23 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <SensirionI2CScd4x.h>
|
||||
|
||||
class SCD4XSensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
SensirionI2CScd4x scd4x = SensirionI2CScd4x();
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
SCD4XSensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user