找回密码
 立即注册

微信扫码登录

搜索
查看: 358|回复: 2

[教程系列] 好久没有发贴了,共享一个比较全面的判断居家模式的流

[复制链接]

47

主题

182

回帖

1765

积分

金牌会员

积分
1765
金钱
1536
HASS币
0
发表于 4 天前 | 显示全部楼层 |阅读模式
本帖最后由 lambilly 于 2025-9-22 22:57 编辑

这个居家模式本人优化了比较久,前面一个分类延时,是为了解决扫地机时老是变化模式。同时也解决晚上短时出房间门(比如尿尿)而触发的模式变化。

屏幕截图_22-9-2025_22477_home.lamnas.top.jpeg
屏幕截图_22-9-2025_225533_home.lamnas.top.jpeg
屏幕截图_22-9-2025_22562_home.lamnas.top.jpeg

flows.zip (5.52 KB, 下载次数: 6)
// 获取当前时间对象(每次执行时更新)
const now = new Date();
// ============= 休息时间段配置(精确到分钟) ============ //
const REST_TIME = {
    WORKDAY: [
        [22, 30, 8, 30],    // 工作日休息时段1: 22:30-次日8:30
        [12, 30, 14, 30]    // 工作日休息时段2: 12:30-14:30
    ],
    RESTDAY: [
        [23, 0, 11, 0],   // 节假日休息时段1: 23:00-次日11:00
        [13, 0, 17, 0]    // 节假日休息时段2: 13:00-17:00
    ]
};

// ============== 系统状态枚举 =============== //
const HOME_MODE = {
    AWAY: '离家模式',                           // 🚗家中无人且扫地机停止
    CLEAN: '清洁模式',                          // 🧹家中无人但扫地机运行
    HOME: '在家模式',                           // 🏡家中有人且非休息时段
    REST: '休息模式',                           // 🛌家中有人且休息时间段
    RELAX: '休闲模式',                          // 🛋️家中有人且音乐播放中
    MOVIE: '观影模式'                            // 🎬家中有人且观影播放中
};

const MODE_ICON_MAP = {
    [HOME_MODE.AWAY]: '🚪',
    [HOME_MODE.CLEAN]: '🧹',
    [HOME_MODE.HOME]: '🏠',
    [HOME_MODE.REST]: '💤',
    [HOME_MODE.RELAX]: '🛋️',
    [HOME_MODE.MOVIE]: '🎬'
};
// ============= 核心判断逻辑 ============= //
let currentMode;
let home_detail;
let family_detail = msg.homeCount > 0 ?  `${msg.homeCount}人在家。` : "无人在家。";
if (msg.homeCount === 0) {
    // 无人场景判断
    const vacuumStates = new Set(["docked", "idle", "unavailable", "unknown", "paused", "error"]);
    currentMode = vacuumStates.has(msg.vacuum) 
        ? HOME_MODE.AWAY 
        : HOME_MODE.CLEAN;
    home_detail = vacuumStates.has(msg.vacuum) 
        ? `今天是${msg.workday},当前无人在家,切换到${currentMode}。` 
        : `今天是${msg.workday},当前扫地机正在工作,切换到${currentMode}。`;
} else {
    // 有人场景判断
    const restPeriods = (msg.workday === "工作日" || msg.workday === "调休日") 
        ? REST_TIME.WORKDAY 
        : REST_TIME.RESTDAY;
    let inRestTime = false;
    for (const range of restPeriods) {
        if (isWithinTimeRange(now, range)) {
            inRestTime = true;
            break;
        }
    }
    
    // 合并休息条件判断(时间段+房门 或 光照条件)
    const lowLight = 
        (msg.zwDoor === "off" && msg.zwLight < 50 ) || 
        (msg.cwDoor === "off" && msg.cwLight === "off" );
    
    if ((inRestTime && msg.roomDoor !== "on") || lowLight) {
        currentMode = HOME_MODE.REST;
        if (inRestTime) {
            home_detail = `今天是${msg.workday},当前有 ${msg.homeCount} 人在家,${getCurrentTime(now)}为休息时段,切换到${currentMode}。`;
        } else {
            const lightStatus = getLightStatus(msg);
            home_detail = `今天是${msg.workday},当前有 ${msg.homeCount} 人在家,${lightStatus},切换到${currentMode}。`;
        }
    } else {
        // 新增休闲\观影模式判断:音乐\电视正在播放
        if (msg.sfMusic === 'playing') {
            currentMode = HOME_MODE.RELAX;
            home_detail = `今天是${msg.workday},当前有 ${msg.homeCount} 人在家听音乐,切换到${currentMode}。`;
        } else if (msg.ktTV === 'playing' && msg.ktTV_data.attributes.app_name !== '动态屏保') {
            currentMode = HOME_MODE.MOVIE;
            home_detail = `今天是${msg.workday},当前有 ${msg.homeCount} 人在家看电视,切换到${currentMode}。`;
        }
         else {
            currentMode = HOME_MODE.HOME;
            home_detail = `今天是${msg.workday},当前有 ${msg.homeCount} 人在家,切换到${currentMode}。`;
        }
    }
}

