Koenkk / zigbee-herdsman-converters

Collection of device converters to be used with zigbee-herdsman
MIT License
896 stars 2.99k forks source link

_TZE204_r0jdjrvi does not support functions from TS0601_cover_1 #6517

Closed andrejsoucek closed 9 months ago

andrejsoucek commented 11 months ago

TS0601_cover_1 exposes motor speed and reverse direction. The _TZE204_r0jdjrvi device does not. Pairing is done differently than described in the z2m documentation (three short presses and one long).

This MR added the device as TS0601_cover_1: https://github.com/Koenkk/zigbee-herdsman-converters/pull/5708

I don't have tuya gateway but I might be able to guess the datapoints and prepare a converter. I hope it will support setter for position.

andrejsoucek commented 11 months ago

@darki73 does your device work correctly with TS0601_cover_1?

andrejsoucek commented 10 months ago

I have just ordered a tuya zigbee hub to debug this device...

darki73 commented 10 months ago

@andrejsoucek Hi, sorry for the late response, been a tough couple of weeks.

TLDR: It is indeed working with the proposed MR https://github.com/Koenkk/zigbee-herdsman-converters/pull/5708, however, due to unknown issues, after some time (or in some cases straight up) it will stop working as the device with stop reporting all of it's DPIs, so the only solution is to create dumbed-down variation which only exposes the position, even the reverse_direction sometimes might not get reported resulting in the device not being recognized by the Z2M.

I've ended up with writing a manual converter for this device as it sometimes just fails to report it's states and seems like required to boot off with the simplest controlls.

This is what i've been using for the past couple of months, as the fix i've suggested works at most half of the time.

const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const presets = exposes.presets;
const access = exposes.access;

const definition = {
    fingerprint: [
        {
            modelID: 'TS0601',
            manufacturerName: '_TZE204_r0jdjrvi'
        }
    ],
    model: 'TS0601_lilistore',
    vendor: 'TuYa',
    description: 'lilistore Tuya ZigBee Motorized Curtain Roller',
    fromZigbee: [
        legacy.fromZigbee.tuya_cover, 
        fz.ignore_basic_report
    ],
    toZigbee: [
        legacy.toZigbee.tuya_cover_control, 
        legacy.toZigbee.tuya_cover_options
    ],
    exposes: [
        presets.cover_position().setAccess('position', access.STATE_SET),

        exposes
            .composite('options', 'options', access.STATE_SET)
                .withFeature(
                    exposes.binary('reverse_direction', access.STATE_SET, true, false)
                        .withDescription('Reverse the motor direction')
                ),
    ]
};

module.exports = definition;

Even with this code, sometimes it fails to report the ability to reverse the direction of the motor, but after a couple of power off / on cycles it starts to work just fine.

And with regards to ordering a hub, even the tuya hub placed near the device itself will fail after some time, due to unknown reason. Simple example, it will somehow forget which direction is open or closed, so i have to flip the switch inside the Z2M.

My guess it is just a cheap rebranded thing which works sometimes...

What is even more concerning, despite having the physical cable (antenna) going out from its box, it still gets lower LQI when compared to the leak sensor which is placed inside the hatch on the ceiling (gypsum) image

andrejsoucek commented 10 months ago

@darki73 that's sad...anyway I can live with that I guess, I just need to be able to set position (or at least 0%, 50%, 100%). I still haven't figured out if the motor remembers where the minimum and maximum is or it just goes until it gets blocked. I will try your converter, thank you.

darki73 commented 10 months ago

@andrejsoucek The motor just goes until it is unable to go no more. Issue with that, the rating for Nm on the motor is incorrect, mine presented as 3Nm, but in fact, it is unable to move the curtain which was moved by the 2Nm motor. Well, it moves, but really struggles for the last meter or so. (The reason i changed the motors is that the original one was using Wi-Fi and in an even there is a slight delay with communication with the TuYa server, the curtains will just go into the "unknown" state and will stop working)

Why this is an issue: I have a sliding windows in my apartment, there is a beam connecting 2nd and 3rd portion of the "window", it provides some resistance, so even a slight tension on the curtain will stop motor from opening them completely, so i had to 3D print the half-sphere shaped doodad so the curtains can slide without providing to much tension on the motor, otherwise it will think that it reached the end and will stop moving, and as a result, your new 0-100-0 will be updated and you will have to manually drag the curtain to open position, then to closed position to update the values.

Position setting works just fine, here is the automation i use to open main shades in the bedroom to 50% at 9 am:

- alias: Open Bedroom Main Shades at Sunrise
  description: ""
  trigger:
    - platform: time
      at: "09:00:00"
  condition: []
  action:
    - service: cover.set_cover_position
      data:
        position: 50
      target:
        entity_id: cover.bedroom_main_shades
  mode: single

So no issues here. Just a note, first you need to manually drag the curtain in either close / open position, then in the Z2M you need to toggle "reverse_motor" if the reported state does not match as the motor itself seems to have no idea which way is open by default and which is closed.

P.S. This converter was tested on the 1.32.1-1 version (had to rollback due to issues with other devices), and i am still on this version.

