Skip to content

Commit

Permalink
Add CCTFR6400 (Koenkk#2558)
Browse files Browse the repository at this point in the history
* Add CCTFR6700

* Add schneider_pilot_mode

* Add Schneider Electric CCTFR6700

* File already exists

* Add schneider_pilot_mode to CCTFR6700

* Update toZigbee.js

* Added fromZigbee for schneider_pilot_mode

* Udpated toZigbee for schneider_pilot_mode

* Added fromZigbee pilot mode and fixed expose for energy/power

* Removed configureKey

* Update schneider_electric.js

* Added measured temperature SET for CCTFR6700

* Added measured temperature SET for CCTFR6700

Requires 'report' capability merged into herdsman.

* Added push/pop to global store

Used for deferred writes

* Added toZigbee for CCTFR6400

* Added CCTFR6400 thermostat

* Added from zigbee for CCTFR6400

Also forced local_temperature othewise Home assistant is not happy

* Improved CCTFR6400 and 6700

* Added UI temperature update of CCTFR6400

* Updated using ClusterAttributeValue

* Updated using ClusterAttributeValue

* Updated using ClusterAttributeValue

* Removed legacy support for schneider_thermostat_system_mode

* Removed temperature expose

Temperature is exposed as local_temperature only

* CCTFR6400 tempreature exposed as local_temperature

* Used sendWhenActive for keypadLockout

* Used sendWhenActive for keypadLockout and added defaults

* Fixed schneider_ui_action convert

* Simplified schneider_thermostat_control_sequence_of_operation

* Reverted Push/pop value

* Update toZigbee.js

* Update toZigbee.js

* Update schneider_electric.js

* Update fromZigbee.js

* Update schneider_electric.js

* Update schneider_electric.js

* Fix'

Co-authored-by: Koen Kanters <koenkanters94@gmail.com>
  • Loading branch information
H3buss and Koenkk authored May 22, 2021
1 parent f0a05c5 commit d0fb06c
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 3 deletions.
48 changes: 48 additions & 0 deletions converters/fromZigbee.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const tuya = require('../lib/tuya');
const globalStore = require('../lib/store');
const constants = require('../lib/constants');
const libColor = require('../lib/color');
const utils = require('../lib/utils');

const converters = {
// #region Generic/recommended converters
Expand Down Expand Up @@ -5570,6 +5571,53 @@ const converters = {
return result;
},
},
schneider_ui_action: {
cluster: 'wiserDeviceInfo',
type: 'attributeReport',
convert: (model, msg, publish, options, meta) => {
if (hasAlreadyProcessedMessage(msg)) return;

const data = msg.data['deviceInfo'].split(',');
if (data[0] === 'UI' && data[1]) {
const result = {action: utils.toSnakeCase(data[1])};

let screenAwake = globalStore.getValue(msg.endpoint, 'screenAwake');
screenAwake = screenAwake != undefined ? screenAwake : false;
let keypadLocked = msg.endpoint.getClusterAttributeValue('hvacUserInterfaceCfg', 'keypadLockout');
keypadLocked = keypadLocked != undefined ? keypadLocked != 0 : false;

// Emulate UI temperature update
if (data[1] === 'ScreenWake') {
globalStore.putValue(msg.endpoint, 'screenAwake', true);
} else if (data[1] === 'ScreenSleep') {
globalStore.putValue(msg.endpoint, 'screenAwake', false);
} else if (screenAwake && !keypadLocked) {
let occupiedHeatingSetpoint = msg.endpoint.getClusterAttributeValue('hvacThermostat', 'occupiedHeatingSetpoint');
occupiedHeatingSetpoint = occupiedHeatingSetpoint != null ? occupiedHeatingSetpoint : 400;

if (data[1] === 'ButtonPressMinusDown') {
occupiedHeatingSetpoint -= 50;
} else if (data[1] === 'ButtonPressPlusDown') {
occupiedHeatingSetpoint += 50;
}

msg.endpoint.saveClusterAttributeKeyValue('hvacThermostat', {occupiedHeatingSetpoint: occupiedHeatingSetpoint});
result.occupied_heating_setpoint = occupiedHeatingSetpoint/100;
}

return result;
}
},
},
schneider_temperature: {
cluster: 'msTemperatureMeasurement',
type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
const temperature = parseFloat(msg.data['measuredValue']) / 100.0;
const property = postfixWithEndpointName('local_temperature', msg, model);
return {[property]: calibrateAndPrecisionRoundOptions(temperature, options, 'temperature')};
},
},

// #endregion

