Bluetooth integrations (Chandler Water Filter and Homedics Drift)

Yikes, sorry folks! I was moving fast during some development, copying files between my HA core repo and my custom components repo. Looks like I accidentally wiped out the version field in the manifest file.

I have the tab open right now with the instructions on setting up the GitHub action to integrate with HACS—I’ll try to find time to do that this weekend. As well as add some basic README.

But yeah, @elmorehouz — that’s pretty accurate for me. Sounds like James has it on his radar :slight_smile:

re: @n6ham — cloning into the custom_components dir + having a version in the manifest (totally my bad) should be all you need. And as long as your bluetooth adapter can manage active connections (and you don’t have any other BLE relays/proxies that compete with HA’s BLE advertisement prioritization), the device should get auto-discovered and pop-up on the integrations page

1 Like

It worked! Thank you!

1 Like

@toekneestuck my first PR - changed the unit of reserve_capacity from gallons to percents

Btw, my salt readings are “undefined”. Is there a way to log the raw json somehow?
I’ve already enabled debug logging in the component menu and rebooted, but still don’t see anything meanigfull in the system log

Hmm, if you have the log level set to debug, you should be seeing a bunch of stuff being written. Specifically this line will log every decoded JSON payload it receives: hass_chandler_systems/api.py at 392a8418742ae638400a063a3d9027067cd083a6 · toekneestuck/hass_chandler_systems · GitHub

fwiw, the other way I’ve adjusted log level during runtime is go to Settings → Developer Tools → Actions, search for “set level” (and select it), then click the “go to yaml mode” button, input the following, and click ‘perform’:

action: logger.set_level
data:
  custom_components.hass_chandler_systems: debug

Thank you for merging my PR, adding the doc and updating the component - I re-installed it via HACS!

Re logs: there’s a non-zero chance that I’m just looking in the wrong place. I have no experience with HA custom component development, thus - may make trivial mistakes.

I enabled debug logging and expected to see logs in Settings > System > Logs (Home Assistant Core).

Well, as I expected - it was a user error. I didn’t realize that captured debug log will be available for download when debug logging is turned off.

Anyhow, this is the portion of the payload related to the salt brine tank:

'dbtw': 18, 'dbth': 26, 'dbts': 270, 'dbtr': 1800

dbtw - the brine tank width in inches
dbth - the max fill height in inches
dbts - the max capacity calculated based on two parameters above in pounds
dbtr - the brine tank level in pounds x 10

@toekneestuck I wonder if your board is on an older firmware? I got my board from Chandler Systems just last week.

@n6ham I’m running C6.18, but I have a sediment filter, not a water softener, so there’s certainly some tweaking to be done to make sure the integration covers all the different valve/filter cases.

It looks like typos in my const.py file for the brine tank salt — that should be easy enough to fix:

KEY_SALT_TANK_CAPACITY = "dst"  # Pounds, brine tank capacity — W
KEY_SALT_TANK_REMAINING = "dsr"  # Pounds, salt left in tank — RW

Looking through the dashboard API docs though, I don’t see the heigh/width definitions, so they never made it in: Signature-API-Guide/api-dashboard.md at f48408b86005a4df6827973b4931360f77ab84fc · ChandlerSystems/Signature-API-Guide · GitHub

I have a sediment filter, not a water softener, so there’s certainly some tweaking to be done to make sure the integration covers all the different valve/filter cases.

I.e. you’ve never seen the keys below?

KEY_SALT_TANK_CAPACITY = "dst"  # Pounds, brine tank capacity — W
KEY_SALT_TANK_REMAINING = "dsr"  # Pounds, salt left in tank — RW

In such case I can simply replace them.

Looking through the dashboard API docs though, I don’t see the heigh/width definitions

There was a typo in the doc. James confirmed that my key/value pairs are what I think they are in the issue I opened yesterday.

Quote:

#define KEY_DB_BRINE_TANK_WIDTH              "dbtw"
#define KEY_DB_BRINE_TANK_FILL_HEIGHT        "dbth"
#define KEY_DB_BRINE_TANK_REFILL_TIME        "dbrt"  /*! @note Write-Only */
#define KEY_DB_BRINE_TANK_TOTAL_SALT_LBS     "dbts"  /*! @note Write-Only */
#define KEY_DB_BRINE_TANK_REMAINING_SALT_LBS "dbtr

His rationale for not documenting brine tank width and height - they are not that useful in a context of Home Assistant. I just saw those values based on the payload from my device and matched them agains the data in he app.

I’ll send a pr shortly with the update keys

P.S. There must be a way to define sets of the sensors based on the device model. Now we have access to two different devices and can experiment with them

Hi Tony,

