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

Loratap SC400ZB-EU-V5S (TS130F curtain switch) percentage position not working #2724

Closed
jopeyyyy opened this issue Nov 7, 2023 · 11 comments
Closed
Labels
Tuya Request/PR regarding a Tuya device

Comments

@jopeyyyy
Copy link

jopeyyyy commented Nov 7, 2023

Problem description

Switch is calibrated and working correctly up/down/stop and even reporting correct state and position but go_to_lift_percentage function does not work

Solution description

get the go_to_lift_percentage function working or a tool to send commands up/down and stop calculated based on the calibration time.

Screenshots/Video

image #2707

Device signature

{
  "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0203",
      "input_clusters": [
        "0x0000",
        "0x0004",
        "0x0005",
        "0x0006",
        "0x0102",
        "0xe001"
      ],
      "output_clusters": [
        "0x000a",
        "0x0019"
      ]
    },
    "242": {
      "profile_id": "0xa1e0",
      "device_type": "0x0061",
      "input_clusters": [],
      "output_clusters": [
        "0x0021"
      ]
    }
  },
  "manufacturer": "_TZ3000_qa8s8vca",
  "model": "TS130F",
  "class": "ts130f.TuyaTS130ESTC"
}


Diagnostic information

{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2023.11.1",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.11.6",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Europe/Paris",
    "os_name": "Linux",
    "os_version": "6.1.59",
    "supervisor": "2023.10.1",
    "host_os": "Home Assistant OS 11.1",
    "docker_version": "24.0.6",
    "chassis": "embedded",
    "run_as_root": true
  },
  "custom_components": {
    "zha_toolkit": {
      "version": "v1.1.6",
      "requirements": [
        "pytz"
      ]
    },
    "localtuya": {
      "version": "5.2.1",
      "requirements": []
    },
    "dreame_vacuum": {
      "version": "v2.0.0b6",
      "requirements": [
        "pillow",
        "numpy",
        "pybase64",
        "requests",
        "pycryptodome",
        "python-miio",
        "py-mini-racer",
        "tzlocal"
      ]
    },
    "cover_time_based_synced": {
      "version": "2.0.0",
      "requirements": []
    },
    "hacs": {
      "version": "1.33.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "landroid_cloud": {
      "version": "3.1.0",
      "requirements": [
        "pyworxcloud==4.0.2"
      ]
    }
  },
  "integration_manifest": {
    "domain": "zha",
    "name": "Zigbee Home Automation",
    "after_dependencies": [
      "onboarding",
      "usb"
    ],
    "codeowners": [
      "@dmulcahey",
      "@adminiuga",
      "@puddly"
    ],
    "config_flow": true,
    "dependencies": [
      "file_upload"
    ],
    "documentation": "https://www.home-assistant.io/integrations/zha",
    "iot_class": "local_polling",
    "loggers": [
      "aiosqlite",
      "bellows",
      "crccheck",
      "pure_pcapy3",
      "zhaquirks",
      "zigpy",
      "zigpy_deconz",
      "zigpy_xbee",
      "zigpy_zigate",
      "zigpy_znp",
      "universal_silabs_flasher"
    ],
    "requirements": [
      "bellows==0.36.8",
      "pyserial==3.5",
      "pyserial-asyncio==0.6",
      "zha-quirks==0.0.106",
      "zigpy-deconz==0.21.1",
      "zigpy==0.59.0",
      "zigpy-xbee==0.19.0",
      "zigpy-zigate==0.11.0",
      "zigpy-znp==0.11.6",
      "universal-silabs-flasher==0.0.14",
      "pyserial-asyncio-fast==0.11"
    ],
    "usb": [
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*2652*",
        "known_devices": [
          "slae.sh cc2652rb stick"
        ]
      },
      {
        "vid": "1A86",
        "pid": "55D4",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus v2"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*sonoff*plus*",
        "known_devices": [
          "sonoff zigbee dongle plus"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*tubeszb*",
        "known_devices": [
          "TubesZB Coordinator"
        ]
      },
      {
        "vid": "1A86",
        "pid": "7523",
        "description": "*zigstar*",
        "known_devices": [
          "ZigStar Coordinators"
        ]
      },
      {
        "vid": "1CF1",
        "pid": "0030",
        "description": "*conbee*",
        "known_devices": [
          "Conbee II"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8A2A",
        "description": "*zigbee*",
        "known_devices": [
          "Nortek HUSBZB-1"
        ]
      },
      {
        "vid": "0403",
        "pid": "6015",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate+"
        ]
      },
      {
        "vid": "10C4",
        "pid": "EA60",
        "description": "*zigate*",
        "known_devices": [
          "ZiGate"
        ]
      },
      {
        "vid": "10C4",
        "pid": "8B34",
        "description": "*bv 2010/10*",
        "known_devices": [
          "Bitron Video AV2010/10"
        ]
      }
    ],
    "zeroconf": [
      {
        "type": "_esphomelib._tcp.local.",
        "name": "tube*"
      },
      {
        "type": "_zigate-zigbee-gateway._tcp.local.",
        "name": "*zigate*"
      },
      {
        "type": "_zigstar_gw._tcp.local.",
        "name": "*zigstar*"
      },
      {
        "type": "_uzg-01._tcp.local.",
        "name": "uzg-01*"
      },
      {
        "type": "_slzb-06._tcp.local.",
        "name": "slzb-06*"
      }
    ],
    "is_built_in": true
  },
  "data": {
    "ieee": "**REDACTED**",
    "nwk": 4129,
    "manufacturer": "_TZ3000_qa8s8vca",
    "model": "TS130F",
    "name": "_TZ3000_qa8s8vca TS130F",
    "quirk_applied": true,
    "quirk_class": "ts130f.TuyaTS130ESTC",
    "quirk_id": null,
    "manufacturer_code": 4417,
    "power_source": "Mains",
    "lqi": 212,
    "rssi": -47,
    "last_seen": "2023-11-07T14:15:58",
    "available": true,
    "device_type": "Router",
    "signature": {
      "node_descriptor": "NodeDescriptor(logical_type=<LogicalType.Router: 1>, complex_descriptor_available=0, user_descriptor_available=0, reserved=0, aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4417, maximum_buffer_size=66, maximum_incoming_transfer_size=66, server_mask=10752, maximum_outgoing_transfer_size=66, descriptor_capability_field=<DescriptorCapability.NONE: 0>, *allocate_address=True, *is_alternate_pan_coordinator=False, *is_coordinator=False, *is_end_device=False, *is_full_function_device=True, *is_mains_powered=True, *is_receiver_on_when_idle=True, *is_router=True, *is_security_capable=False)",
      "endpoints": {
        "1": {
          "profile_id": "0x0104",
          "device_type": "0x0203",
          "input_clusters": [
            "0x0000",
            "0x0004",
            "0x0005",
            "0x0006",
            "0x0102",
            "0xe001"
          ],
          "output_clusters": [
            "0x000a",
            "0x0019"
          ]
        },
        "242": {
          "profile_id": "0xa1e0",
          "device_type": "0x0061",
          "input_clusters": [],
          "output_clusters": [
            "0x0021"
          ]
        }
      },
      "manufacturer": "_TZ3000_qa8s8vca",
      "model": "TS130F"
    },
    "active_coordinator": false,
    "entities": [
      {
        "entity_id": "cover.rollladen_buro_cover",
        "name": "_TZ3000_qa8s8vca TS130F"
      },
      {
        "entity_id": "switch.rollladen_buro_switch",
        "name": "_TZ3000_qa8s8vca TS130F"
      }
    ],
    "neighbors": [],
    "routes": [],
    "endpoint_names": [
      {
        "name": "WINDOW_COVERING_CONTROLLER"
      },
      {
        "name": "PROXY_BASIC"
      }
    ],
    "user_given_name": "Rollladen B\u00fcro",
    "device_reg_id": "71d7a050aa03354d24de3aec06c8e182",
    "area_id": "buro",
    "cluster_details": {
      "1": {
        "device_type": {
          "name": "WINDOW_COVERING_CONTROLLER",
          "id": 515
        },
        "profile_id": 260,
        "in_clusters": {
          "0x0000": {
            "endpoint_attribute": "basic",
            "attributes": {
              "0x0004": {
                "attribute_name": "manufacturer",
                "value": "_TZ3000_qa8s8vca"
              },
              "0x0005": {
                "attribute_name": "model",
                "value": "TS130F"
              }
            },
            "unsupported_attributes": {}
          },
          "0x0004": {
            "endpoint_attribute": "groups",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0005": {
            "endpoint_attribute": "scenes",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0006": {
            "endpoint_attribute": "on_off",
            "attributes": {
              "0x8001": {
                "attribute_name": "backlight_mode",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0000": {
                "attribute_name": "on_off"
              },
              "0x4003": {
                "attribute_name": "start_up_on_off"
              }
            }
          },
          "0x0102": {
            "endpoint_attribute": "window_covering",
            "attributes": {
              "0xf001": {
                "attribute_name": "calibration",
                "value": 1
              },
              "0xf003": {
                "attribute_name": "calibration_time",
                "value": 210
              },
              "0x0008": {
                "attribute_name": "current_position_lift_percentage",
                "value": 0
              },
              "0x8000": {
                "attribute_name": "motor_mode",
                "value": 0
              },
              "0xf002": {
                "attribute_name": "motor_reversal",
                "value": 0
              },
              "0xf000": {
                "attribute_name": "tuya_moving_state",
                "value": 0
              }
            },
            "unsupported_attributes": {
              "0x0015": {
                "attribute_name": "acceleration_time_lift"
              },
              "0x0009": {
                "attribute_name": "current_position_tilt_percentage"
              }
            }
          },
          "0xe001": {
            "endpoint_attribute": "tuya_external_switch_type",
            "attributes": {},
            "unsupported_attributes": {}
          }
        },
        "out_clusters": {
          "0x000a": {
            "endpoint_attribute": "time",
            "attributes": {},
            "unsupported_attributes": {}
          },
          "0x0019": {
            "endpoint_attribute": "ota",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      },
      "242": {
        "device_type": {
          "name": "PROXY_BASIC",
          "id": 97
        },
        "profile_id": 41440,
        "in_clusters": {},
        "out_clusters": {
          "0x0021": {
            "endpoint_attribute": "green_power",
            "attributes": {},
            "unsupported_attributes": {}
          }
        }
      }
    }
  }
}

Logs

Custom quirk

"""Device handler for loratap TS130F smart curtain switch."""
from zigpy.profiles import zgp, zha
from zigpy.quirks import CustomCluster, CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.closures import WindowCovering
from zigpy.zcl.clusters.general import (
    Basic,
    GreenPowerProxy,
    Groups,
    OnOff,
    Ota,
    Scenes,
    Time,
)

from zhaquirks.const import (
    DEVICE_TYPE,
    ENDPOINTS,
    INPUT_CLUSTERS,
    MODEL,
    OUTPUT_CLUSTERS,
    PROFILE_ID,
)
from zhaquirks.tuya import SwitchBackLight, TuyaZBExternalSwitchTypeCluster

ATTR_CURRENT_POSITION_LIFT_PERCENTAGE = 0x0008
CMD_GO_TO_LIFT_PERCENTAGE = 0x0005


class TuyaWithBacklightOnOffCluster(CustomCluster, OnOff):
    """Tuya Zigbee On Off cluster with extra attributes."""

    attributes = OnOff.attributes.copy()
    attributes.update({0x8001: ("backlight_mode", SwitchBackLight)})


class MotorMode(t.enum8):
    """Tuya motor mode enum."""

    STRONG_MOTOR = 0x00
    WEAK_MOTOR = 0x01


class TuyaCoveringCluster(CustomCluster, WindowCovering):
    """TuyaSmartCurtainWindowCoveringCluster: Allow to setup Window covering tuya devices."""

    attributes = WindowCovering.attributes.copy()
    attributes.update({0x8000: ("motor_mode", MotorMode)})
    attributes.update({0xF000: ("tuya_moving_state", t.enum8)})
    attributes.update({0xF001: ("calibration", t.enum8)})
    attributes.update({0xF002: ("motor_reversal", t.enum8)})
    attributes.update({0xF003: ("calibration_time", t.uint16_t)})

    def _update_attribute(self, attrid, value):
        if attrid == ATTR_CURRENT_POSITION_LIFT_PERCENTAGE:
            # Invert the percentage value (cf https://github.com/dresden-elektronik/deconz-rest-plugin/issues/3757)
            value = 100 - value
        super()._update_attribute(attrid, value)

    async def command(
        self, command_id, *args, manufacturer=None, expect_reply=True, tsn=None
    ):
        """Override default command to invert percent lift value."""
        if command_id == CMD_GO_TO_LIFT_PERCENTAGE:
            percent = args[0]
            # Invert the percentage value (cf https://github.com/dresden-elektronik/deconz-rest-plugin/issues/3757)
            percent = 100 - percent
            v = (percent,)
            return await super().command(command_id, *v)
        return await super().command(
            command_id,
            *args,
            manufacturer=manufacturer,
            expect_reply=expect_reply,
            tsn=tsn,
        )


class TuyaTS130FTI(CustomDevice):
    """Tuya smart curtain roller shutter Time In."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0, 4, 5, 6, 10, 0x0102], output_clusters=[25]))
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Time.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    Time.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [Ota.cluster_id],
            },
        },
    }


class TuyaZemismartTS130F(CustomDevice):
    """Tuya ZemiSmart smart curtain roller shutter."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0x0000, 0x0004, 0x0005, 0x0006, 0x0102], output_clusters=[0x000a, 0x0019]))
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
        },
    }


