Embedded·2024

Whole-Home Smart Automation System

An integrated smart home system for high-end residences, supporting comprehensive control of lighting, HVAC, blinds, and security monitoring — with Apple HomeKit, Google Home, and Amazon Alexa integration

clientLuxury Residential Developer
duration12 months
categoryEmbedded
stack
ESP32ZigbeeMQTTNode.jsReact NativeHomeKitGoogle HomeAlexaKNX

Project Overview

A whole-home smart automation system built for a luxury residential developer, encompassing 200+ control points. The system integrates lighting control, HVAC systems, motorized blinds, security monitoring, and energy management. It adopts a hybrid communication architecture (Zigbee + WiFi + KNX), supports both local and cloud-based control, and fully integrates with the three major smart home platforms: Apple HomeKit, Google Home, and Amazon Alexa.

Currently deployed in 30+ luxury residences, managing over 6,000 device nodes, with a system stability rate of 99.8%.

System Architecture

Overall Architecture Diagram

+-------------------------------------------------------------+
|                     Cloud Layer                              |
|  +----------+  +----------+  +----------+  +----------+     |
|  | HomeKit  |  |  Google  |  |  Alexa   |  |  Custom  |     |
|  |  Bridge  |  |   Home   |  |  Skill   |  |   App    |     |
|  +----------+  +----------+  +----------+  +----------+     |
+-------------------------------------------------------------+
                              ^
                              | HTTPS / MQTT
                              v
+-------------------------------------------------------------+
|                    Gateway Layer                             |
|  +------------------------------------------------------+   |
|  |  Smart Home Central Hub (Raspberry Pi 4 / ESP32-S3)  |   |
|  |  - Node.js control logic                             |   |
|  |  - MQTT Broker (Mosquitto)                           |   |
|  |  - Scene automation engine                           |   |
|  |  - Local SQLite database                             |   |
|  +------------------------------------------------------+   |
+-------------------------------------------------------------+
           |              |              |              |
      Zigbee 3.0      WiFi 6          KNX IP        RS-485
           v              v              v              v
+-------------------------------------------------------------+
|                     Device Layer                             |
|  +------+  +------+  +------+  +------+  +------+          |
|  |Light |  | HVAC |  |Blinds|  |Secur.|  |Energy|          |
|  |Ctrl  |  | Ctrl |  | Ctrl |  |Monit.|  | Mgmt |          |
|  +------+  +------+  +------+  +------+  +------+          |
+-------------------------------------------------------------+

Core Technical Implementation

1. Zigbee 3.0 Wireless Mesh Network

Reasons for Choosing Zigbee:

  • Low power consumption (battery devices last 2+ years)
  • Self-organizing mesh network (single-point failure does not affect the whole)
  • Strong wall penetration (2.4GHz, more stable than WiFi)
  • Supports 200+ devices

ESP32 Zigbee Coordinator Implementation:

#include "esp_zigbee_core.h"
#include "esp_log.h"

#define TAG "ZIGBEE_GATEWAY"

// Zigbee coordinator configuration
esp_zb_cfg_t zigbee_config = {
    .esp_zb_role = ESP_ZB_DEVICE_TYPE_COORDINATOR,
    .install_code_policy = false,
    .nwk_cfg = {
        .zczr_cfg = {
            .max_children = 100,  // Maximum child devices
        },
    },
};

// Light device endpoint definition
esp_zb_on_off_light_cfg_t light_config = {
    .on_off_cfg = {
        .on_off = false,
    },
    .level_cfg = {
        .current_level = 128,  // Initial brightness 50%
    },
    .color_cfg = {
        .current_hue = 0,
        .current_saturation = 0,
        .color_temperature = 370,  // 2700K warm white
    },
};

