Skip to content

Add support for Wearable device status for xiaomi-ble#166322

Closed
lzghzr wants to merge 1 commit into
home-assistant:devfrom
lzghzr:xiaomi_wearable_device
Closed

Add support for Wearable device status for xiaomi-ble#166322
lzghzr wants to merge 1 commit into
home-assistant:devfrom
lzghzr:xiaomi_wearable_device

Conversation

@lzghzr
Copy link
Copy Markdown
Contributor

@lzghzr lzghzr commented Mar 24, 2026

Proposed change

This PR adds three SENSOR_DESCRIPTIONS for Xiaomi wearable devices, which are required for the Xiaomi MiBand 10.

  • CHARGING_STATE - Sensor: Not charging, Charging, Full and Unknown
  • ASLEEP - Binary sensor: On means Asleep, Off means Awake
  • WEARING - Binary sensor: On means Wearing, Off means Not Wearing,

Depedency bump will be done in a separate PR: #167384

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

@lzghzr lzghzr requested review from Ernst79 and Jc2k as code owners March 24, 2026 11:02
Copilot AI review requested due to automatic review settings March 24, 2026 11:02
Copy link
Copy Markdown
Contributor

@home-assistant home-assistant Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lzghzr

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

@home-assistant home-assistant Bot added cla-needed integration: xiaomi_ble new-feature small-pr PRs with less than 30 lines. Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage labels Mar 24, 2026
@home-assistant home-assistant Bot marked this pull request as draft March 24, 2026 11:02
@home-assistant
Copy link
Copy Markdown
Contributor

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@home-assistant
Copy link
Copy Markdown
Contributor

Hey there @Jc2k, @Ernst79, mind taking a look at this pull request as it has been labeled with an integration (xiaomi_ble) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of xiaomi_ble can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign xiaomi_ble Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the Xiaomi BLE integration’s sensor mapping to expose additional wearable-status sensors needed for newer Xiaomi wearables (e.g., MiBand 10).

Changes:

  • Add sensor descriptions for wearable charging state, sleep state, and wearing status.
  • Assign appropriate icons for the new wearable-status sensors.

Comment on lines +217 to +221
# Charging state for Wearable device
(ExtendedSensorDeviceClass.CHARGING_STATE, None): SensorEntityDescription(
key=str(ExtendedSensorDeviceClass.CHARGING_STATE),
icon="mdi:battery-charging",
),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add coverage in tests/components/xiaomi_ble/test_sensor.py to verify the new wearable sensors (charging state, sleep state, device wearing status) are created and expose the expected friendly name/icon and state values from an advertisement payload.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 24, 2026 15:52
@lzghzr lzghzr marked this pull request as ready for review March 24, 2026 15:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +217 to +221
# Charging state for Wearable device
(ExtendedSensorDeviceClass.CHARGING_STATE, None): SensorEntityDescription(
key=str(ExtendedSensorDeviceClass.CHARGING_STATE),
icon="mdi:battery-charging",
),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update these wearable state sensors to be modeled as enum sensors and align the processor typing accordingly. These values are discrete strings (e.g., "Charging"/"Full", "Awake"), but the sensor update pipeline is currently typed/cast as float | None; set device_class=SensorDeviceClass.ENUM with options for the allowed states and update the PassiveBluetoothDataUpdate/XiaomiPassiveBluetoothDataProcessor generics and native_value return type to use StateType (or include str) instead of float so the annotations match actual values.

