Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the same battery calculation as ZHA in Tuya TS0203 door sensors #7681

Merged
merged 6 commits into from
Jul 7, 2024

Conversation

deviantintegral
Copy link
Contributor

This PR improves battery readings for TS0203 sensors, or at least matches ZHA which will allow for greater collaboration and hopefully fewer support threads.

I recently purchased a load tester for batteries, and have been using that to check devices which seemed to have unreliable battery reporting.

TS0203 door sensors:

  • Show the battery voltage at 2.5V for months or years at a time. Yet, those same batteries will show up at 80% on my MBT-1 battery tester.
  • Show up in z2m at 1%.
  • Also report battery percentage as 1%.... for months on end, separate from our own calculations.

I haven't truly run one of these batteries out yet though, so I don't know for sure what the lower voltage end is.

ZigBee Cluster Library Frame, Command: Report Attributes, Seq: 215
    Frame Control Field: Profile-wide (0x18)
    Sequence Number: 215
    Command: Report Attributes (0x0a)
    Attribute Field
        Attribute: Battery Voltage (0x0020)
        Data Type: 8-Bit Unsigned Integer (0x20)
        Measured Battery Voltage: 2.5 [V]

ZigBee Cluster Library Frame, Command: Report Attributes, Seq: 219
    Frame Control Field: Profile-wide (0x18)
    Sequence Number: 219
    Command: Report Attributes (0x0a)
    Attribute Field
        Attribute: Battery Percentage Remaining (0x0021)
        Data Type: 8-Bit Unsigned Integer (0x20)
        Remaining Battery Percentage: 1.0 [%]

This has previously been reported at Koenkk/zigbee2mqtt#17337.

Here's the corresponding code in ZHA, which doesn't have any device specific overrides so applies to these sensors:

https://github.com/zigpy/zha-device-handlers/blob/c6ed94a52a469e72b32ece2a92d528060c7fd034/zhaquirks/__init__.py#L195-L228

I traced the voltage numbers to the PR, which doesn't describe why they were changed:

zigpy/zha-device-handlers#208

Likewise, the issue and commits in zigbee2mqtt don't describe how it's voltage readings were found:

Koenkk/zigbee2mqtt#4466

There's also this discussion with no resolution: Koenkk/zigbee2mqtt#17337

With all this in mind, I think:

  1. The current battery reporting is unreliable at best. I don't think it's providing helpful information to end users.
  2. The door sensors themselves certainly have broken percentage reporting. I think they may also have incorrect voltage reporting and are under-reporting voltage.
  3. Given the challenges in the space, it makes more sense for us to match what ZHA does so users aren't surprised with vastly different values when switching.

So, here's a PR that does that!

There is a greater risk of devices going from 2500 mV to zero with no warning. Today, the issue is that users may replace perfectly fine batteries prematurely. I'm hoping to track this myself and see if there's a voltage drop I can rely on to tweak this in the future, but that may take many months or even years!

@deviantintegral
Copy link
Contributor Author

deviantintegral commented Jun 23, 2024

It looks like this change causes some bounciness in battery readings. I'm not sure why, but one of my sensors (_TZ3000_oxslv1c9) just reported with only the battery percentage and not the battery voltage. That caused the percent to go back to 1%, ignoring our own calculations:

ZigBee Cluster Library Frame, Command: Report Attributes, Seq: 226
    Frame Control Field: Profile-wide (0x18)
    Sequence Number: 226
    Command: Report Attributes (0x0a)
    Attribute Field
        Attribute: Battery Percentage Remaining (0x0021)
        Data Type: 8-Bit Unsigned Integer (0x20)
        Remaining Battery Percentage: 1.0 [%]

Other sensors seem to report them at the same time.

Should we remove the battery percent reporting from these devices in the configure function? Or, simply say "this device reports inaccurate battery info, it's not our problem" in the docs? I suppose we could start with just ignoring the models that I have on hand similar to the exposes function.

@Koenkk
Copy link
Owner

Koenkk commented Jun 24, 2024

I propose to ignore the battery % by adding a fromZigbee converter which only processes the voltage.

@deviantintegral
Copy link
Contributor Author

I started down the path of adding a new converter, but I don't think it makes for a clear design.

The problem is that we still need a way to define what battery curve to use - and there's no way to easily pass additional parameters into the converter - except for meta, which we already have:

    batteryUsingOnlyVoltage: {
        cluster: 'genPowerCfg',
        type: ['attributeReport', 'readResponse'],
        convert: (model, msg, publish, options, meta) => {
            const payload: KeyValueAny = {};
            if (msg.data.hasOwnProperty('batteryVoltage') && (msg.data['batteryVoltage'] < 255)) {
                // Deprecated: voltage is = mV now but should be V
                payload.voltage = msg.data['batteryVoltage'] * 100;

                if (model.meta && model.meta.battery && model.meta.battery.voltageToPercentage) {
                    payload.battery = batteryVoltageToPercentage(payload.voltage, model.meta.battery.voltageToPercentage);
                }
            }

            return payload;
        },
    } satisfies Fz.Converter,

I think adding a model.meta.battery.useVoltageOnly property is clearer to those adding devices and be simpler in the converter.

@deviantintegral
Copy link
Contributor Author

I ended up doing the converter method, because batteryVoltageToPercentage() will error if the battery voltage curve isn't set.

@@ -816,7 +816,7 @@ const definitions: Definition[] = [
model: 'TS0203',
vendor: 'Tuya',
description: 'Door sensor',
fromZigbee: [fz.ias_contact_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_contact_alarm_1_report],
fromZigbee: [fz.ias_contact_alarm_1, fz.batteryIgnoringPercentage, fz.ignore_basic_report, fz.ias_contact_alarm_1_report],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This ends up doing this for all models, not just the ones I've tested myself. Is that OK?

@@ -352,6 +396,7 @@ const converters1 = {
convert: (model, msg, publish, options, meta) => {
const payload: KeyValueAny = {};
if (msg.data.hasOwnProperty('batteryPercentageRemaining') && (msg.data['batteryPercentageRemaining'] < 255)) {
Copy link
Owner

Choose a reason for hiding this comment

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

I'm thinking now, maybe we should always ignore the battery % reporting when voltageToPercentage is set since those will always conflict with each other.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That vastly simplifies this PR, and avoids the need to have a new converter. I've force-pushed here as resolving merge conflicts wasn't worth the effort.

src/converters/fromZigbee.ts Outdated Show resolved Hide resolved
model.meta?.battery?.voltageToPercentage != null &&
model.meta?.battery?.voltageToPercentage == null &&
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I always enjoy when writing a test uncovers a bug :D.

Copy link
Owner

Choose a reason for hiding this comment

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

Nice 😄

@Koenkk Koenkk merged commit 3ffbe2f into Koenkk:master Jul 7, 2024
2 checks passed
@Koenkk
Copy link
Owner

Koenkk commented Jul 7, 2024

Thanks!

lgraf pushed a commit to lgraf/zigbee-herdsman-converters that referenced this pull request Jul 7, 2024
…oenkk#7681)

* (fix) Ignore reported percentage when using voltage to calculate

* fix style

* Use optional chaining for optional properties

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>

* Add tests for battery percentage conversion

* Fix inverted null check

---------

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
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