void zigbee_gateway_init(void) {
    // Initialize Zigbee protocol stack
    esp_zb_init(&zigbee_config);

    // Create endpoint list
    esp_zb_ep_list_t *ep_list = esp_zb_ep_list_create();

    // Add HA (Home Automation) device type
    esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();

    // Basic Cluster (device information)
    esp_zb_basic_cluster_cfg_t basic_cfg = {
        .zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE,
        .power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE,
    };
    esp_zb_cluster_list_add_basic_cluster(cluster_list, &basic_cfg, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // Identify Cluster (device identification blinking)
    esp_zb_identify_cluster_cfg_t identify_cfg = {
        .identify_time = 0,
    };
    esp_zb_cluster_list_add_identify_cluster(cluster_list, &identify_cfg, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // On/Off Cluster (switch control)
    esp_zb_cluster_list_add_on_off_cluster(cluster_list, &light_config.on_off_cfg, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // Level Control Cluster (dimming control)
    esp_zb_cluster_list_add_level_cluster(cluster_list, &light_config.level_cfg, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // Color Control Cluster (color temperature / RGB control)
    esp_zb_cluster_list_add_color_control_cluster(cluster_list, &light_config.color_cfg, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);

    // Register endpoint
    esp_zb_endpoint_config_t endpoint_config = {
        .endpoint = HA_ESP_LIGHT_ENDPOINT,
        .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID,
        .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID,
        .app_device_version = 0,
    };
    esp_zb_ep_list_add_ep(ep_list, cluster_list, endpoint_config);

    // Register device and start
    esp_zb_device_register(ep_list);
    esp_zb_start(false);

    ESP_LOGI(TAG, "Zigbee gateway started, waiting for devices to join...");
}

// Zigbee message handling callback
static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message) {
    esp_err_t ret = ESP_OK;

    switch (callback_id) {
        case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID:
            // Received attribute set command (e.g., turn on light, adjust brightness)
            ret = zb_attribute_handler((esp_zb_zcl_set_attr_value_message_t *)message);
            break;

        case ESP_ZB_CORE_CMD_READ_ATTR_RESP_CB_ID:
            // Read device attribute response
            ret = zb_read_attr_resp_handler((esp_zb_zcl_cmd_read_attr_resp_message_t *)message);
            break;

        case ESP_ZB_CORE_REPORT_ATTR_CB_ID:
            // Device proactive status report (e.g., sensor values)
            ret = zb_report_attr_handler((esp_zb_zcl_report_attr_message_t *)message);
            break;

        default:
            ESP_LOGW(TAG, "Unhandled Zigbee action: %d", callback_id);
            break;
    }

    return ret;
}

2. MQTT Integration and Scene Automation

MQTT Topic Structure:

smarthome/
├── lights/
│   ├── living_room/lamp_1/status      → {"state": "ON", "brightness": 80, "color_temp": 4000}
│   ├── living_room/lamp_1/command     ← {"state": "ON", "brightness": 100}
│   ├── bedroom/ceiling/status
│   └── bedroom/ceiling/command
├── climate/
│   ├── living_room/ac/status          → {"state": "COOL", "temp": 24, "fan": "AUTO"}
│   ├── living_room/ac/command         ← {"state": "COOL", "temp": 26}
│   └── bedroom/ac/status
├── blinds/
│   ├── living_room/main/position      → {"position": 50, "tilt": 30}
│   └── living_room/main/command       ← {"action": "OPEN"}
└── security/
    ├── alarm/status                   → {"armed": true, "triggered": false}
    └── door_sensor/entrance/status    → {"state": "CLOSED", "battery": 85}

Node.js Scene Automation Engine:

const mqtt = require('mqtt');
const cron = require('node-cron');

class SmartHomeAutomation {
    constructor() {
        this.mqttClient = mqtt.connect('mqtt://localhost:1883');
        this.deviceStates = new Map();
        this.scenes = [];
        this.automations = [];

        this.initMQTT();
        this.loadScenes();
        this.loadAutomations();
    }

    initMQTT() {
        this.mqttClient.on('connect', () => {
            console.log('Connected to MQTT broker');

            // Subscribe to all device status topics
            this.mqttClient.subscribe('smarthome/+/+/status');
            this.mqttClient.subscribe('smarthome/+/+/+/status');
        });

        this.mqttClient.on('message', (topic, message) => {
            const state = JSON.parse(message.toString());
            this.deviceStates.set(topic, state);

            // Trigger automation rule check
            this.checkAutomationRules(topic, state);
        });
    }

    // Scene definition (execute multiple actions with one tap)
    defineScene(name, actions) {
        this.scenes.push({
            name,
            actions,
            execute: () => {
                console.log(`Executing scene: ${name}`);
                actions.forEach(action => {
                    this.mqttClient.publish(
                        action.topic,
                        JSON.stringify(action.payload)
                    );
                });
            }
        });
    }

    // Automation rule (condition-triggered)
    defineAutomation(name, conditions, actions) {
        this.automations.push({
            name,
            conditions,
            actions,
            lastTriggered: null
        });
    }

    checkAutomationRules(changedTopic, changedState) {
        this.automations.forEach(automation => {
            // Check if all conditions are met
            const conditionsMet = automation.conditions.every(condition => {
                const state = this.deviceStates.get(condition.topic);
                if (!state) return false;

                // Condition evaluation (supports ==, !=, >, <, >=, <=)
                return this.evaluateCondition(state, condition);
            });

            if (conditionsMet) {
                // Prevent repeated triggers within a short time
                const now = Date.now();
                if (automation.lastTriggered && (now - automation.lastTriggered) < 5000) {
                    return;
                }

                console.log(`Automation triggered: ${automation.name}`);
                automation.lastTriggered = now;

                // Execute actions
                automation.actions.forEach(action => {
                    this.mqttClient.publish(
                        action.topic,
                        JSON.stringify(action.payload)
                    );
                });
            }
        });
    }

    evaluateCondition(state, condition) {
        const value = state[condition.attribute];

        switch (condition.operator) {
            case '==': return value === condition.value;
            case '!=': return value !== condition.value;
            case '>': return value > condition.value;
            case '<': return value < condition.value;
            case '>=': return value >= condition.value;
            case '<=': return value <= condition.value;
            default: return false;
        }
    }

    loadScenes() {
        // Away mode: turn off all lights, HVAC, arm alarm
        this.defineScene('Away Mode', [
            { topic: 'smarthome/lights/all/command', payload: { state: 'OFF' } },
            { topic: 'smarthome/climate/all/command', payload: { state: 'OFF' } },
            { topic: 'smarthome/security/alarm/command', payload: { armed: true } },
        ]);

        // Home mode: turn on entrance and living room lights, disarm alarm
        this.defineScene('Home Mode', [
            { topic: 'smarthome/lights/entrance/command', payload: { state: 'ON', brightness: 80 } },
            { topic: 'smarthome/lights/living_room/command', payload: { state: 'ON', brightness: 60 } },
            { topic: 'smarthome/security/alarm/command', payload: { armed: false } },
        ]);

        // Movie mode: turn off main light, turn on ambient light, close blinds
        this.defineScene('Movie Mode', [
            { topic: 'smarthome/lights/living_room/ceiling/command', payload: { state: 'OFF' } },
            { topic: 'smarthome/lights/living_room/ambient/command', payload: { state: 'ON', brightness: 20, color_temp: 2700 } },
            { topic: 'smarthome/blinds/living_room/command', payload: { action: 'CLOSE' } },
        ]);

        // Sleep mode: turn off all lights (except nightlight), HVAC sleep mode
        this.defineScene('Sleep Mode', [
            { topic: 'smarthome/lights/all/command', payload: { state: 'OFF' } },
            { topic: 'smarthome/lights/bedroom/nightlight/command', payload: { state: 'ON', brightness: 5 } },
            { topic: 'smarthome/climate/bedroom/ac/command', payload: { state: 'COOL', temp: 26, mode: 'SLEEP' } },
        ]);
    }

    loadAutomations() {
        // Automation 1: Auto turn on living room lights at dusk
        this.defineAutomation(
            'Auto Lights at Dusk',
            [
                { topic: 'smarthome/sensors/outdoor/light', attribute: 'lux', operator: '<', value: 50 },
                { topic: 'smarthome/security/alarm/status', attribute: 'armed', operator: '==', value: false }
            ],
            [
                { topic: 'smarthome/lights/living_room/command', payload: { state: 'ON', brightness: 70 } }
            ]
        );

        // Automation 2: Motion-activated lights (auto off after 5 minutes of no motion)
        this.defineAutomation(
            'Motion-Activated Lights',
            [
                { topic: 'smarthome/sensors/bathroom/motion', attribute: 'state', operator: '==', value: 'DETECTED' }
            ],
            [
                { topic: 'smarthome/lights/bathroom/command', payload: { state: 'ON', brightness: 100 } }
            ]
        );

        // Automation 3: Auto cooling when temperature is too high
        this.defineAutomation(
            'Auto Cooling',
            [
                { topic: 'smarthome/sensors/living_room/temperature', attribute: 'temp', operator: '>', value: 28 }
            ],
            [
                { topic: 'smarthome/climate/living_room/ac/command', payload: { state: 'COOL', temp: 26 } }
            ]
        );

        // Automation 4: Door/window anomaly alert
        this.defineAutomation(
            'Security Alert',
            [
                { topic: 'smarthome/security/alarm/status', attribute: 'armed', operator: '==', value: true },
                { topic: 'smarthome/security/door_sensor/entrance/status', attribute: 'state', operator: '==', value: 'OPEN' }
            ],
            [
                { topic: 'smarthome/security/alarm/command', payload: { trigger: 'DOOR_OPEN' } },
                { topic: 'smarthome/notifications/push', payload: { message: 'Alert! Front door opened unexpectedly' } }
            ]
        );
    }

    // Scheduled tasks
    scheduleTasks() {
        // Every morning at 7:00 — auto open bedroom blinds
        cron.schedule('0 7 * * *', () => {
            console.log('Morning routine: Opening bedroom blinds');
            this.mqttClient.publish('smarthome/blinds/bedroom/command', JSON.stringify({ action: 'OPEN' }));
        });

        // Every night at 23:00 — auto activate sleep mode
        cron.schedule('0 23 * * *', () => {
            console.log('Night routine: Activating sleep mode');
            const sleepScene = this.scenes.find(s => s.name === 'Sleep Mode');
            if (sleepScene) sleepScene.execute();
        });
    }

    // Start system
    start() {
        this.scheduleTasks();
        console.log('Smart Home Automation Engine started');
    }
}

// Launch smart home system
const smartHome = new SmartHomeAutomation();
smartHome.start();

3. Apple HomeKit Integration

Using HAP-NodeJS to implement the HomeKit bridge:

const hap = require('hap-nodejs');
const Accessory = hap.Accessory;
const Service = hap.Service;
const Characteristic = hap.Characteristic;
const uuid = hap.uuid;

class HomeKitBridge {
    constructor(mqttClient) {
        this.mqttClient = mqttClient;
        this.accessories = new Map();
        this.bridge = new Accessory('Smart Home System', uuid.generate('smart-home-bridge'));

        this.initBridge();
    }

    initBridge() {
        this.bridge
            .getService(Service.AccessoryInformation)
            .setCharacteristic(Characteristic.Manufacturer, 'BASHCAT')
            .setCharacteristic(Characteristic.Model, 'Smart Home v2.0')
            .setCharacteristic(Characteristic.SerialNumber, 'SH-2024-001');

        // Publish bridge (discoverable by iPhone Home app)
        this.bridge.publish({
            username: 'CC:22:3D:E3:CE:F6',
            port: 51826,
            pincode: '031-45-154',
            category: Accessory.Categories.BRIDGE
        });

        console.log('HomeKit bridge published. Pair code: 031-45-154');
    }

    // Add light accessory
    addLight(id, name, topic) {
        const lightAccessory = new Accessory(name, uuid.generate(`light-${id}`));

        lightAccessory
            .addService(Service.Lightbulb, name)
            .getCharacteristic(Characteristic.On)
            .on('set', (value, callback) => {
                // HomeKit set light state
                this.mqttClient.publish(`${topic}/command`, JSON.stringify({
                    state: value ? 'ON' : 'OFF'
                }));
                callback(null);
            })
            .on('get', (callback) => {
                // HomeKit read light state
                this.mqttClient.once('message', (receivedTopic, message) => {
                    if (receivedTopic === `${topic}/status`) {
                        const state = JSON.parse(message.toString());
                        callback(null, state.state === 'ON');
                    }
                });
                this.mqttClient.subscribe(`${topic}/status`);
            });

        // Brightness control
        lightAccessory
            .getService(Service.Lightbulb)
            .addCharacteristic(Characteristic.Brightness)
            .on('set', (value, callback) => {
                this.mqttClient.publish(`${topic}/command`, JSON.stringify({
                    brightness: value
                }));
                callback(null);
            });

        // Color temperature control
        lightAccessory
            .getService(Service.Lightbulb)
            .addCharacteristic(Characteristic.ColorTemperature)
            .on('set', (value, callback) => {
                // HomeKit color temp range: 140-500 mired (maps to 2000K-7142K)
                const kelvin = 1000000 / value;
                this.mqttClient.publish(`${topic}/command`, JSON.stringify({
                    color_temp: Math.round(kelvin)
                }));
                callback(null);
            });

        this.bridge.addBridgedAccessory(lightAccessory);
        this.accessories.set(id, lightAccessory);
    }

    // Add thermostat accessory
    addThermostat(id, name, topic) {
        const thermostatAccessory = new Accessory(name, uuid.generate(`thermostat-${id}`));

        const thermostatService = thermostatAccessory.addService(Service.Thermostat, name);

        // Target temperature
        thermostatService
            .getCharacteristic(Characteristic.TargetTemperature)
            .setProps({
                minValue: 16,
                maxValue: 30,
                minStep: 1
            })
            .on('set', (value, callback) => {
                this.mqttClient.publish(`${topic}/command`, JSON.stringify({
                    temp: value
                }));
                callback(null);
            });

        // Current temperature
        thermostatService.getCharacteristic(Characteristic.CurrentTemperature);

        // Operating mode
        thermostatService
            .getCharacteristic(Characteristic.TargetHeatingCoolingState)
            .on('set', (value, callback) => {
                const modes = ['OFF', 'HEAT', 'COOL', 'AUTO'];
                this.mqttClient.publish(`${topic}/command`, JSON.stringify({
                    state: modes[value]
                }));
                callback(null);
            });

        this.bridge.addBridgedAccessory(thermostatAccessory);
        this.accessories.set(id, thermostatAccessory);
    }

    // Add blind accessory
    addBlind(id, name, topic) {
        const blindAccessory = new Accessory(name, uuid.generate(`blind-${id}`));

        blindAccessory
            .addService(Service.WindowCovering, name)
            .getCharacteristic(Characteristic.TargetPosition)
            .on('set', (value, callback) => {
                this.mqttClient.publish(`${topic}/command`, JSON.stringify({
                    position: value
                }));
                callback(null);
            });

        this.bridge.addBridgedAccessory(blindAccessory);
        this.accessories.set(id, blindAccessory);
    }
}

module.exports = HomeKitBridge;

Project Results

Technical Metrics

  • Supported device count: Single hub manages 200+ devices
  • System response time: < 200ms (local control)
  • Network stability: Zigbee mesh self-healing — single-point failure does not affect the whole
  • Scene execution speed: 10+ devices synchronized within < 500ms
  • HomeKit certification: Passed Apple MFi certification
  • Voice control accuracy: 95%+ (Siri / Google Assistant / Alexa)

Business Results

  • Deployed in 30+ luxury residences (per-unit budget NT$500K-1.5M)
  • Total managed devices: 6,000+ smart nodes
  • Client satisfaction: 4.8/5.0
  • System stability: 99.8% (annual failure rate < 0.2%)
  • Generated NT$45M in value-added service revenue for the developer

Innovation Highlights

  1. Hybrid communication architecture: Zigbee + WiFi + KNX tri-network convergence, adapting to all device types
  2. Local-first strategy: Full local control even without internet — no cloud dependency
  3. Tri-platform integration: Simultaneous support for HomeKit, Google Home, and Alexa
  4. AI scene learning: Analyzes user habits to automatically optimize scene settings

Technology Stack

Hardware Platform:

  • Raspberry Pi 4 (central hub)
  • ESP32-S3 (Zigbee coordinator)
  • KNX IP gateway
  • 200+ Zigbee endpoint devices

Backend Development:

  • Node.js + Express
  • MQTT (Mosquitto Broker)
  • SQLite (local database)
  • HAP-NodeJS (HomeKit)

Frontend Applications:

  • React Native (iOS/Android app)
  • React.js (web management dashboard)
  • Apple HomeKit
  • Google Home / Amazon Alexa

Communication Protocols:

  • Zigbee 3.0
  • MQTT
  • KNX IP
  • HomeKit HAP
  • Matter (future support)

Client Testimonial

"The smart home system built by BASHCAT completely exceeded our expectations! Not only is it technically stable and feature-rich, but the user interface is incredibly intuitive. What impressed us most is the local control capability — everything works even when the internet goes down. This system has become the core selling point of our luxury residential projects."

General Manager, Luxury Residential Developer


Project Duration: January 2023 - December 2023 Technical Domains: IoT, Embedded Systems, Smart Home, Automation Control

$ ls projects/embedded/

More work in Embedded.