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
- Hybrid communication architecture: Zigbee + WiFi + KNX tri-network convergence, adapting to all device types
- Local-first strategy: Full local control even without internet — no cloud dependency
- Tri-platform integration: Simultaneous support for HomeKit, Google Home, and Alexa
- 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