home 2 жил өмнө
commit
1092e07f86

BIN
ca.jks


+ 63 - 0
config

@@ -0,0 +1,63 @@
+# debug     调试模式
+# serverIp  服务ip
+# deviceId  华为云配置deviceId
+# secret    华为云配置secret
+# connectConfigList 设备配置 {[
+#   equipmentNo     设备编号
+#   ipAddress       设备ip地址
+#   port            设备ip端口号
+#   type            设备类型
+#       -> 1 注塑机
+#       -> 2 滚印机
+#       -> 3 组装机
+#       -> 4 螺纹头
+#       -> 5 注射针
+#   other {         其他配置:每种协议特有配置统一放这
+#       如:
+#       type为 2、3、4、5 时,走modBusTcp协议:可配置以下信息,不配置则为默认值
+#           slavedId                        从机地址 默认 1
+#           coilsOffSet                     0x开始读取地址 默认:0
+#           coilsQuantity                   0x读取位数 默认:100
+#           discreteInputsOffSet            1x开始读取地址 默认:0
+#           discreteInputsQuantity          1x读取位数 默认:100
+#           inputRegistersOffSet            3x开始读取地址 默认:0
+#           inputRegistersQuantity          3x读取位数 默认:100
+#           holdingRegistersOffSet          4x开始读取地址 默认:0
+#           holdingRegistersQuantity        4x读取位数 默认:100
+#   }
+# ]}
+
+
+{
+    "debug": true,
+    "serverIp": "a1625d5cc8.iot-mqtts.cn-north-4.myhuaweicloud.com",
+    "deviceId": "62d4ff516b9813541d51f893_test_node_01",
+    "secret": "fjhx2012",
+
+    "connectConfigList": [
+#        {
+#            "equipmentNo": "test1",
+#            "ipAddress": "192.168.0.140",
+#            "port": 502,
+#            "type": 2
+#        },
+        {
+             "equipmentNo": "test1",
+             "ipAddress": "192.168.1.174",
+             "port": 502,
+             "type": 2,
+             "other": {
+                "slavedId": 1,
+                "coilsOffSet": 0,
+                "coilsQuantity": 17,
+                "discreteInputsOffSet": 0,
+                "discreteInputsQuantity": 21,
+                "inputRegistersOffSet": 0,
+                "inputRegistersQuantity": 0,
+                "holdingRegistersOffSet": 0,
+                "holdingRegistersQuantity": 4
+             }
+        }
+    ]
+
+}

+ 75 - 0
pom.xml

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.example</groupId>
+    <artifactId>IotUpperComputer</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>2.0.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.24</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.80</version>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.9</version>
+        </dependency>
+
+        <!--Milo客户端的依赖-->
+        <dependency>
+            <groupId>org.eclipse.milo</groupId>
+            <artifactId>sdk-client</artifactId>
+            <version>0.6.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.paho</groupId>
+            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
+            <version>1.2.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-jms-client</artifactId>
+            <version>0.61.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.intelligt.modbus</groupId>
+            <artifactId>jlibmodbus</artifactId>
+            <version>1.2.9.7</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 91 - 0
src/main/java/com/fjhx/MyMain.java