// ============= 状态追踪处理 ============= //
// 从消息中获取历史状态(使用统一字段名 changed_time)
const preMode = msg.homeMode;
const preChangedTime = msg.homeMode_data.attributes.changed_time
    ? new Date(msg.homeMode_data.attributes.changed_time) // 反序列化历史时间
    : null;

// 使用更严谨的模式变化判断及时间戳处理
const isModeChanged = preMode !== currentMode;
const changedTime = isModeChanged
    ? now
    : (preChangedTime || now); // 维持历史时间或初始化(仅首次)

// 记录上一个模式(仅在模式变化时更新)
const lastMode = isModeChanged ? preMode : (msg.homeMode_data.attributes.last_mode || preMode);

// 正确计算时间差(转换为时间戳)
const sinceTime = formatDuration(
    now.getTime() - changedTime.getTime()
);

// ================= 构造返回消息 ================= //
msg = {
    home_mode: currentMode,
    home_mode_icon: MODE_ICON_MAP[currentMode] || '',
    home_count: msg.homeCount,
    today_holiday: msg.workday || '',
    changed_time: formatDate(changedTime),
    since_time: sinceTime,
    home_detail: home_detail,
    family_detail: family_detail,
    update_time: formatDate(now),
    last_mode: lastMode  // 新增上一个模式记录
};

return msg;


// ============= 工具函数 ============= //
// 1.时间段转成分钟函数
function convertToMinutes(hours, minutes) {
    return hours * 60 + minutes;
}

// 2.判断当前是否在时间段内函数
function isWithinTimeRange(now, [startHour, startMin, endHour, endMin]) {
    const currentMinutes = now.getHours() * 60 + now.getMinutes();
    const startMinutes = convertToMinutes(startHour, startMin);
    let endMinutes = convertToMinutes(endHour, endMin);
    
    // 处理跨天时间段
    if (endMinutes < startMinutes) {
        endMinutes += 24 * 60; // 加上一天的分钟数
        return currentMinutes >= startMinutes || 
               currentMinutes <= endMinutes - 24 * 60;
    }
    return currentMinutes >= startMinutes &&  currentMinutes <= endMinutes;
}

// 3.时间格式函数
function formatDate(now) {
    var date = now.toLocaleString("zh-CN", {
        timeZone: "Asia/Shanghai",
        hour12: false,
        year: "numeric",
        month: "2-digit",
        day: "2-digit",
        hour: "2-digit",
        minute: "2-digit",
        second: "2-digit"
    });
    date = date.replace(/\//g, "-");
    return date;
}

// 4.时长格式化函数
function formatDuration(ms) {
    if (typeof ms !== "number" || ms < 0) return "0分钟";
    const seconds = Math.floor(ms / 1000);
    const days = Math.floor(seconds / 86400);
    const hours = Math.floor((seconds % 86400) / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
// 智能显示策略:
// 1. 优先显示天数
// 2. 无天数时显示小时+分钟
// 3. 无小时时仅显示分钟
    return (
        days > 0 ? `${days}天${hours}小时` :
        hours > 0 ? `${hours}小时${minutes}分钟` : `${minutes}分钟` );
}

// 5.获取当前时间字符串(几点几分)
function getCurrentTime(date) {
    return `${date.getHours()}点${date.getMinutes()}分`;
}

// 6.获取光线状态描述
function getLightStatus(msg) {
    const lights = [];
    if (msg.zwDoor === "off" && msg.zwLight < 50 ) lights.push(`主卧门关闭中、光线暗`);
    if (msg.cwDoor === "off" && msg.cwLight === "off" ) lights.push(`次卧门关闭中、光线暗`);
    if (lights.length === 0) return "房间光线较亮";
    return lights.join("、") ;
}





评分

参与人数 1金钱 +20 收起 理由
dscao + 20 感谢楼主分享!

查看全部评分

回复

使用道具 举报

ZDZX 手机认证

6

主题

103

回帖

729

积分

高级会员

积分
729
金钱
620
HASS币
0
发表于 4 天前 | 显示全部楼层
有所启发
回复

使用道具 举报

8

主题

169

回帖

866

积分

高级会员

积分
866
金钱
689
HASS币
0
发表于 3 天前 | 显示全部楼层
感谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian ( 晋ICP备17001384号-1 )

GMT+8, 2025-9-26 03:22 , Processed in 0.163080 second(s), 9 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表