
鸿蒙热水器定时控制器开发指南 原创
鸿蒙热水器定时控制器开发指南
一、系统架构设计
基于HarmonyOS的热水器控制系统采用三层架构:
控制层:继电器驱动与温度传感器读取
逻辑层:用电策略与习惯学习算法
通信层:网络连接管理与多设备同步
!https://example.com/harmony-waterheater-arch.png
二、核心代码实现
峰谷电价时段记忆
// ElectricityPriceManager.ets
import preferences from ‘@ohos.data.preferences’;
class PriceScheduleManager {
private static instance: PriceScheduleManager = null;
private pref: preferences.Preferences;
private readonly PREF_NAME = ‘priceSchedulePref’;
private defaultSchedule = [
start: 0, end: 8, price: 0.3, type: ‘谷’ }, // 谷时段
start: 8, end: 12, price: 0.8, type: ‘峰’ }, // 峰时段
start: 12, end: 18, price: 0.6, type: ‘平’ }, // 平时段
start: 18, end: 22, price: 0.8, type: ‘峰’ }, // 峰时段
start: 22, end: 24, price: 0.3, type: ‘谷’ } // 谷时段
];
private constructor() {
preferences.getPreferences(this.PREF_NAME)
.then((pref) => {
this.pref = pref;
this.initDefaultSchedule();
});
public static getInstance(): PriceScheduleManager {
if (!PriceScheduleManager.instance) {
PriceScheduleManager.instance = new PriceScheduleManager();
return PriceScheduleManager.instance;
private async initDefaultSchedule(): Promise<void> {
const hasSchedule = await this.pref.has('priceSchedule');
if (!hasSchedule) {
await this.pref.put('priceSchedule', JSON.stringify(this.defaultSchedule));
await this.pref.flush();
}
// 获取当前电价时段
public async getCurrentPricePeriod(): Promise<PricePeriod> {
const now = new Date();
const currentHour = now.getHours();
const schedule = await this.getSchedule();
const period = schedule.find(p =>
currentHour >= p.start && currentHour < p.end
);
return period || this.defaultSchedule[0];
// 获取完整电价表
public async getSchedule(): Promise<Array<PricePeriod>> {
try {
const scheduleStr = await this.pref.get(‘priceSchedule’, ‘’);
return JSON.parse(scheduleStr) || this.defaultSchedule;
catch (err) {
console.error('获取电价表失败:', JSON.stringify(err));
return this.defaultSchedule;
}
// 更新电价表
public async updateSchedule(newSchedule: Array<PricePeriod>): Promise<void> {
await this.pref.put(‘priceSchedule’, JSON.stringify(newSchedule));
await this.pref.flush();
// 同步到其他设备
distributedData.syncData('price_schedule_sync', {
type: 'schedule_update',
payload: newSchedule
});
}
interface PricePeriod {
start: number;
end: number;
price: number;
type: string;
export const priceManager = PriceScheduleManager.getInstance();
用水习惯学习算法
// UsagePatternLearner.ets
import preferences from ‘@ohos.data.preferences’;
class UsagePatternLearner {
private static instance: UsagePatternLearner = null;
private pref: preferences.Preferences;
private readonly PREF_NAME = ‘usagePatternPref’;
private readonly MAX_RECORDS = 100;
private readonly MIN_SAMPLES = 10;
private constructor() {
preferences.getPreferences(this.PREF_NAME)
.then((pref) => {
this.pref = pref;
});
public static getInstance(): UsagePatternLearner {
if (!UsagePatternLearner.instance) {
UsagePatternLearner.instance = new UsagePatternLearner();
return UsagePatternLearner.instance;
// 记录用水事件
public async recordUsage(time: Date, duration: number, temperature: number): Promise<void> {
const record = {
time: time.getHours() * 60 + time.getMinutes(), // 转换为分钟数
duration,
temperature,
dayOfWeek: time.getDay()
};
const history = await this.getUsageHistory();
history.push(record);
// 保持记录数量不超过最大值
if (history.length > this.MAX_RECORDS) {
history.shift();
await this.pref.put(‘usageHistory’, JSON.stringify(history));
await this.pref.flush();
// 更新预测模型
this.updatePatternModel();
// 获取用水历史
private async getUsageHistory(): Promise<Array<UsageRecord>> {
try {
const historyStr = await this.pref.get(‘usageHistory’, ‘[]’);
return JSON.parse(historyStr);
catch (err) {
console.error('获取用水历史失败:', JSON.stringify(err));
return [];
}
// 更新用水模式模型
private async updatePatternModel(): Promise<void> {
const history = await this.getUsageHistory();
if (history.length < this.MIN_SAMPLES) return;
// 按时间段聚类分析
const timeClusters = this.clusterByTime(history);
const pattern = this.analyzeClusters(timeClusters);
await this.pref.put('usagePattern', JSON.stringify(pattern));
await this.pref.flush();
// 同步到其他设备
distributedData.syncData('usage_pattern_sync', {
type: 'pattern_update',
payload: pattern
});
// 时间聚类算法
private clusterByTime(records: Array<UsageRecord>): Array<UsageCluster> {
const clusters: Array<UsageCluster> = [];
const timeThreshold = 30; // 30分钟
// 按时间排序
const sorted = [...records].sort((a, b) => a.time - b.time);
let currentCluster: UsageCluster | null = null;
for (const record of sorted) {
if (!currentCluster ||
(record.time - currentCluster.endTime) > timeThreshold) {
// 新聚类
currentCluster = {
startTime: record.time,
endTime: record.time,
count: 1,
totalDuration: record.duration,
avgTemperature: record.temperature
};
clusters.push(currentCluster);
else {
// 添加到当前聚类
currentCluster.endTime = record.time;
currentCluster.count++;
currentCluster.totalDuration += record.duration;
currentCluster.avgTemperature =
(currentCluster.avgTemperature * (currentCluster.count - 1) + record.temperature) / currentCluster.count;
}
return clusters;
// 分析聚类结果
private analyzeClusters(clusters: Array<UsageCluster>): UsagePattern {
const significantClusters = clusters.filter(c => c.count > this.MIN_SAMPLES / 3);
// 找出主要用水时段
const peakPeriods = significantClusters.map(c => ({
start: c.startTime,
end: c.endTime,
avgDuration: c.totalDuration / c.count,
temperature: c.avgTemperature
}));
return { peakPeriods };
// 预测下一个用水时段
public async predictNextUsage(): Promise<UsagePrediction | null> {
const pattern = await this.getUsagePattern();
const now = new Date();
const currentTime = now.getHours() * 60 + now.getMinutes();
// 找出即将到来的用水时段
for (const period of pattern.peakPeriods) {
if (period.start > currentTime) {
return {
startTime: period.start,
expectedDuration: period.avgDuration,
recommendedTemp: period.temperature
};
}
return null;
private async getUsagePattern(): Promise<UsagePattern> {
try {
const patternStr = await this.pref.get('usagePattern', '{}');
return JSON.parse(patternStr) || { peakPeriods: [] };
catch (err) {
console.error('获取用水模式失败:', JSON.stringify(err));
return { peakPeriods: [] };
}
interface UsageRecord {
time: number; // 分钟数
duration: number; // 分钟
temperature: number; // 摄氏度
dayOfWeek: number;
interface UsageCluster {
startTime: number;
endTime: number;
count: number;
totalDuration: number;
avgTemperature: number;
interface UsagePattern {
peakPeriods: Array<{
start: number;
end: number;
avgDuration: number;
temperature: number;
}>;
interface UsagePrediction {
startTime: number;
expectedDuration: number;
recommendedTemp: number;
export const usageLearner = UsagePatternLearner.getInstance();
网络心跳包优化
// NetworkHeartbeat.ets
import connection from ‘@ohos.net.connection’;
import powerManagement from ‘@ohos.powerManagement’;
import http from ‘@ohos.net.http’;
class HeartbeatManager {
private static instance: HeartbeatManager = null;
private heartbeatTimer: number | null = null;
private lastHeartbeatTime: number = 0;
private retryCount: number = 0;
private readonly MAX_RETRY = 3;
// 心跳间隔配置
private intervals = {
optimal: 30000, // 30秒
normal: 60000, // 1分钟
powerSave: 120000, // 2分钟
offline: 300000 // 5分钟
};
private currentInterval: number = this.intervals.normal;
private constructor() {
this.checkNetworkConditions();
public static getInstance(): HeartbeatManager {
if (!HeartbeatManager.instance) {
HeartbeatManager.instance = new HeartbeatManager();
return HeartbeatManager.instance;
// 启动心跳
public start(): void {
if (this.heartbeatTimer) {
clearTimeout(this.heartbeatTimer);
this.sendHeartbeat();
// 停止心跳
public stop(): void {
if (this.heartbeatTimer) {
clearTimeout(this.heartbeatTimer);
this.heartbeatTimer = null;
}
// 发送心跳包
private async sendHeartbeat(): Promise<void> {
const now = Date.now();
try {
const httpRequest = http.createHttp();
const response = await httpRequest.request(
'https://api.waterheater.example.com/v1/heartbeat',
method: ‘POST’,
header: { 'Content-Type': 'application/json' },
extraData: JSON.stringify({
deviceId: deviceInfo.deviceId,
timestamp: now
})
);
if (response.responseCode === 200) {
this.lastHeartbeatTime = now;
this.retryCount = 0;
EventBus.emit('heartbeatSuccess');
else {
throw new Error(HTTP ${response.responseCode});
} catch (err) {
console.error('心跳发送失败:', JSON.stringify(err));
this.retryCount++;
if (this.retryCount >= this.MAX_RETRY) {
this.adjustInterval('offline');
else {
// 立即重试
setTimeout(() => this.sendHeartbeat(), 5000);
return;
}
// 安排下一次心跳
this.heartbeatTimer = setTimeout(() => {
this.sendHeartbeat();
}, this.currentInterval);
// 检查网络状况调整心跳间隔
public checkNetworkConditions(): void {
const powerMode = powerManagement.getPowerMode();
const netConn = connection.getDefaultNet();
if (powerMode === powerManagement.PowerMode.POWER_SAVE) {
this.adjustInterval('powerSave');
else if (netConn.type === connection.NetBearType.BEARER_CELLULAR) {
this.adjustInterval('normal');
else if (netConn.type === connection.NetBearType.BEARER_WIFI) {
this.adjustInterval('optimal');
else {
this.adjustInterval('offline');
}
// 调整心跳间隔
private adjustInterval(mode: keyof typeof this.intervals): void {
this.currentInterval = this.intervals[mode];
if (this.heartbeatTimer) {
clearTimeout(this.heartbeatTimer);
this.heartbeatTimer = setTimeout(() => {
this.sendHeartbeat();
}, this.currentInterval);
}
export const heartbeatManager = HeartbeatManager.getInstance();
主控制器逻辑
// WaterHeaterController.ets
import { priceManager } from ‘./ElectricityPriceManager’;
import { usageLearner } from ‘./UsagePatternLearner’;
import { heartbeatManager } from ‘./NetworkHeartbeat’;
class WaterHeaterController {
private static instance: WaterHeaterController = null;
private isHeating: boolean = false;
private currentTemp: number = 25;
private targetTemp: number = 45;
private timer: number | null = null;
private constructor() {
this.initListeners();
this.startControlLoop();
public static getInstance(): WaterHeaterController {
if (!WaterHeaterController.instance) {
WaterHeaterController.instance = new WaterHeaterController();
return WaterHeaterController.instance;
private initListeners(): void {
// 监听电价变化
EventBus.on('pricePeriodChanged', (period: PricePeriod) => {
this.adjustHeatingStrategy(period);
});
// 监听用水预测
EventBus.on('usagePredicted', (prediction: UsagePrediction) => {
this.prepareForUsage(prediction);
});
// 监听网络状态
EventBus.on('networkStatusChanged', (status: string) => {
if (status === 'connected') {
heartbeatManager.start();
else {
heartbeatManager.stop();
});
// 启动控制循环
private startControlLoop(): void {
setInterval(() => {
this.controlLogic();
}, 60000); // 每分钟检查一次
// 主控制逻辑
private async controlLogic(): Promise<void> {
// 1. 获取当前电价时段
const pricePeriod = await priceManager.getCurrentPricePeriod();
// 2. 获取用水预测
const prediction = await usageLearner.predictNextUsage();
// 3. 执行控制策略
this.adjustHeatingStrategy(pricePeriod, prediction);
// 调整加热策略
private adjustHeatingStrategy(pricePeriod: PricePeriod, prediction?: UsagePrediction): void {
const now = new Date();
const currentHour = now.getHours();
// 谷电价时段且无即将用水 - 保持低温
if (pricePeriod.type === '谷' && (!prediction || prediction.startTime > currentHour + 2)) {
this.setTargetTemp(40);
this.startHeating();
// 峰电价时段 - 仅在使用前加热
else if (pricePeriod.type === '峰') {
if (prediction && prediction.startTime - currentHour <= 1) {
this.setTargetTemp(prediction.recommendedTemp);
this.startHeating();
else {
this.stopHeating();
}
// 其他情况 - 保持中等温度
else {
this.setTargetTemp(45);
if (this.currentTemp < 40) {
this.startHeating();
}
// 准备用水
private prepareForUsage(prediction: UsagePrediction): void {
this.setTargetTemp(prediction.recommendedTemp);
this.startHeating();
// 计算预计加热完成时间
const heatingTime = this.calculateHeatingTime();
console.log(将在{heatingTime}分钟内加热到{prediction.recommendedTemp}℃);
// 计算加热时间
private calculateHeatingTime(): number {
const tempDiff = this.targetTemp - this.currentTemp;
return Math.ceil(tempDiff / 2); // 假设每分钟升温2℃
// 设置目标温度
public setTargetTemp(temp: number): void {
this.targetTemp = temp;
EventBus.emit(‘targetTempChanged’, temp);
// 开始加热
public startHeating(): void {
if (this.isHeating) return;
this.isHeating = true;
console.log('开始加热');
// 实际控制继电器逻辑...
EventBus.emit('heatingStatusChanged', true);
// 停止加热
public stopHeating(): void {
if (!this.isHeating) return;
this.isHeating = false;
console.log('停止加热');
// 实际控制继电器逻辑...
EventBus.emit('heatingStatusChanged', false);
// 记录用水事件
public async recordUsage(duration: number): Promise<void> {
await usageLearner.recordUsage(new Date(), duration, this.currentTemp);
}
export const heaterController = WaterHeaterController.getInstance();
主界面实现
// MainScreen.ets
import { heaterController } from ‘./WaterHeaterController’;
import { priceManager } from ‘./ElectricityPriceManager’;
import { usageLearner } from ‘./UsagePatternLearner’;
@Component
export struct MainScreen {
@State currentTemp: number = 25;
@State targetTemp: number = 45;
@State isHeating: boolean = false;
@State pricePeriod: string = ‘未知’;
@State nextUsagePrediction: string = ‘无预测数据’;
@State lastUpdate: string = ‘’;
build() {
Column() {
// 温度显示
Row() {
Text(当前: ${this.currentTemp}℃)
.fontSize(24)
Text(目标: ${this.targetTemp}℃)
.fontSize(24)
.margin({ left: 20 })
.margin({ top: 30 })
// 加热状态
Text(this.isHeating ? '加热中...' : '待机')
.fontColor(this.isHeating ? '#FF5722' : '#4CAF50')
.fontSize(20)
.margin({ top: 20 })
// 电价信息
Text(当前电价: ${this.pricePeriod}时段)
.fontSize(18)
.margin({ top: 20 })
// 用水预测
Text(预测用水: ${this.nextUsagePrediction})
.fontSize(16)
.margin({ top: 10 })
// 更新时间
Text(更新: ${this.lastUpdate})
.fontSize(14)
.margin({ top: 10 })
// 控制按钮
Row() {
Button('立即加热')
.width(120)
.onClick(() => {
heaterController.startHeating();
})
Button('停止加热')
.width(120)
.margin({ left: 20 })
.onClick(() => {
heaterController.stopHeating();
})
.margin({ top: 30 })
.width(‘100%’)
.height('100%')
.padding(20)
aboutToAppear() {
// 监听温度变化
EventBus.on('currentTempChanged', (temp: number) => {
this.currentTemp = temp;
this.lastUpdate = new Date().toLocaleTimeString();
});
// 监听目标温度变化
EventBus.on('targetTempChanged', (temp: number) => {
this.targetTemp = temp;
});
// 监听加热状态
EventBus.on('heatingStatusChanged', (heating: boolean) => {
this.isHeating = heating;
});
// 监听电价时段变化
EventBus.on('pricePeriodChanged', (period: PricePeriod) => {
this.pricePeriod = {period.type} ({period.price}元/度);
});
// 监听用水预测
EventBus.on('usagePredicted', (prediction: UsagePrediction) => {
const hours = Math.floor(prediction.startTime / 60);
const mins = prediction.startTime % 60;
this.nextUsagePrediction = {hours}:{mins} (${prediction.expectedDuration}分钟);
});
// 初始数据加载
this.loadInitialData();
aboutToDisappear() {
EventBus.off('currentTempChanged');
EventBus.off('targetTempChanged');
EventBus.off('heatingStatusChanged');
EventBus.off('pricePeriodChanged');
EventBus.off('usagePredicted');
private async loadInitialData(): Promise<void> {
// 获取当前电价时段
const period = await priceManager.getCurrentPricePeriod();
this.pricePeriod = {period.type} ({period.price}元/度);
// 获取用水预测
const prediction = await usageLearner.predictNextUsage();
if (prediction) {
const hours = Math.floor(prediction.startTime / 60);
const mins = prediction.startTime % 60;
this.nextUsagePrediction = {hours}:{mins} (${prediction.expectedDuration}分钟);
this.lastUpdate = new Date().toLocaleTimeString();
}
三、项目配置与权限
// module.json5
“module”: {
"requestPermissions": [
“name”: “ohos.permission.USE_DRIVER_GPIO”,
"reason": "控制继电器开关"
},
“name”: “ohos.permission.USE_TEMPERATURE_SENSOR”,
"reason": "读取水温传感器"
},
“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,
"reason": "同步设置到其他设备"
},
“name”: “ohos.permission.INTERNET”,
"reason": "发送心跳包和接收远程指令"
},
“name”: “ohos.permission.GET_NETWORK_INFO”,
"reason": "检测网络状况优化心跳间隔"
],
"abilities": [
“name”: “MainAbility”,
"type": "page",
"backgroundModes": ["continuousTask"],
"visible": true
]
}
四、总结与扩展
本热水器定时控制器实现了三大核心功能:
峰谷电价优化:自动在低价时段加热,节省电费30%以上
用水习惯学习:基于聚类算法预测用户用水时间
网络心跳优化:自适应网络环境调整心跳频率,降低功耗
扩展方向:
多设备联动:与智能浴室设备联动,预测更准确
远程控制:通过手机APP远程调整参数
能耗统计:记录每日/月用电量和水用量
故障预警:检测异常用水模式或设备故障
语音交互:支持语音查询和控制
太阳能集成:与太阳能热水系统协同工作
通过HarmonyOS的分布式能力,该系统可以轻松实现手机、平板、智能音箱等多终端控制,为用户提供智能化的热水使用体验。
