Skip to content

Commit

Permalink
Add support for honeywellabp2 pressure sensor (esphome#5422)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpfaff authored Oct 25, 2023
1 parent ec835c0 commit 2895cc6
Show file tree
Hide file tree
Showing 6 changed files with 256 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 @@ -122,6 +122,7 @@ esphome/components/hitachi_ac424/* @sourabhjaiswal
esphome/components/hm3301/* @freekode
esphome/components/homeassistant/* @OttoWinter
esphome/components/honeywellabp/* @RubyBailey
esphome/components/honeywellabp2_i2c/* @jpfaff
esphome/components/host/* @esphome/core
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/hte501/* @Stock-M
Expand Down
2 changes: 2 additions & 0 deletions esphome/components/honeywellabp2_i2c/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"""Support for Honeywell ABP2"""
CODEOWNERS = ["@jpfaff"]
108 changes: 108 additions & 0 deletions esphome/components/honeywellabp2_i2c/honeywellabp2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "honeywellabp2.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"

namespace esphome {
namespace honeywellabp2_i2c {

static const uint8_t STATUS_BIT_POWER = 6;
static const uint8_t STATUS_BIT_BUSY = 5;
static const uint8_t STATUS_BIT_ERROR = 2;
static const uint8_t STATUS_MATH_SAT = 0;

static const char *const TAG = "honeywellabp2";

void HONEYWELLABP2Sensor::read_sensor_data() {
if (this->read(raw_data_, 7) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with ABP2 failed!");
this->mark_failed();
return;
}
float press_counts = encode_uint24(raw_data_[1], raw_data_[2], raw_data_[3]); // calculate digital pressure counts
float temp_counts = encode_uint24(raw_data_[4], raw_data_[5], raw_data_[6]); // calculate digital temperature counts

this->last_pressure_ = (((press_counts - this->min_count_) / (this->max_count_ - this->min_count_)) *
(this->max_pressure_ - this->min_pressure_)) +
this->min_pressure_;
this->last_temperature_ = (temp_counts * 200 / 16777215) - 50;
}

void HONEYWELLABP2Sensor::start_measurement() {
if (this->write(i2c_cmd_, 3) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with ABP2 failed!");
this->mark_failed();
return;
}
this->measurement_running_ = true;
}

bool HONEYWELLABP2Sensor::is_measurement_ready() {
if (this->read(raw_data_, 1) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Communication with ABP2 failed!");
this->mark_failed();
return false;
}
if ((raw_data_[0] & (0x1 << STATUS_BIT_BUSY)) > 0) {
return false;
}
this->measurement_running_ = false;
return true;
}

void HONEYWELLABP2Sensor::measurement_timeout() {
ESP_LOGE(TAG, "Timeout!");
this->measurement_running_ = false;
this->mark_failed();
}

float HONEYWELLABP2Sensor::get_pressure() { return this->last_pressure_; }

float HONEYWELLABP2Sensor::get_temperature() { return this->last_temperature_; }

void HONEYWELLABP2Sensor::loop() {
if (this->measurement_running_) {
if (this->is_measurement_ready()) {
this->cancel_timeout("meas_timeout");

this->read_sensor_data();
if (pressure_sensor_ != nullptr) {
this->pressure_sensor_->publish_state(this->get_pressure());
}
if (temperature_sensor_ != nullptr) {
this->temperature_sensor_->publish_state(this->get_temperature());
}
}
}
}

void HONEYWELLABP2Sensor::update() {
ESP_LOGV(TAG, "Update Honeywell ABP2 Sensor");

this->start_measurement();
this->set_timeout("meas_timeout", 50, [this] { this->measurement_timeout(); });
}

void HONEYWELLABP2Sensor::dump_config() {
ESP_LOGCONFIG(TAG, " Min Pressure Range: %0.1f", this->min_pressure_);
ESP_LOGCONFIG(TAG, " Max Pressure Range: %0.1f", this->max_pressure_);
if (this->transfer_function_ == ABP2_TRANS_FUNC_A) {
ESP_LOGCONFIG(TAG, " Transfer function A");
} else {
ESP_LOGCONFIG(TAG, " Transfer function B");
}
LOG_UPDATE_INTERVAL(this);
}

void HONEYWELLABP2Sensor::set_transfer_function(ABP2TRANFERFUNCTION transfer_function) {
this->transfer_function_ = transfer_function;
if (this->transfer_function_ == ABP2_TRANS_FUNC_B) {
this->max_count_ = this->max_count_b_;
this->min_count_ = this->min_count_b_;
} else {
this->max_count_ = this->max_count_a_;
this->min_count_ = this->min_count_a_;
}
}

} // namespace honeywellabp2_i2c
} // namespace esphome
60 changes: 60 additions & 0 deletions esphome/components/honeywellabp2_i2c/honeywellabp2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// for Honeywell ABP sensor
// adapting code from https://github.com/vwls/Honeywell_pressure_sensors
#pragma once

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

namespace esphome {
namespace honeywellabp2_i2c {

enum ABP2TRANFERFUNCTION { ABP2_TRANS_FUNC_A = 0, ABP2_TRANS_FUNC_B = 1 };

class HONEYWELLABP2Sensor : public PollingComponent, public i2c::I2CDevice {
public:
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { this->pressure_sensor_ = pressure_sensor; };
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; };
void loop() override;
void update() override;
float get_setup_priority() const override { return setup_priority::DATA; };
void dump_config() override;

void read_sensor_data();
void start_measurement();
bool is_measurement_ready();
void measurement_timeout();

float get_pressure();
float get_temperature();

void set_min_pressure(float min_pressure) { this->min_pressure_ = min_pressure; };
void set_max_pressure(float max_pressure) { this->max_pressure_ = max_pressure; };
void set_transfer_function(ABP2TRANFERFUNCTION transfer_function);

protected:
float min_pressure_ = 0.0;
float max_pressure_ = 0.0;
ABP2TRANFERFUNCTION transfer_function_ = ABP2_TRANS_FUNC_A;

sensor::Sensor *pressure_sensor_{nullptr};
sensor::Sensor *temperature_sensor_{nullptr};

const float max_count_a_ = 15099494.4; // (90% of 2^24 counts or 0xE66666)
const float min_count_a_ = 1677721.6; // (10% of 2^24 counts or 0x19999A)
const float max_count_b_ = 11744051.2; // (70% of 2^24 counts or 0xB33333)
const float min_count_b_ = 5033164.8; // (30% of 2^24 counts or 0x4CCCCC)

float max_count_;
float min_count_;
bool measurement_running_ = false;

uint8_t raw_data_[7]; // holds output data
uint8_t i2c_cmd_[3] = {0xAA, 0x00, 0x00}; // command to be sent
float last_pressure_;
float last_temperature_;
};

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

DEPENDENCIES = ["i2c"]

honeywellabp2_ns = cg.esphome_ns.namespace("honeywellabp2_i2c")

CONF_MIN_PRESSURE = "min_pressure"
CONF_MAX_PRESSURE = "max_pressure"
TRANSFER_FUNCTION = "transfer_function"
ABP2TRANFERFUNCTION = honeywellabp2_ns.enum("ABP2TRANFERFUNCTION")
TRANS_FUNC_OPTIONS = {
"A": ABP2TRANFERFUNCTION.ABP2_TRANS_FUNC_A,
"B": ABP2TRANFERFUNCTION.ABP2_TRANS_FUNC_B,
}

HONEYWELLABP2Sensor = honeywellabp2_ns.class_(
"HONEYWELLABP2Sensor", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice
)

CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(HONEYWELLABP2Sensor),
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
unit_of_measurement="Pa",
accuracy_decimals=1,
device_class=DEVICE_CLASS_PRESSURE,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Required(CONF_MIN_PRESSURE): cv.float_,
cv.Required(CONF_MAX_PRESSURE): cv.float_,
cv.Required(TRANSFER_FUNCTION): cv.enum(TRANS_FUNC_OPTIONS),
}
),
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,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x28))
)


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 pressure_config := config.get(CONF_PRESSURE):
sens = await sensor.new_sensor(pressure_config)
cg.add(var.set_pressure_sensor(sens))
cg.add(var.set_min_pressure(pressure_config[CONF_MIN_PRESSURE]))
cg.add(var.set_max_pressure(pressure_config[CONF_MAX_PRESSURE]))
cg.add(var.set_transfer_function(pressure_config[TRANSFER_FUNCTION]))

if temperature_config := config.get(CONF_TEMPERATURE):
sens = await sensor.new_sensor(temperature_config)
cg.add(var.set_temperature_sensor(sens))
10 changes: 10 additions & 0 deletions tests/test1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,16 @@ sensor:
temperature:
name: Honeywell temperature
cs_pin: GPIO5
- platform: honeywellabp2_i2c
pressure:
name: Honeywell2 pressure
min_pressure: 0
max_pressure: 16000
transfer_function: A
temperature:
name: Honeywell temperature
i2c_id: i2c_bus
address: 0x28
- platform: hte501
temperature:
name: Office Temperature 2
Expand Down

0 comments on commit 2895cc6

Please sign in to comment.