From 7904a07e7f4e438b49a5f4c62969b49bc3ba1a45 Mon Sep 17 00:00:00 2001 From: Patrick762 Date: Sat, 23 Sep 2023 17:52:18 +0200 Subject: [PATCH] added ep600 dc input, prevent pack polling --- custom_components/bluetti_bt/config_flow.py | 2 +- custom_components/bluetti_bt/const.py | 72 +++++++++++++++++++ custom_components/bluetti_bt/coordinator.py | 80 ++++++++++----------- custom_components/bluetti_bt/sensor.py | 4 +- custom_components/bluetti_bt/switch.py | 4 +- 5 files changed, 115 insertions(+), 47 deletions(-) diff --git a/custom_components/bluetti_bt/config_flow.py b/custom_components/bluetti_bt/config_flow.py index d487271..975a068 100644 --- a/custom_components/bluetti_bt/config_flow.py +++ b/custom_components/bluetti_bt/config_flow.py @@ -17,7 +17,7 @@ from homeassistant.data_entry_flow import FlowResult from homeassistant.helpers import selector from . import get_type_by_bt_name -from .const import CONF_PERSISTENT_CONN, CONF_POLLING_INTERVAL, DATA_COORDINATOR, DOMAIN, CONF_USE_CONTROLS +from .const import CONF_PERSISTENT_CONN, CONF_POLLING_INTERVAL, DOMAIN, CONF_USE_CONTROLS _LOGGER = logging.getLogger(__name__) diff --git a/custom_components/bluetti_bt/const.py b/custom_components/bluetti_bt/const.py index acbf2ab..202cf06 100644 --- a/custom_components/bluetti_bt/const.py +++ b/custom_components/bluetti_bt/const.py @@ -79,6 +79,78 @@ ADDITIONAL_DEVICE_FIELDS = { advanced=False, home_assistant_extra={"name": "High Voltage Safety Module Version"}, ), + 'pv_input_power1': MqttFieldConfig( + type=MqttFieldType.NUMERIC, + setter=False, + advanced=False, + home_assistant_extra={ + "name": "Solar Input Power 1", + "unit_of_measurement": "W", + "device_class": "power", + "state_class": "measurement", + "force_update": True, + }, + ), + 'pv_input_voltage1': MqttFieldConfig( + type=MqttFieldType.NUMERIC, + setter=False, + advanced=False, + home_assistant_extra={ + "name": "Solar Input Voltage 1", + "unit_of_measurement": "V", + "device_class": "voltage", + "state_class": "measurement", + "force_update": True, + }, + ), + 'pv_input_current1': MqttFieldConfig( + type=MqttFieldType.NUMERIC, + setter=False, + advanced=False, + home_assistant_extra={ + "name": "Solar Input Current 1", + "unit_of_measurement": "A", + "device_class": "current", + "state_class": "measurement", + "force_update": True, + }, + ), + 'pv_input_power2': MqttFieldConfig( + type=MqttFieldType.NUMERIC, + setter=False, + advanced=False, + home_assistant_extra={ + "name": "Solar Input Power 2", + "unit_of_measurement": "W", + "device_class": "power", + "state_class": "measurement", + "force_update": True, + }, + ), + 'pv_input_voltage2': MqttFieldConfig( + type=MqttFieldType.NUMERIC, + setter=False, + advanced=False, + home_assistant_extra={ + "name": "Solar Input Voltage 2", + "unit_of_measurement": "V", + "device_class": "voltage", + "state_class": "measurement", + "force_update": True, + }, + ), + 'pv_input_current2': MqttFieldConfig( + type=MqttFieldType.NUMERIC, + setter=False, + advanced=False, + home_assistant_extra={ + "name": "Solar Input Current 2", + "unit_of_measurement": "A", + "device_class": "current", + "state_class": "measurement", + "force_update": True, + }, + ), "adl400_ac_input_power_phase1": MqttFieldConfig( type=MqttFieldType.NUMERIC, setter=False, diff --git a/custom_components/bluetti_bt/coordinator.py b/custom_components/bluetti_bt/coordinator.py index 06bda77..534d686 100644 --- a/custom_components/bluetti_bt/coordinator.py +++ b/custom_components/bluetti_bt/coordinator.py @@ -44,6 +44,13 @@ class DummyDevice(BluettiDevice): self.struct = device.struct if device.type == "EP600": + # DC Solar Input (copied from PR https://github.com/warhammerkid/bluetti_mqtt/pull/87 by KM011092) + self.struct.add_uint_field('pv_input_power1', 1212) # MPP 1 in - value * 0.1 + #self.struct.add_uint_field('pv_input_voltage1', 1213) # MPP 1 in - value * 0.1 + #self.struct.add_uint_field('pv_input_current1', 1214) # MPP 1 in + self.struct.add_uint_field('pv_input_power2', 1220) # MPP 2 in - value * 0.1 + #self.struct.add_uint_field('pv_input_voltage2', 1221) # MPP 2 in - value * 0.1 + #self.struct.add_uint_field('pv_input_current2', 1222) # MPP 2 in # ADL400 Smart Meter for AC Solar self.struct.add_uint_field("adl400_ac_input_power_phase1", 1228) self.struct.add_uint_field("adl400_ac_input_power_phase2", 1236) @@ -73,9 +80,6 @@ class DummyDevice(BluettiDevice): self.struct.add_decimal_field("ac_output_current_phase1", 1512, 1) self.struct.add_decimal_field("ac_output_current_phase2", 1519, 1) self.struct.add_decimal_field("ac_output_current_phase3", 1526, 1) - # Testing - # for i in range(0, 10): - # self.struct.add_decimal_field("testing"+str(i), 1520+i, 1) super().__init__(device.address, device.type, device.sn) self._parent = device @@ -94,28 +98,18 @@ class DummyDevice(BluettiDevice): ReadHoldingRegisters(1500, 27), ReadHoldingRegisters(2022, 6), ReadHoldingRegisters(2213, 4), + ReadHoldingRegisters(1212, 11), # Battery ReadHoldingRegisters(6101, 7), ReadHoldingRegisters(6175, 11), - # Testing - # ReadHoldingRegisters(100, 62), - # ReadHoldingRegisters(1100, 51), - # ReadHoldingRegisters(1200, 80), - # ReadHoldingRegisters(1300, 31), - # ReadHoldingRegisters(1400, 48), - # ReadHoldingRegisters(1500, 30), - # ReadHoldingRegisters(2000, 89), - # ReadHoldingRegisters(2200, 41), - # ReadHoldingRegisters(2300, 36), - # ReadHoldingRegisters(6000, 32), - # ReadHoldingRegisters(6100, 100), - # ReadHoldingRegisters(6300, 100), ] return self._parent.polling_commands @property def pack_polling_commands(self) -> List[ReadHoldingRegisters]: + if self.type == "EP600": + return [] return self._parent.pack_polling_commands @property @@ -224,36 +218,38 @@ class PollingCoordinator(DataUpdateCoordinator): except ParseError: self.logger.warning("Got a parse exception...") - - # pack polling - for pack in range (1, self.bluetti_device.pack_num_max + 1): - # Set current pack number - await self.async_send_command( - self.bluetti_device.build_setter_command('pack_num', pack) - ) - - for command in self.bluetti_device.pack_polling_commands: - # Request & parse result for each pack - try: - body = command.parse_response( - await self.async_send_command(command) + + if len(self.bluetti_device.pack_polling_commands) > 0: + _LOGGER.debug("Polling battery packs") + # pack polling + for pack in range (1, self.bluetti_device.pack_num_max + 1): + # Set current pack number + await self.async_send_command( + self.bluetti_device.build_setter_command('pack_num', pack) ) - parsed = self.bluetti_device.parse( - command.starting_address, body - ) - self.logger.debug("Parsed data: %s", parsed) - packNo = parsed.get('pack_num') - if not isinstance(packNo, int) or packNo != pack: - self.logger.debug("Parsed pack_num(%s) does not match expected '%s'", packNo, pack) - continue + for command in self.bluetti_device.pack_polling_commands: + # Request & parse result for each pack + try: + body = command.parse_response( + await self.async_send_command(command) + ) + parsed = self.bluetti_device.parse( + command.starting_address, body + ) + self.logger.debug("Parsed data: %s", parsed) - for key, value in parsed.items(): - parsed_data.update({key+str(pack):value}) + pack_number = parsed.get('pack_num') + if not isinstance(pack_number, int) or pack_number != pack: + self.logger.debug("Parsed pack_num(%s) does not match expected '%s'", pack_number, pack) + continue + + for key, value in parsed.items(): + parsed_data.update({key+str(pack):value}) + + except ParseError: + self.logger.warning("Got a parse exception...") - except ParseError: - self.logger.warning("Got a parse exception...") - except TimeoutError: self.logger.debug("Polling timed out for device %s", mac_loggable(self._address)) return None diff --git a/custom_components/bluetti_bt/sensor.py b/custom_components/bluetti_bt/sensor.py index 12579dc..0cf39f2 100644 --- a/custom_components/bluetti_bt/sensor.py +++ b/custom_components/bluetti_bt/sensor.py @@ -65,7 +65,7 @@ async def async_setup_entry( for pack in range (1, bluetti_device.pack_num_max + 1): for name, field in battery_pack_fields(pack).items(): all_fields.update({name+str(pack):field}) - + for field_key, field_config in all_fields.items(): if bluetti_device.has_field(field_key) or field_config.id_override is not None: category = None @@ -151,7 +151,7 @@ class BluettiSensor(CoordinatorEntity, SensorEntity): response_data = self.coordinator.data.get(self._response_key) if response_data is None: - _LOGGER.debug("No data for available for (%s)",self._response_key) + _LOGGER.debug("No data for available for (%s)", self._response_key) self._attr_available = False return diff --git a/custom_components/bluetti_bt/switch.py b/custom_components/bluetti_bt/switch.py index 184cb55..62280e4 100644 --- a/custom_components/bluetti_bt/switch.py +++ b/custom_components/bluetti_bt/switch.py @@ -6,7 +6,7 @@ import asyncio import logging import async_timeout -from bleak import BleakClient, BleakError +from bleak import BleakError from homeassistant.components import bluetooth from homeassistant.components.switch import SwitchEntity, SwitchDeviceClass @@ -33,7 +33,7 @@ from bluetti_mqtt.mqtt_client import ( ) from . import device_info as dev_info, get_unique_id -from .const import CONTROL_FIELDS, DATA_COORDINATOR, DATA_POLLING_RUNNING, DOMAIN, ADDITIONAL_DEVICE_FIELDS +from .const import CONTROL_FIELDS, DATA_COORDINATOR, DOMAIN, ADDITIONAL_DEVICE_FIELDS from .coordinator import PollingCoordinator, DummyDevice from .utils import mac_loggable, unique_id_loggable