python使用MQTT给硬件传输图片的实现方法


Posted in Python onMay 05, 2019

最近因需要用python写一个微服务来用MQTT给硬件传输图片,其中python用的是flask框架,大概流程如下:

python使用MQTT给硬件传输图片的实现方法

协议为:

需要将图片数据封装成多个消息进行传输,每个消息传输的数据字节数为1400Byte。
消息(MQTT Payload) 格式:Web服务器-------->BASE:

python使用MQTT给硬件传输图片的实现方法

反馈:BASE---------> Web服务器:

python使用MQTT给硬件传输图片的实现方法

如果Web服务器发送完一个“数据传输消息”后,5S内没有收到MQTT“反馈消息”或者收到的反馈中显示“数据包不完整”,则重发该“数据传输消息”。

程序流程图

根据上面的协议,可以得到如下的流程图:

python使用MQTT给硬件传输图片的实现方法

代码如下:

# encoding:utf-8
from flask import Flask, jsonify
from flask_restful import Api, Resource, reqparse
from PIL import Image
from io import BytesIO
import requests
import os, logging, time
import paho.mqtt.client as mqtt
import struct
from flask_cors import *
# 日志配置信息
logging.basicConfig(
  level=logging.INFO,
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s (runing by %(funcName)s',
)
class Mqtt(object):
  def __init__(self, img_data, size):
    self.MQTTHOST = '*******'
    self.MQTTPORT = "******"
    # 订阅和发送的主题
    self.topic_from_base = 'mqttTestSub'
    self.topic_to_base = 'mqttTestPub'
    self.client_id = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
    self.client = mqtt.Client(self.client_id)
    # 完成链接后的回掉函数
    self.client.on_connect = self.on_connect
    # 图片大小
    self.size = size
    # 用于跳出死循环,结束任务
    self.finished = None
    # 包的编号
    self.index = 0
    # 将收到的图片数据按大小分成列表
    self.image_data_list = [img_data[x:x + 1400] for x in range(0, self.size, 1400)]
    # 记录发布后的数据,用于监控时延
    self.pub_time = 0
    self.header_to_base = 0xffffeeee
    self.header_from_base = 0xeeeeffff
    # 功能标识
    self.function_begin = 0x01
    self.function_doing = 0x02
    self.function_finished = 0x03
    # 包的完整和非完整状态
    self.whole_package = 0x01
    self.bad_package = 0x00
    # 头信息的格式,小端模式
    self.format_to_base = "<Lbhh"
    self.format_from_base = "<Lbhb"
    # 如果重发包时,用于检查是否重发第一个包
    self.first = True
    # 如果重发包时,用于检查是否重发最后一个包
    self.last = False
    self.begin_data = 'image.jpg;' + str(self.size)
  # 链接mqtt服务器函数
  def on_mqtt_connect(self):
    self.client.connect(self.MQTTHOST, self.MQTTPORT, 60)
    self.client.loop_start()
  # 链接完成后的回调函数
  def on_connect(self, client, userdata, flags, rc):
    logging.info("+++ Connected with result code {} +++".format(str(rc)))
    self.client.subscribe(self.topic_from_base)
  # 订阅函数
  def subscribe(self):
    self.client.subscribe(self.topic_from_base, 1)
    # 消息到来处理函数
    self.client.on_message = self.on_message
  # 接收到信息后的回调函数
  def on_message(self, client, userdata, msg):
    # 如果接受第一个包则不需要重发第一个
    self.first = False
    # 将接受到的包进行解压,得到一个元组
    base_tuple = struct.unpack(self.format_from_base, msg.payload)
    logging.info("+++ imageData's letgth is {}, base_tupe is {} +++".format(self.size, base_tuple))
    logging.info("+++ package_number is {}, package_status_from_base is {} +++"
           .format(base_tuple[2], base_tuple[3]))
    # 检查接受到信息的头部是否正确
    if base_tuple[0] == self.header_from_base:
      logging.info("+++ function_from_base is {} +++".format(base_tuple[1]))
      # 是否完成传输,如果完成则退出
      if base_tuple[1] == self.function_finished:
        logging.info("+++ finish work +++")
        self.finished = 1
        self.client.disconnect()
      else:
        # 是否是最后一个包
        if self.index == len(self.image_data_list) - 1:
          self.publish('finished', self.function_finished)
          self.last = True
          logging.info("+++ finished_data_to_base is finished+++")
        else:
          # 如果接收到的包不是 0x03则进行传送数据
          if base_tuple[1] == self.function_begin or base_tuple[1] == self.function_doing:
            logging.info("+++ package_number is {}, package_status_from_base is {} +++"
                   .format(base_tuple[2],base_tuple[3]))
            # 如果数据的反馈中,包的状态是1则继续发下一个包
            if base_tuple[3] == self.whole_package:
              self.publish(self.index, self.function_doing)
              logging.info("+++ data_to_base is finished+++")
              self.index += 1
            # 如果数据的反馈中,包的状态是0则重发数据包
            elif base_tuple[3] == self.bad_package:
              re_package_number = base_tuple[2]
              self.publish(re_package_number-1, self.function_doing)
              logging.info("+++ re_data_to_base is finished+++")
            else:
              logging.info("+++ package_status_from_base is not 0 or 1 +++")
              self.client.disconnect()
          else:
            logging.info("+++ function_identifier is illegal +++")
            self.client.disconnect()
    else:
      logging.info("+++ header_from_base is illegal +++")
      self.client.disconnect()
  # 数据发送函数
  def publish(self, index, fuc):
    # 看是否是最后一个包
    if index == 'finished':
      length = 0
      package_number = 0
      data = b''
    else:
      length = len(self.image_data_list[index])
      package_number = index
      data = self.image_data_list[index]
    # 打包数据头信息
    buffer = struct.pack(
      self.format_to_base,
      self.header_to_base,
      fuc,
      package_number,
      length
    )
    to_base_data = buffer + data
    # mqtt发送
    self.client.publish(
      self.topic_to_base,
      to_base_data
    )
    self.pub_time = time.time()
  # 发送第一个包函数
  def publish_begin(self):
    buffer = struct.pack(
      self.format_to_base,
      self.header_to_base,
      self.function_begin,
      0,
      len(self.begin_data.encode('utf-8')),
    )
    begin_data = buffer + self.begin_data.encode('utf-8')
    self.client.publish(self.topic_to_base, begin_data)
  # 控制函数
  def control(self):
    self.on_mqtt_connect()
    self.publish_begin()
    begin_time = time.time()
    self.pub_time = time.time()
    self.subscribe()
    while True:
      time.sleep(1)
      # 超过5秒重传
      date = time.time() - self.pub_time
      if date > 5:
        # 是否重传第一个包
        if self.first == True:
          self.publish_begin()
          logging.info('+++ this is timeout first_data +++')
        # 是否重传最后一个包
        elif self.last == True:
          self.publish('finished', self.function_finished)
          logging.info('+++ this is timeout last_data +++')
        else:
          self.publish(self.index-1, self.function_doing)
          logging.info('+++ this is timeout middle_data +++')
      if self.finished == 1:
        logging.info('+++ all works is finished+++')
        break
    print(str(time.time()-begin_time) + 'begin_time - end_time')
app = Flask(__name__)
api = Api(app)
CORS(app, supports_credentials=True)
# 接受参数
parser = reqparse.RequestParser()
parser.add_argument('url', help='mqttImage url', location='args', type=str)
class GetImage(Resource):
  # 得到参数并从图床下载到本地
  def get(self):
    args = parser.parse_args()
    url = args.get('url')
    response = requests.get(url)
    # 获取图片
    image = Image.open(BytesIO(response.content))
    # 存取图片
    add = os.path.join(os.path.abspath(''), 'image.jpg')
    image.save(add)
    # 得到图片大小
    size = os.path.getsize(add)
    f = open(add, 'rb')
    imageData = f.read()
    f.close()
    # 进行mqtt传输
    mqtt = Mqtt(imageData, size)
    mqtt.control()
    # 删除文件
    os.remove(add)
    logging.info('*** the result of control is {} ***'.format(1))
    return jsonify({
      "imageData": 1
    })
api.add_resource(GetImage, '/image')
if __name__ == '__main__':
  app.run(debug=True, host='0.0.0.0')

总结

以上所述是小编给大家介绍的python使用MQTT给硬件传输图片的实现方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
Python实现的简单模板引擎功能示例
Sep 02 Python
Python获取指定文件夹下的文件名的方法
Feb 06 Python
对python中的乘法dot和对应分量相乘multiply详解
Nov 14 Python
python 字典 setdefault()和get()方法比较详解
Aug 07 Python
python实现简单成绩录入系统
Sep 19 Python
pandas中遍历dataframe的每一个元素的实现
Oct 23 Python
mac使用python识别图形验证码功能
Jan 10 Python
Python3 Tensorlfow:增加或者减小矩阵维度的实现
May 22 Python
使用python matploblib库绘制准确率,损失率折线图
Jun 16 Python
Python3爬虫中Ajax的用法
Jul 10 Python
基于Python的身份证验证识别和数据处理详解
Nov 14 Python
详解Django关于StreamingHttpResponse与FileResponse文件下载的最优方法
Jan 07 Python
Python实现的插入排序,冒泡排序,快速排序,选择排序算法示例
May 04 #Python
Python实现数据结构线性链表(单链表)算法示例
May 04 #Python
Python实现html转换为pdf报告(生成pdf报告)功能示例
May 04 #Python
Python实现将HTML转成PDF的方法分析
May 04 #Python
Python第三方库face_recognition在windows上的安装过程
May 03 #Python
Python人脸识别第三方库face_recognition接口说明文档
May 03 #Python
Python使用到第三方库PyMuPDF图片与pdf相互转换
May 03 #Python
You might like
php 论坛采集程序 模拟登陆,抓取页面 实现代码
2009/07/09 PHP
PHP动态柱状图实现方法
2015/03/30 PHP
在openSUSE42.1下编译安装PHP7 的方法
2015/12/24 PHP
PHP中include和require的区别实例分析
2017/05/07 PHP
javascript 字符串连接的性能问题(多浏览器)
2008/11/18 Javascript
Jquery实现图片左右自动滚动示例
2013/09/25 Javascript
ajax读取数据后使用jqchart显示图表的方法
2015/06/10 Javascript
vue获取当前激活路由的方法
2018/03/17 Javascript
jQuery滚动条美化插件nicescroll简单用法示例
2018/04/18 jQuery
详解使用element-ui table组件的筛选功能的一个小坑
2018/11/02 Javascript
微信jssdk逻辑在vue中的运用详解
2018/11/14 Javascript
深入理解Vue.js轻量高效的前端组件化方案
2018/12/10 Javascript
Three.js实现简单3D房间布局
2018/12/30 Javascript
AutoJs实现刷宝短视频的思路详解
2020/05/22 Javascript
vue-cli4.x创建企业级项目的方法步骤
2020/06/18 Javascript
在Vue中使用CSS3实现内容无缝滚动的示例代码
2020/11/27 Vue.js
[40:03]Liquid vs Optic 2018国际邀请赛淘汰赛BO3 第一场 8.21
2018/08/22 DOTA
详解Django之auth模块(用户认证)
2018/04/17 Python
python实现图片彩色转化为素描
2019/01/15 Python
Python学习笔记之图片人脸检测识别实例教程
2019/03/06 Python
Python操作rabbitMQ的示例代码
2019/03/19 Python
Python对HTML转义字符进行反转义的实现方法
2019/04/28 Python
python 使用递归回溯完美解决八皇后的问题
2020/02/26 Python
Python ATM功能实现代码实例
2020/03/19 Python
python基于socket函数实现端口扫描
2020/05/28 Python
python 实现控制鼠标键盘
2020/11/27 Python
世界上最全面的汽车零部件和配件集合:JC Whitney
2016/09/04 全球购物
商务日语毕业生自荐信范文
2013/11/14 职场文书
项目建议书范文
2014/05/12 职场文书
广播体操口号
2014/06/18 职场文书
环卫工人节活动总结
2014/08/29 职场文书
自我检讨书范文
2015/01/28 职场文书
《蜜蜂引路》教学反思
2016/02/22 职场文书
Redis延迟队列和分布式延迟队列的简答实现
2021/05/13 Redis
Linux安装apache服务器的配置过程
2021/11/27 Servers
MySQL数据库⾼可⽤HA实现小结
2022/01/22 MySQL