Mirror of espurna firmware for wireless switches and more
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

179 lines
5.7 KiB

// -----------------------------------------------------------------------------
// SHT3X Sensor over I2C (Wemos)
// Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
// -----------------------------------------------------------------------------
#if SENSOR_SUPPORT && SHT3X_I2C_SUPPORT
#pragma once
#include "I2CSensor.h"
#include "../utils.h"
static
#if __cplusplus >= 201703L
constexpr
#endif
bool _sht3x_crc8(uint8_t msb, uint8_t lsb, uint8_t expected) {
/*
* adapted from https://github.com/Risele/SHT3x/blob/master/SHT3x.cpp
* Name : CRC-8
* Poly : 0x31 x^8 + x^5 + x^4 + 1
* Init : 0xFF
* Revert: false
* XorOut: 0x00
* Check : for 0xBE,0xEF CRC is 0x92
*/
constexpr uint8_t Init { 0xFF };
constexpr uint8_t Mask { 0x80 };
constexpr uint8_t Poly { 0x31 };
uint8_t crc = Init;
crc ^= msb;
for (size_t i = 0; i < 8; ++i) {
crc = crc & Mask ? (crc << 1) ^ Poly : crc << 1;
}
crc ^= lsb;
for (size_t i = 0; i < 8; ++i) {
crc = crc & Mask ? (crc << 1) ^ Poly : crc << 1;
}
return crc == expected;
}
#if __cplusplus >= 201703L
static_assert(_sht3x_crc8(0xBE, 0xEF, 0x92), "");
#endif
class SHT3XI2CSensor : public I2CSensor<> {
public:
// ---------------------------------------------------------------------
// Sensor API
// ---------------------------------------------------------------------
unsigned char id() const override {
return SENSOR_SHT3X_I2C_ID;
}
unsigned char count() const override {
return 2;
}
// Initialization method, must be idempotent
void begin() override {
if (!_dirty) return;
// I2C auto-discover
static constexpr uint8_t addresses[] {0x44, 0x45};
const auto address = findAndLock(addresses);
if (address == 0) {
return;
}
// Soft reset, ensure sensor is in default state
i2c_write_uint8(address, 0x30, 0xA2);
espurna::time::blockingDelay(
espurna::duration::Milliseconds(500));
_ready = true;
_dirty = false;
}
// Descriptive name of the sensor
String description() const override {
char buffer[32];
snprintf_P(buffer, sizeof(buffer),
PSTR("SHT3X @ I2C (0x%02X)"), lockedAddress());
return String(buffer);
}
// Type for slot # index
unsigned char type(unsigned char index) const override {
if (index == 0) return MAGNITUDE_TEMPERATURE;
if (index == 1) return MAGNITUDE_HUMIDITY;
return MAGNITUDE_NONE;
}
// Pre-read hook (usually to populate registers with up-to-date data)
void pre() override {
_error = SENSOR_ERROR_OK;
const auto address = lockedAddress();
// Measurement High Repeatability with Clock Stretch Enabled
i2c_write_uint8(address, 0x2C, 0x06);
espurna::time::blockingDelay(
espurna::duration::Milliseconds(20));
unsigned char buffer[6];
i2c_read_buffer(address, buffer, std::size(buffer));
// result bytes are as follows
// cTemp msb, cTemp lsb, cTemp crc, humidity msb, humidity lsb, humidity crc
if ((_sht3x_crc8(buffer[0], buffer[1], buffer[2])) && (_sht3x_crc8(buffer[3], buffer[4], buffer[5]))) {
_temperature = ((((buffer[0] * 256.0) + buffer[1]) * 175) / 65535.0) - 45;
_humidity = ((((buffer[3] * 256.0) + buffer[4]) * 100) / 65535.0);
} else {
_error = SENSOR_ERROR_CRC;
}
#if SENSOR_DEBUG
_statusRegister();
#endif
}
// Current value for slot # index
double value(unsigned char index) override {
if (index == 0) return _temperature;
if (index == 1) return _humidity;
return 0;
}
private:
// Read the status register and output to Debug log
void _statusRegister() {
const auto address = lockedAddress();
// Request status register reading
i2c_write_uint8(address, 0xF3, 0x2D);
espurna::time::blockingDelay(
espurna::duration::Milliseconds(20));
unsigned char buffer[3];
i2c_read_buffer(address, buffer, std::size(buffer));
if (_sht3x_crc8(buffer[0],buffer[1],buffer[2])) {
// see https://sensirion.com/resource/datasheet/sht3x-d
uint16_t status = (buffer[0] << 8) | (buffer[1] & 0xff);
auto bit = [&](uint16_t offset) {
return (status & (1 << offset)) ? '1' : '0';
};
DEBUG_MSG_P(PSTR("[SHT3X] Status 0x%04X - crc:%c cmd:%c rst:%c tta:%c rhta:%c htr:%c alrt:%c\n"),
status,
bit(0), // last write crc status
bit(1), // last command status
bit(4), // system reset detected
bit(10), // T tracking alert
bit(11), // RH tracking alert
bit(13), // heater status
bit(15)); // alert pending status (1 when at least one alert)
}
else {
DEBUG_MSG_P(PSTR("[SHT3X] Checksum error when reading status register\n"));
}
// Clear status register
i2c_write_uint8(address, 0x30, 0x41);
}
double _temperature = 0;
double _humidity = 0;
};
#endif // SENSOR_SUPPORT && SHT3X_I2C_SUPPORT