[cse7761] Add current_input option for current transformer boards such as the Sonoff POW CT (#7836)

Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
mick96
2026-10-11 17:00:16 -10:00
committed by GitHub
co-authored by Clyde Stubbs pre-commit-ci-lite[bot] Jesse Hills J. Nick Koston J. Nick Koston
parent 6095d9d610
commit d19bb7f4be
8 changed files with 64 additions and 14 deletions
+22 -7
View File
@@ -18,6 +18,14 @@ static constexpr int CSE7761_UREF = 42563; // RmsUc
static constexpr int CSE7761_IREF = 52241; // RmsIAC
static constexpr int CSE7761_PREF = 44513; // PowerPAC
// Empirical Sonoff POW CT factor taken from Tasmota
static constexpr uint32_t CURRENT_TRANSFORMER_COEFFICIENT_SCALE = 5;
// PGA 16x on both current channels
static constexpr uint16_t SYSCON_SHUNT = 0xFF04;
// All PGAs 1x, ADC2ON
static constexpr uint16_t SYSCON_CURRENT_TRANSFORMER = 0xFE00;
// System clock (3.579545MHz) / 8, divided by Ufreq gives the line frequency in Hz
static constexpr float CSE7761_UFREQ_CLOCK = 3579545.0f / 8.0f;
@@ -68,6 +76,8 @@ void CSE7761Component::dump_config() {
if (this->is_failed()) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
}
ESP_LOGCONFIG(TAG, " Current input: %s",
LOG_STR_ARG(this->is_current_transformer_() ? LOG_STR("current transformer") : LOG_STR("shunt")));
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "Voltage", this->voltage_sensor_);
LOG_SENSOR(" ", "Current 1", this->current_sensor_1_);
@@ -93,7 +103,7 @@ void CSE7761Component::write_(uint8_t reg, uint16_t data) {
buffer[1] = reg;
uint32_t len = 2;
if (data) {
if (data < 0xFF) {
if (data <= 0xFF) {
buffer[2] = data & 0xFF;
len = 3;
} else {
@@ -158,16 +168,17 @@ uint32_t CSE7761Component::read_(uint8_t reg, uint8_t size) {
}
uint32_t CSE7761Component::coefficient_by_unit_(uint32_t unit) {
const uint32_t scale = this->is_current_transformer_() ? CURRENT_TRANSFORMER_COEFFICIENT_SCALE : 1;
uint32_t coeff = 0;
switch (unit) {
case RMS_UC:
coeff = this->data_.coefficient[RMS_UC];
return coeff ? 0x400000 * 100 / coeff : 0;
case RMS_IAC:
coeff = this->data_.coefficient[RMS_IAC];
coeff = this->data_.coefficient[RMS_IAC] * scale;
return coeff ? (0x800000 * 100 / coeff) * 10 : 0; // Stay within 32 bits
case POWER_PAC:
coeff = this->data_.coefficient[POWER_PAC];
coeff = this->data_.coefficient[POWER_PAC] * scale;
return coeff ? 0x80000000 / coeff : 0;
}
return 0;
@@ -195,9 +206,11 @@ bool CSE7761Component::chip_init_() {
if (!this->read_(CSE7761_REG_HFCONST, 2, &hf_const)) {
ESP_LOGW(TAG, "HFConst read failed, energy unavailable");
}
// The pulse counters follow the raw power, so they need the same front end factor as power
const float input_scale = this->is_current_transformer_() ? CURRENT_TRANSFORMER_COEFFICIENT_SCALE : 1.0f;
for (uint8_t channel = 0; channel < 2; channel++) {
uint32_t scale = this->data_.coefficient[ENERGY_AC + channel] * hf_const;
this->energy_[channel].wh_per_pulse = static_cast<float>(scale) * CSE7761_ENERGY_WH_SCALE;
this->energy_[channel].wh_per_pulse = static_cast<float>(scale) * CSE7761_ENERGY_WH_SCALE * input_scale;
}
}
@@ -205,7 +218,8 @@ bool CSE7761Component::chip_init_() {
uint8_t sys_status = this->read_(CSE7761_REG_SYSSTATUS, 1);
if (sys_status & 0x10) { // Write enable to protected registers (WREN)
this->write_(CSE7761_REG_SYSCON | 0x80, 0xFF04);
this->write_(CSE7761_REG_SYSCON | 0x80,
this->is_current_transformer_() ? SYSCON_CURRENT_TRANSFORMER : SYSCON_SHUNT);
this->write_(CSE7761_REG_EMUCON | 0x80, 0x1183);
// WaveEN|ZxEN, needed for Ufreq
this->write_(CSE7761_REG_EMUCON2 | 0x80, this->frequency_sensor_ != nullptr ? 0x0FE5 : 0x0FC1);
@@ -226,14 +240,15 @@ void CSE7761Component::get_data_() {
uint32_t value = this->read_(CSE7761_REG_RMSU, 3);
this->data_.voltage_rms = (value >= 0x800000) ? 0 : value;
// No load threshold of 10mA with a shunt; the raw value stands for 5 times more with a current transformer
value = this->read_(CSE7761_REG_RMSIA, 3);
this->data_.current_rms[0] = ((value >= 0x800000) || (value < 1600)) ? 0 : value; // No load threshold of 10mA
this->data_.current_rms[0] = ((value >= 0x800000) || (value < 1600)) ? 0 : value;
value = this->read_(CSE7761_REG_POWERPA, 4);
// PowerPA is two's complement signed 32-bit per datasheet
this->data_.active_power[0] = (0 == this->data_.current_rms[0]) ? 0 : static_cast<int32_t>(value);
value = this->read_(CSE7761_REG_RMSIB, 3);
this->data_.current_rms[1] = ((value >= 0x800000) || (value < 1600)) ? 0 : value; // No load threshold of 10mA
this->data_.current_rms[1] = ((value >= 0x800000) || (value < 1600)) ? 0 : value;
value = this->read_(CSE7761_REG_POWERPB, 4);
// PowerPB is two's complement signed 32-bit per datasheet
this->data_.active_power[1] = (0 == this->data_.current_rms[1]) ? 0 : static_cast<int32_t>(value);
+10
View File
@@ -21,9 +21,15 @@ struct CSE7761EnergyChannel {
float wh_per_pulse{0.0f};
};
enum class CSE7761CurrentInput : uint8_t {
CSE7761_CURRENT_INPUT_SHUNT,
CSE7761_CURRENT_INPUT_CURRENT_TRANSFORMER,
};
/// This class implements support for the CSE7761 UART power sensor.
class CSE7761Component final : public PollingComponent, public uart::UARTDevice {
public:
explicit CSE7761Component(CSE7761CurrentInput current_input) : current_input_(current_input) {}
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
void set_frequency_sensor(sensor::Sensor *frequency_sensor) { frequency_sensor_ = frequency_sensor; }
void set_power_factor_1_sensor(sensor::Sensor *power_factor_sensor_1) {
@@ -51,7 +57,11 @@ class CSE7761Component final : public PollingComponent, public uart::UARTDevice
sensor::Sensor *energy_sensors_[2]{nullptr, nullptr};
CSE7761DataStruct data_;
CSE7761EnergyChannel energy_[2];
const CSE7761CurrentInput current_input_;
bool is_current_transformer_() const {
return this->current_input_ == CSE7761CurrentInput::CSE7761_CURRENT_INPUT_CURRENT_TRANSFORMER;
}
void write_(uint8_t reg, uint16_t data);
bool read_once_(uint8_t reg, uint8_t size, uint32_t *value);
bool read_(uint8_t reg, uint8_t size, uint32_t *value);
+11 -1
View File
@@ -36,11 +36,21 @@ CONF_ACTIVE_POWER_2 = "active_power_2"
CONF_ENERGY_1 = "energy_1"
CONF_ENERGY_2 = "energy_2"
CONF_POWER_FACTOR_1 = "power_factor_1"
CONF_CURRENT_INPUT = "current_input"
CSE7761CurrentInput = cse7761_ns.enum("CSE7761CurrentInput", is_class=True)
CURRENT_INPUTS = {
"shunt": CSE7761CurrentInput.CSE7761_CURRENT_INPUT_SHUNT,
"current_transformer": CSE7761CurrentInput.CSE7761_CURRENT_INPUT_CURRENT_TRANSFORMER,
}
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(CSE7761Component),
cv.Optional(CONF_CURRENT_INPUT, default="shunt"): cv.enum(
CURRENT_INPUTS, lower=True
),
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
unit_of_measurement=UNIT_VOLT,
accuracy_decimals=1,
@@ -112,7 +122,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
var = cg.new_Pvariable(config[CONF_ID], config[CONF_CURRENT_INPUT])
await cg.register_component(var, config)
await uart.register_uart_device(var, config)
@@ -0,0 +1,11 @@
sensor:
- platform: cse7761
current_input: current_transformer
voltage:
name: CSE7761 CT Voltage
current_1:
name: CSE7761 CT Current 1
active_power_1:
name: CSE7761 CT Active Power 1
energy_1:
name: CSE7761 CT Energy 1
+1 -2
View File
@@ -4,5 +4,4 @@ substitutions:
packages:
uart_38400_even: !include ../../test_build_components/common/uart_38400_even/esp32-idf.yaml
<<: !include common.yaml
cse7761: !include common.yaml
@@ -4,5 +4,4 @@ substitutions:
packages:
uart_38400_even: !include ../../test_build_components/common/uart_38400_even/esp8266-ard.yaml
<<: !include common.yaml
cse7761: !include common.yaml
@@ -4,5 +4,4 @@ substitutions:
packages:
uart_38400_even: !include ../../test_build_components/common/uart_38400_even/rp2040-ard.yaml
<<: !include common.yaml
cse7761: !include common.yaml
@@ -0,0 +1,7 @@
substitutions:
tx_pin: GPIO12
rx_pin: GPIO14
packages:
uart_38400_even: !include ../../test_build_components/common/uart_38400_even/esp32-idf.yaml
cse7761: !include common-current-transformer.yaml