[INA3221] Add optional flags to expose all functionality (#16309)

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
rwalker777
2026-10-12 16:21:00 -10:00
committed by GitHub
co-authored by pre-commit-ci-lite[bot] J. Nick Koston J. Nick Koston
parent 753c10e5ea
commit 74e96b7da6
8 changed files with 352 additions and 73 deletions
+107 -29
View File
@@ -13,6 +13,24 @@ static const uint8_t INA3221_REGISTER_CHANNEL2_SHUNT_VOLTAGE = 0x03;
static const uint8_t INA3221_REGISTER_CHANNEL2_BUS_VOLTAGE = 0x04;
static const uint8_t INA3221_REGISTER_CHANNEL3_SHUNT_VOLTAGE = 0x05;
static const uint8_t INA3221_REGISTER_CHANNEL3_BUS_VOLTAGE = 0x06;
#ifdef USE_INA3221_ALERT_LIMITS
static constexpr uint8_t INA3221_REGISTER_CHANNEL1_CRITICAL_ALERT = 0x07;
static constexpr uint8_t INA3221_REGISTER_CHANNEL1_WARNING_ALERT = 0x0A;
#endif
#ifdef USE_INA3221_SUMMATION
static constexpr uint8_t INA3221_REGISTER_SHUNT_VOLTAGE_SUM = 0x0D;
static constexpr uint8_t INA3221_REGISTER_MASK_ENABLE = 0x0F;
#endif
// Configuration register: bit 15 resets the chip, bits 14..12 enable channels 1..3 (the same bit
// positions select channels for summation in the mask/enable register) and bits 2..0 set the mode.
// Code generation fills in the averaging and conversion time fields.
static constexpr uint16_t INA3221_CONFIG_RESET = 0x8000;
static constexpr uint16_t INA3221_CONFIG_CHANNEL1_ENABLE = 0x4000;
static constexpr uint16_t INA3221_CONFIG_CHANNEL_MASK = 0x7000;
static constexpr uint16_t INA3221_CONFIG_MODE_MASK = 0x0007;
static constexpr uint32_t READ_TIMEOUT_ID = 0;
// Addresses:
// A0 = GND -> 0x40
@@ -21,37 +39,38 @@ static const uint8_t INA3221_REGISTER_CHANNEL3_BUS_VOLTAGE = 0x06;
// A0 = SCL -> 0x43
void INA3221Component::setup() {
// Config Register
// 0bx000000000000000 << 15 RESET Bit (1 -> trigger reset)
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, 0x8000)) {
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, INA3221_CONFIG_RESET)) {
this->mark_failed();
return;
}
delay(1);
uint16_t config = 0;
// 0b0xxx000000000000 << 12 Channel Enables (1 -> ON)
if (this->channels_[0].exists()) {
config |= 0b0100000000000000;
}
if (this->channels_[1].exists()) {
config |= 0b0010000000000000;
}
if (this->channels_[2].exists()) {
config |= 0b0001000000000000;
}
// 0b0000xxx000000000 << 9 Averaging Mode (0 -> 1 sample, 111 -> 1024 samples)
config |= 0b0000000000000000;
// 0b0000000xxx000000 << 6 Bus Voltage Conversion time (100 -> 1.1ms, 111 -> 8.244 ms)
config |= 0b0000000111000000;
// 0b0000000000xxx000 << 3 Shunt Voltage Conversion time (same as above)
config |= 0b0000000000111000;
// 0b0000000000000xxx << 0 Operating mode (111 -> Shunt and bus, continuous)
config |= 0b0000000000000111;
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, config)) {
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, this->config_)) {
this->mark_failed();
return;
}
#ifdef USE_INA3221_ALERT_LIMITS
for (uint8_t i = 0; i < 3; i++) {
const INA3221Channel &channel = this->channels_[i];
if ((channel.critical_limit_ != 0 &&
!this->write_byte_16(INA3221_REGISTER_CHANNEL1_CRITICAL_ALERT + i, channel.critical_limit_)) ||
(channel.warning_limit_ != 0 &&
!this->write_byte_16(INA3221_REGISTER_CHANNEL1_WARNING_ALERT + i, channel.warning_limit_))) {
this->mark_failed();
return;
}
}
#endif
#ifdef USE_INA3221_SUMMATION
// Sum the shunt voltages of every enabled channel
if (this->sum_shunt_voltage_sensor_ != nullptr &&
!this->write_byte_16(INA3221_REGISTER_MASK_ENABLE, this->config_ & INA3221_CONFIG_CHANNEL_MASK)) {
this->mark_failed();
return;
}
#endif
}
void INA3221Component::dump_config() {
@@ -61,6 +80,10 @@ void INA3221Component::dump_config() {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
LOG_UPDATE_INTERVAL(this);
ESP_LOGCONFIG(TAG, " Config register: 0x%04X", this->config_);
if (this->single_shot_wait_ms_ != 0) {
ESP_LOGCONFIG(TAG, " Single-shot conversion: %u ms", this->single_shot_wait_ms_);
}
LOG_SENSOR(" ", "Bus Voltage #1", this->channels_[0].bus_voltage_sensor_);
LOG_SENSOR(" ", "Shunt Voltage #1", this->channels_[0].shunt_voltage_sensor_);
@@ -74,6 +97,11 @@ void INA3221Component::dump_config() {
LOG_SENSOR(" ", "Shunt Voltage #3", this->channels_[2].shunt_voltage_sensor_);
LOG_SENSOR(" ", "Current #3", this->channels_[2].current_sensor_);
LOG_SENSOR(" ", "Power #3", this->channels_[2].power_sensor_);
#ifdef USE_INA3221_SUMMATION
LOG_SENSOR(" ", "Sum Shunt Voltage", this->sum_shunt_voltage_sensor_);
LOG_SENSOR(" ", "Sum Current", this->sum_current_sensor_);
LOG_SENSOR(" ", "Sum Power", this->sum_power_sensor_);
#endif
}
inline uint8_t ina3221_bus_voltage_register(int channel) { return 0x02 + channel * 2; }
@@ -81,11 +109,36 @@ inline uint8_t ina3221_bus_voltage_register(int channel) { return 0x02 + channel
inline uint8_t ina3221_shunt_voltage_register(int channel) { return 0x01 + channel * 2; }
void INA3221Component::update() {
if (this->single_shot_wait_ms_ == 0) {
this->read_data_();
return;
}
// In single-shot mode, writing the configuration register starts one conversion of every channel
if (!this->write_byte_16(INA3221_REGISTER_CONFIG, this->config_)) {
this->status_set_warning();
return;
}
this->set_timeout(READ_TIMEOUT_ID, this->single_shot_wait_ms_, [this]() { this->read_data_(); });
}
void INA3221Component::read_data_() {
#ifdef USE_INA3221_SUMMATION
// The software sums need every enabled channel's readings, not only the ones with their own sensors
const bool sum_all = this->sum_current_sensor_ != nullptr || this->sum_power_sensor_ != nullptr;
float total_current_a = 0.0f;
float total_power_w = 0.0f;
#else
constexpr bool sum_all = false;
#endif
for (int i = 0; i < 3; i++) {
if ((this->config_ & (INA3221_CONFIG_CHANNEL1_ENABLE >> i)) == 0) {
continue;
}
INA3221Channel &channel = this->channels_[i];
float bus_voltage_v = NAN, current_a = NAN;
uint16_t raw;
if (channel.should_measure_bus_voltage()) {
if (sum_all || channel.should_measure_bus_voltage()) {
if (!this->read_byte_16(ina3221_bus_voltage_register(i), &raw)) {
this->status_set_warning();
return;
@@ -94,7 +147,7 @@ void INA3221Component::update() {
if (channel.bus_voltage_sensor_ != nullptr)
channel.bus_voltage_sensor_->publish_state(bus_voltage_v);
}
if (channel.should_measure_shunt_voltage()) {
if (sum_all || channel.should_measure_shunt_voltage()) {
if (!this->read_byte_16(ina3221_shunt_voltage_register(i), &raw)) {
this->status_set_warning();
return;
@@ -109,17 +162,42 @@ void INA3221Component::update() {
if (channel.power_sensor_ != nullptr) {
channel.power_sensor_->publish_state(bus_voltage_v * current_a);
}
#ifdef USE_INA3221_SUMMATION
if (sum_all) {
total_current_a += current_a;
total_power_w += bus_voltage_v * current_a;
}
#endif
}
#ifdef USE_INA3221_SUMMATION
if (this->sum_shunt_voltage_sensor_ != nullptr) {
uint16_t raw;
if (!this->read_byte_16(INA3221_REGISTER_SHUNT_VOLTAGE_SUM, &raw)) {
this->status_set_warning();
return;
}
// 40 uV per step, held in bits 15..1
this->sum_shunt_voltage_sensor_->publish_state(int16_t(raw) * 40.0f / 2.0f / 1000000.0f);
}
if (this->sum_current_sensor_ != nullptr) {
this->sum_current_sensor_->publish_state(total_current_a);
}
if (this->sum_power_sensor_ != nullptr) {
this->sum_power_sensor_->publish_state(total_power_w);
}
#endif
}
void INA3221Component::on_powerdown() {
// Mode 0 powers the chip down; setup() resets it on the next boot
this->write_byte_16(INA3221_REGISTER_CONFIG, static_cast<uint16_t>(this->config_ & ~INA3221_CONFIG_MODE_MASK));
}
void INA3221Component::set_shunt_resistance(int channel, float resistance_ohm) {
this->channels_[channel].shunt_resistance_ = resistance_ohm;
}
bool INA3221Component::INA3221Channel::exists() {
return this->bus_voltage_sensor_ != nullptr || this->shunt_voltage_sensor_ != nullptr ||
this->current_sensor_ != nullptr || this->power_sensor_ != nullptr;
}
bool INA3221Component::INA3221Channel::should_measure_shunt_voltage() {
return this->shunt_voltage_sensor_ != nullptr || this->current_sensor_ != nullptr || this->power_sensor_ != nullptr;
}
+24 -1
View File
@@ -7,10 +7,17 @@
namespace esphome::ina3221 {
class INA3221Component final : public PollingComponent, public i2c::I2CDevice {
#ifdef USE_INA3221_SUMMATION
SUB_SENSOR(sum_shunt_voltage)
SUB_SENSOR(sum_current)
SUB_SENSOR(sum_power)
#endif
public:
void setup() override;
void dump_config() override;
void update() override;
void on_powerdown() override;
void set_bus_voltage_sensor(int channel, sensor::Sensor *obj) { this->channels_[channel].bus_voltage_sensor_ = obj; }
void set_shunt_voltage_sensor(int channel, sensor::Sensor *obj) {
@@ -19,19 +26,35 @@ class INA3221Component final : public PollingComponent, public i2c::I2CDevice {
void set_current_sensor(int channel, sensor::Sensor *obj) { this->channels_[channel].current_sensor_ = obj; }
void set_power_sensor(int channel, sensor::Sensor *obj) { this->channels_[channel].power_sensor_ = obj; }
void set_shunt_resistance(int channel, float resistance_ohm);
/// Configuration register value built by code generation: channel enables, averaging, conversion times, mode
void set_config_register(uint16_t config) { this->config_ = config; }
/// Time one single-shot conversion of every enabled channel takes; zero means continuous mode
void set_single_shot_wait_ms(uint16_t wait_ms) { this->single_shot_wait_ms_ = wait_ms; }
#ifdef USE_INA3221_ALERT_LIMITS
void set_warning_limit(int channel, uint16_t reg) { this->channels_[channel].warning_limit_ = reg; }
void set_critical_limit(int channel, uint16_t reg) { this->channels_[channel].critical_limit_ = reg; }
#endif
protected:
void read_data_();
struct INA3221Channel {
float shunt_resistance_{0.1f};
sensor::Sensor *bus_voltage_sensor_{nullptr};
sensor::Sensor *shunt_voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_{nullptr};
sensor::Sensor *power_sensor_{nullptr};
#ifdef USE_INA3221_ALERT_LIMITS
// Alert limit register values; zero keeps the chip default, which never trips
uint16_t warning_limit_{0};
uint16_t critical_limit_{0};
#endif
bool exists();
bool should_measure_shunt_voltage();
bool should_measure_bus_voltage();
} channels_[3];
uint16_t config_{0};
uint16_t single_shot_wait_ms_{0};
};
} // namespace esphome::ina3221
+187 -37
View File
@@ -1,5 +1,8 @@
from typing import Any
import esphome.codegen as cg
from esphome.components import i2c, sensor
from esphome.components.const import CONF_ADC_AVERAGING, CONF_ADC_TIME
import esphome.config_validation as cv
from esphome.const import (
CONF_BUS_VOLTAGE,
@@ -8,6 +11,7 @@ from esphome.const import (
CONF_POWER,
CONF_SHUNT_RESISTANCE,
CONF_SHUNT_VOLTAGE,
CONF_UPDATE_INTERVAL,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_POWER,
DEVICE_CLASS_VOLTAGE,
@@ -23,69 +27,195 @@ DEPENDENCIES = ["i2c"]
CONF_CHANNEL_1 = "channel_1"
CONF_CHANNEL_2 = "channel_2"
CONF_CHANNEL_3 = "channel_3"
CONF_CONTINUOUS_MODE = "continuous_mode"
CONF_WARNING_CURRENT_LIMIT = "warning_current_limit"
CONF_CRITICAL_CURRENT_LIMIT = "critical_current_limit"
CONF_SUM_SHUNT_VOLTAGE = "sum_shunt_voltage"
CONF_SUM_CURRENT = "sum_current"
CONF_SUM_POWER = "sum_power"
CHANNELS = (CONF_CHANNEL_1, CONF_CHANNEL_2, CONF_CHANNEL_3)
# Configuration register layout: channel enables in bits 14..12, averaging in 11..9,
# bus conversion time in 8..6, shunt conversion time in 5..3, operating mode in 2..0
CHANNEL_ENABLE_BITS = (1 << 14, 1 << 13, 1 << 12)
ADC_AVERAGING_SHIFT = 9
ADC_TIME_BUS_SHIFT = 6
ADC_TIME_SHUNT_SHIFT = 3
MODE_SINGLE_SHOT = 0b011
MODE_CONTINUOUS = 0b111
# Register field value by sample count and by conversion time in microseconds
ADC_AVERAGING = {1: 0, 4: 1, 16: 2, 64: 3, 128: 4, 256: 5, 512: 6, 1024: 7}
ADC_TIMES_US = {140: 0, 204: 1, 332: 2, 588: 3, 1100: 4, 2116: 5, 4156: 6, 8244: 7}
# Alert limits are shunt voltages in 40 uV steps, held in bits 15..3
ALERT_LIMIT_LSB_V = 40e-6
ALERT_LIMIT_MAX_V = 0x0FFF * ALERT_LIMIT_LSB_V
# Headroom on top of the computed conversion time before the results are read
SINGLE_SHOT_MARGIN_MS = 5
ina3221_ns = cg.esphome_ns.namespace("ina3221")
INA3221Component = ina3221_ns.class_(
"INA3221Component", cg.PollingComponent, i2c.I2CDevice
)
INA3221_CHANNEL_SCHEMA = cv.Schema(
{
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_SHUNT_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=2,
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,
),
cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All(
cv.resistance, cv.Range(min=0.0, max=32.0)
),
}
VOLTAGE_SCHEMA = sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_VOLTAGE,
state_class=STATE_CLASS_MEASUREMENT,
)
CURRENT_SCHEMA = sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
accuracy_decimals=2,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
)
POWER_SCHEMA = sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
accuracy_decimals=2,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
)
CURRENT_LIMIT_SCHEMA = cv.All(cv.current, cv.Range(min=0.0, min_included=False))
def validate_adc_time(value: Any) -> int:
value = cv.positive_time_period_microseconds(value).total_microseconds
return cv.one_of(*ADC_TIMES_US, int=True)(value)
def validate_alert_limits(config: ConfigType) -> ConfigType:
shunt = config[CONF_SHUNT_RESISTANCE]
for key in (CONF_WARNING_CURRENT_LIMIT, CONF_CRITICAL_CURRENT_LIMIT):
if (limit := config.get(key)) is None:
continue
if limit * shunt > ALERT_LIMIT_MAX_V:
raise cv.Invalid(
f"{key} times shunt_resistance exceeds the "
f"{ALERT_LIMIT_MAX_V * 1000:.1f} mV alert range",
path=[key],
)
if alert_limit_register(limit, shunt) == 0:
raise cv.Invalid(
f"{key} times shunt_resistance is below the "
f"{ALERT_LIMIT_LSB_V * 1e6:.0f} µV alert resolution",
path=[key],
)
return config
INA3221_CHANNEL_SCHEMA = cv.All(
cv.Schema(
{
cv.Optional(CONF_BUS_VOLTAGE): VOLTAGE_SCHEMA,
cv.Optional(CONF_SHUNT_VOLTAGE): VOLTAGE_SCHEMA,
cv.Optional(CONF_CURRENT): CURRENT_SCHEMA,
cv.Optional(CONF_POWER): POWER_SCHEMA,
cv.Optional(CONF_SHUNT_RESISTANCE, default=0.1): cv.All(
cv.resistance, cv.Range(min=0.0, max=32.0)
),
cv.Optional(CONF_WARNING_CURRENT_LIMIT): CURRENT_LIMIT_SCHEMA,
cv.Optional(CONF_CRITICAL_CURRENT_LIMIT): CURRENT_LIMIT_SCHEMA,
}
),
cv.has_at_least_one_key(
CONF_BUS_VOLTAGE,
CONF_SHUNT_VOLTAGE,
CONF_CURRENT,
CONF_POWER,
CONF_WARNING_CURRENT_LIMIT,
CONF_CRITICAL_CURRENT_LIMIT,
),
validate_alert_limits,
)
CONFIG_SCHEMA = (
def adc_times_us(config: ConfigType) -> tuple[int, int]:
"""Return the bus and shunt conversion times in microseconds."""
adc_time = config[CONF_ADC_TIME]
if isinstance(adc_time, dict):
return adc_time[CONF_BUS_VOLTAGE], adc_time[CONF_SHUNT_VOLTAGE]
return adc_time, adc_time
def single_shot_wait_ms(config: ConfigType) -> int:
"""Time one conversion of every enabled channel takes, plus headroom."""
bus_us, shunt_us = adc_times_us(config)
channels = sum(1 for channel in CHANNELS if channel in config)
total_us = (bus_us + shunt_us) * config[CONF_ADC_AVERAGING] * channels
return -(-total_us // 1000) + SINGLE_SHOT_MARGIN_MS
def validate_single_shot_interval(config: ConfigType) -> ConfigType:
if config[CONF_CONTINUOUS_MODE]:
return config
wait_ms = single_shot_wait_ms(config)
if config[CONF_UPDATE_INTERVAL].total_milliseconds <= wait_ms:
raise cv.Invalid(
f"A single-shot conversion of all channels takes {wait_ms} ms, which does "
f"not fit in the update_interval; lower {CONF_ADC_AVERAGING} or "
f"{CONF_ADC_TIME}, or raise the interval",
path=[CONF_UPDATE_INTERVAL],
)
return config
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(INA3221Component),
cv.Optional(CONF_CHANNEL_1): INA3221_CHANNEL_SCHEMA,
cv.Optional(CONF_CHANNEL_2): INA3221_CHANNEL_SCHEMA,
cv.Optional(CONF_CHANNEL_3): INA3221_CHANNEL_SCHEMA,
cv.Optional(CONF_CONTINUOUS_MODE, default=True): cv.boolean,
cv.Optional(CONF_ADC_AVERAGING, default=1): cv.one_of(
*ADC_AVERAGING, int=True
),
cv.Optional(CONF_ADC_TIME, default="8244us"): cv.Any(
validate_adc_time,
cv.Schema(
{
cv.Required(CONF_BUS_VOLTAGE): validate_adc_time,
cv.Required(CONF_SHUNT_VOLTAGE): validate_adc_time,
}
),
),
cv.Optional(CONF_SUM_SHUNT_VOLTAGE): VOLTAGE_SCHEMA,
cv.Optional(CONF_SUM_CURRENT): CURRENT_SCHEMA,
cv.Optional(CONF_SUM_POWER): POWER_SCHEMA,
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x40))
.extend(i2c.i2c_device_schema(0x40)),
cv.has_at_least_one_key(*CHANNELS),
validate_single_shot_interval,
)
def alert_limit_register(current_a: float, shunt_ohm: float) -> int:
return round(current_a * shunt_ohm / ALERT_LIMIT_LSB_V) << 3
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
for i, channel in enumerate([CONF_CHANNEL_1, CONF_CHANNEL_2, CONF_CHANNEL_3]):
if channel not in config:
bus_us, shunt_us = adc_times_us(config)
register = (
ADC_AVERAGING[config[CONF_ADC_AVERAGING]] << ADC_AVERAGING_SHIFT
| ADC_TIMES_US[bus_us] << ADC_TIME_BUS_SHIFT
| ADC_TIMES_US[shunt_us] << ADC_TIME_SHUNT_SHIFT
| (MODE_CONTINUOUS if config[CONF_CONTINUOUS_MODE] else MODE_SINGLE_SHOT)
)
for i, channel in enumerate(CHANNELS):
if (conf := config.get(channel)) is None:
continue
conf = config[channel]
if CONF_SHUNT_RESISTANCE in conf:
cg.add(var.set_shunt_resistance(i, conf[CONF_SHUNT_RESISTANCE]))
register |= CHANNEL_ENABLE_BITS[i]
shunt = conf[CONF_SHUNT_RESISTANCE]
cg.add(var.set_shunt_resistance(i, shunt))
if CONF_BUS_VOLTAGE in conf:
sens = await sensor.new_sensor(conf[CONF_BUS_VOLTAGE])
cg.add(var.set_bus_voltage_sensor(i, sens))
@@ -98,3 +228,23 @@ async def to_code(config: ConfigType) -> None:
if CONF_POWER in conf:
sens = await sensor.new_sensor(conf[CONF_POWER])
cg.add(var.set_power_sensor(i, sens))
for key, setter in (
(CONF_WARNING_CURRENT_LIMIT, var.set_warning_limit),
(CONF_CRITICAL_CURRENT_LIMIT, var.set_critical_limit),
):
if (limit := conf.get(key)) is not None:
cg.add_define("USE_INA3221_ALERT_LIMITS")
cg.add(setter(i, alert_limit_register(limit, shunt)))
cg.add(var.set_config_register(register))
if not config[CONF_CONTINUOUS_MODE]:
cg.add(var.set_single_shot_wait_ms(single_shot_wait_ms(config)))
if any(
key in config
for key in (CONF_SUM_SHUNT_VOLTAGE, CONF_SUM_CURRENT, CONF_SUM_POWER)
):
cg.add_define("USE_INA3221_SUMMATION")
sensors = sensor.sub_sensors(config)
await sensors(CONF_SUM_SHUNT_VOLTAGE, var.set_sum_shunt_voltage_sensor)
await sensors(CONF_SUM_CURRENT, var.set_sum_current_sensor)
await sensors(CONF_SUM_POWER, var.set_sum_power_sensor)
+2
View File
@@ -91,6 +91,8 @@
#define USE_I2S_AUDIO_SPDIF_MODE
#define USE_IMAGE
#define USE_IMPROV_BLE_STATE_CALLBACK
#define USE_INA3221_ALERT_LIMITS
#define USE_INA3221_SUMMATION
#define USE_INFRARED
#define USE_IR_RF
#define USE_IR_RF_TRANSMIT_COMPLETE
+29
View File
@@ -13,3 +13,32 @@ sensor:
shunt_voltage:
name: INA3221 Channel 1 Shunt Voltage
update_interval: 15s
- platform: ina3221
i2c_id: i2c_bus
address: 0x41
continuous_mode: false
adc_averaging: 4
adc_time:
bus_voltage: 2116us
shunt_voltage: 1.1ms
channel_1:
shunt_resistance: 0.05 ohm
current:
name: INA3221 B Channel 1 Current
warning_current_limit: 1A
critical_current_limit: 2A
channel_2:
shunt_resistance: 0.05 ohm
bus_voltage:
name: INA3221 B Channel 2 Bus Voltage
channel_3:
shunt_resistance: 0.05 ohm
power:
name: INA3221 B Channel 3 Power
sum_shunt_voltage:
name: INA3221 B Sum Shunt Voltage
sum_current:
name: INA3221 B Sum Current
sum_power:
name: INA3221 B Sum Power
update_interval: 15s
+1 -2
View File
@@ -1,4 +1,3 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
<<: !include common.yaml
ina3221: !include common.yaml
@@ -1,4 +1,3 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml
<<: !include common.yaml
ina3221: !include common.yaml
@@ -1,4 +1,3 @@
packages:
i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml
<<: !include common.yaml
ina3221: !include common.yaml