Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LPS22HB_ADDR_ALT 0x5D
#define SHT31_4x_ADDR 0x44
#define SHT31_4x_ADDR_ALT 0x45
#define SHT21_ADDR 0x40 // same address as INA_ADDR
#ifndef HAS_SHT21
#define HAS_SHT21 0 // set to one to override detection of INA219/260 devices at this address
#endif
#define PMSA003I_ADDR 0x12
#define QMA6100P_ADDR 0x12
#define AHT10_ADDR 0x38
Expand Down
1 change: 1 addition & 0 deletions src/detect/ScanI2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ScanI2C
MAX17048,
MCP9808,
SHT31,
SHT21,
SHT4X,
SHTC3,
LPS22HB,
Expand Down
10 changes: 10 additions & 0 deletions src/detect/ScanI2CTwoWire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
#endif
#if !defined(M5STACK_UNITC6L)
#if !HAS_SHT21
case INA_ADDR:
#endif
case INA_ADDR_ALTERNATE:
case INA_ADDR_WAVESHARE_UPS:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
Expand Down Expand Up @@ -401,6 +403,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)

break;

#if HAS_SHT21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a register you can look up on the SHT21 that is unique to that model, or at least able to distinguish it from the other chips that share the address? That way we could detect it and use it without a firmware rebuild.

case SHT21_ADDR:
// SHT21 / HTU21D family commonly at 0x40
logFoundDevice("SHT21/HTU21D", (uint8_t)addr.address);
type = SHT21;
break;
#endif

SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address)
case RCWL9620_ADDR:
// get MAX30102 PARTID
Expand Down
8 changes: 5 additions & 3 deletions src/mesh/generated/meshtastic/telemetry.pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ typedef enum _meshtastic_TelemetrySensorType {
/* TSL2561 light sensor */
meshtastic_TelemetrySensorType_TSL2561 = 44,
/* BH1750 light sensor */
meshtastic_TelemetrySensorType_BH1750 = 45
meshtastic_TelemetrySensorType_BH1750 = 45,
/* STH21 Temperature and R. Humidity sensor */
meshtastic_TelemetrySensorType_SHT21 = 46
} meshtastic_TelemetrySensorType;

/* Struct definitions */
Expand Down Expand Up @@ -461,8 +463,8 @@ extern "C" {

/* Helper constants for enums */
#define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_BH1750
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_BH1750+1))
#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SHT21
#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SHT21+1))



Expand Down
7 changes: 7 additions & 0 deletions src/modules/Telemetry/EnvironmentTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
#include "Sensor/SHT31Sensor.h"
#endif

#if HAS_SHT21
#include "Sensor/SHT21Sensor.h"
#endif

#if __has_include(<Adafruit_LPS2X.h>)
#include "Sensor/LPS22HBSensor.h"
#endif
Expand Down Expand Up @@ -202,6 +206,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
#if __has_include(<Adafruit_SHT31.h>)
addSensor<SHT31Sensor>(i2cScanner, ScanI2C::DeviceType::SHT31);
#endif
#if HAS_SHT21
addSensor<SHT21Sensor>(i2cScanner, ScanI2C::DeviceType::SHT21);
#endif
#if __has_include(<Adafruit_LPS2X.h>)
addSensor<LPS22HBSensor>(i2cScanner, ScanI2C::DeviceType::LPS22HB);
#endif
Expand Down
85 changes: 85 additions & 0 deletions src/modules/Telemetry/Sensor/SHT21Sensor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "configuration.h"

#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR

#include "SHT21Sensor.h"
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Wire.h>
#include <cmath>

// SHT21 I2C address and commands (use no-hold commands to avoid clock-stretch issues)
static const uint8_t CMD_TEMP_NOHOLD = 0xF3;
static const uint8_t CMD_HUM_NOHOLD = 0xF5;

static bool read_sht21_raw(TwoWire *bus, uint8_t addr, uint8_t cmd, uint16_t &raw, uint16_t waitMs)
{
bus->beginTransmission(addr);
bus->write(cmd);
if (bus->endTransmission() != 0)
return false;
// Wait for measurement to complete (no-hold mode)
delay(waitMs);
int toRead = 3; // two data bytes + CRC
bus->requestFrom((int)addr, toRead);
if (bus->available() < 2)
return false;
uint8_t msb = bus->read();
uint8_t lsb = bus->read();
if (bus->available())
(void)bus->read();

raw = ((uint16_t)msb << 8) | lsb;
// clear status bits per datasheet
raw &= ~0x0003;
return true;
}

SHT21Sensor::SHT21Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT21, "SHT21") {}

bool SHT21Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
{
LOG_INFO("Init sensor: %s", sensorName);
i2c = bus;
i2c_addr = dev->address.address ? dev->address.address : SHT21_ADDR;

uint16_t raw;
// use no-hold command and wait for conversion (max ~85ms for temp)
if (!read_sht21_raw(i2c, i2c_addr, CMD_TEMP_NOHOLD, raw, 85)) {
return false;
}
float temp = -46.85f + 175.72f * ((float)raw / 65536.0f);
// basic sanity check
if (temp < -50.0f || temp > 150.0f)
return false;

status = true;
initI2CSensor();
return true;
}

bool SHT21Sensor::getMetrics(meshtastic_Telemetry *measurement)
{
measurement->variant.environment_metrics.has_temperature = true;
measurement->variant.environment_metrics.has_relative_humidity = true;

LOG_DEBUG("SHT21 getMetrics");

uint16_t raw_t = 0, raw_h = 0;
if (!read_sht21_raw(i2c, i2c_addr, CMD_TEMP_NOHOLD, raw_t, 85))
return false;
// humidity max conversion time ~29ms
if (!read_sht21_raw(i2c, i2c_addr, CMD_HUM_NOHOLD, raw_h, 30))
return false;

float temp = -46.85f + 175.72f * ((float)raw_t / 65536.0f);
float rh = -6.0f + 125.0f * ((float)raw_h / 65536.0f);

// Round to 2 decimal places for telemetry
measurement->variant.environment_metrics.temperature = roundf(temp * 100.0f) / 100.0f;
measurement->variant.environment_metrics.relative_humidity = roundf(rh * 100.0f) / 100.0f;

return true;
}

#endif
22 changes: 22 additions & 0 deletions src/modules/Telemetry/Sensor/SHT21Sensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "configuration.h"

#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR

#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Wire.h>

class SHT21Sensor : public TelemetrySensor
{
private:
TwoWire *i2c = nullptr;
uint8_t i2c_addr = 0;
bool status = false;

public:
SHT21Sensor();
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
};

#endif