mirror of
https://github.com/esphome/esphome.git
synced 2025-02-08 14:10:54 +00:00
110 lines
3.8 KiB
C++
110 lines
3.8 KiB
C++
#pragma once
|
|
|
|
#include "esphome/core/component.h"
|
|
#include "esphome/components/uart/uart.h"
|
|
#include "esphome/components/sensor/sensor.h"
|
|
|
|
namespace esphome {
|
|
namespace bl0940 {
|
|
|
|
static const float BL0940_PREF = 1430;
|
|
static const float BL0940_UREF = 33000;
|
|
static const float BL0940_IREF = 275000; // 2750 from tasmota. Seems to generate values 100 times too high
|
|
|
|
// Measured to 297J per click according to power consumption of 5 minutes
|
|
// Converted to kWh (3.6MJ per kwH). Used to be 256 * 1638.4
|
|
static const float BL0940_EREF = 3.6e6 / 297;
|
|
|
|
struct ube24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
|
|
uint8_t l;
|
|
uint8_t m;
|
|
uint8_t h;
|
|
} __attribute__((packed));
|
|
|
|
struct ube16_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
|
|
uint8_t l;
|
|
uint8_t h;
|
|
} __attribute__((packed));
|
|
|
|
struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-align)
|
|
uint8_t l;
|
|
uint8_t m;
|
|
int8_t h;
|
|
} __attribute__((packed));
|
|
|
|
// Caveat: All these values are big endian (low - middle - high)
|
|
|
|
union DataPacket { // NOLINT(altera-struct-pack-align)
|
|
uint8_t raw[35];
|
|
struct {
|
|
uint8_t frame_header; // value of 0x58 according to docs. 0x55 according to Tasmota real world tests. Reality wins.
|
|
ube24_t i_fast_rms; // 0x00
|
|
ube24_t i_rms; // 0x04
|
|
ube24_t RESERVED0; // reserved
|
|
ube24_t v_rms; // 0x06
|
|
ube24_t RESERVED1; // reserved
|
|
sbe24_t watt; // 0x08
|
|
ube24_t RESERVED2; // reserved
|
|
ube24_t cf_cnt; // 0x0A
|
|
ube24_t RESERVED3; // reserved
|
|
ube16_t tps1; // 0x0c
|
|
uint8_t RESERVED4; // value of 0x00
|
|
ube16_t tps2; // 0x0c
|
|
uint8_t RESERVED5; // value of 0x00
|
|
uint8_t checksum; // checksum
|
|
};
|
|
} __attribute__((packed));
|
|
|
|
class BL0940 : public PollingComponent, public uart::UARTDevice {
|
|
public:
|
|
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
|
|
void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; }
|
|
void set_power_sensor(sensor::Sensor *power_sensor) { power_sensor_ = power_sensor; }
|
|
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
|
|
void set_internal_temperature_sensor(sensor::Sensor *internal_temperature_sensor) {
|
|
internal_temperature_sensor_ = internal_temperature_sensor;
|
|
}
|
|
void set_external_temperature_sensor(sensor::Sensor *external_temperature_sensor) {
|
|
external_temperature_sensor_ = external_temperature_sensor;
|
|
}
|
|
|
|
void loop() override;
|
|
|
|
void update() override;
|
|
void setup() override;
|
|
void dump_config() override;
|
|
|
|
protected:
|
|
sensor::Sensor *voltage_sensor_{nullptr};
|
|
sensor::Sensor *current_sensor_{nullptr};
|
|
// NB This may be negative as the circuits is seemingly able to measure
|
|
// power in both directions
|
|
sensor::Sensor *power_sensor_{nullptr};
|
|
sensor::Sensor *energy_sensor_{nullptr};
|
|
sensor::Sensor *internal_temperature_sensor_{nullptr};
|
|
sensor::Sensor *external_temperature_sensor_{nullptr};
|
|
|
|
// Max difference between two measurements of the temperature. Used to avoid noise.
|
|
float max_temperature_diff_{0};
|
|
// Divide by this to turn into Watt
|
|
float power_reference_ = BL0940_PREF;
|
|
// Divide by this to turn into Volt
|
|
float voltage_reference_ = BL0940_UREF;
|
|
// Divide by this to turn into Ampere
|
|
float current_reference_ = BL0940_IREF;
|
|
// Divide by this to turn into kWh
|
|
float energy_reference_ = BL0940_EREF;
|
|
|
|
float update_temp_(sensor::Sensor *sensor, ube16_t packed_temperature) const;
|
|
|
|
static uint32_t to_uint32_t(ube24_t input);
|
|
|
|
static int32_t to_int32_t(sbe24_t input);
|
|
|
|
static bool validate_checksum(const DataPacket *data);
|
|
|
|
void received_package_(const DataPacket *data) const;
|
|
};
|
|
} // namespace bl0940
|
|
} // namespace esphome
|