zigbee2mqtt
zigbee2mqtt copied to clipboard
[New device support]: Namron Zigbee Thermostat 16A White
Link
https://www.namron.com/products/namron-zigbee-termostat-16a-hvit/
Database entry
{"id":4,"type":"Router","ieeeAddr":"0x70ac08fffe6d0475","nwkAddr":49234,"manufId":4098,"manufName":"Namron AS","powerSource":"Mains (single phase)","modelId":"4512758","epList":[1],"endpoints":{"1":{"profId":260,"epId":1,"devId":769,"inClusterList":[0,3,4,5,6,513,516,1794,2820],"outClusterList":[3,10,25],"clusters":{"genOnOff":{"attributes":{"onOff":1}},"genBasic":{"attributes":{"modelId":"4512758","manufacturerName":"Namron AS","appVersion":0,"stackVersion":0,"hwVersion":0}}},"binds":[],"configuredReportings":[],"meta":{}}},"appVersion":0,"stackVersion":0,"hwVersion":0,"dateCode":"20230711","swBuildId":"1.07","zclVersion":8,"interviewCompleted":true,"meta":{},"lastSeen":1702597418555,"defaultSendRequestWhen":"immediate"}
Comments
Completely new to HA and this Thermostat had way too many options. A fellow tester (all creds to him) did some testing with this and he made the code linked below. Make note, for this to work you also need to modify the zigbee2mqtt conf yaml file and add the following after friendly name: homeassistant: climate: action_template: |- {% if value_json.system_mode != 'off' or value_json.power > 0 %} {% set values = {'off': 'idle','idle':'idle','heat':'heating','cool':'cooling'} %} {{ values[value_json.running_mode] }} {% else %} off {% endif %}
External converter
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 constants = require('zigbee-herdsman-converters/lib/constants');
const e = exposes.presets;
const ea = exposes.access;
const utils = require('zigbee-herdsman-converters/lib/utils');
const {
Zcl
} = require('zigbee-herdsman');
const local = {
fz: {
namron_thermostat_new: {
cluster: 'hvacThermostat',
type: ['readResponse', 'attributeReport'],
convert: (model, msg, publish, options, meta) => {
const result = KeyValue = {};
const data = msg.data;
if (data.hasOwnProperty('pIHeatingDemand')) { // regulator_percentage
result['pi_heating_demand'] = data['pIHeatingDemand'];
}
if (data.hasOwnProperty('runningMode')) { // runningMode
const lookup = {0: 'off', 3: 'cool', 4: 'heat', 16: 'idle'};
result['running_mode'] = utils.getFromLookup(data['runningMode'], lookup);
}
if (data.hasOwnProperty(0x8000)) { // windowCheck
result['window_check'] = data[0x8000];
}
if (data.hasOwnProperty(0x8001)) { // frost
result['frost'] = data[0x8001];
}
if (data.hasOwnProperty(0x8002)) { // windowState
result['window_state'] = data[0x8002] ? 'opened' : 'closed';
}
if (data.hasOwnProperty(0x8004)) { // sensorMode
const lookup = { 0: 'a', 1: 'f', 2: 'af', 3: 'a2', 4: 'a2f', 5: 'fp', 6: 'p'};
result['sensor_mode'] = utils.getFromLookup(data[0x8004], lookup);
}
if (data.hasOwnProperty(0x8005)) { // backlight
result['backlight'] = parseFloat(data[0x8005]);
}
if (data.hasOwnProperty(0x8006)) { // fault
const lookup = {0: 'none', 1: 'er1', 2: 'er2', 4: 'er3', 8: 'er4', 16: 'er5', 32: 'er6', 64: 'er7', 128: 'er8'};
result['fault'] = utils.getFromLookup(data[0x8006], lookup);
}
if (data.hasOwnProperty(0x8007)) { // regulator
result['regulator'] = data[0x8007];
}
return result;
},
},
},
tz: {
namron_thermostat_new: {
key: ['pi_heating_demand', 'running_mode', 'window_check', 'frost', 'window_state',
'sensor_mode', 'backlight', 'fault', 'regulator'],
convertSet: async(entity, key, value, meta) => {
if (key === 'pi_heating_demand') {
const payload = {'pIHeatingDemand': {value: parseInt(value), type: Zcl.DataType.int8}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'running_mode') {
const lookup = {'off': 0, 'cool': 3, 'heat': 4, 'idle': 16};
const payload = {'runningMode': {value: utils.getFromLookup(value, lookup), type: Zcl.DataType.enum8}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'window_check') {
const lookup = {'disabled': false, 'enabled': true};
const payload = {0x8000: {value: utils.getFromLookup(value, lookup), type: Zcl.DataType.boolean}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'frost') {
const lookup = {'disabled': false, 'enabled': true};
const payload = {0x8001: {value: utils.getFromLookup(value, lookup), type: Zcl.DataType.boolean}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'window_state') {
const lookup = {'closed': false, 'opened': true};
const payload = {0x8002: {value: utils.getFromLookup(value, lookup), type: Zcl.DataType.boolean}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'sensor_mode') {
const lookup = {'a': 0, 'f': 1, 'af': 2, 'a2': 3, 'a2f': 4, 'fp': 5, 'p': 6};
const payload = {0x8004: {value: utils.getFromLookup(value, lookup), type: Zcl.DataType.enum8}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'backlight') {
const payload = {0x8005: {value: value, type: Zcl.DataType.uint8}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'fault') {
const lookup = {'none': 0, 'er1': 1, 'er2': 2, 'er3': 3, 'er4': 4, 'er5': 5, 'er6': 6, 'er7': 7, 'er8': 8};
const payload = {0x8006: {value: utils.getFromLookup(value, lookup), type: Zcl.DataType.enum8}};
await entity.write('hvacThermostat', payload);
}
else if (key === 'regulator') {
const payload = {0x8007: {value: value, type: Zcl.DataType.uint8}};
await entity.write('hvacThermostat', payload);
}
},
convertGet: async (entity, key, meta) => {
switch (key) {
case 'pi_heating_demand':
await entity.read('hvacThermostat', ['pIHeatingDemand']);
break;
case 'running_mode':
await entity.read('hvacThermostat', ['runningMode']);
break;
case 'window_check':
await entity.read('hvacThermostat', [0x8000]);
break;
case 'frost':
await entity.read('hvacThermostat', [0x8001]);
break;
case 'window_state':
await entity.read('hvacThermostat', [0x8002]);
break;
case 'sensor_mode':
await entity.read('hvacThermostat', [0x8004]);
break;
case 'backlight':
await entity.read('hvacThermostat', [0x8005]);
break;
case 'fault':
await entity.read('hvacThermostat', [0x8006]);
break;
case 'regulator':
await entity.read('hvacThermostat', [0x8007]);
break;
default: // Unknown key
throw new Error(`Unhandled key local.tz.namron_thermostat_new.convertGet ${key}`);
}
},
},
}
};
const definition = {
zigbeeModel: ['4512758'],
model: '4512758',
vendor: 'Namron',
description: 'Namron thermostat and power regulator',
fromZigbee: [fz.thermostat, fz.metering, fz.electrical_measurement,
fz.namron_hvac_user_interface, fz.namron_thermostat, local.fz.namron_thermostat_new],
toZigbee: [tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint, tz.thermostat_occupancy,
tz.thermostat_local_temperature_calibration, tz.thermostat_local_temperature, tz.thermostat_outdoor_temperature,
tz.thermostat_system_mode, tz.thermostat_control_sequence_of_operation,
tz.namron_thermostat_child_lock, tz.namron_thermostat, local.tz.namron_thermostat_new],
exposes: [
e.climate()
.withSetpoint('occupied_heating_setpoint', 5, 40, 0.5)
.withLocalTemperature()
.withLocalTemperatureCalibration(-3, 3, 0.1)
.withSystemMode(['off', 'cool', 'heat'])
.withRunningState(['idle', 'cool', 'heat'], ea.STATE),
e.power(), e.current(),
e.binary('child_lock', ea.ALL, 'LOCK', 'UNLOCK')
.withDescription('Enables/disables physical input on the device'),
e.binary('window_check', ea.ALL, 'enabled', 'disabled'),
e.binary('window_state', ea.STATE_GET, 'opened', 'closed'),
e.binary('frost', ea.ALL, 'enabled', 'disabled'),
e.enum('sensor_mode', ea.ALL, ['a', 'f', 'af', 'a2', 'a2f', 'fp', 'p']),
e.enum('fault', ea.STATE_GET, ['none', 'er1', 'er2', 'er3', 'er4', 'er5', 'er6', 'er7', 'er8']),
e.numeric('backlight', ea.ALL)
.withValueMin(0).withValueMax(100).withValueStep(5)
.withUnit('%'),
e.numeric('regulator', ea.ALL)
.withValueMin(0).withValueMax(30).withValueStep(1)
.withUnit('minutes'),
e.numeric('pi_heating_demand', ea.ALL)
.withValueMin(0).withValueMax(100).withValueStep(10)
.withUnit('%'),
],
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint = device.getEndpoint(1);
const binds = [
'seMetering', 'haElectricalMeasurement', 'hvacThermostat', 'hvacUserInterfaceCfg',
];
await reporting.bind(endpoint, coordinatorEndpoint, binds);
// Metering
await endpoint.read('haElectricalMeasurement', ['acCurrentMultiplier', 'acCurrentDivisor', 'acPowerMultiplier', 'acPowerDivisor']);
await reporting.readMeteringMultiplierDivisor(endpoint);
await reporting.rmsCurrent(endpoint, {min: 5, change: 10});
await reporting.activePower(endpoint, {min: 5, change: 15});
await reporting.thermostatTemperature(endpoint, {min: 0, change: 50});
await reporting.thermostatOccupiedHeatingSetpoint(endpoint, {min: 5});
await reporting.thermostatKeypadLockMode(endpoint, {min: 5});
await reporting.thermostatSystemMode(endpoint, {min: 5});
await reporting.thermostatPIHeatingDemand(endpoint, {min: 5});
await reporting.thermostatRunningMode(endpoint);
const options = {};
// Custom
await endpoint.configureReporting('hvacThermostat', [{ // windowCheck
attribute: {ID: 0x8000, type: 16},
minimumReportInterval: 5,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: null}],
options);
await endpoint.configureReporting('hvacThermostat', [{ // frost
attribute: {ID: 0x8001, type: 16},
minimumReportInterval: 5,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: null}],
options);
await endpoint.configureReporting('hvacThermostat', [{ // windowState
attribute: {ID: 0x8002, type: 16},
minimumReportInterval: 0,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: null}],
options);
await endpoint.configureReporting('hvacThermostat', [{ // sensorMode
attribute: {ID: 0x8004, type: 48},
minimumReportInterval: 5,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: null}],
options);
await endpoint.configureReporting('hvacThermostat', [{ // backlight
attribute: {ID: 0x8005, type: 32},
minimumReportInterval: 5,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: null}],
options);
await endpoint.configureReporting('hvacThermostat', [{ // fault
attribute: {ID: 0x8006, type: 24},
minimumReportInterval: 0,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: null}],
options);
await endpoint.configureReporting('hvacThermostat', [{ // regulator
attribute: {ID: 0x8007, type: 32},
minimumReportInterval: 0,
maximumReportInterval: constants.repInterval.HOUR,
reportableChange: null}],
options);
await endpoint.read('hvacThermostat', ['systemMode', 'runningMode', 'occupiedHeatingSetpoint']);
await endpoint.read('hvacThermostat', [0x8000, 0x8001, 0x8002, 0x8004, 0x8005, 0x8006, 0x8007]);
},
};
module.exports = definition;
Supported color modes
No response
Color temperature range
No response