[关闭]
@richey 2021-09-30T03:14:46.000000Z 字数 24113 阅读 5327

第三章 物联网创新设计综合实践

物联网创新设计实践 讲义

3 物联网创新设计实践

3.1 物联网创新实践综合项目

3.1.1 分组安排

image.png-79.9kB
image.png-204kB

3.1.2 题目串讲

3.2 python语言基础

3.2.1 python3语言基础及其开发环境安装

如图,证明python3.7已经安装完成。
- 下载并安装pycharm 社区版
https://www.jetbrains.com/pycharm/download/#section=windows
image.png-122.1kB
image.png-30.9kB
- 最简单的python程序

  1. # coding=utf8
  2. print "hello world!\r\n"

3.2.2 语法

3.2.2.1 缩进(严格缩进4个空格)

  1. def fun1():
  2. print("你好!\r\n")
  3. fun1()

3.2.2.2 数据结构及数据类型

-list列表

  1. def fun1():
  2. print ("你好!\r\n")
  3. fun1()
  4. l=[1,2,5,6,8]
  5. print(l)
  6. print (l[3])
  7. for item in l:
  8. print (item)

-元组
ython的元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,列表使用方括号。

  1. tup1 = ('physics', 'chemistry', 1997, 2000);
  2. tup2 = (1, 2, 3, 4, 5 );
  3. tup3 = "a", "b", "c", "d";
  4. print (tup1)
  5. print (tup2)
  6. print (tup3)

-字典dict

  1. bdict = {'name':'allen', 'age':'40'}
  2. for key in bdict.keys():
  3. print (key)
  4. print (bdict[key])

3.2.2.3 if、for、while、break

3.3 物联网应用服务器端软件设计

3.3.1 twisted异步网络通信库

3.3.1.1 介绍

参考:http://blog.csdn.net/hanhuili/article/details/9389433
Twisted是用Python实现的基于事件驱动的网络引擎框架。Twisted支持许多常见的传输及应用层协议,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。Twisted对于其支持的所有协议都带有客户端和服务器实现,同时附带有基于命令行的工具,使得配置和部署产品级的Twisted应用变得非常方便。
twisted技术架构.jpg-56.3kB

3.3.1.2 Reactor

Reactor是事件管理器,用于注册、注销事件,运行事件循环,当事件发生时调用回调函数处理。Reactor可以感知网络、文件系统以及定时器事件。它等待然后处理这些事件,从特定于平台的行为中抽象出来,并提供统一的接口,使得在网络协议栈的任何位置对事件做出响应都变得简单。
关于reactor有下面几个结论:
Twisted的reactor只有通过调用reactor.run()来启动。
reactor循环是在其开始的进程中运行,也就是运行在主进程中。
一旦启动,就会一直运行下去。reactor就会在程序的控制下(或者具体在一个启动它的线程的控制下)。reactor循环并不会消耗任何CPU的资源。并不需要显式的创建reactor,只需要引入就OK了。

3.3.1.3 Transports

Transports代表网络中两个通信结点之间的连接。Transports负责描述连接的细节,比如连接是面向流式的还是面向数据报的,流控以及可靠性。TCP、UDP和Unix套接字可作为transports的例子。它们被设计为“满足最小功能单元,同时具有最大程度的可复用性”,而且从协议实现中分离出来,这让许多协议可以采用相同类型的传输。Transports实现了ITransports接口,它包含如下的方法:
write 以非阻塞的方式按顺序依次将数据写到物理连接上
writeSequence 将一个字符串列表写到物理连接上
loseConnection 将所有挂起的数据写入,然后关闭连接
getPeer 取得连接中对端的地址信息
getHost 取得连接中本端的地址信息
将transports从协议中分离出来也使得对这两个层次的测试变得更加简单。可以通过简单地写入一个字符串来模拟传输,用这种方式来检查。

3.3.1.4 Protocols

Protocols描述了如何以异步的方式处理网络中的事件。HTTP、DNS以及IMAP是应用层协议中的例子。Protocols实现了IProtocol接口,它包含如下的方法:
makeConnection 在transport对象和服务器之间建立一条连接
connectionMade 连接建立起来后调用
dataReceived 接收数据时调用
connectionLost 关闭连接时调用

3.3.1.5 Factory

切确的说,它取名不太好,应该叫做FactoryOfProtocals,即协议工厂(也就是工厂模式),用来管理协议对象实例的。

