From 5b0abf191e2aefa1e50dfd159e52489b1e7996d0 Mon Sep 17 00:00:00 2001 From: Florian Loitsch Date: Mon, 6 Jan 2025 12:02:49 +0100 Subject: [PATCH] Fix negative temperatures (#12) The DHT22 supports negative temperatures which weren't read correctly. Fixes #10. --- README.md | 12 +++++++++++- package.yaml | 4 +++- src/dht11.toit | 13 +++++++++++-- src/dht22.toit | 28 ++++++++++++++++++++++++++-- src/driver_.toit | 6 ------ 5 files changed, 51 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 70e3c32..1de04fb 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,17 @@ lot of code. ## Implementation details -The DHT11 and DHT22 drivers are timing sensitive, and the drivers are therefore implemented using the RMT controller which allows for precise timings. +The DHT11 and DHT22 drivers are timing sensitive, and the drivers are therefore implemented +using the RMT controller which allows for precise timings. + +## Compatibility + +The driver has been tested on DHT11 and DHT22 sensors. + +It should work with other sensors that use the same protocol: +DHT12, KY-015, DHT33, AM2320, AM2321, or AM2322. + +If you have one of these sensors, please let us know if it works. ## Features and bugs diff --git a/package.yaml b/package.yaml index ad74189..2e3a82b 100644 --- a/package.yaml +++ b/package.yaml @@ -1,4 +1,6 @@ name: dhtxx -description: Drivers for the DHT11 and DHT22 (aka AM2302 or RHT03) humidity and temperature sensors. +description: | + Drivers for the DHT11 and DHT22 (aka AM2302 or RHT03) humidity and temperature sensors. + Other compatible sensors: DHT12, KY-015, DHT33, AM2320, AM2321, or AM2322. environment: sdk: ^2.0.0-alpha.1 diff --git a/src/dht11.toit b/src/dht11.toit index f24c93a..608597c 100644 --- a/src/dht11.toit +++ b/src/dht11.toit @@ -5,7 +5,16 @@ import gpio import .driver_ as driver +/** +Driver for the DHT11 sensor. + +Should also work for compatible sensors like the DHT12 or KY-015. +*/ class Dht11 extends driver.Driver: + static HUMIDITY_INTEGRAL_PART_ ::= 0 + static HUMIDITY_DECIMAL_PART_ ::= 1 + static TEMPERATURE_INTEGRAL_PART_ ::= 2 + static TEMPERATURE_DECIMAL_PART_ ::= 3 /** Constructs an instance of the Dht11 driver. @@ -19,7 +28,7 @@ class Dht11 extends driver.Driver: super pin --in_channel_id=in_channel_id --out_channel_id=out_channel_id --max_retries=max_retries parse_temperature_ data/ByteArray -> float: - return data[driver.Driver.TEMPERATURE_INTEGRAL_PART_].to_float + return data[TEMPERATURE_INTEGRAL_PART_].to-float + data[TEMPERATURE_DECIMAL_PART_] * 0.1 parse_humidity_ data/ByteArray -> float: - return data[driver.Driver.HUMIDITY_INTEGRAL_PART_].to_float + return data[HUMIDITY_INTEGRAL_PART_].to-float + data[HUMIDITY_DECIMAL_PART_] * 0.1 diff --git a/src/dht22.toit b/src/dht22.toit index b082663..9896ceb 100644 --- a/src/dht22.toit +++ b/src/dht22.toit @@ -6,7 +6,14 @@ import gpio import io show BIG_ENDIAN import .driver_ as driver +/** +Driver for the DHT22 sensor. + +Should also work for compatible sensors like the DHT33, AM2320, AM2321, or AM2322. +*/ class Dht22 extends driver.Driver: + static HUMIDITY_INDEX_ ::= 0 + static TEMPERATURE_INDEX_ ::= 2 /** Constructs an instance of the Dht22 driver. @@ -20,7 +27,24 @@ class Dht22 extends driver.Driver: super pin --in_channel_id=in_channel_id --out_channel_id=out_channel_id --max_retries=max_retries parse_temperature_ data/ByteArray -> float: - return (BIG_ENDIAN.uint16 data driver.Driver.TEMPERATURE_INTEGRAL_PART_) / 10.0 + // The temperature is a big-endian 16-bit integer. + // Some sensors use the first bit to indicate the sign of the temperature; others + // encode the value as 2's complement. + // Since valid temperature values can only be in a small range, we can use the + // second bit to determine which approach the sensor uses. + // If the first two bits were 1 and the sensor wasn't using 2's complement, then + // the temperature would be lower than -64 degrees which is outside the supported + // range. + byte1 := data[TEMPERATURE_INDEX_] + temperature10/int := ? + if (byte1 & 0x80 == 0) or (byte1 & 0x40 == 1): + // The temperature is positive or the sensor uses 2's complement. + temperature10 = BIG-ENDIAN.int16 data TEMPERATURE_INDEX_ + else: + // The temperature is negative, but the sensor uses the first bit to indicate the sign. + temperature10 = BIG-ENDIAN.uint16 data TEMPERATURE_INDEX_ + temperature10 = -(temperature10 & 0x7FFF) + return temperature10 * 0.1 parse_humidity_ data/ByteArray -> float: - return (BIG_ENDIAN.uint16 data driver.Driver.HUMIDITY_INTEGRAL_PART_) / 10.0 + return (BIG_ENDIAN.uint16 data HUMIDITY_INDEX_) * 0.1 diff --git a/src/driver_.toit b/src/driver_.toit index 40f1dd1..49930af 100644 --- a/src/driver_.toit +++ b/src/driver_.toit @@ -26,12 +26,6 @@ class DhtResult: return "T: $(%.2f temperature), H: $(%.2f humidity)" abstract class Driver: - static HUMIDITY_INTEGRAL_PART_ ::= 0 - static HUMIDITY_DECIMAL_PART_ ::= 1 - static TEMPERATURE_INTEGRAL_PART_ ::= 2 - static TEMPERATURE_DECIMAL_PART_ ::= 3 - static CHECKSUM_PART_ ::= 4 - channel_in_ /rmt.Channel channel_out_ /rmt.Channel max_retries_ /int