发布日期:2024年4月10日
一、项目架构设计
本教程将开发一个完整的智能家居控制平台,支持以下核心功能:
- 多端控制:iOS/Android/小程序/H5统一体验
- 设备配网:蓝牙/WiFi双模智能连接
- 场景联动:可视化规则引擎
- 实时监控:WebSocket数据推送
- 语音控制:集成主流语音助手
技术栈:UniApp + Vue3 + uView UI + MQTT + ECharts
二、项目初始化与配置
1. 创建UniApp项目
# 使用Vue3/Vite模板
npx degit dcloudio/uni-preset-vue#vite smart-home
# 安装依赖
cd smart-home
npm install
npm install uview-ui mqtt.js echarts wx-ble
2. 多端适配配置
// manifest.json 配置
{
"app-plus": {
"usingComponents": true,
"nvueCompiler": "uni-app"
},
"mp-weixin": {
"appid": "YOUR_WX_APPID",
"requiredBackgroundModes": ["bluetooth"]
},
"h5": {
"router": {
"mode": "history"
}
}
}
// 条件编译处理
// #ifdef APP-PLUS
const deviceModule = uni.requireNativePlugin('DeviceModule')
// #endif
// #ifdef MP-WEIXIN
const ble = require('./utils/wx-ble.js')
// #endif
三、设备连接核心实现
1. 蓝牙设备发现与连接
// utils/ble-connector.js
export class BleConnector {
static async searchDevices() {
// #ifdef APP-PLUS
const devices = await uni.startBluetoothDevicesDiscovery({
services: ['0000FFE0-0000-1000-8000-00805F9B34FB']
})
// #endif
// #ifdef MP-WEIXIN
const devices = await ble.startDiscovery()
// #endif
return devices.map(device => ({
name: device.name,
deviceId: device.deviceId,
RSSI: device.RSSI
}))
}
static async connect(deviceId) {
// #ifdef APP-PLUS
const connection = await uni.createBLEConnection({ deviceId })
// #endif
// #ifdef MP-WEIXIN
const connection = await ble.connectDevice(deviceId)
// #endif
return {
...connection,
onDisconnect: (callback) => {
uni.onBLEConnectionStateChange(state => {
if (!state.connected) callback()
})
}
}
}
}
2. WiFi设备配网模块
// utils/wifi-config.js
export async function smartConfig(wifiInfo) {
// 通用UDP广播配网
const udp = uni.createUDPSocket()
const configData = this.generateConfigPacket(wifiInfo)
udp.send({
address: '255.255.255.255',
port: 10000,
message: configData
})
return new Promise((resolve) => {
udp.onMessage(res => {
if (res.message.toString() === 'ACK') {
resolve(true)
}
})
setTimeout(() => resolve(false), 10000)
})
}
function generateConfigPacket({ ssid, password }) {
// 生成设备特定的配网数据包
const encoder = new TextEncoder()
return encoder.encode(
`WIFI:${ssid}:${password}:${Date.now()}`
)
}
四、实时通信系统
1. MQTT服务封装
// services/mqtt.js
import mqtt from 'mqtt/dist/mqtt.min'
export class MQTTClient {
constructor() {
this.client = null
this.subscriptions = new Map()
}
connect(options) {
return new Promise((resolve, reject) => {
this.client = mqtt.connect('wxs://iot.example.com/mqtt', {
clientId: `client_${Date.now()}`,
...options
})
this.client.on('connect', () => {
this.resubscribe()
resolve()
})
this.client.on('message', (topic, payload) => {
const handlers = this.subscriptions.get(topic) || []
handlers.forEach(handler =>
handler(JSON.parse(payload.toString()))
)
})
this.client.on('error', reject)
})
}
subscribe(topic, callback) {
if (!this.subscriptions.has(topic)) {
this.subscriptions.set(topic, [])
this.client.subscribe(topic)
}
this.subscriptions.get(topic).push(callback)
}
publish(topic, message) {
this.client.publish(topic, JSON.stringify(message))
}
}
2. 消息协议设计
// protocals/device-message.js
export const MessageType = {
STATUS_UPDATE: 1,
CONTROL_COMMAND: 2,
ALERT_NOTIFICATION: 3
}
export function encodeMessage(type, payload) {
return {
ver: 1,
timestamp: Date.now(),
type,
payload,
checksum: this.calculateChecksum(payload)
}
}
export function decodeMessage(raw) {
if (raw.ver !== 1) throw new Error('协议版本不匹配')
if (raw.checksum !== this.calculateChecksum(raw.payload)) {
throw new Error('校验失败')
}
return {
type: raw.type,
data: raw.payload,
timestamp: raw.timestamp
}
}
五、控制界面开发
1. 设备控制卡片组件
<template>
<view class="device-card" :class="[statusClass, { disabled: !device.online }]">
<view class="header" @click="toggleExpand">
<u-icon :name="device.icon" size="24"></u-icon>
<text class="name">{{ device.name }}</text>
<u-badge :value="device.alerts" v-if="device.alerts"></u-badge>
</view>
<view class="controls" v-if="expanded">
<template v-for="control in device.controls">
<switch-control
v-if="control.type === 'switch'"
:model-value="control.value"
@change="handleControl(control.key, $event)"
/>
<slider-control
v-else-if="control.type === 'slider'"
:model-value="control.value"
@change="handleControl(control.key, $event)"
/>
</template>
</view>
</view>
</template>
<script setup>
const props = defineProps({
device: {
type: Object,
required: true
}
})
const emit = defineEmits(['control'])
const expanded = ref(false)
const statusClass = computed(() => {
return props.device.status === 'active' ? 'active' : 'inactive'
})
function handleControl(key, value) {
emit('control', {
deviceId: props.device.id,
key,
value
})
}
</script>
2. 场景联动编辑器
<template>
<view class="scene-editor">
<view class="condition" v-for="(cond, index) in conditions" :key="index">
<picker
:value="cond.deviceId"
@change="selectDevice(index, $event)"
range="devices"
range-key="name"
>
<view>{{ getDeviceName(cond.deviceId) || '选择设备' }}</view>
</picker>
<!-- 条件与动作配置UI -->
</view>
<u-button @click="addCondition">添加条件</u-button>
<u-button @click="saveScene" type="primary">保存场景</u-button>
</view>
</template>
<script setup>
const devices = ref([])
const conditions = ref([{ deviceId: '', trigger: '', actions: [] }])
onMounted(async () => {
devices.value = await fetchDevices()
})
function addCondition() {
conditions.value.push({ deviceId: '', trigger: '', actions: [] })
}
async function saveScene() {
await api.createScene({
name: '自定义场景',
conditions: conditions.value
})
uni.showToast({ title: '保存成功' })
}
</script>
六、多端适配方案
1. 平台特定代码处理
// utils/voice-control.js
export function initVoiceControl() {
// #ifdef APP-PLUS
const voice = uni.requireNativePlugin('VoiceControl')
voice.init({
appId: 'YOUR_APP_ID'
})
return voice
// #endif
// #ifdef MP-WEIXIN
return wx.startVoiceRecognize({
lang: 'zh_CN'
})
// #endif
// #ifdef H5
return new Promise((resolve) => {
if ('webkitSpeechRecognition' in window) {
resolve(new window.webkitSpeechRecognition())
} else {
uni.showModal({
title: '提示',
content: '当前浏览器不支持语音识别'
})
}
})
// #endif
}
2. 响应式布局设计
// composables/useResponsive.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useResponsive() {
const screenWidth = ref(uni.getSystemInfoSync().windowWidth)
const isMobile = computed(() => screenWidth.value screenWidth.value >= 768 && screenWidth.value screenWidth.value >= 992)
const updateSize = () => {
screenWidth.value = uni.getSystemInfoSync().windowWidth
}
onMounted(() => {
uni.onWindowResize(updateSize)
})
onUnmounted(() => {
uni.offWindowResize(updateSize)
})
return { isMobile, isTablet, isDesktop }
}
七、打包发布与优化
1. 多平台构建命令
# 微信小程序
npm run build:mp-weixin
# H5
npm run build:h5
# App打包
npm run build:app-plus
# 生成Android APK
cd dist/build/app-plus && zip -r ../android.zip ./*
# iOS打包(需Xcode)
open /dist/build/app-plus/ios
2. 性能优化策略
// 图片懒加载
<image
lazy-load
:src="imageUrl"
mode="aspectFill"
></image>
// 组件按需加载
const HeavyComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
)
// 数据缓存
uni.setStorage({
key: 'device_list',
data: JSON.stringify(devices.value),
success: () => {
console.log('缓存成功')
}
})
八、总结与扩展
通过本教程,您已经掌握了:
- UniApp物联网应用开发全流程
- 多端设备连接与控制
- 实时通信系统的实现
- 复杂交互界面的开发
- 跨平台适配方案
扩展学习方向:
- 机器学习设备行为预测
- WebAssembly性能优化
- 3D设备可视化
- 离线语音控制集成