Core Entities
Home: home_id, owner_id, name, address, timezone, created_at. Room: room_id, home_id, name, floor_number. Device: device_id, home_id, room_id, name, type (LIGHT, THERMOSTAT, LOCK, CAMERA, SENSOR, SWITCH, PLUG), manufacturer, model, firmware_version, status (ONLINE, OFFLINE, ERROR), last_seen_at, metadata (JSONB: capabilities, config). DeviceState: device_id, attribute (power, brightness, temperature, lock_state, motion_detected), value (JSON), recorded_at. (Time-series: one row per state change.) AutomationRule: rule_id, home_id, name, is_enabled, trigger (JSON: type, conditions), actions (JSON array: device_id, command, params), created_by. AutomationLog: log_id, rule_id, triggered_at, trigger_data (JSON), actions_taken (JSON), status (SUCCESS, PARTIAL, FAILED). Scene: scene_id, home_id, name, actions (JSON array: device commands to execute together), icon.
Device Communication and Protocol Gateway
IoT devices use various protocols: Z-Wave, Zigbee, Wi-Fi (MQTT, HTTP), Matter (new standard). A Protocol Gateway translates between these protocols and the platform’s internal MQTT broker. Architecture: devices connect to the gateway (local hub or cloud). Gateway publishes device events to MQTT topics: home/{home_id}/device/{device_id}/state. Commands are sent to: home/{home_id}/device/{device_id}/command. The backend subscribes to state topics and unsubscribes/publishes commands. MQTT quality of service: QoS 1 (at-least-once delivery) for device state updates. QoS 2 (exactly-once) for critical commands (lock/unlock). Device shadow: maintain the last known state of each device in Redis even when the device is offline (used to show current state in the UI without querying the device directly).
class DeviceService:
def send_command(self, device_id: str, command: str,
params: dict, actor_id: int) -> CommandResult:
device = self.db.get_device(device_id)
if device.status == "OFFLINE":
return CommandResult(success=False,
error="Device is offline")
# Validate command against device capabilities
if not self._is_supported(device, command, params):
return CommandResult(success=False,
error=f"Command {command} not supported")
# Publish to MQTT command topic
payload = json.dumps({
"command": command,
"params": params,
"request_id": str(uuid4()),
"actor_id": actor_id,
"timestamp": datetime.utcnow().isoformat()
})
self.mqtt.publish(
topic=f"home/{device.home_id}/device/{device_id}/command",
payload=payload,
qos=2 if command in ("lock", "unlock", "alarm") else 1
)
# Wait for acknowledgment (with timeout)
ack = self.ack_store.wait(device_id, timeout_ms=5000)
return CommandResult(success=ack is not None,
error=None if ack else "Command timeout")
Automation Rule Engine
Automation rules: IF trigger_condition THEN execute_actions. Trigger types: Device state change: “when motion sensor detects motion”. Schedule: “at 7:00 AM on weekdays”. Sunrise/sunset: “30 minutes before sunset”. Geofence: “when owner leaves home”. Threshold: “when temperature drops below 65°F”. Rule evaluation: device state changes publish to Kafka. The Rule Engine consumer reads events and evaluates active rules for the home. For each rule: check if the trigger condition matches the event. If yes: execute all actions (send device commands). Scheduling: a cron-based scheduler fires schedule-triggered rules at the configured time. Conflict resolution: if multiple rules try to set conflicting device states (one turns lights off, another turns on), last-write-wins by default. Users can set rule priorities to control conflict resolution.
Real-Time Dashboard and WebSocket Updates
The mobile app/web dashboard shows real-time device states. Architecture: device state changes (from MQTT) → Kafka topic (device_states) → State consumer (updates Redis device shadow + DB) AND WebSocket broadcaster. WebSocket broadcaster: for each device state change, find all WebSocket sessions for users who have access to that home, push the update. Connection management: WebSocket connections are maintained per session. The broadcaster checks Redis for active sessions per home (SET: ws_sessions:{home_id} = {session_ids}). Session cleanup: on WebSocket disconnect, remove from the set. TTL on the set (extend on each message) prevents stale entries. For scale: WebSocket gateway is horizontally scaled; a Redis pub/sub channel (SUBSCRIBE home:{home_id}:updates) broadcasts state changes to all gateway instances, which forward to their connected sessions for that home.
See also: Apple Interview Prep
See also: Atlassian Interview Prep
See also: Databricks Interview Prep
See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering
See also: Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering