diff --git a/device-types.js b/device-types.js index fdbd27f..a01efc2 100644 --- a/device-types.js +++ b/device-types.js @@ -710,6 +710,29 @@ const types = { }, decorator: defaultDecorator, }, + THERMOSTAT_2: { + defaultState: { + temperature: 0, + scale: 'CELSIUS', + lowerSetpoint: 0, + upperSetpoint: 0, + lowerSetpointScale: 'CELSIUS', + upperSetpointScale: 'CELSIUS', + thermostatMode: 'OFF', + powerState: 'OFF', + }, + validators: { + temperature: temperatureValue, + scale: temperatureScale, + thermostatMode, + lowerSetpoint: wrapValidator(temperatureValue, 'lowerSetpoint'), + upperSetpoint: wrapValidator(temperatureValue, 'upperSetpoint'), + lowerSetpointScale: wrapValidator(temperatureScale, 'lowerSetpointScale'), + upperSetpointScale: wrapValidator(temperatureScale, 'upperSetpointScale'), + powerState, + }, + decorator: defaultDecorator, + }, } //---HELPERS--- diff --git a/directives.js b/directives.js index 35a56e0..624e314 100644 --- a/directives.js +++ b/directives.js @@ -172,11 +172,26 @@ const directives = { SelectInput: (request, _currentState) => ({ input: request.directive.payload.input, }), - SetTargetTemperature: (request, _currentState) => ({ - targetTemperature: request.directive.payload.targetSetpoint.value, - targetScale: request.directive.payload.targetSetpoint.scale, - powerState: 'ON', - }), + SetTargetTemperature: (request, currentState) => { + const newState = { + powerState: 'ON', + } + + if (currentState.template === 'THERMOSTAT') { + newState['targetTemperature'] = + request.directive.payload.targetSetpoint.value + newState['targetScale'] = request.directive.payload.targetSetpoint.scale + } else if (currentState.template === 'THERMOSTAT_2') { + newState['lowerSetpoint'] = request.directive.payload.lowerSetpoint.value + newState['lowerSetpointScale'] = + request.directive.payload.lowerSetpoint.scale + newState['upperSetpoint'] = request.directive.payload.upperSetpoint.value + newState['upperSetpointScale'] = + request.directive.payload.upperSetpoint.scale + } + + return newState + }, SetThermostatMode: (request, _currentState) => { const newState = { thermostatMode: request.directive.payload.thermostatMode.value, @@ -418,6 +433,24 @@ function buildPropertiesFromState(state) { ) } + if (state.hasOwnProperty('lowerSetpoint')) { + properties.push( + makeProperty('Alexa.ThermostatController', 'lowerSetpoint', { + value: state.lowerSetpoint, + scale: state.lowerSetpointScale, + }) + ) + } + + if (state.hasOwnProperty('upperSetpoint')) { + properties.push( + makeProperty('Alexa.ThermostatController', 'upperSetpoint', { + value: state.upperSetpoint, + scale: state.upperSetpointScale, + }) + ) + } + if (state.hasOwnProperty('temperature')) { properties.push( makeProperty('Alexa.TemperatureSensor', 'temperature', { diff --git a/img/examples.png b/img/examples.png new file mode 100644 index 0000000..eecfa5d Binary files /dev/null and b/img/examples.png differ diff --git a/package.json b/package.json index d3e4497..ace158c 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/csuermann/node-red-contrib-virtual-smart-home" + "url": "git+https://github.com/csuermann/node-red-contrib-virtual-smart-home.git" }, "keywords": [ "Alexa", diff --git a/readme.md b/readme.md index 8d6acfc..696ed24 100644 --- a/readme.md +++ b/readme.md @@ -1,23 +1,10 @@ # Virtual Smart Home (VSH) -A Node-RED node that represents a virtual device which can be controlled via +A Node-RED node that represents a virtual smart home device which can be controlled via Amazon Alexa. Requires the '_virtual smart home_' skill to be enabled for your Amazon account. -## Availability - -The _virtual smart home_ skill is available in the Amazon skill stores in the following locales: - -- [English (AU)](https://www.amazon.com.au/dp/B08JV9RT7H) -- [English (CA)](https://www.amazon.ca/dp/B08JV9RT7H) -- [English (GB)](https://www.amazon.co.uk/dp/B08JV9RT7H) -- [English (IN)](https://www.amazon.in/dp/B08JV9RT7H) -- [English (US)](https://www.amazon.com/dp/B08JV9RT7H) -- [French (FR)](https://www.amazon.fr/dp/B08JV9RT7H) -- [German (DE)](https://www.amazon.de/dp/B08JV9RT7H) -- [Italian (IT)](https://www.amazon.it/dp/B08JV9RT7H) -- [Portuguese (BR)](https://www.amazon.com.br/dp/B08JV9RT7H) -- [Spanish (ES)](https://www.amazon.es/dp/B08JV9RT7H) +![Examples](./img/examples.png) ## Highlights @@ -27,16 +14,18 @@ The _virtual smart home_ skill is available in the Amazon skill stores in the fo - Contact Sensor - Dimmable Light Bulb - Dimmer Switch + - Doorbell Event Source - Entertainment Device - Fan - Garage Door Opener (en-US locale only) - Lock - Motion Sensor - Plug - - Switch - Scene + - Switch - Temperature Sensor - - Thermostat + - Thermostat (Single-setpoint) + - Thermostat (Dual-setpoint) - no separate account needed. Just link your existing Amazon account. - new virtual devices can simply be dragged onto the Node-RED canvas and will proactively be discovered by Alexa. No need to ask Alexa to discover devices. @@ -77,6 +66,21 @@ like when the node gets invoked via Alexa. In this case `payload.source` is set Please ensure that your setup does not send too many messages to Alexa. Otherwise you risk getting your account blocked. +## Availability + +The _virtual smart home_ skill is available in the Amazon skill stores in the following locales: + +- [English (AU)](https://www.amazon.com.au/dp/B08JV9RT7H) +- [English (CA)](https://www.amazon.ca/dp/B08JV9RT7H) +- [English (GB)](https://www.amazon.co.uk/dp/B08JV9RT7H) +- [English (IN)](https://www.amazon.in/dp/B08JV9RT7H) +- [English (US)](https://www.amazon.com/dp/B08JV9RT7H) +- [French (FR)](https://www.amazon.fr/dp/B08JV9RT7H) +- [German (DE)](https://www.amazon.de/dp/B08JV9RT7H) +- [Italian (IT)](https://www.amazon.it/dp/B08JV9RT7H) +- [Portuguese (BR)](https://www.amazon.com.br/dp/B08JV9RT7H) +- [Spanish (ES)](https://www.amazon.es/dp/B08JV9RT7H) + ## Setup Instructions ### In the Alexa app diff --git a/virtual-device.html b/virtual-device.html index 55231b9..8a5733a 100644 --- a/virtual-device.html +++ b/virtual-device.html @@ -182,7 +182,8 @@ - + + @@ -699,13 +700,18 @@

