Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for color temperature in Mired & Use separate identifier for SpecialColorLight #337

Merged
merged 3 commits into from
Aug 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`<br>(optional) `checkState=true/false`<br>(optional) `colorTemperatureRange="minK,maxK"`<br>_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`<br>(optional) `checkState=true/false`<br>(optional) `colorTemperatureRange="minK,maxK"`<br>_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" }
Expand Down
11 changes: 7 additions & 4 deletions functions/commands/colorabsolutetemperature.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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 -
Expand All @@ -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(',');
}
Expand Down
4 changes: 2 additions & 2 deletions functions/commands/thermostattemperaturesetpoint.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand All @@ -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();
}
Expand Down
4 changes: 2 additions & 2 deletions functions/commands/thermostattemperaturesetpointhigh.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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();
}
Expand Down
4 changes: 2 additions & 2 deletions functions/commands/thermostattemperaturesetpointlow.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand All @@ -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();
}
Expand Down
24 changes: 18 additions & 6 deletions functions/devices/specialcolorlight.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const DefaultDevice = require('./default.js');
const convertMired = require('../utilities.js').convertMired;

class SpecialColorLight extends DefaultDevice {
static get type() {
Expand All @@ -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)
);
}
Expand All @@ -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
};
}
}
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -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();
}
}

Expand Down
4 changes: 2 additions & 2 deletions functions/devices/temperaturesensor.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions functions/devices/thermostat.js
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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]);
}
}
}
Expand Down
19 changes: 13 additions & 6 deletions functions/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
16 changes: 15 additions & 1 deletion tests/commands/colorabsolutetemperature.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,28 @@ describe('ColorAbsoluteTemperature Command', () => {
metadata: {
ga: {
config: {
useKelvin: true
colorUnit: 'kelvin'
}
}
}
};
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', () => {
Expand Down
Loading