@@ -0,0 +1,91 @@
+package com.fjhx;
+
+import cn.hutool.cron.CronUtil;
+import cn.hutool.cron.task.Task;
+import com.alibaba.fastjson.JSONObject;
+import com.fjhx.emums.EquipmentEnum;
+import com.fjhx.entity.ConfigEntity;
+import com.fjhx.entity.ConnectConfig;
+import com.fjhx.equipment.EquipmentAbstract;
+import com.fjhx.utils.MyUtil;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+public class MyMain {
+
+    //    public static MqttClient mqttClient = new MqttClient();
+    public static ConfigEntity config;
+
+
+    public static void main(String[] args) {
+
+        System.out.println("version: 22.11.22");
+        MyUtil.infoLog("程序启动中...");
+
+        // 读取配置文件
+        if (!readConfigFile()) return;
+
+        List<ConnectConfig> connectConfigList = config.getConnectConfigList();
+
+        for (ConnectConfig connectConfig : connectConfigList) {
+            EquipmentAbstract equipment = EquipmentEnum.getEquipment(connectConfig);
+            if (equipment == null) continue;
+
+            CronUtil.schedule("0/3 * * * * *", (Task) () -> {
+                String data = equipment.readDataStr();
+                MyUtil.infoLog(data);
+
+                equipment.uploadIot(data);
+            });
+        }
+
+        CronUtil.setMatchSecond(true);
+        CronUtil.start();
+    }
+
+    /**
+     * 读取配置文件
+     */
+    public static boolean readConfigFile() {
+        try {
+            // 获取配置文件路径
+            File file = new File(MyUtil.dir + "\\config");
+            if (!file.exists()) {
+                MyUtil.errorLog("配置文件不存在");
+                return false;
+            }
+
+            // 读取配置文件
+            InputStreamReader read = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);
+            BufferedReader bufferedReader = new BufferedReader(read);
+            StringBuilder builder = new StringBuilder();
+            String lineTxt;
+            while ((lineTxt = bufferedReader.readLine()) != null) {
+                String trim = lineTxt.trim();
+                if (!trim.startsWith("#")) {
+                    builder.append(trim);
+                }
+            }
+
+            String json = builder.toString();
+
+            try {
+                config = JSONObject.parseObject(json, ConfigEntity.class);
+            } catch (Exception e) {
+                MyUtil.errorLog("配置文件格式错误");
+                return false;
+            }
+
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+}

+ 28 - 0
src/main/java/com/fjhx/client/ClientAbstract.java

@@ -0,0 +1,28 @@
+package com.fjhx.client;
+
+import com.fjhx.entity.ConnectConfig;
+import lombok.Getter;
+
+/**
+ * 链接抽象工厂
+ */
+@Getter
+public abstract class ClientAbstract {
+
+    protected ConnectConfig connectConfig;
+
+    public ClientAbstract(ConnectConfig connectConfig) {
+        this.connectConfig = connectConfig;
+    }
+
+    /**
+     * 开启链接
+     */
+    public abstract void connect();
+
+    /**
+     * 读取数据
+     */
+    public abstract Object readData();
+
+}

+ 105 - 0
src/main/java/com/fjhx/client/impl/ModbusTcpClient.java

@@ -0,0 +1,105 @@
+package com.fjhx.client.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fjhx.client.ClientAbstract;
+import com.fjhx.entity.ConnectConfig;
+import com.fjhx.entity.agreement.config.ModBusTcpConfig;
+import com.fjhx.entity.agreement.data.ModBusTcpData;
+import com.fjhx.utils.MyUtil;
+import com.intelligt.modbus.jlibmodbus.Modbus;
+import com.intelligt.modbus.jlibmodbus.master.ModbusMaster;
+import com.intelligt.modbus.jlibmodbus.master.ModbusMasterFactory;
+import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
+import lombok.SneakyThrows;
+
+import java.net.InetAddress;
+
+/**
+ * ModbusTcp链接实现
+ */
+public class ModbusTcpClient extends ClientAbstract {
+
+    static {
+        // 开启计数器
+        Modbus.setAutoIncrementTransactionId(true);
+    }
+
+    private final ModBusTcpConfig modBusTcpConfig;
+
+    private ModbusMaster client;
+
+    public ModbusTcpClient(ConnectConfig connectConfig) {
+        super(connectConfig);
+
+        JSONObject other = super.connectConfig.getOther();
+        modBusTcpConfig = null == other ? new ModBusTcpConfig() : other.toJavaObject(ModBusTcpConfig.class);
+    }
+
+    @SneakyThrows
+    @Override
+    public void connect() {
+        // 设置主机TCP参数
+        TcpParameters tcpParameters = new TcpParameters();
+        // TCP设置长连接
+        tcpParameters.setKeepAlive(true);
+        // 设置端口号
+        tcpParameters.setPort(connectConfig.getPort());
+        // TCP参数设置ip地址
+        tcpParameters.setHost(InetAddress.getByName(connectConfig.getIpAddress()));
+        // 创建一个主机
+        client = ModbusMasterFactory.createModbusMasterTCP(tcpParameters);
+        // 开启链接
+        client.connect();
+    }
+
+    @SneakyThrows
+    @Override
+    public Object readData() {
+        // 是否链接
+        boolean connected = client.isConnected();
+
+        ModBusTcpData modBusTcpData = new ModBusTcpData();
+
+        if (connected) {
+            Integer slavedId = modBusTcpConfig.getSlavedId();
+
+            // 0x
+            if (modBusTcpConfig.getCoilsQuantity() > 0) {
+                boolean[] coils = client.readCoils(slavedId,
+                        modBusTcpConfig.getCoilsOffSet(), modBusTcpConfig.getCoilsQuantity());
+
+                modBusTcpData.setCoils(coils);
+            }
+
+            // 1x
+            if (modBusTcpConfig.getDiscreteInputsQuantity() > 0) {
+                boolean[] discreteInputs = client.readDiscreteInputs(slavedId,
+                        modBusTcpConfig.getDiscreteInputsOffSet(), modBusTcpConfig.getDiscreteInputsQuantity());
+
+                modBusTcpData.setDiscreteInputs(discreteInputs);
+            }
+
+            // 3x
+            if (modBusTcpConfig.getInputRegistersQuantity() > 0) {
+                int[] inputRegisters = client.readInputRegisters(slavedId,
+                        modBusTcpConfig.getInputRegistersOffSet(), modBusTcpConfig.getInputRegistersQuantity());
+
+                modBusTcpData.setInputRegisters(inputRegisters);
+            }
+
+            // 4x
+            if (modBusTcpConfig.getHoldingRegistersQuantity() > 0) {
+                int[] holdingRegisters = client.readHoldingRegisters(slavedId,
+                        modBusTcpConfig.getHoldingRegistersOffSet(), modBusTcpConfig.getHoldingRegistersQuantity());
+
+                modBusTcpData.setHoldingRegisters(holdingRegisters);
+            }
+
+        } else {
+            MyUtil.errorLog("设备未连接");
+        }
+
+        return modBusTcpData;
+    }
+
+}

+ 105 - 0
src/main/java/com/fjhx/client/impl/OpcUaClient.java

@@ -0,0 +1,105 @@
+package com.fjhx.client.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fjhx.client.ClientAbstract;
+import com.fjhx.entity.ConnectConfig;
+import com.fjhx.entity.agreement.data.OpcUaData;
+import lombok.SneakyThrows;
+import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
+import org.eclipse.milo.opcua.sdk.client.nodes.UaNode;
+import org.eclipse.milo.opcua.stack.core.Identifiers;
+import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
+import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
+import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
+import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * opcUa链接实现
+ */
+public class OpcUaClient extends ClientAbstract {
+
+    private org.eclipse.milo.opcua.sdk.client.OpcUaClient client;
+
+    public OpcUaClient(ConnectConfig connectConfig) {
+        super(connectConfig);
+    }
+
+    @SneakyThrows
+    @Override
+    public void connect() {
+        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
+        Files.createDirectories(securityTempDir);
+        if (!Files.exists(securityTempDir)) {
+            throw new Exception("unable to create security dir: " + securityTempDir);
+        }
+
+        // 端口号
+        String port = ObjectUtil.isEmpty(connectConfig.getPort()) ? "" : ":" + connectConfig.getPort();
+
+        // 连接
+        client = org.eclipse.milo.opcua.sdk.client.OpcUaClient.create(
+                "opc.tcp://" + connectConfig.getIpAddress() + port,
+                endpoints -> endpoints.stream()
+                        .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
+                        .findFirst(),
+                configBuilder -> configBuilder
+                        .setApplicationName(LocalizedText.english("eclipse milo opc-ua client"))
+                        .setApplicationUri("urn:eclipse:milo:examples:client")
+                        //访问方式
+                        .setIdentityProvider(new AnonymousProvider())
+                        .setRequestTimeout(UInteger.valueOf(5000))
+                        .build());
+
+        //开启连接
+        client.connect().get();
+    }
+
+    @Override
+    public Object readData() {
+        List<OpcUaData> nodeList = new ArrayList<>();
+        browseNode(nodeList, null);
+        return nodeList;
+    }
+
+    /**
+     * 遍历树形节点
+     *
+     * @param uaNode 节点
+     */
+    @SneakyThrows
+    private void browseNode(List<OpcUaData> nodeList, UaNode uaNode) {
+        List<? extends UaNode> nodes;
+
+        if (uaNode == null) {
+            nodes = client.getAddressSpace().browseNodes(Identifiers.ObjectsFolder);
+        } else {
+            nodes = client.getAddressSpace().browseNodes(uaNode);
+        }
+
+        for (UaNode nd : nodes) {
+            // 排除系统行性节点,这些系统性节点名称一般都是以"_"开头
+            if (Objects.requireNonNull(nd.getBrowseName().getName()).contains("_")) {
+                continue;
+            }
+
+            NodeId nodeId = nd.getNodeId();
+
+            OpcUaData opcUaData = new OpcUaData();
+            opcUaData.setId(nodeId.getIdentifier().toString());
+            opcUaData.setNs(nodeId.getNamespaceIndex().toString());
+            opcUaData.setType(nodeId.getType().name());
+            opcUaData.setNodeName(nd.getBrowseName().getName());
+            nodeList.add(opcUaData);
+
+            browseNode(nodeList, nd);
+        }
+    }
+
+}

+ 33 - 0
src/main/java/com/fjhx/emums/AgreementEnum.java

@@ -0,0 +1,33 @@
+package com.fjhx.emums;
+
+import com.fjhx.client.ClientAbstract;
+import com.fjhx.client.impl.ModbusTcpClient;
+import com.fjhx.client.impl.OpcUaClient;
+import com.fjhx.entity.ConnectConfig;
+import lombok.Getter;
+import lombok.SneakyThrows;
+
+/**
+ * 协议枚举
+ */
+@Getter
+public enum AgreementEnum {
+
+    OpcUa(OpcUaClient.class),
+    ModbusTcp(ModbusTcpClient.class);
+
+    private final Class<? extends ClientAbstract> clientClass;
+
+    AgreementEnum(Class<? extends ClientAbstract> clientClass) {
+        this.clientClass = clientClass;
+    }
+
+    /**
+     * 获取链接
+     */
+    @SneakyThrows
+    public ClientAbstract getClient(ConnectConfig connectConfig) {
+        return clientClass.getDeclaredConstructor(ConnectConfig.class).newInstance(connectConfig);
+    }
+
+}

+ 64 - 0
src/main/java/com/fjhx/emums/EquipmentEnum.java

@@ -0,0 +1,64 @@
+package com.fjhx.emums;
+
+import com.fjhx.entity.ConnectConfig;
+import com.fjhx.equipment.EquipmentAbstract;
+import com.fjhx.equipment.impl.*;
+import com.fjhx.utils.MyUtil;
+import lombok.Getter;
+import lombok.SneakyThrows;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+public enum EquipmentEnum {
+
+    INJECTION_MOLDING_MACHINE(1, "注塑机", AgreementEnum.OpcUa, InjectionMoldingMachineEquipment.class),
+    ROLL_PRINTER(2, "滚印机", AgreementEnum.ModbusTcp, RollPrinterEquipment.class),
+    ASSEMBLING_MACHINE(3, "组装机", AgreementEnum.ModbusTcp, AssemblingMachineEquipment.class),
+    THREADED_HEAD(4, "螺纹头", AgreementEnum.ModbusTcp, ThreadedHeadEquipment.class),
+    INJECTION_NEEDLE(5, "注射针", AgreementEnum.ModbusTcp, InjectionNeedleEquipment.class);
+
+    EquipmentEnum(Integer type, String typeName, AgreementEnum agreementEnum, Class<? extends EquipmentAbstract> equipment) {
+        this.type = type;
+        this.typeName = typeName;
+        this.agreementEnum = agreementEnum;
+        this.equipment = equipment;
+    }
+
+    // 设备类型
+    private final Integer type;
+    // 类型名称
+    private final String typeName;
+    // 协议
+    private final AgreementEnum agreementEnum;
+    // 设备工厂
+    private final Class<? extends EquipmentAbstract> equipment;
+
+    // 枚举map
+    private static final Map<Integer, EquipmentEnum> map = new HashMap<>();
+
+    static {
+        for (EquipmentEnum value : EquipmentEnum.values()) {
+            map.put(value.type, value);
+        }
+    }
+
+    /**
+     * 获取设备对象
+     */
+    @SneakyThrows
+    public static EquipmentAbstract getEquipment(ConnectConfig connectConfig) {
+        EquipmentEnum equipmentEnum = map.get(connectConfig.getType());
+
+        if (equipmentEnum == null) {
+            MyUtil.errorLog("没有指定的设备类型:" + connectConfig.getType());
+            return null;
+        }
+
+        EquipmentAbstract equipmentAbstract = equipmentEnum.equipment.newInstance();
+        equipmentAbstract.init(connectConfig, equipmentEnum.agreementEnum);
+        return equipmentAbstract;
+    }
+
+}

+ 38 - 0
src/main/java/com/fjhx/entity/ConfigEntity.java

@@ -0,0 +1,38 @@
+package com.fjhx.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class ConfigEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 调试模式
+     */
+    private Integer debug;
+
+    /**
+     * 服务ip
+     */
+    private String serverIp;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 密钥
+     */
+    private String secret;
+
+    /**
+     * 设备配置
+     */
+    private List<ConnectConfig> connectConfigList;
+
+}

