Merge branch 'dev' into optolink

This commit is contained in:
j0ta29 2023-10-25 23:32:00 +02:00 committed by GitHub
commit b1d09d1de5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1158 additions and 21 deletions

View file

@ -85,6 +85,7 @@ esphome/components/dsmr/* @glmnet @zuidwijk
esphome/components/duty_time/* @dudanov
esphome/components/ee895/* @Stock-M
esphome/components/ektf2232/* @jesserockz
esphome/components/emc2101/* @ellull
esphome/components/ens210/* @itn3rd77
esphome/components/esp32/* @esphome/core
esphome/components/esp32_ble/* @jesserockz
@ -122,6 +123,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
@ -233,6 +235,7 @@ esphome/components/pulse_meter/* @TrentHouliston @cstaahl @stevebaxter
esphome/components/pvvx_mithermometer/* @pasiz
esphome/components/qmp6988/* @andrewpc
esphome/components/qr_code/* @wjtje
esphome/components/qwiic_pir/* @kahrendt
esphome/components/radon_eye_ble/* @jeffeb3
esphome/components/radon_eye_rd200/* @jeffeb3
esphome/components/rc522/* @glmnet

View file

@ -104,7 +104,8 @@ void CurrentBasedCover::loop() {
ESP_LOGD(TAG, "'%s' - Close position reached. Took %.1fs.", this->name_.c_str(), dur);
this->direction_idle_(COVER_CLOSED);
}
} else if (now - this->start_dir_time_ > this->max_duration_) {
}
if (now - this->start_dir_time_ > this->max_duration_) {
ESP_LOGD(TAG, "'%s' - Max duration reached. Stopping cover.", this->name_.c_str());
this->direction_idle_();
}

View file

@ -0,0 +1,81 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c
from esphome.const import CONF_ID, CONF_INVERTED, CONF_RESOLUTION
CODEOWNERS = ["@ellull"]
DEPENDENCIES = ["i2c"]
CONF_PWM = "pwm"
CONF_DIVIDER = "divider"
CONF_DAC = "dac"
CONF_CONVERSION_RATE = "conversion_rate"
CONF_EMC2101_ID = "emc2101_id"
emc2101_ns = cg.esphome_ns.namespace("emc2101")
Emc2101DACConversionRate = emc2101_ns.enum("Emc2101DACConversionRate")
CONVERSIONS_PER_SECOND = {
"1/16": Emc2101DACConversionRate.Emc2101_DAC_1_EVERY_16S,
"1/8": Emc2101DACConversionRate.Emc2101_DAC_1_EVERY_8S,
"1/4": Emc2101DACConversionRate.Emc2101_DAC_1_EVERY_4S,
"1/2": Emc2101DACConversionRate.Emc2101_DAC_1_EVERY_2S,
"1": Emc2101DACConversionRate.Emc2101_DAC_1_EVERY_SECOND,
"2": Emc2101DACConversionRate.Emc2101_DAC_2_EVERY_SECOND,
"4": Emc2101DACConversionRate.Emc2101_DAC_4_EVERY_SECOND,
"8": Emc2101DACConversionRate.Emc2101_DAC_8_EVERY_SECOND,
"16": Emc2101DACConversionRate.Emc2101_DAC_16_EVERY_SECOND,
"32": Emc2101DACConversionRate.Emc2101_DAC_32_EVERY_SECOND,
}
Emc2101Component = emc2101_ns.class_("Emc2101Component", cg.Component, i2c.I2CDevice)
EMC2101_COMPONENT_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_EMC2101_ID): cv.use_id(Emc2101Component),
}
)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(Emc2101Component),
cv.Optional(CONF_PWM): cv.Schema(
{
cv.Optional(CONF_RESOLUTION, default=23): cv.int_range(
min=0, max=31
),
cv.Optional(CONF_DIVIDER, default=1): cv.uint8_t,
}
),
cv.Optional(CONF_DAC): cv.Schema(
{
cv.Optional(CONF_CONVERSION_RATE, default="16"): cv.enum(
CONVERSIONS_PER_SECOND
),
}
),
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x4C)),
cv.has_exactly_one_key(CONF_PWM, CONF_DAC),
)
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 pwm_config := config.get(CONF_PWM):
cg.add(var.set_dac_mode(False))
cg.add(var.set_pwm_resolution(pwm_config[CONF_RESOLUTION]))
cg.add(var.set_pwm_divider(pwm_config[CONF_DIVIDER]))
if dac_config := config.get(CONF_DAC):
cg.add(var.set_dac_mode(True))
cg.add(var.set_dac_conversion_rate(dac_config[CONF_CONVERSION_RATE]))
cg.add(var.set_inverted(config[CONF_INVERTED]))

View file

@ -0,0 +1,169 @@
// Implementation based on:
// - Adafruit_EMC2101: https://github.com/adafruit/Adafruit_EMC2101
// - Official Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/2101.pdf
#include "esphome/core/log.h"
#include "emc2101.h"
namespace esphome {
namespace emc2101 {
static const char *const TAG = "EMC2101";
static const uint8_t EMC2101_CHIP_ID = 0x16; // EMC2101 default device id from part id
static const uint8_t EMC2101_ALT_CHIP_ID = 0x28; // EMC2101 alternate device id from part id
// EMC2101 registers from the datasheet. We only define what we use.
static const uint8_t EMC2101_REGISTER_INTERNAL_TEMP = 0x00; // The internal temperature register
static const uint8_t EMC2101_REGISTER_EXTERNAL_TEMP_MSB = 0x01; // high byte for the external temperature reading
static const uint8_t EMC2101_REGISTER_DAC_CONV_RATE = 0x04; // DAC convesion rate config
static const uint8_t EMC2101_REGISTER_EXTERNAL_TEMP_LSB = 0x10; // low byte for the external temperature reading
static const uint8_t EMC2101_REGISTER_CONFIG = 0x03; // configuration register
static const uint8_t EMC2101_REGISTER_TACH_LSB = 0x46; // Tach RPM data low byte
static const uint8_t EMC2101_REGISTER_TACH_MSB = 0x47; // Tach RPM data high byte
static const uint8_t EMC2101_REGISTER_FAN_CONFIG = 0x4A; // General fan config register
static const uint8_t EMC2101_REGISTER_FAN_SETTING = 0x4C; // Fan speed for non-LUT settings
static const uint8_t EMC2101_REGISTER_PWM_FREQ = 0x4D; // PWM frequency setting
static const uint8_t EMC2101_REGISTER_PWM_DIV = 0x4E; // PWM frequency divisor
static const uint8_t EMC2101_REGISTER_WHOAMI = 0xFD; // Chip ID register
// EMC2101 configuration bits from the datasheet. We only define what we use.
// Determines the funcionallity of the ALERT/TACH pin.
// 0 (default): The ALERT/TECH pin will function as an open drain, active low interrupt.
// 1: The ALERT/TECH pin will function as a high impedance TACH input. This may require an
// external pull-up resistor to set the proper signaling levels.
static const uint8_t EMC2101_ALT_TCH_BIT = 1 << 2;
// Determines the FAN output mode.
// 0 (default): PWM output enabled at FAN pin.
// 1: DAC output enabled at FAN ping.
static const uint8_t EMC2101_DAC_BIT = 1 << 4;
// Overrides the CLK_SEL bit and uses the Frequency Divide Register to determine
// the base PWM frequency. It is recommended that this bit be set for maximum PWM resolution.
// 0 (default): The base clock frequency for the PWM is determined by the CLK_SEL bit.
// 1 (recommended): The base clock that is used to determine the PWM frequency is set by the
// Frequency Divide Register
static const uint8_t EMC2101_CLK_OVR_BIT = 1 << 2;
// Sets the polarity of the Fan output driver.
// 0 (default): The polarity of the Fan output driver is non-inverted. A '00h' setting will
// correspond to a 0% duty cycle or a minimum DAC output voltage.
// 1: The polarity of the Fan output driver is inverted. A '00h' setting will correspond to a
// 100% duty cycle or a maximum DAC output voltage.
static const uint8_t EMC2101_POLARITY_BIT = 1 << 4;
float Emc2101Component::get_setup_priority() const { return setup_priority::HARDWARE; }
void Emc2101Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up Emc2101 sensor...");
// make sure we're talking to the right chip
uint8_t chip_id = reg(EMC2101_REGISTER_WHOAMI).get();
if ((chip_id != EMC2101_CHIP_ID) && (chip_id != EMC2101_ALT_CHIP_ID)) {
ESP_LOGE(TAG, "Wrong chip ID %02X", chip_id);
this->mark_failed();
return;
}
// Configure EMC2101
i2c::I2CRegister config = reg(EMC2101_REGISTER_CONFIG);
config |= EMC2101_ALT_TCH_BIT;
if (this->dac_mode_) {
config |= EMC2101_DAC_BIT;
}
if (this->inverted_) {
config |= EMC2101_POLARITY_BIT;
}
if (this->dac_mode_) { // DAC mode configurations
// set DAC conversion rate
reg(EMC2101_REGISTER_DAC_CONV_RATE) = this->dac_conversion_rate_;
} else { // PWM mode configurations
// set PWM divider
reg(EMC2101_REGISTER_FAN_CONFIG) |= EMC2101_CLK_OVR_BIT;
reg(EMC2101_REGISTER_PWM_DIV) = this->pwm_divider_;
// set PWM resolution
reg(EMC2101_REGISTER_PWM_FREQ) = this->pwm_resolution_;
}
}
void Emc2101Component::dump_config() {
ESP_LOGCONFIG(TAG, "Emc2101 component:");
LOG_I2C_DEVICE(this);
if (this->is_failed()) {
ESP_LOGE(TAG, "Communication with EMC2101 failed!");
}
ESP_LOGCONFIG(TAG, " Mode: %s", this->dac_mode_ ? "DAC" : "PWM");
if (this->dac_mode_) {
ESP_LOGCONFIG(TAG, " DAC Conversion Rate: %X", this->dac_conversion_rate_);
} else {
ESP_LOGCONFIG(TAG, " PWM Resolution: %02X", this->pwm_resolution_);
ESP_LOGCONFIG(TAG, " PWM Divider: %02X", this->pwm_divider_);
}
ESP_LOGCONFIG(TAG, " Inverted: %s", YESNO(this->inverted_));
}
void Emc2101Component::set_duty_cycle(float value) {
uint8_t duty_cycle = remap(value, 0.0f, 1.0f, (uint8_t) 0, this->max_output_value_);
ESP_LOGD(TAG, "Setting duty fan setting to %02X", duty_cycle);
if (!this->write_byte(EMC2101_REGISTER_FAN_SETTING, duty_cycle)) {
ESP_LOGE(TAG, "Communication with EMC2101 failed!");
this->status_set_warning();
return;
}
}
float Emc2101Component::get_duty_cycle() {
uint8_t duty_cycle;
if (!this->read_byte(EMC2101_REGISTER_FAN_SETTING, &duty_cycle)) {
ESP_LOGE(TAG, "Communication with EMC2101 failed!");
this->status_set_warning();
return NAN;
}
return remap(duty_cycle, (uint8_t) 0, this->max_output_value_, 0.0f, 1.0f);
}
float Emc2101Component::get_internal_temperature() {
uint8_t temperature;
if (!this->read_byte(EMC2101_REGISTER_INTERNAL_TEMP, &temperature)) {
ESP_LOGE(TAG, "Communication with EMC2101 failed!");
this->status_set_warning();
return NAN;
}
return temperature;
}
float Emc2101Component::get_external_temperature() {
// Read **MSB** first to match 'Data Read Interlock' behavior from 6.1 of datasheet
uint8_t lsb, msb;
if (!this->read_byte(EMC2101_REGISTER_EXTERNAL_TEMP_MSB, &msb) ||
!this->read_byte(EMC2101_REGISTER_EXTERNAL_TEMP_LSB, &lsb)) {
ESP_LOGE(TAG, "Communication with EMC2101 failed!");
this->status_set_warning();
return NAN;
}
// join msb and lsb (5 least significant bits are not used)
uint16_t raw = (msb << 8 | lsb) >> 5;
return raw * 0.125;
}
float Emc2101Component::get_speed() {
// Read **LSB** first to match 'Data Read Interlock' behavior from 6.1 of datasheet
uint8_t lsb, msb;
if (!this->read_byte(EMC2101_REGISTER_TACH_LSB, &lsb) || !this->read_byte(EMC2101_REGISTER_TACH_MSB, &msb)) {
ESP_LOGE(TAG, "Communication with EMC2101 failed!");
this->status_set_warning();
return NAN;
}
// calculate RPMs
uint16_t tach = msb << 8 | lsb;
return tach == 0xFFFF ? 0.0f : 5400000.0f / tach;
}
} // namespace emc2101
} // namespace esphome

View file

@ -0,0 +1,115 @@
#pragma once
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
namespace esphome {
namespace emc2101 {
/** Enum listing all DAC conversion rates for the EMC2101.
*
* Specific values of the enum constants are register values taken from the EMC2101 datasheet.
*/
enum Emc2101DACConversionRate {
EMC2101_DAC_1_EVERY_16_S,
EMC2101_DAC_1_EVERY_8_S,
EMC2101_DAC_1_EVERY_4_S,
EMC2101_DAC_1_EVERY_2_S,
EMC2101_DAC_1_EVERY_SECOND,
EMC2101_DAC_2_EVERY_SECOND,
EMC2101_DAC_4_EVERY_SECOND,
EMC2101_DAC_8_EVERY_SECOND,
EMC2101_DAC_16_EVERY_SECOND,
EMC2101_DAC_32_EVERY_SECOND,
};
/// This class includes support for the EMC2101 i2c fan controller.
/// The device has an output (PWM or DAC) and several sensors and this
/// class is for the EMC2101 configuration.
class Emc2101Component : public Component, public i2c::I2CDevice {
public:
/** Sets the mode of the output.
*
* @param dac_mode false for PWM output and true for DAC mode.
*/
void set_dac_mode(bool dac_mode) {
this->dac_mode_ = dac_mode;
this->max_output_value_ = 63;
}
/** Sets the PWM resolution.
*
* @param resolution the PWM resolution.
*/
void set_pwm_resolution(uint8_t resolution) {
this->pwm_resolution_ = resolution;
this->max_output_value_ = 2 * resolution;
}
/** Sets the PWM divider used to derive the PWM frequency.
*
* @param divider The PWM divider.
*/
void set_pwm_divider(uint8_t divider) { this->pwm_divider_ = divider; }
/** Sets the DAC conversion rate (how many conversions per second).
*
* @param conversion_rate The DAC conversion rate.
*/
void set_dac_conversion_rate(Emc2101DACConversionRate conversion_rate) {
this->dac_conversion_rate_ = conversion_rate;
}
/** Inverts the polarity of the Fan output.
*
* @param inverted Invert or not the Fan output.
*/
void set_inverted(bool inverted) { this->inverted_ = inverted; }
/** Sets the Fan output duty cycle
*
* @param value The duty cycle value, from 0.0f to 1.0f.
*/
void set_duty_cycle(float value);
/** Gets the Fan output duty cycle
*
* @return The duty cycle percentage from 0.0f to 1.0f.
*/
float get_duty_cycle();
/** Gets the internal temperature sensor reading.
*
* @return The temperature in degrees celsius.
*/
float get_internal_temperature();
/** Gets the external temperature sensor reading.
*
* @return The temperature in degrees celsius.
*/
float get_external_temperature();
/** Gets the tachometer speed sensor reading.
*
* @return The fan speed in RPMs.
*/
float get_speed();
/** Used by ESPHome framework. */
void setup() override;
/** Used by ESPHome framework. */
void dump_config() override;
/** Used by ESPHome framework. */
float get_setup_priority() const override;
bool dac_mode_{false};
bool inverted_{false};
uint8_t max_output_value_;
uint8_t pwm_resolution_;
uint8_t pwm_divider_;
Emc2101DACConversionRate dac_conversion_rate_;
};
} // namespace emc2101
} // namespace esphome

