diff --git a/docs/USAGE.md b/docs/USAGE.md
index 0f44d6be..1e133a58 100644
--- a/docs/USAGE.md
+++ b/docs/USAGE.md
@@ -66,17 +66,17 @@ Dimmer { ga="Light" }
Color { ga="Light" [ colorTemperatureRange="2000,9000" ] }
```
-#### `Light as Group with separate Color and Brightness`
+#### `Light as Group with separate Controls`
| | |
|---|---|
| **Device Type** | [Light](https://developers.google.com/assistant/smarthome/guides/light) |
| **Supported Traits** | [OnOff](https://developers.google.com/assistant/smarthome/traits/onoff), [ColorSetting](https://developers.google.com/assistant/smarthome/traits/colorsetting), [Brightness](https://developers.google.com/assistant/smarthome/traits/brightness) |
-| **Supported Items** | Group as `light` with the following members: (optional) Number or Dimmer as `lightBrightness`, (optional) Number or Dimmer as `lightColorTemperature`, (optional) Color as `lightColor`, (optional) Switch as `lightPower` |
-| **Configuration** | (optional) `useKelvin=true/false`
(optional) `checkState=true/false`
(optional) `colorTemperatureRange="minK,maxK"`
_Hint: if you want to use `lightColorTemperature` you either need to set `useKelvin=true` or `colorTemperatureRange`_ |
+| **Supported Items** | Group as `SpecialColorLight` with the following members: (optional) Number or Dimmer as `lightBrightness`, (optional) Number or Dimmer as `lightColorTemperature`, (optional) Color as `lightColor`, (optional) Switch as `lightPower` |
+| **Configuration** | (optional) `colorUnit=percent/kelvin/mired`
(optional) `checkState=true/false`
(optional) `colorTemperatureRange="minK,maxK"`
_Hint: if you want to use `lightColorTemperature` you either need to set `colorUnit` to `kelvin` or `mired` or define a `colorTemperatureRange` as `colorUnit` defaults to `percent`_ |
```shell
-Group lightGroup { ga="Light" [ useKelvin=true, colorTemperatureRange="2000,9000" ] }
+Group lightGroup { ga="SpecialColorLight" [ colorUnit="kelvin", colorTemperatureRange="2000,9000" ] }
Switch powerItem (lightGroup) { ga="lightPower" }
Dimmer brightnessItem (lightGroup) { ga="lightBrightness" }
Color colorItem (lightGroup) { ga="lightColor" }
diff --git a/functions/commands/colorabsolutetemperature.js b/functions/commands/colorabsolutetemperature.js
index 93298381..45476642 100644
--- a/functions/commands/colorabsolutetemperature.js
+++ b/functions/commands/colorabsolutetemperature.js
@@ -1,7 +1,6 @@
const DefaultCommand = require('./default.js');
const SpecialColorLight = require('../devices/specialcolorlight.js');
-const rgb2hsv = require('../utilities.js').rgb2hsv;
-const kelvin2rgb = require('../utilities.js').kelvin2rgb;
+const { convertMired, convertRgbToHsv, convertKelvinToRgb } = require('../utilities.js');
class ColorAbsoluteTemperature extends DefaultCommand {
static get type() {
@@ -35,9 +34,13 @@ class ColorAbsoluteTemperature extends DefaultCommand {
static convertParamsToValue(params, item, device) {
if (this.getDeviceType(device) === 'SpecialColorLight') {
try {
- if (SpecialColorLight.useKelvin(item)) {
+ const colorUnit = SpecialColorLight.getColorUnit(item);
+ if (colorUnit === 'kelvin') {
return params.color.temperature.toString();
}
+ if (colorUnit === 'mired') {
+ return convertMired(params.color.temperature).toString();
+ }
const { temperatureMinK, temperatureMaxK } = SpecialColorLight.getAttributes(item).colorTemperatureRange;
return (
100 -
@@ -47,7 +50,7 @@ class ColorAbsoluteTemperature extends DefaultCommand {
return '0';
}
}
- const hsv = rgb2hsv(kelvin2rgb(params.color.temperature));
+ const hsv = convertRgbToHsv(convertKelvinToRgb(params.color.temperature));
const hsvArray = item.state.split(',').map((val) => Number(val));
return [Math.round(hsv.hue * 100) / 100, Math.round(hsv.saturation * 1000) / 10, hsvArray[2]].join(',');
}
diff --git a/functions/commands/thermostattemperaturesetpoint.js b/functions/commands/thermostattemperaturesetpoint.js
index 7fba7407..ffff3131 100644
--- a/functions/commands/thermostattemperaturesetpoint.js
+++ b/functions/commands/thermostattemperaturesetpoint.js
@@ -1,6 +1,6 @@
const DefaultCommand = require('./default.js');
const Thermostat = require('../devices/thermostat.js');
-const convertToFahrenheit = require('../utilities.js').convertToFahrenheit;
+const convertCelsiusToFahrenheit = require('../utilities.js').convertCelsiusToFahrenheit;
class ThermostatTemperatureSetpoint extends DefaultCommand {
static get type() {
@@ -26,7 +26,7 @@ class ThermostatTemperatureSetpoint extends DefaultCommand {
static convertParamsToValue(params, item) {
let value = params.thermostatTemperatureSetpoint;
if (Thermostat.useFahrenheit(item)) {
- value = convertToFahrenheit(value);
+ value = convertCelsiusToFahrenheit(value);
}
return value.toString();
}
diff --git a/functions/commands/thermostattemperaturesetpointhigh.js b/functions/commands/thermostattemperaturesetpointhigh.js
index ec659bda..610563e8 100644
--- a/functions/commands/thermostattemperaturesetpointhigh.js
+++ b/functions/commands/thermostattemperaturesetpointhigh.js
@@ -1,6 +1,6 @@
const DefaultCommand = require('./default.js');
const Thermostat = require('../devices/thermostat.js');
-const convertToFahrenheit = require('../utilities.js').convertToFahrenheit;
+const convertCelsiusToFahrenheit = require('../utilities.js').convertCelsiusToFahrenheit;
class ThermostatTemperatureSetpointHigh extends DefaultCommand {
static get type() {
@@ -28,7 +28,7 @@ class ThermostatTemperatureSetpointHigh extends DefaultCommand {
static convertParamsToValue(params, item) {
let value = params.thermostatTemperatureSetpointHigh;
if (Thermostat.useFahrenheit(item)) {
- value = convertToFahrenheit(value);
+ value = convertCelsiusToFahrenheit(value);
}
return value.toString();
}
diff --git a/functions/commands/thermostattemperaturesetpointlow.js b/functions/commands/thermostattemperaturesetpointlow.js
index 1327fa9f..cb36a7a7 100644
--- a/functions/commands/thermostattemperaturesetpointlow.js
+++ b/functions/commands/thermostattemperaturesetpointlow.js
@@ -1,6 +1,6 @@
const DefaultCommand = require('./default.js');
const Thermostat = require('../devices/thermostat.js');
-const convertToFahrenheit = require('../utilities.js').convertToFahrenheit;
+const convertCelsiusToFahrenheit = require('../utilities.js').convertCelsiusToFahrenheit;
class ThermostatTemperatureSetpointLow extends DefaultCommand {
static get type() {
@@ -26,7 +26,7 @@ class ThermostatTemperatureSetpointLow extends DefaultCommand {
static convertParamsToValue(params, item) {
let value = params.thermostatTemperatureSetpointLow;
if (Thermostat.useFahrenheit(item)) {
- value = convertToFahrenheit(value);
+ value = convertCelsiusToFahrenheit(value);
}
return value.toString();
}
diff --git a/functions/devices/specialcolorlight.js b/functions/devices/specialcolorlight.js
index 24d48246..c765244e 100644
--- a/functions/devices/specialcolorlight.js
+++ b/functions/devices/specialcolorlight.js
@@ -1,4 +1,5 @@
const DefaultDevice = require('./default.js');
+const convertMired = require('../utilities.js').convertMired;
class SpecialColorLight extends DefaultDevice {
static get type() {
@@ -9,13 +10,17 @@ class SpecialColorLight extends DefaultDevice {
return ['action.devices.traits.OnOff', 'action.devices.traits.Brightness', 'action.devices.traits.ColorSetting'];
}
+ static isCompatible(item = {}) {
+ return item.metadata && item.metadata.ga && item.metadata.ga.value.toLowerCase() == 'specialcolorlight';
+ }
+
static matchesItemType(item) {
const members = this.getMembers(item);
return (
item.type === 'Group' &&
Object.keys(members).length > 1 &&
(!('lightColorTemperature' in members) ||
- this.useKelvin(item) ||
+ this.getColorUnit(item) !== 'percent' ||
!!this.getAttributes(item).colorTemperatureRange)
);
}
@@ -30,9 +35,10 @@ class SpecialColorLight extends DefaultDevice {
if ('colorTemperatureRange' in config) {
const [min, max] = config.colorTemperatureRange.split(',').map((s) => Number(s.trim()));
if (!isNaN(min) && !isNaN(max)) {
+ const colorUnit = this.getColorUnit(item);
attributes.colorTemperatureRange = {
- temperatureMinK: min,
- temperatureMaxK: max
+ temperatureMinK: colorUnit === 'mired' ? convertMired(max) : min,
+ temperatureMaxK: colorUnit === 'mired' ? convertMired(min) : max
};
}
}
@@ -74,10 +80,15 @@ class SpecialColorLight extends DefaultDevice {
break;
}
try {
- if (this.useKelvin(item)) {
+ const colorUnit = this.getColorUnit(item);
+ if (colorUnit === 'kelvin') {
state.color = {
temperatureK: Number(members[member].state)
};
+ } else if (colorUnit === 'mired') {
+ state.color = {
+ temperatureK: convertMired(Number(members[member].state))
+ };
} else {
const { temperatureMinK, temperatureMaxK } = this.getAttributes(item).colorTemperatureRange;
state.color = {
@@ -111,8 +122,9 @@ class SpecialColorLight extends DefaultDevice {
return members;
}
- static useKelvin(item) {
- return this.getConfig(item).useKelvin === true;
+ static getColorUnit(item) {
+ const colorUnit = this.getConfig(item).colorUnit || 'percent';
+ return colorUnit.toLowerCase();
}
}
diff --git a/functions/devices/temperaturesensor.js b/functions/devices/temperaturesensor.js
index 7e58d911..84e9f467 100644
--- a/functions/devices/temperaturesensor.js
+++ b/functions/devices/temperaturesensor.js
@@ -1,5 +1,5 @@
const DefaultDevice = require('./default.js');
-const convertToCelsius = require('../utilities.js').convertToCelsius;
+const convertFahrenheitToCelsius = require('../utilities.js').convertFahrenheitToCelsius;
class TemperatureSensor extends DefaultDevice {
static get type() {
@@ -28,7 +28,7 @@ class TemperatureSensor extends DefaultDevice {
static getState(item) {
let state = Number(parseFloat(item.state).toFixed(1));
if (this.getConfig(item).useFahrenheit === true) {
- state = convertToCelsius(state);
+ state = convertFahrenheitToCelsius(state);
}
return {
temperatureSetpointCelsius: state,
diff --git a/functions/devices/thermostat.js b/functions/devices/thermostat.js
index a70931e1..a9aba5df 100644
--- a/functions/devices/thermostat.js
+++ b/functions/devices/thermostat.js
@@ -1,5 +1,5 @@
const DefaultDevice = require('./default.js');
-const convertToCelsius = require('../utilities.js').convertToCelsius;
+const convertFahrenheitToCelsius = require('../utilities.js').convertFahrenheitToCelsius;
class Thermostat extends DefaultDevice {
static get type() {
@@ -50,7 +50,7 @@ class Thermostat extends DefaultDevice {
} else {
state[member] = Number(parseFloat(members[member].state).toFixed(1));
if (member.indexOf('Temperature') > 0 && this.useFahrenheit(item)) {
- state[member] = convertToCelsius(state[member]);
+ state[member] = convertFahrenheitToCelsius(state[member]);
}
}
}
diff --git a/functions/utilities.js b/functions/utilities.js
index 5b981312..2f439ccb 100644
--- a/functions/utilities.js
+++ b/functions/utilities.js
@@ -23,22 +23,22 @@ module.exports = {
* @param {number} value temperature in Fahrenheit
* @returns {number} temperature value converted to Celsius
*/
- convertToCelsius: (value) => {
+ convertFahrenheitToCelsius: (value) => {
return Number((((value - 32) * 5) / 9).toFixed(1));
},
/**
* @param {number} value temperature in Celsius
* @returns {number} temperature value converted to Fahrenheit
*/
- convertToFahrenheit: (value) => {
+ convertCelsiusToFahrenheit: (value) => {
return Math.round((value * 9) / 5 + 32);
},
/**
- * @param {number} kelvin color temperature as Kelvin
+ * @param {number} value color temperature as Kelvin
* @returns {object} color temperature value converted to RGB
*/
- kelvin2rgb: (kelvin) => {
- const temp = kelvin / 100;
+ convertKelvinToRgb: (value) => {
+ const temp = value / 100;
const r = temp <= 66 ? 255 : 329.698727446 * Math.pow(temp - 60, -0.1332047592);
const g =
temp <= 66
@@ -51,11 +51,18 @@ module.exports = {
b: b < 0 ? 0 : b > 255 ? 255 : Math.round(b)
};
},
+ /**
+ * @param {number} value color temperature as Kelvin or Mired
+ * @returns {number} color temperature value converted to Mired or Kelvin
+ */
+ convertMired: (value) => {
+ return Math.round(Math.pow(10, 6) / value);
+ },
/**
* @param {object} rgb color as RGB
* @returns {object} color value converted to HSV
*/
- rgb2hsv: ({ r, g, b }) => {
+ convertRgbToHsv: ({ r, g, b }) => {
r = r / 255;
g = g / 255;
b = b / 255;
diff --git a/tests/commands/colorabsolutetemperature.test.js b/tests/commands/colorabsolutetemperature.test.js
index 3e94b700..6083e6b5 100644
--- a/tests/commands/colorabsolutetemperature.test.js
+++ b/tests/commands/colorabsolutetemperature.test.js
@@ -63,7 +63,7 @@ describe('ColorAbsoluteTemperature Command', () => {
metadata: {
ga: {
config: {
- useKelvin: true
+ colorUnit: 'kelvin'
}
}
}
@@ -71,6 +71,20 @@ describe('ColorAbsoluteTemperature Command', () => {
const device = { customData: { deviceType: 'SpecialColorLight' } };
expect(Command.convertParamsToValue(params, item, device)).toBe('2000');
});
+
+ test('convertParamsToValue SpecialColorLight Mired', () => {
+ const item = {
+ metadata: {
+ ga: {
+ config: {
+ colorUnit: 'mired'
+ }
+ }
+ }
+ };
+ const device = { customData: { deviceType: 'SpecialColorLight' } };
+ expect(Command.convertParamsToValue(params, item, device)).toBe('500');
+ });
});
test('getResponseStates', () => {
diff --git a/tests/devices/specialcolorlight.test.js b/tests/devices/specialcolorlight.test.js
index 2bc697c3..1e861845 100644
--- a/tests/devices/specialcolorlight.test.js
+++ b/tests/devices/specialcolorlight.test.js
@@ -6,7 +6,7 @@ describe('SpecialColorLight Device', () => {
Device.isCompatible({
metadata: {
ga: {
- value: 'LIGHT'
+ value: 'SpecialColorLight'
}
}
})
@@ -14,7 +14,7 @@ describe('SpecialColorLight Device', () => {
});
test('matchesItemType', () => {
- const item = {
+ const item1 = {
type: 'Group',
metadata: {
ga: {
@@ -71,7 +71,7 @@ describe('SpecialColorLight Device', () => {
ga: {
value: 'LIGHT',
config: {
- useKelvin: true
+ colorUnit: 'kelvin'
}
}
},
@@ -164,12 +164,40 @@ describe('SpecialColorLight Device', () => {
}
]
};
- expect(Device.matchesItemType(item)).toBe(true);
+ const item7 = {
+ type: 'Group',
+ metadata: {
+ ga: {
+ value: 'LIGHT',
+ config: {
+ colorUnit: 'mired'
+ }
+ }
+ },
+ members: [
+ {
+ metadata: {
+ ga: {
+ value: 'lightBrightness'
+ }
+ }
+ },
+ {
+ metadata: {
+ ga: {
+ value: 'lightColorTemperature'
+ }
+ }
+ }
+ ]
+ };
+ expect(Device.matchesItemType(item1)).toBe(true);
expect(Device.matchesItemType(item2)).toBe(false);
expect(Device.matchesItemType(item3)).toBe(true);
expect(Device.matchesItemType(item4)).toBe(true);
expect(Device.matchesItemType(item5)).toBe(true);
expect(Device.matchesItemType(item6)).toBe(false);
+ expect(Device.matchesItemType(item7)).toBe(true);
expect(Device.matchesItemType({ type: 'Color' })).toBe(false);
expect(Device.matchesItemType({ type: 'Group', groupType: 'Color' })).toBe(false);
expect(Device.matchesItemType({ type: 'Group', groupType: 'Dimmer' })).toBe(false);
@@ -207,6 +235,25 @@ describe('SpecialColorLight Device', () => {
expect(Device.getAttributes(item1)).toStrictEqual({});
});
+ test('getAttributes colorTemperatureRange with mired', () => {
+ const item = {
+ metadata: {
+ ga: {
+ config: {
+ colorUnit: 'mired',
+ colorTemperatureRange: '250,454'
+ }
+ }
+ }
+ };
+ expect(Device.getAttributes(item)).toStrictEqual({
+ colorTemperatureRange: {
+ temperatureMinK: 2203,
+ temperatureMaxK: 4000
+ }
+ });
+ });
+
test('getAttributes color', () => {
const item = {
metadata: {
@@ -283,7 +330,7 @@ describe('SpecialColorLight Device', () => {
ga: {
value: 'LIGHT',
config: {
- useKelvin: true
+ colorUnit: 'kelvin'
}
}
},
@@ -315,20 +362,20 @@ describe('SpecialColorLight Device', () => {
});
});
- test('getState zero brightness', () => {
+ test('getState mired', () => {
const item = {
type: 'Group',
metadata: {
ga: {
value: 'LIGHT',
config: {
- colorTemperatureRange: '1000,4000'
+ colorUnit: 'mired'
}
}
},
members: [
{
- state: '0',
+ state: '50',
metadata: {
ga: {
value: 'lightBrightness'
@@ -336,7 +383,7 @@ describe('SpecialColorLight Device', () => {
}
},
{
- state: '20',
+ state: '200',
metadata: {
ga: {
value: 'lightColorTemperature'
@@ -346,29 +393,28 @@ describe('SpecialColorLight Device', () => {
]
};
expect(Device.getState(item)).toStrictEqual({
- on: false,
- brightness: 0,
+ on: true,
+ brightness: 50,
color: {
- temperatureK: 3400
+ temperatureK: 5000
}
});
});
- test('getState use kelvin', () => {
+ test('getState zero brightness', () => {
const item = {
type: 'Group',
metadata: {
ga: {
value: 'LIGHT',
config: {
- colorTemperatureRange: '1000,4000',
- useKelvin: true
+ colorTemperatureRange: '1000,4000'
}
}
},
members: [
{
- state: '50',
+ state: '0',
metadata: {
ga: {
value: 'lightBrightness'
@@ -376,7 +422,7 @@ describe('SpecialColorLight Device', () => {
}
},
{
- state: '2000',
+ state: '20',
metadata: {
ga: {
value: 'lightColorTemperature'
@@ -386,10 +432,10 @@ describe('SpecialColorLight Device', () => {
]
};
expect(Device.getState(item)).toStrictEqual({
- on: true,
- brightness: 50,
+ on: false,
+ brightness: 0,
color: {
- temperatureK: 2000
+ temperatureK: 3400
}
});
});
diff --git a/tests/utilities.test.js b/tests/utilities.test.js
index 549d7895..d008df8d 100644
--- a/tests/utilities.test.js
+++ b/tests/utilities.test.js
@@ -1,27 +1,36 @@
const Utilities = require('../functions/utilities.js');
describe('Utilities', () => {
- test('convertToCelsius', () => {
- expect(Utilities.convertToCelsius(10.0)).toEqual(-12.2);
- expect(Utilities.convertToCelsius(0.0)).toEqual(-17.8);
+ test('convertFahrenheitToCelsius', () => {
+ expect(Utilities.convertFahrenheitToCelsius(10.0)).toEqual(-12.2);
+ expect(Utilities.convertFahrenheitToCelsius(0.0)).toEqual(-17.8);
});
- test('convertToFahrenheit', () => {
- expect(Utilities.convertToFahrenheit(10.0)).toEqual(50);
- expect(Utilities.convertToFahrenheit(0.0)).toEqual(32);
+ test('convertCelsiusToFahrenheit', () => {
+ expect(Utilities.convertCelsiusToFahrenheit(10.0)).toEqual(50);
+ expect(Utilities.convertCelsiusToFahrenheit(0.0)).toEqual(32);
});
- test('kelvin2rgb', () => {
- expect(Utilities.kelvin2rgb(2000)).toStrictEqual({ b: 14, g: 137, r: 255 });
- expect(Utilities.kelvin2rgb(5900)).toEqual({ b: 234, g: 244, r: 255 });
- expect(Utilities.kelvin2rgb(9000)).toEqual({ b: 255, g: 223, r: 210 });
+ test('convertKelvinToRgb', () => {
+ expect(Utilities.convertKelvinToRgb(2000)).toStrictEqual({ b: 14, g: 137, r: 255 });
+ expect(Utilities.convertKelvinToRgb(5900)).toEqual({ b: 234, g: 244, r: 255 });
+ expect(Utilities.convertKelvinToRgb(9000)).toEqual({ b: 255, g: 223, r: 210 });
});
- test('rgb2hsv', () => {
- expect(Utilities.rgb2hsv({ r: 50, g: 10, b: 100 })).toStrictEqual({ hue: 266.67, saturation: 0.9, value: 0.39 });
- expect(Utilities.rgb2hsv({ r: 0, g: 0, b: 0 })).toStrictEqual({ hue: 0, saturation: 0, value: 0 });
- expect(Utilities.rgb2hsv({ r: 255, g: 0, b: 0 })).toStrictEqual({ hue: 0, saturation: 1, value: 1 });
- expect(Utilities.rgb2hsv({ r: 0, g: 255, b: 0 })).toStrictEqual({ hue: 120, saturation: 1, value: 1 });
- expect(Utilities.rgb2hsv({ r: 0, g: 0, b: 255 })).toStrictEqual({ hue: 240, saturation: 1, value: 1 });
+ test('convertKelvinToMired', () => {
+ expect(Utilities.convertMired(3400)).toBe(294);
+ expect(Utilities.convertMired(294)).toBe(3401);
+ });
+
+ test('convertRgbToHsv', () => {
+ expect(Utilities.convertRgbToHsv({ r: 50, g: 10, b: 100 })).toStrictEqual({
+ hue: 266.67,
+ saturation: 0.9,
+ value: 0.39
+ });
+ expect(Utilities.convertRgbToHsv({ r: 0, g: 0, b: 0 })).toStrictEqual({ hue: 0, saturation: 0, value: 0 });
+ expect(Utilities.convertRgbToHsv({ r: 255, g: 0, b: 0 })).toStrictEqual({ hue: 0, saturation: 1, value: 1 });
+ expect(Utilities.convertRgbToHsv({ r: 0, g: 255, b: 0 })).toStrictEqual({ hue: 120, saturation: 1, value: 1 });
+ expect(Utilities.convertRgbToHsv({ r: 0, g: 0, b: 255 })).toStrictEqual({ hue: 240, saturation: 1, value: 1 });
});
});