Since updating this integration from your first initial commit to the lastest, I’ve found that entities under this device stop updating. I’ve verified that my bluetooth adapter is still functioning, connection to the valve continues to work from the Legacy View app. I’m able to get it to update by disabling and re-enabling the integration.

Debug logs show the following right after the last poll was received.

2026-03-04 14:22:44.378 DEBUG (MainThread) [custom_components.chandler_systems.api] [receive_handler] got MARCO, sending POLO
2026-03-04 14:22:45.603 DEBUG (MainThread) [custom_components.chandler_systems.api] [receive_handler] got MARCO, sending POLO
2026-03-04 14:22:46.832 DEBUG (MainThread) [custom_components.chandler_systems.api] [receive_handler] got MARCO, sending POLO
2026-03-04 14:22:48.046 DEBUG (MainThread) [custom_components.chandler_systems.api] [receive_handler] got MARCO, sending POLO
2026-03-04 14:22:48.271 DEBUG (MainThread) [custom_components.chandler_systems.api] Sending graceful disconnect command to device
2026-03-04 14:22:48.406 INFO (MainThread) [custom_components.chandler_systems.api] Disconnected from Chandler Systems device C5:63:FB:D5:3D:A3
2026-03-04 14:23:57.653 DEBUG (MainThread) [custom_components.chandler_systems.api] Found signature service with read char a725458c-bee2-4d2e-9555-edf5a8082303 and write char a725458c-bee3-4d2e-9555-edf5a8082303
2026-03-04 14:24:17.639 INFO (MainThread) [custom_components.chandler_systems.api] BLE connection to C5:63:FB:D5:3D:A3 dropped
2026-03-04 14:24:17.639 INFO (MainThread) [custom_components.chandler_systems.api] Connected to Chandler Systems device C5:63:FB:D5:3D:A3
2026-03-04 14:24:17.639 DEBUG (MainThread) [custom_components.chandler_systems.api] Sending ID Status Packet (0xEA) for device identification
2026-03-04 14:24:17.639 ERROR (MainThread) [custom_components.chandler_systems] C5:63:FB:D5:3D:A3: Failure while polling
Traceback (most recent call last):
  File "/config/custom_components/chandler_systems/coordinator.py", line 127, in _async_update
    await api.authenticate(self.auth_key)
  File "/config/custom_components/chandler_systems/api.py", line 183, in authenticate
    initial_data = await self.identify(lock=False)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/chandler_systems/api.py", line 160, in identify
    await self._write_gatt(b"\xea", lock=lock)
  File "/config/custom_components/chandler_systems/api.py", line 490, in _write_gatt
    raise ChandlerSystemsConnectionError("Not connected to device")
custom_components.chandler_systems.api.ChandlerSystemsConnectionError: Not connected to device

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/bluetooth/active_update_coordinator.py", line 127, in _async_poll
    self.data = await self._async_poll_data(self._last_service_info)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/bluetooth/active_update_coordinator.py", line 120, in _async_poll_data
    return await self._poll_method(last_service_info)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/chandler_systems/coordinator.py", line 139, in _async_update
    raise UpdateFailed(f"Failed to connect to {self.address}: {err}") from err
homeassistant.helpers.update_coordinator.UpdateFailed: Failed to connect to C5:63:FB:D5:3D:A3: Not connected to device

Any ideas what might be causing this?

Definitely. I started with a somewhat crude approach, by defining exclusivity sets, and then at runtime I exclude the sensors that don’t apply based on the valve type

The timestamps on these logs are interesting. Note that ~20s passes between finding the read/write characteristics and the next log lines that all get written in the same event loop / millisecond.

It looks like something hung during the await self.client.start_notify() call (which subscribes to notifications from the device) and the bluetooth connection was dropped by HA or your bluetooth adapter during that time.

Does this happen consistently for you or randomly? I’m not sure what would cause the hanging, I’m not familiar enough with the guts of the BleakClient, or what bluetooth adapter you’re using.

It happens multiple times each day. Usually doesn’t last more than 2 hours after toggling the the integration before it crashes again.

I’m using a ESP32 has a bluetooth proxy. The other sensors on that ESP32 don’t report any failed pollings during that time so I don’t believe it’s an ESP32 issue. I could purchase a USB bluetooth adapter and pass that through to the HA VM to rule it out though.

Just wanted to check if this was a me issue or others are experiencing it as well.

Ack. I’m also using an esp32 with the esphome bluetooth proxy. Do you have to power cycle the valve to get things working again, or just reloading the integration?

I also experience seemingly random disconnects regularly, however not yet in this exact code path that you documented. Also, my bluetooth disconnects typically lead to the valve becoming unresponsive until I power cycle it. If yours is also doing this, then I assume it’s related to this open issue.