+ 36 - 0
src/main/java/com/fjhx/entity/ConnectConfig.java

@@ -0,0 +1,36 @@
+package com.fjhx.entity;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class ConnectConfig implements Serializable {
+
+    /**
+     * 设备编号
+     */
+    private String equipmentNo;
+
+    /**
+     * 设备ip地址
+     */
+    private String ipAddress;
+
+    /**
+     * 设备端口号
+     */
+    private Integer port;
+
+    /**
+     * 设备类型
+     */
+    private Integer type;
+
+    /**
+     * 其他配置
+     */
+    private JSONObject other;
+
+}

+ 22 - 0
src/main/java/com/fjhx/entity/UploadEntity.java

@@ -0,0 +1,22 @@
+package com.fjhx.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class UploadEntity extends ConnectConfig {
+
+    /**
+     * 记录时间
+     */
+    private Date createTime;
+
+    /**
+     * 生成数据
+     */
+    private Object data;
+
+}

+ 53 - 0
src/main/java/com/fjhx/entity/agreement/config/ModBusTcpConfig.java

@@ -0,0 +1,53 @@
+package com.fjhx.entity.agreement.config;
+
+import lombok.Data;
+
+@Data
+public class ModBusTcpConfig {
+
+    /**
+     * 从机地址
+     */
+    Integer slavedId = 1;
+
+    /**
+     * 0x开始读取地址
+     */
+    Integer coilsOffSet = 0;
+
+    /**
+     * 0x读取位数
+     */
+    Integer coilsQuantity = 100;
+
+    /**
+     * 1x开始读取地址
+     */
+    Integer discreteInputsOffSet = 0;
+
+    /**
+     * 1x读取位数
+     */
+    Integer discreteInputsQuantity = 100;
+
+    /**
+     * 3x开始读取地址
+     */
+    Integer inputRegistersOffSet = 0;
+
+    /**
+     * 3x读取位数
+     */
+    Integer inputRegistersQuantity = 100;
+
+    /**
+     * 4x开始读取地址
+     */
+    Integer holdingRegistersOffSet = 0;
+
+    /**
+     * 4x读取位数
+     */
+    Integer holdingRegistersQuantity = 100;
+
+}

