鸿蒙app 能耗统计图表(日/周/月用电量分析)【华为云根技术】
【摘要】 引言随着智能家居与能源管理需求的提升,用户需要直观地了解设备用电情况以优化能耗。鸿蒙App可利用系统能耗统计接口(或对接智能电表/插座的IoT数据),实现日/周/月用电量分析并以图表形式展示,帮助用户发现高耗电设备、制定节能策略。技术背景鸿蒙能耗数据来源系统级:@ohos.batteryStatistics(部分设备支持获取应用级能耗)IoT设备:通过华为云IoT或私有协议获取智能插座/电...
引言
技术背景
-
鸿蒙能耗数据来源 -
系统级: @ohos.batteryStatistics(部分设备支持获取应用级能耗) -
IoT设备:通过华为云IoT或私有协议获取智能插座/电表数据 -
数据库:本地或分布式数据库存储历史用电记录
-
-
图表绘制:使用鸿蒙 lottie或集成EChartsWebView 方案,或自绘 Canvas 柱状图/折线图 -
时间维度聚合:按日、周、月对原始数据进行分组求和 -
权限: ohos.permission.READ_METERING_DATA(系统能耗)、ohos.permission.INTERNET(IoT数据)
应用使用场景
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
原理解释
核心原理
-
数据采集:定时从系统或IoT设备获取用电量(单位:kWh)。 -
存储:存入关系型数据库(如 @ohos.data.relationalStore)或分布式数据库。 -
聚合计算:根据日/周/月维度对数据分组求和。 -
可视化:将聚合结果渲染为柱状图/折线图。
时间维度聚合公式
-
日: SUM(kWh) WHERE date = 'YYYY-MM-DD' -
周: SUM(kWh) WHERE week = ISOWeekNumber -
月: SUM(kWh) WHERE month = 'YYYY-MM'
核心特性
-
支持多数据源(系统+IoT) -
日/周/月视图切换 -
数据持久化与增量更新 -
图表动画与交互(点击查看详情) -
分布式数据共享(多设备查看同一份用电数据)
原理流程图
graph TD
A[数据采集] --> B[存入数据库]
B --> C{用户选择视图}
C -->|日| D[按天聚合数据]
C -->|周| E[按周聚合数据]
C -->|月| F[按月聚合数据]
D --> G[生成图表数据]
E --> G
F --> G
G --> H[Canvas/ECharts渲染]
H --> I[展示用电量图表]
环境准备
-
DevEco Studio 4.0+ -
HarmonyOS SDK 9+ -
Language: ArkTS -
权限配置( module.json5):
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "获取IoT设备能耗数据",
"usedScene": { "abilities": ["MainAbility"], "when": "inuse" }
},
{
"name": "ohos.permission.READ_METERING_DATA",
"reason": "读取系统能耗统计",
"usedScene": { "abilities": ["MainAbility"], "when": "inuse" }
}
]
}
}
实际详细应用代码示例实现
1. 数据模型
export class EnergyRecord {
id: number = 0;
deviceId: string = '';
timestamp: number = 0; // Unix时间戳(毫秒)
kwh: number = 0; // 用电量
cost: number = 0; // 电费(元)
}
2. 数据库帮助类(RelationalStore)
import relationalStore from '@ohos.data.relationalStore';
import { EnergyRecord } from '../models/EnergyRecord';
export class EnergyDatabase {
private rdbStore: relationalStore.RdbStore | null = null;
private tableName: string = 'energy_record';
async init(context: any): Promise<void> {
const config: relationalStore.StoreConfig = {
name: 'energy.db',
securityLevel: relationalStore.SecurityLevel.S1
};
this.rdbStore = await relationalStore.getRdbStore(context, config);
await this.rdbStore.executeSql(
`CREATE TABLE IF NOT EXISTS ${this.tableName} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
deviceId TEXT NOT NULL,
timestamp INTEGER NOT NULL,
kwh REAL NOT NULL,
cost REAL NOT NULL
)`
);
}
async insert(record: EnergyRecord): Promise<void> {
if (!this.rdbStore) return;
const values = [record.deviceId, record.timestamp, record.kwh, record.cost];
await this.rdbStore.insert(this.tableName, values);
}
async queryByDay(date: string): Promise<EnergyRecord[]> {
if (!this.rdbStore) return [];
const predicates = new relationalStore.RdbPredicates(this.tableName);
predicates.equalTo('date(timestamp/1000, \'unixepoch\')', date);
const resultSet = await this.rdbStore.query(predicates, ['deviceId', 'timestamp', 'kwh', 'cost']);
const list: EnergyRecord[] = [];
while (resultSet.goToNextRow()) {
list.push({
id: resultSet.getLong(resultSet.getColumnIndex('rowid')),
deviceId: resultSet.getString(resultSet.getColumnIndex('deviceId')),
timestamp: resultSet.getLong(resultSet.getColumnIndex('timestamp')),
kwh: resultSet.getDouble(resultSet.getColumnIndex('kwh')),
cost: resultSet.getDouble(resultSet.getColumnIndex('cost'))
});
}
resultSet.close();
return list;
}
async queryGroupByDay(start: number, end: number): Promise<Map<string, number>> {
if (!this.rdbStore) return new Map();
const predicates = new relationalStore.RdbPredicates(this.tableName);
predicates.between('timestamp', start, end);
const sql = `SELECT strftime('%Y-%m-%d', timestamp/1000, 'unixepoch') as day, SUM(kwh) as totalKwh FROM ${this.tableName} WHERE timestamp BETWEEN ? AND ? GROUP BY day`;
const resultSet = await this.rdbStore.querySql(sql, [start, end]);
const map = new Map<string, number>();
while (resultSet.goToNextRow()) {
const day = resultSet.getString(resultSet.getColumnIndex('day'));
const total = resultSet.getDouble(resultSet.getColumnIndex('totalKwh'));
map.set(day, total);
}
resultSet.close();
return map;
}
}
3. 能耗数据服务(模拟IoT数据)
import { EnergyRecord } from '../models/EnergyRecord';
import { EnergyDatabase } from '../database/EnergyDatabase';
export class EnergyService {
private dbHelper = new EnergyDatabase();
async init(context: any) {
await this.dbHelper.init(context);
// 模拟插入一些数据
await this.mockData();
}
private async mockData() {
const now = Date.now();
const oneDay = 86400000;
for (let i = 6; i >= 0; i--) {
const ts = now - i * oneDay;
await this.dbHelper.insert({
deviceId: 'plug_01',
timestamp: ts,
kwh: 2 + Math.random() * 3,
cost: 1.2 + Math.random() * 2
});
}
}
async getDailyUsage(date: string): Promise<EnergyRecord[]> {
return await this.dbHelper.queryByDay(date);
}
async getWeeklyUsage(): Promise<Map<string, number>> {
const now = Date.now();
const weekStart = now - 7 * 86400000;
return await this.dbHelper.queryGroupByDay(weekStart, now);
}
async getMonthlyUsage(): Promise<Map<string, number>> {
const now = Date.now();
const monthStart = now - 30 * 86400000;
return await this.dbHelper.queryGroupByDay(monthStart, now);
}
}
4. 图表绘制(Canvas 柱状图示例)
import { CanvasRenderingContext2D } from '@ohos.graphics.canvas';
@Component
export struct BarChart {
@Prop data: Map<string, number> = new Map();
@Prop barColor: string = '#4CAF50';
private ctx: CanvasRenderingContext2D | null = null;
build() {
Canvas(this.context)
.width('100%')
.height(300)
.onReady((ctx: CanvasRenderingContext2D) => {
this.ctx = ctx;
this.draw();
})
}
private draw() {
if (!this.ctx || this.data.size === 0) return;
const width = this.ctx.width;
const height = this.ctx.height;
const keys = Array.from(this.data.keys());
const values = Array.from(this.data.values());
const maxVal = Math.max(...values);
const barWidth = width / keys.length * 0.8;
const gap = width / keys.length * 0.2;
this.ctx.clearRect(0, 0, width, height);
this.ctx.fillStyle = this.barColor;
keys.forEach((key, idx) => {
const x = idx * (barWidth + gap);
const barHeight = (values[idx] / maxVal) * (height - 20);
const y = height - barHeight - 10;
this.ctx.fillRect(x, y, barWidth, barHeight);
// 绘制标签
this.ctx.fillStyle = '#000';
this.ctx.font = '12px sans-serif';
this.ctx.fillText(key, x, height - 5);
// 绘制数值
this.ctx.fillText(values[idx].toFixed(2) + 'kWh', x, y - 5);
this.ctx.fillStyle = this.barColor;
});
}
}
5. 主页面集成
import { EnergyService } from '../services/EnergyService';
import { BarChart } from '../components/BarChart';
@Entry
@Component
struct Index {
@State viewType: 'day' | 'week' | 'month' = 'week';
@State chartData: Map<string, number> = new Map();
private energySvc = new EnergyService();
aboutToAppear() {
this.energySvc.init(getContext(this)).then(() => {
this.loadData();
});
}
loadData() {
if (this.viewType === 'week') {
this.energySvc.getWeeklyUsage().then(data => this.chartData = data);
} else if (this.viewType === 'month') {
this.energySvc.getMonthlyUsage().then(data => this.chartData = data);
}
}
build() {
Column({ space: 20 }) {
Text('用电量分析').fontSize(24).fontWeight(FontWeight.Bold)
Row() {
Button('日').onClick(() => { this.viewType = 'day'; this.loadData(); })
Button('周').onClick(() => { this.viewType = 'week'; this.loadData(); })
Button('月').onClick(() => { this.viewType = 'month'; this.loadData(); })
}
BarChart({ data: this.chartData, barColor: '#2196F3' })
}
.width('100%').height('100%').justifyContent(FlexAlign.Center)
}
}
运行结果
-
页面顶部显示“用电量分析”标题与日/周/月切换按钮。 -
选择“周”视图,柱状图显示最近 7 天每天的总用电量(kWh)。 -
柱高与数值成正比,底部显示日期,顶部显示具体用电量。
测试步骤以及详细代码
-
创建 HarmonyOS 项目,添加上述文件与权限。 -
真机运行,观察模拟数据生成的图表。 -
替换 mockData为真实 IoT 数据接口(HTTP 请求智能插座)。 -
验证日/周/月数据聚合正确性。 -
多设备登录同一账号,检查分布式数据库同步(需配置 distributedKVStore)。
部署场景
-
家庭能源管家 App:实时监控并分析全屋用电。 -
物业管理系统:统计各户月度用电,生成账单。 -
工业设备监控:分析产线设备能耗趋势。
疑难解答
|
|
|
|
|---|---|---|
|
|
|
timestamp存储单位与查询条件 |
|
|
|
@ohos.data.distributedData |
|
|
|
|
未来展望
-
接入 AI 预测模型,预测未来用电峰值。 -
与鸿蒙智慧屏联动,大屏展示家庭能耗热力图。 -
支持碳排放换算与环保积分。
技术趋势与挑战
-
趋势:端云协同能耗分析;联邦学习保护隐私下的多户能耗模型训练。 -
挑战:海量 IoT 数据实时聚合性能;跨时区时间分组准确性;设备离线数据补传。
总结
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)