mirror of
https://github.com/esphome/esphome.git
synced 2024-12-26 07:24:54 +01:00
Add ADE7953 Support (#593)
* Add ADE795 support * Lint * Fix * Fix, add test
This commit is contained in:
parent
9c30f4cc68
commit
cdb9c59662
8 changed files with 206 additions and 14 deletions
0
esphome/components/ade7953/__init__.py
Normal file
0
esphome/components/ade7953/__init__.py
Normal file
51
esphome/components/ade7953/ade7953.cpp
Normal file
51
esphome/components/ade7953/ade7953.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "ade7953.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953 {
|
||||
|
||||
static const char *TAG = "ade7953";
|
||||
|
||||
void ADE7953::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "ADE7953:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_SENSOR(" ", "Voltage Sensor", this->voltage_sensor_);
|
||||
LOG_SENSOR(" ", "Current A Sensor", this->current_a_sensor_);
|
||||
LOG_SENSOR(" ", "Current B Sensor", this->current_b_sensor_);
|
||||
LOG_SENSOR(" ", "Active Power A Sensor", this->active_power_a_sensor_);
|
||||
LOG_SENSOR(" ", "Active Power B Sensor", this->active_power_b_sensor_);
|
||||
}
|
||||
|
||||
#define ADE_PUBLISH_(name, factor) \
|
||||
if (name) { \
|
||||
float value = *name / factor; \
|
||||
this->name##_sensor_->publish_state(value); \
|
||||
}
|
||||
#define ADE_PUBLISH(name, factor) ADE_PUBLISH_(name, factor)
|
||||
|
||||
void ADE7953::update() {
|
||||
if (!this->is_setup_)
|
||||
return;
|
||||
|
||||
auto active_power_a = this->ade_read_<int32_t>(0x0312);
|
||||
ADE_PUBLISH(active_power_a, 154.0f);
|
||||
auto active_power_b = this->ade_read_<int32_t>(0x0313);
|
||||
ADE_PUBLISH(active_power_b, 154.0f);
|
||||
auto current_a = this->ade_read_<uint32_t>(0x031A);
|
||||
ADE_PUBLISH(current_a, 100000.0f);
|
||||
auto current_b = this->ade_read_<uint32_t>(0x031B);
|
||||
ADE_PUBLISH(current_b, 100000.0f);
|
||||
auto voltage = this->ade_read_<uint32_t>(0x031C);
|
||||
ADE_PUBLISH(voltage, 26000.0f);
|
||||
|
||||
// auto apparent_power_a = this->ade_read_<int32_t>(0x0310);
|
||||
// auto apparent_power_b = this->ade_read_<int32_t>(0x0311);
|
||||
// auto reactive_power_a = this->ade_read_<int32_t>(0x0314);
|
||||
// auto reactive_power_b = this->ade_read_<int32_t>(0x0315);
|
||||
// auto power_factor_a = this->ade_read_<int16_t>(0x010A);
|
||||
// auto power_factor_b = this->ade_read_<int16_t>(0x010B);
|
||||
}
|
||||
|
||||
} // namespace ade7953
|
||||
} // namespace esphome
|
67
esphome/components/ade7953/ade7953.h
Normal file
67
esphome/components/ade7953/ade7953.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953 {
|
||||
|
||||
class ADE7953 : public i2c::I2CDevice, public PollingComponent {
|
||||
public:
|
||||
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
|
||||
void set_current_a_sensor(sensor::Sensor *current_a_sensor) { current_a_sensor_ = current_a_sensor; }
|
||||
void set_current_b_sensor(sensor::Sensor *current_b_sensor) { current_b_sensor_ = current_b_sensor; }
|
||||
void set_active_power_a_sensor(sensor::Sensor *active_power_a_sensor) {
|
||||
active_power_a_sensor_ = active_power_a_sensor;
|
||||
}
|
||||
void set_active_power_b_sensor(sensor::Sensor *active_power_b_sensor) {
|
||||
active_power_b_sensor_ = active_power_b_sensor;
|
||||
}
|
||||
|
||||
void setup() override {
|
||||
this->set_timeout(100, [this]() {
|
||||
this->ade_write_<uint8_t>(0x0010, 0x04);
|
||||
this->ade_write_<uint8_t>(0x00FE, 0xAD);
|
||||
this->ade_write_<uint16_t>(0x0120, 0x0030);
|
||||
this->is_setup_ = true;
|
||||
});
|
||||
}
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
template<typename T> bool ade_write_(uint16_t reg, T value) {
|
||||
std::vector<uint8_t> data;
|
||||
data.push_back(reg >> 8);
|
||||
data.push_back(reg >> 0);
|
||||
for (int i = sizeof(T) - 1; i >= 0; i--)
|
||||
data.push_back(value >> (i * 8));
|
||||
return this->write_bytes_raw(data);
|
||||
}
|
||||
template<typename T> optional<T> ade_read_(uint16_t reg) {
|
||||
uint8_t hi = reg >> 8;
|
||||
uint8_t lo = reg >> 0;
|
||||
if (!this->write_bytes_raw({hi, lo}))
|
||||
return {};
|
||||
auto ret = this->read_bytes_raw<sizeof(T)>();
|
||||
if (!ret.has_value())
|
||||
return {};
|
||||
T result = 0;
|
||||
for (int i = 0, j = sizeof(T) - 1; i < sizeof(T); i++, j--)
|
||||
result |= T((*ret)[i]) << (j * 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_setup_{false};
|
||||
sensor::Sensor *voltage_sensor_{nullptr};
|
||||
sensor::Sensor *current_a_sensor_{nullptr};
|
||||
sensor::Sensor *current_b_sensor_{nullptr};
|
||||
sensor::Sensor *active_power_a_sensor_{nullptr};
|
||||
sensor::Sensor *active_power_b_sensor_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace ade7953
|
||||
} // namespace esphome
|
39
esphome/components/ade7953/sensor.py
Normal file
39
esphome/components/ade7953/sensor.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, i2c
|
||||
from esphome.const import CONF_ID, CONF_VOLTAGE, \
|
||||
UNIT_VOLT, ICON_FLASH, UNIT_AMPERE, UNIT_WATT
|
||||
|
||||
DEPENDENCIES = ['i2c']
|
||||
|
||||
ace7953_ns = cg.esphome_ns.namespace('ade7953')
|
||||
ADE7953 = ace7953_ns.class_('ADE7953', cg.PollingComponent, i2c.I2CDevice)
|
||||
|
||||
CONF_CURRENT_A = 'current_a'
|
||||
CONF_CURRENT_B = 'current_b'
|
||||
CONF_ACTIVE_POWER_A = 'active_power_a'
|
||||
CONF_ACTIVE_POWER_B = 'active_power_b'
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(): cv.declare_id(ADE7953),
|
||||
|
||||
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1),
|
||||
cv.Optional(CONF_CURRENT_A): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
|
||||
cv.Optional(CONF_CURRENT_B): sensor.sensor_schema(UNIT_AMPERE, ICON_FLASH, 2),
|
||||
cv.Optional(CONF_ACTIVE_POWER_A): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1),
|
||||
cv.Optional(CONF_ACTIVE_POWER_B): sensor.sensor_schema(UNIT_WATT, ICON_FLASH, 1),
|
||||
}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x38))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
|
||||
for key in [CONF_VOLTAGE, CONF_CURRENT_A, CONF_CURRENT_B, CONF_ACTIVE_POWER_A,
|
||||
CONF_ACTIVE_POWER_B]:
|
||||
if key not in config:
|
||||
continue
|
||||
conf = config[key]
|
||||
sens = yield sensor.new_sensor(conf)
|
||||
cg.add(getattr(var, 'set_{}_sensor'.format(key))(sens))
|
|
@ -135,6 +135,9 @@ bool I2CComponent::read_bytes(uint8_t address, uint8_t a_register, uint8_t *data
|
|||
delay(conversion);
|
||||
return this->raw_receive(address, data, len);
|
||||
}
|
||||
bool I2CComponent::read_bytes_raw(uint8_t address, uint8_t *data, uint8_t len) {
|
||||
return this->raw_receive(address, data, len);
|
||||
}
|
||||
bool I2CComponent::read_bytes_16(uint8_t address, uint8_t a_register, uint16_t *data, uint8_t len,
|
||||
uint32_t conversion) {
|
||||
if (!this->write_bytes(address, a_register, nullptr, 0))
|
||||
|
@ -156,6 +159,11 @@ bool I2CComponent::write_bytes(uint8_t address, uint8_t a_register, const uint8_
|
|||
this->raw_write(address, data, len);
|
||||
return this->raw_end_transmission(address);
|
||||
}
|
||||
bool I2CComponent::write_bytes_raw(uint8_t address, const uint8_t *data, uint8_t len) {
|
||||
this->raw_begin_transmission(address);
|
||||
this->raw_write(address, data, len);
|
||||
return this->raw_end_transmission(address);
|
||||
}
|
||||
bool I2CComponent::write_bytes_16(uint8_t address, uint8_t a_register, const uint16_t *data, uint8_t len) {
|
||||
this->raw_begin_transmission(address);
|
||||
this->raw_write(address, &a_register, 1);
|
||||
|
|
|
@ -42,6 +42,7 @@ class I2CComponent : public Component {
|
|||
* @return If the operation was successful.
|
||||
*/
|
||||
bool read_bytes(uint8_t address, uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0);
|
||||
bool read_bytes_raw(uint8_t address, uint8_t *data, uint8_t len);
|
||||
|
||||
/** Read len amount of 16-bit words (MSB first) from a register into data.
|
||||
*
|
||||
|
@ -69,6 +70,7 @@ class I2CComponent : public Component {
|
|||
* @return If the operation was successful.
|
||||
*/
|
||||
bool write_bytes(uint8_t address, uint8_t a_register, const uint8_t *data, uint8_t len);
|
||||
bool write_bytes_raw(uint8_t address, const uint8_t *data, uint8_t len);
|
||||
|
||||
/** Write len amount of 16-bit words (MSB first) to the specified register for address.
|
||||
*
|
||||
|
@ -151,7 +153,6 @@ class I2CDevice {
|
|||
/// Manually set the parent i2c bus for this device.
|
||||
void set_i2c_parent(I2CComponent *parent);
|
||||
|
||||
protected:
|
||||
/** Read len amount of bytes from a register into data. Optionally with a conversion time after
|
||||
* writing the register value to the bus.
|
||||
*
|
||||
|
@ -161,15 +162,23 @@ class I2CDevice {
|
|||
* @param conversion The time in ms between writing the register value and reading out the value.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0); // NOLINT
|
||||
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len, uint32_t conversion = 0);
|
||||
bool read_bytes_raw(uint8_t *data, uint8_t len) { return this->parent_->read_bytes_raw(this->address_, data, len); }
|
||||
|
||||
template<size_t N> optional<std::array<uint8_t, N>> read_bytes(uint8_t a_register) { // NOLINT
|
||||
template<size_t N> optional<std::array<uint8_t, N>> read_bytes(uint8_t a_register) {
|
||||
std::array<uint8_t, N> res;
|
||||
if (!this->read_bytes(a_register, res.data(), N)) {
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
template<size_t N> optional<std::array<uint8_t, N>> read_bytes_raw() {
|
||||
std::array<uint8_t, N> res;
|
||||
if (!this->read_bytes_raw(res.data(), N)) {
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Read len amount of 16-bit words (MSB first) from a register into data.
|
||||
*
|
||||
|
@ -179,12 +188,12 @@ class I2CDevice {
|
|||
* @param conversion The time in ms between writing the register value and reading out the value.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
bool read_bytes_16(uint8_t a_register, uint16_t *data, uint8_t len, uint32_t conversion = 0); // NOLINT
|
||||
bool read_bytes_16(uint8_t a_register, uint16_t *data, uint8_t len, uint32_t conversion = 0);
|
||||
|
||||
/// Read a single byte from a register into the data variable. Return true if successful.
|
||||
bool read_byte(uint8_t a_register, uint8_t *data, uint32_t conversion = 0); // NOLINT
|
||||
bool read_byte(uint8_t a_register, uint8_t *data, uint32_t conversion = 0);
|
||||
|
||||
optional<uint8_t> read_byte(uint8_t a_register) { // NOLINT
|
||||
optional<uint8_t> read_byte(uint8_t a_register) {
|
||||
uint8_t data;
|
||||
if (!this->read_byte(a_register, &data))
|
||||
return {};
|
||||
|
@ -192,7 +201,7 @@ class I2CDevice {
|
|||
}
|
||||
|
||||
/// Read a single 16-bit words (MSB first) from a register into the data variable. Return true if successful.
|
||||
bool read_byte_16(uint8_t a_register, uint16_t *data, uint32_t conversion = 0); // NOLINT
|
||||
bool read_byte_16(uint8_t a_register, uint16_t *data, uint32_t conversion = 0);
|
||||
|
||||
/** Write len amount of 8-bit bytes to the specified register.
|
||||
*
|
||||
|
@ -201,7 +210,10 @@ class I2CDevice {
|
|||
* @param len The amount of bytes to write to the bus.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len); // NOLINT
|
||||
bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len);
|
||||
bool write_bytes_raw(const uint8_t *data, uint8_t len) {
|
||||
return this->parent_->write_bytes_raw(this->address_, data, len);
|
||||
}
|
||||
|
||||
/** Write a vector of data to a register.
|
||||
*
|
||||
|
@ -209,13 +221,17 @@ class I2CDevice {
|
|||
* @param data The data to write.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
bool write_bytes(uint8_t a_register, const std::vector<uint8_t> &data) { // NOLINT
|
||||
bool write_bytes(uint8_t a_register, const std::vector<uint8_t> &data) {
|
||||
return this->write_bytes(a_register, data.data(), data.size());
|
||||
}
|
||||
bool write_bytes_raw(const std::vector<uint8_t> &data) { return this->write_bytes_raw(data.data(), data.size()); }
|
||||
|
||||
template<size_t N> bool write_bytes(uint8_t a_register, const std::array<uint8_t, N> &data) { // NOLINT
|
||||
template<size_t N> bool write_bytes(uint8_t a_register, const std::array<uint8_t, N> &data) {
|
||||
return this->write_bytes(a_register, data.data(), data.size());
|
||||
}
|
||||
template<size_t N> bool write_bytes_raw(const std::array<uint8_t, N> &data) {
|
||||
return this->write_bytes_raw(data.data(), data.size());
|
||||
}
|
||||
|
||||
/** Write len amount of 16-bit words (MSB first) to the specified register.
|
||||
*
|
||||
|
@ -224,14 +240,15 @@ class I2CDevice {
|
|||
* @param len The amount of bytes to write to the bus.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
bool write_bytes_16(uint8_t a_register, const uint16_t *data, uint8_t len); // NOLINT
|
||||
bool write_bytes_16(uint8_t a_register, const uint16_t *data, uint8_t len);
|
||||
|
||||
/// Write a single byte of data into the specified register. Return true if successful.
|
||||
bool write_byte(uint8_t a_register, uint8_t data); // NOLINT
|
||||
bool write_byte(uint8_t a_register, uint8_t data);
|
||||
|
||||
/// Write a single 16-bit word of data into the specified register. Return true if successful.
|
||||
bool write_byte_16(uint8_t a_register, uint16_t data); // NOLINT
|
||||
bool write_byte_16(uint8_t a_register, uint16_t data);
|
||||
|
||||
protected:
|
||||
uint8_t address_{0x00};
|
||||
I2CComponent *parent_{nullptr};
|
||||
};
|
||||
|
|
|
@ -54,7 +54,6 @@ def run_tidy(args, tmpdir, queue, lock, failed_files):
|
|||
if rc != 0:
|
||||
print()
|
||||
print("\033[0;32m************* File \033[1;32m{}\033[0m".format(path))
|
||||
print(invocation_s)
|
||||
print(output)
|
||||
print()
|
||||
failed_files.append(path)
|
||||
|
|
|
@ -203,6 +203,17 @@ sensor:
|
|||
value: 15.0
|
||||
- binary_sensor: bin3
|
||||
value: 100.0
|
||||
- platform: ade7953
|
||||
voltage:
|
||||
name: ADE7953 Voltage
|
||||
current_a:
|
||||
name: ADE7953 Current A
|
||||
current_b:
|
||||
name: ADE7953 Current B
|
||||
active_power_a:
|
||||
name: ADE7953 Active Power A
|
||||
active_power_b:
|
||||
name: ADE7953 Active Power B
|
||||
|
||||
time:
|
||||
- platform: homeassistant
|
||||
|
|
Loading…
Reference in a new issue