diff --git a/.homeycompose/capabilities/summer_winter.json b/.homeycompose/capabilities/summer_winter.json new file mode 100644 index 0000000..4de903a --- /dev/null +++ b/.homeycompose/capabilities/summer_winter.json @@ -0,0 +1,9 @@ +{ + "title": { + "en": "Season" + }, + "type": "string", + "getable": true, + "setable": false, + "uiComponent": "sensor" +} diff --git a/.homeycompose/capabilities/valve_cooling.json b/.homeycompose/capabilities/valve_cooling.json new file mode 100644 index 0000000..5664a57 --- /dev/null +++ b/.homeycompose/capabilities/valve_cooling.json @@ -0,0 +1,10 @@ +{ + "title": { + "en": "Cooling" + }, + "type": "boolean", + "getable": true, + "setable": false, + "uiComponent": "sensor", + "uiQuickAction": false +} diff --git a/.homeycompose/capabilities/valve_heating.json b/.homeycompose/capabilities/valve_heating.json new file mode 100644 index 0000000..9dec3e9 --- /dev/null +++ b/.homeycompose/capabilities/valve_heating.json @@ -0,0 +1,10 @@ +{ + "title": { + "en": "Heating" + }, + "type": "boolean", + "getable": true, + "setable": false, + "uiComponent": "sensor", + "uiQuickAction": false +} diff --git a/.homeycompose/capabilities/vimar_thermostat_mode.json b/.homeycompose/capabilities/vimar_thermostat_mode.json new file mode 100644 index 0000000..47718e8 --- /dev/null +++ b/.homeycompose/capabilities/vimar_thermostat_mode.json @@ -0,0 +1,36 @@ + +{ + "type": "enum", + "title": { + "en": "Mode" + }, + "values": [ + { + "id": "1", + "title": { + "en": "Comfort" + } + }, + { + "id": "2", + "title": { + "en": "Standby" + } + }, + { + "id": "3", + "title": { + "en": "Economy" + } + }, + { + "id": "4", + "title": { + "en": "Protect" + } + } + ], + "getable": true, + "setable": true, + "uiComponent": "picker" + } \ No newline at end of file diff --git a/.homeycompose/drivers/pair/select_groupaddresses/index.html b/.homeycompose/drivers/pair/select_groupaddresses/index.html index 7ca418e..f42152d 100644 --- a/.homeycompose/drivers/pair/select_groupaddresses/index.html +++ b/.homeycompose/drivers/pair/select_groupaddresses/index.html @@ -1,571 +1,657 @@
-

-

- - - - - - - - - -

- +

+

+ + + + + + + + + + +