andrejsoucek commented 10 months ago

@darki73 thanks, I have the same issue with unsufficient strength, I am using two of these motors to open my pergola roof. The roof is split into 2 parts, one part is fine, the closing is slower than opening because it needs to pull the slats but it closes fine. The second part actually gets stuck in most cases while in the middle of closing. So I 3D printed a planetary gear box which is now really powerful and I need to somehow tell the motor to stop or it will either break the pergola or the gearbox. :laughing: But the roof is now closed and motor shows position 0. So once it gets stuck on the other "end" (in fully open position) it should show 100 and it's done. I want to test it ASAP but there is snow on the roof right now... :snowflake: :grimacing:

BTW regarding the reverse direction I have never seen it reported by either of the 2 motors.

darki73 commented 10 months ago

I mean, in case you really need to dig in, these are the last reported DPIs by the motor (the last time i used the TuYa hub):

primary_entity:
  entity: cover
  class: curtain
  category: config
  name: Smart Curtain Motor
  mode: auto
  dps:
    - id: 1
      type: string
      name: control
      persist: true
      mapping:
        - dps_val: open
          value: open
        - dps_val: close
          value: close
        - dps_val: stop
          value: stop
        - dps_val: continue
          value: continue
    - id: 2
      type: integer
      name: position
      persist: true
      optional: true
      range:
        min: 0
        max: 100
        step: 1
        scale: 0
      unit: "%"
    - id: 3
      type: integer
      name: current_position
      readonly: true
      optional: true
      range:
        min: 0
        max: 100
        step: 1
        scale: 0
      unit: "%"
    - id: 7
      type: string
      name: action
      readonly: true
      optional: true
      mapping:
        - dps_val: opening
          constraint: current_position
          conditions:
            - dps_val: 100
              value: opened
            - dps_val: null
              value: opened
            - value: opening
        - dps_val: closing
          constraint: current_position
          conditions:
            - dps_val: 0
              value: closed
            - dps_val: null
              value: closed
            - value: closing
    - id: 11
      type: boolean
      name: open
      readonly: true
      optional: true
      mapping:
        - dps_val: fully_open
          value: true
        - dps_val: fully_close
          value: false
secondary_entities:
  - entity: switch
    category: config
    name: Reverse Motor Direction
    dps:
      - id: 101
        type: boolean
        name: switch
        optional: true
        mapping:
          - dps_val: true
            value: true
          - dps_val: false
            value: false
          - dps_val: null
            value: false
  - entity: switch
    category: config
    name: Auto Power
    dps:
      - id: 6
        type: boolean
        name: switch
        optional: true
  - entity: switch
    category: config
    name: Limit Setting
    dps:
      - id: 102
        type: boolean
        name: switch
        optional: true
        mapping:
          - dps_val: true
            value: true
          - dps_val: false
            value: false
          - dps_val: null
            value: false
  - entity: binary_sensor
    name: Motor
    class: problem
    category: diagnostic
    dps:
      - id: 12
        type: bitfield
        name: sensor
        optional: true
        mapping:
          - dps_val: -1
            value: false
          - dps_val: 0
            value: false
          - dps_val: null
            value: false
          - value: true

Just a side note, they WILL NOT WORK, at least, if you add all of them in the converter, the only reliable way to make it some what 99.9% operational is to have position and reverse_direction as the only things managed by the converter.

P.S. I guess you can ignore all the other code i have, as technically it supposed to work, but it will not most of the time, for example, motor indeed supports the continue operation, but will not work most of the time.

P.P.S. The yaml is from either localtuya or tuya-local (i dont remember), so you might need to adjust it to the ZHC and Z2M if you would like to give it a go.

P.P.P.S. In regards to the reported by the motor, thing is, if you add any datapoints which are not reported by the motor, it simply will not get recognized by the Z2M, so if you add a DPI setting to the converter and motor is still recognized, then that means that motor indeed reports this value. (at least this is what i had, had to remove all of the entries one by one until it got recognized)

Aaaand, another side note: image As you can see, the ZHC and Z2M are smart enough to know that motor provides the stop functionality, but the reverse_direction on this screenshot is the "unknown" state as motor itself does not explicitly reports it, but it will honor the setting whenever you click on either True or False, and it will remain visible (whichever you've chosen) until the powerout even, then it will fail to report it again, but will still work as if this setting is set to either True or False.

darki73 commented 9 months ago

@andrejsoucek

Well, i've went over all the hoops to get it to the state it actually works with all the datapoints and here is the final result:

const tuya = require('zigbee-herdsman-converters/lib/tuya')
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const exposesPresets = exposes.presets;
const exposesAccess = exposes.access;

module.exports = {
    fingerprint: tuya.fingerprint('TS0601', ['_TZE204_r0jdjrvi']),
    model: 'TS0601_lilistore',
    vendor: 'TuYa',
    description: 'lilistore Tuya ZigBee Motorized Curtain Roller',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    onEvent: tuya.onEventSetTime,
    options: [exposes.options.invert_cover()],
    configure: tuya.configureMagicPacket,
    exposes: [
        exposesPresets.cover_position().setAccess('position', exposesAccess.STATE_SET),
        exposesPresets.enum('reverse_direction', exposesAccess.STATE_SET, ['forward', 'back']).withDescription('Reverse the motor direction'),
        exposesPresets.binary('motor_fault', exposesAccess.STATE, true, false).withDescription('Motor Fault'),
    ],
    whiteLabel: [
        tuya.whitelabel('Lilistore', 'TS0601_lilistore', 'Cover motor', ['_TZE204_r0jdjrvi']),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'state', tuya.valueConverterBasic.lookup({'OPEN': tuya.enum(0), 'STOP': tuya.enum(1), 'CLOSE': tuya.enum(2), 'CONTINUE': tuya.enum(3)})],
            [2, 'position', tuya.valueConverter.coverPosition],
            [3, 'position', tuya.valueConverter.raw],
            [5, 'reverse_direction', tuya.valueConverterBasic.lookup({'forward': tuya.enum(0), 'back': tuya.enum(1)})],
            [12, 'motor_fault', tuya.valueConverter.trueFalse1],
        ],
    }
};

