-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #54 from Patrick762/dev
[WIP] Release
- Loading branch information
Showing
40 changed files
with
2,237 additions
and
922 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .const import * | ||
from .exceptions import * | ||
from .utils.commands import ReadHoldingRegisters |
70 changes: 70 additions & 0 deletions
70
custom_components/bluetti_bt/bluetti_bt_lib/base_devices/BluettiDevice.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
"""Bluetti device.""" | ||
|
||
# Reduced copy of https://github.com/warhammerkid/bluetti_mqtt/blob/main/bluetti_mqtt/core/devices/bluetti_device.py | ||
|
||
from typing import Any, List | ||
|
||
from ..utils.commands import ReadHoldingRegisters, WriteSingleRegister | ||
from ..utils.struct import BoolField, DeviceStruct, EnumField | ||
|
||
|
||
class BluettiDevice: | ||
struct: DeviceStruct | ||
|
||
def __init__(self, address: str, type: str, sn: str): | ||
self.address = address | ||
self.type = type | ||
self.sn = sn | ||
|
||
def parse(self, address: int, data: bytes) -> dict: | ||
return self.struct.parse(address, data) | ||
|
||
@property | ||
def pack_num_max(self): | ||
""" | ||
A given device has a maximum number of battery packs, including the | ||
internal battery if it has one. We can provide this information statically | ||
so it's not necessary to poll the device. | ||
""" | ||
return 1 | ||
|
||
@property | ||
def polling_commands(self) -> List[ReadHoldingRegisters]: | ||
"""A given device has an optimal set of commands for polling""" | ||
raise NotImplementedError | ||
|
||
@property | ||
def pack_polling_commands(self) -> List[ReadHoldingRegisters]: | ||
"""A given device may have a set of commands for polling pack data""" | ||
return [] | ||
|
||
@property | ||
def writable_ranges(self) -> List[range]: | ||
"""The address ranges that are writable""" | ||
return [] | ||
|
||
@property | ||
def pack_num_field(self) -> List[ReadHoldingRegisters]: | ||
"""The address 'range' of the pack num result. Matches pack_num_result""" | ||
return [] | ||
|
||
def has_field(self, field: str): | ||
return any(f.name == field for f in self.struct.fields) | ||
|
||
def has_field_setter(self, field: str): | ||
matches = [f for f in self.struct.fields if f.name == field] | ||
return any(any(f.address in r for r in self.writable_ranges) for f in matches) | ||
|
||
def build_setter_command(self, field: str, value: Any): | ||
matches = [f for f in self.struct.fields if f.name == field] | ||
device_field = next( | ||
f for f in matches if any(f.address in r for r in self.writable_ranges) | ||
) | ||
|
||
# Convert value to an integer | ||
if isinstance(device_field, EnumField): | ||
value = device_field.enum[value].value | ||
elif isinstance(device_field, BoolField): | ||
value = 1 if value else 0 | ||
|
||
return WriteSingleRegister(device_field.address, value) |
64 changes: 64 additions & 0 deletions
64
custom_components/bluetti_bt/bluetti_bt_lib/base_devices/ProtocolV1Device.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
"""Base device definition for V1 Protocol devices.""" | ||
|
||
from typing import List | ||
|
||
from ..utils.commands import ReadHoldingRegisters | ||
from ..utils.struct import DeviceStruct | ||
from .BluettiDevice import BluettiDevice | ||
|
||
|
||
class ProtocolV1Device(BluettiDevice): | ||
def __init__(self, address: str, type: str, sn: str): | ||
self.struct = DeviceStruct() | ||
|
||
# Device info | ||
self.struct.add_string_field("device_type", 10, 6) | ||
self.struct.add_sn_field("serial_number", 17) | ||
|
||
# Power IO | ||
self.struct.add_uint_field("dc_input_power", 36) | ||
self.struct.add_uint_field("ac_input_power", 37) | ||
self.struct.add_uint_field("ac_output_power", 38) | ||
self.struct.add_uint_field("dc_output_power", 39) | ||
|
||
# Power IO statistics | ||
self.struct.add_decimal_field( | ||
"power_generation", 41, 1 | ||
) # Total power generated since last reset (kwh) | ||
|
||
# Battery | ||
self.struct.add_uint_field("total_battery_percent", 43) | ||
|
||
# Output state | ||
self.struct.add_bool_field("ac_output_on", 48) | ||
self.struct.add_bool_field("dc_output_on", 49) | ||
|
||
# Pack selector | ||
self.struct.add_uint_field("pack_num", 3006) # internal | ||
|
||
# Output controls | ||
self.struct.add_bool_field("ac_output_on_switch", 3007) | ||
self.struct.add_bool_field("dc_output_on_switch", 3008) | ||
|
||
super().__init__(address, type, sn) | ||
|
||
@property | ||
def polling_commands(self) -> List[ReadHoldingRegisters]: | ||
return [ | ||
ReadHoldingRegisters(10, 10), | ||
ReadHoldingRegisters(36, 4), | ||
ReadHoldingRegisters(41, 1), | ||
ReadHoldingRegisters(43, 1), | ||
ReadHoldingRegisters(48, 2), | ||
ReadHoldingRegisters(3007, 2), | ||
] | ||
|
||
@property | ||
def writable_ranges(self) -> List[range]: | ||
return [range(3006, 3009)] | ||
|
||
@property | ||
def pack_num_field(self) -> List[ReadHoldingRegisters]: | ||
return [ | ||
ReadHoldingRegisters(96, 1), | ||
] |
Oops, something went wrong.