diff --git a/README.md b/README.md index 69a7427..2168e31 100644 --- a/README.md +++ b/README.md @@ -42,14 +42,19 @@ node tuya-mqtt.js // For debugging purpose, to use DEBUG : https://www.npmjs.com/package/debug -//on Linux machines at the bash command prompt: +//on Linux machines at the bash command prompt, to turn ON DEBUG: DEBUG=* tuya-mqtt.js +//on Linux machines at the bash command prompt, to turn OFF DEBUG: +DEBUG=-* tuya-mqtt.js -// on Windows machines at the cmd.exe command prompt: -Set DEBUG=* tuya-mqtt.js +// on Windows machines at the cmd.exe command prompt, to turn ON DEBUG: +Set DEBUG=* & node c:/openhab2/userdata/etc/scripts/tuya-mqtt.js + +// on Windows machines at the cmd.exe command prompt, to turn OFF DEBUG: +Set DEBUG=-* & node c:/openhab2/userdata/etc/scripts/tuya-mqtt.js ``` -URL to [DEBUG](https://www.npmjs.com/package/debug) +URL to install [DEBUG](https://www.npmjs.com/package/debug) @@ -68,7 +73,12 @@ Change device state (by topic): - tuya////command/toggle - tuya////command/TOGGLE - tuya////command/{ "dps": 1, "set": true } + - tuya////command/{ "dps": 7, "set": true } - tuya////command/{ "multiple": true, "data": { "1": true, "7": true } } + - tuya////command/{ "schema": true } + - tuya////command/{ "multiple": true, "data": { "1": true, "2": "scene_4" } } + - tuya////command/{ "multiple": true, "data": + { "1": true, "2": "scene", "6": "c479000025ffc3" } } Change device state (by payload) Use with OpenHAB 2.X MQTT bindings or others where only a single command topic is preferred: @@ -86,13 +96,18 @@ NOTE: notice that nothing follows the word command, DO NOT but a "/" in after co "toggle" "TOGGLE" "{ \"dps\": 1, \"set\": true }" + "{ \"dps\": 7, \"set\": true }" "{ \"multiple\": true, \"data\": { \"1\": true, \"7\": true } }" + "{ \"schema\": true }" + "{ \"multiple\": true, \"data\": { \"1\": true, \"2\": \"scene_4\" } }" + "{ \"multiple\": true, \"data\": { \"1\": true, \"2\": \"scene\", \"6\": \"c479000025ffc3\" } }" Change color of lightbulb (payload as HSB-Color) tuya////color Example: 64,0,100 + 0,0,89 ``` ### MQTT Topic's (read data) @@ -125,9 +140,9 @@ Switch tuya_kitchen_coffeemachine_mqtt "Steckdose Kaffeemaschine" ( () ["Lighting"] { - mqtt="<[broker:tuya/lightbulb////state:state:default:.*], - >[broker:tuya/lightbulb////command/on:command:ON:true], - >[broker:tuya/lightbulb////command/off:command:OFF:false]" + mqtt="<[broker:tuya////state:state:default:.*], + >[broker:tuya////command/on:command:ON:true], + >[broker:tuya////command/off:command:OFF:false]" } ``` @@ -140,7 +155,7 @@ Group gTuyaLivingColor "Tuya color group" Color tuya_livingroom_colorpicker "Stehlampe farbe" (LivingDining) String tuya_livingroom_ledstrip_tv_color "Set color [%s]" (gTuyaLivingColor, LivingDining) { - mqtt=">[broker:tuya/lightbulb////color:command:*:default]" + mqtt=">[broker:tuya////color:command:*:default]" } @@ -195,12 +210,12 @@ Bridge mqtt:broker:myUnsecureBroker [ host="localhost", secure=false ] Thing mqtt:topic:myCustomMQTT { Channels: - Type switch : tuya_kitchen_coffeemachine_mqtt "Kitchen Coffee Machine MQTT Channel" [ + Type switch : tuya_kitchen_coffeemachine_mqtt_channel "Kitchen Coffee Machine MQTT Channel" [ stateTopic="tuya////state", commandTopic="tuya////command", // optional custom mqtt-payloads for ON and OFF - on="{ \"dps": 1, \"set\": true }, + on="{ \"dps\": 1, \"set\": true }", off="0" ] } @@ -209,7 +224,7 @@ Bridge mqtt:broker:myUnsecureBroker [ host="localhost", secure=false ] # *.item Example Switch tuya_kitchen_coffeemachine_mqtt "Kitchen Coffee Machine Switch" (gKitchen, gTuya) ["Switchable"] { - channel="mqtt:topic:myMosquitto:tuya:coffeemachine" + channel="mqtt:topic:myUnsecureBroker:myCustomMQTT:tuya_kitchen_coffeemachine_mqtt_channel" } ``` @@ -221,17 +236,18 @@ For one RGB bulb you would need a separate channel with the command topic set to Bridge mqtt:broker:myUnsecureBroker [ host="localhost", secure=false ] { - - Type colorHSB : livingroom_floorlamp_1_color "Livingroom floorlamp color MQTT Channel" [ - stateTopic="tuya/lightbulb/05200399bcddc2e02ec9/b58cf92e8bc5c899/192.168.178.49/state", - commandTopic="tuya/lightbulb/05200399bcddc2e02ec9/b58cf92e8bc5c899/192.168.178.49/color" - ] - + Thing mqtt:topic:myCustomMQTT { + Channels: + Type colorHSB : livingroom_floorlamp_1_color "Livingroom floorlamp color MQTT Channel" [ + stateTopic="tuya/05200399bcddc2e02ec9/b58cf92e8bc5c899/192.168.178.49/state", + commandTopic="tuya/05200399bcddc2e02ec9/b58cf92e8bc5c899/192.168.178.49/color" + ] + } } # *.item Example Color tuya_livingroom_colorpicker "Floorlamp colorpicker" (gLivingroom){ - channel="mqtt:topic:myMosquitto:tuya:livingroom_floorlamp_1_color" + channel="mqtt:topic:myUnsecureBroker:myCustomMQTT:livingroom_floorlamp_1_color" } ``` @@ -241,9 +257,15 @@ Color tuya_livingroom_colorpicker "Floorlamp colorpicker" (gLivingroom){ Switch item=tuya_kitchen_coffeemachine_mqtt +# turn the color bulb off or on +Switch item=tuya_livingroom_colorpicker label="RGB lamp [%s]" + +# pick the color level to send to the color bulb via MQTT color Channel +Slider item=tuya_livingroom_colorpicker label="RGB lamp level [%s]" minValue=0 maxValue=100 step=1 + +# color picked and sent via MQTT Color channel +Colorpicker item=tuya_livingroom_colorpicker label="RGB lamp color [%s]" icon="colorpicker" sendFrequency=30000 -# Colorpicker for Lightbulbs -Colorpicker item=tuya_livingroom_colorpicker label="RGB lamp color" sendFrequency=30000 ``` diff --git a/tuya-color.js b/tuya-color.js index 84b58c1..2e702aa 100644 --- a/tuya-color.js +++ b/tuya-color.js @@ -26,6 +26,58 @@ function TuyaColorLight() { this.dps = {}; } +/** + * calculate color value from given brightness percentage + * @param (Integer) percentage 0-100 percentage value + * @returns (Integer) color value from 25 - 255 + * @private + */ +TuyaColorLight.prototype._convertBrightnessPercentageToVal = function(brt_percentage){ + // the brightness scale does not start at 0 but starts at 25 - 255 + // this linear equation is a better fit to the conversion to 255 scale + var tmp = Math.round(2.3206*brt_percentage+22.56); + debug('Converted brightness percentage ' + brt_percentage + ' to: ' + tmp); + return tmp; +} + +/** + * calculate percentage from brightness color value + * @param brt_val 25 - 255 brightness color value + * @returns {Integer} 0 - 100 integer percent + * @private + */ +TuyaColorLight.prototype._convertValtoBrightnessPercentage = function(brt_val){ + var tmp = Math.round( (brt_val-22.56)/2.3206); + debug('Converted brightness value ' + brt_val + ' to: ' + tmp); + return tmp; +} + +/** + * calculate color value from given saturation percentage OR color temperature percentage + * @param (Integer) temp_percentage 0-100 percentage value + * @returns {Integer} saturation or color temperature value from 0 - 255 + * @private + */ +TuyaColorLight.prototype._convertSATorColorTempPercentageToVal = function(temp_percentage){ + // the saturation OR temperature scale does start at 0 - 255 + // this is a perfect linear equation fit for the saturation OR temperature scale conversion + var tmp = Math.round(((2.5498*temp_percentage)-0.4601)); + debug('Converted saturation OR temperature percentage ' + temp_percentage + ' to: ' + tmp); + return tmp; +} + +/** + * calculate percentage from saturation value OR color temperature value + * @param temp_val 0 - 255 saturation or color temperature value + * @returns {Integer} 0 - 100 integer percent + * @private + */ +TuyaColorLight.prototype._convertValtoSATorColorTempPercentage = function(temp_val){ + var tmp = Math.round( (temp_val+0.4601/2.5498)); + debug('Converted saturation OR temperature value ' + temp_val + ' to: ' + tmp); + return tmp; +} + /** * calculate color value from given percentage * @param {Integer} percentage 0-100 percentage value @@ -105,6 +157,18 @@ TuyaColorLight.prototype._ValIsHex = function (h) { return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(h) }; +/** + * get width Hex digits from given value + * @param (Integer) value, decimal value to convert to hex string + * @param (Integer) width, the number of hex digits to return + * @returns {string} value as HEX containing (width) number of hex digits + * @private + */ +TuyaColorLight.prototype._getHex = function (value,width){ + var hex = (value+Math.pow(16, width)).toString(16).slice(-width).toLowerCase(); + debug('value: ' + value + ' hex: ' + hex); + return hex; +} /** * get AlphaHex from percentage brightness * @param {Integer} brightness @@ -138,7 +202,8 @@ TuyaColorLight.prototype.setSaturation = function (value) { */ TuyaColorLight.prototype.setBrightness = function (value) { this.brightness = value; - var newValue = this._convertPercentageToVal(value); + //var newValue = this._convertPercentageToVal(value); + var newValue = this._convertBrightnessPercentageToVal(value); debug("BRIGHTNESS from UI: " + value + ' Converted from 100 to 255 scale: ' + newValue); } @@ -181,26 +246,20 @@ TuyaColorLight.prototype.setHSL = function (hue, saturation, brightness) { this.setHue(hue); } -TuyaColorLight.prototype._stripBraces = function (string) { - return string.slice(1,-1); -} /** * Set color from given string * @param {String} colorValue could be HEX or HSL color type * @returns {Object} dps settings for given color */ TuyaColorLight.prototype.setColor = function (colorValue) { - var colorValue2; + debug("Recieved color", colorValue); - debug("Received color", colorValue); - colorValue2 = this._stripBraces(colorValue); - debug("colorValue2 = "+colorValue2); - if (this._ValIsHex(colorValue2)) { + if (this._ValIsHex(colorValue)) { debug("Color is Hex"); - color = convert.hex.hsl(colorValue2); + var color = convert.hex.hsl(colorValue); } else { debug("Color is HSL"); - var color = colorValue2.split(","); + var color = colorValue.split(","); // convert strings to numbers color.forEach(function (element, key) { color[key] = parseInt(element, 10); @@ -225,29 +284,65 @@ TuyaColorLight.prototype.getDps = function () { var lightness = Math.round(this.brightness / 2); var brightness = this.brightness; - var apiBrightness = this._convertPercentageToVal(brightness); - var alphaBrightness = this._getAlphaHex(brightness); + //var apiBrightness = this._convertPercentageToVal(brightness); + var apiBrightness = this._convertBrightnessPercentageToVal(brightness); + + //var alphaBrightness = this._getAlphaHex(brightness); + var alphaBrightness = this._getHex(apiBrightness,2); var hexColor1 = convert.hsl.hex(color.H, color.S, lightness); - var hexColor2 = convert.hsl.hex(0, 0, lightness); + //var hexColor2 = convert.hsl.hex(0, 0, lightness); + var hexColor2 = this._getHex(color.H,4); + hexColor2 = hexColor2 + this._getHex(this._convertSATorColorTempPercentageToVal(color.S),2); var colorTemperature = this.colorTemperature; var lightColor = (hexColor1 + hexColor2 + alphaBrightness).toLowerCase(); - var temperature = (this.colorMode === 'colour') ? 255 : this._convertColorTemperature(colorTemperature); + //var temperature = (this.colorMode === 'colour') ? 255 : this._convertColorTemperature(colorTemperature); + // color temperature percentage is at a fixed 51% + var temperature = this._convertSATorColorTempPercentageToVal(51); - dpsTmp = { - '1': true, - '2': this.colorMode, - '3': apiBrightness, - '4': temperature, - '5': lightColor - // '6' : hexColor + hexColor + 'ff' - }; - debug("dps", dpsTmp); - return dpsTmp; + // if the bulb is in colour mode than the dps 3 and dps 4 are ignored by the bulb but if you set it now + // some tuya bulbs will ignore dps 5 because you set dps 3 or dps 4 + // FOR colour mode the bulb looks at dps 1, dps 2, and dps 5. + // DPS 5 is in the following format: + // HSL to HEX format are the leftmost hex digits (hex digits 14 - 9) + // hex digits 8 - 5 are the HSB/HSL Hue value in HEX format + // hex digits 4 - 3 are the HSB/HSL Saturation percentage as a value (converted to 0-255 scale) in HEX format + // hex digits 2 - 1 are the HSB Brightness percentage as a value (converted to 25-255 scale) in HEX format + + if (this.colorMode === 'colour') { + dpsTmp = { + '1': true, + '2': this.colorMode, + //'3': apiBrightness, + //'4': temperature, + '5': lightColor + // '6' : hexColor + hexColor + 'ff' + }; + debug("dps", dpsTmp); + return dpsTmp; + } + + // if the bulb is in white mode then the dps 5 value is ignored by the bulb but if you set dps 5 value now + // you may not get a response back from the bulb on the dps values + // FOR white mode the bulb looks at dps 1, dps 2, dps 3 and dps 4 + // DPS 3 is the HSB/HSL Brightness percentage converted to a value from 25 to 255 in decimal format + // DPS 4 is the HSB/HSL Saturation percentage converted to a value from 0 to 255 in decimal format + if (this.colorMode === 'white'){ + dpsTmp = { + '1': true, + '2': this.colorMode, + '3': apiBrightness, + '4': temperature, + //'5': lightColor + // '6' : hexColor + hexColor + 'ff' + }; + debug("dps", dpsTmp); + return dpsTmp; + } } module.exports = TuyaColorLight;