class TuyaTS130FTOGP(CustomDevice):
    """Tuya Oxt smart curtain roller shutter."""

    signature = {
        MODEL: "TS130F",
        ENDPOINTS: {
            # <SimpleDescriptor endpoint=1 profile=260 device_type=0x0202
            # device_version=1
            # input_clusters=[0x0000, 0x0004, 0x0005, 0x0102]
            # output_clusters=[0x000a, 0x0019]>
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
            # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
            # input_clusters=[]
            # output_clusters=[33]>
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }


class TuyaTS130FTI2(CustomDevice):
    """Tuya smart curtain roller shutter Time In."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0203, device_version=1, input_clusters=[0x0000, 0x0004, 0x0005, 0x0006, 0x0102], output_clusters=[0x000a, 0x0019]))
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
        },
    }


class TuyaTS130FTO(CustomDevice):
    """Tuya smart curtain roller shutter Time Out."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0, 4, 5, 6, 10, 0x0102], output_clusters=[25]))
        # This singnature is not correct is one copy of the first one and the cluster is not inline with the device.
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
        },
    }


class TuyaTS130GP(CustomDevice):
    """Tuya ZemiSmart smart curtain roller shutter with Green Power."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0, 4, 5, 6, 0x0102], output_clusters=[0x000a, 0x0019]))
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }


class TuyaTS130Double_GP(CustomDevice):
    """Tuya double smart curtain roller shutter with Green Power."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0, 4, 5, 6, 0x0102], output_clusters=[0x000a, 0x0019]))
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                # "profile_id": 260, "device_type": "0x0202",
                # "in_clusters": ["0x0004","0x0005","0x0006","0x0102"],
                # "out_clusters": []
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }


