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 相关文章推荐
python3 实现的人人影视网站自动签到
Jun 19 Python
python实现数据预处理之填充缺失值的示例
Dec 22 Python
用python简单实现mysql数据同步到ElasticSearch的教程
May 30 Python
pandas表连接 索引上的合并方法
Jun 08 Python
python 读写文件,按行修改文件的方法
Jul 12 Python
Python http接口自动化测试框架实现方法示例
Dec 06 Python
6行Python代码实现进度条效果(Progress、tqdm、alive-progress​​​​​​​和PySimpleGUI库)
Jan 06 Python
python add_argument()用法解析
Jan 29 Python
matplotlib.pyplot.plot()参数使用详解
Jul 28 Python
Python 捕获代码中所有异常的方法
Aug 03 Python
详解python中的闭包
Sep 07 Python
基于OpenCV的网络实时视频流传输的实现
Nov 15 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 IP转换整形(ip2long)的详解
2013/06/06 PHP
CodeIgniter分页类pagination使用方法示例
2016/03/28 PHP
js停止输出代码
2008/07/20 Javascript
jQuery表单验证插件formValidator(改进版)
2012/02/03 Javascript
jQuery之end()和pushStack()使用介绍
2012/02/07 Javascript
jQuery中$.fn的用法示例介绍
2013/11/05 Javascript
不用一句js代码初始化组件
2016/01/27 Javascript
AngularJS中使用ngModal模态框实例
2017/05/27 Javascript
JavaScript 中调用 Kotlin 方法实例详解
2017/06/09 Javascript
基于 webpack2 实现的多入口项目脚手架详解
2017/06/26 Javascript
vue-quill-editor实现图片上传功能
2017/08/08 Javascript
浅谈es6语法 (Proxy和Reflect的对比)
2017/10/24 Javascript
判断div滑动到底部的scroll实例代码
2017/11/15 Javascript
Vue 将后台传过来的带html字段的字符串转换为 HTML
2018/03/29 Javascript
node使用Mongoose类库实现简单的增删改查
2018/11/08 Javascript
vue遍历生成的输入框 绑定及修改值示例
2019/10/30 Javascript
jdk1.8+vue elementui实现多级菜单功能
2020/09/24 Javascript
使用memory_profiler监测python代码运行时内存消耗方法
2018/12/03 Python
Python面向对象程序设计中类的定义、实例化、封装及私有变量/方法详解
2019/02/28 Python
Python使用Beautiful Soup爬取豆瓣音乐排行榜过程解析
2019/08/15 Python
python爬虫库scrapy简单使用实例详解
2020/02/10 Python
HTML5 解析规则分析
2009/08/14 HTML / CSS
GNC健安喜官方海外旗舰店:美国著名保健品牌
2017/01/04 全球购物
新西兰领先的内衣店:Bendon Lingerie新西兰
2018/07/11 全球购物
技校生自我鉴定范文
2013/09/26 职场文书
求职信写作要突出重点
2014/01/01 职场文书
光信息科学与技术专业职业生涯规划
2014/03/13 职场文书
团代会主持词
2014/04/02 职场文书
“向国旗敬礼”主题班会活动设计方案
2014/09/27 职场文书
幼儿园个人师德总结
2015/02/06 职场文书
2015年消费者权益日活动总结
2015/02/09 职场文书
个人优缺点总结
2015/02/28 职场文书
幼儿园教师工作总结2015
2015/04/02 职场文书
学历证明范文
2015/06/16 职场文书
田径运动会通讯稿
2015/07/18 职场文书
简述python四种分词工具,盘点哪个更好用?
2021/04/13 Python