通过语音指令控制家庭窗帘开关,根据室外光照强度,自动调节窗帘开合度,优化室内采光。

21 阅读9分钟

智能窗帘光照优化系统

一、实际应用场景描述

场景背景

在煤矿智能化开采的办公区和调度中心,由于建筑结构原因,部分区域采光不均匀。传统窗帘控制依赖人工操作,无法根据室外光照强度自动调节,导致:

  1. 白天光照过强时,屏幕反光影响监控画面观察
  2. 光照不足时,需要额外照明增加能耗
  3. 煤矿调度员需频繁调整窗帘,分散注意力
  4. 无法与智能语音系统集成,操作不便

痛点分析

  1. 能效浪费:人工控制不及时,照明与自然光不协调
  2. 工作效率:频繁手动调节影响煤矿调度员专注度
  3. 健康影响:光照不均匀导致视觉疲劳
  4. 智能化不足:缺乏语音控制和自动调节功能
  5. 数据缺失:无光照数据记录,难以优化采光策略

二、核心逻辑讲解

系统架构

光照传感器 → 语音识别 → 智能决策 → 电机控制 → 状态反馈

控制策略

  1. 光照优先策略:根据室外光照自动调节开合度
  2. 时间策略:不同时间段采用不同光照目标
  3. 语音覆盖:语音指令可临时覆盖自动控制
  4. 学习优化:记录调节习惯,优化控制参数
  5. 节能模式:无人时进入节能状态

光照调节算法

if 光照强度 < 最低舒适值: 窗帘开合度 = 100% elif 光照强度 > 最高舒适值: 窗帘开合度 = 0% else: 开合度 = 100% - (光照强度 - 最低值) / (最高值 - 最低值) * 100%

三、代码实现

项目结构

smart_curtain/ ├── main.py # 主程序 ├── voice/ │ ├── init.py │ ├── voice_recognizer.py # 语音识别模块 │ └── command_parser.py # 指令解析模块 ├── sensors/ │ ├── init.py │ ├── light_sensor.py # 光照传感器 │ └── position_sensor.py # 位置传感器 ├── actuators/ │ ├── init.py │ └── curtain_motor.py # 窗帘电机控制 ├── control/ │ ├── init.py │ ├── light_controller.py # 光照控制器 │ └── schedule_controller.py # 日程控制器 ├── config/ │ ├── init.py │ ├── settings.py # 系统配置 │ └── scene_modes.py # 场景模式 ├── utils/ │ ├── init.py │ ├── logger.py # 日志模块 │ ├── data_manager.py # 数据管理 │ └── energy_calculator.py # 能耗计算 ├── tests/ # 测试代码 ├── docs/ # 文档 ├── requirements.txt # 依赖包 └── README.md # 说明文档

  1. 配置文件 (config/settings.py)

""" 智能窗帘系统配置文件 """ from datetime import time from enum import Enum

class CurtainMode(Enum): """窗帘工作模式""" AUTO = "auto" # 自动模式 MANUAL = "manual" # 手动模式 SCHEDULE = "schedule" # 日程模式 VOICE = "voice" # 语音控制模式 VACATION = "vacation" # 假期模式

class LightLevel(Enum): """光照等级""" DARK = "dark" # 黑暗: < 50 lux DIM = "dim" # 昏暗: 50-200 lux COMFORT = "comfort" # 舒适: 200-1000 lux BRIGHT = "bright" # 明亮: 1000-3000 lux GLARE = "glare" # 刺眼: > 3000 lux

class SystemConfig: """系统配置参数"""

# 光照控制参数 (单位: lux)
LIGHT_THRESHOLDS = {
    'min_comfort': 200,      # 最小舒适光照
    'max_comfort': 1000,     # 最大舒适光照
    'min_bright': 1000,      # 最小明亮光照
    'max_bright': 3000,      # 最大明亮光照
    'glare_threshold': 3000, # 刺眼光照阈值
    'dark_threshold': 50,    # 黑暗阈值
}

# 窗帘控制参数
CURTAIN_SETTINGS = {
    'max_open_percent': 100,   # 最大开合度
    'min_open_percent': 0,     # 最小开合度
    'move_speed': 5,           # 运动速度 (%/秒)
    'motor_power': 12,         # 电机功率 (W)
    'calibration_position': 0, # 校准位置
}