Copilot uses AI. Check for mistakes.
Comment on lines +217 to +231
# Charging state for Wearable device
(ExtendedSensorDeviceClass.CHARGING_STATE, None): SensorEntityDescription(
key=str(ExtendedSensorDeviceClass.CHARGING_STATE),
icon="mdi:battery-charging",
),
# Sleep state for Wearable device
(ExtendedSensorDeviceClass.SLEEP_STATE, None): SensorEntityDescription(
key=str(ExtendedSensorDeviceClass.SLEEP_STATE),
icon="mdi:sleep",
),
# Device wearing status for Wearable device
(ExtendedSensorDeviceClass.DEVICE_WEARING_STATUS, None): SensorEntityDescription(
key=str(ExtendedSensorDeviceClass.DEVICE_WEARING_STATUS),
icon="mdi:watch",
),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ernst79 Might know more about this, but aren't these all binary sensors as they sounds like on/off values? Is there a way for xiaomi_ble to handle such values?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Charging state can have 3 values.

    if xobj[0] == 0:
        charging_state = "Charging"
    elif xobj[0] == 1:
        charging_state = "Not Charging"
    elif xobj[0] == 2:
        charging_state = "Full"

I think the others also have more than two possible values.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we don't really have a device class for full, but we do have one for charging, and that also is taken into account for example in the UI

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if we want to give users the best experience, I'd say that it should be a binary sensor (maybe 1 for charging not charging and 1 for full), but if that is hard to architect in this integration then this would be fine as well I guess

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as you said, it's difficult to represent three states with a binary sensor.
Sleep status and wearing status might be possible, but that would require adding new states in binary sensor. I don't know if that is easy.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please hold with any changes, as I don't agree with Joost. In my opinion, we should keep it as one sensor. Anyways I have put this PR on the agenda of the next core meeting on Tuesday. Will report back afterwards.

For this reason, I will also draft it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@edenhaus If adding the sleep state to the binary sensor description, it is necessary to consider how to distinguish whether "sleep" refers to the device sleeping or a person sleeping, as this may cause confusion for translators. Since my native language is Chinese, the terms "sleep" and "wake" have already caused me confusion.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, charger state can be a single sensor, but the other 2 sound like binary description.

Could it help if the entity name is "Wearer sleep state"? Or something along those lines to indicate that we're talking about the person wearing the device being asleep as opposed to the device itself?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joostlek I updated the charger state and added options to specify settings. The other two were changed to binary sensors, and the local language range is now limited to the xiaomi_ble to avoid ambiguity.

@lzghzr lzghzr mentioned this pull request Apr 4, 2026
21 tasks
Copilot AI review requested due to automatic review settings April 5, 2026 01:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()

assert entry.data[CONF_SLEEPY_DEVICE] is True
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion is incorrect for the M2456B1 device being tested. The Xiaomi Smart Band 10 (M2456B1) is not a sleepy device, so CONF_SLEEPY_DEVICE should not be set to True. This assertion was likely copied from the previous test_sleepy_device_restore_state test but does not apply here. This test will fail if executed.

Suggested change
assert entry.data[CONF_SLEEPY_DEVICE] is True
assert entry.data.get(CONF_SLEEPY_DEVICE) is not True

Copilot uses AI. Check for mistakes.
assert await hass.config_entries.async_unload(entry.entry_id)
await hass.async_block_till_done()

assert entry.data[CONF_SLEEPY_DEVICE] is True
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion is incorrect for the M2456B1 device being tested. The Xiaomi Smart Band 10 (M2456B1) is not a sleepy device, so CONF_SLEEPY_DEVICE should not be set to True. This assertion was likely copied from the previous test_sleepy_device_restore_state test but does not apply here. This test will fail if executed.

