[
{
"id": "0c80c77a78fa17d1",
"type": "subflow",
"name": "Loxone - Tradfri GW translator for tunable white light bulbs",
"info": "This node translates between Loxone home automation and IKEA Tradfri gateway. \n\nIt is to be used for tunable white light bulbs and converts brightness and color temperature between both worlds. \n\n**NOTE:** It is based on the the **node-red-contrib-ikea-tradfri**__ nodes and only works with the IKEA tradfri gateway, NOT with other zigbee gateways, e.g. does not with a Philips Hue bridge or conBee USB sticks! \n\nIt also requires the **node-red-contrib-loxone**__ nodes!\n\nMany thanks to the authors of these excellent nodes - Michael de Wit and Patrik Mayer!\n\nIt allows changes from BOTH sides, e.g. IKEA remote controls, IKEA smart home app, Loxone app and other Loxone logic at the (almost) same time. \n\n\nEnjoy!\n\nSome technical information:\n\nunits for brightness:\n - Loxone is using integer numbers from 0=dark to 100=bright\n - IKEA is using integer numbers from 0=dark to 254=bright\n - node-red-contrib-ikea-tradfri is using decimal numbers with one decimal place from 0.0=dark to 100.0=bright\n\nunits for color temperature:\n - Loxone is using integer numbers in Kelvin from 2700=warm to 6500=cold\n - IKEA is using integer numbers in Mireds from 250=cold to 454=warm\n - node-red-contrib-ikea-tradfri is using decimal numbers with one decimal place from 0.0=cold to 100.0=warm\n\nThe communication is fully event based and does not poll each side. There are little problems with the conversion of units that are solved by using a short \"lock\" of a few seconds once one side - either Loxone or IKEA Tradfri gateway - has send a new event. By using this lock an ongoing \"ping pong\" is prevented.\n\nOn the Loxone side you may use the light control v2 function block with an output of type lumitech that is connected to a virtual output (no real address required) and a virtual output command (again, no specific configuration required). The output just has to be defined to be included in the structure file (http://miniserver/data/LoxAPP3.json).\n\nOn the IKEA tradfri side you have to deal with the instance ID's of your light bulbs, but with a debug node that is connected to the tradfri-monitor node it is quite easy to see all information from your light bulbs that have changed their values.",
"category": "",
"in": [
{
"x": 60,
"y": 100,
"wires": [
{
"id": "0d62f659c1a26115"
}
]
}
],
"out": [
{
"x": 1040,
"y": 240,
"wires": [
{
"id": "930a0b1315772b31",
"port": 0
},
{
"id": "7d9d8d1204279594",
"port": 0
}
]
},
{
"x": 1040,
"y": 300,
"wires": [
{
"id": "7d9d8d1204279594",
"port": 1
},
{
"id": "1038dd5d0313899a",
"port": 0
}
]
}
],
"env": [],
"meta": {
"module": "Loxone - Tradfri GW translator for tunable white light bulbs",
"version": "0.1.0",
"author": "jan.wachsmuth@web.de",
"desc": "Translator between Loxone Lumitech and Tradfri tunable white light bulbs (node-red-contrib-ikea-tradfri)",
"keywords": "Loxone IKEA Tradfri node-red-contrib-ikea-tradfri tunable white",
"license": "MIT"
},
"color": "#FDF0C2",
"inputLabels": [
"Event from Loxone or IKEA Tradfri gateway"
],
"outputLabels": [
"Output to loxone-control-out node",
"Output to tradfri-light-control"
],
"icon": "node-red/light.svg"
},
{
"id": "930a0b1315772b31",
"type": "function",
"z": "0c80c77a78fa17d1",
"name": "get Tradfri lightbulb info",
"func": "var brightness, colorTemp;\n\n// color information from an IKEA Tradfri module\n\n// brightness from 0..100\nbrightness = Math.round(msg.payload.dimmer);\n\n// Loxone does not has a separate value for brightness and on/off, \n// so brightness is set to 0, if the light is off\nif (!msg.payload.isOn)\n brightness = 0;\n\n// colorTemp in from 100=warm to 0=cold\ncolorTemp = msg.payload.colorTemperature;\n \n// convert colorTemperature from node-red-contrib-ikea-tradfri to Kelvin\n// node-red-contrib-ikea-tradfri is using 100=warm to 0=cold\n// IKEA is using white spectrum [cold=250, warm=454] in Mireds \n// Loxone is using color temperature in Kelvin\n// 2700 K (Loxone) = warm white = 454 (IKEA) = 100 (node-red-contrib-ikea-tradfri)\n// 6500 K (Loxone) = cool white = 250 (IKEA) = 0 (node-red-contrib-ikea-tradfri)\ncolorTemp = Math.round(6500 - colorTemp / 100 * (6500 - 2700));\n\n//node.warn(\"Loxone brightness=\" + brightness + \", colorTemp=\" + colorTemp);\n\n// output to Loxone\nreturn { payload: 'temp(' + brightness + ',' + colorTemp + ')' };\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 610,
"y": 240,
"wires": [
[]
],
"inputLabels": [
"Tradfri control properties"
],
"outputLabels": [
"brightness"
]
},
{
"id": "7d9d8d1204279594",
"type": "function",
"z": "0c80c77a78fa17d1",
"name": "get Loxone colorpickerV2 info",
"func": "var retVal = [null, null];\nvar rgb, brightness = 0, colorTemp = 2700, hsv = [0, 0, 0];\n\n// color information from a Lumitech control in Loxone\n// is either in proper format 'temp(brightness,colorTemp)' ...\nif (msg.payload.slice(0, 4) == \"temp\") {\n // brightness from 0..100 and colorTemp in k from 2700 to 6500\n [brightness, colorTemp] = msg.payload.slice(5, -1).split(\",\");\n}\n\n// ... or in format 'hsv(hue,saturation,value)'\nif (msg.payload.slice(0, 3) == \"hsv\") {\n hsv = msg.payload.slice(4, -1).split(\",\");\n\n // brightness from 0..100 is third number\n brightness = hsv[2];\n \n // colorTemp is set to neutral\n // a conversion from hsv to rgb would give values > 6500 for temp, so this is dropped\n colorTemp = 4600;\n\n // output back to Loxone to change from RGB to dual white\n retVal[0] = { payload: 'temp(' + brightness + ',' + colorTemp + ')' };\n}\n// convert to number\nbrightness = parseInt(brightness,10);\n\n// convert colorTemperature from Kelvin to a value: 0.0=cold to 100.0=warm \n// 2700 K = warm white = 454 (IKEA value) = 100 (node-red-contrib-ikea-tradfri)\n// 6500 K = cool white = 250 (IKEA value) = 0 (node-red-contrib-ikea-tradfri)\ncolorTemp = Math.round(1000 - (colorTemp - 2700) / (6500 - 2700) * 1000) / 10;\n\nnode.warn(\"Tradfri brightness=\" + brightness + \", colorTemp=\" + colorTemp);\n\nmsg = {};\nmsg.topic = 1;\nmsg.payload = {};\nmsg.payload.transitionTime = 1;\nmsg.payload.colorTemperature = colorTemp; \n\n// don't send brightness to the light bulb, if it was switched off - this preserves the old value,\n// so the old brightness is restored, when the bulb is turned on by a button or IKEA remote control \nif (brightness > 0) {\n msg.payload.brightness = brightness;\n //msg.payload.onOff = true; \n}\nelse\n msg.payload.onOff = false; \n \n// output only to Tradfri gateway\nretVal[1] = msg;\n\nreturn retVal;",
"outputs": 2,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 630,
"y": 300,
"wires": [
[],
[
"3e755ab51c758d93"
]
]
},
{
"id": "35b740fbb06af02e",
"type": "trigger",
"z": "0c80c77a78fa17d1",
"name": "",
"op1": "true",
"op2": "false",
"op1type": "bool",
"op2type": "bool",
"duration": "3",
"extend": true,
"overrideDelay": false,
"units": "s",
"reset": "",
"bytopic": "all",
"topic": "topic",
"outputs": 1,
"x": 560,
"y": 120,
"wires": [
[
"84aca9817b674067"
]
]
},
{
"id": "54e1282461153296",
"type": "change",
"z": "0c80c77a78fa17d1",
"name": "Event from Loxone",
"rules": [
{
"t": "set",
"p": "eventFromLoxone",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 750,
"y": 520,
"wires": [
[
"4161281e4cd3a68c"
]
]
},
{
"id": "a46d182146b622c7",
"type": "switch",
"z": "0c80c77a78fa17d1",
"name": "blocki tradfri input?",
"property": "eventFromLoxone",
"propertyType": "flow",
"rules": [
{
"t": "true"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 350,
"y": 180,
"wires": [
[],
[
"930a0b1315772b31",
"35b740fbb06af02e",
"7af0262630a8ccc0"
]
]
},
{
"id": "bfc4df008e93c1e2",
"type": "switch",
"z": "0c80c77a78fa17d1",
"name": "block loxone input?",
"property": "eventFromTradfri",
"propertyType": "flow",
"rules": [
{
"t": "true"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 350,
"y": 340,
"wires": [
[],
[
"7d9d8d1204279594",
"dd67214b82d879e8",
"802ee46615ccdcce"
]
]
},
{
"id": "4161281e4cd3a68c",
"type": "debug",
"z": "0c80c77a78fa17d1",
"name": "Event from Loxone",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 970,
"y": 520,
"wires": []
},
{
"id": "dd67214b82d879e8",
"type": "trigger",
"z": "0c80c77a78fa17d1",
"name": "",
"op1": "true",
"op2": "false",
"op1type": "bool",
"op2type": "bool",
"duration": "3",
"extend": true,
"overrideDelay": false,
"units": "s",
"reset": "",
"bytopic": "all",
"topic": "topic",
"outputs": 1,
"x": 560,
"y": 520,
"wires": [
[
"54e1282461153296"
]
]
},
{
"id": "84aca9817b674067",
"type": "change",
"z": "0c80c77a78fa17d1",
"name": "Event from Tradfri",
"rules": [
{
"t": "set",
"p": "eventFromTradfri",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 750,
"y": 120,
"wires": [
[
"53da3ee2b237186f"
]
]
},
{
"id": "53da3ee2b237186f",
"type": "debug",
"z": "0c80c77a78fa17d1",
"name": "Event from Tradfri",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 970,
"y": 120,
"wires": []
},
{
"id": "0d62f659c1a26115",
"type": "switch",
"z": "0c80c77a78fa17d1",
"name": "from?",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "fromTradfri",
"vt": "str"
},
{
"t": "eq",
"v": "fromLoxone",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 130,
"y": 240,
"wires": [
[
"a46d182146b622c7"
],
[
"bfc4df008e93c1e2"
]
],
"inputLabels": [
"Event from Loxone or Tradfri Gateway?"
],
"outputLabels": [
"Events from Tradfri Gateway",
"Events from Loxone Gateway"
]
},
{
"id": "7af0262630a8ccc0",
"type": "debug",
"z": "0c80c77a78fa17d1",
"name": "Spot A1 from Tradfri Gateway",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 630,
"y": 180,
"wires": []
},
{
"id": "802ee46615ccdcce",
"type": "debug",
"z": "0c80c77a78fa17d1",
"name": "Spot A1 from Loxone",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 600,
"y": 460,
"wires": []
},
{
"id": "1038dd5d0313899a",
"type": "delay",
"z": "0c80c77a78fa17d1",
"name": "delay for transitionTime * 1.5",
"pauseType": "delayv",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 800,
"y": 360,
"wires": [
[]
]
},
{
"id": "afa9f7a1ab61b87e",
"type": "comment",
"z": "0c80c77a78fa17d1",
"name": "Workaround for tunable white ",
"info": "Workaround for moods where brightness AND colorTemperature are changed at the same time.\n\nHowever it may have side effects when many changes are send in a short amount of time.\n\nA better workaround is to set msg.payload.transitionTime = 0;\n\nWith that setting, you don't have the soft dimming that is quite nice, but it's working fine. \n\nWhen the issue is fixed, you may change the transitionTime back to 1 or more seconds to get back the soft dimming.",
"x": 640,
"y": 400,
"wires": []
},
{
"id": "3e755ab51c758d93",
"type": "change",
"z": "0c80c77a78fa17d1",
"name": "add delay",
"rules": [
{
"t": "set",
"p": "delay",
"pt": "msg",
"to": "payload.transitionTime * 1500",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 580,
"y": 360,
"wires": [
[
"1038dd5d0313899a"
]
]
},
{
"id": "922bb42aec09c9e6",
"type": "tab",
"label": "tunable white example",
"disabled": false,
"info": "",
"env": []
},
{
"id": "69ebc498059e3ede",
"type": "tradfri-state",
"z": "922bb42aec09c9e6",
"gateway": "06a0a469d683c2d3",
"name": "Spot A1 Arbeitszimmer",
"accessories": [
"65550"
],
"groups": [
""
],
"logInputErrors": true,
"x": 1030,
"y": 1240,
"wires": [
[]
]
},
{
"id": "a574f827b846868c",
"type": "tradfri-light-control",
"z": "922bb42aec09c9e6",
"gateway": "06a0a469d683c2d3",
"name": "Tradfri Spot",
"action": "{}",
"accessories": [
"65550",
"65551",
"65552",
"65553",
"65554"
],
"groups": [
""
],
"logInputErrors": true,
"x": 1090,
"y": 420,
"wires": []
},
{
"id": "8a0f2121627e90bf",
"type": "function",
"z": "922bb42aec09c9e6",
"name": "add onOff property",
"func": "var x = msg.payload;\n\nmsg.payload = {\"isOn\": x}\ndelete msg.topic;\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 330,
"y": 1320,
"wires": [
[]
]
},
{
"id": "0ac2539172469261",
"type": "tradfri-monitor",
"z": "922bb42aec09c9e6",
"gateway": "06a0a469d683c2d3",
"name": "Spot A1",
"x": 100,
"y": 80,
"wires": [
[
"7cceb554cb2f621f"
]
]
},
{
"id": "995c70f889b1b3cf",
"type": "debug",
"z": "922bb42aec09c9e6",
"name": "Tradfri",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": true,
"complete": "payload",
"targetType": "msg",
"statusVal": "payload",
"statusType": "auto",
"x": 490,
"y": 220,
"wires": []
},
{
"id": "d6afd3aeabbb473f",
"type": "loxone-control-out",
"z": "922bb42aec09c9e6",
"name": "Tradfri Spot A1",
"miniserver": "1e51a4aa1ec3da6d",
"control": "0b715072-0065-c156-ffffefc088fafadd/AI2",
"x": 1100,
"y": 340,
"wires": []
},
{
"id": "2014fb3205878d86",
"type": "loxone-control-in",
"z": "922bb42aec09c9e6",
"name": "Tradfri Spot A1",
"miniserver": "1e51a4aa1ec3da6d",
"control": "0b715072-0065-c156-ffffefc088fafadd/AI2",
"state": "12df38ed-032f-9d40-ffff525a658b3902",
"x": 160,
"y": 340,
"wires": [
[
"9a9425665d4796fa"
]
]
},
{
"id": "acbb0e39095ae029",
"type": "ui_switch",
"z": "922bb42aec09c9e6",
"d": true,
"name": "",
"label": "switch",
"tooltip": "",
"group": "9f945d53947ae192",
"order": 1,
"width": 0,
"height": 0,
"passthru": true,
"decouple": "false",
"topic": "onOff",
"topicType": "str",
"style": "",
"onvalue": "true",
"onvalueType": "bool",
"onicon": "",
"oncolor": "",
"offvalue": "false",
"offvalueType": "bool",
"officon": "",
"offcolor": "",
"animate": false,
"className": "",
"x": 570,
"y": 1260,
"wires": [
[
"666235fe4cc84e42"
]
]
},
{
"id": "939ba2da073cfb7d",
"type": "debug",
"z": "922bb42aec09c9e6",
"name": "Spot A1 send to Loxone",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 1130,
"y": 280,
"wires": []
},
{
"id": "45a3489a146152d8",
"type": "debug",
"z": "922bb42aec09c9e6",
"name": "Spot A1 send to Tradfri Gateway",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 1140,
"y": 520,
"wires": []
},
{
"id": "7cceb554cb2f621f",
"type": "switch",
"z": "922bb42aec09c9e6",
"name": "Split Events",
"property": "payload.instanceId",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "65550",
"vt": "num"
},
{
"t": "eq",
"v": "65551",
"vt": "num"
},
{
"t": "eq",
"v": "65552",
"vt": "num"
},
{
"t": "eq",
"v": "65553",
"vt": "num"
},
{
"t": "eq",
"v": "65554",
"vt": "num"
},
{
"t": "eq",
"v": "65549",
"vt": "num"
},
{
"t": "eq",
"v": "65555",
"vt": "num"
}
],
"checkall": "false",
"repair": false,
"outputs": 7,
"x": 290,
"y": 180,
"wires": [
[
"0cce3bc6957b2e79"
],
[],
[],
[],
[],
[
"995c70f889b1b3cf"
],
[
"995c70f889b1b3cf"
]
],
"inputLabels": [
"Tradfri Events"
],
"outputLabels": [
"Tradfri Spot A1",
"",
"",
"",
"",
"",
null
]
},
{
"id": "0cce3bc6957b2e79",
"type": "change",
"z": "922bb42aec09c9e6",
"name": "Lightbulb, from Tradfri",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.lightbulb",
"tot": "msg"
},
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "fromTradfri",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 540,
"y": 160,
"wires": [
[
"48f101cf816f294e"
]
]
},
{
"id": "666235fe4cc84e42",
"type": "debug",
"z": "922bb42aec09c9e6",
"name": "onOff",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 730,
"y": 1300,
"wires": []
},
{
"id": "48f101cf816f294e",
"type": "subflow:0c80c77a78fa17d1",
"z": "922bb42aec09c9e6",
"name": "Loxone - Tradfri translation",
"x": 780,
"y": 340,
"wires": [
[
"939ba2da073cfb7d",
"d6afd3aeabbb473f"
],
[
"a574f827b846868c",
"45a3489a146152d8"
]
]
},
{
"id": "9a9425665d4796fa",
"type": "change",
"z": "922bb42aec09c9e6",
"name": "Lightbulb, from Loxone",
"rules": [
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "fromLoxone",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 470,
"y": 340,
"wires": [
[
"48f101cf816f294e"
]
]
},
{
"id": "06a0a469d683c2d3",
"type": "tradfri-config",
"name": "MyHome",
"gatewayHost": "TRADFRI-Gateway-MAC-address.local",
"identity": "my_tradfri_identity",
"preSharedKey": "my_tradfri_psk"
},
{
"id": "1e51a4aa1ec3da6d",
"type": "loxone-miniserver",
"host": "192.168.1.25",
"port": "80",
"enctype": "0",
"active": true,
"keepalive": "30000"
},
{
"id": "9f945d53947ae192",
"type": "ui_group",
"name": "Licht Arbeitszimmer",
"tab": "348a8a2c8d17ee09",
"order": 2,
"disp": true,
"width": "6",
"collapse": false,
"className": ""
},
{
"id": "348a8a2c8d17ee09",
"type": "ui_tab",
"name": "Home",
"icon": "dashboard",
"disabled": false,
"hidden": false
}
]