提交工程,小程序源码已完成,单片机待完成

This commit is contained in:
2026-02-10 20:21:41 +08:00
commit fd55a14b62
3778 changed files with 1062672 additions and 0 deletions

View File

@@ -0,0 +1,501 @@
// 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';
}
});