+ 47 - 0
src/main/java/com/fjhx/entity/agreement/data/ModBusTcpData.java

@@ -0,0 +1,47 @@
+package com.fjhx.entity.agreement.data;
+
+import cn.hutool.core.convert.Convert;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ModBusTcpData {
+
+    /**
+     * 0x
+     */
+    List<Boolean> coils;
+
+    /**
+     * 1x
+     */
+    List<Boolean> discreteInputs;
+
+    /**
+     * 3x
+     */
+    List<Integer> inputRegisters;
+
+    /**
+     * 4x
+     */
+    List<Integer> holdingRegisters;
+
+    public void setCoils(boolean[] coils) {
+        this.coils = Convert.toList(Boolean.class, coils);
+    }
+
+    public void setDiscreteInputs(boolean[] discreteInputs) {
+        this.discreteInputs = Convert.toList(Boolean.class, discreteInputs);
+    }
+
+    public void setInputRegisters(int[] inputRegisters) {
+        this.inputRegisters = Convert.toList(Integer.class, inputRegisters);
+    }
+
+    public void setHoldingRegisters(int[] holdingRegisters) {
+        this.holdingRegisters = Convert.toList(Integer.class, holdingRegisters);
+    }
+
+}

+ 28 - 0
src/main/java/com/fjhx/entity/agreement/data/OpcUaData.java

