esp32学习 mqtt传输图片及数据可视化

mqtt传输图片并在网页上显示

  • 前言
  • 开源mqtt.js库
  • base64 编码
  • 模拟发送
  • web可视化

前言

由于最近在做水果识别系统,打算将识别出的结果传输到微信小程序,由于微信小程序限制太多,先在网页上进行实验

开源mqtt.js库

mqtt.js是一个开源的js库,而且兼容微信小程序,使用也比较简单,github网址mqtt.js,这里使用cdn的方式使用。

<script src="https://unpkg.com/[email protected]/dist/mqtt.min.js"></script>

首先初始化信息

const options = {
      // 认证信息
      clientId: '设备id',
      username: '用户名',
      password: '密码',
}

然后进行连接

const client = mqtt.connect('ws://域名或ip:端口号/mqtt', options);

因为我使用的是自己搭建的mqtt服务端,没有域名,所以这里我选择ws方式,除了ws还有wss方式,两者的区别是ws不安全,wss较为安全,ws的默认端口为8083,wss默认端口为443

订阅主题

client.subscribe('主题名');

然后是发送

client.publish(topic, message, 可选q0s)

然后是接受函数

client.on('message', function (topic, message) {
	在这里处理	
})

base64 编码

由于esp32的ram较小,只有512k,运行是用户可用的ram只剩200k左右,在传输图片是采用jpeg压缩,jpeg是一种有损压缩,压缩后可将图片体积大大减小,k210采集的图片为224224,如果采用rgb565,需要的大小大概为224224*2/1024=98k,这个大小对于esp32来说太大了,故在k210上对图片进行压缩,采用网上的一个c语言压缩代码,转换为jpg文件,压缩后大概15k。
压缩完成之后为二进制,二进制在传输过程中比较麻烦,一般为了传输方便都会对二进制流进行base64编码,base64编码完成之后可以完全用字符串表示
base64编码的原理就是将3个字节的内容用4个字节表示,可能这个时候就有些困惑,这不体积变大了吗?是的,编码后体积会变大三分之四,但是编码后传输更加方便
这里借鉴披荆又斩棘的讲解base64原理
在编码完之后所以的数据都可以用字符串表示,而且js可以直接显示base64流。下面为esp32 base64的编码代码

static const char *ALPHA_BASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
char *encode(const char *buf, const long size, char *base64Char) {
    int a = 0;
    int i = 0;
    while (i < size) {
        char b0 = buf[i++];
        char b1 = (i < size) ? buf[i++] : 0;
        char b2 = (i < size) ? buf[i++] : 0;
         
        int int63 = 0x3F; //  00111111
        int int255 = 0xFF; // 11111111
        base64Char[a++] = ALPHA_BASE[(b0 >> 2) & int63];
        base64Char[a++] = ALPHA_BASE[((b0 << 4) | ((b1 & int255) >> 4)) & int63];
        base64Char[a++] = ALPHA_BASE[((b1 << 2) | ((b2 & int255) >> 6)) & int63];
        base64Char[a++] = ALPHA_BASE[b2 & int63];
    }
    switch (size % 3) {
        case 1:
            base64Char[--a] = '=';
        case 2:
            base64Char[--a] = '=';
    }
    return base64Char;
}

模拟发送

由于我买杜邦线的时候全买成公对公的了,故现在只能模拟mqtt发送图片,这里我使用win画板做一幅图,然后使用python转换为.h文件
这里附赠一个简单的jpg转.h代码

import os
filename = 'test.jpg'
wd=[]
with open(filename, 'rb') as f:
    filename2= 'test.h'
    
    with open(filename2,'w+') as f2:
        k='const char test[]={'
        k2=','
        f2.write(str(k))
        size = os.path.getsize(filename) #获得文件大小 
        for i in range(size):
            m = f.read(1)
            n=int.from_bytes(m, byteorder='big', signed=False)
            f2.write(str(n))
            if i<size-1:
                f2.write(str(k2))
            print(i)
            i=i+1
        k='};'
        f2.write(str(k))
    f2.close()
f2.close()

转换之后jpg文件就变成了c语言的数组

int len=8842*4/3+1;
char* data = (char*) malloc(len);
char *base64=encode(test, 8842, data);
esp_mqtt_client_publish(client, "photo", (const char *)base64, len, 1, 0);

数组长度为8842,这里首先计算需要申请的内存大小,编码后为原文件的三分之四,然后进行编码,发送到photo主题。

接下来是js部分,创建一个div

<img src="apple.jpg" id="userImge" style="width: 50%;height:50%;" name="userImge" >

