Zigbee2MQTT - Tuya 4-button Scene Switch (TS0044)

Hi everyone. I faced the same problem. I bought a TS004F switch and it did not work with zigbee2mqtt. So I spent a little time and wrote an external conveter for it. But I couldn’t get everything to work. Single press events work for all 4 buttons, and hold event works only for the 2 right side buttons. No other events (like double click) appear in the console in debug mode so I can’t write a converter for them.

To use my converter add the following lines to your configuration.yaml:

  - TS004F.js

And save the code below in the file data/TS004F.js next to the file configuration.yaml:
(UPD: the data dir is the dir where the configuration.yaml file is located and may have a different name for you)

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 e = exposes.presets;
const ea = exposes.access;

const bind = async (endpoint, target, clusters) => {
    for (const cluster of clusters) {
        await endpoint.bind(cluster, target);

  Buttons numbers:
     | 1 | 3 |
     | 2 | 4 |

const leftButtonsConverter = {
    cluster: 'genOnOff',
    type: ['commandOn', 'commandOff', 'commandToggle'],
    convert: (model, msg, publish, options, meta) => {
        if (msg.type === 'commandOn') {
            return { action: '1_single' };
        if (msg.type === 'commandOff') {
            return { action: '2_single' };

const rightButtonsConverter = {
    cluster: 'genLevelCtrl',
    type: ['commandStep', 'commandMove', 'commandStop'],
    convert: (model, msg, publish, options, meta) => {    
        if (msg.type === 'commandStep') {
            if (msg.data.stepmode === 0) {
                return { action: '3_single' };
            else if (msg.data.stepmode === 1) {
                return { action: '4_single' };
        else if (msg.type === 'commandMove') {
            if (msg.data.movemode === 0) {
                return { action: '3_hold' };
            else if (msg.data.movemode === 1) {
                return { action: '4_hold' };
        else if (msg.type === 'commandStop') {
            // No data available to determine which button was released
            return { action: 'release' };
        // No 'double' events are fired

const definition = {
    zigbeeModel: ['TS004F'],
    model: 'TS004F',
    vendor: 'TuYa',
    description: 'Wireless switch with 4 buttons',
    whiteLabel: [{vendor: '_TZ3000_xabckq1v', model: 'TS004F'}],

    // Exposed commands are similar to the Tuya TS0044 switch
    exposes: [
            '3_single', '3_hold',
            '4_single', '4_hold'
            '1_single', '1_double', '1_hold',
            '2_single', '2_double', '2_hold',
            '3_single', '3_double', '3_hold',
            '4_single', '4_double', '4_hold'

    fingerprint: [
            modelID: 'TS004F',
            manufacturerName: '_TZ3000_xabckq1v'
    fromZigbee: [
    toZigbee: [
    meta: {
        configureKey: 1,
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        await bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl']);
        await bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
        const payload = [{
            attribute: 'batteryPercentageRemaining',
            minimumReportInterval: 0,
            maximumReportInterval: 3600,
            reportableChange: 1,
        }, {
            attribute: 'batteryVoltage',
            minimumReportInterval: 0,
            maximumReportInterval: 3600,
            reportableChange: 1,
        await endpoint.configureReporting('genPowerCfg', payload);

module.exports = definition;

Then you can use the blueprint described here.


Thanks, I verified it and it works as you said. I had to remove the extend import line, but it is unused anyway. And the configure step fails with timeout, so I guess you based it off of some other similar device, or does configure work with your switch? Do you think there is a chance a different mode can be configured so all the functions work for all buttons?

Edit: Configure works now, thanks!

Thank you so much for sharing it!

Yes, you’re right. This is my first expirience with home assistant programming. Before writing my own converters, I tried some converters for Tuya devices that are already supported, and I saw “configuring…” logs in the console during this time. I did not get what this means :slight_smile:

Could you please share with others the steps I missed to get my config working?

UPD: I forgot to say that I was using the dev branch of zigbee2mqtt.

Thank You very much for sharing this.

Aiditz, thank you again for putting it together. I am not really familiar with converters.
Can you please give us some more details about it?
I added the first code to configuration.yaml, but I cant find the path data/ to add TS00F4.js file.’

Also, I am not sure if I am using the dev branch of zigbee2mqttt. Is it essential to get this working?

First of all, sorry for my English.
I did so. I stopped the zigbee2mqtt add-on. In its configuration panel, I added an appropriate entry in the external_converters section.

I saved the configuration. In the zigbee2mqtt plugin directory (for me it’s /share/zigbee2mqtt) I created the TS004F.js file. I launched the add-on and restarted the Home Assistant.
After these manipulations, when pairing the TS004F, it was correctly recognized.


Hey All, Does anyone know if this switch will work with this blueprint connected through a Hue Bridge? I don’t have a Zigbee directly on my hassio host yet.


thanks for this, not sure if i am missing something

but i can’t find switch in entity in blueprint, i click arrow down, i get “no matching entties found”

. although its been added and i can see the device in zigbee. please see attached

Does anyone else have a problem with TS004F that you have to press the button twice before an action will get triggered?

Double clicking won’t do anything. But clicking twice with 1s in between the presses will trigger the action.
Just pressing the button once will work like 10% of the time.

This blueprint has been working flawlessly with multiple devices for a few weeks now!
Thank you so much!

I’ve used it with:

Zemismart 4-gang Scene Switch

Zemismart 2-gang Switch

Switches similar to the first one in 2-gang and 3-gang

(These ones are branded “MOES”.)

Obviously, with 2-gang and 3-gang, you need to ignore the blueprint’s inputs for buttons 3 and/or 4.

There’s however one more switch that this blueprint didn’t accommodate as-is, and it is the 1-gang scene switch:

Contrary to the others, this switch does not send payloads prefixed with the button’s number (eg 1_single, 2_double, etc). Payloads are simply single, double and hold. All I had to do was to add the following lines to the end of the blueprint for it to work

  - conditions: 
    - "{{ command == 'single' }}"
    sequence: !input "button_one_short_press"
  - conditions: 
    - "{{ command == 'double' }}"
    sequence: !input "button_one_double_press"
  - conditions: 
    - "{{ command == 'hold' }}"
    sequence: !input "button_one_long_press"

In case you accept PRs… Support 1-gang switch by davidstosik · Pull Request #1 · AramidX/ha-blueprint · GitHub


Sorry for the very dumb question but I’m sure I’m not the only new guy in home assistant that is facing this problem, therefore I would like to ask you:

What configuarion.yaml are you talking about? The base configuration file of home assistant? The configuration file of zigbee2mtqq?

Thanks in advance, but i can’t put your solution to work!

1 Like


I am trying to add the blueprint you developed and I have the issue with configuration.yaml. Could you be so kind and assist?

I have added below into the configuration.yaml:


In the same folder I have created *.js

HA is showing following below message: Component error: external_converters - Integration ‘external_converters’ not found.

Thanks in advance,

@HeroiAmarelo @kalatos Hello,

External converters are applied to the configuration.yaml of the zigbee2mqtt service. In my case, this is the file “/opt/zigbee2mqtt/data/configuration.yaml”, where “/opt/zigbee2mqtt/” is the path where the zigbee2mqtt is installed.

Thanks! Unfortunately even after that nothing really happens because it doesn’t matter what I do, when I press any button nothing happens on home assistant, there’s no info in the log neither… therefore no matter what blueprints I follow the buttons won’t ever do a thing… It’s strange because the buttons do work if connected to a TUYA ZIGBEE HUB.

I’ve seen other people with this problem. Not sure any of you suffered the same, and if you do, what did you do to solve it? I have 2 buttons.

Thank you very much for the answer. I was trying to put the configuration into the proper file now in the catalog zigbee2mqtt. What are my concerns now:

  1. Visual studio code is telling about missing comma:

Is the configuration properly set? The file TS004F.js is also in catalog zigbee2mqtt

  1. zigbee2mqtt is working with above configuration but I am trying to permit again TS004F I am getting Unsupported device :frowning:

Dear Community,

I am trying to make it work next night and unfortunately without success at all. I followed the instruction of how to add connector into the HA instance as well as set of the tutorials on YouTube bot for me it’ simply does not work like described.

What I did:

  1. I created file TS004F.js in the home path of zigbee2mqtt

  1. I added configuration through the configuration tab on the Supervisor tab:

With the line in the configuration unfortunately Add-On zigbee2mqtt stops working showing error message: “502: Bad Gateway” When I delete line from configuration (external_converters:

  • TS004F.js) Add-on back to normal work.

Here is the piece of log from the zigbee2mqtt module:

Use node --trace-warnings ... to show where the warning was created)
(node:12964) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see Command-line API | Node.js v21.6.2 Documentation). (rejection id: 1)
(node:12964) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
[00:52:11] INFO: Handing over control to Zigbee2mqtt Core …

Can I ask about your support here? Thanks!

I test this switch (TS004F) with Tuya Zigbee Hub, and all 12 functions worked!! Then I tested with deconz/conbeeII and only worked 6 functions, same as zigbee2mqtt. There’s something wrong here, why SmartLife app can access 12 functions and zb2mqtt or deconz can’t…??

I have 04 switchs of this model, and really want this to work as advised…
Can I help to debug, or try anything else ???

have you tried to using zigbee2mqtt edge version? i just got my 4 button switch and it was unsupported on the zigbee2mqtt… once i switched to the edge version… it got supported… now testing the blueprint…

cant get the blueprint to work though… sucks
gonna use node red

Thanks for this, I was about to return the remote. Hopefully it can get finished so its fully functional.