简介:这份微信小程序智慧农业平台源码包,面向计算机、物联网、通信工程等专业的高校学生与开发者,可用于毕业设计、课程设计、项目立项演示或自学进阶。项目采用前后端分离架构,并集成物联网设备数据采集与控制,完整覆盖从终端到云端的业务链路。压缩包共441个文件,约3.59MB,以js逻辑脚本、json配置、wxss样式、wxml页面结构为主,另有png图片资源、tsx与ts组件、md说明文档及wxs脚本等,目录组织清晰,便于按模块阅读与二次开发。已有56人学习关注。资源包含设计文档与可运行源码,读者可借此掌握小程序页面搭建、接口联调、数据库迁移及设备接入等关键环节,也能在此基础上修改功能,直接用于毕设、课设或作业提交,遇到配置与运行问题还可获得远程指导,适合希望快速上手智慧农业类项目的学习者。
1. 从一份小程序毕设包说起:智慧农业平台到底能跑通什么
去年帮几个做物联网方向的同学看毕设,十份里有七份是"智慧农业"——但真正能把小程序、后端、设备端三端数据打通的不到两份。大部分是前端页面写得很漂亮,点一下"浇水"按钮,后端返回一个写死的{"status": "ok"},传感器数据全靠Math.random()生成。这份《微信小程序智慧农业平台(前端+后端+物联网设备集成)》的资源包,从文件结构看至少把三端都放进去了:index.html和index.css是前端展示层,多个index.js分散在不同目录对应小程序页面逻辑和后端服务,migrate_to_mysql.js说明数据层用的是 MySQL 而非内存存储,publish.js大概率是设备端数据上报脚本。如果你正在找一个小程序毕设的完整骨架,或者想看看物联网数据从设备到小程序这条链路在代码层面怎么串起来,这份资源值得拆开看。它适合计算机、物联网、通信工程方向的学生做课设或毕设起步,也适合刚接触小程序全栈的开发者拿来做二次开发。
2. 拆包先看目录:三端文件怎么分工
拿到一个压缩包,我习惯先不急着跑,而是把目录结构过一遍。这份资源的文件命名不算规范——多个index.js同名散落在不同目录,如果不先理清谁是谁,后面调试会非常痛苦。
2.1 前端层:小程序页面与静态资源
从文件清单看,前端部分包含index.html、index.css和若干image3.jpeg这类图片资源。这里有个容易误判的点:微信小程序的页面文件标准后缀是.wxml和.wxss,而不是.html和.css。所以有两种可能——要么这份资源的前端其实是一个 H5 页面(用index.html做展示,通过 web-view 嵌入小程序),要么是开发者用了某种转换工具把 HTML 转成了 WXML。不管是哪种,你拿到手第一件事是确认前端入口文件的实际类型。
常见做法是:打开index.html,看里面有没有<script>引用小程序 API(比如wx.开头的调用)。如果有,说明它是混合方案;如果没有,那它就是一个纯 H5 展示页,需要你手动迁移到小程序原生页面。
# 先看目录结构,理清文件分布 find . -type f -name "*.js" | head -20 find . -type f -name "*.html" -o -name "*.css" -o -name "*.json"这段命令的作用是快速列出所有 JS 文件和前端资源文件的位置。find . -type f表示从当前目录递归查找普通文件,-name "*.js"按扩展名过滤。跑完之后你会得到一张文件地图,后面改代码时就知道该去哪个目录找。
2.2 后端层:Node.js 服务与 MySQL 迁移脚本
migrate_to_mysql.js这个文件名信息量很大。它说明项目原本可能用的是 SQLite 或直接读 JSON 文件,后来迁移到了 MySQL。迁移脚本通常包含建表语句、字段映射和数据导入逻辑。你需要在跑起来之前先确认两件事:MySQL 版本是否兼容脚本里的语法,以及连接配置写在哪里。
// migrate_to_mysql.js 典型结构(根据文件名推断) const mysql = require('mysql2'); const connection = mysql.createConnection({ host: 'localhost', // 数据库地址,本地开发一般不改 user: 'root', // 用户名,按自己环境改 password: 'your_pass', // 密码,必须改 database: 'smart_farm' // 库名,建议保持默认 }); // 建表:传感器数据表 connection.query(` CREATE TABLE IF NOT EXISTS sensor_data ( id INT AUTO_INCREMENT PRIMARY KEY, device_id VARCHAR(50) NOT NULL, temperature FLOAT, humidity FLOAT, soil_moisture FLOAT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) `, (err) => { if (err) console.error('建表失败:', err.message); else console.log('sensor_data 表就绪'); });上面这段是根据migrate_to_mysql.js这个文件名推断的典型结构。关键参数有三个:host一般本地开发不用改,user和password必须换成你自己 MySQL 的配置,database如果脚本里写死了库名,你得先在 MySQL 里CREATE DATABASE smart_farm否则连接会直接报ER_BAD_DB_ERROR。字段方面,device_id是设备唯一标识,temperature、humidity、soil_moisture对应温度、湿度、土壤含水量,created_at用TIMESTAMP自动记录写入时间——这个设计在后续做历史曲线查询时很关键。
2.3 设备端:publish.js 的数据上报逻辑
publish.js从命名看是设备端的数据发布脚本。物联网设备通常通过 MQTT 协议把传感器读数发到 broker,后端再订阅 topic 拿数据。如果这份资源用的是 HTTP 轮询而不是 MQTT,那publish.js里应该是一个setInterval定时向后台接口 POST 数据。
// publish.js 模拟设备上报(HTTP 方式) const axios = require('axios'); const DEVICE_ID = 'sensor_001'; // 设备编号,多设备时需区分 const REPORT_INTERVAL = 5000; // 上报间隔,单位毫秒 setInterval(async () => { const payload = { device_id: DEVICE_ID, temperature: (20 + Math.random() * 10).toFixed(1), // 模拟 20-30 度 humidity: (40 + Math.random() * 30).toFixed(1), // 模拟 40-70% soil_moisture: (30 + Math.random() * 40).toFixed(1) // 模拟 30-70% }; try { await axios.post('http://localhost:3000/api/report', payload); console.log('上报成功:', payload); } catch (e) { console.error('上报失败:', e.message); } }, REPORT_INTERVAL);这段代码的核心逻辑是:每隔 5 秒生成一组模拟传感器数据,通过 POST 请求发到后端/api/report接口。DEVICE_ID在多设备场景下必须唯一,否则后端无法区分数据来源。REPORT_INTERVAL设 5000 毫秒是常见做法,太快会给后端压力,太慢曲线会断。注意toFixed(1)把浮点数转成一位小数的字符串,如果后端字段类型是FLOAT,MySQL 会自动转换,但如果接口做了严格类型校验可能会报错——这是实际调试中容易翻车的地方。
3. 把项目跑起来:环境配置与启动顺序
文件看明白了,接下来是让它真正跑起来。三端项目的启动有先后顺序,搞错了就会出现"前端报跨域、后端连不上库、设备端发出去没人收"的连锁问题。
3.1 后端服务启动与数据库初始化
先起后端,因为前端和设备端都依赖它。Node.js 项目第一步永远是装依赖。
# 进入后端目录(假设后端在 server/ 或根目录) cd server # 如果后端就在根目录则跳过 # 安装依赖 npm install # 先跑迁移脚本建表 node migrate_to_mysql.js # 启动后端服务 node index.js # 或者如果 package.json 里有 start 脚本 npm startnpm install会根据package.json里的dependencies字段拉取所有依赖包。如果项目没有package.json(有些毕设包确实会漏),你需要手动装:npm install express mysql2 axios。node migrate_to_mysql.js必须在启动服务之前跑,否则后端第一次查询就会因为表不存在而报ER_NO_SUCH_TABLE。启动成功后终端一般会打印Server running on port 3000之类的信息,记下这个端口号,后面配前端接口地址要用。
提示:如果
npm install卡住不动,先检查 npm 源。国内环境常见做法是临时指定镜像源,但不要写进项目配置文件里,否则换台机器就失效。
3.2 小程序端配置与接口地址修改
小程序端要跑起来,首先得有微信开发者工具。导入项目时选择包含app.json的目录——如果这份资源里没有app.json,说明前端可能还是 H5 形态,你需要先在开发者工具里新建一个小程序项目,再把页面文件迁移过去。
接口地址是第二个要改的地方。后端跑在localhost:3000,但小程序开发者工具里的请求默认走的是https://且需要配置合法域名。本地调试阶段,在开发者工具右上角"详情"里勾选"不校验合法域名"就能绕过。
// 小程序端 request 封装(常见写法) const BASE_URL = 'http://localhost:3000'; // 改成你后端实际地址 function request(path, method = 'GET', data = {}) { return new Promise((resolve, reject) => { wx.request({ url: `${BASE_URL}${path}`, method, data, success: (res) => { if (res.statusCode === 200) resolve(res.data); else reject(new Error(`HTTP ${res.statusCode}`)); }, fail: reject }); }); } // 调用示例:获取最新传感器数据 request('/api/latest').then(data => { console.log('温度:', data.temperature); }).catch(err => console.error(err));BASE_URL是唯一需要改的配置项,指向后端服务地址。wx.request是小程序原生网络请求 API,返回的是 Promise 包装后的结果。statusCode === 200判断是基础容错,实际项目里还要处理 401、500 等状态。注意localhost在小程序真机上是不通的——真机调试时要把BASE_URL换成电脑的局域网 IP,比如http://192.168.1.100:3000,且手机和电脑必须在同一网络下。
3.3 设备端上报脚本运行与数据验证
后端和小程序都就绪后,最后启动publish.js。
# 新开一个终端窗口,运行设备上报脚本 node publish.js跑起来后你会看到终端每隔 5 秒打印一条"上报成功"。这时候去小程序页面刷新,应该能看到传感器数值在变化。如果小程序端数据不动,按这个顺序排查:先看publish.js终端有没有报错,再看后端终端有没有收到 POST 请求的日志,最后检查小程序请求的接口路径和后端路由是否一致。
验证数据是否真正落库,最直接的方式是查 MySQL:
-- 查最近 10 条传感器数据 SELECT device_id, temperature, humidity, soil_moisture, created_at FROM sensor_data ORDER BY created_at DESC LIMIT 10;如果这条 SQL 能查出数据,说明"设备端 → 后端 → 数据库"这条链路是通的。查不出来就回到上一步看后端有没有报错。ORDER BY created_at DESC保证最新的数据排在最前面,LIMIT 10避免一次拉太多。
4. 避坑指南:跑这个包最容易翻车的五个地方
这份资源的功能覆盖是完整的,但毕设包的通病它基本都有——配置硬编码、依赖版本锁死、文档缺失。下面五条是我实际拆这类项目时踩过的坑,按出现频率从高到低排。
4.1 数据库连接报 ER_ACCESS_DENIED_ERROR
现象:跑migrate_to_mysql.js或启动后端时,终端报Access denied for user 'root'@'localhost'。
原因:脚本里的数据库密码是原作者本机的,跟你环境不一致。有些包甚至写的是空密码或123456。
解决:找到数据库配置文件(通常在migrate_to_mysql.js和后端index.js里各有一处),把password改成你本机 MySQL 的实际密码。如果 MySQL 8.0 还报ER_NOT_SUPPORTED_AUTH_MODE,是因为 8.0 默认用caching_sha2_password插件,而旧版mysql包不支持,换成mysql2包即可。
4.2 小程序请求报"不在以下 request 合法域名列表中"
现象:小程序模拟器里点按钮没反应,控制台报域名校验失败。
原因:微信开发者工具默认开启域名校验,而localhost不在合法域名列表里。
解决:开发者工具右上角"详情" → "本地设置" → 勾选"不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书"。这只在开发阶段有效,上线前必须把接口部署到已备案的 HTTPS 域名并配置到小程序后台。
4.3 publish.js 跑起来但后端收不到数据
现象:publish.js终端显示"上报成功",但数据库里没数据,后端也没日志。
原因:publish.js里的接口地址写的是http://localhost:3000/api/report,但后端实际路由可能是/api/data/report或/report,路径不匹配时后端返回 404,而publish.js的catch可能只打印了e.message没打印状态码,看起来像成功。
解决:在后端index.js里搜app.post找到实际路由路径,跟publish.js里的 URL 对齐。同时把publish.js的错误处理改成打印完整响应:console.error('上报失败:', e.response?.status, e.response?.data)。
4.4 多个 index.js 改错文件
现象:改了半天代码,重启服务后行为没变化。
原因:这份资源里有多个同名index.js,分布在小程序页面目录、后端目录、可能还有工具目录。你改的那个不是实际运行的那个。
解决:用find . -name "index.js" -exec grep -l "app.listen" {} \;找到真正启动 HTTP 服务的那个文件。-exec grep -l表示对每个找到的文件执行 grep 并只输出匹配的文件名,app.listen是 Express 启动服务的标志性调用。
4.5 传感器数据曲线不刷新
现象:小程序页面能显示数据,但数值一直不变,手动下拉刷新才更新。
原因:页面没有做定时轮询或 WebSocket 推送,只在onLoad时请求了一次。
解决:在页面onShow里加setInterval定时请求,页面onHide时clearInterval。间隔建议 5-10 秒,跟设备上报频率对齐。如果项目用的是 MQTT,检查小程序端wx.connectSocket的连接状态和 topic 订阅是否正确。
5. 二次开发切入点:从能跑到能用还差哪几步
把项目跑通只是第一步。毕设答辩时老师最爱问的两个问题是"你的创新点在哪"和"这个数据是真的吗"。前者需要你在现有骨架上加功能,后者需要你把模拟数据换成真实传感器。
5.1 用真实传感器替换模拟数据
publish.js里的Math.random()是模拟数据,换成真实传感器有两种常见路径。一种是 ESP8266/ESP32 通过串口读 DHT11 温湿度传感器,再用 HTTP 或 MQTT 发出去;另一种是树莓派上用 Python 读 GPIO,通过requests库 POST 到后端。不管哪种,后端接口不用改,只需要把publish.js里的数据生成逻辑替换成传感器读取逻辑。
// 以串口读取为例(需要 npm install serialport) const SerialPort = require('serialport'); const Readline = require('@serialport/parser-readline'); const port = new SerialPort({ path: 'COM3', baudRate: 9600 }); const parser = port.pipe(new Readline({ delimiter: '\n' })); parser.on('data', async (line) => { // 假设传感器输出格式为 "T:25.3,H:60.1,S:45.2" const parts = line.trim().split(','); const payload = { device_id: 'sensor_001', temperature: parseFloat(parts[0].split(':')[1]), humidity: parseFloat(parts[1].split(':')[1]), soil_moisture: parseFloat(parts[2].split(':')[1]) }; await axios.post('http://localhost:3000/api/report', payload); });path: 'COM3'是 Windows 下的串口号,Linux 下一般是/dev/ttyUSB0,Mac 下是/dev/tty.usbserial-xxx。baudRate: 9600要和传感器固件里的波特率一致,不一致会读到乱码。delimiter: '\n'表示按换行符切分数据帧,如果你的传感器固件不是按行输出,这里要改。
5.2 加一个历史数据查询接口
现有接口大概率只有"最新数据"和"上报数据"两个。答辩时老师往往会问"能不能看历史曲线",这时候你需要加一个按时间范围查询的接口。
// 后端新增:GET /api/history?device_id=xxx&hours=24 app.get('/api/history', async (req, res) => { const { device_id, hours = 24 } = req.query; const sql = ` SELECT temperature, humidity, soil_moisture, created_at FROM sensor_data WHERE device_id = ? AND created_at >= DATE_SUB(NOW(), INTERVAL ? HOUR) ORDER BY created_at ASC `; try { const [rows] = await pool.query(sql, [device_id, parseInt(hours)]); res.json({ code: 0, data: rows }); } catch (e) { res.status(500).json({ code: 1, msg: e.message }); } });DATE_SUB(NOW(), INTERVAL ? HOUR)是 MySQL 的日期减法函数,NOW()取当前时间,减掉hours小时得到起始时间点。parseInt(hours)是必须的,因为req.query拿到的都是字符串,直接传给 MySQL 的INTERVAL会报语法错误。返回结果按created_at ASC升序排列,方便前端直接画折线图。
5.3 小程序端加 ECharts 折线图
小程序原生没有图表组件,常见做法是用echarts-for-weixin。把ec-canvas组件拷到项目里,在页面 JSON 里注册,然后onReady时初始化图表实例,把/api/history返回的数据喂给series[0].data。
// 页面 js 中初始化图表 import * as echarts from '../../components/ec-canvas/echarts'; function initChart(canvas, width, height, dpr) { const chart = echarts.init(canvas, null, { width, height, devicePixelRatio: dpr }); canvas.setChart(chart); chart.setOption({ xAxis: { type: 'category', data: [] }, yAxis: { type: 'value' }, series: [{ type: 'line', data: [], smooth: true }] }); return chart; } // 拿到历史数据后更新 request('/api/history?device_id=sensor_001&hours=24').then(res => { const times = res.data.map(item => item.created_at.slice(11, 16)); // 取 HH:mm const temps = res.data.map(item => item.temperature); chart.setOption({ xAxis: { data: times }, series: [{ data: temps }] }); });slice(11, 16)是从"2024-01-15 14:30:00"这种格式里截出"14:30",只显示时分让 X 轴不至于太挤。smooth: true让折线变平滑,视觉上更像真实传感器曲线。注意ec-canvas的初始化必须在onReady之后,在onLoad里调会拿不到 canvas 节点。
从那以后我每次拿到毕设包,都强制先跑一遍find . -name "*.js" | xargs grep -l "listen\|connect"把真正的入口文件找出来,再动手改配置。这份智慧农业平台的骨架是完整的,三端链路能跑通,剩下的就是往里面填真实数据和业务逻辑。希望帮到你。
本文还有配套的精品资源,点击获取