// 获取当前时间对象(每次执行时更新)
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("、") ;
}