Temperature Sensor

-

Thermostat

+

Thermostat (Single-setpoint)

payload.powerState string
'ON' or 'OFF'
+
+ payload.temperature + float +
+
Measured temperature
payload.scale string @@ -714,6 +720,11 @@

Thermostat

Scale / unit of temperature. Allowed values: 'CELSIUS', 'FAHRENHEIT', 'KELVIN' +
+ payload.targetTemperature + float +
+
Target temperature
payload.targetScale string @@ -723,15 +734,57 @@

Thermostat

'FAHRENHEIT', 'KELVIN'
- payload.targetTemperature + payload.thermostatMode + string +
+
'AUTO', 'HEAT', 'COOL', 'ECO', 'OFF'
+
+

Thermostat (Dual-setpoint)

+
+
+ payload.powerState + string +
+
'ON' or 'OFF'
+
+ payload.lowerSetpoint float
-
Target temperature
+
Lower setpoint temperature
+
+ payload.lowerSetpointScale + string +
+
+ Scale / unit of lowerSetpoint. Allowed values: 'CELSIUS', 'FAHRENHEIT', + 'KELVIN' +
+
+ payload.upperSetpoint + float +
+
Upper setpoint temperature
+
+ payload.upperSetpointScale + string +
+
+ Scale / unit of upperSetpoint. Allowed values: 'CELSIUS', 'FAHRENHEIT', + 'KELVIN' +
payload.temperature float
Measured temperature
+
+ payload.scale + string +
+
+ Scale / unit of temperature. Allowed values: 'CELSIUS', 'FAHRENHEIT', + 'KELVIN' +
payload.thermostatMode string