pvvx/ZigbeeTLc

MHO-C401N-z not supported in Z2M?

Closed this issue · 24 comments

I just got my MHO-301 and flashed it to v0120 firmware. I'm using it with the Z2M add on in HA and it is reporting temperature and humidity.

However the Z2M GUI (in which is shows up as a MHO-C401N-z) is reporting it as an unsupported device. Is that to be expected or should I be using an external converter?

Thanks

I used this converter, just changed the name, I'm not 100% it's ok but it works https://github.com/pvvx/ZigbeeTLc/blob/master/z2m/lywsd03mmc-z.js

// Autor: Markus Bodengriller https://github.com/Bodengriller
// requires zigbee2mqtt v1.34+
// external converter for Xiaomi LYWSD03MMC https://github.com/pvvx/ZigbeeTLc
// based on external converter for devbis-Firmware
// https://raw.githubusercontent.com/devbis/z03mmc/master/converters/lywsd03mmc.js

const {
    battery,
    temperature,
    humidity,
    enumLookup,
    binary,
    numeric,
    quirkAddEndpointCluster,
} = require('zigbee-herdsman-converters/lib/modernExtend');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const ota = require('zigbee-herdsman-converters/lib/ota');

const dataType = {
    boolean: 0x10,
    uint8: 0x20,
    uint16: 0x21,
    int8: 0x28,
    int16: 0x29,
    enum8: 0x30,
};

const definition = {
    zigbeeModel: ['MHO-C401N-z'],
    model: 'MHO-C401N',
    vendor: 'MiaMiaoCe',
    description: 'E-Ink Temperature & humidity sensor with custom firmware',
    extend: [
        quirkAddEndpointCluster({
            endpointID: 1,
            outputClusters: [],
            inputClusters: [
                'genPowerCfg',
                'msTemperatureMeasurement',
                'msRelativeHumidity',
                'hvacUserInterfaceCfg',
            ],
        }),
        battery({percentage: true}),
        temperature({reporting: {min: 10, max: 300, change: 10}}),
        humidity({reporting: {min: 10, max: 300, change: 50}}),
        enumLookup({
            name: 'temperature_display_mode',
            lookup: {'celsius': 0, 'fahrenheit': 1},
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0000, type: dataType.enum8},
            description: 'The units of the temperature displayed on the device screen.',
        }),
        binary({
            name: 'show_smiley',
            valueOn: ['SHOW', 0],
            valueOff: ['HIDE', 1],
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0002, type: dataType.enum8},
            description: 'Whether to show a smiley on the device screen.',
        }),
        numeric({
            name: 'temperature_calibration',
            unit: 'ºC',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0100, type: dataType.int8},
            valueMin: -12.7,
            valueMax: 12.7,
            valueStep: 0.1,
            scale: 10,
            description: 'The temperature calibration, in 0.1° steps.',
        }),
        numeric({
            name: 'humidity_calibration',
            unit: '%',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0101, type: dataType.int8},
            valueMin: -12.7,
            valueMax: 12.7,
            valueStep: 0.1,
            scale: 10,
            description: 'The humidity offset is set in 0.1 % steps.',
        }),
        numeric({
            name: 'comfort_temperature_min',
            unit: 'ºC',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0102, type: dataType.int8},
            valueMin: -127.0,
            valueMax: 127.0,
            description: 'Comfort parameters/Temperature minimum, in 1°C steps.',
        }),
        numeric({
            name: 'comfort_temperature_max',
            unit: 'ºC',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0103, type: dataType.int8},
            valueMin: -127.0,
            valueMax: 127.0,
            description: 'Comfort parameters/Temperature maximum, in 1°C steps.',
        }),
        numeric({
            name: 'comfort_humidity_min',
            unit: '%',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0104, type: dataType.uint8},
            valueMin: 0.0,
            valueMax: 100.0,
            description: 'Comfort parameters/Humidity minimum, in 1% steps.',
        }),
        numeric({
            name: 'comfort_humidity_max',
            unit: '%',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0105, type: dataType.uint8},
            valueMin: 0.0,
            valueMax: 100.0,
            description: 'Comfort parameters/Humidity maximum, in 1% steps.',
        }),
    ],
    ota: ota.zigbeeOTA,
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        const bindClusters = ['msTemperatureMeasurement', 'msRelativeHumidity', 'genPowerCfg'];
        await reporting.bind(endpoint, coordinatorEndpoint, bindClusters);
        await reporting.temperature(endpoint, {min: 10, max: 300, change: 10});
        await reporting.humidity(endpoint, {min: 10, max: 300, change: 50});
        await reporting.batteryPercentageRemaining(endpoint);
        try {
            await endpoint.read('hvacThermostat', [0x0010, 0x0011, 0x0102, 0x0103, 0x0104, 0x0105]);
            await endpoint.read('msTemperatureMeasurement', [0x0010]);
            await endpoint.read('msRelativeHumidity', [0x0010]);
        } catch (e) {
            /* backward compatibility */
        }
    },
};

