[ { "id": "controller1", "type": "alexa-home-controller", "controllername": "Smart Home Hub", "port": "80", "useHttps": false, "useNode": false, "maxItems": -1, "x": 150, "y": 80, "wires": [] }, { "id": "living-room-light", "type": "alexa-home", "devicename": "Living Room Light", "devicetype": "Extended color light", "x": 150, "y": 160, "wires": [["device-router1"]] }, { "id": "kitchen-fan", "type": "alexa-home", "devicename": "Kitchen Fan", "devicetype": "Fan", "x": 150, "y": 200, "wires": [["device-router1"]] }, { "id": "front-door-lock", "type": "alexa-home", "devicename": "Front Door Lock", "devicetype": "Smart Lock", "x": 150, "y": 240, "wires": [["device-router1"]] }, { "id": "garage-door", "type": "alexa-home", "devicename": "Garage Door", "devicetype": "Garage Door Opener", "x": 150, "y": 280, "wires": [["device-router1"]] }, { "id": "thermostat", "type": "alexa-home", "devicename": "Living Room Thermostat", "devicetype": "Thermostat", "x": 150, "y": 320, "wires": [["device-router1"]] }, { "id": "motion-sensor", "type": "alexa-home", "devicename": "Living Room Motion", "devicetype": "Motion Sensor", "x": 150, "y": 360, "wires": [["device-router1"]] }, { "id": "contact-sensor", "type": "alexa-home", "devicename": "Front Door Sensor", "devicetype": "Contact Sensor", "x": 150, "y": 400, "wires": [["device-router1"]] }, { "id": "smart-switch", "type": "alexa-home", "devicename": "Patio Light Switch", "devicetype": "Smart Switch", "x": 150, "y": 440, "wires": [["device-router1"]] }, { "id": "window-blinds", "type": "alexa-home", "devicename": "Living Room Blinds", "devicetype": "Blinds", "x": 150, "y": 480, "wires": [["device-router1"]] }, { "id": "device-router1", "type": "function", "name": "Device Router & State Manager", "func": "// Central device router with state management and automation\n// Routes commands to appropriate handlers and manages device states\n\nconst deviceName = msg.alexa_device_name || 'Unknown Device';\nconst deviceType = msg.alexa_device_type || 'Unknown Type';\nconst command = msg.payload.command || 'unknown';\n\n// Initialize global context for device states if not exists\nif (!global.get('deviceStates')) {\n global.set('deviceStates', {});\n}\n\nconst deviceStates = global.get('deviceStates');\n\n// Update device state\ndeviceStates[deviceName] = {\n ...deviceStates[deviceName],\n lastCommand: command,\n lastUpdate: new Date().toISOString(),\n power: msg.payload.on,\n deviceType: deviceType\n};\n\n// Add device-specific state information\nswitch (deviceType) {\n case 'Extended color light':\n case 'Color light':\n case 'Dimmable light':\n deviceStates[deviceName] = {\n ...deviceStates[deviceName],\n brightness: msg.payload.bri_normalized || 0,\n color: msg.payload.xy || null\n };\n break;\n \n case 'Fan':\n deviceStates[deviceName] = {\n ...deviceStates[deviceName],\n speed: msg.payload.bri_normalized || 0 // Fan speed as percentage\n };\n break;\n \n case 'Thermostat':\n deviceStates[deviceName] = {\n ...deviceStates[deviceName],\n targetTemp: msg.payload.temperature || 22,\n mode: msg.payload.mode || 'auto'\n };\n break;\n \n case 'Blinds':\n deviceStates[deviceName] = {\n ...deviceStates[deviceName],\n position: msg.payload.percentage || 0 // 0 = closed, 100 = open\n };\n break;\n}\n\n// Save updated states\nglobal.set('deviceStates', deviceStates);\n\n// Create routing message\nconst routingMsg = {\n topic: `device/${deviceName.toLowerCase().replace(/\\s+/g, '_')}`,\n payload: {\n device: deviceName,\n deviceType: deviceType,\n command: command,\n originalPayload: msg.payload,\n state: deviceStates[deviceName],\n timestamp: new Date().toISOString()\n }\n};\n\n// Route to appropriate output based on device type\nswitch (deviceType) {\n case 'Extended color light':\n case 'Color light':\n case 'Dimmable light':\n return [routingMsg, null, null, null, null]; // Output 1: Lights\n \n case 'Fan':\n case 'Smart Switch':\n return [null, routingMsg, null, null, null]; // Output 2: Switches/Fans\n \n case 'Smart Lock':\n case 'Garage Door Opener':\n return [null, null, routingMsg, null, null]; // Output 3: Security\n \n case 'Thermostat':\n return [null, null, null, routingMsg, null]; // Output 4: Climate\n \n case 'Motion Sensor':\n case 'Contact Sensor':\n case 'Blinds':\n return [null, null, null, null, routingMsg]; // Output 5: Sensors/Blinds\n \n default:\n // Unknown device type - send to general output\n return [routingMsg, null, null, null, null];\n}", "outputs": 5, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 320, "wires": [ ["light-handler1"], ["switch-fan-handler1"], ["security-handler1"], ["climate-handler1"], ["sensor-blind-handler1"] ] }, { "id": "light-handler1", "type": "function", "name": "Light Controller", "func": "// Handle lighting devices with advanced color and brightness control\n\nconst device = msg.payload.device;\nconst state = msg.payload.state;\nconst original = msg.payload.originalPayload;\n\nlet output = {\n device: device,\n power: state.power,\n brightness: state.brightness || 0\n};\n\n// Handle color information\nif (state.color && Array.isArray(state.color)) {\n // Convert XY to RGB for hardware that needs it\n const x = state.color[0];\n const y = state.color[1];\n \n // Simplified XY to RGB conversion\n const z = 1.0 - x - y;\n const Y = state.brightness / 100;\n const X = (Y / y) * x;\n const Z = (Y / y) * z;\n \n // Convert to RGB (simplified)\n let r = X * 1.656492 - Y * 0.354851 - Z * 0.255038;\n let g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152;\n let b = X * 0.051713 - Y * 0.121364 + Z * 1.011530;\n \n // Normalize and convert to 0-255\n r = Math.max(0, Math.min(1, r)) * 255;\n g = Math.max(0, Math.min(1, g)) * 255;\n b = Math.max(0, Math.min(1, b)) * 255;\n \n output.color = {\n xy: state.color,\n rgb: {\n r: Math.round(r),\n g: Math.round(g),\n b: Math.round(b)\n }\n };\n}\n\n// Add specific control based on command\nswitch (original.command) {\n case 'switch':\n output.action = 'power';\n break;\n case 'dim':\n output.action = 'brightness';\n break;\n case 'color':\n output.action = 'color';\n break;\n default:\n output.action = 'status';\n}\n\nmsg.topic = `lights/${device.toLowerCase().replace(/\\s+/g, '_')}`;\nmsg.payload = output;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 680, "y": 200, "wires": [["mqtt-lights1", "debug-lights1"]] }, { "id": "switch-fan-handler1", "type": "function", "name": "Switch & Fan Controller", "func": "// Handle switches and fans with speed control\n\nconst device = msg.payload.device;\nconst state = msg.payload.state;\nconst original = msg.payload.originalPayload;\nconst deviceType = msg.payload.deviceType;\n\nlet output = {\n device: device,\n deviceType: deviceType,\n power: state.power\n};\n\nif (deviceType === 'Fan') {\n // Handle fan speed control\n output.speed = state.speed || 0;\n output.speedLevel = 'off';\n \n if (state.speed > 0 && state.speed <= 33) {\n output.speedLevel = 'low';\n } else if (state.speed > 33 && state.speed <= 66) {\n output.speedLevel = 'medium';\n } else if (state.speed > 66) {\n output.speedLevel = 'high';\n }\n \n output.action = original.command === 'dim' ? 'speed' : 'power';\n} else {\n // Handle simple switch\n output.action = 'power';\n}\n\nmsg.topic = `switches/${device.toLowerCase().replace(/\\s+/g, '_')}`;\nmsg.payload = output;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 690, "y": 260, "wires": [["mqtt-switches1", "debug-switches1"]] }, { "id": "security-handler1", "type": "function", "name": "Security Controller", "func": "// Handle security devices (locks, garage doors)\n\nconst device = msg.payload.device;\nconst state = msg.payload.state;\nconst original = msg.payload.originalPayload;\nconst deviceType = msg.payload.deviceType;\n\nlet output = {\n device: device,\n deviceType: deviceType,\n power: state.power,\n timestamp: state.lastUpdate\n};\n\nif (deviceType === 'Smart Lock') {\n output.locked = !state.power; // Inverted: on = unlocked, off = locked\n output.action = state.power ? 'unlock' : 'lock';\n output.status = state.power ? 'unlocked' : 'locked';\n \n // Security logging\n output.securityEvent = {\n type: 'lock_operation',\n action: output.action,\n device: device,\n timestamp: state.lastUpdate,\n source: 'alexa_voice_command'\n };\n \n} else if (deviceType === 'Garage Door Opener') {\n output.open = state.power;\n output.action = state.power ? 'open' : 'close';\n output.status = state.power ? 'open' : 'closed';\n \n // Security logging\n output.securityEvent = {\n type: 'garage_operation',\n action: output.action,\n device: device,\n timestamp: state.lastUpdate,\n source: 'alexa_voice_command'\n };\n}\n\nmsg.topic = `security/${device.toLowerCase().replace(/\\s+/g, '_')}`;\nmsg.payload = output;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 690, "y": 320, "wires": [["mqtt-security1", "debug-security1", "security-log1"]] }, { "id": "climate-handler1", "type": "function", "name": "Climate Controller", "func": "// Handle thermostat and climate control\n\nconst device = msg.payload.device;\nconst state = msg.payload.state;\nconst original = msg.payload.originalPayload;\n\nlet output = {\n device: device,\n power: state.power,\n targetTemp: state.targetTemp || 22,\n mode: state.mode || 'auto',\n timestamp: state.lastUpdate\n};\n\n// Handle temperature adjustments\nif (original.command === 'dim') {\n // Use brightness as temperature adjustment (-50 to +50)\n const tempAdjust = (original.bri_normalized - 50) / 2; // Scale to ±25°C\n output.targetTemp = Math.round((22 + tempAdjust) * 10) / 10; // Round to 0.1°C\n output.action = 'temperature';\n} else {\n output.action = state.power ? 'on' : 'off';\n}\n\n// Ensure reasonable temperature range\noutput.targetTemp = Math.max(10, Math.min(35, output.targetTemp));\n\n// Add climate status\noutput.status = {\n heating: output.targetTemp > 22 && state.power,\n cooling: output.targetTemp < 22 && state.power,\n auto: output.mode === 'auto' && state.power,\n off: !state.power\n};\n\nmsg.topic = `climate/${device.toLowerCase().replace(/\\s+/g, '_')}`;\nmsg.payload = output;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 680, "y": 380, "wires": [["mqtt-climate1", "debug-climate1"]] }, { "id": "sensor-blind-handler1", "type": "function", "name": "Sensor & Blind Controller", "func": "// Handle sensors and window coverings\n\nconst device = msg.payload.device;\nconst state = msg.payload.state;\nconst original = msg.payload.originalPayload;\nconst deviceType = msg.payload.deviceType;\n\nlet output = {\n device: device,\n deviceType: deviceType,\n timestamp: state.lastUpdate\n};\n\nif (deviceType === 'Blinds') {\n // Handle blind position control\n output.position = state.position || 0;\n output.action = original.command === 'dim' ? 'position' : 'power';\n \n if (original.command === 'dim') {\n output.position = original.bri_normalized || 0;\n } else {\n output.position = state.power ? 100 : 0; // Fully open or closed\n }\n \n output.status = {\n open: output.position > 50,\n closed: output.position < 10,\n partial: output.position >= 10 && output.position <= 50\n };\n \n} else {\n // Handle sensors (motion, contact)\n output.triggered = state.power;\n output.action = 'status';\n \n if (deviceType === 'Motion Sensor') {\n output.motion = state.power;\n output.status = state.power ? 'motion_detected' : 'no_motion';\n } else if (deviceType === 'Contact Sensor') {\n output.contact = state.power ? 'open' : 'closed';\n output.status = state.power ? 'door_open' : 'door_closed';\n }\n \n // Trigger automation if sensor is activated\n if (state.power) {\n output.automationTrigger = {\n type: deviceType.toLowerCase().replace(' ', '_'),\n device: device,\n timestamp: state.lastUpdate\n };\n }\n}\n\nmsg.topic = `sensors/${device.toLowerCase().replace(/\\s+/g, '_')}`;\nmsg.payload = output;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 700, "y": 440, "wires": [["mqtt-sensors1", "debug-sensors1", "automation-trigger1"]] }, { "id": "mqtt-lights1", "type": "mqtt out", "name": "Lights MQTT", "topic": "", "qos": "", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "", "x": 900, "y": 180, "wires": [] }, { "id": "mqtt-switches1", "type": "mqtt out", "name": "Switches MQTT", "topic": "", "qos": "", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "", "x": 910, "y": 240, "wires": [] }, { "id": "mqtt-security1", "type": "mqtt out", "name": "Security MQTT", "topic": "", "qos": "", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "", "x": 910, "y": 300, "wires": [] }, { "id": "mqtt-climate1", "type": "mqtt out", "name": "Climate MQTT", "topic": "", "qos": "", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "", "x": 900, "y": 360, "wires": [] }, { "id": "mqtt-sensors1", "type": "mqtt out", "name": "Sensors MQTT", "topic": "", "qos": "", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "", "x": 910, "y": 420, "wires": [] }, { "id": "debug-lights1", "type": "debug", "name": "Lights Debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 900, "y": 200, "wires": [] }, { "id": "debug-switches1", "type": "debug", "name": "Switches Debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 910, "y": 260, "wires": [] }, { "id": "debug-security1", "type": "debug", "name": "Security Debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 910, "y": 320, "wires": [] }, { "id": "debug-climate1", "type": "debug", "name": "Climate Debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 900, "y": 380, "wires": [] }, { "id": "debug-sensors1", "type": "debug", "name": "Sensors Debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 910, "y": 440, "wires": [] }, { "id": "security-log1", "type": "function", "name": "Security Logger", "func": "// Log security events to file or database\n\nif (msg.payload.securityEvent) {\n const logEntry = {\n timestamp: new Date().toISOString(),\n event: msg.payload.securityEvent,\n device: msg.payload.device,\n action: msg.payload.action,\n status: msg.payload.status\n };\n \n // Store in flow context for demonstration\n let securityLog = flow.get('securityLog') || [];\n securityLog.push(logEntry);\n \n // Keep only last 100 entries\n if (securityLog.length > 100) {\n securityLog = securityLog.slice(-100);\n }\n \n flow.set('securityLog', securityLog);\n \n // Send to security monitoring system\n msg.topic = 'security/events';\n msg.payload = logEntry;\n \n return msg;\n}\n\nreturn null;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 900, "y": 340, "wires": [["mqtt-security-log1"]] }, { "id": "automation-trigger1", "type": "function", "name": "Automation Engine", "func": "// Simple automation based on sensor triggers\n\nif (msg.payload.automationTrigger) {\n const trigger = msg.payload.automationTrigger;\n const deviceStates = global.get('deviceStates') || {};\n \n let automationActions = [];\n \n // Motion sensor automation\n if (trigger.type === 'motion_sensor' && trigger.device === 'Living Room Motion') {\n // Turn on living room light when motion detected\n automationActions.push({\n device: 'Living Room Light',\n action: 'turn_on',\n brightness: 80,\n color: [0.3227, 0.329], // Warm white\n reason: 'motion_detected'\n });\n }\n \n // Door sensor automation\n if (trigger.type === 'contact_sensor' && trigger.device === 'Front Door Sensor') {\n // Turn on patio light when door opens\n automationActions.push({\n device: 'Patio Light Switch',\n action: 'turn_on',\n reason: 'door_opened'\n });\n \n // Log security event\n automationActions.push({\n type: 'security_alert',\n message: 'Front door opened',\n timestamp: trigger.timestamp\n });\n }\n \n if (automationActions.length > 0) {\n msg.topic = 'automation/actions';\n msg.payload = {\n trigger: trigger,\n actions: automationActions,\n timestamp: new Date().toISOString()\n };\n \n return msg;\n }\n}\n\nreturn null;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 920, "y": 460, "wires": [["debug-automation1"]] }, { "id": "mqtt-security-log1", "type": "mqtt out", "name": "Security Log MQTT", "topic": "", "qos": "", "retain": "true", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "", "x": 930, "y": 340, "wires": [] }, { "id": "debug-automation1", "type": "debug", "name": "Automation Debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 920, "y": 480, "wires": [] }, { "id": "state-monitor1", "type": "inject", "name": "View Device States", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "{}", "payloadType": "json", "x": 160, "y": 560, "wires": [["state-viewer1"]] }, { "id": "state-viewer1", "type": "function", "name": "Device State Viewer", "func": "// Display current states of all devices\n\nconst deviceStates = global.get('deviceStates') || {};\nconst securityLog = flow.get('securityLog') || [];\n\nconst summary = {\n totalDevices: Object.keys(deviceStates).length,\n deviceStates: deviceStates,\n recentSecurityEvents: securityLog.slice(-5),\n devicesByType: {},\n powerStatus: {\n on: 0,\n off: 0\n },\n lastUpdated: new Date().toISOString()\n};\n\n// Categorize devices by type\nObject.keys(deviceStates).forEach(deviceName => {\n const device = deviceStates[deviceName];\n const type = device.deviceType || 'Unknown';\n \n if (!summary.devicesByType[type]) {\n summary.devicesByType[type] = [];\n }\n \n summary.devicesByType[type].push({\n name: deviceName,\n power: device.power,\n lastUpdate: device.lastUpdate\n });\n \n // Count power status\n if (device.power) {\n summary.powerStatus.on++;\n } else {\n summary.powerStatus.off++;\n }\n});\n\nmsg.topic = 'system/status';\nmsg.payload = summary;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 560, "wires": [["debug-states1"]] }, { "id": "debug-states1", "type": "debug", "name": "System States", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 580, "y": 560, "wires": [] }, { "id": "comment1", "type": "comment", "name": "Multi-Device Smart Home Integration", "info": "This example demonstrates comprehensive multi-device smart home integration with:\n\n**Device Types Supported:**\n- **Lighting**: Extended color, Color, Dimmable lights\n- **Climate**: Thermostat with temperature control\n- **Security**: Smart locks, Garage door openers\n- **Sensors**: Motion sensors, Contact sensors\n- **Switches**: Smart switches, Fans with speed control\n- **Window Coverings**: Blinds with position control\n\n**Key Features:**\n- Central device router with state management\n- Device-specific command processing\n- Global state persistence across Node-RED restarts\n- Automated device categorization and routing\n- Security event logging and monitoring\n- Basic automation engine with sensor triggers\n- MQTT integration with retained messages\n- Comprehensive debug outputs for each device type\n- Real-time device state monitoring\n\n**Voice Commands Examples:**\n- \"Alexa, turn on the living room light\"\n- \"Alexa, set the kitchen fan to medium speed\"\n- \"Alexa, lock the front door\"\n- \"Alexa, open the garage door\"\n- \"Alexa, set the thermostat to 72 degrees\"\n- \"Alexa, open the living room blinds\"\n\n**Automation Features:**\n- Motion detection → Auto light activation\n- Door sensor → Security lighting\n- Comprehensive security event logging\n- Device state persistence and monitoring\n\n**Technical Implementation:**\n- Global context for cross-flow device state\n- Flow context for security event history\n- MQTT topics organized by device category\n- Retained messages for state persistence\n- Error handling and device validation\n- Timestamp tracking for all operations\n\n**Setup Instructions:**\n1. Configure MQTT broker for all output nodes\n2. Customize device names and room assignments\n3. Adjust automation rules in automation engine\n4. Deploy flow and ask Alexa to discover devices\n5. Test individual devices and monitor debug output\n6. Use 'View Device States' to monitor system status", "x": 220, "y": 40, "wires": [] } ]