鸿蒙智慧农业大棚监测系统开发指南 原创

进修的泡芙
发布于 2025-6-23 13:34
浏览
0收藏

鸿蒙智慧农业大棚监测系统开发指南

一、系统架构设计

基于HarmonyOS的分布式能力和物联网技术,我们设计了一套农业大棚监测系统,主要功能包括:
土壤墒情预测:基于历史数据和环境因素预测土壤湿度变化

多节点组网:优化大棚内传感器节点的网络拓扑

天气预警:集成气象数据提供异常天气预警

跨设备协同:多终端实时同步监测数据

智能灌溉:根据预测模型自动调节灌溉系统

!https://example.com/harmony-greenhouse-arch.png

二、核心代码实现
土壤墒情预测服务

// SoilMoistureService.ets
import neuralNetwork from ‘@ohos.ai.neuralNetwork’;
import sensor from ‘@ohos.sensor’;

class SoilMoistureService {
private static instance: SoilMoistureService;
private model: neuralNetwork.Model | null = null;
private history: MoistureData[] = [];
private predictionInterval: number = 3600000; // 1小时预测一次

private constructor() {
this.initModel();
this.startPredictionLoop();
private async initModel(): Promise<void> {

try {
  // 加载预训练的LSTM土壤墒情预测模型
  this.model = await neuralNetwork.loadModel({
    modelPath: 'models/soil_moisture_lstm.nn',
    quantization: true
  });
  
  // 加载历史数据
  this.loadHistory();

catch (error) {

  console.error('Failed to load prediction model:', error);

}

private async loadHistory(): Promise<void> {
const history = await storage.get(‘moistureHistory’);
if (history) {
this.history = JSON.parse(history);
}

public static getInstance(): SoilMoistureService {
if (!SoilMoistureService.instance) {
SoilMoistureService.instance = new SoilMoistureService();
return SoilMoistureService.instance;

private startPredictionLoop(): void {

setInterval(() => {
  this.predictMoisture();
}, this.predictionInterval);

public async recordCurrentMoisture(data: MoistureData): Promise<void> {

this.history.push(data);

// 保留最近7天数据
if (this.history.length > 7 * 24) {
  this.history.shift();

// 保存数据

await storage.set('moistureHistory', JSON.stringify(this.history));

private async predictMoisture(): Promise<void> {

if (!this.model || this.history.length < 24) return;

try {
  // 准备输入数据
  const input = this.prepareInput();
  
  // 运行预测
  const output = await this.model.run(input);
  
  // 解析预测结果
  const predictions = this.parseOutput(output);
  
  // 触发预测事件
  EventBus.emit('moisturePredicted', predictions);

catch (error) {

  console.error('Moisture prediction failed:', error);

}

private prepareInput(): neuralNetwork.Tensor {
// 使用最近24小时数据预测未来6小时
const recentData = this.history.slice(-24);

return {
  data: this.normalizeData(recentData),
  shape: [1, 24, 5] // [批次, 时间步, 特征]
};

private normalizeData(data: MoistureData[]): number[] {

// 归一化处理
const maxMoisture = Math.max(...data.map(d => d.moisture));
const maxTemp = Math.max(...data.map(d => d.temperature));

return data.flatMap(d => [
  d.moisture / maxMoisture,
  d.temperature / maxTemp,
  d.humidity / 100,
  d.lightIntensity / 10000,
  d.watered ? 1 : 0
]);

private parseOutput(output: neuralNetwork.Tensor): MoisturePrediction[] {

const data = output.data as number[];
const now = Date.now();

return [

hours: 1, moisture: data[0] * 100 }, // 1小时后

hours: 3, moisture: data[1] * 100 }, // 3小时后

hours: 6, moisture: data[2] * 100 } // 6小时后

];

public getHistory(): MoistureData[] {

return [...this.history];

public getLatestPrediction(): MoisturePrediction | null {

const predictions = EventBus.getLastEvent('moisturePredicted');
return predictions ? predictions[0] : null;

}

export const moistureService = SoilMoistureService.getInstance();

多节点组网服务

// MeshNetworkService.ets
import net from ‘@ohos.net’;
import deviceManager from ‘@ohos.distributedHardware.deviceManager’;

class MeshNetworkService {
private static instance: MeshNetworkService;
private nodes: SensorNode[] = [];
private networkTopology: ‘star’ ‘mesh’
‘hybrid’ = ‘hybrid’;
private updateInterval: number = 300000; // 5分钟优化一次

private constructor() {
this.initNetwork();
this.startOptimizationLoop();
private initNetwork(): void {

this.discoverNodes();
this.establishConnections();

private startOptimizationLoop(): void {

setInterval(() => {
  this.optimizeNetwork();
}, this.updateInterval);

public static getInstance(): MeshNetworkService {

if (!MeshNetworkService.instance) {
  MeshNetworkService.instance = new MeshNetworkService();

return MeshNetworkService.instance;

private async discoverNodes(): Promise<void> {

const devices = await deviceManager.getTrustedDeviceList();
this.nodes = devices.map(device => ({
  id: device.deviceId,
  type: 'sensor',
  rssi: this.getRssi(device.deviceId),
  battery: 100, // 初始值
  lastSeen: Date.now()
}));

private getRssi(deviceId: string): number {

// 模拟获取信号强度
return Math.floor(Math.random() * 100) - 50; // -50到50dBm

private establishConnections(): void {

// 根据初始拓扑建立连接
switch (this.networkTopology) {
  case 'star':
    this.setupStarNetwork();
    break;
  case 'mesh':
    this.setupMeshNetwork();
    break;
  default:
    this.setupHybridNetwork();

}

private setupStarNetwork(): void {
// 找到中心节点(信号最强)
const centerNode = this.nodes.reduce((prev, current) =>
(prev.rssi > current.rssi) ? prev : current
);

// 其他节点连接到中心节点
this.nodes.forEach(node => {
  if (node.id !== centerNode.id) {
    net.connect({
      target: centerNode.id,
      type: 'BLE'
    });

});

private setupMeshNetwork(): void {

// 每个节点连接到最近的3个节点
this.nodes.forEach(node => {
  const neighbors = this.getClosestNodes(node.id, 3);
  neighbors.forEach(neighbor => {
    net.connect({
      target: neighbor.id,
      type: 'BLE'
    });
  });
});

private setupHybridNetwork(): void {

// 混合拓扑: 区域星型+全局网状
const zones = this.groupNodesByZone();

zones.forEach(zone => {
  const center = zone.reduce((prev, current) => 
    (prev.rssi > current.rssi) ? prev : current
  );
  
  zone.forEach(node => {
    if (node.id !== center.id) {
      net.connect({
        target: center.id,
        type: 'BLE'
      });

});

});

// 连接各区域中心
const centers = zones.map(zone => 
  zone.reduce((prev, current) => 
    (prev.rssi > current.rssi) ? prev : current
  )
);

for (let i = 0; i < centers.length - 1; i++) {
  net.connect({
    target: centers[i + 1].id,
    type: 'BLE'
  });

}

private groupNodesByZone(): SensorNode[][] {
// 简单按位置分组(实际项目应使用GPS或信号强度)
const zones: SensorNode[][] = [];
let currentZone: SensorNode[] = [];

this.nodes.forEach((node, index) => {
  currentZone.push(node);
  
  if (currentZone.length >= 5 || index === this.nodes.length - 1) {
    zones.push([...currentZone]);
    currentZone = [];

});

return zones;

private getClosestNodes(nodeId: string, count: number): SensorNode[] {

const node = this.nodes.find(n => n.id === nodeId);
if (!node) return [];

return [...this.nodes]
  .filter(n => n.id !== nodeId)
  .sort((a, b) => Math.abs(b.rssi) - Math.abs(a.rssi))
  .slice(0, count);

private optimizeNetwork(): void {

// 检查节点状态
this.updateNodeStatus();

// 重新评估拓扑
const weakNodes = this.nodes.filter(n => n.rssi < -70);

if (weakNodes.length > this.nodes.length / 3) {
  // 超过1/3节点信号弱,切换到网状拓扑
  this.networkTopology = 'mesh';

else if (weakNodes.length > 0) {

  // 少量弱节点,使用混合拓扑
  this.networkTopology = 'hybrid';

else {

  // 所有节点信号良好,使用星型拓扑
  this.networkTopology = 'star';

// 重新建立连接

this.establishConnections();

private updateNodeStatus(): void {

this.nodes.forEach(node => {
  node.rssi = this.getRssi(node.id);
  node.lastSeen = Date.now();
  
  // 模拟电量消耗
  node.battery = Math.max(0, node.battery - 0.5);
});

// 移除离线节点
this.nodes = this.nodes.filter(n => 
  Date.now() - n.lastSeen < 600000 // 10分钟
);

public getNetworkTopology(): string {

return this.networkTopology;

public getNodeCount(): number {

return this.nodes.length;

public getNodeStatus(nodeId: string): SensorNode | null {

return this.nodes.find(n => n.id === nodeId) || null;

public getAllNodes(): SensorNode[] {

return [...this.nodes];

}

export const meshNetwork = MeshNetworkService.getInstance();

天气预警服务

// WeatherAlertService.ets
import http from ‘@ohos.net.http’;
import geolocation from ‘@ohos.geolocation’;

class WeatherAlertService {
private static instance: WeatherAlertService;
private apiKey: string = ‘YOUR_API_KEY’;
private location: Location | null = null;
private weatherData: WeatherData | null = null;
private lastUpdate: number = 0;
private updateInterval: number = 3600000; // 1小时更新一次

private constructor() {
this.initLocation();
this.startUpdateLoop();
private initLocation(): void {

geolocation.getCurrentLocation((err, location) => {
  if (!err && location) {
    this.location = {
      latitude: location.latitude,
      longitude: location.longitude
    };
    this.fetchWeatherData();

});

private startUpdateLoop(): void {

setInterval(() => {
  this.fetchWeatherData();
}, this.updateInterval);

public static getInstance(): WeatherAlertService {

if (!WeatherAlertService.instance) {
  WeatherAlertService.instance = new WeatherAlertService();

return WeatherAlertService.instance;

private async fetchWeatherData(): Promise<void> {

if (!this.location) return;

try {
  const httpRequest = http.createHttp();
  const url = https://api.openweathermap.org/data/2.5/forecast?lat={this.location.latitude}&lon={this.location.longitude}&appid=${this.apiKey};
  
  const response = await httpRequest.request(url);
  this.weatherData = JSON.parse(response.result);
  this.lastUpdate = Date.now();
  
  this.checkAlerts();

catch (error) {

  console.error('Failed to fetch weather data:', error);

}

private checkAlerts(): void {
if (!this.weatherData) return;

const alerts: WeatherAlert[] = [];

// 检查异常天气
this.weatherData.list.forEach(forecast => {
  const weather = forecast.weather[0];
  const windSpeed = forecast.wind.speed;
  const rain = forecast.rain?.['1h'] || 0;
  
  // 大风预警
  if (windSpeed > 10) { // 10m/s
    alerts.push({
      type: 'wind',
      severity: 'warning',
      startTime: forecast.dt * 1000,
      endTime: (forecast.dt + 3600) * 1000,
      value: windSpeed
    });

// 暴雨预警

  if (rain > 20) { // 20mm/h
    alerts.push({
      type: 'rain',
      severity: 'warning',
      startTime: forecast.dt * 1000,
      endTime: (forecast.dt + 3600) * 1000,
      value: rain
    });

// 低温预警

  if (forecast.main.temp < 5) { // 5°C
    alerts.push({
      type: 'cold',
      severity: 'warning',
      startTime: forecast.dt * 1000,
      endTime: (forecast.dt + 3600) * 1000,
      value: forecast.main.temp
    });

});

if (alerts.length > 0) {
  EventBus.emit('weatherAlerts', alerts);

}

public getCurrentWeather(): WeatherData | null {
return this.weatherData;
public getAlerts(): WeatherAlert[] {

const alerts = EventBus.getLastEvent('weatherAlerts');
return alerts || [];

public getLastUpdateTime(): number {

return this.lastUpdate;

public setUpdateInterval(interval: number): void {

this.updateInterval = interval;

}

export const weatherService = WeatherAlertService.getInstance();

跨设备同步服务

// SyncService.ets
import distributedData from ‘@ohos.data.distributedData’;
import deviceManager from ‘@ohos.distributedHardware.deviceManager’;

class SyncService {
private static instance: SyncService;
private kvManager: distributedData.KVManager;
private kvStore: distributedData.KVStore;
private connectedDevices: string[] = [];

private constructor() {
this.initKVStore();
this.initDeviceListener();
private async initKVStore(): Promise<void> {

const config = {
  bundleName: 'com.example.greenhouse',
  userInfo: { userId: 'default' }
};

this.kvManager = distributedData.createKVManager(config);
this.kvStore = await this.kvManager.getKVStore('greenhouse_sync', {
  createIfMissing: true,
  backup: false,
  autoSync: true,
  kvStoreType: distributedData.KVStoreType.SINGLE_VERSION
});

this.kvStore.on('dataChange', (data) => {
  this.handleRemoteChanges(data);
});

private initDeviceListener(): void {

deviceManager.on('deviceStateChange', (data) => {
  this.handleDeviceStateChange(data);
});

this.updateConnectedDevices();

private async updateConnectedDevices(): Promise<void> {

const devices = await deviceManager.getTrustedDeviceList();
this.connectedDevices = devices.map(d => d.deviceId);

private handleDeviceStateChange(data: deviceManager.DeviceStateChangeData): void {

if (data.deviceState === deviceManager.DeviceState.ONLINE) {
  if (!this.connectedDevices.includes(data.deviceId)) {
    this.connectedDevices.push(data.deviceId);

} else if (data.deviceState === deviceManager.DeviceState.OFFLINE) {

  this.connectedDevices = this.connectedDevices.filter(id => id !== data.deviceId);

}

public static getInstance(): SyncService {
if (!SyncService.instance) {
SyncService.instance = new SyncService();
return SyncService.instance;

public async syncSensorData(data: SensorData): Promise<void> {

const syncData: SyncSensorData = {
  ...data,
  deviceId: deviceManager.getLocalDevice().id,
  timestamp: Date.now()
};

await this.kvStore.put(sensor_{data.nodeId}_{Date.now()}, JSON.stringify(syncData));

public async syncMoisturePrediction(prediction: MoisturePrediction): Promise<void> {

const syncData: SyncPrediction = {
  ...prediction,
  deviceId: deviceManager.getLocalDevice().id,
  timestamp: Date.now()
};

await this.kvStore.put(prediction_${Date.now()}, JSON.stringify(syncData));

public async syncWeatherAlert(alert: WeatherAlert): Promise<void> {

const syncData: SyncAlert = {
  ...alert,
  deviceId: deviceManager.getLocalDevice().id,
  timestamp: Date.now()
};

await this.kvStore.put(alert_{alert.type}_{Date.now()}, JSON.stringify(syncData));

private handleRemoteChanges(data: distributedData.ChangeInfo): void {

if (data.deviceId === deviceManager.getLocalDevice().id) return;

try {
  const parsed = JSON.parse(data.value);
  
  if (data.key.startsWith('sensor_')) {
    EventBus.emit('remoteSensorData', parsed);

else if (data.key.startsWith(‘prediction_’)) {

    EventBus.emit('remotePrediction', parsed);

else if (data.key.startsWith(‘alert_’)) {

    EventBus.emit('remoteWeatherAlert', parsed);

} catch (error) {

  console.error('Failed to parse sync data:', error);

}

public async getConnectedDevices(): Promise<string[]> {
await this.updateConnectedDevices();
return […this.connectedDevices];
public async broadcastCommand(command: GreenhouseCommand): Promise<void> {

const syncCommand: SyncCommand = {
  type: 'command',
  command,
  timestamp: Date.now(),
  deviceId: deviceManager.getLocalDevice().id
};

await this.kvStore.put(command_${Date.now()}, JSON.stringify(syncCommand));

}

export const syncService = SyncService.getInstance();

三、主界面实现
大棚监测主界面

// GreenhouseView.ets
@Component
struct GreenhouseView {
@State sensorData: SensorData[] = [];
@State predictions: MoisturePrediction[] = [];
@State alerts: WeatherAlert[] = [];
@State connectedNodes: number = 0;
@State topology: string = ‘hybrid’;

aboutToAppear() {
this.initEventListeners();
this.loadInitialData();
build() {

Column() {
  // 状态栏
  StatusBar({
    nodeCount: this.connectedNodes,
    topology: this.topology
  })
  .margin({ top: 16, bottom: 16 })
  
  // 土壤墒情图表
  MoistureChart({
    history: this.sensorData,
    predictions: this.predictions
  })
  .height(200)
  .margin({ bottom: 16 })
  
  // 天气预警
  if (this.alerts.length > 0) {
    WeatherAlerts({ alerts: this.alerts })
      .margin({ bottom: 16 })

// 传感器节点列表

  NodeList({ nodes: this.sensorData })
    .layoutWeight(1)

.padding(16)

private initEventListeners(): void {

EventBus.on('remoteSensorData', (data) => {
  this.updateSensorData(data);
});

EventBus.on('remotePrediction', (prediction) => {
  this.updatePrediction(prediction);
});

EventBus.on('remoteWeatherAlert', (alert) => {
  this.addAlert(alert);
});

EventBus.on('networkTopologyChanged', (topology) => {
  this.topology = topology;
});

private async loadInitialData(): Promise<void> {

this.sensorData = await sensorService.getLatestData();
this.predictions = await moistureService.getLatestPredictions();
this.alerts = weatherService.getAlerts();
this.connectedNodes = meshNetwork.getNodeCount();
this.topology = meshNetwork.getNetworkTopology();

private updateSensorData(data: SensorData): void {

const index = this.sensorData.findIndex(d => d.nodeId === data.nodeId);

if (index >= 0) {
  this.sensorData[index] = data;

else {

  this.sensorData.push(data);

this.sensorData = […this.sensorData];

private updatePrediction(prediction: MoisturePrediction): void {

const index = this.predictions.findIndex(p => 
  p.hours === prediction.hours
);

if (index >= 0) {
  this.predictions[index] = prediction;

else {

  this.predictions.push(prediction);

this.predictions = […this.predictions];

private addAlert(alert: WeatherAlert): void {

this.alerts = [alert, ...this.alerts];

}

@Component
struct StatusBar {
private nodeCount: number;
private topology: string;

build() {
Row() {
Column() {
Text(${this.nodeCount})
.fontSize(18)
.fontWeight(FontWeight.Bold)
Text(‘节点’)
.fontSize(12)
.margin({ right: 16 })

  Column() {
    Text(this.getTopologyName())
      .fontSize(18)
      .fontWeight(FontWeight.Bold)
    Text('拓扑')
      .fontSize(12)

}

private getTopologyName(): string {

switch (this.topology) {
  case 'star': return '星型';
  case 'mesh': return '网状';
  default: return '混合';

}

@Component

struct MoistureChart {
private history: SensorData[];
private predictions: MoisturePrediction[];

build() {
Canvas({ context: this.getContext() })
.width(‘100%’)
.height(‘100%’)
.onReady(() => this.drawChart())
private getContext(): CanvasRenderingContext2D {

// 创建并返回Canvas上下文
return new CanvasRenderingContext2D();

private drawChart(): void {

// 实现绘制土壤墒情曲线图的逻辑
// 实际项目中可以使用第三方图表库

}

@Component
struct WeatherAlerts {
private alerts: WeatherAlert[];

build() {
Column() {
Text(‘天气预警’)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 8 })

  ForEach(this.alerts, (alert) => {
    AlertItem({ alert })
      .margin({ bottom: 8 })
  })

}

@Component

struct AlertItem {
private alert: WeatherAlert;

build() {
Row() {
Image(this.getAlertIcon())
.width(24)
.height(24)
.margin({ right: 8 })

  Column() {
    Text(this.getAlertTitle())
      .fontSize(14)
      .fontWeight(FontWeight.Bold)
    
    Text(this.getAlertTime())
      .fontSize(12)
      .fontColor('#666666')

.layoutWeight(1)

  Text({this.alert.value}{this.getUnit()})
    .fontSize(14)

.padding(8)

.backgroundColor('#FFF5F5')
.borderRadius(4)

private getAlertIcon(): Resource {

switch (this.alert.type) {
  case 'rain': return $r('app.media.ic_rain');
  case 'wind': return $r('app.media.ic_wind');
  case 'cold': return $r('app.media.ic_cold');
  default: return $r('app.media.ic_alert');

}

private getAlertTitle(): string {
switch (this.alert.type) {
case ‘rain’: return ‘暴雨预警’;
case ‘wind’: return ‘大风预警’;
case ‘cold’: return ‘低温预警’;
default: return ‘天气预警’;
}

private getAlertTime(): string {
const date = new Date(this.alert.startTime);
return {date.getHours()}:{date.getMinutes().toString().padStart(2, ‘0’)};
private getUnit(): string {

switch (this.alert.type) {
  case 'rain': return 'mm';
  case 'wind': return 'm/s';
  case 'cold': return '°C';
  default: return '';

}

@Component

struct NodeList {
private nodes: SensorData[];

build() {
List() {
ForEach(this.nodes, (node) => {
ListItem() {
NodeItem({ node })
})

}

@Component

struct NodeItem {
private node: SensorData;

build() {
Row() {
Column() {
Text(节点 ${node.nodeId.substr(0, 8)})
.fontSize(16)
.fontWeight(FontWeight.Bold)

    Text(温度: {node.temperature.toFixed(1)}°C 湿度: {node.humidity.toFixed(1)}%)
      .fontSize(14)

.layoutWeight(1)

  Column() {
    Text(${node.moisture.toFixed(1)}%)
      .fontSize(18)
      .fontColor(this.getMoistureColor(node.moisture))
    
    Text('土壤湿度')
      .fontSize(12)

}

.padding(12)
.backgroundColor('#FFFFFF')
.borderRadius(8)

private getMoistureColor(moisture: number): string {

if (moisture < 30) return '#FF5722'; // 干旱
if (moisture > 70) return '#2196F3'; // 过湿
return '#4CAF50'; // 正常

}

灌溉控制界面

// IrrigationView.ets
@Component
struct IrrigationView {
@State autoMode: boolean = true;
@State schedule: IrrigationSchedule[] = [];
@State nextWatering: number | null = null;

aboutToAppear() {
this.loadSchedule();
build() {

Column() {
  // 自动模式切换
  Row() {
    Text('自动灌溉')
      .fontSize(16)
      .layoutWeight(1)
    
    Toggle({ type: ToggleType.Switch, isOn: this.autoMode })
      .onChange((isOn) => this.toggleAutoMode(isOn))

.margin({ bottom: 24 })

  // 下次灌溉时间
  if (this.nextWatering) {
    Text(下次灌溉: ${this.formatTime(this.nextWatering)})
      .fontSize(16)
      .margin({ bottom: 16 })

// 灌溉计划列表

  ScheduleList({ schedule: this.schedule })
    .layoutWeight(1)
  
  // 添加计划按钮
  Button('添加计划')
    .onClick(() => this.showAddDialog())
    .width('100%')
    .height(48)

.padding(16)

private loadSchedule(): void {

this.schedule = irrigationService.getSchedule();
this.nextWatering = irrigationService.getNextWateringTime();
this.autoMode = irrigationService.isAutoMode();

private toggleAutoMode(enabled: boolean): void {

this.autoMode = enabled;
irrigationService.setAutoMode(enabled);

private formatTime(timestamp: number): string {

const date = new Date(timestamp);
return {date.getMonth() + 1}月{date.getDate()}日 {date.getHours()}:{date.getMinutes().toString().padStart(2, '0')};

private showAddDialog(): void {

router.push({ url: 'pages/AddSchedule' });

}

@Component
struct ScheduleList {
private schedule: IrrigationSchedule[];

build() {
List() {
ForEach(this.schedule, (item) => {
ListItem() {
ScheduleItem({ schedule: item })
})

}

@Component

struct ScheduleItem {
private schedule: IrrigationSchedule;

build() {
Row() {
Column() {
Text(this.formatTime(this.schedule.time))
.fontSize(16)
.fontWeight(FontWeight.Bold)

    Text(持续时间: ${this.schedule.duration}分钟)
      .fontSize(14)

.layoutWeight(1)

  Button('删除')
    .onClick(() => this.deleteSchedule())
    .width(80)

.padding(12)

.backgroundColor('#FFFFFF')
.borderRadius(8)

private formatTime(time: number): string {

const date = new Date(time);
return {date.getHours().toString().padStart(2, '0')}:{date.getMinutes().toString().padStart(2, '0')};

private deleteSchedule(): void {

irrigationService.removeSchedule(this.schedule.id);

}

四、高级功能实现
智能灌溉服务

// IrrigationService.ets
import { moistureService } from ‘./SoilMoistureService’;
import { weatherService } from ‘./WeatherAlertService’;

class IrrigationService {
private static instance: IrrigationService;
private schedule: IrrigationSchedule[] = [];
private isAutoMode: boolean = true;
private nextWatering: number | null = null;
private wateringTimer: number | null = null;

private constructor() {
this.loadSchedule();
this.initEventListeners();
private initEventListeners(): void {

EventBus.on('moisturePredicted', (predictions) => {
  if (this.isAutoMode) {
    this.adjustWatering(predictions);

});

EventBus.on('weatherAlerts', (alerts) => {
  if (this.isAutoMode) {
    this.handleWeatherAlerts(alerts);

});

public static getInstance(): IrrigationService {

if (!IrrigationService.instance) {
  IrrigationService.instance = new IrrigationService();

return IrrigationService.instance;

private loadSchedule(): void {

const saved = storage.get('irrigationSchedule');
if (saved) {
  this.schedule = JSON.parse(saved);
  this.calculateNextWatering();

}

private saveSchedule(): void {
storage.set(‘irrigationSchedule’, JSON.stringify(this.schedule));
this.calculateNextWatering();
public setAutoMode(enabled: boolean): void {

this.isAutoMode = enabled;
storage.set('irrigationAutoMode', enabled);

if (enabled) {
  this.adjustWatering(moistureService.getLatestPredictions());

}

public isAutoMode(): boolean {
return this.isAutoMode;
public getSchedule(): IrrigationSchedule[] {

return [...this.schedule];

public addSchedule(schedule: IrrigationSchedule): void {

this.schedule.push(schedule);
this.saveSchedule();

public removeSchedule(id: string): void {

this.schedule = this.schedule.filter(s => s.id !== id);
this.saveSchedule();

private calculateNextWatering(): void {

if (this.schedule.length === 0) {
  this.nextWatering = null;
  return;

const now = Date.now();

let nextTime: number | null = null;

for (const item of this.schedule) {
  const timeToday = new Date();
  timeToday.setHours(
    new Date(item.time).getHours(),
    new Date(item.time).getMinutes(),
    0, 0
  );
  
  if (timeToday.getTime() > now && 
      (nextTime === null || timeToday.getTime() < nextTime)) {
    nextTime = timeToday.getTime();

}

this.nextWatering = nextTime;

// 设置定时器
if (this.wateringTimer) {
  clearTimeout(this.wateringTimer);

if (this.nextWatering) {

  const delay = this.nextWatering - now;
  this.wateringTimer = setTimeout(() => {
    this.executeWatering();
  }, delay);

}

private executeWatering(): void {
const currentSchedule = this.schedule.find(s => {
const scheduleTime = new Date(s.time);
const now = new Date();
return scheduleTime.getHours() === now.getHours() &&
scheduleTime.getMinutes() === now.getMinutes();
});

if (currentSchedule) {
  EventBus.emit('startWatering', {
    duration: currentSchedule.duration,
    scheduleId: currentSchedule.id
  });

this.calculateNextWatering();

private adjustWatering(predictions: MoisturePrediction[]): void {

if (predictions.length === 0) return;

const next6h = predictions.find(p => p.hours === 6);
if (!next6h) return;

// 根据预测湿度调整灌溉
if (next6h.moisture < 40) { // 干旱
  this.addEmergencyWatering(30); // 30分钟紧急灌溉

else if (next6h.moisture > 70) { // 过湿

  this.cancelNextWatering();

}

private handleWeatherAlerts(alerts: WeatherAlert[]): void {
const rainAlerts = alerts.filter(a => a.type === ‘rain’);

if (rainAlerts.length > 0) {
  // 有降雨预警,取消下次灌溉
  this.cancelNextWatering();

}

private addEmergencyWatering(duration: number): void {
const now = Date.now();
const emergencySchedule: IrrigationSchedule = {
id: ‘emergency_’ + now,
duration,
isEmergency: true
};

this.schedule.push(emergencySchedule);
this.saveSchedule();

private cancelNextWatering(): void {

if (!this.nextWatering) return;

// 找到并删除计划中的对应项
const scheduleTime = new Date(this.nextWatering);
this.schedule = this.schedule.filter(s => {
  const sTime = new Date(s.time);
  return !(sTime.getHours() === scheduleTime.getHours() && 
           sTime.getMinutes() === scheduleTime.getMinutes());
});

this.saveSchedule();

public getNextWateringTime(): number | null {

return this.nextWatering;

public manualWatering(duration: number): void {

EventBus.emit('startWatering', {
  duration,
  manual: true
});

}

export const irrigationService = IrrigationService.getInstance();

传感器数据聚合服务

// SensorDataService.ets
import { meshNetwork } from ‘./MeshNetworkService’;
import { syncService } from ‘./SyncService’;

class SensorDataService {
private static instance: SensorDataService;
private sensorData: SensorData[] = [];
private aggregationInterval: number = 60000; // 1分钟聚合一次

private constructor() {
this.startAggregation();
public static getInstance(): SensorDataService {

if (!SensorDataService.instance) {
  SensorDataService.instance = new SensorDataService();

return SensorDataService.instance;

private startAggregation(): void {

setInterval(() => {
  this.aggregateData();
}, this.aggregationInterval);

private aggregateData(): void {

const nodes = meshNetwork.getAllNodes();
const aggregated: SensorData[] = [];

// 按区域分组聚合
const zones = this.groupByZone(nodes);

zones.forEach(zone => {
  const zoneData = this.aggregateZoneData(zone);
  if (zoneData) {
    aggregated.push(zoneData);

});

this.sensorData = aggregated;

// 同步到其他设备
aggregated.forEach(data => {
  syncService.syncSensorData(data);
});

private groupByZone(nodes: SensorNode[]): SensorNode[][] {

// 简单按节点ID前缀分组(实际项目应根据位置分组)
const zones: Map<string, SensorNode[]> = new Map();

nodes.forEach(node => {
  const zoneId = node.id.substr(0, 3); // 前3字符作为区域ID
  
  if (!zones.has(zoneId)) {
    zones.set(zoneId, []);

zones.get(zoneId)!.push(node);

});

return Array.from(zones.values());

private aggregateZoneData(nodes: SensorNode[]): SensorData | null {

if (nodes.length === 0) return null;

// 计算平均值
const avgMoisture = nodes.reduce((sum, node) => 
  sum + node.moisture, 0) / nodes.length;

const avgTemp = nodes.reduce((sum, node) => 
  sum + node.temperature, 0) / nodes.length;

const avgHumidity = nodes.reduce((sum, node) => 
  sum + node.humidity, 0) / nodes.length;

return {
  nodeId: zone_${nodes[0].id.substr(0, 3)},
  timestamp: Date.now(),
  moisture: avgMoisture,
  temperature: avgTemp,
  humidity: avgHumidity,
  battery: Math.min(...nodes.map(n => n.battery))
};

public getLatestData(): SensorData[] {

return [...this.sensorData];

public getZoneData(zoneId: string): SensorData | null {

return this.sensorData.find(d => d.nodeId === zone_${zoneId}) || null;

public setAggregationInterval(interval: number): void {

this.aggregationInterval = interval;

}

export const sensorService = SensorDataService.getInstance();

设备管理服务

// DeviceManagementService.ets
import power from ‘@ohos.power’;
import { meshNetwork } from ‘./MeshNetworkService’;

class DeviceManagementService {
private static instance: DeviceManagementService;
private batteryOptimization: boolean = true;
private powerMode: power.Mode = power.Mode.NORMAL;

private constructor() {
this.initPowerListener();
private initPowerListener(): void {

power.on('powerModeChange', (mode) => {
  this.powerMode = mode;
  this.adjustNodeParameters();
});

public static getInstance(): DeviceManagementService {

if (!DeviceManagementService.instance) {
  DeviceManagementService.instance = new DeviceManagementService();

return DeviceManagementService.instance;

private adjustNodeParameters(): void {

const nodes = meshNetwork.getAllNodes();

nodes.forEach(node => {
  // 根据电源模式调整节点采样频率
  const interval = this.getSamplingInterval();
  meshNetwork.setNodeSamplingInterval(node.id, interval);
});

private getSamplingInterval(): number {

switch (this.powerMode) {
  case power.Mode.POWER_SAVE: return 300000; // 5分钟
  case power.Mode.PERFORMANCE: return 60000; // 1分钟
  default: return 120000; // 2分钟

}

public enableBatteryOptimization(enabled: boolean): void {
this.batteryOptimization = enabled;

if (enabled) {
  power.setMode(power.Mode.POWER_SAVE);

else {

  power.setMode(power.Mode.NORMAL);

}

public isBatteryOptimizationEnabled(): boolean {
return this.batteryOptimization;
public getPowerMode(): power.Mode {

return this.powerMode;

public getNodeStatus(nodeId: string): NodeStatus | null {

const node = meshNetwork.getNodeStatus(nodeId);
if (!node) return null;

return {
  id: node.id,
  battery: node.battery,
  lastSeen: node.lastSeen,
  signalStrength: this.getSignalQuality(node.rssi)
};

private getSignalQuality(rssi: number): string {

if (rssi >= -50) return '优秀';
if (rssi >= -70) return '良好';
if (rssi >= -80) return '一般';
return '差';

public rebootNode(nodeId: string): void {

meshNetwork.sendCommand(nodeId, 'reboot');

public updateNodeFirmware(nodeId: string): void {

meshNetwork.sendCommand(nodeId, 'update');

}

export const deviceManager = DeviceManagementService.getInstance();

五、总结

本智慧农业大棚监测系统实现了以下核心价值:

智能组网:自适应网络拓扑优化节点通信

气象预警:实时监测异常天气并提供预警

跨端协同:多终端同步监测数据和控制指令

节水灌溉:基于预测模型优化灌溉计划

扩展方向:
增加作物生长模型

集成病虫害监测

开发产量预测功能

支持更多传感器类型

添加区块链数据存证

注意事项:
土壤传感器需定期校准

网络拓扑优化会消耗额外电量

气象服务需要API密钥

首次使用建议进行系统校准

低电量节点可能影响数据精度

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2025-6-23 13:39:46修改
收藏
回复
举报
回复
    相关推荐