module.exports = definition;

Create the file named mho-c401n-z.js in /config/zigbee2mqtt and fill with data provided.
Go to Z2M settings / External converters
Add mho-c401n-z.js
Press Submit
Restart Z2M

Thanks much!

FW v0.1.2.1 not working with this converter or this one https://github.com/pvvx/ZigbeeTLc/blob/master/z2m/zigbeetlc_v0121.js

Official support for all v0.1.2.1+ ZigbeeTLc devices was merged into Zigbee2MQTT master today:
Koenkk/zigbee-herdsman-converters#7457

Already updated Z2M to v1.37.0-1 and removed external converters, LYWSD03MMC works just fine but MHO-C401N shows as not supported.
Also, I think OTA is broken for both LYWSD03MMC and MHO-C401N, shows update available but then the error:

Update of 'Bath Weather' failed (OTA: Timeout, device did not request any image blocks)

Its looking for MHO-C401N-z or MHO-C401N-bz. Also its LYWSD03MMC-z, LYWSD03MMC is assuming devbis firmware.

MHO-C401N-z and LYWSD03MMC-z with v0.1.2.1 on both.

Probably MHO-C401N-z don't have something enabled in firmware.

Also, I think OTA is broken for both LYWSD03MMC and MHO-C401N, shows update available but then the error:

Update of 'Bath Weather' failed (OTA: Timeout, device did not request any image blocks)

Koenkk/zigbee-herdsman-converters#7457 (comment)

Could be this change?
Can you please check if you can update a device with v1.37.0-1?

pvvx commented

Probably MHO-C401N-z don't have something enabled in firmware.

All the problems Z2M has are from selecting a device by name, and not by digital identifiers of firmware version, device type and manufacturer number.

Zigbee OTA does not use the device name.
https://github.com/pvvx/ZigbeeTLc/blob/master/bin/index.json

Ver 0.1.2.1 has the function of changing the device name. It works without problems with software that supports Zigbee 3.0.

Some Tuya devices have the same names, but the functionality depends on the firmware version. This is not resolved in Z2M.

The ZigbeeTLc firmware will not adapt to the quirks of the Z2M. Firmwares are created for easy use in Home Assistant for users who do not know and do not want to learn programming languages in Z2M.
If You want to use Z2M, then you need to be able to independently program special scripts for any new Zigbee device each time.

I double checked the OTA update issue, I believe its an issue in the latest Z2M version.

Both the pre-existing converter (using legacy methods) as well as the modernExtend implementation time out:

