diff --git a/esphome/components/mcp3221/__init__.py b/esphome/components/mcp3221/__init__.py new file mode 100644 index 0000000000..677bb78c35 --- /dev/null +++ b/esphome/components/mcp3221/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@philippderdiedas"] diff --git a/esphome/components/mcp3221/mcp3221_sensor.cpp b/esphome/components/mcp3221/mcp3221_sensor.cpp new file mode 100644 index 0000000000..2164bc32ad --- /dev/null +++ b/esphome/components/mcp3221/mcp3221_sensor.cpp @@ -0,0 +1,41 @@ +#include "mcp3221_sensor.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace mcp3221 { + +static const char *const TAG = "mcp3221"; + +void MCP3221Sensor::setup() { + ESP_LOGCONFIG(TAG, "Probing MCP3221..."); + + if (!this->write(nullptr, 0)) { + this->mark_failed(); + return; + } +} + +float MCP3221Sensor::get_setup_priority() const { return setup_priority::DATA; } + +float MCP3221Sensor::sample() { + uint8_t data[2]; + if (!this->read(data, 2)) { + ESP_LOGW(TAG, "Failed to read data from MCP3221"); + this->status_set_warning(); + return NAN; + } + + uint16_t value = (data[0] << 8) | data[1]; + float voltage = value * this->reference_voltage_ / 4096.0f; + + return voltage; +} + +void MCP3221Sensor::update() { + float v = this->sample(); + this->publish_state(v); +} + +} // namespace mcp3221 +} // namespace esphome diff --git a/esphome/components/mcp3221/mcp3221_sensor.h b/esphome/components/mcp3221/mcp3221_sensor.h new file mode 100644 index 0000000000..5d54638a30 --- /dev/null +++ b/esphome/components/mcp3221/mcp3221_sensor.h @@ -0,0 +1,30 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/automation.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" + +#include + +namespace esphome { +namespace mcp3221 { + +class MCP3221Sensor : public sensor::Sensor, + public PollingComponent, + public voltage_sampler::VoltageSampler, + public i2c::I2CDevice { + public: + void setup() override; + void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; } + float get_setup_priority() const override; + void update() override; + float sample() override; + + protected: + float reference_voltage_; +}; + +} // namespace mcp3221 +} // namespace esphome diff --git a/esphome/components/mcp3221/sensor.py b/esphome/components/mcp3221/sensor.py new file mode 100644 index 0000000000..df04d1e72e --- /dev/null +++ b/esphome/components/mcp3221/sensor.py @@ -0,0 +1,47 @@ +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_RAW, + CONF_REFERENCE_VOLTAGE, + DEVICE_CLASS_VOLTAGE, + ICON_SCALE, + STATE_CLASS_MEASUREMENT, + UNIT_VOLT, +) + +DEPENDENCIES = ["i2c"] + +# CONF_CONTINUOUS_MODE = "continuous_mode" + + +mcp3221_ns = cg.esphome_ns.namespace("mcp3221") +MCP3221Sensor = mcp3221_ns.class_( + "MCP3221Sensor", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice +) + + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + MCP3221Sensor, + icon=ICON_SCALE, + accuracy_decimals=0, + state_class=STATE_CLASS_MEASUREMENT, + device_class=DEVICE_CLASS_VOLTAGE, + unit_of_measurement=UNIT_VOLT, + ) + .extend( + { + cv.Optional(CONF_REFERENCE_VOLTAGE, default="3.3V"): cv.voltage, + cv.Optional(CONF_RAW, default=False): cv.boolean, + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x48)) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config)