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获得时间的实例说明
Mar 25 Python
python实现简单的TCP代理服务器
Oct 08 Python
Python实现的数据结构与算法之基本搜索详解
Apr 22 Python
Python实现在tkinter中使用matplotlib绘制图形的方法示例
Jan 18 Python
python实现点对点聊天程序
Jul 28 Python
pygame实现简易飞机大战
Sep 11 Python
Python3实现定时任务的四种方式
Jun 03 Python
Django用户认证系统 组与权限解析
Aug 02 Python
numpy.array 操作使用简单总结
Nov 08 Python
python实现将一维列表转换为多维列表(numpy+reshape)
Nov 29 Python
在tensorflow中实现去除不足一个batch的数据
Jan 20 Python
python线程join方法原理解析
Feb 11 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学习 字符串课件
2008/06/15 PHP
PHP中uploaded_files函数使用方法详解
2011/03/09 PHP
phplist及phpmailer(组合使用)通过gmail发送邮件的配置方法
2016/03/30 PHP
php 实现Hash表功能实例详解
2016/11/29 PHP
PHP标准库 (SPL)――Countable用法示例
2020/06/05 PHP
Javascript-Mozilla和IE中的一个函数直接量的问题
2007/01/09 Javascript
jQuery拖动图片删除示例
2013/05/10 Javascript
常见浏览器多长时间会提示“脚本运行时间过长”总结
2014/04/29 Javascript
JavaScript用Number方法实现string转int
2014/05/13 Javascript
JS+DIV实现的卷帘效果示例
2017/03/22 Javascript
JavaScript制作简单的框选图表
2017/05/15 Javascript
JavaScript创建对象_动力节点Java学院整理
2017/06/27 Javascript
JavaScript实现简单的双色球(实例讲解)
2017/07/31 Javascript
LayUi中接口传数据成功,表格不显示数据的解决方法
2018/08/19 Javascript
微信小程序实现banner图轮播效果
2020/06/28 Javascript
vue点击当前路由高亮小案例
2019/09/26 Javascript
vue 全局环境切换问题
2019/10/27 Javascript
js实现淘宝浏览商品放大镜功能
2020/10/28 Javascript
element-plus一个vue3.xUI框架(element-ui的3.x 版初体验)
2020/12/02 Vue.js
[26:24]完美副总裁、DOTA2负责人蔡玮专访:电竞如人生
2014/09/11 DOTA
浅谈python中的占位符
2017/11/09 Python
python中文分词,使用结巴分词对python进行分词(实例讲解)
2017/11/14 Python
Python 在字符串中加入变量的实例讲解
2018/05/02 Python
Python Numpy:找到list中的np.nan值方法
2018/10/30 Python
利用Python如何实现一个小说网站雏形
2018/11/23 Python
Appium+Python自动化测试之运行App程序示例
2019/01/23 Python
Ranorex通过Python将报告发送到邮箱的方法
2020/01/12 Python
python相对企业语言优势在哪
2020/06/12 Python
如何利用Python动态模拟太阳系运转
2020/09/04 Python
python时间time模块处理大全
2020/10/25 Python
python基于selenium爬取斗鱼弹幕
2021/02/20 Python
html5模拟平抛运动(模拟小球平抛运动过程)
2013/07/25 HTML / CSS
Linux文件操作命令都有哪些
2015/02/27 面试题
婚内分居协议书范文
2014/11/26 职场文书
音乐教师求职信范文
2015/03/20 职场文书
python实现高效的遗传算法
2021/04/07 Python