鸿蒙能耗监测仪表盘开发指南(基于Hi3516) 原创

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

鸿蒙能耗监测仪表盘开发指南(基于Hi3516)

一、系统架构设计

基于HarmonyOS的能耗监测系统,通过Hi3516开发板采集用电数据,实现以下功能:
实时监测:采集插座电压、电流、功率等数据

可视化展示:多维度展示能耗数据

跨设备同步:通过分布式能力实现多设备数据共享

异常预警:检测异常用电情况

!https://example.com/harmony-energy-monitor-arch.png

二、核心代码实现
数据采集服务

// EnergyDataService.ets
import driver from ‘@ohos.driver’;
import distributedData from ‘@ohos.distributedData’;

class EnergyDataService {
private static instance: EnergyDataService = null;
private hi3516Driver: driver.Driver | null = null;
private dataManager: distributedData.DataManager;
private listeners: DataListener[] = [];

private constructor() {
this.initDriver();
this.initDataManager();
public static getInstance(): EnergyDataService {

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

return EnergyDataService.instance;

private async initDriver(): Promise<void> {

try {
  this.hi3516Driver = await driver.createDriver('hi3516');
  await this.hi3516Driver.init();
  
  // 启动定时数据采集
  setInterval(() => {
    this.collectEnergyData();
  }, 5000); // 每5秒采集一次

catch (err) {

  console.error('初始化驱动失败:', JSON.stringify(err));

}

private initDataManager(): void {
this.dataManager = distributedData.createDataManager({
bundleName: ‘com.example.energymonitor’,
area: distributedData.Area.GLOBAL,
isEncrypted: true
});

this.dataManager.registerDataListener('energy_sync', (data) => {
  this.handleSyncData(data);
});

private async collectEnergyData(): Promise<void> {

if (!this.hi3516Driver) return;

try {
  // 从Hi3516读取传感器数据
  const voltage = await this.hi3516Driver.read('voltage');
  const current = await this.hi3516Driver.read('current');
  const power = voltage * current;
  const energy = power * (5 / 3600); // 5秒的能耗(kWh)
  
  const energyData: EnergyData = {
    timestamp: Date.now(),
    voltage: parseFloat(voltage.toFixed(2)),
    current: parseFloat(current.toFixed(3)),
    power: parseFloat(power.toFixed(1)),
    energy: parseFloat(energy.toFixed(5)),
    deviceId: this.dataManager.getDeviceId()
  };
  
  // 通知监听器
  this.listeners.forEach(listener => {
    listener.onDataUpdate(energyData);
  });
  
  // 同步到其他设备
  this.syncEnergyData(energyData);

catch (err) {

  console.error('采集能耗数据失败:', JSON.stringify(err));

}

private syncEnergyData(data: EnergyData): void {
this.dataManager.syncData(‘energy_sync’, {
type: ‘energy_data’,
data: data,
timestamp: Date.now()
});
private handleSyncData(data: any): void {

if (!data || data.type !== 'energy_data') return;

this.listeners.forEach(listener => {
  listener.onDataUpdate(data.data);
});

public addListener(listener: DataListener): void {

if (!this.listeners.includes(listener)) {
  this.listeners.push(listener);

}

public removeListener(listener: DataListener): void {
this.listeners = this.listeners.filter(l => l !== listener);
public async release(): Promise<void> {

if (this.hi3516Driver) {
  await this.hi3516Driver.release();
  this.hi3516Driver = null;

}

interface DataListener {

onDataUpdate(data: EnergyData): void;
interface EnergyData {

timestamp: number;
voltage: number; // 电压(V)
current: number; // 电流(A)
power: number; // 功率(W)
energy: number; // 能耗(kWh)
deviceId: string;
export const energyService = EnergyDataService.getInstance();

仪表盘界面

// DashboardScreen.ets
import { energyService } from ‘./EnergyDataService’;

@Component
export struct DashboardScreen {
@State currentData: EnergyData | null = null;
@State historyData: EnergyData[] = [];
@State connectedDevices: string[] = [];
@State isAlert: boolean = false;

private timer: number = 0;

build() {
Column() {
// 标题栏
Row() {
Text(‘能耗监测仪表盘’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)

    Button('设备')
      .width(80)
      .onClick(() => {
        this.showDeviceDialog();
      })

.padding(10)

  .width('100%')
  
  // 报警提示
  if (this.isAlert) {
    Row() {
      Image($r('app.media.ic_alert'))
        .width(24)
        .height(24)
        .margin({ right: 8 })
      
      Text('检测到异常用电!')
        .fontSize(16)
        .fontColor(Color.Red)

.padding(10)

    .width('90%')
    .backgroundColor('#FFF0F0')
    .borderRadius(8)
    .margin({ bottom: 10 })

// 实时数据卡片

  if (this.currentData) {
    Grid() {
      GridItem() {
        EnergyCard({
          title: '电压',
          value: this.currentData.voltage,
          unit: 'V',
          icon: $r('app.media.ic_voltage')
        })

GridItem() {

        EnergyCard({
          title: '电流',
          value: this.currentData.current,
          unit: 'A',
          icon: $r('app.media.ic_current')
        })

GridItem() {

        EnergyCard({
          title: '功率',
          value: this.currentData.power,
          unit: 'W',
          icon: $r('app.media.ic_power')
        })

GridItem() {

        EnergyCard({
          title: '能耗',
          value: this.currentData.energy * 1000, // 转换为Wh
          unit: 'Wh',
          icon: $r('app.media.ic_energy')
        })

}

    .columnsTemplate('1fr 1fr')
    .rowsTemplate('1fr 1fr')
    .columnsGap(10)
    .rowsGap(10)
    .height(300)
    .margin({ bottom: 20 })

// 历史数据图表

  EnergyChart({
    data: this.historyData,
    width: '100%',
    height: 200
  })
  .margin({ bottom: 20 })
  
  // 设备状态
  if (this.connectedDevices.length > 0) {
    Column() {
      Text('已连接设备:')
        .fontSize(16)
        .margin({ bottom: 8 })
      
      ForEach(this.connectedDevices, (deviceId) => {
        Text(设备 ${deviceId})
          .fontSize(14)
          .margin({ bottom: 4 })
      })

.width(‘90%’)

    .padding(10)
    .backgroundColor('#F5F5F5')
    .borderRadius(8)
    .margin({ bottom: 20 })

}

.width('100%')
.height('100%')
.padding(20)
.onAppear(() => {
  energyService.addListener({
    onDataUpdate: (data) => {
      this.updateEnergyData(data);

});

  // 每5分钟清理一次历史数据
  this.timer = setInterval(() => {
    if (this.historyData.length > 100) {
      this.historyData = this.historyData.slice(-100);

}, 300000);

})
.onDisappear(() => {
  energyService.removeListener({
    onDataUpdate: () => {}
  });
  
  if (this.timer) {
    clearInterval(this.timer);

})

private updateEnergyData(data: EnergyData): void {

this.currentData = data;
this.historyData.push(data);

// 异常检测
this.isAlert = data.power > 2000 || data.current > 10; // 功率>2000W或电流>10A视为异常

// 如果是其他设备的数据,添加到连接设备列表
if (data.deviceId !== energyService.getDeviceId() && 
    !this.connectedDevices.includes(data.deviceId)) {
  this.connectedDevices.push(data.deviceId);

}

private showDeviceDialog(): void {
const dialog = new AlertDialog({
title: ‘选择设备’,
customComponent: DeviceSelector({
onDeviceSelect: (deviceId) => {
this.connectToDevice(deviceId);
}),

  buttons: [

text: ‘取消’,

      action: () => {}

]

});
dialog.show();

private connectToDevice(deviceId: string): void {

if (!this.connectedDevices.includes(deviceId)) {
  this.connectedDevices.push(deviceId);
  prompt.showToast({ message: 已连接设备 ${deviceId} });

}

@Component

struct EnergyCard {
private title: string;
private value: number;
private unit: string;
private icon: Resource;

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

    Text(this.title)
      .fontSize(16)

.margin({ bottom: 8 })

  Row(Align.Center) {
    Text(this.value.toFixed(this.unit === 'A' ? 3 : 1))
      .fontSize(24)
      .fontWeight(FontWeight.Bold)
      .margin({ right: 4 })
    
    Text(this.unit)
      .fontSize(16)
      .fontColor('#666666')

}

.padding(15)
.width('100%')
.backgroundColor(Color.White)
.borderRadius(8)

}

@Component
struct EnergyChart {
private data: EnergyData[];
private width: string | number;
private height: string | number;

build() {
Canvas()
.width(this.width)
.height(this.height)
.onReady((context: CanvasRenderingContext2D) => {
this.drawChart(context);
})
private drawChart(ctx: CanvasRenderingContext2D): void {

if (this.data.length === 0) return;

const width = ctx.width;
const height = ctx.height;
const padding = 20;
const chartWidth = width - padding * 2;
const chartHeight = height - padding * 2;

// 清空画布
ctx.clearRect(0, 0, width, height);

// 绘制坐标轴
ctx.beginPath();
ctx.strokeStyle = '#CCCCCC';
ctx.lineWidth = 1;

// X轴
ctx.moveTo(padding, height - padding);
ctx.lineTo(width - padding, height - padding);

// Y轴
ctx.moveTo(padding, height - padding);
ctx.lineTo(padding, padding);

// Y轴刻度
const maxPower = Math.max(...this.data.map(d => d.power), 1000);
const yStep = chartHeight / 5;

for (let i = 0; i <= 5; i++) {
  const y = height - padding - i * yStep;
  ctx.moveTo(padding, y);
  ctx.lineTo(padding - 5, y);
  
  ctx.textAlign = 'right';
  ctx.textBaseline = 'middle';
  ctx.fillStyle = '#666666';
  ctx.font = '12px sans-serif';
  ctx.fillText((maxPower * i / 5).toFixed(0), padding - 10, y);

ctx.stroke();

// 绘制功率曲线
ctx.beginPath();
ctx.strokeStyle = '#4285F4';
ctx.lineWidth = 2;

const xStep = chartWidth / (this.data.length - 1);
const startX = padding;
const startY = height - padding - (this.data[0].power / maxPower) * chartHeight;

ctx.moveTo(startX, startY);

for (let i = 1; i < this.data.length; i++) {
  const x = padding + i * xStep;
  const y = height - padding - (this.data[i].power / maxPower) * chartHeight;
  ctx.lineTo(x, y);

ctx.stroke();

// 绘制数据点
ctx.fillStyle = '#4285F4';

for (let i = 0; i < this.data.length; i += Math.floor(this.data.length / 10)) {
  const x = padding + i * xStep;
  const y = height - padding - (this.data[i].power / maxPower) * chartHeight;
  
  ctx.beginPath();
  ctx.arc(x, y, 3, 0, Math.PI * 2);
  ctx.fill();

}

设备管理组件

// DeviceManager.ets
import distributedDeviceManager from ‘@ohos.distributedDeviceManager’;

@Component
export struct DeviceManager {
@State availableDevices: distributedDeviceManager.DeviceInfo[] = [];

private deviceManager: distributedDeviceManager.DeviceManager;

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

try {
  this.deviceManager = await distributedDeviceManager.createDeviceManager('com.example.energymonitor');
  
  // 监听设备状态变化
  this.deviceManager.on('deviceStateChange', (data) => {
    this.handleDeviceStateChange(data);
  });
  
  // 初始发现设备
  this.discoverDevices();

catch (err) {

  console.error('初始化设备管理器失败:', JSON.stringify(err));

}

private async discoverDevices(): Promise<void> {
try {
const devices = await this.deviceManager.getAvailableDeviceList();
this.availableDevices = devices;
catch (err) {

  console.error('发现设备失败:', JSON.stringify(err));

}

private handleDeviceStateChange(data: any): void {
switch (data.action) {
case ‘add’:
this.availableDevices.push(data.device);
break;
case ‘remove’:
this.availableDevices = this.availableDevices.filter(d => d.deviceId !== data.device.deviceId);
break;
case ‘update’:
const index = this.availableDevices.findIndex(d => d.deviceId === data.device.deviceId);
if (index >= 0) {
this.availableDevices[index] = data.device;
break;

}

build() {
Column() {
Text(‘可用设备’)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })

  if (this.availableDevices.length === 0) {
    Text('未发现可用设备')
      .fontSize(16)
      .margin({ top: 20 })

else {

    ForEach(this.availableDevices, (device) => {
      Row() {
        Image(this.getDeviceIcon(device.deviceType))
          .width(40)
          .height(40)
          .margin({ right: 10 })
        
        Column() {
          Text(device.deviceName)
            .fontSize(16)
          
          Text(this.getDeviceTypeName(device.deviceType))
            .fontSize(12)
            .fontColor('#666666')

.layoutWeight(1)

        Button('连接')
          .width(80)
          .onClick(() => {
            this.connectToDevice(device.deviceId);
          })

.padding(10)

      .width('100%')
      .backgroundColor(Color.White)
      .borderRadius(8)
      .margin({ bottom: 10 })
    })

Button(‘刷新设备列表’)

    .width('80%')
    .height(40)
    .margin({ top: 20 })
    .onClick(() => {
      this.discoverDevices();
    })

.width(‘100%’)

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

private getDeviceIcon(deviceType: string): Resource {

switch (deviceType) {
  case 'smartPlug': return $r('app.media.ic_smartplug');
  case 'energyMonitor': return $r('app.media.ic_energymonitor');
  default: return $r('app.media.ic_device');

}

private getDeviceTypeName(deviceType: string): string {
switch (deviceType) {
case ‘smartPlug’: return ‘智能插座’;
case ‘energyMonitor’: return ‘能耗监测仪’;
default: return ‘其他设备’;
}

private connectToDevice(deviceId: string): void {
// 实际实现应使用设备管理服务
prompt.showToast({ message: 已连接设备 ${deviceId} });
router.back();
}

三、项目配置与权限
权限配置

// module.json5
“module”: {

"requestPermissions": [

“name”: “ohos.permission.ACCESS_DRIVER”,

    "reason": "访问Hi3516驱动"
  },

“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,

    "reason": "同步能耗数据"
  },

“name”: “ohos.permission.ACCESS_DISTRIBUTED_DEVICE_MANAGER”,

    "reason": "发现和连接其他设备"
  },

“name”: “ohos.permission.READ_MEDIA”,

    "reason": "读取媒体文件"
  },

“name”: “ohos.permission.WRITE_MEDIA”,

    "reason": "保存报表"

],

"abilities": [

“name”: “MainAbility”,

    "type": "page",
    "visible": true
  },

“name”: “DeviceAbility”,

    "type": "page",
    "visible": true

]

}

资源文件

// resources/base/media/media.json
“media”: [

“name”: “ic_voltage”,

  "type": "svg",
  "src": "media/voltage.svg"
},

“name”: “ic_current”,

  "type": "svg",
  "src": "media/current.svg"
},

“name”: “ic_power”,

  "type": "svg",
  "src": "media/power.svg"
},

“name”: “ic_energy”,

  "type": "svg",
  "src": "media/energy.svg"
},

“name”: “ic_alert”,

  "type": "svg",
  "src": "media/alert.svg"
},

“name”: “ic_smartplug”,

  "type": "svg",
  "src": "media/smartplug.svg"
},

“name”: “ic_energymonitor”,

  "type": "svg",
  "src": "media/energymonitor.svg"

]

四、总结与扩展

本能耗监测仪表盘实现了以下核心功能:
实时采集:通过Hi3516精确采集用电数据

可视化展示:多维度展示电压、电流、功率等数据

跨设备同步:多设备实时共享能耗数据

异常预警:检测异常用电情况

扩展方向:
能耗分析:提供能耗趋势分析和节能建议

远程控制:支持远程控制智能插座开关

报表导出:生成日/周/月能耗报表

场景联动:与其他智能设备联动控制

云存储:安全存储历史能耗数据

通过HarmonyOS的分布式能力和Hi3516的硬件能力,我们构建了一个高效、可靠的能耗监测系统,帮助用户更好地管理和优化能源使用。

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