Skip to content

Instantly share code, notes, and snippets.

@monosoul
Last active October 14, 2025 16:03
Show Gist options
  • Save monosoul/b2e07598d96eee3eaf9c07fb00576cbd to your computer and use it in GitHub Desktop.
Save monosoul/b2e07598d96eee3eaf9c07fb00576cbd to your computer and use it in GitHub Desktop.
Schneider Electric MEG5779 converter for Zigbee2MQTT
const { deviceAddCustomCluster, numeric } = require('zigbee-herdsman-converters/lib/modernExtend');
const Zcl = require('zigbee-herdsman').Zcl;
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 utils = require('zigbee-herdsman-converters/lib/utils');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const e = exposes.presets;
const ea = exposes.access;
const manufacturerOptions = { manufacturerCode: Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC };
const megExtend = {
hvacUserInterfaceCfgCluster: () =>
deviceAddCustomCluster('hvacUserInterfaceCfg', {
ID: Zcl.Clusters.hvacUserInterfaceCfg.ID,
attributes: {
displayBrightnessActive: {
ID: 0xe000,
type: Zcl.DataType.UINT8,
manufacturerCode: Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC,
},
displayBrightnessInactive: {
ID: 0xe001,
type: Zcl.DataType.UINT8,
manufacturerCode: Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC,
},
displayActiveTimeout: {
ID: 0xe002,
type: Zcl.DataType.UINT16,
manufacturerCode: Zcl.ManufacturerCode.SCHNEIDER_ELECTRIC,
},
},
commands: {},
commandsResponse: {},
}),
displayBrightnessActive: () =>
numeric({
name: 'display_brightness_active',
cluster: 'hvacUserInterfaceCfg',
attribute: 'displayBrightnessActive',
description: 'Sets brightness of the temperature display during active state',
entityCategory: 'config',
unit: '%',
valueMin: 0,
valueMax: 100,
valueStep: 1,
zigbeeCommandOptions: manufacturerOptions,
}),
displayBrightnessInactive: () =>
numeric({
name: 'display_brightness_inactive',
cluster: 'hvacUserInterfaceCfg',
attribute: 'displayBrightnessInactive',
description: 'Sets brightness of the temperature display during inactive state',
entityCategory: 'config',
unit: '%',
valueMin: 0,
valueMax: 100,
valueStep: 1,
zigbeeCommandOptions: manufacturerOptions,
}),
displayActiveTimeout: () =>
numeric({
name: 'display_active_timeout',
cluster: 'hvacUserInterfaceCfg',
attribute: 'displayActiveTimeout',
description: 'Sets timeout of the temperature display active state',
entityCategory: 'config',
unit: 'seconds',
valueMin: 5,
valueMax: 600,
valueStep: 5,
zigbeeCommandOptions: manufacturerOptions,
}),
};
async function safeRead(endpoint, cluster, attributes, logger) {
try {
await endpoint.read(cluster, attributes);
} catch (err) {
console.log(`[meg5779] safeRead: failed reading ${cluster} ${JSON.stringify(attributes)}: ${err.message}`);
}
}
const definition = {
zigbeeModel: ['MEG5779'],
model: 'MEG5779',
vendor: 'Schneider Electric',
description: 'Merten Connected Room Temperature Controller',
fromZigbee: [
fz.stelpro_thermostat,
fz.metering,
fz.schneider_pilot_mode,
fz.wiser_device_info,
fz.hvac_user_interface,
fz.temperature
],
toZigbee: [
tz.thermostat_occupied_heating_setpoint,
tz.thermostat_system_mode,
tz.thermostat_running_state,
tz.thermostat_local_temperature,
tz.thermostat_temperature_display_mode,
tz.schneider_thermostat_keypad_lockout,
tz.schneider_pilot_mode,
tz.thermostat_min_heat_setpoint_limit,
tz.thermostat_max_heat_setpoint_limit,
],
exposes: [
e.binary("keypad_lockout", ea.STATE_SET, "lock1", "unlock").withDescription("Enables/disables physical input on the device"),
e.enum('temperature_display_mode', ea.ALL, ['celsius', 'fahrenheit'])
.withDescription('The temperature format displayed on the thermostat screen'),
e.climate()
.withLocalTemperature()
.withSetpoint('occupied_heating_setpoint', 4, 40, 0.5)
.withSystemMode(['off', 'heat'])
.withRunningState(['idle', 'heat'])
.withPiHeatingDemand(),
e
.numeric("min_heat_setpoint_limit", ea.ALL)
.withUnit("°C")
.withDescription("Minimum Heating set point limit")
.withValueMin(4)
.withValueMax(40)
.withValueStep(0.5),
e
.numeric("max_heat_setpoint_limit", ea.ALL)
.withUnit("°C")
.withDescription("Maximum Heating set point limit")
.withValueMin(4)
.withValueMax(40)
.withValueStep(0.5),
e
.numeric("local_temperature", ea.STATE)
.withUnit("°C")
.withDescription("Local temperature measured by the thermostat"),
],
extend: [
megExtend.hvacUserInterfaceCfgCluster(),
megExtend.displayBrightnessActive(),
megExtend.displayBrightnessInactive(),
megExtend.displayActiveTimeout(),
],
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint1 = device.getEndpoint(1);
const endpoint2 = device.getEndpoint(2);
await reporting.bind(endpoint1, coordinatorEndpoint, ['hvacThermostat', 'hvacUserInterfaceCfg']);
await reporting.thermostatPIHeatingDemand(endpoint1);
await reporting.thermostatOccupiedHeatingSetpoint(endpoint1);
await endpoint1.read("hvacThermostat", ["localTemp"]);
await endpoint1.read("hvacThermostat", ["absMinHeatSetpointLimit"]);
await endpoint1.read("hvacThermostat", ["absMaxHeatSetpointLimit"]);
await endpoint1.read("hvacThermostat", ["minHeatSetpointLimit"]);
await endpoint1.read("hvacThermostat", ["maxHeatSetpointLimit"]);
await endpoint1.read("hvacThermostat", ["occupiedHeatingSetpoint"]);
await endpoint1.read("hvacThermostat", ["systemMode"]);
await safeRead(endpoint1, "hvacThermostat", ["runningState"], logger);
await reporting.bind(endpoint2, coordinatorEndpoint, ['msTemperatureMeasurement']);
await reporting.temperature(endpoint2);
await endpoint1.read('hvacUserInterfaceCfg',['keypadLockout','tempDisplayMode']);
await endpoint1.read('hvacUserInterfaceCfg',['displayBrightnessActive']);
await endpoint1.read('hvacUserInterfaceCfg',['displayBrightnessInactive']);
await endpoint1.read('hvacUserInterfaceCfg',['displayActiveTimeout']);
},
};
module.exports = definition;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment