Flutter Modbus TCP通信插件modbus_client_tcp的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter Modbus TCP通信插件modbus_client_tcp的使用

Introduction

modbus_client_tcp 是一组实现Modbus Client发送请求到远程设备(即Modbus Server)的包。以下是该包的一些关键特性:

  • Modbus Client:为TCP/UDP和Serial协议提供基础实现。
  • Modbus Client TCP:通过以太网网络使用TCP协议发送请求。
  • Modbus Client UDP:通过以太网网络使用UDP协议发送请求。
  • Modbus Client Serial:通过串行端口使用ASCII和RTU协议发送请求。

为了最小化项目依赖,这些包被分开实现。对于串行实现,Flutter项目只需添加flutter_libserialport包,而Dart项目则需要构建libserialport库。

Features

modbus_client_tcp 提供了多种功能来优化与Modbus服务器的通信:

  • 自动连接模式:通过设置ModbusConnectionMode来自定义send命令的行为。
  • 单元ID:可以在客户端和请求中指定目标单元ID。
  • 响应超时:可以为客户端实例或请求设置响应超时。
  • 服务器发现:从起始IP地址发现Modbus服务器。
  • 连接超时:为TCP客户端指定连接超时。
  • 连接后延迟:在某些情况下,连接后延迟发送请求。
  • 元素类型:支持多种数值和位元素类型。
  • 文件记录:支持文件记录功能码0x14和0x15。
  • 字节序:定义Modbus寄存器中的字节排列方式。
  • 元素组:创建元素组以优化请求。
  • 自定义请求实现:通过继承ModbusRequest类实现自定义请求。
  • 日志记录:启用日志记录功能。

Usage

读取请求 (Read Request)

import 'package:modbus_client/modbus_client.dart';
import 'package:modbus_client_tcp/modbus_client_tcp.dart';

void main() async {
  // 创建一个Modbus int16寄存器元素
  var batteryTemperature = ModbusInt16Register(
      name: "BatteryTemperature",
      type: ModbusElementType.inputRegister,
      address: 22,
      uom: "°C",
      multiplier: 0.1,
      onUpdate: (self) => print(self));

  // 发现Modbus服务器
  var serverIp = await ModbusClientTcp.discover("192.168.0.0");
  if (serverIp == null) {
    ModbusAppLogger.shout("No modbus server found!");
    return;
  }
  
  // 创建Modbus客户端
  var modbusClient = ModbusClientTcp(serverIp, unitId: 1);

  // 发送读取请求
  await modbusClient.send(batteryTemperature.getReadRequest());

  // 结束连接
  modbusClient.disconnect();
}

写入请求 (Write Request)

import 'package:modbus_client/modbus_client.dart';
import 'package:modbus_client_tcp/modbus_client_tcp.dart';

enum BatteryStatus implements ModbusIntEnum {
  offline(0),
  standby(1),
  running(2),
  fault(3),
  sleepMode(4);

  const BatteryStatus(this.intValue);

  @override
  final int intValue;

  @override
  String toString() {
    return name;
  }
}

void main() async {
  var batteryStatus = ModbusEnumRegister(
      name: "BatteryStatus",
      address: 11,
      type: ModbusElementType.holdingRegister,
      enumValues: BatteryStatus.values,
      onUpdate: (self) => print(self));

  // 发现Modbus服务器
  var serverIp = await ModbusClientTcp.discover("192.168.0.0");
  if (serverIp == null) {
    ModbusAppLogger.shout("No modbus server found!");
    return;
  }
  
  // 创建Modbus客户端
  var modbusClient = ModbusClientTcp(serverIp, unitId: 1);

  var req = batteryStatus.getWriteRequest(BatteryStatus.running);
  var res = await modbusClient.send(req);
  print(res.name);

  modbusClient.disconnect();
}

元素组读取请求 (Group Read Request)

import 'package:modbus_client/modbus_client.dart';
import 'package:modbus_client_tcp/modbus_client_tcp.dart';

enum BatteryStatus implements ModbusIntEnum {
  offline(0),
  standby(1),
  running(2),
  fault(3),
  sleepMode(4);

  const BatteryStatus(this.intValue);

  @override
  final int intValue;
}