# 语音控制参数
VOICE_SETTINGS = {
    'wake_word': '小智',       # 唤醒词
    'language': 'zh-CN',       # 语言
    'timeout': 5,              # 超时时间(秒)
    'sensitivity': 0.7,        # 识别灵敏度
}

# 时间控制参数
SCHEDULE_SETTINGS = {
    'morning_start': time(6, 0),    # 早晨开始
    'day_start': time(8, 0),        # 白天开始
    'evening_start': time(18, 0),    # 傍晚开始
    'night_start': time(22, 0),     # 夜晚开始
    'workday_hours': {              # 工作日时间
        'start': time(8, 0),
        'end': time(18, 0)
    },
    'weekend_hours': {              # 周末时间
        'start': time(9, 0),
        'end': time(20, 0)
    }
}

# 系统参数
SYSTEM_SETTINGS = {
    'update_interval': 5,           # 更新间隔(秒)
    'data_save_interval': 60,        # 数据保存间隔(秒)
    'max_motor_runtime': 30,         # 电机最大运行时间(秒)
    'emergency_stop_delay': 3,       # 急停延迟(秒)
    'learning_mode': True,           # 学习模式
}

# 能源管理参数
ENERGY_SETTINGS = {
    'power_save_mode': True,         # 节能模式
    'idle_timeout': 300,             # 空闲超时(秒)
    'night_mode': True,              # 夜间模式
    'vacation_mode': False,          # 假期模式
}

class RoomConfig: """房间配置参数"""

def __init__(self, room_name: str, window_area: float, orientation: str):
    """
    初始化房间配置
    
    参数:
        room_name: 房间名称
        window_area: 窗户面积(m²)
        orientation: 朝向 (N, S, E, W, NE, NW, SE, SW)
    """
    self.room_name = room_name
    self.window_area = window_area
    self.orientation = orientation
    
    # 朝向对应的光照系数
    self.orientation_factors = {
        'S': 1.0,   # 南向,光照最强
        'SE': 0.9,  # 东南
        'SW': 0.9,  # 西南
        'E': 0.8,   # 东
        'W': 0.8,   # 西
        'NE': 0.7,  # 东北
        'NW': 0.7,  # 西北
        'N': 0.6,   # 北向,光照最弱
    }
    
    # 房间功能对应的光照需求
    self.room_functions = {
        'office': {'min_lux': 300, 'max_lux': 750},
        'conference': {'min_lux': 200, 'max_lux': 500},
        'control_room': {'min_lux': 300, 'max_lux': 600},
        'rest_room': {'min_lux': 150, 'max_lux': 300},
        'corridor': {'min_lux': 100, 'max_lux': 200},
    }

2. 语音识别模块 (voice/voice_recognizer.py)

""" 语音识别模块 支持语音指令控制窗帘 """ import speech_recognition as sr from queue import Queue from threading import Thread, Event import time from datetime import datetime from typing import Optional, Callable, Dict, Any import re

class VoiceCommand: """语音命令类"""

def __init__(self, text: str, confidence: float, timestamp: datetime = None):
    """
    初始化语音命令
    
    参数:
        text: 识别文本
        confidence: 置信度
        timestamp: 时间戳
    """
    self.text = text.lower().strip()
    self.confidence = confidence
    self.timestamp = timestamp or datetime.now()
    self.parsed = self._parse_command()

def _parse_command(self) -> Dict[str, Any]:
    """解析语音命令"""
    patterns = {
        'open': r'(打开|开启|拉开|展开).{0,3}(窗帘|帘子)',
        'close': r'(关闭|关上|合上|拉上).{0,3}(窗帘|帘子)',
        'stop': r'(停止|停下|暂停)',
        'percent': r'(调整|设置|调到).{0,5}(\d{1,3})[%%]',
        'half': r'(半开|一半|50%)',
        'full': r'(全开|全部打开|100%)',
        'mode': r'(模式|切换到).{0,5}(自动|手动|定时|睡眠|度假)',
        'scene': r'(场景|模式).{0,5}(工作|阅读|休息|影音|会客)',
        'query': r'(状态|查询|现在)',
    }
    
    parsed = {'command': 'unknown', 'parameters': {}}
    
    for cmd, pattern in patterns.items():
        match = re.search(pattern, self.text)
        if match:
            parsed['command'] = cmd
            if cmd == 'percent':
                parsed['parameters'] = {'percent': int(match.group(2))}
            elif cmd == 'mode':
                parsed['parameters'] = {'mode': match.group(2)}
            elif cmd == 'scene':
                parsed['parameters'] = {'scene': match.group(2)}
            break
    
    return parsed

