鸿蒙跨端婴儿监护报警系统开发指南 原创

进修的泡芙
发布于 2025-6-22 17:35
浏览
0收藏

鸿蒙跨端婴儿监护报警系统开发指南

一、项目概述

本文基于HarmonyOS的音频分析能力和分布式技术,开发一款智能婴儿监护报警系统。该系统能够实时监测婴儿哭声,在检测到异常时向多设备发送报警通知,借鉴了《鸿蒙跨端U同步》中多设备数据同步的技术原理。

二、系统架构

±--------------------+ ±--------------------+ ±--------------------+
主监护设备 <-----> 分布式数据总线 <-----> 家长终端设备
(婴儿房监控器) (Distributed Bus) (手机/智能手表)
±---------±---------+ ±---------±---------+ ±---------±---------+

±---------v----------+ ±---------v----------+ ±---------v----------+
哭声检测模块 报警通知模块 状态同步模块
(Cry Detection) (Alert Notification) (Status Sync)

±--------------------+ ±--------------------+ ±--------------------+

三、核心代码实现
婴儿监护服务

// src/main/ets/service/BabyMonitorService.ts
import { audio } from ‘@ohos.multimedia.audio’;
import { distributedData } from ‘@ohos.data.distributedData’;
import { BusinessError } from ‘@ohos.base’;
import { notification } from ‘@ohos.notification’;
import { soundAnalysis } from ‘@ohos.ai.soundAnalysis’;

