INA260 Current and Power Sensor support (#2788)

This commit is contained in:
MrEditor97 2021-12-31 09:08:49 +00:00 committed by GitHub
parent 07ff3a853f
commit 23edb18d7e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 248 additions and 0 deletions

View file

@ -75,6 +75,7 @@ esphome/components/homeassistant/* @OttoWinter
esphome/components/hrxl_maxsonar_wr/* @netmikey
esphome/components/i2c/* @esphome/core
esphome/components/improv_serial/* @esphome/core
esphome/components/ina260/* @MrEditor97
esphome/components/inkbird_ibsth1_mini/* @fkirill
esphome/components/inkplate6/* @jesserockz
esphome/components/integration/* @OttoWinter

View file

View file

@ -0,0 +1,128 @@
#include "ina260.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
namespace esphome {
namespace ina260 {
static const char *const TAG = "ina260";
// | A0 | A1 | Address |
// | GND | GND | 0x40 |
// | GND | V_S+ | 0x41 |
// | GND | SDA | 0x42 |
// | GND | SCL | 0x43 |
// | V_S+ | GND | 0x44 |
// | V_S+ | V_S+ | 0x45 |
// | V_S+ | SDA | 0x46 |
// | V_S+ | SCL | 0x47 |
// | SDA | GND | 0x48 |
// | SDA | V_S+ | 0x49 |
// | SDA | SDA | 0x4A |
// | SDA | SCL | 0x4B |
// | SCL | GND | 0x4C |
// | SCL | V_S+ | 0x4D |
// | SCL | SDA | 0x4E |
// | SCL | SCL | 0x4F |
static const uint8_t INA260_REGISTER_CONFIG = 0x00;
static const uint8_t INA260_REGISTER_CURRENT = 0x01;
static const uint8_t INA260_REGISTER_BUS_VOLTAGE = 0x02;
static const uint8_t INA260_REGISTER_POWER = 0x03;
static const uint8_t INA260_REGISTER_MASK_ENABLE = 0x06;
static const uint8_t INA260_REGISTER_ALERT_LIMIT = 0x07;
static const uint8_t INA260_REGISTER_MANUFACTURE_ID = 0xFE;
static const uint8_t INA260_REGISTER_DEVICE_ID = 0xFF;
void INA260Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up INA260...");
// Reset device on setup
if (!this->write_byte_16(INA260_REGISTER_CONFIG, 0x8000)) {
this->error_code_ = DEVICE_RESET_FAILED;
this->mark_failed();
return;
}
delay(2);
this->read_byte_16(INA260_REGISTER_MANUFACTURE_ID, &this->manufacture_id_);
this->read_byte_16(INA260_REGISTER_DEVICE_ID, &this->device_id_);
if (this->manufacture_id_ != (uint16_t) 0x5449 || this->device_id_ != (uint16_t) 0x2270) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (!this->write_byte_16(INA260_REGISTER_CONFIG, (uint16_t) 0b0000001100000111)) {
this->error_code_ = FAILED_TO_UPDATE_CONFIGURATION;
this->mark_failed();
return;
}
}
void INA260Component::dump_config() {
ESP_LOGCONFIG(TAG, "INA260:");
LOG_I2C_DEVICE(this);
LOG_UPDATE_INTERVAL(this);
ESP_LOGCONFIG(TAG, " Manufacture ID: 0x%x", this->manufacture_id_);
ESP_LOGCONFIG(TAG, " Device ID: 0x%x", this->device_id_);
LOG_SENSOR(" ", "Bus Voltage", this->bus_voltage_sensor_);
LOG_SENSOR(" ", "Current", this->current_sensor_);
LOG_SENSOR(" ", "Power", this->power_sensor_);
switch (this->error_code_) {
case COMMUNICATION_FAILED:
ESP_LOGE(TAG, "Connected device does not match a known INA260 sensor");
break;
case DEVICE_RESET_FAILED:
ESP_LOGE(TAG, "Device reset failed - Is the device connected?");
break;
case FAILED_TO_UPDATE_CONFIGURATION:
ESP_LOGE(TAG, "Failed to update device configuration");
break;
case NONE:
default:
break;
}
}
void INA260Component::update() {
if (this->bus_voltage_sensor_ != nullptr) {
uint16_t raw_bus_voltage;
if (!this->read_byte_16(INA260_REGISTER_BUS_VOLTAGE, &raw_bus_voltage)) {
this->status_set_warning();
return;
}
float bus_voltage_v = int16_t(raw_bus_voltage) * 0.00125f;
this->bus_voltage_sensor_->publish_state(bus_voltage_v);
}
if (this->current_sensor_ != nullptr) {
uint16_t raw_current;
if (!this->read_byte_16(INA260_REGISTER_CURRENT, &raw_current)) {
this->status_set_warning();
return;
}
float current_a = int16_t(raw_current) * 0.00125f;
this->current_sensor_->publish_state(current_a);
}
if (this->power_sensor_ != nullptr) {
uint16_t raw_power;
if (!this->read_byte_16(INA260_REGISTER_POWER, &raw_power)) {
this->status_set_warning();
return;
}
float power_w = ((int16_t(raw_power) * 10.0f) / 1000.0f);
this->power_sensor_->publish_state(power_w);
}
this->status_clear_warning();
}
} // namespace ina260
} // namespace esphome

View file

@ -0,0 +1,39 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace ina260 {
class INA260Component : public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
void update() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_bus_voltage_sensor(sensor::Sensor *bus_voltage_sensor) { this->bus_voltage_sensor_ = bus_voltage_sensor; }
void set_current_sensor(sensor::Sensor *current_sensor) { this->current_sensor_ = current_sensor; }
void set_power_sensor(sensor::Sensor *power_sensor) { this->power_sensor_ = power_sensor; }
protected:
uint16_t manufacture_id_{0};
uint16_t device_id_{0};
sensor::Sensor *bus_voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
enum ErrorCode {
NONE,
COMMUNICATION_FAILED,
DEVICE_RESET_FAILED,
FAILED_TO_UPDATE_CONFIGURATION,
} error_code_{NONE};
};
} // namespace ina260
} // namespace esphome

View file

@ -0,0 +1,71 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ID,
CONF_BUS_VOLTAGE,
CONF_CURRENT,
CONF_POWER,
DEVICE_CLASS_VOLTAGE,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_POWER,
STATE_CLASS_MEASUREMENT,
UNIT_VOLT,
UNIT_AMPERE,
UNIT_WATT,
)
DEPENDENCIES = ["i2c"]
CODEOWNERS = ["@MrEditor97"]
ina260_ns = cg.esphome_ns.namespace("ina260")
INA260Component = ina260_ns.class_(
"INA260Component", cg.PollingComponent, i2c.I2CDevice
)
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(INA260Component),
cv.Optional(CONF_BUS_VOLTAGE): sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_CURRENT): sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=3,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_POWER): sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x40))
)
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 CONF_BUS_VOLTAGE in config:
sens = await sensor.new_sensor(config[CONF_BUS_VOLTAGE])
cg.add(var.set_bus_voltage_sensor(sens))
if CONF_CURRENT in config:
sens = await sensor.new_sensor(config[CONF_CURRENT])
cg.add(var.set_current_sensor(sens))
if CONF_POWER in config:
sens = await sensor.new_sensor(config[CONF_POWER])
cg.add(var.set_power_sensor(sens))

View file

@ -307,6 +307,15 @@ sensor:
name: "Wave Mini Pressure"
tvoc:
name: "Wave Mini VOC"
- platform: ina260
address: 0x40
current:
name: "INA260 Current"
power:
name: "INA260 Power"
bus_voltage:
name: "INA260 Voltage"
update_interval: 60s
time:
- platform: homeassistant