diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c8eccae..cbf2e50 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -161,15 +161,40 @@ jobs: - name: Write secrets.yaml shell: bash run: 'echo -e "wifi_ssid: ssid\nwifi_password: password\nmqtt_host: host\nmqtt_username: username\nmqtt_password: password" > secrets.yaml' - - run: | + - name: Write tests/secrets.yaml + shell: bash + run: 'echo -e "wifi_ssid: ssid\nwifi_password: password\nmqtt_host: host\nmqtt_username: username\nmqtt_password: password" > tests/secrets.yaml' + - name: Validate esp8266 example configurations + run: | esphome -s external_components_source components config esp8266-example.yaml esphome -s external_components_source components config esp8266-example-debug.yaml esphome -s external_components_source components config esp8266-example-faker.yaml + esphome -s external_components_source components config esp8266-boqiang-example.yaml + esphome -s external_components_source components config esp8266-boqiang-example-debug.yaml + esphome -s external_components_source components config esp8266-boqiang-example-faker.yaml + esphome -s external_components_source components config esp8266-boqiang-bms001-example.yaml + esphome -s external_components_source components config esp8266-boqiang-bms001-example-debug.yaml + esphome -s external_components_source components config esp8266-boqiang-bms001-example-faker.yaml esphome -s external_components_source components config esp8266-example-multiple-battery-banks.yaml - - run: | + - name: Validate esp32 example configurations + run: | esphome -s external_components_source components config esp32-example.yaml esphome -s external_components_source components config esp32-example-debug.yaml esphome -s external_components_source components config esp32-example-faker.yaml + esphome -s external_components_source components config esp32-boqiang-example.yaml + esphome -s external_components_source components config esp32-boqiang-example-debug.yaml + esphome -s external_components_source components config esp32-boqiang-example-faker.yaml + esphome -s external_components_source components config esp32-boqiang-bms001-example.yaml + esphome -s external_components_source components config esp32-boqiang-bms001-example-debug.yaml + esphome -s external_components_source components config esp32-boqiang-bms001-example-faker.yaml + - name: Validate test configurations + run: | + esphome -s external_components_source ../components config tests/esp8266-boqiang-emulator.yaml + esphome -s external_components_source ../components config tests/esp8266-boqiang-test.yaml + esphome -s external_components_source ../components config tests/esp8266-fake-bms.yaml + esphome -s external_components_source ../components config tests/esp8266-protocol-version.yaml + esphome -s external_components_source ../components config tests/esp8266-requests.yaml + esphome -s external_components_source ../components config tests/esp8266-seplos-emulator.yaml esphome-compile: runs-on: ubuntu-latest @@ -206,8 +231,12 @@ jobs: - name: Write secrets.yaml shell: bash run: 'echo -e "wifi_ssid: ssid\nwifi_password: password\nmqtt_host: host\nmqtt_username: username\nmqtt_password: password" > secrets.yaml' - - run: | + - name: Compile esp8266 example configurations + run: | esphome -s external_components_source components compile esp8266-example-faker.yaml + esphome -s external_components_source components compile esp8266-boqiang-example-faker.yaml esphome -s external_components_source components compile esp8266-example-multiple-battery-banks.yaml - - run: | + - name: Compile esp32 example configurations + run: | esphome -s external_components_source components compile esp32-example-faker.yaml + esphome -s external_components_source components compile esp32-boqiang-example-faker.yaml diff --git a/README.md b/README.md index a1844d2..0fe696f 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,17 @@ ESPHome component to monitor Seplos BMS via UART or RS485 * 1101-ZH26 (reported by [@faizan-elite](https://github.com/syssi/esphome-seplos-bms/issues/2)) * 1101-MZ02 (reported by [@fajera81](https://github.com/syssi/esphome-seplos-bms/discussions/33)) * 1101-10E-SP76-16S (reported by [@tobox](https://github.com/syssi/esphome-seplos-bms/discussions/42)) +* Boqiang BMS007-LD43-16S-HW (reported by [@xdilian](https://github.com/syssi/esphome-seplos-bms/discussions/43)) requires custom settings + ``` + protocol_version: 0x26 + override_pack: 1 + ``` +* Boqiang BMS001-HS01-15S (reported by [@xdilian](https://github.com/syssi/esphome-seplos-bms/discussions/43)) requires custom settings + ``` + protocol_version: 0x26 + override_pack: 1 + override_cell_count: 10 + ``` ## Untested devices diff --git a/components/seplos_bms/__init__.py b/components/seplos_bms/__init__.py index 4a71602..2cfeb0a 100644 --- a/components/seplos_bms/__init__.py +++ b/components/seplos_bms/__init__.py @@ -8,7 +8,10 @@ MULTI_CONF = True CONF_SEPLOS_BMS_ID = "seplos_bms_id" -CONF_ENABLE_FAKE_TRAFFIC = "enable_fake_traffic" +CONF_OVERRIDE_CELL_COUNT = "override_cell_count" + +DEFAULT_PROTOCOL_VERSION = 0x20 +DEFAULT_ADDRESS = 0x00 seplos_bms_ns = cg.esphome_ns.namespace("seplos_bms") SeplosBms = seplos_bms_ns.class_( @@ -19,11 +22,17 @@ cv.Schema( { cv.GenerateID(): cv.declare_id(SeplosBms), - cv.Optional(CONF_ENABLE_FAKE_TRAFFIC, default=False): cv.boolean, + cv.Optional(CONF_OVERRIDE_CELL_COUNT, default=0): cv.int_range( + min=0, max=16 + ), } ) .extend(cv.polling_component_schema("10s")) - .extend(seplos_modbus.seplos_modbus_device_schema(0x00)) + .extend( + seplos_modbus.seplos_modbus_device_schema( + DEFAULT_PROTOCOL_VERSION, DEFAULT_ADDRESS + ) + ) ) @@ -32,4 +41,4 @@ async def to_code(config): await cg.register_component(var, config) await seplos_modbus.register_seplos_modbus_device(var, config) - cg.add(var.set_enable_fake_traffic(config[CONF_ENABLE_FAKE_TRAFFIC])) + cg.add(var.set_override_cell_count(config[CONF_OVERRIDE_CELL_COUNT])) diff --git a/components/seplos_bms/seplos_bms.cpp b/components/seplos_bms/seplos_bms.cpp index 2438f08..2ba80c8 100644 --- a/components/seplos_bms/seplos_bms.cpp +++ b/components/seplos_bms/seplos_bms.cpp @@ -13,13 +13,13 @@ void SeplosBms::on_seplos_modbus_data(const std::vector &data) { // 14 77 142 (0x8E) // 15 79 146 (0x92) // 16 81 150 (0x96) - // 24 97 182 (0xB6) guessed - if (data.size() >= 65 && data[8] >= 8 && data[8] <= 24) { + if (data.size() >= 44 && data[8] >= 8 && data[8] <= 16) { this->on_telemetry_data_(data); return; } - ESP_LOGW(TAG, "Unhandled data received: %s", format_hex_pretty(&data.front(), data.size()).c_str()); + ESP_LOGW(TAG, "Unhandled data received (data_len: 0x%02X): %s", data[5], + format_hex_pretty(&data.front(), data.size()).c_str()); } void SeplosBms::on_telemetry_data_(const std::vector &data) { @@ -27,10 +27,12 @@ void SeplosBms::on_telemetry_data_(const std::vector &data) { return (uint16_t(data[i + 0]) << 8) | (uint16_t(data[i + 1]) << 0); }; - ESP_LOGI(TAG, "Telemetry frame received"); + ESP_LOGI(TAG, "Telemetry frame (%d bytes) received", data.size()); + ESP_LOGVV(TAG, " %s", format_hex_pretty(&data.front(), data.size()).c_str()); // -> // 0x2000460010960001100CD70CE90CF40CD60CEF0CE50CE10CDC0CE90CF00CE80CEF0CEA0CDA0CDE0CD8060BA60BA00B970BA60BA50BA2FD5C14A0344E0A426803134650004603E8149F0000000000000000 + // 0x26004600307600011000000000000000000000000000000000000000000000000000000000000000000608530853085308530BAC0B9000000000002D0213880001E6B8 // // *Data* // @@ -43,8 +45,9 @@ void SeplosBms::on_telemetry_data_(const std::vector &data) { // 5 0x96 Data length LENID 150 / 2 = 75 // 6 0x00 Data flag // 7 0x01 Command group + ESP_LOGV(TAG, "Command group: %d", data[7]); // 8 0x10 Number of cells 16 - uint8_t cells = data[8]; + uint8_t cells = (this->override_cell_count_) ? this->override_cell_count_ : data[8]; ESP_LOGV(TAG, "Number of cells: %d", cells); // 9 0x0C 0xD7 Cell voltage 1 3287 * 0.001f = 3.287 V @@ -122,12 +125,24 @@ void SeplosBms::on_telemetry_data_(const std::vector &data) { // 65 0x46 0x50 Rated capacity 18000 * 0.01f = 180.00 Ah this->publish_state_(this->rated_capacity_sensor_, (float) seplos_get_16bit(offset + 11) * 0.01f); + if (data.size() < offset + 13 + 2) { + return; + } + // 67 0x00 0x46 Number of cycles 70 this->publish_state_(this->charging_cycles_sensor_, (float) seplos_get_16bit(offset + 13)); + if (data.size() < offset + 15 + 2) { + return; + } + // 69 0x03 0xE8 State of health 1000 * 0.1f = 100.0 % this->publish_state_(this->state_of_health_sensor_, (float) seplos_get_16bit(offset + 15) * 0.1f); + if (data.size() < offset + 17 + 2) { + return; + } + // 71 0x14 0x9F Port voltage 5279 * 0.01f = 52.79 V this->publish_state_(this->port_voltage_sensor_, (float) seplos_get_16bit(offset + 17) * 0.01f); @@ -139,7 +154,6 @@ void SeplosBms::on_telemetry_data_(const std::vector &data) { void SeplosBms::dump_config() { ESP_LOGCONFIG(TAG, "SeplosBms:"); - ESP_LOGCONFIG(TAG, " Fake traffic enabled: %s", YESNO(this->enable_fake_traffic_)); LOG_SENSOR("", "Minimum Cell Voltage", this->min_cell_voltage_sensor_); LOG_SENSOR("", "Maximum Cell Voltage", this->max_cell_voltage_sensor_); LOG_SENSOR("", "Minimum Voltage Cell", this->min_voltage_cell_sensor_); @@ -187,27 +201,7 @@ float SeplosBms::get_setup_priority() const { return setup_priority::BUS - 1.0f; } -void SeplosBms::update() { - this->send(0x42, this->address_); - - if (this->enable_fake_traffic_) { - // 14S telemetry - this->on_seplos_modbus_data({0x20, 0x00, 0x46, 0x00, 0xA0, 0x8E, 0x00, 0x01, 0x0E, 0x0F, 0xBB, 0x0F, 0xB6, - 0x0F, 0xAC, 0x0F, 0xAC, 0x0F, 0xB9, 0x0F, 0xB6, 0x0F, 0xB9, 0x0F, 0xBD, 0x0F, - 0xBD, 0x0F, 0xBD, 0x0F, 0xBC, 0x0F, 0xBF, 0x0F, 0xBF, 0x0F, 0xBF, 0x06, 0x0B, - 0x2D, 0x0B, 0x2A, 0x0B, 0x30, 0x0B, 0x2A, 0x0B, 0x52, 0x0B, 0x2F, 0x00, 0x37, - 0x16, 0x03, 0xCA, 0x04, 0x0A, 0xDA, 0xC0, 0x03, 0x9B, 0xDA, 0xC0, 0x00, 0x02, - 0x03, 0xE8, 0x16, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); - - // 16S telemetry - this->on_seplos_modbus_data({0x20, 0x00, 0x46, 0x00, 0x10, 0x96, 0x00, 0x01, 0x10, 0x0C, 0xD8, 0x0C, 0xE8, 0x0C, - 0xF4, 0x0C, 0xD7, 0x0C, 0xEE, 0x0C, 0xE5, 0x0C, 0xE1, 0x0C, 0xDD, 0x0C, 0xE9, 0x0C, - 0xF0, 0x0C, 0xE8, 0x0C, 0xEF, 0x0C, 0xEB, 0x0C, 0xDA, 0x0C, 0xDE, 0x0C, 0xD9, 0x06, - 0x0B, 0xA6, 0x0B, 0xA0, 0x0B, 0x97, 0x0B, 0xA6, 0x0B, 0xA5, 0x0B, 0xA2, 0xFD, 0x72, - 0x14, 0xA0, 0x34, 0x4A, 0x0A, 0x42, 0x68, 0x03, 0x13, 0x46, 0x50, 0x00, 0x46, 0x03, - 0xE8, 0x14, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x7C}); - } -} +void SeplosBms::update() { this->send(0x42, this->pack_); } void SeplosBms::publish_state_(binary_sensor::BinarySensor *binary_sensor, const bool &state) { if (binary_sensor == nullptr) diff --git a/components/seplos_bms/seplos_bms.h b/components/seplos_bms/seplos_bms.h index d5af306..487d7b8 100644 --- a/components/seplos_bms/seplos_bms.h +++ b/components/seplos_bms/seplos_bms.h @@ -70,7 +70,8 @@ class SeplosBms : public PollingComponent, public seplos_modbus::SeplosModbusDev void set_errors_text_sensor(text_sensor::TextSensor *errors_text_sensor) { errors_text_sensor_ = errors_text_sensor; } - void set_enable_fake_traffic(bool enable_fake_traffic) { enable_fake_traffic_ = enable_fake_traffic; } + void set_override_cell_count(uint8_t override_cell_count) { this->override_cell_count_ = override_cell_count; } + void on_seplos_modbus_data(const std::vector &data) override; void dump_config() override; @@ -109,7 +110,7 @@ class SeplosBms : public PollingComponent, public seplos_modbus::SeplosModbusDev sensor::Sensor *temperature_sensor_{nullptr}; } temperatures_[6]; - bool enable_fake_traffic_; + uint8_t override_cell_count_{0}; void publish_state_(binary_sensor::BinarySensor *binary_sensor, const bool &state); void publish_state_(sensor::Sensor *sensor, float value); diff --git a/components/seplos_modbus/__init__.py b/components/seplos_modbus/__init__.py index 9e7b7e8..dee6d54 100644 --- a/components/seplos_modbus/__init__.py +++ b/components/seplos_modbus/__init__.py @@ -1,7 +1,7 @@ -import esphome.codegen as cg -import esphome.config_validation as cv from esphome import pins +import esphome.codegen as cg from esphome.components import uart +import esphome.config_validation as cv from esphome.const import CONF_ADDRESS, CONF_FLOW_CONTROL_PIN, CONF_ID from esphome.cpp_helpers import gpio_pin_expression @@ -14,6 +14,8 @@ CONF_SEPLOS_MODBUS_ID = "seplos_modbus_id" CONF_RX_TIMEOUT = "rx_timeout" +CONF_PROTOCOL_VERSION = "protocol_version" +CONF_OVERRIDE_PACK = "override_pack" CONFIG_SCHEMA = ( cv.Schema( @@ -42,14 +44,15 @@ async def to_code(config): cg.add(var.set_flow_control_pin(pin)) -def seplos_modbus_device_schema(default_address): +def seplos_modbus_device_schema(default_protocol_version, default_address): schema = { cv.GenerateID(CONF_SEPLOS_MODBUS_ID): cv.use_id(SeplosModbus), + cv.Optional(CONF_ADDRESS, default=default_address): cv.hex_uint8_t, + cv.Optional( + CONF_PROTOCOL_VERSION, default=default_protocol_version + ): cv.hex_uint8_t, + cv.Optional(CONF_OVERRIDE_PACK): cv.hex_uint8_t, } - if default_address is None: - schema[cv.Required(CONF_ADDRESS)] = cv.hex_uint8_t - else: - schema[cv.Optional(CONF_ADDRESS, default=default_address)] = cv.hex_uint8_t return cv.Schema(schema) @@ -57,4 +60,10 @@ async def register_seplos_modbus_device(var, config): parent = await cg.get_variable(config[CONF_SEPLOS_MODBUS_ID]) cg.add(var.set_parent(parent)) cg.add(var.set_address(config[CONF_ADDRESS])) + cg.add(var.set_protocol_version(config[CONF_PROTOCOL_VERSION])) cg.add(parent.register_device(var)) + + if CONF_OVERRIDE_PACK in config: + cg.add(var.set_pack(config[CONF_OVERRIDE_PACK])) + else: + cg.add(var.set_pack(config[CONF_ADDRESS])) diff --git a/components/seplos_modbus/seplos_modbus.cpp b/components/seplos_modbus/seplos_modbus.cpp index 47b88c2..433040e 100644 --- a/components/seplos_modbus/seplos_modbus.cpp +++ b/components/seplos_modbus/seplos_modbus.cpp @@ -83,7 +83,7 @@ bool SeplosModbus::parse_seplos_modbus_byte_(uint8_t byte) { // Start of frame if (raw[0] != 0x7E) { - ESP_LOGW(TAG, "Invalid header."); + ESP_LOGW(TAG, "Invalid header"); // return false to reset buffer return false; @@ -98,7 +98,7 @@ bool SeplosModbus::parse_seplos_modbus_byte_(uint8_t byte) { uint16_t remote_crc = uint16_t(ascii_hex_to_byte(raw[at - 4], raw[at - 3])) << 8 | (uint16_t(ascii_hex_to_byte(raw[at - 2], raw[at - 1])) << 0); if (computed_crc != remote_crc) { - ESP_LOGW(TAG, "SeplosBms CRC Check failed! %04X != %04X", computed_crc, remote_crc); + ESP_LOGW(TAG, "CRC Check failed! 0x%04X != 0x%04X", computed_crc, remote_crc); return false; } @@ -135,19 +135,19 @@ float SeplosModbus::get_setup_priority() const { return setup_priority::BUS - 1.0f; } -void SeplosModbus::send(uint8_t address, uint8_t function, uint8_t value) { +void SeplosModbus::send(uint8_t protocol_version, uint8_t address, uint8_t function, uint8_t value) { if (this->flow_control_pin_ != nullptr) this->flow_control_pin_->digital_write(true); const uint16_t lenid = lchksum(1 * 2); std::vector data; - data.push_back(0x20); // VER - data.push_back(address); // ADDR - data.push_back(0x46); // CID1 - data.push_back(function); // CID2 (0x42) - data.push_back(lenid >> 8); // LCHKSUM (0xE0) - data.push_back(lenid >> 0); // LENGTH (0x02) - data.push_back(value); // VALUE (0x00) + data.push_back(protocol_version); // VER + data.push_back(address); // ADDR + data.push_back(0x46); // CID1 + data.push_back(function); // CID2 (0x42) + data.push_back(lenid >> 8); // LCHKSUM (0xE0) + data.push_back(lenid >> 0); // LENGTH (0x02) + data.push_back(value); // VALUE (0x00) const uint16_t frame_len = data.size(); std::string payload = "~"; // SOF (0x7E) diff --git a/components/seplos_modbus/seplos_modbus.h b/components/seplos_modbus/seplos_modbus.h index 88b8629..7fe5242 100644 --- a/components/seplos_modbus/seplos_modbus.h +++ b/components/seplos_modbus/seplos_modbus.h @@ -22,7 +22,7 @@ class SeplosModbus : public uart::UARTDevice, public Component { float get_setup_priority() const override; - void send(uint8_t address, uint8_t function, uint8_t value); + void send(uint8_t protocol_version, uint8_t address, uint8_t function, uint8_t value); void set_rx_timeout(uint16_t rx_timeout) { rx_timeout_ = rx_timeout; } void set_flow_control_pin(GPIOPin *flow_control_pin) { this->flow_control_pin_ = flow_control_pin; } @@ -43,14 +43,20 @@ class SeplosModbusDevice { public: void set_parent(SeplosModbus *parent) { parent_ = parent; } void set_address(uint8_t address) { address_ = address; } + void set_pack(uint8_t pack) { pack_ = pack; } + void set_protocol_version(uint8_t protocol_version) { protocol_version_ = protocol_version; } virtual void on_seplos_modbus_data(const std::vector &data) = 0; - void send(uint8_t function, uint8_t value) { this->parent_->send(this->address_, function, value); } + void send(uint8_t function, uint8_t value) { + this->parent_->send(this->protocol_version_, this->address_, function, value); + } protected: friend SeplosModbus; SeplosModbus *parent_; uint8_t address_; + uint8_t pack_; + uint8_t protocol_version_; }; } // namespace seplos_modbus diff --git a/esp32-boqiang-bms001-example-debug.yaml b/esp32-boqiang-bms001-example-debug.yaml new file mode 100644 index 0000000..24bf159 --- /dev/null +++ b/esp32-boqiang-bms001-example-debug.yaml @@ -0,0 +1,21 @@ +<<: !include esp32-boqiang-bms001-example.yaml + +logger: + level: DEBUG + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + debug: + dummy_receiver: false + direction: BOTH + # after: + # delimiter: "\r" + # sequence: + # - lambda: UARTDebug::log_string(direction, bytes); diff --git a/esp32-boqiang-bms001-example-faker.yaml b/esp32-boqiang-bms001-example-faker.yaml new file mode 100644 index 0000000..0385869 --- /dev/null +++ b/esp32-boqiang-bms001-example-faker.yaml @@ -0,0 +1,13 @@ +<<: !include esp32-boqiang-bms001-example-debug.yaml + +# Telemetry response of a BMS001-HS01-15S +interval: + - interval: 2s + then: + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x26, 0x00, 0x46, 0x00, 0x40, 0x48, 0x00, 0x01, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x06, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0xCC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, + 0xEF, 0xB7 + }); diff --git a/esp32-boqiang-bms001-example.yaml b/esp32-boqiang-bms001-example.yaml new file mode 100644 index 0000000..1a041a1 --- /dev/null +++ b/esp32-boqiang-bms001-example.yaml @@ -0,0 +1,139 @@ +substitutions: + name: seplos-bms + device_description: "Monitor a Boqiang BMS via RS485" + external_components_source: github://syssi/esphome-seplos-bms@main + tx_pin: GPIO4 + rx_pin: GPIO5 + +esphome: + name: ${name} + comment: ${device_description} + project: + name: "syssi.esphome-seplos-bms" + version: 1.0.0 + +esp32: + board: wemos_d1_mini32 + +external_components: + - source: ${external_components_source} + refresh: 0s + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + +api: +ota: +logger: + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + +seplos_modbus: + id: modbus0 + uart_id: uart0 + rx_timeout: 150ms + +seplos_bms: + id: bms0 + # Dip switch configuration of a single pack setup / address 0x0 + # 8 7 6 5 4 3 2 1 + # off, off, off, off, off, off, off, off + address: 0x00 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x26 + override_pack: 1 + override_cell_count: 10 + seplos_modbus_id: modbus0 + update_interval: 10s + +sensor: + - platform: seplos_bms + min_cell_voltage: + name: "${name} min cell voltage" + max_cell_voltage: + name: "${name} max cell voltage" + min_voltage_cell: + name: "${name} min voltage cell" + max_voltage_cell: + name: "${name} max voltage cell" + delta_cell_voltage: + name: "${name} delta cell voltage" + average_cell_voltage: + name: "${name} average cell voltage" + cell_voltage_1: + name: "${name} cell voltage 1" + cell_voltage_2: + name: "${name} cell voltage 2" + cell_voltage_3: + name: "${name} cell voltage 3" + cell_voltage_4: + name: "${name} cell voltage 4" + cell_voltage_5: + name: "${name} cell voltage 5" + cell_voltage_6: + name: "${name} cell voltage 6" + cell_voltage_7: + name: "${name} cell voltage 7" + cell_voltage_8: + name: "${name} cell voltage 8" + cell_voltage_9: + name: "${name} cell voltage 9" + cell_voltage_10: + name: "${name} cell voltage 10" + cell_voltage_11: + name: "${name} cell voltage 11" + cell_voltage_12: + name: "${name} cell voltage 12" + cell_voltage_13: + name: "${name} cell voltage 13" + cell_voltage_14: + name: "${name} cell voltage 14" + cell_voltage_15: + name: "${name} cell voltage 15" + cell_voltage_16: + name: "${name} cell voltage 16" + temperature_1: + name: "${name} temperature 1" + temperature_2: + name: "${name} temperature 2" + temperature_3: + name: "${name} temperature 3" + temperature_4: + name: "${name} temperature 4" + temperature_5: + name: "${name} environment temperature" + temperature_6: + name: "${name} mosfet temperature" + total_voltage: + name: "${name} total voltage" + current: + name: "${name} current" + power: + name: "${name} power" + charging_power: + name: "${name} charging power" + discharging_power: + name: "${name} discharging power" + residual_capacity: + name: "${name} residual capacity" + battery_capacity: + name: "${name} battery capacity" + rated_capacity: + name: "${name} rated capacity" + state_of_charge: + name: "${name} state of charge" + charging_cycles: + name: "${name} charging cycles" + state_of_health: + name: "${name} state of health" + port_voltage: + name: "${name} port voltage" diff --git a/esp32-boqiang-example-debug.yaml b/esp32-boqiang-example-debug.yaml new file mode 100644 index 0000000..873fc70 --- /dev/null +++ b/esp32-boqiang-example-debug.yaml @@ -0,0 +1,21 @@ +<<: !include esp32-boqiang-example.yaml + +logger: + level: DEBUG + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + debug: + dummy_receiver: false + direction: BOTH + # after: + # delimiter: "\r" + # sequence: + # - lambda: UARTDebug::log_string(direction, bytes); diff --git a/esp32-boqiang-example-faker.yaml b/esp32-boqiang-example-faker.yaml new file mode 100644 index 0000000..2e1d4d4 --- /dev/null +++ b/esp32-boqiang-example-faker.yaml @@ -0,0 +1,13 @@ +<<: !include esp32-boqiang-example-debug.yaml + +interval: + - interval: 2s + then: + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x26, 0x00, 0x46, 0x00, 0x30, 0x76, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x08, 0x53, 0x08, 0x53, 0x08, 0x53, 0x08, 0x53, 0x0B, 0xAD, 0x0B, 0x96, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2F, 0x02, 0x13, 0x88, 0x00, 0x01, 0xE6, 0xAF + }); diff --git a/esp32-boqiang-example.yaml b/esp32-boqiang-example.yaml new file mode 100644 index 0000000..009092b --- /dev/null +++ b/esp32-boqiang-example.yaml @@ -0,0 +1,138 @@ +substitutions: + name: seplos-bms + device_description: "Monitor a Boqiang BMS via RS485" + external_components_source: github://syssi/esphome-seplos-bms@main + tx_pin: GPIO4 + rx_pin: GPIO5 + +esphome: + name: ${name} + comment: ${device_description} + project: + name: "syssi.esphome-seplos-bms" + version: 1.0.0 + +esp32: + board: wemos_d1_mini32 + +external_components: + - source: ${external_components_source} + refresh: 0s + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + +api: +ota: +logger: + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + +seplos_modbus: + id: modbus0 + uart_id: uart0 + rx_timeout: 150ms + +seplos_bms: + id: bms0 + # Dip switch configuration of a single pack setup / address 0x0 + # 8 7 6 5 4 3 2 1 + # off, off, off, off, off, off, off, off + address: 0x00 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x26 + override_pack: 1 + seplos_modbus_id: modbus0 + update_interval: 10s + +sensor: + - platform: seplos_bms + min_cell_voltage: + name: "${name} min cell voltage" + max_cell_voltage: + name: "${name} max cell voltage" + min_voltage_cell: + name: "${name} min voltage cell" + max_voltage_cell: + name: "${name} max voltage cell" + delta_cell_voltage: + name: "${name} delta cell voltage" + average_cell_voltage: + name: "${name} average cell voltage" + cell_voltage_1: + name: "${name} cell voltage 1" + cell_voltage_2: + name: "${name} cell voltage 2" + cell_voltage_3: + name: "${name} cell voltage 3" + cell_voltage_4: + name: "${name} cell voltage 4" + cell_voltage_5: + name: "${name} cell voltage 5" + cell_voltage_6: + name: "${name} cell voltage 6" + cell_voltage_7: + name: "${name} cell voltage 7" + cell_voltage_8: + name: "${name} cell voltage 8" + cell_voltage_9: + name: "${name} cell voltage 9" + cell_voltage_10: + name: "${name} cell voltage 10" + cell_voltage_11: + name: "${name} cell voltage 11" + cell_voltage_12: + name: "${name} cell voltage 12" + cell_voltage_13: + name: "${name} cell voltage 13" + cell_voltage_14: + name: "${name} cell voltage 14" + cell_voltage_15: + name: "${name} cell voltage 15" + cell_voltage_16: + name: "${name} cell voltage 16" + temperature_1: + name: "${name} temperature 1" + temperature_2: + name: "${name} temperature 2" + temperature_3: + name: "${name} temperature 3" + temperature_4: + name: "${name} temperature 4" + temperature_5: + name: "${name} environment temperature" + temperature_6: + name: "${name} mosfet temperature" + total_voltage: + name: "${name} total voltage" + current: + name: "${name} current" + power: + name: "${name} power" + charging_power: + name: "${name} charging power" + discharging_power: + name: "${name} discharging power" + residual_capacity: + name: "${name} residual capacity" + battery_capacity: + name: "${name} battery capacity" + rated_capacity: + name: "${name} rated capacity" + state_of_charge: + name: "${name} state of charge" + charging_cycles: + name: "${name} charging cycles" + state_of_health: + name: "${name} state of health" + port_voltage: + name: "${name} port voltage" diff --git a/esp32-example-faker.yaml b/esp32-example-faker.yaml index e014b3b..2b175e9 100644 --- a/esp32-example-faker.yaml +++ b/esp32-example-faker.yaml @@ -1,4 +1,24 @@ <<: !include esp32-example-debug.yaml -seplos_bms: - enable_fake_traffic: true +interval: + - interval: 4s + then: + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x20, 0x00, 0x46, 0x00, 0xA0, 0x8E, 0x00, 0x01, 0x0E, 0x0F, 0xBB, 0x0F, 0xB6, + 0x0F, 0xAC, 0x0F, 0xAC, 0x0F, 0xB9, 0x0F, 0xB6, 0x0F, 0xB9, 0x0F, 0xBD, 0x0F, + 0xBD, 0x0F, 0xBD, 0x0F, 0xBC, 0x0F, 0xBF, 0x0F, 0xBF, 0x0F, 0xBF, 0x06, 0x0B, + 0x2D, 0x0B, 0x2A, 0x0B, 0x30, 0x0B, 0x2A, 0x0B, 0x52, 0x0B, 0x2F, 0x00, 0x37, + 0x16, 0x03, 0xCA, 0x04, 0x0A, 0xDA, 0xC0, 0x03, 0x9B, 0xDA, 0xC0, 0x00, 0x02, + 0x03, 0xE8, 0x16, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }); + - delay: 2s + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x20, 0x00, 0x46, 0x00, 0x10, 0x96, 0x00, 0x01, 0x10, 0x0C, 0xD8, 0x0C, 0xE8, 0x0C, + 0xF4, 0x0C, 0xD7, 0x0C, 0xEE, 0x0C, 0xE5, 0x0C, 0xE1, 0x0C, 0xDD, 0x0C, 0xE9, 0x0C, + 0xF0, 0x0C, 0xE8, 0x0C, 0xEF, 0x0C, 0xEB, 0x0C, 0xDA, 0x0C, 0xDE, 0x0C, 0xD9, 0x06, + 0x0B, 0xA6, 0x0B, 0xA0, 0x0B, 0x97, 0x0B, 0xA6, 0x0B, 0xA5, 0x0B, 0xA2, 0xFD, 0x72, + 0x14, 0xA0, 0x34, 0x4A, 0x0A, 0x42, 0x68, 0x03, 0x13, 0x46, 0x50, 0x00, 0x46, 0x03, + 0xE8, 0x14, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x7C + }); diff --git a/esp32-example.yaml b/esp32-example.yaml index 0848e83..ac326df 100644 --- a/esp32-example.yaml +++ b/esp32-example.yaml @@ -48,6 +48,8 @@ seplos_bms: # 8 7 6 5 4 3 2 1 # off, off, off, off, off, off, off, off address: 0x00 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x20 seplos_modbus_id: modbus0 update_interval: 10s diff --git a/esp8266-boqiang-bms001-example-debug.yaml b/esp8266-boqiang-bms001-example-debug.yaml new file mode 100644 index 0000000..448d93f --- /dev/null +++ b/esp8266-boqiang-bms001-example-debug.yaml @@ -0,0 +1,21 @@ +<<: !include esp8266-boqiang-bms001-example.yaml + +logger: + level: DEBUG + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + debug: + dummy_receiver: false + direction: BOTH + # after: + # delimiter: "\r" + # sequence: + # - lambda: UARTDebug::log_string(direction, bytes); diff --git a/esp8266-boqiang-bms001-example-faker.yaml b/esp8266-boqiang-bms001-example-faker.yaml new file mode 100644 index 0000000..b91f7ae --- /dev/null +++ b/esp8266-boqiang-bms001-example-faker.yaml @@ -0,0 +1,13 @@ +<<: !include esp8266-boqiang-bms001-example-debug.yaml + +# Telemetry response of a BMS001-HS01-15S +interval: + - interval: 2s + then: + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x26, 0x00, 0x46, 0x00, 0x40, 0x48, 0x00, 0x01, 0x0F, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x06, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0xCC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, + 0xEF, 0xB7 + }); diff --git a/esp8266-boqiang-bms001-example.yaml b/esp8266-boqiang-bms001-example.yaml new file mode 100644 index 0000000..adec430 --- /dev/null +++ b/esp8266-boqiang-bms001-example.yaml @@ -0,0 +1,139 @@ +substitutions: + name: seplos-bms + device_description: "Monitor a Boqiang BMS001 via RS485" + external_components_source: github://syssi/esphome-seplos-bms@main + tx_pin: GPIO4 + rx_pin: GPIO5 + +esphome: + name: ${name} + comment: ${device_description} + project: + name: "syssi.esphome-seplos-bms" + version: 1.0.0 + +esp8266: + board: d1_mini + +external_components: + - source: ${external_components_source} + refresh: 0s + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + +api: +ota: +logger: + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + +seplos_modbus: + id: modbus0 + uart_id: uart0 + rx_timeout: 150ms + +seplos_bms: + id: bms0 + # Dip switch configuration of a single pack setup / address 0x0 + # 8 7 6 5 4 3 2 1 + # off, off, off, off, off, off, off, off + address: 0x00 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x26 + override_pack: 1 + override_cell_count: 10 + seplos_modbus_id: modbus0 + update_interval: 10s + +sensor: + - platform: seplos_bms + min_cell_voltage: + name: "${name} min cell voltage" + max_cell_voltage: + name: "${name} max cell voltage" + min_voltage_cell: + name: "${name} min voltage cell" + max_voltage_cell: + name: "${name} max voltage cell" + delta_cell_voltage: + name: "${name} delta cell voltage" + average_cell_voltage: + name: "${name} average cell voltage" + cell_voltage_1: + name: "${name} cell voltage 1" + cell_voltage_2: + name: "${name} cell voltage 2" + cell_voltage_3: + name: "${name} cell voltage 3" + cell_voltage_4: + name: "${name} cell voltage 4" + cell_voltage_5: + name: "${name} cell voltage 5" + cell_voltage_6: + name: "${name} cell voltage 6" + cell_voltage_7: + name: "${name} cell voltage 7" + cell_voltage_8: + name: "${name} cell voltage 8" + cell_voltage_9: + name: "${name} cell voltage 9" + cell_voltage_10: + name: "${name} cell voltage 10" + cell_voltage_11: + name: "${name} cell voltage 11" + cell_voltage_12: + name: "${name} cell voltage 12" + cell_voltage_13: + name: "${name} cell voltage 13" + cell_voltage_14: + name: "${name} cell voltage 14" + cell_voltage_15: + name: "${name} cell voltage 15" + cell_voltage_16: + name: "${name} cell voltage 16" + temperature_1: + name: "${name} temperature 1" + temperature_2: + name: "${name} temperature 2" + temperature_3: + name: "${name} temperature 3" + temperature_4: + name: "${name} temperature 4" + temperature_5: + name: "${name} environment temperature" + temperature_6: + name: "${name} mosfet temperature" + total_voltage: + name: "${name} total voltage" + current: + name: "${name} current" + power: + name: "${name} power" + charging_power: + name: "${name} charging power" + discharging_power: + name: "${name} discharging power" + residual_capacity: + name: "${name} residual capacity" + battery_capacity: + name: "${name} battery capacity" + rated_capacity: + name: "${name} rated capacity" + state_of_charge: + name: "${name} state of charge" + charging_cycles: + name: "${name} charging cycles" + state_of_health: + name: "${name} state of health" + port_voltage: + name: "${name} port voltage" diff --git a/esp8266-boqiang-example-debug.yaml b/esp8266-boqiang-example-debug.yaml new file mode 100644 index 0000000..749bb65 --- /dev/null +++ b/esp8266-boqiang-example-debug.yaml @@ -0,0 +1,21 @@ +<<: !include esp8266-boqiang-example.yaml + +logger: + level: DEBUG + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + debug: + dummy_receiver: false + direction: BOTH + # after: + # delimiter: "\r" + # sequence: + # - lambda: UARTDebug::log_string(direction, bytes); diff --git a/esp8266-boqiang-example-faker.yaml b/esp8266-boqiang-example-faker.yaml new file mode 100644 index 0000000..128979e --- /dev/null +++ b/esp8266-boqiang-example-faker.yaml @@ -0,0 +1,14 @@ +<<: !include esp8266-boqiang-example-debug.yaml + +# Telemetry response of a BMS007-LD43-16S-HW +interval: + - interval: 2s + then: + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x26, 0x00, 0x46, 0x00, 0x30, 0x76, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x08, 0x53, 0x08, 0x53, 0x08, 0x53, 0x08, 0x53, 0x0B, 0xAD, 0x0B, 0x96, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2F, 0x02, 0x13, 0x88, 0x00, 0x01, 0xE6, 0xAF + }); diff --git a/esp8266-boqiang-example.yaml b/esp8266-boqiang-example.yaml new file mode 100644 index 0000000..f1679dc --- /dev/null +++ b/esp8266-boqiang-example.yaml @@ -0,0 +1,138 @@ +substitutions: + name: seplos-bms + device_description: "Monitor a Boqiang BMS via RS485" + external_components_source: github://syssi/esphome-seplos-bms@main + tx_pin: GPIO4 + rx_pin: GPIO5 + +esphome: + name: ${name} + comment: ${device_description} + project: + name: "syssi.esphome-seplos-bms" + version: 1.0.0 + +esp8266: + board: d1_mini + +external_components: + - source: ${external_components_source} + refresh: 0s + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + +api: +ota: +logger: + +uart: + id: uart0 + # Please set the default baudrate of your Seplos BMS model here. It's sometimes 19200 baud instead of 9600. + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + # The increased RX buffer size is important because + # the full BMS response must fit into the buffer + rx_buffer_size: 384 + +seplos_modbus: + id: modbus0 + uart_id: uart0 + rx_timeout: 150ms + +seplos_bms: + id: bms0 + # Dip switch configuration of a single pack setup / address 0x0 + # 8 7 6 5 4 3 2 1 + # off, off, off, off, off, off, off, off + address: 0x00 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x26 + override_pack: 1 + seplos_modbus_id: modbus0 + update_interval: 10s + +sensor: + - platform: seplos_bms + min_cell_voltage: + name: "${name} min cell voltage" + max_cell_voltage: + name: "${name} max cell voltage" + min_voltage_cell: + name: "${name} min voltage cell" + max_voltage_cell: + name: "${name} max voltage cell" + delta_cell_voltage: + name: "${name} delta cell voltage" + average_cell_voltage: + name: "${name} average cell voltage" + cell_voltage_1: + name: "${name} cell voltage 1" + cell_voltage_2: + name: "${name} cell voltage 2" + cell_voltage_3: + name: "${name} cell voltage 3" + cell_voltage_4: + name: "${name} cell voltage 4" + cell_voltage_5: + name: "${name} cell voltage 5" + cell_voltage_6: + name: "${name} cell voltage 6" + cell_voltage_7: + name: "${name} cell voltage 7" + cell_voltage_8: + name: "${name} cell voltage 8" + cell_voltage_9: + name: "${name} cell voltage 9" + cell_voltage_10: + name: "${name} cell voltage 10" + cell_voltage_11: + name: "${name} cell voltage 11" + cell_voltage_12: + name: "${name} cell voltage 12" + cell_voltage_13: + name: "${name} cell voltage 13" + cell_voltage_14: + name: "${name} cell voltage 14" + cell_voltage_15: + name: "${name} cell voltage 15" + cell_voltage_16: + name: "${name} cell voltage 16" + temperature_1: + name: "${name} temperature 1" + temperature_2: + name: "${name} temperature 2" + temperature_3: + name: "${name} temperature 3" + temperature_4: + name: "${name} temperature 4" + temperature_5: + name: "${name} environment temperature" + temperature_6: + name: "${name} mosfet temperature" + total_voltage: + name: "${name} total voltage" + current: + name: "${name} current" + power: + name: "${name} power" + charging_power: + name: "${name} charging power" + discharging_power: + name: "${name} discharging power" + residual_capacity: + name: "${name} residual capacity" + battery_capacity: + name: "${name} battery capacity" + rated_capacity: + name: "${name} rated capacity" + state_of_charge: + name: "${name} state of charge" + charging_cycles: + name: "${name} charging cycles" + state_of_health: + name: "${name} state of health" + port_voltage: + name: "${name} port voltage" diff --git a/esp8266-example-faker.yaml b/esp8266-example-faker.yaml index 2aa8fe5..6889f52 100644 --- a/esp8266-example-faker.yaml +++ b/esp8266-example-faker.yaml @@ -1,4 +1,24 @@ <<: !include esp8266-example-debug.yaml -seplos_bms: - enable_fake_traffic: true +interval: + - interval: 4s + then: + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x20, 0x00, 0x46, 0x00, 0xA0, 0x8E, 0x00, 0x01, 0x0E, 0x0F, 0xBB, 0x0F, 0xB6, + 0x0F, 0xAC, 0x0F, 0xAC, 0x0F, 0xB9, 0x0F, 0xB6, 0x0F, 0xB9, 0x0F, 0xBD, 0x0F, + 0xBD, 0x0F, 0xBD, 0x0F, 0xBC, 0x0F, 0xBF, 0x0F, 0xBF, 0x0F, 0xBF, 0x06, 0x0B, + 0x2D, 0x0B, 0x2A, 0x0B, 0x30, 0x0B, 0x2A, 0x0B, 0x52, 0x0B, 0x2F, 0x00, 0x37, + 0x16, 0x03, 0xCA, 0x04, 0x0A, 0xDA, 0xC0, 0x03, 0x9B, 0xDA, 0xC0, 0x00, 0x02, + 0x03, 0xE8, 0x16, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }); + - delay: 2s + - lambda: |- + id(bms0).on_seplos_modbus_data({ + 0x20, 0x00, 0x46, 0x00, 0x10, 0x96, 0x00, 0x01, 0x10, 0x0C, 0xD8, 0x0C, 0xE8, 0x0C, + 0xF4, 0x0C, 0xD7, 0x0C, 0xEE, 0x0C, 0xE5, 0x0C, 0xE1, 0x0C, 0xDD, 0x0C, 0xE9, 0x0C, + 0xF0, 0x0C, 0xE8, 0x0C, 0xEF, 0x0C, 0xEB, 0x0C, 0xDA, 0x0C, 0xDE, 0x0C, 0xD9, 0x06, + 0x0B, 0xA6, 0x0B, 0xA0, 0x0B, 0x97, 0x0B, 0xA6, 0x0B, 0xA5, 0x0B, 0xA2, 0xFD, 0x72, + 0x14, 0xA0, 0x34, 0x4A, 0x0A, 0x42, 0x68, 0x03, 0x13, 0x46, 0x50, 0x00, 0x46, 0x03, + 0xE8, 0x14, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x7C + }); diff --git a/esp8266-example-multiple-battery-banks.yaml b/esp8266-example-multiple-battery-banks.yaml index 173c225..8f01367 100644 --- a/esp8266-example-multiple-battery-banks.yaml +++ b/esp8266-example-multiple-battery-banks.yaml @@ -49,6 +49,8 @@ seplos_bms: # 8 7 6 5 4 3 2 1 # off, off, off, off, off, off, off, on address: 0x01 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x20 seplos_modbus_id: modbus0 update_interval: 10s - id: battery_bank1 @@ -56,6 +58,8 @@ seplos_bms: # 8 7 6 5 4 3 2 1 # off, off, off, off, off, off, on, off address: 0x02 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x20 seplos_modbus_id: modbus0 update_interval: 10s - id: battery_bank2 @@ -63,6 +67,8 @@ seplos_bms: # 8 7 6 5 4 3 2 1 # off, off, off, off, off, off, on, on address: 0x03 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x20 seplos_modbus_id: modbus0 update_interval: 10s diff --git a/esp8266-example.yaml b/esp8266-example.yaml index ea18d19..944e76b 100644 --- a/esp8266-example.yaml +++ b/esp8266-example.yaml @@ -48,6 +48,8 @@ seplos_bms: # 8 7 6 5 4 3 2 1 # off, off, off, off, off, off, off, off address: 0x00 + # Known protocol versions: 0x20 (Seplos), 0x26 (Boqiang) + protocol_version: 0x20 seplos_modbus_id: modbus0 update_interval: 10s diff --git a/tests/esp8266-boqiang-emulator.yaml b/tests/esp8266-boqiang-emulator.yaml new file mode 100644 index 0000000..cd228e4 --- /dev/null +++ b/tests/esp8266-boqiang-emulator.yaml @@ -0,0 +1,46 @@ +substitutions: + name: boqiang-emu + tx_pin: GPIO4 + rx_pin: GPIO5 + +esphome: + name: ${name} + +esp8266: + board: d1_mini + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + +api: +ota: +logger: + +uart: + id: uart0 + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + debug: + direction: BOTH + dummy_receiver: true + after: + delimiter: "\r" + sequence: + - lambda: UARTDebug::log_string(direction, bytes); + - lambda: + std::string request(bytes.begin(), bytes.end()); + if(request == "~2000464F0000FD9A\r") { + id(uart0).write_str("~260046000000FDAE\r"); + return; + } + if(request == "~260046510000FDA8\r") { + id(uart0).write_str("~26004600C040424D5330372D4C44343301084A532D52696368706F77657220436F2E2C4C7464EFF7\r"); + return; + } + if(request == "~26004642E00201FD30\r") { + id(uart0).write_str("~26004600307600011000000000000000000000000000000000000000000000000000000000000000000608530853085308530BAD0B9600000000002F0213880001E6AF\r"); + return; + } + ESP_LOGD("Lambda", "Unhandled request %s", request.c_str()); diff --git a/tests/esp8266-boqiang-test.yaml b/tests/esp8266-boqiang-test.yaml new file mode 100644 index 0000000..4dc7c12 --- /dev/null +++ b/tests/esp8266-boqiang-test.yaml @@ -0,0 +1,45 @@ +substitutions: + name: boqiang-bms-tests + tx_pin: GPIO4 + rx_pin: GPIO5 + +esphome: + name: ${name} + +esp8266: + board: d1_mini + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + +api: +ota: +logger: + +uart: + id: uart0 + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + debug: + direction: BOTH + dummy_receiver: true + after: + delimiter: "\r" + sequence: + - lambda: UARTDebug::log_string(direction, bytes); + +interval: + - interval: 6s + then: + # Address 0x00, pack 0x01 + - uart.write: "~26004642E00201FD30\r" + - delay: 2s + + # Address 0x00, pack 0x00 + - uart.write: "~26004642E00200FD31\r" + - delay: 2s + + # Address 0x01, pack 0x01 + - uart.write: "~26014642E00201FD2F\r" diff --git a/esp8266-fake-bms.yaml b/tests/esp8266-fake-bms.yaml similarity index 98% rename from esp8266-fake-bms.yaml rename to tests/esp8266-fake-bms.yaml index 430dcfa..1a7b50c 100644 --- a/esp8266-fake-bms.yaml +++ b/tests/esp8266-fake-bms.yaml @@ -1,6 +1,6 @@ substitutions: name: seplos-bms-tx - device_description: "Fake Seplos BMS" + device_description: "Fake Seplos BMS protocol version 0x20" tx_pin: GPIO4 rx_pin: GPIO5 diff --git a/tests/esp8266-protocol-version.yaml b/tests/esp8266-protocol-version.yaml new file mode 100644 index 0000000..0012591 --- /dev/null +++ b/tests/esp8266-protocol-version.yaml @@ -0,0 +1,37 @@ +substitutions: + name: seplos-bms + tx_pin: GPIO4 + rx_pin: GPIO5 + +esphome: + name: ${name} + +esp8266: + board: d1_mini + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_password + +api: +ota: +logger: + +uart: + id: uart0 + baud_rate: 9600 + tx_pin: ${tx_pin} + rx_pin: ${rx_pin} + debug: + direction: BOTH + dummy_receiver: true + after: + delimiter: "\r" + sequence: + - lambda: UARTDebug::log_string(direction, bytes); + +interval: + - interval: 5s + then: + # Get protocol version (CID2 `0x4F`) + - uart.write: "~2000464F0000FD9A\r" diff --git a/tests/esp8266-seplos-emulator.yaml b/tests/esp8266-seplos-emulator.yaml index 628d5e2..83aebe2 100644 --- a/tests/esp8266-seplos-emulator.yaml +++ b/tests/esp8266-seplos-emulator.yaml @@ -1,7 +1,7 @@ substitutions: name: seplos-emu - tx_pin: GPIO1 - rx_pin: GPIO3 + tx_pin: GPIO4 + rx_pin: GPIO5 esphome: name: ${name} @@ -16,7 +16,6 @@ wifi: api: ota: logger: - baud_rate: 0 uart: id: uart0