
鸿蒙能耗监测仪表盘开发指南 原创
鸿蒙能耗监测仪表盘开发指南
一、系统架构设计
基于HarmonyOS的能耗监测仪表盘,利用Hi3516开发板采集用电数据,通过分布式能力实现多设备协同:
数据采集:Hi3516实时采集电压、电流等参数
智能分析:计算功率、能耗等关键指标
跨设备同步:多设备共享监测数据
可视化展示:多维度展示能耗数据
!https://example.com/harmony-energy-monitor-arch.png
二、核心代码实现
数据采集服务
// DataCollectorService.ets
import driver from ‘@ohos.driver’;
import distributedData from ‘@ohos.distributedData’;
class DataCollectorService {
private static instance: DataCollectorService = null;
private hi3516Driver: driver.Driver;
private dataManager: distributedData.DataManager;
private collectionListeners: CollectionListener[] = [];
private constructor() {
this.initDriver();
this.initDataManager();
public static getInstance(): DataCollectorService {
if (!DataCollectorService.instance) {
DataCollectorService.instance = new DataCollectorService();
return DataCollectorService.instance;
private initDriver(): void {
const context = getContext() as common.Context;
this.hi3516Driver = driver.createDriver('hi3516', context);
// 配置采样参数
this.hi3516Driver.setConfig({
samplingRate: 1000, // 1秒采样一次
channels: ['voltage', 'current', 'power']
});
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);
});
public async startCollection(): Promise<void> {
try {
await this.hi3516Driver.start();
// 定时采集数据
setInterval(async () => {
const data = await this.collectData();
this.notifyListeners(data);
this.syncData(data);
}, 1000);
catch (err) {
console.error('启动数据采集失败:', JSON.stringify(err));
}
private async collectData(): Promise<EnergyData> {
const result: EnergyData = {
timestamp: Date.now(),
voltage: 0,
current: 0,
power: 0,
energy: 0,
deviceId: this.dataManager.getDeviceId()
};
try {
// 从Hi3516读取传感器数据
const voltage = await this.hi3516Driver.read('voltage');
const current = await this.hi3516Driver.read('current');
result.voltage = parseFloat(voltage.toFixed(2));
result.current = parseFloat(current.toFixed(3));
result.power = result.voltage * result.current;
result.energy = result.power * (1 / 3600); // 1秒的能耗(kWh)
return result;
catch (err) {
console.error('采集数据失败:', JSON.stringify(err));
return result;
}
private notifyListeners(data: EnergyData): void {
this.collectionListeners.forEach(listener => {
listener.onDataUpdate(data);
});
private syncData(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.collectionListeners.forEach(listener => {
listener.onDataUpdate(data.data);
});
public addListener(listener: CollectionListener): void {
if (!this.collectionListeners.includes(listener)) {
this.collectionListeners.push(listener);
}
public removeListener(listener: CollectionListener): void {
this.collectionListeners = this.collectionListeners.filter(l => l !== listener);
}
interface CollectionListener {
onDataUpdate(data: EnergyData): void;
interface EnergyData {
timestamp: number;
voltage: number; // 电压(V)
current: number; // 电流(A)
power: number; // 功率(W)
energy: number; // 能耗(kWh)
deviceId: string;
export const dataService = DataCollectorService.getInstance();
数据分析服务
// AnalysisService.ets
import { dataService } from ‘./DataCollectorService’;
class AnalysisService {
private static instance: AnalysisService = null;
private analysisListeners: AnalysisListener[] = [];
private historyData: EnergyData[] = [];
private constructor() {
this.setupDataListener();
public static getInstance(): AnalysisService {
if (!AnalysisService.instance) {
AnalysisService.instance = new AnalysisService();
return AnalysisService.instance;
private setupDataListener(): void {
dataService.addListener({
onDataUpdate: (data) => {
this.processData(data);
});
private processData(data: EnergyData): void {
// 保存历史数据
this.historyData.push(data);
if (this.historyData.length > 3600) { // 保留1小时数据
this.historyData.shift();
// 计算统计数据
const stats = this.calculateStats();
// 通知监听器
this.notifyListeners(data, stats);
private calculateStats(): EnergyStats {
if (this.historyData.length === 0) {
return {
avgPower: 0,
maxPower: 0,
minPower: 0,
totalEnergy: 0
};
let totalPower = 0;
let maxPower = 0;
let minPower = Infinity;
let totalEnergy = 0;
this.historyData.forEach(data => {
totalPower += data.power;
maxPower = Math.max(maxPower, data.power);
minPower = Math.min(minPower, data.power);
totalEnergy += data.energy;
});
return {
avgPower: totalPower / this.historyData.length,
maxPower: maxPower,
minPower: minPower,
totalEnergy: totalEnergy
};
private notifyListeners(data: EnergyData, stats: EnergyStats): void {
this.analysisListeners.forEach(listener => {
listener.onAnalysisUpdate(data, stats);
});
public addListener(listener: AnalysisListener): void {
if (!this.analysisListeners.includes(listener)) {
this.analysisListeners.push(listener);
}
public removeListener(listener: AnalysisListener): void {
this.analysisListeners = this.analysisListeners.filter(l => l !== listener);
public getHistoryData(): EnergyData[] {
return [...this.historyData];
}
interface AnalysisListener {
onAnalysisUpdate(data: EnergyData, stats: EnergyStats): void;
interface EnergyStats {
avgPower: number;
maxPower: number;
minPower: number;
totalEnergy: number;
export const analysisService = AnalysisService.getInstance();
仪表盘主界面
// DashboardScreen.ets
import { dataService } from ‘./DataCollectorService’;
import { analysisService } from ‘./AnalysisService’;
@Component
export struct DashboardScreen {
@State currentData: EnergyData | null = null;
@State stats: EnergyStats = {
avgPower: 0,
maxPower: 0,
minPower: 0,
totalEnergy: 0
};
@State connectedDevices: string[] = [];
@State isCollecting: boolean = false;
build() {
Column() {
// 标题栏
Row() {
Text(‘能耗监测仪表盘’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Button(this.isCollecting ? '停止监测' : '开始监测')
.width(120)
.onClick(() => {
this.toggleCollection();
})
.padding(10)
.width('100%')
// 实时数据显示
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 })
// 统计数据显示
Column() {
Text('统计信息')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Row() {
Column() {
Text('平均功率')
.fontSize(14)
.fontColor('#666666')
Text(${this.stats.avgPower.toFixed(2)} W)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Column() {
Text('最大功率')
.fontSize(14)
.fontColor('#666666')
Text(${this.stats.maxPower.toFixed(2)} W)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Column() {
Text('最小功率')
.fontSize(14)
.fontColor('#666666')
Text(${this.stats.minPower.toFixed(2)} W)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
Column() {
Text('总能耗')
.fontSize(14)
.fontColor('#666666')
Text(${this.stats.totalEnergy.toFixed(3)} kWh)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
.padding(10)
.width('100%')
.padding(15)
.width('90%')
.backgroundColor('#F5F5F5')
.borderRadius(8)
.margin({ bottom: 20 })
// 设备连接状态
if (this.connectedDevices.length > 0) {
Column() {
Text('已连接设备')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 8 })
ForEach(this.connectedDevices, (device) => {
Text(device)
.fontSize(14)
.margin({ bottom: 4 })
})
.padding(10)
.width('90%')
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ bottom: 20 })
// 历史数据图表
EnergyChart({
data: analysisService.getHistoryData(),
width: '100%',
height: 200
})
.margin({ bottom: 20 })
// 控制按钮
Button('协同监测')
.width('80%')
.height(50)
.onClick(() => {
this.showDeviceSelector();
})
.width(‘100%’)
.height('100%')
.padding(20)
.onAppear(() => {
dataService.addListener({
onDataUpdate: (data) => {
this.currentData = data;
});
analysisService.addListener({
onAnalysisUpdate: (data, stats) => {
this.stats = stats;
});
})
.onDisappear(() => {
dataService.removeListener({
onDataUpdate: () => {}
});
analysisService.removeListener({
onAnalysisUpdate: () => {}
});
})
private toggleCollection(): void {
if (this.isCollecting) {
dataService.stopCollection();
else {
dataService.startCollection();
this.isCollecting = !this.isCollecting;
private showDeviceSelector(): void {
const dialog = new AlertDialog({
title: '选择协同设备',
items: ['设备1', '设备2', '设备3'], // 实际应从设备管理服务获取
onSelect: (index) => {
this.connectToDevice(index);
});
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();
}
三、项目配置与权限
权限配置
// module.json5
“module”: {
"requestPermissions": [
“name”: “ohos.permission.ACCESS_DRIVER”,
"reason": "访问Hi3516驱动"
},
“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,
"reason": "同步能耗数据"
},
“name”: “ohos.permission.INTERNET”,
"reason": "加载AI模型"
},
“name”: “ohos.permission.ACCESS_DISTRIBUTED_DEVICE_MANAGER”,
"reason": "发现和连接其他设备"
},
“name”: “ohos.permission.MEDIA_LOCATION”,
"reason": "访问媒体位置信息"
],
"abilities": [
“name”: “MainAbility”,
"type": "page",
"visible": true
},
“name”: “DeviceAbility”,
"type": "page",
"visible": true
},
“name”: “DataCollectionAbility”,
"type": "service",
"backgroundModes": ["dataTransfer"]
]
}
四、总结与扩展
本能耗监测仪表盘实现了以下核心功能:
实时采集:通过Hi3516精确采集用电数据
智能分析:计算功率、能耗等关键指标
多设备协同:多设备实时共享监测数据
可视化展示:多维度展示能耗数据
扩展方向:
能耗预警:设置阈值触发警报
节能建议:基于数据分析提供节能建议
报表导出:生成日/周/月能耗报表
设备管理:对接智能电表管理系统
云同步:安全地上传数据到云端
通过HarmonyOS的分布式能力和Hi3516的硬件能力,我们构建了一个高效、可靠的能源监测系统,帮助用户更好地管理和优化能源使用。
