Skip to content

Commit

Permalink
Merge pull request #69 from warhammerkid/dc-input-current-range-limit
Browse files Browse the repository at this point in the history
Add range limits to DC input current to filter out bad values
  • Loading branch information
warhammerkid authored Mar 20, 2023
2 parents d205f87 + 557d9f3 commit fed0c7f
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## FUTURE

* Add a bluetti-discovery command that can collect information from unsupported Bluetti devices
* Out-of-range DC input current values are no longer reported

## 0.11.1

Expand Down
2 changes: 1 addition & 1 deletion bluetti_mqtt/core/devices/ac300.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def __init__(self, address: str, sn: str):
self.struct.add_decimal_field('ac_input_frequency', 0x00, 0x50, 2)
self.struct.add_decimal_field('internal_dc_input_voltage', 0x00, 0x56, 1)
self.struct.add_uint_field('internal_dc_input_power', 0x00, 0x57)
self.struct.add_decimal_field('internal_dc_input_current', 0x00, 0x58, 1)
self.struct.add_decimal_field('internal_dc_input_current', 0x00, 0x58, 1, (0, 15))

# Page 0x00 - Battery Data
self.struct.add_uint_field('pack_num_max', 0x00, 0x5B)
Expand Down
2 changes: 1 addition & 1 deletion bluetti_mqtt/core/devices/ep500.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def __init__(self, address: str, sn: str):
self.struct.add_decimal_field('ac_input_frequency', 0x00, 0x50, 2)
self.struct.add_decimal_field('internal_dc_input_voltage', 0x00, 0x56, 1)
self.struct.add_uint_field('internal_dc_input_power', 0x00, 0x57)
self.struct.add_decimal_field('internal_dc_input_current', 0x00, 0x58, 1)
self.struct.add_decimal_field('internal_dc_input_current', 0x00, 0x58, 1, (0, 15))

# Page 0x00 - Battery Data
self.struct.add_uint_field('pack_num_max', 0x00, 0x5B)
Expand Down
2 changes: 1 addition & 1 deletion bluetti_mqtt/core/devices/ep500p.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def __init__(self, address: str, sn: str):
self.struct.add_decimal_field('ac_input_frequency', 0x00, 0x50, 2)
self.struct.add_decimal_field('internal_dc_input_voltage', 0x00, 0x56, 1)
self.struct.add_uint_field('internal_dc_input_power', 0x00, 0x57)
self.struct.add_decimal_field('internal_dc_input_current', 0x00, 0x58, 1)
self.struct.add_decimal_field('internal_dc_input_current', 0x00, 0x58, 1, (0, 15))

# Page 0x00 - Battery Data
self.struct.add_uint_field('pack_num_max', 0x00, 0x5B)
Expand Down
40 changes: 32 additions & 8 deletions bluetti_mqtt/core/devices/struct.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from decimal import Decimal
from enum import Enum
import struct
from typing import Any, List, Type
from typing import Any, List, Optional, Tuple, Type


class DeviceField:
Expand All @@ -14,14 +14,24 @@ def __init__(self, name: str, page: int, offset: int, size: int):
def parse(self, data: bytes) -> Any:
raise NotImplementedError

def in_range(self, val: Any) -> bool:
return True


class UintField(DeviceField):
def __init__(self, name: str, page: int, offset: int):
def __init__(self, name: str, page: int, offset: int, range: Optional[Tuple[int, int]]):
self.range = range
super().__init__(name, page, offset, 1)

def parse(self, data: bytes) -> int:
return struct.unpack('!H', data)[0]

def in_range(self, val: int) -> bool:
if self.range is None:
return True
else:
return val >= self.range[0] and val <= self.range[1]


class BoolField(DeviceField):
def __init__(self, name: str, page: int, offset: int):
Expand All @@ -42,14 +52,21 @@ def parse(self, data: bytes) -> Any:


class DecimalField(DeviceField):
def __init__(self, name: str, page: int, offset: int, scale: int):
def __init__(self, name: str, page: int, offset: int, scale: int, range: Optional[Tuple[int, int]]):
self.scale = scale
self.range = range
super().__init__(name, page, offset, 1)

def parse(self, data: bytes) -> Decimal:
val = Decimal(struct.unpack('!H', data)[0])
return val / 10 ** self.scale

def in_range(self, val: Decimal) -> bool:
if self.range is None:
return True
else:
return val >= self.range[0] and val <= self.range[1]


class DecimalArrayField(DeviceField):
def __init__(self, name: str, page: int, offset: int, size: int, scale: int):
Expand Down Expand Up @@ -91,17 +108,17 @@ class DeviceStruct:
def __init__(self):
self.fields = []

def add_uint_field(self, name: str, page: int, offset: int):
self.fields.append(UintField(name, page, offset))
def add_uint_field(self, name: str, page: int, offset: int, range: Tuple[int, int] = None):
self.fields.append(UintField(name, page, offset, range))

def add_bool_field(self, name: str, page: int, offset: int):
self.fields.append(BoolField(name, page, offset))

def add_enum_field(self, name: str, page: int, offset: int, enum: Type[Enum]):
self.fields.append(EnumField(name, page, offset, enum))

def add_decimal_field(self, name: str, page: int, offset: int, scale: int):
self.fields.append(DecimalField(name, page, offset, scale))
def add_decimal_field(self, name: str, page: int, offset: int, scale: int, range: Tuple[int, int] = None):
self.fields.append(DecimalField(name, page, offset, scale, range))

def add_decimal_array_field(self, name: str, page: int, offset: int, size: int, scale: int):
self.fields.append(DecimalArrayField(name, page, offset, size, scale))
Expand Down Expand Up @@ -130,6 +147,13 @@ def parse(self, page: int, offset: int, data: bytes) -> dict:
for f in fields:
data_start = 2 * (f.offset - offset)
field_data = data[data_start:data_start + 2 * f.size]
parsed[f.name] = f.parse(field_data)
val = f.parse(field_data)

# Skip if the value is "out-of-range" - sometimes the sensors
# report weird values
if not f.in_range(val):
continue

parsed[f.name] = val

return parsed

0 comments on commit fed0c7f

Please sign in to comment.