mirror of
https://github.com/meshtastic/firmware.git
synced 2025-08-03 20:30:43 +00:00
WIP Sen5X functions
This commit is contained in:
parent
94df0cb636
commit
d7bb0f7cdf
@ -199,6 +199,4 @@ lib_deps =
|
|||||||
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
|
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
|
||||||
sensirion/Sensirion Core@0.7.1
|
sensirion/Sensirion Core@0.7.1
|
||||||
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
||||||
sensirion/Sensirion I2C SCD4x@1.1.0
|
sensirion/Sensirion I2C SCD4x@1.1.0
|
||||||
# renovate: datasource=custom.pio depName=Sensirion I2C SEN5X packageName=sensirion/library/Sensirion I2C SEN5X
|
|
||||||
sensirion/Sensirion I2C SEN5X
|
|
@ -9,10 +9,6 @@
|
|||||||
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
|
||||||
#include "meshUtils.h" // vformat
|
#include "meshUtils.h" // vformat
|
||||||
|
|
||||||
#define SEN50_NAME 48
|
|
||||||
#define SEN54_NAME 52
|
|
||||||
#define SEN55_NAME 53
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
bool in_array(uint8_t *array, int size, uint8_t lookfor)
|
||||||
@ -114,6 +110,58 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// for SEN5X detection
|
||||||
|
bool probeSEN5X(const ScanI2C::DeviceAddress& addr, TwoWire* i2cBus) {
|
||||||
|
uint8_t cmd[] = { 0xD0, 0x33 }; // Read Serial Number command
|
||||||
|
uint8_t rxBuf[9] = {0};
|
||||||
|
|
||||||
|
i2cBus->beginTransmission(addr.address);
|
||||||
|
i2cBus->write(cmd, 2);
|
||||||
|
if (i2cBus->endTransmission() != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
delay(20); // wait for response
|
||||||
|
|
||||||
|
if (i2cBus->requestFrom(addr.address, (uint8_t)9) != 9)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < 9 && i2cBus->available(); ++i)
|
||||||
|
rxBuf[i] = i2cBus->read();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String readSEN5xProductName(TwoWire* i2cBus, uint8_t address) {
|
||||||
|
uint8_t cmd[] = { 0xD0, 0x14 };
|
||||||
|
uint8_t response[48] = {0};
|
||||||
|
|
||||||
|
i2cBus->beginTransmission(address);
|
||||||
|
i2cBus->write(cmd, 2);
|
||||||
|
if (i2cBus->endTransmission() != 0) return "";
|
||||||
|
|
||||||
|
delay(20);
|
||||||
|
if (i2cBus->requestFrom(address, (uint8_t)48) != 48) return "";
|
||||||
|
|
||||||
|
for (int i = 0; i < 48 && i2cBus->available(); ++i) {
|
||||||
|
response[i] = i2cBus->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
char productName[33] = {0};
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < 48 && j < 32; i += 3) {
|
||||||
|
if (response[i] >= 32 && response[i] <= 126)
|
||||||
|
productName[j++] = response[i];
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (response[i + 1] >= 32 && response[i + 1] <= 126)
|
||||||
|
productName[j++] = response[i + 1];
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return String(productName);
|
||||||
|
}
|
||||||
|
|
||||||
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
|
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
|
||||||
case ADDR: \
|
case ADDR: \
|
||||||
logFoundDevice(__VA_ARGS__); \
|
logFoundDevice(__VA_ARGS__); \
|
||||||
@ -131,6 +179,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
DeviceAddress addr(port, 0x00);
|
DeviceAddress addr(port, 0x00);
|
||||||
|
|
||||||
uint16_t registerValue = 0x00;
|
uint16_t registerValue = 0x00;
|
||||||
|
String prod = "";
|
||||||
ScanI2C::DeviceType type;
|
ScanI2C::DeviceType type;
|
||||||
TwoWire *i2cBus;
|
TwoWire *i2cBus;
|
||||||
#ifdef RV3028_RTC
|
#ifdef RV3028_RTC
|
||||||
@ -473,40 +522,25 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
|||||||
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
|
case ICM20948_ADDR_ALT: // same as MPU6050_ADDR
|
||||||
// ICM20948 Register check
|
// ICM20948 Register check
|
||||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
|
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
|
||||||
|
prod = readSEN5xProductName(i2cBus, addr.address);
|
||||||
if (registerValue == 0xEA) {
|
if (registerValue == 0xEA) {
|
||||||
type = ICM20948;
|
type = ICM20948;
|
||||||
logFoundDevice("ICM20948", (uint8_t)addr.address);
|
logFoundDevice("ICM20948", (uint8_t)addr.address);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// TODO refurbish to find the model
|
if (prod.startsWith("SEN55")) {
|
||||||
// Just a hack for the hackathon
|
|
||||||
if (addr.address == SEN5X_ADDR) {
|
|
||||||
type = SEN5X;
|
type = SEN5X;
|
||||||
logFoundDevice("SEN5X", (uint8_t)addr.address);
|
logFoundDevice("Sensirion SEN55", addr.address);
|
||||||
|
break;
|
||||||
|
} else if (prod.startsWith("SEN54")) {
|
||||||
|
type = SEN5X;
|
||||||
|
logFoundDevice("Sensirion SEN54", addr.address);
|
||||||
|
break;
|
||||||
|
} else if (prod.startsWith("SEN50")) {
|
||||||
|
type = SEN5X;
|
||||||
|
logFoundDevice("Sensirion SEN50", addr.address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can get the 0xD014 register to find the model. This is not a simple task
|
|
||||||
// There is a buffer returned - getRegisterValue is not enough (maybe)
|
|
||||||
// registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD014), 6);
|
|
||||||
// Important to leave delay
|
|
||||||
// delay(50);
|
|
||||||
|
|
||||||
// const uint8_t nameSize = 48;
|
|
||||||
// uint8_t name[nameSize] = ®isterValue;
|
|
||||||
|
|
||||||
// switch(name[4]){
|
|
||||||
// case SEN50_NAME:
|
|
||||||
// type = SEN50;
|
|
||||||
// break;
|
|
||||||
// case SEN54_NAME:
|
|
||||||
// type = SEN54;
|
|
||||||
// break;
|
|
||||||
// case SEN55_NAME:
|
|
||||||
// type = SEN55;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (addr.address == BMX160_ADDR) {
|
if (addr.address == BMX160_ADDR) {
|
||||||
type = BMX160;
|
type = BMX160;
|
||||||
logFoundDevice("BMX160", (uint8_t)addr.address);
|
logFoundDevice("BMX160", (uint8_t)addr.address);
|
||||||
|
@ -24,7 +24,12 @@ PMSA003ISensor pmsa003iSensor;
|
|||||||
NullSensor pmsa003iSensor;
|
NullSensor pmsa003iSensor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(<SensirionI2CSen5x.h>)
|
// Small hack
|
||||||
|
#ifndef INCLUDE_SEN5X
|
||||||
|
#define INCLUDE_SEN5X 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef INCLUDE_SEN5X
|
||||||
#include "Sensor/SEN5XSensor.h"
|
#include "Sensor/SEN5XSensor.h"
|
||||||
SEN5XSensor sen5xSensor;
|
SEN5XSensor sen5xSensor;
|
||||||
#else
|
#else
|
||||||
|
@ -1,14 +1,169 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<SensirionI2CSen5x.h>)
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "SEN5XSensor.h"
|
#include "SEN5XSensor.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
#include <SensirionI2CSen5x.h>
|
|
||||||
|
|
||||||
SEN5XSensor::SEN5XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SEN5X, "SEN5X") {}
|
SEN5XSensor::SEN5XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SEN5X, "SEN5X") {}
|
||||||
|
|
||||||
|
bool SEN5XSensor::getVersion()
|
||||||
|
{
|
||||||
|
if (!sendCommand(SEN5X_GET_FIRMWARE_VERSION)){
|
||||||
|
LOG_ERROR("SEN5X: Error sending version command");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
delay(20); // From Sensirion Arduino library
|
||||||
|
|
||||||
|
uint8_t versionBuffer[12];
|
||||||
|
size_t charNumber = readBuffer(&versionBuffer[0], 3);
|
||||||
|
if (charNumber == 0) {
|
||||||
|
LOG_ERROR("SEN5X: Error getting data ready flag value");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
firmwareVer = versionBuffer[0] + (versionBuffer[1] / 10);
|
||||||
|
hardwareVer = versionBuffer[3] + (versionBuffer[4] / 10);
|
||||||
|
protocolVer = versionBuffer[5] + (versionBuffer[6] / 10);
|
||||||
|
|
||||||
|
LOG_INFO("SEN5X Firmware Version: %d", firmwareVer);
|
||||||
|
LOG_INFO("SEN5X Hardware Version: %d", hardwareVer);
|
||||||
|
LOG_INFO("SEN5X Protocol Version: %d", protocolVer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEN5XSensor::findModel()
|
||||||
|
{
|
||||||
|
if (!sendCommand(SEN5X_GET_PRODUCT_NAME)) {
|
||||||
|
LOG_ERROR("SEN5X: Error asking for product name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
delay(50); // From Sensirion Arduino library
|
||||||
|
|
||||||
|
const uint8_t nameSize = 48;
|
||||||
|
uint8_t name[nameSize];
|
||||||
|
size_t charNumber = readBuffer(&name[0], nameSize);
|
||||||
|
if (charNumber == 0) {
|
||||||
|
LOG_ERROR("SEN5X: Error getting device name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only check the last character that defines the model SEN5X
|
||||||
|
switch(name[4])
|
||||||
|
{
|
||||||
|
case 48:
|
||||||
|
model = SEN50;
|
||||||
|
LOG_INFO("SEN5X: found sensor model SEN50");
|
||||||
|
break;
|
||||||
|
case 52:
|
||||||
|
model = SEN54;
|
||||||
|
LOG_INFO("SEN5X: found sensor model SEN54");
|
||||||
|
break;
|
||||||
|
case 53:
|
||||||
|
model = SEN55;
|
||||||
|
LOG_INFO("SEN5X: found sensor model SEN55");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEN5XSensor::sendCommand(uint16_t command)
|
||||||
|
{
|
||||||
|
uint8_t nothing;
|
||||||
|
return sendCommand(command, ¬hing, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEN5XSensor::sendCommand(uint16_t command, uint8_t* buffer, uint8_t byteNumber)
|
||||||
|
{
|
||||||
|
// At least we need two bytes for the command
|
||||||
|
uint8_t bufferSize = 2;
|
||||||
|
|
||||||
|
// Add space for CRC bytes (one every two bytes)
|
||||||
|
if (byteNumber > 0) bufferSize += byteNumber + (byteNumber / 2);
|
||||||
|
|
||||||
|
uint8_t toSend[bufferSize];
|
||||||
|
uint8_t i = 0;
|
||||||
|
toSend[i++] = static_cast<uint8_t>((command & 0xFF00) >> 8);
|
||||||
|
toSend[i++] = static_cast<uint8_t>((command & 0x00FF) >> 0);
|
||||||
|
|
||||||
|
// Prepare buffer with CRC every third byte
|
||||||
|
uint8_t bi = 0;
|
||||||
|
if (byteNumber > 0) {
|
||||||
|
while (bi < byteNumber) {
|
||||||
|
toSend[i++] = buffer[bi++];
|
||||||
|
toSend[i++] = buffer[bi++];
|
||||||
|
uint8_t calcCRC = CRC(&buffer[bi - 2]);
|
||||||
|
toSend[i++] = calcCRC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit the data
|
||||||
|
bus->beginTransmission(address);
|
||||||
|
size_t writtenBytes = bus->write(toSend, bufferSize);
|
||||||
|
uint8_t i2c_error = bus->endTransmission();
|
||||||
|
|
||||||
|
if (writtenBytes != bufferSize) {
|
||||||
|
LOG_ERROR("SEN5X: Error writting on I2C bus");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i2c_error != 0) {
|
||||||
|
LOG_ERROR("SEN5X: Error on I2c communication: %x", i2c_error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t SEN5XSensor::readBuffer(uint8_t* buffer, uint8_t byteNumber)
|
||||||
|
{
|
||||||
|
size_t readedBytes = bus->requestFrom(address, byteNumber);
|
||||||
|
|
||||||
|
if (readedBytes != byteNumber) {
|
||||||
|
LOG_ERROR("SEN5X: Error reading I2C bus");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t i = 0;
|
||||||
|
uint8_t receivedBytes = 0;
|
||||||
|
while (readedBytes > 0) {
|
||||||
|
buffer[i++] = bus->read(); // Just as a reminder: i++ returns i and after that increments.
|
||||||
|
buffer[i++] = bus->read();
|
||||||
|
uint8_t recvCRC = bus->read();
|
||||||
|
uint8_t calcCRC = CRC(&buffer[i - 2]);
|
||||||
|
if (recvCRC != calcCRC) {
|
||||||
|
LOG_ERROR("SEN5X: Checksum error while receiving msg");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
readedBytes -=3;
|
||||||
|
receivedBytes += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return receivedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t SEN5XSensor::CRC(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
// This code is based on Sensirion's own implementation https://github.com/Sensirion/arduino-core/blob/41fd02cacf307ec4945955c58ae495e56809b96c/src/SensirionCrc.cpp
|
||||||
|
uint8_t crc = 0xff;
|
||||||
|
|
||||||
|
for (uint8_t i=0; i<2; i++){
|
||||||
|
|
||||||
|
crc ^= buffer[i];
|
||||||
|
|
||||||
|
for (uint8_t bit=8; bit>0; bit--) {
|
||||||
|
if (crc & 0x80)
|
||||||
|
crc = (crc << 1) ^ 0x31;
|
||||||
|
else
|
||||||
|
crc = (crc << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t SEN5XSensor::runOnce()
|
int32_t SEN5XSensor::runOnce()
|
||||||
{
|
{
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
LOG_INFO("Init sensor: %s", sensorName);
|
||||||
@ -16,30 +171,54 @@ int32_t SEN5XSensor::runOnce()
|
|||||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
}
|
}
|
||||||
|
|
||||||
sen5x.begin(*nodeTelemetrySensorsMap[sensorType].second);
|
bus = nodeTelemetrySensorsMap[sensorType].second;
|
||||||
|
// sen5x.begin(*bus);
|
||||||
|
|
||||||
delay(25); // without this there is an error on the deviceReset function (NOT WORKING)
|
delay(50); // without this there is an error on the deviceReset function
|
||||||
|
|
||||||
uint16_t error;
|
if (!sendCommand(SEN5X_RESET)) {
|
||||||
char errorMessage[256];
|
LOG_ERROR("SEN5X: Error reseting device");
|
||||||
error = sen5x.deviceReset();
|
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
if (error) {
|
}
|
||||||
LOG_INFO("Error trying to execute deviceReset(): ");
|
delay(200); // From Sensirion Arduino library
|
||||||
errorToString(error, errorMessage, 256);
|
|
||||||
LOG_INFO(errorMessage);
|
if (!findModel()) {
|
||||||
|
LOG_ERROR("SEN5X: error finding sensor model");
|
||||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = sen5x.startMeasurement();
|
// Check if firmware version allows The direct switch between Measurement and RHT/Gas-Only Measurement mode
|
||||||
if (error) {
|
if (!getVersion()) return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
LOG_INFO("Error trying to execute startMeasurement(): ");
|
if (firmwareVer < 2) {
|
||||||
errorToString(error, errorMessage, 256);
|
LOG_ERROR("SEN5X: error firmware is too old and will not work with this implementation");
|
||||||
LOG_INFO(errorMessage);
|
|
||||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
} else {
|
|
||||||
status = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detection succeeded
|
||||||
|
state = SEN5X_IDLE;
|
||||||
|
status = 1;
|
||||||
|
LOG_INFO("SEN5X Enabled");
|
||||||
|
|
||||||
|
// uint16_t error;
|
||||||
|
// char errorMessage[256];
|
||||||
|
// error = sen5x.deviceReset();
|
||||||
|
// if (error) {
|
||||||
|
// LOG_INFO("Error trying to execute deviceReset(): ");
|
||||||
|
// errorToString(error, errorMessage, 256);
|
||||||
|
// LOG_INFO(errorMessage);
|
||||||
|
// return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// error = sen5x.startMeasurement();
|
||||||
|
// if (error) {
|
||||||
|
// LOG_INFO("Error trying to execute startMeasurement(): ");
|
||||||
|
// errorToString(error, errorMessage, 256);
|
||||||
|
// LOG_INFO(errorMessage);
|
||||||
|
// return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||||
|
// } else {
|
||||||
|
// status = 1;
|
||||||
|
// }
|
||||||
|
|
||||||
return initI2CSensor();
|
return initI2CSensor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,26 +226,24 @@ void SEN5XSensor::setup()
|
|||||||
{
|
{
|
||||||
#ifdef SEN5X_ENABLE_PIN
|
#ifdef SEN5X_ENABLE_PIN
|
||||||
pinMode(SEN5X_ENABLE_PIN, OUTPUT);
|
pinMode(SEN5X_ENABLE_PIN, OUTPUT);
|
||||||
|
digitalWrite(SEN5X_ENABLE_PIN, HIGH);
|
||||||
|
delay(25);
|
||||||
#endif /* SEN5X_ENABLE_PIN */
|
#endif /* SEN5X_ENABLE_PIN */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SEN5X_ENABLE_PIN
|
#ifdef SEN5X_ENABLE_PIN
|
||||||
void SEN5XSensor::sleep() {
|
// void SEN5XSensor::sleep() {
|
||||||
digitalWrite(SEN5X_ENABLE_PIN, LOW);
|
// digitalWrite(SEN5X_ENABLE_PIN, LOW);
|
||||||
state = State::IDLE;
|
// state = SSEN5XState::SEN5X_OFF;
|
||||||
}
|
// }
|
||||||
|
|
||||||
uint32_t SEN5XSensor::wakeUp() {
|
// uint32_t SEN5XSensor::wakeUp() {
|
||||||
digitalWrite(SEN5X_ENABLE_PIN, HIGH);
|
// digitalWrite(SEN5X_ENABLE_PIN, HIGH);
|
||||||
state = State::ACTIVE;
|
// state = SEN5XState::SEN5X_IDLE;
|
||||||
return SEN5X_WARMUP_MS;
|
// return SEN5X_WARMUP_MS;
|
||||||
}
|
// }
|
||||||
#endif /* SEN5X_ENABLE_PIN */
|
#endif /* SEN5X_ENABLE_PIN */
|
||||||
|
|
||||||
bool SEN5XSensor::isActive() {
|
|
||||||
return state == State::ACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
{
|
{
|
||||||
uint16_t error;
|
uint16_t error;
|
||||||
@ -82,24 +259,24 @@ bool SEN5XSensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
float vocIndex;
|
float vocIndex;
|
||||||
float noxIndex;
|
float noxIndex;
|
||||||
|
|
||||||
error = sen5x.readMeasuredValues(
|
// error = sen5x.readMeasuredValues(
|
||||||
massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0,
|
// massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0,
|
||||||
massConcentrationPm10p0, ambientHumidity, ambientTemperature, vocIndex,
|
// massConcentrationPm10p0, ambientHumidity, ambientTemperature, vocIndex,
|
||||||
noxIndex);
|
// noxIndex);
|
||||||
|
|
||||||
if (error) {
|
// if (error) {
|
||||||
LOG_INFO("Error trying to execute readMeasuredValues(): ");
|
// LOG_INFO("Error trying to execute readMeasuredValues(): ");
|
||||||
errorToString(error, errorMessage, 256);
|
// errorToString(error, errorMessage, 256);
|
||||||
LOG_INFO(errorMessage);
|
// LOG_INFO(errorMessage);
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
measurement->variant.air_quality_metrics.has_pm10_standard = true;
|
// measurement->variant.air_quality_metrics.has_pm10_standard = true;
|
||||||
measurement->variant.air_quality_metrics.pm10_standard = massConcentrationPm1p0;
|
// measurement->variant.air_quality_metrics.pm10_standard = massConcentrationPm1p0;
|
||||||
measurement->variant.air_quality_metrics.has_pm25_standard = true;
|
// measurement->variant.air_quality_metrics.has_pm25_standard = true;
|
||||||
measurement->variant.air_quality_metrics.pm25_standard = massConcentrationPm2p5;
|
// measurement->variant.air_quality_metrics.pm25_standard = massConcentrationPm2p5;
|
||||||
measurement->variant.air_quality_metrics.has_pm100_standard = true;
|
// measurement->variant.air_quality_metrics.has_pm100_standard = true;
|
||||||
measurement->variant.air_quality_metrics.pm100_standard = massConcentrationPm10p0;
|
// measurement->variant.air_quality_metrics.pm100_standard = massConcentrationPm10p0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,64 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<SensirionI2CSen5x.h>)
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
#include <SensirionI2CSen5x.h>
|
#include "Wire.h"
|
||||||
|
// #include <SensirionI2CSen5x.h>
|
||||||
|
|
||||||
#ifndef SEN5X_WARMUP_MS
|
#ifndef SEN5X_WARMUP_MS
|
||||||
// from the SEN5X datasheet
|
// from the SEN5X datasheet
|
||||||
#define SEN5X_WARMUP_MS_SMALL 30000
|
#define SEN5X_WARMUP_MS 30000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class SEN5XSensor : public TelemetrySensor
|
class SEN5XSensor : public TelemetrySensor
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SensirionI2CSen5x sen5x;
|
TwoWire * bus;
|
||||||
// PM25_AQI_Data pmsa003iData = {0};
|
uint8_t address;
|
||||||
|
|
||||||
|
bool getVersion();
|
||||||
|
float firmwareVer = -1;
|
||||||
|
float hardwareVer = -1;
|
||||||
|
float protocolVer = -1;
|
||||||
|
bool findModel();
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
#define SEN5X_RESET 0xD304
|
||||||
|
#define SEN5X_GET_PRODUCT_NAME 0xD014
|
||||||
|
#define SEN5X_GET_FIRMWARE_VERSION 0xD100
|
||||||
|
#define SEN5X_START_MEASUREMENT 0x0021
|
||||||
|
#define SEN5X_START_MEASUREMENT_RHT_GAS 0x0037
|
||||||
|
#define SEN5X_STOP_MEASUREMENT 0x0104
|
||||||
|
#define SEN5X_READ_DATA_READY 0x0202
|
||||||
|
#define SEN5X_START_FAN_CLEANING 0x5607
|
||||||
|
#define SEN5X_RW_VOCS_STATE 0x6181
|
||||||
|
|
||||||
|
#define SEN5X_READ_VALUES 0x03C4
|
||||||
|
#define SEN5X_READ_RAW_VALUES 0x03D2
|
||||||
|
#define SEN5X_READ_PM_VALUES 0x0413
|
||||||
|
|
||||||
|
enum SEN5Xmodel { SEN5X_UNKNOWN = 0, SEN50 = 0b001, SEN54 = 0b010, SEN55 = 0b100 };
|
||||||
|
SEN5Xmodel model = SEN5X_UNKNOWN;
|
||||||
|
|
||||||
|
enum SEN5XState { SEN5X_OFF, SEN5X_IDLE, SEN5X_MEASUREMENT, SEN5X_MEASUREMENT_2, SEN5X_CLEANING, SEN5X_NOT_DETECTED };
|
||||||
|
SEN5XState state = SEN5X_OFF;
|
||||||
|
|
||||||
|
bool sendCommand(uint16_t wichCommand);
|
||||||
|
bool sendCommand(uint16_t wichCommand, uint8_t* buffer, uint8_t byteNumber=0);
|
||||||
|
uint8_t readBuffer(uint8_t* buffer, uint8_t byteNumber); // Return number of bytes received
|
||||||
|
uint8_t CRC(uint8_t* buffer);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void setup() override;
|
virtual void setup() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum State {
|
|
||||||
IDLE = 0,
|
|
||||||
ACTIVE = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef SEN5X_ENABLE_PIN
|
// #ifdef SEN5X_ENABLE_PIN
|
||||||
void sleep();
|
// void sleep();
|
||||||
uint32_t wakeUp();
|
// uint32_t wakeUp();
|
||||||
State state = State::IDLE;
|
// #endif
|
||||||
#else
|
|
||||||
State state = State::ACTIVE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SEN5XSensor();
|
SEN5XSensor();
|
||||||
bool isActive();
|
bool isActive();
|
||||||
|
Loading…
Reference in New Issue
Block a user