View file

@ -0,0 +1,21 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_ID
from .. import EMC2101_COMPONENT_SCHEMA, CONF_EMC2101_ID, emc2101_ns
DEPENDENCIES = ["emc2101"]
EMC2101Output = emc2101_ns.class_("EMC2101Output", output.FloatOutput)
CONFIG_SCHEMA = EMC2101_COMPONENT_SCHEMA.extend(
{
cv.Required(CONF_ID): cv.declare_id(EMC2101Output),
}
)
async def to_code(config):
paren = await cg.get_variable(config[CONF_EMC2101_ID])
var = cg.new_Pvariable(config[CONF_ID], paren)
await output.register_output(var, config)

View file

@ -0,0 +1,9 @@
#include "emc2101_output.h"
namespace esphome {
namespace emc2101 {
void EMC2101Output::write_state(float state) { this->parent_->set_duty_cycle(state); }
} // namespace emc2101
} // namespace esphome

View file

@ -0,0 +1,22 @@
#pragma once
#include "../emc2101.h"
#include "esphome/components/output/float_output.h"
namespace esphome {
namespace emc2101 {
/// This class allows to control the EMC2101 output.
class EMC2101Output : public output::FloatOutput {
public:
EMC2101Output(Emc2101Component *parent) : parent_(parent) {}
protected:
/** Used by ESPHome framework. */
void write_state(float state) override;
Emc2101Component *parent_;
};
} // namespace emc2101
} // namespace esphome