Now, these datapoints are extracted from the TuYa IOT Cloud, not using legacy anymore, and now the motor direction actually works as intended (i guess they've changed something, as now it only supports forward and back as strings instead of true and false.

For some reason, it even started to work a bit faster (no more strange delays between command issued and action performed).

Sadly, this motor only supports basic set of functions, there is no limits, no nothing, just open / close / set position.

Side note, in the

exposesPresets.cover_position().setAccess('position', exposesAccess.STATE_SET),

motor straight up refuses to work without .setAccess('position', exposesAccess.STATE_SET), even though the examples in the officially supported devices work without it, so it is kinda needed.

andrejsoucek commented 9 months ago

@darki73 thanks for this, are you going to put it to a merge request?

darki73 commented 9 months ago

@andrejsoucek Hey, i made a PR https://github.com/Koenkk/zigbee-herdsman-converters/pull/6830

It should remove the invalid assignment made by the https://github.com/Koenkk/zigbee-herdsman-converters/pull/5708 and should work as expected.

There are some changes i made to the code as the original code somewhat failed to work with the HA cards (they were not getting the proper state, but everything was working fine through the automations).

As of now, while it is not yet merged, the following code should work just fine:

const tuya = require('zigbee-herdsman-converters/lib/tuya')
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const exposesPresets = exposes.presets;
const exposesAccess = exposes.access;

module.exports = {
    fingerprint: tuya.fingerprint('TS0601', ['_TZE204_r0jdjrvi']),
    model: 'TS0601_lilistore',
    vendor: 'TuYa',
    description: 'lilistore Tuya ZigBee Motorized Curtain Roller',
    fromZigbee: [tuya.fz.datapoints],
    toZigbee: [tuya.tz.datapoints],
    onEvent: tuya.onEventSetTime,
    options: [exposes.options.invert_cover()],
    configure: tuya.configureMagicPacket,
    exposes: [
        exposesPresets.cover_position().setAccess('position', ea.STATE_SET),
        exposesPresets.enum('reverse_direction', exposesAccess.STATE_SET, ['forward', 'back']).withDescription('Reverse the motor direction'),
        exposesPresets.binary('motor_fault', exposesAccess.STATE, true, false).withDescription('Motor Fault'),
    ],
    whiteLabel: [
        tuya.whitelabel('Lilistore', 'TS0601_lilistore', 'Cover motor', ['_TZE204_r0jdjrvi']),
    ],
    meta: {
        tuyaDatapoints: [
            [1, 'state', tuya.valueConverterBasic.lookup({'OPEN': tuya.enum(0), 'STOP': tuya.enum(1), 'CLOSE': tuya.enum(2)})],
            [2, 'position', tuya.valueConverter.coverPositionInverted],
            [3, 'position', tuya.valueConverter.coverPositionInverted],
            [5, 'reverse_direction', tuya.valueConverterBasic.lookup({'forward': tuya.enum(0), 'back': tuya.enum(1)})],
            [12, 'motor_fault', tuya.valueConverter.trueFalse1],
        ],
    }
};
kabturek commented 7 months ago

Thanks for the work guys. I have the same motor and i'm not sure if i have a defective one or going crazy - mine doesn't want to connect through any zigbee router - when it's close to the coordinator it works fine. when i put it in the final position (1m from an ikea zigbee bulb and many other routers in sight) it stops working "Failed to ping etc". I've left it for couple of hours there and nothings happens. @darki73 @andrejsoucek are your motors directly connected to the coordinator ?

darki73 commented 7 months ago

@kabturek Hey, 1 directly (gypsum wall), and two are through set of phillips plugs (3 between motor and coordinator), work just fine, mine though is a sonoff (I guess) usb plus with external antenna

darki73 commented 7 months ago

@kabturek

Here is the USB dongle - SONOFF Zigbee 3.0 USB Dongle Plus V2

And here is the map, for the Bedroom Shades

Screenshot 2024-03-11 at 11 45 26

Just a note, i specifically purchased the Phillips plugs as i've read somewhere that they are the most reliable ones for building the "bridge" between the end device and the coordinator.