Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d021f4c4e7 | ||
|
|
0fe8ed28f8 | ||
|
|
6d52fea75e | ||
|
|
caa300d2fb | ||
|
|
28dbb7cbe7 | ||
|
|
cba9439e62 | ||
|
|
9619c2d439 | ||
|
|
f5ce759af9 | ||
|
|
72205195f2 | ||
|
|
f008d9465f | ||
|
|
5532ec023d | ||
|
|
e96fa4c869 | ||
|
|
87714450ca | ||
|
|
70ecaccbb2 | ||
|
|
f6a2acacd3 |
+1
-1
@@ -69,7 +69,7 @@ monitor_speed = 115200
|
||||
monitor_filters = direct
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/6bfd1f135e1ebe37afd6050bb4b9964cea3fcfda.zip
|
||||
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/2e26010040e028baee72e2093402fa7b3c59e430.zip
|
||||
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
|
||||
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
|
||||
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#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 established 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);
|
||||
setPreviousClock(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool restoreClock()
|
||||
{
|
||||
if (this->previousClock) {
|
||||
LOG_DEBUG("Restoring I2C clock to %uHz", this->previousClock);
|
||||
i2cBus->setClock(this->previousClock);
|
||||
setPreviousClock(0);
|
||||
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,31 +0,0 @@
|
||||
#include "reClockI2C.h"
|
||||
#include "ScanI2CTwoWire.h"
|
||||
|
||||
uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, bool force)
|
||||
{
|
||||
|
||||
uint32_t currentClock = 0;
|
||||
|
||||
/* 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 desired speed.
|
||||
Only for cases where we can know OR predefine the speed, we can do this.
|
||||
*/
|
||||
|
||||
// TODO add getClock function or return a predefined clock speed per variant?
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
currentClock = i2cBus->getClock();
|
||||
#endif
|
||||
|
||||
if ((currentClock != desiredClock) || force) {
|
||||
LOG_DEBUG("Changing I2C clock to %u", desiredClock);
|
||||
i2cBus->setClock(desiredClock);
|
||||
}
|
||||
|
||||
return currentClock;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
#ifndef RECLOCK_I2C_
|
||||
#define RECLOCK_I2C_
|
||||
|
||||
#include "ScanI2CTwoWire.h"
|
||||
#include <Wire.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint32_t reClockI2C(uint32_t desiredClock, TwoWire *i2cBus, bool force);
|
||||
|
||||
#endif
|
||||
@@ -478,6 +478,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
|
||||
dispdev = new SH1106Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
isI2cScreen = true;
|
||||
#elif defined(USE_ST7789)
|
||||
#ifdef ESP_PLATFORM
|
||||
dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7789_SDA,
|
||||
@@ -495,6 +496,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
#elif defined(USE_SSD1306)
|
||||
dispdev = new SSD1306Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
isI2cScreen = true;
|
||||
#if defined(OLED_Y_OFFSET_PAGES)
|
||||
// Panels whose active window does not start at GDDRAM row 0 (e.g. 72x40
|
||||
// modules on pages 3..7) need a fixed vertical page shift on every write.
|
||||
@@ -523,6 +525,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
#elif defined(USE_ST7567)
|
||||
dispdev = new ST7567Wire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
isI2cScreen = true;
|
||||
#elif ARCH_PORTDUINO
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
if (portduino_config.displayPanel != no_screen) {
|
||||
@@ -533,12 +536,14 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
isAUTOOled = true;
|
||||
isI2cScreen = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
dispdev = new AutoOLEDWire(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
isAUTOOled = true;
|
||||
isI2cScreen = true;
|
||||
#endif
|
||||
|
||||
#if defined(USE_ST7789)
|
||||
|
||||
@@ -73,6 +73,9 @@ class Screen
|
||||
void showOverlayBanner(BannerOverlayOptions) {}
|
||||
void setFrames(FrameFocus focus) {}
|
||||
void endAlert() {}
|
||||
bool getIsI2cScreen() const { return false; }
|
||||
uint32_t getI2cFrequency() const { return 0; }
|
||||
ScanI2C::I2CPort getI2CPort() const { return ScanI2C::I2CPort::NO_I2C; }
|
||||
};
|
||||
} // namespace graphics
|
||||
#else
|
||||
@@ -260,6 +263,22 @@ class Screen : public concurrency::OSThread
|
||||
Screen &operator=(const Screen &) = delete;
|
||||
|
||||
ScanI2C::DeviceAddress address_found;
|
||||
bool getIsI2cScreen() const { return isI2cScreen; }
|
||||
// Return I2C Speed, or 0 if none
|
||||
uint32_t getI2cFrequency() const
|
||||
{
|
||||
if (getIsI2cScreen())
|
||||
return dispdev->getI2cFrequency();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
ScanI2C::I2CPort getI2CPort() const
|
||||
{
|
||||
if (getIsI2cScreen())
|
||||
return address_found.port;
|
||||
else
|
||||
return ScanI2C::I2CPort::NO_I2C;
|
||||
}
|
||||
meshtastic_Config_DisplayConfig_OledType model;
|
||||
OLEDDISPLAY_GEOMETRY geometry;
|
||||
|
||||
@@ -654,6 +673,7 @@ class Screen : public concurrency::OSThread
|
||||
int32_t runOnce() final;
|
||||
|
||||
bool isAUTOOled = false;
|
||||
bool isI2cScreen = false;
|
||||
|
||||
// Screen dimensions (for convenience)
|
||||
// Defined during Screen::setup
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Router.h"
|
||||
#include "TransmitHistory.h"
|
||||
#include "UnitConversions.h"
|
||||
#include "detect/ScanI2CTwoWire.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "graphics/images.h"
|
||||
@@ -41,12 +42,13 @@ void AirQualityTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
||||
if (!moduleConfig.telemetry.air_quality_enabled && !AIR_QUALITY_TELEMETRY_MODULE_ENABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Air Quality Telemetry adding I2C devices...");
|
||||
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
Note: this was previously on runOnce, which didnt take effect
|
||||
Note: this was previously on runOnce, which didn't take effect
|
||||
as other modules already had already been initialized (screen)
|
||||
*/
|
||||
|
||||
@@ -54,6 +56,52 @@ void AirQualityTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
||||
// moduleConfig.telemetry.air_quality_screen_enabled = 1;
|
||||
// moduleConfig.telemetry.air_quality_interval = 15;
|
||||
|
||||
// Add here supported sensors in the Air Quality module
|
||||
// These sensors will be scanned twice, once in the first scan,
|
||||
// and secondly in the first run of the module
|
||||
if (!supportedSensors.count(PMSA003I_ADDR))
|
||||
supportedSensors[PMSA003I_ADDR] = ScanI2C::DeviceType::PMSA003I;
|
||||
if (!supportedSensors.count(SEN5X_ADDR))
|
||||
supportedSensors[SEN5X_ADDR] = ScanI2C::DeviceType::SEN5X;
|
||||
#if __has_include(<SensirionI2cScd4x.h>)
|
||||
if (!supportedSensors.count(SCD4X_ADDR))
|
||||
supportedSensors[SCD4X_ADDR] = ScanI2C::DeviceType::SCD4X;
|
||||
#endif
|
||||
#if __has_include(<SensirionI2cSfa3x.h>)
|
||||
if (!supportedSensors.count(SFA30_ADDR))
|
||||
supportedSensors[SFA30_ADDR] = ScanI2C::DeviceType::SFA30;
|
||||
#endif
|
||||
#if __has_include(<SensirionI2cScd30.h>)
|
||||
if (!supportedSensors.count(SCD30_ADDR))
|
||||
supportedSensors[SCD30_ADDR] = ScanI2C::DeviceType::SCD30;
|
||||
#endif
|
||||
|
||||
if (!firstTime) {
|
||||
// Re-scan for late comming sensors
|
||||
LOG_INFO("Re-scanning supported sensors...");
|
||||
|
||||
for (const auto &[address, type] : supportedSensors) {
|
||||
|
||||
if (!i2cScanner->exists(type)) {
|
||||
LOG_INFO("Re-scanning on address 0x%x", address);
|
||||
uint8_t array_address[1] = {address};
|
||||
#if defined(I2C_SDA1) || (defined(NRF52840_XXAA) && (WIRE_INTERFACES_COUNT == 2))
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, array_address, sizeof(array_address));
|
||||
#endif
|
||||
|
||||
#if defined(I2C_SDA)
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, array_address, sizeof(array_address));
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if (portduino_config.i2cdev != "") {
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, array_address, sizeof(array_address));
|
||||
}
|
||||
#elif HAS_WIRE
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, array_address, sizeof(array_address));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// order by priority of metrics/values (low top, high bottom)
|
||||
addSensor<PMSA003ISensor>(i2cScanner, ScanI2C::DeviceType::PMSA003I);
|
||||
addSensor<SEN5XSensor>(i2cScanner, ScanI2C::DeviceType::SEN5X);
|
||||
@@ -94,6 +142,10 @@ int32_t AirQualityTelemetryModule::runOnce()
|
||||
if (moduleConfig.telemetry.air_quality_enabled) {
|
||||
LOG_INFO("Air quality Telemetry: init");
|
||||
|
||||
// Re-scan I2C bus
|
||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||
i2cScanFinished(i2cScanner.get());
|
||||
|
||||
// check if we have at least one sensor
|
||||
if (!sensors.empty()) {
|
||||
result = DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
@@ -110,10 +162,10 @@ int32_t AirQualityTelemetryModule::runOnce()
|
||||
}
|
||||
|
||||
// Wake up the sensors that need it
|
||||
LOG_INFO("Waking up sensors...");
|
||||
uint32_t lastTelemetry =
|
||||
transmitHistory ? transmitHistory->getLastSentToMeshMillis(TX_HISTORY_KEY_AIR_QUALITY_TELEMETRY) : 0;
|
||||
for (TelemetrySensor *sensor : sensors) {
|
||||
LOG_DEBUG("Checking if %s needs to wake up", sensor->sensorName);
|
||||
if (!sensor->canSleep()) {
|
||||
LOG_DEBUG("%s sensor doesn't have sleep feature. Skipping", sensor->sensorName);
|
||||
} else if (((lastTelemetry == 0) || !Throttle::isWithinTimespanMs(lastTelemetry - sensor->wakeUpTimeMs(),
|
||||
@@ -154,8 +206,8 @@ int32_t AirQualityTelemetryModule::runOnce()
|
||||
}
|
||||
|
||||
// Send to sleep sensors that consume power
|
||||
LOG_DEBUG("Sending sensors to sleep");
|
||||
for (TelemetrySensor *sensor : sensors) {
|
||||
LOG_DEBUG("Checking if %s can be sent to sleep", sensor->sensorName);
|
||||
if (sensor->isActive() && sensor->canSleep()) {
|
||||
if (sensor->wakeUpTimeMs() <
|
||||
(int32_t)Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval,
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseTelemetryModule.h"
|
||||
#include <map>
|
||||
|
||||
#ifndef AIR_QUALITY_TELEMETRY_MODULE_ENABLE
|
||||
#define AIR_QUALITY_TELEMETRY_MODULE_ENABLE 0
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "NodeDB.h"
|
||||
#include "ProtobufModule.h"
|
||||
#include "detect/ScanI2C.h"
|
||||
#include "detect/ScanI2CConsumer.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
@@ -69,6 +70,9 @@ class AirQualityTelemetryModule : private concurrency::OSThread,
|
||||
uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute
|
||||
// uint32_t sendToPhoneIntervalMs = 1000; // Send to phone every minute
|
||||
uint32_t lastSentToPhone = 0;
|
||||
|
||||
// Map for supported sensors to re-scan
|
||||
std::map<uint8_t, ScanI2C::DeviceType> supportedSensors;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,15 @@ static std::forward_list<TelemetrySensor *> sensors;
|
||||
template <typename T> void addSensor(const ScanI2C *i2cScanner, ScanI2C::DeviceType type)
|
||||
{
|
||||
ScanI2C::FoundDevice dev = i2cScanner->find(type);
|
||||
// Avoid adding the same device twice
|
||||
if (dev.type != ScanI2C::DeviceType::NONE) {
|
||||
for (const TelemetrySensor *_sensor : sensors) {
|
||||
if ((_sensor->_address == dev.address.address) && (_sensor->_port == dev.address.port)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dev.type != ScanI2C::DeviceType::NONE || type == ScanI2C::DeviceType::NONE) {
|
||||
TelemetrySensor *sensor = new T();
|
||||
#if WIRE_INTERFACES_COUNT > 1
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||
|
||||
#include "../detect/reClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "PMSA003ISensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
@@ -13,34 +12,37 @@ PMSA003ISensor::PMSA003ISensor() : TelemetrySensor(meshtastic_TelemetrySensorTyp
|
||||
|
||||
bool PMSA003ISensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
LOG_INFO("%s: Init sensor", sensorName);
|
||||
#ifdef PMSA003I_ENABLE_PIN
|
||||
pinMode(PMSA003I_ENABLE_PIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
// TODO PMS5003I sometimes get late to the party...
|
||||
|
||||
_bus = bus;
|
||||
_address = dev->address.address;
|
||||
|
||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
_port = dev->address.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 */
|
||||
|
||||
_bus->beginTransmission(_address);
|
||||
if (_bus->endTransmission() != 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
#if defined(PMSA003I_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||
|
||||
status = 1;
|
||||
LOG_INFO("%s Enabled", sensorName);
|
||||
@@ -57,19 +59,17 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
}
|
||||
|
||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(PMSA003I_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s: attempting to reclock speed to %uHz", sensorName, PMSA003I_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(PMSA003I_I2C_CLOCK_SPEED);
|
||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||
|
||||
_bus->requestFrom(_address, (uint8_t)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_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,12 +77,13 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
buffer[i] = _bus->read();
|
||||
}
|
||||
|
||||
#if defined(PMSA003I_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* PMSA003I_I2C_CLOCK_SPEED */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -138,7 +139,7 @@ bool PMSA003ISensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
measurement->variant.air_quality_metrics.has_particles_100um = true;
|
||||
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.pm100_standard);
|
||||
|
||||
@@ -197,7 +198,7 @@ void PMSA003ISensor::sleep()
|
||||
uint32_t PMSA003ISensor::wakeUp()
|
||||
{
|
||||
#ifdef PMSA003I_ENABLE_PIN
|
||||
LOG_INFO("Waking up %s", sensorName);
|
||||
LOG_INFO("%s: Waking up", sensorName);
|
||||
digitalWrite(PMSA003I_ENABLE_PIN, HIGH);
|
||||
state = State::ACTIVE;
|
||||
pmMeasureStarted = getTime();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||
|
||||
#include "../detect/ReClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "RTC.h"
|
||||
#include "TelemetrySensor.h"
|
||||
@@ -33,8 +34,9 @@ class PMSA003ISensor : public TelemetrySensor
|
||||
uint32_t pmMeasureStarted = 0;
|
||||
|
||||
uint8_t buffer[PMSA003I_FRAME_LENGTH]{};
|
||||
TwoWire *_bus{};
|
||||
uint8_t _address{};
|
||||
#ifdef PMSA003I_I2C_CLOCK_SPEED
|
||||
ReClockI2C reClockI2C;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd30.h>)
|
||||
|
||||
#include "../detect/reClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "SCD30Sensor.h"
|
||||
|
||||
@@ -12,29 +11,26 @@ SCD30Sensor::SCD30Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SCD3
|
||||
|
||||
bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
LOG_INFO("%s: Init sensor", sensorName);
|
||||
|
||||
_bus = bus;
|
||||
_address = dev->address.address;
|
||||
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
_port = dev->address.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 */
|
||||
|
||||
scd30.begin(*_bus, _address);
|
||||
|
||||
if (!startMeasurement()) {
|
||||
LOG_ERROR("%s: Failed to start periodic measurement", sensorName);
|
||||
#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -42,9 +38,10 @@ bool SCD30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
LOG_WARN("%s: Could not determine ASC state", sensorName);
|
||||
}
|
||||
|
||||
#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
|
||||
if (state == SCD30_MEASUREMENT) {
|
||||
status = 1;
|
||||
@@ -62,30 +59,26 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
float co2, temperature, humidity;
|
||||
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s: attempting to reclock speed to %uHz", sensorName, SCD30_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SCD30_I2C_CLOCK_SPEED);
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
|
||||
if (scd30.readMeasurementData(co2, temperature, humidity) != SCD30_NO_ERROR) {
|
||||
LOG_ERROR("SCD30: Failed to read measurement data.");
|
||||
#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
LOG_ERROR("%s: Failed to read measurement data", sensorName);
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
|
||||
if (co2 == 0) {
|
||||
LOG_ERROR("SCD30: Invalid CO₂ reading.");
|
||||
LOG_ERROR("%s: Invalid CO₂ reading", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -96,7 +89,7 @@ bool SCD30Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
measurement->variant.air_quality_metrics.co2_temperature = temperature;
|
||||
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;
|
||||
}
|
||||
@@ -283,7 +276,7 @@ bool SCD30Sensor::setTemperature(float tempReference)
|
||||
|
||||
tempOffset = (temperature - tempReference);
|
||||
if (tempOffset < 0) {
|
||||
LOG_ERROR("%s temperature offset is only positive", sensorName);
|
||||
LOG_ERROR("%s: temperature offset is only positive", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -372,23 +365,17 @@ bool SCD30Sensor::isActive()
|
||||
*/
|
||||
uint32_t SCD30Sensor::wakeUp()
|
||||
{
|
||||
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return 0;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
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 */
|
||||
|
||||
startMeasurement();
|
||||
|
||||
#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -400,21 +387,16 @@ uint32_t SCD30Sensor::wakeUp()
|
||||
void SCD30Sensor::sleep()
|
||||
{
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
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 */
|
||||
|
||||
stopMeasurement();
|
||||
|
||||
#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
}
|
||||
|
||||
bool SCD30Sensor::canSleep()
|
||||
@@ -438,14 +420,8 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa
|
||||
AdminMessageHandleResult result;
|
||||
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return AdminMessageHandleResult::NOT_HANDLED;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
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 */
|
||||
|
||||
switch (request->which_payload_variant) {
|
||||
@@ -501,9 +477,10 @@ AdminMessageHandleResult SCD30Sensor::handleAdminMessage(const meshtastic_MeshPa
|
||||
result = AdminMessageHandleResult::NOT_HANDLED;
|
||||
}
|
||||
|
||||
#if defined(SCD30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD30_I2C_CLOCK_SPEED */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd30.h>)
|
||||
|
||||
#include "../detect/ReClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <SensirionI2cScd30.h>
|
||||
@@ -12,8 +13,9 @@ class SCD30Sensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
SensirionI2cScd30 scd30;
|
||||
TwoWire *_bus{};
|
||||
uint8_t _address{};
|
||||
#ifdef SCD30_I2C_CLOCK_SPEED
|
||||
ReClockI2C reClockI2C;
|
||||
#endif
|
||||
|
||||
bool performFRC(uint16_t targetCO2);
|
||||
bool setASC(bool ascEnabled);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd4x.h>)
|
||||
|
||||
#include "../detect/reClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "SCD4XSensor.h"
|
||||
|
||||
@@ -18,14 +17,11 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
_address = dev->address.address;
|
||||
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
_port = dev->address.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 */
|
||||
|
||||
scd4x.begin(*_bus, _address);
|
||||
@@ -35,9 +31,10 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
|
||||
// Stop periodic measurement
|
||||
if (!stopMeasurement()) {
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -48,33 +45,37 @@ bool SCD4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
LOG_INFO("%s: Found SCD41", sensorName);
|
||||
if (!powerUp()) {
|
||||
LOG_ERROR("%s: Error trying to execute powerUp()", sensorName);
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!getASC(ascActive)) {
|
||||
LOG_ERROR("%s: Unable to check if ASC is enabled", sensorName);
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start measurement in selected power mode (low power by default)
|
||||
if (!startMeasurement()) {
|
||||
LOG_ERROR("%s: Couldn't start measurement", sensorName);
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
|
||||
if (state == SCD4X_MEASUREMENT) {
|
||||
status = 1;
|
||||
@@ -99,31 +100,27 @@ bool SCD4XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
float temperature, humidity;
|
||||
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s: attempting to reclock speed to %uHz", sensorName, SCD4X_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SCD4X_I2C_CLOCK_SPEED);
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
|
||||
bool dataReady;
|
||||
error = scd4x.getDataReadyStatus(dataReady);
|
||||
if (error != SCD4X_NO_ERROR || !dataReady) {
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
LOG_ERROR("SCD4X: Data is not ready");
|
||||
return false;
|
||||
}
|
||||
|
||||
error = scd4x.readMeasurement(co2, temperature, humidity);
|
||||
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
|
||||
LOG_DEBUG("Got %s readings: co2=%u, co2_temp=%.2f, co2_hum%.2f", sensorName, co2, temperature, humidity);
|
||||
if (error != SCD4X_NO_ERROR) {
|
||||
@@ -637,34 +634,31 @@ bool SCD4XSensor::powerDown()
|
||||
}
|
||||
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
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 */
|
||||
|
||||
if (!stopMeasurement()) {
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scd4x.powerDown() != SCD4X_NO_ERROR) {
|
||||
LOG_ERROR("%s: Error trying to execute sleep()", sensorName);
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
|
||||
state = SCD4X_OFF;
|
||||
return true;
|
||||
@@ -711,27 +705,23 @@ uint32_t SCD4XSensor::wakeUp()
|
||||
{
|
||||
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return 0;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
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 */
|
||||
|
||||
if (startMeasurement()) {
|
||||
co2MeasureStarted = getTime();
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
return SCD4X_WARMUP_MS;
|
||||
}
|
||||
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -743,21 +733,16 @@ uint32_t SCD4XSensor::wakeUp()
|
||||
void SCD4XSensor::sleep()
|
||||
{
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
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 */
|
||||
|
||||
stopMeasurement();
|
||||
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -797,14 +782,8 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa
|
||||
AdminMessageHandleResult result;
|
||||
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SCD4X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return AdminMessageHandleResult::NOT_HANDLED;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
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 */
|
||||
|
||||
// TODO: potentially add selftest command?
|
||||
@@ -907,9 +886,10 @@ AdminMessageHandleResult SCD4XSensor::handleAdminMessage(const meshtastic_MeshPa
|
||||
// Start measurement mode
|
||||
this->startMeasurement();
|
||||
|
||||
#if defined(SCD4X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SCD4X_I2C_CLOCK_SPEED */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cScd4x.h>)
|
||||
|
||||
#include "../detect/ReClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "RTC.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <SensirionI2cScd4x.h>
|
||||
|
||||
// Max speed 400kHz
|
||||
#define SCD4X_I2C_CLOCK_SPEED 100000
|
||||
#define SCD4X_I2C_CLOCK_SPEED 400000
|
||||
#define SCD4X_WARMUP_MS 5000
|
||||
|
||||
class SCD4XSensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
SensirionI2cScd4x scd4x;
|
||||
TwoWire *_bus{};
|
||||
uint8_t _address{};
|
||||
#ifdef SCD4X_I2C_CLOCK_SPEED
|
||||
ReClockI2C reClockI2C;
|
||||
#endif
|
||||
|
||||
bool performFRC(uint32_t targetCO2);
|
||||
bool setASCBaseline(uint32_t targetCO2);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
|
||||
|
||||
#include "../detect/reClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "FSCommon.h"
|
||||
#include "SEN5XSensor.h"
|
||||
@@ -18,7 +17,7 @@ SEN5XSensor::SEN5XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SEN5
|
||||
bool SEN5XSensor::getVersion()
|
||||
{
|
||||
if (!sendCommand(SEN5X_GET_FIRMWARE_VERSION)) {
|
||||
LOG_ERROR("SEN5X: Error sending version command");
|
||||
LOG_ERROR("%s: Error sending version command", sensorName);
|
||||
return false;
|
||||
}
|
||||
delay(20); // From Sensirion Datasheet
|
||||
@@ -26,7 +25,7 @@ bool SEN5XSensor::getVersion()
|
||||
uint8_t versionBuffer[12]{};
|
||||
size_t charNumber = readBuffer(&versionBuffer[0], 3);
|
||||
if (charNumber == 0) {
|
||||
LOG_ERROR("SEN5X: Error getting data ready flag value");
|
||||
LOG_ERROR("%s: Error getting data ready flag value", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -34,9 +33,9 @@ bool SEN5XSensor::getVersion()
|
||||
hardwareVer = versionBuffer[3] + (versionBuffer[4] / 10);
|
||||
protocolVer = versionBuffer[5] + (versionBuffer[6] / 10);
|
||||
|
||||
LOG_INFO("SEN5X Firmware Version: %0.2f", firmwareVer);
|
||||
LOG_INFO("SEN5X Hardware Version: %0.2f", hardwareVer);
|
||||
LOG_INFO("SEN5X Protocol Version: %0.2f", protocolVer);
|
||||
LOG_INFO("%s: Firmware Version: %0.2f", sensorName, firmwareVer);
|
||||
LOG_INFO("%s: Hardware Version: %0.2f", sensorName, hardwareVer);
|
||||
LOG_INFO("%s: Protocol Version: %0.2f", sensorName, protocolVer);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -44,7 +43,7 @@ bool SEN5XSensor::getVersion()
|
||||
bool SEN5XSensor::findModel()
|
||||
{
|
||||
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;
|
||||
}
|
||||
delay(50); // From Sensirion Datasheet
|
||||
@@ -53,7 +52,7 @@ bool SEN5XSensor::findModel()
|
||||
uint8_t name[nameSize];
|
||||
size_t charNumber = readBuffer(&name[0], nameSize);
|
||||
if (charNumber == 0) {
|
||||
LOG_ERROR("SEN5X: Error getting device name");
|
||||
LOG_ERROR("%s: Error getting device name", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -61,15 +60,15 @@ bool SEN5XSensor::findModel()
|
||||
switch (name[4]) {
|
||||
case 48:
|
||||
model = SEN50;
|
||||
LOG_INFO("SEN5X: found sensor model SEN50");
|
||||
LOG_INFO("%s: found sensor model SEN50", sensorName);
|
||||
break;
|
||||
case 52:
|
||||
model = SEN54;
|
||||
LOG_INFO("SEN5X: found sensor model SEN54");
|
||||
LOG_INFO("%s: found sensor model SEN54", sensorName);
|
||||
break;
|
||||
case 53:
|
||||
model = SEN55;
|
||||
LOG_INFO("SEN5X: found sensor model SEN55");
|
||||
LOG_INFO("%s: found sensor model SEN55", sensorName);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -108,14 +107,8 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum
|
||||
}
|
||||
|
||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s: Attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SEN5X_I2C_CLOCK_SPEED);
|
||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||
|
||||
// Transmit the data
|
||||
@@ -126,17 +119,18 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum
|
||||
size_t writtenBytes = _bus->write(toSend, bufferSize);
|
||||
uint8_t i2c_error = _bus->endTransmission();
|
||||
|
||||
#if defined(SEN5X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||
|
||||
if (writtenBytes != bufferSize) {
|
||||
LOG_ERROR("SEN5X: Error writting on I2C bus");
|
||||
LOG_ERROR("%s: Error writing on I2C bus", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
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 true;
|
||||
@@ -145,19 +139,17 @@ bool SEN5XSensor::sendCommand(uint16_t command, uint8_t *buffer, uint8_t byteNum
|
||||
uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber)
|
||||
{
|
||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SEN5X_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s: Attempting to reclock speed to %uHz", sensorName, SEN5X_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SEN5X_I2C_CLOCK_SPEED);
|
||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||
|
||||
size_t readBytes = _bus->requestFrom(_address, 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;
|
||||
}
|
||||
|
||||
@@ -169,15 +161,21 @@ uint8_t SEN5XSensor::readBuffer(uint8_t *buffer, uint8_t byteNumber)
|
||||
uint8_t recvCRC = _bus->read();
|
||||
uint8_t calcCRC = sen5xCRC(&buffer[i - 2]);
|
||||
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;
|
||||
}
|
||||
readBytes -= 3;
|
||||
receivedBytes += 2;
|
||||
}
|
||||
#if defined(SEN5X_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
|
||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s: restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SEN5X_I2C_CLOCK_SPEED */
|
||||
|
||||
return receivedBytes;
|
||||
}
|
||||
@@ -305,24 +303,24 @@ bool SEN5XSensor::vocStateToSensor()
|
||||
}
|
||||
|
||||
if (!vocStateValid()) {
|
||||
LOG_INFO("SEN5X: VOC state is invalid, not sending");
|
||||
LOG_INFO("%s: VOC state is invalid, not sending", sensorName);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!sendCommand(SEN5X_STOP_MEASUREMENT)) {
|
||||
LOG_ERROR("SEN5X: Error stoping measurement");
|
||||
LOG_ERROR("%s: Error stopping measurement", sensorName);
|
||||
return false;
|
||||
}
|
||||
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],
|
||||
vocState[6], vocState[7]);
|
||||
|
||||
// Note: send command already takes into account the CRC
|
||||
// buffer size increment needed
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -335,10 +333,10 @@ bool SEN5XSensor::vocStateFromSensor()
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -350,13 +348,13 @@ bool SEN5XSensor::vocStateFromSensor()
|
||||
delay(20); // From Sensirion Datasheet
|
||||
|
||||
if (receivedNumber == 0) {
|
||||
LOG_DEBUG("SEN5X: Error getting VOC's state");
|
||||
LOG_DEBUG("%s: Error getting VOC's state", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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],
|
||||
vocState[3], vocState[4], vocState[5], vocState[6], vocState[7]);
|
||||
LOG_DEBUG("%s: VOC state retrieved from sensor: [%u, %u, %u, %u, %u, %u, %u, %u]", sensorName, vocState[0], vocState[1],
|
||||
vocState[2], vocState[3], vocState[4], vocState[5], vocState[6], vocState[7]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -368,11 +366,11 @@ bool SEN5XSensor::loadState()
|
||||
auto file = FSCom.open(sen5XStateFileName, FILE_O_READ);
|
||||
bool okay = false;
|
||||
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};
|
||||
|
||||
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 {
|
||||
lastCleaning = sen5xstate.last_cleaning_time;
|
||||
lastCleaningValid = sen5xstate.last_cleaning_valid;
|
||||
@@ -404,12 +402,12 @@ bool SEN5XSensor::loadState()
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
LOG_INFO("No %s state found (File: %s)", sensorName, sen5XStateFileName);
|
||||
LOG_INFO("%s: No state found (File: %s)", sensorName, sen5XStateFileName);
|
||||
}
|
||||
spiLock->unlock();
|
||||
return okay;
|
||||
#else
|
||||
LOG_ERROR("SEN5X: ERROR - Filesystem not implemented");
|
||||
LOG_ERROR("%s: Filesystem not implemented", sensorName);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -442,7 +440,7 @@ bool SEN5XSensor::saveState()
|
||||
pb_ostream_t stream = {&writecb, static_cast<Print *>(&file), meshtastic_SEN5XState_size};
|
||||
|
||||
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 {
|
||||
okay = true;
|
||||
}
|
||||
@@ -454,7 +452,7 @@ bool SEN5XSensor::saveState()
|
||||
|
||||
return okay;
|
||||
#else
|
||||
LOG_ERROR("%s: ERROR - Filesystem not implemented", sensorName);
|
||||
LOG_ERROR("%s: Filesystem not implemented", sensorName);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -466,10 +464,10 @@ bool SEN5XSensor::isActive()
|
||||
uint32_t SEN5XSensor::wakeUp()
|
||||
{
|
||||
|
||||
LOG_DEBUG("SEN5X: Waking up sensor");
|
||||
LOG_DEBUG("%s: Waking up sensor", sensorName);
|
||||
|
||||
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?
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
@@ -481,7 +479,7 @@ uint32_t SEN5XSensor::wakeUp()
|
||||
pmMeasureStarted = getTime();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -490,7 +488,7 @@ bool SEN5XSensor::vocStateStable()
|
||||
uint32_t now;
|
||||
now = getTime();
|
||||
uint32_t sinceFirstMeasureStarted = (now - rhtGasMeasureStarted);
|
||||
LOG_DEBUG("sinceFirstMeasureStarted: %us", sinceFirstMeasureStarted);
|
||||
LOG_DEBUG("%s: sinceFirstMeasureStarted: %us", sensorName, sinceFirstMeasureStarted);
|
||||
return sinceFirstMeasureStarted > SEN5X_VOC_STATE_WARMUP_S;
|
||||
}
|
||||
|
||||
@@ -502,25 +500,25 @@ bool SEN5XSensor::startCleaning()
|
||||
|
||||
// Note that cleaning command can only be run when the sensor is in measurement mode
|
||||
if (!sendCommand(SEN5X_START_MEASUREMENT)) {
|
||||
LOG_ERROR("SEN5X: Error starting measurment mode");
|
||||
LOG_ERROR("%s: Error starting measurement mode", sensorName);
|
||||
return false;
|
||||
}
|
||||
delay(50); // From Sensirion Datasheet
|
||||
|
||||
if (!sendCommand(SEN5X_START_FAN_CLEANING)) {
|
||||
LOG_ERROR("SEN5X: Error starting fan cleaning");
|
||||
LOG_ERROR("%s: Error starting fan cleaning", sensorName);
|
||||
return false;
|
||||
}
|
||||
delay(20); // From Sensirion Datasheet
|
||||
|
||||
// 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();
|
||||
while (millis() - started < 10500) {
|
||||
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
|
||||
uint32_t now;
|
||||
@@ -537,21 +535,25 @@ bool SEN5XSensor::startCleaning()
|
||||
bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
{
|
||||
state = SEN5X_NOT_DETECTED;
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
LOG_INFO("%s: Init sensor", sensorName);
|
||||
|
||||
_bus = bus;
|
||||
_address = dev->address.address;
|
||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||
_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
|
||||
|
||||
if (!sendCommand(SEN5X_RESET)) {
|
||||
LOG_ERROR("SEN5X: Error reseting device");
|
||||
LOG_ERROR("%s: error resetting device", sensorName);
|
||||
return false;
|
||||
}
|
||||
delay(200); // From Sensirion Datasheet
|
||||
|
||||
if (!findModel()) {
|
||||
LOG_ERROR("SEN5X: error finding sensor model");
|
||||
LOG_ERROR("%s: error finding sensor model", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -559,7 +561,7 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
if (!getVersion())
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
delay(200); // From Sensirion Datasheet
|
||||
@@ -584,11 +586,12 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
|
||||
if (passed > ONE_WEEK_IN_SECONDS && (now > SEN5X_VOC_VALID_DATE)) {
|
||||
// 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,
|
||||
lastCleaning);
|
||||
LOG_INFO("%s: More than a week (%us) since last cleaning in epoch (%us). Trigger, cleaning...", sensorName,
|
||||
passed, lastCleaning);
|
||||
startCleaning();
|
||||
} 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 {
|
||||
// We assume the device has just been updated or it is new,
|
||||
@@ -597,29 +600,29 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
// Otherwise, we will never trigger cleaning in some cases
|
||||
lastCleaning = now;
|
||||
lastCleaningValid = true;
|
||||
LOG_INFO("SEN5X: No valid last cleaning date found, saving it now: %us", lastCleaning);
|
||||
LOG_INFO("%s: No valid last cleaning date found, saving it now: %us", sensorName, lastCleaning);
|
||||
saveState();
|
||||
}
|
||||
|
||||
if (model != SEN50) {
|
||||
if (!vocValid) {
|
||||
LOG_INFO("SEN5X: No valid VOC's state found");
|
||||
LOG_INFO("%s: No valid VOC's state found", sensorName);
|
||||
} else {
|
||||
// Check if state is recent
|
||||
if (vocStateRecent(now)) {
|
||||
// If current date greater than 01/01/2018 (validity check)
|
||||
// Send it to the sensor
|
||||
LOG_INFO("SEN5X: VOC state is valid and recent");
|
||||
LOG_INFO("%s: VOC state is valid and recent", sensorName);
|
||||
vocStateToSensor();
|
||||
} else {
|
||||
LOG_INFO("SEN5X: VOC state is too old or date is invalid");
|
||||
LOG_DEBUG("SEN5X: vocTime %u, Passed %u, and now %u", vocTime, passed, now);
|
||||
LOG_INFO("%s: VOC state is too old or date is invalid", sensorName);
|
||||
LOG_DEBUG("%s: vocTime %u, Passed %u, and now %u", sensorName, vocTime, passed, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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);
|
||||
@@ -632,16 +635,16 @@ bool SEN5XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
bool SEN5XSensor::readValues()
|
||||
{
|
||||
if (!sendCommand(SEN5X_READ_VALUES)) {
|
||||
LOG_ERROR("SEN5X: Error sending read command");
|
||||
LOG_ERROR("%s: Error sending read command", sensorName);
|
||||
return false;
|
||||
}
|
||||
LOG_DEBUG("SEN5X: Reading PM Values");
|
||||
LOG_DEBUG("%s: Reading PM Values", sensorName);
|
||||
delay(20); // From Sensirion Datasheet
|
||||
|
||||
uint8_t dataBuffer[16]{};
|
||||
size_t receivedNumber = readBuffer(&dataBuffer[0], 24);
|
||||
if (receivedNumber == 0) {
|
||||
LOG_ERROR("SEN5X: Error getting values");
|
||||
LOG_ERROR("%s: Error getting values", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -666,16 +669,16 @@ bool SEN5XSensor::readValues()
|
||||
sen5xmeasurement.vocIndex = !isnan(int_vocIndex) ? int_vocIndex / 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -684,17 +687,17 @@ bool SEN5XSensor::readValues()
|
||||
bool SEN5XSensor::readPNValues(bool cumulative)
|
||||
{
|
||||
if (!sendCommand(SEN5X_READ_PM_VALUES)) {
|
||||
LOG_ERROR("SEN5X: Error sending read command");
|
||||
LOG_ERROR("%s: Error sending read command", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_DEBUG("SEN5X: Reading PN Values");
|
||||
LOG_DEBUG("%s: Reading PN Values", sensorName);
|
||||
delay(20); // From Sensirion Datasheet
|
||||
|
||||
uint8_t dataBuffer[20]{};
|
||||
size_t receivedNumber = readBuffer(&dataBuffer[0], 30);
|
||||
if (receivedNumber == 0) {
|
||||
LOG_ERROR("SEN5X: Error getting PN values");
|
||||
LOG_ERROR("%s: Error getting PN values", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -728,7 +731,7 @@ bool SEN5XSensor::readPNValues(bool cumulative)
|
||||
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.pN10p0, sen5xmeasurement.tSize);
|
||||
|
||||
@@ -742,7 +745,7 @@ uint8_t SEN5XSensor::getMeasurements()
|
||||
|
||||
// Try to get new data
|
||||
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;
|
||||
}
|
||||
delay(20); // From Sensirion Datasheet
|
||||
@@ -750,7 +753,7 @@ uint8_t SEN5XSensor::getMeasurements()
|
||||
uint8_t dataReadyBuffer[3];
|
||||
size_t charNumber = readBuffer(&dataReadyBuffer[0], 3);
|
||||
if (charNumber == 0) {
|
||||
LOG_ERROR("SEN5X: Error getting device version value");
|
||||
LOG_ERROR("%s: Error getting device version value", sensorName);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -758,17 +761,17 @@ uint8_t SEN5XSensor::getMeasurements()
|
||||
uint32_t sinceLastDataPollMs = (now - lastDataPoll) * 1000;
|
||||
// Check if data is ready, and if since last time we requested is less than 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;
|
||||
}
|
||||
|
||||
if (!readValues()) {
|
||||
LOG_ERROR("SEN5X: Error getting readings");
|
||||
LOG_ERROR("%s: Error getting readings", sensorName);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!readPNValues(false)) {
|
||||
LOG_ERROR("SEN5X: Error getting PN readings");
|
||||
LOG_ERROR("%s: Error getting PN readings", sensorName);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -787,13 +790,13 @@ int32_t SEN5XSensor::pendingForReadyMs()
|
||||
uint32_t now;
|
||||
now = getTime();
|
||||
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) {
|
||||
case SEN5X_MEASUREMENT: {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -807,7 +810,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 ((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;
|
||||
// Report how many seconds are pending to cover the first warm up period
|
||||
return SEN5X_WARMUP_MS_2 - sincePmMeasureStarted;
|
||||
@@ -829,9 +832,9 @@ int32_t SEN5XSensor::pendingForReadyMs()
|
||||
|
||||
bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
LOG_INFO("SEN5X: Attempting to get metrics");
|
||||
LOG_INFO("%s: Attempting to get metrics", sensorName);
|
||||
if (!isActive()) {
|
||||
LOG_INFO("SEN5X: not in measurement mode");
|
||||
LOG_INFO("%s: not in measurement mode", sensorName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -921,9 +924,9 @@ void SEN5XSensor::setMode(bool setOneShot)
|
||||
{
|
||||
oneShotMode = setOneShot;
|
||||
if (oneShotMode) {
|
||||
LOG_INFO("%s setting mode to one shot mode", sensorName);
|
||||
LOG_INFO("%s: setting mode to one shot mode", sensorName);
|
||||
} 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
|
||||
|
||||
#include "../detect/ReClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "RTC.h"
|
||||
#include "TelemetrySensor.h"
|
||||
@@ -60,8 +61,9 @@ struct _SEN5XMeasurements {
|
||||
class SEN5XSensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
TwoWire *_bus{};
|
||||
uint8_t _address{};
|
||||
#ifdef SEN5X_I2C_CLOCK_SPEED
|
||||
ReClockI2C reClockI2C;
|
||||
#endif
|
||||
|
||||
bool getVersion();
|
||||
float firmwareVer = -1;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cSfa3x.h>)
|
||||
|
||||
#include "../detect/reClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "SFA30Sensor.h"
|
||||
|
||||
@@ -16,39 +15,39 @@ bool SFA30Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||
_address = dev->address.address;
|
||||
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
_port = dev->address.port;
|
||||
reClockI2C.setup(_bus, _port);
|
||||
|
||||
LOG_INFO("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
sfa30.begin(*_bus, _address);
|
||||
delay(20);
|
||||
|
||||
if (this->isError(sfa30.deviceReset())) {
|
||||
#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
state = State::IDLE;
|
||||
if (this->isError(sfa30.startContinuousMeasurement())) {
|
||||
#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("%s starting measurement", sensorName);
|
||||
|
||||
#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_INFO("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
status = 1;
|
||||
state = State::ACTIVE;
|
||||
@@ -72,14 +71,8 @@ bool SFA30Sensor::isError(uint16_t response)
|
||||
void SFA30Sensor::sleep()
|
||||
{
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
// Note - not recommended for this sensor on a periodic basis
|
||||
@@ -87,11 +80,12 @@ void SFA30Sensor::sleep()
|
||||
LOG_ERROR("%s: can't stop measurement", sensorName);
|
||||
};
|
||||
|
||||
#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
LOG_INFO("%s: stop measurement", sensorName);
|
||||
LOG_DEBUG("%s: stop measurement", sensorName);
|
||||
state = State::IDLE;
|
||||
measureStarted = 0;
|
||||
}
|
||||
@@ -99,27 +93,23 @@ void SFA30Sensor::sleep()
|
||||
uint32_t SFA30Sensor::wakeUp()
|
||||
{
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
LOG_INFO("Waking up %s", sensorName);
|
||||
LOG_DEBUG("Waking up %s", sensorName);
|
||||
if (this->isError(sfa30.startContinuousMeasurement())) {
|
||||
#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
state = State::ACTIVE;
|
||||
measureStarted = getTime();
|
||||
@@ -164,24 +154,23 @@ bool SFA30Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
float temperature = 0.0;
|
||||
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
#ifdef CAN_RECLOCK_I2C
|
||||
uint32_t currentClock = reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, false);
|
||||
#elif !HAS_SCREEN
|
||||
reClockI2C(SFA30_I2C_CLOCK_SPEED, _bus, true);
|
||||
#else
|
||||
LOG_WARN("%s can't be used at this clock speed, with a screen", sensorName);
|
||||
return false;
|
||||
#endif /* CAN_RECLOCK_I2C */
|
||||
LOG_DEBUG("%s attempting to reclock speed to %uHz", sensorName, SFA30_I2C_CLOCK_SPEED);
|
||||
reClockI2C.setClock(SFA30_I2C_CLOCK_SPEED);
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
if (this->isError(sfa30.readMeasuredValues(hcho, humidity, temperature))) {
|
||||
LOG_WARN("%s: No values", sensorName);
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(SFA30_I2C_CLOCK_SPEED) && defined(CAN_RECLOCK_I2C)
|
||||
reClockI2C(currentClock, _bus, false);
|
||||
#endif
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
LOG_DEBUG("%s restoring clock speed", sensorName);
|
||||
reClockI2C.restoreClock();
|
||||
#endif /* SFA30_I2C_CLOCK_SPEED */
|
||||
|
||||
measurement->variant.air_quality_metrics.has_form_temperature = true;
|
||||
measurement->variant.air_quality_metrics.has_form_humidity = true;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR && __has_include(<SensirionI2cSfa3x.h>)
|
||||
|
||||
#include "../detect/ReClockI2C.h"
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "RTC.h"
|
||||
#include "TelemetrySensor.h"
|
||||
@@ -19,8 +20,10 @@ class SFA30Sensor : public TelemetrySensor
|
||||
uint32_t measureStarted = 0;
|
||||
|
||||
SensirionI2cSfa3x sfa30;
|
||||
TwoWire *_bus{};
|
||||
uint8_t _address{};
|
||||
#ifdef SFA30_I2C_CLOCK_SPEED
|
||||
ReClockI2C reClockI2C;
|
||||
#endif
|
||||
|
||||
bool isError(uint16_t response);
|
||||
|
||||
public:
|
||||
|
||||
@@ -56,6 +56,11 @@ class TelemetrySensor
|
||||
}
|
||||
|
||||
const char *sensorName;
|
||||
// TODO: Rename?
|
||||
uint8_t _address = 0;
|
||||
TwoWire *_bus{};
|
||||
ScanI2C::I2CPort _port = ScanI2C::I2CPort::NO_I2C;
|
||||
|
||||
// TODO: delete after migration
|
||||
bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; }
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ build_flags =
|
||||
-DLIBPAX_BLE
|
||||
-DHAS_UDP_MULTICAST=1
|
||||
;-DDEBUG_HEAP
|
||||
-DCAN_RECLOCK_I2C
|
||||
-DCAN_GET_I2C_CLOCK
|
||||
|
||||
lib_deps =
|
||||
${arduino_base.lib_deps}
|
||||
|
||||
Reference in New Issue
Block a user