当前位置: 首页 > news >正文

微信小程序:农户手机上的「农场管家」

微信小程序:农户手机上的「农场管家」

平台搭好了,但农户不可能打开电脑看数据。他们需要手机上扫一下就能看到大棚温湿度、点一下就能远程开水泵。这篇用 UniApp(Vue 3)开发一个小程序:实时数据、远程控制、告警推送、农事记录。


为什么不学微信原生开发?

微信原生开发用 WXML + WXSS + JS,语法独一份,不能用 Vue/React 生态。UniApp 的好处:

  • 一套代码编译到微信小程序 + H5 + App
  • 用 Vue 3 组合式 API,前端人不需额外学习成本
  • 插件生态(uView UI 等)够用
  • 微信扫码即用,农户零安装

安装 UniApp CLI:

npminstall-g@dcloudio/uvm uvm use3.0.0 npx degit dcloudio/uni-preset-vue#vite farm-miniappcdfarm-miniapp&&npminstall

页面架构——四个 Tab 搞定

TabBar ├── 🏠 首页 → 大棚/地块卡片列表 ├── 📊 监控 → 选中地块的实时数据 + 曲线 ├── 🎮 控制 → 灌溉/通风/补光 远程开关 └── 👤 我的 → 设置/农事记录/关于

首页:大棚卡片

