Skip to content

Commit

Permalink
Merge pull request #22 from tarontop/main
Browse files Browse the repository at this point in the history
Add reset energy
  • Loading branch information
tarontop authored Aug 21, 2024
2 parents 7a0235a + 8cb77a0 commit 3f70a66
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 13 deletions.
29 changes: 23 additions & 6 deletions athom-energy-monitor-x2.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
substitutions:
name: "athom-energy-monitor-x2"
friendly_name: "Athom Energy Monitor"
name: "athom-em-2"
friendly_name: "Athom Energy Meter"
# Allows ESP device to be automatically lined to an 'Area' in Home Assistant. Typically used for areas such as 'Lounge Room', 'Kitchen' etc
room: ""
device_description: "athom bl0906 energy monitor (2 channels)"
project_name: "Athom Technology.Athom Energy Monitor(2 Channels)"
project_version: "2.0.2"
device_description: "athom bl0906 energy meter (2 channels)"
project_name: "Athom Technology.Athom Energy Meter(2 Channels)"
project_version: "2.0.3"
update_interval: 5s
# Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
dns_domain: ""
Expand Down Expand Up @@ -42,7 +42,7 @@ esphome:
friendly_name: "${friendly_name}"
area: "${room}"
name_add_mac_suffix: true
min_version: 2024.6.0
min_version: 2024.7.0
project:
name: "${project_name}"
version: "${project_version}"
Expand Down Expand Up @@ -180,6 +180,7 @@ sensor:
device_class: ""

- platform: bl0906
id: id_bl0906
update_interval: "${update_interval}"
frequency:
name: 'Frequency'
Expand Down Expand Up @@ -301,6 +302,22 @@ button:
internal: false
entity_category: config

- platform: template
name: Reset Energy
entity_category: config
on_press:
then:
- globals.set:
id: id_Energy_1_persist
value: '0.0'
- globals.set:
id: id_Energy_2_persist
value: '0.0'
- globals.set:
id: id_Energy_sum_persist
value: '0.0'
- bl0906.reset_energy: id_bl0906

text_sensor:
- platform: wifi_info
ip_address:
Expand Down
41 changes: 35 additions & 6 deletions athom-energy-monitor-x6.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
substitutions:
name: "athom-energy-monitor-x6"
friendly_name: "Athom Energy Monitor"
name: "athom-em-6"
friendly_name: "Athom Energy Meter"
# Allows ESP device to be automatically lined to an 'Area' in Home Assistant. Typically used for areas such as 'Lounge Room', 'Kitchen' etc
room: ""
device_description: "athom bl0906 energy monitor (6 channels)"
project_name: "Athom Technology.Athom Energy Monitor(6 Channels)"
project_version: "2.0.2"
device_description: "athom bl0906 energy meter (6 channels)"
project_name: "Athom Technology.Athom Energy Meter(6 Channels)"
project_version: "2.0.3"
update_interval: 5s
# Define a domain for this device to use. i.e. iot.home.lan (so device will appear as athom-smart-plug-v2.iot.home.lan in DNS/DHCP logs)
dns_domain: ""
Expand Down Expand Up @@ -54,7 +54,7 @@ esphome:
friendly_name: "${friendly_name}"
area: "${room}"
name_add_mac_suffix: true
min_version: 2024.6.0
min_version: 2024.7.0
project:
name: "${project_name}"
version: "${project_version}"
Expand Down Expand Up @@ -236,6 +236,7 @@ sensor:
device_class: ""

- platform: bl0906
id: id_bl0906
update_interval: "${update_interval}"
frequency:
name: 'Frequency'
Expand Down Expand Up @@ -489,6 +490,34 @@ button:
internal: false
entity_category: config

- platform: template
name: Reset Energy
entity_category: config
on_press:
then:
- globals.set:
id: id_Energy_1_persist
value: '0.0'
- globals.set:
id: id_Energy_2_persist
value: '0.0'
- globals.set:
id: id_Energy_3_persist
value: '0.0'
- globals.set:
id: id_Energy_4_persist
value: '0.0'
- globals.set:
id: id_Energy_5_persist
value: '0.0'
- globals.set:
id: id_Energy_6_persist
value: '0.0'
- globals.set:
id: id_Energy_sum_persist
value: '0.0'
- bl0906.reset_energy: id_bl0906

text_sensor:
- platform: wifi_info
ip_address:
Expand Down
52 changes: 52 additions & 0 deletions components/bl0906/bl0906.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ static const uint8_t BL0906_WATTGN_4 = 0xBA;
static const uint8_t BL0906_WATTGN_5 = 0xBD;
static const uint8_t BL0906_WATTGN_6 = 0xBE; // Channel_6

// User write protection setting register,
// You must first write 0x5555 to the write protection setting register before writing to other registers.
static const uint8_t BL0906_USR_WRPROT = 0x9E;

// Reset Register
static const uint8_t BL0906_SOFT_RESET = 0x9F;

const uint8_t BL0906_INIT[2][6] = {
// Reset to default
{BL0906_WRITE_COMMAND, BL0906_SOFT_RESET, 0x5A, 0x5A, 0x5A, 0x52},
// Enable User Operation Write
{BL0906_WRITE_COMMAND, BL0906_USR_WRPROT, 0x55, 0x55, 0x00, 0xB7}};

void BL0906::loop() {
if (this->current_channel_ == UINT8_MAX) {
return;
Expand Down Expand Up @@ -126,6 +139,7 @@ void BL0906::loop() {
return;
}
this->current_channel_++;
handleActionCallback();
}

void BL0906::setup() {
Expand Down Expand Up @@ -163,6 +177,44 @@ uint8_t bl0906_checksum(const uint8_t address, const DataPacket *data) {
return (address + data->l + data->m + data->h) ^ 0xFF;
}

int BL0906::addActionCallBack(ActionCallbackFuncPtr ptrFunc) {
m_vecActionCallback.push_back(ptrFunc);
return m_vecActionCallback.size();
}

void BL0906::handleActionCallback() {
if (m_vecActionCallback.size() == 0) {
return;
}
ActionCallbackFuncPtr ptrFunc = nullptr;
for (int i = 0; i < m_vecActionCallback.size(); i++) {
ptrFunc = m_vecActionCallback[i];
if (ptrFunc) {
ESP_LOGI(TAG, "HandleActionCallback[%d]...", i);
(this->*ptrFunc)();
}
}

while (this->available()) {
this->read();
}

m_vecActionCallback.clear();
if (m_process_state != PROCESS_DONE) {
m_process_state = PROCESS_DONE;
}
}

// Reset energy
void BL0906::reset_energy() {
this->write_array(BL0906_INIT[0], 6);
delay(1);
this->flush();

ESP_LOGW(TAG, "RMSOS:%02X%02X%02X%02X%02X%02X", BL0906_INIT[0][0], BL0906_INIT[0][1], BL0906_INIT[0][2],
BL0906_INIT[0][3], BL0906_INIT[0][4], BL0906_INIT[0][5]);
}

// Read data
void BL0906::read_data(const uint8_t address, const float reference, sensor::Sensor *sensor) {
if (sensor == nullptr) {
Expand Down
27 changes: 27 additions & 0 deletions components/bl0906/bl0906.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
#include "esphome/core/component.h"
#include "esphome/core/datatypes.h"
#include "esphome/core/automation.h"

// https://www.belling.com.cn/media/file_object/bel_product/BL0906/datasheet/BL0906_V1.02_cn.pdf
// https://www.belling.com.cn/media/file_object/bel_product/BL0906/guide/BL0906%20APP%20Note_V1.02.pdf
Expand Down Expand Up @@ -60,6 +62,11 @@ struct sbe24_t { // NOLINT(readability-identifier-naming,altera-struct-pack-ali
int8_t h;
} __attribute__((packed));

typedef enum process_state_ { PROCESS_DONE = 0 } process_state;
template<typename... Ts> class ResetEnergyAction;
class BL0906;
typedef void (BL0906::*ActionCallbackFuncPtr)(void);

class BL0906 : public PollingComponent, public uart::UARTDevice {
public:
void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; }
Expand Down Expand Up @@ -92,6 +99,8 @@ class BL0906 : public PollingComponent, public uart::UARTDevice {
void dump_config() override;

protected:
process_state m_process_state{PROCESS_DONE};
template<typename... Ts> friend class ResetEnergyAction;
sensor::Sensor *voltage_sensor_{nullptr};
sensor::Sensor *current_sensor_1_{nullptr};
sensor::Sensor *current_sensor_2_{nullptr};
Expand Down Expand Up @@ -136,6 +145,8 @@ class BL0906 : public PollingComponent, public uart::UARTDevice {

static int32_t to_int32_t(sbe24_t input);

void reset_energy();

void read_data(const uint8_t address, const float reference, sensor::Sensor *sensor_);

void Bias_correction(const uint8_t address, const float measurements, const float Correction);
Expand All @@ -144,6 +155,22 @@ class BL0906 : public PollingComponent, public uart::UARTDevice {
const float coefficient);

uint8_t current_channel_ = 0;
int addActionCallBack(ActionCallbackFuncPtr ptrFunc);
void handleActionCallback();
bool isNeedHandleActionCallback() { return (m_vecActionCallback.size() > 0); }

private:
std::vector<ActionCallbackFuncPtr> m_vecActionCallback{};
};

template<typename... Ts> class ResetEnergyAction : public Action<Ts...> {
public:
ResetEnergyAction(BL0906 *bl0906) : bl0906_(bl0906) {}

void play(Ts... x) override { this->bl0906_->addActionCallBack(&BL0906::reset_energy);}

protected:
BL0906 *bl0906_;
};
} // namespace bl0906
} // namespace esphome
17 changes: 16 additions & 1 deletion components/bl0906/sensor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.automation import maybe_simple_id
from esphome.components import sensor, uart
from esphome.const import (
CONF_CHANNEL,
Expand Down Expand Up @@ -28,11 +30,12 @@
)

DEPENDENCIES = ["uart"]

AUTO_LOAD = ["bl0906"]
CONF_TOTAL_ENERGY = "total_energy"

bl0906_ns = cg.esphome_ns.namespace("bl0906")
BL0906 = bl0906_ns.class_("BL0906", cg.PollingComponent, uart.UARTDevice)
ResetEnergyAction = bl0906_ns.class_("ResetEnergyAction", automation.Action)

CONFIG_SCHEMA = (
cv.Schema(
Expand Down Expand Up @@ -105,6 +108,18 @@
.extend(cv.polling_component_schema("60s"))
)

@automation.register_action(
"bl0906.reset_energy",
ResetEnergyAction,
maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(BL0906),
}
),
)
async def reset_energy_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)

async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
Expand Down

0 comments on commit 3f70a66

Please sign in to comment.