Koenkk / zigbee2mqtt

Zigbee 🐝 to MQTT bridge 🌉, get rid of your proprietary Zigbee bridges 🔨
https://www.zigbee2mqtt.io
GNU General Public License v3.0
12.11k stars 1.68k forks source link

TuYa_cover_control: Unhandled DP #101 for _TZE200_zah67ekd #17363

Closed pawelsky closed 1 year ago

pawelsky commented 1 year ago

What happened?

When switching the Moes AM43-0.45/40-ES-EZ(TY) cover motor between the tilt and lift mode (by pressing the SET button 5 times) I'm getting the "Unhandled DP #101" errors as on screenshots below:

Any chance to add support for this DP?

What did you expect to happen?

I'd expect the DP #101 to be handled

How to reproduce it (minimal and precise)

Power on and bind the motor. Press the set button 5 times, observe the logs/errors

Zigbee2MQTT version

1.30.3-1

Adapter firmware version

20210708

Adapter

Itead_Sonoff_Zigbee_3.0_USB_Dongle_Plus

Debug log

No response

Koenkk commented 1 year ago

To figure out what these dp means, please follow https://www.zigbee2mqtt.io/advanced/support-new-devices/03_find_tuya_data_points.html

pawelsky commented 1 year ago

Unfortunately I do not have Tuya Zigbee Gateway, but I'd assume that value of 0 for DP 101 means the device switched to tilt mode and value of 1 means the device switched to lift mode.

I may order the gateway at some point as I'd also like to figure out the battery level and light sensor (from the solar panel) reporting for this motor. Any recommendation which one to buy (and nod spend fortune on it)? Preferably a wired one.

pawelsky commented 1 year ago

OK, so I was able to order a cheap, used Gateway from Moes (to match the Moes branded motor I have, just in case there are any differences to regular Tuya one).

I was able to confirm that DP 101 is indeed for switching between tilt and lift mode. It is called jolcon, where jol is representing the tilt mode and con the lift mode: Here is a screenshot from Tuya IoT Platform jolcon

I've also detected 3 more useful DPs:

Please let me know if any additional information is needed

Koenkk commented 1 year ago

Can you check with the following external converter: https://gist.github.com/Koenkk/12256a02e6f582e4e369014d2ff1d03b

pawelsky commented 1 year ago

After adding the converter and playing a bit with the motor, yes, all four DPs are visible in the State tab

state

However with the new converter it is no longer possible to change the position, reverse_direction and and motor_speed in the Exposes tab

exposes

Also the invert_cover option is now gone from the Settings (specific) tab. This is how it looed like before, without the new converter.

image

Oh, and it would be great if the 4 new DPs were modifiable from the Z2M UI.

Koenkk commented 1 year ago

We will add this back later, this is just for testing the converter. I'm a bit confused the upper/lower limit is a boolean, this doesn't make sense right? (should be a numerical value?)

pawelsky commented 1 year ago

No, it does not return any numerical value, the boolean value just informs you whether the limit has been set or not. Before the limits are set the position DP is not even returned (as the motor does not know which position of your blind to interpret as 0% and which as 100%).

The way it works in the app is that you move the blind to the end position and set the corresponding limit to true. Once you've set both of them the motor now knows where the 0% and 100% is and starts returning the position DP accordingly.

Once set it is not possible to change the limits in the app. The only way to do that is to do the factory_reset, and set everything back again. From the motor itself however you can change a single limit with a button combination so I'm guessing it should be in general possible to set single limit back to false, move to a desired position and set it back to true, but I would need to experiment with that a little once setting of these values is implemented.

BTW there are two more DPs:

I've added them to the converter file you provided and they are nicely updated on the Exposes tab

const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const extend = require('zigbee-herdsman-converters/lib/extend');
const ota = require('zigbee-herdsman-converters/lib/ota');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const utils = require('zigbee-herdsman-converters/lib/utils');
const globalStore = require('zigbee-herdsman-converters/lib/store');
const e = exposes.presets;
const ea = exposes.access;