void main() async {
  // 创建Modbus元素组
  var batteryRegs = ModbusElementsGroup([
    ModbusEnumRegister(
        name: "BatteryStatus",
        type: ModbusElementType.holdingRegister,
        address: 37000,
        enumValues: BatteryStatus.values),
    ModbusInt32Register(
        name: "BatteryChargingPower",
        type: ModbusElementType.holdingRegister,
        address: 37001,
        uom: "W",
        description: "> 0: charging - < 0: discharging"),
    ModbusUint16Register(
        name: "BatteryCharge",
        type: ModbusElementType.holdingRegister,
        address: 37004,
        uom: "%",
        multiplier: 0.1),
    ModbusUint16Register(
        name: "BatteryTemperature",
        type: ModbusElementType.holdingRegister,
        address: 37022,
        uom: "°C",
        multiplier: 0.1),
  ]);

  // 发现Modbus服务器
  var serverIp = await ModbusClientTcp.discover("192.168.0.0");
  if (serverIp == null) {
    ModbusAppLogger.shout("No modbus server found!");
    return;
  }
  
  // 创建Modbus客户端
  var modbusClient = ModbusClientTcp(serverIp, unitId: 1);

  // 发送读取请求
  await modbusClient.send(batteryRegs.getReadRequest());
  print(batteryRegs[0]);
  print(batteryRegs[1]);
  print(batteryRegs[2]);
  print(batteryRegs[3]);

  // 结束连接
  modbusClient.disconnect();
}

文件记录写入和读取示例 (File Records Write and Read Example)

import 'dart:typed_data';

import 'package:modbus_client/modbus_client.dart';
import 'package:modbus_client_tcp/modbus_client_tcp.dart';

void main() async {
  // 简单的Modbus日志记录
  ModbusAppLogger(Level.FINE);

  // 创建Modbus客户端
  var modbusClient = ModbusClientTcp("127.0.0.1", unitId: 1);

  // 写入两个文件记录
  var r1 = ModbusFileUint16Record(
      fileNumber: 4,
      recordNumber: 1,
      recordData: Uint16List.fromList([12573, 56312]));
  var r2 = ModbusFileDoubleRecord(
      fileNumber: 3,
      recordNumber: 9,
      recordData: Float64List.fromList([123.5634, 125756782.8492]));
  await modbusClient.send(ModbusFileRecordsWriteRequest([r1, r2]));

  // 读取两个文件记录
  r1 = ModbusFileUint16Record.empty(
      fileNumber: 4, recordNumber: 1, recordDataCount: 2);
  r2 = ModbusFileDoubleRecord.empty(
      fileNumber: 3, recordNumber: 9, recordDataCount: 2);
  await modbusClient.send(ModbusFileRecordsReadRequest([r1, r2]));

  // 写入多个记录
  var multipleRecords =
      ModbusFileMultipleRecord(fileNumber: 4, recordNumber: 1);
  multipleRecords.addNext(ModbusRecordType.int16, -123);
  multipleRecords.addNext(ModbusRecordType.uint16, 5000);
  multipleRecords.addNext(ModbusRecordType.int32, -1234567890);
  multipleRecords.addNext(ModbusRecordType.uint32, 1234567890);
  multipleRecords.addNext(ModbusRecordType.float, 123.45);
  multipleRecords.addNext(ModbusRecordType.double, 12345.6789);
  await modbusClient.send(multipleRecords.getWriteRequest());

  multipleRecords = ModbusFileMultipleRecord.empty(
      fileNumber: 4, recordNumber: 1, recordDataByteLength: 24);
  await modbusClient.send(multipleRecords.getReadRequest());
  multipleRecords.start();
  print(multipleRecords.getNext(ModbusRecordType.int16));
  print(multipleRecords.getNext(ModbusRecordType.uint16));
  print(multipleRecords.getNext(ModbusRecordType.int32));
  print(multipleRecords.getNext(ModbusRecordType.uint32));
  print(multipleRecords.getNext(ModbusRecordType.float));
  print(multipleRecords.getNext(ModbusRecordType.double));

  // 结束连接
  modbusClient.disconnect();
}

华为SUN2000逆变器寄存器 (Huawei SUN2000 Inverter Registers)

import 'package:modbus_client/modbus_client.dart';
import 'package:modbus_client_tcp/modbus_client_tcp.dart';

enum BatteryStatus implements ModbusIntEnum {
  offline(0),
  standby(1),
  running(2),
  fault(3),
  sleepMode(4);

  const BatteryStatus(this.intValue);

  @override
  final int intValue;
}

enum MeterStatus implements ModbusIntEnum {
  offline(0),
  normal(1);

  const MeterStatus(this.intValue);

  @override
  final int intValue;
}