View file

@ -0,0 +1,74 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
CONF_ID,
CONF_SPEED,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
UNIT_PERCENT,
UNIT_REVOLUTIONS_PER_MINUTE,
ICON_PERCENT,
)
from .. import EMC2101_COMPONENT_SCHEMA, CONF_EMC2101_ID, emc2101_ns
DEPENDENCIES = ["emc2101"]
CONF_INTERNAL_TEMPERATURE = "internal_temperature"
CONF_EXTERNAL_TEMPERATURE = "external_temperature"
CONF_DUTY_CYCLE = "duty_cycle"
EMC2101Sensor = emc2101_ns.class_("EMC2101Sensor", cg.PollingComponent)
CONFIG_SCHEMA = EMC2101_COMPONENT_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(EMC2101Sensor),
cv.Optional(CONF_INTERNAL_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_EXTERNAL_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=3,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_SPEED): sensor.sensor_schema(
unit_of_measurement=UNIT_REVOLUTIONS_PER_MINUTE,
accuracy_decimals=2,
state_class=STATE_CLASS_MEASUREMENT,
icon="mdi:fan",
),
cv.Optional(CONF_DUTY_CYCLE): sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=2,
state_class=STATE_CLASS_MEASUREMENT,
icon=ICON_PERCENT,
),
}
).extend(cv.polling_component_schema("60s"))
async def to_code(config):
paren = await cg.get_variable(config[CONF_EMC2101_ID])
var = cg.new_Pvariable(config[CONF_ID], paren)
await cg.register_component(var, config)
if CONF_INTERNAL_TEMPERATURE in config:
sens = await sensor.new_sensor(config[CONF_INTERNAL_TEMPERATURE])
cg.add(var.set_internal_temperature_sensor(sens))
if CONF_EXTERNAL_TEMPERATURE in config:
sens = await sensor.new_sensor(config[CONF_EXTERNAL_TEMPERATURE])
cg.add(var.set_external_temperature_sensor(sens))
if CONF_SPEED in config:
sens = await sensor.new_sensor(config[CONF_SPEED])
cg.add(var.set_speed_sensor(sens))
if CONF_DUTY_CYCLE in config:
sens = await sensor.new_sensor(config[CONF_DUTY_CYCLE])
cg.add(var.set_duty_cycle_sensor(sens))

