Browse Source

1、线程开启根据端口号进行分配;

prod_202403
mh 10 months ago
parent
commit
75aeaa8a12
  1. 3
      user-service/src/main/java/com/mh/user/constants/Constant.java
  2. 3
      user-service/src/main/java/com/mh/user/controller/DeviceOperateController.java
  3. 9
      user-service/src/main/java/com/mh/user/job/DealDataJob.java
  4. 20
      user-service/src/main/java/com/mh/user/mapper/SysParamMapper.java
  5. 27
      user-service/src/main/java/com/mh/user/serialport/SerialPortSendReceive2.java
  6. 6
      user-service/src/main/java/com/mh/user/serialport/SerialPortSingle2.java
  7. 16
      user-service/src/main/java/com/mh/user/service/SysParamService.java
  8. 11
      user-service/src/main/java/com/mh/user/service/impl/DeviceControlServiceImpl.java
  9. 27
      user-service/src/main/java/com/mh/user/service/impl/SysParamServiceImpl.java
  10. 20
      user-service/src/main/java/com/mh/user/utils/AnalysisReceiveOrder485.java
  11. 3
      user-service/src/test/java/com/mh/user/UserServiceApplicationTests.java
  12. 4
      热水新增脚本.sql

3
user-service/src/main/java/com/mh/user/constants/Constant.java

