diff --git a/CHANGELOG.md b/CHANGELOG.md index 9214991b0..b704d3944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. ### Breaking Changed ### Changed +- Refactored I2C drivers HTU21, BH1750 and HYT ### Fixed - Shutter missing HOLD on shutterbutton (#22108) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c121e70d4..af0b6d471 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -146,6 +146,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - GPIOViewer from v1.5.5 to v1.5.6 - Energy BL09xx command ``CurrentSet`` input changed from Ampere to milliAmpere - Energy force Apparent Power equals Active Power when (Calculated) Apparent Power is less than Active Power [#20653](https://github.com/arendst/Tasmota/issues/20653) +- Refactored I2C drivers HTU21, BH1750 and HYT ### Fixed - Crash when calling TasmotaSerial destructor when initialized with incorrect arguments [#22036](https://github.com/arendst/Tasmota/issues/22036) diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino index 2408bee00..660ce2fd1 100644 --- a/tasmota/tasmota_support/support_a_i2c.ino +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -149,6 +149,8 @@ int32_t I2cRead24(uint8_t addr, uint8_t reg, uint8_t bus = 0) { return i2c_buffer; } +/*-------------------------------------------------------------------------------------------*/ + bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus = 0) { TwoWire& myWire = I2cGetWire(bus); if (&myWire == nullptr) { return false; } // No valid I2c bus @@ -166,6 +168,10 @@ bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus return (x); // 0 = Error, 1 = OK } +bool I2cWrite0(uint8_t addr, uint8_t reg, uint8_t bus = 0) { + return I2cWrite(addr, reg, 0, 0, bus); // 0 = Error, 1 = OK +} + bool I2cWrite8(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) { return I2cWrite(addr, reg, val, 1, bus); // 0 = Error, 1 = OK } @@ -178,14 +184,12 @@ bool I2cWrite16(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) { * Return code: 0 = OK, 1 = Error \*-------------------------------------------------------------------------------------------*/ -bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { +bool I2cReadBuffer0(uint8_t addr, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { TwoWire& myWire = I2cGetWire(bus); if (&myWire == nullptr) { return true; } // No valid I2c bus - myWire.beginTransmission((uint8_t)addr); - myWire.write((uint8_t)reg); - myWire.endTransmission(); - if (len != myWire.requestFrom((uint8_t)addr, (uint8_t)len)) { + myWire.requestFrom((uint8_t)addr, (uint8_t)len); + if (myWire.available() != len) { return true; // 1 = Error } while (len--) { @@ -195,9 +199,34 @@ bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, u return false; // 0 = OK } -int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { +bool I2cReadBuffer(uint8_t addr, int reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { TwoWire& myWire = I2cGetWire(bus); - if (&myWire == nullptr) { return 1; } // 1 = Error, No valid I2c bus + if (&myWire == nullptr) { return true; } // No valid I2c bus + + myWire.beginTransmission((uint8_t)addr); + if (reg > -1) { + myWire.write((uint8_t)reg); + if (reg > 255) { + myWire.write((uint8_t)(reg >> 8)); + } + myWire.endTransmission(); + } + if (len != myWire.requestFrom((uint8_t)addr, (uint8_t)len)) { + return true; // 1 = Error + } + while (len--) { + *reg_data = (uint8_t)myWire.read(); + reg_data++; + } + if (reg < 0) { + myWire.endTransmission(); + } + return false; // 0 = OK +} + +bool I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { + TwoWire& myWire = I2cGetWire(bus); + if (&myWire == nullptr) { return true; } // 1 = Error, No valid I2c bus myWire.beginTransmission((uint8_t)addr); myWire.write((uint8_t)reg); @@ -206,7 +235,7 @@ int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len reg_data++; } myWire.endTransmission(); - return 0; // 0 = OK + return false; // 0 = OK } /*-------------------------------------------------------------------------------------------*/ diff --git a/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino b/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino index 311854dcb..f8ab6319c 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino @@ -85,19 +85,23 @@ uint8_t HtuCheckCrc8(uint16_t data) { } bool HtuReset(void) { +/* TwoWire& myWire = I2cGetWire(Htu.bus); if (&myWire == nullptr) { return false; } // No valid I2c bus myWire.beginTransmission(HTU21_ADDR); myWire.write(HTU21_RESET); myWire.endTransmission(); +*/ + I2cWrite0(HTU21_ADDR, HTU21_RESET, Htu.bus); + delay(15); // Reset takes 15ms return true; } uint8_t HtuReadDeviceId(void) { if (!HtuReset()) { return 0; }; // Fixes ESP32 sensor loss at restart - +/* uint16_t deviceID = 0; uint8_t checksum = 0; @@ -116,6 +120,16 @@ uint8_t HtuReadDeviceId(void) { } else { deviceID = 0; } +*/ + uint8_t data[3]; + I2cReadBuffer(HTU21_ADDR, HTU21_SERIAL2_READ2 << 8 | HTU21_SERIAL2_READ1, data, 3, Htu.bus); + uint16_t deviceID = (data[0] << 8) | data[1]; + if (HtuCheckCrc8(deviceID) == data[2]) { + deviceID = deviceID >> 8; + } else { + deviceID = 0; + } + return (uint8_t)deviceID; } @@ -146,12 +160,24 @@ void HtuInit(void) { HtuSetResolution(HTU21_RES_RH12_T14); } -bool HtuRead(void) { - uint8_t checksum = 0; - uint16_t sensorval = 0; +bool HtuI2cRead(uint8_t reg, uint8_t hdelay, uint16_t &sensorval) { + if (!I2cWrite0(HTU21_ADDR, reg, Htu.bus)) { return false; } + delay(hdelay); // Sensor time at max resolution + uint8_t data[3] = { 0 }; + if (!I2cReadBuffer0(HTU21_ADDR, data, 3, Htu.bus)) { + sensorval = data[0] << 8 | data[1]; // MSB, LSB + } + if (HtuCheckCrc8(sensorval) != data[2]) { return false; } // Checksum mismatch + return true; +} +bool HtuRead(void) { if (Htu.valid) { Htu.valid--; } + uint16_t sensorval = 0; +/* + uint8_t checksum = 0; + TwoWire& myWire = I2cGetWire(Htu.bus); myWire.beginTransmission(HTU21_ADDR); myWire.write(HTU21_READTEMP); @@ -180,6 +206,11 @@ bool HtuRead(void) { checksum = myWire.read(); } if (HtuCheckCrc8(sensorval) != checksum) { return false; } // Checksum mismatch +*/ + if (!HtuI2cRead(HTU21_READTEMP, Htu.delay_temp, sensorval)) { return false; } // Checksum mismatch + Htu.temperature = ConvertTemp(0.002681f * (float)sensorval - 46.85f); + + if (!HtuI2cRead(HTU21_READHUM, Htu.delay_humidity, sensorval)) { return false; } // Checksum mismatch sensorval ^= 0x02; // clear status bits Htu.humidity = 0.001907f * (float)sensorval - 6; diff --git a/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino b/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino index 6f49bd450..8b711dae6 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino @@ -79,13 +79,17 @@ uint8_t Bh1750Resolution(uint32_t sensor_index) { } bool Bh1750SetResolution(uint32_t sensor_index) { +/* TwoWire& myWire = I2cGetWire(Bh1750_sensors[sensor_index].bus); myWire.beginTransmission(Bh1750_sensors[sensor_index].address); myWire.write(Bh1750.resolution[Bh1750Resolution(sensor_index)]); return (!myWire.endTransmission()); +*/ + return I2cWrite0(Bh1750_sensors[sensor_index].address, Bh1750.resolution[Bh1750Resolution(sensor_index)], Bh1750_sensors[sensor_index].bus); } bool Bh1750SetMTreg(uint32_t sensor_index) { +/* TwoWire& myWire = I2cGetWire(Bh1750_sensors[sensor_index].bus); if (&myWire == nullptr) { return false; } // No valid I2c bus myWire.beginTransmission(Bh1750_sensors[sensor_index].address); @@ -96,16 +100,31 @@ bool Bh1750SetMTreg(uint32_t sensor_index) { data = BH1750_MEASUREMENT_TIME_LOW | (Bh1750_sensors[sensor_index].mtreg & 0x1F); myWire.write(data); if (myWire.endTransmission()) { return false; } +*/ + uint8_t reg = BH1750_MEASUREMENT_TIME_HIGH | ((Bh1750_sensors[sensor_index].mtreg >> 5) & 0x07); + if (!I2cWrite0(Bh1750_sensors[sensor_index].address, reg, Bh1750_sensors[sensor_index].bus)) { + return false; + } + reg = BH1750_MEASUREMENT_TIME_LOW | (Bh1750_sensors[sensor_index].mtreg & 0x1F); + if (!I2cWrite0(Bh1750_sensors[sensor_index].address, reg, Bh1750_sensors[sensor_index].bus)) { + return false; + } return Bh1750SetResolution(sensor_index); } bool Bh1750Read(uint32_t sensor_index) { if (Bh1750_sensors[sensor_index].valid) { Bh1750_sensors[sensor_index].valid--; } - +/* TwoWire& myWire = I2cGetWire(Bh1750_sensors[sensor_index].bus); if (2 != myWire.requestFrom(Bh1750_sensors[sensor_index].address, (uint8_t)2)) { return false; } float illuminance = (myWire.read() << 8) | myWire.read(); +*/ + uint8_t data[2]; + if (I2cReadBuffer0(Bh1750_sensors[sensor_index].address, data, 2, Bh1750_sensors[sensor_index].bus)) { + return false; + } + float illuminance = (data[0] << 8) | data[1]; illuminance *= 57.5 / (float)Bh1750_sensors[sensor_index].mtreg; // Fix #16022 if (1 == Bh1750Resolution(sensor_index)) { illuminance /= 2; diff --git a/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino b/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino index 2064d21a7..c0c97e24a 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino @@ -44,7 +44,7 @@ struct HYT { bool HYT_Read(void) { if (HYT.valid) { HYT.valid--; } - +/* TwoWire& myWire = I2cGetWire(HYT.bus); if (&myWire == nullptr) { return false; } // No valid I2c bus myWire.beginTransmission(HYT_ADDR); @@ -64,6 +64,18 @@ bool HYT_Read(void) { HYT.humidity = ConvertHumidity(humidity); HYT.temperature = ConvertTemp(temperature); } +*/ + uint8_t data[4]; + if (!I2cReadBuffer(HYT_ADDR, -1, data, 4, HYT.bus)) { + // Convert the data to 14-bits + float humidity = ((((data[0] & 0x3F) * 256) + data[1]) * 100.0) / 16383.0; + int temp = ((data[2] * 256) + (data[3] & 0xFC)) / 4; + float temperature = (temp / 16384.0) * 165.0 - 40.0; + + HYT.humidity = ConvertHumidity(humidity); + HYT.temperature = ConvertTemp(temperature); + } + if (isnan(HYT.temperature) || isnan(HYT.humidity)) { return false; } HYT.valid = SENSOR_MAX_MISS;