mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-27 11:31:47 +00:00
Abstract AirQualityTelemetry module
Previously the module was designed around a single sensor. This patch brings it into line with the same design as EnvironmentTelemetry.
This commit is contained in:
parent
a28e83c35a
commit
318da220dc
@ -10,12 +10,32 @@
|
|||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
|
#include "UnitConversions.h"
|
||||||
#include "detect/ScanI2CTwoWire.h"
|
#include "detect/ScanI2CTwoWire.h"
|
||||||
|
#include "graphics/ScreenFonts.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "sleep.h"
|
||||||
#include <Throttle.h>
|
#include <Throttle.h>
|
||||||
|
|
||||||
|
// Sensors
|
||||||
|
#include "Sensor/PMSA0031Sensor.h"
|
||||||
|
#include "Sensor/SCD4XSensor.h"
|
||||||
|
|
||||||
|
SCD4XSensor scd4xSensor;
|
||||||
|
PMSA0031Sensor pmsa0031Sensor;
|
||||||
|
|
||||||
int32_t AirQualityTelemetryModule::runOnce()
|
int32_t AirQualityTelemetryModule::runOnce()
|
||||||
{
|
{
|
||||||
|
if (sleepOnNextExecution == true) {
|
||||||
|
sleepOnNextExecution = false;
|
||||||
|
uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval,
|
||||||
|
default_telemetry_broadcast_interval_secs);
|
||||||
|
LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.", nightyNightMs);
|
||||||
|
doDeepSleep(nightyNightMs, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t result = UINT32_MAX;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Uncomment the preferences below if you want to use the module
|
Uncomment the preferences below if you want to use the module
|
||||||
without having to configure it from the PythonAPI or WebUI.
|
without having to configure it from the PythonAPI or WebUI.
|
||||||
@ -34,28 +54,13 @@ int32_t AirQualityTelemetryModule::runOnce()
|
|||||||
|
|
||||||
if (moduleConfig.telemetry.air_quality_enabled) {
|
if (moduleConfig.telemetry.air_quality_enabled) {
|
||||||
LOG_INFO("Air quality Telemetry: Initializing");
|
LOG_INFO("Air quality Telemetry: Initializing");
|
||||||
if (!aqi.begin_I2C()) {
|
|
||||||
LOG_WARN("Could not establish i2c connection to AQI sensor. Rescanning...");
|
if (scd4xSensor.hasSensor())
|
||||||
// rescan for late arriving sensors. AQI Module starts about 10 seconds into the boot so this is plenty.
|
result = scd4xSensor.runOnce();
|
||||||
uint8_t i2caddr_scan[] = {PMSA0031_ADDR};
|
if (pmsa0031Sensor.hasSensor())
|
||||||
uint8_t i2caddr_asize = 1;
|
result = pmsa0031Sensor.runOnce();
|
||||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
|
||||||
#if defined(I2C_SDA1)
|
|
||||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize);
|
|
||||||
#endif
|
|
||||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize);
|
|
||||||
auto found = i2cScanner->find(ScanI2C::DeviceType::PMSA0031);
|
|
||||||
if (found.type != ScanI2C::DeviceType::NONE) {
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first = found.address.address;
|
|
||||||
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].second =
|
|
||||||
i2cScanner->fetchI2CBus(found.address);
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
return disable();
|
|
||||||
}
|
|
||||||
return 1000;
|
|
||||||
}
|
}
|
||||||
return disable();
|
return result;
|
||||||
} else {
|
} else {
|
||||||
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
|
// if we somehow got to a second run of this module with measurement disabled, then just wait forever
|
||||||
if (!moduleConfig.telemetry.air_quality_enabled)
|
if (!moduleConfig.telemetry.air_quality_enabled)
|
||||||
@ -69,13 +74,15 @@ int32_t AirQualityTelemetryModule::runOnce()
|
|||||||
airTime->isTxAllowedAirUtil()) {
|
airTime->isTxAllowedAirUtil()) {
|
||||||
sendTelemetry();
|
sendTelemetry();
|
||||||
lastSentToMesh = millis();
|
lastSentToMesh = millis();
|
||||||
} else if (service->isToPhoneQueueEmpty()) {
|
} else if (((lastSentToPhone == 0) || !Throttle::isWithinTimespanMs(lastSentToPhone, sendToPhoneIntervalMs)) &&
|
||||||
|
(service->isToPhoneQueueEmpty())) {
|
||||||
// Just send to phone when it's not our time to send to mesh yet
|
// Just send to phone when it's not our time to send to mesh yet
|
||||||
// Only send while queue is empty (phone assumed connected)
|
// Only send while queue is empty (phone assumed connected)
|
||||||
sendTelemetry(NODENUM_BROADCAST, true);
|
sendTelemetry(NODENUM_BROADCAST, true);
|
||||||
|
lastSentToPhone = millis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sendToPhoneIntervalMs;
|
return min(sendToPhoneIntervalMs, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||||
@ -84,9 +91,9 @@ bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPack
|
|||||||
#ifdef DEBUG_PORT
|
#ifdef DEBUG_PORT
|
||||||
const char *sender = getSenderShortName(mp);
|
const char *sender = getSenderShortName(mp);
|
||||||
|
|
||||||
LOG_INFO("(Received from %s): pm10_standard=%i, pm25_standard=%i, pm100_standard=%i", sender,
|
LOG_INFO("(Received from %s): pm10_standard=%i, pm25_standard=%i, pm100_standard=%i, co2=%i ppm", sender,
|
||||||
t->variant.air_quality_metrics.pm10_standard, t->variant.air_quality_metrics.pm25_standard,
|
t->variant.air_quality_metrics.pm10_standard, t->variant.air_quality_metrics.pm25_standard,
|
||||||
t->variant.air_quality_metrics.pm100_standard);
|
t->variant.air_quality_metrics.pm100_standard, t->variant.air_quality_metrics.co2);
|
||||||
|
|
||||||
LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i",
|
LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i",
|
||||||
t->variant.air_quality_metrics.pm10_environmental, t->variant.air_quality_metrics.pm25_environmental,
|
t->variant.air_quality_metrics.pm10_environmental, t->variant.air_quality_metrics.pm25_environmental,
|
||||||
@ -102,32 +109,68 @@ bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPack
|
|||||||
return false; // Let others look at this message also if they want
|
return false; // Let others look at this message also if they want
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m)
|
bool AirQualityTelemetryModule::wantUIFrame()
|
||||||
{
|
{
|
||||||
if (!aqi.read(&data)) {
|
return moduleConfig.telemetry.environment_screen_enabled;
|
||||||
LOG_WARN("Skipping send measurements. Could not read AQIn");
|
}
|
||||||
return false;
|
|
||||||
|
void AirQualityTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||||
|
{
|
||||||
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
|
if (lastMeasurementPacket == nullptr) {
|
||||||
|
// If there's no valid packet, display "Environment"
|
||||||
|
display->drawString(x, y, "Air Quality");
|
||||||
|
display->drawString(x, y += _fontHeight(FONT_SMALL), "No measurement");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode the last measurement packet
|
||||||
|
meshtastic_Telemetry lastMeasurement;
|
||||||
|
uint32_t agoSecs = service->GetTimeSinceMeshPacket(lastMeasurementPacket);
|
||||||
|
const char *lastSender = getSenderShortName(*lastMeasurementPacket);
|
||||||
|
|
||||||
|
const meshtastic_Data &p = lastMeasurementPacket->decoded;
|
||||||
|
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &lastMeasurement)) {
|
||||||
|
display->drawString(x, y, "Measurement Error");
|
||||||
|
LOG_ERROR("Unable to decode last packet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display "Env. From: ..." on its own
|
||||||
|
display->drawString(x, y, "AQ. From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
|
||||||
|
|
||||||
|
// Continue with the remaining details
|
||||||
|
/*display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||||
|
"Temp/Hum: " + last_temp + " / " +
|
||||||
|
String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");*/
|
||||||
|
|
||||||
|
/*if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) {
|
||||||
|
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||||
|
"Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA");
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m)
|
||||||
|
{
|
||||||
|
// XXX
|
||||||
|
bool valid = true;
|
||||||
|
bool hasSensor = false;
|
||||||
m->time = getTime();
|
m->time = getTime();
|
||||||
m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
|
m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag;
|
||||||
m->variant.air_quality_metrics.pm10_standard = data.pm10_standard;
|
m->variant.air_quality_metrics = meshtastic_AirQualityMetrics_init_zero;
|
||||||
m->variant.air_quality_metrics.pm25_standard = data.pm25_standard;
|
|
||||||
m->variant.air_quality_metrics.pm100_standard = data.pm100_standard;
|
|
||||||
|
|
||||||
m->variant.air_quality_metrics.pm10_environmental = data.pm10_env;
|
if (scd4xSensor.hasSensor()) {
|
||||||
m->variant.air_quality_metrics.pm25_environmental = data.pm25_env;
|
valid = valid && scd4xSensor.getMetrics(m);
|
||||||
m->variant.air_quality_metrics.pm100_environmental = data.pm100_env;
|
hasSensor = true;
|
||||||
|
}
|
||||||
|
if (pmsa0031Sensor.hasSensor()) {
|
||||||
|
valid = valid && pmsa0031Sensor.getMetrics(m);
|
||||||
|
hasSensor = true;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INFO("(Sending): PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i",
|
return valid && hasSensor;
|
||||||
m->variant.air_quality_metrics.pm10_standard, m->variant.air_quality_metrics.pm25_standard,
|
|
||||||
m->variant.air_quality_metrics.pm100_standard);
|
|
||||||
|
|
||||||
LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i",
|
|
||||||
m->variant.air_quality_metrics.pm10_environmental, m->variant.air_quality_metrics.pm25_environmental,
|
|
||||||
m->variant.air_quality_metrics.pm100_environmental);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply()
|
meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply()
|
||||||
@ -162,6 +205,14 @@ bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
|||||||
{
|
{
|
||||||
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
|
||||||
if (getAirQualityTelemetry(&m)) {
|
if (getAirQualityTelemetry(&m)) {
|
||||||
|
LOG_INFO("(Sending): PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i, cO2=%i ppm",
|
||||||
|
m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard,
|
||||||
|
m.variant.air_quality_metrics.pm100_standard, m.variant.air_quality_metrics.co2);
|
||||||
|
|
||||||
|
LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i",
|
||||||
|
m.variant.air_quality_metrics.pm10_environmental, m.variant.air_quality_metrics.pm25_environmental,
|
||||||
|
m.variant.air_quality_metrics.pm100_environmental);
|
||||||
|
|
||||||
meshtastic_MeshPacket *p = allocDataProtobuf(m);
|
meshtastic_MeshPacket *p = allocDataProtobuf(m);
|
||||||
p->to = dest;
|
p->to = dest;
|
||||||
p->decoded.want_response = false;
|
p->decoded.want_response = false;
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "Adafruit_PM25AQI.h"
|
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
|
#include <OLEDDisplay.h>
|
||||||
|
#include <OLEDDisplayUi.h>
|
||||||
|
|
||||||
class AirQualityTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
|
class AirQualityTelemetryModule : private concurrency::OSThread, public ProtobufModule<meshtastic_Telemetry>
|
||||||
{
|
{
|
||||||
@ -20,10 +21,15 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf
|
|||||||
ProtobufModule("AirQualityTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
|
ProtobufModule("AirQualityTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg)
|
||||||
{
|
{
|
||||||
lastMeasurementPacket = nullptr;
|
lastMeasurementPacket = nullptr;
|
||||||
setIntervalFromNow(10 * 1000);
|
|
||||||
aqi = Adafruit_PM25AQI();
|
|
||||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||||
|
setIntervalFromNow(10 * 1000);
|
||||||
}
|
}
|
||||||
|
virtual bool wantUIFrame() override;
|
||||||
|
#if !HAS_SCREEN
|
||||||
|
void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||||
|
#else
|
||||||
|
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Called to handle a particular incoming message
|
/** Called to handle a particular incoming message
|
||||||
@ -42,12 +48,12 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf
|
|||||||
bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Adafruit_PM25AQI aqi;
|
|
||||||
PM25_AQI_Data data = {0};
|
|
||||||
bool firstTime = true;
|
bool firstTime = true;
|
||||||
meshtastic_MeshPacket *lastMeasurementPacket;
|
meshtastic_MeshPacket *lastMeasurementPacket;
|
||||||
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
|
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
|
||||||
uint32_t lastSentToMesh = 0;
|
uint32_t lastSentToMesh = 0;
|
||||||
|
uint32_t lastSentToPhone = 0;
|
||||||
|
uint32_t sensor_read_error_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -32,7 +32,6 @@
|
|||||||
#include "Sensor/NAU7802Sensor.h"
|
#include "Sensor/NAU7802Sensor.h"
|
||||||
#include "Sensor/OPT3001Sensor.h"
|
#include "Sensor/OPT3001Sensor.h"
|
||||||
#include "Sensor/RCWL9620Sensor.h"
|
#include "Sensor/RCWL9620Sensor.h"
|
||||||
#include "Sensor/SCD4XSensor.h"
|
|
||||||
#include "Sensor/SHT31Sensor.h"
|
#include "Sensor/SHT31Sensor.h"
|
||||||
#include "Sensor/SHT4XSensor.h"
|
#include "Sensor/SHT4XSensor.h"
|
||||||
#include "Sensor/SHTC3Sensor.h"
|
#include "Sensor/SHTC3Sensor.h"
|
||||||
@ -57,7 +56,6 @@ AHT10Sensor aht10Sensor;
|
|||||||
MLX90632Sensor mlx90632Sensor;
|
MLX90632Sensor mlx90632Sensor;
|
||||||
DFRobotLarkSensor dfRobotLarkSensor;
|
DFRobotLarkSensor dfRobotLarkSensor;
|
||||||
NAU7802Sensor nau7802Sensor;
|
NAU7802Sensor nau7802Sensor;
|
||||||
SCD4XSensor scd4xSensor;
|
|
||||||
BMP3XXSensor bmp3xxSensor;
|
BMP3XXSensor bmp3xxSensor;
|
||||||
#ifdef T1000X_SENSOR_EN
|
#ifdef T1000X_SENSOR_EN
|
||||||
T1000xSensor t1000xSensor;
|
T1000xSensor t1000xSensor;
|
||||||
@ -149,8 +147,6 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
|||||||
result = nau7802Sensor.runOnce();
|
result = nau7802Sensor.runOnce();
|
||||||
if (max17048Sensor.hasSensor())
|
if (max17048Sensor.hasSensor())
|
||||||
result = max17048Sensor.runOnce();
|
result = max17048Sensor.runOnce();
|
||||||
if (scd4xSensor.hasSensor())
|
|
||||||
result = scd4xSensor.runOnce();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -247,10 +243,6 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
|||||||
if (lastMeasurement.variant.environment_metrics.weight != 0)
|
if (lastMeasurement.variant.environment_metrics.weight != 0)
|
||||||
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
display->drawString(x, y += _fontHeight(FONT_SMALL),
|
||||||
"Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg");
|
"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)
|
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
|
||||||
@ -266,9 +258,9 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
|
|||||||
t->variant.environment_metrics.temperature);
|
t->variant.environment_metrics.temperature);
|
||||||
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f", sender, t->variant.environment_metrics.voltage,
|
LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f", sender, t->variant.environment_metrics.voltage,
|
||||||
t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance, t->variant.environment_metrics.lux);
|
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, co2=%d ppm", sender,
|
LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg", sender,
|
||||||
t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction,
|
t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction,
|
||||||
t->variant.environment_metrics.weight, t->variant.environment_metrics.co2);
|
t->variant.environment_metrics.weight);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// release previous packet before occupying a new spot
|
// release previous packet before occupying a new spot
|
||||||
@ -395,10 +387,6 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
|||||||
valid = valid && max17048Sensor.getMetrics(m);
|
valid = valid && max17048Sensor.getMetrics(m);
|
||||||
hasSensor = true;
|
hasSensor = true;
|
||||||
}
|
}
|
||||||
if (scd4xSensor.hasSensor()) {
|
|
||||||
valid = valid && scd4xSensor.getMetrics(m);
|
|
||||||
hasSensor = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return valid && hasSensor;
|
return valid && hasSensor;
|
||||||
@ -449,8 +437,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
|
|||||||
LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f, lux=%f", m.variant.environment_metrics.voltage,
|
LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f, lux=%f", m.variant.environment_metrics.voltage,
|
||||||
m.variant.environment_metrics.iaq, m.variant.environment_metrics.distance, m.variant.environment_metrics.lux);
|
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, co2=%d ppm", m.variant.environment_metrics.wind_speed,
|
LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees, weight=%fkg", m.variant.environment_metrics.wind_speed,
|
||||||
m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight, m.variant.environment_metrics.co2);
|
m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight);
|
||||||
|
|
||||||
sensor_read_error_count = 0;
|
sensor_read_error_count = 0;
|
||||||
|
|
||||||
@ -594,11 +582,6 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
|
|||||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (scd4xSensor.hasSensor()) {
|
|
||||||
result = scd4xSensor.handleAdminMessage(mp, request, response);
|
|
||||||
if (result != AdminMessageHandleResult::NOT_HANDLED)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
47
src/modules/Telemetry/Sensor/PMSA0031Sensor.cpp
Normal file
47
src/modules/Telemetry/Sensor/PMSA0031Sensor.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
|
||||||
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "PMSA0031Sensor.h"
|
||||||
|
#include "TelemetrySensor.h"
|
||||||
|
#include <Adafruit_PM25AQI.h>
|
||||||
|
|
||||||
|
PMSA0031Sensor::PMSA0031Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_PMSA003I, "PMSA0031") {}
|
||||||
|
|
||||||
|
int32_t PMSA0031Sensor::runOnce()
|
||||||
|
{
|
||||||
|
LOG_INFO("Init sensor: %s\n", sensorName);
|
||||||
|
if (!hasSensor()) {
|
||||||
|
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
|
}
|
||||||
|
aqi = Adafruit_PM25AQI();
|
||||||
|
delay(10000);
|
||||||
|
aqi.begin_I2C();
|
||||||
|
/* nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first = found.address.address;
|
||||||
|
nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].second =
|
||||||
|
i2cScanner->fetchI2CBus(found.address););*/
|
||||||
|
return initI2CSensor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PMSA0031Sensor::setup() {}
|
||||||
|
|
||||||
|
bool PMSA0031Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
|
{
|
||||||
|
uint16_t co2, error;
|
||||||
|
float temperature, humidity;
|
||||||
|
if (!aqi.read(&data)) {
|
||||||
|
LOG_WARN("Skipping send measurements. Could not read AQIn");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
measurement->variant.air_quality_metrics.pm10_standard = data.pm10_standard;
|
||||||
|
measurement->variant.air_quality_metrics.pm25_standard = data.pm25_standard;
|
||||||
|
measurement->variant.air_quality_metrics.pm100_standard = data.pm100_standard;
|
||||||
|
|
||||||
|
measurement->variant.air_quality_metrics.pm10_environmental = data.pm10_env;
|
||||||
|
measurement->variant.air_quality_metrics.pm25_environmental = data.pm25_env;
|
||||||
|
measurement->variant.air_quality_metrics.pm100_environmental = data.pm100_env;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
24
src/modules/Telemetry/Sensor/PMSA0031Sensor.h
Normal file
24
src/modules/Telemetry/Sensor/PMSA0031Sensor.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
|
||||||
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
|
#include "TelemetrySensor.h"
|
||||||
|
#include <Adafruit_PM25AQI.h>
|
||||||
|
|
||||||
|
class PMSA0031Sensor : public TelemetrySensor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Adafruit_PM25AQI aqi;
|
||||||
|
PM25_AQI_Data data = {0};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setup() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PMSA0031Sensor();
|
||||||
|
virtual int32_t runOnce() override;
|
||||||
|
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -28,28 +28,23 @@ int32_t SCD4XSensor::runOnce()
|
|||||||
return initI2CSensor();
|
return initI2CSensor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SCD4XSensor::setup()
|
void SCD4XSensor::setup() {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
{
|
{
|
||||||
uint16_t co2, error;
|
uint16_t co2, error;
|
||||||
float temperature, humidity;
|
float temperature, humidity;
|
||||||
error = scd4x.readMeasurement(
|
error = scd4x.readMeasurement(co2, temperature, humidity);
|
||||||
co2, temperature, humidity
|
|
||||||
);
|
|
||||||
if (error || co2 == 0) {
|
if (error || co2 == 0) {
|
||||||
LOG_DEBUG("Skipping invalid SCD4X measurement.\n");
|
LOG_DEBUG("Skipping invalid SCD4X measurement.\n");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
measurement->variant.environment_metrics.has_temperature = true;
|
measurement->variant.environment_metrics.has_temperature = true;
|
||||||
measurement->variant.environment_metrics.has_relative_humidity = true;
|
measurement->variant.environment_metrics.has_relative_humidity = true;
|
||||||
measurement->variant.environment_metrics.has_co2 = true;
|
measurement->variant.air_quality_metrics.has_co2 = true;
|
||||||
measurement->variant.environment_metrics.temperature = temperature;
|
measurement->variant.environment_metrics.temperature = temperature;
|
||||||
measurement->variant.environment_metrics.relative_humidity = humidity;
|
measurement->variant.environment_metrics.relative_humidity = humidity;
|
||||||
measurement->variant.environment_metrics.co2 = co2;
|
measurement->variant.air_quality_metrics.co2 = co2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user