然后在client.on(‘message’, function (topic, message)mqtt接受函数里判断主题,并显示,在js里显示base64只需要一句代码

$("#userImge").attr("src","data:image/jpg;base64,"+p1);

web可视化

web可视化选用百度开源可视化库echarts,官方连接百度可视化库,因为是国人制作,里面的文档都挺详细,而且官方速度访问快多了,可以在官网在线修改。
上面有很多例程,基本涵盖需要的可视化工具。
最后附上一个简单的代码,这个代码是移动端布局,电脑布局排版会乱。如果没有服务器,想在手机上随时查看,可以放到github博客上运行。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
    <title>myProject</title>
    <!-- 引入 js/echarts.min.js -->
    <script src="js/echarts.min.js"></script>
	<script src="https://unpkg.com/[email protected]/dist/mqtt.min.js"></script>
	<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<style>
body{
  background:url("smart.jpg") no-repeat;
  background-size: 100%;
}
.t{
	margin-top:10%;
}
.div1{
	margin-top:70px;
	width:100%;
	 display: flex;
	}
.div2{
	margin-left:5%;
	 display: flex;
	}
</style>		
</head>
<body>
	<div class="t"><center><h1>水果分拣系统设计</h1></center></div>
 	<div class=div1>
	<img src="apple.jpg" id="userImge" style="width: 50%;height:50%;" name="userImge" >
	<div style="width: 50%;height:200px;">
		<center><h3 ><a id="num">0</a>个苹果</h3></center>
		<center><h3>体积:中</h3></center>
		<center><h3>成熟度:<a id="csd">85</a>%</h3></center>
		<div class="div2">
		<center><button id="bu" style="width: 80px;height:30px">接收图片</button></center>
		<center><button id="but" style="width: 80px;height:30px;margin-left:5%;">ledon</button></center>
	    </div>
	</div>
    </div>

    
    <div id="dev" style="width: 100%;height:300px;"></div>
	

    <script>
	//初始化仪表盘
	var myChart = new Array();
	var option = new Array();


	 myChart = echarts.init(document.getElementById('dev'));
	
	option = {
    backgroundColor: '#2c343c',

    title: {
        text: '苹果数量统计',
        left: 'center',
        top: 20,
        textStyle: {
            color: '#ccc'
        }
    },

    tooltip: {
        trigger: 'item',
        formatter: '{a} 
{b} : {c} ({d}%)'
}, visualMap: { show: false, min: 80, max: 600, inRange: { colorLightness: [0, 1] } }, series: [ { name: '访问来源', type: 'pie', radius: '55%', center: ['50%', '50%'], data: [ {value: 200, name: '大苹果'}, {value: 100, name: '标准苹果'}, {value: 100, name: '小苹果'}, ].sort(function (a, b) { return a.value - b.value; }), roseType: 'radius', label: { color: 'rgba(255, 255, 255, 0.3)' }, labelLine: { lineStyle: { color: 'rgba(255, 255, 255, 0.3)' }, smooth: 0.2, length: 10, length2: 20 }, itemStyle: { color: '#c23531', shadowBlur: 200, shadowColor: 'rgba(0, 0, 0, 0.5)' }, animationType: 'scale', animationEasing: 'elasticOut', animationDelay: function (idx) { return Math.random() * 200; } } ] }; //初始化mqtt信息 const options = { // 认证信息 clientId: '设备id', username: '用户名', password: '密码', } const client = mqtt.connect('wss://域名:443/mqtt', options); client.subscribe('up'); client.subscribe('photo'); $("#bu").click(function(){ str1="{\"id\":\"up\"}"; client.publish("sw_led",str1,1); }); $("#but").click(function(){ var st=$("#but").text(); console.log(st); if(st=="ledon") { str1="{\"id\":\"on\"}"; client.publish("sw_led",str1,1); $("#but").text("ledoff"); }else { str1="{\"id\":\"off\"}"; client.publish("sw_led",str1,1); $("#but").text("ledon"); } //str1="{\"id\":\"up\"}"; // client.publish("sw_led",str1,1); }); //myChart.setOption(option, true) myChart.setOption(option, true) //接受信息 client.on('message', function (topic, message) { var p1 = message.toString(); //console.log(p1); if(topic=="up") { var p2 = JSON.parse(p1); console.log(p2); $("#csd").html(p2.val); option.series[0].data[0].value = p2.val; myChart.setOption(option, true) } else if(topic=="photo") { $("#userImge").attr("src","data:image/jpg;base64,"+p1); } }) client.on('reconnect', (error) => { console.log('正在重连:', error) }) client.on('connect', (error) => { console.log('连接成功:', error) }) client.on('error', (error) => { console.log('连接失败:', error) }) </script> </body> </html>

你可能感兴趣的:(esp32学习 mqtt传输图片及数据可视化)