飞腾派
直播中

jf_25674040

2年用户 109经验值
擅长:可编程逻辑 MEMS/传感技术 接口/总线/驱动 控制/MCU
私信 关注
[经验]

【飞腾派4G版免费试用】环境中甲醛浓度的显示

经历过装修的社会人,不免总是在担心一个事情,那就是环境中甲醛浓度到底现在是多少?会不会对人的生活有影响,我们今天一起来探讨甲醛的web界面显示:
本次我们使用到的甲醛模组是ze08-ch2o
图片.png
又是一个串口,无非就是工作环境是啥,管脚定义是啥的?
图片.png
工作电压要求是3.7V~5.5V的电压,(*附件:萤火工场·CEK8903飞腾派硬件规格书-V1.01.pdf)
就近原则,选择4,6管脚作为电源输入,8,10作为通讯口。
图片.png
模块管脚定义,物理层妥妥的搞完。
图片.png
协议层,妥妥的使用主动上传,省去发起的操作;
图片.png
Django+pyserial实现后端数据的读取和存储
首先更改Django中的models.py

class CH2O(models.Model):
    ch2o = models.FloatField()
    add_time = models.DateTimeField(auto_now_add=True)
    class Meta:
        db_table='ze08'

处理一下数据库

python manage.py makemigrations chat
python manage.py sqlmigrate chat 0002
python manage.py migrate

用pyserial实现甲醛数据的获取,同时实现数据存储到数据库

import threading
import time
import serial
from .models import  CH2O

class MySerial(object):
  def __init__(self):
      self.ser = None

  def get_port_list(self):
      port_list = list(serial.tools.list_ports.comports())
      return port_list

  def open_serial_port(self, port, baud):
      try:
          self.ser = serial.Serial(port, baud, timeout=0.3, interCharTimeout=0.05)
      except Exception as e:
          self.ser = None
          raise Exception(e)

  def close_serial_port(self):
      if self.ser == None:
          raise Exception("no selected serial")
      try:
          self.ser.close()
          self.ser = None
      except Exception as e:
          raise Exception(e)

  def read(self):
      if self.ser == None:
          raise Exception("no selected serial")
      try:
          time.sleep(0.001)
          return self.ser.read(self.ser.in_waiting)
      except Exception as e:
          raise Exception(e)

class Ze08Ch2o(object):
    def __init__(self, device, baud) -> None:
        self.serial = MySerial()
        self.serial.open_serial_port(device, baud)
        self.recv_thread_ = threading.Thread(target=self.recv_thread)
        self.recv_thread_.start()

    def calc_checksum(self, bytes_value):
        checksum = 0
        for byte_ in bytes_value:
            checksum += byte_
        checksum = checksum % (0xff + 1)
        if checksum == 0xff:
            return True
        return False

    def recv_thread(self):
        recv_buffer = bytes()
        while True:
            try:
                recv_buffer += self.serial.read()
            except Exception as e:
                print(str(e))
            if len(recv_buffer) < 9:
                time.sleep(0.01)
                continue
            else:
                if recv_buffer[0] != 0xff:
                    recv_buffer = recv_buffer[1:]
                else:
                    if len(recv_buffer) >= 9:
                        phase_buffer = recv_buffer[:9]
                        recv_buffer = recv_buffer[9:]
                        if self.calc_checksum(phase_buffer) == True:
                            int_formaldehyde = int.from_bytes(phase_buffer[4:6], byteorder='big')
                            float_formaldehyde = int_formaldehyde /1000.0 *1.25
                            CH2O.objects.create(ch2o=float_formaldehyde)
                            print("formaldehyde: {:>.4f}".format(float_formaldehyde))
                        time.sleep(0.001)

#z = Ze08Ch2o('/dev/ttyAMA2', 9600)

在channels实现的websocket上添加关于甲醛浓度的代码,实现从数据库中读取甲醛浓度数据和aht10的温湿度数据

def my_send(self):
        if self.clients:
            wendu = Temperature.objects.order_by('-id').first()
            ch2o = CH2O.objects.order_by('-id').first()
            self.send(text_data=json.dumps({'humid': wendu.humid, 'thermo': wendu.thermo, 'formaldehyde': ch2o.ch2o}))
            #self.send(text_data=json.dumps({"message": "hello world"}))