3.3.2 串口收发数据范例

  1. # coding=utf8
  2. import sys
  3. import re
  4. if sys.platform == 'win32':
  5. from twisted.internet import win32eventreactor
  6. win32eventreactor.install()
  7. from twisted.internet import defer, threads
  8. from twisted.internet.serialport import SerialPort
  9. from twisted.internet import protocol,task, reactor, error
  10. from twisted.protocols.basic import LineReceiver
  11. from twisted.python import log, usage
  12. class GasSim(LineReceiver):
  13. def __init__(self):
  14. self._lc1 = task.LoopingCall(self.sendCmd)
  15. self._lc1.start(3,False)
  16. def sendCmd(self):
  17. self.sendLine("@01c100001".encode('utf-8'))
  18. def lineReceived(self, line):
  19. line = line.decode('utf-8')
  20. print(line)
  21. if(re.match('@\d{2}\D\w{4}\d{2}',line)):
  22. if(line[3] == 'D'):
  23. print (u'接收到1条命令!\r\n')
  24. tmpstr = "当前电压值=%.3f" % (int(line[4:8],16)/1000.0)
  25. print (tmpstr)
  26. if __name__ == '__main__':
  27. s = SerialPort(GasSim(), 'COM5', reactor, baudrate=9600)
  28. reactor.run()

3.3.3 socket网络数据通信基础

本小节已经合并到下一小节

3.3.4 网络通信程序及数据库读写

3.3.4.1 redis key/value数据库

安装redis,直接解压运行即可。
image.png-193kB

3.3.4.1.1 启动redis服务(运行exe文件即可)

image.png-277.1kB

3.3.4.1.2 redis数据库讲解
3.3.4.1.3 要点讲解

  1. # coding: utf-8
  2. import re
  3. import datetime
  4. import time
  5. import json
  6. import redis
  7. from twisted.internet import reactor, task, protocol
  8. from twisted.internet import defer, threads
  9. from twisted.internet.protocol import Protocol, error, Factory
  10. from twisted.protocols.basic import LineReceiver
  11. r = redis.Redis(host='127.0.0.1',port=6379,db=0)
  12. def getCurrentStrTime():
  13. return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
  14. class GasServerProtocol(LineReceiver):
  15. def __init__(self, factory):
  16. self.id = ''
  17. self.factory = factory
  18. def connectionMade(self):
  19. print((
  20. "[%s]: %s连接到服务器端。" %
  21. (getCurrentStrTime(), self.transport.getPeer())))
  22. self.sendLine("$99'".encode('utf-8'))
  23. def connectionLost(self, reason):
  24. if self.id in self.factory.clients:
  25. del self.factory.clients[self.id]
  26. print("[%s]:ID %s 下线" % (getCurrentStrTime(), self.id))
  27. print((
  28. "[%s]: %s断开了连接,原因是%s" %
  29. (getCurrentStrTime(),
  30. self.transport.getPeer(),
  31. reason)))
  32. def lineReceived(self, data):
  33. data = data.decode('utf-8')
  34. tmpstr = ("[%s]: 收到数据 %s") % (getCurrentStrTime(), data)
  35. print(tmpstr)
  36. if(re.match("\$\d{2}\$", data)):
  37. self.id = str(data[1:3])
  38. dicttmp = {}
  39. dicttmp['handle'] = self
  40. dicttmp['timestamp'] = time.time()
  41. self.factory.clients[self.id] = dicttmp
  42. print("[%s]:ID %s 注册成功" % (getCurrentStrTime(), self.id))
  43. if(re.match('@\d{2}\D\w{4}\d{2}',data)):
  44. if(data[3] == 'D'):
  45. print('接收到1条命令!\r\n')
  46. volttmp = (int(data[4:8],16)/1000.0)
  47. tmpstr = "当前电压值=%.3f" % volttmp
  48. print(tmpstr)
  49. dicttmp = {}
  50. dicttmp['collecttime'] = getCurrentStrTime()
  51. dicttmp['volt'] = volttmp
  52. dicttmp['id'] = self.id
  53. r.set(self.id, json.dumps(dicttmp))
  54. print(r.get(self.id))
  55. class GasServerFactory(Factory):
  56. def __init__(self):
  57. self.clients = {} # maps clients ids to GasServerProtocol instances
  58. self._lc = task.LoopingCall(self.send_to_clients)
  59. self._lc.start(3,now=False)
  60. def buildProtocol(self, addr):
  61. return GasServerProtocol(self)
  62. def send_to_clients(self):
  63. for client_addr in self.clients :
  64. self.clients[client_addr]['handle'].sendLine('hello!'.encode('utf-8'))
  65. def startMoniter():
  66. print("[%s]启动监控服务" % getCurrentStrTime())
  67. cf = GasServerFactory()
  68. reactor.listenTCP(8234, cf)
  69. reactor.run()
  70. def stopMoniter():
  71. print("[%s]停止监控服务" % getCurrentStrTime())
  72. try:
  73. reactor.crash()
  74. except RuntimeError:
  75. return defer.fail()
  76. else:
  77. return defer.succeed(None)
  78. startMoniter()

