inital upload
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
|
||||||
|
CODEOWNERS = ["@DitroniXDev"]
|
||||||
|
|
||||||
|
atm90e36_ns = cg.esphome_ns.namespace("atm90e36")
|
||||||
|
ATM90E36Component = atm90e36_ns.class_("ATM90E36Component", cg.Component)
|
||||||
|
|
||||||
|
CONF_ATM90E36_ID = "atm90e36_id"
|
||||||
@@ -0,0 +1,516 @@
|
|||||||
|
#include "atm90e36.h"
|
||||||
|
#include <cinttypes>
|
||||||
|
#include <cmath>
|
||||||
|
#include <numbers>
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace atm90e36 {
|
||||||
|
|
||||||
|
static const char *const TAG = "atm90e36";
|
||||||
|
//Loop called by normal ESP32 Loop()
|
||||||
|
void ATM90E36Component::loop() {
|
||||||
|
if (this->get_publish_interval_flag_()) {
|
||||||
|
this->set_publish_interval_flag_(false);
|
||||||
|
for (uint8_t phase = 0; phase < 3; phase++) {
|
||||||
|
if (this->phase_[phase].voltage_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].voltage_ = this->get_phase_voltage_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].current_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].current_ = this->get_phase_current_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].power_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].active_power_ = this->get_phase_active_power_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].power_factor_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].power_factor_ = this->get_phase_power_factor_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].reactive_power_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].reactive_power_ = this->get_phase_reactive_power_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].apparent_power_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].apparent_power_ = this->get_phase_apparent_power_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].forward_active_energy_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].forward_active_energy_ = this->get_phase_forward_active_energy_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].reverse_active_energy_ = this->get_phase_reverse_active_energy_(phase);
|
||||||
|
|
||||||
|
if (this->phase_[phase].phase_angle_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].phase_angle_ = this->get_phase_angle_(phase);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// After the local store is collected we can publish them trusting they are within +-1 hardware sampling
|
||||||
|
if (this->phase_[phase].voltage_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].voltage_sensor_->publish_state(this->get_local_phase_voltage_(phase));
|
||||||
|
|
||||||
|
if (this->phase_[phase].current_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].current_sensor_->publish_state(this->get_local_phase_current_(phase));
|
||||||
|
|
||||||
|
if (this->phase_[phase].power_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].power_sensor_->publish_state(this->get_local_phase_active_power_(phase));
|
||||||
|
|
||||||
|
if (this->phase_[phase].power_factor_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].power_factor_sensor_->publish_state(this->get_local_phase_power_factor_(phase));
|
||||||
|
|
||||||
|
if (this->phase_[phase].reactive_power_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].reactive_power_sensor_->publish_state(this->get_local_phase_reactive_power_(phase));
|
||||||
|
|
||||||
|
if (this->phase_[phase].apparent_power_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].apparent_power_sensor_->publish_state(this->get_local_phase_apparent_power_(phase));
|
||||||
|
|
||||||
|
if (this->phase_[phase].forward_active_energy_sensor_ != nullptr) {
|
||||||
|
this->phase_[phase].forward_active_energy_sensor_->publish_state(
|
||||||
|
this->get_local_phase_forward_active_energy_(phase));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->phase_[phase].reverse_active_energy_sensor_ != nullptr) {
|
||||||
|
this->phase_[phase].reverse_active_energy_sensor_->publish_state(
|
||||||
|
this->get_local_phase_reverse_active_energy_(phase));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->phase_[phase].phase_angle_sensor_ != nullptr)
|
||||||
|
this->phase_[phase].phase_angle_sensor_->publish_state(this->get_local_phase_angle_(phase));
|
||||||
|
|
||||||
|
if (this->phase_[phase].harmonic_active_power_sensor_ != nullptr) {
|
||||||
|
this->phase_[phase].harmonic_active_power_sensor_->publish_state(
|
||||||
|
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->freq_sensor_ != nullptr)
|
||||||
|
this->freq_sensor_->publish_state(this->get_frequency_());
|
||||||
|
|
||||||
|
if (this->chip_temperature_sensor_ != nullptr)
|
||||||
|
this->chip_temperature_sensor_->publish_state(this->get_chip_temperature_());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATM90E36Component::update() {
|
||||||
|
this->set_publish_interval_flag_(true);
|
||||||
|
this->status_clear_warning();
|
||||||
|
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
this->check_phase_status();
|
||||||
|
this->check_freq_status();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//Setup called by ESP32 setup()
|
||||||
|
void ATM90E36Component::setup() {
|
||||||
|
this->spi_setup();
|
||||||
|
this->cs_summary_ = this->cs_->dump_summary();
|
||||||
|
const char *cs = this->cs_summary_.c_str();
|
||||||
|
|
||||||
|
uint16_t mmode0 = 0x87; // 3P4W 50Hz
|
||||||
|
uint16_t high_thresh = 0;
|
||||||
|
uint16_t low_thresh = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (line_freq_ == 60) {
|
||||||
|
mmode0 |= 1 << 12; // sets 12th bit to 1, 60Hz
|
||||||
|
// for freq threshold registers
|
||||||
|
high_thresh = 6300; // 63.00 Hz
|
||||||
|
low_thresh = 5700; // 57.00 Hz
|
||||||
|
} else {
|
||||||
|
high_thresh = 5300; // 53.00 Hz
|
||||||
|
low_thresh = 4700; // 47.00 Hz
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_phases_ == 2) {
|
||||||
|
mmode0 |= 1 << 8; // sets 8th bit to 1, 3P3W
|
||||||
|
mmode0 |= 0 << 1; // sets 1st bit to 0, phase b is not counted into the all-phase sum energy/power (P/Q/S)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Calulate MMMode1 taking current_gain gain_dpga and gain_voltage
|
||||||
|
pga_cal = pga_current_;
|
||||||
|
pga_cal |= pga_voltage_ << 8;
|
||||||
|
pga_cal |= dpga_gain_ << 14;
|
||||||
|
|
||||||
|
this->write16_(ATM90E36_REGISTER_SOFTRESET, 0x789A, false); // Perform soft reset
|
||||||
|
delay(6); // Wait for the minimum 5ms + 1ms
|
||||||
|
this->write16_(ATM90E36_REGISTER_FUNCEN0, 0x0000); // Voltage sag
|
||||||
|
this->write16_(ATM90E36_REGISTER_FUNCEN1, 0x0000); // Voltage sag
|
||||||
|
this->write16_(ATM90E36_REGISTER_SAGTH, calculate_voltage_threshold(50.0, this->phase_[0].voltage_gain_, 1)); // Voltage sag
|
||||||
|
this->write16_(ATM90E36_REGISTER_CONFIGSTART, 0x5678); // Start Config of chip
|
||||||
|
this->write16_(ATM90E36_REGISTER_PLCONSTH, 0x0861); // PL Constant MSB (default) = 140625000
|
||||||
|
this->write16_(ATM90E36_REGISTER_PLCONSTL, 0xC468); // PL Constant LSB (default)
|
||||||
|
this->write16_(ATM90E36_REGISTER_MMODE0, mmode0); // Mode Config (frequency set in main program) mmode0
|
||||||
|
this->write16_(ATM90E36_REGISTER_MMODE1, pga_cal); // PGA Gain Configuration for Current Channels 0x5555
|
||||||
|
this->write16_(ATM90E36_REGISTER_PSTARTTH, 0x0000); // All Active Startup Power Threshold - 0.02A/0.00032 = 7500
|
||||||
|
this->write16_(ATM90E36_REGISTER_QSTARTTH, 0x0000); // All Reactive Startup Power Threshold - 50%
|
||||||
|
this->write16_(ATM90E36_REGISTER_SSTARTTH, 0x0000); // All Reactive Startup Power Threshold - 50%
|
||||||
|
this->write16_(ATM90E36_REGISTER_PPHASETH, 0x0000); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750
|
||||||
|
this->write16_(ATM90E36_REGISTER_QPHASETH, 0x0000); // Each phase Reactive Phase Threshold - 10%
|
||||||
|
this->write16_(ATM90E36_REGISTER_SPHASETH, 0x0000); // Apparent Phase Threshold
|
||||||
|
this->write16_(ATM90E36_REGISTER_CSO, 0x4741); // Checksum 0
|
||||||
|
|
||||||
|
this->write16_(ATM90E36_REGISTER_CALSTART, 0x5678); // Metering calibration startup
|
||||||
|
this->write16_(ATM90E36_REGISTER_PQGAINA, 0x0000); // CT1 line active power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_PHIA, 0x0000); // CT1 line reactive power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_PQGAINB, 0x0000); // CT2 line active power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_PHIB, 0x0000); // CT2 line reactive power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_PQGAINC, 0x0000); // CT3 line active power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_PHIC, 0x0000); // CT3 line reactive power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_POFFSETA, 0x0000); // Line calibration gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_QOFFSETA, 0x0000); // Line calibration angle
|
||||||
|
this->write16_(ATM90E36_REGISTER_POFFSETB, 0x0000); // Line calibration gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_QOFFSETB, 0x0000); // Line calibration angle
|
||||||
|
this->write16_(ATM90E36_REGISTER_POFFSETC, 0x0000); // Line calibration gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_QOFFSETC, 0x0000); // Line calibration angle
|
||||||
|
this->write16_(ATM90E36_REGISTER_CS1, 0x0000); // Checksum 1
|
||||||
|
|
||||||
|
// **************** FUNDAMENTAL/HARMONIC & ENERGY CALIBRATION REGISTERS ****************
|
||||||
|
this->write16_(ATM90E36_REGISTER_HARMSTART, 0x5678); // Metering calibration startup
|
||||||
|
this->write16_(ATM90E36_REGISTER_POFFSETAF, 0x0000); // CT1 Fund. active power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_POFFSETBF, 0x0000); // CT2 Fund. active power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_POFFSETCF, 0x0000); // CT3 Fund. active power offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_PGAINAF, 0x0000); // CT1 Fund. active power gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_PGAINBF, 0x0000); // CT2 Fund. active power gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_PGAINCF, 0x0000); // CT3 Fund. active power gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_CS2, 0x0000); // Checksum 2
|
||||||
|
|
||||||
|
// **************** MEASUREMENT CALIBRATION REGISTERS ****************
|
||||||
|
this->write16_(ATM90E36_REGISTER_ADJSTART, 0x5678); // Measurement calibration
|
||||||
|
|
||||||
|
this->write16_(ATM90E36_REGISTER_UGAINA, this->phase_[0].voltage_gain_); // CT1 SVoltage RMS gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_IGAINA, this->phase_[0].ct_gain_); // CT1 line current gain.
|
||||||
|
this->write16_(ATM90E36_REGISTER_UOFFSETA, 0x0000); // CT1 Voltage offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_IOFFSETA, 0x0000); // CT1 line current offset
|
||||||
|
|
||||||
|
this->write16_(ATM90E36_REGISTER_UGAINB, this->phase_[1].voltage_gain_); // CT2 SVoltage RMS gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_IGAINB, this->phase_[1].ct_gain_); // CT2 line current gain.
|
||||||
|
this->write16_(ATM90E36_REGISTER_UOFFSETB, 0x0000); // CT2 Voltage offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_IOFFSETB, 0x0000); // CT2 line current offset
|
||||||
|
|
||||||
|
this->write16_(ATM90E36_REGISTER_UGAINC, this->phase_[2].voltage_gain_); // CT3 SVoltage RMS gain
|
||||||
|
this->write16_(ATM90E36_REGISTER_IGAINC, this->phase_[2].ct_gain_); // CT3 line current gain.
|
||||||
|
this->write16_(ATM90E36_REGISTER_UOFFSETA, 0x0000); // CT3 Voltage offset
|
||||||
|
this->write16_(ATM90E36_REGISTER_IOFFSETA, 0x0000); // CT3 line current offset
|
||||||
|
// N
|
||||||
|
this->write16_(ATM90E36_REGISTER_IGAINN, 0xFD7F); // D line current gain
|
||||||
|
|
||||||
|
this->write16_(ATM90E36_REGISTER_CS3, 0x02F6); // Checksum 3
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATM90E36Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG("", "ATM90E36:");
|
||||||
|
LOG_PIN(" CS Pin: ", this->cs_);
|
||||||
|
if (this->is_failed()) {
|
||||||
|
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||||
|
}
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
LOG_SENSOR(" ", "Voltage A", this->phase_[PHASEA].voltage_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Current A", this->phase_[PHASEA].current_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Power A", this->phase_[PHASEA].power_sensor_);
|
||||||
|
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(" ", "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(" ", "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(" ", "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_);
|
||||||
|
LOG_SENSOR(" ", "Active Forward Energy B", this->phase_[PHASEB].forward_active_energy_sensor_);
|
||||||
|
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(" ", "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(" ", "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(" ", "Frequency", this->freq_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Chip Temp", this->chip_temperature_sensor_);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_setup_priority() const { return setup_priority::IO; }
|
||||||
|
|
||||||
|
// R/C registers can conly be cleared after the LastSPIData register is updated (register 78H)
|
||||||
|
// Peakdetect period: 05H. Bit 15:8 are PeakDet_period in ms. 7:0 are Sag_period
|
||||||
|
// Default is 143FH (20ms, 63ms)
|
||||||
|
uint16_t ATM90E36Component::read16_(uint16_t a_register) {
|
||||||
|
this->enable();
|
||||||
|
delay_microseconds_safe(10); // min delay between CS low and first SCK is 200ns - 1us is plenty
|
||||||
|
uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
|
||||||
|
uint8_t addrl = (a_register & 0xFF);
|
||||||
|
uint8_t data[4] = {addrh, addrl, 0x00, 0x00};
|
||||||
|
this->transfer_array(data, 4);
|
||||||
|
uint16_t output = encode_uint16(data[2], data[3]);
|
||||||
|
ESP_LOGVV(TAG, "read16_ 0x%04" PRIX16 " output 0x%04" PRIX16, a_register, output);
|
||||||
|
delay_microseconds_safe(10); // allow the last clock to propagate before releasing CS
|
||||||
|
this->disable();
|
||||||
|
delay_microseconds_safe(1); // meet minimum CS high time before next transaction
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATM90E36Component::write16_(uint16_t a_register, uint16_t val, bool validate) {
|
||||||
|
ESP_LOGVV(TAG, "write16_ 0x%04" PRIX16 " val 0x%04" PRIX16, a_register, val);
|
||||||
|
uint8_t addrh = ((a_register >> 8) & 0x03);
|
||||||
|
uint8_t addrl = (a_register & 0xFF);
|
||||||
|
uint8_t data[4] = {addrh, addrl, uint8_t((val >> 8) & 0xFF), uint8_t(val & 0xFF)};
|
||||||
|
this->enable();
|
||||||
|
delay_microseconds_safe(1); // ensure CS setup time
|
||||||
|
this->write_array(data, 4);
|
||||||
|
delay_microseconds_safe(1); // allow clock to settle before raising CS
|
||||||
|
this->disable();
|
||||||
|
delay_microseconds_safe(1); // ensure minimum CS high time
|
||||||
|
if (validate)
|
||||||
|
this->validate_spi_read_(val, "write16()");
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_voltage_(uint8_t phase) { return this->phase_[phase].voltage_; }
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_current_(uint8_t phase) { return this->phase_[phase].current_; }
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_active_power_(uint8_t phase) { return this->phase_[phase].active_power_; }
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_reactive_power_(uint8_t phase) { return this->phase_[phase].reactive_power_; }
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_apparent_power_(uint8_t phase) { return this->phase_[phase].apparent_power_; }
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_power_factor_(uint8_t phase) { return this->phase_[phase].power_factor_; }
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_forward_active_energy_(uint8_t phase) {
|
||||||
|
return this->phase_[phase].forward_active_energy_;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_reverse_active_energy_(uint8_t phase) {
|
||||||
|
return this->phase_[phase].reverse_active_energy_;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_local_phase_angle_(uint8_t phase) { return this->phase_[phase].phase_angle_; }
|
||||||
|
|
||||||
|
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_phase_voltage_(uint8_t phase) {
|
||||||
|
uint16_t voltage = this->read16_(ATM90E36_REGISTER_URMS + phase);
|
||||||
|
this->validate_spi_read_(voltage, "get_phase_voltage()");
|
||||||
|
|
||||||
|
if (voltage < 50) {
|
||||||
|
voltage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (float) voltage / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_voltage_avg_(uint8_t phase) {
|
||||||
|
const uint8_t reads = 10;
|
||||||
|
uint32_t accumulation = 0;
|
||||||
|
uint16_t voltage = 0;
|
||||||
|
for (uint8_t i = 0; i < reads; i++) {
|
||||||
|
voltage = this->read16_(ATM90E36_REGISTER_URMS + phase);
|
||||||
|
this->validate_spi_read_(voltage, "get_phase_voltage_avg_()");
|
||||||
|
accumulation += voltage;
|
||||||
|
}
|
||||||
|
voltage = accumulation / reads;
|
||||||
|
this->phase_[phase].voltage_ = (float) voltage / 100;
|
||||||
|
return this->phase_[phase].voltage_;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_current_avg_(uint8_t phase) {
|
||||||
|
const uint8_t reads = 10;
|
||||||
|
uint32_t accumulation = 0;
|
||||||
|
uint16_t current = 0;
|
||||||
|
for (uint8_t i = 0; i < reads; i++) {
|
||||||
|
current = this->read16_(ATM90E36_REGISTER_IRMS + phase);
|
||||||
|
this->validate_spi_read_(current, "get_phase_current_avg_()");
|
||||||
|
accumulation += current;
|
||||||
|
}
|
||||||
|
current = accumulation / reads;
|
||||||
|
this->phase_[phase].current_ = (float) current / 1000;
|
||||||
|
return this->phase_[phase].current_;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_current_(uint8_t phase) {
|
||||||
|
const uint16_t current = this->read16_(ATM90E36_REGISTER_IRMS + phase);
|
||||||
|
this->validate_spi_read_(current, "get_phase_current_()");
|
||||||
|
return (float) current / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_active_power_(uint8_t phase) {
|
||||||
|
float val = (float)this->read16_(ATM90E36_REGISTER_PMEAN + phase);
|
||||||
|
|
||||||
|
if (val >= 0xFFFF) {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_reactive_power_(uint8_t phase) {
|
||||||
|
int16_t val = (int16_t)this->read16_(ATM90E36_REGISTER_QMEAN + phase);
|
||||||
|
return (float)val / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_apparent_power_(uint8_t phase) {
|
||||||
|
const int val = this->read16_(ATM90E36_REGISTER_SMEANT + phase);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_power_factor_(uint8_t phase) {
|
||||||
|
uint16_t powerfactor = this->read16_(ATM90E36_REGISTER_PFMEAN + phase); // unsigned to compare to lastspidata
|
||||||
|
this->validate_spi_read_(powerfactor, "get_phase_power_factor_()");
|
||||||
|
return (float) ((int16_t) powerfactor) / 1000; // make it signed again
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_forward_active_energy_(uint8_t phase) {
|
||||||
|
const uint16_t val = this->read16_(ATM90E36_REGISTER_APENERGY + phase);
|
||||||
|
if ((UINT32_MAX - this->phase_[phase].cumulative_forward_active_energy_) > val) {
|
||||||
|
this->phase_[phase].cumulative_forward_active_energy_ += val;
|
||||||
|
} else {
|
||||||
|
this->phase_[phase].cumulative_forward_active_energy_ = val;
|
||||||
|
}
|
||||||
|
// 0.01CF resolution = 0.003125 Wh per count
|
||||||
|
return ((float) this->phase_[phase].cumulative_forward_active_energy_ * (10.0f / 3200.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_reverse_active_energy_(uint8_t phase) {
|
||||||
|
const uint16_t val = this->read16_(ATM90E36_REGISTER_ANENERGY + phase);
|
||||||
|
if (UINT32_MAX - this->phase_[phase].cumulative_reverse_active_energy_ > val) {
|
||||||
|
this->phase_[phase].cumulative_reverse_active_energy_ += val;
|
||||||
|
} else {
|
||||||
|
this->phase_[phase].cumulative_reverse_active_energy_ = val;
|
||||||
|
}
|
||||||
|
// 0.01CF resolution = 0.003125 Wh per count
|
||||||
|
return ((float) this->phase_[phase].cumulative_reverse_active_energy_ * (10.0f / 3200.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_harmonic_active_power_(uint8_t phase) {
|
||||||
|
int16_t val = (int16_t)this->read16_(ATM90E36_REGISTER_PMEANH + phase);
|
||||||
|
return (float)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_phase_angle_(uint8_t phase) {
|
||||||
|
int16_t val = (int16_t)this->read16_(ATM90E36_REGISTER_PANGLE + phase) / 10.0;
|
||||||
|
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_frequency_() {
|
||||||
|
const uint16_t freq = this->read16_(ATM90E36_REGISTER_FREQ);
|
||||||
|
return (float) freq / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E36Component::get_chip_temperature_() {
|
||||||
|
const uint16_t ctemp = this->read16_(ATM90E36_REGISTER_TEMP);
|
||||||
|
return (float) ctemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
void ATM90E36Component::check_phase_status() {
|
||||||
|
SysStatus0 state0;
|
||||||
|
SysStatus1 state1;
|
||||||
|
|
||||||
|
state0.data = this->read16_(ATM90E36_REGISTER_SYSSTATUS0);
|
||||||
|
state1.data = this->read16_(ATM90E36_REGISTER_SYSSTATUS1);
|
||||||
|
|
||||||
|
std::string status;
|
||||||
|
|
||||||
|
if (state0.bits.SagWarn) {
|
||||||
|
status += "Voltage Sag; ";
|
||||||
|
}
|
||||||
|
if (state1.bits.THDUOv) {
|
||||||
|
status += "Over Voltage; ";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *sensor = this->phase_status_text_sensor_;
|
||||||
|
if (sensor == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!status.empty()) {
|
||||||
|
status.pop_back(); // remove space
|
||||||
|
status.pop_back(); // remove semicolon
|
||||||
|
ESP_LOGW(TAG, "%s: %s", sensor->get_name().c_str(), status.c_str());
|
||||||
|
sensor->publish_state(status);
|
||||||
|
} else {
|
||||||
|
sensor->publish_state("Okay");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATM90E36Component::check_freq_status() {
|
||||||
|
SysStatus0 state0;
|
||||||
|
|
||||||
|
state0.data = this->read16_(ATM90E36_REGISTER_SYSSTATUS0);
|
||||||
|
|
||||||
|
std::string freq_status;
|
||||||
|
|
||||||
|
if (state0.bits.SagWarn) {
|
||||||
|
freq_status = "LOW";
|
||||||
|
} else {
|
||||||
|
freq_status = "Normal";
|
||||||
|
}
|
||||||
|
if (this->freq_status_text_sensor_ != nullptr) {
|
||||||
|
if (freq_status == "Normal") {
|
||||||
|
ESP_LOGD(TAG, "Frequency status: %s", freq_status.c_str());
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "Frequency status: %s", freq_status.c_str());
|
||||||
|
}
|
||||||
|
this->freq_status_text_sensor_->publish_state(freq_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t ATM90E36Component::calculate_voltage_threshold(int line_freq, uint16_t ugain, float multiplier) {
|
||||||
|
// this assumes that 60Hz electrical systems use 120V mains,
|
||||||
|
// which is usually, but not always the case
|
||||||
|
float nominal_voltage = (line_freq == 60) ? 120.0f : 220.0f;
|
||||||
|
float target_voltage = nominal_voltage * multiplier;
|
||||||
|
|
||||||
|
float peak_01v = target_voltage * 100.0f * std::numbers::sqrt2_v<float>; // convert RMS → peak, scale to 0.01V
|
||||||
|
float divider = (2.0f * ugain) / 32768.0f;
|
||||||
|
|
||||||
|
float threshold = peak_01v / divider;
|
||||||
|
|
||||||
|
return static_cast<uint16_t>(threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATM90E36Component::validate_spi_read_(uint16_t expected, const char *context) {
|
||||||
|
uint16_t last = this->read16_(ATM90E36_REGISTER_LASTSPIDATA);
|
||||||
|
if (last != expected) {
|
||||||
|
if (context != nullptr) {
|
||||||
|
ESP_LOGW(TAG, "[%s] SPI read mismatch: expected 0x%04X, got 0x%04X", context, expected, last);
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "SPI read mismatch: expected 0x%04X, got 0x%04X", expected, last);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atm90e36
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "atm90e36_reg.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/spi/spi.h"
|
||||||
|
#include "esphome/core/application.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/preferences.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace atm90e36 {
|
||||||
|
|
||||||
|
class ATM90E36Component : public PollingComponent,
|
||||||
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH,
|
||||||
|
spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_2MHZ> {
|
||||||
|
public:
|
||||||
|
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"};
|
||||||
|
void loop() override;
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
void update() override;
|
||||||
|
void set_voltage_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].voltage_sensor_ = obj; }
|
||||||
|
void set_current_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].current_sensor_ = obj; }
|
||||||
|
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_forward_active_energy_sensor(int phase, sensor::Sensor *obj) {
|
||||||
|
this->phase_[phase].forward_active_energy_sensor_ = obj;
|
||||||
|
}
|
||||||
|
void set_reverse_active_energy_sensor(int phase, sensor::Sensor *obj) {
|
||||||
|
this->phase_[phase].reverse_active_energy_sensor_ = obj;
|
||||||
|
}
|
||||||
|
void set_power_factor_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].power_factor_sensor_ = obj; }
|
||||||
|
void set_phase_angle_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].phase_angle_sensor_ = obj; }
|
||||||
|
void set_harmonic_active_power_sensor(int phase, sensor::Sensor *obj) {
|
||||||
|
this->phase_[phase].harmonic_active_power_sensor_ = obj;
|
||||||
|
}
|
||||||
|
void set_peak_current_sensor(int phase, sensor::Sensor *obj) { this->phase_[phase].peak_current_sensor_ = obj; }
|
||||||
|
void set_volt_gain(int phase, uint16_t gain) {
|
||||||
|
this->phase_[phase].voltage_gain_ = gain;
|
||||||
|
}
|
||||||
|
void set_ct_gain(int phase, uint16_t gain) {
|
||||||
|
this->phase_[phase].ct_gain_ = gain;
|
||||||
|
}
|
||||||
|
void set_freq_sensor(sensor::Sensor *freq_sensor) { freq_sensor_ = freq_sensor; }
|
||||||
|
void set_peak_current_signed(bool flag) { peak_current_signed_ = flag; }
|
||||||
|
void set_chip_temperature_sensor(sensor::Sensor *chip_temperature_sensor) {
|
||||||
|
chip_temperature_sensor_ = chip_temperature_sensor;
|
||||||
|
}
|
||||||
|
void set_line_freq(int freq) { line_freq_ = freq; }
|
||||||
|
void set_current_phases(int phases) { current_phases_ = phases; }
|
||||||
|
void set_pga_current(uint16_t gain) { pga_current_ = gain; }
|
||||||
|
void set_pga_voltage(uint16_t gain) { pga_voltage_ = gain; }
|
||||||
|
void set_dpga_gain(uint16_t gain) { dpga_gain_ = gain; }
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
void set_reference_voltage(uint8_t phase, number::Number *ref_voltage) { ref_voltages_[phase] = ref_voltage; }
|
||||||
|
void set_reference_current(uint8_t phase, number::Number *ref_current) { ref_currents_[phase] = ref_current; }
|
||||||
|
#endif
|
||||||
|
float get_reference_voltage(uint8_t phase) {
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
return (phase >= 0 && phase < 3 && ref_voltages_[phase]) ? ref_voltages_[phase]->state : 120.0; // Default voltage
|
||||||
|
#else
|
||||||
|
return 120.0; // Default voltage
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
float get_reference_current(uint8_t phase) {
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
return (phase >= 0 && phase < 3 && ref_currents_[phase]) ? ref_currents_[phase]->state : 5.0f; // Default current
|
||||||
|
#else
|
||||||
|
return 5.0f; // Default current
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
bool using_saved_calibrations_ = false; // Track if stored calibrations are being used
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
void check_phase_status();
|
||||||
|
void check_freq_status();
|
||||||
|
void check_over_current();
|
||||||
|
void set_phase_status_text_sensor(text_sensor::TextSensor *sensor) {
|
||||||
|
this->phase_status_text_sensor_ = sensor;
|
||||||
|
}
|
||||||
|
void set_freq_status_text_sensor(text_sensor::TextSensor *sensor) { this->freq_status_text_sensor_ = sensor; }
|
||||||
|
#endif
|
||||||
|
uint16_t calculate_voltage_threshold(int line_freq, uint16_t ugain, float multiplier);
|
||||||
|
int32_t last_periodic_millis = millis();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
#ifdef USE_NUMBER
|
||||||
|
number::Number *ref_voltages_[3]{nullptr, nullptr, nullptr};
|
||||||
|
number::Number *ref_currents_[3]{nullptr, nullptr, nullptr};
|
||||||
|
#endif
|
||||||
|
uint16_t read16_(uint16_t a_register);
|
||||||
|
void write16_(uint16_t a_register, uint16_t val, bool validate = true);
|
||||||
|
float get_local_phase_voltage_(uint8_t phase);
|
||||||
|
float get_local_phase_current_(uint8_t phase);
|
||||||
|
float get_local_phase_active_power_(uint8_t phase);
|
||||||
|
float get_local_phase_reactive_power_(uint8_t phase);
|
||||||
|
float get_local_phase_apparent_power_(uint8_t phase);
|
||||||
|
float get_local_phase_power_factor_(uint8_t phase);
|
||||||
|
float get_local_phase_forward_active_energy_(uint8_t phase);
|
||||||
|
float get_local_phase_reverse_active_energy_(uint8_t phase);
|
||||||
|
float get_local_phase_angle_(uint8_t phase);
|
||||||
|
float get_local_phase_harmonic_active_power_(uint8_t phase);
|
||||||
|
float get_local_phase_peak_current_(uint8_t phase);
|
||||||
|
float get_phase_voltage_(uint8_t phase);
|
||||||
|
float get_phase_voltage_avg_(uint8_t phase);
|
||||||
|
float get_phase_current_(uint8_t phase);
|
||||||
|
float get_phase_current_avg_(uint8_t phase);
|
||||||
|
float get_phase_active_power_(uint8_t phase);
|
||||||
|
float get_phase_reactive_power_(uint8_t phase);
|
||||||
|
float get_phase_apparent_power_(uint8_t phase);
|
||||||
|
float get_phase_power_factor_(uint8_t phase);
|
||||||
|
float get_phase_forward_active_energy_(uint8_t phase);
|
||||||
|
float get_phase_reverse_active_energy_(uint8_t phase);
|
||||||
|
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_frequency_();
|
||||||
|
float get_chip_temperature_();
|
||||||
|
bool get_publish_interval_flag_() { return publish_interval_flag_; };
|
||||||
|
void set_publish_interval_flag_(bool flag) { publish_interval_flag_ = flag; };
|
||||||
|
void restore_offset_calibrations_();
|
||||||
|
void restore_power_offset_calibrations_();
|
||||||
|
void restore_gain_calibrations_();
|
||||||
|
void save_offset_calibration_to_memory_();
|
||||||
|
void save_gain_calibration_to_memory_();
|
||||||
|
void save_power_offset_calibration_to_memory_();
|
||||||
|
void write_offsets_to_registers_(uint8_t phase, int16_t voltage_offset, int16_t current_offset);
|
||||||
|
void write_power_offsets_to_registers_(uint8_t phase, int16_t p_offset, int16_t q_offset);
|
||||||
|
void write_gains_to_registers_();
|
||||||
|
bool verify_gain_writes_();
|
||||||
|
bool validate_spi_read_(uint16_t expected, const char *context = nullptr);
|
||||||
|
void log_calibration_status_();
|
||||||
|
|
||||||
|
struct ATM90E32Phase {
|
||||||
|
uint16_t voltage_gain_{0};
|
||||||
|
uint16_t ct_gain_{0};
|
||||||
|
int16_t voltage_offset_{0};
|
||||||
|
int16_t current_offset_{0};
|
||||||
|
int16_t active_power_offset_{0};
|
||||||
|
int16_t reactive_power_offset_{0};
|
||||||
|
float voltage_{0};
|
||||||
|
float current_{0};
|
||||||
|
float active_power_{0};
|
||||||
|
float reactive_power_{0};
|
||||||
|
float apparent_power_{0};
|
||||||
|
float power_factor_{0};
|
||||||
|
float forward_active_energy_{0};
|
||||||
|
float reverse_active_energy_{0};
|
||||||
|
float phase_angle_{0};
|
||||||
|
float harmonic_active_power_{0};
|
||||||
|
float peak_current_{0};
|
||||||
|
sensor::Sensor *voltage_sensor_{nullptr};
|
||||||
|
sensor::Sensor *current_sensor_{nullptr};
|
||||||
|
sensor::Sensor *power_sensor_{nullptr};
|
||||||
|
sensor::Sensor *reactive_power_sensor_{nullptr};
|
||||||
|
sensor::Sensor *apparent_power_sensor_{nullptr};
|
||||||
|
sensor::Sensor *power_factor_sensor_{nullptr};
|
||||||
|
sensor::Sensor *forward_active_energy_sensor_{nullptr};
|
||||||
|
sensor::Sensor *reverse_active_energy_sensor_{nullptr};
|
||||||
|
sensor::Sensor *phase_angle_sensor_{nullptr};
|
||||||
|
sensor::Sensor *harmonic_active_power_sensor_{nullptr};
|
||||||
|
sensor::Sensor *peak_current_sensor_{nullptr};
|
||||||
|
uint32_t cumulative_forward_active_energy_{0};
|
||||||
|
uint32_t cumulative_reverse_active_energy_{0};
|
||||||
|
} phase_[3];
|
||||||
|
|
||||||
|
union SysStatus0 {
|
||||||
|
uint16_t data;
|
||||||
|
struct {
|
||||||
|
bool b0 : 1;
|
||||||
|
bool b1 : 1;
|
||||||
|
bool PhaseLoseWn : 1;
|
||||||
|
bool SagWarn : 1;
|
||||||
|
bool b4 : 1;
|
||||||
|
bool b5 : 1;
|
||||||
|
bool IRevWn : 1;
|
||||||
|
bool URevWn : 1;
|
||||||
|
bool CS3Err : 1;
|
||||||
|
bool b9 : 1;
|
||||||
|
bool CS2Err : 1;
|
||||||
|
bool b11 : 1;
|
||||||
|
bool CS1Err : 1;
|
||||||
|
bool b13 : 1;
|
||||||
|
bool CS0Err : 1;
|
||||||
|
bool b15 : 1;
|
||||||
|
} bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
union SysStatus1 {
|
||||||
|
uint16_t data;
|
||||||
|
struct {
|
||||||
|
bool RevPchgC : 1;
|
||||||
|
bool RevPchgB : 1;
|
||||||
|
bool RevPchgA : 1;
|
||||||
|
bool RevPchgT : 1;
|
||||||
|
bool RevQchgC : 1;
|
||||||
|
bool RevQchgB : 1;
|
||||||
|
bool RevQchgA : 1;
|
||||||
|
bool RevQchgT : 1;
|
||||||
|
bool b8 : 1;
|
||||||
|
bool DFTDone : 1;
|
||||||
|
bool THDIOv : 1;
|
||||||
|
bool THDUOv : 1;
|
||||||
|
bool b12 : 1;
|
||||||
|
bool b13 : 1;
|
||||||
|
bool INOv0 : 1;
|
||||||
|
bool INOv1 : 1;
|
||||||
|
} bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
ESPPreferenceObject offset_pref_;
|
||||||
|
ESPPreferenceObject power_offset_pref_;
|
||||||
|
ESPPreferenceObject gain_calibration_pref_;
|
||||||
|
std::string cs_summary_;
|
||||||
|
|
||||||
|
sensor::Sensor *freq_sensor_{nullptr};
|
||||||
|
#ifdef USE_TEXT_SENSOR
|
||||||
|
text_sensor::TextSensor *phase_status_text_sensor_{nullptr};
|
||||||
|
text_sensor::TextSensor *freq_status_text_sensor_{nullptr};
|
||||||
|
#endif
|
||||||
|
sensor::Sensor *chip_temperature_sensor_{nullptr};
|
||||||
|
uint16_t pga_current_{0x15};
|
||||||
|
uint16_t pga_voltage_{0x15};
|
||||||
|
uint16_t dpga_gain_{0x2};
|
||||||
|
int line_freq_{60};
|
||||||
|
int current_phases_{3};
|
||||||
|
bool publish_interval_flag_{false};
|
||||||
|
bool peak_current_signed_{false};
|
||||||
|
uint16_t pga_cal{0x0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atm90e32
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace atm90e36 {
|
||||||
|
|
||||||
|
/* STATUS REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SOFTRESET = 0x00; // Software Reset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SYSSTATUS0 = 0x01; // System Status 0
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SYSSTATUS1 = 0x02; // System Status 1
|
||||||
|
static const uint16_t ATM90E36_REGISTER_FUNCEN0 = 0x03; // Function Enable 0
|
||||||
|
static const uint16_t ATM90E36_REGISTER_FUNCEN1 = 0x04; // Function Enable 1
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ZXCONFIG = 0x07; // Zero-Crossing Config
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SAGTH = 0x08; // Voltage Sag Th
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PHASELOSSTH = 0x09; // Voltage Phase Losing Th
|
||||||
|
static const uint16_t ATM90E36_REGISTER_INWARNTH0 = 0x0A; // Threshold for sampled (from ADC) N line rms current
|
||||||
|
static const uint16_t ATM90E36_REGISTER_INWARNTH1 = 0x0B; // Threshold for sampled (from ADC) N line rms current
|
||||||
|
static const uint16_t ATM90E36_REGISTER_THDNUTH = 0x0C; // Voltage THD Warning Threshold
|
||||||
|
static const uint16_t ATM90E36_REGISTER_THDNITH = 0x0D; // Current THD Warning Threshold
|
||||||
|
static const uint16_t ATM90E36_REGISTER_DMACTRL = 0x0E; // DMA Mode Interface Control
|
||||||
|
static const uint16_t ATM90E36_REGISTER_LASTSPIDATA = 0x0F; // Last Read/ Write SPI Value
|
||||||
|
|
||||||
|
/* LOW POWER MODE REGISTERS - NOT USED */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_DETECTCTRL = 0x10;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_DETECTTH1 = 0x11;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_DETECTTH2 = 0x12;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_DETECTTH3 = 0x13;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMOFFSETA = 0x14;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMOFFSETB = 0x15;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMOFFSETC = 0x16;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMPGA = 0x17;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMIRMSA = 0x18;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMIRMSB = 0x19;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMIRMSC = 0x1A;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMCONFIG = 0x10B;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMAVGSAMPLES = 0x1C;
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMIRMSLSB = 0x1D;
|
||||||
|
|
||||||
|
/* CONFIGURATION REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_CONFIGSTART = 0x30; // Calibration Start Command
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PLCONSTH = 0x31; // High Word of PL_Constant
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PLCONSTL = 0x32; // Low Word of PL_Constant
|
||||||
|
static const uint16_t ATM90E36_REGISTER_MMODE0 = 0x33; // Metering Mode Config
|
||||||
|
static const uint16_t ATM90E36_REGISTER_MMODE1 = 0x34; // PGA Gain Configuration for Current Channels
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PSTARTTH = 0x35; // Startup Power Th (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QSTARTTH = 0x36; // Startup Power Th (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SSTARTTH = 0x37; // Startup Power Th (S)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PPHASETH = 0x38; // Startup Power Accum Th (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QPHASETH = 0x39; // Startup Power Accum Th (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SPHASETH = 0x3A; // Startup Power Accum Th (S)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_CSO = 0x3B; // Checksum 0
|
||||||
|
|
||||||
|
/* CALIBRATION REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_CALSTART = 0X40; // Calibration Start Command
|
||||||
|
static const uint16_t ATM90E36_REGISTER_POFFSETA = 0x41; // A Line Power Offset (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QOFFSETA = 0x42; // A Line Power Offset (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_POFFSETB = 0x43; // B Line Power Offset (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QOFFSETB = 0x44; // B Line Power Offset (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_POFFSETC = 0x45; // C Line Power Offset (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QOFFSETC = 0x46; // C Line Power Offset (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PQGAINA = 0x47; // A Line Calibration Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PHIA = 0x48; // A Line Calibration Angle
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PQGAINB = 0x49; // B Line Calibration Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PHIB = 0x4A; // B Line Calibration Angle
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PQGAINC = 0x4B; // C Line Calibration Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PHIC = 0x4C; // C Line Calibration Angle
|
||||||
|
static const uint16_t ATM90E36_REGISTER_CS1 = 0X4D; // Checksum 1
|
||||||
|
|
||||||
|
/* FUNDAMENTAL/HARMONIC ENERGY CALIBRATION REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_HARMSTART = 0X50; // Harmonic Calibration Startup Command
|
||||||
|
static const uint16_t ATM90E36_REGISTER_POFFSETAF = 0x51; // A Fund Power Offset (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_POFFSETBF = 0x52; // B Fund Power Offset (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_POFFSETCF = 0x53; // C Fund Power Offset (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PGAINAF = 0x54; // A Fund Power Gain (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PGAINBF = 0x55; // B Fund Power Gain (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PGAINCF = 0x56; // C Fund Power Gain (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_CS2 = 0X57; // Checksum 2
|
||||||
|
|
||||||
|
/* MEASUREMENT CALIBRATION REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ADJSTART = 0X60; // Measurement Calibration Startup Command
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UGAINA = 0x61; // A Voltage RMS Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IGAINA = 0x62; // A Current RMS Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UOFFSETA = 0x63; // A Voltage Offset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IOFFSETA = 0x64; // A Current Offset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UGAINB = 0x65; // B Voltage RMS Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IGAINB = 0x66; // B Current RMS Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UOFFSETB = 0x67; // B Voltage Offset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IOFFSETB = 0x68; // B Current Offset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UGAINC = 0x69; // C Voltage RMS Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IGAINC = 0x6A; // C Current RMS Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UOFFSETC = 0x6B; // C Voltage Offset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IOFFSETC = 0x6C; // C Current Offset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IGAINN = 0x6D; // N Current Gain
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IOFFSETN = 0x6E; // N Current Offset
|
||||||
|
static const uint16_t ATM90E36_REGISTER_CS3 = 0X6F; // Checksum 3
|
||||||
|
|
||||||
|
/* ENERGY REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYT = 0x80; // Total Forward Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGY = 0x81; // Forward Active Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYA = 0x81; // A Forward Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYB = 0x82; // B Forward Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYC = 0x83; // C Forward Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYT = 0x84; // Total Reverse Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGY = 0x85; // Reverse Active Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYA = 0x85; // A Reverse Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYB = 0x86; // B Reverse Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYC = 0x87; // C Reverse Active
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RPENERGYT = 0x88; // Total Forward Reactive
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RPENERGYA = 0x89; // A Forward Reactive
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RPENERGYB = 0x8A; // B Forward Reactive
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RPENERGYC = 0x8B; // C Forward Reactive
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RNENERGYT = 0x8C; // Total Reverse Reactive
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RNENERGYA = 0x8D; // A Reverse Reactive
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RNENERGYB = 0x8E; // B Reverse Reactive
|
||||||
|
static const uint16_t ATM90E36_REGISTER_RNENERGYC = 0x8F; // C Reverse Reactive
|
||||||
|
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SAENERGYT = 0x90; // Total Apparent Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SENERGYA = 0x91; // A Apparent Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SENERGYB = 0x92; // B Apparent Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SENERGYC = 0x93; // C Apparent Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SVENERGYT = 0X94; // (Vector Sum) Total Apparent Energy
|
||||||
|
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ENSTATUS0 = 0X95; // Metering Status 0
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ENSTATUS1 = 0X96; // Metering Status 1
|
||||||
|
///////////////// 0x97 // Reserved Register
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SVMEANT = 0X98; // (Vector Sum) Total Apparent Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SVMEANTLSB = 0X99; // lSB of (Vector Sum) Total Apparent Power
|
||||||
|
|
||||||
|
/* FUNDAMENTAL / HARMONIC ENERGY REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYTF = 0xA0; // Total Forward Fund. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYAF = 0xA1; // A Forward Fund. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYBF = 0xA2; // B Forward Fund. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYCF = 0xA3; // C Forward Fund. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYTF = 0xA4; // Total Reverse Fund Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYAF = 0xA5; // A Reverse Fund. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYBF = 0xA6; // B Reverse Fund. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYCF = 0xA7; // C Reverse Fund. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYTH = 0xA8; // Total Forward Harm. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYAH = 0xA9; // A Forward Harm. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYBH = 0xAA; // B Forward Harm. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_APENERGYCH = 0xAB; // C Forward Harm. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYTH = 0xAC; // Total Reverse Harm. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYAH = 0xAD; // A Reverse Harm. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYBH = 0xAE; // B Reverse Harm. Energy
|
||||||
|
static const uint16_t ATM90E36_REGISTER_ANENERGYCH = 0xAF; // C Reverse Harm. Energy
|
||||||
|
|
||||||
|
/* POWER & P.F. REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANT = 0xB0; // Phase Active Total (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEAN = 0xB1; // Phase A Active Power start for loop (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANA = 0xB1; // Phase A Active Power (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANB = 0xB2; // Phase B Active Power (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANC = 0xB3; // Phase C Active Power (P)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANT = 0xB4; // Potencia Media Total (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEAN = 0xB5; // Reactive Power all Phases (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANA = 0xB5; // Reactive Power A (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANB = 0xB6; // Reactive Power B (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANC = 0xB7; // Reactive Power C (Q)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SMEANT = 0xB8; // Apparent Power All Phases (S)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SMEANA = 0xB9; // Apparent Power A (S)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SMEANB = 0xBA; // Apparent Power B (S)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SMEANC = 0xBB; // Apparent Power C (S)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PFMEANT = 0xBC; // Total Power Factor all Phases
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PFMEAN = 0xBD; // Power Factor Start for loop
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PFMEANA = 0xBD; // Power Factor A
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PFMEANB = 0xBE; // Power Factor B
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PFMEANC = 0xBF; // Power Factor C
|
||||||
|
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANTLSB = 0xC0; // Lower Word (Tot. Act. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANLSB = 0xC1; // Lower Word Reg Base (Active Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANALSB = 0xC1; // Lower Word (A Act. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANBLSB = 0xC2; // Lower Word (B Act. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANCLSB = 0xC3; // Lower Word (C Act. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANTLSB = 0xC4; // Lower Word (Tot. React. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANLSB = 0xC5; // Lower Word Reg Base (Reactive Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANALSB = 0xC5; // Lower Word (A React. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANBLSB = 0xC6; // Lower Word (B React. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_QMEANCLSB = 0xC7; // Lower Word (C React. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SAMEANTLSB = 0xC8; // Lower Word (Tot. App. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SMEANALSB = 0xC9; // Lower Word (A App. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SMEANBLSB = 0xCA; // Lower Word (B App. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_SMEANCLSB = 0xCB; // Lower Word (C App. Power)
|
||||||
|
|
||||||
|
/* FUND/HARM POWER & V/I RMS REGISTERS */
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANTF = 0xD0; // Total Active Fund. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANAF = 0xD1; // A Active Fund. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANBF = 0xD2; // B Active Fund. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANCF = 0xD3; // C Active Fund. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANTH = 0xD4; // Total Active Harm. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANH = 0xD5; // Active Harm. Power Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANAH = 0xD5; // A Active Harm. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANBH = 0xD6; // B Active Harm. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANCH = 0xD7; // C Active Harm. Power
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMS = 0xD9; // RMS Voltage Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMSA = 0xD9; // A RMS Voltage
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMSB = 0xDA; // B RMS Voltage
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMSC = 0xDB; // C RMS Voltage
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMS = 0xDD; // RMS Current Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMSA = 0xDD; // A RMS Current
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMSB = 0xDE; // B RMS Current
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMSC = 0xDF; // C RMS Current
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMSN = 0xD8; // Calculated N RMS Current
|
||||||
|
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANTFLSB = 0xE0; // Lower Word (Tot. Act. Fund. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANAFLSB = 0xE1; // Lower Word (A Act. Fund. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANBFLSB = 0xE2; // Lower Word (B Act. Fund. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANCFLSB = 0xE3; // Lower Word (C Act. Fund. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANTHLSB = 0xE4; // Lower Word (Tot. Act. Harm. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANHLSB = 0xE5; // Lower Word (A Act. Harm. Power) Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANAHLSB = 0xE5; // Lower Word (A Act. Harm. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANBHLSB = 0xE6; // Lower Word (B Act. Harm. Power)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PMEANCHLSB = 0xE7; // Lower Word (C Act. Harm. Power)
|
||||||
|
///////////////// 0xE8 // Reserved Register
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMSLSB = 0xE9; // Lower Word RMS Voltage Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMSALSB = 0xE9; // Lower Word (A RMS Voltage)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMSBLSB = 0xEA; // Lower Word (B RMS Voltage)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_URMSCLSB = 0xEB; // Lower Word (C RMS Voltage)
|
||||||
|
///////////////// 0xEC // Reserved Register
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMSLSB = 0xED; // Lower Word RMS Current Reg Base
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMSALSB = 0xED; // Lower Word (A RMS Current)
|
||||||
|
static const uint16_t ATM90E36_REGISTER_IRMSBLSB = 0xEE; // Lower Word (B RMS Current)
|
||||||
|
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
|
||||||
|
//////////////// 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_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
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PANGLEB = 0xFA; // B Mean Phase Angle
|
||||||
|
static const uint16_t ATM90E36_REGISTER_PANGLEC = 0xFB; // C Mean Phase Angle
|
||||||
|
static const uint16_t ATM90E36_REGISTER_TEMP = 0xFC; // Measured Temperature
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UANGLEA = 0xFD; // A Voltage Phase Angle
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UANGLEB = 0xFE; // B Voltage Phase Angle
|
||||||
|
static const uint16_t ATM90E36_REGISTER_UANGLEC = 0xFF; // C Voltage Phase Angle
|
||||||
|
|
||||||
|
} // namespace atm90e32
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import number
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_MAX_VALUE,
|
||||||
|
CONF_MIN_VALUE,
|
||||||
|
CONF_MODE,
|
||||||
|
CONF_PHASE_A,
|
||||||
|
CONF_PHASE_B,
|
||||||
|
CONF_PHASE_C,
|
||||||
|
CONF_REFERENCE_VOLTAGE,
|
||||||
|
CONF_STEP,
|
||||||
|
ENTITY_CATEGORY_CONFIG,
|
||||||
|
UNIT_AMPERE,
|
||||||
|
UNIT_VOLT,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .. import atm90e36_ns
|
||||||
|
from ..sensor import ATM90E36Component
|
||||||
|
|
||||||
|
ATM90E36Number = atm90e36_ns.class_(
|
||||||
|
"ATM90E36Number", number.Number, cg.Parented.template(ATM90E36Component)
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_REFERENCE_CURRENT = "reference_current"
|
||||||
|
PHASE_KEYS = [CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]
|
||||||
|
|
||||||
|
|
||||||
|
REFERENCE_VOLTAGE_PHASE_SCHEMA = cv.All(
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_MODE, default="box"): cv.string,
|
||||||
|
cv.Optional(CONF_MIN_VALUE, default=100.0): cv.float_,
|
||||||
|
cv.Optional(CONF_MAX_VALUE, default=260.0): cv.float_,
|
||||||
|
cv.Optional(CONF_STEP, default=0.1): cv.float_,
|
||||||
|
}
|
||||||
|
).extend(
|
||||||
|
number.number_schema(
|
||||||
|
class_=ATM90E36Number,
|
||||||
|
unit_of_measurement=UNIT_VOLT,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
icon="mdi:power-plug",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
REFERENCE_CURRENT_PHASE_SCHEMA = cv.All(
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_MODE, default="box"): cv.string,
|
||||||
|
cv.Optional(CONF_MIN_VALUE, default=1.0): cv.float_,
|
||||||
|
cv.Optional(CONF_MAX_VALUE, default=200.0): cv.float_,
|
||||||
|
cv.Optional(CONF_STEP, default=0.1): cv.float_,
|
||||||
|
}
|
||||||
|
).extend(
|
||||||
|
number.number_schema(
|
||||||
|
class_=ATM90E36Number,
|
||||||
|
unit_of_measurement=UNIT_AMPERE,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
icon="mdi:home-lightning-bolt",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
REFERENCE_VOLTAGE_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_PHASE_A): REFERENCE_VOLTAGE_PHASE_SCHEMA,
|
||||||
|
cv.Optional(CONF_PHASE_B): REFERENCE_VOLTAGE_PHASE_SCHEMA,
|
||||||
|
cv.Optional(CONF_PHASE_C): REFERENCE_VOLTAGE_PHASE_SCHEMA,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
REFERENCE_CURRENT_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_PHASE_A): REFERENCE_CURRENT_PHASE_SCHEMA,
|
||||||
|
cv.Optional(CONF_PHASE_B): REFERENCE_CURRENT_PHASE_SCHEMA,
|
||||||
|
cv.Optional(CONF_PHASE_C): REFERENCE_CURRENT_PHASE_SCHEMA,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_ID): cv.use_id(ATM90E36Component),
|
||||||
|
cv.Optional(CONF_REFERENCE_VOLTAGE): REFERENCE_VOLTAGE_SCHEMA,
|
||||||
|
cv.Optional(CONF_REFERENCE_CURRENT): REFERENCE_CURRENT_SCHEMA,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
parent = await cg.get_variable(config[CONF_ID])
|
||||||
|
|
||||||
|
if voltage_cfg := config.get(CONF_REFERENCE_VOLTAGE):
|
||||||
|
voltage_objs = [None, None, None]
|
||||||
|
|
||||||
|
for i, key in enumerate(PHASE_KEYS):
|
||||||
|
if validated := voltage_cfg.get(key):
|
||||||
|
obj = await number.new_number(
|
||||||
|
validated,
|
||||||
|
min_value=validated["min_value"],
|
||||||
|
max_value=validated["max_value"],
|
||||||
|
step=validated["step"],
|
||||||
|
)
|
||||||
|
await cg.register_parented(obj, parent)
|
||||||
|
voltage_objs[i] = obj
|
||||||
|
|
||||||
|
# Inherit from A → B/C if only A defined
|
||||||
|
if voltage_objs[0] is not None:
|
||||||
|
for i in range(3):
|
||||||
|
if voltage_objs[i] is None:
|
||||||
|
voltage_objs[i] = voltage_objs[0]
|
||||||
|
|
||||||
|
for i, obj in enumerate(voltage_objs):
|
||||||
|
if obj is not None:
|
||||||
|
cg.add(parent.set_reference_voltage(i, obj))
|
||||||
|
|
||||||
|
if current_cfg := config.get(CONF_REFERENCE_CURRENT):
|
||||||
|
for i, key in enumerate(PHASE_KEYS):
|
||||||
|
if validated := current_cfg.get(key):
|
||||||
|
obj = await number.new_number(
|
||||||
|
validated,
|
||||||
|
min_value=validated["min_value"],
|
||||||
|
max_value=validated["max_value"],
|
||||||
|
step=validated["step"],
|
||||||
|
)
|
||||||
|
await cg.register_parented(obj, parent)
|
||||||
|
cg.add(parent.set_reference_current(i, obj))
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/atm90e36/atm90e36.h"
|
||||||
|
#include "esphome/components/number/number.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace atm90e36 {
|
||||||
|
|
||||||
|
class ATM90E36Number : public number::Number, public Parented<ATM90E36Component> {
|
||||||
|
public:
|
||||||
|
void control(float value) override { this->publish_state(value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atm90e32
|
||||||
|
} // namespace esphome
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import sensor, spi
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_APPARENT_POWER,
|
||||||
|
CONF_CURRENT,
|
||||||
|
CONF_FORWARD_ACTIVE_ENERGY,
|
||||||
|
CONF_FREQUENCY,
|
||||||
|
CONF_ID,
|
||||||
|
CONF_LINE_FREQUENCY,
|
||||||
|
CONF_PHASE_A,
|
||||||
|
CONF_PHASE_ANGLE,
|
||||||
|
CONF_PHASE_B,
|
||||||
|
CONF_PHASE_C,
|
||||||
|
CONF_POWER,
|
||||||
|
CONF_POWER_FACTOR,
|
||||||
|
CONF_REACTIVE_POWER,
|
||||||
|
CONF_REVERSE_ACTIVE_ENERGY,
|
||||||
|
CONF_VOLTAGE,
|
||||||
|
DEVICE_CLASS_APPARENT_POWER,
|
||||||
|
DEVICE_CLASS_CURRENT,
|
||||||
|
DEVICE_CLASS_ENERGY,
|
||||||
|
DEVICE_CLASS_POWER,
|
||||||
|
DEVICE_CLASS_POWER_FACTOR,
|
||||||
|
DEVICE_CLASS_REACTIVE_POWER,
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
DEVICE_CLASS_VOLTAGE,
|
||||||
|
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
ICON_CURRENT_AC,
|
||||||
|
ICON_LIGHTBULB,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
STATE_CLASS_TOTAL_INCREASING,
|
||||||
|
UNIT_AMPERE,
|
||||||
|
UNIT_CELSIUS,
|
||||||
|
UNIT_DEGREES,
|
||||||
|
UNIT_HERTZ,
|
||||||
|
UNIT_VOLT,
|
||||||
|
UNIT_VOLT_AMPS,
|
||||||
|
UNIT_VOLT_AMPS_REACTIVE,
|
||||||
|
UNIT_WATT,
|
||||||
|
UNIT_WATT_HOURS,
|
||||||
|
)
|
||||||
|
|
||||||
|
from . import atm90e36_ns
|
||||||
|
|
||||||
|
CONF_CHIP_TEMPERATURE = "chip_temperature"
|
||||||
|
CONF_GAIN_CURRNT = "gain_current"
|
||||||
|
CONF_GAIN_DPGA = "gain_dpga"
|
||||||
|
CONF_GAIN_CURRENT = "gain_current"
|
||||||
|
CONF_CURRENT_PHASES = "current_phases"
|
||||||
|
CONF_GAIN_VOLTAGE = "gain_voltage"
|
||||||
|
CONF_GAIN_CT = "gain_ct"
|
||||||
|
CONF_OFFSET_VOLTAGE = "offset_voltage"
|
||||||
|
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_ENABLE_OFFSET_CALIBRATION = "enable_offset_calibration"
|
||||||
|
CONF_ENABLE_GAIN_CALIBRATION = "enable_gain_calibration"
|
||||||
|
CONF_PHASE_STATUS = "phase_status"
|
||||||
|
CONF_FREQUENCY_STATUS = "frequency_status"
|
||||||
|
UNIT_DEG = "degrees"
|
||||||
|
LINE_FREQS = {
|
||||||
|
"50HZ": 50,
|
||||||
|
"60HZ": 60,
|
||||||
|
}
|
||||||
|
CURRENT_PHASES = {
|
||||||
|
"2": 2,
|
||||||
|
"3": 3,
|
||||||
|
}
|
||||||
|
CURRENT_GAINS = {
|
||||||
|
"1X": 0x0,
|
||||||
|
"2X": 0x15,
|
||||||
|
"4X": 0x2A,
|
||||||
|
}
|
||||||
|
|
||||||
|
VOLTAGE_GAINS = {
|
||||||
|
"1X": 0x0,
|
||||||
|
"2X": 0x15,
|
||||||
|
"4X": 0x2A,
|
||||||
|
}
|
||||||
|
|
||||||
|
DPGA_GAINS = {
|
||||||
|
"1X": 0x0,
|
||||||
|
"2X": 0x1,
|
||||||
|
"4X": 0x2,
|
||||||
|
"8X": 0x3
|
||||||
|
}
|
||||||
|
|
||||||
|
ATM90E36Component = atm90e36_ns.class_(
|
||||||
|
"ATM90E36Component", cg.PollingComponent, spi.SPIDevice
|
||||||
|
)
|
||||||
|
|
||||||
|
ATM90E36_PHASE_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_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=0,
|
||||||
|
device_class=DEVICE_CLASS_POWER,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_VOLT_AMPS_REACTIVE,
|
||||||
|
icon=ICON_LIGHTBULB,
|
||||||
|
accuracy_decimals=2,
|
||||||
|
device_class=DEVICE_CLASS_REACTIVE_POWER,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_APPARENT_POWER): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_VOLT_AMPS,
|
||||||
|
accuracy_decimals=2,
|
||||||
|
device_class=DEVICE_CLASS_APPARENT_POWER,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema(
|
||||||
|
accuracy_decimals=2,
|
||||||
|
device_class=DEVICE_CLASS_POWER_FACTOR,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_WATT_HOURS,
|
||||||
|
accuracy_decimals=2,
|
||||||
|
device_class=DEVICE_CLASS_ENERGY,
|
||||||
|
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_WATT_HOURS,
|
||||||
|
accuracy_decimals=2,
|
||||||
|
device_class=DEVICE_CLASS_ENERGY,
|
||||||
|
state_class=STATE_CLASS_TOTAL_INCREASING,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_PHASE_ANGLE): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_DEGREES,
|
||||||
|
accuracy_decimals=2,
|
||||||
|
device_class=DEVICE_CLASS_POWER,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_HARMONIC_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_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_,
|
||||||
|
cv.Optional(CONF_OFFSET_CURRENT, default=0): cv.int_,
|
||||||
|
cv.Optional(CONF_OFFSET_ACTIVE_POWER, default=0): cv.int_,
|
||||||
|
cv.Optional(CONF_OFFSET_REACTIVE_POWER, default=0): cv.int_,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(ATM90E36Component),
|
||||||
|
cv.Optional(CONF_PHASE_A): ATM90E36_PHASE_SCHEMA,
|
||||||
|
cv.Optional(CONF_PHASE_B): ATM90E36_PHASE_SCHEMA,
|
||||||
|
cv.Optional(CONF_PHASE_C): ATM90E36_PHASE_SCHEMA,
|
||||||
|
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_HERTZ,
|
||||||
|
icon=ICON_CURRENT_AC,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_CHIP_TEMPERATURE): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
|
),
|
||||||
|
cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True),
|
||||||
|
cv.Optional(CONF_CURRENT_PHASES, default="3"): cv.enum(
|
||||||
|
CURRENT_PHASES, upper=True
|
||||||
|
),
|
||||||
|
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_ENABLE_OFFSET_CALIBRATION, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_ENABLE_GAIN_CALIBRATION, default=False): cv.boolean,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.polling_component_schema("60s"))
|
||||||
|
.extend(spi.spi_device_schema())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await spi.register_spi_device(var, config)
|
||||||
|
|
||||||
|
for i, phase in enumerate([CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]):
|
||||||
|
if phase not in config:
|
||||||
|
continue
|
||||||
|
conf = config[phase]
|
||||||
|
cg.add(var.set_volt_gain(i, conf[CONF_GAIN_VOLTAGE]))
|
||||||
|
cg.add(var.set_ct_gain(i, conf[CONF_GAIN_CT]))
|
||||||
|
if voltage_config := conf.get(CONF_VOLTAGE):
|
||||||
|
sens = await sensor.new_sensor(voltage_config)
|
||||||
|
cg.add(var.set_voltage_sensor(i, sens))
|
||||||
|
if current_config := conf.get(CONF_CURRENT):
|
||||||
|
sens = await sensor.new_sensor(current_config)
|
||||||
|
cg.add(var.set_current_sensor(i, sens))
|
||||||
|
if power_config := conf.get(CONF_POWER):
|
||||||
|
sens = await sensor.new_sensor(power_config)
|
||||||
|
cg.add(var.set_power_sensor(i, sens))
|
||||||
|
if reactive_power_config := conf.get(CONF_REACTIVE_POWER):
|
||||||
|
sens = await sensor.new_sensor(reactive_power_config)
|
||||||
|
cg.add(var.set_reactive_power_sensor(i, sens))
|
||||||
|
if apparent_power_config := conf.get(CONF_APPARENT_POWER):
|
||||||
|
sens = await sensor.new_sensor(apparent_power_config)
|
||||||
|
cg.add(var.set_apparent_power_sensor(i, sens))
|
||||||
|
if power_factor_config := conf.get(CONF_POWER_FACTOR):
|
||||||
|
sens = await sensor.new_sensor(power_factor_config)
|
||||||
|
cg.add(var.set_power_factor_sensor(i, sens))
|
||||||
|
if forward_active_energy_config := conf.get(CONF_FORWARD_ACTIVE_ENERGY):
|
||||||
|
sens = await sensor.new_sensor(forward_active_energy_config)
|
||||||
|
cg.add(var.set_forward_active_energy_sensor(i, sens))
|
||||||
|
if reverse_active_energy_config := conf.get(CONF_REVERSE_ACTIVE_ENERGY):
|
||||||
|
sens = await sensor.new_sensor(reverse_active_energy_config)
|
||||||
|
cg.add(var.set_reverse_active_energy_sensor(i, sens))
|
||||||
|
if phase_angle_config := conf.get(CONF_PHASE_ANGLE):
|
||||||
|
sens = await sensor.new_sensor(phase_angle_config)
|
||||||
|
cg.add(var.set_phase_angle_sensor(i, sens))
|
||||||
|
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 frequency_config := config.get(CONF_FREQUENCY):
|
||||||
|
sens = await sensor.new_sensor(frequency_config)
|
||||||
|
cg.add(var.set_freq_sensor(sens))
|
||||||
|
if chip_temperature_config := config.get(CONF_CHIP_TEMPERATURE):
|
||||||
|
sens = await sensor.new_sensor(chip_temperature_config)
|
||||||
|
cg.add(var.set_chip_temperature_sensor(sens))
|
||||||
|
cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
|
||||||
|
cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES]))
|
||||||
|
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]))
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import text_sensor
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_ID, CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C
|
||||||
|
|
||||||
|
from ..sensor import ATM90E36Component
|
||||||
|
|
||||||
|
CONF_PHASE_STATUS = "phase_status"
|
||||||
|
CONF_FREQUENCY_STATUS = "frequency_status"
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.use_id(ATM90E36Component),
|
||||||
|
cv.Optional(CONF_PHASE_STATUS): text_sensor.text_sensor_schema(
|
||||||
|
icon="mdi:flash-alert"
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_FREQUENCY_STATUS): text_sensor.text_sensor_schema(
|
||||||
|
icon="mdi:lightbulb-alert"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
parent = await cg.get_variable(config[CONF_ID])
|
||||||
|
|
||||||
|
if phase_cfg := config.get(CONF_PHASE_STATUS):
|
||||||
|
sens = await text_sensor.new_text_sensor(phase_cfg)
|
||||||
|
cg.add(parent.set_phase_status_text_sensor(sens))
|
||||||
|
|
||||||
|
if freq_status_config := config.get(CONF_FREQUENCY_STATUS):
|
||||||
|
sens = await text_sensor.new_text_sensor(freq_status_config)
|
||||||
|
cg.add(parent.set_freq_status_text_sensor(sens))
|
||||||
Reference in New Issue
Block a user