class TuyaTS130ESTC(CustomDevice):
    """Tuya ZigBee Curtain Switch Module with External Switch Type Cluster."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0x0000, 0x0004, 0x0005, 0x0006, 0x0102, 0xE001], output_clusters=[0x000a, 0x0019]))
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                    TuyaZBExternalSwitchTypeCluster,
                ],
                OUTPUT_CLUSTERS: [
                    Time.cluster_id,
                    Ota.cluster_id,
                ],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }


class TuyaTS130Double_GP_ESTC(CustomDevice):
    """Tuya double smart curtain roller shutter with Green Power and External Switch Type Cluster."""

    signature = {
        # SizePrefixedSimpleDescriptor(endpoint=1, profile=260, device_type=0x0202, device_version=1, input_clusters=[0, 4, 5, 6, 0x0102, 0xE001], output_clusters=[0x000a, 0x0019]))
        MODEL: "TS130F",
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                # "profile_id": 260, "device_type": "0x0202",
                # "in_clusters": ["0x0004","0x0005","0x0006","0x0102"],
                # "out_clusters": []
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    OnOff.cluster_id,
                    WindowCovering.cluster_id,
                    TuyaZBExternalSwitchTypeCluster.cluster_id,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                # <SimpleDescriptor endpoint=242 profile=41440 device_type=97
                # input_clusters=[]
                # output_clusters=[33]
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }
    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                    TuyaZBExternalSwitchTypeCluster,
                ],
                OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
            },
            2: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
                INPUT_CLUSTERS: [
                    Groups.cluster_id,
                    Scenes.cluster_id,
                    TuyaWithBacklightOnOffCluster,
                    TuyaCoveringCluster,
                    TuyaZBExternalSwitchTypeCluster,
                ],
                OUTPUT_CLUSTERS: [],
            },
            242: {
                PROFILE_ID: zgp.PROFILE_ID,
                DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
                INPUT_CLUSTERS: [],
                OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
            },
        },
    }

Additional information

I'm new to home assistant and managed it to got the local quirk working but I would say that's it.
I spent a lot of hours ready and searching for solutions but I didn't find the right thing.
If I try to send command: go_to_lift_percentage (id: 0x0005), I have a slider from with value from 0 to 255. But I got an error:
image

image

The return of the actual position in percent works, even if commanded via the physical buttons.

image

What about "time based cover synced", can that help me in my case? I tried to install it (adding to the configuration.yaml) but I don't know how to use it...

Hope someone can help me as it's the only zigbee roller shutter switch which has physical buttons which are superposed and not always backlight on and to a good price (I need 17 pieces). The light from other switches disturbs me in the night and to find the button without light with a glas touch panel is not so easy...

Thanks!

@jopeyyyy
Copy link
Author

jopeyyyy commented Nov 9, 2023

Hi, nobody who can help me out there?

@gignonje
Copy link

Hi,

I have same issue with Loratap SC400ZB-EU-V2 (with glass panel), identified as _TZ3000_qa8s8vca TS130F. Up and down work, position don't.

Hope someone finds a fix.

@jopeyyyy
Copy link
Author

Great! Or not great but nice that I'm not alone... I'm sure there are more out there with this issue...

It would be great to have something were you can put the time for up and down from each roller so you have exact positioning. Of course the manual operation would not be registered or used but that is like never the time (for me).
Even if working based on the feedback time which the switch gives would be nice, so if positioning would not be 100% exact due to different up and down time, but then even the physical operation would be known by home assistant.

@gignonje: does your switch gives feedback of the actual position in id: 0x0008 too?

@gignonje
Copy link

gignonje commented Nov 13, 2023

Great! Or not great but nice that I'm not alone... I'm sure there are more out there with this issue...

It would be great to have something were you can put the time for up and down from each roller so you have exact positioning. Of course the manual operation would not be registered or used but that is like never the time (for me). Even if working based on the feedback time which the switch gives would be nice, so if positioning would not be 100% exact due to different up and down time, but then even the physical operation would be known by home assistant.

@gignonje: does your switch gives feedback of the actual position in id: 0x0008 too?

Yes it is ! (But only after it has stopped moving)
image

@jopeyyyy
Copy link
Author

Perfect! I thinks that's something the specialists can work with...

I would like too but I have not enough knowledge in that domain 😢

@jopeyyyy
Copy link
Author

finaly got the cover_rf_time_based integration working and for me it's ok.

I also Tried to by the double switch version:
image

This one, the percentage works out of the box, but trying to send the commands got_to_lift_percentage directly also ends with the same error.

However, I now ordered several of the simple version for me.

@trudetta
Copy link

finaly got the cover_rf_time_based integration working and for me it's ok.

I also Tried to by the double switch version: image

This one, the percentage works out of the box, but trying to send the commands got_to_lift_percentage directly also ends with the same error.

However, I now ordered several of the simple version for me.

How did you manage, can you explain to us? Thanks in advance.

@jopeyyyy
Copy link
Author

After setting up the shutter switch in HA and calibrating it or entering the calibration time in the zigbee modul itself
You need to install the integration via hacs and add to the configuration yaml an entry for each shutter like this with the appropriate times for up and down and the name of the new created entity(name:...):

image

Then you need to restart HA.

After that you can add in the dashboard a manual type:
image

And that's it!

Note: now, if you use the hardware buttons on the switch, the dashboard will not reflect the actual position.

But as the switch itself return the actual shutter position (due to the defined calibration_ time) there must be a way to use this information to update the position in the dashboard (for the new created entity). There is this option for this in the integration but I didn't get that working for now. Is there anybody who could help here?? Then everything would be perfect as even hardware button would react onto the dashboard....

@TobiasB91
Copy link

After setting up the shutter switch in HA and calibrating it or entering the calibration time in the zigbee modul itself You need to install the integration via hacs and add to the configuration yaml an entry for each shutter like this with the appropriate times for up and down and the name of the new created entity(name:...):

image

Then you need to restart HA.

After that you can add in the dashboard a manual type: image

And that's it!

Note: now, if you use the hardware buttons on the switch, the dashboard will not reflect the actual position.

But as the switch itself return the actual shutter position (due to the defined calibration_ time) there must be a way to use this information to update the position in the dashboard (for the new created entity). There is this option for this in the integration but I didn't get that working for now. Is there anybody who could help here?? Then everything would be perfect as even hardware button would react onto the dashboard....

That sounds very good! Can you tell me which cover_rf_time_based integration you used? There seems to be a lot of forks of this on github. Thank you! :)

@jopeyyyy
Copy link
Author

jopeyyyy commented Feb 1, 2024

@jopeyyyy
Copy link
Author

jopeyyyy commented Feb 1, 2024

YEAH!

Just got it working like I wanted so with hardware operation being reflected in Dashboard, that's the automation:

alias: Position Rollladen Büro
description: ""
trigger:
  - entity_id:
      - cover.rollladen_buero_o
    platform: state
    attribute: current_position
condition: []
action:
  - data:
      confident: true
      position: "{{ state_attr('cover.rollladen_buero_o', 'current_position') }}"
      position_type: current
      entity_id: cover.rollladen_buro
    service: cover_rf_time_based.set_known_position
mode: single

Each time the shutter stops, the entities from the rf cover time based are updated in Dashboard and that even if using the hardware buttons! PERFECT!

@jopeyyyy jopeyyyy closed this as completed Feb 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Tuya Request/PR regarding a Tuya device
Projects
None yet
Development

No branches or pull requests

5 participants