iobroker.zigbee2mqtt 2.13.6 → 2.13.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -10
- package/admin/jsonConfig.json +11 -0
- package/io-package.json +73 -70
- package/lib/check.js +12 -6
- package/lib/colors.js +4 -6
- package/lib/deviceController.js +64 -39
- package/lib/exposes.js +623 -466
- package/lib/imageController.js +24 -12
- package/lib/messages.js +10 -4
- package/lib/mqttServerController.js +12 -5
- package/lib/nonGenericDevicesExtension.js +30 -31
- package/lib/rgb.js +50 -52
- package/lib/states.js +650 -494
- package/lib/statesController.js +22 -13
- package/lib/utils.js +5 -5
- package/lib/websocketController.js +6 -4
- package/lib/z2mController.js +18 -12
- package/main.js +38 -17
- package/package.json +23 -21
package/lib/imageController.js
CHANGED
|
@@ -7,22 +7,30 @@ class ImageController {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
sanitizeModelIDForImageUrl(modelName) {
|
|
10
|
-
|
|
10
|
+
const modelNameString = modelName.replace('/', '_');
|
|
11
|
+
// eslint-disable-next-line no-control-regex
|
|
12
|
+
return modelNameString.replace(/\u0000/g, '');
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
sanitizeZ2MDeviceName(deviceName) {
|
|
14
|
-
|
|
16
|
+
const deviceNameString = deviceName.replace(/:|\s|\//g, '-');
|
|
17
|
+
// eslint-disable-next-line no-control-regex
|
|
18
|
+
return deviceName ? deviceNameString.replace(/\u0000/g, '') : 'NA';
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
getZ2mDeviceImage(device) {
|
|
18
22
|
if (device && device.definition && device.definition.model) {
|
|
19
|
-
|
|
23
|
+
const icoString = `https://www.zigbee2mqtt.io/images/devices/${this.sanitizeZ2MDeviceName(device.definition.model)}.jpg`;
|
|
24
|
+
// eslint-disable-next-line no-control-regex
|
|
25
|
+
return icoString.replace(/\u0000/g, '');
|
|
20
26
|
}
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
getSlsDeviceImage(device) {
|
|
24
30
|
if (device && device.model_id) {
|
|
25
|
-
|
|
31
|
+
const icoString = `https://slsys.github.io/Gateway/devices/png/${this.sanitizeModelIDForImageUrl(device.model_id)}.png`;
|
|
32
|
+
// eslint-disable-next-line no-control-regex
|
|
33
|
+
return icoString.replace(/\u0000/g, '');
|
|
26
34
|
}
|
|
27
35
|
}
|
|
28
36
|
|
|
@@ -68,15 +76,20 @@ class ImageController {
|
|
|
68
76
|
// Load Image Metadata
|
|
69
77
|
const origIconMeta = await sharp(icon.file).metadata();
|
|
70
78
|
// Check whether the image needs to be resized
|
|
71
|
-
if (
|
|
79
|
+
if (
|
|
80
|
+
(origIconMeta.height && origIconMeta.height > imageSize) ||
|
|
81
|
+
(origIconMeta.width && origIconMeta.width > imageSize)
|
|
82
|
+
) {
|
|
72
83
|
// Resize image to 28x28 pixel
|
|
73
|
-
this.adapter.log.info(
|
|
84
|
+
this.adapter.log.info(
|
|
85
|
+
`Resize image for device model ${device.definition.model} from: ${origIconMeta.width}x${origIconMeta.height} to ${imageSize}x${imageSize}`
|
|
86
|
+
);
|
|
74
87
|
icon.file = await sharp(icon.file)
|
|
75
88
|
.resize({
|
|
76
89
|
width: imageSize,
|
|
77
90
|
height: imageSize,
|
|
78
91
|
fit: sharp.fit.cover,
|
|
79
|
-
position: sharp.strategy.entropy
|
|
92
|
+
position: sharp.strategy.entropy,
|
|
80
93
|
})
|
|
81
94
|
.toBuffer();
|
|
82
95
|
// Replace the original image with the resize image.
|
|
@@ -88,24 +101,23 @@ class ImageController {
|
|
|
88
101
|
}
|
|
89
102
|
// Create and output Base64
|
|
90
103
|
return `data:image/png;base64,${icon.file.toString('base64')}`;
|
|
91
|
-
|
|
92
104
|
}
|
|
93
105
|
getFileNameWithExtension(url) {
|
|
94
106
|
const path = new URL(url).pathname;
|
|
95
107
|
const filename = path.split('/').pop();
|
|
96
|
-
|
|
108
|
+
// eslint-disable-next-line no-control-regex
|
|
109
|
+
return filename.replace(/\u0000/g, '');
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
async downloadIcon(adapter, url, namespace) {
|
|
100
113
|
try {
|
|
101
114
|
const res = await axios.get(url, { responseType: 'arraybuffer' });
|
|
102
115
|
await adapter.writeFileAsync(namespace, this.getFileNameWithExtension(url), res.data);
|
|
103
|
-
}
|
|
104
|
-
catch (ex) {
|
|
116
|
+
} catch (ex) {
|
|
105
117
|
adapter.log.warn(ex);
|
|
106
118
|
}
|
|
107
119
|
}
|
|
108
120
|
}
|
|
109
121
|
module.exports = {
|
|
110
122
|
ImageController,
|
|
111
|
-
};
|
|
123
|
+
};
|
package/lib/messages.js
CHANGED
|
@@ -17,7 +17,9 @@ async function adapterInfo(config, log) {
|
|
|
17
17
|
} else if (config.connectionType == 'exmqtt') {
|
|
18
18
|
log.info(`|| Zigbee2MQTT Externanl MQTT Server: ${config.externalMqttServerIP}`);
|
|
19
19
|
log.info(`|| Zigbee2MQTT Externanl MQTT Port: ${config.externalMqttServerPort}`);
|
|
20
|
-
log.info(
|
|
20
|
+
log.info(
|
|
21
|
+
`|| Zigbee2MQTT Externanl MQTT Credentials: ${config.externalMqttServerCredentials ? 'use' : 'unused'}`
|
|
22
|
+
);
|
|
21
23
|
} else if (config.connectionType == 'intmqtt') {
|
|
22
24
|
log.info(`|| Zigbee2MQTT Internal MQTT IP-Bind: ${config.mqttServerIPBind}`);
|
|
23
25
|
log.info(`|| Zigbee2MQTT Internal MQTT Port: ${config.mqttServerPort}`);
|
|
@@ -42,12 +44,16 @@ async function adapterInfo(config, log) {
|
|
|
42
44
|
async function zigbee2mqttInfo(payload, log) {
|
|
43
45
|
log.info('============================ Zigbee2MQTT Information =============================');
|
|
44
46
|
log.info(`|| Zigbee2MQTT Version: ${payload.version} `);
|
|
45
|
-
log.info(
|
|
46
|
-
|
|
47
|
+
log.info(
|
|
48
|
+
`|| Coordinator type: ${payload.coordinator.type} Version: ${payload.coordinator.meta.revision} Serial: ${payload.config.serial.port}`
|
|
49
|
+
);
|
|
50
|
+
log.info(
|
|
51
|
+
`|| Network panid ${payload.network.pan_id} channel: ${payload.network.channel} ext_pan_id: ${payload.network.extended_pan_id}`
|
|
52
|
+
);
|
|
47
53
|
log.info('==================================================================================');
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
module.exports = {
|
|
51
57
|
adapterInfo,
|
|
52
58
|
zigbee2mqttInfo,
|
|
53
|
-
};
|
|
59
|
+
};
|
|
@@ -11,12 +11,17 @@ class MqttServerController {
|
|
|
11
11
|
async createMQTTServer() {
|
|
12
12
|
try {
|
|
13
13
|
const NedbPersistence = require('aedes-persistence-nedb');
|
|
14
|
-
const db = new NedbPersistence({
|
|
14
|
+
const db = new NedbPersistence({
|
|
15
|
+
path: `${core.getAbsoluteInstanceDataDir(this.adapter)}/mqttData`,
|
|
16
|
+
prefix: '',
|
|
17
|
+
});
|
|
15
18
|
// @ts-ignore
|
|
16
19
|
const aedes = Aedes({ persistence: db });
|
|
17
20
|
mqttServer = net.createServer(aedes.handle);
|
|
18
21
|
mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
|
|
19
|
-
this.adapter.log.info(
|
|
22
|
+
this.adapter.log.info(
|
|
23
|
+
`Statring MQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
|
|
24
|
+
);
|
|
20
25
|
});
|
|
21
26
|
} catch (err) {
|
|
22
27
|
this.adapter.log.error(err);
|
|
@@ -29,7 +34,9 @@ class MqttServerController {
|
|
|
29
34
|
const aedes = Aedes();
|
|
30
35
|
mqttServer = net.createServer(aedes.handle);
|
|
31
36
|
mqttServer.listen(this.adapter.config.mqttServerPort, this.adapter.config.mqttServerIPBind, () => {
|
|
32
|
-
this.adapter.log.info(
|
|
37
|
+
this.adapter.log.info(
|
|
38
|
+
`Statring DummyMQTT-Server on IP ${this.adapter.config.mqttServerIPBind} and Port ${this.adapter.config.mqttServerPort}`
|
|
39
|
+
);
|
|
33
40
|
});
|
|
34
41
|
} catch (err) {
|
|
35
42
|
this.adapter.log.error(err);
|
|
@@ -44,5 +51,5 @@ class MqttServerController {
|
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
module.exports = {
|
|
47
|
-
MqttServerController
|
|
48
|
-
};
|
|
54
|
+
MqttServerController,
|
|
55
|
+
};
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
const nonGenDevStatesDefs = {
|
|
2
2
|
// https://www.zigbee2mqtt.io/devices/HG06467.html#trigger-effects
|
|
3
|
-
HG06467: [
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
HG06467: [
|
|
4
|
+
{
|
|
5
|
+
id: 'effect',
|
|
6
|
+
prop: 'effect',
|
|
7
|
+
name: 'effect',
|
|
8
|
+
icon: undefined,
|
|
9
|
+
role: 'state',
|
|
10
|
+
write: true,
|
|
11
|
+
read: true,
|
|
12
|
+
type: 'string',
|
|
13
|
+
def: '{"effect":{"effect":"snake","speed":100,"colors":[{"r":255,"g":0,"b":0},{"r":0,"g":255,"b":0},{"r":0,"g":0,"b":255}]}}',
|
|
14
|
+
setter: (value) => {
|
|
15
|
+
try {
|
|
16
|
+
const valObj = JSON.parse(value);
|
|
17
|
+
if (valObj.effect && valObj.effect.effect) {
|
|
18
|
+
return valObj.effect;
|
|
19
|
+
}
|
|
20
|
+
return valObj;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return undefined;
|
|
18
23
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
getter: payload => {
|
|
27
|
-
if (!payload.effect) {
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
return JSON.stringify(payload.effect);
|
|
24
|
+
},
|
|
25
|
+
getter: (payload) => {
|
|
26
|
+
if (!payload.effect) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
return JSON.stringify(payload.effect);
|
|
30
|
+
},
|
|
31
31
|
},
|
|
32
|
-
|
|
32
|
+
],
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
function getStateDefinition(model) {
|
|
@@ -39,9 +39,8 @@ function getStateDefinition(model) {
|
|
|
39
39
|
} else {
|
|
40
40
|
return [];
|
|
41
41
|
}
|
|
42
|
-
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
module.exports = {
|
|
46
|
-
getStateDefinition
|
|
47
|
-
};
|
|
45
|
+
getStateDefinition,
|
|
46
|
+
};
|
package/lib/rgb.js
CHANGED
|
@@ -65,31 +65,27 @@ function cie_to_rgb(x, y, brightness) {
|
|
|
65
65
|
// @ts-ignore
|
|
66
66
|
let green = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;
|
|
67
67
|
// @ts-ignore
|
|
68
|
-
let blue = X * 0.051713 - Y * 0.121364 + Z * 1.
|
|
68
|
+
let blue = X * 0.051713 - Y * 0.121364 + Z * 1.01153;
|
|
69
69
|
|
|
70
70
|
//If red, green or blue is larger than 1.0 set it back to the maximum of 1.0
|
|
71
71
|
if (red > blue && red > green && red > 1.0) {
|
|
72
|
-
|
|
73
72
|
green = green / red;
|
|
74
73
|
blue = blue / red;
|
|
75
74
|
red = 1.0;
|
|
76
75
|
} else if (green > blue && green > red && green > 1.0) {
|
|
77
|
-
|
|
78
76
|
red = red / green;
|
|
79
77
|
blue = blue / green;
|
|
80
78
|
green = 1.0;
|
|
81
79
|
} else if (blue > red && blue > green && blue > 1.0) {
|
|
82
|
-
|
|
83
80
|
red = red / blue;
|
|
84
81
|
green = green / blue;
|
|
85
82
|
blue = 1.0;
|
|
86
83
|
}
|
|
87
84
|
|
|
88
85
|
//Reverse gamma correction
|
|
89
|
-
red = red <= 0.0031308 ? 12.92 * red : (1.0 + 0.055) * Math.pow(red,
|
|
90
|
-
green = green <= 0.0031308 ? 12.92 * green : (1.0 + 0.055) * Math.pow(green,
|
|
91
|
-
blue = blue <= 0.0031308 ? 12.92 * blue : (1.0 + 0.055) * Math.pow(blue,
|
|
92
|
-
|
|
86
|
+
red = red <= 0.0031308 ? 12.92 * red : (1.0 + 0.055) * Math.pow(red, 1.0 / 2.4) - 0.055;
|
|
87
|
+
green = green <= 0.0031308 ? 12.92 * green : (1.0 + 0.055) * Math.pow(green, 1.0 / 2.4) - 0.055;
|
|
88
|
+
blue = blue <= 0.0031308 ? 12.92 * blue : (1.0 + 0.055) * Math.pow(blue, 1.0 / 2.4) - 0.055;
|
|
93
89
|
|
|
94
90
|
//Convert normalized decimal to decimal
|
|
95
91
|
red = Math.round(red * 255);
|
|
@@ -111,7 +107,6 @@ function cie_to_rgb(x, y, brightness) {
|
|
|
111
107
|
return [red, green, blue];
|
|
112
108
|
}
|
|
113
109
|
|
|
114
|
-
|
|
115
110
|
/**
|
|
116
111
|
* Converts RGB color space to CIE color space
|
|
117
112
|
* @param {Number} red
|
|
@@ -121,14 +116,14 @@ function cie_to_rgb(x, y, brightness) {
|
|
|
121
116
|
*/
|
|
122
117
|
function rgb_to_cie(red, green, blue) {
|
|
123
118
|
// Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device
|
|
124
|
-
red =
|
|
125
|
-
green =
|
|
126
|
-
blue =
|
|
119
|
+
red = red > 0.04045 ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : red / 12.92;
|
|
120
|
+
green = green > 0.04045 ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : green / 12.92;
|
|
121
|
+
blue = blue > 0.04045 ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : blue / 12.92;
|
|
127
122
|
|
|
128
123
|
// RGB values to XYZ using the Wide RGB D65 conversion formula
|
|
129
124
|
const X = red * 0.664511 + green * 0.154324 + blue * 0.162028;
|
|
130
125
|
const Y = red * 0.283881 + green * 0.668433 + blue * 0.047685;
|
|
131
|
-
const Z = red * 0.000088 + green * 0.
|
|
126
|
+
const Z = red * 0.000088 + green * 0.07231 + blue * 0.986039;
|
|
132
127
|
|
|
133
128
|
// Calculate the xy values from the XYZ values
|
|
134
129
|
let x = (X / (X + Y + Z)).toFixed(4);
|
|
@@ -149,9 +144,8 @@ function rgb_to_cie(red, green, blue) {
|
|
|
149
144
|
return [x, y];
|
|
150
145
|
}
|
|
151
146
|
|
|
152
|
-
|
|
153
147
|
function hsvToRGB(h, s, v) {
|
|
154
|
-
h = h % 360 / 360;
|
|
148
|
+
h = (h % 360) / 360;
|
|
155
149
|
s = s / 100;
|
|
156
150
|
v = v / 100;
|
|
157
151
|
|
|
@@ -159,7 +153,7 @@ function hsvToRGB(h, s, v) {
|
|
|
159
153
|
let g;
|
|
160
154
|
let b;
|
|
161
155
|
if (arguments.length === 1) {
|
|
162
|
-
s = h.s, v = h.v, h = h.h;
|
|
156
|
+
(s = h.s), (v = h.v), (h = h.h);
|
|
163
157
|
}
|
|
164
158
|
const i = Math.floor(h * 6);
|
|
165
159
|
const f = h * 6 - i;
|
|
@@ -168,22 +162,22 @@ function hsvToRGB(h, s, v) {
|
|
|
168
162
|
const t = v * (1 - (1 - f) * s);
|
|
169
163
|
switch (i % 6) {
|
|
170
164
|
case 0:
|
|
171
|
-
r = v, g = t, b = p;
|
|
165
|
+
(r = v), (g = t), (b = p);
|
|
172
166
|
break;
|
|
173
167
|
case 1:
|
|
174
|
-
r = q, g = v, b = p;
|
|
168
|
+
(r = q), (g = v), (b = p);
|
|
175
169
|
break;
|
|
176
170
|
case 2:
|
|
177
|
-
r = p, g = v, b = t;
|
|
171
|
+
(r = p), (g = v), (b = t);
|
|
178
172
|
break;
|
|
179
173
|
case 3:
|
|
180
|
-
r = p, g = q, b = v;
|
|
174
|
+
(r = p), (g = q), (b = v);
|
|
181
175
|
break;
|
|
182
176
|
case 4:
|
|
183
|
-
r = t, g = p, b = v;
|
|
177
|
+
(r = t), (g = p), (b = v);
|
|
184
178
|
break;
|
|
185
179
|
case 5:
|
|
186
|
-
r = v, g = p, b = q;
|
|
180
|
+
(r = v), (g = p), (b = q);
|
|
187
181
|
break;
|
|
188
182
|
}
|
|
189
183
|
return {
|
|
@@ -195,13 +189,13 @@ function hsvToRGB(h, s, v) {
|
|
|
195
189
|
|
|
196
190
|
function rgbToHSV(r, g, b, numeric) {
|
|
197
191
|
if (arguments.length === 1) {
|
|
198
|
-
g = r.g, b = r.b, r = r.r;
|
|
192
|
+
(g = r.g), (b = r.b), (r = r.r);
|
|
199
193
|
}
|
|
200
194
|
const max = Math.max(r, g, b);
|
|
201
195
|
const min = Math.min(r, g, b);
|
|
202
196
|
const d = max - min;
|
|
203
197
|
let h;
|
|
204
|
-
const s =
|
|
198
|
+
const s = max === 0 ? 0 : d / max;
|
|
205
199
|
const v = max / 255;
|
|
206
200
|
|
|
207
201
|
switch (max) {
|
|
@@ -209,24 +203,25 @@ function rgbToHSV(r, g, b, numeric) {
|
|
|
209
203
|
h = 0;
|
|
210
204
|
break;
|
|
211
205
|
case r:
|
|
212
|
-
h =
|
|
206
|
+
h = g - b + d * (g < b ? 6 : 0);
|
|
213
207
|
h /= 6 * d;
|
|
214
208
|
break;
|
|
215
209
|
case g:
|
|
216
|
-
h =
|
|
210
|
+
h = b - r + d * 2;
|
|
217
211
|
h /= 6 * d;
|
|
218
212
|
break;
|
|
219
213
|
case b:
|
|
220
|
-
h =
|
|
214
|
+
h = r - g + d * 4;
|
|
221
215
|
h /= 6 * d;
|
|
222
216
|
break;
|
|
223
217
|
}
|
|
224
|
-
if (numeric)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
218
|
+
if (numeric)
|
|
219
|
+
return {
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
h: Math.round(h * 360),
|
|
222
|
+
s: Math.round(s * 100),
|
|
223
|
+
v: Math.round(v * 100),
|
|
224
|
+
};
|
|
230
225
|
return {
|
|
231
226
|
// @ts-ignore
|
|
232
227
|
h: (h * 360).toFixed(3),
|
|
@@ -236,9 +231,9 @@ function rgbToHSV(r, g, b, numeric) {
|
|
|
236
231
|
}
|
|
237
232
|
|
|
238
233
|
function colorArrayFromString(value) {
|
|
239
|
-
if (typeof
|
|
234
|
+
if (typeof value === 'string') {
|
|
240
235
|
const rv = [];
|
|
241
|
-
value.split(',').forEach(element => {
|
|
236
|
+
value.split(',').forEach((element) => {
|
|
242
237
|
rv.push(colors.ParseColor(element));
|
|
243
238
|
});
|
|
244
239
|
return rv;
|
|
@@ -248,7 +243,7 @@ function colorArrayFromString(value) {
|
|
|
248
243
|
|
|
249
244
|
function colorStringFromRGBArray(payload) {
|
|
250
245
|
const rv = [];
|
|
251
|
-
payload.forEach(element => {
|
|
246
|
+
payload.forEach((element) => {
|
|
252
247
|
rv.push(rgb_to_rgbstring(element));
|
|
253
248
|
});
|
|
254
249
|
return rv.toString();
|
|
@@ -261,14 +256,11 @@ function hsv_to_cie(h, s, v) {
|
|
|
261
256
|
|
|
262
257
|
function rgb_to_rgbstring(element) {
|
|
263
258
|
let col = '#';
|
|
264
|
-
if (element && element.hasOwnProperty('r'))
|
|
265
|
-
col = col + element.r.toString(16).padStart(2, '0');
|
|
259
|
+
if (element && element.hasOwnProperty('r')) col = col + element.r.toString(16).padStart(2, '0');
|
|
266
260
|
else col = col + '00';
|
|
267
|
-
if (element && element.hasOwnProperty('g'))
|
|
268
|
-
col = col + element.g.toString(16).padStart(2, '0');
|
|
261
|
+
if (element && element.hasOwnProperty('g')) col = col + element.g.toString(16).padStart(2, '0');
|
|
269
262
|
else col = col + '00';
|
|
270
|
-
if (element && element.hasOwnProperty('b'))
|
|
271
|
-
col = col + element.b.toString(16).padStart(2, '0');
|
|
263
|
+
if (element && element.hasOwnProperty('b')) col = col + element.b.toString(16).padStart(2, '0');
|
|
272
264
|
else col = col + '00';
|
|
273
265
|
return col;
|
|
274
266
|
}
|
|
@@ -280,16 +272,22 @@ function hsbToRGB(h, s, b) {
|
|
|
280
272
|
} else {
|
|
281
273
|
const hue = h % 360;
|
|
282
274
|
const f = hue % 60;
|
|
283
|
-
const p = Math.round(
|
|
284
|
-
const q = Math.round(
|
|
285
|
-
const t = Math.round(
|
|
275
|
+
const p = Math.round(b * (100 - s) * 0.0255);
|
|
276
|
+
const q = Math.round(b * (6000 - s * f) * 0.000425);
|
|
277
|
+
const t = Math.round(b * (6000 - s * (60 - f)) * 0.000425);
|
|
286
278
|
switch (Math.floor(hue / 60)) {
|
|
287
|
-
case 0:
|
|
288
|
-
|
|
289
|
-
case
|
|
290
|
-
|
|
291
|
-
case
|
|
292
|
-
|
|
279
|
+
case 0:
|
|
280
|
+
return [br, t, p];
|
|
281
|
+
case 1:
|
|
282
|
+
return [q, br, p];
|
|
283
|
+
case 2:
|
|
284
|
+
return [p, br, t];
|
|
285
|
+
case 3:
|
|
286
|
+
return [p, q, br];
|
|
287
|
+
case 4:
|
|
288
|
+
return [t, p, br];
|
|
289
|
+
case 5:
|
|
290
|
+
return [br, p, q];
|
|
293
291
|
}
|
|
294
292
|
}
|
|
295
293
|
return false;
|
|
@@ -309,4 +307,4 @@ module.exports = {
|
|
|
309
307
|
colorStringFromRGBArray,
|
|
310
308
|
hsvToRGBString,
|
|
311
309
|
hsbToRGB,
|
|
312
|
-
};
|
|
310
|
+
};
|