[2024-05-03 07:12:18] info: 	z2m: Updating 'Ambient - Living' to latest firmware
[2024-05-03 07:14:49] error: 	z2m: Update of 'Ambient - Living' failed (OTA: Timeout, device did not request any image blocks)`

This was definitely working before I pulled the newest Z2M.

Note that since this version I have EZSP driver issues as well:

zh:ezsp: Deprecated driver 'ezsp' currently in use, 'ember' will become the officially supported EmberZNet driver in next release. If using Zigbee2MQTT see https://github.com/Koenkk/zigbee2mqtt/discussions/21462

@TeHashX is your deployment on EZSP or different?

On Z2M i have Dongle-P with v20230507 firmware.
On Z2M-Edge I have SkyConnect with v7.4.0.0, tried with ezsp and ember.
On both, I get OTA timeout.

pvvx commented

Have You tried using the index.json file for OTA instead of Koenkk/zigbee-OTA?
There may be problems with access or files in Koenkk/zigbee-OTA...

I don't have Z2M, but I just checked OTA in ZHA:
image
Zigbee OTA in BLE.

Have You tried using the index.json file for OTA instead of Koenkk/zigbee-OTA? There may be problems with access or files in Koenkk/zigbee-OTA...

I don't have Z2M, but I just checked OTA in ZHA: image Zigbee OTA in BLE.

The OTA issue is not important, I use local index file and show update available but after clicking update will timeout.

The biggest issue is with MHO-C401N and firmware v0.1.2.1, device is not supported in Z2M, v1.36.1-1 (with external converter #83 (comment) or v1.37.0-1 with included converter Koenkk/zigbee-herdsman-converters#7457

With v1.2.1 and #83 (comment) converter is kind of working but if I try to change calibration values I get a lot of errors in the log like in the screenshot

Screenshot 2024-05-03 at 14 46 56

BTW, nice feature to change device name (works in Z2M too) but unfortunately it's not usable in Z2M because converters.

Screenshot 2024-05-03 at 15 00 06

That's way I ask if all features are enabled in firmware!

pvvx commented

In version 0.1.2.1, the Poll Control cluster was removed. The reason is that some new versions of programs that work with the coordinator set the Poll Control period to 6 seconds or less.
Less than specified in the "Poll Control min" parameter. This requires the device to wake up at every set polling interval, resulting in unnecessary battery drain.
A few months ago such phenomena were not observed. Something has changed in external programs - someone really wants to drain users’ batteries.
In v0.1.2.1 this interval is strictly specified by the user. (ClusterID: 0x0204 (Thermostat User Interface Configuration) ; Attr: 0x0107, UINT8 (id:0x20), Measurement interval, range: 3..255 seconds. Default 10 seconds.)


When setting default values:

Cluster:
PollControl (Endpoint id: 1, Id: 0x0020)
Attributes:
checkin_interval (id: 0x0000) = 14400 (3600 sec)
checkin_interval_min (id: 0x0004) = 80 (20 sec)
long_poll_interval (id: 0x0001) = 40 (10 sec)
long_poll_interval_min (id: 0x0005) = 40 (10 sec)

But external software sets "long_poll_interval" to 24 (6 sec) (!).


ZigBee Cluster Library Specification
3.16.4.1.6 LongPollIntervalMin Attribute
The Poll Control Server MAY optionally provide its own minimum value for the LongPollInterval to protect against another device setting the value to too short a time resulting in an inadvertent power drain on the device.


Therefore, until the Poll Control settings are corrected, will have to disable this cluster.

PS: Z2M, ZHA, etc. have many bugs and incorrect algorithms. No software meets the advertised Zigbee 3.0 specifications.

Until some more advanced user will create a good converter, we can use this one, it's compatible with firmware v0.1.2.1 but not with earlier versions. I only changed some int8 to int16.

// Autor: Markus Bodengriller https://github.com/Bodengriller
// requires zigbee2mqtt v1.34+
// external converter for Xiaomi MHO-C401N https://github.com/pvvx/ZigbeeTLc
// based on external converter for devbis-Firmware
// https://raw.githubusercontent.com/devbis/z03mmc/master/converters/lywsd03mmc.js
// requires firmware 0.1.2.1+

const {
    battery,
    temperature,
    humidity,
    enumLookup,
    binary,
    numeric,
    quirkAddEndpointCluster,
} = require('zigbee-herdsman-converters/lib/modernExtend');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const ota = require('zigbee-herdsman-converters/lib/ota');

const dataType = {
    boolean: 0x10,
    uint8: 0x20,
    uint16: 0x21,
    int8: 0x28,
    int16: 0x29,
    enum8: 0x30,
};

const definition = {
    zigbeeModel: ['MHO-C401N-z'],
    model: 'MHO-C401N',
    vendor: 'Xiaomi',
    description: 'E-Ink Temperature & humidity sensor with custom firmware',
    extend: [
        quirkAddEndpointCluster({
            endpointID: 1,
            outputClusters: [],
            inputClusters: [
                'genPowerCfg',
                'msTemperatureMeasurement',
                'msRelativeHumidity',
                'hvacUserInterfaceCfg',
            ],
        }),
        battery({percentage: true}),
        temperature({reporting: {min: 10, max: 300, change: 10}, access: 'STATE'}),
        humidity({reporting: {min: 2, max: 300, change: 50}, access: 'STATE'}),
        enumLookup({
            name: 'temperature_display_mode',
            lookup: {'celsius': 0, 'fahrenheit': 1},
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0000, type: dataType.enum8},
            description: 'The units of the temperature displayed on the device screen.',
        }),
        binary({
            name: 'smiley',
            valueOn: ['SHOW', 0],
            valueOff: ['HIDE', 1],
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0002, type: dataType.enum8},
            description: 'Whether to show a smiley on the device screen.',
        }),
        numeric({
            name: 'temperature_calibration',
            unit: 'ºC',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0100, type: dataType.int16},
            valueMin: -12.7,
            valueMax: 12.7,
            valueStep: 0.01,
            scale: 10,
            description: 'The temperature calibration, in 0.01° steps.',
        }),
        numeric({
            name: 'humidity_calibration',
            unit: '%',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0101, type: dataType.int16},
            valueMin: -12.7,
            valueMax: 12.7,
            valueStep: 0.01,
            scale: 10,
            description: 'The humidity offset is set in 0.01 % steps.',
        }),
        numeric({
            name: 'comfort_temperature_min',
            unit: 'ºC',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0102, type: dataType.int16},
            valueMin: -127.0,
            valueMax: 127.0,
            scale: 100,
            description: 'Comfort parameters/Temperature minimum, in 1°C steps.',
        }),
        numeric({
            name: 'comfort_temperature_max',
            unit: 'ºC',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0103, type: dataType.int16},
            valueMin: -127.0,
            valueMax: 127.0,
            scale: 100,
            description: 'Comfort parameters/Temperature maximum, in 1°C steps.',
        }),
        numeric({
            name: 'comfort_humidity_min',
            unit: '%',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0104, type: dataType.uint16},
            valueMin: 0.0,
            valueMax: 100.0,
            scale: 100,
            description: 'Comfort parameters/Humidity minimum, in 1% steps.',
        }),
        numeric({
            name: 'comfort_humidity_max',
            unit: '%',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0105, type: dataType.uint16},
            valueMin: 0.0,
            valueMax: 100.0,
            scale: 100,
            description: 'Comfort parameters/Humidity maximum, in 1% steps.',
        }),
        numeric({
            name: 'measurement_interval',
            unit: 's',
            cluster: 'hvacUserInterfaceCfg',
            attribute: {ID: 0x0107, type: dataType.uint8},
            valueMin: 3,
            valueMax: 255,
            description: 'Measurement interval, default 10 seconds.',
        }),
    ],
    ota: ota.zigbeeOTA,
    configure: async (device, coordinatorEndpoint, logger) => {
        const endpoint = device.getEndpoint(1);
        const bindClusters = ['msTemperatureMeasurement', 'msRelativeHumidity', 'genPowerCfg'];
        await reporting.bind(endpoint, coordinatorEndpoint, bindClusters);
        await reporting.temperature(endpoint, {min: 10, max: 300, change: 10});
        await reporting.humidity(endpoint, {min: 10, max: 300, change: 50});
        await reporting.batteryPercentageRemaining(endpoint);
        try {
            await endpoint.read('hvacThermostat', [0x0010, 0x0011, 0x0102, 0x0103, 0x0104, 0x0105, 0x0107]);
            await endpoint.read('msTemperatureMeasurement', [0x0010]);
            await endpoint.read('msRelativeHumidity', [0x0010]);
        } catch (e) {
            /* backward compatibility */
        }
    },
};

module.exports = definition;
pvvx commented

The only drawback is smiley which is always sad, no matter what values are selected.

'Comfort parameters' in 0.01 °C or % steps.

image

Until some more advanced user will create a good converter, we can use this one, it's compatible with firmware v0.1.2.1 but not with earlier versions. I only changed some int8 to int16.

thanks alot, that worked for me - the MHO-C401N-z is now properly recognized!

Until some more advanced user will create a good converter, we can use this one, it's compatible with firmware v0.1.2.1 but not with earlier versions. I only changed some int8 to int16.

thanks alot, that worked for me - the MHO-C401N-z is now properly recognized!

A pull request is created and will be included in the next Z2M release.

Until some more advanced user will create a good converter, we can use this one, it's compatible with firmware v0.1.2.1 but not with earlier versions. I only changed some int8 to int16.

// Autor: Markus Bodengriller https://github.com/Bodengriller
// requires zigbee2mqtt v1.34+

I am completely new, how can I add the converter in Z2M?

Until some more advanced user will create a good converter, we can use this one, it's compatible with firmware v0.1.2.1 but not with earlier versions. I only changed some int8 to int16.

// Autor: Markus Bodengriller https://github.com/Bodengriller
// requires zigbee2mqtt v1.34+

I am completely new, how can I add the converter in Z2M?

Use Z2M Edge addon or follow this steps:
1 - Create a file named mho-c401n-z.js in /config/zigbee2mqtt and paste the converter code
2 - In Z2M settings / External converters add mho-c401n-z.js and press Submit
3 - Restart Z2M addon
4 - Enjoy!

Use Z2M Edge addon or follow this steps: 1 - Create a file named mho-c401n-z.js in /config/zigbee2mqtt and paste the converter code 2 - In Z2M settings / External converters add mho-c401n-z.js and press Submit 3 - Restart Z2M addon 4 - Enjoy!

Thank you :) works perfectly