void main() async {
  ModbusAppLogger(Level.INFO);

  // 发现Modbus服务器
  var serverIp = await ModbusClientTcp.discover("192.168.0.0");
  if (serverIp == null) {
    ModbusAppLogger.shout("No modbus server found!");
    return;
  }
  
  // 创建Modbus客户端
  var client = ModbusClientTcp(serverIp,
      serverPort: 502,
      unitId: 1,
      responseTimeout: Duration(seconds: 3),
      connectionTimeout: Duration(seconds: 1),
      delayAfterConnect: Duration(seconds: 1));

  var batteryRegs = ModbusElementsGroup([
    ModbusEnumRegister(
        name: "BatteryStatus",
        type: ModbusElementType.holdingRegister,
        address: 37000,
        enumValues: BatteryStatus.values),
    ModbusInt32Register(
        name: "BatteryChargingPower",
        type: ModbusElementType.holdingRegister,
        address: 37001,
        uom: "W",
        description: "> 0: charging - < 0: discharging"),
    ModbusUint16Register(
        name: "BatteryTemperature",
        type: ModbusElementType.holdingRegister,
        address: 37022,
        uom: "°C",
        multiplier: 0.1),
    ModbusUint16Register(
        name: "BatteryCharge",
        type: ModbusElementType.holdingRegister,
        address: 37004,
        uom: "%",
        multiplier: 0.1),
  ]);

  var meterRegs = ModbusElementsGroup([
    ModbusEnumRegister(
        name: "MeterStatus",
        type: ModbusElementType.holdingRegister,
        address: 37100,
        enumValues: MeterStatus.values),
    ModbusInt32Register(
        name: "MeterGridVoltagePhaseA",
        type: ModbusElementType.holdingRegister,
        address: 37101,
        uom: "V",
        multiplier: 0.1),
    // ... 其他寄存器 ...
  ]);

  try {
    var batteryRegsReq = batteryRegs.getReadRequest();
    var res = await client.send(batteryRegsReq);
    if (res == ModbusResponseCode.requestSucceed) {
      for (var element in batteryRegs) {
        print(element);
      }
    } else {
      print(res);
    }

    var meterRegsReq = meterRegs.getReadRequest();
    res = await client.send(meterRegsReq);
    if (res == ModbusResponseCode.requestSucceed) {
      for (var element in meterRegs) {
        print(element);
      }
    } else {
      print(res);
    }
  } finally {
    client.disconnect();
  }
}

以上代码展示了如何使用modbus_client_tcp插件进行Modbus TCP通信的基本操作。你可以根据实际需求调整IP地址、寄存器地址和其他参数。


更多关于Flutter Modbus TCP通信插件modbus_client_tcp的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Modbus TCP通信插件modbus_client_tcp的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个使用Flutter中的modbus_client_tcp插件进行Modbus TCP通信的示例代码。这个示例展示了如何连接到Modbus TCP服务器、读取保持寄存器和写入单个线圈。

首先,确保你已经在pubspec.yaml文件中添加了modbus_client_tcp依赖:

dependencies:
  flutter:
    sdk: flutter
  modbus_client_tcp: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来是示例代码:

import 'package:flutter/material.dart';
import 'package:modbus_client_tcp/modbus_client_tcp.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String result = "";

  @override
  void initState() {
    super.initState();
    _connectAndCommunicate();
  }

  Future<void> _connectAndCommunicate() async {
    try {
      // 创建Modbus TCP客户端
      final client = ModbusTCPClient(
        host: '192.168.1.100',  // 替换为你的Modbus TCP服务器IP地址
        port: 502,             // Modbus TCP默认端口
        unitId: 1,             // Modbus单元标识符
      );

      // 连接到服务器
      await client.connect();

      // 读取保持寄存器(功能码03)
      final holdingRegisters = await client.readHoldingRegisters(
        startAddress: 0,       // 起始地址
        quantity: 10,          // 读取数量
      );

      // 打印读取结果
      setState(() {
        result = "Holding Registers: ${holdingRegisters.map((e) => e.toHex()).join(", ")}";
      });

      // 写入单个线圈(功能码05)
      final writeResult = await client.writeSingleCoil(
        coilAddress: 0,        // 线圈地址
        value: true,           // 写入值(true为ON,false为OFF)
      );

      // 打印写入结果
      setState(() {
        result += "\nWrite Single Coil Result: $writeResult";
      });

      // 断开连接
      await client.disconnect();
    } catch (e) {
      // 处理异常
      setState(() {
        result = "Error: $e";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Modbus TCP Communication'),
        ),
        body: Center(
          child: Text(result),
        ),
      ),
    );
  }
}

代码说明:

  1. 依赖导入

    • 导入fluttermodbus_client_tcp包。
  2. 主应用

    • 创建一个MyApp类,它包含一个状态_MyAppState
  3. 状态初始化

    • initState方法中调用_connectAndCommunicate方法,该方法负责连接Modbus TCP服务器、读取保持寄存器和写入单个线圈。
  4. Modbus TCP客户端

    • 使用ModbusTCPClient类创建一个客户端实例,并指定服务器IP地址、端口和单元标识符。
  5. 连接和通信

    • 使用connect方法连接到服务器。
    • 使用readHoldingRegisters方法读取保持寄存器。
    • 使用writeSingleCoil方法写入单个线圈。
    • 使用disconnect方法断开连接。
  6. UI更新

    • 使用setState方法更新UI,显示读取和写入的结果。
  7. 异常处理

    • 捕获并处理连接和通信过程中可能发生的异常。

请确保你的Modbus TCP服务器正在运行,并且IP地址、端口和单元标识符配置正确。这个示例代码只是一个简单的演示,实际应用中可能需要更复杂的错误处理和状态管理。

回到顶部