Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ef9d38a6e | ||
|
|
463f02b09b | ||
|
|
8eb09a32f0 | ||
|
|
e8b9db9a42 | ||
|
|
9c7e5968bb | ||
|
|
0420511d90 | ||
|
|
dcc6131d02 | ||
|
|
11716084c9 | ||
|
|
aa1c3ef425 | ||
|
|
a8931e09c7 | ||
|
|
66a7de9051 |
No files matched your search
@@ -0,0 +1,76 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: File a bug report
|
||||||
|
title: "[Bug]: "
|
||||||
|
labels: ["bug"]
|
||||||
|
assignees:
|
||||||
|
- octocat
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: Also tell us, what did you expect to happen?
|
||||||
|
placeholder: Tell us what you see!
|
||||||
|
value: "An exception appeared"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Version
|
||||||
|
description: What version of our software are you running?
|
||||||
|
options:
|
||||||
|
- 0.0.11
|
||||||
|
- 0.0.10
|
||||||
|
- 0.0.9
|
||||||
|
default: 0
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: What device are you seeing the problem on?
|
||||||
|
multiple: true
|
||||||
|
options:
|
||||||
|
- AC60
|
||||||
|
- AC200M
|
||||||
|
- AC300
|
||||||
|
- AC500
|
||||||
|
- EB3A
|
||||||
|
- EP500
|
||||||
|
- EP500P
|
||||||
|
- EP900
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: bluetooth
|
||||||
|
attributes:
|
||||||
|
label: What bluetooth connection are you using?
|
||||||
|
multiple: false
|
||||||
|
options:
|
||||||
|
- USB dongle
|
||||||
|
- ESPHome bluetooth proxy
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: options-changed
|
||||||
|
attributes:
|
||||||
|
label: Have you changed the integration settings?
|
||||||
|
multiple: false
|
||||||
|
options:
|
||||||
|
- No
|
||||||
|
- Yes (Please write down the changed settings in the next step)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: options-details
|
||||||
|
attributes:
|
||||||
|
label: Integration settings (if you changed them)
|
||||||
|
description: Please use one line per option
|
||||||
|
render: text
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Relevant log output
|
||||||
|
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||||
|
render: shell
|
||||||
@@ -7,6 +7,9 @@ Bluetti Integration for Home Assistant
|
|||||||
|
|
||||||
Based on [bluetti_mqtt](https://github.com/warhammerkid/bluetti_mqtt).
|
Based on [bluetti_mqtt](https://github.com/warhammerkid/bluetti_mqtt).
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
This integration is provided without any warranty or support by Bluetti (unfortunately). I do not take responsibility for any problems it may cause in all cases. Use it at your own risk.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
To install this integration, you first need [HACS](https://hacs.xyz/) installed.
|
To install this integration, you first need [HACS](https://hacs.xyz/) installed.
|
||||||
After the installation, you can use this button to install the integration:
|
After the installation, you can use this button to install the integration:
|
||||||
@@ -24,6 +27,7 @@ After the installation, you can use this button to install the integration:
|
|||||||
- EP500
|
- EP500
|
||||||
- EP500P
|
- EP500P
|
||||||
- EP600 (tested)
|
- EP600 (tested)
|
||||||
|
- EP760 (beta, untested)
|
||||||
|
|
||||||
### Available sensors:
|
### Available sensors:
|
||||||
All sensors which are available in bluetti_mqtt (Based on [this file](https://github.com/warhammerkid/bluetti_mqtt/blob/main/bluetti_mqtt/mqtt_client.py)).
|
All sensors which are available in bluetti_mqtt (Based on [this file](https://github.com/warhammerkid/bluetti_mqtt/blob/main/bluetti_mqtt/mqtt_client.py)).
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
|
||||||
|
from bluetti_mqtt.bluetooth import build_device as orig_build_device
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_MAX_RETRIES,
|
CONF_MAX_RETRIES,
|
||||||
CONF_PERSISTENT_CONN,
|
CONF_PERSISTENT_CONN,
|
||||||
@@ -20,10 +22,13 @@ from .const import (
|
|||||||
CONF_USE_CONTROLS,
|
CONF_USE_CONTROLS,
|
||||||
DATA_COORDINATOR,
|
DATA_COORDINATOR,
|
||||||
DATA_POLLING_RUNNING,
|
DATA_POLLING_RUNNING,
|
||||||
|
DEVICE_NAME_RE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
MANUFACTURER,
|
MANUFACTURER,
|
||||||
)
|
)
|
||||||
from .coordinator import PollingCoordinator
|
from .coordinator import PollingCoordinator
|
||||||
|
from .devices.ep600 import EP600
|
||||||
|
from .devices.ep760 import EP760
|
||||||
|
|
||||||
PLATFORMS: [Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
PLATFORMS: [Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -102,4 +107,15 @@ def get_type_by_bt_name(bt_name: str):
|
|||||||
dev_type = "EP500"
|
dev_type = "EP500"
|
||||||
elif bt_name.startswith("EP600"):
|
elif bt_name.startswith("EP600"):
|
||||||
dev_type = "EP600"
|
dev_type = "EP600"
|
||||||
|
elif bt_name.startswith("EP760"):
|
||||||
|
dev_type = "EP760"
|
||||||
return dev_type
|
return dev_type
|
||||||
|
|
||||||
|
def build_device(address: str, name: str):
|
||||||
|
match = DEVICE_NAME_RE.match(name)
|
||||||
|
if match[1] == 'EP760':
|
||||||
|
return EP760(address, match[2])
|
||||||
|
elif match[1] == 'EP600':
|
||||||
|
return EP600(address, match[2])
|
||||||
|
else:
|
||||||
|
return orig_build_device(address, name)
|
||||||
@@ -18,16 +18,15 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
)
|
)
|
||||||
|
|
||||||
from bluetti_mqtt.bluetooth import build_device
|
|
||||||
from bluetti_mqtt.mqtt_client import (
|
from bluetti_mqtt.mqtt_client import (
|
||||||
NORMAL_DEVICE_FIELDS,
|
NORMAL_DEVICE_FIELDS,
|
||||||
DC_INPUT_FIELDS,
|
DC_INPUT_FIELDS,
|
||||||
MqttFieldType,
|
MqttFieldType,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import device_info as dev_info, get_unique_id
|
from . import device_info as dev_info, get_unique_id, build_device
|
||||||
from .const import DATA_COORDINATOR, DOMAIN, ADDITIONAL_DEVICE_FIELDS
|
from .const import DATA_COORDINATOR, DOMAIN, ADDITIONAL_DEVICE_FIELDS
|
||||||
from .coordinator import PollingCoordinator, DummyDevice
|
from .coordinator import PollingCoordinator
|
||||||
from .utils import unique_id_loggable
|
from .utils import unique_id_loggable
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -49,7 +48,6 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
# Add sensors according to device_info
|
# Add sensors according to device_info
|
||||||
bluetti_device = build_device(address, device_name)
|
bluetti_device = build_device(address, device_name)
|
||||||
bluetti_device = DummyDevice(bluetti_device)
|
|
||||||
|
|
||||||
sensors_to_add = []
|
sensors_to_add = []
|
||||||
all_fields = NORMAL_DEVICE_FIELDS
|
all_fields = NORMAL_DEVICE_FIELDS
|
||||||
@@ -91,6 +89,7 @@ class BluettiBinarySensor(CoordinatorEntity, BinarySensorEntity):
|
|||||||
"""Init battery entity."""
|
"""Init battery entity."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
|
|
||||||
|
self._attr_has_entity_name = True
|
||||||
e_name = f"{device_info.get('name')} {name}"
|
e_name = f"{device_info.get('name')} {name}"
|
||||||
self._address = address
|
self._address = address
|
||||||
self._response_key = response_key
|
self._response_key = response_key
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
"""Constants for the Bluetti BT integration."""
|
"""Constants for the Bluetti BT integration."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
from bluetti_mqtt.mqtt_client import MqttFieldConfig, MqttFieldType
|
from bluetti_mqtt.mqtt_client import MqttFieldConfig, MqttFieldType
|
||||||
|
|
||||||
DOMAIN = "bluetti_bt"
|
DOMAIN = "bluetti_bt"
|
||||||
@@ -15,6 +17,8 @@ CONF_MAX_RETRIES = "max_retries"
|
|||||||
DATA_COORDINATOR = "coordinator"
|
DATA_COORDINATOR = "coordinator"
|
||||||
DATA_POLLING_RUNNING = "polling_running"
|
DATA_POLLING_RUNNING = "polling_running"
|
||||||
|
|
||||||
|
DEVICE_NAME_RE = re.compile(r'^(AC200M|AC300|AC500|AC60|EP500P|EP500|EP600|EP760|EB3A)(\d+)$')
|
||||||
|
|
||||||
CONTROL_FIELDS = [
|
CONTROL_FIELDS = [
|
||||||
"ac_output_on",
|
"ac_output_on",
|
||||||
"dc_output_on",
|
"dc_output_on",
|
||||||
|
|||||||
@@ -21,110 +21,17 @@ from bluetti_mqtt.bluetooth import (
|
|||||||
BadConnectionError,
|
BadConnectionError,
|
||||||
ModbusError,
|
ModbusError,
|
||||||
ParseError,
|
ParseError,
|
||||||
build_device,
|
|
||||||
)
|
)
|
||||||
from bluetti_mqtt.core.devices.bluetti_device import BluettiDevice
|
from bluetti_mqtt.core.devices.bluetti_device import BluettiDevice
|
||||||
from bluetti_mqtt.core.commands import ReadHoldingRegisters
|
from bluetti_mqtt.core.commands import ReadHoldingRegisters
|
||||||
|
|
||||||
|
from . import build_device
|
||||||
from .const import DATA_POLLING_RUNNING, DOMAIN
|
from .const import DATA_POLLING_RUNNING, DOMAIN
|
||||||
from .utils import mac_loggable
|
from .utils import mac_loggable
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DummyDevice(BluettiDevice):
|
|
||||||
"""Dummy device used to add more fields to existing devices.
|
|
||||||
|
|
||||||
Changes made here are only temporary and should also be
|
|
||||||
contributed to https://github.com/warhammerkid/bluetti_mqtt
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, device: BluettiDevice):
|
|
||||||
"""Init dummy device with real device."""
|
|
||||||
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)
|
|
||||||
self.struct.add_uint_field("adl400_ac_input_power_phase3", 1244)
|
|
||||||
self.struct.add_decimal_field("adl400_ac_input_voltage_phase1", 1229, 1)
|
|
||||||
self.struct.add_decimal_field("adl400_ac_input_voltage_phase2", 1237, 1)
|
|
||||||
self.struct.add_decimal_field("adl400_ac_input_voltage_phase3", 1245, 1)
|
|
||||||
# Grid Input
|
|
||||||
self.struct.add_decimal_field("grid_input_frequency", 1300, 1)
|
|
||||||
self.struct.add_uint_field("grid_input_power_phase1", 1313)
|
|
||||||
self.struct.add_uint_field("grid_input_power_phase2", 1319)
|
|
||||||
self.struct.add_uint_field("grid_input_power_phase3", 1325)
|
|
||||||
self.struct.add_decimal_field("grid_input_voltage_phase1", 1314, 1)
|
|
||||||
self.struct.add_decimal_field("grid_input_voltage_phase2", 1320, 1)
|
|
||||||
self.struct.add_decimal_field("grid_input_voltage_phase3", 1326, 1)
|
|
||||||
self.struct.add_decimal_field("grid_input_current_phase1", 1315, 1)
|
|
||||||
self.struct.add_decimal_field("grid_input_current_phase2", 1321, 1)
|
|
||||||
self.struct.add_decimal_field("grid_input_current_phase3", 1327, 1)
|
|
||||||
# EP600 AC Output
|
|
||||||
self.struct.add_decimal_field("ac_output_frequency", 1500, 1)
|
|
||||||
self.struct.add_uint_field("ac_output_power_phase1", 1510)
|
|
||||||
self.struct.add_uint_field("ac_output_power_phase2", 1517)
|
|
||||||
self.struct.add_uint_field("ac_output_power_phase3", 1524)
|
|
||||||
self.struct.add_decimal_field("ac_output_voltage_phase1", 1511, 1)
|
|
||||||
self.struct.add_decimal_field("ac_output_voltage_phase2", 1518, 1)
|
|
||||||
self.struct.add_decimal_field("ac_output_voltage_phase3", 1525, 1)
|
|
||||||
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)
|
|
||||||
|
|
||||||
super().__init__(device.address, device.type, device.sn)
|
|
||||||
self._parent = device
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pack_num_max(self):
|
|
||||||
return self._parent.pack_num_max
|
|
||||||
|
|
||||||
@property
|
|
||||||
def polling_commands(self) -> List[ReadHoldingRegisters]:
|
|
||||||
if self.type == "EP600":
|
|
||||||
return [
|
|
||||||
ReadHoldingRegisters(100, 62),
|
|
||||||
ReadHoldingRegisters(1228, 19),
|
|
||||||
ReadHoldingRegisters(1300, 28),
|
|
||||||
ReadHoldingRegisters(1500, 27),
|
|
||||||
ReadHoldingRegisters(2022, 6),
|
|
||||||
ReadHoldingRegisters(2213, 4),
|
|
||||||
ReadHoldingRegisters(1212, 11),
|
|
||||||
# Battery
|
|
||||||
ReadHoldingRegisters(6101, 7),
|
|
||||||
ReadHoldingRegisters(6175, 11),
|
|
||||||
]
|
|
||||||
|
|
||||||
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
|
|
||||||
def logging_commands(self) -> List[ReadHoldingRegisters]:
|
|
||||||
return self._parent.logging_commands
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pack_logging_commands(self) -> List[ReadHoldingRegisters]:
|
|
||||||
return self._parent.pack_logging_commands
|
|
||||||
|
|
||||||
@property
|
|
||||||
def writable_ranges(self) -> List[range]:
|
|
||||||
return self._parent.writable_ranges
|
|
||||||
|
|
||||||
|
|
||||||
class PollingCoordinator(DataUpdateCoordinator):
|
class PollingCoordinator(DataUpdateCoordinator):
|
||||||
"""Polling coordinator."""
|
"""Polling coordinator."""
|
||||||
|
|
||||||
@@ -150,14 +57,11 @@ class PollingCoordinator(DataUpdateCoordinator):
|
|||||||
self.notify_future = None
|
self.notify_future = None
|
||||||
self.current_command = None
|
self.current_command = None
|
||||||
self.notify_response = bytearray()
|
self.notify_response = bytearray()
|
||||||
bluetti_device = build_device(address, device_name)
|
self.bluetti_device = build_device(address, device_name)
|
||||||
self.persistent_conn = persistent_conn
|
self.persistent_conn = persistent_conn
|
||||||
self.polling_timeout = polling_timeout
|
self.polling_timeout = polling_timeout
|
||||||
self.max_retries = max_retries
|
self.max_retries = max_retries
|
||||||
|
|
||||||
# Add or modify device fields
|
|
||||||
self.bluetti_device = DummyDevice(bluetti_device)
|
|
||||||
|
|
||||||
# Create client
|
# Create client
|
||||||
self.logger.debug("Creating client")
|
self.logger.debug("Creating client")
|
||||||
device = bluetooth.async_ble_device_from_address(hass, address)
|
device = bluetooth.async_ble_device_from_address(hass, address)
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
"""EP600 Field definitions.
|
||||||
|
|
||||||
|
Changes made here are only temporary and should also be
|
||||||
|
contributed to https://github.com/warhammerkid/bluetti_mqtt
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from bluetti_mqtt.core.devices.bluetti_device import BluettiDevice
|
||||||
|
from bluetti_mqtt.core.devices.struct import DeviceStruct
|
||||||
|
from bluetti_mqtt.core.commands import ReadHoldingRegisters
|
||||||
|
|
||||||
|
class EP600(BluettiDevice):
|
||||||
|
def __init__(self, address: str, sn: str):
|
||||||
|
self.struct = DeviceStruct()
|
||||||
|
|
||||||
|
self.struct.add_uint_field('total_battery_percent', 102)
|
||||||
|
self.struct.add_swap_string_field('device_type', 110, 6)
|
||||||
|
self.struct.add_sn_field('serial_number', 116)
|
||||||
|
self.struct.add_decimal_field('power_generation', 154, 1) # Total power generated since last reset (kwh)
|
||||||
|
self.struct.add_swap_string_field('device_type', 1101, 6)
|
||||||
|
self.struct.add_sn_field('serial_number', 1107)
|
||||||
|
self.struct.add_decimal_field('power_generation', 1202, 1) # Total power generated since last reset (kwh)
|
||||||
|
self.struct.add_uint_field('battery_range_start', 2022)
|
||||||
|
self.struct.add_uint_field('battery_range_end', 2023)
|
||||||
|
self.struct.add_uint_field('max_ac_input_power', 2213)
|
||||||
|
self.struct.add_uint_field('max_ac_input_current', 2214)
|
||||||
|
self.struct.add_uint_field('max_ac_output_power', 2215)
|
||||||
|
self.struct.add_uint_field('max_ac_output_current', 2216)
|
||||||
|
self.struct.add_swap_string_field('battery_type', 6101, 6)
|
||||||
|
self.struct.add_sn_field('battery_serial_number', 6107)
|
||||||
|
self.struct.add_version_field('bcu_version', 6175)
|
||||||
|
self.struct.add_version_field('bmu_version', 6178)
|
||||||
|
self.struct.add_version_field('safety_module_version', 6181)
|
||||||
|
self.struct.add_version_field('high_voltage_module_version', 6184)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
self.struct.add_uint_field("adl400_ac_input_power_phase3", 1244)
|
||||||
|
self.struct.add_decimal_field("adl400_ac_input_voltage_phase1", 1229, 1)
|
||||||
|
self.struct.add_decimal_field("adl400_ac_input_voltage_phase2", 1237, 1)
|
||||||
|
self.struct.add_decimal_field("adl400_ac_input_voltage_phase3", 1245, 1)
|
||||||
|
|
||||||
|
# Grid Input
|
||||||
|
self.struct.add_decimal_field("grid_input_frequency", 1300, 1)
|
||||||
|
self.struct.add_uint_field("grid_input_power_phase1", 1313)
|
||||||
|
self.struct.add_uint_field("grid_input_power_phase2", 1319)
|
||||||
|
self.struct.add_uint_field("grid_input_power_phase3", 1325)
|
||||||
|
self.struct.add_decimal_field("grid_input_voltage_phase1", 1314, 1)
|
||||||
|
self.struct.add_decimal_field("grid_input_voltage_phase2", 1320, 1)
|
||||||
|
self.struct.add_decimal_field("grid_input_voltage_phase3", 1326, 1)
|
||||||
|
self.struct.add_decimal_field("grid_input_current_phase1", 1315, 1)
|
||||||
|
self.struct.add_decimal_field("grid_input_current_phase2", 1321, 1)
|
||||||
|
self.struct.add_decimal_field("grid_input_current_phase3", 1327, 1)
|
||||||
|
|
||||||
|
# EP600 AC Output
|
||||||
|
self.struct.add_decimal_field("ac_output_frequency", 1500, 1)
|
||||||
|
self.struct.add_uint_field("ac_output_power_phase1", 1510)
|
||||||
|
self.struct.add_uint_field("ac_output_power_phase2", 1517)
|
||||||
|
self.struct.add_uint_field("ac_output_power_phase3", 1524)
|
||||||
|
self.struct.add_decimal_field("ac_output_voltage_phase1", 1511, 1)
|
||||||
|
self.struct.add_decimal_field("ac_output_voltage_phase2", 1518, 1)
|
||||||
|
self.struct.add_decimal_field("ac_output_voltage_phase3", 1525, 1)
|
||||||
|
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)
|
||||||
|
|
||||||
|
super().__init__(address, 'EP600', sn)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def polling_commands(self) -> List[ReadHoldingRegisters]:
|
||||||
|
return [
|
||||||
|
ReadHoldingRegisters(100, 62),
|
||||||
|
ReadHoldingRegisters(1228, 19),
|
||||||
|
ReadHoldingRegisters(1300, 28),
|
||||||
|
ReadHoldingRegisters(1500, 27),
|
||||||
|
ReadHoldingRegisters(2022, 6),
|
||||||
|
ReadHoldingRegisters(2213, 4),
|
||||||
|
ReadHoldingRegisters(1212, 11),
|
||||||
|
# Battery
|
||||||
|
ReadHoldingRegisters(6101, 7),
|
||||||
|
ReadHoldingRegisters(6175, 11),
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pack_polling_commands(self) -> List[ReadHoldingRegisters]:
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def logging_commands(self) -> List[ReadHoldingRegisters]:
|
||||||
|
return [
|
||||||
|
ReadHoldingRegisters(100, 62),
|
||||||
|
ReadHoldingRegisters(1100, 51),
|
||||||
|
ReadHoldingRegisters(1200, 90),
|
||||||
|
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),
|
||||||
|
]
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
"""EP760 Field definitions.
|
||||||
|
|
||||||
|
Changes made here are only temporary and should also be
|
||||||
|
contributed to https://github.com/warhammerkid/bluetti_mqtt
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from bluetti_mqtt.core.devices.bluetti_device import BluettiDevice
|
||||||
|
from bluetti_mqtt.core.devices.struct import DeviceStruct
|
||||||
|
from bluetti_mqtt.core.commands import ReadHoldingRegisters
|
||||||
|
|
||||||
|
class EP760(BluettiDevice):
|
||||||
|
def __init__(self, address: str, sn: str):
|
||||||
|
self.struct = DeviceStruct()
|
||||||
|
|
||||||
|
# TODO has to be tested
|
||||||
|
|
||||||
|
self.struct.add_uint_field('total_battery_percent', 102)
|
||||||
|
self.struct.add_swap_string_field('device_type', 110, 6)
|
||||||
|
self.struct.add_sn_field('serial_number', 116)
|
||||||
|
self.struct.add_decimal_field('power_generation', 154, 1)
|
||||||
|
self.struct.add_swap_string_field('device_type', 1101, 6)
|
||||||
|
self.struct.add_sn_field('serial_number', 1107)
|
||||||
|
self.struct.add_decimal_field('power_generation', 1202, 1)
|
||||||
|
self.struct.add_uint_field('battery_range_start', 2022)
|
||||||
|
self.struct.add_uint_field('battery_range_end', 2023)
|
||||||
|
self.struct.add_uint_field('max_ac_input_power', 2213)
|
||||||
|
self.struct.add_uint_field('max_ac_input_current', 2214)
|
||||||
|
self.struct.add_uint_field('max_ac_output_power', 2215)
|
||||||
|
self.struct.add_uint_field('max_ac_output_current', 2216)
|
||||||
|
self.struct.add_swap_string_field('battery_type', 6101, 6)
|
||||||
|
self.struct.add_sn_field('battery_serial_number', 6107)
|
||||||
|
self.struct.add_version_field('bcu_version', 6175)
|
||||||
|
self.struct.add_version_field('bmu_version', 6178)
|
||||||
|
self.struct.add_version_field('safety_module_version', 6181)
|
||||||
|
self.struct.add_version_field('high_voltage_module_version', 6184)
|
||||||
|
|
||||||
|
super().__init__(address, 'EP760', sn)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def polling_commands(self) -> List[ReadHoldingRegisters]:
|
||||||
|
return [
|
||||||
|
ReadHoldingRegisters(100, 62),
|
||||||
|
ReadHoldingRegisters(2022, 2),
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pack_polling_commands(self) -> List[ReadHoldingRegisters]:
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def logging_commands(self) -> List[ReadHoldingRegisters]:
|
||||||
|
return [
|
||||||
|
ReadHoldingRegisters(100, 62),
|
||||||
|
ReadHoldingRegisters(1100, 51),
|
||||||
|
ReadHoldingRegisters(1200, 90),
|
||||||
|
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),
|
||||||
|
]
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
{ "local_name": "AC60*" },
|
{ "local_name": "AC60*" },
|
||||||
{ "local_name": "EB3A*" },
|
{ "local_name": "EB3A*" },
|
||||||
{ "local_name": "EP500*" },
|
{ "local_name": "EP500*" },
|
||||||
{ "local_name": "EP600*" }
|
{ "local_name": "EP600*" },
|
||||||
|
{ "local_name": "EP760*" }
|
||||||
],
|
],
|
||||||
"codeowners": ["@Patrick762"],
|
"codeowners": ["@Patrick762"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
@@ -18,5 +19,5 @@
|
|||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"issue_tracker": "https://github.com/Patrick762/hassio-bluetti-bt/issues",
|
"issue_tracker": "https://github.com/Patrick762/hassio-bluetti-bt/issues",
|
||||||
"requirements": ["bluetti_mqtt==0.15.0"],
|
"requirements": ["bluetti_mqtt==0.15.0"],
|
||||||
"version": "0.0.11"
|
"version": "0.0.13"
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,6 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
)
|
)
|
||||||
|
|
||||||
from bluetti_mqtt.bluetooth import build_device
|
|
||||||
from bluetti_mqtt.mqtt_client import (
|
from bluetti_mqtt.mqtt_client import (
|
||||||
NORMAL_DEVICE_FIELDS,
|
NORMAL_DEVICE_FIELDS,
|
||||||
DC_INPUT_FIELDS,
|
DC_INPUT_FIELDS,
|
||||||
@@ -30,9 +29,9 @@ from bluetti_mqtt.mqtt_client import (
|
|||||||
battery_pack_fields,
|
battery_pack_fields,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import device_info as dev_info, get_unique_id
|
from . import device_info as dev_info, get_unique_id, build_device
|
||||||
from .const import DATA_COORDINATOR, DOMAIN, CONF_OPTIONS, DIAGNOSTIC_FIELDS, ADDITIONAL_DEVICE_FIELDS
|
from .const import DATA_COORDINATOR, DOMAIN, CONF_OPTIONS, DIAGNOSTIC_FIELDS, ADDITIONAL_DEVICE_FIELDS
|
||||||
from .coordinator import PollingCoordinator, DummyDevice
|
from .coordinator import PollingCoordinator
|
||||||
from .utils import unique_id_loggable
|
from .utils import unique_id_loggable
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -54,7 +53,6 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
# Add sensors according to device_info
|
# Add sensors according to device_info
|
||||||
bluetti_device = build_device(address, device_name)
|
bluetti_device = build_device(address, device_name)
|
||||||
bluetti_device = DummyDevice(bluetti_device)
|
|
||||||
|
|
||||||
sensors_to_add = []
|
sensors_to_add = []
|
||||||
all_fields = NORMAL_DEVICE_FIELDS
|
all_fields = NORMAL_DEVICE_FIELDS
|
||||||
@@ -122,6 +120,7 @@ class BluettiSensor(CoordinatorEntity, SensorEntity):
|
|||||||
"""Init battery entity."""
|
"""Init battery entity."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
|
|
||||||
|
self._attr_has_entity_name = True
|
||||||
e_name = f"{device_info.get('name')} {name}"
|
e_name = f"{device_info.get('name')} {name}"
|
||||||
self._address = address
|
self._address = address
|
||||||
self._response_key = response_key
|
self._response_key = response_key
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ from homeassistant.helpers.update_coordinator import (
|
|||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
)
|
)
|
||||||
|
|
||||||
from bluetti_mqtt.bluetooth import build_device
|
|
||||||
from bluetti_mqtt.bluetooth.client import BluetoothClient
|
from bluetti_mqtt.bluetooth.client import BluetoothClient
|
||||||
from bluetti_mqtt.core.devices.bluetti_device import BluettiDevice
|
from bluetti_mqtt.core.devices.bluetti_device import BluettiDevice
|
||||||
from bluetti_mqtt.mqtt_client import (
|
from bluetti_mqtt.mqtt_client import (
|
||||||
@@ -32,9 +31,9 @@ from bluetti_mqtt.mqtt_client import (
|
|||||||
MqttFieldType,
|
MqttFieldType,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import device_info as dev_info, get_unique_id
|
from . import device_info as dev_info, get_unique_id, build_device
|
||||||
from .const import CONTROL_FIELDS, DATA_COORDINATOR, DOMAIN, ADDITIONAL_DEVICE_FIELDS
|
from .const import CONTROL_FIELDS, DATA_COORDINATOR, DOMAIN, ADDITIONAL_DEVICE_FIELDS
|
||||||
from .coordinator import PollingCoordinator, DummyDevice
|
from .coordinator import PollingCoordinator
|
||||||
from .utils import mac_loggable, unique_id_loggable
|
from .utils import mac_loggable, unique_id_loggable
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -56,7 +55,6 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
# Add sensors according to device_info
|
# Add sensors according to device_info
|
||||||
bluetti_device = build_device(address, device_name)
|
bluetti_device = build_device(address, device_name)
|
||||||
bluetti_device = DummyDevice(bluetti_device)
|
|
||||||
|
|
||||||
sensors_to_add = []
|
sensors_to_add = []
|
||||||
all_fields = NORMAL_DEVICE_FIELDS
|
all_fields = NORMAL_DEVICE_FIELDS
|
||||||
@@ -108,6 +106,7 @@ class BluettiSwitch(CoordinatorEntity, SwitchEntity):
|
|||||||
self._entry_id = entry_id
|
self._entry_id = entry_id
|
||||||
|
|
||||||
self._attr_device_info = device_info
|
self._attr_device_info = device_info
|
||||||
|
self._attr_has_entity_name = True
|
||||||
self._attr_name = e_name
|
self._attr_name = e_name
|
||||||
self._attr_available = False
|
self._attr_available = False
|
||||||
self._attr_unique_id = get_unique_id(e_name)
|
self._attr_unique_id = get_unique_id(e_name)
|
||||||
|
|||||||
Reference in new issue
Block a user