From 28aedae8d72613fc9d712af323a3c503bcf62d3d Mon Sep 17 00:00:00 2001 From: Eduard Llull Date: Wed, 25 Oct 2023 20:30:11 +0200 Subject: [PATCH] Add Emc2101 (#4491) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/emc2101/__init__.py | 81 +++++++++ esphome/components/emc2101/emc2101.cpp | 169 ++++++++++++++++++ esphome/components/emc2101/emc2101.h | 115 ++++++++++++ esphome/components/emc2101/output/__init__.py | 21 +++ .../emc2101/output/emc2101_output.cpp | 9 + .../emc2101/output/emc2101_output.h | 22 +++ esphome/components/emc2101/sensor/__init__.py | 74 ++++++++ .../emc2101/sensor/emc2101_sensor.cpp | 43 +++++ .../emc2101/sensor/emc2101_sensor.h | 39 ++++ 10 files changed, 574 insertions(+) create mode 100644 esphome/components/emc2101/__init__.py create mode 100644 esphome/components/emc2101/emc2101.cpp create mode 100644 esphome/components/emc2101/emc2101.h create mode 100644 esphome/components/emc2101/output/__init__.py create mode 100644 esphome/components/emc2101/output/emc2101_output.cpp create mode 100644 esphome/components/emc2101/output/emc2101_output.h create mode 100644 esphome/components/emc2101/sensor/__init__.py create mode 100644 esphome/components/emc2101/sensor/emc2101_sensor.cpp create mode 100644 esphome/components/emc2101/sensor/emc2101_sensor.h diff --git a/CODEOWNERS b/CODEOWNERS index ad44d52639..b2c0d013be 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -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 diff --git a/esphome/components/emc2101/__init__.py b/esphome/components/emc2101/__init__.py new file mode 100644 index 0000000000..7a7b31cf14 --- /dev/null +++ b/esphome/components/emc2101/__init__.py @@ -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])) diff --git a/esphome/components/emc2101/emc2101.cpp b/esphome/components/emc2101/emc2101.cpp new file mode 100644 index 0000000000..2f45b2e27a --- /dev/null +++ b/esphome/components/emc2101/emc2101.cpp @@ -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 diff --git a/esphome/components/emc2101/emc2101.h b/esphome/components/emc2101/emc2101.h new file mode 100644 index 0000000000..0f4bc560dd --- /dev/null +++ b/esphome/components/emc2101/emc2101.h @@ -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 diff --git a/esphome/components/emc2101/output/__init__.py b/esphome/components/emc2101/output/__init__.py new file mode 100644 index 0000000000..461ef73de1 --- /dev/null +++ b/esphome/components/emc2101/output/__init__.py @@ -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) diff --git a/esphome/components/emc2101/output/emc2101_output.cpp b/esphome/components/emc2101/output/emc2101_output.cpp new file mode 100644 index 0000000000..2ed506cd99 --- /dev/null +++ b/esphome/components/emc2101/output/emc2101_output.cpp @@ -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 diff --git a/esphome/components/emc2101/output/emc2101_output.h b/esphome/components/emc2101/output/emc2101_output.h new file mode 100644 index 0000000000..232df6ff5f --- /dev/null +++ b/esphome/components/emc2101/output/emc2101_output.h @@ -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 diff --git a/esphome/components/emc2101/sensor/__init__.py b/esphome/components/emc2101/sensor/__init__.py new file mode 100644 index 0000000000..03d3d0314e --- /dev/null +++ b/esphome/components/emc2101/sensor/__init__.py @@ -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)) diff --git a/esphome/components/emc2101/sensor/emc2101_sensor.cpp b/esphome/components/emc2101/sensor/emc2101_sensor.cpp new file mode 100644 index 0000000000..2a199f48e9 --- /dev/null +++ b/esphome/components/emc2101/sensor/emc2101_sensor.cpp @@ -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 diff --git a/esphome/components/emc2101/sensor/emc2101_sensor.h b/esphome/components/emc2101/sensor/emc2101_sensor.h new file mode 100644 index 0000000000..3e8dcebc8e --- /dev/null +++ b/esphome/components/emc2101/sensor/emc2101_sensor.h @@ -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