def is_valid(self) -> bool:
    """检查命令是否有效"""
    return self.confidence > 0.6 and self.parsed['command'] != 'unknown'

def __str__(self) -> str:
    return f"语音命令: {self.text} (置信度: {self.confidence:.2f})"

class VoiceRecognizer: """语音识别器"""

def __init__(self, config: Dict[str, Any] = None):
    """
    初始化语音识别器
    
    参数:
        config: 配置参数
    """
    self.config = config or {
        'wake_word': '小智',
        'language': 'zh-CN',
        'timeout': 5,
        'sensitivity': 0.7,
        'energy_threshold': 300,  # 环境噪音阈值
    }
    
    self.recognizer = sr.Recognizer()
    self.microphone = sr.Microphone()
    self.command_queue = Queue()
    self.listening = False
    self.listening_event = Event()
    
    # 调整环境噪音
    self._adjust_for_ambient_noise()
    
    # 回调函数
    self.on_command_callback = None
    self.on_wake_callback = None
    self.on_error_callback = None
    
    # 语音指令映射
    self.command_map = {
        'open': 'open_curtain',
        'close': 'close_curtain',
        'stop': 'stop_curtain',
        'percent': 'set_position',
        'half': 'set_half',
        'full': 'set_full',
        'mode': 'change_mode',
        'scene': 'change_scene',
        'query': 'query_status',
    }

def _adjust_for_ambient_noise(self, duration: int = 1):
    """调整环境噪音"""
    print("[INFO] 正在调整环境噪音,请保持安静...")
    with self.microphone as source:
        self.recognizer.adjust_for_ambient_noise(source, duration=duration)
    print("[INFO] 环境噪音调整完成")

def _listen_in_background(self):
    """后台监听语音"""
    with self.microphone as source:
        while self.listening:
            try:
                print("[INFO] 正在监听语音...")
                audio = self.recognizer.listen(
                    source, 
                    timeout=self.config['timeout'],
                    phrase_time_limit=5
                )
                
                # 识别语音
                try:
                    text = self.recognizer.recognize_google(
                        audio, 
                        language=self.config['language']
                    )
                    confidence = 0.8  # 模拟置信度
                    
                    print(f"[语音识别] 识别结果: {text}")
                    
                    # 检查唤醒词
                    if self.config['wake_word'] in text:
                        if self.on_wake_callback:
                            self.on_wake_callback()
                        continue
                    
                    # 创建命令对象
                    command = VoiceCommand(text, confidence)
                    
                    if command.is_valid():
                        self.command_queue.put(command)
                        if self.on_command_callback:
                            self.on_command_callback(command)
                
                except sr.UnknownValueError:
                    print("[语音识别] 无法理解语音")
                except sr.RequestError as e:
                    print(f"[语音识别] 请求错误: {e}")
                
            except sr.WaitTimeoutError:
                continue
            except Exception as e:
                if self.on_error_callback:
                    self.on_error_callback(e)
                print(f"[语音识别] 错误: {e}")

def start_listening(self):
    """开始监听语音"""
    if not self.listening:
        self.listening = True
        self.listening_event.clear()
        self.listen_thread = Thread(target=self._listen_in_background, daemon=True)
        self.listen_thread.start()
        print("[INFO] 语音监听已启动")

def stop_listening(self):
    """停止监听语音"""
    self.listening = False
    self.listening_event.set()
    if hasattr(self, 'listen_thread'):
        self.listen_thread.join(timeout=2)
    print("[INFO] 语音监听已停止")

def get_command(self, timeout: float = None) -> Optional[VoiceCommand]:
    """
    获取语音命令
    
    参数:
        timeout: 超时时间
    
    返回:
        语音命令对象,无命令时返回None
    """
    try:
        return self.command_queue.get(timeout=timeout)
    except:
        return None

def register_command_callback(self, callback: Callable):
    """注册命令回调函数"""
    self.on_command_callback = callback