Suggested change
assert entry.data[CONF_SLEEPY_DEVICE] is True
assert entry.data.get(CONF_SLEEPY_DEVICE) is not True

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 5, 2026 10:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment on lines +76 to +116
ExtendedBinarySensorDeviceClass.ASLEEP: BinarySensorEntityDescription(
key=str(ExtendedBinarySensorDeviceClass.ASLEEP),
icon="mdi:sleep",
name="Asleep",
translation_key="asleep",
),
ExtendedBinarySensorDeviceClass.CHILDLOCK: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.CHILDLOCK,
),
ExtendedBinarySensorDeviceClass.DEVICE_FORCIBLY_REMOVED: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.DEVICE_FORCIBLY_REMOVED,
device_class=BinarySensorDeviceClass.PROBLEM,
),
ExtendedBinarySensorDeviceClass.DOOR_LEFT_OPEN: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.DOOR_LEFT_OPEN,
device_class=BinarySensorDeviceClass.PROBLEM,
),
ExtendedBinarySensorDeviceClass.DOOR_STUCK: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.DOOR_STUCK,
device_class=BinarySensorDeviceClass.PROBLEM,
),
ExtendedBinarySensorDeviceClass.FINGERPRINT: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.FINGERPRINT,
icon="mdi:fingerprint",
),
ExtendedBinarySensorDeviceClass.KNOCK_ON_THE_DOOR: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.KNOCK_ON_THE_DOOR,
),
ExtendedBinarySensorDeviceClass.PRY_THE_DOOR: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.PRY_THE_DOOR,
device_class=BinarySensorDeviceClass.TAMPER,
),
ExtendedBinarySensorDeviceClass.TOOTHBRUSH: BinarySensorEntityDescription(
key=ExtendedBinarySensorDeviceClass.TOOTHBRUSH,
),
ExtendedBinarySensorDeviceClass.WEARING: BinarySensorEntityDescription(
key=str(ExtendedBinarySensorDeviceClass.WEARING),
icon="mdi:watch-variant",
name="Wearing",
translation_key="wearing",
),
Copy link

Copilot AI Apr 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with other ExtendedBinarySensorDeviceClass entries in the dictionary (ANTILOCK, ARMED, CHILDLOCK, etc.), the key parameter should use the enum value directly without str() conversion. While both approaches may work, using str() only for these two entries is inconsistent with the established pattern in this file.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 7, 2026 22:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

key=ExtendedBinarySensorDeviceClass.TOOTHBRUSH,
),
ExtendedBinarySensorDeviceClass.WEARING: BinarySensorEntityDescription(
key=str(ExtendedBinarySensorDeviceClass.WEARING),
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix inconsistency: remove str() conversion to match the pattern used by ASLEEP and other ExtendedBinarySensorDeviceClass entries.

Suggested change
key=str(ExtendedBinarySensorDeviceClass.WEARING),
key=ExtendedBinarySensorDeviceClass.WEARING,

Copilot uses AI. Check for mistakes.
@lzghzr lzghzr force-pushed the xiaomi_wearable_device branch from ad4aa1b to 0afede5 Compare April 8, 2026 11:35
@lzghzr lzghzr marked this pull request as ready for review April 8, 2026 11:40
Copilot AI review requested due to automatic review settings April 8, 2026 11:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

key=str(ExtendedSensorDeviceClass.CHARGING_STATE),
device_class=SensorDeviceClass.ENUM,
icon="mdi:battery-charging",
options=["Charging", "Not Charging", "Full", "Unknown"],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Are we able to make these snake_case?
  2. Can we map unknown to None? (Otherwise the automation editor shows Unknown twice

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.To maintain consistency with other sensors in xiaomi_ble, snake_case was not used. I will try using snake_case, and if I encounter unsolvable issues, I will remove the options attribute.
2. I will change "Unknown" to "Other" to distinguish it from "None".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. When you use snake case, you can use the translations to translate it
  2. I would argue that Unknown means the same as unknown, so no need to map it to Other IMO

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joostlek Sorry, I encountered some unsolvable issues, so I abandoned this pull request.

key=str(ExtendedSensorDeviceClass.CHARGING_STATE),
device_class=SensorDeviceClass.ENUM,
icon="mdi:battery-charging",
options=["Charging", "Not Charging", "Full", "Unknown"],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. When you use snake case, you can use the translations to translate it
  2. I would argue that Unknown means the same as unknown, so no need to map it to Other IMO

@home-assistant home-assistant Bot marked this pull request as draft April 10, 2026 17:57
@lzghzr lzghzr closed this Apr 12, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 13, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla-signed integration: xiaomi_ble new-feature Quality Scale: No score small-pr PRs with less than 30 lines. Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants