Skip to content

[External Converter]: TS110E from _TZ3210_j4tasjju #33247

Description

@NeJo123

Link

https://www.immax.sk/immax-neo-smart-controller-stmievatelny-v9-2-tlacidlovy-zigbee-3-0-p24247/

Database entry

{"id":17,"type":"Router","ieeeAddr":"0xa4c138fa923f4357","nwkAddr":64677,"manufId":4417,"manufName":"_TZ3210_j4tasjju","powerSource":"Mains (single phase)","modelId":"TS110E","epList":[1,2,242],"endpoints":{"1":{"profId":260,"epId":1,"devId":257,"inClusterList":[5,4,6,8,57345,4096,3,0],"outClusterList":[25,10],"clusters":{"genBasic":{"attributes":{"modelId":"TS110E","manufacturerName":"_TZ3210_j4tasjju","powerSource":1,"zclVersion":3,"appVersion":68,"stackVersion":0,"hwVersion":1,"dateCode":""}},"genOnOff":{"attributes":{"32770":0,"61440":0,"onOff":0,"moesStartUpOnOff":1}},"genLevelCtrl":{"attributes":{"61440":392,"64515":10,"64516":1000}}},"binds":[],"configuredReportings":[],"meta":{}},"2":{"profId":260,"epId":2,"devId":257,"inClusterList":[5,4,6,8,57345,5,4],"outClusterList":[],"clusters":{"genOnOff":{"attributes":{"61440":0,"onOff":1}},"genLevelCtrl":{"attributes":{"61440":392,"64515":10,"64516":1000}}},"binds":[],"configuredReportings":[],"meta":{}},"242":{"profId":41440,"epId":242,"devId":97,"inClusterList":[],"outClusterList":[33],"clusters":{},"binds":[],"configuredReportings":[],"meta":{}}},"appVersion":68,"stackVersion":0,"hwVersion":1,"dateCode":"","zclVersion":3,"interviewCompleted":true,"interviewState":"SUCCESSFUL","meta":{"configured":332242049},"lastSeen":1790893781908}

Zigbee2MQTT version

2.14.1 (unknown)

External converter

// Immax 07582L / TS110E / _TZ3210_j4tasjju
// Target: Zigbee2MQTT 2.14.1 (zigbee-herdsman-converters 26.105.0).
// Inspired by the upstream TS110E_2gang_1 definition:
// https://github.com/Koenkk/zigbee-herdsman-converters/blob/v26.105.0/src/devices/tuya.ts
// Device evidence: endpoint 1, genOnOff attribute 0x8002 was read as 1,
// written as ENUM8 0, and read back as 0. Power-cycle testing is still required.

import * as m from 'zigbee-herdsman-converters/lib/modernExtend';
import {presets as e} from 'zigbee-herdsman-converters/lib/exposes';

const startupAttribute = 0x8002;
const startupValues = {off: 0, on: 1, previous: 2};

// A single setting, like the reference definition. Pin it to endpoint 1,
// where support was verified; do not advertise untested endpoint-2 settings.
const startupToZigbee = {
    key: ['power_on_behavior'],
    convertSet: async (_entity, _key, value, meta) => {
        if (!Object.hasOwn(startupValues, value)) {
            throw new Error('power_on_behavior must be off, on or previous');
        }
        const endpoint = meta.device.getEndpoint(1);
        await endpoint.write('genOnOff', {
            [startupAttribute]: {value: startupValues[value], type: 0x30},
        });
        // A read request also verifies the value on the device.
        const response = await endpoint.read('genOnOff', [startupAttribute]);
        const actual = response[startupAttribute] ?? response.moesStartUpOnOff;
        if (actual !== startupValues[value]) {
            throw new Error(`Power-on behavior verification failed: expected ${startupValues[value]}, received ${actual}`);
        }
        return {state: {power_on_behavior: value}};
    },
    convertGet: async (_entity, _key, meta) => {
        await meta.device.getEndpoint(1).read('genOnOff', [startupAttribute]);
    },
};

const startupFromZigbee = {
    cluster: 'genOnOff',
    type: ['attributeReport', 'readResponse'],
    convert: (_model, msg) => {
        if (msg.endpoint.ID !== 1) return;
        const raw = msg.data[startupAttribute] ?? msg.data.moesStartUpOnOff;
        const value = {0: 'off', 1: 'on', 2: 'previous'}[raw];
        if (value !== undefined) return {power_on_behavior: value};
    },
};

export default {
    fingerprint: [{modelID: 'TS110E', manufacturerName: '_TZ3210_j4tasjju'}],
    model: '07582L',
    vendor: 'Immax',
    description: 'NEO V9 two-channel switch',
    extend: [
        m.deviceEndpoints({endpoints: {'1': 1, '2': 2}}),
        m.onOff({
            endpointNames: ['1', '2'],
            powerOnBehavior: false,
            configureReporting: true,
        }),
    ],
    fromZigbee: [startupFromZigbee],
    toZigbee: [startupToZigbee],
    exposes: [e.power_on_behavior(['off', 'on', 'previous'])],
};

What does/doesn't work with the external definition?

Working:

  • Both output channels can be switched ON and OFF independently.
  • The exposes are no longer duplicated.
  • Power-on behavior works through genOnOff attribute 0x8002 on endpoint 1.
  • Attribute 0x8002 was successfully read, written and read back.
  • Power-on behavior mapping is: 0 = off, 1 = on, 2 = previous.

Not working:

  • Dimming could not be confirmed on this device.
  • The TS110E_2gang_1 brightness converter produced no observable physical brightness change.
  • The TS110E_2gang_2 converter was rejected with: UNSUP_COMMAND genLevelCtrl:moveToLevelTuya.
  • A direct standard genLevelCtrl:moveToLevel command completed without an error and Zigbee2MQTT published the requested brightness optimistically, but no physical brightness change occurred.

The submitted converter therefore intentionally exposes only two ON/OFF channels and one power-on behavior setting.

Image

Notes

software_build_id: undefined
date_code: ``
endpoints:

{"1":{"clusters":{"input":["genScenes","genGroups","genOnOff","genLevelCtrl","57345","touchlink","genIdentify","genBasic"],"output":["genOta","genTime"]},"name":"1"},"2":{"clusters":{"input":["genScenes","genGroups","genOnOff","genLevelCtrl","57345","genScenes","genGroups"],"output":[]},"name":"2"},"242":{"clusters":{"input":[],"output":["greenPower"]}}}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions