import time
import random
class DummySensor:
def measure(self):
pass
def temperature(self):
# 使温度变化更平滑,模拟真实环境
current_temp = getattr(self, 'current_temp', 25)
self.current_temp = round(current_temp + random.uniform(-0.5, 0.5), 1)
return max(20, min(30, self.current_temp))
def humidity(self):
# 使湿度变化更平滑,模拟真实环境
current_hum = getattr(self, 'current_hum', 50)
self.current_hum = round(current_hum + random.uniform(-2, 2), 1)
return max(30, min(80, self.current_hum))
class DummyUltrasonic:
def distance_cm(self):
# 模拟水位变化,大部分时间高于阈值
if random.random() < 0.9: # 90%概率水位正常
return round(random.uniform(3, 10), 1)
else: # 10%概率低水位
return round(random.uniform(0, 2), 1)
class DummyPin:
IN = 0
OUT = 1
PULL_UP = 2
def __init__(self, pin, mode=None, pull=None):
self.pin = pin
self.mode = mode
self.pull = pull
self.value_state = 0
self.last_print_time = 0
self.blink_interval = 0 # 闪烁间隔(ms)
self.blink_state = 0 # 闪烁状态
def value(self, val=None):
current_time = time.time() * 1000 # 毫秒
if val is not None:
# 处理闪烁逻辑
if isinstance(val, int):
self.value_state = val
self.blink_interval = 0 # 关闭闪烁
elif isinstance(val, float):
self.blink_interval = val * 1000 # 转换为毫秒
else:
raise ValueError("val must be int or float")
# 打印状态变化
self._print_status()
else:
# 处理闪烁逻辑
if self.blink_interval > 0:
self.blink_state = int(current_time // self.blink_interval) % 2
# 每500ms更新一次显示
if current_time - self.last_print_time > 500:
self._print_status()
self.last_print_time = current_time
return self.blink_state
else:
return self.value_state
def _print_status(self):
status = ""
if self.pin == 12: # 电源LED
status = "开启" if self.value_state else "关闭"
print(f"电源LED ({self.pin}): {status}")
elif self.pin == 13: # 水位LED
if self.blink_interval > 0:
status = f"闪烁({int(1000/self.blink_interval)}Hz)"
else:
status = "开启" if self.value_state else "关闭"
print(f"水位LED ({self.pin}): {status}")
elif self.pin == 14: # 工作LED
status = "开启" if self.value_state else "关闭"
print(f"工作LED ({self.pin}): {status}")
elif self.pin == 23: # 继电器
status = "开启(加湿)" if self.value_state else "关闭"
print(f"继电器 ({self.pin}): {status}")
class DummyI2C:
def __init__(self, id, scl, sda, freq):
pass
class DummyOLED:
def __init__(self, width, height, i2c):
self.width = width
self.height = height
self.buffer = []
self.last_update_time = 0
def fill(self, val):
self.buffer = []
def text(self, string, x, y):
self.buffer.append(f"[{x},{y}]: {string}")
def show(self):
current_time = time.time()
# 限制更新频率为2Hz,避免刷屏
if current_time - self.last_update_time > 0.5:
print("OLED显示:")
for line in self.buffer:
print(line)
print("-" * 30)
self.last_update_time = current_time
# 初始化模拟硬件
dht_sensor = DummySensor()
ultrasonic = DummyUltrasonic()
pir_sensor = DummyPin(2, mode=DummyPin.IN)
relay = DummyPin(23, mode=DummyPin.OUT)
button_up = DummyPin(5, mode=DummyPin.IN, pull=DummyPin.PULL_UP)
button_down = DummyPin(15, mode=DummyPin.IN, pull=DummyPin.PULL_UP)
i2c = DummyI2C(0, scl=DummyPin(22), sda=DummyPin(21), freq=400000)
oled = DummyOLED(128, 64, i2c)
# 初始化LED引脚
led_power = DummyPin(12, mode=DummyPin.OUT) # 绿色LED-电源指示
led_water = DummyPin(13, mode=DummyPin.OUT) # 红色LED-低水位报警
led_working = DummyPin(14, mode=DummyPin.OUT) # 蓝色LED-工作状态
# 阈值设置
humidity_threshold = 50 # 初始湿度阈值50%
low_water_level = 2 # 低水位阈值2cm
setting_mode = False # 设置模式标志
last_button_time = 0 # 上次按钮按下时间
button_debounce = 300 # 按钮消抖时间(ms)
# 全局变量存储PIR状态
pir_current_status = "无人"
# 模拟保存设置
def save_settings():
print(f"保存湿度阈值: {humidity_threshold}%")
return True
# 模拟加载设置
def load_settings():
print(f"加载湿度阈值: {humidity_threshold}%")
return humidity_threshold
# 模拟时间校准
def sync_time():
return "2025-06-17", "15:30:45"
# 传感器数据读取函数
def read_sensors():
global pir_current_status
try:
dht_sensor.measure()
temp = dht_sensor.temperature()
hum = dht_sensor.humidity()
water_level = ultrasonic.distance_cm()
# 模拟PIR状态变化,增加一些持续性
if random.random() < 0.1: # 10%概率改变状态
pir_current_status = "有人" if random.random() > 0.7 else "无人"
print(f"读取传感器: 温度={temp}°C, 湿度={hum}%, 水位={water_level}cm, PIR={pir_current_status}")
return temp, hum, water_level, pir_current_status
except Exception as e:
print(f"传感器读取错误: {e}")
return None, None, None, None
# LED状态控制函数
def update_led_status(temp, hum, water_level, pir_status, relay_status):
# 电源指示灯(常亮)
led_power.value(1)
# 低水位报警(闪烁)
if water_level is not None and water_level <= low_water_level:
led_water.value(0.5) # 0.5秒闪烁周期(2Hz)
else:
led_water.value(0)
# 工作状态指示
if relay_status: # 继电器开启(加湿中)
led_working.value(1)
else:
led_working.value(0)
# 按钮处理函数
def handle_buttons():
global humidity_threshold, setting_mode, last_button_time
current_time = int(time.time() * 1000) # 毫秒级时间
# 模拟按钮按下(每5秒随机按下一个按钮)
if random.random() < 0.05: # 5%概率按下按钮
if random.random() > 0.5: # 50%概率按上调按钮
button_up.value_state = 0 # 模拟按钮按下
print("模拟按下阈值上调按钮")
else:
button_down.value_state = 0 # 模拟按钮按下
print("模拟按下阈值下调按钮")
else:
button_up.value_state = 1 # 按钮释放
button_down.value_state = 1 # 按钮释放
# 阈值上调按钮
if not button_up.value():
if current_time - last_button_time > button_debounce:
last_button_time = current_time
if setting_mode:
if humidity_threshold < 70:
humidity_threshold += 1
save_settings() # 保存设置
oled.fill(0)
oled.text("设置湿度阈值", 0, 0)
oled.text(f"{humidity_threshold}%", 50, 25)
oled.show()
else:
# 短按切换设置模式
setting_mode = True
oled.fill(0)
oled.text("设置湿度阈值", 0, 0)
oled.text(f"{humidity_threshold}%", 50, 25)
oled.show()
# 阈值下调按钮
if not button_down.value():
if current_time - last_button_time > button_debounce:
last_button_time = current_time
if setting_mode:
if humidity_threshold > 30:
humidity_threshold -= 1
save_settings() # 保存设置
oled.fill(0)
oled.text("设置湿度阈值", 0, 0)
oled.text(f"{humidity_threshold}%", 50, 25)
oled.show()
else:
# 长按退出设置模式(模拟长按:持续按下超过1秒)
if current_time - last_button_time > 1000:
setting_mode = False
oled.fill(0)
oled.text("设置已保存", 30, 25)
oled.show()
time.sleep(1)
# 主循环
def main():
global humidity_threshold
# 从模拟NVS加载保存的阈值
humidity_threshold = load_settings()
name = "张三"
student_id = "2023001"
# 开机显示姓名学号和时间
date, time_str = sync_time()
oled.fill(0)
oled.text(f"姓名:{name}", 0, 0)
oled.text(f"学号:{student_id}", 0, 16)
oled.text(f"{date} 周二", 0, 32)
oled.text(time_str, 0, 48)
oled.show()
# 开机LED测试
print("LED测试开始:")
led_power.value(1)
led_water.value(1)
led_working.value(1)
time.sleep(1)
led_water.value(0)
led_working.value(0)
print("LED测试完成")
time.sleep(2)
# 显示初始阈值
oled.fill(0)
oled.text("初始湿度阈值", 0, 0)
oled.text(f"{humidity_threshold}%", 50, 25)
oled.show()
time.sleep(2)
# 错误计数
error_count = 0
try:
print("进入主循环...")
while True:
try:
# 处理按钮输入
handle_buttons()
# 读取传感器数据
temp, hum, water_level, pir_status = read_sensors()
if temp is not None and hum is not None and water_level is not None:
# 控制逻辑
if hum < humidity_threshold and water_level > low_water_level:
relay.value(1) # 启动雾化器
else:
relay.value(0) # 关闭雾化器
# 更新LED状态
update_led_status(temp, hum, water_level, pir_status, relay.value())
# 主动更新LED闪烁状态
led_water.value()
led_working.value()
# 非设置模式下显示传感器数据
if not setting_mode:
oled.fill(0)
oled.text(f"温度: {temp}°C", 0, 0)
oled.text(f"湿度: {hum}%", 0, 16)
oled.text(f"水位: {water_level:.1f}cm", 0, 32)
oled.text(f"状态: {pir_status}", 0, 48)
oled.text(f"阈值: {humidity_threshold}%", 0, 56)
oled.show()
# 重置错误计数
error_count = 0
else:
# 传感器读取失败
error_count += 1
print(f"传感器读取失败,计数: {error_count}/5")
if error_count > 5:
# 连续多次错误,进入保护模式
relay.value(0)
led_water.value(0.2) # 快速闪烁(5Hz)
oled.fill(0)
oled.text("传感器错误!", 30, 25)
oled.show()
time.sleep(2)
time.sleep(0.2) # 主循环延时
except Exception as e:
print(f"主循环错误: {e}")
relay.value(0) # 安全关闭
time.sleep(1)
except KeyboardInterrupt:
print("程序已停止")
relay.value(0) # 确保安全关闭
# 运行主程序
main()