Expand Down
46 changes: 46 additions & 0 deletions converters/toZigbee.js
Original file line number Diff line number Diff line change
Expand Up @@ -4886,6 +4886,52 @@ const converters = {
await entity.read('schneiderSpecificPilotMode', ['pilotMode'], {manufacturerCode: 0x105e});
},
},
schneider_temperature_measured_value: {
key: ['temperature_measured_value'],
convertSet: async (entity, key, value, meta) => {
await entity.report('msTemperatureMeasurement', {'measuredValue': Math.round(value*100)});
},
},
schneider_thermostat_system_mode: {
key: ['system_mode'],
convertSet: async (entity, key, value, meta) => {
const systemMode = utils.getKey(constants.thermostatSystemModes, value, undefined, Number);
entity.saveClusterAttributeKeyValue('hvacThermostat', {systemMode: systemMode});
return {state: {system_mode: value}};
},
},
schneider_thermostat_occupied_heating_setpoint: {
key: ['occupied_heating_setpoint'],
convertSet: async (entity, key, value, meta) => {
const occupiedHeatingSetpoint = (Math.round((value * 2).toFixed(1)) / 2).toFixed(1) * 100;
entity.saveClusterAttributeKeyValue('hvacThermostat', {occupiedHeatingSetpoint: occupiedHeatingSetpoint});
return {state: {occupied_heating_setpoint: value}};
},
},
schneider_thermostat_control_sequence_of_operation: {
key: ['control_sequence_of_operation'],
convertSet: async (entity, key, value, meta) => {
const val = utils.getKey(constants.thermostatControlSequenceOfOperations, value, value, Number);
entity.saveClusterAttributeKeyValue('hvacThermostat', {ctrlSeqeOfOper: val});
return {state: {control_sequence_of_operation: value}};
},
},
schneider_thermostat_pi_heating_demand: {
key: ['pi_heating_demand'],
convertSet: async (entity, key, value, meta) => {
entity.saveClusterAttributeKeyValue('hvacThermostat', {pIHeatingDemand: value});
return {state: {pi_heating_demand: value}};
},
},
schneider_thermostat_keypad_lockout: {
key: ['keypad_lockout'],
convertSet: async (entity, key, value, meta) => {
const keypadLockout = utils.getKey(constants.keypadLockoutMode, value, value, Number);
entity.write('hvacUserInterfaceCfg', {keypadLockout}, {sendWhenActive: true});
entity.saveClusterAttributeKeyValue('hvacUserInterfaceCfg', {keypadLockout});
return {state: {keypad_lockout: value}};
},
},
ZNCJMB14LM: {
key: ['theme',
'standby_enabled',
Expand Down
34 changes: 31 additions & 3 deletions devices/schneider_electric.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,10 +197,12 @@ module.exports = [
vendor: 'Schneider Electric',
description: 'Heating thermostat',
fromZigbee: [fz.thermostat, fz.metering, fz.schneider_pilot_mode],
toZigbee: [tz.thermostat_system_mode, tz.thermostat_running_state, tz.thermostat_local_temperature,
tz.thermostat_occupied_heating_setpoint, tz.thermostat_control_sequence_of_operation, tz.schneider_pilot_mode],
toZigbee: [tz.schneider_temperature_measured_value, tz.thermostat_system_mode, tz.thermostat_running_state,
tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_control_sequence_of_operation,
tz.schneider_pilot_mode, tz.schneider_temperature_measured_value],
exposes: [e.power(), e.energy(),
exposes.enum('schneider_pilot_mode', ea.ALL, ['relay', 'pilot']).withDescription('Controls piloting mode'),
exposes.enum('schneider_pilot_mode', ea.ALL, ['contactor', 'pilot']).withDescription('Controls piloting mode'),
exposes.numeric('temperature_measured_value', ea.SET),
exposes.climate().withSetpoint('occupied_heating_setpoint', 4, 30, 0.5).withLocalTemperature()
.withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand()],
configure: async (device, coordinatorEndpoint, logger) => {
Expand All @@ -214,4 +216,30 @@ module.exports = [
await reporting.currentSummDelivered(endpoint2, {min: 0, max: 60, change: 1});
},
},
{
fingerprint: [{modelID: 'Thermostat', manufacturerName: 'Schneider Electric'}],
model: 'CCTFR6400',
vendor: 'Schneider Electric',
description: 'Temperature/Humidity measurement with thermostat interface',
fromZigbee: [fz.battery, fz.schneider_temperature, fz.humidity, fz.thermostat, fz.schneider_ui_action],
toZigbee: [tz.schneider_thermostat_system_mode, tz.schneider_thermostat_occupied_heating_setpoint,
tz.schneider_thermostat_control_sequence_of_operation, tz.schneider_thermostat_pi_heating_demand,
tz.schneider_thermostat_keypad_lockout],
exposes: [e.keypad_lockout().withAccess(ea.STATE_SET), e.humidity(), e.battery(), e.battery_voltage(),
e.action(['screen_sleep', 'screen_wake', 'button_press_plus_down', 'button_press_center_down', 'button_press_minus_down']),
exposes.climate().withSetpoint('occupied_heating_setpoint', 4, 30, 0.5, ea.SET).withLocalTemperature(ea.STATE)
.withPiHeatingDemand(ea.SET)],
meta: {battery: {dontDividePercentage: true}},
configure: async (device, coordinatorEndpoint, logger) => {
const endpoint1 = device.getEndpoint(1);
await reporting.bind(endpoint1, coordinatorEndpoint,
['genPowerCfg', 'hvacThermostat', 'msTemperatureMeasurement', 'msRelativeHumidity']);
await reporting.temperature(endpoint1);
await reporting.humidity(endpoint1);
await reporting.batteryPercentageRemaining(endpoint1);
endpoint1.saveClusterAttributeKeyValue('genBasic', {zclVersion: 3});
endpoint1.saveClusterAttributeKeyValue('hvacThermostat', {schneiderWiserSpecific: 1, systemMode: 4, ctrlSeqeOfOper: 2});
endpoint1.saveClusterAttributeKeyValue('hvacUserInterfaceCfg', {keypadLockout: 0});
},
},
];

0 comments on commit d0fb06c

Please sign in to comment.