502 lines
10 KiB
JavaScript
502 lines
10 KiB
JavaScript
// index.js
|
||
Page({
|
||
data: {
|
||
// 导航栏高度数据
|
||
navBarHeight: getApp().globalData.navBarHeight,
|
||
statusBarHeight: getApp().globalData.statusBarHeight,
|
||
menuBottom: getApp().globalData.menuBottom,
|
||
menuHeight: getApp().globalData.menuHeight,
|
||
|
||
// MQTT 连接状态
|
||
mqttStatus: '未连接',
|
||
isConnected: false,
|
||
|
||
// 数据显示
|
||
temperature: '--',
|
||
humidity: '--',
|
||
foodWeight: 0,
|
||
waterLevel: 0,
|
||
systemMode: 'auto', // auto: 自动, manual: 手动
|
||
|
||
// 设置数据
|
||
feedTimes: [], // 喂食时间点
|
||
singleFeedWeight: 50, // 单次喂食重量(克)
|
||
|
||
// 弹窗控制
|
||
showTimePicker: false,
|
||
showSettings: false,
|
||
currentEditingTimeIndex: -1,
|
||
|
||
// 加载状态
|
||
loading: false,
|
||
|
||
// 消息日志
|
||
messages: [],
|
||
|
||
// MQTT 主题
|
||
topics: {
|
||
sensor: 'petfeeder/sensor', // 传感器数据
|
||
control: 'petfeeder/control', // 控制指令
|
||
config: 'petfeeder/config', // 配置更新
|
||
status: 'petfeeder/status' // 状态查询
|
||
}
|
||
},
|
||
|
||
onLoad() {
|
||
// 获取导航栏高度数据
|
||
const app = getApp();
|
||
this.setData({
|
||
navBarHeight: app.globalData.navBarHeight,
|
||
statusBarHeight: app.globalData.statusBarHeight,
|
||
menuBottom: app.globalData.menuBottom,
|
||
menuHeight: app.globalData.menuHeight
|
||
});
|
||
|
||
// 页面加载时获取MQTT连接状态
|
||
this.updateConnectionStatus();
|
||
|
||
// 加载保存的设置
|
||
this.loadSettings();
|
||
|
||
// 请求当前状态
|
||
this.requestStatus();
|
||
|
||
// 延迟检查连接状态(确保MQTT初始化完成)
|
||
setTimeout(() => {
|
||
this.updateConnectionStatus();
|
||
}, 1000);
|
||
},
|
||
|
||
onShow() {
|
||
// 页面显示时更新状态
|
||
this.updateConnectionStatus();
|
||
},
|
||
|
||
/**
|
||
* 更新连接状态
|
||
*/
|
||
updateConnectionStatus() {
|
||
const app = getApp();
|
||
const isConnected = app.globalData.isMQTTConnected;
|
||
console.log('更新连接状态:', isConnected);
|
||
|
||
this.setData({
|
||
isConnected: isConnected,
|
||
mqttStatus: isConnected ? '已连接' : '未连接'
|
||
});
|
||
},
|
||
|
||
/**
|
||
* MQTT消息回调函数
|
||
*/
|
||
onMQTTMessage(topic, message) {
|
||
try {
|
||
const messageStr = message.toString().trim();
|
||
const messageData = JSON.parse(messageStr);
|
||
|
||
console.log('收到MQTT消息:', topic, messageData);
|
||
|
||
// 更新连接状态(收到消息说明连接正常)
|
||
const app = getApp();
|
||
this.setData({
|
||
isConnected: app.globalData.isMQTTConnected,
|
||
mqttStatus: app.globalData.isMQTTConnected ? '已连接' : '未连接'
|
||
});
|
||
|
||
// 处理传感器数据
|
||
if (topic.includes('sensor')) {
|
||
this.handleSensorData(messageData);
|
||
}
|
||
|
||
// 处理状态数据
|
||
else if (topic.includes('status')) {
|
||
this.handleStatusData(messageData);
|
||
}
|
||
|
||
// 处理配置确认
|
||
else if (topic.includes('config')) {
|
||
this.handleConfigResponse(messageData);
|
||
}
|
||
|
||
// 添加到消息日志
|
||
this.addMessageLog(topic, messageStr);
|
||
|
||
} catch (error) {
|
||
console.error('处理MQTT消息失败:', error);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 处理传感器数据
|
||
*/
|
||
handleSensorData(data) {
|
||
console.log('处理传感器数据:', data);
|
||
console.log('当前页面数据:', this.data);
|
||
|
||
this.setData({
|
||
temperature: data.temperature || '--',
|
||
humidity: data.humidity || '--',
|
||
foodWeight: data.foodWeight || 0,
|
||
waterLevel: data.waterLevel || 0
|
||
}, () => {
|
||
console.log('setData 回调执行完成');
|
||
console.log('更新后页面数据:', this.data);
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 处理状态数据
|
||
*/
|
||
handleStatusData(data) {
|
||
if (data.mode) {
|
||
this.setData({
|
||
systemMode: data.mode
|
||
});
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 处理配置响应
|
||
*/
|
||
handleConfigResponse(data) {
|
||
if (data.success) {
|
||
wx.showToast({
|
||
title: '配置保存成功',
|
||
icon: 'success'
|
||
});
|
||
} else {
|
||
wx.showToast({
|
||
title: '配置保存失败',
|
||
icon: 'error'
|
||
});
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 添加消息日志
|
||
*/
|
||
addMessageLog(topic, message) {
|
||
const logItem = {
|
||
topic: topic,
|
||
message: message,
|
||
time: new Date().toLocaleTimeString()
|
||
};
|
||
|
||
const messages = this.data.messages;
|
||
messages.unshift(logItem);
|
||
|
||
if (messages.length > 10) {
|
||
messages.pop();
|
||
}
|
||
|
||
this.setData({ messages });
|
||
},
|
||
|
||
/**
|
||
* 切换系统模式
|
||
*/
|
||
toggleMode() {
|
||
const newMode = this.data.systemMode === 'auto' ? 'manual' : 'auto';
|
||
|
||
// 先发送控制命令,成功后再更新UI
|
||
const sent = this.sendControlCommand({
|
||
action: 'setMode',
|
||
mode: newMode
|
||
});
|
||
|
||
if (sent) {
|
||
this.setData({ systemMode: newMode });
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 手动喂食
|
||
*/
|
||
manualFeed() {
|
||
if (this.data.systemMode === 'auto') {
|
||
wx.showModal({
|
||
title: '提示',
|
||
content: '当前为自动模式,是否要切换到手动模式进行喂食?',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
this.toggleMode();
|
||
setTimeout(() => {
|
||
this.executeFeed();
|
||
}, 500);
|
||
}
|
||
}
|
||
});
|
||
} else {
|
||
this.executeFeed();
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 执行喂食命令
|
||
*/
|
||
executeFeed() {
|
||
this.sendControlCommand({
|
||
action: 'feed',
|
||
amount: this.data.singleFeedWeight
|
||
});
|
||
|
||
wx.showToast({
|
||
title: `喂食${this.data.singleFeedWeight}克`,
|
||
icon: 'loading',
|
||
duration: 2000
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 手动补水
|
||
*/
|
||
manualWater() {
|
||
this.sendControlCommand({
|
||
action: 'addWater'
|
||
});
|
||
|
||
wx.showToast({
|
||
title: '补水中...',
|
||
icon: 'loading',
|
||
duration: 3000
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 刷新数据
|
||
*/
|
||
refreshData() {
|
||
this.setData({ loading: true });
|
||
|
||
// 请求最新数据
|
||
this.requestStatus();
|
||
|
||
setTimeout(() => {
|
||
this.setData({ loading: false });
|
||
wx.showToast({
|
||
title: '数据已刷新',
|
||
icon: 'success'
|
||
});
|
||
}, 1000);
|
||
},
|
||
|
||
/**
|
||
* 发送控制命令
|
||
*/
|
||
sendControlCommand(command) {
|
||
const app = getApp();
|
||
|
||
if (!app.globalData.isMQTTConnected) {
|
||
wx.showToast({
|
||
title: 'MQTT未连接',
|
||
icon: 'none'
|
||
});
|
||
return false;
|
||
}
|
||
|
||
const message = {
|
||
...command,
|
||
timestamp: new Date().toISOString()
|
||
};
|
||
|
||
return app.publishMQTT(this.data.topics.control, message);
|
||
},
|
||
|
||
/**
|
||
* 请求状态
|
||
*/
|
||
requestStatus() {
|
||
this.sendControlCommand({
|
||
action: 'getStatus'
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 打开设置
|
||
*/
|
||
openSettings() {
|
||
this.setData({ showSettings: true });
|
||
},
|
||
|
||
/**
|
||
* 关闭设置
|
||
*/
|
||
closeSettings() {
|
||
this.setData({ showSettings: false });
|
||
},
|
||
|
||
/**
|
||
* 添加喂食时间
|
||
*/
|
||
addFeedTime() {
|
||
if (this.data.feedTimes.length >= 2) {
|
||
wx.showToast({
|
||
title: '最多设置2个时间点',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
this.setData({ currentEditingTimeIndex: -1, showTimePicker: true });
|
||
},
|
||
|
||
/**
|
||
* 编辑喂食时间
|
||
*/
|
||
editFeedTime(e) {
|
||
const index = e.currentTarget.dataset.index;
|
||
this.setData({
|
||
currentEditingTimeIndex: index,
|
||
showTimePicker: true
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 删除喂食时间
|
||
*/
|
||
deleteFeedTime(e) {
|
||
const index = e.currentTarget.dataset.index;
|
||
const feedTimes = this.data.feedTimes;
|
||
feedTimes.splice(index, 1);
|
||
this.setData({ feedTimes });
|
||
},
|
||
|
||
/**
|
||
* 时间选择确认
|
||
*/
|
||
onTimeConfirm(e) {
|
||
console.log('时间选择返回值:', e.detail);
|
||
|
||
const time = e.detail;
|
||
let hours, minutes;
|
||
|
||
// type="time" 时,Vant 返回的可能是对象、字符串或数组
|
||
if (Array.isArray(time)) {
|
||
// 如果是数组格式 [hours, minutes]
|
||
hours = time[0];
|
||
minutes = time[1];
|
||
} else if (typeof time === 'object' && time !== null) {
|
||
// 如果是对象格式 { hours, minutes } 或 { hour, minute }
|
||
hours = time.hours !== undefined ? time.hours : time.hour;
|
||
minutes = time.minutes !== undefined ? time.minutes : time.minute;
|
||
} else if (typeof time === 'string' && time.includes(':')) {
|
||
// 如果是字符串格式 "HH:mm"
|
||
const parts = time.split(':');
|
||
hours = parseInt(parts[0], 10);
|
||
minutes = parseInt(parts[1], 10);
|
||
} else {
|
||
// 其他情况作为时间戳处理
|
||
const date = new Date(time);
|
||
hours = date.getHours();
|
||
minutes = date.getMinutes();
|
||
}
|
||
|
||
console.log('解析结果 hours:', hours, 'minutes:', minutes);
|
||
|
||
const timeString = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
|
||
console.log('时间字符串:', timeString);
|
||
|
||
const feedTimes = this.data.feedTimes;
|
||
|
||
if (this.data.currentEditingTimeIndex === -1) {
|
||
// 新增
|
||
feedTimes.push(timeString);
|
||
feedTimes.sort();
|
||
} else {
|
||
// 编辑
|
||
feedTimes[this.data.currentEditingTimeIndex] = timeString;
|
||
feedTimes.sort();
|
||
}
|
||
|
||
this.setData({
|
||
feedTimes,
|
||
showTimePicker: false,
|
||
currentEditingTimeIndex: -1
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 时间选择取消
|
||
*/
|
||
onTimeCancel() {
|
||
this.setData({
|
||
showTimePicker: false,
|
||
currentEditingTimeIndex: -1
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 单次喂食重量改变
|
||
*/
|
||
onFeedWeightChange(e) {
|
||
this.setData({
|
||
singleFeedWeight: e.detail
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 保存设置
|
||
*/
|
||
saveSettings() {
|
||
const config = {
|
||
feedTimes: this.data.feedTimes,
|
||
singleFeedWeight: this.data.singleFeedWeight
|
||
};
|
||
|
||
// 发送配置到设备
|
||
const app = getApp();
|
||
if (app.globalData.isMQTTConnected) {
|
||
app.publishMQTT(this.data.topics.config, config);
|
||
}
|
||
|
||
// 保存到本地存储
|
||
wx.setStorageSync('petfeeder_config', config);
|
||
|
||
this.setData({ showSettings: false });
|
||
|
||
wx.showToast({
|
||
title: '设置已保存',
|
||
icon: 'success'
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 加载设置
|
||
*/
|
||
loadSettings() {
|
||
const config = wx.getStorageSync('petfeeder_config');
|
||
if (config) {
|
||
this.setData({
|
||
feedTimes: config.feedTimes || [],
|
||
singleFeedWeight: config.singleFeedWeight || 50
|
||
});
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 格式化水位显示
|
||
*/
|
||
getWaterLevelText(level) {
|
||
return level === 1 ? '满水' : '缺水';
|
||
},
|
||
|
||
getWaterLevelType(level) {
|
||
return level === 1 ? 'success' : 'danger';
|
||
},
|
||
|
||
/**
|
||
* 格式化模式显示
|
||
*/
|
||
getModeText(mode) {
|
||
return mode === 'auto' ? '自动模式' : '手动模式';
|
||
},
|
||
|
||
/**
|
||
* 格式化模式类型
|
||
*/
|
||
getModeType(mode) {
|
||
return mode === 'auto' ? 'success' : 'primary';
|
||
}
|
||
});
|
||
|