image_1butgll69iv91ega1ss81n1otp2p.png-21.6kB
image_1butgo936730t37dgg1en5gdj39.png-6.3kB
无标题.png-162.7kB
image_1butgg3mm5mn1gpcccu1esl1b0ps.png-42.1kB

3.3.5 RESTful API接口后端软件

  1. # coding=utf-8
  2. from flask import render_template, request, redirect
  3. from flask import abort,jsonify,url_for,render_template, request, redirect
  4. from flask_cors import CORS
  5. import json
  6. import redis
  7. from flask import Flask
  8. import datetime
  9. from flask_cors import CORS
  10. app = Flask(__name__)
  11. CORS(app)
  12. r = redis.Redis(host='127.0.0.1', port=6379, db=0)
  13. @app.route('/')
  14. def hello_world():
  15. return '你好!'
  16. @app.route('/voltage')
  17. def get_voltage():
  18. id = request.args.get('id', '')
  19. if id:
  20. json_data = r.get(id)
  21. if json_data:
  22. return jsonify(json.loads(json_data))
  23. return 'no data!'
  24. return 'no id!'
  25. if __name__ == '__main__':
  26. app.run(host='0.0.0.0', port=int("5000"))

111.png-198.9kB

3.3.6 mysql 关系数据库

3.3.6.1 新建数据库

