For an example of triggering an Alexa routine I've cut off a flow which comes from a sensor, but you can inject, after selecting, to any one of your routines. To identify the routine id use the first flow to obtain a JSON file of all your routines. I paste this into a JSON editor and then do a search for name or text.
2 flows
[
{
"id": "def7600210803eeb",
"type": "alexa-remote-other",
"z": "21d84dbb515216e9",
"name": "",
"account": "c8738129.d902c",
"config": {
"option": "get",
"value": {
"what": "automationRoutines"
}
},
"x": 445,
"y": 1635,
"wires": [
[
"0abbf3c1275e6f45"
]
]
},
{
"id": "0abbf3c1275e6f45",
"type": "debug",
"z": "21d84dbb515216e9",
"name": "debug 2742",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 845,
"y": 1635,
"wires":
},
{
"id": "4dfc8442c13e9286",
"type": "inject",
"z": "21d84dbb515216e9",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 150,
"y": 1635,
"wires": [
[
"def7600210803eeb"
]
]
},
{
"id": "c3268dd5e3e811e5",
"type": "alexa-remote-routine",
"z": "21d84dbb515216e9",
"name": "",
"account": "c8738129.d902c",
"routineNode": {
"type": "routine",
"payload": {
"routine": {
"type": "str",
"value": "amzn1.alexa.automation.a6ae1445-9686-4990-a5d0-71753aec92d5"
},
"device": {
"type": "str",
"value": "G0014D05950217R3"
}
}
},
"x": 425,
"y": 1785,
"wires": [
]
},
{
"id": "3c0273531140159d",
"type": "inject",
"z": "21d84dbb515216e9",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "Hello in the kitchen hope you are having a nice day",
"payloadType": "str",
"x": 150,
"y": 1785,
"wires": [
[
"c3268dd5e3e811e5"
]
]
},
{
"id": "2036e74dbc3ac86a",
"type": "comment",
"z": "21d84dbb515216e9",
"name": "Identify Alexa Routines (JSON)",
"info": "",
"x": 175,
"y": 1545,
"wires":
},
{
"id": "00743065292fca9a",
"type": "comment",
"z": "21d84dbb515216e9",
"name": "Trigger a Routine",
"info": "",
"x": 155,
"y": 1710,
"wires":
},
{
"id": "c8738129.d902c",
"type": "alexa-remote-account",
"name": "alexa remote 2",
"authMethod": "proxy",
"proxyOwnIp": "192.168.0.85",
"proxyPort": "3456",
"cookieFile": "/data/context/alexa.json",
"refreshInterval": "14",
"alexaServiceHost": "alexa.amazon.es",
"pushDispatchHost": "",
"amazonPage": "amazon.es",
"acceptLanguage": "es-ES",
"onKeywordInLanguage": "",
"userAgent": "",
"usePushConnection": "on",
"autoInit": "on"
}
]
For an example of announcement and notification this is a flow I'm playing around with now, so there's room for improvement if anyone wants to suggest. It needs the ChatGPT node with the API Key.
I have it processing the weather alerts that I get from Openweather API. Basically these alerts are rather poorly composed, sometimes very long and where I am, mix English and Spanish. So I give an instruction to ChatGPT in the function node to resume and translate them. I have put a recent alert in the inject node so you can try anything there.
Flow
[
{
"id": "9ec27c6166de10dd",
"type": "http request",
"z": "1df1e1e64c4206dc",
"name": "Request to OpenAI",
"method": "POST",
"ret": "obj",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": ,
"x": 730,
"y": 440,
"wires": [
[
"910402d9cb1be179",
"a262c2e6c7f96b80"
]
]
},
{
"id": "84d5f4f5de057ec9",
"type": "alexa-remote-routine",
"z": "1df1e1e64c4206dc",
"name": "Echo Pasillo",
"account": "c8738129.d902c",
"routineNode": {
"type": "speak",
"payload": {
"type": "announcement",
"text": {
"type": "msg",
"value": "payload"
},
"devices": [
"G0014D0594970BXM"
]
}
},
"x": 1170,
"y": 520,
"wires": [
]
},
{
"id": "8c3389be0598a84f",
"type": "inject",
"z": "1df1e1e64c4206dc",
"name": "Free form text for Open API",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "Maximum gust of wind: 70 km/h. Viento del oeste. El aviso se refiere principalmente al sur de la zona.",
"payloadType": "str",
"x": 200,
"y": 380,
"wires": [
[
"83bd7a8f6dbf5248"
]
]
},
{
"id": "abab11b413a1fd3d",
"type": "alexa-remote-routine",
"z": "1df1e1e64c4206dc",
"name": "Alexa",
"account": "c8738129.d902c",
"routineNode": {
"type": "pushNotification",
"payload": {
"text": {
"type": "msg",
"value": "payload"
},
"title": {
"type": "str",
"value": "Alexa AI"
}
}
},
"x": 1190,
"y": 600,
"wires": [
]
},
{
"id": "910402d9cb1be179",
"type": "function",
"z": "1df1e1e64c4206dc",
"name": "Splits chunks 255 for Echo",
"func": "// Function to clean up duplicated line feeds\nfunction cleanUpText(text) {\n // Replace multiple occurrences of line feed (\n) or carriage return + line feed (\r\n) with a single line feed\n return text.replace(/(\r\n|\n)+/g, '\n');\n}\n\n// Function to split the text into chunks of 250 characters\nfunction splitText(text) {\n const maxLength = 250;\n let result = ;\n let start = 0;\n\n while (start < text.length) {\n // Slice up to the maxLength\n let end = Math.min(start + maxLength, text.length);\n // Find the last occurrence of a full stop or comma within the slice\n let splitPoint = Math.max(text.lastIndexOf('.', end), text.lastIndexOf(',', end));\n\n // If no full stop or comma is found, look for the last space to avoid splitting words\n if (splitPoint === -1 || splitPoint <= start) {\n splitPoint = text.lastIndexOf(' ', end);\n\n // If no space is found, split at the max length\n if (splitPoint === -1 || splitPoint <= start) {\n splitPoint = end;\n }\n }\n\n // Push the chunk to the result array\n result.push(text.slice(start, splitPoint + 1).trim());\n\n // Update the starting point for the next chunk\n start = splitPoint + 1;\n }\n\n return result;\n}\n\n\n// Function to send chunks in sequence with a 10-second delay (max 5 chunks)\nfunction sendChunksWithDelay(chunks) {\n // Limit the number of chunks to 3\n let maxChunks = Math.min(chunks.length, 3);\n \n for (let index = 0; index < maxChunks; index++) {\n setTimeout(() => {\n // Construct the message with the same key for each chunk\n let chunkMsg = { payload: chunks[index] };\n // Send the message\n node.send(chunkMsg);\n }, index * 10000); // 10 seconds per chunk\n }\n}\n\n// Get the incoming payload (text string)\nvar reply = msg.payload.choices[0].message.content\nvar text = "Hi John, " + reply;\n\n// Clean up duplicated line feeds from the text\ntext = cleanUpText(text);\n\n// Split the text into chunks\nlet chunks = splitText(text);\n\n// Send each chunk with a 10-second delay\nsendChunksWithDelay(chunks);\n\n// Return null because we are using node.send() to output messages asynchronously\nreturn null;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": ,
"x": 880,
"y": 520,
"wires": [
[
"84d5f4f5de057ec9"
]
]
},
{
"id": "a262c2e6c7f96b80",
"type": "function",
"z": "1df1e1e64c4206dc",
"name": "Splits chunks 125 for Alexa iPhone",
"func": "// Function to clean up duplicated line feeds\nfunction cleanUpText(text) {\n // Replace multiple occurrences of line feed (\n) or carriage return + line feed (\r\n) with a single line feed\n return text.replace(/(\r\n|\n)+/g, '\n');\n}\n\n// Function to split the text into chunks of 125 characters\nfunction splitText(text) {\n const maxLength = 125;\n let result = ;\n let start = 0;\n\n while (start < text.length) {\n // Slice up to the maxLength\n let end = Math.min(start + maxLength, text.length);\n // Find the last occurrence of a full stop or comma within the slice\n let splitPoint = Math.max(text.lastIndexOf('.', end), text.lastIndexOf(',', end));\n\n // If no full stop or comma is found, look for the last space to avoid splitting words\n if (splitPoint === -1 || splitPoint <= start) {\n splitPoint = text.lastIndexOf(' ', end);\n\n // If no space is found, split at the max length\n if (splitPoint === -1 || splitPoint <= start) {\n splitPoint = end;\n }\n }\n\n // Push the chunk to the result array\n result.push(text.slice(start, splitPoint + 1).trim());\n\n // Update the starting point for the next chunk\n start = splitPoint + 1;\n }\n\n return result;\n}\n\n\n// Function to send chunks in sequence with a 10-second delay (max 5 chunks)\nfunction sendChunksWithDelay(chunks) {\n // Limit the number of chunks to 3\n let maxChunks = Math.min(chunks.length, 3); \n for (let index = 0; index < maxChunks; index++) {\n setTimeout(() => {\n\n // Construct the message with the same key for each chunk\n let chunkMsg = { payload: chunks[index] };\n \n // Send the message asynchronously\n node.send(chunkMsg);\n }, index * 10000); // 10 seconds per chunk\n }\n}\n\n// Get the incoming payload (text string)\nvar reply = msg.payload.choices[0].message.content\nvar text = "Hi John, " + reply;\n\n// Function clean up duplicated line feeds from the text\ntext = cleanUpText(text);\n\n// Function split the text into chunks\nlet chunks = splitText(text);\n\n//Function send using node.send() each chunk with a 10-second delay\nsendChunksWithDelay(chunks);\n\n// Return null because we are using node.send() to output messages asynchronously\nreturn null;\n",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": ,
"x": 640,
"y": 600,
"wires": [
[
"abab11b413a1fd3d"
]
]
},
{
"id": "83bd7a8f6dbf5248",
"type": "function",
"z": "1df1e1e64c4206dc",
"name": "Prepare ChatGPT Request",
"func": "let api = msg.payload;\nlet txt = "Resume this weather report to a brief summary in familiar English";// Instruction to AI\n\n// Convert them to a string\napi = api.toString();\ntxt = txt.toString();\nmsg.payload = txt + ":- " +api;\n\n// Define the OpenAI API endpoint and key\nmsg.url = "https://api.openai.com/v1/chat/completions\";\nmsg.headers = {\n "Content-Type": "application/json",\n "Authorization": "Bearer sk-VBFD242464216431246363544543132341345341+35433"// API Key\n};\n\n// Prepare the body with model and messages (conversation history)\nmsg.payload = {\n model: "gpt-3.5-turbo", // specify GPT-3.5 turbo model or other\n messages: [\n { "role": "system", "content": "You are a helpful assistant." }, // Optional system role\n { "role": "user", "content": msg.payload } // User's input from the inject node\n ],\n max_tokens: 100, // Adjust the response length\n temperature: 0.7 // Adjust the creativity level\n};\n\nreturn msg;\n",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": ,
"x": 480,
"y": 440,
"wires": [
[
"9ec27c6166de10dd"
]
]
},
{
"id": "91cb24cfc5d2a247",
"type": "comment",
"z": "1df1e1e64c4206dc",
"name": "Api Key 1 ",
"info": "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",
"x": 120,
"y": 280,
"wires":
},
{
"id": "c8738129.d902c",
"type": "alexa-remote-account",
"name": "alexa remote 2",
"authMethod": "proxy",
"proxyOwnIp": "192.168.0.85",
"proxyPort": "3456",
"cookieFile": "/data/context/alexa.json",
"refreshInterval": "14",
"alexaServiceHost": "alexa.amazon.es",
"pushDispatchHost": "",
"amazonPage": "amazon.es",
"acceptLanguage": "es-ES",
"onKeywordInLanguage": "",
"userAgent": "",
"usePushConnection": "on",
"autoInit": "on"
}
]