@ -9,7 +9,8 @@ package com.mh.user.constants;
*/ */
public class Constant { public class Constant {
public static boolean CONTROL_WEB_FLAG = false; public static final CharSequence CUSTOM_NAME_HUAXIA = "华厦";
public static boolean CONTROL_WEB_FLAG = false;
public static boolean SEND_STATUS = false; // 指令发送状态 public static boolean SEND_STATUS = false; // 指令发送状态
public static volatile boolean FLAG = false; public static volatile boolean FLAG = false;

3
user-service/src/main/java/com/mh/user/controller/DeviceOperateController.java

@ -49,6 +49,7 @@ public class DeviceOperateController {
public HttpResult operateDevice(@RequestBody List<SerialPortModel> params) { public HttpResult operateDevice(@RequestBody List<SerialPortModel> params) {
try { try {
Constant.WEB_FLAG = true; //单抄,暂时停止采集 Constant.WEB_FLAG = true; //单抄,暂时停止采集
Thread.sleep(800);
String returnStr = deviceControlService.readOrWriteDevice(params, Constant.WRITE); String returnStr = deviceControlService.readOrWriteDevice(params, Constant.WRITE);
if (!StringUtils.isBlank(returnStr) && "fail".equals(returnStr)) { if (!StringUtils.isBlank(returnStr) && "fail".equals(returnStr)) {
return HttpResult.error(500, "fail"); return HttpResult.error(500, "fail");
@ -70,8 +71,8 @@ public class DeviceOperateController {
public HttpResult readData(@RequestBody List<SerialPortModel> params) { public HttpResult readData(@RequestBody List<SerialPortModel> params) {
try { try {
Constant.WEB_FLAG = true; //单抄,暂时停止采集 Constant.WEB_FLAG = true; //单抄,暂时停止采集
Thread.sleep(800);
String rtData = deviceControlService.readOrWriteDevice(params, Constant.READ); String rtData = deviceControlService.readOrWriteDevice(params, Constant.READ);
Constant.WEB_FLAG = false; //单抄,恢复采集
if (ExchangeStringUtil.getJSONType(rtData)) { if (ExchangeStringUtil.getJSONType(rtData)) {
Map map = JSONObject.parseObject(rtData); Map map = JSONObject.parseObject(rtData);
return HttpResult.ok("success", map); return HttpResult.ok("success", map);

9
user-service/src/main/java/com/mh/user/job/DealDataJob.java

@ -3,12 +3,10 @@ package com.mh.user.job;
import com.mh.user.constants.Constant; import com.mh.user.constants.Constant;
import com.mh.user.entity.DeviceCodeParamEntity; import com.mh.user.entity.DeviceCodeParamEntity;
import com.mh.user.serialport.SerialPortThread; import com.mh.user.serialport.SerialPortThread;
import com.mh.user.service.DeviceCodeParamService;
import com.mh.user.service.DealDataService; import com.mh.user.service.DealDataService;
import com.mh.user.utils.CacheUtil; import com.mh.user.utils.CacheUtil;
import com.mh.user.utils.ComThreadPoolService; import com.mh.user.utils.ComThreadPoolService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -33,11 +31,6 @@ public class DealDataJob {
private final DealDataService dealDataService; private final DealDataService dealDataService;
@Autowired
private DeviceCodeParamService deviceCodeParamService;
private static int taskTimes = 1;
public DealDataJob(DealDataService dealDataService) { public DealDataJob(DealDataService dealDataService) {
this.dealDataService = dealDataService; this.dealDataService = dealDataService;
} }
@ -136,7 +129,7 @@ public class DealDataJob {
Date date = new Date(); Date date = new Date();
String curDate = sdf1.format(date); String curDate = sdf1.format(date);
String name = dealDataService.customName(); String name = dealDataService.customName();
if (name != null && name.length() > 0 && name.contains("华夏学院")) { if (name != null && name.contains("华夏学院")) {
dealDataService.proEnergySum2(curDate); dealDataService.proEnergySum2(curDate);
} else { } else {
dealDataService.proEnergySum(curDate); dealDataService.proEnergySum(curDate);

20
user-service/src/main/java/com/mh/user/mapper/SysParamMapper.java

@ -0,0 +1,20 @@
package com.mh.user.mapper;
import com.mh.user.entity.SysParamEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
/**
* @author LJF
* @version 1.0
* @project CHWS
* @description 系统参数
* @date 2024-01-16 08:58:43
*/
@Mapper
public interface SysParamMapper {
@Select("select top 1 * from SysParam ")
SysParamEntity selectSysParam();
}

27
user-service/src/main/java/com/mh/user/serialport/SerialPortSendReceive2.java

@ -3,10 +3,8 @@ package com.mh.user.serialport;
import com.mh.common.utils.StringUtils; import com.mh.common.utils.StringUtils;
import com.mh.user.constants.Constant; import com.mh.user.constants.Constant;
import com.mh.user.entity.DeviceCodeParamEntity; import com.mh.user.entity.DeviceCodeParamEntity;
import com.mh.user.service.BuildingService; import com.mh.user.entity.SysParamEntity;
import com.mh.user.service.DeviceCodeParamService; import com.mh.user.service.*;
import com.mh.user.service.DeviceInstallService;
import com.mh.user.service.NowDataService;
import com.mh.user.utils.*; import com.mh.user.utils.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -44,6 +42,8 @@ public class SerialPortSendReceive2 {
BuildingService buildingService = context.getBean(BuildingService.class); BuildingService buildingService = context.getBean(BuildingService.class);
AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485(); AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485();
SysParamService sysParamService = context.getBean(SysParamService.class);
public void serialPortSend(String sort, String thread) { public void serialPortSend(String sort, String thread) {
SerialPort serialPort = null; SerialPort serialPort = null;
CacheUtil cacheUtil = CacheUtil.getInstance(); CacheUtil cacheUtil = CacheUtil.getInstance();
@ -59,7 +59,9 @@ public class SerialPortSendReceive2 {
for (int i = 0; i < deviceManageEntityList.size(); i++) { for (int i = 0; i < deviceManageEntityList.size(); i++) {
//判断网页端是否有操作设备的 //判断网页端是否有操作设备的
if (Constant.WEB_FLAG) { if (Constant.WEB_FLAG) {
SerialTool.closePort(serialPort); if (serialPort != null) {
SerialTool.closePort(serialPort);
}
log.info("有指令下发退出定时采集"); log.info("有指令下发退出定时采集");
break; break;
} }
@ -201,7 +203,7 @@ public class SerialPortSendReceive2 {
} }
} }
static void analysisReceiveData(String dateStr, public void analysisReceiveData(String dateStr,
String deviceType, String deviceType,
String registerAddr, String registerAddr,
String brand, String brand,
@ -228,8 +230,17 @@ public class SerialPortSendReceive2 {
} else if (dataStr.length() == 30 && deviceType.equals("状态检测")) {//五路状态读取,兼容旧版系统 } else if (dataStr.length() == 30 && deviceType.equals("状态检测")) {//五路状态读取,兼容旧版系统
analysisReceiveOrder485.analysisStateOrder485(dataStr, registerAddr, brand, buildingId, buildingName); analysisReceiveOrder485.analysisStateOrder485(dataStr, registerAddr, brand, buildingId, buildingName);
} else if (deviceType.equals("水位开关") && registerAddr.equals("0010")) { } else if (deviceType.equals("水位开关") && registerAddr.equals("0010")) {
analysisReceiveOrder485.analysisPumpStateOrder(dataStr, registerAddr, brand, buildingId, buildingName); //创新,热泵状态与水位共用一个8路设备 log.info("进入水位开关,地址==>{}", registerAddr);
// analysisReceiveOrder485.analysisRelayOrder485(dataStr,registerAddr,brand,buildingId); //华厦 SysParamEntity sysParamEntity = sysParamService.selectSysParam();
if (null != sysParamEntity && !StringUtils.isBlank(sysParamEntity.getCustomName())) {
if (sysParamEntity.getCustomName().contains(Constant.CUSTOM_NAME_HUAXIA)) {
analysisReceiveOrder485.analysisRelayOrder485(dataStr,registerAddr,brand,buildingId, buildingName); //华厦
} else {
analysisReceiveOrder485.analysisPumpStateOrder(dataStr, registerAddr, brand, buildingId, buildingName); //创新,热泵状态与水位共用一个8路设备
}
} else {
analysisReceiveOrder485.analysisPumpStateOrder(dataStr, registerAddr, brand, buildingId, buildingName); //创新,热泵状态与水位共用一个8路设备
}
nowDataService.proWaterLevel(dateStr, buildingId, ""); //保存时间点楼栋水位 nowDataService.proWaterLevel(dateStr, buildingId, ""); //保存时间点楼栋水位
} else if (deviceType.equals("温度变送器")) { } else if (deviceType.equals("温度变送器")) {
analysisReceiveOrder485.analysisMulTempOrder485(dataStr, registerAddr, brand, buildingId, buildingName); analysisReceiveOrder485.analysisMulTempOrder485(dataStr, registerAddr, brand, buildingId, buildingName);

6
user-service/src/main/java/com/mh/user/serialport/SerialPortSingle2.java

@ -96,9 +96,12 @@ public class SerialPortSingle2 {
//返回值全部变成大写 //返回值全部变成大写
String receiveData = receiveStr.toUpperCase(); String receiveData = receiveStr.toUpperCase();
//截取去掉FE //截取去掉FE
String dataStr = receiveData.replace("FE", "");
String deviceType = deviceCodeParamEntity.getDeviceType(); String deviceType = deviceCodeParamEntity.getDeviceType();
String deviceAddr = deviceCodeParamEntity.getDeviceAddr(); String deviceAddr = deviceCodeParamEntity.getDeviceAddr();
String dataStr = receiveData;
if ("水表".equals(deviceType) || "电表".equals(deviceType)) {
dataStr = receiveData.replace("FE", "");
}
String registerAddr = deviceCodeParamEntity.getRegisterAddr(); String registerAddr = deviceCodeParamEntity.getRegisterAddr();
String brand = deviceCodeParamEntity.getBrand(); String brand = deviceCodeParamEntity.getBrand();
String buildingId = deviceCodeParamEntity.getBuildingId(); String buildingId = deviceCodeParamEntity.getBuildingId();
@ -123,6 +126,7 @@ public class SerialPortSingle2 {
analysisReceiveOrder485.analysisStateOrder485(dataStr, registerAddr, brand, buildingId, buildingName); analysisReceiveOrder485.analysisStateOrder485(dataStr, registerAddr, brand, buildingId, buildingName);
} else if (deviceType.equals("水位开关") && (StringUtils.isBlank(registerAddr) || (registerAddr.equals("0018") || registerAddr.equals("0017")))) { } else if (deviceType.equals("水位开关") && (StringUtils.isBlank(registerAddr) || (registerAddr.equals("0018") || registerAddr.equals("0017")))) {
rtData = analysisReceiveOrder485.analysisRelayOrder4852(dataStr, registerAddr, brand, buildingId, buildingName); rtData = analysisReceiveOrder485.analysisRelayOrder4852(dataStr, registerAddr, brand, buildingId, buildingName);
log.info("水位开关读取或者设置返回值==>{}", rtData);
} else if (deviceType.equals("热泵")) { } else if (deviceType.equals("热泵")) {
rtData = analysisReceiveOrder485.analysisPumpOrder4852(dataStr, registerAddr, brand, buildingId, buildingName); rtData = analysisReceiveOrder485.analysisPumpOrder4852(dataStr, registerAddr, brand, buildingId, buildingName);
} else if (deviceType.equals("时控")) { } else if (deviceType.equals("时控")) {

16
user-service/src/main/java/com/mh/user/service/SysParamService.java

@ -0,0 +1,16 @@
package com.mh.user.service;
import com.mh.user.entity.SysParamEntity;
/**
* @author LJF
* @version 1.0
* @project CHWS
* @description 系统参数
* @date 2024-01-16 09:02:21
*/
public interface SysParamService {
SysParamEntity selectSysParam();
}

11
user-service/src/main/java/com/mh/user/service/impl/DeviceControlServiceImpl.java

@ -44,6 +44,8 @@ public class DeviceControlServiceImpl implements DeviceControlService {
@Override @Override
public String readOrWriteDevice(List<SerialPortModel> params, String type) { public String readOrWriteDevice(List<SerialPortModel> params, String type) {
try { try {
// 26 03 10 00 00 00 00 00 01 00 01 00 01 00 01 00 00 00 00 FE 86
SerialPortSingle2 serialPortSingle = new SerialPortSingle2(); SerialPortSingle2 serialPortSingle = new SerialPortSingle2();
String rtData = ""; String rtData = "";
for (SerialPortModel serialPortModel : params) { for (SerialPortModel serialPortModel : params) {
@ -91,6 +93,7 @@ public class DeviceControlServiceImpl implements DeviceControlService {
break; break;
case "水位开关": case "水位开关":
rtData = handleWaterLevelSwitch(serialPortModel, deviceCodeParam, controlData, rtData, type, serialPortSingle); rtData = handleWaterLevelSwitch(serialPortModel, deviceCodeParam, controlData, rtData, type, serialPortSingle);
log.info("设备类型为水位开关==>{}", rtData);
break; break;
case "温度变送器": case "温度变送器":
rtData = handleTemperatureTransmitter(serialPortModel, deviceCodeParam, controlData, rtData, type, serialPortSingle); rtData = handleTemperatureTransmitter(serialPortModel, deviceCodeParam, controlData, rtData, type, serialPortSingle);
@ -171,8 +174,8 @@ public class DeviceControlServiceImpl implements DeviceControlService {
deviceCodeParam.setFunCode("06"); //功能码写数据 deviceCodeParam.setFunCode("06"); //功能码写数据
if (!serialPortModel.getDataValue().equals("100%")) { if (!serialPortModel.getDataValue().equals("100%")) {
deviceCodeParam.setDataValue("100%"); deviceCodeParam.setDataValue("100%");
// serialPortSingle.serialPortSend(deviceCodeParam);//生成并发送指令 serialPortSingle.serialPortSend(deviceCodeParam);//生成并发送指令
// Thread.sleep(1000); Thread.sleep(1000);
} }
break; break;
case "顶威": case "顶威":
@ -182,8 +185,8 @@ public class DeviceControlServiceImpl implements DeviceControlService {
deviceCodeParam.setFunCode("12"); //功能码写数据 deviceCodeParam.setFunCode("12"); //功能码写数据
if (!serialPortModel.getDataValue().equals("100%")) { if (!serialPortModel.getDataValue().equals("100%")) {
deviceCodeParam.setDataValue("100%"); deviceCodeParam.setDataValue("100%");
// serialPortSingle.serialPortSend(deviceCodeParam);//生成并发送指令 serialPortSingle.serialPortSend(deviceCodeParam);//生成并发送指令
// Thread.sleep(1000); Thread.sleep(1000);
} }
break; break;
} }

27
user-service/src/main/java/com/mh/user/service/impl/SysParamServiceImpl.java

@ -0,0 +1,27 @@
package com.mh.user.service.impl;
import com.mh.user.entity.SysParamEntity;
import com.mh.user.mapper.SysParamMapper;
import com.mh.user.service.SysParamService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author LJF
* @version 1.0
* @project CHWS
* @description 系统参数
* @date 2024-01-16 09:02:58
*/
@Service
public class SysParamServiceImpl implements SysParamService {
@Resource
private SysParamMapper sysParamMapper;
@Override
public SysParamEntity selectSysParam() {
return sysParamMapper.selectSysParam();
}
}

20
user-service/src/main/java/com/mh/user/utils/AnalysisReceiveOrder485.java

@ -671,10 +671,7 @@ public class AnalysisReceiveOrder485 {
public void analysisMulTempOrder485(final String receiveData, final String registerAddr, final String brand, final String buildingId, final String buildingName) { public void analysisMulTempOrder485(final String receiveData, final String registerAddr, final String brand, final String buildingId, final String buildingName) {
// threadPoolService.execute(() -> { // threadPoolService.execute(() -> {
String checkStr = receiveData.substring(0, receiveData.length() - 4);// 检验报文 String checkStr = receiveData.substring(0, receiveData.length() - 4);// 检验报文
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); String checkWord = ExchangeStringUtil.getStrCRC16(checkStr);//生成校验码
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (!checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) { if (!checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) {
log.info("温度变送器报文检验失败: " + receiveData); log.info("温度变送器报文检验失败: " + receiveData);
} }
@ -789,10 +786,7 @@ public class AnalysisReceiveOrder485 {
// threadPoolService.execute(() -> { // threadPoolService.execute(() -> {
// 检验报文 // 检验报文
String checkStr = receiveData.substring(0, receiveData.length() - 4); String checkStr = receiveData.substring(0, receiveData.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); String checkWord = ExchangeStringUtil.getStrCRC16(checkStr);//生成校验码
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (!checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) { if (!checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) {
log.info("温控报文检验失败: " + receiveData); log.info("温控报文检验失败: " + receiveData);
return; return;
@ -826,10 +820,7 @@ public class AnalysisReceiveOrder485 {
public void analysisPressureOrder485(final String receiveData, final String registerAddr, final String brand, String buildingId, String buildingName) { public void analysisPressureOrder485(final String receiveData, final String registerAddr, final String brand, String buildingId, String buildingName) {
// threadPoolService.execute(() -> { // threadPoolService.execute(() -> {
String checkStr = receiveData.substring(0, receiveData.length() - 4);// 检验报文 String checkStr = receiveData.substring(0, receiveData.length() - 4);// 检验报文
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); String checkWord = ExchangeStringUtil.getStrCRC16(checkStr);//生成校验码
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (!checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) { if (!checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) {
log.info("压变报文检验失败: " + receiveData); log.info("压变报文检验失败: " + receiveData);
return; return;
@ -1632,10 +1623,7 @@ public class AnalysisReceiveOrder485 {
String dateStr = sdf1.format(date); String dateStr = sdf1.format(date);
// 检验报文 // 检验报文
String checkStr = receiveData.substring(0, receiveData.length() - 4); String checkStr = receiveData.substring(0, receiveData.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); String checkWord = ExchangeStringUtil.getStrCRC16(checkStr);//生成校验码
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
String sValue = null; String sValue = null;
if (checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) { if (checkWord.equalsIgnoreCase(receiveData.substring(receiveData.length() - 4))) {

3
user-service/src/test/java/com/mh/user/UserServiceApplicationTests.java

@ -6,6 +6,7 @@ import com.mh.user.serialport.SerialPortThread;
import com.mh.user.service.DeviceManageService; import com.mh.user.service.DeviceManageService;
import com.mh.user.service.GaugeService; import com.mh.user.service.GaugeService;
import com.mh.user.utils.*; import com.mh.user.utils.*;
import org.checkerframework.checker.units.qual.A;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@ -104,5 +105,7 @@ class UserServiceApplicationTests {
+ "00" + ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.IntToHex(Integer.parseInt(dataValue.substring(4, 6))),2) + "00" + ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.IntToHex(Integer.parseInt(dataValue.substring(4, 6))),2)
+ "00" + ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.IntToHex(Integer.parseInt(dataValue.substring(6, 8))),2); + "00" + ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.IntToHex(Integer.parseInt(dataValue.substring(6, 8))),2);
System.out.println(strData); System.out.println(strData);
AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485();
analysisReceiveOrder485.analysisRelayOrder4852("26 03 10 00 00 00 00 00 01 00 01 00 01 00 01 00 00 00 00 FE 86 ".replace(" ", ""), "0018", "远向", "1", "1栋");
} }
} }

4
热水新增脚本.sql

@ -14,3 +14,7 @@ exec sp_addextendedproperty N'MS_Description', N'设备地址', N'schema', N'dbo
alter table waterLevel add device_name varchar(50) not null default ''; alter table waterLevel add device_name varchar(50) not null default '';
exec sp_addextendedproperty N'MS_Description', N'设备名称', N'schema', N'dbo',N'table', N'waterLevel', N'column', N'device_name'; exec sp_addextendedproperty N'MS_Description', N'设备名称', N'schema', N'dbo',N'table', N'waterLevel', N'column', N'device_name';
-- 2024-01-16 批量更新采集的参数thread
update device_code_param set thread = substring(data_com,4,len(data_com))
update device_code_param2 set thread = substring(data_com,4,len(data_com))
update device_code_param3 set thread = substring(data_com,4,len(data_com))

Loading…
Cancel
Save