
鸿蒙跨端智能植物浇灌系统开发指南 原创
鸿蒙跨端智能植物浇灌系统开发指南
一、系统架构设计
基于HarmonyOS的物联网和分布式技术,构建智能植物浇灌系统:
传感层:土壤湿度传感器实时监测
控制层:自动控制水泵进行灌溉
决策层:根据植物类型和湿度数据智能决策
跨端同步层:多设备间同步浇灌状态和数据
!https://example.com/harmony-plant-watering-arch.png
二、核心代码实现
灌溉控制服务
// IrrigationService.ets
import iot from ‘@ohos.iot’;
import distributedData from ‘@ohos.distributedData’;
import { PlantInfo, WateringRecord } from ‘./PlantTypes’;
class IrrigationService {
private static instance: IrrigationService = null;
private sensorManager: iot.SensorManager;
private deviceManager: iot.DeviceManager;
private dataManager: distributedData.DataManager;
private listeners: IrrigationListener[] = [];
private plants: PlantInfo[] = [];
private constructor() {
this.initSensorManager();
this.initDeviceManager();
this.initDataManager();
public static getInstance(): IrrigationService {
if (!IrrigationService.instance) {
IrrigationService.instance = new IrrigationService();
return IrrigationService.instance;
private initSensorManager(): void {
try {
this.sensorManager = iot.createSensorManager(getContext());
// 初始化湿度传感器
this.sensorManager.registerSensor({
sensorType: iot.SensorType.SOIL_MOISTURE,
callback: (data) => {
this.handleMoistureData(data);
});
catch (err) {
console.error('初始化传感器管理器失败:', JSON.stringify(err));
}
private initDeviceManager(): void {
try {
this.deviceManager = iot.createDeviceManager(getContext());
// 初始化水泵设备
this.deviceManager.registerDevice({
deviceType: iot.DeviceType.WATER_PUMP,
deviceId: 'pump_001',
callback: (status) => {
this.handlePumpStatus(status);
});
catch (err) {
console.error('初始化设备管理器失败:', JSON.stringify(err));
}
private initDataManager(): void {
this.dataManager = distributedData.createDataManager({
bundleName: ‘com.example.irrigation’,
area: distributedData.Area.GLOBAL,
isEncrypted: true
});
this.dataManager.registerDataListener('irrigation_sync', (data) => {
this.handleSyncData(data);
});
public async requestPermissions(): Promise<boolean> {
try {
const permissions = [
'ohos.permission.USE_IOT',
'ohos.permission.DISTRIBUTED_DATASYNC'
];
const result = await abilityAccessCtrl.requestPermissionsFromUser(
getContext(),
permissions
);
return result.grantedPermissions.length === permissions.length;
catch (err) {
console.error('请求权限失败:', JSON.stringify(err));
return false;
}
public async addPlant(plant: PlantInfo): Promise<void> {
this.plants = […this.plants, plant];
this.syncPlant(plant);
public async removePlant(plantId: string): Promise<void> {
this.plants = this.plants.filter(p => p.id !== plantId);
this.dataManager.syncData('plant_remove', {
type: 'plant_removed',
data: { plantId },
timestamp: Date.now()
});
public async startWatering(plantId: string, duration: number): Promise<void> {
const plant = this.plants.find(p => p.id === plantId);
if (!plant) return;
try {
// 打开水泵
await this.deviceManager.controlDevice({
deviceId: 'pump_001',
operation: 'turn_on',
duration: duration
});
// 记录浇水
const record: WateringRecord = {
plantId: plantId,
duration: duration,
timestamp: Date.now()
};
this.syncWateringRecord(record);
catch (err) {
console.error('启动浇水失败:', JSON.stringify(err));
throw err;
}
public async stopWatering(): Promise<void> {
try {
await this.deviceManager.controlDevice({
deviceId: ‘pump_001’,
operation: ‘turn_off’
});
catch (err) {
console.error('停止浇水失败:', JSON.stringify(err));
throw err;
}
private handleMoistureData(data: any): void {
// 检查所有植物的湿度需求
this.plants.forEach(plant => {
if (data.moisture < plant.minMoisture) {
// 需要浇水
this.startWatering(plant.id, plant.wateringDuration);
});
this.syncMoistureData(data);
private handlePumpStatus(status: any): void {
this.notifyPumpStatusChanged(status);
private syncPlant(plant: PlantInfo): void {
this.dataManager.syncData('plant_sync', {
type: 'plant_added',
data: plant,
timestamp: Date.now()
});
private syncMoistureData(data: any): void {
this.dataManager.syncData('moisture_sync', {
type: 'moisture_data',
data: data,
timestamp: Date.now()
});
private syncWateringRecord(record: WateringRecord): void {
this.dataManager.syncData('watering_sync', {
type: 'watering_record',
data: record,
timestamp: Date.now()
});
private handleSyncData(data: any): void {
if (!data) return;
switch (data.type) {
case 'plant_added':
this.handlePlantAdded(data.data);
break;
case 'plant_removed':
this.handlePlantRemoved(data.data.plantId);
break;
case 'moisture_data':
this.handleMoistureUpdate(data.data);
break;
case 'watering_record':
this.handleWateringRecord(data.data);
break;
case 'pump_status':
this.handlePumpStatusUpdate(data.data);
break;
}
private handlePlantAdded(plant: PlantInfo): void {
if (!this.plants.some(p => p.id === plant.id)) {
this.plants = […this.plants, plant];
this.notifyPlantAdded(plant);
private handlePlantRemoved(plantId: string): void {
this.plants = this.plants.filter(p => p.id !== plantId);
this.notifyPlantRemoved(plantId);
private handleMoistureUpdate(data: any): void {
this.notifyMoistureUpdated(data);
private handleWateringRecord(record: WateringRecord): void {
this.notifyWateringRecorded(record);
private handlePumpStatusUpdate(status: any): void {
this.notifyPumpStatusChanged(status);
private notifyPlantAdded(plant: PlantInfo): void {
this.listeners.forEach(listener => {
listener.onPlantAdded?.(plant);
});
private notifyPlantRemoved(plantId: string): void {
this.listeners.forEach(listener => {
listener.onPlantRemoved?.(plantId);
});
private notifyMoistureUpdated(data: any): void {
this.listeners.forEach(listener => {
listener.onMoistureUpdated?.(data);
});
private notifyWateringRecorded(record: WateringRecord): void {
this.listeners.forEach(listener => {
listener.onWateringRecorded?.(record);
});
private notifyPumpStatusChanged(status: any): void {
this.listeners.forEach(listener => {
listener.onPumpStatusChanged?.(status);
});
public addListener(listener: IrrigationListener): void {
if (!this.listeners.includes(listener)) {
this.listeners.push(listener);
}
public removeListener(listener: IrrigationListener): void {
this.listeners = this.listeners.filter(l => l !== listener);
}
interface IrrigationListener {
onPlantAdded?(plant: PlantInfo): void;
onPlantRemoved?(plantId: string): void;
onMoistureUpdated?(data: any): void;
onWateringRecorded?(record: WateringRecord): void;
onPumpStatusChanged?(status: any): void;
export const irrigationService = IrrigationService.getInstance();
主界面实现
// MainScreen.ets
import { irrigationService } from ‘./IrrigationService’;
import { PlantInfo, WateringRecord } from ‘./PlantTypes’;
@Component
export struct MainScreen {
@State hasPermission: boolean = false;
@State plants: PlantInfo[] = [];
@State moistureLevel: number = 0;
@State isPumpOn: boolean = false;
@State wateringRecords: WateringRecord[] = [];
@State showAddPlantDialog: boolean = false;
@State newPlant: PlantInfo = this.createEmptyPlant();
build() {
Column() {
// 标题栏
Row() {
Text(‘智能植物浇灌’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Button(this.hasPermission ? '添加植物' : '授权')
.width(100)
.onClick(() => {
if (this.hasPermission) {
this.showAddPlantDialog = true;
else {
this.requestPermissions();
})
.padding(10)
.width('100%')
// 湿度指示器
Column() {
Text('土壤湿度')
.fontSize(18)
.margin({ bottom: 10 })
Row() {
Progress({
value: this.moistureLevel,
total: 100,
style: ProgressStyle.Ring
})
.width(100)
.height(100)
Column() {
Text(${this.moistureLevel}%)
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text(this.getMoistureStatusText())
.fontSize(16)
.fontColor(this.getMoistureStatusColor())
.margin({ left: 20 })
}
.padding(20)
.width('90%')
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 20 })
// 水泵状态
Row() {
Text('水泵状态:')
.fontSize(16)
.margin({ right: 10 })
Text(this.isPumpOn ? '运行中' : '停止')
.fontSize(16)
.fontColor(this.isPumpOn ? '#4CAF50' : '#F44336')
if (this.isPumpOn) {
Button('停止')
.width(80)
.height(30)
.margin({ left: 20 })
.onClick(() => {
irrigationService.stopWatering();
})
}
.padding(10)
.width('90%')
.backgroundColor('#FFFFFF')
.borderRadius(8)
.margin({ bottom: 20 })
// 植物列表
if (this.plants.length > 0) {
Column() {
Text('我的植物')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
List({ space: 10 }) {
ForEach(this.plants, (plant) => {
ListItem() {
Row() {
Image(plant.image)
.width(60)
.height(60)
.borderRadius(8)
.margin({ right: 15 })
Column() {
Text(plant.name)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 5 })
Text(需求湿度: ${plant.minMoisture}%)
.fontSize(14)
.fontColor('#666666')
.layoutWeight(1)
Button('浇水')
.width(80)
.height(30)
.onClick(() => {
irrigationService.startWatering(plant.id, plant.wateringDuration);
})
.padding(10)
.width('100%')
})
.height(200)
.width(‘100%’)
.margin({ bottom: 20 })
else {
Column() {
Text('暂无植物')
.fontSize(18)
.margin({ bottom: 10 })
Text('点击"添加植物"按钮添加您的植物')
.fontSize(16)
.fontColor('#666666')
.padding(20)
.width('90%')
.backgroundColor('#F5F5F5')
.borderRadius(8)
.margin({ bottom: 20 })
// 浇水记录
Column() {
Text('浇水记录')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
if (this.wateringRecords.length > 0) {
List({ space: 5 }) {
ForEach(this.wateringRecords.slice(0, 5), (record) => {
ListItem() {
Row() {
const plant = this.plants.find(p => p.id === record.plantId);
Text(plant?.name || '未知植物')
.fontSize(14)
.layoutWeight(1)
Text(${record.duration}秒)
.fontSize(14)
.margin({ right: 10 })
Text(this.formatTime(record.timestamp))
.fontSize(14)
.fontColor('#666666')
.padding(10)
.width('100%')
})
.height(150)
else {
Text('暂无浇水记录')
.fontSize(16)
.fontColor('#666666')
}
.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(8)
.width(‘100%’)
.height('100%')
.padding(20)
// 添加植物对话框
if (this.showAddPlantDialog) {
DialogComponent({
title: '添加植物',
content: this.buildPlantDialogContent(),
confirm: {
value: '添加',
action: () => this.addPlant()
},
cancel: {
value: '取消',
action: () => {
this.showAddPlantDialog = false;
this.newPlant = this.createEmptyPlant();
}
})
}
private buildPlantDialogContent(): void {
Column() {
TextInput({ placeholder: ‘植物名称’, text: this.newPlant.name })
.onChange((value: string) => {
this.newPlant.name = value;
})
.margin({ bottom: 15 })
TextInput({ placeholder: '最小湿度(%)', text: this.newPlant.minMoisture.toString() })
.onChange((value: string) => {
this.newPlant.minMoisture = parseInt(value) || 0;
})
.margin({ bottom: 15 })
TextInput({ placeholder: '浇水时长(秒)', text: this.newPlant.wateringDuration.toString() })
.onChange((value: string) => {
this.newPlant.wateringDuration = parseInt(value) || 0;
})
.margin({ bottom: 15 })
Button('选择图片')
.width(200)
.onClick(() => {
this.pickPlantImage();
})
.padding(20)
private createEmptyPlant(): PlantInfo {
return {
id: '',
name: '',
image: $r('app.media.ic_plant_default'),
minMoisture: 50,
wateringDuration: 10,
addedAt: Date.now()
};
private getMoistureStatusText(): string {
if (this.moistureLevel < 30) return '非常干燥';
if (this.moistureLevel < 50) return '干燥';
if (this.moistureLevel < 70) return '适中';
return '湿润';
private getMoistureStatusColor(): string {
if (this.moistureLevel < 30) return '#F44336';
if (this.moistureLevel < 50) return '#FF9800';
if (this.moistureLevel < 70) return '#4CAF50';
return '#2196F3';
private formatTime(timestamp: number): string {
const date = new Date(timestamp);
return {date.getHours()}:{date.getMinutes().toString().padStart(2, '0')};
private async checkPermissions(): Promise<void> {
try {
const permissions = [
'ohos.permission.USE_IOT',
'ohos.permission.DISTRIBUTED_DATASYNC'
];
const result = await abilityAccessCtrl.verifyPermissions(
getContext(),
permissions
);
this.hasPermission = result.every(perm => perm.granted);
catch (err) {
console.error('检查权限失败:', JSON.stringify(err));
this.hasPermission = false;
}
private async requestPermissions(): Promise<void> {
this.hasPermission = await irrigationService.requestPermissions();
if (!this.hasPermission) {
prompt.showToast({ message: '授权失败,无法使用浇灌功能' });
}
private async pickPlantImage(): Promise<void> {
try {
const picker = new photo.Picker();
const result = await picker.select({
type: photo.PickerType.IMAGE,
maxSelectNumber: 1
});
if (result.photoUris.length > 0) {
const file = await fileIo.open(result.photoUris[0], fileIo.OpenMode.READ_ONLY);
const buffer = await fileIo.read(file.fd, { length: 0 });
await fileIo.close(file.fd);
this.newPlant.image = buffer.buffer;
} catch (err) {
console.error('选择图片失败:', JSON.stringify(err));
prompt.showToast({ message: '选择图片失败,请重试' });
}
private async addPlant(): Promise<void> {
if (!this.newPlant.name.trim()) {
prompt.showToast({ message: ‘请输入植物名称’ });
return;
if (this.newPlant.minMoisture <= 0 || this.newPlant.minMoisture > 100) {
prompt.showToast({ message: '请输入有效的湿度值(1-100)' });
return;
if (this.newPlant.wateringDuration <= 0) {
prompt.showToast({ message: '请输入有效的浇水时长' });
return;
try {
const plant: PlantInfo = {
...this.newPlant,
id: Date.now().toString(),
addedAt: Date.now()
};
await irrigationService.addPlant(plant);
this.showAddPlantDialog = false;
this.newPlant = this.createEmptyPlant();
catch (err) {
console.error('添加植物失败:', JSON.stringify(err));
prompt.showToast({ message: '添加植物失败,请重试' });
}
private handlePlantAdded(plant: PlantInfo): void {
this.plants = […this.plants, plant];
private handlePlantRemoved(plantId: string): void {
this.plants = this.plants.filter(p => p.id !== plantId);
private handleMoistureUpdated(data: any): void {
this.moistureLevel = data.moisture;
private handleWateringRecorded(record: WateringRecord): void {
this.wateringRecords = [record, ...this.wateringRecords];
private handlePumpStatusChanged(status: any): void {
this.isPumpOn = status.isOn;
}
类型定义
// PlantTypes.ets
export interface PlantInfo {
id: string;
name: string;
image: Resource | ArrayBuffer;
minMoisture: number; // 最小湿度百分比
wateringDuration: number; // 浇水时长(秒)
addedAt: number;
export interface WateringRecord {
plantId: string;
duration: number; // 浇水时长(秒)
timestamp: number;
三、项目配置与权限
权限配置
// module.json5
“module”: {
"requestPermissions": [
“name”: “ohos.permission.USE_IOT”,
"reason": "控制灌溉设备和传感器"
},
“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,
"reason": "同步灌溉数据"
],
"abilities": [
“name”: “MainAbility”,
"type": "page",
"visible": true
]
}
四、总结与扩展
本智能植物浇灌系统实现了以下核心功能:
实时监测:持续监测土壤湿度变化
智能灌溉:根据植物需求自动控制浇水
多植物管理:支持多种植物不同湿度需求
远程控制:通过多设备远程查看和控制
历史记录:保存浇水记录便于分析
扩展方向:
环境监测:增加光照、温度等环境监测
植物数据库:建立植物养护知识库
生长记录:记录植物生长变化
智能预测:预测最佳浇水时间
社区分享:分享植物养护经验
AI诊断:通过图像识别植物健康状况
通过HarmonyOS的分布式技术,我们构建了一个智能化的植物养护系统,能够自动监测植物需求并进行精准灌溉,同时支持多设备间的数据同步和协同控制,让植物养护变得更加简单高效。