@@ -0,0 +1,28 @@
+package com.fjhx.entity.agreement.data;
+
+import lombok.Data;
+
+@Data
+public class OpcUaData {
+
+    /**
+     * 节点id
+     */
+    private String id;
+
+    /**
+     * 节点名称
+     */
+    private String nodeName;
+
+    /**
+     * ns
+     */
+    private String ns;
+
+    /**
+     * 节点类型
+     */
+    private String type;
+
+}

+ 78 - 0
src/main/java/com/fjhx/equipment/EquipmentAbstract.java

@@ -0,0 +1,78 @@
+package com.fjhx.equipment;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fjhx.client.ClientAbstract;
+import com.fjhx.emums.AgreementEnum;
+import com.fjhx.entity.ConnectConfig;
+import com.fjhx.entity.UploadEntity;
+import com.fjhx.utils.MqttClient;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class EquipmentAbstract {
+
+    // 初始化华为IoTDA监听
+    protected static MqttClient mqttClient = new MqttClient();
+
+    protected ConnectConfig connectConfig;
+    protected ClientAbstract client;
+
+    static {
+        mqttClient.connect();
+    }
+
+    /**
+     * 初始化
+     *
+     * @param connectConfig 连接信息
+     */
+    public void init(ConnectConfig connectConfig, AgreementEnum agreementEnum) {
+        // 记录链接配置
+        this.connectConfig = connectConfig;
+        // 开启链接
+        this.client = agreementEnum.getClient(connectConfig);
+        client.connect();
+    }
+
+    /**
+     * 读取数据
+     */
+    public Object readData() {
+        return client.readData();
+    }
+
+    public String readDataStr() {
+        return JSONObject.toJSONString(readData());
+    }
+
+    /**
+     * 把数据推送到华为云Iot
+     */
+    public void uploadIot(Object object) {
+
+        ConnectConfig connectConfig = client.getConnectConfig();
+
+        UploadEntity uploadEntity = BeanUtil.toBean(connectConfig, UploadEntity.class);
+        uploadEntity.setCreateTime(new Date());
+        uploadEntity.setData(object);
+
+        Map<String, Object> properties = new HashMap<>();
+        properties.put("DeviceData", JSON.toJSONString(uploadEntity));
+
+        Map<String, Object> service = new HashMap<>();
+        service.put("service_id", "Data");
+        service.put("properties", properties);
+
+        Map<Object, Object> services = new HashMap<>();
+        services.put("services", Collections.singletonList(service));
+
+        // 上传统计数据到华为IoTDA
+        mqttClient.publishMessage(JSON.toJSONString(services));
+    }
+
+}

