diff --git a/components/ATM90E36/atm90e36.cpp b/components/ATM90E36/atm90e36.cpp index 537c8e7..87fe196 100644 --- a/components/ATM90E36/atm90e36.cpp +++ b/components/ATM90E36/atm90e36.cpp @@ -43,8 +43,8 @@ void ATM90E36Component::loop() { if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) this->phase_[phase].harmonic_active_power_ = this->get_phase_harmonic_active_power_(phase); - if (this->phase_[phase].peak_current_sensor_ != nullptr) - this->phase_[phase].peak_current_ = this->get_phase_peak_current_(phase); +// if (this->phase_[phase].peak_current_sensor_ != nullptr) +// this->phase_[phase].peak_current_ = this->get_phase_peak_current_(phase); // After the local store is collected we can publish them trusting they are within +-1 hardware sampling if (this->phase_[phase].voltage_sensor_ != nullptr) @@ -83,9 +83,29 @@ void ATM90E36Component::loop() { this->get_local_phase_harmonic_active_power_(phase)); } - if (this->phase_[phase].peak_current_sensor_ != nullptr) - this->phase_[phase].peak_current_sensor_->publish_state(this->get_local_phase_peak_current_(phase)); +// if (this->phase_[phase].peak_current_sensor_ != nullptr) +// this->phase_[phase].peak_current_sensor_->publish_state(this->get_local_phase_peak_current_(phase)); } + // THD values + if (this->thd_voltage_a_sensor_ != nullptr) { + this->thd_voltage_a_sensor_->publish_state(this->get_thd_voltage_a()); + } + if (this->thd_current_a_sensor_ != nullptr) { + this->thd_current_a_sensor_->publish_state(this->get_thd_current_a()); + } + if (this->thd_voltage_b_sensor_ != nullptr) { + this->thd_voltage_b_sensor_->publish_state(this->get_thd_voltage_b()); + } + if (this->thd_current_b_sensor_ != nullptr) { + this->thd_current_b_sensor_->publish_state(this->get_thd_current_b()); + } + if (this->thd_voltage_c_sensor_ != nullptr) { + this->thd_voltage_c_sensor_->publish_state(this->get_thd_voltage_c()); + } + if (this->thd_current_c_sensor_ != nullptr) { + this->thd_current_c_sensor_->publish_state(this->get_thd_current_c()); + } + if (this->freq_sensor_ != nullptr) this->freq_sensor_->publish_state(this->get_frequency_()); @@ -214,14 +234,18 @@ void ATM90E36Component::dump_config() { LOG_SENSOR(" ", "Reactive Power A", this->phase_[PHASEA].reactive_power_sensor_); LOG_SENSOR(" ", "Apparent Power A", this->phase_[PHASEA].apparent_power_sensor_); LOG_SENSOR(" ", "PF A", this->phase_[PHASEA].power_factor_sensor_); + LOG_SENSOR(" ", "THD Voltage A", this->thd_voltage_a_sensor_); + LOG_SENSOR(" ", "THD Current A", this->thd_current_a_sensor_); LOG_SENSOR(" ", "Active Forward Energy A", this->phase_[PHASEA].forward_active_energy_sensor_); LOG_SENSOR(" ", "Active Reverse Energy A", this->phase_[PHASEA].reverse_active_energy_sensor_); LOG_SENSOR(" ", "Harmonic Power A", this->phase_[PHASEA].harmonic_active_power_sensor_); LOG_SENSOR(" ", "Phase Angle A", this->phase_[PHASEA].phase_angle_sensor_); - LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEA].peak_current_sensor_); +// LOG_SENSOR(" ", "Peak Current A", this->phase_[PHASEA].peak_current_sensor_); LOG_SENSOR(" ", "Voltage B", this->phase_[PHASEB].voltage_sensor_); LOG_SENSOR(" ", "Current B", this->phase_[PHASEB].current_sensor_); LOG_SENSOR(" ", "Power B", this->phase_[PHASEB].power_sensor_); + LOG_SENSOR(" ", "THD Voltage B", this->thd_voltage_b_sensor_); + LOG_SENSOR(" ", "THD Current B", this->thd_current_b_sensor_); LOG_SENSOR(" ", "Reactive Power B", this->phase_[PHASEB].reactive_power_sensor_); LOG_SENSOR(" ", "Apparent Power B", this->phase_[PHASEB].apparent_power_sensor_); LOG_SENSOR(" ", "PF B", this->phase_[PHASEB].power_factor_sensor_); @@ -229,18 +253,20 @@ void ATM90E36Component::dump_config() { LOG_SENSOR(" ", "Active Reverse Energy B", this->phase_[PHASEB].reverse_active_energy_sensor_); LOG_SENSOR(" ", "Harmonic Power B", this->phase_[PHASEB].harmonic_active_power_sensor_); LOG_SENSOR(" ", "Phase Angle B", this->phase_[PHASEB].phase_angle_sensor_); - LOG_SENSOR(" ", "Peak Current B", this->phase_[PHASEB].peak_current_sensor_); +// LOG_SENSOR(" ", "Peak Current B", this->phase_[PHASEB].peak_current_sensor_); LOG_SENSOR(" ", "Voltage C", this->phase_[PHASEC].voltage_sensor_); LOG_SENSOR(" ", "Current C", this->phase_[PHASEC].current_sensor_); LOG_SENSOR(" ", "Power C", this->phase_[PHASEC].power_sensor_); LOG_SENSOR(" ", "Reactive Power C", this->phase_[PHASEC].reactive_power_sensor_); LOG_SENSOR(" ", "Apparent Power C", this->phase_[PHASEC].apparent_power_sensor_); LOG_SENSOR(" ", "PF C", this->phase_[PHASEC].power_factor_sensor_); + LOG_SENSOR(" ", "THD Voltage C", this->thd_voltage_c_sensor_); + LOG_SENSOR(" ", "THD Current C", this->thd_current_c_sensor_); LOG_SENSOR(" ", "Active Forward Energy C", this->phase_[PHASEC].forward_active_energy_sensor_); LOG_SENSOR(" ", "Active Reverse Energy C", this->phase_[PHASEC].reverse_active_energy_sensor_); LOG_SENSOR(" ", "Harmonic Power C", this->phase_[PHASEC].harmonic_active_power_sensor_); LOG_SENSOR(" ", "Phase Angle C", this->phase_[PHASEC].phase_angle_sensor_); - LOG_SENSOR(" ", "Peak Current C", this->phase_[PHASEC].peak_current_sensor_); +// LOG_SENSOR(" ", "Peak Current C", this->phase_[PHASEC].peak_current_sensor_); LOG_SENSOR(" ", "Frequency", this->freq_sensor_); LOG_SENSOR(" ", "Chip Temp", this->chip_temperature_sensor_); } @@ -292,6 +318,36 @@ float ATM90E36Component::get_local_phase_apparent_power_(uint8_t phase) { return float ATM90E36Component::get_local_phase_power_factor_(uint8_t phase) { return this->phase_[phase].power_factor_; } +float ATM90E36Component::get_thd_voltage_a() { + uint16_t val = this->read16_(ATM90E36_REGISTER_THDNUA); + return (float)val / 100.0; // Adjust division scale based on your calibration constraints +} + +float ATM90E36Component::get_thd_current_a() { + uint16_t val = this->read16_(ATM90E36_REGISTER_THDNIA); + return (float)val / 100.0; +} + +float ATM90E36Component::get_thd_voltage_b() { + uint16_t val = this->read16_(ATM90E36_REGISTER_THDNUB); + return (float)val / 100.0; // Adjust division scale based on your calibration constraints +} + +float ATM90E36Component::get_thd_current_b() { + uint16_t val = this->read16_(ATM90E36_REGISTER_THDNIB); + return (float)val / 100.0; +} + +float ATM90E36Component::get_thd_voltage_c() { + uint16_t val = this->read16_(ATM90E36_REGISTER_THDNUC); + return (float)val / 100.0; // Adjust division scale based on your calibration constraints +} + +float ATM90E36Component::get_thd_current_c() { + uint16_t val = this->read16_(ATM90E36_REGISTER_THDNIC); + return (float)val / 100.0; +} + float ATM90E36Component::get_local_phase_forward_active_energy_(uint8_t phase) { return this->phase_[phase].forward_active_energy_; } @@ -306,7 +362,7 @@ float ATM90E36Component::get_local_phase_harmonic_active_power_(uint8_t phase) { return this->phase_[phase].harmonic_active_power_; } -float ATM90E36Component::get_local_phase_peak_current_(uint8_t phase) { return this->phase_[phase].peak_current_; } +//float ATM90E36Component::get_local_phase_peak_current_(uint8_t phase) { return this->phase_[phase].peak_current_; } float ATM90E36Component::get_phase_voltage_(uint8_t phase) { uint16_t voltage = this->read16_(ATM90E36_REGISTER_URMS + phase); @@ -411,13 +467,13 @@ float ATM90E36Component::get_phase_angle_(uint8_t phase) { return (val > 180) ? (float) (val - 360.0f) : (float) val; } -float ATM90E36Component::get_phase_peak_current_(uint8_t phase) { - int16_t val = (float) this->read16_(ATM90E36_REGISTER_IPEAK + phase); - if (!this->peak_current_signed_) - val = std::abs(val); - // phase register * phase current gain value / 1000 * 2^13 - return (val * this->phase_[phase].ct_gain_ / 8192000.0); -} +//float ATM90E36Component::get_phase_peak_current_(uint8_t phase) { +// int16_t val = (float) this->read16_(ATM90E36_REGISTER_IPEAK + phase); +// if (!this->peak_current_signed_) +// val = std::abs(val); +// // phase register * phase current gain value / 1000 * 2^13 +// return (val * this->phase_[phase].ct_gain_ / 8192000.0); +//} float ATM90E36Component::get_frequency_() { const uint16_t freq = this->read16_(ATM90E36_REGISTER_FREQ); diff --git a/components/ATM90E36/atm90e36.h b/components/ATM90E36/atm90e36.h index c77f046..681de69 100644 --- a/components/ATM90E36/atm90e36.h +++ b/components/ATM90E36/atm90e36.h @@ -19,7 +19,7 @@ class ATM90E36Component : public PollingComponent, static const uint8_t PHASEA = 0; static const uint8_t PHASEB = 1; static const uint8_t PHASEC = 2; - const char *phase_labels[3] = {"A", "B", "C"}; + const char *phase_labels[3] = {"A", "B", "C"}; void loop() override; void setup() override; void dump_config() override; @@ -30,6 +30,24 @@ class ATM90E36Component : public PollingComponent, void set_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].power_sensor_ = obj; } void set_reactive_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].reactive_power_sensor_ = obj; } void set_apparent_power_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].apparent_power_sensor_ = obj; } + void set_thd_voltage_a_sensor(sensor::Sensor *thd_voltage_a_sensor) { + thd_voltage_a_sensor_ = thd_voltage_a_sensor; + } + void set_thd_current_a_sensor(sensor::Sensor *thd_current_a_sensor) { + thd_current_a_sensor_ = thd_current_a_sensor; + } + void set_thd_voltage_b_sensor(sensor::Sensor *thd_voltage_b_sensor) { + thd_voltage_b_sensor_ = thd_voltage_b_sensor; + } + void set_thd_current_b_sensor(sensor::Sensor *thd_current_b_sensor) { + thd_current_b_sensor_ = thd_current_b_sensor; + } + void set_thd_voltage_c_sensor(sensor::Sensor *thd_voltage_c_sensor) { + thd_voltage_c_sensor_ = thd_voltage_c_sensor; + } + void set_thd_current_c_sensor(sensor::Sensor *thd_current_c_sensor) { + thd_current_c_sensor_ = thd_current_c_sensor; + } void set_forward_active_energy_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].forward_active_energy_sensor_ = obj; } @@ -120,6 +138,12 @@ class ATM90E36Component : public PollingComponent, float get_phase_angle_(uint8_t phase); float get_phase_harmonic_active_power_(uint8_t phase); float get_phase_peak_current_(uint8_t phase); + float get_thd_voltage_a(); + float get_thd_current_a(); + float get_thd_voltage_b(); + float get_thd_current_b(); + float get_thd_voltage_c(); + float get_thd_current_c(); float get_frequency_(); float get_chip_temperature_(); bool get_publish_interval_flag_() { return publish_interval_flag_; }; @@ -169,7 +193,7 @@ class ATM90E36Component : public PollingComponent, uint32_t cumulative_forward_active_energy_{0}; uint32_t cumulative_reverse_active_energy_{0}; } phase_[3]; - + union SysStatus0 { uint16_t data; struct { @@ -191,7 +215,7 @@ class ATM90E36Component : public PollingComponent, bool b15 : 1; } bits; }; - + union SysStatus1 { uint16_t data; struct { @@ -220,6 +244,12 @@ class ATM90E36Component : public PollingComponent, std::string cs_summary_; sensor::Sensor *freq_sensor_{nullptr}; + sensor::Sensor *thd_voltage_a_sensor_{nullptr}; + sensor::Sensor *thd_current_a_sensor_{nullptr}; + sensor::Sensor *thd_voltage_b_sensor_{nullptr}; + sensor::Sensor *thd_current_b_sensor_{nullptr}; + sensor::Sensor *thd_voltage_c_sensor_{nullptr}; + sensor::Sensor *thd_current_c_sensor_{nullptr}; #ifdef USE_TEXT_SENSOR text_sensor::TextSensor *phase_status_text_sensor_{nullptr}; text_sensor::TextSensor *freq_status_text_sensor_{nullptr}; diff --git a/components/ATM90E36/atm90e36_reg.h b/components/ATM90E36/atm90e36_reg.h index 7626074..71e1cf4 100644 --- a/components/ATM90E36/atm90e36_reg.h +++ b/components/ATM90E36/atm90e36_reg.h @@ -222,14 +222,20 @@ static const uint16_t ATM90E36_REGISTER_IRMSBLSB = 0xEE; // Lower Word (B RMS static const uint16_t ATM90E36_REGISTER_IRMSCLSB = 0xEF; // Lower Word (C RMS Current) /* THD, FREQUENCY, ANGLE & TEMPTEMP REGISTERS*/ -static const uint16_t ATM90E36_REGISTER_UPEAKA = 0xF1; // A Voltage Peak -static const uint16_t ATM90E36_REGISTER_UPEAKB = 0xF2; // B Voltage Peak -static const uint16_t ATM90E36_REGISTER_UPEAKC = 0xF3; // C Voltage Peak +static const uint16_t ATM90E36_REGISTER_THDNUA = 0xF1; // Phase A Voltage THD +static const uint16_t ATM90E36_REGISTER_THDNUB = 0xF2; // Phase B Voltage THD +static const uint16_t ATM90E36_REGISTER_THDNUC = 0xF3; // Phase C Voltage THD +static const uint16_t ATM90E36_REGISTER_THDNIA = 0xF5; // Phase A Current THD +static const uint16_t ATM90E36_REGISTER_THDNIB = 0xF6; // Phase B Current THD +static const uint16_t ATM90E36_REGISTER_THDNIC = 0xF7; // Phase C Current THD +//static const uint16_t ATM90E36_REGISTER_UPEAKA = 0xF1; // A Voltage Peak +//static const uint16_t ATM90E36_REGISTER_UPEAKB = 0xF2; // B Voltage Peak +//static const uint16_t ATM90E36_REGISTER_UPEAKC = 0xF3; // C Voltage Peak //////////////// 0xF4 // Reserved Register -static const uint16_t ATM90E36_REGISTER_IPEAK = 0xF5; // Peak Current Reg Base -static const uint16_t ATM90E36_REGISTER_IPEAKA = 0xF5; // A Current Peak -static const uint16_t ATM90E36_REGISTER_IPEAKB = 0xF6; // B Current Peak -static const uint16_t ATM90E36_REGISTER_IPEAKC = 0xF7; // C Current Peak +//static const uint16_t ATM90E36_REGISTER_IPEAK = 0xF5; // Peak Current Reg Base +//static const uint16_t ATM90E36_REGISTER_IPEAKA = 0xF5; // A Current Peak +//static const uint16_t ATM90E36_REGISTER_IPEAKB = 0xF6; // B Current Peak +//static const uint16_t ATM90E36_REGISTER_IPEAKC = 0xF7; // C Current Peak static const uint16_t ATM90E36_REGISTER_FREQ = 0xF8; // Frequency static const uint16_t ATM90E36_REGISTER_PANGLE = 0xF9; // Mean Phase Angle Reg Base static const uint16_t ATM90E36_REGISTER_PANGLEA = 0xF9; // A Mean Phase Angle diff --git a/components/ATM90E36/sensor.py b/components/ATM90E36/sensor.py index aab1ddb..98c9051 100644 --- a/components/ATM90E36/sensor.py +++ b/components/ATM90E36/sensor.py @@ -27,6 +27,7 @@ from esphome.const import ( DEVICE_CLASS_VOLTAGE, ENTITY_CATEGORY_DIAGNOSTIC, ICON_CURRENT_AC, + ICON_FLASH, ICON_LIGHTBULB, STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING, @@ -34,6 +35,7 @@ from esphome.const import ( UNIT_CELSIUS, UNIT_DEGREES, UNIT_HERTZ, + UNIT_PERCENT, UNIT_VOLT, UNIT_VOLT_AMPS, UNIT_VOLT_AMPS_REACTIVE, @@ -55,11 +57,17 @@ CONF_OFFSET_CURRENT = "offset_current" CONF_OFFSET_ACTIVE_POWER = "offset_active_power" CONF_OFFSET_REACTIVE_POWER = "offset_reactive_power" CONF_HARMONIC_POWER = "harmonic_power" -CONF_PEAK_CURRENT = "peak_current" -CONF_PEAK_CURRENT_SIGNED = "peak_current_signed" +#CONF_PEAK_CURRENT = "peak_current" +#CONF_PEAK_CURRENT_SIGNED = "peak_current_signed" CONF_ENABLE_OFFSET_CALIBRATION = "enable_offset_calibration" CONF_ENABLE_GAIN_CALIBRATION = "enable_gain_calibration" CONF_PHASE_STATUS = "phase_status" +CONF_THD_VOLTAGE_A = "thd_voltage_a" +CONF_THD_CURRENT_A = "thd_current_a" +CONF_THD_VOLTAGE_B = "thd_voltage_b" +CONF_THD_CURRENT_B = "thd_current_b" +CONF_THD_VOLTAGE_C = "thd_voltage_c" +CONF_THD_CURRENT_C = "thd_current_c" CONF_FREQUENCY_STATUS = "frequency_status" UNIT_DEG = "degrees" LINE_FREQS = { @@ -155,12 +163,12 @@ ATM90E36_PHASE_SCHEMA = cv.Schema( device_class=DEVICE_CLASS_POWER, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Optional(CONF_PEAK_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_PEAK_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_GAIN_VOLTAGE, default=7305): cv.uint16_t, cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t, cv.Optional(CONF_OFFSET_VOLTAGE, default=0): cv.int_, @@ -197,9 +205,39 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_GAIN_CURRENT, default="1X"): cv.enum(CURRENT_GAINS, upper=True), cv.Optional(CONF_GAIN_VOLTAGE, default="1X"): cv.enum(VOLTAGE_GAINS, upper=True), cv.Optional(CONF_GAIN_DPGA, default="1X"): cv.enum(DPGA_GAINS, upper=True), - cv.Optional(CONF_PEAK_CURRENT_SIGNED, default=False): cv.boolean, +# cv.Optional(CONF_PEAK_CURRENT_SIGNED, default=False): cv.boolean, cv.Optional(CONF_ENABLE_OFFSET_CALIBRATION, default=False): cv.boolean, cv.Optional(CONF_ENABLE_GAIN_CALIBRATION, default=False): cv.boolean, + cv.Optional(CONF_THD_VOLTAGE_A): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon="mdi:sine-wave", + accuracy_decimals=2, + ), + cv.Optional(CONF_THD_CURRENT_A): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon="mdi:sine-wave", + accuracy_decimals=2, + ), + cv.Optional(CONF_THD_VOLTAGE_B): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon="mdi:sine-wave", + accuracy_decimals=2, + ), + cv.Optional(CONF_THD_CURRENT_B): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon="mdi:sine-wave", + accuracy_decimals=2, + ), + cv.Optional(CONF_THD_VOLTAGE_C): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon="mdi:sine-wave", + accuracy_decimals=2, + ), + cv.Optional(CONF_THD_CURRENT_C): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + icon="mdi:sine-wave", + accuracy_decimals=2, + ), } ) .extend(cv.polling_component_schema("60s")) @@ -248,9 +286,9 @@ async def to_code(config): if harmonic_active_power_config := conf.get(CONF_HARMONIC_POWER): sens = await sensor.new_sensor(harmonic_active_power_config) cg.add(var.set_harmonic_active_power_sensor(i, sens)) - if peak_current_config := conf.get(CONF_PEAK_CURRENT): - sens = await sensor.new_sensor(peak_current_config) - cg.add(var.set_peak_current_sensor(i, sens)) +# if peak_current_config := conf.get(CONF_PEAK_CURRENT): +# sens = await sensor.new_sensor(peak_current_config) +# cg.add(var.set_peak_current_sensor(i, sens)) if frequency_config := config.get(CONF_FREQUENCY): sens = await sensor.new_sensor(frequency_config) cg.add(var.set_freq_sensor(sens)) @@ -262,4 +300,22 @@ async def to_code(config): cg.add(var.set_pga_current(config[CONF_GAIN_CURRENT])) cg.add(var.set_pga_voltage(config[CONF_GAIN_VOLTAGE])) cg.add(var.set_dpga_gain(config[CONF_GAIN_DPGA])) - cg.add(var.set_peak_current_signed(config[CONF_PEAK_CURRENT_SIGNED])) +# cg.add(var.set_peak_current_signed(config[CONF_PEAK_CURRENT_SIGNED])) + if CONF_THD_VOLTAGE_A in config: + sens = await sensor.new_sensor(config[CONF_THD_VOLTAGE_A]) + cg.add(var.set_thd_voltage_a_sensor(sens)) + if CONF_THD_CURRENT_A in config: + sens = await sensor.new_sensor(config[CONF_THD_CURRENT_A]) + cg.add(var.set_thd_current_a_sensor(sens)) + if CONF_THD_VOLTAGE_B in config: + sens = await sensor.new_sensor(config[CONF_THD_VOLTAGE_B]) + cg.add(var.set_thd_voltage_b_sensor(sens)) + if CONF_THD_CURRENT_B in config: + sens = await sensor.new_sensor(config[CONF_THD_CURRENT_B]) + cg.add(var.set_thd_current_b_sensor(sens)) + if CONF_THD_VOLTAGE_C in config: + sens = await sensor.new_sensor(config[CONF_THD_VOLTAGE_C]) + cg.add(var.set_thd_voltage_c_sensor(sens)) + if CONF_THD_CURRENT_C in config: + sens = await sensor.new_sensor(config[CONF_THD_CURRENT_C]) + cg.add(var.set_thd_current_c_sensor(sens))