mirror of
https://github.com/esphome/esphome.git
synced 2024-11-30 10:44:13 +01:00
a1b28cb36e
Co-authored-by: David Monro <david.monro@anu.edu.au>
329 lines
14 KiB
C++
329 lines
14 KiB
C++
#include "atm90e32.h"
|
|
#include "atm90e32_reg.h"
|
|
#include "esphome/core/log.h"
|
|
|
|
namespace esphome {
|
|
namespace atm90e32 {
|
|
|
|
static const char *const TAG = "atm90e32";
|
|
|
|
void ATM90E32Component::update() {
|
|
if (this->read16_(ATM90E32_REGISTER_METEREN) != 1) {
|
|
this->status_set_warning();
|
|
return;
|
|
}
|
|
|
|
if (this->phase_[0].voltage_sensor_ != nullptr) {
|
|
this->phase_[0].voltage_sensor_->publish_state(this->get_line_voltage_a_());
|
|
}
|
|
if (this->phase_[1].voltage_sensor_ != nullptr) {
|
|
this->phase_[1].voltage_sensor_->publish_state(this->get_line_voltage_b_());
|
|
}
|
|
if (this->phase_[2].voltage_sensor_ != nullptr) {
|
|
this->phase_[2].voltage_sensor_->publish_state(this->get_line_voltage_c_());
|
|
}
|
|
if (this->phase_[0].current_sensor_ != nullptr) {
|
|
this->phase_[0].current_sensor_->publish_state(this->get_line_current_a_());
|
|
}
|
|
if (this->phase_[1].current_sensor_ != nullptr) {
|
|
this->phase_[1].current_sensor_->publish_state(this->get_line_current_b_());
|
|
}
|
|
if (this->phase_[2].current_sensor_ != nullptr) {
|
|
this->phase_[2].current_sensor_->publish_state(this->get_line_current_c_());
|
|
}
|
|
if (this->phase_[0].power_sensor_ != nullptr) {
|
|
this->phase_[0].power_sensor_->publish_state(this->get_active_power_a_());
|
|
}
|
|
if (this->phase_[1].power_sensor_ != nullptr) {
|
|
this->phase_[1].power_sensor_->publish_state(this->get_active_power_b_());
|
|
}
|
|
if (this->phase_[2].power_sensor_ != nullptr) {
|
|
this->phase_[2].power_sensor_->publish_state(this->get_active_power_c_());
|
|
}
|
|
if (this->phase_[0].reactive_power_sensor_ != nullptr) {
|
|
this->phase_[0].reactive_power_sensor_->publish_state(this->get_reactive_power_a_());
|
|
}
|
|
if (this->phase_[1].reactive_power_sensor_ != nullptr) {
|
|
this->phase_[1].reactive_power_sensor_->publish_state(this->get_reactive_power_b_());
|
|
}
|
|
if (this->phase_[2].reactive_power_sensor_ != nullptr) {
|
|
this->phase_[2].reactive_power_sensor_->publish_state(this->get_reactive_power_c_());
|
|
}
|
|
if (this->phase_[0].power_factor_sensor_ != nullptr) {
|
|
this->phase_[0].power_factor_sensor_->publish_state(this->get_power_factor_a_());
|
|
}
|
|
if (this->phase_[1].power_factor_sensor_ != nullptr) {
|
|
this->phase_[1].power_factor_sensor_->publish_state(this->get_power_factor_b_());
|
|
}
|
|
if (this->phase_[2].power_factor_sensor_ != nullptr) {
|
|
this->phase_[2].power_factor_sensor_->publish_state(this->get_power_factor_c_());
|
|
}
|
|
if (this->phase_[0].forward_active_energy_sensor_ != nullptr) {
|
|
this->phase_[0].forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_a_());
|
|
}
|
|
if (this->phase_[1].forward_active_energy_sensor_ != nullptr) {
|
|
this->phase_[1].forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_b_());
|
|
}
|
|
if (this->phase_[2].forward_active_energy_sensor_ != nullptr) {
|
|
this->phase_[2].forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_c_());
|
|
}
|
|
if (this->phase_[0].reverse_active_energy_sensor_ != nullptr) {
|
|
this->phase_[0].reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_a_());
|
|
}
|
|
if (this->phase_[1].reverse_active_energy_sensor_ != nullptr) {
|
|
this->phase_[1].reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_b_());
|
|
}
|
|
if (this->phase_[2].reverse_active_energy_sensor_ != nullptr) {
|
|
this->phase_[2].reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_c_());
|
|
}
|
|
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_());
|
|
}
|
|
this->status_clear_warning();
|
|
}
|
|
|
|
void ATM90E32Component::setup() {
|
|
ESP_LOGCONFIG(TAG, "Setting up ATM90E32 Component...");
|
|
this->spi_setup();
|
|
|
|
uint16_t mmode0 = 0x87; // 3P4W 50Hz
|
|
if (line_freq_ == 60) {
|
|
mmode0 |= 1 << 12; // sets 12th bit to 1, 60Hz
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
this->write16_(ATM90E32_REGISTER_SOFTRESET, 0x789A); // Perform soft reset
|
|
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x55AA); // enable register config access
|
|
this->write16_(ATM90E32_REGISTER_METEREN, 0x0001); // Enable Metering
|
|
if (this->read16_(ATM90E32_REGISTER_LASTSPIDATA) != 0x0001) {
|
|
ESP_LOGW(TAG, "Could not initialize ATM90E32 IC, check SPI settings");
|
|
this->mark_failed();
|
|
return;
|
|
}
|
|
this->write16_(ATM90E32_REGISTER_PLCONSTH, 0x0861); // PL Constant MSB (default) = 140625000
|
|
this->write16_(ATM90E32_REGISTER_PLCONSTL, 0xC468); // PL Constant LSB (default)
|
|
this->write16_(ATM90E32_REGISTER_ZXCONFIG, 0xD654); // ZX2, ZX1, ZX0 pin config
|
|
this->write16_(ATM90E32_REGISTER_MMODE0, mmode0); // Mode Config (frequency set in main program)
|
|
this->write16_(ATM90E32_REGISTER_MMODE1, pga_gain_); // PGA Gain Configuration for Current Channels
|
|
this->write16_(ATM90E32_REGISTER_PSTARTTH, 0x1D4C); // All Active Startup Power Threshold - 0.02A/0.00032 = 7500
|
|
this->write16_(ATM90E32_REGISTER_QSTARTTH, 0x1D4C); // All Reactive Startup Power Threshold - 50%
|
|
this->write16_(ATM90E32_REGISTER_PPHASETH, 0x02EE); // Each Phase Active Phase Threshold - 0.002A/0.00032 = 750
|
|
this->write16_(ATM90E32_REGISTER_QPHASETH, 0x02EE); // Each phase Reactive Phase Threshold - 10%
|
|
this->write16_(ATM90E32_REGISTER_UGAINA, this->phase_[0].volt_gain_); // A Voltage rms gain
|
|
this->write16_(ATM90E32_REGISTER_IGAINA, this->phase_[0].ct_gain_); // A line current gain
|
|
this->write16_(ATM90E32_REGISTER_UGAINB, this->phase_[1].volt_gain_); // B Voltage rms gain
|
|
this->write16_(ATM90E32_REGISTER_IGAINB, this->phase_[1].ct_gain_); // B line current gain
|
|
this->write16_(ATM90E32_REGISTER_UGAINC, this->phase_[2].volt_gain_); // C Voltage rms gain
|
|
this->write16_(ATM90E32_REGISTER_IGAINC, this->phase_[2].ct_gain_); // C line current gain
|
|
this->write16_(ATM90E32_REGISTER_CFGREGACCEN, 0x0000); // end configuration
|
|
}
|
|
|
|
void ATM90E32Component::dump_config() {
|
|
ESP_LOGCONFIG("", "ATM90E32:");
|
|
LOG_PIN(" CS Pin: ", this->cs_);
|
|
if (this->is_failed()) {
|
|
ESP_LOGE(TAG, "Communication with ATM90E32 failed!");
|
|
}
|
|
LOG_UPDATE_INTERVAL(this);
|
|
LOG_SENSOR(" ", "Voltage A", this->phase_[0].voltage_sensor_);
|
|
LOG_SENSOR(" ", "Current A", this->phase_[0].current_sensor_);
|
|
LOG_SENSOR(" ", "Power A", this->phase_[0].power_sensor_);
|
|
LOG_SENSOR(" ", "Reactive Power A", this->phase_[0].reactive_power_sensor_);
|
|
LOG_SENSOR(" ", "PF A", this->phase_[0].power_factor_sensor_);
|
|
LOG_SENSOR(" ", "Active Forward Energy A", this->phase_[0].forward_active_energy_sensor_);
|
|
LOG_SENSOR(" ", "Active Reverse Energy A", this->phase_[0].reverse_active_energy_sensor_);
|
|
LOG_SENSOR(" ", "Voltage B", this->phase_[1].voltage_sensor_);
|
|
LOG_SENSOR(" ", "Current B", this->phase_[1].current_sensor_);
|
|
LOG_SENSOR(" ", "Power B", this->phase_[1].power_sensor_);
|
|
LOG_SENSOR(" ", "Reactive Power B", this->phase_[1].reactive_power_sensor_);
|
|
LOG_SENSOR(" ", "PF B", this->phase_[1].power_factor_sensor_);
|
|
LOG_SENSOR(" ", "Active Forward Energy B", this->phase_[1].forward_active_energy_sensor_);
|
|
LOG_SENSOR(" ", "Active Reverse Energy B", this->phase_[1].reverse_active_energy_sensor_);
|
|
LOG_SENSOR(" ", "Voltage C", this->phase_[2].voltage_sensor_);
|
|
LOG_SENSOR(" ", "Current C", this->phase_[2].current_sensor_);
|
|
LOG_SENSOR(" ", "Power C", this->phase_[2].power_sensor_);
|
|
LOG_SENSOR(" ", "Reactive Power C", this->phase_[2].reactive_power_sensor_);
|
|
LOG_SENSOR(" ", "PF C", this->phase_[2].power_factor_sensor_);
|
|
LOG_SENSOR(" ", "Active Forward Energy C", this->phase_[2].forward_active_energy_sensor_);
|
|
LOG_SENSOR(" ", "Active Reverse Energy C", this->phase_[2].reverse_active_energy_sensor_);
|
|
LOG_SENSOR(" ", "Frequency", this->freq_sensor_);
|
|
LOG_SENSOR(" ", "Chip Temp", this->chip_temperature_sensor_);
|
|
}
|
|
float ATM90E32Component::get_setup_priority() const { return setup_priority::DATA; }
|
|
|
|
uint16_t ATM90E32Component::read16_(uint16_t a_register) {
|
|
uint8_t addrh = (1 << 7) | ((a_register >> 8) & 0x03);
|
|
uint8_t addrl = (a_register & 0xFF);
|
|
uint8_t data[2];
|
|
uint16_t output;
|
|
|
|
this->enable();
|
|
delayMicroseconds(10);
|
|
this->write_byte(addrh);
|
|
this->write_byte(addrl);
|
|
delayMicroseconds(4);
|
|
this->read_array(data, 2);
|
|
this->disable();
|
|
|
|
output = (uint16_t(data[0] & 0xFF) << 8) | (data[1] & 0xFF);
|
|
ESP_LOGVV(TAG, "read16_ 0x%04X output 0x%04X", a_register, output);
|
|
return output;
|
|
}
|
|
|
|
int ATM90E32Component::read32_(uint16_t addr_h, uint16_t addr_l) {
|
|
uint16_t val_h = this->read16_(addr_h);
|
|
uint16_t val_l = this->read16_(addr_l);
|
|
int32_t val = (val_h << 16) | val_l;
|
|
|
|
ESP_LOGVV(TAG, "read32_ addr_h 0x%04X val_h 0x%04X addr_l 0x%04X val_l 0x%04X = %d", addr_h, val_h, addr_l, val_l,
|
|
val);
|
|
|
|
return val;
|
|
}
|
|
|
|
void ATM90E32Component::write16_(uint16_t a_register, uint16_t val) {
|
|
uint8_t addrh = (a_register >> 8) & 0x03;
|
|
uint8_t addrl = (a_register & 0xFF);
|
|
|
|
ESP_LOGVV(TAG, "write16_ 0x%04X val 0x%04X", a_register, val);
|
|
this->enable();
|
|
delayMicroseconds(10);
|
|
this->write_byte(addrh);
|
|
this->write_byte(addrl);
|
|
delayMicroseconds(4);
|
|
this->write_byte((val >> 8) & 0xff);
|
|
this->write_byte(val & 0xFF);
|
|
this->disable();
|
|
}
|
|
|
|
float ATM90E32Component::get_line_voltage_a_() {
|
|
uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMSA);
|
|
return (float) voltage / 100;
|
|
}
|
|
float ATM90E32Component::get_line_voltage_b_() {
|
|
uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMSB);
|
|
return (float) voltage / 100;
|
|
}
|
|
float ATM90E32Component::get_line_voltage_c_() {
|
|
uint16_t voltage = this->read16_(ATM90E32_REGISTER_URMSC);
|
|
return (float) voltage / 100;
|
|
}
|
|
float ATM90E32Component::get_line_current_a_() {
|
|
uint16_t current = this->read16_(ATM90E32_REGISTER_IRMSA);
|
|
return (float) current / 1000;
|
|
}
|
|
float ATM90E32Component::get_line_current_b_() {
|
|
uint16_t current = this->read16_(ATM90E32_REGISTER_IRMSB);
|
|
return (float) current / 1000;
|
|
}
|
|
float ATM90E32Component::get_line_current_c_() {
|
|
uint16_t current = this->read16_(ATM90E32_REGISTER_IRMSC);
|
|
return (float) current / 1000;
|
|
}
|
|
float ATM90E32Component::get_active_power_a_() {
|
|
int val = this->read32_(ATM90E32_REGISTER_PMEANA, ATM90E32_REGISTER_PMEANALSB);
|
|
return val * 0.00032f;
|
|
}
|
|
float ATM90E32Component::get_active_power_b_() {
|
|
int val = this->read32_(ATM90E32_REGISTER_PMEANB, ATM90E32_REGISTER_PMEANBLSB);
|
|
return val * 0.00032f;
|
|
}
|
|
float ATM90E32Component::get_active_power_c_() {
|
|
int val = this->read32_(ATM90E32_REGISTER_PMEANC, ATM90E32_REGISTER_PMEANCLSB);
|
|
return val * 0.00032f;
|
|
}
|
|
float ATM90E32Component::get_reactive_power_a_() {
|
|
int val = this->read32_(ATM90E32_REGISTER_QMEANA, ATM90E32_REGISTER_QMEANALSB);
|
|
return val * 0.00032f;
|
|
}
|
|
float ATM90E32Component::get_reactive_power_b_() {
|
|
int val = this->read32_(ATM90E32_REGISTER_QMEANB, ATM90E32_REGISTER_QMEANBLSB);
|
|
return val * 0.00032f;
|
|
}
|
|
float ATM90E32Component::get_reactive_power_c_() {
|
|
int val = this->read32_(ATM90E32_REGISTER_QMEANC, ATM90E32_REGISTER_QMEANCLSB);
|
|
return val * 0.00032f;
|
|
}
|
|
float ATM90E32Component::get_power_factor_a_() {
|
|
int16_t pf = this->read16_(ATM90E32_REGISTER_PFMEANA);
|
|
return (float) pf / 1000;
|
|
}
|
|
float ATM90E32Component::get_power_factor_b_() {
|
|
int16_t pf = this->read16_(ATM90E32_REGISTER_PFMEANB);
|
|
return (float) pf / 1000;
|
|
}
|
|
float ATM90E32Component::get_power_factor_c_() {
|
|
int16_t pf = this->read16_(ATM90E32_REGISTER_PFMEANC);
|
|
return (float) pf / 1000;
|
|
}
|
|
float ATM90E32Component::get_forward_active_energy_a_() {
|
|
uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGYA);
|
|
if ((UINT32_MAX - this->phase_[0].cumulative_forward_active_energy_) > val) {
|
|
this->phase_[0].cumulative_forward_active_energy_ += val;
|
|
} else {
|
|
this->phase_[0].cumulative_forward_active_energy_ = val;
|
|
}
|
|
return ((float) this->phase_[0].cumulative_forward_active_energy_ * 10 / 3200);
|
|
}
|
|
float ATM90E32Component::get_forward_active_energy_b_() {
|
|
uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGYB);
|
|
if (UINT32_MAX - this->phase_[1].cumulative_forward_active_energy_ > val) {
|
|
this->phase_[1].cumulative_forward_active_energy_ += val;
|
|
} else {
|
|
this->phase_[1].cumulative_forward_active_energy_ = val;
|
|
}
|
|
return ((float) this->phase_[1].cumulative_forward_active_energy_ * 10 / 3200);
|
|
}
|
|
float ATM90E32Component::get_forward_active_energy_c_() {
|
|
uint16_t val = this->read16_(ATM90E32_REGISTER_APENERGYC);
|
|
if (UINT32_MAX - this->phase_[2].cumulative_forward_active_energy_ > val) {
|
|
this->phase_[2].cumulative_forward_active_energy_ += val;
|
|
} else {
|
|
this->phase_[2].cumulative_forward_active_energy_ = val;
|
|
}
|
|
return ((float) this->phase_[2].cumulative_forward_active_energy_ * 10 / 3200);
|
|
}
|
|
float ATM90E32Component::get_reverse_active_energy_a_() {
|
|
uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGYA);
|
|
if (UINT32_MAX - this->phase_[0].cumulative_reverse_active_energy_ > val) {
|
|
this->phase_[0].cumulative_reverse_active_energy_ += val;
|
|
} else {
|
|
this->phase_[0].cumulative_reverse_active_energy_ = val;
|
|
}
|
|
return ((float) this->phase_[0].cumulative_reverse_active_energy_ * 10 / 3200);
|
|
}
|
|
float ATM90E32Component::get_reverse_active_energy_b_() {
|
|
uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGYB);
|
|
if (UINT32_MAX - this->phase_[1].cumulative_reverse_active_energy_ > val) {
|
|
this->phase_[1].cumulative_reverse_active_energy_ += val;
|
|
} else {
|
|
this->phase_[1].cumulative_reverse_active_energy_ = val;
|
|
}
|
|
return ((float) this->phase_[1].cumulative_reverse_active_energy_ * 10 / 3200);
|
|
}
|
|
float ATM90E32Component::get_reverse_active_energy_c_() {
|
|
uint16_t val = this->read16_(ATM90E32_REGISTER_ANENERGYC);
|
|
if (UINT32_MAX - this->phase_[2].cumulative_reverse_active_energy_ > val) {
|
|
this->phase_[2].cumulative_reverse_active_energy_ += val;
|
|
} else {
|
|
this->phase_[2].cumulative_reverse_active_energy_ = val;
|
|
}
|
|
return ((float) this->phase_[2].cumulative_reverse_active_energy_ * 10 / 3200);
|
|
}
|
|
float ATM90E32Component::get_frequency_() {
|
|
uint16_t freq = this->read16_(ATM90E32_REGISTER_FREQ);
|
|
return (float) freq / 100;
|
|
}
|
|
float ATM90E32Component::get_chip_temperature_() {
|
|
uint16_t ctemp = this->read16_(ATM90E32_REGISTER_TEMP);
|
|
return (float) ctemp;
|
|
}
|
|
} // namespace atm90e32
|
|
} // namespace esphome
|