Skip to content

Commit

Permalink
Add support of Honeywell HumidIcon (I2C HIH series) Temperature & Hum…
Browse files Browse the repository at this point in the history
…idity sensor (#5730)
  • Loading branch information
Benichou34 committed Jan 18, 2024
1 parent 39bd829 commit c9c8d39
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ esphome/components/heatpumpir/* @rob-deutsch
esphome/components/hitachi_ac424/* @sourabhjaiswal
esphome/components/hm3301/* @freekode
esphome/components/homeassistant/* @OttoWinter
esphome/components/honeywell_hih_i2c/* @Benichou34
esphome/components/honeywellabp/* @RubyBailey
esphome/components/honeywellabp2_i2c/* @jpfaff
esphome/components/host/* @esphome/core
Expand Down
2 changes: 2 additions & 0 deletions esphome/components/honeywell_hih_i2c/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"""Support for Honeywell HumidIcon HIH"""
CODEOWNERS = ["@Benichou34"]
97 changes: 97 additions & 0 deletions esphome/components/honeywell_hih_i2c/honeywell_hih.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Honeywell HumidIcon I2C Sensors
// https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/humidity-with-temperature-sensors/common/documents/sps-siot-i2c-comms-humidicon-tn-009061-2-en-ciid-142171.pdf
//

#include "honeywell_hih.h"
#include "esphome/core/log.h"

namespace esphome {
namespace honeywell_hih_i2c {

static const char *const TAG = "honeywell_hih.i2c";

static const uint8_t REQUEST_CMD[1] = {0x00}; // Measurement Request Format
static const uint16_t MAX_COUNT = 0x3FFE; // 2^14 - 2

void HoneywellHIComponent::read_sensor_data_() {
uint8_t data[4];

if (this->read(data, sizeof(data)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with Honeywell HIH failed!");
this->mark_failed();
return;
}

const uint16_t raw_humidity = (static_cast<uint16_t>(data[0] & 0x3F) << 8) | data[1];
float humidity = (static_cast<float>(raw_humidity) / MAX_COUNT) * 100;

const uint16_t raw_temperature = (static_cast<uint16_t>(data[2]) << 6) | (data[3] >> 2);
float temperature = (static_cast<float>(raw_temperature) / MAX_COUNT) * 165 - 40;

ESP_LOGD(TAG, "Got temperature=%.2f°C humidity=%.2f%%", temperature, humidity);
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(temperature);
if (this->humidity_sensor_ != nullptr)
this->humidity_sensor_->publish_state(humidity);
}

void HoneywellHIComponent::start_measurement_() {
if (this->write(REQUEST_CMD, sizeof(REQUEST_CMD)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with Honeywell HIH failed!");
this->mark_failed();
return;
}

this->measurement_running_ = true;
}

bool HoneywellHIComponent::is_measurement_ready_() {
uint8_t data[1];

if (this->read(data, sizeof(data)) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with Honeywell HIH failed!");
this->mark_failed();
return false;
}

// Check status bits
return ((data[0] & 0xC0) == 0x00);
}

void HoneywellHIComponent::measurement_timeout_() {
ESP_LOGE(TAG, "Honeywell HIH Timeout!");
this->measurement_running_ = false;
this->mark_failed();
}

void HoneywellHIComponent::update() {
ESP_LOGV(TAG, "Update Honeywell HIH Sensor");

this->start_measurement_();
// The measurement cycle duration is typically 36.65 ms for temperature and humidity readings.
this->set_timeout("meas_timeout", 100, [this] { this->measurement_timeout_(); });
}

void HoneywellHIComponent::loop() {
if (this->measurement_running_ && this->is_measurement_ready_()) {
this->measurement_running_ = false;
this->cancel_timeout("meas_timeout");
this->read_sensor_data_();
}
}

void HoneywellHIComponent::dump_config() {
ESP_LOGD(TAG, "Honeywell HIH:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication with Honeywell HIH failed!");
}
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
LOG_UPDATE_INTERVAL(this);
}

float HoneywellHIComponent::get_setup_priority() const { return setup_priority::DATA; }

} // namespace honeywell_hih_i2c
} // namespace esphome
34 changes: 34 additions & 0 deletions esphome/components/honeywell_hih_i2c/honeywell_hih.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Honeywell HumidIcon I2C Sensors
#pragma once

#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"

namespace esphome {
namespace honeywell_hih_i2c {

class HoneywellHIComponent : public PollingComponent, public i2c::I2CDevice {
public:
void dump_config() override;
float get_setup_priority() const override;
void loop() override;
void update() override;

void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }

protected:
bool measurement_running_{false};
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};

private:
void read_sensor_data_();
void start_measurement_();
bool is_measurement_ready_();
void measurement_timeout_();
};

} // namespace honeywell_hih_i2c
} // namespace esphome
56 changes: 56 additions & 0 deletions esphome/components/honeywell_hih_i2c/sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_HUMIDITY,
CONF_ID,
CONF_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_PERCENT,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_HUMIDITY,
)

DEPENDENCIES = ["i2c"]

honeywell_hih_ns = cg.esphome_ns.namespace("honeywell_hih_i2c")
HONEYWELLHIComponent = honeywell_hih_ns.class_(
"HoneywellHIComponent", cg.PollingComponent, i2c.I2CDevice
)

CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(HONEYWELLHIComponent),
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=1,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x27))
)


async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)

if temperature_config := config.get(CONF_TEMPERATURE):
sens = await sensor.new_sensor(temperature_config)
cg.add(var.set_temperature_sensor(sens))

if humidity_config := config.get(CONF_HUMIDITY):
sens = await sensor.new_sensor(humidity_config)
cg.add(var.set_humidity_sensor(sens))
7 changes: 7 additions & 0 deletions tests/test1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,13 @@ sensor:
oversampling: 8x
update_interval: 15s
i2c_id: i2c_bus
- platform: honeywell_hih_i2c
temperature:
name: Living Room Temperature 7
humidity:
name: Living Room Humidity 7
update_interval: 15s
i2c_id: i2c_bus
- platform: honeywellabp
pressure:
name: Honeywell pressure
Expand Down

0 comments on commit c9c8d39

Please sign in to comment.