概要
采用python模拟硬件设备、虚拟机ubuntu系统模拟云服务器、部署EMQX消息服务器响应物联网数据的发布和订阅。
1、模拟传感器设备(ModbusTCP协议)
提示:这里可以采用真实的传感器进行替换,确认传感器数据传输协议(串口通讯/modbus..)
本demo采用python3.8.6,modbus_tk模块,模拟一个气象传感器(modbustcp通讯),具体实现如下:
# 创建modbustcp服务器
from modbus_tk import modbus_tcp
import modbus_tk.defines as cst
import random
import time
# 创建modbus服务器
server = modbus_tcp.TcpServer(port=502)
# 启动服务器
server.start()
# 添加从机(Slave ID 1),创建一个包含10个寄存器的块
slave = server.add_slave(1)
slave.add_block("block0", cst.HOLDING_REGISTERS, 0, 10)
try:
while True:
# 随机生成气象数据
temperature = int(random.uniform(20.0, 30.0) * 10) # 温度 (放大10倍保存一位小数)
humidity = int(random.uniform(40.0, 60.0) * 10) # 湿度 (放大10倍保存一位小数)
pressure = int(random.uniform(1000.0, 1020.0)) # 压力
wind_speed = int(random.uniform(0.0, 10.0) * 10) # 风速 (放大10倍保存一位小数)
wind_direction = random.randint(0, 360) # 风向
# 将数据写入寄存器
slave.set_values('block0', 0, [temperature, humidity, pressure, wind_speed, wind_direction])
print(f"Temperature: {temperature/10.0} C, Humidity: {humidity/10.0} %, Pressure: {pressure} hPa, Wind Speed: {wind_speed/10.0} m/s, Wind Direction: {wind_direction} °")
# 每2秒更新一次数据
time.sleep(2)
finally:
# 关闭服务器
server.stop()
modbustcp服务器启动后,建议进行验证。可以使用modbus poll,或者使用python脚本测试,python脚本测试如下:
# 导入模块
import time
import modbus_tk.modbus_tcp as modbus_tcp
import modbus_tk.defines as cst
# 连接到Modbus TCP服务器(本地测试)
modbus_client = modbus_tcp.TcpMaster(host="127.0.0.1", port=502)
modbus_client.set_timeout(5.0)
try:
while True:
# 读取Modbus寄存器中的数据,使用函数码3来读取保持寄存器
data = modbus_client.execute(1, cst.READ_HOLDING_REGISTERS, 0, 5)
temperature = data[0] / 10.0 # 温度,缩放回原值
humidity = data[1] / 10.0 # 湿度,缩放回原值
pressure = data[2] # 压力
wind_speed = data[3] / 10.0 # 风速,缩放回原值
wind_direction = data[4] # 风向
# 创建上传的数据负载
payload = {
"temperature": temperature,
"humidity": humidity,
"pressure": pressure,
"wind_speed": wind_speed,
"wind_direction": wind_direction,
}
print(f"Published: {payload}")
# 每隔2秒读取和上传一次数据
time.sleep(2)
finally:
# 关闭Modbus TCP客户端
modbus_client.close()
可以在终端窗口看到数据流,表明模拟传感器正常。
2、EMQX部署(MQTT Broker)
提示:这里可以采用云服务器进行部署,云服务免维护且支持公网ip,(也可以使用本地电脑搭配5G使用[支持ipv6],还未测试过)
本demo使用vmware虚拟机,创建一个ubuntu20.04,模拟云服务器。云服务器部署EMQX具体步骤如下:
- 更新包列表
sudo apt update
- 配置EMQX apt 源
curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash
- 安装EMQX
sudo apt-get install emqx
- 启动EMQX
sudo systemctl start emqx
- 网页端验证
如果使用的云服务器,需注意配置端口权限
在浏览器输入http://192.168.205.136:18083
访问EMQX后台,ip地址选择自己的公网ip或者测试用的局域网ip。默认用户名:admin
和密码 :public
。
3、传感器数据读取&数据上传EMQX(MQTT协议)
提示:MQTT协议,EMQX消息服务器有很多细节,集群、权限,传输质量等,本处只演示实现路径
本demo采用python3.8.6,modbus_tk、paho.mqtt模块,读取modbustcp服务器数据,并采用MQTT协议将数据发布到EMQX服务器上,具体实现如下:
# 导入模块
import time
import modbus_tk.modbus_tcp as modbus_tcp
import paho.mqtt.client as mqtt
import modbus_tk.defines as cst
# MQTT配置, ip 192.168.205.136, 端口 1883,topic sensor/qixiang_data
# 连接到MQTT Broker
mqtt_client = mqtt.Client()
mqtt_client .connect("192.168.205.136", 1883, 60) # 注意更改IP,1883是默认端口
MQTT_TOPIC = "sensor/qixiang_data"
# 连接到Modbus TCP服务器(本地测试)
modbus_client = modbus_tcp.TcpMaster(host="127.0.0.1", port=502)
modbus_client.set_timeout(5.0)
# 读取并发布数据
try:
while True:
# 读取Modbus寄存器中的数据,使用函数码3来读取保持寄存器
data = modbus_client.execute(1, cst.READ_HOLDING_REGISTERS, 0, 5)
temperature = data[0] / 10.0 # 温度,缩放回原值
humidity = data[1] / 10.0 # 湿度,缩放回原值
pressure = data[2] # 压力
wind_speed = data[3] / 10.0 # 风速,缩放回原值
wind_direction = data[4] # 风向
# 创建上传的数据负载
payload = {
"temperature": temperature,
"humidity": humidity,
"pressure": pressure,
"wind_speed": wind_speed,
"wind_direction": wind_direction,
}
# 将数据上传到MQTT broker
mqtt_client.publish(MQTT_TOPIC, str(payload))
print(f"Published: {payload}")
# 每隔5秒读取和上传一次数据
time.sleep(5)
finally:
# 关闭Modbus TCP客户端和MQTT客户端
modbus_client.close()
mqtt_client.disconnect()
可以在EMQX的后台中,看到连接的会话。
4、MQTT数据订阅
测试MQTT消息服务器,数据正常订阅,测试如下:
import paho.mqtt.client as mqtt
# MQTT配置
MQTT_BROKER = "192.168.205.136" # 替换为你的EMQX broker地址
MQTT_PORT = 1883 # 根据实际情况设置端口
MQTT_TOPIC = "sensor/qixiang_data" # 你想要订阅的主题
# 当连接到MQTT Broker时被调用
def on_connect(client, userdata, flags, rc):
print(f"Connected with result code {rc}")
client.subscribe(MQTT_TOPIC) # 订阅主题
# 当接收到来自服务器的消息时被调用
def on_message(client, userdata, msg):
print(f"Topic: {msg.topic}\nMessage: {msg.payload.decode()}")
# 设置MQTT客户端
mqtt_client = mqtt.Client()
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
# 连接到MQTT Broker
mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60)
# 开始监听并处理网络流量
mqtt_client.loop_forever()
可以看到数据流,表面数据已经成功上云,并可以通过MQTT订阅的方式获取得到。
4、Web端展示
提示:数据上云后,一般需要通过网页端展示出来,便于用户直观的了解监测信息,一般采用数据库存储MQTT订阅的消息,然后前后端开发,实现数据的实时展示
本demo采用python3.8.6,flask、paho.mqtt模块,简单的演示一下数据前端展示(不涉及数据库操作),创建一个项目文件夹project,添加一个后端文件app.py,内容如下:
from flask import Flask, render_template, jsonify
import paho.mqtt.client as mqtt
import threading
app = Flask(__name__)
# MQTT 配置
MQTT_BROKER = "192.168.205.136"
MQTT_PORT = 1883
MQTT_TOPIC = "sensor/qixiang_data"
latest_data = ""
# 当连接到MQTT Broker时被调用
def on_connect(client, userdata, flags, rc):
print(f"Connected with result code {rc}")
client.subscribe(MQTT_TOPIC)
# 当接收到来自服务器的消息时被调用
def on_message(client, userdata, msg):
global latest_data
latest_data = msg.payload.decode()
print(f"Message received: {latest_data}")
# 设置MQTT客户端
mqtt_client = mqtt.Client()
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
def start_mqtt():
mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60)
mqtt_client.loop_forever()
# 启动MQTT客户端的后台线程
mqtt_thread = threading.Thread(target=start_mqtt)
mqtt_thread.daemon = True
mqtt_thread.start()
@app.route('/')
def index():
return render_template('index.html')
# 前端发起get请求,获取最新的数据展示到页面上
@app.route('/data', methods=['GET'])
def get_data():
return jsonify({"data": latest_data})
if __name__ == '__main__':
app.run(debug=True)
project文件夹下创建一个templates文件夹,放入app.py所需要的index.html模板,index.html如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Real-time Data</title>
<script>
function fetchData() {
fetch('/data')
.then(response => response.json())
.then(data => {
document.getElementById('data').innerText = JSON.stringify(data);
});
}
setInterval(fetchData, 1000); // 每秒钟请求一次数据
</script>
</head>
<body>
<h1>Real-time Data</h1>
<pre id="data">Waiting for data...</pre>
</body>
</html>
执行app.py文件,访问提示的网址,即可看到前端页面上展示的数据。
至此,实现传感器数据采集上云,并前端展示。