def register_wake_callback(self, callback: Callable):
    """注册唤醒回调函数"""
    self.on_wake_callback = callback

def register_error_callback(self, callback: Callable):
    """注册错误回调函数"""
    self.on_error_callback = callback

def test_microphone(self) -> bool:
    """测试麦克风"""
    try:
        with self.microphone as source:
            print("[INFO] 正在测试麦克风,请说话...")
            audio = self.recognizer.listen(source, timeout=3)
            print("[INFO] 麦克风测试成功")
            return True
    except Exception as e:
        print(f"[ERROR] 麦克风测试失败: {e}")
        return False

class VoiceFeedback: """语音反馈模块(模拟TTS)"""

def __init__(self):
    """初始化语音反馈"""
    self.responses = {
        'wake': "我在,请说",
        'opening': "正在打开窗帘",
        'closing': "正在关闭窗帘",
        'stopping': "已停止",
        'setting': "已调整到{}%",
        'mode_changed': "已切换到{}模式",
        'scene_changed': "已切换到{}场景",
        'query': "当前窗帘开合度{}%,光照强度{}勒克斯",
        'error': "抱歉,我没有听懂",
        'success': "好的",
    }

def speak(self, response_type: str, **kwargs):
    """
    语音反馈
    
    参数:
        response_type: 反馈类型
        **kwargs: 格式化参数
    """
    if response_type in self.responses:
        text = self.responses[response_type].format(**kwargs)
        print(f"[语音反馈] {text}")
        # 实际使用时可以调用TTS引擎
        # self.tts_engine.say(text)
        # self.tts_engine.runAndWait()

3. 光照传感器模块 (sensors/light_sensor.py)

""" 光照传感器模块 """ import random import time from abc import ABC, abstractmethod from datetime import datetime, timedelta from typing import Tuple, Optional from enum import Enum

class LightSensorType(Enum): """光照传感器类型""" SIMULATED = "simulated" BH1750 = "bh1750" TSL2561 = "tsl2561" MAX44009 = "max44009"

class LightSensor(ABC): """光照传感器抽象基类"""

def __init__(self, sensor_id: str, location: str, orientation: str = "S"):
    """
    初始化传感器
    
    参数:
        sensor_id: 传感器ID
        location: 传感器位置
        orientation: 朝向
    """
    self.sensor_id = sensor_id
    self.location = location
    self.orientation = orientation
    self.status = "disconnected"
    self.last_reading = None
    self.last_update = None
    self.calibration_offset = 0.0

@abstractmethod
def connect(self) -> bool:
    """连接传感器"""
    pass

@abstractmethod
def disconnect(self) -> bool:
    """断开传感器连接"""
    pass

@abstractmethod
def read_light(self) -> float:
    """
    读取光照强度
    
    返回:
        光照强度(lux)
    """
    pass

def calibrate(self, reference_value: float) -> float:
    """
    校准传感器
    
    参数:
        reference_value: 参考光照值
    
    返回:
        校准偏移量
    """
    actual_value = self.read_light()
    self.calibration_offset = reference_value - actual_value
    return self.calibration_offset

def get_status(self) -> dict:
    """获取传感器状态"""
    return {
        "sensor_id": self.sensor_id,
        "location": self.location,
        "orientation": self.orientation,
        "status": self.status,
        "calibration_offset": self.calibration_offset,
        "last_update": self.last_update
    }

class SimulatedLightSensor(LightSensor): """模拟光照传感器"""

def __init__(self, sensor_id: str, location: str, orientation: str = "S", 
             base_light: float = 1000.0):
    """
    初始化模拟传感器
    
    参数:
        sensor_id: 传感器ID
        location: 位置
        orientation: 朝向
        base_light: 基础光照强度
    """
    super().__init__(sensor_id, location, orientation)
    self.base_light = base_light
    self.weather_effect = 1.0
    self.time_effect = 1.0
    self.season_effect = 1.0
    
    # 朝向系数
    self.orientation_factors = {
        'S': 1.0, 'SE': 0.9, 'SW': 0.9,
        'E': 0.8, 'W': 0.8,
        'NE': 0.7, 'NW': 0.7, 'N': 0.6
    }

def connect(self) -> bool:
    """连接模拟传感器"""
    print(f"[INFO] 连接光照传感器 {self.sensor_id}{self.location}")
    self.status = "connected"
    return True