interface BabyStatus {
isCrying: boolean;
cryIntensity: number; // 0-100
cryDuration: number; // 秒
timestamp: number;
environmentNoise: number; // dB
interface AlertRecord {

id: string;
startTime: number;
endTime?: number;
duration?: number;
intensity: number;
audioClip?: string; // 音频片段路径
export class BabyMonitorService {

private static instance: BabyMonitorService;
private kvStore: distributedData.KVStore | null = null;
private readonly STORE_ID = ‘baby_monitor_store’;
private audioCapturer: audio.AudioCapturer | null = null;
private soundAnalyzer: soundAnalysis.SoundAnalyzer | null = null;
private currentStatus: BabyStatus = {
isCrying: false,
cryIntensity: 0,
cryDuration: 0,
timestamp: Date.now(),
environmentNoise: 0
};
private alertHistory: AlertRecord[] = [];
private currentAlert: AlertRecord | null = null;
private audioBuffer: number[] = [];
private readonly BUFFER_SIZE = 10; // 保存最近10秒的音频数据

private constructor() {
this.initKVStore();
this.initAudioCapturer();
this.initSoundAnalyzer();
public static getInstance(): BabyMonitorService {

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

return BabyMonitorService.instance;

private async initKVStore(): Promise<void> {

try {
  const options: distributedData.KVManagerConfig = {
    bundleName: 'com.example.babymonitor',
    userInfo: {
      userId: '0',
      userType: distributedData.UserType.SAME_USER_ID

};

  const kvManager = distributedData.createKVManager(options);
  this.kvStore = await kvManager.getKVStore({
    storeId: this.STORE_ID,
    options: {
      createIfMissing: true,
      encrypt: false,
      backup: false,
      autoSync: true,
      kvStoreType: distributedData.KVStoreType.SINGLE_VERSION

});

  this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (data) => {
    data.insertEntries.forEach((entry: distributedData.Entry) => {
      if (entry.key === 'baby_status') {
        this.notifyStatusChange(entry.value.value as BabyStatus);

else if (entry.key === ‘baby_alert’) {

        this.notifyAlert(entry.value.value as AlertRecord);

});

  });

catch (e) {

  console.error(Failed to initialize KVStore. Code: {e.code}, message: {e.message});

}

private async initAudioCapturer(): Promise<void> {
try {
const audioStreamInfo: audio.AudioStreamInfo = {
samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_16000,
channels: audio.AudioChannel.CHANNEL_1,
sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
};

  const audioCapturerInfo: audio.AudioCapturerInfo = {
    source: audio.SourceType.SOURCE_TYPE_MIC,
    capturerFlags: 0
  };
  
  this.audioCapturer = await audio.createAudioCapturer({
    streamInfo: audioStreamInfo,
    capturerInfo: audioCapturerInfo
  });
  
  this.audioCapturer.on('audioCapturerDataArrival', (buffer: ArrayBuffer) => {
    this.processAudio(buffer);
  });
  
  await this.audioCapturer.start();

catch (e) {

  console.error(Failed to initialize audio capturer. Code: {e.code}, message: {e.message});

}

private async initSoundAnalyzer(): Promise<void> {
try {
const config: soundAnalysis.SoundAnalyzerConfig = {
analyzerType: soundAnalysis.AnalyzerType.BABY_CRY,
sampleRate: 16000,
sensitivity: 0.8
};

  this.soundAnalyzer = await soundAnalysis.createSoundAnalyzer(config);

catch (e) {

  console.error(Failed to initialize sound analyzer. Code: {e.code}, message: {e.message});

}

private processAudio(buffer: ArrayBuffer): void {
if (!this.soundAnalyzer) return;

try {
  const audioData = new Int16Array(buffer);
  
  // 保存音频数据到缓冲区
  this.updateAudioBuffer(audioData);
  
  // 分析音频
  const result = this.soundAnalyzer.analyze(audioData);
  
  // 更新环境噪音水平
  this.currentStatus.environmentNoise = this.calculateNoiseLevel(audioData);
  
  // 检测哭声
  if (result.isBabyCry) {
    this.handleCryDetection(result.intensity);

else if (this.currentStatus.isCrying) {

    this.handleCryEnd();

this.currentStatus.timestamp = Date.now();

  this.scheduleSync();

catch (e) {

  console.error(Failed to process audio. Code: {e.code}, message: {e.message});

}

private updateAudioBuffer(data: Int16Array): void {
// 简化的音频缓冲处理 (实际应用中应使用更高效的实现)
this.audioBuffer = […this.audioBuffer, …Array.from(data)];

// 保持缓冲区大小
const maxSamples = this.BUFFER_SIZE * 16000; // 10秒的16kHz音频
if (this.audioBuffer.length > maxSamples) {
  this.audioBuffer = this.audioBuffer.slice(this.audioBuffer.length - maxSamples);

}

private calculateNoiseLevel(data: Int16Array): number {
// 计算RMS音量(dB)
let sum = 0;
for (let i = 0; i < data.length; i++) {
sum += data[i] * data[i];
const rms = Math.sqrt(sum / data.length);

return 20 * Math.log10(rms / 32768); // 转换为dB

private handleCryDetection(intensity: number): void {

const now = Date.now();

if (!this.currentStatus.isCrying) {
  // 新的哭声事件
  this.currentStatus.isCrying = true;
  this.currentStatus.cryIntensity = intensity;
  this.currentStatus.cryDuration = 0;
  
  this.currentAlert = {
    id: alert_${now},
    startTime: now,
    intensity: intensity,
    audioClip: this.saveAudioClip() // 保存音频片段
  };
  
  this.triggerAlert();

else {

  // 持续哭声
  this.currentStatus.cryIntensity = Math.max(this.currentStatus.cryIntensity, intensity);
  this.currentStatus.cryDuration = (now - this.currentAlert.startTime) / 1000;
  
  if (this.currentAlert) {
    this.currentAlert.intensity = this.currentStatus.cryIntensity;

}

private handleCryEnd(): void {

this.currentStatus.isCrying = false;
this.currentStatus.cryIntensity = 0;

if (this.currentAlert) {
  this.currentAlert.endTime = Date.now();
  this.currentAlert.duration = (this.currentAlert.endTime - this.currentAlert.startTime) / 1000;
  
  this.alertHistory.unshift(this.currentAlert);
  if (this.alertHistory.length > 50) {
    this.alertHistory = this.alertHistory.slice(0, 50);

this.syncAlertHistory();

  this.currentAlert = null;

}

private saveAudioClip(): string {
// 实际应用中应保存音频数据到文件并返回路径
// 这里简化为返回空字符串
return ‘’;
private triggerAlert(): void {

if (!this.currentAlert) return;

// 本地通知
notification.show({
  id: 1,
  contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
  title: '婴儿哭声检测',
  text: '检测到婴儿哭声,请查看',
  smallIcon: $r('app.media.ic_baby'),
  largeIcon: $r('app.media.ic_baby_large')
});

// 同步报警信息
if (this.kvStore) {
  this.kvStore.put('baby_alert', { value: this.currentAlert });

}

private scheduleSync(): void {
if (this.syncTimer) {
clearTimeout(this.syncTimer);
this.syncTimer = setTimeout(() => {

  this.syncStatus();
  this.syncTimer = null;
}, 2000); // 2秒内多次更新只同步一次

private syncTimer: number | null = null;

private async syncStatus(): Promise<void> {
if (this.kvStore) {
try {
await this.kvStore.put(‘baby_status’, { value: this.currentStatus });
catch (e) {

    console.error(Failed to sync baby status. Code: {e.code}, message: {e.message});

}

private async syncAlertHistory(): Promise<void> {

if (this.kvStore) {
  try {
    await this.kvStore.put('alert_history', { value: this.alertHistory });

catch (e) {

    console.error(Failed to sync alert history. Code: {e.code}, message: {e.message});

}

private notifyStatusChange(newStatus: BabyStatus): void {

// 使用时间戳解决冲突 - 保留最新的状态
if (newStatus.timestamp > this.currentStatus.timestamp) {
  this.currentStatus = newStatus;

}

private notifyAlert(alert: AlertRecord): void {
// 实际应用中应该处理远程报警通知
console.log(‘Received remote alert:’, alert);
public async getCurrentStatus(): Promise<BabyStatus> {

if (!this.kvStore) return this.currentStatus;

try {
  const entry = await this.kvStore.get('baby_status');
  return entry?.value || this.currentStatus;

catch (e) {

  console.error(Failed to get baby status. Code: {e.code}, message: {e.message});
  return this.currentStatus;

}

public async getAlertHistory(): Promise<AlertRecord[]> {
if (!this.kvStore) return this.alertHistory;

try {
  const entry = await this.kvStore.get('alert_history');
  return entry?.value || this.alertHistory;

catch (e) {

  console.error(Failed to get alert history. Code: {e.code}, message: {e.message});
  return this.alertHistory;

}

public async destroy(): Promise<void> {
if (this.kvStore) {
this.kvStore.off(‘dataChange’);
if (this.audioCapturer) {

  await this.audioCapturer.stop();
  await this.audioCapturer.release();

if (this.soundAnalyzer) {

  this.soundAnalyzer.release();

}

监护界面组件

// src/main/ets/components/BabyMonitor.ets
@Component
export struct BabyMonitor {
private monitorService = BabyMonitorService.getInstance();
@State currentStatus: BabyStatus = {
isCrying: false,
cryIntensity: 0,
cryDuration: 0,
timestamp: 0,
environmentNoise: 0
};
@State alertHistory: AlertRecord[] = [];
@State showHistory: boolean = false;

aboutToAppear(): void {
this.loadCurrentStatus();
this.loadAlertHistory();
private async loadCurrentStatus(): Promise<void> {

this.currentStatus = await this.monitorService.getCurrentStatus();

private async loadAlertHistory(): Promise<void> {

this.alertHistory = await this.monitorService.getAlertHistory();

build() {

Stack() {
  // 状态显示
  Column() {
    // 环境噪音指示器
    Row() {
      Text('环境噪音:')
        .fontSize(16)
        .margin({ right: 10 });
      
      Progress({
        value: this.currentStatus.environmentNoise,
        total: 100,
        type: ProgressType.Linear
      })
      .width('60%')
      .height(10)
      .color(this.getNoiseColor(this.currentStatus.environmentNoise));
      
      Text(${this.currentStatus.environmentNoise.toFixed(0)} dB)
        .fontSize(16)
        .margin({ left: 10 });

.width(‘100%’)

    .margin({ bottom: 30 });
    
    // 哭声状态
    Column() {
      if (this.currentStatus.isCrying) {
        Image($r('app.media.ic_cry'))
          .width(100)
          .height(100)
          .margin({ bottom: 20 });
        
        Text('检测到婴儿哭声!')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#F44336')
          .margin({ bottom: 10 });
        
        Text(强度: ${this.currentStatus.cryIntensity.toFixed(0)}%)
          .fontSize(18)
          .margin({ bottom: 5 });
        
        Text(持续时间: ${this.currentStatus.cryDuration.toFixed(0)}秒)
          .fontSize(18)
          .margin({ bottom: 20 });
        
        Button('安抚记录')
          .type(ButtonType.Capsule)
          .width('60%')
          .backgroundColor('#FF4081')
          .fontColor('#FFFFFF')
          .margin({ bottom: 20 });

else {

        Image($r('app.media.ic_sleep'))
          .width(100)
          .height(100)
          .margin({ bottom: 20 });
        
        Text('婴儿状态正常')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor('#4CAF50');

}

    .width('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center);

.width(‘100%’)

  .height('100%')
  .padding(40)
  .justifyContent(FlexAlign.Center)
  .alignItems(HorizontalAlign.Center);
  
  // 历史记录按钮
  Button($r('app.media.ic_history'))
    .type(ButtonType.Circle)
    .width(60)
    .height(60)
    .backgroundColor('#2196F3')
    .fontColor('#FFFFFF')
    .position({ x: '85%', y: '10%' })
    .onClick(() => {
      this.showHistory = true;
    });

.width(‘100%’)

.height('100%')

// 历史记录对话框
if (this.showHistory) {
  Dialog.show({
    title: '报警历史记录',
    content: this.buildHistoryContent(),
    confirm: {
      value: '关闭',
      action: () => {
        this.showHistory = false;

}

  });

}

@Builder
private buildHistoryContent() {
Column() {
if (this.alertHistory.length > 0) {
List({ space: 10 }) {
ForEach(this.alertHistory, (alert) => {
ListItem() {
Column() {
Row() {
Text(new Date(alert.startTime).toLocaleTimeString())
.fontSize(16)
.fontWeight(FontWeight.Bold)
.layoutWeight(1);

              Text(强度: ${alert.intensity.toFixed(0)}%)
                .fontSize(14)
                .fontColor('#F44336');

.margin({ bottom: 5 });

            Row() {
              Text(持续时间: ${alert.duration?.toFixed(0) || '未知'}秒)
                .fontSize(14)
                .fontColor('#666666')
                .layoutWeight(1);
              
              if (alert.audioClip) {
                Button('播放')
                  .type(ButtonType.Normal)
                  .width(60)
                  .height(30)
                  .fontSize(12)
                  .onClick(() => {
                    this.playAudioClip(alert.audioClip);
                  });

}

.width(‘100%’)

          .padding(15)
          .backgroundColor('#FFFFFF')
          .borderRadius(10)

})

.width(‘100%’)

    .height(400)

else {

    Text('没有报警记录')
      .fontSize(16)
      .fontColor('#666666')
      .margin({ top: 50 });

}

.width('100%')
.padding(10)

private getNoiseColor(level: number): string {

if (level < 40) return '#4CAF50';
if (level < 70) return '#FFC107';
return '#F44336';

private playAudioClip(clipPath: string): void {

// 实际应用中应播放音频片段
console.log('Playing audio clip:', clipPath);

}

主界面实现

// src/main/ets/pages/BabyMonitorPage.ets
import { BabyMonitorService } from ‘…/service/BabyMonitorService’;
import { BabyMonitor } from ‘…/components/BabyMonitor’;

@Entry
@Component
struct BabyMonitorPage {
@State activeTab: number = 0;
@State deviceList: string[] = [];
private monitorService = BabyMonitorService.getInstance();

build() {
Column() {
// 标题
Text(‘婴儿监护系统’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  // 标签页
  Tabs({ barPosition: BarPosition.Start }) {
    TabContent() {
      // 监护主界面
      BabyMonitor()

.tabBar(‘监护状态’);

    TabContent() {
      // 设备管理标签页
      this.buildDevicesTab()

.tabBar(‘设备管理’);

    TabContent() {
      // 设置标签页
      this.buildSettingsTab()

.tabBar(‘设置’);

.barWidth(‘100%’)

  .barHeight(50)
  .width('100%')
  .height('80%')

.width(‘100%’)

.height('100%')
.padding(20)
.onAppear(() => {
  // 模拟获取设备列表
  setTimeout(() => {
    this.deviceList = ['婴儿房监护器', '父母手机', '客厅平板'];
  }, 1000);
});

@Builder

private buildDevicesTab() {
Column() {
Text(‘已连接设备’)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  if (this.deviceList.length > 0) {
    List({ space: 15 }) {
      ForEach(this.deviceList, (device) => {
        ListItem() {
          Row() {
            Image($r('app.media.ic_device'))
              .width(40)
              .height(40)
              .margin({ right: 15 });
            
            Text(device)
              .fontSize(16)
              .layoutWeight(1);
            
            if (device === '婴儿房监护器') {
              Text('主设备')
                .fontSize(14)
                .fontColor('#4CAF50');

}

          .width('100%')
          .padding(15)
          .backgroundColor('#FFFFFF')
          .borderRadius(10)

})

.width(‘100%’)

    .layoutWeight(1);

else {

    Text('没有连接的设备')
      .fontSize(16)
      .fontColor('#666666')
      .margin({ top: 50 });

Button(‘添加设备’)

    .type(ButtonType.Capsule)
    .width('80%')
    .margin({ top: 30 })
    .backgroundColor('#2196F3')
    .fontColor('#FFFFFF');

.width(‘100%’)

.height('100%')
.padding(10);

@Builder

private buildSettingsTab() {
Column() {
Text(‘报警设置’)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  // 灵敏度设置
  Row() {
    Text('检测灵敏度:')
      .fontSize(16)
      .layoutWeight(1);
    
    Slider({
      value: 80,
      min: 0,
      max: 100,
      step: 1,
      style: SliderStyle.OutSet
    })
    .blockColor('#4CAF50')
    .width('60%');

.width(‘100%’)

  .margin({ bottom: 20 });
  
  // 通知设置
  Row() {
    Text('通知方式:')
      .fontSize(16)
      .margin({ right: 10 });
    
    Toggle({ type: ToggleType.Checkbox, isOn: true })
      .margin({ right: 15 });
    
    Text('推送通知')
      .fontSize(16);

.width(‘100%’)

  .margin({ bottom: 15 });
  
  Row() {
    Text('')
      .fontSize(16)
      .margin({ right: 10 });
    
    Toggle({ type: ToggleType.Checkbox, isOn: true })
      .margin({ right: 15 });
    
    Text('声音提醒')
      .fontSize(16);

.width(‘100%’)

  .margin({ bottom: 15 });
  
  Row() {
    Text('')
      .fontSize(16)
      .margin({ right: 10 });
    
    Toggle({ type: ToggleType.Checkbox, isOn: false })
      .margin({ right: 15 });
    
    Text('震动提醒')
      .fontSize(16);

.width(‘100%’)

  .margin({ bottom: 30 });
  
  // 保存按钮
  Button('保存设置')
    .type(ButtonType.Capsule)
    .width('80%')
    .backgroundColor('#4CAF50')
    .fontColor('#FFFFFF');

.width(‘100%’)

.height('100%')
.padding(20);

}

四、与游戏同步技术的结合点
分布式状态同步:借鉴游戏中多玩家状态同步机制,实现婴儿状态的跨设备实时同步

实时音频流处理:类似游戏中的实时数据流,处理音频数据

设备角色分配:类似游戏中的主机/客户端角色,确定主监护设备和从属设备

时间同步机制:确保多设备间的时间戳一致,类似游戏中的时间同步

数据压缩传输:优化报警信息的传输效率,类似游戏中的网络优化

五、关键特性实现
哭声检测算法:

  const result = this.soundAnalyzer.analyze(audioData);

if (result.isBabyCry) {
this.handleCryDetection(result.intensity);

报警触发机制:

  notification.show({
 id: 1,
 contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
 title: '婴儿哭声检测',
 text: '检测到婴儿哭声,请查看',
 smallIcon: $r('app.media.ic_baby'),
 largeIcon: $r('app.media.ic_baby_large')

});

历史记录同步:

  this.kvStore.put('alert_history', { value: this.alertHistory });

音频缓冲处理:

  this.audioBuffer = [...this.audioBuffer, ...Array.from(data)];

if (this.audioBuffer.length > maxSamples) {
this.audioBuffer = this.audioBuffer.slice(this.audioBuffer.length - maxSamples);

六、性能优化策略
音频采样率优化:

  const audioStreamInfo: audio.AudioStreamInfo = {
 samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_16000, // 16kHz采样率
 channels: audio.AudioChannel.CHANNEL_1,
 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE

};

批量状态更新:

  private scheduleSync(): void {
 if (this.syncTimer) clearTimeout(this.syncTimer);
 this.syncTimer = setTimeout(() => {
   this.syncStatus();
   this.syncTimer = null;
 }, 2000); // 2秒内多次更新只同步一次

本地缓存优先:

  public async getCurrentStatus(): Promise<BabyStatus> {
 // 先返回本地缓存
 const cachedStatus = this.currentStatus;
 
 // 异步从分布式存储获取最新状态
 if (this.kvStore) {
   this.kvStore.get('baby_status').then((entry) => {
     if (entry?.value) {
       this.currentStatus = entry.value;

});

return cachedStatus;

资源释放管理:

  public async destroy(): Promise<void> {
 if (this.audioCapturer) {
   await this.audioCapturer.stop();
   await this.audioCapturer.release();

if (this.soundAnalyzer) {

   this.soundAnalyzer.release();

}

七、项目扩展方向
视频监控集成:结合摄像头实现音视频同步监控

环境监测:集成温湿度传感器监测婴儿房环境

智能安抚:检测到哭声后自动播放安抚音乐

成长记录:记录婴儿睡眠和活动模式

多婴儿支持:支持同时监控多个婴儿

八、总结

本婴儿监护报警系统实现了以下核心功能:
基于HarmonyOS AI能力的婴儿哭声检测

实时报警通知与历史记录

多设备间的状态同步

直观的用户界面和报警显示

通过借鉴游戏中的多设备同步技术,我们构建了一个可靠的婴儿监护解决方案。该项目展示了HarmonyOS在音频处理和分布式技术方面的强大能力,为开发者提供了智能家居和健康监护类应用开发的参考方案。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