View file

@ -0,0 +1,43 @@
#include "emc2101_sensor.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace emc2101 {
static const char *const TAG = "EMC2101.sensor";
float EMC2101Sensor::get_setup_priority() const { return setup_priority::DATA; }
void EMC2101Sensor::dump_config() {
ESP_LOGCONFIG(TAG, "Emc2101 sensor:");
LOG_SENSOR(" ", "Internal temperature", this->internal_temperature_sensor_);
LOG_SENSOR(" ", "External temperature", this->external_temperature_sensor_);
LOG_SENSOR(" ", "Speed", this->speed_sensor_);
LOG_SENSOR(" ", "Duty cycle", this->duty_cycle_sensor_);
}
void EMC2101Sensor::update() {
if (this->internal_temperature_sensor_ != nullptr) {
float internal_temperature = this->parent_->get_internal_temperature();
this->internal_temperature_sensor_->publish_state(internal_temperature);
}
if (this->external_temperature_sensor_ != nullptr) {
float external_temperature = this->parent_->get_external_temperature();
this->external_temperature_sensor_->publish_state(external_temperature);
}
if (this->speed_sensor_ != nullptr) {
float speed = this->parent_->get_speed();
this->speed_sensor_->publish_state(speed);
}
if (this->duty_cycle_sensor_ != nullptr) {
float duty_cycle = this->parent_->get_duty_cycle();
this->duty_cycle_sensor_->publish_state(duty_cycle * 100.0f);
}
}
} // namespace emc2101
} // namespace esphome