+ 10 - 0
src/main/java/com/fjhx/equipment/impl/AssemblingMachineEquipment.java

@@ -0,0 +1,10 @@
+package com.fjhx.equipment.impl;
+
+import com.fjhx.equipment.EquipmentAbstract;
+
+/**
+ * 组装机
+ */
+public class AssemblingMachineEquipment extends EquipmentAbstract {
+
+}

+ 10 - 0
src/main/java/com/fjhx/equipment/impl/InjectionMoldingMachineEquipment.java

@@ -0,0 +1,10 @@
+package com.fjhx.equipment.impl;
+
+import com.fjhx.equipment.EquipmentAbstract;
+
+/**
+ * 注塑机
+ */
+public class InjectionMoldingMachineEquipment extends EquipmentAbstract {
+
+}

+ 10 - 0
src/main/java/com/fjhx/equipment/impl/InjectionNeedleEquipment.java

@@ -0,0 +1,10 @@
+package com.fjhx.equipment.impl;
+
+import com.fjhx.equipment.EquipmentAbstract;
+
+/**
+ * 注射针
+ */
+public class InjectionNeedleEquipment  extends EquipmentAbstract {
+
+}

+ 10 - 0
src/main/java/com/fjhx/equipment/impl/RollPrinterEquipment.java

@@ -0,0 +1,10 @@
+package com.fjhx.equipment.impl;
+
+import com.fjhx.equipment.EquipmentAbstract;
+
+/**
+ * 滚印机
+ */
+public class RollPrinterEquipment extends EquipmentAbstract {
+
+}

+ 10 - 0
src/main/java/com/fjhx/equipment/impl/ThreadedHeadEquipment.java

@@ -0,0 +1,10 @@
+package com.fjhx.equipment.impl;
+
+import com.fjhx.equipment.EquipmentAbstract;
+
+/**
+ * 螺纹头
+ */
+public class ThreadedHeadEquipment extends EquipmentAbstract {
+
+}

