Skip to content

add battery level sensors for yeelink.curtain.ctmt2 - #2854

Open
almirus wants to merge 2 commits into
al-one:masterfrom
almirus:master
Open

add battery level sensors for yeelink.curtain.ctmt2#2854
almirus wants to merge 2 commits into
al-one:masterfrom
almirus:master

Conversation

@almirus

@almirus almirus commented May 30, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for the yeelink.curtain.ctmt2 device, including its battery level specifications, customization configurations, and Jinja templates for parsing its properties. It also enhances the update_miio_props method in device.py to support custom property getters (like get_prop) and template rendering for properties. The review feedback suggests improving the Jinja template logic in templates.py by using props.get_child | int(1) instead of props.get_child | default(1) | int to ensure a robust fallback to 1 when the value is None.

"'coolwind_gear': val[1],"
"'venting_gear': val[2],"
"} }}",
'yeelink_curtain_ctmt2_miio_properties': "{%- set child = props.get_child | default(1) | int %}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using props.get_child | default(1) | int can result in child being evaluated as 0 if props.get_child is None (since the default filter in Jinja only replaces undefined values by default, and None | int defaults to 0). To ensure robust fallback to 1 when the value is None or cannot be parsed, use props.get_child | int(1) instead.

Suggested change
'yeelink_curtain_ctmt2_miio_properties': "{%- set child = props.get_child | default(1) | int %}"
'yeelink_curtain_ctmt2_miio_properties': "{%- set child = props.get_child | int(1) %}"

@al-one

al-one commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Thanks for adding battery support for yeelink.curtain.ctmt2. Looking at this more carefully, I think there are three concrete issues that all point in the same direction: this should be done via miio2miot adaptation, not by extending the generic local miio update path.

1. Should go through MIIO_TO_MIOT_SPECS instead of a local template

The data source here (get_child, battery, battery2 via miio get_prop) is exactly what the existing Miio2MiotHelper flow is designed for. Other devices whose upstream MIOT spec is missing a battery property already use this pattern, e.g.:

  • custom_components/xiaomi_miot/core/miio2miot_specs.py:1146'prop.4.1': {'prop': 'battery'}
  • custom_components/xiaomi_miot/core/miio2miot_specs.py:1276'prop.3.1': {'prop': 'battery'}
  • custom_components/xiaomi_miot/core/miio2miot_specs.py:2664
  • custom_components/xiaomi_miot/core/miio2miot_specs.py:2914

A cleaner approach would be to add a MIIO_TO_MIOT_SPECS entry for yeelink.curtain.ctmt2 that maps get_child, battery, battery2 to the two new MIOT properties. That keeps this device consistent with the rest of the codebase and avoids touching update_miio_props().

2. Reserve iids starting from 100

In custom_components/xiaomi_miot/core/miot_specs_extend.json, the new properties are added with iid:9 and iid:10. The upstream spec for yeelink.curtain.ctmt2 currently has no properties in SIID3 at all, so this is not a hard collision today, but it picks low numbers that the official spec can easily claim later. The existing convention in this file is to start added properties from 100 (see chuangmi.plug.v1 at 101, chuangmi.ihcooker.chefnic at 101, etc.). I’d suggest re-numbering these to 100/101.

3. The local template’s fallback is unsafe for None

In custom_components/xiaomi_miot/core/templates.py:

{%- set child = props.get_child | default(1) | int %}

Jinja’s default(1) only triggers on Undefined. If the device returns get_child = None (which miio numeric properties can do on transient errors), this becomes None | int, which usually evaluates to 0 and changes the meaning of the “single-motor” branch. The cloud template in the same PR already uses the safer pattern props.get('prop.get_child',1) | int(1); the local template should match it, e.g. {%- set child = props.get_child | int(1) %}.

Summary

The battery feature itself looks valid, but I’d prefer this be reworked into a standard miio2miot adaptation (new miio_specs entry, iids 100/101 in miot_specs_extend.json, and dropping the miio_property_getter / miio_properties_template generalisation in update_miio_props). That way the device follows the same pattern as other “upstream-missing-battery” devices and avoids introducing a parallel local-miio templating path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants