mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 09:01:49 +00:00 
			
		
		
		
	Add support for Daly Smart BMS
This commit is contained in:
		
							
								
								
									
										30
									
								
								esphome/components/daly_bms/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/daly_bms/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import uart
 | 
				
			||||||
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CODEOWNERS = ["@s1lvi0"]
 | 
				
			||||||
 | 
					DEPENDENCIES = ["uart"]
 | 
				
			||||||
 | 
					AUTO_LOAD = ["sensor", "text_sensor", "binary_sensor"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_BSM_DALY_ID = "bms_daly_id"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					daly_bms = cg.esphome_ns.namespace("daly_bms")
 | 
				
			||||||
 | 
					DalyBmsComponent = daly_bms.class_("DalyBmsComponent", uart.UARTDevice, cg.Component)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.All(
 | 
				
			||||||
 | 
					    cv.Schema(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            cv.GenerateID(): cv.declare_id(DalyBmsComponent),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					    .extend(uart.UART_DEVICE_SCHEMA)
 | 
				
			||||||
 | 
					    .extend(cv.polling_component_schema("30s")),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					    await uart.register_uart_device(var, config)
 | 
				
			||||||
							
								
								
									
										46
									
								
								esphome/components/daly_bms/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								esphome/components/daly_bms/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import binary_sensor
 | 
				
			||||||
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					from . import DalyBmsComponent, CONF_BSM_DALY_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_CHARGING_MOS_ENABLED = "charging_mos_enabled"
 | 
				
			||||||
 | 
					CONF_DISCHARGING_MOS_ENABLED = "discharging_mos_enabled"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TYPES = [
 | 
				
			||||||
 | 
					    CONF_CHARGING_MOS_ENABLED,
 | 
				
			||||||
 | 
					    CONF_DISCHARGING_MOS_ENABLED,
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.All(
 | 
				
			||||||
 | 
					    cv.Schema(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            cv.GenerateID(CONF_BSM_DALY_ID): cv.use_id(DalyBmsComponent),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_CHARGING_MOS_ENABLED): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_DISCHARGING_MOS_ENABLED): binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def setup_conf(config, key, hub):
 | 
				
			||||||
 | 
					    if key in config:
 | 
				
			||||||
 | 
					        conf = config[key]
 | 
				
			||||||
 | 
					        sens = cg.new_Pvariable(conf[CONF_ID])
 | 
				
			||||||
 | 
					        await binary_sensor.register_binary_sensor(sens, conf)
 | 
				
			||||||
 | 
					        cg.add(getattr(hub, f"set_{key}_binary_sensor")(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    hub = await cg.get_variable(config[CONF_BSM_DALY_ID])
 | 
				
			||||||
 | 
					    for key in TYPES:
 | 
				
			||||||
 | 
					        await setup_conf(config, key, hub)
 | 
				
			||||||
							
								
								
									
										188
									
								
								esphome/components/daly_bms/daly_bms.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								esphome/components/daly_bms/daly_bms.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
				
			|||||||
 | 
					#include "daly_bms.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace daly_bms {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "daly_bms";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const unsigned char DALY_TEMPERATURE_OFFSET = 40;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const unsigned char DALY_REQUEST_battery_level = 0x90;
 | 
				
			||||||
 | 
					static const unsigned char DALY_REQUEST_MIN_MAX_VOLTAGE = 0x91;
 | 
				
			||||||
 | 
					static const unsigned char DALY_REQUEST_MIN_MAX_TEMPERATURE = 0x92;
 | 
				
			||||||
 | 
					static const unsigned char DALY_REQUEST_MOS = 0x93;
 | 
				
			||||||
 | 
					static const unsigned char DALY_REQUEST_STATUS = 0x94;
 | 
				
			||||||
 | 
					static const unsigned char DALY_REQUEST_TEMPERATURE = 0x96;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DalyBmsComponent::setup() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DalyBmsComponent::dump_config() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "DALY_BMS:");
 | 
				
			||||||
 | 
					  this->check_uart_settings(9600);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DalyBmsComponent::update() {
 | 
				
			||||||
 | 
					  this->request_data(DALY_REQUEST_battery_level);
 | 
				
			||||||
 | 
					  this->request_data(DALY_REQUEST_MIN_MAX_VOLTAGE);
 | 
				
			||||||
 | 
					  this->request_data(DALY_REQUEST_MIN_MAX_TEMPERATURE);
 | 
				
			||||||
 | 
					  this->request_data(DALY_REQUEST_MOS);
 | 
				
			||||||
 | 
					  this->request_data(DALY_REQUEST_STATUS);
 | 
				
			||||||
 | 
					  this->request_data(DALY_REQUEST_TEMPERATURE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unsigned char *get_battery_level_data;
 | 
				
			||||||
 | 
					  int available_data = this->available();
 | 
				
			||||||
 | 
					  if (available_data >= 13) {
 | 
				
			||||||
 | 
					    get_battery_level_data = (unsigned char *) malloc(available_data);
 | 
				
			||||||
 | 
					    this->read_array(get_battery_level_data, available_data);
 | 
				
			||||||
 | 
					    this->decode_data(get_battery_level_data, available_data);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float DalyBmsComponent::get_setup_priority() const { return setup_priority::DATA; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DalyBmsComponent::request_data(unsigned char data_id) {
 | 
				
			||||||
 | 
					  unsigned char request_message[13];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  request_message[0] = 0xA5;     // Start Flag
 | 
				
			||||||
 | 
					  request_message[1] = 0x80;     // Communication Module Address
 | 
				
			||||||
 | 
					  request_message[2] = data_id;  // Data ID
 | 
				
			||||||
 | 
					  request_message[3] = 0x08;     // Data Length (Fixed)
 | 
				
			||||||
 | 
					  request_message[4] = 0x00;     // Empty Data
 | 
				
			||||||
 | 
					  request_message[5] = 0x00;     //     |
 | 
				
			||||||
 | 
					  request_message[6] = 0x00;     //     |
 | 
				
			||||||
 | 
					  request_message[7] = 0x00;     //     |
 | 
				
			||||||
 | 
					  request_message[8] = 0x00;     //     |
 | 
				
			||||||
 | 
					  request_message[9] = 0x00;     //     |
 | 
				
			||||||
 | 
					  request_message[10] = 0x00;    //     |
 | 
				
			||||||
 | 
					  request_message[11] = 0x00;    // Empty Data
 | 
				
			||||||
 | 
					  request_message[12] = (unsigned char) (request_message[0] + request_message[1] + request_message[2] +
 | 
				
			||||||
 | 
					                                         request_message[3]);  // Checksum (Lower byte of the other bytes sum)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  this->write_array(request_message, sizeof(request_message));
 | 
				
			||||||
 | 
					  this->flush();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DalyBmsComponent::decode_data(unsigned char *data, int length) {
 | 
				
			||||||
 | 
					  unsigned char *start_flag_position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (data != NULL) {
 | 
				
			||||||
 | 
					    start_flag_position = (unsigned char *) strchr((const char *) data, 0xA5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (start_flag_position != NULL) {
 | 
				
			||||||
 | 
					      length = length - (start_flag_position - data);
 | 
				
			||||||
 | 
					      data = start_flag_position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (length >= 13 && data[1] == 0x01) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        unsigned char checksum;
 | 
				
			||||||
 | 
					        int sum = 0;
 | 
				
			||||||
 | 
					        for (int i = 0; i < 12; i++) {
 | 
				
			||||||
 | 
					          sum += data[i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        checksum = sum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (checksum == data[12]) {
 | 
				
			||||||
 | 
					          switch (data[2]) {
 | 
				
			||||||
 | 
					            case DALY_REQUEST_battery_level:
 | 
				
			||||||
 | 
					              if (this->voltage_sensor_) {
 | 
				
			||||||
 | 
					                this->voltage_sensor_->publish_state((float) (((data[4] << 8) | data[5]) / 10));
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->current_sensor_) {
 | 
				
			||||||
 | 
					                this->current_sensor_->publish_state((float) ((((data[8] << 8) | data[9]) - 30000) / 10));
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->battery_level_sensor_) {
 | 
				
			||||||
 | 
					                this->battery_level_sensor_->publish_state((float) (((data[10] << 8) | data[11]) / 10));
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case DALY_REQUEST_MIN_MAX_VOLTAGE:
 | 
				
			||||||
 | 
					              if (this->max_cell_voltage_) {
 | 
				
			||||||
 | 
					                this->max_cell_voltage_->publish_state((float) ((data[4] << 8) | data[5]) / 1000);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->max_cell_volatge_number_) {
 | 
				
			||||||
 | 
					                this->max_cell_volatge_number_->publish_state(data[6]);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->min_cell_voltage_) {
 | 
				
			||||||
 | 
					                this->min_cell_voltage_->publish_state((float) ((data[7] << 8) | data[8]) / 1000);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->min_cell_voltage_number_) {
 | 
				
			||||||
 | 
					                this->min_cell_voltage_number_->publish_state(data[9]);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case DALY_REQUEST_MIN_MAX_TEMPERATURE:
 | 
				
			||||||
 | 
					              if (this->max_temperature_) {
 | 
				
			||||||
 | 
					                this->max_temperature_->publish_state(data[4] - DALY_TEMPERATURE_OFFSET);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->max_temperature_probe_number_) {
 | 
				
			||||||
 | 
					                this->max_temperature_probe_number_->publish_state(data[5]);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->min_temperature_) {
 | 
				
			||||||
 | 
					                this->min_temperature_->publish_state(data[6] - DALY_TEMPERATURE_OFFSET);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->min_temperature_probe_number_) {
 | 
				
			||||||
 | 
					                this->min_temperature_probe_number_->publish_state(data[7]);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case DALY_REQUEST_MOS:
 | 
				
			||||||
 | 
					              if (this->status_text_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					                switch (data[4]) {
 | 
				
			||||||
 | 
					                  case 0:
 | 
				
			||||||
 | 
					                    this->status_text_sensor_->publish_state("Stationary");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                  case 1:
 | 
				
			||||||
 | 
					                    this->status_text_sensor_->publish_state("Charging");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                  case 2:
 | 
				
			||||||
 | 
					                    this->status_text_sensor_->publish_state("Discharging");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                  default:
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->charging_mos_enabled_) {
 | 
				
			||||||
 | 
					                this->charging_mos_enabled_->publish_state(data[5]);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->discharging_mos_enabled_) {
 | 
				
			||||||
 | 
					                this->discharging_mos_enabled_->publish_state(data[6]);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (this->remaining_capacity_) {
 | 
				
			||||||
 | 
					                this->remaining_capacity_->publish_state(
 | 
				
			||||||
 | 
					                    (float) ((data[8] << 24) | (data[9] << 16) | (data[10] << 8) | data[11]) / 1000);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case DALY_REQUEST_STATUS:
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            case DALY_REQUEST_TEMPERATURE:
 | 
				
			||||||
 | 
					              if (data[4] == 1) {
 | 
				
			||||||
 | 
					                if (this->temperature_1_sensor_) {
 | 
				
			||||||
 | 
					                  this->temperature_1_sensor_->publish_state(data[5] - DALY_TEMPERATURE_OFFSET);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (this->temperature_2_sensor_) {
 | 
				
			||||||
 | 
					                  this->temperature_2_sensor_->publish_state(data[6] - DALY_TEMPERATURE_OFFSET);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          data = &data[13];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        data = NULL;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      data = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  free(data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace daly_bms
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										81
									
								
								esphome/components/daly_bms/daly_bms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								esphome/components/daly_bms/daly_bms.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/components/text_sensor/text_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/components/binary_sensor/binary_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/components/uart/uart.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace daly_bms {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DalyBmsComponent : public PollingComponent, public uart::UARTDevice {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  DalyBmsComponent() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // SENSORS
 | 
				
			||||||
 | 
					  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_battery_level_sensor(sensor::Sensor *battery_level_sensor) { battery_level_sensor_ = battery_level_sensor; }
 | 
				
			||||||
 | 
					  void set_max_cell_voltage_sensor(sensor::Sensor *max_cell_voltage) { max_cell_voltage_ = max_cell_voltage; }
 | 
				
			||||||
 | 
					  void set_max_cell_voltage_number_sensor(sensor::Sensor *max_cell_volatge_number) {
 | 
				
			||||||
 | 
					    max_cell_volatge_number_ = max_cell_volatge_number;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void set_min_cell_voltage_sensor(sensor::Sensor *min_cell_voltage) { min_cell_voltage_ = min_cell_voltage; }
 | 
				
			||||||
 | 
					  void set_min_cell_voltage_number_sensor(sensor::Sensor *min_cell_voltage_number) {
 | 
				
			||||||
 | 
					    min_cell_voltage_number_ = min_cell_voltage_number;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void set_max_temperature_sensor(sensor::Sensor *max_temperature) { max_temperature_ = max_temperature; }
 | 
				
			||||||
 | 
					  void set_max_temperature_probe_number_sensor(sensor::Sensor *max_temperature_probe_number) {
 | 
				
			||||||
 | 
					    max_temperature_probe_number_ = max_temperature_probe_number;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void set_min_temperature_sensor(sensor::Sensor *min_temperature) { min_temperature_ = min_temperature; }
 | 
				
			||||||
 | 
					  void set_min_temperature_probe_number_sensor(sensor::Sensor *min_temperature_probe_number) {
 | 
				
			||||||
 | 
					    min_temperature_probe_number_ = min_temperature_probe_number;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void set_remaining_capacity_sensor(sensor::Sensor *remaining_capacity) { remaining_capacity_ = remaining_capacity; }
 | 
				
			||||||
 | 
					  void set_temperature_1_sensor(sensor::Sensor *temperature_1_sensor) { temperature_1_sensor_ = temperature_1_sensor; }
 | 
				
			||||||
 | 
					  void set_temperature_2_sensor(sensor::Sensor *temperature_2_sensor) { temperature_2_sensor_ = temperature_2_sensor; }
 | 
				
			||||||
 | 
					  // TEXT_SENSORS
 | 
				
			||||||
 | 
					  void set_status_text_sensor(text_sensor::TextSensor *status_text_sensor) { status_text_sensor_ = status_text_sensor; }
 | 
				
			||||||
 | 
					  // BINARY_SENSORS
 | 
				
			||||||
 | 
					  void set_charging_mos_enabled_binary_sensor(binary_sensor::BinarySensor *charging_mos_enabled) {
 | 
				
			||||||
 | 
					    charging_mos_enabled_ = charging_mos_enabled;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void set_discharging_mos_enabled_binary_sensor(binary_sensor::BinarySensor *discharging_mos_enabled) {
 | 
				
			||||||
 | 
					    discharging_mos_enabled_ = discharging_mos_enabled;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setup() override;
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					  void update() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  float get_setup_priority() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  void request_data(unsigned char data_id);
 | 
				
			||||||
 | 
					  void decode_data(unsigned char *data, int length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  sensor::Sensor *voltage_sensor_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *current_sensor_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *battery_level_sensor_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *max_cell_voltage_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *max_cell_volatge_number_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *min_cell_voltage_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *min_cell_voltage_number_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *max_temperature_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *max_temperature_probe_number_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *min_temperature_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *min_temperature_probe_number_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *remaining_capacity_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *temperature_1_sensor_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *temperature_2_sensor_{nullptr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  text_sensor::TextSensor *status_text_sensor_{nullptr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  binary_sensor::BinarySensor *charging_mos_enabled_{nullptr};
 | 
				
			||||||
 | 
					  binary_sensor::BinarySensor *discharging_mos_enabled_{nullptr};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace daly_bms
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										203
									
								
								esphome/components/daly_bms/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								esphome/components/daly_bms/sensor.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,203 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import sensor
 | 
				
			||||||
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_VOLTAGE,
 | 
				
			||||||
 | 
					    CONF_CURRENT,
 | 
				
			||||||
 | 
					    CONF_BATTERY_LEVEL,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_CURRENT,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_BATTERY,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					    STATE_CLASS_NONE,
 | 
				
			||||||
 | 
					    UNIT_VOLT,
 | 
				
			||||||
 | 
					    UNIT_AMPERE,
 | 
				
			||||||
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
 | 
					    UNIT_EMPTY,
 | 
				
			||||||
 | 
					    ICON_FLASH,
 | 
				
			||||||
 | 
					    ICON_PERCENT,
 | 
				
			||||||
 | 
					    ICON_COUNTER,
 | 
				
			||||||
 | 
					    ICON_THERMOMETER,
 | 
				
			||||||
 | 
					    ICON_GAUGE,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from . import DalyBmsComponent, CONF_BSM_DALY_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_MAX_CELL_VOLTAGE = "max_cell_voltage"
 | 
				
			||||||
 | 
					CONF_MAX_CELL_VOLTAGE_NUMBER = "max_cell_voltage_number"
 | 
				
			||||||
 | 
					CONF_MIN_CELL_VOLTAGE = "min_cell_voltage"
 | 
				
			||||||
 | 
					CONF_MIN_CELL_VOLTAGE_NUMBER = "min_cell_voltage_number"
 | 
				
			||||||
 | 
					CONF_MAX_TEMPERATURE = "max_temperature"
 | 
				
			||||||
 | 
					CONF_MAX_TEMPERATURE_PROBE_NUMBER = "max_temperature_probe_number"
 | 
				
			||||||
 | 
					CONF_MIN_TEMPERATURE = "min_temperature"
 | 
				
			||||||
 | 
					CONF_MIN_TEMPERATURE_PROBE_NUMBER = "min_temperature_probe_number"
 | 
				
			||||||
 | 
					CONF_STATUS = "status"
 | 
				
			||||||
 | 
					CONF_CELLS_NUMBER = "cells_number"
 | 
				
			||||||
 | 
					CONF_TEMPERATURE_PROBES_NUMBER = "temperature_probe_number"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_REMAINING_CAPACITY = "remaining_capacity"
 | 
				
			||||||
 | 
					CONF_TEMPERATURE_1 = "temperature_1"
 | 
				
			||||||
 | 
					CONF_TEMPERATURE_2 = "temperature_2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ICON_CURRENT_DC = "mdi:current-dc"
 | 
				
			||||||
 | 
					ICON_BATTERY_OUTLINE = "mdi:battery-outline"
 | 
				
			||||||
 | 
					ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up"
 | 
				
			||||||
 | 
					ICON_THERMOMETER_CHEVRON_DOWN = "mdi:thermometer-chevron-down"
 | 
				
			||||||
 | 
					ICON_CAR_BATTERY = "mdi:car-battery"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UNIT_AMPERE_HOUR = "Ah"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TYPES = [
 | 
				
			||||||
 | 
					    CONF_VOLTAGE,
 | 
				
			||||||
 | 
					    CONF_CURRENT,
 | 
				
			||||||
 | 
					    CONF_BATTERY_LEVEL,
 | 
				
			||||||
 | 
					    CONF_MAX_CELL_VOLTAGE,
 | 
				
			||||||
 | 
					    CONF_MAX_CELL_VOLTAGE_NUMBER,
 | 
				
			||||||
 | 
					    CONF_MIN_CELL_VOLTAGE,
 | 
				
			||||||
 | 
					    CONF_MIN_CELL_VOLTAGE_NUMBER,
 | 
				
			||||||
 | 
					    CONF_MAX_TEMPERATURE,
 | 
				
			||||||
 | 
					    CONF_MAX_TEMPERATURE_PROBE_NUMBER,
 | 
				
			||||||
 | 
					    CONF_MIN_TEMPERATURE,
 | 
				
			||||||
 | 
					    CONF_MIN_TEMPERATURE_PROBE_NUMBER,
 | 
				
			||||||
 | 
					    CONF_CELLS_NUMBER,
 | 
				
			||||||
 | 
					    CONF_TEMPERATURE_PROBES_NUMBER,
 | 
				
			||||||
 | 
					    CONF_REMAINING_CAPACITY,
 | 
				
			||||||
 | 
					    CONF_TEMPERATURE_1,
 | 
				
			||||||
 | 
					    CONF_TEMPERATURE_2,
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.All(
 | 
				
			||||||
 | 
					    cv.Schema(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            cv.GenerateID(CONF_BSM_DALY_ID): cv.use_id(DalyBmsComponent),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_VOLT,
 | 
				
			||||||
 | 
					                ICON_FLASH,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_CURRENT): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_AMPERE,
 | 
				
			||||||
 | 
					                ICON_CURRENT_DC,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_CURRENT,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_PERCENT,
 | 
				
			||||||
 | 
					                ICON_PERCENT,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_BATTERY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MAX_CELL_VOLTAGE): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_VOLT,
 | 
				
			||||||
 | 
					                ICON_FLASH,
 | 
				
			||||||
 | 
					                2,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MAX_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_EMPTY,
 | 
				
			||||||
 | 
					                ICON_COUNTER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					                STATE_CLASS_NONE,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MIN_CELL_VOLTAGE): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_VOLT,
 | 
				
			||||||
 | 
					                ICON_FLASH,
 | 
				
			||||||
 | 
					                2,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MIN_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_EMPTY,
 | 
				
			||||||
 | 
					                ICON_COUNTER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					                STATE_CLASS_NONE,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MAX_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_THERMOMETER_CHEVRON_UP,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MAX_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_EMPTY,
 | 
				
			||||||
 | 
					                ICON_COUNTER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					                STATE_CLASS_NONE,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MIN_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_THERMOMETER_CHEVRON_DOWN,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MIN_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_EMPTY,
 | 
				
			||||||
 | 
					                ICON_COUNTER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					                STATE_CLASS_NONE,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_REMAINING_CAPACITY): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_AMPERE_HOUR,
 | 
				
			||||||
 | 
					                ICON_GAUGE,
 | 
				
			||||||
 | 
					                2,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_CELLS_NUMBER): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_EMPTY,
 | 
				
			||||||
 | 
					                ICON_COUNTER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					                STATE_CLASS_NONE,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_TEMPERATURE_PROBES_NUMBER): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_EMPTY,
 | 
				
			||||||
 | 
					                ICON_COUNTER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					                STATE_CLASS_NONE,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_TEMPERATURE_1): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_THERMOMETER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_TEMPERATURE_2): sensor.sensor_schema(
 | 
				
			||||||
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_THERMOMETER,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def setup_conf(config, key, hub):
 | 
				
			||||||
 | 
					    if key in config:
 | 
				
			||||||
 | 
					        conf = config[key]
 | 
				
			||||||
 | 
					        sens = await sensor.new_sensor(conf)
 | 
				
			||||||
 | 
					        cg.add(getattr(hub, f"set_{key}_sensor")(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    hub = await cg.get_variable(config[CONF_BSM_DALY_ID])
 | 
				
			||||||
 | 
					    for key in TYPES:
 | 
				
			||||||
 | 
					        await setup_conf(config, key, hub)
 | 
				
			||||||
							
								
								
									
										42
									
								
								esphome/components/daly_bms/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								esphome/components/daly_bms/text_sensor.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import text_sensor
 | 
				
			||||||
 | 
					from esphome.const import CONF_ICON, CONF_ID
 | 
				
			||||||
 | 
					from . import DalyBmsComponent, CONF_BSM_DALY_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_STATUS = "status"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ICON_CAR_BATTERY = "mdi:car-battery"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TYPES = [
 | 
				
			||||||
 | 
					    CONF_STATUS,
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.All(
 | 
				
			||||||
 | 
					    cv.Schema(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            cv.GenerateID(CONF_BSM_DALY_ID): cv.use_id(DalyBmsComponent),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_STATUS): text_sensor.TEXT_SENSOR_SCHEMA.extend(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    cv.GenerateID(): cv.declare_id(text_sensor.TextSensor),
 | 
				
			||||||
 | 
					                    cv.Optional(CONF_ICON, default=ICON_CAR_BATTERY): cv.icon,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def setup_conf(config, key, hub):
 | 
				
			||||||
 | 
					    if key in config:
 | 
				
			||||||
 | 
					        conf = config[key]
 | 
				
			||||||
 | 
					        sens = cg.new_Pvariable(conf[CONF_ID])
 | 
				
			||||||
 | 
					        await text_sensor.register_text_sensor(sens, conf)
 | 
				
			||||||
 | 
					        cg.add(getattr(hub, f"set_{key}_text_sensor")(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    hub = await cg.get_variable(config[CONF_BSM_DALY_ID])
 | 
				
			||||||
 | 
					    for key in TYPES:
 | 
				
			||||||
 | 
					        await setup_conf(config, key, hub)
 | 
				
			||||||
		Reference in New Issue
	
	Block a user