3.3.6.2 新建表

  1. CREATE TABLE `device` (
  2. `Id` int(11) NOT NULL AUTO_INCREMENT,
  3. `device_id` varchar(64) DEFAULT NULL,
  4. `name` varchar(255) DEFAULT NULL,
  5. PRIMARY KEY (`Id`),
  6. KEY `device_id` (`device_id`)
  7. ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  8. CREATE TABLE `iot_history_data` (
  9. `Id` int(11) NOT NULL AUTO_INCREMENT,
  10. `device_id` varchar(64) DEFAULT NULL,
  11. `collect_time` datetime DEFAULT NULL,
  12. `temperature` float DEFAULT NULL,
  13. `humidity` float DEFAULT NULL,
  14. `voltage` float DEFAULT NULL,
  15. PRIMARY KEY (`Id`),
  16. UNIQUE KEY `device_id` (`device_id`,`collect_time`)
  17. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
  18. #
  19. CREATE TABLE `iot_realtime_data` (
  20. `Id` int(11) NOT NULL AUTO_INCREMENT,
  21. `device_id` varchar(64) DEFAULT NULL,
  22. `collect_time` datetime DEFAULT NULL,
  23. `temperature` float DEFAULT NULL,
  24. `humidity` float DEFAULT NULL,
  25. `voltage` float DEFAULT NULL,
  26. PRIMARY KEY (`Id`)
  27. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  28. CREATE TABLE `position` (
  29. `Id` int(11) NOT NULL AUTO_INCREMENT,
  30. `device_id` varchar(255) DEFAULT NULL,
  31. `longitude` varchar(255) DEFAULT NULL,
  32. `latitude` varchar(255) DEFAULT NULL,
  33. `collect_time` datetime DEFAULT NULL,
  34. PRIMARY KEY (`Id`)
  35. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

3.3.6.3 操作mysql数据库

-增加功能
在现有功能基础上,每5分钟将数据存入iot的iot_history_data表中

  1. # coding=utf8
  2. #testNet.py
  3. import re
  4. import time
  5. import json
  6. import redis
  7. from datetime import datetime
  8. from twisted.internet import reactor, task, protocol
  9. from twisted.internet import defer, threads
  10. from twisted.internet.protocol import Protocol, error, Factory
  11. from twisted.protocols.basic import LineReceiver
  12. from dbhelper import insert_iot_record
  13. r = redis.Redis(host='127.0.0.1',port=6379,db=0)
  14. def getCurrentStrTime():
  15. return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
  16. class GasServerProtocol(LineReceiver):
  17. def __init__(self, factory):
  18. self.id = ''
  19. self.factory = factory
  20. self.last_iot_time = datetime.now()
  21. self.fisrt_recv_flag = True
  22. def connectionMade(self):
  23. print(
  24. "[%s]: %s连接到服务器端。" %
  25. (getCurrentStrTime(), self.transport.getPeer()))
  26. self.sendLine("$99'".encode('utf-8'))
  27. def connectionLost(self, reason):
  28. if self.id in self.factory.clients:
  29. del self.factory.clients[self.id]
  30. print ("[%s]:ID %s 下线" % (getCurrentStrTime(), self.id))
  31. print(
  32. "[%s]: %s断开了连接,原因是%s" %
  33. (getCurrentStrTime(),
  34. self.transport.getPeer(),
  35. reason))
  36. def insert_iot_record_cb(self, result):
  37. print (result)
  38. self.last_iot_time = datetime.now()
  39. self.fisrt_recv_flag = False
  40. def lineReceived(self, data):
  41. data = data.decode('utf-8')
  42. tmpstr = ("[%s]: 收到数据 %s") % (getCurrentStrTime(), data)
  43. print (tmpstr)
  44. if(re.match("\$\d{2}\$", data)):
  45. self.id = str(data[1:3])
  46. dicttmp = {}
  47. dicttmp['handle'] = self
  48. dicttmp['timestamp'] = time.time()
  49. self.factory.clients[self.id] = dicttmp
  50. print ("[%s]:ID %s 注册成功" % (getCurrentStrTime(), self.id))
  51. if(re.match('@\d{2}\D\w{12}\d{2}',data)):
  52. if(data[3] == 'D'):
  53. print (u'接收到1条命令!\r\n')
  54. volttmp = (int(data[4:8],16)/1000.0)
  55. temperature = (int(data[8:12],16)/10.0)
  56. humidity = (int(data[12:16],16)/10.0)
  57. dicttmp = {}
  58. dicttmp['collecttime'] = getCurrentStrTime()
  59. dicttmp['voltage'] = volttmp
  60. dicttmp['temperature'] = temperature
  61. dicttmp['humidity'] = humidity
  62. dicttmp['id'] = self.id
  63. r.set(self.id, json.dumps(dicttmp))
  64. print (r.get(self.id))
  65. current_time = datetime.now()
  66. if((current_time - self.last_iot_time).seconds >= 5 * 60 or self.fisrt_recv_flag):
  67. insert_iot_record( r.get(self.id)).addCallback(
  68. self.insert_iot_record_cb)
  69. class GasServerFactory(Factory):
  70. def __init__(self):
  71. self.clients = {} # maps clients ids to GasServerProtocol instances
  72. self._lc = task.LoopingCall(self.send_to_clients)
  73. self._lc.start(3,now=False)
  74. def buildProtocol(self, addr):
  75. return GasServerProtocol(self)
  76. def send_to_clients(self):
  77. for client_addr in self.clients :
  78. self.clients[client_addr]['handle'].sendLine('hello!'.encode('utf-8'))
  79. def startMoniter():
  80. print ("[%s]启动监控服务" % getCurrentStrTime())
  81. cf = GasServerFactory()
  82. reactor.listenTCP(8235, cf)
  83. reactor.run()
  84. def stopMoniter():
  85. print ("[%s]停止监控服务" % getCurrentStrTime())
  86. try:
  87. reactor.crash()
  88. except RuntimeError:
  89. return defer.fail()
  90. else:
  91. return defer.succeed(None)
  92. startMoniter()
  1. # coding=utf-8
  2. # dbhelper.py
  3. from flask_sqlalchemy import SQLAlchemy
  4. from twisted.enterprise import adbapi
  5. import binascii
  6. import decimal
  7. import datetime
  8. import MySQLdb
  9. import json
  10. db_conn = 'MySQLdb'
  11. db_user = 'root'
  12. db_pass = 'root'
  13. db_host = '127.0.0.1'
  14. db_database = 'iot'
  15. dbpool = adbapi.ConnectionPool(
  16. db_conn,
  17. host=db_host,
  18. user=db_user,
  19. passwd=db_pass,
  20. db=db_database,
  21. charset='utf8',
  22. cp_reconnect=True)
  23. def _insert_iot_record(trans, record):
  24. iot_dict = json.loads(record) # 根据字符串书写格式,将字符串自动转换成 字典类型
  25. print (iot_dict)
  26. try:
  27. sql = 'insert into iot_history_data (device_id,voltage,humidity,temperature,collect_time)'+\
  28. ' values(\'%s\',\'%6.2f\',\'%6.2f\',\'%6.2f\',\'%s\')' % (
  29. iot_dict['id'], iot_dict['voltage'], iot_dict['humidity'], iot_dict['temperature'], iot_dict['collecttime'])
  30. print (sql)
  31. result = trans.execute(sql)
  32. return 'True'
  33. except:
  34. return 'False'
  35. def insert_iot_record(record):
  36. return dbpool.runInteraction(_insert_iot_record, record)

image.png-125.2kB

image.png-122.2kB

image.png-194.8kB

3.4 物联网应用移动端软件设计

3.4.1 打包下载:云盘webapp目录

3.4.2.安装node.js、npm及sublime text3

3.4.3 安装vue的UI框架vux

用sublime打开工程文件夹,讲解文件结构
image_1buv64h5ug2d1s3vq5fnea19co9.png-216.1kB

3.4.4 iconfont图标库

3.4.5 webapp设计

  1. // The Vue build version to load with the `import` command
  2. // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
  3. import Vue from 'vue'
  4. import FastClick from 'fastclick'
  5. import VueRouter from 'vue-router'
  6. import App from './App'
  7. import Home from './components/HelloFromVux'
  8. import { AjaxPlugin } from 'vux'
  9. Vue.use(AjaxPlugin)
  10. //this.$http.defaults.baseURL = '127.0.0.1:5000';
  11. Vue.use(VueRouter)
  12. const routes = [{
  13. path: '/',
  14. component: Home
  15. }]
  16. const router = new VueRouter({
  17. routes
  18. })
  19. FastClick.attach(document.body)
  20. Vue.config.productionTip = false
  21. /* eslint-disable no-new */
  22. new Vue({
  23. router,
  24. render: h => h(App)
  25. }).$mount('#app-box')
  1. <template>
  2. <div>
  3. <x-header class="header" :left-options="{showBack: false}">
  4. 物联网应用系统
  5. </x-header>
  6. <divider>
  7. 实时数据
  8. </divider>
  9. <grid>
  10. <grid-item >
  11. <ul class="grid">
  12. <li
  13. <span class="grid-iot-icon" slot="icon" >&#xe604;</span>
  14. </li>
  15. <li class = "grid-text1">气温(℃)</li>
  16. <li class = "grid-text2"> {{my_data.temperature}}</li>
  17. </ul>
  18. </grid-item>
  19. <grid-item >
  20. <ul class="grid">
  21. <li
  22. <span class="grid-iot-icon" slot="icon" >&#xe63d;</span>
  23. </li>
  24. <li class = "grid-text1">湿度(%)</li>
  25. <li class = "grid-text2"> {{my_data.humidity}}</li>
  26. </ul>
  27. </grid-item>
  28. <grid-item >
  29. <ul class="grid">
  30. <li
  31. <span class="grid-iot-icon" slot="icon" >&#xe646;</span>
  32. </li>
  33. <li class = "grid-text1">电压(V)</li>
  34. <li class = "grid-text2"> {{my_data.voltage}}</li>
  35. </ul>
  36. </grid-item>
  37. </grid>
  38. </div>
  39. </template>
  40. <script>
  41. import { Group, Cell,Divider,XHeader,Flexbox,FlexboxItem,Grid, GridItem } from 'vux'
  42. export default {
  43. components: {
  44. Group,
  45. Cell,
  46. Divider,
  47. XHeader,
  48. Flexbox,
  49. FlexboxItem,
  50. Grid,
  51. GridItem
  52. },
  53. data () {
  54. return {
  55. // note: changing this line won't causes changes
  56. // with hot-reload because the reloaded component
  57. // preserves its current state and we are modifying
  58. // its initial state.
  59. msg: 'Hello World!',
  60. my_data:[],
  61. }
  62. },
  63. mounted() {
  64. this.getData();
  65. this.timerGetData = setInterval(this.getData, 3000);
  66. },
  67. beforeDestroy() {
  68. clearInterval(this.timerGetData)
  69. },
  70. methods: {
  71. getData() {
  72. this.$http({
  73. url: 'http://127.0.0.1:5000/voltage?id=12',
  74. method: 'GET',
  75. })
  76. .then((res) => {
  77. this.my_data = res.data;
  78. console.log('success ');
  79. }, (res) => {
  80. console.log('error ');
  81. });
  82. },
  83. }
  84. }
  85. </script>
  86. <style>
  87. .vux-demo {
  88. text-align: center;
  89. }
  90. .logo {
  91. width: 100px;
  92. height: 100px
  93. }
  94. .grid-iot-icon {
  95. font-family: 'iot';
  96. font-size: 32px;
  97. color: @theme-color;
  98. text-align: center;
  99. }
  100. .grid-text1 {
  101. text-align: center;
  102. color: grey;
  103. list-style-type:none;
  104. font-size: 18px;
  105. }
  106. .grid-text2 {
  107. text-align: center;
  108. color: black;
  109. list-style-type:none;
  110. font-size: 22px;
  111. }
  112. .grid {
  113. font-size: 22px;
  114. text-align: center;
  115. background-color: white;
  116. list-style-type:none;
  117. }
  118. .header {
  119. background-color: @theme-color;
  120. }
  121. </style>

3.4.6 底部tabbar及百度地图的实现

3.4.6.1底部导航tabbar

  1. <template>
  2. <div>
  3. <tabbar style="position:fixed" slot="bottom">
  4. <tabbar-item link="/">
  5. <span class="iot-icon-title" slot="icon">&#xe7a4;</span>
  6. <span class="iot-text-title" slot="label">首页</span>
  7. </tabbar-item>
  8. <tabbar-item link="/map">
  9. <span class="iot-icon-title" slot="icon">&#xe602;</span>
  10. <span class="iot-text-title" slot="label">监控</span>
  11. </tabbar-item>
  12. <tabbar-item link="home">
  13. <span class="iot-icon-title1" slot="icon">&#xe68d;</span>
  14. <span class="iot-text-title" slot="label">查询</span>
  15. </tabbar-item>
  16. <tabbar-item >
  17. <span class="iot-icon-title" slot="icon">&#xe637;</span>
  18. <span class="iot-text-title" slot="label">设置</span>
  19. </tabbar-item>
  20. </tabbar>
  21. </div>
  22. </template>
  23. <script>
  24. import { Tabbar, TabbarItem } from 'vux'
  25. export default {
  26. ready () {
  27. document.querySelector('body').style.height = '100%'
  28. document.querySelector('html').style.height = '100%'
  29. document.querySelector('#app').style.height = '100%'
  30. },
  31. components: {
  32. Tabbar,
  33. TabbarItem
  34. }
  35. }
  36. </script>
  37. <style lang="less">
  38. .iot-tabbar {
  39. position: fixed;
  40. }
  41. .iot-icon-title {
  42. font-family: 'iot';
  43. font-size: 32px;
  44. line-height: 30px;
  45. }
  46. .iot-icon-title1 {
  47. font-family: 'iot';
  48. font-size: 28px;
  49. line-height: 32px;
  50. }
  51. .iot-text-title {
  52. font-size: 14px;
  53. line-height: 28px;
  54. }
  55. </style>

3.4.6.2 百度地图

  1. <template>
  2. <div>
  3. <div style="height: 10%; overflow: auto;">
  4. <h3>Simple map</h3>
  5. Marker is placed at {{ marker.lat }}, {{ marker.lng }}
  6. </div>
  7. <v-map style="height: 90%" :zoom="zoom" :center="center">
  8. <v-tilelayer :url="url" :attribution="attribution"></v-tilelayer>
  9. <v-marker :lat-lng="marker"></v-marker>
  10. </v-map>
  11. </div>
  12. </template>
  13. <script>
  14. import Vue2Leaflet from 'vue2-leaflet';
  15. export default {
  16. components: {
  17. 'v-map': Vue2Leaflet.Map,
  18. 'v-tilelayer' :Vue2Leaflet.TileLayer,
  19. 'v-marker': Vue2Leaflet.Marker
  20. },
  21. data () {
  22. return {
  23. zoom:13,
  24. center: L.latLng(47.413220, -1.219482),
  25. url:'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
  26. attribution:'&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
  27. marker: L.latLng(47.413220, -1.219482),
  28. }
  29. }
  30. }
  31. </script>
  1. // The Vue build version to load with the `import` command
  2. // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
  3. import Vue from 'vue'
  4. import FastClick from 'fastclick'
  5. import VueRouter from 'vue-router'
  6. import App from './App'
  7. import Home from './components/HelloFromVux'
  8. import Hello from './components/Hello'
  9. import Map from './components/BMap'
  10. import BaiduMap from 'vue-baidu-map'
  11. Vue.use(BaiduMap, {
  12. // ak 是在百度地图开发者平台申请的密钥 详见 http://lbsyun.baidu.com/apiconsole/key */
  13. ak: 'YOUR_APP_KEY'
  14. })
  15. import { AjaxPlugin } from 'vux'
  16. Vue.use(AjaxPlugin)
  17. //this.$http.defaults.baseURL = '127.0.0.1:5000';
  18. Vue.use(VueRouter)
  19. const routes = [{
  20. path: '/',
  21. name: 'default',
  22. component: Home
  23. },{
  24. path: '/map',
  25. component: Map
  26. },{
  27. path: '*',
  28. redirect: { name: 'default' },
  29. }
  30. ]
  31. const router = new VueRouter({
  32. hashbang: false,
  33. linkActiveClass: 'active',
  34. mode: 'history',
  35. base: __dirname,
  36. routes
  37. })
  38. FastClick.attach(document.body)
  39. /* eslint-disable no-new */
  40. new Vue({
  41. router,
  42. render: h => h(App)
  43. }).$mount('#app-box')

image_1bvcqignm1vkkd7g199910ks1t3n13.png-291.8kB

3.5 手机端反向控制单片机的设计与实现

3.5.1 复习如何从单片机读取数据?

3.5.2 如何从手机反向控制单片机?

3.5.3 flask进程

  1. #testFlask.py
  2. # coding=utf-8
  3. from flask import render_template, request, redirect
  4. from flask import abort,jsonify,url_for,render_template, request, redirect
  5. from flask_cors import CORS, cross_origin
  6. from flask_restless import APIManager
  7. import json
  8. import redis
  9. from flask import Flask
  10. import datetime
  11. from flask_cors import CORS
  12. from flask_sqlalchemy import SQLAlchemy
  13. from database import db
  14. from application import app
  15. from models import IotHistoryData,Position
  16. r = redis.Redis(host='127.0.0.1', port=6379, db=0)
  17. apimanager = APIManager(app, flask_sqlalchemy_db=db)
  18. apimanager.create_api(IotHistoryData,
  19. methods=['GET'],
  20. # url_prefix='/api/v1',
  21. # preprocessors=dict(GET_SINGLE=[auth_func], GET_MANY=[auth_func]),
  22. results_per_page=100,
  23. url_prefix='',
  24. collection_name='history',)
  25. apimanager.create_api(Position,
  26. methods=['GET','PUT','PATCH','POST'],
  27. # url_prefix='/api/v1',
  28. # preprocessors=dict(GET_SINGLE=[auth_func], GET_MANY=[auth_func]),
  29. results_per_page=100,
  30. url_prefix='',
  31. include_columns = ['Id', 'latitude', 'longitude','collect_time'],
  32. collection_name='position',)
  33. @app.route('/')
  34. def hello_world():
  35. return '你好!'
  36. @app.route('/voltage')
  37. def get_voltage():
  38. id = request.args.get('id', '')
  39. if id:
  40. json_data = r.get(id)
  41. if json_data:
  42. return jsonify(json.loads(json_data))
  43. return 'no data!'
  44. return 'no id!'
  45. @app.route('/relay', methods=['POST'])
  46. def set_relay():
  47. json_data = request.get_data()
  48. py_data = json.loads(json_data)
  49. r.lpush('front_tcp', (json.dumps(py_data)).encode('utf-8'))
  50. return jsonify(py_data)
  51. if __name__ == '__main__':
  52. app.run(host='127.0.0.1', port=int("5000"))

3.5.4 twisted进程

  1. #testNetRedis.py
  2. # coding=utf8
  3. import re
  4. import time
  5. import json
  6. import redis
  7. from datetime import datetime
  8. from twisted.internet import reactor, task, protocol
  9. from twisted.internet import defer, threads
  10. from twisted.internet.protocol import Protocol, error, Factory
  11. from twisted.protocols.basic import LineReceiver
  12. from dbhelper import insert_iot_record
  13. r = redis.Redis(host='127.0.0.1',port=6379,db=0)
  14. def getCurrentStrTime():
  15. return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
  16. class GasServerProtocol(LineReceiver):
  17. def __init__(self, factory):
  18. self.id = ''
  19. self.factory = factory
  20. self.last_iot_time = datetime.now()
  21. self.fisrt_recv_flag = True
  22. def connectionMade(self):
  23. print(
  24. "[%s]: %s连接到服务器端。" %
  25. (getCurrentStrTime(), self.transport.getPeer()))
  26. self.sendLine("$99'".encode('utf-8'))
  27. def connectionLost(self, reason):
  28. if self.id in self.factory.clients:
  29. del self.factory.clients[self.id]
  30. print("[%s]:ID %s 下线" % (getCurrentStrTime(), self.id))
  31. print(
  32. "[%s]: %s断开了连接,原因是%s" %
  33. (getCurrentStrTime(),
  34. self.transport.getPeer(),
  35. reason))
  36. def insert_iot_record_cb(self, result):
  37. print(result)
  38. self.last_iot_time = datetime.now()
  39. self.fisrt_recv_flag = False
  40. def lineReceived(self, data):
  41. data = data.decode('utf-8')
  42. tmpstr = ("[%s]: 收到数据 %s") % (getCurrentStrTime(), data)
  43. print(tmpstr)
  44. if(re.match("\$\d{2}\$", data)):
  45. self.id = str(data[1:3])
  46. dicttmp = {}
  47. dicttmp['handle'] = self
  48. dicttmp['timestamp'] = time.time()
  49. self.factory.clients[self.id] = dicttmp
  50. print("[%s]:ID %s 注册成功" % (getCurrentStrTime(), self.id))
  51. if(re.match('@\d{2}\D\w{12}\d{2}',data)):
  52. if(data[3] == 'D'):
  53. print(u'接收到1条命令!\r\n')
  54. volttmp = (int(data[4:8],16)/1000.0)
  55. temperature = (int(data[8:12],16)/10.0)
  56. humidity = (int(data[12:16],16)/10.0)
  57. dicttmp = {}
  58. dicttmp['collecttime'] = getCurrentStrTime()
  59. dicttmp['voltage'] = volttmp
  60. dicttmp['temperature'] = temperature
  61. dicttmp['humidity'] = humidity
  62. dicttmp['id'] = self.id
  63. r.set(self.id, json.dumps(dicttmp))
  64. print(r.get(self.id))
  65. current_time = datetime.now()
  66. if((current_time - self.last_iot_time).seconds >= 5 * 60 or self.fisrt_recv_flag):
  67. insert_iot_record( r.get(self.id)).addCallback(
  68. self.insert_iot_record_cb)
  69. class GasServerFactory(Factory):
  70. def __init__(self):
  71. self.clients = {} # maps clients ids to GasServerProtocol instances
  72. self._lc = task.LoopingCall(self.send_to_clients)
  73. self._lc.start(60,now=False)
  74. def buildProtocol(self, addr):
  75. return GasServerProtocol(self)
  76. def send_to_clients(self):
  77. for client_addr in self.clients :
  78. self.clients[client_addr]['handle'].sendLine('@12d000000'.encode('utf-8'))
  79. @defer.inlineCallbacks
  80. def receive_from_mq(self):
  81. try:
  82. data = yield r.rpop('front_tcp')
  83. if data and data != '':
  84. print(u'接收到1条命令!%s\r\n' % (data))
  85. self.process_data_from_mq(data)
  86. except:
  87. pass
  88. def process_data_from_mq(self, data):
  89. loads_data = (json.loads(data))
  90. command = loads_data.get('command')
  91. addr = (loads_data.get('addr'))
  92. mydata = loads_data.get('data')
  93. send_data = '@%s%s%s01' % (addr,command,mydata)
  94. send_data = send_data.encode('utf-8')
  95. self.clients[addr]['handle'].sendLine(send_data)
  96. def startMoniter():
  97. print("[%s]启动监控服务" % getCurrentStrTime())
  98. cf = GasServerFactory()
  99. task_receive_data_from_mq = task.LoopingCall(cf.receive_from_mq)
  100. task_receive_data_from_mq.start(0.1, now=False)
  101. reactor.listenTCP(8234, cf)
  102. reactor.run()
  103. def stopMoniter():
  104. print("[%s]停止监控服务" % getCurrentStrTime())
  105. try:
  106. reactor.crash()
  107. except RuntimeError:
  108. return defer.fail()
  109. else:
  110. return defer.succeed(None)
  111. startMoniter()

3.5.5调试界面

image_1c12shb1j1cgj5ub1r1n1lkq1mclm.png-219.8kB

image_1c12si1h7irfa8n1l3tqomd313.png-260kB

image_1c12sjt10ss9de81qto1ri816hm1g.png-240.5kB

image.png-930.8kB

  1. 当出现“ModuleNotFoundError: No module named XX”怎么办?
    一般是由于缺少依赖库导致的 ,pip install 库名 可以解决
  2. pyhton应用依赖的库汇总
    • pip install flask
    • pip install pyserial
    • pip install mysqlclient
    • pip install flask_restless
    • pip install flask_cors
    • pip install pypiwin32
    • pip install twisted
    • pip install redis
    • pip install flask_sqlalchemy
  3. 3.

3.6 部署到阿里云服务器

image.png-237.9kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注