Here is a simple integration of OpenLuup/vera device to Alexa via Node-red.
The speed is fast sub 1 second responses.
Requirements -
node-red.
alexa.
node-red-contrib-amazon-echo(local Hue devices).
openluup or Vera (or any controller via http requests).
Capabilities-
Binary switch.
dimming switch.
rgb switch.
Run scenes.
Each alexa device node is configured in the topic of the amazon-echo device node -
(device number#type of switch)
bnary - 123#binary.
dimming - 123#dimming.
rgb - 123#colour (W/D is default 310 to adjust colour temp add value to end e.g. 123#colour#300
scene - 123#scene#124 (123 on 124 off. 124 can be omitted).
Enter the ip of your controller in the http request block.
Just copy code and import into Node-red
[
{
"id": "de7838ac.ebead",
"type": "amazon-echo-hub",
"z": "8659fc6b.981b4",
"port": "8980",
"processinput": "0",
"discovery": true,
"x": 150,
"y": 840,
"wires": [
[
"cd0ae070.e98378",
"a605448.899d8b8",
"21ca89ff.b0f6ce"
]
]
},
{
"id": "a605448.899d8b8",
"type": "amazon-echo-device",
"z": "8659fc6b.981b4",
"name": "bedroom four",
"topic": "199#colour",
"x": 410,
"y": 860,
"wires": [
[
"688830f.c57775"
]
]
},
{
"id": "21ca89ff.b0f6ce",
"type": "amazon-echo-device",
"z": "8659fc6b.981b4",
"name": "app safe",
"topic": "164#binary",
"x": 390,
"y": 900,
"wires": [
[
"688830f.c57775"
]
]
},
{
"id": "cd0ae070.e98378",
"type": "amazon-echo-device",
"z": "8659fc6b.981b4",
"name": "lounge 1",
"topic": "8#dimming",
"x": 390,
"y": 940,
"wires": [
[
"688830f.c57775"
]
]
},
{
"id": "688830f.c57775",
"type": "function",
"z": "8659fc6b.981b4",
"name": "",
"func": "let types = {\n \"dimming\":[\"urn:upnp-org:serviceId:Dimming1\",\"SetLoadLevelTarget\",\"newLoadlevelTarget\"],\n \"binary\":[\"urn:upnp-org:serviceId:SwitchPower1\",\"SetTarget\",\"newTargetValue\"],\n \"scene\":[\"urn:micasaverde-com:serviceId:HomeAutomationGateway1\",\"RunScene\",\"SceneNum\"],\n \"colour\":[\"urn:micasaverde-com:serviceId:Color1\",{\"tt\":\"SetColor\",\"hs\":\"SetColorRGB\",\"ct\":\"SetColorTemp\"},{\"tt\":\"newColorTarget\",\"hs\":\"newColorRGBTarget\",\"ct\":\"newColorTempTarget\"}] \t\n}\nfunction binaryPayload(device, type, turnOn, payload) {\n payload.id = \"action\";\n payload.serviceId = type[0];\n payload.DeviceNum = device;\n payload.action = type[1];\n payload[type[2]] = (turnOn === true ? 1 : 0);\n payload.message = payload[type[2]];\nreturn payload;\n}\n\nfunction dimmingPayload(device, type, level, payload) {\n payload.id = \"action\";\n payload.serviceId = type[0];\n payload.DeviceNum = device;\n payload.action = type[1];\n payload[type[2]] = level;\n payload.message = level;\nreturn payload;\n}\nfunction scenePayload(device, type, turnOn, payload) {\n payload.id = \"action\";\n payload.serviceId = type[0];\n payload.action = type[1];\n payload[type[2]] = (turnOn === true ? device[0] : (device[2] || device[0]));\n payload.message =\"Run Scene \" + payload[type[2]];\nreturn payload;\n}\n\nfunction rgbPayload(device, types, msg, payload) { \n if(msg.on === true && msg.meta.changes.on === false && msg.meta[\"input\"].on === true){\n payload = binaryPayload(device[0], types[\"binary\"], msg.on, {});\n }else if (msg.meta.changes.percentage && msg.on === true){\n payload = dimmingPayload(device[0], types[\"dimming\"], msg.percentage, {});\n }else if (msg.on === true && msg.colormode === \"hs\"){\n payload.id = \"action\";\n payload.serviceId = types[\"colour\"][0];\n payload.DeviceNum = device[0];\n payload.action = types[\"colour\"][1][\"hs\"];\n payload[types[\"colour\"][2][\"hs\"]] = msg.rgb.join(\",\");\n payload.message = msg.rgb.join(\",\");\n }else if (msg.on === true && msg.colormode === \"ct\"){\n let diff = msg.ct - (Number(device[2]) || 310);\n msg.ct = (diff < 0) ? \"D\" + Math.min(Math.abs(diff * 1.7),255).toFixed() : \"W\" + Math.abs(Math.min((diff * 1.7),255) - 255).toFixed();\n payload.id = \"action\";\n payload.serviceId = types[\"colour\"][0];\n payload.DeviceNum = device[0];\n payload.action = types[\"colour\"][1][\"ct\"];\n payload[types[\"colour\"][2][\"ct\"]] = msg.ct;\n payload.message = msg.ct;\n }\nreturn payload;\n}\n\nmsg.topic = msg.topic.split(\"#\").map(Function.prototype.call, String.prototype.trim);\nmsg.hold = msg.payload;\nmsg.payload = {};\nlet type = msg.topic[1] || \"binary\";\nif(msg.topic[1] === \"scene\"){\n msg.payload = scenePayload(msg.topic, types[\"scene\"], msg.on, {});\n}else if (msg.topic[1] === \"binary\" || msg.percentage === 0 || msg.on === false){\n msg.payload = binaryPayload(msg.topic[0], types[\"binary\"], msg.on, {});\n}else if(msg.topic[1] ===\"dimming\"){\n msg.payload = dimmingPayload(msg.topic[0], types[\"dimming\"], msg.percentage, {});\n}else if (msg.topic[1] === \"colour\"){\n msg.payload = rgbPayload(msg.topic, types, msg, {});\n}\nlet error = [\"green\", msg.topic[1] + \" | \" + msg.topic[0], msg.payload.message];\ndelete msg.payload.message;\nif (Object.keys(msg.payload).length < 1){\n error[0] =\"red\";\n error[2] =\"failed to create payload\";\n}\nnode.status({\"fill\": error[0],\"shape\":\"ring\",\"text\": error[1] + \" | \" + error[2]});\n\nreturn msg;\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 590,
"y": 940,
"wires": [
[
"680d28ae.8a163"
]
]
},
{
"id": "680d28ae.8a163",
"type": "http request",
"z": "8659fc6b.981b4",
"name": "Get request",
"method": "GET",
"ret": "txt",
"paytoqs": "query",
"url": "http://192.168.1.11:3480/data_request",
"tls": "",
"persist": false,
"proxy": "",
"authType": "",
"x": 760,
"y": 1000,
"wires": [
[
"cb471442.5d60c8"
]
]
}
]