Compare commits

...
7 Commits
Author SHA1 Message Date
Patrick762 6478825503 Merge pull request #107 from Patrick762/next
Fixed values and improved unavailable handling
2024-06-02 14:06:20 +02:00
Patrick762 3169ee182e increase version number 2024-06-02 14:03:02 +02:00
Patrick762 ece1fc4129 only set unavailable after 5 retries 2024-06-02 13:58:21 +02:00
Patrick762 4d54e048c5 ignore packs not connected 2024-06-02 13:49:18 +02:00
Patrick762 09a9112279 check pack_num after setting it 2024-06-02 13:48:45 +02:00
Patrick762 b37276ec52 updated ac200l sensors based on feedback 2024-06-02 13:12:43 +02:00
Patrick762 4f88792371 Update bug_report.yaml 2024-05-31 17:16:26 +02:00
6 changed files with 76 additions and 37 deletions

No files matched your search

+2 -13
View File
@@ -14,21 +14,10 @@ body:
value: "An exception appeared" value: "An exception appeared"
validations: validations:
required: true required: true
- type: dropdown - type: textarea
id: version id: version
attributes: attributes:
label: Version label: What version of our software are you running?
description: What version of our software are you running?
options:
- 0.0.17
- 0.0.16
- 0.0.15
- 0.0.14
- 0.0.13
- 0.0.11
- 0.0.10
- 0.0.9
default: 0
validations: validations:
required: true required: true
- type: textarea - type: textarea
+32 -7
View File
@@ -96,6 +96,27 @@ class BluettiBinarySensor(CoordinatorEntity, BinarySensorEntity):
def available(self) -> bool: def available(self) -> bool:
"""Return if entity is available.""" """Return if entity is available."""
return self._attr_available return self._attr_available
def _set_available(self):
"""Set sensor as available."""
self._attr_available = True
self._unavailable_counter = 0
self._attr_extra_state_attributes = {}
self.async_write_ha_state()
def _set_unavailable(self, cause: str = "Unknown"):
"""Set sensor as unavailable."""
self._unavailable_counter += 1
self._attr_extra_state_attributes = {
"unavailable_counter": self._unavailable_counter,
"unavailable_cause": cause,
}
if self._unavailable_counter >= 5:
self._attr_available = False
self.async_write_ha_state()
@callback @callback
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None:
@@ -103,20 +124,25 @@ class BluettiBinarySensor(CoordinatorEntity, BinarySensorEntity):
if self.coordinator.reader.persistent_conn and not self.coordinator.reader.client.is_connected: if self.coordinator.reader.persistent_conn and not self.coordinator.reader.client.is_connected:
return return
if self.coordinator.data is None:
_LOGGER.debug(
"Data from coordinator is None",
)
self._set_unavailable("Data is None")
return
_LOGGER.debug("Updating state of %s", unique_id_loggable(self._attr_unique_id)) _LOGGER.debug("Updating state of %s", unique_id_loggable(self._attr_unique_id))
if not isinstance(self.coordinator.data, dict): if not isinstance(self.coordinator.data, dict):
_LOGGER.debug( _LOGGER.debug(
"Invalid data from coordinator (binary_sensor.%s)", unique_id_loggable(self._attr_unique_id) "Invalid data from coordinator (binary_sensor.%s)", unique_id_loggable(self._attr_unique_id)
) )
self._attr_available = False self._set_unavailable("Invalid data")
self.async_write_ha_state()
return return
response_data = self.coordinator.data.get(self._response_key) response_data = self.coordinator.data.get(self._response_key)
if response_data is None: if response_data is None:
self._attr_available = False self._set_unavailable("No data")
self.async_write_ha_state()
return return
if not isinstance(response_data, bool): if not isinstance(response_data, bool):
@@ -125,10 +151,9 @@ class BluettiBinarySensor(CoordinatorEntity, BinarySensorEntity):
unique_id_loggable(self._attr_unique_id), unique_id_loggable(self._attr_unique_id),
response_data, response_data,
) )
self._attr_available = False self._set_unavailable("Invalid data type")
self.async_write_ha_state()
return return
self._attr_available = True self._set_available()
self._attr_is_on = self.coordinator.data[self._response_key] is True self._attr_is_on = self.coordinator.data[self._response_key] is True
self.async_write_ha_state() self.async_write_ha_state()
@@ -110,7 +110,12 @@ class DeviceReader:
await self._async_send_command(command) await self._async_send_command(command)
) )
_LOGGER.debug("Raw data set: %s", body) _LOGGER.debug("Raw data set: %s", body)
# b'\x00\x02' b'\x00\x03' here (seems like result)
# Check set pack_num
set_pack = int.from_bytes(body, byteorder='big')
if set_pack is not pack:
_LOGGER.warning("Pack polling failed (pack_num %i doesn't match expected %i)", set_pack, pack)
continue
for command in pack_commands: for command in pack_commands:
# Request & parse result for each pack # Request & parse result for each pack
@@ -124,7 +129,9 @@ class DeviceReader:
_LOGGER.debug("Parsed data: %s", parsed) _LOGGER.debug("Parsed data: %s", parsed)
for key, value in parsed.items(): for key, value in parsed.items():
parsed_data.update({key + str(pack): value}) # Ignore likely unavailable pack data
if value != 0:
parsed_data.update({key + str(pack): value})
except ParseError: except ParseError:
_LOGGER.warning("Got a parse exception...") _LOGGER.warning("Got a parse exception...")
@@ -13,17 +13,17 @@ class AC200L(ProtocolV1Device):
# Details # Details
self.struct.add_enum_field("ac_output_mode", 70, OutputMode) self.struct.add_enum_field("ac_output_mode", 70, OutputMode)
self.struct.add_decimal_field("internal_ac_voltage", 71, 1) self.struct.add_decimal_field("internal_ac_voltage", 71, 1, multiplier=10)
self.struct.add_decimal_field("internal_current_one", 72, 1) self.struct.add_decimal_field("internal_current_one", 72, 1)
self.struct.add_uint_field("internal_power_one", 73) self.struct.add_uint_field("internal_power_one", 73)
self.struct.add_decimal_field("internal_ac_frequency", 74, 2) self.struct.add_decimal_field("internal_ac_frequency", 74, 2, multiplier=10)
self.struct.add_uint_field("internal_dc_input_voltage", 86) self.struct.add_uint_field("internal_dc_input_voltage", 86, multiplier=.1)
self.struct.add_decimal_field("internal_dc_input_power", 87, 1) self.struct.add_decimal_field("internal_dc_input_power", 87, 1, multiplier=10)
self.struct.add_decimal_field("internal_dc_input_current", 88, 2) self.struct.add_decimal_field("internal_dc_input_current", 88, 2)
# Battery packs # Battery packs
self.struct.add_uint_field("pack_num_max", 91) # internal self.struct.add_uint_field("pack_num_max", 91) # internal
self.struct.add_decimal_field("total_battery_voltage", 92, 1) self.struct.add_decimal_field("total_battery_voltage", 92, 1, multiplier=.1)
self.struct.add_uint_field("pack_num_result", 96) # internal self.struct.add_uint_field("pack_num_result", 96) # internal
self.struct.add_decimal_field("pack_voltage", 98, 2) # Full pack voltage self.struct.add_decimal_field("pack_voltage", 98, 2) # Full pack voltage
self.struct.add_uint_field("pack_battery_percent", 99) self.struct.add_uint_field("pack_battery_percent", 99)
+1 -1
View File
@@ -23,5 +23,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": [], "requirements": [],
"version": "0.1.0" "version": "0.1.1"
} }
+27 -9
View File
@@ -114,6 +114,7 @@ class BluettiSensor(CoordinatorEntity, SensorEntity):
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
self._unavailable_counter = 0
self._attr_device_info = device_info self._attr_device_info = device_info
self._attr_name = name self._attr_name = name
@@ -130,6 +131,27 @@ class BluettiSensor(CoordinatorEntity, SensorEntity):
"""Return if entity is available.""" """Return if entity is available."""
return self._attr_available return self._attr_available
def _set_available(self):
"""Set sensor as available."""
self._attr_available = True
self._unavailable_counter = 0
self._attr_extra_state_attributes = {}
self.async_write_ha_state()
def _set_unavailable(self, cause: str = "Unknown"):
"""Set sensor as unavailable."""
self._unavailable_counter += 1
self._attr_extra_state_attributes = {
"unavailable_counter": self._unavailable_counter,
"unavailable_cause": cause,
}
if self._unavailable_counter >= 5:
self._attr_available = False
self.async_write_ha_state()
@callback @callback
def _handle_coordinator_update(self) -> None: def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator.""" """Handle updated data from the coordinator."""
@@ -141,8 +163,7 @@ class BluettiSensor(CoordinatorEntity, SensorEntity):
_LOGGER.debug( _LOGGER.debug(
"Data from coordinator is None", "Data from coordinator is None",
) )
self._attr_available = False self._set_unavailable("Data is None")
self.async_write_ha_state()
return return
_LOGGER.debug("Updating state of %s", unique_id_loggable(self._attr_unique_id)) _LOGGER.debug("Updating state of %s", unique_id_loggable(self._attr_unique_id))
@@ -150,15 +171,13 @@ class BluettiSensor(CoordinatorEntity, SensorEntity):
_LOGGER.warning( _LOGGER.warning(
"Invalid data from coordinator (sensor.%s)", unique_id_loggable(self._attr_unique_id) "Invalid data from coordinator (sensor.%s)", unique_id_loggable(self._attr_unique_id)
) )
self._attr_available = False self._set_unavailable("Invalid data")
self.async_write_ha_state()
return return
response_data = self.coordinator.data.get(self._response_key) response_data = self.coordinator.data.get(self._response_key)
if response_data is None: 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 self._set_unavailable("No data")
self.async_write_ha_state()
return return
if ( if (
@@ -174,11 +193,10 @@ class BluettiSensor(CoordinatorEntity, SensorEntity):
response_data, response_data,
type(response_data), type(response_data),
) )
self._attr_available = False self._set_unavailable("Invalid data type")
self.async_write_ha_state()
return return
self._attr_available = True self._set_available()
# Different for enum and numeric # Different for enum and numeric
if ( if (