+
diff --git a/app.json b/app.json index fc1450f..5e71027 100644 --- a/app.json +++ b/app.json @@ -283,6 +283,39 @@ } ], "id": "trigger_to_scene" + }, + { + "id": "set-window-switch", + "title": { + "en": "Set Window Switch" + }, + "args": [ + { + "type": "device", + "name": "device", + "filter": "driver_id=vimar_thermostat_02952.b" + }, + { + "type": "checkbox", + "name": "open", + "title": { + "en": "Window open" + } + } + ] + }, + { + "id": "reset_to_basesetpoint", + "title": { + "en": "Reset to Base Setpoint" + }, + "args": [ + { + "type": "device", + "name": "device", + "filter": "driver_id=vimar_thermostat_02952.b" + } + ] } ] }, @@ -1843,6 +1876,201 @@ ] } ] + }, + { + "images": { + "large": "/drivers/vimar_thermostat_02952.b/assets/images/large.png", + "small": "/drivers/vimar_thermostat_02952.b/assets/images/small.png" + }, + "platforms": [ + "local" + ], + "connectivity": [ + "lan" + ], + "pair": [ + { + "id": "select_interface", + "navigation": { + "next": "select_groupaddresses" + } + }, + { + "id": "parse_knxproj", + "navigation": { + "next": "select_groupaddresses", + "prev": "select_groupaddresses" + } + }, + { + "id": "select_groupaddresses", + "options": { + "devicetype": "vimar_thermostat_02952.b" + }, + "navigation": { + "prev": "select_interface" + } + } + ], + "id": "vimar_thermostat_02952.b", + "name": { + "en": "Vimar Thermostat", + "nl": "Vimar Thermostaat" + }, + "class": "thermostat", + "capabilities": [ + "target_temperature", + "measure_temperature", + "vimar_thermostat_mode", + "valve_heating", + "valve_cooling", + "summer_winter" + ], + "settings": [ + { + "type": "group", + "label": { + "en": "KNX groupaddress", + "nl": "KNX groepadressen" + }, + "children": [ + { + "id": "ga_temperature_target", + "type": "text", + "label": { + "en": "Setpoint Shift address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_temperature_measure", + "type": "text", + "label": { + "en": "Actual Temperature address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_temperature_target_actual", + "type": "text", + "label": { + "en": "Actual setpoint address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_thermostat_mode", + "type": "text", + "label": { + "en": "Thermostat mode address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_thermostat_mode_state", + "type": "text", + "label": { + "en": "Thermostat mode state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_summerwinter_state", + "type": "text", + "label": { + "en": "Summer/Winter state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_window_switch", + "type": "text", + "label": { + "en": "Window Switch address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_valve_heating_state", + "type": "text", + "label": { + "en": "Heating Valve state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_valve_cooling_state", + "type": "text", + "label": { + "en": "Cooling Valve state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + } + ] + }, + { + "type": "group", + "label": { + "en": "Network settings", + "nl": "Netwerk instellingen" + }, + "children": [ + { + "id": "macAddress", + "type": "text", + "label": { + "en": "Interface MAC address", + "nl": "Interface MAC adres" + }, + "value": "", + "hint": { + "en": "MAC address of the required KNX IP interface", + "nl": "MAC adres van de KNX IP interface" + } + }, + { + "id": "ipAddress", + "type": "text", + "label": { + "en": "Interface IP address", + "nl": "Interface IP adres" + }, + "value": "", + "hint": { + "en": "IP address of the required KNX IP interface", + "nl": "IP adres van de KNX IP interface" + } + } + ] + } + ] } ], "capabilities": { @@ -1874,6 +2102,70 @@ "setable": true, "uiComponent": "button", "uiQuickAction": true + }, + "summer_winter": { + "title": { + "en": "Season" + }, + "type": "string", + "getable": true, + "setable": false, + "uiComponent": "sensor" + }, + "valve_cooling": { + "title": { + "en": "Cooling" + }, + "type": "boolean", + "getable": true, + "setable": false, + "uiComponent": "sensor", + "uiQuickAction": false + }, + "valve_heating": { + "title": { + "en": "Heating" + }, + "type": "boolean", + "getable": true, + "setable": false, + "uiComponent": "sensor", + "uiQuickAction": false + }, + "vimar_thermostat_mode": { + "type": "enum", + "title": { + "en": "Mode" + }, + "values": [ + { + "id": "1", + "title": { + "en": "Comfort" + } + }, + { + "id": "2", + "title": { + "en": "Standby" + } + }, + { + "id": "3", + "title": { + "en": "Economy" + } + }, + { + "id": "4", + "title": { + "en": "Protect" + } + } + ], + "getable": true, + "setable": true, + "uiComponent": "picker" } } } \ No newline at end of file diff --git a/drivers/vimar_thermostat_02952.b/assets/images/large.png b/drivers/vimar_thermostat_02952.b/assets/images/large.png new file mode 100644 index 0000000..7442800 Binary files /dev/null and b/drivers/vimar_thermostat_02952.b/assets/images/large.png differ diff --git a/drivers/vimar_thermostat_02952.b/assets/images/small.png b/drivers/vimar_thermostat_02952.b/assets/images/small.png new file mode 100644 index 0000000..8867fc6 Binary files /dev/null and b/drivers/vimar_thermostat_02952.b/assets/images/small.png differ diff --git a/drivers/vimar_thermostat_02952.b/device.js b/drivers/vimar_thermostat_02952.b/device.js new file mode 100644 index 0000000..cb978cc --- /dev/null +++ b/drivers/vimar_thermostat_02952.b/device.js @@ -0,0 +1,226 @@ +'use strict'; + +const KNXGenericDevice = require('../../lib/GenericKNXDevice'); +const DatapointTypeParser = require('../../lib/DatapointTypeParser'); + +// +// I am hating the way to do the shift calculation +// either we have to get all 8 combinations, and then keep track of summer/winter and mode, or +// keep track of actual setpoint and shift, and calculate the new shift based on the calculated base setpoint +// +class VimarThermostat02952BDevice extends KNXGenericDevice { + + onInit() { + super.onInit(); + + // Initialize variables + this.currentSetpoint = undefined; + this.currentSetpointShift = undefined; + this.currentSetpointBase = undefined; + + this.registerCapabilityListener('target_temperature', this.onCapabilityTargetTemperature.bind(this)); + this.registerCapabilityListener('vimar_thermostat_mode', this.onCapabilityMode.bind(this)); + + // Maybe this can be placed better during pairing? + if (!this.settings.ga_summerwinter_state && this.hasCapability('summer_winter')) { + this.removeCapability('summer_winter'); + this.knxInterface.removeKNXConnectionListener(this.settings.ga_summerwinter_state, this.KNXEventHandler); + } + if (!this.settings.ga_valve_heating_state && this.hasCapability('valve_heating')) { + this.removeCapability('valve_heating'); + this.knxInterface.removeKNXConnectionListener(this.settings.ga_valve_heating_state, this.KNXEventHandler); + } + if (!this.settings.ga_valve_cooling_state && this.hasCapability('valve_cooling')) { + this.removeCapability('valve_cooling'); + this.knxInterface.removeKNXConnectionListener(this.settings.ga_valve_cooling_state, this.KNXEventHandler); + } + } + + async onKNXEvent(groupaddress, data) { + super.onKNXEvent(groupaddress, data); + + try { + if (groupaddress === this.settings.ga_temperature_target) { + this.currentSetpointShift = DatapointTypeParser.dpt9(data); + setTimeout(() => { + this.currentSetpointShift = undefined; + }, 500); + } + if (groupaddress === this.settings.ga_temperature_target_actual) { + this.currentSetpoint = DatapointTypeParser.dpt9(data); + await this.setCapabilityValue('target_temperature', this.currentSetpoint); + setTimeout(() => { + this.currentSetpoint = undefined; + }, 500); + } + + if (this.currentSetpoint !== undefined && this.currentSetpointShift !== undefined) { + this.currentSetpointBase = this.currentSetpoint - this.currentSetpointShift; + } + + if (groupaddress === this.settings.ga_temperature_measure) { + await this.setCapabilityValue('measure_temperature', DatapointTypeParser.dpt9(data)); + } + if (groupaddress === this.settings.ga_valve_heating_state) { + await this.setCapabilityValue('valve_heating', DatapointTypeParser.onoff(data)); + } + if (groupaddress === this.settings.ga_valve_cooling_state) { + await this.setCapabilityValue('valve_cooling', DatapointTypeParser.onoff(data)); + } + if (groupaddress === this.settings.ga_summerwinter_state) { + await this.setCapabilityValue('summer_winter', DatapointTypeParser.onoff(data) ? 'Winter' : 'Summer'); + } + if (groupaddress === this.settings.ga_thermostat_mode_state) { + if (this.settings.ga_temperature_measure) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_measure); + } + if (this.settings.ga_temperature_target_actual) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_target_actual); + } + + await this.setCapabilityValue('vimar_thermostat_mode', `${DatapointTypeParser.dpt17(data)}`); + } + } catch (error) { + this.log('Error in onKNXEvent', error); + } + } + + addKNXEventListeners(settings) { + super.addKNXEventListeners(settings); + + // The ga_temperature_target and ga_temperature_measure are added by super + this.knxInterface.addKNXEventListener(settings.ga_temperature_target_actual, this.KNXEventHandler); + this.knxInterface.addKNXEventListener(settings.ga_thermostat_mode_state, this.KNXEventHandler); + this.knxInterface.addKNXEventListener(settings.ga_summerwinter_state, this.KNXEventHandler); + this.knxInterface.addKNXEventListener(settings.ga_valve_heating_state, this.KNXEventHandler); + this.knxInterface.addKNXEventListener(settings.ga_valve_cooling_state, this.KNXEventHandler); + } + + async onKNXConnection(connectionStatus) { + super.onKNXConnection(connectionStatus); + + try { + if (connectionStatus === 'connected') { + // Reading the groupaddress will trigger a event on the bus. + // This will be catched by onKNXEvent, hence the return value is not used. + if (this.settings.ga_temperature_target) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_target); + } + if (this.settings.ga_temperature_measure) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_measure); + } + if (this.settings.ga_temperature_target_actual) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_target_actual); + } + if (this.settings.ga_thermostat_mode_state) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_thermostat_mode_state); + } + if (this.settings.ga_summerwinter_state) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_summerwinter_state); + } + if (this.settings.ga_valve_heating_state) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_valve_heating_state); + } + if (this.settings.ga_valve_cooling_state) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_valve_cooling_state); + } + } + } catch (knxerror) { + this.log('Failed to read', knxerror); + } + } + + async onCapabilityMode(value, opts) { + if (this.knxInterface && this.settings.ga_thermostat_mode) { + try { + await this.knxInterface.writeKNXGroupAddress(this.settings.ga_thermostat_mode, value, 'DPT17'); + } catch (knxerror) { + this.log(knxerror); + throw new Error(this.homey.__('errors.mode_set_failed')); + } + + // Wait a bit before reading the temperature, + // as the mode change will trigger a new setpoint + // the knx lib has an issue when sending read requests too fast after a write, + // it will actually send them before + await (new Promise((resolve) => setTimeout(resolve, 400))); + + if (this.settings.ga_temperature_measure) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_measure); + } + if (this.settings.ga_temperature_target_actual) { + await this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_target_actual); + } + } + } + + onCapabilityTargetTemperature(value, opts) { + this.getMeasuredTemperature(); + if (this.knxInterface && this.settings.ga_temperature_target) { + if (this.currentSetpointBase === undefined) { + throw new Error('Actual setpoint and shift are unknown'); + } + + const newShift = value - this.currentSetpointBase; + return this.knxInterface.writeKNXGroupAddress(this.settings.ga_temperature_target, newShift, 'DPT9.1') + .catch((knxerror) => { + this.log(knxerror); + throw new Error(this.homey.__('errors.temperature_set_failed')); + }); + } + return null; + } + + getMeasuredTemperature() { + if (this.settings.ga_temperature_measure) { + this.knxInterface.readKNXGroupAddress(this.settings.ga_temperature_measure) + .catch((knxerror) => { + this.log(knxerror); + throw new Error(this.homey.__('errors.temperature_get_failed')); + }); + } + } + + /** + * onSettings is called when the user updates the device's settings. + * @param {object} event the onSettings event data + * @param {object} event.oldSettings The old settings object + * @param {object} event.newSettings The new settings object + * @param {string[]} event.changedKeys An array of keys changed since the previous version + * @returns {Promise} return a custom message that will be displayed + */ + async onSettings({ oldSettings, newSettings, changedKeys }) { + await super.onSettings({ oldSettings, newSettings, changedKeys }); + + if (!newSettings.ga_summerwinter_state && this.hasCapability('summer_winter')) { + this.removeCapability('summer_winter'); + if (oldSettings.ga_summerwinter_state) { + this.knxInterface.removeKNXConnectionListener(oldSettings.ga_summerwinter_state, this.KNXEventHandler); + } + } else if (newSettings.ga_summerwinter_state && !this.hasCapability('summer_winter')) { + this.addCapability('summer_winter'); + this.knxInterface.addKNXEventListener(newSettings.ga_summerwinter_state, this.KNXEventHandler); + } + if (!newSettings.ga_valve_heating_state && this.hasCapability('valve_heating')) { + this.removeCapability('valve_heating'); + if (oldSettings.ga_valve_heating_state) { + this.knxInterface.removeKNXConnectionListener(oldSettings.ga_valve_heating_state, this.KNXEventHandler); + } + } else if (newSettings.ga_valve_heating_state && !this.hasCapability('valve_heating')) { + this.addCapability('valve_heating'); + this.knxInterface.addKNXEventListener(newSettings.ga_valve_heating_state, this.KNXEventHandler); + } + if (!newSettings.ga_valve_cooling_state && this.hasCapability('valve_cooling')) { + this.removeCapability('valve_cooling'); + if (oldSettings.ga_valve_cooling_state) { + this.knxInterface.removeKNXConnectionListener(oldSettings.ga_valve_cooling_state, this.KNXEventHandler); + } + } else if (newSettings.ga_valve_cooling_state && !this.hasCapability('valve_cooling')) { + this.addCapability('valve_cooling'); + this.knxInterface.addKNXEventListener(newSettings.ga_valve_cooling_state, this.KNXEventHandler); + } + } + +} + +module.exports = VimarThermostat02952BDevice; diff --git a/drivers/vimar_thermostat_02952.b/driver.compose.json b/drivers/vimar_thermostat_02952.b/driver.compose.json new file mode 100644 index 0000000..517b1e3 --- /dev/null +++ b/drivers/vimar_thermostat_02952.b/driver.compose.json @@ -0,0 +1,189 @@ +{ + "$extends" :["knx_driver"], + "id": "vimar_thermostat_02952.b", + "name": { + "en": "Vimar Thermostat", + "nl": "Vimar Thermostaat" + }, + "class": "thermostat", + "capabilities": [ + "target_temperature", + "measure_temperature", + "vimar_thermostat_mode", + "valve_heating", + "valve_cooling", + "summer_winter" + ], + "pair" : [ + { + "id": "select_interface", + "$template": "select_interface", + "navigation": { + "next": "select_groupaddresses" + } + }, + { + "id": "parse_knxproj", + "$template": "parse_knxproj", + "navigation": { + "next": "select_groupaddresses", + "prev": "select_groupaddresses" + } + }, + { + "id": "select_groupaddresses", + "$template": "select_groupaddresses", + "options": { + "devicetype": "vimar_thermostat_02952.b" + }, + "navigation": { + "prev": "select_interface" + } + } + ], + "settings": [ + { + "type": "group", + "label": { + "en": "KNX groupaddress", + "nl": "KNX groepadressen" + }, + "children": [ + { + "id": "ga_temperature_target", + "type": "text", + "label": { + "en": "Setpoint Shift address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_temperature_measure", + "type": "text", + "label": { + "en": "Actual Temperature address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_temperature_target_actual", + "type": "text", + "label": { + "en": "Actual setpoint address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_thermostat_mode", + "type": "text", + "label": { + "en": "Thermostat mode address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_thermostat_mode_state", + "type": "text", + "label": { + "en": "Thermostat mode state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_summerwinter_state", + "type": "text", + "label": { + "en": "Summer/Winter state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_window_switch", + "type": "text", + "label": { + "en": "Window Switch address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_valve_heating_state", + "type": "text", + "label": { + "en": "Heating Valve state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + }, + { + "id": "ga_valve_cooling_state", + "type": "text", + "label": { + "en": "Cooling Valve state address" + }, + "value": "", + "hint": { + "en": "Enter groupaddress" + } + } + ] + }, + { + "type": "group", + "label": { + "en": "Network settings", + "nl": "Netwerk instellingen" + }, + "children": [ + { + "id": "macAddress", + "type": "text", + "label": { + "en": "Interface MAC address", + "nl": "Interface MAC adres" + }, + "value" : "", + "hint": { + "en": "MAC address of the required KNX IP interface", + "nl": "MAC adres van de KNX IP interface" + } + }, + { + "id": "ipAddress", + "type": "text", + "label": { + "en": "Interface IP address", + "nl": "Interface IP adres" + }, + "value" : "", + "hint": { + "en": "IP address of the required KNX IP interface", + "nl": "IP adres van de KNX IP interface" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/drivers/vimar_thermostat_02952.b/driver.flow.compose.json b/drivers/vimar_thermostat_02952.b/driver.flow.compose.json new file mode 100644 index 0000000..3061070 --- /dev/null +++ b/drivers/vimar_thermostat_02952.b/driver.flow.compose.json @@ -0,0 +1,25 @@ +{ + "actions": [ + { + "id": "set-window-switch", + "title": { + "en": "Set Window Switch" + }, + "args": [ + { + "type": "checkbox", + "name": "open", + "title": { + "en": "Window open" + } + } + ] + }, + { + "id": "reset_to_basesetpoint", + "title": { + "en": "Reset to Base Setpoint" + } + } + ] +} \ No newline at end of file diff --git a/drivers/vimar_thermostat_02952.b/driver.js b/drivers/vimar_thermostat_02952.b/driver.js new file mode 100644 index 0000000..bc8e8ff --- /dev/null +++ b/drivers/vimar_thermostat_02952.b/driver.js @@ -0,0 +1,29 @@ +'use strict'; + +const KNXGenericDriver = require('../../lib/GenericKNXDriver'); + +class VimarThermostat02952BDriver extends KNXGenericDriver { + + onInit() { + super.onInit(); + + this.homey.flow.getActionCard('set-window-switch').registerRunListener(async (args, state) => { + return args.device.knxInterface.writeKNXGroupAddress(args.device.settings.ga_window_switch, args.open, 'DPT1') + .catch((knxerror) => { + this.log(knxerror); + throw new Error(this.homey.__('errors.window_switch_failed')); + }); + }); + + this.homey.flow.getActionCard('reset_to_basesetpoint').registerRunListener(async (args, state) => { + return args.device.knxInterface.writeKNXGroupAddress(args.device.settings.ga_temperature_target, 0, 'DPT9.1') + .catch((knxerror) => { + this.log(knxerror); + throw new Error(this.homey.__('errors.reset_to_basesetpoint_failed')); + }); + }); + } + +} + +module.exports = VimarThermostat02952BDriver; diff --git a/locales/en.json b/locales/en.json index 7e1a881..d49f5a3 100644 --- a/locales/en.json +++ b/locales/en.json @@ -45,7 +45,14 @@ }, "thermostat": { "target": "Target temperature address", - "measure": "Temperature measurement address" + "actualtarget": "Target temperature status address", + "measure": "Temperature measurement address", + "mode": "Thermostat mode address", + "mode_state": "Thermostat mode status address", + "summer_winter": "Summer/Winter address", + "window_switch": "Window switch address", + "valve_heating": "Heating valve status address", + "valve_cooling": "Cooling valve status address" }, "rgb": { "red_toggle_action": "Toggle address red channel", diff --git a/locales/nl.json b/locales/nl.json index 7da72c1..0335671 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -45,7 +45,14 @@ }, "thermostat": { "target": "Doel temperatuur adres", - "measure": "Ruimtetemperatuur adres" + "actualtarget": "Doel temperatuur status adres", + "measure": "Ruimtetemperatuur adres", + "mode": "Thermostaat modus adres", + "mode_state": "Thermostaat modus status adres", + "summer_winter": "Zomer/Winter adres", + "window_switch": "Raamschakelaar adres", + "valve_heating": "Verwarmingsklep status adres", + "valve_cooling": "Koelklep status adres" }, "rgb": { "red_toggle_action": "Schakel adres rood kanaal",