View file

@ -0,0 +1,39 @@
#pragma once
#include "../emc2101.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
namespace esphome {
namespace emc2101 {
/// This class exposes the EMC2101 sensors.
class EMC2101Sensor : public PollingComponent {
public:
EMC2101Sensor(Emc2101Component *parent) : parent_(parent) {}
/** Used by ESPHome framework. */
void dump_config() override;
/** Used by ESPHome framework. */
void update() override;
/** Used by ESPHome framework. */
float get_setup_priority() const override;
/** Used by ESPHome framework. */
void set_internal_temperature_sensor(sensor::Sensor *sensor) { this->internal_temperature_sensor_ = sensor; }
/** Used by ESPHome framework. */
void set_external_temperature_sensor(sensor::Sensor *sensor) { this->external_temperature_sensor_ = sensor; }
/** Used by ESPHome framework. */
void set_speed_sensor(sensor::Sensor *sensor) { this->speed_sensor_ = sensor; }
/** Used by ESPHome framework. */
void set_duty_cycle_sensor(sensor::Sensor *sensor) { this->duty_cycle_sensor_ = sensor; }
protected:
Emc2101Component *parent_;
sensor::Sensor *internal_temperature_sensor_{nullptr};
sensor::Sensor *external_temperature_sensor_{nullptr};
sensor::Sensor *speed_sensor_{nullptr};
sensor::Sensor *duty_cycle_sensor_{nullptr};
};
} // namespace emc2101
} // namespace esphome

View file

@ -0,0 +1,2 @@
"""Support for Honeywell ABP2"""
CODEOWNERS = ["@jpfaff"]

View file

@ -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

View file

@ -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

View file

@ -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))

View file

@ -139,17 +139,22 @@ def _process_base_package(config: dict) -> dict:
) from e
return packages
packages = {}
packages = None
error = ""
try:
packages = get_packages(files)
except cv.Invalid:
if revert is not None:
revert()
packages = get_packages(files)
finally:
if packages is None:
raise cv.Invalid("Failed to load packages")
except cv.Invalid as e:
error = e
try:
if revert is not None:
revert()
packages = get_packages(files)
except cv.Invalid as er:
error = er
if packages is None:
raise cv.Invalid(f"Failed to load packages. {error}")
return {"packages": packages}

View file

View file

