Refurbish ReClockI2C API
* Make ReClockI2C API class * Use new API in AirQualityTelemetry module * Minor changes on some logs
This commit is contained in:
@@ -0,0 +1,98 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef RECLOCK_I2C_
|
||||||
|
#define RECLOCK_I2C_
|
||||||
|
|
||||||
|
#include "../graphics/Screen.h"
|
||||||
|
#include "ScanI2CTwoWire.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Class to set and restore the I2C clock temporarily on a i2cBus
|
||||||
|
See https://github.com/arduino/Arduino/issues/11457
|
||||||
|
Currently, only ESP32 can getClock()
|
||||||
|
While all cores can setClock()
|
||||||
|
https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50
|
||||||
|
https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60
|
||||||
|
https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103
|
||||||
|
For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes)
|
||||||
|
we need to reclock I2C and set it back to the previous stablished speed.
|
||||||
|
Only for cases where we can know it (ESP32 or known screen) we can do this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern graphics::Screen *screen;
|
||||||
|
|
||||||
|
class ReClockI2C
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setup(TwoWire *i2cBus, ScanI2C::I2CPort port)
|
||||||
|
{
|
||||||
|
this->i2cBus = i2cBus;
|
||||||
|
this->port = port;
|
||||||
|
this->previousClock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setClock(uint32_t desiredClock)
|
||||||
|
{
|
||||||
|
uint32_t currentClock = this->getClock();
|
||||||
|
|
||||||
|
if (currentClock) {
|
||||||
|
LOG_DEBUG("Current I2C frequency: %uHz", currentClock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentClock != desiredClock) {
|
||||||
|
LOG_DEBUG("Changing I2C clock to %uHz", desiredClock);
|
||||||
|
this->i2cBus->setClock(desiredClock);
|
||||||
|
// If the clock is 0Hz, we still store it
|
||||||
|
// We'll check in restoreClock function
|
||||||
|
setPreviousClock(currentClock);
|
||||||
|
LOG_DEBUG("Stored previous clock I2C clock: %uHz", this->previousClock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("I2C clock was already %uHz. Skipping", desiredClock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool restoreClock()
|
||||||
|
{
|
||||||
|
if (this->previousClock) {
|
||||||
|
LOG_DEBUG("Restoring I2C clock to %uHz", this->previousClock);
|
||||||
|
i2cBus->setClock(this->previousClock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOG_DEBUG("I2C clock was unknown. Not restored");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TwoWire *i2cBus{};
|
||||||
|
ScanI2C::I2CPort port{};
|
||||||
|
uint32_t previousClock = 0;
|
||||||
|
|
||||||
|
void setPreviousClock(uint32_t clock) { this->previousClock = clock; }
|
||||||
|
|
||||||
|
uint32_t getClock()
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef CAN_GET_I2C_CLOCK
|
||||||
|
return this->i2cBus->getClock();
|
||||||
|
#elif HAS_SCREEN
|
||||||
|
if (screen) {
|
||||||
|
// If we get a non-zero response here, the screen has set a speed
|
||||||
|
uint32_t screenClock = 0;
|
||||||
|
ScanI2C::I2CPort screenPort = ScanI2C::I2CPort::NO_I2C;
|
||||||
|
screenClock = screen->getI2cFrequency();
|
||||||
|
screenPort = screen->getI2CPort();
|
||||||
|
// Check if i2c port is the same, and that we got a screenClock back (0 means the screen didn't set it)
|
||||||
|
if (screenClock && (screenPort == this->port)) {
|
||||||
|
LOG_DEBUG("Screen defined I2C frequency: %uHz", screenClock);
|
||||||
|
return screenClock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#include "reClockI2C.h"
|
|
||||||
#include "ScanI2CTwoWire.h"
|
|
||||||
|
|
||||||
/* See https://github.com/arduino/Arduino/issues/11457
|
|
||||||
Currently, only ESP32 can getClock()
|
|
||||||
While all cores can setClock()
|
|
||||||
https://github.com/sandeepmistry/arduino-nRF5/blob/master/libraries/Wire/Wire.h#L50
|
|
||||||
https://github.com/earlephilhower/arduino-pico/blob/master/libraries/Wire/src/Wire.h#L60
|
|
||||||
https://github.com/stm32duino/Arduino_Core_STM32/blob/main/libraries/Wire/src/Wire.h#L103
|
|
||||||
For cases when I2C speed is different to the ones defined by sensors (see defines in sensor classes)
|
|
||||||
we need to reclock I2C and set it back to the previous stablished speed.
|
|
||||||
Only for cases where we can know it (ESP32 or known screen) we can do this.
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, ScanI2C::I2CPort port)
|
|
||||||
{
|
|
||||||
|
|
||||||
uint32_t currentClock = 0;
|
|
||||||
uint32_t screenClock = 0;
|
|
||||||
ScanI2C::I2CPort screenPort = ScanI2C::I2CPort::NO_I2C;
|
|
||||||
|
|
||||||
// Assume that if we can't getClock, or there is no screen, we can set the clock speed at will
|
|
||||||
#ifdef CAN_RECLOCK_I2C
|
|
||||||
currentClock = i2cBus->getClock();
|
|
||||||
LOG_DEBUG("Current I2C frequency: %uHz", currentClock);
|
|
||||||
#elif HAS_SCREEN
|
|
||||||
if (screen) {
|
|
||||||
// If we get a non-zero response here, the screen has set a speed
|
|
||||||
screenClock = screen->getI2cFrequency();
|
|
||||||
screenPort = screen->getI2CPort();
|
|
||||||
// Check if i2c port is the same, and that we got a screenClock back (0 means the screen didn't set it)
|
|
||||||
if (screenClock && (screenPort == port))
|
|
||||||
currentClock = screenClock;
|
|
||||||
LOG_DEBUG("Screen defined I2C frequency: %uHz", screenClock);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (currentClock != desiredClock) {
|
|
||||||
LOG_DEBUG("Changing I2C clock to %uHz", desiredClock);
|
|
||||||
i2cBus->setClock(desiredClock);
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentClock;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
#ifndef RECLOCK_I2C_
|
|
||||||
#define RECLOCK_I2C_
|
|
||||||
|
|
||||||
#include "../graphics/Screen.h"
|
|
||||||
#include "ScanI2CTwoWire.h"
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, ScanI2C::I2CPort port);
|
|
||||||
|
|
||||||
extern graphics::Screen *screen;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -110,10 +110,10 @@ int32_t AirQualityTelemetryModule::runOnce()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wake up the sensors that need it
|
// Wake up the sensors that need it
|
||||||
LOG_INFO("Waking up sensors...");
|
|
||||||
uint32_t lastTelemetry =
|
uint32_t lastTelemetry =
|
||||||
transmitHistory ? transmitHistory->getLastSentToMeshMillis(TX_HISTORY_KEY_AIR_QUALITY_TELEMETRY) : 0;
|
transmitHistory ? transmitHistory->getLastSentToMeshMillis(TX_HISTORY_KEY_AIR_QUALITY_TELEMETRY) : 0;
|
||||||
for (TelemetrySensor *sensor : sensors) {
|
for (TelemetrySensor *sensor : sensors) {
|
||||||
|
LOG_DEBUG("Checking if %s needs to wake up", sensor->sensorName);
|
||||||
if (!sensor->canSleep()) {
|
if (!sensor->canSleep()) {
|
||||||
LOG_DEBUG("%s sensor doesn't have sleep feature. Skipping", sensor->sensorName);
|
LOG_DEBUG("%s sensor doesn't have sleep feature. Skipping", sensor->sensorName);
|
||||||
} else if (((lastTelemetry == 0) || !Throttle::isWithinTimespanMs(lastTelemetry - sensor->wakeUpTimeMs(),
|
} else if (((lastTelemetry == 0) || !Throttle::isWithinTimespanMs(lastTelemetry - sensor->wakeUpTimeMs(),
|
||||||
@@ -154,8 +154,8 @@ int32_t AirQualityTelemetryModule::runOnce()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send to sleep sensors that consume power
|
// Send to sleep sensors that consume power
|
||||||
LOG_DEBUG("Sending sensors to sleep");
|
|
||||||
for (TelemetrySensor *sensor : sensors) {
|
for (TelemetrySensor *sensor : sensors) {
|
||||||
|
LOG_DEBUG("Checking if %s can be sent to sleep", sensor->sensorName);
|
||||||
if (sensor->isActive() && sensor->canSleep()) {
|
if (sensor->isActive() && sensor->canSleep()) {
|
||||||
if (sensor->wakeUpTimeMs() <
|
if (sensor->wakeUpTimeMs() <
|
||||||
(int32_t)Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval,
|
(int32_t)Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||||
|
|
||||||
#include "../detect/reClockI2C.h"
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "PMSA003ISensor.h"
|
#include "PMSA003ISensor.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
@@ -13,31 +12,36 @@ PMSA003ISensor::PMSA003ISensor() : TelemetrySensor(meshtastic_TelemetrySensorTyp
|
|||||||
|
|
||||||
bool PMSA003ISensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
bool PMSA003ISensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
{
|
{
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
LOG_INFO("%s: Init sensor", sensorName);
|
||||||
#ifdef PMSA003I_ENABLE_PIN
|
#ifdef PMSA003I_ENABLE_PIN
|
||||||
pinMode(PMSA003I_ENABLE_PIN, OUTPUT);
|
pinMode(PMSA003I_ENABLE_PIN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// TODO PMS5003I sometimes get late to the party...
|
||||||
|
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
_address = dev->address.address;
|
_address = dev->address.address;
|
||||||
_port = dev->address.port;
|
|
||||||
|
|
||||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED);
|
_port = dev->address.port;
|
||||||
uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setup(_bus, _port);
|
||||||
|
|
||||||
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED);
|
||||||
|
reClockI2C.setClock(PMSA003I_I2C_CLOCK_SPEED);
|
||||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
_bus->beginTransmission(_address);
|
_bus->beginTransmission(_address);
|
||||||
if (_bus->endTransmission() != 0) {
|
if (_bus->endTransmission() != 0) {
|
||||||
LOG_WARN("%s not found on I2C at 0x12", sensorName);
|
LOG_WARN("%s not found on I2C at 0x12", sensorName);
|
||||||
|
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||||
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
|
reClockI2C.restoreClock();
|
||||||
|
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
status = 1;
|
status = 1;
|
||||||
@@ -55,13 +59,17 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(PMSA003I_I2C_CLOCK_SPEED);
|
||||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
_bus->requestFrom(_address, (uint8_t)PMSA003I_FRAME_LENGTH);
|
_bus->requestFrom(_address, (uint8_t)PMSA003I_FRAME_LENGTH);
|
||||||
if (_bus->available() < PMSA003I_FRAME_LENGTH) {
|
if (_bus->available() < PMSA003I_FRAME_LENGTH) {
|
||||||
LOG_WARN("%s read failed: incomplete data (%d bytes)", sensorName, _bus->available());
|
LOG_WARN("%s: read failed: incomplete data (%d bytes)", sensorName, _bus->available());
|
||||||
|
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||||
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
|
reClockI2C.restoreClock();
|
||||||
|
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,14 +78,12 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (buffer[0] != 0x42 || buffer[1] != 0x4D) {
|
if (buffer[0] != 0x42 || buffer[1] != 0x4D) {
|
||||||
LOG_WARN("%s frame header invalid: 0x%02X 0x%02X", sensorName, buffer[0], buffer[1]);
|
LOG_WARN("%s: frame header invalid: 0x%02X 0x%02X", sensorName, buffer[0], buffer[1]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +139,7 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
measurement->variant.air_quality_metrics.has_particles_100um = true;
|
measurement->variant.air_quality_metrics.has_particles_100um = true;
|
||||||
measurement->variant.air_quality_metrics.particles_100um = read16(buffer, 26);
|
measurement->variant.air_quality_metrics.particles_100um = read16(buffer, 26);
|
||||||
|
|
||||||
LOG_DEBUG("Got %s readings: pM1p0_standard=%u, pM2p5_standard=%u, pM10p0_standard=%u", sensorName,
|
LOG_DEBUG("%s: Got readings: pM1p0_standard=%u, pM2p5_standard=%u, pM10p0_standard=%u", sensorName,
|
||||||
measurement->variant.air_quality_metrics.pm10_standard, measurement->variant.air_quality_metrics.pm25_standard,
|
measurement->variant.air_quality_metrics.pm10_standard, measurement->variant.air_quality_metrics.pm25_standard,
|
||||||
measurement->variant.air_quality_metrics.pm100_standard);
|
measurement->variant.air_quality_metrics.pm100_standard);
|
||||||
|
|
||||||
@@ -192,7 +198,7 @@ void PMSA003ISensor::sleep()
|
|||||||
uint32_t PMSA003ISensor::wakeUp()
|
uint32_t PMSA003ISensor::wakeUp()
|
||||||
{
|
{
|
||||||
#ifdef PMSA003I_ENABLE_PIN
|
#ifdef PMSA003I_ENABLE_PIN
|
||||||
LOG_INFO("Waking up %s", sensorName);
|
LOG_INFO("%s: Waking up", sensorName);
|
||||||
digitalWrite(PMSA003I_ENABLE_PIN, HIGH);
|
digitalWrite(PMSA003I_ENABLE_PIN, HIGH);
|
||||||
state = State::ACTIVE;
|
state = State::ACTIVE;
|
||||||
pmMeasureStarted = getTime();
|
pmMeasureStarted = getTime();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||||
|
|
||||||
|
#include "../detect/ReClockI2C.h"
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
@@ -35,7 +36,10 @@ class PMSA003ISensor : public TelemetrySensor
|
|||||||
uint8_t buffer[PMSA003I_FRAME_LENGTH]{};
|
uint8_t buffer[PMSA003I_FRAME_LENGTH]{};
|
||||||
TwoWire *_bus{};
|
TwoWire *_bus{};
|
||||||
uint8_t _address{};
|
uint8_t _address{};
|
||||||
|
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||||
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
||||||
|
ReClockI2C reClockI2C;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd30.h>)
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd30.h>)
|
||||||
|
|
||||||
#include "../detect/reClockI2C.h"
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "SCD30Sensor.h"
|
#include "SCD30Sensor.h"
|
||||||
|
|
||||||
@@ -12,15 +11,16 @@ SCD30Sensor::SCD30Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SCD3
|
|||||||
|
|
||||||
bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
{
|
{
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
LOG_INFO("%s: Init sensor", sensorName);
|
||||||
|
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
_address = dev->address.address;
|
_address = dev->address.address;
|
||||||
_port = dev->address.port;
|
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
_port = dev->address.port;
|
||||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setup(_bus, _port);
|
||||||
|
|
||||||
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
||||||
|
reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
scd30.begin(*_bus, _address);
|
scd30.begin(*_bus, _address);
|
||||||
@@ -28,10 +28,8 @@ bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
if (!startMeasurement()) {
|
if (!startMeasurement()) {
|
||||||
LOG_ERROR("%s: Failed to start periodic measurement", sensorName);
|
LOG_ERROR("%s: Failed to start periodic measurement", sensorName);
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -41,10 +39,8 @@ bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (state == SCD30_MEASUREMENT) {
|
if (state == SCD30_MEASUREMENT) {
|
||||||
@@ -63,31 +59,27 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
float co2, temperature, humidity;
|
float co2, temperature, humidity;
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (scd30.readMeasurementData(co2, temperature, humidity) != SCD30_NO_ERROR) {
|
if (scd30.readMeasurementData(co2, temperature, humidity) != SCD30_NO_ERROR) {
|
||||||
LOG_ERROR("SCD30: Failed to read measurement data.");
|
LOG_ERROR("%s: Failed to read measurement data", sensorName);
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (co2 == 0) {
|
if (co2 == 0) {
|
||||||
LOG_ERROR("SCD30: Invalid CO₂ reading.");
|
LOG_ERROR("%s: Invalid CO₂ reading", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +90,7 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
measurement->variant.air_quality_metrics.co2_temperature = temperature;
|
measurement->variant.air_quality_metrics.co2_temperature = temperature;
|
||||||
measurement->variant.air_quality_metrics.co2_humidity = humidity;
|
measurement->variant.air_quality_metrics.co2_humidity = humidity;
|
||||||
|
|
||||||
LOG_DEBUG("Got %s readings: co2=%u, co2_temp=%.2f, co2_hum=%.2f", sensorName, (uint32_t)co2, temperature, humidity);
|
LOG_DEBUG("%s: Got readings: co2=%u, co2_temp=%.2f, co2_hum=%.2f", sensorName, (uint32_t)co2, temperature, humidity);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -285,7 +277,7 @@ bool SCD30Sensor::setTemperature(float tempReference)
|
|||||||
|
|
||||||
tempOffset = (temperature - tempReference);
|
tempOffset = (temperature - tempReference);
|
||||||
if (tempOffset < 0) {
|
if (tempOffset < 0) {
|
||||||
LOG_ERROR("%s temperature offset is only positive", sensorName);
|
LOG_ERROR("%s: temperature offset is only positive", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,17 +367,15 @@ bool SCD30Sensor::isActive()
|
|||||||
uint32_t SCD30Sensor::wakeUp()
|
uint32_t SCD30Sensor::wakeUp()
|
||||||
{
|
{
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
startMeasurement();
|
startMeasurement();
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -398,17 +388,15 @@ uint32_t SCD30Sensor::wakeUp()
|
|||||||
void SCD30Sensor::sleep()
|
void SCD30Sensor::sleep()
|
||||||
{
|
{
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
stopMeasurement();
|
stopMeasurement();
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,8 +421,8 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa
|
|||||||
AdminMessageHandleResult result;
|
AdminMessageHandleResult result;
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
switch (request->which_payload_variant) {
|
switch (request->which_payload_variant) {
|
||||||
@@ -491,10 +479,8 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd30.h>)
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd30.h>)
|
||||||
|
|
||||||
|
#include "../detect/ReClockI2C.h"
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
#include <SensirionI2cScd30.h>
|
#include <SensirionI2cScd30.h>
|
||||||
@@ -14,7 +15,10 @@ class SCD30Sensor : public TelemetrySensor
|
|||||||
SensirionI2cScd30 scd30;
|
SensirionI2cScd30 scd30;
|
||||||
TwoWire *_bus{};
|
TwoWire *_bus{};
|
||||||
uint8_t _address{};
|
uint8_t _address{};
|
||||||
|
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||||
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
||||||
|
ReClockI2C reClockI2C;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool performFRC(uint16_t targetCO2);
|
bool performFRC(uint16_t targetCO2);
|
||||||
bool setASC(bool ascEnabled);
|
bool setASC(bool ascEnabled);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd4x.h>)
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd4x.h>)
|
||||||
|
|
||||||
#include "../detect/reClockI2C.h"
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "SCD4XSensor.h"
|
#include "SCD4XSensor.h"
|
||||||
|
|
||||||
@@ -18,8 +17,11 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
_address = dev->address.address;
|
_address = dev->address.address;
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
_port = dev->address.port;
|
||||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setup(_bus, _port);
|
||||||
|
|
||||||
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
||||||
|
reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
scd4x.begin(*_bus, _address);
|
scd4x.begin(*_bus, _address);
|
||||||
@@ -30,10 +32,8 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
// Stop periodic measurement
|
// Stop periodic measurement
|
||||||
if (!stopMeasurement()) {
|
if (!stopMeasurement()) {
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -46,10 +46,8 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
if (!powerUp()) {
|
if (!powerUp()) {
|
||||||
LOG_ERROR("%s: Error trying to execute powerUp()", sensorName);
|
LOG_ERROR("%s: Error trying to execute powerUp()", sensorName);
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -58,10 +56,8 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
if (!getASC(ascActive)) {
|
if (!getASC(ascActive)) {
|
||||||
LOG_ERROR("%s: Unable to check if ASC is enabled", sensorName);
|
LOG_ERROR("%s: Unable to check if ASC is enabled", sensorName);
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -70,19 +66,15 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
if (!startMeasurement()) {
|
if (!startMeasurement()) {
|
||||||
LOG_ERROR("%s: Couldn't start measurement", sensorName);
|
LOG_ERROR("%s: Couldn't start measurement", sensorName);
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (state == SCD4X_MEASUREMENT) {
|
if (state == SCD4X_MEASUREMENT) {
|
||||||
@@ -108,18 +100,16 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
float temperature, humidity;
|
float temperature, humidity;
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
bool dataReady;
|
bool dataReady;
|
||||||
error = scd4x.getDataReadyStatus(dataReady);
|
error = scd4x.getDataReadyStatus(dataReady);
|
||||||
if (error != SCD4X_NO_ERROR || !dataReady) {
|
if (error != SCD4X_NO_ERROR || !dataReady) {
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
LOG_ERROR("SCD4X: Data is not ready");
|
LOG_ERROR("SCD4X: Data is not ready");
|
||||||
return false;
|
return false;
|
||||||
@@ -128,10 +118,8 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
error = scd4x.readMeasurement(co2, temperature, humidity);
|
error = scd4x.readMeasurement(co2, temperature, humidity);
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
LOG_DEBUG("Got %s readings: co2=%u, co2_temp=%.2f, co2_hum%.2f", sensorName, co2, temperature, humidity);
|
LOG_DEBUG("Got %s readings: co2=%u, co2_temp=%.2f, co2_hum%.2f", sensorName, co2, temperature, humidity);
|
||||||
@@ -646,16 +634,14 @@ bool SCD4XSensor::powerDown()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (!stopMeasurement()) {
|
if (!stopMeasurement()) {
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -663,19 +649,15 @@ bool SCD4XSensor::powerDown()
|
|||||||
if (scd4x.powerDown() != SCD4X_NO_ERROR) {
|
if (scd4x.powerDown() != SCD4X_NO_ERROR) {
|
||||||
LOG_ERROR("%s: Error trying to execute sleep()", sensorName);
|
LOG_ERROR("%s: Error trying to execute sleep()", sensorName);
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
state = SCD4X_OFF;
|
state = SCD4X_OFF;
|
||||||
@@ -723,26 +705,22 @@ uint32_t SCD4XSensor::wakeUp()
|
|||||||
{
|
{
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (startMeasurement()) {
|
if (startMeasurement()) {
|
||||||
co2MeasureStarted = getTime();
|
co2MeasureStarted = getTime();
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
return SCD4X_WARMUP_MS;
|
return SCD4X_WARMUP_MS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -755,17 +733,15 @@ uint32_t SCD4XSensor::wakeUp()
|
|||||||
void SCD4XSensor::sleep()
|
void SCD4XSensor::sleep()
|
||||||
{
|
{
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
stopMeasurement();
|
stopMeasurement();
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,8 +782,8 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa
|
|||||||
AdminMessageHandleResult result;
|
AdminMessageHandleResult result;
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
LOG_INFO("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
// TODO: potentially add selftest command?
|
// TODO: potentially add selftest command?
|
||||||
@@ -911,10 +887,8 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa
|
|||||||
this->startMeasurement();
|
this->startMeasurement();
|
||||||
|
|
||||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd4x.h>)
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd4x.h>)
|
||||||
|
|
||||||
|
#include "../detect/ReClockI2C.h"
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
#include <SensirionI2cScd4x.h>
|
#include <SensirionI2cScd4x.h>
|
||||||
|
|
||||||
// Max speed 400kHz
|
// Max speed 400kHz
|
||||||
#define SCD4X_I2C_CLOCK_SPEED 100000
|
#define SCD4X_I2C_CLOCK_SPEED 400000
|
||||||
#define SCD4X_WARMUP_MS 5000
|
#define SCD4X_WARMUP_MS 5000
|
||||||
|
|
||||||
class SCD4XSensor : public TelemetrySensor
|
class SCD4XSensor : public TelemetrySensor
|
||||||
@@ -17,7 +18,10 @@ class SCD4XSensor : public TelemetrySensor
|
|||||||
SensirionI2cScd4x scd4x;
|
SensirionI2cScd4x scd4x;
|
||||||
TwoWire *_bus{};
|
TwoWire *_bus{};
|
||||||
uint8_t _address{};
|
uint8_t _address{};
|
||||||
|
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||||
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
||||||
|
ReClockI2C reClockI2C;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool performFRC(uint32_t targetCO2);
|
bool performFRC(uint32_t targetCO2);
|
||||||
bool setASCBaseline(uint32_t targetCO2);
|
bool setASCBaseline(uint32_t targetCO2);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||||
|
|
||||||
#include "../detect/reClockI2C.h"
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
#include "SEN5XSensor.h"
|
#include "SEN5XSensor.h"
|
||||||
@@ -18,7 +17,7 @@ SEN5XSensor::SEN5XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SEN5
|
|||||||
bool SEN5XSensor::getVersion()
|
bool SEN5XSensor::getVersion()
|
||||||
{
|
{
|
||||||
if (!sendCommand(SEN5X_GET_FIRMWARE_VERSION)) {
|
if (!sendCommand(SEN5X_GET_FIRMWARE_VERSION)) {
|
||||||
LOG_ERROR("SEN5X: Error sending version command");
|
LOG_ERROR("%s: Error sending version command", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(20); // From Sensirion Datasheet
|
delay(20); // From Sensirion Datasheet
|
||||||
@@ -26,7 +25,7 @@ bool SEN5XSensor::getVersion()
|
|||||||
uint8_t versionBuffer[12]{};
|
uint8_t versionBuffer[12]{};
|
||||||
size_t charNumber = readBuffer(&versionBuffer[0], 3);
|
size_t charNumber = readBuffer(&versionBuffer[0], 3);
|
||||||
if (charNumber == 0) {
|
if (charNumber == 0) {
|
||||||
LOG_ERROR("SEN5X: Error getting data ready flag value");
|
LOG_ERROR("%s: Error getting data ready flag value", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,9 +33,9 @@ bool SEN5XSensor::getVersion()
|
|||||||
hardwareVer = versionBuffer[3] + (versionBuffer[4] / 10);
|
hardwareVer = versionBuffer[3] + (versionBuffer[4] / 10);
|
||||||
protocolVer = versionBuffer[5] + (versionBuffer[6] / 10);
|
protocolVer = versionBuffer[5] + (versionBuffer[6] / 10);
|
||||||
|
|
||||||
LOG_INFO("SEN5X Firmware Version: %0.2f", firmwareVer);
|
LOG_INFO("%s: Firmware Version: %0.2f", sensorName, firmwareVer);
|
||||||
LOG_INFO("SEN5X Hardware Version: %0.2f", hardwareVer);
|
LOG_INFO("%s: Hardware Version: %0.2f", sensorName, hardwareVer);
|
||||||
LOG_INFO("SEN5X Protocol Version: %0.2f", protocolVer);
|
LOG_INFO("%s: Protocol Version: %0.2f", sensorName, protocolVer);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -44,7 +43,7 @@ bool SEN5XSensor::getVersion()
|
|||||||
bool SEN5XSensor::findModel()
|
bool SEN5XSensor::findModel()
|
||||||
{
|
{
|
||||||
if (!sendCommand(SEN5X_GET_PRODUCT_NAME)) {
|
if (!sendCommand(SEN5X_GET_PRODUCT_NAME)) {
|
||||||
LOG_ERROR("SEN5X: Error asking for product name");
|
LOG_ERROR("%s: Error asking for product name", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(50); // From Sensirion Datasheet
|
delay(50); // From Sensirion Datasheet
|
||||||
@@ -53,7 +52,7 @@ bool SEN5XSensor::findModel()
|
|||||||
uint8_t name[nameSize];
|
uint8_t name[nameSize];
|
||||||
size_t charNumber = readBuffer(&name[0], nameSize);
|
size_t charNumber = readBuffer(&name[0], nameSize);
|
||||||
if (charNumber == 0) {
|
if (charNumber == 0) {
|
||||||
LOG_ERROR("SEN5X: Error getting device name");
|
LOG_ERROR("%s: Error getting device name", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,15 +60,15 @@ bool SEN5XSensor::findModel()
|
|||||||
switch (name[4]) {
|
switch (name[4]) {
|
||||||
case 48:
|
case 48:
|
||||||
model = SEN50;
|
model = SEN50;
|
||||||
LOG_INFO("SEN5X: found sensor model SEN50");
|
LOG_INFO("%s: found sensor model SEN50", sensorName);
|
||||||
break;
|
break;
|
||||||
case 52:
|
case 52:
|
||||||
model = SEN54;
|
model = SEN54;
|
||||||
LOG_INFO("SEN5X: found sensor model SEN54");
|
LOG_INFO("%s: found sensor model SEN54", sensorName);
|
||||||
break;
|
break;
|
||||||
case 53:
|
case 53:
|
||||||
model = SEN55;
|
model = SEN55;
|
||||||
LOG_INFO("SEN5X: found sensor model SEN55");
|
LOG_INFO("%s: found sensor model SEN55", sensorName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,8 +133,8 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED);
|
LOG_DEBUG("%s: Attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SEN5X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
// Transmit the data
|
// Transmit the data
|
||||||
@@ -147,19 +146,17 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum
|
|||||||
uint8_t i2c_error = _bus->endTransmission();
|
uint8_t i2c_error = _bus->endTransmission();
|
||||||
|
|
||||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (writtenBytes != bufferSize) {
|
if (writtenBytes != bufferSize) {
|
||||||
LOG_ERROR("SEN5X: Error writting on I2C bus");
|
LOG_ERROR("%s: Error writting on I2C bus", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_error != 0) {
|
if (i2c_error != 0) {
|
||||||
LOG_ERROR("SEN5X: Error on I2C communication: %x", i2c_error);
|
LOG_ERROR("%s: Error on I2C communication: %x", sensorName, i2c_error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -168,13 +165,17 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum
|
|||||||
uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber)
|
uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber)
|
||||||
{
|
{
|
||||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED);
|
LOG_DEBUG("%s: Attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SEN5X_I2C_CLOCK_SPEED);
|
||||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
size_t readBytes = _bus->requestFrom(_address, byteNumber);
|
size_t readBytes = _bus->requestFrom(_address, byteNumber);
|
||||||
if (readBytes != byteNumber) {
|
if (readBytes != byteNumber) {
|
||||||
LOG_ERROR("SEN5X: Error reading I2C bus");
|
LOG_ERROR("%s: Error reading I2C bus", sensorName);
|
||||||
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
|
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||||
|
reClockI2C.restoreClock();
|
||||||
|
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +187,11 @@ uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber)
|
|||||||
uint8_t recvCRC = _bus->read();
|
uint8_t recvCRC = _bus->read();
|
||||||
uint8_t calcCRC = sen5xCRC(&buffer[i - 2]);
|
uint8_t calcCRC = sen5xCRC(&buffer[i - 2]);
|
||||||
if (recvCRC != calcCRC) {
|
if (recvCRC != calcCRC) {
|
||||||
LOG_ERROR("SEN5X: Checksum error while receiving msg");
|
LOG_ERROR("%s: Checksum error while receiving msg", sensorName);
|
||||||
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
|
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||||
|
reClockI2C.restoreClock();
|
||||||
|
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
readBytes -= 3;
|
readBytes -= 3;
|
||||||
@@ -194,10 +199,8 @@ uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
return receivedBytes;
|
return receivedBytes;
|
||||||
@@ -326,24 +329,24 @@ bool SEN5XSensor::vocStateToSensor()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!vocStateValid()) {
|
if (!vocStateValid()) {
|
||||||
LOG_INFO("SEN5X: VOC state is invalid, not sending");
|
LOG_INFO("%s: VOC state is invalid, not sending", sensorName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sendCommand(SEN5X_STOP_MEASUREMENT)) {
|
if (!sendCommand(SEN5X_STOP_MEASUREMENT)) {
|
||||||
LOG_ERROR("SEN5X: Error stoping measurement");
|
LOG_ERROR("%s: Error stoping measurement", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(200); // From Sensirion Datasheet
|
delay(200); // From Sensirion Datasheet
|
||||||
|
|
||||||
LOG_DEBUG("SEN5X: Sending VOC state to sensor");
|
LOG_DEBUG("%s: Sending VOC state to sensor", sensorName);
|
||||||
LOG_DEBUG("[%u, %u, %u, %u, %u, %u, %u, %u]", vocState[0], vocState[1], vocState[2], vocState[3], vocState[4], vocState[5],
|
LOG_DEBUG("[%u, %u, %u, %u, %u, %u, %u, %u]", vocState[0], vocState[1], vocState[2], vocState[3], vocState[4], vocState[5],
|
||||||
vocState[6], vocState[7]);
|
vocState[6], vocState[7]);
|
||||||
|
|
||||||
// Note: send command already takes into account the CRC
|
// Note: send command already takes into account the CRC
|
||||||
// buffer size increment needed
|
// buffer size increment needed
|
||||||
if (!sendCommand(SEN5X_RW_VOCS_STATE, vocState, SEN5X_VOC_STATE_BUFFER_SIZE)) {
|
if (!sendCommand(SEN5X_RW_VOCS_STATE, vocState, SEN5X_VOC_STATE_BUFFER_SIZE)) {
|
||||||
LOG_ERROR("SEN5X: Error sending VOC's state command'");
|
LOG_ERROR("%s: Error sending VOC's state command'", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,10 +359,10 @@ bool SEN5XSensor::vocStateFromSensor()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO("SEN5X: Getting VOC state from sensor");
|
LOG_INFO("%s: Getting VOC state from sensor", sensorName);
|
||||||
// Ask VOCs state from the sensor
|
// Ask VOCs state from the sensor
|
||||||
if (!sendCommand(SEN5X_RW_VOCS_STATE)) {
|
if (!sendCommand(SEN5X_RW_VOCS_STATE)) {
|
||||||
LOG_ERROR("SEN5X: Error sending VOC's state command'");
|
LOG_ERROR("%s: Error sending VOC's state command'", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,13 +374,13 @@ bool SEN5XSensor::vocStateFromSensor()
|
|||||||
delay(20); // From Sensirion Datasheet
|
delay(20); // From Sensirion Datasheet
|
||||||
|
|
||||||
if (receivedNumber == 0) {
|
if (receivedNumber == 0) {
|
||||||
LOG_DEBUG("SEN5X: Error getting VOC's state");
|
LOG_DEBUG("%s: Error getting VOC's state", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the state (if debug is on)
|
// Print the state (if debug is on)
|
||||||
LOG_DEBUG("SEN5X: VOC state retrieved from sensor: [%u, %u, %u, %u, %u, %u, %u, %u]", vocState[0], vocState[1], vocState[2],
|
LOG_DEBUG("%s: VOC state retrieved from sensor: [%u, %u, %u, %u, %u, %u, %u, %u]", sensorName, vocState[0], vocState[1],
|
||||||
vocState[3], vocState[4], vocState[5], vocState[6], vocState[7]);
|
vocState[2], vocState[3], vocState[4], vocState[5], vocState[6], vocState[7]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -389,11 +392,11 @@ bool SEN5XSensor::loadState()
|
|||||||
auto file = FSCom.open(sen5XStateFileName, FILE_O_READ);
|
auto file = FSCom.open(sen5XStateFileName, FILE_O_READ);
|
||||||
bool okay = false;
|
bool okay = false;
|
||||||
if (file) {
|
if (file) {
|
||||||
LOG_INFO("%s state read from %s", sensorName, sen5XStateFileName);
|
LOG_INFO("%s: state read from %s", sensorName, sen5XStateFileName);
|
||||||
pb_istream_t stream = {&readcb, &file, meshtastic_SEN5XState_size};
|
pb_istream_t stream = {&readcb, &file, meshtastic_SEN5XState_size};
|
||||||
|
|
||||||
if (!pb_decode(&stream, &meshtastic_SEN5XState_msg, &sen5xstate)) {
|
if (!pb_decode(&stream, &meshtastic_SEN5XState_msg, &sen5xstate)) {
|
||||||
LOG_ERROR("Error: can't decode protobuf %s", PB_GET_ERROR(&stream));
|
LOG_ERROR("%s: can't decode protobuf %s", sensorName, PB_GET_ERROR(&stream));
|
||||||
} else {
|
} else {
|
||||||
lastCleaning = sen5xstate.last_cleaning_time;
|
lastCleaning = sen5xstate.last_cleaning_time;
|
||||||
lastCleaningValid = sen5xstate.last_cleaning_valid;
|
lastCleaningValid = sen5xstate.last_cleaning_valid;
|
||||||
@@ -425,12 +428,12 @@ bool SEN5XSensor::loadState()
|
|||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("No %s state found (File: %s)", sensorName, sen5XStateFileName);
|
LOG_INFO("%s: No state found (File: %s)", sensorName, sen5XStateFileName);
|
||||||
}
|
}
|
||||||
spiLock->unlock();
|
spiLock->unlock();
|
||||||
return okay;
|
return okay;
|
||||||
#else
|
#else
|
||||||
LOG_ERROR("SEN5X: ERROR - Filesystem not implemented");
|
LOG_ERROR("%s: Filesystem not implemented", sensorName);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +466,7 @@ bool SEN5XSensor::saveState()
|
|||||||
pb_ostream_t stream = {&writecb, static_cast<Print *>(&file), meshtastic_SEN5XState_size};
|
pb_ostream_t stream = {&writecb, static_cast<Print *>(&file), meshtastic_SEN5XState_size};
|
||||||
|
|
||||||
if (!pb_encode(&stream, &meshtastic_SEN5XState_msg, &sen5xstate)) {
|
if (!pb_encode(&stream, &meshtastic_SEN5XState_msg, &sen5xstate)) {
|
||||||
LOG_ERROR("Error: can't encode protobuf %s", PB_GET_ERROR(&stream));
|
LOG_ERROR("%s: can't encode protobuf %s", sensorName, PB_GET_ERROR(&stream));
|
||||||
} else {
|
} else {
|
||||||
okay = true;
|
okay = true;
|
||||||
}
|
}
|
||||||
@@ -475,7 +478,7 @@ bool SEN5XSensor::saveState()
|
|||||||
|
|
||||||
return okay;
|
return okay;
|
||||||
#else
|
#else
|
||||||
LOG_ERROR("%s: ERROR - Filesystem not implemented", sensorName);
|
LOG_ERROR("%s: Filesystem not implemented", sensorName);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,10 +490,10 @@ bool SEN5XSensor::isActive()
|
|||||||
uint32_t SEN5XSensor::wakeUp()
|
uint32_t SEN5XSensor::wakeUp()
|
||||||
{
|
{
|
||||||
|
|
||||||
LOG_DEBUG("SEN5X: Waking up sensor");
|
LOG_DEBUG("%s: Waking up sensor", sensorName);
|
||||||
|
|
||||||
if (!sendCommand(SEN5X_START_MEASUREMENT)) {
|
if (!sendCommand(SEN5X_START_MEASUREMENT)) {
|
||||||
LOG_ERROR("SEN5X: Error starting measurement");
|
LOG_ERROR("%s: Error starting measurement", sensorName);
|
||||||
// TODO - what should this return?? Something actually on the default interval?
|
// TODO - what should this return?? Something actually on the default interval?
|
||||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
}
|
}
|
||||||
@@ -502,7 +505,7 @@ uint32_t SEN5XSensor::wakeUp()
|
|||||||
pmMeasureStarted = getTime();
|
pmMeasureStarted = getTime();
|
||||||
state = SEN5X_MEASUREMENT;
|
state = SEN5X_MEASUREMENT;
|
||||||
if (state == SEN5X_MEASUREMENT)
|
if (state == SEN5X_MEASUREMENT)
|
||||||
LOG_INFO("SEN5X: Started measurement mode");
|
LOG_INFO("%s: Started measurement mode", sensorName);
|
||||||
return SEN5X_WARMUP_MS_1;
|
return SEN5X_WARMUP_MS_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,7 +514,7 @@ bool SEN5XSensor::vocStateStable()
|
|||||||
uint32_t now;
|
uint32_t now;
|
||||||
now = getTime();
|
now = getTime();
|
||||||
uint32_t sinceFirstMeasureStarted = (now - rhtGasMeasureStarted);
|
uint32_t sinceFirstMeasureStarted = (now - rhtGasMeasureStarted);
|
||||||
LOG_DEBUG("sinceFirstMeasureStarted: %us", sinceFirstMeasureStarted);
|
LOG_DEBUG("%s: sinceFirstMeasureStarted: %us", sensorName, sinceFirstMeasureStarted);
|
||||||
return sinceFirstMeasureStarted > SEN5X_VOC_STATE_WARMUP_S;
|
return sinceFirstMeasureStarted > SEN5X_VOC_STATE_WARMUP_S;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,25 +526,25 @@ bool SEN5XSensor::startCleaning()
|
|||||||
|
|
||||||
// Note that cleaning command can only be run when the sensor is in measurement mode
|
// Note that cleaning command can only be run when the sensor is in measurement mode
|
||||||
if (!sendCommand(SEN5X_START_MEASUREMENT)) {
|
if (!sendCommand(SEN5X_START_MEASUREMENT)) {
|
||||||
LOG_ERROR("SEN5X: Error starting measurment mode");
|
LOG_ERROR("%s: Error starting measurment mode", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(50); // From Sensirion Datasheet
|
delay(50); // From Sensirion Datasheet
|
||||||
|
|
||||||
if (!sendCommand(SEN5X_START_FAN_CLEANING)) {
|
if (!sendCommand(SEN5X_START_FAN_CLEANING)) {
|
||||||
LOG_ERROR("SEN5X: Error starting fan cleaning");
|
LOG_ERROR("%s: Error starting fan cleaning", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(20); // From Sensirion Datasheet
|
delay(20); // From Sensirion Datasheet
|
||||||
|
|
||||||
// This message will be always printed so the user knows the device it's not hung
|
// This message will be always printed so the user knows the device it's not hung
|
||||||
LOG_INFO("SEN5X: Started fan cleaning it will take 10 seconds...");
|
LOG_INFO("%s: Started fan cleaning it will take 10 seconds...", sensorName);
|
||||||
|
|
||||||
uint16_t started = millis();
|
uint16_t started = millis();
|
||||||
while (millis() - started < 10500) {
|
while (millis() - started < 10500) {
|
||||||
delay(500);
|
delay(500);
|
||||||
}
|
}
|
||||||
LOG_INFO("SEN5X: Cleaning done!!");
|
LOG_INFO("%s: Cleaning done", sensorName);
|
||||||
|
|
||||||
// Save timestamp in flash so we know when a week has passed
|
// Save timestamp in flash so we know when a week has passed
|
||||||
uint32_t now;
|
uint32_t now;
|
||||||
@@ -558,22 +561,25 @@ bool SEN5XSensor::startCleaning()
|
|||||||
bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
{
|
{
|
||||||
state = SEN5X_NOT_DETECTED;
|
state = SEN5X_NOT_DETECTED;
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
LOG_INFO("%s: Init sensor", sensorName);
|
||||||
|
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
_address = dev->address.address;
|
_address = dev->address.address;
|
||||||
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
_port = dev->address.port;
|
_port = dev->address.port;
|
||||||
|
reClockI2C.setup(_bus, _port);
|
||||||
|
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
delay(50); // without this there is an error on the deviceReset function
|
delay(50); // without this there is an error on the deviceReset function
|
||||||
|
|
||||||
if (!sendCommand(SEN5X_RESET)) {
|
if (!sendCommand(SEN5X_RESET)) {
|
||||||
LOG_ERROR("SEN5X: Error reseting device");
|
LOG_ERROR("%s: error reseting device", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(200); // From Sensirion Datasheet
|
delay(200); // From Sensirion Datasheet
|
||||||
|
|
||||||
if (!findModel()) {
|
if (!findModel()) {
|
||||||
LOG_ERROR("SEN5X: error finding sensor model");
|
LOG_ERROR("%s: error finding sensor model", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,7 +587,7 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
if (!getVersion())
|
if (!getVersion())
|
||||||
return false;
|
return false;
|
||||||
if (firmwareVer < 2) {
|
if (firmwareVer < 2) {
|
||||||
LOG_ERROR("SEN5X: error firmware is too old and will not work with this implementation");
|
LOG_ERROR("%s: firmware is too old and will not work with this implementation", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
delay(200); // From Sensirion Datasheet
|
delay(200); // From Sensirion Datasheet
|
||||||
@@ -606,11 +612,12 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
if (passed > ONE_WEEK_IN_SECONDS && (now > SEN5X_VOC_VALID_DATE)) {
|
if (passed > ONE_WEEK_IN_SECONDS && (now > SEN5X_VOC_VALID_DATE)) {
|
||||||
// If current date greater than 01/01/2018 (validity check)
|
// If current date greater than 01/01/2018 (validity check)
|
||||||
LOG_INFO("SEN5X: More than a week (%us) since last cleaning in epoch (%us). Trigger, cleaning...", passed,
|
LOG_INFO("%s: More than a week (%us) since last cleaning in epoch (%us). Trigger, cleaning...", sensorName,
|
||||||
lastCleaning);
|
passed, lastCleaning);
|
||||||
startCleaning();
|
startCleaning();
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("SEN5X: Cleaning not needed (%ds passed). Last cleaning date (in epoch): %us", passed, lastCleaning);
|
LOG_INFO("%s: Cleaning not needed (%ds passed). Last cleaning date (in epoch): %us", sensorName, passed,
|
||||||
|
lastCleaning);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We assume the device has just been updated or it is new,
|
// We assume the device has just been updated or it is new,
|
||||||
@@ -619,29 +626,29 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
// Otherwise, we will never trigger cleaning in some cases
|
// Otherwise, we will never trigger cleaning in some cases
|
||||||
lastCleaning = now;
|
lastCleaning = now;
|
||||||
lastCleaningValid = true;
|
lastCleaningValid = true;
|
||||||
LOG_INFO("SEN5X: No valid last cleaning date found, saving it now: %us", lastCleaning);
|
LOG_INFO("%s: No valid last cleaning date found, saving it now: %us", sensorName, lastCleaning);
|
||||||
saveState();
|
saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model != SEN50) {
|
if (model != SEN50) {
|
||||||
if (!vocValid) {
|
if (!vocValid) {
|
||||||
LOG_INFO("SEN5X: No valid VOC's state found");
|
LOG_INFO("%s: No valid VOC's state found", sensorName);
|
||||||
} else {
|
} else {
|
||||||
// Check if state is recent
|
// Check if state is recent
|
||||||
if (vocStateRecent(now)) {
|
if (vocStateRecent(now)) {
|
||||||
// If current date greater than 01/01/2018 (validity check)
|
// If current date greater than 01/01/2018 (validity check)
|
||||||
// Send it to the sensor
|
// Send it to the sensor
|
||||||
LOG_INFO("SEN5X: VOC state is valid and recent");
|
LOG_INFO("%s: VOC state is valid and recent", sensorName);
|
||||||
vocStateToSensor();
|
vocStateToSensor();
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("SEN5X: VOC state is too old or date is invalid");
|
LOG_INFO("%s: VOC state is too old or date is invalid", sensorName);
|
||||||
LOG_DEBUG("SEN5X: vocTime %u, Passed %u, and now %u", vocTime, passed, now);
|
LOG_DEBUG("%s: vocTime %u, Passed %u, and now %u", sensorName, vocTime, passed, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO - Should this actually ignore? We could end up never cleaning...
|
// TODO - Should this actually ignore? We could end up never cleaning...
|
||||||
LOG_INFO("SEN5X: Not enough RTCQuality, ignoring saved cleaning and VOC state");
|
LOG_INFO("%s: Not enough RTCQuality, ignoring saved cleaning and VOC state", sensorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
idle(false);
|
idle(false);
|
||||||
@@ -654,16 +661,16 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
bool SEN5XSensor::readValues()
|
bool SEN5XSensor::readValues()
|
||||||
{
|
{
|
||||||
if (!sendCommand(SEN5X_READ_VALUES)) {
|
if (!sendCommand(SEN5X_READ_VALUES)) {
|
||||||
LOG_ERROR("SEN5X: Error sending read command");
|
LOG_ERROR("%s: Error sending read command", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_DEBUG("SEN5X: Reading PM Values");
|
LOG_DEBUG("%s: Reading PM Values", sensorName);
|
||||||
delay(20); // From Sensirion Datasheet
|
delay(20); // From Sensirion Datasheet
|
||||||
|
|
||||||
uint8_t dataBuffer[16]{};
|
uint8_t dataBuffer[16]{};
|
||||||
size_t receivedNumber = readBuffer(&dataBuffer[0], 24);
|
size_t receivedNumber = readBuffer(&dataBuffer[0], 24);
|
||||||
if (receivedNumber == 0) {
|
if (receivedNumber == 0) {
|
||||||
LOG_ERROR("SEN5X: Error getting values");
|
LOG_ERROR("%s: Error getting values", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,16 +695,16 @@ bool SEN5XSensor::readValues()
|
|||||||
sen5xmeasurement.vocIndex = !isnan(int_vocIndex) ? int_vocIndex / 10.0f : FLT_MAX;
|
sen5xmeasurement.vocIndex = !isnan(int_vocIndex) ? int_vocIndex / 10.0f : FLT_MAX;
|
||||||
sen5xmeasurement.noxIndex = !isnan(int_noxIndex) ? int_noxIndex / 10.0f : FLT_MAX;
|
sen5xmeasurement.noxIndex = !isnan(int_noxIndex) ? int_noxIndex / 10.0f : FLT_MAX;
|
||||||
|
|
||||||
LOG_DEBUG("Got %s readings: pM1p0=%u, pM2p5=%u, pM4p0=%u, pM10p0=%u", sensorName, sen5xmeasurement.pM1p0,
|
LOG_DEBUG("%s: Got readings: pM1p0=%u, pM2p5=%u, pM4p0=%u, pM10p0=%u", sensorName, sen5xmeasurement.pM1p0,
|
||||||
sen5xmeasurement.pM2p5, sen5xmeasurement.pM4p0, sen5xmeasurement.pM10p0);
|
sen5xmeasurement.pM2p5, sen5xmeasurement.pM4p0, sen5xmeasurement.pM10p0);
|
||||||
|
|
||||||
if (model != SEN50) {
|
if (model != SEN50) {
|
||||||
LOG_DEBUG("Got %s readings: humidity=%.2f, temperature=%.2f, vocIndex=%.2f", sensorName, sen5xmeasurement.humidity,
|
LOG_DEBUG("%s: Got readings: humidity=%.2f, temperature=%.2f, vocIndex=%.2f", sensorName, sen5xmeasurement.humidity,
|
||||||
sen5xmeasurement.temperature, sen5xmeasurement.vocIndex);
|
sen5xmeasurement.temperature, sen5xmeasurement.vocIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model == SEN55) {
|
if (model == SEN55) {
|
||||||
LOG_DEBUG("Got %s readings: noxIndex=%.2f", sensorName, sen5xmeasurement.noxIndex);
|
LOG_DEBUG("%s: Got readings: noxIndex=%.2f", sensorName, sen5xmeasurement.noxIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -706,17 +713,17 @@ bool SEN5XSensor::readValues()
|
|||||||
bool SEN5XSensor::readPNValues(bool cumulative)
|
bool SEN5XSensor::readPNValues(bool cumulative)
|
||||||
{
|
{
|
||||||
if (!sendCommand(SEN5X_READ_PM_VALUES)) {
|
if (!sendCommand(SEN5X_READ_PM_VALUES)) {
|
||||||
LOG_ERROR("SEN5X: Error sending read command");
|
LOG_ERROR("%s: Error sending read command", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("SEN5X: Reading PN Values");
|
LOG_DEBUG("%s: Reading PN Values", sensorName);
|
||||||
delay(20); // From Sensirion Datasheet
|
delay(20); // From Sensirion Datasheet
|
||||||
|
|
||||||
uint8_t dataBuffer[20]{};
|
uint8_t dataBuffer[20]{};
|
||||||
size_t receivedNumber = readBuffer(&dataBuffer[0], 30);
|
size_t receivedNumber = readBuffer(&dataBuffer[0], 30);
|
||||||
if (receivedNumber == 0) {
|
if (receivedNumber == 0) {
|
||||||
LOG_ERROR("SEN5X: Error getting PN values");
|
LOG_ERROR("%s: Error getting PN values", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,7 +757,7 @@ bool SEN5XSensor::readPNValues(bool cumulative)
|
|||||||
sen5xmeasurement.pN1p0 -= sen5xmeasurement.pN0p5;
|
sen5xmeasurement.pN1p0 -= sen5xmeasurement.pN0p5;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Got %s readings: pN0p5=%u, pN1p0=%u, pN2p5=%u, pN4p0=%u, pN10p0=%u, tSize=%.2f", sensorName,
|
LOG_DEBUG("%s: Got readings: pN0p5=%u, pN1p0=%u, pN2p5=%u, pN4p0=%u, pN10p0=%u, tSize=%.2f", sensorName,
|
||||||
sen5xmeasurement.pN0p5, sen5xmeasurement.pN1p0, sen5xmeasurement.pN2p5, sen5xmeasurement.pN4p0,
|
sen5xmeasurement.pN0p5, sen5xmeasurement.pN1p0, sen5xmeasurement.pN2p5, sen5xmeasurement.pN4p0,
|
||||||
sen5xmeasurement.pN10p0, sen5xmeasurement.tSize);
|
sen5xmeasurement.pN10p0, sen5xmeasurement.tSize);
|
||||||
|
|
||||||
@@ -764,7 +771,7 @@ uint8_t SEN5XSensor::getMeasurements()
|
|||||||
|
|
||||||
// Try to get new data
|
// Try to get new data
|
||||||
if (!sendCommand(SEN5X_READ_DATA_READY)) {
|
if (!sendCommand(SEN5X_READ_DATA_READY)) {
|
||||||
LOG_ERROR("SEN5X: Error sending command data ready flag");
|
LOG_ERROR("%s: Error sending command data ready flag", sensorName);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
delay(20); // From Sensirion Datasheet
|
delay(20); // From Sensirion Datasheet
|
||||||
@@ -772,7 +779,7 @@ uint8_t SEN5XSensor::getMeasurements()
|
|||||||
uint8_t dataReadyBuffer[3];
|
uint8_t dataReadyBuffer[3];
|
||||||
size_t charNumber = readBuffer(&dataReadyBuffer[0], 3);
|
size_t charNumber = readBuffer(&dataReadyBuffer[0], 3);
|
||||||
if (charNumber == 0) {
|
if (charNumber == 0) {
|
||||||
LOG_ERROR("SEN5X: Error getting device version value");
|
LOG_ERROR("%s: Error getting device version value", sensorName);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -780,17 +787,17 @@ uint8_t SEN5XSensor::getMeasurements()
|
|||||||
uint32_t sinceLastDataPollMs = (now - lastDataPoll) * 1000;
|
uint32_t sinceLastDataPollMs = (now - lastDataPoll) * 1000;
|
||||||
// Check if data is ready, and if since last time we requested is less than SEN5X_POLL_INTERVAL
|
// Check if data is ready, and if since last time we requested is less than SEN5X_POLL_INTERVAL
|
||||||
if (!dataReady && (sinceLastDataPollMs > SEN5X_POLL_INTERVAL)) {
|
if (!dataReady && (sinceLastDataPollMs > SEN5X_POLL_INTERVAL)) {
|
||||||
LOG_INFO("SEN5X: Data is not ready");
|
LOG_INFO("%s: Data is not ready", sensorName);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!readValues()) {
|
if (!readValues()) {
|
||||||
LOG_ERROR("SEN5X: Error getting readings");
|
LOG_ERROR("%s: Error getting readings", sensorName);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!readPNValues(false)) {
|
if (!readPNValues(false)) {
|
||||||
LOG_ERROR("SEN5X: Error getting PN readings");
|
LOG_ERROR("%s: Error getting PN readings", sensorName);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,13 +816,13 @@ int32_t SEN5XSensor::pendingForReadyMs()
|
|||||||
uint32_t now;
|
uint32_t now;
|
||||||
now = getTime();
|
now = getTime();
|
||||||
uint32_t sincePmMeasureStarted = (now - pmMeasureStarted) * 1000;
|
uint32_t sincePmMeasureStarted = (now - pmMeasureStarted) * 1000;
|
||||||
LOG_DEBUG("SEN5X: Since measure started: %ums", sincePmMeasureStarted);
|
LOG_DEBUG("%s: Since measure started: %ums", sensorName, sincePmMeasureStarted);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case SEN5X_MEASUREMENT: {
|
case SEN5X_MEASUREMENT: {
|
||||||
|
|
||||||
if (sincePmMeasureStarted < SEN5X_WARMUP_MS_1) {
|
if (sincePmMeasureStarted < SEN5X_WARMUP_MS_1) {
|
||||||
LOG_INFO("SEN5X: not enough time passed since starting measurement");
|
LOG_INFO("%s: not enough time passed since starting measurement", sensorName);
|
||||||
return SEN5X_WARMUP_MS_1 - sincePmMeasureStarted;
|
return SEN5X_WARMUP_MS_1 - sincePmMeasureStarted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,7 +836,7 @@ int32_t SEN5XSensor::pendingForReadyMs()
|
|||||||
|
|
||||||
// If the reading is low (the tyhreshold is in #/cm3) and second warmUp hasn't passed we return to come back later
|
// If the reading is low (the tyhreshold is in #/cm3) and second warmUp hasn't passed we return to come back later
|
||||||
if ((sen5xmeasurement.pN4p0 / 100) < SEN5X_PN4P0_CONC_THD && sincePmMeasureStarted < SEN5X_WARMUP_MS_2) {
|
if ((sen5xmeasurement.pN4p0 / 100) < SEN5X_PN4P0_CONC_THD && sincePmMeasureStarted < SEN5X_WARMUP_MS_2) {
|
||||||
LOG_INFO("SEN5X: Concentration is low, we will ask again in the second warm up period");
|
LOG_INFO("%s: Concentration is low, we will ask again in the second warm up period", sensorName);
|
||||||
state = SEN5X_MEASUREMENT_2;
|
state = SEN5X_MEASUREMENT_2;
|
||||||
// Report how many seconds are pending to cover the first warm up period
|
// Report how many seconds are pending to cover the first warm up period
|
||||||
return SEN5X_WARMUP_MS_2 - sincePmMeasureStarted;
|
return SEN5X_WARMUP_MS_2 - sincePmMeasureStarted;
|
||||||
@@ -851,9 +858,9 @@ int32_t SEN5XSensor::pendingForReadyMs()
|
|||||||
|
|
||||||
bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
{
|
{
|
||||||
LOG_INFO("SEN5X: Attempting to get metrics");
|
LOG_INFO("%s: Attempting to get metrics", sensorName);
|
||||||
if (!isActive()) {
|
if (!isActive()) {
|
||||||
LOG_INFO("SEN5X: not in measurement mode");
|
LOG_INFO("%s: not in measurement mode", sensorName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,9 +950,9 @@ void SEN5XSensor::setMode(bool setOneShot)
|
|||||||
{
|
{
|
||||||
oneShotMode = setOneShot;
|
oneShotMode = setOneShot;
|
||||||
if (oneShotMode) {
|
if (oneShotMode) {
|
||||||
LOG_INFO("%s setting mode to one shot mode", sensorName);
|
LOG_INFO("%s: setting mode to one shot mode", sensorName);
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("%s setting mode to continuous mode", sensorName);
|
LOG_INFO("%s: setting mode to continuous mode", sensorName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||||
|
|
||||||
|
#include "../detect/ReClockI2C.h"
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
@@ -62,7 +63,10 @@ class SEN5XSensor : public TelemetrySensor
|
|||||||
private:
|
private:
|
||||||
TwoWire *_bus{};
|
TwoWire *_bus{};
|
||||||
uint8_t _address{};
|
uint8_t _address{};
|
||||||
|
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||||
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
||||||
|
ReClockI2C reClockI2C;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool getVersion();
|
bool getVersion();
|
||||||
float firmwareVer = -1;
|
float firmwareVer = -1;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cSfa3x.h>)
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cSfa3x.h>)
|
||||||
|
|
||||||
#include "../detect/reClockI2C.h"
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "SFA30Sensor.h"
|
#include "SFA30Sensor.h"
|
||||||
|
|
||||||
@@ -14,11 +13,13 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
_bus = bus;
|
_bus = bus;
|
||||||
_address = dev->address.address;
|
_address = dev->address.address;
|
||||||
_port = dev->address.port;
|
|
||||||
|
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
|
_port = dev->address.port;
|
||||||
|
reClockI2C.setup(_bus, _port);
|
||||||
|
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
sfa30.begin(*_bus, _address);
|
sfa30.begin(*_bus, _address);
|
||||||
@@ -26,10 +27,8 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
if (this->isError(sfa30.deviceReset())) {
|
if (this->isError(sfa30.deviceReset())) {
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -37,10 +36,8 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
state = State::IDLE;
|
state = State::IDLE;
|
||||||
if (this->isError(sfa30.startContinuousMeasurement())) {
|
if (this->isError(sfa30.startContinuousMeasurement())) {
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -48,10 +45,8 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
LOG_INFO("%s starting measurement", sensorName);
|
LOG_INFO("%s starting measurement", sensorName);
|
||||||
|
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
status = 1;
|
status = 1;
|
||||||
@@ -77,7 +72,7 @@ void SFA30Sensor::sleep()
|
|||||||
{
|
{
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
// Note - not recommended for this sensor on a periodic basis
|
// Note - not recommended for this sensor on a periodic basis
|
||||||
@@ -86,10 +81,8 @@ void SFA30Sensor::sleep()
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
LOG_INFO("%s: stop measurement", sensorName);
|
LOG_INFO("%s: stop measurement", sensorName);
|
||||||
@@ -101,25 +94,21 @@ uint32_t SFA30Sensor::wakeUp()
|
|||||||
{
|
{
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
LOG_INFO("Waking up %s", sensorName);
|
LOG_INFO("Waking up %s", sensorName);
|
||||||
if (this->isError(sfa30.startContinuousMeasurement())) {
|
if (this->isError(sfa30.startContinuousMeasurement())) {
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
state = State::ACTIVE;
|
state = State::ACTIVE;
|
||||||
@@ -166,25 +155,21 @@ bool SFA30Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
|
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, _port);
|
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
if (this->isError(sfa30.readMeasuredValues(hcho, humidity, temperature))) {
|
if (this->isError(sfa30.readMeasuredValues(hcho, humidity, temperature))) {
|
||||||
LOG_WARN("%s: No values", sensorName);
|
LOG_WARN("%s: No values", sensorName);
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
if (currentClock) {
|
LOG_INFO("%s restoring clock speed", sensorName);
|
||||||
LOG_INFO("%s restoring clock speed to %uHz", sensorName, currentClock);
|
reClockI2C.restoreClock();
|
||||||
reClockI2C(currentClock, _bus, _port);
|
|
||||||
}
|
|
||||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||||
|
|
||||||
measurement->variant.air_quality_metrics.has_form_temperature = true;
|
measurement->variant.air_quality_metrics.has_form_temperature = true;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cSfa3x.h>)
|
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cSfa3x.h>)
|
||||||
|
|
||||||
|
#include "../detect/ReClockI2C.h"
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
@@ -21,7 +22,10 @@ class SFA30Sensor : public TelemetrySensor
|
|||||||
SensirionI2cSfa3x sfa30;
|
SensirionI2cSfa3x sfa30;
|
||||||
TwoWire *_bus{};
|
TwoWire *_bus{};
|
||||||
uint8_t _address{};
|
uint8_t _address{};
|
||||||
|
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||||
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
||||||
|
ReClockI2C reClockI2C;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool isError(uint16_t response);
|
bool isError(uint16_t response);
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ build_flags =
|
|||||||
-DLIBPAX_BLE
|
-DLIBPAX_BLE
|
||||||
-DHAS_UDP_MULTICAST=1
|
-DHAS_UDP_MULTICAST=1
|
||||||
;-DDEBUG_HEAP
|
;-DDEBUG_HEAP
|
||||||
-DCAN_RECLOCK_I2C
|
-DCAN_GET_I2C_CLOCK
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${arduino_base.lib_deps}
|
${arduino_base.lib_deps}
|
||||||
|
|||||||
Reference in New Issue
Block a user