浴室热水器智能温控系统
一、实际应用场景与痛点
应用场景
家庭浴室热水器存在明显的用水时间规律:
- 早高峰(6:00-9:00):家庭洗漱、洗澡集中时段
- 晚高峰(18:00-23:00):下班后洗澡、洗碗等
- 日常时段:零星用水
- 季节变化:夏季用水量少、温度低,冬季需求相反
- 家庭结构:单身、夫妻、有孩家庭用水习惯不同
痛点分析
- 预热延迟:临时用水需等待加热,浪费时间和水资源
- 温度波动:多人连续用水时水温不稳,忽冷忽热
- 能源浪费:24小时保温耗能,或频繁开关机
- 使用不便:需手动调节温度,特别是老人儿童
- 安全隐患:水温过高可能导致烫伤
- 设备损耗:频繁启停加热器缩短使用寿命
二、核心逻辑讲解
系统架构
采用"预测-控制"双环智能控制系统:
数据采集层 ──▶ 习惯学习层 ──▶ 预测决策层 ──▶ 实时控制层 │ │ │ │ 温度传感器 用水模式 用水预测 PID控制器 流量传感器 识别(聚类) (时间序列) + 前馈补偿 时间记录 行为建模 加热计划
核心算法原理
- 用水模式识别(无监督学习)
- 基于历史数据聚类分析用水习惯
- 识别早晚高峰、工作日/周末模式
- 用水需求预测(时间序列+LSTM)
- 预测未来24小时用水量和水温需求
- 考虑季节、天气、节假日因素
- 智能预热策略(强化学习)
- 提前加热,确保用水时温度适宜
- 平衡即时性与节能目标
- 稳定温度控制(模糊自适应PID)
- 实时调节加热功率和水流混合
- 前馈补偿应对水压变化
优化目标函数
总成本 = α·能耗成本 + β·等待时间 + γ·温度波动 + δ·设备损耗 其中:α+β+γ+δ=1,权重可调
三、模块化代码实现
项目结构
smart_water_heater/ │ ├── main.py # 主程序入口 ├── config.py # 配置文件 ├── requirements.txt # 依赖包 ├── simulate_data.py # 数据生成(模拟/测试用) │ ├── core/ # 核心算法模块 │ ├── init.py │ ├── pattern_learner.py # 用水模式学习 │ ├── demand_predictor.py # 需求预测 │ ├── preheat_scheduler.py # 预热调度 │ └── temperature_controller.py # 温度控制器 │ ├── sensors/ # 传感器接口 │ ├── init.py │ ├── temperature_sensor.py │ ├── flow_sensor.py │ └── virtual_sensors.py # 模拟传感器 │ ├── models/ # 数据模型 │ ├── init.py │ ├── water_usage.py │ ├── user_habit.py │ └── system_state.py │ ├── utils/ # 工具函数 │ ├── init.py │ ├── data_logger.py │ ├── time_utils.py │ ├── energy_calculator.py │ └── visualization.py │ ├── database/ # 数据存储 │ ├── init.py │ ├── data_manager.py │ └── habit_database.db # SQLite数据库 │ ├── tests/ # 测试文件 │ ├── init.py │ ├── test_pattern_learner.py │ └── test_controller.py │ └── web_interface/ # Web界面(可选) ├── app.py ├── templates/ └── static/
核心代码实现
main.py
#!/usr/bin/env python3 """ 智能热水器温控系统主程序 基于用水习惯预测的自适应温度控制系统 """
import time import logging import json from datetime import datetime, timedelta from typing import Dict, List, Tuple import threading from queue import Queue import numpy as np
导入自定义模块
from config import SystemConfig from models.system_state import SystemState from core.pattern_learner import UsagePatternLearner from core.demand_predictor import DemandPredictor from core.preheat_scheduler import PreheatScheduler from core.temperature_controller import AdaptiveTemperatureController from sensors.virtual_sensors import VirtualSensorSystem from utils.data_logger import DataLogger from utils.visualization import SystemVisualizer from database.data_manager import DataManager
配置日志
logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('water_heater.log'), logging.StreamHandler() ] ) logger = logging.getLogger(name)
class SmartWaterHeaterSystem: """智能热水器系统主类"""
def __init__(self, config_path: str = 'config.yaml'):
"""
初始化智能热水器系统
Args:
config_path: 配置文件路径
"""
# 加载配置
self.config = SystemConfig(config_path)
# 初始化系统状态
self.state = SystemState()
# 初始化数据管理器
self.data_manager = DataManager('database/habit_database.db')
# 初始化核心模块
self.pattern_learner = UsagePatternLearner(self.config, self.data_manager)
self.demand_predictor = DemandPredictor(self.config, self.data_manager)
self.preheat_scheduler = PreheatScheduler(self.config)
self.temp_controller = AdaptiveTemperatureController(self.config)
# 初始化传感器(虚拟/真实)
self.sensors = VirtualSensorSystem()
# 初始化工具
self.data_logger = DataLogger()
self.visualizer = SystemVisualizer()
# 消息队列
self.control_queue = Queue()
self.sensor_queue = Queue()
# 线程控制
self.running = False
self.control_thread = None
self.sensor_thread = None
# 统计数据
self.stats = {
'total_energy_used': 0.0, # kWh
'total_water_used': 0.0, # 升
'avg_wait_time': 0.0, # 秒
'temp_stability': 0.0, # 温度稳定性得分
'comfort_score': 0.0 # 舒适度得分
}
# 加载历史数据
self._load_historical_data()
logger.info("智能热水器系统初始化完成")
def _load_historical_data(self):
"""加载历史用水数据"""
try:
# 加载最近30天的数据
end_date = datetime.now()
start_date = end_date - timedelta(days=30)
historical_data = self.data_manager.get_usage_data(start_date, end_date)
if historical_data:
# 训练用水模式识别模型
self.pattern_learner.train(historical_data)
# 初始化需求预测模型
self.demand_predictor.initialize(historical_data)
logger.info(f"加载了 {len(historical_data)} 条历史用水记录")
else:
logger.info("无历史数据,将使用默认配置")
except Exception as e:
logger.error(f"加载历史数据失败: {e}")
def _sensor_reading_thread(self):
"""传感器数据读取线程"""
logger.info("传感器数据采集线程启动")
while self.running:
try:
# 读取所有传感器数据
sensor_data = self.sensors.read_all()
# 更新系统状态
self.state.update_from_sensors(sensor_data)
# 放入消息队列
self.sensor_queue.put({
'timestamp': datetime.now(),
'data': sensor_data,
'type': 'sensor_update'
})
# 记录数据
self.data_logger.log_sensor_data(sensor_data)
# 每秒读取一次
time.sleep(1)
except Exception as e:
logger.error(f"传感器读取错误: {e}")
time.sleep(5)
def _control_thread(self):
"""主控制线程"""
logger.info("主控制线程启动")
# 上次预测时间
last_prediction_time = datetime.now() - timedelta(hours=1)
while self.running:
try:
current_time = datetime.now()
# 1. 处理传感器数据
if not self.sensor_queue.empty():
sensor_msg = self.sensor_queue.get_nowait()
self._process_sensor_data(sensor_msg)
# 2. 每小时更新一次预测
if (current_time - last_prediction_time).seconds >= 3600:
self._update_predictions(current_time)
last_prediction_time = current_time
# 3. 检查是否需要预热
self._check_preheat(current_time)
# 4. 执行温度控制
self._execute_temperature_control()
# 5. 更新统计信息
self._update_statistics()
# 控制频率:每秒10次
time.sleep(0.1)
except Exception as e:
logger.error(f"控制线程错误: {e}")
time.sleep(1)
def _process_sensor_data(self, sensor_msg: Dict):
"""处理传感器数据"""
sensor_data = sensor_msg['data']
# 检测是否开始用水
if sensor_data['water_flow'] > self.config.FLOW_THRESHOLD:
if not self.state.water_running:
# 开始用水事件
self._handle_water_start(sensor_msg['timestamp'])
self.state.water_running = True
else:
if self.state.water_running:
# 结束用水事件
self._handle_water_end(sensor_msg['timestamp'])
self.state.water_running = False
# 检测水温异常
if sensor_data['outlet_temp'] > self.config.MAX_SAFE_TEMP:
logger.warning(f"出水温度过高: {sensor_data['outlet_temp']}°C")
self._emergency_shutdown()
def _handle_water_start(self, timestamp: datetime):
"""处理开始用水事件"""
logger.info(f"检测到用水开始: {timestamp.strftime('%H:%M:%S')}")
# 记录用水开始
self.state.current_usage_start = timestamp
self.state.usage_count_today += 1
# 如果是预测的用水时间,给予正反馈
predicted_usage = self.demand_predictor.get_current_prediction()
if predicted_usage and predicted_usage['expected']:
# 预测准确,增强模型信心
self.demand_predictor.update_feedback(True)
# 切换到实时控制模式
self.temp_controller.set_mode('realtime')
def _handle_water_end(self, timestamp: datetime):
"""处理结束用水事件"""
if self.state.current_usage_start:
duration = (timestamp - self.state.current_usage_start).seconds
# 记录用水数据
usage_record = {
'start_time': self.state.current_usage_start,
'end_time': timestamp,
'duration': duration,
'avg_flow': self.state.current_flow_rate,
'avg_temp': self.state.current_outlet_temp,
'energy_used': self.state.current_energy_used
}
# 保存到数据库
self.data_manager.add_usage_record(usage_record)
# 更新用水习惯模型
self.pattern_learner.update_with_new_record(usage_record)
logger.info(f"用水结束: 时长{duration}秒, "
f"平均流量{self.state.current_flow_rate:.1f}L/min, "
f"平均温度{self.state.current_outlet_temp:.1f}°C")
# 重置状态
self.state.reset_usage_session()
def _update_predictions(self, current_time: datetime):
"""更新用水需求预测"""
try:
# 获取未来24小时预测
predictions = self.demand_predictor.predict_next_24h(current_time)
# 更新预热计划
preheat_plan = self.preheat_scheduler.generate_schedule(
predictions,
current_time,
self.state.tank_temp
)
# 应用预热计划
self.state.preheat_schedule = preheat_plan
# 记录预测结果
self.data_logger.log_prediction(predictions)
# 可视化预测结果(可选)
if self.config.ENABLE_VISUALIZATION:
self.visualizer.plot_predictions(predictions, current_time)
logger.info(f"已更新用水预测和预热计划,未来24小时预测用水次数: {len(predictions)}")
except Exception as e:
logger.error(f"更新预测失败: {e}")
def _check_preheat(self, current_time: datetime):
"""检查并执行预热"""
if not self.state.preheat_schedule:
return
# 查找当前时间应该执行的预热任务
for task in self.state.preheat_schedule:
if task['start_time'] <= current_time <= task['end_time']:
if not task['executed']:
# 执行预热
self._execute_preheat(task, current_time)
break
def _execute_preheat(self, task: Dict, current_time: datetime):
"""执行预热任务"""
logger.info(f"执行预热: 目标温度{task['target_temp']}°C, "
f"预计用水时间{task['water_usage_time'].strftime('%H:%M')}")
# 设置加热器目标温度
target_temp = task['target_temp']
heating_power = self.temp_controller.calculate_preheat_power(
current_temp=self.state.tank_temp,
target_temp=target_temp,
time_available=(task['water_usage_time'] - current_time).seconds
)
# 控制加热器
self.temp_controller.set_heating_power(heating_power)
self.state.heating_power = heating_power
# 标记任务已执行
task['executed'] = True
task['actual_start_time'] = current_time
# 记录预热事件
self.data_logger.log_preheat_event(task)
def _execute_temperature_control(self):
"""执行实时温度控制"""
if self.state.water_running:
# 实时用水控制模式
control_output = self.temp_controller.realtime_control(
setpoint=self.state.target_outlet_temp,
current_temp=self.state.outlet_temp,
flow_rate=self.state.current_flow_rate,
inlet_temp=self.state.inlet_temp
)
else:
# 保温控制模式
control_output = self.temp_controller.keep_warm_control(
current_temp=self.state.tank_temp,
target_temp=self.config.IDLE_TEMP
)
# 应用控制输出
self._apply_control_output(control_output)
def _apply_control_output(self, control_output: Dict):
"""应用控制输出到执行器"""
# 更新加热器功率
if 'heating_power' in control_output:
self.state.heating_power = control_output['heating_power']
# 模拟加热效果
heating_effect = control_output['heating_power'] * 0.001 # 简化模型
# 更新水温
if self.state.water_running:
# 用水时加热效果有限
temp_increase = heating_effect * 0.1
else:
# 保温时加热效果明显
temp_increase = heating_effect * 0.5
self.state.tank_temp += temp_increase
self.state.tank_temp = min(self.state.tank_temp, self.config.MAX_TANK_TEMP)
# 更新混水阀位置(如果支持)
if 'mix_valve_position' in control_output:
self.state.mix_valve_position = control_output['mix_valve_position']
# 计算出口温度(简化模型)
tank_temp = self.state.tank_temp
inlet_temp = self.state.inlet_temp
valve_pos = self.state.mix_valve_position # 0-1, 0全冷水,1全热水
self.state.outlet_temp = inlet_temp + (tank_temp - inlet_temp) * valve_pos
# 记录控制动作
self.data_logger.log_control_action(control_output)
def _emergency_shutdown(self):
"""紧急关闭"""
logger.warning("执行紧急关闭程序")
# 关闭加热器
self.state.heating_power = 0
self.temp_controller.emergency_stop()
# 切换到冷水模式
self.state.mix_valve_position = 0.1
# 发出警报
self._send_alert("水温过高,已执行紧急关闭")
def _send_alert(self, message: str):
"""发送警报"""
logger.warning(f"系统警报: {message}")
# 这里可以集成短信、邮件、APP推送等通知方式
if self.config.ENABLE_NOTIFICATIONS:
# 模拟发送通知
print(f"警报: {message}")
def _update_statistics(self):
"""更新统计数据"""
# 更新能耗统计
self.stats['total_energy_used'] += self.state.heating_power * 0.1 / 3600 # 转换为kWh
# 更新用水统计
if self.state.water_running:
self.stats['total_water_used'] += self.state.current_flow_rate * 0.1 / 60
# 更新温度稳定性统计
temp_variation = abs(self.state.outlet_temp - self.state.target_outlet_temp)
self.stats['temp_stability'] = 0.9 * self.stats['temp_stability'] + 0.1 * (1 - temp_variation / 5)
def set_target_temperature(self, temp: float):
"""用户设置目标温度"""
if self.config.MIN_OUTLET_TEMP <= temp <= self.config.MAX_OUTLET_TEMP:
self.state.target_outlet_temp = temp
logger.info(f"用户设置目标温度: {temp}°C")
return True
else:
logger.warning(f"目标温度{temp}°C超出安全范围")
return False
def set_operating_mode(self, mode: str):
"""设置运行模式"""
valid_modes = ['auto', 'manual', 'eco', 'comfort']
if mode in valid_modes:
self.state.operating_mode = mode
logger.info(f"设置运行模式: {mode}")
# 根据模式调整参数
if mode == 'eco':
self.config.IDLE_TEMP = 45
self.state.target_outlet_temp = 38
elif mode == 'comfort':
self.config.IDLE_TEMP = 60
self.state.target_outlet_temp = 42
return True
else:
logger.warning(f"无效的运行模式: {mode}")
return False
def get_system_status(self) -> Dict:
"""获取系统状态"""
return {
'timestamp': datetime.now().isoformat(),
'tank_temperature': round(self.state.tank_temp, 1),
'outlet_temperature': round(self.state.outlet_temp, 1),
'inlet_temperature': round(self.state.inlet_temp, 1),
'water_flow': round(self.state.current_flow_rate, 1),
'heating_power': round(self.state.heating_power, 1),
'target_temperature': round(self.state.target_outlet_temp, 1),
'water_running': self.state.water_running,
'operating_mode': self.state.operating_mode,
'mix_valve_position': round(self.state.mix_valve_position, 2),
'usage_count_today': self.state.usage_count_today,
'energy_used_today': round(self.stats['total_energy_used'], 2),
'water_used_today': round(self.stats['total_water_used'], 1),
'temperature_stability': round(self.stats['temp_stability'], 3)
}
def start(self):
"""启动系统"""
if self.running:
logger.warning("系统已在运行中")
return
logger.info("启动智能热水器系统...")
self.running = True
# 启动传感器线程
self.sensor_thread = threading.Thread(
target=self._sensor_reading_thread,
name="SensorThread",
daemon=True
)
self.sensor_thread.start()
# 启动控制线程
self.control_thread = threading.Thread(
target=self._control_thread,
name="ControlThread",
daemon=True
)
self.control_thread.start()
logger.info("系统启动完成,开始运行")
def stop(self):
"""停止系统"""
logger.info("停止智能热水器系统...")
self.running = False
# 等待线程结束
if self.sensor_thread:
self.sensor_thread.join(timeout=5)
if self.control_thread:
self.control_thread.join(timeout=5)
# 保存数据
self.data_manager.close()
self.data_logger.save_to_file()
# 生成运行报告
self._generate_report()
logger.info("系统已停止")
def _generate_report(self):
"""生成运行报告"""
report = {
'run_duration': str(datetime.now() - self.state.system_start_time),
'total_energy_used_kwh': round(self.stats['total_energy_used'], 2),
'total_water_used_liters': round(self.stats['total_water_used'], 1),
'average_wait_time_seconds': round(self.stats['avg_wait_time'], 1),
'temperature_stability_score': round(self.stats['temp_stability'], 3),
'comfort_score': round(self.stats['comfort_score'], 3),
'usage_count': self.state.usage_count_today,
'estimated_savings_percent': self._calculate_savings()
}
# 保存报告
report_file = f"report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(report_file, 'w') as f:
json.dump(report, f, indent=2)
logger.info(f"运行报告已生成: {report_file}")
return report
def _calculate_savings(self) -> float:
"""计算节能效果"""
# 基准能耗:传统热水器
baseline_energy = 5.0 # kWh/天(假设值)
# 实际能耗
actual_energy = self.stats['total_energy_used']
# 运行时长(小时)
run_hours = (datetime.now() - self.state.system_start_time).seconds / 3600
if run_hours < 0.1: # 避免除零
run_hours = 1
# 折算为每日能耗
daily_energy =
如果你觉得这个工具好用,欢迎关注我!