@ -0,0 +1,67 @@
from esphome import core
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, binary_sensor
from esphome.const import (
CONF_DEBOUNCE,
DEVICE_CLASS_MOTION,
)
DEPENDENCIES = ["i2c"]
CODEOWNERS = ["@kahrendt"]
qwiic_pir_ns = cg.esphome_ns.namespace("qwiic_pir")
DebounceMode = qwiic_pir_ns.enum("DebounceMode")
DEBOUNCE_MODE_OPTIONS = {
"RAW": DebounceMode.RAW_DEBOUNCE_MODE,
"NATIVE": DebounceMode.NATIVE_DEBOUNCE_MODE,
"HYBRID": DebounceMode.HYBRID_DEBOUNCE_MODE,
}
CONF_DEBOUNCE_MODE = "debounce_mode"
QwiicPIRComponent = qwiic_pir_ns.class_(
"QwiicPIRComponent", cg.Component, i2c.I2CDevice, binary_sensor.BinarySensor
)
def validate_no_debounce_unless_native(config):
if CONF_DEBOUNCE in config:
if config[CONF_DEBOUNCE_MODE] != "NATIVE":
raise cv.Invalid("debounce can only be set if debounce_mode is NATIVE")
return config
CONFIG_SCHEMA = cv.All(
binary_sensor.binary_sensor_schema(
QwiicPIRComponent,
device_class=DEVICE_CLASS_MOTION,
)
.extend(
{
cv.Optional(CONF_DEBOUNCE): cv.All(
cv.time_period,
cv.Range(max=core.TimePeriod(milliseconds=65535)),
),
cv.Optional(CONF_DEBOUNCE_MODE, default="HYBRID"): cv.enum(
DEBOUNCE_MODE_OPTIONS, upper=True
),
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x12)),
validate_no_debounce_unless_native,
)
async def to_code(config):
var = await binary_sensor.new_binary_sensor(config)
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
if debounce_time_setting := config.get(CONF_DEBOUNCE):
cg.add(var.set_debounce_time(debounce_time_setting.total_milliseconds))
else:
cg.add(var.set_debounce_time(1)) # default to 1 ms if not configured
cg.add(var.set_debounce_mode(config[CONF_DEBOUNCE_MODE]))

View file