def disconnect(self) -> bool:
    """断开传感器连接"""
    print(f"[INFO] 断开光照传感器 {self.sensor_id}")
    self.status = "disconnected"
    return True

def _calculate_time_effect(self) -> float:
    """计算时间对光照的影响"""
    now = datetime.now()
    hour = now.hour + now.minute / 60
    
    # 模拟日出日落
    if hour < 6 or hour > 20:  # 夜晚
        return 0.1
    elif hour < 8:  # 早晨
        return 0.3 + 0.7 * (hour - 6) / 2
    elif hour < 10:  # 上午
        return 0.7 + 0.3 * (hour - 8) / 2
    elif hour < 16:  # 中午
        return 1.0
    elif hour < 18:  # 下午
        return 1.0 - 0.3 * (hour - 16) / 2
    else:  # 傍晚
        return 0.7 - 0.6 * (hour - 18) / 2

def _calculate_weather_effect(self) -> float:
    """计算天气对光照的影响"""
    # 模拟天气变化
    hour = datetime.now().hour
    
    if 0 <= hour < 6:  # 夜晚
        weather = random.choice(['clear', 'clear', 'cloudy'])
    elif 6 <= hour < 12:  # 上午
        weather = random.choice(['clear', 'clear', 'cloudy', 'partly_cloudy'])
    elif 12 <= hour < 18:  # 下午
        weather = random.choice(['clear', 'partly_cloudy', 'cloudy', 'rainy'])
    else:  # 傍晚
        weather = random.choice(['clear', 'cloudy', 'rainy'])
    
    weather_factors = {
        'clear': 1.0,
        'partly_cloudy': 0.7,
        'cloudy': 0.4,
        'rainy': 0.2,
        'stormy': 0.1
    }
    
    return weather_factors.get(weather, 0.5)

def _calculate_season_effect(self) -> float:
    """计算季节对光照的影响"""
    now = datetime.now()
    day_of_year = now.timetuple().tm_yday
    
    # 模拟季节变化(正弦波)
    season_factor = 0.8 + 0.4 * math.sin(2 * math.pi * (day_of_year - 80) / 365)
    return season_factor

def read_light(self) -> float:
    """读取模拟光照强度"""
    if self.status != "connected":
        raise ConnectionError("传感器未连接")
    
    # 计算各种影响因子
    self.time_effect = self._calculate_time_effect()
    self.weather_effect = self._calculate_weather_effect()
    self.season_effect = self._calculate_season_effect()
    
    # 朝向系数
    orientation_factor = self.orientation_factors.get(self.orientation, 1.0)
    
    # 计算最终光照强度
    light_level = (self.base_light * 
                  self.time_effect * 
                  self.weather_effect * 
                  self.season_effect * 
                  orientation_factor)
    
    # 添加随机波动
    light_level += random.uniform(-50, 50)
    
    # 确保非负
    light_level = max(0, light_level)
    
    # 更新状态
    self.last_reading = light_level
    self.last_update = time.time()
    
    return light_level + self.calibration_offset

class BH1750Sensor(LightSensor): """BH1750光照传感器实现"""

def __init__(self, sensor_id: str, location: str, orientation: str = "S", 
             i2c_address: int = 0x23, i2c_bus: int = 1):
    """
    初始化BH1750传感器
    
    参数:
        sensor_id: 传感器ID
        location: 位置
        orientation: 朝向
        i2c_address: I2C地址
        i2c_bus: I2C总线
    """
    super().__init__(sensor_id, location, orientation)
    self.i2c_address = i2c_address
    self.i2c_bus = i2c_bus
    self.bus = None

def connect(self) -> bool:
    """连接BH1750传感器"""
    try:
        import smbus
        self.bus = smbus.SMBus(self.i2c_bus)
        
        # 初始化BH1750
        # 0x10: 连续高分辨率模式, 1lx分辨率
        self.bus.write_byte(self.i2c_address, 0x10)
        
        self.status = "connected"
        print(f"[INFO] BH1750传感器 {self.sensor_id} 连接成功")
        return True
        
    except Exception as e:
        print(f"[ERROR] 连接BH1750传感器失败: {e}")
        self.status = "error"
        return False

def disconnect(self) -> bool:
    """断开传感器连接"""
    if se

如果你觉得这个工具好用,欢迎关注我!