+ 267 - 0
src/main/java/com/fjhx/utils/MqttClient.java

@@ -0,0 +1,267 @@
+package com.fjhx.utils;
+
+import com.fjhx.MyMain;
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class MqttClient {
+
+    private final int qosLevel = 1;
+    private MqttAsyncClient client;
+
+    private boolean connectFlag = false;
+
+    // mqtts加密连接
+    private final boolean isSSL = true;
+
+    /**
+     * mqtt建链
+     */
+    public void connect() {
+
+        String url;
+        if (isSSL) {
+            url = "ssl://" + MyMain.config.getServerIp() + ":" + 8883; //mqtts连接
+        } else {
+            url = "tcp://" + MyMain.config.getServerIp() + ":" + 1883; //mqtt连接
+        }
+        try {
+            MqttConnectOptions options = new MqttConnectOptions();
+            if (isSSL) {
+                options.setSocketFactory(getOptionSocketFactory(MyUtil.dir + "\\ca.jks"));
+                options.setHttpsHostnameVerificationEnabled(false);
+            }
+            options.setCleanSession(false);
+            options.setKeepAliveInterval(120);
+            options.setConnectionTimeout(5000);
+            options.setAutomaticReconnect(true);
+            options.setUserName(MyMain.config.getDeviceId());
+            options.setPassword(getPassword().toCharArray());
+
+            //设置MqttClient
+            client = new MqttAsyncClient(url, getClientId(), new MemoryPersistence());
+            client.setCallback(callback);
+            //建立连接
+            client.connect(options, null, new IMqttActionListener() {
+
+                @Override
+                public void onSuccess(IMqttToken iMqttToken) {
+                    connectFlag = true;
+
+                    MyUtil.infoLog("连接成功");
+                }
+
+                @Override
+                public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
+                    MyUtil.errorLog("iot连接失败,正在尝试重新连接");
+
+                    MyUtil.sleep(5 * 1000);
+                    MqttClient.this.connect();
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        while (!connectFlag) {
+            MyUtil.sleep(500L);
+        }
+
+    }
+
+    /**
+     * 上报json数据,注意serviceId要与Profile中的定义对应
+     */
+    public void publishMessage(String jsonMsg) {
+        MqttMessage message = new MqttMessage(jsonMsg.getBytes());
+        try {
+            client.publish(getReportTopic(), message, qosLevel, new IMqttActionListener() {
+
+                @Override
+                public void onSuccess(IMqttToken iMqttToken) {
+//                    publishMessageCallback.onSuccess();
+                }
+
+                @Override
+                public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
+//                    publishMessageCallback.onFailure();
+                }
+
+            });
+        } catch (MqttException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Mqtt回调
+     */
+    public MqttCallback callback = new MqttCallbackExtended() {
+
+        @Override
+        public void connectComplete(boolean reconnect, String serviceURI) {
+            subScribeTopic();
+        }
+
+        @Override
+        public void connectionLost(Throwable throwable) {
+            MyUtil.errorLog("Connection lost.");
+            //可在此处实现重连
+        }
+
+        @Override
+        public void messageArrived(String topic, MqttMessage message) {
+            MyUtil.errorLog("Receive mqtt topic:" + topic + ", message:" + message);
+        }
+
+        @Override
+        public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
+
+        }
+
+    };
+
+    /**
+     * 订阅接收命令topic
+     */
+    public void subScribeTopic() {
+        try {
+            client.subscribe(getCmdRequestTopic(), qosLevel, null, new IMqttActionListener() {
+
+                @Override
+                public void onSuccess(IMqttToken iMqttToken) {
+
+                }
+
+                @Override
+                public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
+                    MyUtil.errorLog("Subscribe mqtt topic fail");
+                }
+
+            });
+        } catch (MqttException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 属性上报topic
+     */
+    private String getReportTopic() {
+        return "$oc/devices/" + MyMain.config.getDeviceId() + "/sys/properties/report";
+    }
+
+    /**
+     * 订阅命令下发topic
+     */
+    private String getCmdRequestTopic() {
+        return "$oc/devices/" + MyMain.config.getDeviceId() + "/sys/commands/#";
+    }
+
+    /**
+     * 加载SSL证书
+     *
+     * @param certPath 证书存放的相对路径
+     */
+    private SocketFactory getOptionSocketFactory(String certPath) {
+        SSLContext sslContext;
+
+        InputStream stream = null;
+        try {
+            stream = new FileInputStream(certPath);
+            sslContext = SSLContext.getInstance("TLS");
+            KeyStore ts = KeyStore.getInstance("JKS");
+            ts.load(stream, null);
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            tmf.init(ts);
+            TrustManager[] tm = tmf.getTrustManagers();
+            sslContext.init(null, tm, new SecureRandom());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        } finally {
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return sslContext.getSocketFactory();
+    }
+
+    /***
+     * 调用sha256算法进行哈希
+     */
+    private String sha256_mac(String message, String tStamp) {
+        String passWord = null;
+        try {
+            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+            SecretKeySpec secret_key = new SecretKeySpec(tStamp.getBytes(), "HmacSHA256");
+            sha256_HMAC.init(secret_key);
+            byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
+            passWord = byteArrayToHexString(bytes);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return passWord;
+    }
+
+    /***
+     * byte数组转16进制字符串
+     */
+    private String byteArrayToHexString(byte[] b) {
+        StringBuilder hs = new StringBuilder();
+        String stmp;
+        for (int n = 0; b != null && n < b.length; n++) {
+            stmp = Integer.toHexString(b[n] & 0XFF);
+            if (stmp.length() == 1) {
+                hs.append('0');
+            }
+            hs.append(stmp);
+        }
+        return hs.toString().toLowerCase();
+    }
+
+    /***
+     * 要求:10位数字
+     */
+    private String getTimeStamp() {
+        return ZonedDateTime.ofInstant(Instant.now(), ZoneId.of("UTC")).format(DateTimeFormatter.ofPattern("yyyyMMddHH"));
+    }
+
+    private String getClientId() {
+        return MyMain.config.getDeviceId() + "_0_0_" + getTimeStamp();
+    }
+
+    private String getPassword() {
+        return sha256_mac(MyMain.config.getSecret(), getTimeStamp());
+    }
+
+    private void close() {
+        try {
+            client.disconnect();
+            client.close();
+        } catch (MqttException e) {
+            e.printStackTrace();
+        }
+    }
+
+}

+ 84 - 0
src/main/java/com/fjhx/utils/MyUtil.java

@@ -0,0 +1,84 @@
+package com.fjhx.utils;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.fjhx.MyMain;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.util.Date;
+
+public class MyUtil {
+
+    // 程序存放地址
+    public static final String dir = System.getProperty("user.dir");
+
+    public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
+    public static final String TIME_FORMAT = "HH:mm:ss.SSS";
+    public static final String DATE_FORMAT = "yyyy-MM-dd";
+
+    public static void sleep(long l) {
+        try {
+            Thread.sleep(l);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * info级别日志
+     */
+    public static void infoLog(String jsonStr) {
+        write(jsonStr, "log\\info");
+    }
+
+    /**
+     * error级别日志
+     */
+    public static void errorLog(String jsonStr) {
+        write(jsonStr, "log\\error");
+    }
+
+    /**
+     * 写入本地数据
+     *
+     * @param text     写入数据
+     * @param pathName 写入路径
+     */
+    private static void write(String text, String pathName) {
+        String path = dir + "\\" + pathName;
+        File file = new File(path);
+        if (!file.exists()) {
+            boolean mkdirs = file.mkdirs();
+            if (!mkdirs) {
+                System.out.println("文件夹创建失败");
+                return;
+            }
+        }
+
+        Date date = new Date();
+        OutputStreamWriter osw = null;
+        FileOutputStream fos = null;
+        try {
+            String filePath = path + "\\" + DateUtil.format(date, DATE_FORMAT) + ".log";
+            fos = new FileOutputStream(filePath, true);
+            osw = new OutputStreamWriter(fos);
+
+            text = " =====》 " + text;
+            System.out.println(DateUtil.format(date, DATE_TIME_FORMAT) + text);
+
+            if (MyMain.config == null || ObjectUtil.equals(MyMain.config.getDebug(), 1)) {
+                osw.write(DateUtil.format(date, TIME_FORMAT) + text + "\r\n");
+            }
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            IoUtil.close(osw);
+            IoUtil.close(fos);
+        }
+    }
+
+}