@ -0,0 +1,137 @@
#include "qwiic_pir.h"
#include "esphome/core/log.h"
namespace esphome {
namespace qwiic_pir {
static const char *const TAG = "qwiic_pir";
void QwiicPIRComponent::setup() {
ESP_LOGCONFIG(TAG, "Setting up Qwiic PIR...");
// Verify I2C communcation by reading and verifying the chip ID
uint8_t chip_id;
if (!this->read_byte(QWIIC_PIR_CHIP_ID, &chip_id)) {
ESP_LOGE(TAG, "Failed to read the chip's ID");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (chip_id != QWIIC_PIR_DEVICE_ID) {
ESP_LOGE(TAG, "Unknown chip ID, is this a Qwiic PIR?");
this->error_code_ = ERROR_WRONG_CHIP_ID;
this->mark_failed();
return;
}
if (!this->write_byte_16(QWIIC_PIR_DEBOUNCE_TIME, this->debounce_time_)) {
ESP_LOGE(TAG, "Failed to configure debounce time.");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (this->debounce_mode_ == NATIVE_DEBOUNCE_MODE) {
// Publish the starting raw state of the PIR sensor
// If NATIVE mode, the binary_sensor state would be unknown until a motion event
if (!this->read_byte(QWIIC_PIR_EVENT_STATUS, &this->event_register_.reg)) {
ESP_LOGE(TAG, "Failed to read initial sensor state.");
this->error_code_ = ERROR_COMMUNICATION_FAILED;
this->mark_failed();
return;
}
this->publish_state(this->event_register_.raw_reading);
}
}
void QwiicPIRComponent::loop() {
// Read Event Register
if (!this->read_byte(QWIIC_PIR_EVENT_STATUS, &this->event_register_.reg)) {
ESP_LOGW(TAG, "Failed to communicate with sensor");
return;
}
if (this->debounce_mode_ == HYBRID_DEBOUNCE_MODE) {
// Use a combination of the raw sensor reading and the device's event detection to determine state
// - The device is hardcoded to use a debounce time of 1 ms in this mode
// - Any event, even if it is object_removed, implies motion was active since the last loop, so publish true
// - Use ESPHome's built-in filters for debouncing
this->publish_state(this->event_register_.raw_reading || this->event_register_.event_available);
if (this->event_register_.event_available) {
this->clear_events_();
}
} else if (this->debounce_mode_ == NATIVE_DEBOUNCE_MODE) {
// Uses the device's firmware to debounce the signal
// - Follows the logic of SparkFun's example implementation:
// https://github.com/sparkfun/SparkFun_Qwiic_PIR_Arduino_Library/blob/master/examples/Example2_PrintPIRStatus/Example2_PrintPIRStatus.ino
// (accessed July 2023)
// - Is unreliable at detecting an object being removed, especially at debounce rates even slightly large
if (this->event_register_.event_available) {
// If an object is detected, publish true
if (this->event_register_.object_detected)
this->publish_state(true);
// If an object has been removed, publish false
if (this->event_register_.object_removed)
this->publish_state(false);
this->clear_events_();
}
} else if (this->debounce_mode_ == RAW_DEBOUNCE_MODE) {
// Publishes the raw PIR sensor reading with no further logic
// - May miss a very short motion detection if the ESP's loop time is slow
this->publish_state(this->event_register_.raw_reading);
}
}
void QwiicPIRComponent::dump_config() {
ESP_LOGCONFIG(TAG, "Qwiic PIR:");
if (this->debounce_mode_ == RAW_DEBOUNCE_MODE) {
ESP_LOGCONFIG(TAG, " Debounce Mode: RAW");
} else if (this->debounce_mode_ == NATIVE_DEBOUNCE_MODE) {
ESP_LOGCONFIG(TAG, " Debounce Mode: NATIVE");
ESP_LOGCONFIG(TAG, " Debounce Time: %ums", this->debounce_time_);
} else if (this->debounce_mode_ == HYBRID_DEBOUNCE_MODE) {
ESP_LOGCONFIG(TAG, " Debounce Mode: HYBRID");
}
switch (this->error_code_) {
case NONE:
break;
case ERROR_COMMUNICATION_FAILED:
ESP_LOGE(TAG, " Communication with Qwiic PIR failed!");
break;
case ERROR_WRONG_CHIP_ID:
ESP_LOGE(TAG, " Qwiic PIR has wrong chip ID - please verify you are using a Qwiic PIR");
break;
default:
ESP_LOGE(TAG, " Qwiic PIR error code %d", (int) this->error_code_);
break;
}
LOG_I2C_DEVICE(this);
LOG_BINARY_SENSOR(" ", "Qwiic PIR Binary Sensor", this);
}
void QwiicPIRComponent::clear_events_() {
// Clear event status register
if (!this->write_byte(QWIIC_PIR_EVENT_STATUS, 0x00))
ESP_LOGW(TAG, "Failed to clear events on sensor");
}
} // namespace qwiic_pir
} // namespace esphome

View file

@ -0,0 +1,70 @@
/*
* Adds support for Qwiic PIR motion sensors that communicate over an I2C bus.
* These sensors use Sharp PIR motion sensors to detect motion. A firmware running on an ATTiny84 translates the digital
* output to I2C communications.
* ATTiny84 firmware: https://github.com/sparkfun/Qwiic_PIR (acccessed July 2023)
* SparkFun's Arduino library: https://github.com/sparkfun/SparkFun_Qwiic_PIR_Arduino_Library (accessed July 2023)
*/
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace qwiic_pir {
// Qwiic PIR I2C Register Addresses
enum {
QWIIC_PIR_CHIP_ID = 0x00,
QWIIC_PIR_EVENT_STATUS = 0x03,
QWIIC_PIR_DEBOUNCE_TIME = 0x05, // uint16_t debounce time in milliseconds
};
enum DebounceMode {
RAW_DEBOUNCE_MODE,
NATIVE_DEBOUNCE_MODE,
HYBRID_DEBOUNCE_MODE,
};
static const uint8_t QWIIC_PIR_DEVICE_ID = 0x72;
class QwiicPIRComponent : public Component, public i2c::I2CDevice, public binary_sensor::BinarySensor {
public:
void setup() override;
void loop() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_debounce_time(uint16_t debounce_time) { this->debounce_time_ = debounce_time; }
void set_debounce_mode(DebounceMode mode) { this->debounce_mode_ = mode; }
protected:
uint16_t debounce_time_{};
DebounceMode debounce_mode_{};
enum ErrorCode {
NONE = 0,
ERROR_COMMUNICATION_FAILED,
ERROR_WRONG_CHIP_ID,
} error_code_{NONE};
union {
struct {
bool raw_reading : 1; // raw state of PIR sensor
bool event_available : 1; // a debounced object has been detected or removed
bool object_removed : 1; // a debounced object is no longer detected
bool object_detected : 1; // a debounced object has been detected
bool : 4;
};
uint8_t reg;
} event_register_ = {.reg = 0};
void clear_events_();
};
} // namespace qwiic_pir
} // namespace esphome

View file

@ -1,5 +1,6 @@
#include "sen5x.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <cinttypes>
@ -135,9 +136,12 @@ void SEN5XComponent::setup() {
ESP_LOGD(TAG, "Firmware version %d", this->firmware_version_);
if (this->voc_sensor_ && this->store_baseline_) {
// Hash with compilation time
uint32_t combined_serial =
encode_uint24(this->serial_number_[0], this->serial_number_[1], this->serial_number_[2]);
// Hash with compilation time and serial number
// This ensures the baseline storage is cleared after OTA
uint32_t hash = fnv1_hash(App.get_compilation_time());
// Serial numbers are unique to each sensor, so mulitple sensors can be used without conflict
uint32_t hash = fnv1_hash(App.get_compilation_time() + std::to_string(combined_serial));
this->pref_ = global_preferences->make_preference<Sen5xBaselines>(hash, true);
if (this->pref_.load(&this->voc_baselines_storage_)) {

View file

@ -16,6 +16,7 @@ from esphome.const import (
CONF_FROM,
CONF_ICON,
CONF_ID,
CONF_IGNORE_OUT_OF_RANGE,
CONF_ON_RAW_VALUE,
CONF_ON_VALUE,
CONF_ON_VALUE_RANGE,
@ -688,6 +689,7 @@ CLAMP_SCHEMA = cv.All(
{
cv.Optional(CONF_MIN_VALUE, default="NaN"): cv.float_,
cv.Optional(CONF_MAX_VALUE, default="NaN"): cv.float_,
cv.Optional(CONF_IGNORE_OUT_OF_RANGE, default=False): cv.boolean,
}
),
validate_clamp,
@ -700,6 +702,7 @@ async def clamp_filter_to_code(config, filter_id):
filter_id,
config[CONF_MIN_VALUE],
config[CONF_MAX_VALUE],
config[CONF_IGNORE_OUT_OF_RANGE],
)

View file

@ -434,13 +434,25 @@ optional<float> CalibratePolynomialFilter::new_value(float value) {
return res;
}
ClampFilter::ClampFilter(float min, float max) : min_(min), max_(max) {}
ClampFilter::ClampFilter(float min, float max, bool ignore_out_of_range)
: min_(min), max_(max), ignore_out_of_range_(ignore_out_of_range) {}
optional<float> ClampFilter::new_value(float value) {
if (std::isfinite(value)) {
if (std::isfinite(this->min_) && value < this->min_)
return this->min_;
if (std::isfinite(this->max_) && value > this->max_)
return this->max_;
if (std::isfinite(this->min_) && value < this->min_) {
if (this->ignore_out_of_range_) {
return {};
} else {
return this->min_;
}
}
if (std::isfinite(this->max_) && value > this->max_) {
if (this->ignore_out_of_range_) {
return {};
} else {
return this->max_;
}
}
}
return value;
}

View file

@ -411,12 +411,13 @@ class CalibratePolynomialFilter : public Filter {
class ClampFilter : public Filter {
public:
ClampFilter(float min, float max);
ClampFilter(float min, float max, bool ignore_out_of_range);
optional<float> new_value(float value) override;
protected:
float min_{NAN};
float max_{NAN};
bool ignore_out_of_range_;
};
class RoundFilter : public Filter {

View file

@ -73,9 +73,10 @@ void SGP30Component::setup() {
return;
}
// Hash with compilation time
// Hash with compilation time and serial number
// This ensures the baseline storage is cleared after OTA
uint32_t hash = fnv1_hash(App.get_compilation_time());
// Serial numbers are unique to each sensor, so mulitple sensors can be used without conflict
uint32_t hash = fnv1_hash(App.get_compilation_time() + std::to_string(this->serial_number_));
this->pref_ = global_preferences->make_preference<SGP30Baselines>(hash, true);
if (this->pref_.load(&this->baselines_storage_)) {

View file

@ -61,9 +61,10 @@ void SGP4xComponent::setup() {
ESP_LOGD(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF));
if (this->store_baseline_) {
// Hash with compilation time
// Hash with compilation time and serial number
// This ensures the baseline storage is cleared after OTA
uint32_t hash = fnv1_hash(App.get_compilation_time());
// Serial numbers are unique to each sensor, so mulitple sensors can be used without conflict
uint32_t hash = fnv1_hash(App.get_compilation_time() + std::to_string(this->serial_number_));
this->pref_ = global_preferences->make_preference<SGP4xBaselines>(hash, true);
if (this->pref_.load(&this->voc_baselines_storage_)) {

View file

@ -335,6 +335,7 @@ CONF_IDLE_LEVEL = "idle_level"
CONF_IDLE_TIME = "idle_time"
CONF_IF = "if"
CONF_IGNORE_EFUSE_MAC_CRC = "ignore_efuse_mac_crc"
CONF_IGNORE_OUT_OF_RANGE = "ignore_out_of_range"
CONF_IGNORE_STRAPPING_WARNING = "ignore_strapping_warning"
CONF_IIR_FILTER = "iir_filter"
CONF_ILLUMINANCE = "illuminance"

View file

@ -750,6 +750,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
@ -1821,6 +1831,9 @@ binary_sensor:
- platform: optolink
name: Disturbance
address: 0x0A82
- platform: qwiic_pir
i2c_id: i2c_bus
name: "Qwiic PIR Motion Sensor"
pca9685:
frequency: 500