提示:文章完成后,目录可以自动生成,如何生成可以参考右边的帮助文档
文章目录
- 前言
- 一、Arduino通信树莓派
- 2.树莓派将数据上传到服务器
-
- 1.用于树莓派Django搭建服务器
- 2.搭建树莓派MySQL数据库
- 3.树莓派数据post到服务器上
- 微信小程序通过服务器获取数据库的值
- 总结
前言
本文主要讲的是智能鱼缸树莓派,也是我认为毕业设计最难的部分。
一、Arduino通信树莓派
看过我上一篇文章的朋友应该知道,现在我们已经实现了Arduino读取传感器的值,我们如何把它传给树莓派?(注:如果手里有全新的覆盆子派,需要安装镜像源,实现远程访问等准备工作。建议B站覆盆子派教程:https://www.bilibili.com/video/BV1bt411c7fC?share_source=copy_web只看前四节课ok) 参考链接:树莓派与Arduino通信 跟着这个帖子成功实现简单的通后(我用的是USB通讯),接下来要做的就是把我的Arduino传感器的数据传输到树莓派。 上代码! 在Arduino IDE写下面的代码,覆盖我上一篇文章Arduino IDE上面的代码(此代码添加到以前的基础上Arduino将数据发送给树莓的部分):
#include <OneWire.h> #include <DallasTemperature.h> #define tempPin 2// 温度传感器数据输出脚接开发板数字引脚2 #define waterpower 7 ///水位传感器VCC引脚 #define waterpin A0 //水位传感器输出引脚 #define oxygenpin A1///溶解氧传感器输出引脚 OneWire oneWire(tempPin); DallasTemperature sensors(&oneWire); int temp_relaypin=3;///温度传感器继电器1引脚3 int waterup_relaypin=4;///水位传感器继电器引脚4 int waterdown_relaypin=5;////水位传感器继电器引脚5 int oxygen_relaypin=9;///溶解氧传感器继电器引脚9 float temperature; int oxygen; int water_level; int val=0; int incomedate = 0; void setup(void) {
Serial.begin(9600);///连接到计算机串口监视器 sensors.begin(); pinMode(temp_relaypin,OUTPUT);//设置继电器1为输出模式
pinMode(tempPin,OUTPUT);//温度传感器输出模式
pinMode(waterup_relaypin,OUTPUT);//继电器输出模式
pinMode(waterdown_relaypin,OUTPUT);//继电器输出模式
pinMode(waterpower,OUTPUT);//将水位传感器VCC引脚设置成输出模式
pinMode(oxygen_relaypin,OUTPUT);//溶解氧继电器4输出模式
digitalWrite(waterpower,LOW);//先将水位传感器VCC引脚关闭
}
int readwatersensor()
{
digitalWrite(waterpower,HIGH);//将水位传感器VCC电源打开给传感器供电
delay(10);
val=analogRead(waterpin);//读取水位传感器A0引脚的值
digitalWrite(waterpower,LOW);//将水位传感器电源关闭
return val;//返回val值
}
void loop(void)
{
//温度
sensors.requestTemperatures(); // 发送命令获取温度
temperature=sensors.getTempCByIndex(0);
//溶解氧
int analog=analogRead(A1);//读取模拟输入值
oxygen=map(analog,0,1023,0,10);//将模拟输入0~1023等比映射到0mg/L~10mg/L
analogWrite(9,oxygen);
//水位
int level=readwatersensor();//让level=val
water_level=readwatersensor();//让water_level=val
if(Serial.available())
{
incomedate = Serial.read();//获取串口接收到的数据
if (incomedate == 't')
{
Serial.println(temperature); //向树莓派发送信息
}
else if (incomedate == 'w')
{
Serial.println(water_level); //向树莓派发送信息
}
else if (incomedate == 'o')
{
Serial.println(oxygen); //向树莓派发送信息
}
}
//继电器控制加热棒
if(temperature<25)//如果温度小于25度
{
digitalWrite(temp_relaypin, HIGH);//继电器1开,加热棒开
}
else
{
digitalWrite(temp_relaypin,LOW); //继电器1关,加热棒关;
}
delay(500);
//继电器控制水泵
if(water_level<550)//如果水位在传感器1CM之下
{
digitalWrite(waterup_relaypin, HIGH);//继电器2开,放水水泵开
}
else
{
if(water_level>640)
{
digitalWrite(waterdown_relaypin, HIGH);//继电器3开,抽水水泵开
}
else
{
digitalWrite(waterup_relaypin, LOW);//继电器2关
digitalWrite(waterdown_relaypin, LOW);//继电器3关
}
}
//继电器控制增氧泵
if(oxygen<5)
{
digitalWrite(oxygen_relaypin, HIGH);//继电器4开,充氧泵开
}
else
{
digitalWrite(oxygen_relaypin, LOW);//继电器4关,充氧泵开
}
delay(500);
}
在树莓派上新建一个post.py文件,写入:
import RPi.GPIO as GPIO
import serial
import time
import json,requests
import datetime
ser = serial.Serial('/dev/ttyUSB0', 9600,timeout=1); #open named port at 9600,1s timeot
#try and exceptstructure are exception handler
while 1:
for i in range(2):
send='t';
ser.write(send.encode());#wrt a string to port
time.sleep(2);
temperature = ser.readline().decode();#read a string from port
print(temperature);
send='w';
ser.write(send.encode());#wrt a string to port
time.sleep(2);
water_level= ser.readline().decode();#read a string from port
print(water_level);
send='o';
ser.write(send.encode());#wrt a string to port
time.sleep(2);
oxygen = ser.readline().decode();#read a string from port
print(oxygen);
注意树莓派代码第六行里的:/dev/ttyUSB0,还有人是/dev/ttyACM0,要知道你的是什么,把树莓派和Arduino用USB连接后,在树莓派终端输入: ls /dev/tty*查看两者连接端口的名字,多出哪个就是哪个。 for i in range(2): 的意思是让树莓派打印两次,因为经过实验,发现第一个值一直打不出来,咱也不知道为什么,硬件有时候就是玄学,所以就让这段代码循环两次,让树莓派和Arduino之间实现稳定的传值。 提醒一下之后post.py里还要写入一部分代码,也就是说目前上面的这段树莓派里的代码只是一部分,所以你试验的时候,可能会出现多余的头文件,然后树莓派的IDE报错,没事,暂时把没有用到的头文件注释掉就好了,后面会用得着的(我可真是太贴心了)。 注意这里是后期要放在论文里的截图,特意把第一个没有打出来的temperature盖住了(怕老师问我我答不上来),然后让程序循环了五次。
二、树莓派把数据上传到服务器
现在我们的树莓派已经得到了从Arduino上传过来的传感器数据了。接下来就是把数据上传到服务器,通过服务器写入到数据库了。首先,我们得有一个基于树莓派的服务器。其次,我们树莓派上得有一个MySQL数据库。然后,我们要把服务器和数据库连接起来。最后,把树莓派上的数据post到服务器。接下来我一部分一部分的细说。 参考链接:https://blog.csdn.net/weixin_52079689/article/details/109383872?spm=1001.2014.3001.5506
1.在树莓派上用Django搭建服务器
参考链接:https://blog.csdn.net/damanchen/article/details/85224686 跟着这个链接,我们可以在树莓派上下载好Django。需要注意的是,你的树莓派要有python,我的3B里python默认的是python2。为了之后方便操作,我需要将python2换成python3,这个视情况而定,你不一定非得改。如果你也想改,推荐链接:https://blog.csdn.net/ylzmm/article/details/107827065 好的。现在我们的树莓派上已经有Django了,可以正式开始创建一个服务器了。
django-admin.py startproject fish_tank2#生成网站
cd fish_tank2
python manage.py startapp index2#生成app
需要说明以下我的项目名都是fish_tank,app都叫index。上面的项目和app是我为了演示新建的。名字会有变化。 这里是有关树莓派数据库的,要加这两句代码。
import pymysql
pymysql.install_as_MySQLdb()
[’*’]是为了让同一局域网下面不同ip都可以访问该服务器。 这是连接数据库。后面会讲到树莓派上搭建数据库,这里就是将数据库与服务器连接起来的代码。
from django.conf.urls import url
from django.urls import path, include
urlpatterns = [
#path('admin/', admin.site.urls),
url(r'^sensor/', include('index.urls')),
]
from django.contrib import admin
# Register your models here.
from .models import *
class SensorAdmin(admin.ModelAdmin):
list_display = ('id', 'time', 'temperature','water_level','oxygen')
admin.site.register(Sensors, SensorAdmin)
from django.apps import AppConfig
class IndexConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'index'
from django.db import models
# Create your models here.
class Sensors(models.Model):
time = models.DateTimeField(auto_now_add=False)
temperature = models.CharField(max_length=10)
water_level= models.CharField(max_length=10)
oxygen = models.CharField(max_length=10)
def __str__(self):
return self.time
(没有的文件就右键新建)
from rest_framework import serializers
from index.models import Sensors
class SensorSerializer(serializers.ModelSerializer):
class Meta:
model = Sensors
fields = ['time', 'temperature','water_level','oxygen']
from django.conf.urls import url
from index import views
urlpatterns = [
url(r'^post', views.Sensors_api.as_view(),name='sensor.Sensors_api'),
url(r'^get', views.SensorView.as_view(),name='sensor.Sensors_api'),
]
这里新建了两个网址,post用来接收树莓派上传的数据,得到的是所有的数据;get用来显示最新的数据,因为我们只需要当前的数据。为什么要写成两个网址呢?是因为post用的接口和get不一样,get用的那个接口可以显示最新值,但是post的那个接口我没有找到如何显示最新的值的方法,所以就写了两个网址,一个用来接收数据,一个用来显示最新数据到服务器上,后续小程序也方便get到最新数据。
from rest_framework.response import Response
from rest_framework.views import APIView
from index.models import Sensors
from index.serializers import SensorSerializer
from rest_framework import generics
# Create your views here.
class Sensors_api(generics.ListCreateAPIView):
#queryset = Sensors.objects.last()
queryset = Sensors.objects.all()
serializer_class = SensorSerializer
class SensorView(APIView):
def get(self, request, *args, **kwargs):
sensor = Sensors.objects.last()
obj = SensorSerializer(sensor)
return Response(obj.data)
这里就可以看出来,我post用的是ListCreateAPIView这个接口,get用的是APIView这个接口。 到此,树莓派上成功搭建起了一个web服务器。
2.在树莓派上搭建MySQL数据库
在树莓派上设置安装MySQL,设置用户名密码,推荐链接:点我 注意这里设置的用户名密码要和setting里连接的一样。 建议在pc端下载Navicate,连接树莓派上的数据库,这样有了图形化界面,建表看着也舒心。 参考链接:点我
python manage.py makemigrations
python manage.py migrate
到此,数据库和服务器全都创建成功,并且进行了连接。
3.树莓派把数据post到服务器上
在刚才树莓派post.py后面加上此代码:
# Post Data to webpage
rqs_headers={
'Content-Type': 'application/json'}
requrl ='http://192.168.43.121:8000/sensor/post/'
new_data = {
"time": datetime.datetime.now(),
"temperature": temperature,
"water_level": water_level,
"oxygen": oxygen
}
class ComplexEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(obj, datetime.date):
return obj.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, obj)
test_data = json.dumps(new_data, cls=ComplexEncoder)
response = requests.post(url=requrl, headers=rqs_headers, data=test_data)
time.sleep(50);
运行服务器: 记得要先进入项目的文件夹在文件夹在运行哦
python manage.py runserver 0.0.0.0:8000
在浏览器上输入:192.168.43.121:8000/sensor/post/和192.168.43.121:8000/sensor/get/ 192.168.43.121是我树莓派的ip地址,你们输网址的时候要改成自己的ip地址。
运行post.py文件,可以看到post页面获取到了所有的值,get页面获取到了最新值,Navicat中可以看到数据库里更新了值。
如果你不想手动点击post.py,而是想让它自动每60秒执行一次,可以:
sudo -i
crontab -e
*/1 * * * * python /home/pi/Desktop/post.py #把这个命令加到最后一行,我设定的是每分钟运行一次,用的时候把注释去掉就好了。
sudo /etc/init.d/cron restart
这个时候post.py里的while 1 就可以去掉了。我把自动执行的放到post2.py里,手动执行的放在post.py里,手动的方便调试,自动的最后使用。 至此,由arduino获取传感器数值,并传给树莓派,树莓派上传到服务器,通过服务器写入到数据库就完成了。
三、微信小程序通过服务器获取数据库的值
最后一步!!终于快写完了!! 我们要开发一个微信小程序,让小程序通过服务器获取到传感器的数值。 微信小程序课程推荐的B站链接: 下载微信开发者工具 注册账号,获取到appid
其实不用做那么复杂,只需要改两段代码,其他的默认就行:
<!--index.wxml-->
<view class="container">
<view class="userinfo">
<block wx:if="{
{canIUseOpenData}}">
<view class="userinfo-avatar" bindtap="bindViewTap">
<open-data type="userAvatarUrl"></open-data>
</view>
<open-data type="userNickName"></open-data>
</block>
<button type="primary" bindtap="get_message">获取传感器数值</button>
<view>时间:{
{
message.time}}</view>
<view>温度:{
{
message.temperature}}</view>
<view>水位:{
{
message.water_level}}</view>
<view>溶解氧:{
{
message.oxygen}}</view>
<view>加热棒:{
{
message.temperature >25 ? '关': '开'}}</view>
<view>充氧泵:{
{
message.oxygen >5 ? '关': '开'}}</view>
<view>加水水泵:{
{
message.water_level <550 ? '开': '关'}}</view>
<view>抽水水泵:{
{
message.water_level >640 ? '开': '关'}}</view>
</view>
</view>
这里只加了一个按钮
// index.js
// 获取应用实例
const app = getApp()
Page({
data: {
message:[],
motto: 'Hello World',
userInfo: {
},
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo'),
canIUseGetUserProfile: false,
canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName') // 如需尝试获取用户信息可改为false
},
// 事件处理函数
bindViewTap() {
wx.navigateTo({
url: '../logs/logs'
})
},
onLoad() {
if (wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
}
},
getUserProfile(e) {
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
wx.getUserProfile({
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log(res)
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
},
getUserInfo(e) {
// 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
console.log(e)
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
},
get_message(){
var that = this;
wx.request({
url: 'http://192.168.43.121:8000/sensor/get',
success(data){
console.log(data.data)
that.setData({
message:data.data})
}
})
},
})
这里get数据。
总结
终于写完了,最后再整体捋一遍 1、arduino获取传感器数值 2、arduino与树莓派进行通讯,树莓派获取传感器数值 3、树莓派将数值上传到服务器上,通过服务器写入数据库,服务器用Django写,然后与树莓派上数据库进行连接。 4、微信小