I cannot really remember. I haven’t been working much with Homeassistant since then.
I don’t think I went any further with this, as the “dirty” solution worked.
I have attached the code I was using (I think). It is located in /config/esphome/custom_components/mycusensor.h
Good luck.
#include "esphome.h"
// status code
#define DPS__SUCCEEDED 0
#define DPS__FAIL_UNKNOWN -1
#define DPS__FAIL_INIT_FAILED -2
#define DPS__FAIL_TOOBUSY -3
#define DPS__FAIL_UNFINISHED -4
// constants
#define DPS__NUM_OF_SCAL_FACTS 8
#define DPS__RESULT_BLOCK_LENGTH 3
typedef struct
{
uint8_t regAddress;
uint8_t length;
} RegBlock_t;
enum RegisterBlocks_e
{
PRS = 0, // pressure value
TEMP, // temperature value
};
const RegBlock_t registerBlocks[2] = {
{0x00, 3},
{0x03, 3},
};
const RegBlock_t coeffBlock = {0x10, 18};
class myclass {
public:
myclass() { _local_address = 0x76; };
void getTwosComplement(int32_t *raw, uint8_t length) {
if (*raw & ((uint32_t)1 << (length - 1)))
*raw -= (uint32_t)1 << length;
}
byte i2c_read(byte reg) {
Wire.beginTransmission(_local_address);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom((byte) _local_address, (byte) 1, (byte) true);
if (Wire.available() == 1)
return (byte) Wire.read();
return 0;
}
void i2c_write(byte reg, byte val) {
Wire.beginTransmission(_local_address);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
int16_t readBlock(RegBlock_t regBlock, uint8_t *buffer) {
//do not read if there is no buffer
if (buffer == NULL)
return 0; //0 bytes read successfully
Wire.beginTransmission((byte) _local_address);
Wire.write(regBlock.regAddress);
Wire.endTransmission(false);
//request length bytes from slave
int16_t ret = Wire.requestFrom((byte) _local_address, regBlock.length, 1U);
//read all received bytes to buffer
for (int16_t count = 0; count < ret; count++)
buffer[count] = Wire.read();
return ret;
}
int16_t getRawResult(int32_t *raw, RegBlock_t reg)
{
uint8_t buffer[DPS__RESULT_BLOCK_LENGTH] = {0};
if (readBlock(reg, buffer) != DPS__RESULT_BLOCK_LENGTH)
return DPS__FAIL_UNKNOWN;
*raw = (uint32_t)buffer[0] << 16 | (uint32_t)buffer[1] << 8 | (uint32_t)buffer[2];
getTwosComplement(raw, 24);
return DPS__SUCCEEDED;
}
int16_t readcoeffs(void) {
// TODO: remove magic number
uint8_t buffer[18];
//read COEF registers to buffer
int16_t ret = readBlock(coeffBlock, buffer);
//compose coefficients from buffer content
m_c0Half = ((uint32_t)buffer[0] << 4) | (((uint32_t)buffer[1] >> 4) & 0x0F);
getTwosComplement(&m_c0Half, 12);
//c0 is only used as c0*0.5, so c0_half is calculated immediately
m_c0Half = m_c0Half / 2U;
//now do the same thing for all other coefficients
m_c1 = (((uint32_t)buffer[1] & 0x0F) << 8) | (uint32_t)buffer[2];
getTwosComplement(&m_c1, 12);
m_c00 = ((uint32_t)buffer[3] << 12) | ((uint32_t)buffer[4] << 4) | (((uint32_t)buffer[5] >> 4) & 0x0F);
getTwosComplement(&m_c00, 20);
m_c10 = (((uint32_t)buffer[5] & 0x0F) << 16) | ((uint32_t)buffer[6] << 8) | (uint32_t)buffer[7];
getTwosComplement(&m_c10, 20);
m_c01 = ((uint32_t)buffer[8] << 8) | (uint32_t)buffer[9];
getTwosComplement(&m_c01, 16);
m_c11 = ((uint32_t)buffer[10] << 8) | (uint32_t)buffer[11];
getTwosComplement(&m_c11, 16);
m_c20 = ((uint32_t)buffer[12] << 8) | (uint32_t)buffer[13];
getTwosComplement(&m_c20, 16);
m_c21 = ((uint32_t)buffer[14] << 8) | (uint32_t)buffer[15];
getTwosComplement(&m_c21, 16);
m_c30 = ((uint32_t)buffer[16] << 8) | (uint32_t)buffer[17];
getTwosComplement(&m_c30, 16);
return DPS__SUCCEEDED;
}
void init() {
readcoeffs();
i2c_write(0x06, 0b00110011);
i2c_write(0x07, 0x80 | 0b00110011);
// patch some error
i2c_write(0x0E, 0xA5);
i2c_write(0x0F, 0x96);
i2c_write(0x62, 0x02);
i2c_write(0x0E, 0x00);
i2c_write(0x0F, 0x00);
i2c_write(0x08, 0b00100111);
}
float getTemp() {
int32_t raw_val;
getRawResult(&raw_val, registerBlocks[TEMP]);
float temp = raw_val;
//scale temperature according to scaling table and oversampling
temp /= scaling_facts[3];
//update last measured temperature
//it will be used for pressure compensation
m_lastTempScal = temp;
//Calculate compensated temperature
temp = m_c0Half + m_c1 * temp;
return temp;
}
float getPressure() {
int32_t raw_val;
getRawResult(&raw_val, registerBlocks[PRS]);
float prs = raw_val;
//scale pressure according to scaling table and oversampling
prs /= scaling_facts[3];
//Calculate compensated pressure
prs = m_c00 + prs * (m_c10 + prs * (m_c20 + prs * m_c30)) + m_lastTempScal * (m_c01 + prs * (m_c11 + prs * m_c21));
//return pressure
return prs;
}
protected:
uint8_t _local_address;
//scaling factor table
static const int32_t scaling_facts[DPS__NUM_OF_SCAL_FACTS];
// compensation coefficients
int32_t m_c0Half;
int32_t m_c1;
int32_t m_c00;
int32_t m_c10;
int32_t m_c01;
int32_t m_c11;
int32_t m_c20;
int32_t m_c21;
int32_t m_c30;
// last measured scaled temperature (necessary for pressure compensation)
float m_lastTempScal;
};
// Over sampling rate: 1 2 4 8 16 32 64 128
const int32_t myclass::scaling_facts[DPS__NUM_OF_SCAL_FACTS] = {524288, 1572864, 3670016, 7864320, 253952, 516096, 1040384, 2088960};
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
class MyCustomSensor : public PollingComponent {
public:
Sensor *temperature_sensor = new Sensor();
Sensor *pressure_sensor = new Sensor();
// constructor
MyCustomSensor() : PollingComponent(15000) {}
//float get_setup_priority() const override { return esphome::setup_priority::BUS; }
void setup() override {
// This will be called by App.setup()
myc = new myclass();
myc->init();
}
void update() override {
// This will be called every "update_interval" milliseconds.
temperature_sensor->publish_state(myc->getTemp());
pressure_sensor->publish_state(myc->getPressure() / 100);
}
protected:
myclass *myc;
};