硬件成本5元-USB串口采集电表数据完整方案-ThingsPanel快速入门
ThingsPanel开源物联网平台支持广泛的协议,灵活自由,本文介绍ThingsPanel通过串口来采集电表数据,简单易行,成本低廉,适合入门者学习试验,也适合一些特定的应用场景做数据采集。
适用场景:
- 降低Modbus设备数据采集成本
- 快速测试Modbus电表数据采集
- 物联网入门学习Modbus相关知识
效果图

方案价值
这套方案最大的价值在于:
- 最低代码改动,复制修改配置即可运行
- 硬件成本低,5块钱,一个USB转RS485连接器即可
- 能快速实现电表数据远程监控,适用于学习、以及正式用途等各种场景
- 支持数据可视化和历史记录查询
- 无需布置复杂的网络,只需要一台电脑和网络即可
接入结构图

所需设备
USB转RS485连接器(淘宝搜索"USB转485",5元左右)
支持Modbus协议的电表
一台电脑(Windows/Mac都可以)
操作步骤
1. 硬件连接
- 将USB转RS485连接器插入电脑
- 将连接器的A+和B-接线端子与电表对应端子连接
- A+ 接电表的 A+
- B- 接电表的 B-

2. 确认设备端口
Windows用户:
打开设备管理器
查看"端口(COM和LPT)"下的COM端口号
Mac用户:
打开终端
输入命令:ls /dev/tty.*
找到类似 /dev/tty.usbserial-110 的设备名
3. 安装Python环境
访问 https://www.python.org/downloads/
下载并安装Python 3.x版本
4. 安装必要的软件包
打开终端或命令提示符,运行:
pip install pyserial pip install pymodbus==3.7.2 pip install paho-mqtt
5. 创建并运行采集程序
创建一个新文件 meter_collector.py
将以下代码复制到文件中(注意修改端口号):
===================代码区域开始=====================
import time
import json
from pymodbus.client.serial import ModbusSerialClient
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
import paho.mqtt.client as mqtt
# MQTT配置-信息来自ThingsPanel平台,创建设备后在设备连接信息中。
MQTT_CONFIG = {
"broker": "47.115.210.16",
"port": 1883,
"username": "fe917b16-d786-3297-8f1",
"password": "f129542",
"client_id": "mqtt_3243936a-c23",
"telemetry_topic": "devices/telemetry",
"control_topic": "devices/telemetry/control/3243936a-c237-8cc5-7ea9-ba586098c2b7"
}
# Modbus配置(来自电表说明书,port需要自行在本机查询)
METER_CONFIG = {
"port": "/dev/tty.usbserial-110",
"baudrate": 9600,
"parity": 'E',
"stopbits": 1,
"bytesize": 8,
"byte_order": Endian.BIG
}
# 如下配置来自于电表设备说明书
DATA_ITEMS = [
{"name": "Voltage", "address": 0, "data_type": "int16-1", "factor": 0.1, "registers": 1},
{"name": "Current", "address": 3, "data_type": "int16-1", "factor": 0.01, "registers": 2},
{"name": "TotalActivePower", "address": 7, "data_type": "int16-1", "factor": 1, "registers": 1},
{"name": "TotalReactivePower", "address": 11, "data_type": "int16-1", "factor": 1, "registers": 1},
{"name": "TotalApparentPower", "address": 15, "data_type": "int16-1", "factor": 1, "registers": 1},
{"name": "TotalPowerFactor", "address": 19, "data_type": "int16-1", "factor": 0.001, "registers": 1},
{"name": "VoltageFrequency", "address": 26, "data_type": "int16-1", "factor": 0.01, "registers": 1}
]
# MQTT回调函数
def on_connect(client, userdata, flags, rc):
print(f"Connected to MQTT broker with result code {rc}")
# 订阅控制主题
client.subscribe(MQTT_CONFIG['control_topic'])
def on_message(client, userdata, msg):
try:
print(f"Received message on topic {msg.topic}: {msg.payload.decode()}")
# 这里可以添加处理接收到的控制命令的逻辑
data = json.loads(msg.payload.decode())
if 'switch' in data:
print(f"Received switch command: {data['switch']}")
except Exception as e:
print(f"Error processing message: {e}")
def create_mqtt_client():
client = mqtt.Client(client_id=MQTT_CONFIG['client_id'])
client.username_pw_set(MQTT_CONFIG['username'], MQTT_CONFIG['password'])
client.on_connect = on_connect
client.on_message = on_message
try:
client.connect(MQTT_CONFIG['broker'], MQTT_CONFIG['port'], 60)
client.loop_start()
return client
except Exception as e:
print(f"MQTT连接失败: {e}")
return None
# Modbus函数(与之前相同)
def create_modbus_client():
return ModbusSerialClient(
port=METER_CONFIG['port'],
baudrate=METER_CONFIG['baudrate'],
parity=METER_CONFIG['parity'],
stopbits=METER_CONFIG['stopbits'],
bytesize=METER_CONFIG['bytesize'],
timeout=1,
retries=3
)
def read_meter_data(client, slave_id):
data = {}
for item in DATA_ITEMS:
try:
result = client.read_holding_registers(
address=item['address'],
count=item['registers'],
slave=slave_id
)
if result and not result.isError():
decoder = BinaryPayloadDecoder.fromRegisters(
result.registers,
byteorder=METER_CONFIG['byte_order'],
wordorder=Endian.BIG
)
if item['data_type'] == 'int16-1':
value = decoder.decode_16bit_int()
else:
value = decoder.decode_16bit_uint()
data[item['name']] = value * item['factor']
else:
data[item['name']] = None
except Exception as e:
print(f"读取 {item['name']} 时出错: {str(e)}")
data[item['name']] = None
return data
def main():
print("正在连接Modbus设备...")
modbus_client = create_modbus_client()
if not modbus_client.connect():
print("无法连接到Modbus设备")
return
print("正在连接MQTT服务器...")
mqtt_client = create_mqtt_client()
if not mqtt_client:
print("无法连接到MQTT服务器")
modbus_client.close()
return
print("开始数据采集和上报循环...")
try:
while True:
data = read_meter_data(modbus_client, slave_id=1)
# 过滤掉读取失败的数据
valid_data = {k: v for k, v in data.items() if v is not None}
if valid_data:
# 发布数据到MQTT
try:
mqtt_client.publish(
MQTT_CONFIG['telemetry_topic'],
json.dumps(valid_data)
)
print(f"数据已上报: {valid_data}")
except Exception as e:
print(f"MQTT发布失败: {e}")
# 等待10秒
time.sleep(10)
except KeyboardInterrupt:
print("\n程序终止...")
finally:
print("正在关闭连接...")
modbus_client.close()
mqtt_client.loop_stop()
mqtt_client.disconnect()
print("连接已关闭")
if __name__ == "__main__":
main()
===================代码区域结束=====================
6. 运行程序
- 打开终端或命令提示符
- 进入程序所在目录
- 运行命令:
python meter_collector.py
7. 查看数据
- 登录 ThingsPanel 平台
- 进入设备详情页面
- 可以看到实时上报的电表数据
常见问题
连接不上设备?
- 检查接线是否正确
- 确认端口号是否正确
- 验证电表波特率是否为9600
数据显示异常?
- 确认电表地址是否为1
- 检查接线是否松动
无法连接平台?
- 检查网络连接
- 验证MQTT配置信息是否正确
扩展功能
- 可以通过修改代码中的 time.sleep(10) 来调整数据上报频率
- 支持添加多个电表,只需修改 slave_id 即可
现在,您的电表数据就可以实时推送到云平台了!
相关文章:
硬件成本5元-USB串口采集电表数据完整方案-ThingsPanel快速入门
ThingsPanel开源物联网平台支持广泛的协议,灵活自由,本文介绍ThingsPanel通过串口来采集电表数据,简单易行,成本低廉,适合入门者学习试验,也适合一些特定的应用场景做数据采集。 适用场景: 降低…...
在AWS EMR上用Hive、Spark、Airflow构建一个高效的ETL程序
在AWS EMR(Elastic MapReduce)上构建一个高效的ETL程序,使用Hive作为数据仓库,Spark作为计算引擎,Airflow作为调度工具时,有几个关键的设计与实施方面需要注意。 在AWS EMR上构建高效的ETL程序,…...
前端(四)css选择器、css的三大特性
css选择器、css的三大特性 文章目录 css选择器、css的三大特性一、css介绍二、css选择器2.1 基本选择器2.2 组合选择器2.3 交集并集选择器2.4序列选择器2.5属性选择器2.6伪类选择器2.7伪元素选择器 三、css三大特性3.1 继承性3.2 层叠性3.3 优先级 一、css介绍 CSS全称为Casca…...
vscode 打开 setting.json
按下Ctrl Shift P(Windows/Linux)或Cmd Shift P(Mac)来打开命令面板。输入open settings,然后选择 Open User Settings(JSON)。打开settings.json文件 ------修改设置-----: 1、 html代码的行长度&am…...
关于网络安全攻防演化博弈的研究小议
1. 拉高视角,从宏观看网络安全攻防 伴随着信息化的发展,网络安全的问题就一直日益突出,与此同时,网络安全技术也成为研究热点,直到今日也没有停止。 从微观来看,网络安全技术研究指的是针对某项或某几项…...
【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(7)
1.问题描述: 推送通知到手机,怎么配置拉起应用指定的页面? 解决方案: 1、如果点击通知栏打开默认Ability的话, actionType可以设置为0, 同时可以在.clickAction.data中,指定待跳转的page页面…...
远程桌面防护的几种方式及优缺点分析
远程桌面登录是管理服务器最主要的方式,于是很多不法分子打起了远程桌面的歪心思。他们采用暴力破解或撞库的方式破解系统密码,悄悄潜入服务器而管理员不自知。 同时远程桌面服务中的远程代码执行漏洞也严重威胁着服务器的安全,攻击者可以利…...
ASP.NET|日常开发中连接Sqlite数据库详解
ASP.NET|日常开发中连接Sqlite数据库详解 前言一、安装和引用相关库1.1 安装 SQLite 驱动1.2 引用命名空间 二、配置连接字符串2.1 连接字符串的基本格式 三、建立数据库连接3.1 创建连接对象并打开连接 四、执行数据库操作4.1 创建表(以简单的用户表为例…...
python的自动化seleium安装配置(包含谷歌的chromedriver)
目录 前言介绍 一、下载谷歌浏览器chromedriver (一)查看谷歌浏览器版本 (二)去官网下载谷歌驱动(chromdriver) (三)谷歌浏览器安装位置解压 (四)配置环境变量 二、pychram里下载安装selenium 三、测试selenium是否成功 前言介绍 Selenium是一个开源的自动化测试工具&…...
QT requested database does not belong to the calling thread.线程中查询数据报错
QT requested database does not belong to the calling thread.线程中查询数据报错 QString name "ttx"; QSqlQueryModel* sql_model; QString sql_comm QString("select * from dssb_moddve_loddt_tab where name%1").arg(name); sql_model->set…...
服务器一般装什么系统?
在服务器管理中,操作系统的选择是一个关键因素,它直接影响到服务器的稳定性、性能和可维护性。那么为什么有些服务器选择Linux,而不是Windows?选择合适的操作系统对服务器的性能和安全性有多么重要? 在众多操作系统中…...
Linux vi/vim 编辑器使用教程
Linux vi/vim 编辑器使用教程 引言 Linux 系统中的 vi 和 vim 是非常强大的文本编辑器,它们以其高效性和灵活性而闻名。vim 是 vi 的增强版,提供了更多的功能和改进的用户界面。本文将详细介绍 vi/vim 的基本用法,包括打开文件、编辑文本、…...
JavaEE多线程案例之阻塞队列
上文我们了解了多线程案例中的单例模式,此文我们来探讨多线程案例之阻塞队列吧 1. 阻塞队列是什么? 阻塞队列是⼀种特殊的队列.也遵守"先进先出"的原则. 阻塞队列是⼀种线程安全的数据结构,并且具有以下特性: 当队列满的时候,继续⼊队列就会…...
梳理你的思路(从OOP到架构设计)_基本OOP知识04
目录 1、 主动型 vs.基於被动型 API 1)卡榫函数实现API 2)API的分类 3)回顾历史 4)API >控制力 2、 结语&复习: 接口与类 1)接口的表示 2)Java的接口表示 1、 主动型 vs.基於被动…...
nginx反向代理(负载均衡)
nginx的代理 代理 四层代理 七层代理 正向代理和缓存的配置方式 🐭🐮🐯🐰🐉🐍🐴🐑🐒🐔🐶🐷 反向代理》负载均衡 负载均衡ÿ…...
Android系统应用主要模块
设置 Android Settings开发总结 Launcher Android Launcher开发学习总结 System UI Android SystemUI 学习总结...
【万字详解】三维重建(二)——NeRF、NeuS、MeshUDF、NeuralUDF、3DGS、GShell
文章目录 一、NeRF:Representing Scenes as Neural Radiance Fields for View Synthesis(推荐读)1.1 式1 神经网络的输入和输出1.2 式2 体素渲染算法1.3 式3 损失函数1.4 位置编码1.5 基本原理二、经典的重建流程2.1 传统的三维重建pipeline2.2 神经网络回归2.3 可微渲染最优…...
【RK3588 Linux 5.x 内核编程】-内核线程与Seqlock
内核线程与Seqlock 文章目录 内核线程与Seqlock1、Seqlock介绍2、Seqlock相关API2.1 初始化2.2 写操作2.3 读操作3、驱动实现4、驱动验证在前面的文章中,我们介绍了 Mutex、Spinlock、Read/Write Spinlock 的使用及其实现。 它们都用于保护共享资源不被两个或多个进程同时修改…...
访问者模式的理解和实践
在软件开发过程中,设计模式为我们提供了解决常见问题的最佳实践。访问者模式(Visitor Pattern)是行为设计模式之一,它将数据操作与数据结构分离,使得在不修改数据结构的前提下,能够定义作用于这些元素的新的…...
在Scala中对Map函数的使用
package pp28{object cscc {def main(args: Array[String]): Unit {val m1 Map("马云 — 阿里巴巴" -> 1964,"马化腾 — 腾讯" -> 1971,"李彦宏 - 百度" -> 1968,"雷军 - 小米" -> 1969,"丁磊 - 网易" -> …...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
