From a4431abea82c2300b07ca1780bf3351452b83504 Mon Sep 17 00:00:00 2001 From: rsumner Date: Sun, 9 Jan 2022 17:04:48 -0600 Subject: [PATCH] MCP3204 4-channel 12-bit ADC component (#2895) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/mcp3204/__init__.py | 27 ++++++++++++++ esphome/components/mcp3204/mcp3204.cpp | 35 +++++++++++++++++++ esphome/components/mcp3204/mcp3204.h | 28 +++++++++++++++ esphome/components/mcp3204/sensor/__init__.py | 32 +++++++++++++++++ .../mcp3204/sensor/mcp3204_sensor.cpp | 23 ++++++++++++ .../mcp3204/sensor/mcp3204_sensor.h | 30 ++++++++++++++++ tests/test4.yaml | 6 ++++ 8 files changed, 182 insertions(+) create mode 100644 esphome/components/mcp3204/__init__.py create mode 100644 esphome/components/mcp3204/mcp3204.cpp create mode 100644 esphome/components/mcp3204/mcp3204.h create mode 100644 esphome/components/mcp3204/sensor/__init__.py create mode 100644 esphome/components/mcp3204/sensor/mcp3204_sensor.cpp create mode 100644 esphome/components/mcp3204/sensor/mcp3204_sensor.h diff --git a/CODEOWNERS b/CODEOWNERS index 5f9a579827..59648b6dbc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -97,6 +97,7 @@ esphome/components/mcp23x08_base/* @jesserockz esphome/components/mcp23x17_base/* @jesserockz esphome/components/mcp23xxx_base/* @jesserockz esphome/components/mcp2515/* @danielschramm @mvturnho +esphome/components/mcp3204/* @rsumner esphome/components/mcp47a1/* @jesserockz esphome/components/mcp9808/* @k7hpn esphome/components/md5/* @esphome/core diff --git a/esphome/components/mcp3204/__init__.py b/esphome/components/mcp3204/__init__.py new file mode 100644 index 0000000000..0536166e56 --- /dev/null +++ b/esphome/components/mcp3204/__init__.py @@ -0,0 +1,27 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import spi +from esphome.const import CONF_ID + +DEPENDENCIES = ["spi"] +MULTI_CONF = True +CODEOWNERS = ["@rsumner"] + +mcp3204_ns = cg.esphome_ns.namespace("mcp3204") +MCP3204 = mcp3204_ns.class_("MCP3204", cg.Component, spi.SPIDevice) + +CONF_REFERENCE_VOLTAGE = "reference_voltage" + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(MCP3204), + cv.Optional(CONF_REFERENCE_VOLTAGE, default="3.3V"): cv.voltage, + } +).extend(spi.spi_device_schema(cs_pin_required=True)) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + cg.add(var.set_reference_voltage(config[CONF_REFERENCE_VOLTAGE])) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) diff --git a/esphome/components/mcp3204/mcp3204.cpp b/esphome/components/mcp3204/mcp3204.cpp new file mode 100644 index 0000000000..44044349a3 --- /dev/null +++ b/esphome/components/mcp3204/mcp3204.cpp @@ -0,0 +1,35 @@ +#include "mcp3204.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace mcp3204 { + +static const char *const TAG = "mcp3204"; + +float MCP3204::get_setup_priority() const { return setup_priority::HARDWARE; } + +void MCP3204::setup() { + ESP_LOGCONFIG(TAG, "Setting up mcp3204"); + this->spi_setup(); +} + +void MCP3204::dump_config() { + ESP_LOGCONFIG(TAG, "MCP3204:"); + LOG_PIN(" CS Pin:", this->cs_); + ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_); +} + +float MCP3204::read_data(uint8_t pin) { + uint8_t adc_primary_config = 0b00000110 & 0b00000111; + uint8_t adc_secondary_config = pin << 6; + this->enable(); + this->transfer_byte(adc_primary_config); + uint8_t adc_primary_byte = this->transfer_byte(adc_secondary_config); + uint8_t adc_secondary_byte = this->transfer_byte(0x00); + this->disable(); + uint16_t digital_value = (adc_primary_byte << 8 | adc_secondary_byte) & 0b111111111111; + return float(digital_value) / 4096.000 * this->reference_voltage_; +} + +} // namespace mcp3204 +} // namespace esphome diff --git a/esphome/components/mcp3204/mcp3204.h b/esphome/components/mcp3204/mcp3204.h new file mode 100644 index 0000000000..27261aa373 --- /dev/null +++ b/esphome/components/mcp3204/mcp3204.h @@ -0,0 +1,28 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/components/spi/spi.h" + +namespace esphome { +namespace mcp3204 { + +class MCP3204 : public Component, + public spi::SPIDevice { + public: + MCP3204() = default; + + void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; } + + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + float read_data(uint8_t pin); + + protected: + float reference_voltage_; +}; + +} // namespace mcp3204 +} // namespace esphome diff --git a/esphome/components/mcp3204/sensor/__init__.py b/esphome/components/mcp3204/sensor/__init__.py new file mode 100644 index 0000000000..1d8701a91e --- /dev/null +++ b/esphome/components/mcp3204/sensor/__init__.py @@ -0,0 +1,32 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, voltage_sampler +from esphome.const import CONF_ID, CONF_NUMBER +from .. import mcp3204_ns, MCP3204 + +AUTO_LOAD = ["voltage_sampler"] + +DEPENDENCIES = ["mcp3204"] + +MCP3204Sensor = mcp3204_ns.class_( + "MCP3204Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler +) +CONF_MCP3204_ID = "mcp3204_id" + +CONFIG_SCHEMA = sensor.SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(MCP3204Sensor), + cv.GenerateID(CONF_MCP3204_ID): cv.use_id(MCP3204), + cv.Required(CONF_NUMBER): cv.int_range(min=0, max=3), + } +).extend(cv.polling_component_schema("60s")) + + +async def to_code(config): + var = cg.new_Pvariable( + config[CONF_ID], + config[CONF_NUMBER], + ) + await cg.register_parented(var, config[CONF_MCP3204_ID]) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) diff --git a/esphome/components/mcp3204/sensor/mcp3204_sensor.cpp b/esphome/components/mcp3204/sensor/mcp3204_sensor.cpp new file mode 100644 index 0000000000..ce0fd25462 --- /dev/null +++ b/esphome/components/mcp3204/sensor/mcp3204_sensor.cpp @@ -0,0 +1,23 @@ +#include "mcp3204_sensor.h" + +#include "esphome/core/log.h" + +namespace esphome { +namespace mcp3204 { + +static const char *const TAG = "mcp3204.sensor"; + +MCP3204Sensor::MCP3204Sensor(uint8_t pin) : pin_(pin) {} + +float MCP3204Sensor::get_setup_priority() const { return setup_priority::DATA; } + +void MCP3204Sensor::dump_config() { + LOG_SENSOR("", "MCP3204 Sensor", this); + ESP_LOGCONFIG(TAG, " Pin: %u", this->pin_); + LOG_UPDATE_INTERVAL(this); +} +float MCP3204Sensor::sample() { return this->parent_->read_data(this->pin_); } +void MCP3204Sensor::update() { this->publish_state(this->sample()); } + +} // namespace mcp3204 +} // namespace esphome diff --git a/esphome/components/mcp3204/sensor/mcp3204_sensor.h b/esphome/components/mcp3204/sensor/mcp3204_sensor.h new file mode 100644 index 0000000000..21c45590ab --- /dev/null +++ b/esphome/components/mcp3204/sensor/mcp3204_sensor.h @@ -0,0 +1,30 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/voltage_sampler/voltage_sampler.h" +#include "esphome/core/component.h" +#include "esphome/core/hal.h" + +#include "../mcp3204.h" + +namespace esphome { +namespace mcp3204 { + +class MCP3204Sensor : public PollingComponent, + public Parented, + public sensor::Sensor, + public voltage_sampler::VoltageSampler { + public: + MCP3204Sensor(uint8_t pin); + + void update() override; + void dump_config() override; + float get_setup_priority() const override; + float sample() override; + + protected: + uint8_t pin_; +}; + +} // namespace mcp3204 +} // namespace esphome diff --git a/tests/test4.yaml b/tests/test4.yaml index 7c1ddee6d8..eec1c2eb5e 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -65,6 +65,9 @@ sx1509: - id: sx1509_hub address: 0x3E +mcp3204: + cs_pin: GPIO23 + sensor: - platform: homeassistant entity_id: sensor.hello_world @@ -215,6 +218,9 @@ sensor: - or: - throttle: "20min" - delta: 0.02 + - platform: mcp3204 + name: "MCP3204 Pin 1" + number: 1 # # platform sensor.apds9960 requires component apds9960