mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
Add support for ATM90E26 (#4366)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
bbf3d382e8
commit
8c5978599a
7 changed files with 555 additions and 0 deletions
|
@ -32,6 +32,7 @@ esphome/components/api/* @OttoWinter
|
||||||
esphome/components/as7341/* @mrgnr
|
esphome/components/as7341/* @mrgnr
|
||||||
esphome/components/async_tcp/* @OttoWinter
|
esphome/components/async_tcp/* @OttoWinter
|
||||||
esphome/components/atc_mithermometer/* @ahpohl
|
esphome/components/atc_mithermometer/* @ahpohl
|
||||||
|
esphome/components/atm90e26/* @danieltwagner
|
||||||
esphome/components/b_parasite/* @rbaron
|
esphome/components/b_parasite/* @rbaron
|
||||||
esphome/components/ballu/* @bazuchan
|
esphome/components/ballu/* @bazuchan
|
||||||
esphome/components/bang_bang/* @OttoWinter
|
esphome/components/bang_bang/* @OttoWinter
|
||||||
|
|
1
esphome/components/atm90e26/__init__.py
Normal file
1
esphome/components/atm90e26/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CODEOWNERS = ["@danieltwagner"]
|
235
esphome/components/atm90e26/atm90e26.cpp
Normal file
235
esphome/components/atm90e26/atm90e26.cpp
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
#include "atm90e26.h"
|
||||||
|
#include "atm90e26_reg.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace atm90e26 {
|
||||||
|
|
||||||
|
static const char *const TAG = "atm90e26";
|
||||||
|
|
||||||
|
void ATM90E26Component::update() {
|
||||||
|
if (this->read16_(ATM90E26_REGISTER_FUNCEN) != 0x0030) {
|
||||||
|
this->status_set_warning();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->voltage_sensor_ != nullptr) {
|
||||||
|
this->voltage_sensor_->publish_state(this->get_line_voltage_());
|
||||||
|
}
|
||||||
|
if (this->current_sensor_ != nullptr) {
|
||||||
|
this->current_sensor_->publish_state(this->get_line_current_());
|
||||||
|
}
|
||||||
|
if (this->power_sensor_ != nullptr) {
|
||||||
|
this->power_sensor_->publish_state(this->get_active_power_());
|
||||||
|
}
|
||||||
|
if (this->reactive_power_sensor_ != nullptr) {
|
||||||
|
this->reactive_power_sensor_->publish_state(this->get_reactive_power_());
|
||||||
|
}
|
||||||
|
if (this->power_factor_sensor_ != nullptr) {
|
||||||
|
this->power_factor_sensor_->publish_state(this->get_power_factor_());
|
||||||
|
}
|
||||||
|
if (this->forward_active_energy_sensor_ != nullptr) {
|
||||||
|
this->forward_active_energy_sensor_->publish_state(this->get_forward_active_energy_());
|
||||||
|
}
|
||||||
|
if (this->reverse_active_energy_sensor_ != nullptr) {
|
||||||
|
this->reverse_active_energy_sensor_->publish_state(this->get_reverse_active_energy_());
|
||||||
|
}
|
||||||
|
if (this->freq_sensor_ != nullptr) {
|
||||||
|
this->freq_sensor_->publish_state(this->get_frequency_());
|
||||||
|
}
|
||||||
|
this->status_clear_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATM90E26Component::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up ATM90E26 Component...");
|
||||||
|
this->spi_setup();
|
||||||
|
|
||||||
|
uint16_t mmode = 0x422; // default values for everything but L/N line current gains
|
||||||
|
mmode |= (gain_pga_ & 0x7) << 13;
|
||||||
|
mmode |= (n_line_gain_ & 0x3) << 11;
|
||||||
|
|
||||||
|
this->write16_(ATM90E26_REGISTER_SOFTRESET, 0x789A); // Perform soft reset
|
||||||
|
this->write16_(ATM90E26_REGISTER_FUNCEN,
|
||||||
|
0x0030); // Voltage sag irq=1, report on warnout pin=1, energy dir change irq=0
|
||||||
|
uint16_t read = this->read16_(ATM90E26_REGISTER_LASTDATA);
|
||||||
|
if (read != 0x0030) {
|
||||||
|
ESP_LOGW(TAG, "Could not initialize ATM90E26 IC, check SPI settings: %d", read);
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: 100 * <nominal voltage, e.g. 230> * sqrt(2) * <fraction of nominal, e.g. 0.9> / (4 * gain_voltage/32768)
|
||||||
|
this->write16_(ATM90E26_REGISTER_SAGTH, 0x17DD); // Voltage sag threshhold 0x1F2F
|
||||||
|
|
||||||
|
// Set metering calibration values
|
||||||
|
this->write16_(ATM90E26_REGISTER_CALSTART, 0x5678); // CAL Metering calibration startup command
|
||||||
|
|
||||||
|
// Configure
|
||||||
|
this->write16_(ATM90E26_REGISTER_MMODE, mmode); // Metering Mode Configuration (see above)
|
||||||
|
|
||||||
|
this->write16_(ATM90E26_REGISTER_PLCONSTH, (pl_const_ >> 16)); // PL Constant MSB
|
||||||
|
this->write16_(ATM90E26_REGISTER_PLCONSTL, pl_const_ & 0xFFFF); // PL Constant LSB
|
||||||
|
|
||||||
|
// Calibrate this to be 1 pulse per Wh
|
||||||
|
this->write16_(ATM90E26_REGISTER_LGAIN, gain_metering_); // L Line Calibration Gain (active power metering)
|
||||||
|
this->write16_(ATM90E26_REGISTER_LPHI, 0x0000); // L Line Calibration Angle
|
||||||
|
this->write16_(ATM90E26_REGISTER_NGAIN, 0x0000); // N Line Calibration Gain
|
||||||
|
this->write16_(ATM90E26_REGISTER_NPHI, 0x0000); // N Line Calibration Angle
|
||||||
|
this->write16_(ATM90E26_REGISTER_PSTARTTH, 0x08BD); // Active Startup Power Threshold (default) = 2237
|
||||||
|
this->write16_(ATM90E26_REGISTER_PNOLTH, 0x0000); // Active No-Load Power Threshold
|
||||||
|
this->write16_(ATM90E26_REGISTER_QSTARTTH, 0x0AEC); // Reactive Startup Power Threshold (default) = 2796
|
||||||
|
this->write16_(ATM90E26_REGISTER_QNOLTH, 0x0000); // Reactive No-Load Power Threshold
|
||||||
|
|
||||||
|
// Compute Checksum for the registers we set above
|
||||||
|
// low byte = sum of all bytes
|
||||||
|
uint16_t cs =
|
||||||
|
((mmode >> 8) + (mmode & 0xFF) + (pl_const_ >> 24) + ((pl_const_ >> 16) & 0xFF) + ((pl_const_ >> 8) & 0xFF) +
|
||||||
|
(pl_const_ & 0xFF) + (gain_metering_ >> 8) + (gain_metering_ & 0xFF) + 0x08 + 0xBD + 0x0A + 0xEC) &
|
||||||
|
0xFF;
|
||||||
|
// high byte = XOR of all bytes
|
||||||
|
cs |= ((mmode >> 8) ^ (mmode & 0xFF) ^ (pl_const_ >> 24) ^ ((pl_const_ >> 16) & 0xFF) ^ ((pl_const_ >> 8) & 0xFF) ^
|
||||||
|
(pl_const_ & 0xFF) ^ (gain_metering_ >> 8) ^ (gain_metering_ & 0xFF) ^ 0x08 ^ 0xBD ^ 0x0A ^ 0xEC)
|
||||||
|
<< 8;
|
||||||
|
|
||||||
|
this->write16_(ATM90E26_REGISTER_CS1, cs);
|
||||||
|
ESP_LOGVV(TAG, "Set CS1 to: 0x%04X", cs);
|
||||||
|
|
||||||
|
// Set measurement calibration values
|
||||||
|
this->write16_(ATM90E26_REGISTER_ADJSTART, 0x5678); // Measurement calibration startup command, registers 31-3A
|
||||||
|
this->write16_(ATM90E26_REGISTER_UGAIN, gain_voltage_); // Voltage RMS gain
|
||||||
|
this->write16_(ATM90E26_REGISTER_IGAINL, gain_ct_); // L line current RMS gain
|
||||||
|
this->write16_(ATM90E26_REGISTER_IGAINN, 0x7530); // N Line Current RMS Gain
|
||||||
|
this->write16_(ATM90E26_REGISTER_UOFFSET, 0x0000); // Voltage Offset
|
||||||
|
this->write16_(ATM90E26_REGISTER_IOFFSETL, 0x0000); // L Line Current Offset
|
||||||
|
this->write16_(ATM90E26_REGISTER_IOFFSETN, 0x0000); // N Line Current Offse
|
||||||
|
this->write16_(ATM90E26_REGISTER_POFFSETL, 0x0000); // L Line Active Power Offset
|
||||||
|
this->write16_(ATM90E26_REGISTER_QOFFSETL, 0x0000); // L Line Reactive Power Offset
|
||||||
|
this->write16_(ATM90E26_REGISTER_POFFSETN, 0x0000); // N Line Active Power Offset
|
||||||
|
this->write16_(ATM90E26_REGISTER_QOFFSETN, 0x0000); // N Line Reactive Power Offset
|
||||||
|
|
||||||
|
// Compute Checksum for the registers we set above
|
||||||
|
cs = ((gain_voltage_ >> 8) + (gain_voltage_ & 0xFF) + (gain_ct_ >> 8) + (gain_ct_ & 0xFF) + 0x75 + 0x30) & 0xFF;
|
||||||
|
cs |= ((gain_voltage_ >> 8) ^ (gain_voltage_ & 0xFF) ^ (gain_ct_ >> 8) ^ (gain_ct_ & 0xFF) ^ 0x75 ^ 0x30) << 8;
|
||||||
|
this->write16_(ATM90E26_REGISTER_CS2, cs);
|
||||||
|
ESP_LOGVV(TAG, "Set CS2 to: 0x%04X", cs);
|
||||||
|
|
||||||
|
this->write16_(ATM90E26_REGISTER_CALSTART,
|
||||||
|
0x8765); // Checks correctness of 21-2B registers and starts normal metering if ok
|
||||||
|
this->write16_(ATM90E26_REGISTER_ADJSTART,
|
||||||
|
0x8765); // Checks correctness of 31-3A registers and starts normal measurement if ok
|
||||||
|
|
||||||
|
uint16_t sys_status = this->read16_(ATM90E26_REGISTER_SYSSTATUS);
|
||||||
|
if (sys_status & 0xC000) { // Checksum 1 Error
|
||||||
|
|
||||||
|
ESP_LOGW(TAG, "Could not initialize ATM90E26 IC: CS1 was incorrect, expected: 0x%04X",
|
||||||
|
this->read16_(ATM90E26_REGISTER_CS1));
|
||||||
|
this->mark_failed();
|
||||||
|
}
|
||||||
|
if (sys_status & 0x3000) { // Checksum 2 Error
|
||||||
|
ESP_LOGW(TAG, "Could not initialize ATM90E26 IC: CS2 was incorrect, expected: 0x%04X",
|
||||||
|
this->read16_(ATM90E26_REGISTER_CS2));
|
||||||
|
this->mark_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATM90E26Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG("", "ATM90E26:");
|
||||||
|
LOG_PIN(" CS Pin: ", this->cs_);
|
||||||
|
if (this->is_failed()) {
|
||||||
|
ESP_LOGE(TAG, "Communication with ATM90E26 failed!");
|
||||||
|
}
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
LOG_SENSOR(" ", "Voltage A", this->voltage_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Current A", this->current_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Power A", this->power_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Reactive Power A", this->reactive_power_sensor_);
|
||||||
|
LOG_SENSOR(" ", "PF A", this->power_factor_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Active Forward Energy A", this->forward_active_energy_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Active Reverse Energy A", this->reverse_active_energy_sensor_);
|
||||||
|
LOG_SENSOR(" ", "Frequency", this->freq_sensor_);
|
||||||
|
}
|
||||||
|
float ATM90E26Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
uint16_t ATM90E26Component::read16_(uint8_t a_register) {
|
||||||
|
uint8_t data[2];
|
||||||
|
uint16_t output;
|
||||||
|
|
||||||
|
this->enable();
|
||||||
|
delayMicroseconds(4);
|
||||||
|
this->write_byte(a_register | 0x80);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATM90E26Component::write16_(uint8_t a_register, uint16_t val) {
|
||||||
|
ESP_LOGVV(TAG, "write16_ 0x%04X val 0x%04X", a_register, val);
|
||||||
|
this->enable();
|
||||||
|
delayMicroseconds(4);
|
||||||
|
this->write_byte(a_register & 0x7F);
|
||||||
|
delayMicroseconds(4);
|
||||||
|
this->write_byte((val >> 8) & 0xFF);
|
||||||
|
this->write_byte(val & 0xFF);
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_line_current_() {
|
||||||
|
uint16_t current = this->read16_(ATM90E26_REGISTER_IRMS);
|
||||||
|
return current / 1000.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_line_voltage_() {
|
||||||
|
uint16_t voltage = this->read16_(ATM90E26_REGISTER_URMS);
|
||||||
|
return voltage / 100.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_active_power_() {
|
||||||
|
int16_t val = this->read16_(ATM90E26_REGISTER_PMEAN); // two's complement
|
||||||
|
return (float) val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_reactive_power_() {
|
||||||
|
int16_t val = this->read16_(ATM90E26_REGISTER_QMEAN); // two's complement
|
||||||
|
return (float) val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_power_factor_() {
|
||||||
|
uint16_t val = this->read16_(ATM90E26_REGISTER_POWERF); // signed
|
||||||
|
if (val & 0x8000) {
|
||||||
|
return -(val & 0x7FF) / 1000.0f;
|
||||||
|
} else {
|
||||||
|
return val / 1000.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_forward_active_energy_() {
|
||||||
|
uint16_t val = this->read16_(ATM90E26_REGISTER_APENERGY);
|
||||||
|
if ((UINT32_MAX - this->cumulative_forward_active_energy_) > val) {
|
||||||
|
this->cumulative_forward_active_energy_ += val;
|
||||||
|
} else {
|
||||||
|
this->cumulative_forward_active_energy_ = val;
|
||||||
|
}
|
||||||
|
// The register holds thenths of pulses, we want to output Wh
|
||||||
|
return (this->cumulative_forward_active_energy_ * 100.0f / meter_constant_);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_reverse_active_energy_() {
|
||||||
|
uint16_t val = this->read16_(ATM90E26_REGISTER_ANENERGY);
|
||||||
|
if (UINT32_MAX - this->cumulative_reverse_active_energy_ > val) {
|
||||||
|
this->cumulative_reverse_active_energy_ += val;
|
||||||
|
} else {
|
||||||
|
this->cumulative_reverse_active_energy_ = val;
|
||||||
|
}
|
||||||
|
return (this->cumulative_reverse_active_energy_ * 100.0f / meter_constant_);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ATM90E26Component::get_frequency_() {
|
||||||
|
uint16_t freq = this->read16_(ATM90E26_REGISTER_FREQ);
|
||||||
|
return freq / 100.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atm90e26
|
||||||
|
} // namespace esphome
|
72
esphome/components/atm90e26/atm90e26.h
Normal file
72
esphome/components/atm90e26/atm90e26.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/sensor/sensor.h"
|
||||||
|
#include "esphome/components/spi/spi.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace atm90e26 {
|
||||||
|
|
||||||
|
class ATM90E26Component : public PollingComponent,
|
||||||
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH,
|
||||||
|
spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_200KHZ> {
|
||||||
|
public:
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
void set_voltage_sensor(sensor::Sensor *obj) { this->voltage_sensor_ = obj; }
|
||||||
|
void set_current_sensor(sensor::Sensor *obj) { this->current_sensor_ = obj; }
|
||||||
|
void set_power_sensor(sensor::Sensor *obj) { this->power_sensor_ = obj; }
|
||||||
|
void set_reactive_power_sensor(sensor::Sensor *obj) { this->reactive_power_sensor_ = obj; }
|
||||||
|
void set_forward_active_energy_sensor(sensor::Sensor *obj) { this->forward_active_energy_sensor_ = obj; }
|
||||||
|
void set_reverse_active_energy_sensor(sensor::Sensor *obj) { this->reverse_active_energy_sensor_ = obj; }
|
||||||
|
void set_power_factor_sensor(sensor::Sensor *obj) { this->power_factor_sensor_ = obj; }
|
||||||
|
void set_freq_sensor(sensor::Sensor *freq_sensor) { freq_sensor_ = freq_sensor; }
|
||||||
|
void set_line_freq(int freq) { line_freq_ = freq; }
|
||||||
|
void set_meter_constant(float val) { meter_constant_ = val; }
|
||||||
|
void set_pl_const(uint32_t pl_const) { pl_const_ = pl_const; }
|
||||||
|
void set_gain_metering(uint16_t gain) { this->gain_metering_ = gain; }
|
||||||
|
void set_gain_voltage(uint16_t gain) { this->gain_voltage_ = gain; }
|
||||||
|
void set_gain_ct(uint16_t gain) { this->gain_ct_ = gain; }
|
||||||
|
void set_gain_pga(uint16_t gain) { gain_pga_ = gain; }
|
||||||
|
void set_n_line_gain(uint16_t gain) { n_line_gain_ = gain; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint16_t read16_(uint8_t a_register);
|
||||||
|
int read32_(uint8_t addr_h, uint8_t addr_l);
|
||||||
|
void write16_(uint8_t a_register, uint16_t val);
|
||||||
|
|
||||||
|
float get_line_voltage_();
|
||||||
|
float get_line_current_();
|
||||||
|
float get_active_power_();
|
||||||
|
float get_reactive_power_();
|
||||||
|
float get_power_factor_();
|
||||||
|
float get_forward_active_energy_();
|
||||||
|
float get_reverse_active_energy_();
|
||||||
|
float get_frequency_();
|
||||||
|
float get_chip_temperature_();
|
||||||
|
|
||||||
|
sensor::Sensor *freq_sensor_{nullptr};
|
||||||
|
sensor::Sensor *voltage_sensor_{nullptr};
|
||||||
|
sensor::Sensor *current_sensor_{nullptr};
|
||||||
|
sensor::Sensor *power_sensor_{nullptr};
|
||||||
|
sensor::Sensor *reactive_power_sensor_{nullptr};
|
||||||
|
sensor::Sensor *power_factor_sensor_{nullptr};
|
||||||
|
sensor::Sensor *forward_active_energy_sensor_{nullptr};
|
||||||
|
sensor::Sensor *reverse_active_energy_sensor_{nullptr};
|
||||||
|
uint32_t cumulative_forward_active_energy_{0};
|
||||||
|
uint32_t cumulative_reverse_active_energy_{0};
|
||||||
|
uint16_t gain_metering_{7481};
|
||||||
|
uint16_t gain_voltage_{26400};
|
||||||
|
uint16_t gain_ct_{31251};
|
||||||
|
uint16_t gain_pga_{0x4};
|
||||||
|
uint16_t n_line_gain_{0x2};
|
||||||
|
int line_freq_{60};
|
||||||
|
float meter_constant_{3200.0f};
|
||||||
|
uint32_t pl_const_{1429876};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atm90e26
|
||||||
|
} // namespace esphome
|
70
esphome/components/atm90e26/atm90e26_reg.h
Normal file
70
esphome/components/atm90e26/atm90e26_reg.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace atm90e26 {
|
||||||
|
|
||||||
|
/* Status and Special Register */
|
||||||
|
static const uint8_t ATM90E26_REGISTER_SOFTRESET = 0x00; // Software Reset
|
||||||
|
static const uint8_t ATM90E26_REGISTER_SYSSTATUS = 0x01; // System Status
|
||||||
|
static const uint8_t ATM90E26_REGISTER_FUNCEN = 0x02; // Function Enable
|
||||||
|
static const uint8_t ATM90E26_REGISTER_SAGTH = 0x03; // Voltage Sag Threshold
|
||||||
|
static const uint8_t ATM90E26_REGISTER_SMALLPMOD = 0x04; // Small-Power Mode
|
||||||
|
static const uint8_t ATM90E26_REGISTER_LASTDATA = 0x06; // Last Read/Write SPI/UART Value
|
||||||
|
|
||||||
|
/* Metering Calibration and Configuration Register */
|
||||||
|
static const uint8_t ATM90E26_REGISTER_LSB = 0x08; // RMS/Power 16-bit LSB
|
||||||
|
static const uint8_t ATM90E26_REGISTER_CALSTART = 0x20; // Calibration Start Command
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PLCONSTH = 0x21; // High Word of PL_Constant
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PLCONSTL = 0x22; // Low Word of PL_Constant
|
||||||
|
static const uint8_t ATM90E26_REGISTER_LGAIN = 0x23; // L Line Calibration Gain
|
||||||
|
static const uint8_t ATM90E26_REGISTER_LPHI = 0x24; // L Line Calibration Angle
|
||||||
|
static const uint8_t ATM90E26_REGISTER_NGAIN = 0x25; // N Line Calibration Gain
|
||||||
|
static const uint8_t ATM90E26_REGISTER_NPHI = 0x26; // N Line Calibration Angle
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PSTARTTH = 0x27; // Active Startup Power Threshold
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PNOLTH = 0x28; // Active No-Load Power Threshold
|
||||||
|
static const uint8_t ATM90E26_REGISTER_QSTARTTH = 0x29; // Reactive Startup Power Threshold
|
||||||
|
static const uint8_t ATM90E26_REGISTER_QNOLTH = 0x2A; // Reactive No-Load Power Threshold
|
||||||
|
static const uint8_t ATM90E26_REGISTER_MMODE = 0x2B; // Metering Mode Configuration
|
||||||
|
static const uint8_t ATM90E26_REGISTER_CS1 = 0x2C; // Checksum 1
|
||||||
|
|
||||||
|
/* Measurement Calibration Register */
|
||||||
|
static const uint8_t ATM90E26_REGISTER_ADJSTART = 0x30; // Measurement Calibration Start Command
|
||||||
|
static const uint8_t ATM90E26_REGISTER_UGAIN = 0x31; // Voltage RMS Gain
|
||||||
|
static const uint8_t ATM90E26_REGISTER_IGAINL = 0x32; // L Line Current RMS Gain
|
||||||
|
static const uint8_t ATM90E26_REGISTER_IGAINN = 0x33; // N Line Current RMS Gain
|
||||||
|
static const uint8_t ATM90E26_REGISTER_UOFFSET = 0x34; // Voltage Offset
|
||||||
|
static const uint8_t ATM90E26_REGISTER_IOFFSETL = 0x35; // L Line Current Offset
|
||||||
|
static const uint8_t ATM90E26_REGISTER_IOFFSETN = 0x36; // N Line Current Offse
|
||||||
|
static const uint8_t ATM90E26_REGISTER_POFFSETL = 0x37; // L Line Active Power Offset
|
||||||
|
static const uint8_t ATM90E26_REGISTER_QOFFSETL = 0x38; // L Line Reactive Power Offset
|
||||||
|
static const uint8_t ATM90E26_REGISTER_POFFSETN = 0x39; // N Line Active Power Offset
|
||||||
|
static const uint8_t ATM90E26_REGISTER_QOFFSETN = 0x3A; // N Line Reactive Power Offset
|
||||||
|
static const uint8_t ATM90E26_REGISTER_CS2 = 0x3B; // Checksum 2
|
||||||
|
|
||||||
|
/* Energy Register */
|
||||||
|
static const uint8_t ATM90E26_REGISTER_APENERGY = 0x40; // Forward Active Energy
|
||||||
|
static const uint8_t ATM90E26_REGISTER_ANENERGY = 0x41; // Reverse Active Energy
|
||||||
|
static const uint8_t ATM90E26_REGISTER_ATENERGY = 0x42; // Absolute Active Energy
|
||||||
|
static const uint8_t ATM90E26_REGISTER_RPENERGY = 0x43; // Forward (Inductive) Reactive Energy
|
||||||
|
static const uint8_t ATM90E26_REGISTER_RNENERG = 0x44; // Reverse (Capacitive) Reactive Energy
|
||||||
|
static const uint8_t ATM90E26_REGISTER_RTENERGY = 0x45; // Absolute Reactive Energy
|
||||||
|
static const uint8_t ATM90E26_REGISTER_ENSTATUS = 0x46; // Metering Status
|
||||||
|
|
||||||
|
/* Measurement Register */
|
||||||
|
static const uint8_t ATM90E26_REGISTER_IRMS = 0x48; // L Line Current RMS
|
||||||
|
static const uint8_t ATM90E26_REGISTER_URMS = 0x49; // Voltage RMS
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PMEAN = 0x4A; // L Line Mean Active Power
|
||||||
|
static const uint8_t ATM90E26_REGISTER_QMEAN = 0x4B; // L Line Mean Reactive Power
|
||||||
|
static const uint8_t ATM90E26_REGISTER_FREQ = 0x4C; // Voltage Frequency
|
||||||
|
static const uint8_t ATM90E26_REGISTER_POWERF = 0x4D; // L Line Power Factor
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PANGLE = 0x4E; // Phase Angle between Voltage and L Line Current
|
||||||
|
static const uint8_t ATM90E26_REGISTER_SMEAN = 0x4F; // L Line Mean Apparent Power
|
||||||
|
static const uint8_t ATM90E26_REGISTER_IRMS2 = 0x68; // N Line Current rms
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PMEAN2 = 0x6A; // N Line Mean Active Power
|
||||||
|
static const uint8_t ATM90E26_REGISTER_QMEAN2 = 0x6B; // N Line Mean Reactive Power
|
||||||
|
static const uint8_t ATM90E26_REGISTER_POWERF2 = 0x6D; // N Line Power Factor
|
||||||
|
static const uint8_t ATM90E26_REGISTER_PANGLE2 = 0x6E; // Phase Angle between Voltage and N Line Current
|
||||||
|
static const uint8_t ATM90E26_REGISTER_SMEAN2 = 0x6F; // N Line Mean Apparent Power
|
||||||
|
|
||||||
|
} // namespace atm90e26
|
||||||
|
} // namespace esphome
|
157
esphome/components/atm90e26/sensor.py
Normal file
157
esphome/components/atm90e26/sensor.py
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import sensor, spi
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_REACTIVE_POWER,
|
||||||
|
CONF_VOLTAGE,
|
||||||
|
CONF_CURRENT,
|
||||||
|
CONF_POWER,
|
||||||
|
CONF_POWER_FACTOR,
|
||||||
|
CONF_FREQUENCY,
|
||||||
|
CONF_FORWARD_ACTIVE_ENERGY,
|
||||||
|
CONF_REVERSE_ACTIVE_ENERGY,
|
||||||
|
DEVICE_CLASS_CURRENT,
|
||||||
|
DEVICE_CLASS_ENERGY,
|
||||||
|
DEVICE_CLASS_POWER,
|
||||||
|
DEVICE_CLASS_POWER_FACTOR,
|
||||||
|
DEVICE_CLASS_VOLTAGE,
|
||||||
|
ICON_LIGHTBULB,
|
||||||
|
ICON_CURRENT_AC,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
STATE_CLASS_TOTAL_INCREASING,
|
||||||
|
UNIT_HERTZ,
|
||||||
|
UNIT_VOLT,
|
||||||
|
UNIT_AMPERE,
|
||||||
|
UNIT_WATT,
|
||||||
|
UNIT_VOLT_AMPS_REACTIVE,
|
||||||
|
UNIT_WATT_HOURS,
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_LINE_FREQUENCY = "line_frequency"
|
||||||
|
CONF_METER_CONSTANT = "meter_constant"
|
||||||
|
CONF_PL_CONST = "pl_const"
|
||||||
|
CONF_GAIN_PGA = "gain_pga"
|
||||||
|
CONF_GAIN_METERING = "gain_metering"
|
||||||
|
CONF_GAIN_VOLTAGE = "gain_voltage"
|
||||||
|
CONF_GAIN_CT = "gain_ct"
|
||||||
|
LINE_FREQS = {
|
||||||
|
"50HZ": 50,
|
||||||
|
"60HZ": 60,
|
||||||
|
}
|
||||||
|
PGA_GAINS = {
|
||||||
|
"1X": 0x4,
|
||||||
|
"4X": 0x0,
|
||||||
|
"8X": 0x1,
|
||||||
|
"16X": 0x2,
|
||||||
|
"24X": 0x3,
|
||||||
|
}
|
||||||
|
|
||||||
|
atm90e26_ns = cg.esphome_ns.namespace("atm90e26")
|
||||||
|
ATM90E26Component = atm90e26_ns.class_(
|
||||||
|
"ATM90E26Component", cg.PollingComponent, spi.SPIDevice
|
||||||
|
)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(ATM90E26Component),
|
||||||
|
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=2,
|
||||||
|
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,
|
||||||
|
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_FREQUENCY): sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_HERTZ,
|
||||||
|
icon=ICON_CURRENT_AC,
|
||||||
|
accuracy_decimals=1,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True),
|
||||||
|
cv.Required(CONF_METER_CONSTANT): cv.positive_float,
|
||||||
|
cv.Optional(CONF_PL_CONST, default=1429876): cv.uint32_t,
|
||||||
|
cv.Optional(CONF_GAIN_METERING, default=7481): cv.uint16_t,
|
||||||
|
cv.Optional(CONF_GAIN_VOLTAGE, default=26400): cv.int_range(
|
||||||
|
min=0, max=32767
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_GAIN_CT, default=31251): cv.uint16_t,
|
||||||
|
cv.Optional(CONF_GAIN_PGA, default="1X"): cv.enum(PGA_GAINS, upper=True),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.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)
|
||||||
|
|
||||||
|
if CONF_VOLTAGE in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_VOLTAGE])
|
||||||
|
cg.add(var.set_voltage_sensor(sens))
|
||||||
|
if CONF_CURRENT in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_CURRENT])
|
||||||
|
cg.add(var.set_current_sensor(sens))
|
||||||
|
if CONF_POWER in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_POWER])
|
||||||
|
cg.add(var.set_power_sensor(sens))
|
||||||
|
if CONF_REACTIVE_POWER in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_REACTIVE_POWER])
|
||||||
|
cg.add(var.set_reactive_power_sensor(sens))
|
||||||
|
if CONF_POWER_FACTOR in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_POWER_FACTOR])
|
||||||
|
cg.add(var.set_power_factor_sensor(sens))
|
||||||
|
if CONF_FORWARD_ACTIVE_ENERGY in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_FORWARD_ACTIVE_ENERGY])
|
||||||
|
cg.add(var.set_forward_active_energy_sensor(sens))
|
||||||
|
if CONF_REVERSE_ACTIVE_ENERGY in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_REVERSE_ACTIVE_ENERGY])
|
||||||
|
cg.add(var.set_reverse_active_energy_sensor(sens))
|
||||||
|
if CONF_FREQUENCY in config:
|
||||||
|
sens = await sensor.new_sensor(config[CONF_FREQUENCY])
|
||||||
|
cg.add(var.set_freq_sensor(sens))
|
||||||
|
cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
|
||||||
|
cg.add(var.set_meter_constant(config[CONF_METER_CONSTANT]))
|
||||||
|
cg.add(var.set_pl_const(config[CONF_PL_CONST]))
|
||||||
|
cg.add(var.set_gain_metering(config[CONF_GAIN_METERING]))
|
||||||
|
cg.add(var.set_gain_voltage(config[CONF_GAIN_VOLTAGE]))
|
||||||
|
cg.add(var.set_gain_ct(config[CONF_GAIN_CT]))
|
||||||
|
cg.add(var.set_gain_pga(config[CONF_GAIN_PGA]))
|
|
@ -483,6 +483,25 @@ sensor:
|
||||||
nir:
|
nir:
|
||||||
name: NIR
|
name: NIR
|
||||||
i2c_id: i2c_bus
|
i2c_id: i2c_bus
|
||||||
|
- platform: atm90e26
|
||||||
|
cs_pin: 5
|
||||||
|
voltage:
|
||||||
|
name: Line Voltage
|
||||||
|
current:
|
||||||
|
name: CT Amps
|
||||||
|
power:
|
||||||
|
name: Active Watts
|
||||||
|
power_factor:
|
||||||
|
name: Power Factor
|
||||||
|
frequency:
|
||||||
|
name: Line Frequency
|
||||||
|
line_frequency: 50Hz
|
||||||
|
meter_constant: 1000
|
||||||
|
pl_const: 1429876
|
||||||
|
gain_pga: 1X
|
||||||
|
gain_metering: 7481
|
||||||
|
gain_voltage: 26400
|
||||||
|
gain_ct: 31251
|
||||||
- platform: atm90e32
|
- platform: atm90e32
|
||||||
cs_pin: 5
|
cs_pin: 5
|
||||||
phase_a:
|
phase_a:
|
||||||
|
|
Loading…
Reference in a new issue