const definition  = {
    fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_zah67ekd'}],
    model: 'TS0601_cover_custom',
    vendor: 'TuYa',
    description: 'Curtain motor/roller blind motor/window pusher/tubular motor',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    exposes: [
        e.cover_position().setAccess('position', ea.STATE_SET),
        exposes.enum('work_state', ea.STATE_SET, ['opening', 'closing').withDescription('Last working state'),
        exposes.enum('reverse_direction', ea.STATE_SET, ['forward', 'back']).withDescription('Reverse the motor direction'),
        exposes.numeric('motor_speed', ea.STATE_SET).withValueMin(0).withValueMax(255).withDescription('Motor speed'),
        exposes.enum('mode', ea.STATE_SET, ['tilt', 'lift']).withDescription('Mode'),
        exposes.binary('factory_reset', ea.STATE_SET, true, false).withDescription('Factory reset'),
        exposes.binary('upper_limit', ea.STATE_SET, true, false).withDescription('Upper limit'),
        exposes.binary('bottom_limit', ea.STATE_SET, true, false).withDescription('Bottom limit'),

    ],
    meta: {
        tuyaDatapoints: [
            [1, 'state', tuya.valueConverterBasic.lookup({'OPEN': tuya.enum(0), 'STOP': tuya.enum(1), 'CLOSE': tuya.enum(2)})],
            [2, 'position', tuya.valueConverter.coverPosition],
            [3, 'position', tuya.valueConverter.raw],
            [5, 'reverse_direction', tuya.valueConverterBasic.lookup({'forward': tuya.enum(0), 'back': tuya.enum(1)})],
            [7, 'work_state', tuya.valueConverterBasic.lookup({'opening': tuya.enum(0), 'closing': tuya.enum(1)})],
            [101, 'mode', tuya.valueConverterBasic.lookup({'tilt': tuya.enum(0), 'lift': tuya.enum(1)})],
            [102, 'factory_reset', tuya.valueConverter.raw],
            [103, 'upper_limit', tuya.valueConverter.raw],
            [104, 'bottom_limit', tuya.valueConverter.raw],
            [105, 'motor_speed', tuya.valueConverter.raw],
        ],
    },
};

module.exports = definition;

image

Koenkk commented 1 year ago

but I would need to experiment with that a little once setting of these values is implemented.

I see you added the corresponding exposes, can you try if setting them works?

pawelsky commented 1 year ago

Only changing the state works. Setting the rest of them does not (see errors on the screenshot below)

image

Koenkk commented 1 year ago

Please check with https://gist.github.com/Koenkk/12256a02e6f582e4e369014d2ff1d03b

pawelsky commented 1 year ago

No change, same errors. :(

Koenkk commented 1 year ago

Made a mistake, updated https://gist.github.com/Koenkk/12256a02e6f582e4e369014d2ff1d03b

pawelsky commented 1 year ago

Unfortunately that did not help either, still same errors :(

Koenkk commented 1 year ago

Ah sorry, made another mistake, https://gist.github.com/Koenkk/12256a02e6f582e4e369014d2ff1d03b should do it

pawelsky commented 1 year ago

Now all of them work except position which gives error as below image

I've played a bit with these DPs and here are my thoughts:

I'm not sure how flexible the UI is but the way I see it for the limits is just a read-only display of the current state of the limit and a "SET" button that would send the "true" value to the motor (+plus a comment explaining that you need to do the factory reset to widen the range).

Koenkk commented 1 year ago

Please test with https://gist.github.com/Koenkk/12256a02e6f582e4e369014d2ff1d03b

pawelsky commented 1 year ago

After correcting the DP names in the key array (the linked file had still the old ones) everything except position works (I'll switch to the dev branch later and report back), but I have some suggestions:

pawelsky commented 1 year ago

Had some issues with switching to the latest-dev branch so I've tested position with Zigbee2MQTT Edge Add-on (which I believe is an equivalent of the dev branch) and the position setting works well. Let me know if that is enough.

Koenkk commented 1 year ago

Updated https://gist.github.com/Koenkk/12256a02e6f582e4e369014d2ff1d03b

is it possible to display a "Do you really want to do the factory reset?

  • this is currently not possible, I've moved it to the bottom.

Let me know if everything is OK then I will merge it.

pawelsky commented 1 year ago

The strings in 'key' array are still incorrect.

Regarding limit setting I have the following proposal (similar to mobile app behavior). The value is displayed as boolean, but when setting (regardless of which value is chosen) it will be always set to true.

changes to the valueConverter

const valueConverter = {
    setTrue: {
        to: (v) => true,
        from: (v) => v,
    },
};

changes to exposes

        exposes.binary('set_upper_limit', ea.STATE_SET, true, false).withDescription('Set the upper limit, to reset limits use factory_reset'),
        exposes.binary('set_bottom_limit', ea.STATE_SET, true, false).withDescription('Set the bottom limit, to reset limits use factory_reset'),

Not sure if that is 100% correct (not an expert in JS, doing some guesswork here) but it works for me - it displays the current state (which was missing) and always sets the value to true.

image

The only thing I'd change would be to make the value read only when it is true, but I don't know how to do that. That would be the exact copy of the mobile app behavior.

Koenkk commented 1 year ago

The strings in 'key' array are still incorrect.

Will fix this once it's integrated

The only thing I'd change would be to make the value read only when it is true,

We cannot make it readonly in the UI, what we can do is throw an error when false is set:

const valueConverter = {
    setTrue: {
        to: (v) => {
              if (v) return true;
              else throw new Error('Limit cannot be unset, use factory_reset')
        },
        from: (v) => v,
    },
};
pawelsky commented 1 year ago

That did the trick. I think it is ready to be integrated.

Koenkk commented 1 year ago

Great, integrated!

Changes will be available in the dev branch in a few hours from now. (https://www.zigbee2mqtt.io/advanced/more/switch-to-dev-branch.html)

pawelsky commented 1 year ago

I can see the set_upper_limit and set_bottom_limit are still ea.SET only, not ea.STATE_SET, so the current state is not really visible. Was it intentional or an omission?

Koenkk commented 1 year ago

nope, fixed!

pawelsky commented 1 year ago

Great, thanks! Would you also mind adding a picture for this device. I've prepared a TS0601_cover_4.jpg (150px x 150px) for your convenience:

TS0601_cover_4

Koenkk commented 1 year ago

Thanks, will do that (with the next release on 1 May)

pawelsky commented 1 year ago

nope, fixed!

I'm afraid the newly released 1.30.4 version still has the limit DPs set as enum rather then the binary.

bachoo786 commented 1 year ago

nope, fixed!

I'm afraid the newly released 1.30.4 version still has the limit DPs set as enum rather then the binary.

1.30.4 has messed up the cover/blinds with homeassistant to be fair :(

pawelsky commented 1 year ago

1.30.4 has messed up the cover/blinds with homeassistant to be fair :(

You mean for the Moes motors, or in general? The Moes motors seem to work for me.

reaper7 commented 1 year ago

1.30.4 has messed up the cover/blinds with homeassistant to be fair :(

https://github.com/Koenkk/zigbee2mqtt/issues/17621

bubez81 commented 11 months ago

hello! What about the battery state?