<!-- pages/home/index.vue --> <script setup> import { ref, onMounted, onUnmounted } from 'vue'; import { connectMQTT } from '@/utils/mqtt'; const devices = ref([]); let mqttClient = null; onMounted(async () => { // 先从服务端拉设备列表 const res = await uni.request({ url: `${BASE_URL}/api/devices` }); devices.value = res.data; // 再连 MQTT 收实时数据更新卡片 mqttClient = connectMQTT(); mqttClient.on('message', (topic, payload) => { const data = JSON.parse(payload); const device = devices.value.find(d => d.deviceId === data.dev); if (device) { device.airTemp = data.data.air_temp; device.airHumidity = data.data.air_humidity; device.soilMoisture = data.data.soil_moisture; device.lastUpdate = new Date(data.ts * 1000); } }); mqttClient.subscribe('farm/+/sensor/+/data'); }); onUnmounted(() => mqttClient?.disconnect()); const navigateToDetail = (device) => { uni.navigateTo({ url: `/pages/monitor/index?deviceId=${device.deviceId}` }); }; </script> <template> <view class="home"> <view class="header"> <text class="title">我的农场</text> <text class="weather">晴 26℃</text> </view> <scroll-view class="device-list" scroll-y> <view v-for="device in devices" :key="device.deviceId" class="device-card" :class="{ offline: !device.online }" @click="navigateToDetail(device)"> <view class="card-header"> <text class="card-title">{{ device.name }}</text> <view class="status-dot" :class="device.online ? 'online' : 'offline'" /> </view> <view class="card-body"> <view class="data-item"> <text class="data-value">{{ device.airTemp ?? '--' }}℃</text> <text class="data-label">温度</text> </view> <view class="data-item"> <text class="data-value">{{ device.airHumidity ?? '--' }}%</text> <text class="data-label">湿度</text> </view> <view class="data-item"> <text class="data-value">{{ device.soilMoisture ?? '--' }}%</text> <text class="data-label">土壤</text> </view> </view> <text class="card-time">{{ device.lastUpdate ?? '暂无数据' }}</text> </view> <view v-if="devices.length === 0" class="empty"> <text>还没有添加设备,联系管理员</text> </view> </scroll-view> </view> </template>

监控页:实时曲线

用 ECharts 的微信小程序版(echarts-for-weixin)画实时曲线:

<!-- pages/monitor/index.vue --> <script setup> import { ref, onMounted, onUnmounted } from 'vue'; const chartData = ref({ temp: [], humidity: [], soil: [] }); let ws = null; onMounted(() => { // WebSocket 订阅该设备的历史 + 实时数据 ws = uni.connectSocket({ url: `wss://your-server/ws/device/${deviceId}`, }); ws.onMessage((res) => { const point = JSON.parse(res.data); chartData.value.temp.push([point.ts * 1000, point.air_temp]); chartData.value.humidity.push([point.ts * 1000, point.air_humidity]); chartData.value.soil.push([point.ts * 1000, point.soil_moisture]); // 只保留最近 500 个点,防止内存溢出 if (chartData.value.temp.length > 500) { chartData.value.temp.shift(); } }); }); onUnmounted(() => ws?.close()); </script> <template> <view class="monitor"> <view class="current-values"> <text class="big-temp">26.5℃</text> <text class="sub-value">湿度 68% | 土壤 35%</text> </view> <!-- echarts 组件,用 echarts-for-weixin --> <ec-canvas ref="chart" canvas-id="monitor-chart" :ec="chartOption" /> <view class="time-tabs"> <text class="tab active">1h</text> <text class="tab">6h</text> <text class="tab">24h</text> <text class="tab">7d</text> </view> </view> </template>

控制页:一键灌溉

远程控制的核心是「小程序 → MQTT → ESP32 → 继电器 → 电磁阀」。

<!-- pages/control/index.vue --> <script setup> import { ref } from 'vue'; const BASE_URL = 'https://your-server'; const valves = ref([ { id: 1, name: '大棚A 灌溉阀', status: false, deviceId: 'pump_01' }, { id: 2, name: '大棚A 通风扇', status: false, deviceId: 'fan_01' }, { id: 3, name: '大棚A 补光灯', status: false, deviceId: 'light_01' }, ]); const toggleValve = async (valve) => { // 1. 调后端 API,后端 publish MQTT 指令 const res = await uni.request({ url: `${BASE_URL}/api/devices/${valve.deviceId}/cmd`, method: 'POST', data: { cmd: valve.status ? 'off' : 'on', seq: Date.now() } }); if (res.data.success) { valve.status = !valve.status; uni.showToast({ title: `${valve.name} ${valve.status ? '已开启' : '已关闭'}` }); } }; // 定时灌溉 const startTimedIrrigation = () => { uni.request({ url: `${BASE_URL}/api/devices/pump_01/cmd`, method: 'POST', data: { cmd: 'irrigate', seq: Date.now(), params: { duration: 600, valve: 1 } // 10 分钟 } }); }; </script> <template> <view class="control"> <view class="section"> <text class="section-title">执行器</text> <view v-for="valve in valves" :key="valve.id" class="control-item"> <text>{{ valve.name }}</text> <switch :checked="valve.status" @change="toggleValve(valve)" color="#07c160" /> </view> </view> <view class="section"> <text class="section-title">快捷操作</text> <button class="quick-btn" @click="startTimedIrrigation"> 💧 定时灌溉 10 分钟 </button> </view> </view> </template>

告警推送:微信服务通知

普通消息模板需要用户主动打开小程序才能看到。要让农户及时收到告警,必须用微信服务通知(订阅消息)。

  1. 在微信公众平台 → 订阅消息 → 申请模板(如「设备告警通知」)
  2. 用户在小程序里点击授权按钮
  3. 后端检测到告警时,调微信 API 推送
// 后端发订阅消息publicvoidsendAlarmNotification(Stringopenid,AlarmRecordalarm){WxMaSubscribeMessagemsg=newWxMaSubscribeMessage();msg.setToUser(openid);msg.setTemplateId("模板ID");msg.setPage("pages/monitor/index?deviceId="+alarm.getDeviceId());msg.addData(newData("thing1",alarm.getRuleName()));// 告警类型msg.addData(newData("thing2",alarm.getDeviceName()));// 设备名称msg.addData(newData("amount3",String.valueOf(alarm.getValue())));// 当前值msg.addData(newData("thing4",alarm.getLevelText()));// 告警级别wxMaService.getSubscribeService().sendSubscribeMsg(msg);}

农事记录

让农户在手机上记下每次浇水、施肥、打药的时间——这个功能做极简就行,一个表单 + 一个列表。

<script setup> const records = ref([]); const form = reactive({ type: '', note: '', date: new Date() }); const addRecord = async () => { await uni.request({ url: `${BASE_URL}/api/farm-records`, method: 'POST', data: { ...form, deviceId: currentDevice.deviceId } }); records.value.unshift({ ...form }); form.note = ''; }; </script> <template> <view class="record-form"> <picker mode="selector" :range="['浇水','施肥','打药','除草','采收']" @change="(e) => form.type = ['water','fertilize','pesticide','weed','harvest'][e.detail.value]"> <text>{{ form.type || '选择类型' }}</text> </picker> <textarea v-model="form.note" placeholder="备注..." /> <button @click="addRecord">记一笔</button> </view> </template>

小程序提醒:首次打开需要微信授权登录(uni.login→ 后端换 openid → 存用户绑定)。UI 尽量大字、大按钮——农户里不少是 50 岁以上的大叔大妈,别搞 12px 的极小字。


下一篇:《自动灌溉系统:AI 什么时候浇水,比老农还准?》——从简单的定时/阈值控制,到结合天气预报、作物生长周期的智能算法。

http://www.cnnetsun.cn/news/3076027.html

相关文章:

  • 自动灌溉系统:AI 什么时候浇水,比老农还准?
  • 批量处理远程共享目录中的特定类型文件(如 .hex、.csv 等)。
  • OpenGL学习笔记-05-着色器-数据类型/输入输出/uniform
  • 基于OpenCV与YOLO的实时目标检测系统搭建指南
  • Docker部署PostgreSQL
  • Playwright混沌工程实战:构建AI增强的韧性Web自动化测试体系
  • 【LeetCode】反转字符串
  • 京东开源实时视频视觉语言交互模型:全栈方案解析与落地实践
  • 智能体颠覆安全-360图龙锋如何用蜂群路线打造中国版Mythos
  • Java 26 发布了, 我人麻了。。
  • 玩三角洲要高配?2026年这5款旗舰游戏本让你杀穿新赛季
  • AI模型门控发布机制解析:原理、实践与行业应用
  • 2026全球EMBA客观测评:科学选型与优质项目解析
  • 工程师转型AI:从跑通Demo到收藏实战秘籍,拒绝高数劝退!
  • 微信聊天记录备份终极指南:如何安全保护你的数字记忆
  • UMDF驱动开发入门:二 详解INF文件与设备类选择
  • 软件测试——黑盒测试
  • AI Agent 三种记忆的工程落地
  • 网络安全事件报告——伪CAPTCHA诱骗用户运行危险的PowerShell脚本
  • 小白可懂的保姆级 Redis 教程
  • ponytail爆火:专治AI编程过度造轮子,代码直接砍半
  • 解密 MCP:开启 AI 与数据交互的新标准
  • 新课标下,小学数学最需要的能力不是“算得快“,而是“想得通“
  • 深入认识ClassLoader - 一次投产失败的复盘
  • DeepSeek美化-为 DeepSeek 网页版引入 Obsidian Border 主题视觉风格
  • RAG基础
  • 做智驾十年,为何Momenta上市换锚?
  • 企业DLP选型指南:从入门到决策,一篇讲透
  • PEAK框架:自然语言驱动的GPU内核优化技术解析
  • Lyra框架:RISC-V处理器验证的异构加速与语义生成技术