Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0943ecf187 | ||
|
|
58f2ec50c4 | ||
|
|
ad536235bb | ||
|
|
ba6611b084 | ||
|
|
3e4b8601e8 | ||
|
|
ebbcea3c4c | ||
|
|
9ef9d38a6e |
No files matched your search
@@ -27,7 +27,7 @@ After the installation, you can use this button to install the integration:
|
|||||||
- EP500
|
- EP500
|
||||||
- EP500P
|
- EP500P
|
||||||
- EP600 (tested)
|
- EP600 (tested)
|
||||||
- EP700 (beta, untested)
|
- 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,8 +12,6 @@ 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,
|
||||||
@@ -22,13 +20,10 @@ 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.ep700 import EP700
|
|
||||||
|
|
||||||
PLATFORMS: [Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
PLATFORMS: [Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -107,15 +102,6 @@ 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("EP700"):
|
elif bt_name.startswith("EP760"):
|
||||||
dev_type = "EP700"
|
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] == 'EP700':
|
|
||||||
return EP700(address, match[2])
|
|
||||||
elif match[1] == 'EP600':
|
|
||||||
return EP600(address, match[2])
|
|
||||||
else:
|
|
||||||
return orig_build_device(address, name)
|
|
||||||
@@ -24,10 +24,10 @@ from bluetti_mqtt.mqtt_client import (
|
|||||||
MqttFieldType,
|
MqttFieldType,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import device_info as dev_info, get_unique_id, build_device
|
from . import device_info as dev_info, get_unique_id
|
||||||
from .const import DATA_COORDINATOR, DOMAIN, ADDITIONAL_DEVICE_FIELDS
|
from .const import DATA_COORDINATOR, DOMAIN, ADDITIONAL_DEVICE_FIELDS
|
||||||
from .coordinator import PollingCoordinator
|
from .coordinator import PollingCoordinator
|
||||||
from .utils import unique_id_loggable
|
from .utils import unique_id_loggable, build_device
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ class BluettiBinarySensor(CoordinatorEntity, BinarySensorEntity):
|
|||||||
self._response_key = response_key
|
self._response_key = response_key
|
||||||
|
|
||||||
self._attr_device_info = device_info
|
self._attr_device_info = device_info
|
||||||
self._attr_name = e_name
|
self._attr_name = 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)
|
||||||
self._attr_entity_category = category
|
self._attr_entity_category = category
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from .const import (
|
|||||||
CONF_POLLING_TIMEOUT,
|
CONF_POLLING_TIMEOUT,
|
||||||
CONF_USE_CONTROLS,
|
CONF_USE_CONTROLS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
SUPPORTED_MODELS,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -58,12 +59,18 @@ class BluettiConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
await self.async_set_unique_id(address, raise_on_progress=False)
|
await self.async_set_unique_id(address, raise_on_progress=False)
|
||||||
self._abort_if_unique_id_configured()
|
self._abort_if_unique_id_configured()
|
||||||
dev_type = get_type_by_bt_name(discovery_info.name)
|
dev_type = get_type_by_bt_name(discovery_info.name)
|
||||||
|
name = re.sub("[^A-Z0-9]+", "", discovery_info.name)
|
||||||
|
|
||||||
|
if dev_type == "Unknown":
|
||||||
|
dev_type = user_input[CONF_TYPE]
|
||||||
|
name = name.replace("PBOX", dev_type)
|
||||||
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=discovery_info.name,
|
title=name,
|
||||||
data={
|
data={
|
||||||
CONF_ADDRESS: discovery_info.address,
|
CONF_ADDRESS: discovery_info.address,
|
||||||
CONF_TYPE: dev_type,
|
CONF_TYPE: dev_type,
|
||||||
CONF_NAME: re.sub("[^A-Z0-9]+", "", discovery_info.name),
|
CONF_NAME: name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -88,6 +95,12 @@ class BluettiConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
for service_info in self._discovered_devices.values()
|
for service_info in self._discovered_devices.values()
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
vol.Optional(CONF_TYPE): vol.In(
|
||||||
|
{
|
||||||
|
model: model
|
||||||
|
for model in SUPPORTED_MODELS
|
||||||
|
}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
|
|||||||
@@ -17,7 +17,18 @@ 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|EP700|EB3A)(\d+)$')
|
SUPPORTED_MODELS = [
|
||||||
|
"AC60",
|
||||||
|
"AC200M",
|
||||||
|
"AC300",
|
||||||
|
"AC500",
|
||||||
|
"EB3A",
|
||||||
|
"EP500",
|
||||||
|
"EP500P",
|
||||||
|
"EP600",
|
||||||
|
"EP760",
|
||||||
|
]
|
||||||
|
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",
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ from bluetti_mqtt.bluetooth import (
|
|||||||
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, build_device
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -137,6 +136,9 @@ class PollingCoordinator(DataUpdateCoordinator):
|
|||||||
self.bluetti_device.build_setter_command('pack_num', pack)
|
self.bluetti_device.build_setter_command('pack_num', pack)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# We need to wait after switching packs for the data to be available
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
for command in self.bluetti_device.pack_polling_commands:
|
for command in self.bluetti_device.pack_polling_commands:
|
||||||
# Request & parse result for each pack
|
# Request & parse result for each pack
|
||||||
try:
|
try:
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
"""EP700 Field definitions.
|
"""EP760 Field definitions.
|
||||||
|
|
||||||
Changes made here are only temporary and should also be
|
Changes made here are only temporary and should also be
|
||||||
contributed to https://github.com/warhammerkid/bluetti_mqtt
|
contributed to https://github.com/warhammerkid/bluetti_mqtt
|
||||||
@@ -10,7 +10,7 @@ from bluetti_mqtt.core.devices.bluetti_device import BluettiDevice
|
|||||||
from bluetti_mqtt.core.devices.struct import DeviceStruct
|
from bluetti_mqtt.core.devices.struct import DeviceStruct
|
||||||
from bluetti_mqtt.core.commands import ReadHoldingRegisters
|
from bluetti_mqtt.core.commands import ReadHoldingRegisters
|
||||||
|
|
||||||
class EP700(BluettiDevice):
|
class EP760(BluettiDevice):
|
||||||
def __init__(self, address: str, sn: str):
|
def __init__(self, address: str, sn: str):
|
||||||
self.struct = DeviceStruct()
|
self.struct = DeviceStruct()
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ class EP700(BluettiDevice):
|
|||||||
self.struct.add_version_field('safety_module_version', 6181)
|
self.struct.add_version_field('safety_module_version', 6181)
|
||||||
self.struct.add_version_field('high_voltage_module_version', 6184)
|
self.struct.add_version_field('high_voltage_module_version', 6184)
|
||||||
|
|
||||||
super().__init__(address, 'EP700', sn)
|
super().__init__(address, 'EP760', sn)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def polling_commands(self) -> List[ReadHoldingRegisters]:
|
def polling_commands(self) -> List[ReadHoldingRegisters]:
|
||||||
@@ -9,7 +9,8 @@
|
|||||||
{ "local_name": "EB3A*" },
|
{ "local_name": "EB3A*" },
|
||||||
{ "local_name": "EP500*" },
|
{ "local_name": "EP500*" },
|
||||||
{ "local_name": "EP600*" },
|
{ "local_name": "EP600*" },
|
||||||
{ "local_name": "EP700*" }
|
{ "local_name": "EP760*" },
|
||||||
|
{ "local_name": "PBOX*" }
|
||||||
],
|
],
|
||||||
"codeowners": ["@Patrick762"],
|
"codeowners": ["@Patrick762"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
@@ -19,5 +20,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.12"
|
"version": "0.0.16"
|
||||||
}
|
}
|
||||||
@@ -29,10 +29,10 @@ from bluetti_mqtt.mqtt_client import (
|
|||||||
battery_pack_fields,
|
battery_pack_fields,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import device_info as dev_info, get_unique_id, build_device
|
from . import device_info as dev_info, get_unique_id
|
||||||
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
|
from .coordinator import PollingCoordinator
|
||||||
from .utils import unique_id_loggable
|
from .utils import unique_id_loggable, build_device
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ class BluettiSensor(CoordinatorEntity, SensorEntity):
|
|||||||
self._response_key = response_key
|
self._response_key = response_key
|
||||||
|
|
||||||
self._attr_device_info = device_info
|
self._attr_device_info = device_info
|
||||||
self._attr_name = e_name
|
self._attr_name = 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)
|
||||||
self._attr_native_unit_of_measurement = unit_of_measurement
|
self._attr_native_unit_of_measurement = unit_of_measurement
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ from bluetti_mqtt.mqtt_client import (
|
|||||||
MqttFieldType,
|
MqttFieldType,
|
||||||
)
|
)
|
||||||
|
|
||||||
from . import device_info as dev_info, get_unique_id, build_device
|
from . import device_info as dev_info, get_unique_id
|
||||||
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
|
from .coordinator import PollingCoordinator
|
||||||
from .utils import mac_loggable, unique_id_loggable
|
from .utils import mac_loggable, unique_id_loggable, build_device
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ class BluettiSwitch(CoordinatorEntity, SwitchEntity):
|
|||||||
|
|
||||||
self._attr_device_info = device_info
|
self._attr_device_info = device_info
|
||||||
self._attr_has_entity_name = True
|
self._attr_has_entity_name = True
|
||||||
self._attr_name = e_name
|
self._attr_name = 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)
|
||||||
self._attr_entity_category = category
|
self._attr_entity_category = category
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
{
|
{
|
||||||
|
"config": {
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Gerät",
|
||||||
|
"type": "Modell (erforderlich bei PBOX Geräten)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
{
|
{
|
||||||
|
"config": {
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"address": "Device",
|
||||||
|
"type": "Model (required for PBOX devices)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
"""Tools."""
|
"""Tools."""
|
||||||
|
|
||||||
|
from bluetti_mqtt.bluetooth import build_device as orig_build_device
|
||||||
|
|
||||||
|
from .const import DEVICE_NAME_RE
|
||||||
|
from .devices.ep600 import EP600
|
||||||
|
from .devices.ep760 import EP760
|
||||||
|
|
||||||
def mac_loggable(mac: str) -> str:
|
def mac_loggable(mac: str) -> str:
|
||||||
"""Remove parts of the mac address for logging."""
|
"""Remove parts of the mac address for logging."""
|
||||||
splitted = mac.split(":")
|
splitted = mac.split(":")
|
||||||
@@ -10,3 +16,12 @@ def unique_id_loggable(unique_id: str) -> str:
|
|||||||
splitted = unique_id.split("_", maxsplit=1)
|
splitted = unique_id.split("_", maxsplit=1)
|
||||||
serial = splitted[0][:6]
|
serial = splitted[0][:6]
|
||||||
return serial + "XXXXXXXXXX" + splitted[1]
|
return serial + "XXXXXXXXXX" + splitted[1]
|
||||||
|
|
||||||
|
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)
|
||||||
Reference in new issue
Block a user