在chatroom的html中增加甲醛数据

<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Chat Room</title>
</head>
<body>
    <textarea id="chat-log" cols="100" rows="20"></textarea><br>
    <input id="chat-message-input" type="text" size="100"><br>
    <input id="chat-message-submit" type="button" value="Send">
    {{ room_name|json_script:"room-name" }}
    <script>
        const roomName = JSON.parse(document.getElementById('room-name').textContent);

        const chatSocket = new WebSocket(
            'ws://'
            + window.location.host
            + '/ws/chat/'
            + roomName
            + '/'
        );

        chatSocket.onmessage = function(e) {
            const data = JSON.parse(e.data);
            document.querySelector('#chat-log').value += ("thermo: " + data.thermo.toFixed(2) + " humid:" + data.humid.toFixed(2)+ " formaldehyde: " + data.formaldehyde.toFixed(4) + '\n');
        };

        chatSocket.onclose = function(e) {
            console.error('Chat socket closed unexpectedly');
        };

        document.querySelector('#chat-message-input').focus();
        document.querySelector('#chat-message-input').onkeyup = function(e) {
            if (e.key === 'Enter') {  // enter, return
                document.querySelector('#chat-message-submit').click();
            }
        };

        document.querySelector('#chat-message-submit').onclick = function(e) {
            const messageInputDom = document.querySelector('#chat-message-input');
            const message = messageInputDom.value;
            chatSocket.send(JSON.stringify({
                'message': message
            }));
            messageInputDom.value = '';
        };
    </script>
</body>
</html>

后端的实时甲醛数据已经搞定;
一段时间的甲醛数据的处理继续撸上;

class formaldehydeView(View):
    def  get(self, request):
        # 当前时间
        now = datetime.datetime.now()
        # 显示10秒前的甲醛浓度
        datetimelist = []
        ch2o_list = []
        start_time = datetime.datetime.strftime(now - datetime.timedelta(seconds=10),"%Y-%m-%d %H:%M:%S")    # 当前时间
        end_time = datetime.datetime.strftime(now,"%Y-%m-%d %H:%M:%S")   # 结束时间
        # 获取在开始时间之后 结束时间之前的的甲醛浓度
        ch2o_fd = CH2O.objects.filter(add_time__gte=start_time,add_time__lte=end_time).all()
        for hcho in ch2o_fd:
            ch2o_list.append(hcho.ch2o)
            datetimelist.append(datetime.datetime.strftime(hcho.add_time,"%Y-%m-%d %H:%M:%S.%f"))
        msg=json.dumps({'datetimelist': datetimelist, 'ch2o_list': ch2o_list})
        return HttpResponse(msg)

在project的路由中添加甲醛浓度的访问

