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的内存泄漏及gc模块的使用分析
Jul 16 Python
python cx_Oracle模块的安装和使用详细介绍
Feb 13 Python
Python 实现随机数详解及实例代码
Apr 15 Python
Python实现随机生成有效手机号码及身份证功能示例
Jun 05 Python
python kmeans聚类简单介绍和实现代码
Feb 23 Python
Python获取系统所有进程PID及进程名称的方法示例
May 24 Python
python实现全盘扫描搜索功能的方法
Feb 14 Python
8段用于数据清洗Python代码(小结)
Oct 31 Python
Python中低维数组填充高维数组的实现
Dec 02 Python
PyTorch的自适应池化Adaptive Pooling实例
Jan 03 Python
Python使用Matlab命令过程解析
Jun 04 Python
带你学习Python如何实现回归树模型
Jul 16 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程序中的常见漏洞进行攻击(下)
2006/10/09 PHP
destoon常用的安全设置概述
2014/06/21 PHP
php日期操作技巧小结
2016/06/25 PHP
PHP重定向与伪静态区别
2017/02/19 PHP
PHP利用正则表达式将相对路径转成绝对路径的方法示例
2017/02/28 PHP
详解Laravel5.6 Passport实现Api接口认证
2018/07/27 PHP
在IE和VB中支持png图片透明效果的实现方法(vb源码打包)
2011/04/01 Javascript
js点击页面其它地方将某个显示的DIV隐藏
2012/07/12 Javascript
面向对象继承实例(a如何继承b问题)(自写)
2013/07/01 Javascript
使用简洁的jQuery方法实现隔行换色功能
2014/01/02 Javascript
jQuery获取和设置表单元素的方法
2014/02/14 Javascript
js中将String转换为number以便比较
2014/07/08 Javascript
分析了一下JQuery中的extend方法实现原理
2015/02/27 Javascript
Javascript发送AJAX请求实例代码
2016/08/21 Javascript
在vue项目中集成graphql(vue-ApolloClient)
2018/09/08 Javascript
用云开发Cloudbase实现小程序多图片内容安全监测的代码详解
2020/06/07 Javascript
详细分析vue响应式原理
2020/06/22 Javascript
vue如何在项目中调用腾讯云的滑动验证码
2020/07/15 Javascript
VsCode里的Vue模板的实现
2020/08/12 Javascript
列举Python中吸引人的一些特性
2015/04/09 Python
Python实现比较两个列表(list)范围
2015/06/12 Python
解决python2.7用pip安装包时出现错误的问题
2017/01/23 Python
基于Python对象引用、可变性和垃圾回收详解
2017/08/21 Python
Python 解决中文写入Excel时抛异常的问题
2018/05/03 Python
Django 对象关系映射(ORM)源码详解
2019/08/06 Python
Python zip函数打包元素实例解析
2019/12/11 Python
Tensorflow之梯度裁剪的实现示例
2020/03/08 Python
python让函数不返回结果的方法
2020/06/22 Python
html5 Canvas画图教程(1)—画图的基本常识
2013/01/09 HTML / CSS
顶级宝石首饰网络零售商:Angara
2016/10/25 全球购物
用友笔试题目
2016/10/25 面试题
出口公司经理求职简历中的自我评价
2013/10/13 职场文书
大课间活动实施方案
2014/03/06 职场文书
2014年收银工作总结
2014/11/13 职场文书
行政处罚决定书
2015/06/24 职场文书
熟背这些句子,让您的英语口语突飞猛进(135句)
2019/09/06 职场文书