"""
URL configuration for mysite project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path,include
from chat.views import ThermoHumidView, formaldehydeView

urlpatterns = [
    path("chat/", include("chat.urls")),
    path('admin/', admin.site.urls),
    path('aht10/', ThermoHumidView.as_view()),
    path('ch2o/', formaldehydeView.as_view()),
]

ok,后端正式做完。
VUE3的前端就这么简单处理以下把

<!--
<script setup>
import HelloWorld from './components/HelloWorld.vue'
import TheWelcome from './components/TheWelcome.vue'
</script>
-->
<template>
<!-- <header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> -->
<div>
当前的温度是:{{thermo}}℃,
当前的湿度是: {{humid}}%,
当前的甲醛浓度: {{formaldehyde}}mg/m3
<div id="thermo"  style="width: 1500px;height: 300px;" />
<div id="humid"  style="width: 1500px;height: 300px;" />
<div id="formaldehyde"  style="width: 1500px;height: 300px;" />
</div>
<!-- </header> -->
</template>
<!--
  <header>
  	<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
  	<div class="wrapper">
		<HelloWorld msg="You did it!" />
  	</div>
  </header>

  <main>
  	<TheWelcome />
  </main>
-->
<script>
import axios from 'axios';
import * as echarts from 'echarts';
//import {init, EChartsOption} from 'echarts';
export default {
    data() {
        return {
            thermo:0 ,
	    humid: 0,
	    formaldehyde: 0,
	    aht10: {
			datetime_list: [],
			thermo_list: [],
			humid_list: [],
		},
	    //datetimelist: [],
	    //thermolist: [],
	    //humidlist: [],
	    ch2o: {
	    	formaldehyde_list: 0,
	    	datetime_list: [],
		},
	    response: ' ',
        }
    },
    methods: {
	thermoView(){
		var chartDom = document.getElementById('thermo');
		var myChart = echarts.init(chartDom);
		let  option = {
		xAxis: {
                    type: 'category',
                    //data: this.aht10_datetimelist
                    data: this.aht10.datetime_list,
                },
                yAxis: {
                    type: 'value',                    
                },
                series: [{
                    //data: this.thermolist,
                    data: this.aht10.thermo_list,
                    type: 'line',
                    smooth: true
                }]
            };
            myChart.setOption(option);
	},
	humidView(){
		var chartDom = document.getElementById('humid');
		var myChart = echarts.init(chartDom);
		let  option = {
		xAxis: {
                    type: 'category',
                    //data: this.datetimelist
                    data: this.aht10.datetime_list,
                },
                yAxis: {
                    type: 'value',                    
                },
                series: [{
                    //data: this.humidlist,
                    data: this.aht10.humid_list,
                    type: 'line',
                    smooth: true
                }]
            };
            myChart.setOption(option);
	},
	formaldehydeView(){
		var chartDom = document.getElementById('formaldehyde');
		var myChart = echarts.init(chartDom);
		let  option = {
		xAxis: {
                    type: 'category',
                    //data: this.datetimelist
                    data: this.ch2o.datetime_list,
                },
                yAxis: {
                    type: 'value',                    
                },
                series: [{
                    //data: this.humidlist,
                    data: this.ch2o.formaldehyde_list,
                    type: 'line',
                    smooth: true
                }]
            };
            myChart.setOption(option);
	},
	checkValue(){
		//this.datetimelist = this.response.data.datetimelist;
		//this.thermolist = this.response.data.thermolist;
		//this.humidlist = this.response.data.humidlist;
		console.log(this.datetimelist);
		this.thermoView();
		this.humidView();
		this.formaldehydeView();
	},
	getList(){
		axios
		.get('/api/aht10/')
		.then(response=>{
			this.response = response;
			this.aht10.datetime_list = response.data.datetimelist;
			this.aht10.thermo_list = response.data.thermolist;
			this.aht10.humid_list = response.data.humidlist;
			console.log(response),
			this.checkValue();})
		.catch(function(error){
			console.log(error);
		});
	},
	getCh2o(){
		axios
		.get('/api/ch2o/')
		.then(response=>{
			this.ch2o.formaldehyde_list = response.data.ch2o_list;
			this.ch2o.datetime_list = response.data.datetimelist;
			console.log(response),
			this.checkValue();})
		.catch(function(error){
			console.log(error);
		});
	},
        getThermoHumid(){
            var socket = new WebSocket("ws:10.43.60.15:8000/ws/chat/room/");
               socket.onopen = function () {
                console.log('connect success.');//成功连接上Websocket
            };
            socket.onmessage = (e=>{
                let data = JSON.parse(e.data);//打印服务端返回的数据
                this.thermo = data['thermo'].toFixed(2)
                this.humid = data['humid'].toFixed(2)
		this.formaldehyde = data['formaldehyde'].toFixed(4),
                console.log(data['thermo'] + data['humid'] + data['formaldehyde'])
		this.getList();
		this.getCh2o();
            })                            
            socket.onclose=function(e){
                console.log(e);
                socket.close(); //关闭TCP连接
            };      
        }
    },
    created() {
        this.getThermoHumid()
	//this.getList()
    }
}
</script>
<style scoped>
  header {
	  line-height: 1.5;
  }
.aht10 {
	width: 450px;
}
.logo {
display: block;
margin: 0 auto 2rem;
}

@media (min-width: 1024px) {
	header {
display: flex;
	 place-items: center;
	 padding-right: calc(var(--section-gap) / 2);
	}

	.logo {
margin: 0 2rem 0 0;
  }

  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
}
</style>

来一张图片展示一下。

图片.png
视频下次补上。。。待续。。。

回帖(1)

alwinlee

2023-12-20 10:51:11
感谢贡献,加油加油
举报

更多回帖

发帖
×
20
完善资料,
赚取积分