diff --git a/.idea/iotos-soft-gateway-demo.iml b/.idea/iotos-soft-gateway-demo.iml
index d2c34ec9145916e1565778a924e3e07f21443433..b71efcc2180d873dc4678b356f45c1b25ed52075 100644
--- a/.idea/iotos-soft-gateway-demo.iml
+++ b/.idea/iotos-soft-gateway-demo.iml
@@ -11,9 +11,9 @@
-
-
-
+
+
+
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 3757d9c31574901a1bfd124e5ef351adfbc9346e..14c1ed9ed84ce0d947a511de109f8fe3548e5a62 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -1,6 +1,11 @@
+
+
+
+
+
diff --git a/README.md b/README.md
index df91b9ee78439153e449685eb6bc0031349813a1..a1e56200d2666f3b1bf1dd269ad158cb9470756a 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,149 @@ tcp 和 udp 按需依赖。
如果 sdk 不能满足,可以 fork sdk 项目,提交 pr,或者自行 fork 之后按照项目发布说明发布到自己的仓库,然后依赖地址改为自己的 git 地址即可。
+## 基本使用
+
+**本软网关封装功能依赖于IoTOS 平台的网关的远程配置功能。**
+
+使用者操作流程如下(黄色部分是与软件网关相关的步骤):
+
+
+
+**第一步:注册登录 IoTOS**
+因 IoTOS 以私有化部署为主,绝大部分情况下开发者可以 superadmin(即超级管理员)登录内网里部署的
+IoTOS,本文以 [ IoTOS 体验站点](http://IoTOS-demo.hekr.me/)为例。
+
+**第二步:创建软件网关产品及设备**
+进入产品中心-产品开发,点击“创建产品”,建立软件网关,“产品信息”栏目根据实际需求而定,“节点类型”和“联网与数据”栏目配置图如下:
+
+
+
+
+
+进入产品中心-设备管理,点击“创建设备”,其中设备 ID 后续会在软件网关代码里使用,取名方法根据实际需求而定。
+
+
+
+**第三步:创建子设备产品及设备**
+进入产品中心-产品开发,点击“创建产品”,“产品信息”栏目根据实际需求而定,“节点类型”和“联网与数据”栏目配置图如下:
+
+
+
+
+
+若使用者要求规范设备 ID,建议进入产品中心-设备管理,点击“批量添加”,使用表格模板实现批量导入。
+
+
+
+*注:此时软件网关的数据转码环节中子设备 ID 和表格应一一对应。*
+
+**第四步:查看并记录网关以及子设备信息**
+进入产品中心-设备管理,点击软件网关的右侧“查看”按钮。
+
+
+
+获取到软件网关 PK、设备 ID 和 devSecret。
+
+
+
+然后以相同的方式获取到子设备的产品 PK、设备 ID。
+
+**第五步:获取并配置网关设备信息**
+进入 IoTOS -产品中心-产品开发,点击上一步创建的软件网关产品,可以获取到 MQTT 接入方式信息,以此为 HOST 值。
+
+
+进入项目路径 `src/main/resources`,打开配置文件 `application.yml` 进行参数配置。
+
+配置文件可以参考 [application.yml](subsystem/src/main/resources/application.yml) 以下配置项为软件网关配置的必填信息
+
+```yaml
+# mqtt配置(必填)
+# 进入产品中心-产品开发-软件网关,"MQTT接入方式"栏目即可查询
+connect.mqtt.endpoint: 106.75.50.110:1883
+# 软件网关的产品pk,进入产品中心-设备管理-软件网关,"产品pk"栏目即可查询
+gateway.pk: fc5dbdd26fee4688a6ab35b63a294cc1
+# 软件网关的设备id,进入产品中心-设备管理-软件网关,"设备id"栏目即可查询
+gateway.devId: gatewaydemo
+# 软件网关的设备密钥,进入产品中心-设备管理-软件网关,"devSecret"栏目点击"复制"按钮即可查询
+gateway.devSecret: d10d6a46f6b5462b88f0d07207479bd2
+```
+
+**第六步:程序运行**
+
+进入项目路径并打开入口程序 [IoTGatewayApplication](src/main/java/me/hekr/iotos/softgateway/IoTGatewayApplication.java)
+
+运行成功后,打开 IoTOS 平台,查看这个网关设备,可以看到设备已经在线,查看 `上下行数据`,可以查看网关设备发送的数据。
+
+**第六步:添加子设备**
+
+打开网关产品的 `远程配置` 标签,选择该网关设备,然后添加如下内容,其中 `子设备 pk` 内容改为上面自己创建的子设备的产品 pk。
+
+```text
+{"pk":"子设备 pk","devId":"demo_subsystem_001","subsystemTerminal":"0001","devName":"demo子系统终端001"}
+{"pk":"子设备 pk","devId":"demo_subsystem_002","subsystemTerminal":"0002","devName":"demo子系统终端002"}
+```
+
+
+
+添加成功后刷新 IoTOS 平台设备列表,可以看到添加了2个新的子设备;但是子设备没有在线,这个需要配合自己的业务进行处理,会在下面进行说明。
+
+可以尝试修改远程配置的内容,删除第一条记录,保存并启用后,查看网关设备的子设备列表,会发现设备列表中只存在一个子设备了。
+
+
+## 业务开发
+
+上面演示中之所以子设备能够自动生成,是因为网关的远程配置功能。配置内容**每行**是一个 `json 对象`。其中 `pk` 、 `devId` 和 `devName` 分别是 IoTOS
+平台上的子设备的 pk,devId 和设备名称,动态注册的时候会根据这3个属性进行注册。 其他的属性根据子系统进行配置,比如子系统中唯一标识设备的属性叫做 `terminalId`
+,则可以使用 `terminalId` 做映射;如果有其他也需要的属性可以一并添加。
+
+### 子设备登录、登出
+
+调用 `KlinkService#devLogin` 方法可以使子设备在线;`devLogout` 则可以使子设备离线。
+
+### 发送业务数据
+
+发送的业务数据的字段需要在产品的[物模型](http://hy.hekr.me/iot-docs-test/web/content/%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5/%E7%89%A9%E6%A8%A1%E5%9E%8B.html)中定义,并且定义相应的命令。
+
+发送数据使用方法: `KlinkService#devSend`。该方法重载了2个方法:
+
+- `public void devSend(String pk, String devId, String cmd)` 可以只发送命令
+- `public void devSend(String pk, String devId, String cmd, Map params)` 发送命令和参数
+
+#### 设备映射
+
+DeviceRemoteConfig 类做了设备映射关系;该关系是通过服务启动的时候自动获取远程配置或者主动更新远程配置来做映射的。
+
+主要方法有:
+
+- `public static Set getAll()` 获取所有设备信息
+- `public static Optional getByPkAndDevId(String pk, String devId)` 根据 pk 和 devId
+ 获取设备信息
+- `public static Optional getBySubSystemProperties(Props p)` 根据子系统的设备属性获取设备信息
+- `public static String getStatus()` 获取状态信息
+- `public String getPk()` 获取设备的 pk
+- `public String getDevId()` 获取设备的 devId
+- `public String getDevName()` 获取设备的名字
+- `public T getProp(String prop)` 根据属性名字获取设备属性值,注意远程配置中数据类型
+
+### 下发命令处理
+
+框架封装了下发命令处理过程,只需要实现 `SubsystemCommandService` 接口并根据要求定义成 Spring 的 bean 即可,Bean要求:
+
+实现类要加 `@Service("{CMD}@SubSystemCommandService")`,其中 `{CMD}` 为 IoTOS 物模型命令。
+
+实现方法 `void handle(DeviceRemoteConfig deviceRemoteConfig, ModelData data)`;参数 `deviceRemoteConfig` 是控制的设备, `data`
+是物模型信息,实际需要参考子产品定义的物模型。
+
+### 其他开发接口
+
+- `MqttDisConnectListener` mqtt 连接监听,可以参考 `CoreMqttConnectedListenerImpl`
+ 实现;如果需要在软网关连接建立或者重连的时候进行业务处理,可以实现这个接口
+- `MqttDisConnectListener` mqtt 断开连接监听,可以参考 `CoreMqttDisConnectListenerImpl`
+ 实现;如果需要在软网关连接断开的时候进行业务处理,可以实现这个接口
+- `TcpMessageListener` tcp server 消息处理监听器
+- `CommonMessageListener` tcp client, udp client, udp server 消息处理监听器
+- `EventListener` 事件监听器
+
## 打包
开发完成后,将网关和子设备产品导出,(如果有其他文件也可以)放到 docs 文件夹下,
diff --git a/pics/addDevGateway.png b/pics/addDevGateway.png
new file mode 100644
index 0000000000000000000000000000000000000000..a00227f72d20ac18f6ff13b5cc9d5579b142d423
Binary files /dev/null and b/pics/addDevGateway.png differ
diff --git a/pics/addProdGateway1.png b/pics/addProdGateway1.png
new file mode 100644
index 0000000000000000000000000000000000000000..cf6bcbc032bda28a9d892b583c709d596d494582
Binary files /dev/null and b/pics/addProdGateway1.png differ
diff --git a/pics/addProdGateway2.png b/pics/addProdGateway2.png
new file mode 100644
index 0000000000000000000000000000000000000000..6e06b8c02cfc4f6970c65087be2ade3d7eb0441a
Binary files /dev/null and b/pics/addProdGateway2.png differ
diff --git a/pics/addProdSub1.png b/pics/addProdSub1.png
new file mode 100644
index 0000000000000000000000000000000000000000..866cb23e1a4c49ba111f9ca7bd72ed40d97d11e5
Binary files /dev/null and b/pics/addProdSub1.png differ
diff --git a/pics/addProdSub2.png b/pics/addProdSub2.png
new file mode 100644
index 0000000000000000000000000000000000000000..43d4fff7bf3750afcffd2c7ab3ff1ebec169a3d3
Binary files /dev/null and b/pics/addProdSub2.png differ
diff --git a/pics/batchImportSub.png b/pics/batchImportSub.png
new file mode 100644
index 0000000000000000000000000000000000000000..2ec7d24094ec61dc77aae8bd8ff75c03c7c1ace4
Binary files /dev/null and b/pics/batchImportSub.png differ
diff --git a/pics/designInstruction.png b/pics/designInstruction.png
new file mode 100644
index 0000000000000000000000000000000000000000..59d7517ac018e4e9075a2fdba95ef8dfae63a3a6
Binary files /dev/null and b/pics/designInstruction.png differ
diff --git a/pics/encryptUtil.png b/pics/encryptUtil.png
new file mode 100644
index 0000000000000000000000000000000000000000..52d416ba750c5d8fb52f812e5ea72ff689745a4c
Binary files /dev/null and b/pics/encryptUtil.png differ
diff --git a/pics/gatewayConfig.png b/pics/gatewayConfig.png
new file mode 100644
index 0000000000000000000000000000000000000000..76edeffa94491d36e8fd8b70c8939c4e856a4327
Binary files /dev/null and b/pics/gatewayConfig.png differ
diff --git a/pics/gatewayRemoteConfig.jpg b/pics/gatewayRemoteConfig.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b9ec100fddea8bd7d8a239702d63dc48c11da410
Binary files /dev/null and b/pics/gatewayRemoteConfig.jpg differ
diff --git a/pics/gatewayRemoteConfigSubDevices.jpg b/pics/gatewayRemoteConfigSubDevices.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e1b9ce3461c7b00a3f84ff68210dd076d84e882b
Binary files /dev/null and b/pics/gatewayRemoteConfigSubDevices.jpg differ
diff --git a/pics/getGatewayInfo.png b/pics/getGatewayInfo.png
new file mode 100644
index 0000000000000000000000000000000000000000..d70ea99f363ffc55d9b9334dbaefd440605db8be
Binary files /dev/null and b/pics/getGatewayInfo.png differ
diff --git a/pics/httpClient.png b/pics/httpClient.png
new file mode 100644
index 0000000000000000000000000000000000000000..0f85896f066703cf8064e5bc38bd5a4b79c65670
Binary files /dev/null and b/pics/httpClient.png differ
diff --git a/pics/northProxy.png b/pics/northProxy.png
new file mode 100644
index 0000000000000000000000000000000000000000..96f6a204d7819d8174eec4707fca71e909d4f93c
Binary files /dev/null and b/pics/northProxy.png differ
diff --git a/pics/operationSequence.png b/pics/operationSequence.png
new file mode 100644
index 0000000000000000000000000000000000000000..916a49454499f938db5e1663248fc31b844a0352
Binary files /dev/null and b/pics/operationSequence.png differ
diff --git a/pics/pluginAsClient.png b/pics/pluginAsClient.png
new file mode 100644
index 0000000000000000000000000000000000000000..8048de3e4383199799f98f741096676014288ffb
Binary files /dev/null and b/pics/pluginAsClient.png differ
diff --git a/pics/pluginAsServer.png b/pics/pluginAsServer.png
new file mode 100644
index 0000000000000000000000000000000000000000..7fb3ac938618814e13894827cf9336050bb30972
Binary files /dev/null and b/pics/pluginAsServer.png differ
diff --git a/pics/postmanTest.png b/pics/postmanTest.png
new file mode 100644
index 0000000000000000000000000000000000000000..8a4a7a6c7ddd9cb27e185a863b9923070dd8fc1c
Binary files /dev/null and b/pics/postmanTest.png differ
diff --git a/pics/runHttpServer.png b/pics/runHttpServer.png
new file mode 100644
index 0000000000000000000000000000000000000000..30c9773617630a6e8299c4bbfdbe5c1768166120
Binary files /dev/null and b/pics/runHttpServer.png differ
diff --git a/pics/structureOverall.png b/pics/structureOverall.png
new file mode 100644
index 0000000000000000000000000000000000000000..079aec932eff07574a016c560a4b6d65abf5812a
Binary files /dev/null and b/pics/structureOverall.png differ
diff --git a/pics/tcpClientLoginSend.png b/pics/tcpClientLoginSend.png
new file mode 100644
index 0000000000000000000000000000000000000000..6940987754f8242656678206292ffa9deadba4e4
Binary files /dev/null and b/pics/tcpClientLoginSend.png differ
diff --git a/pics/tcpClientSendMsg.png b/pics/tcpClientSendMsg.png
new file mode 100644
index 0000000000000000000000000000000000000000..7fb035a382d9d3223962a402d2dea775d477359f
Binary files /dev/null and b/pics/tcpClientSendMsg.png differ
diff --git a/pics/tcpServerLoginRecv.png b/pics/tcpServerLoginRecv.png
new file mode 100644
index 0000000000000000000000000000000000000000..2468b109016717b242b34bac42e566925b962364
Binary files /dev/null and b/pics/tcpServerLoginRecv.png differ
diff --git a/pics/tcpServerLoginSend.png b/pics/tcpServerLoginSend.png
new file mode 100644
index 0000000000000000000000000000000000000000..36c414590247f27205aff151959d413ed9ccbfe5
Binary files /dev/null and b/pics/tcpServerLoginSend.png differ
diff --git a/pics/tcpServerRecvMsg.png b/pics/tcpServerRecvMsg.png
new file mode 100644
index 0000000000000000000000000000000000000000..e5991ef717e2e37cac6374a8f67649875593f8b6
Binary files /dev/null and b/pics/tcpServerRecvMsg.png differ
diff --git a/pics/tcpServerSendMsg.png b/pics/tcpServerSendMsg.png
new file mode 100644
index 0000000000000000000000000000000000000000..1566e7e8aa27f745286aaa6b3c251bb77e68547f
Binary files /dev/null and b/pics/tcpServerSendMsg.png differ
diff --git a/pics/toolOnline.png b/pics/toolOnline.png
new file mode 100644
index 0000000000000000000000000000000000000000..30f8fc01eddf53069a37b4bfe15953d37ff6c86b
Binary files /dev/null and b/pics/toolOnline.png differ
diff --git a/pics/utils.png b/pics/utils.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3c2a383aa1e366eb1d1130c89f54cf6d4a74eb3
Binary files /dev/null and b/pics/utils.png differ
diff --git a/pics/viewGateway1.png b/pics/viewGateway1.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ed3109308c8aae17d03a5ba66567660f991fae7
Binary files /dev/null and b/pics/viewGateway1.png differ
diff --git a/pics/viewGateway2.png b/pics/viewGateway2.png
new file mode 100644
index 0000000000000000000000000000000000000000..0ba594e83cf54459d3c09aefc3a83ddddf66958b
Binary files /dev/null and b/pics/viewGateway2.png differ
diff --git a/pom.xml b/pom.xml
index 2a87494a2a010456727c1cc683ef7041b02cc5e5..93c9fdc6580ea86978fffb916e73f378d2abbbdd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,25 +2,28 @@
+
+ 8
+ 8
+ 3.0.0-SNAPSHOT
+
+
iotos-soft-gateway
me.hekr.iotos.softgateway
- 0.0.1
+ ${iotos.softgateway.version}
4.0.0
jar
iotos-soft-gateway-demo
-
- 8
- 8
- 2.0.1-SNAPSHOT
-
-
hekr-iotos-soft-gateway
- https://gitee.com/geekhekr/iotos-soft-gateway/raw/master/maven/repository
+
+
+
+ https://gitee.com/geekhekr/iotos-soft-gateway/raw/3.0.0-SNAPSHOT/maven/repository
diff --git a/src/main/java/me/hekr/iotos/softgateway/subsystem/dto/RadioDevice.java b/src/main/java/me/hekr/iotos/softgateway/subsystem/dto/RadioDevice.java
index 797c9fe2493a8ece4f2c2ea8844abe2890cd2502..45a1e42a41293c2eedd145e285178b5cdd446717 100644
--- a/src/main/java/me/hekr/iotos/softgateway/subsystem/dto/RadioDevice.java
+++ b/src/main/java/me/hekr/iotos/softgateway/subsystem/dto/RadioDevice.java
@@ -25,6 +25,12 @@ public class RadioDevice implements DeviceMapper {
/** 播放状态 0 停止, 1 播放, 2 暂停 */
private int playStat;
+ public RadioDevice(String radioDevId) {
+ this.radioDevId = radioDevId;
+ }
+
+ public RadioDevice() {}
+
public static RadioDevice parse(DeviceRemoteConfig device) {
RadioDevice dev = new RadioDevice();
dev.setRadioDevId(device.getProp(RADIO_DEV_ID));
diff --git a/src/main/java/me/hekr/iotos/softgateway/subsystem/service/SubsystemService.java b/src/main/java/me/hekr/iotos/softgateway/subsystem/service/SubsystemService.java
new file mode 100644
index 0000000000000000000000000000000000000000..58133ad37e8edb08b26ba345bab49fa19b3de5dc
--- /dev/null
+++ b/src/main/java/me/hekr/iotos/softgateway/subsystem/service/SubsystemService.java
@@ -0,0 +1,46 @@
+package me.hekr.iotos.softgateway.subsystem.service;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import me.hekr.iotos.softgateway.core.klink.KlinkService;
+import me.hekr.iotos.softgateway.core.klink.ModelData;
+import me.hekr.iotos.softgateway.core.listener.DeviceRemoteConfigListenerAdapter;
+import me.hekr.iotos.softgateway.core.utils.ThreadPoolUtil;
+import me.hekr.iotos.softgateway.subsystem.dto.RadioDevice;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/** @author iotos */
+@Service
+public class SubsystemService extends DeviceRemoteConfigListenerAdapter {
+ @Autowired private KlinkService klinkService;
+ @Autowired private UdpServerService udpServerService;
+
+ @Override
+ public void firstAfter() {
+ // 监听到远程配置准备好了,进行业务初始化
+ init();
+ }
+
+ private void init() {
+ ThreadPoolUtil.DEFAULT_SCHEDULED.scheduleWithFixedDelay(
+ this::syncDevices, 0, 60, TimeUnit.SECONDS);
+ }
+
+ public void syncDevices() {
+ List devices = udpServerService.getAllStatus();
+
+ for (RadioDevice d : devices) {
+
+ // 如果是离线,设置iot的设备离线
+ if (d.getStatus() == 0) {
+ klinkService.devLogout(d);
+ continue;
+ }
+
+ ModelData data =
+ ModelData.cmd("report").param("vol", d.getVol()).param("playStat", d.getPlayStat());
+ klinkService.devSend(d, data);
+ }
+ }
+}
diff --git a/src/main/java/me/hekr/iotos/softgateway/subsystem/service/UdpServerService.java b/src/main/java/me/hekr/iotos/softgateway/subsystem/service/UdpServerService.java
index ea59d9ac3894c6c06730f829366abb20c2fd6f3b..d2cb61cee689d7ac5a8e87f3bf3fa0135e175688 100644
--- a/src/main/java/me/hekr/iotos/softgateway/subsystem/service/UdpServerService.java
+++ b/src/main/java/me/hekr/iotos/softgateway/subsystem/service/UdpServerService.java
@@ -7,6 +7,7 @@ import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.IntStream;
import lombok.extern.slf4j.Slf4j;
+import me.hekr.iotos.softgateway.core.enums.ErrorCode;
import me.hekr.iotos.softgateway.core.klink.KlinkService;
import me.hekr.iotos.softgateway.core.klink.ModelData;
import me.hekr.iotos.softgateway.core.utils.JsonUtil;
@@ -16,7 +17,6 @@ import me.hekr.iotos.softgateway.network.udp.UdpClient;
import me.hekr.iotos.softgateway.network.udp.UdpServer;
import me.hekr.iotos.softgateway.subsystem.dto.RadioDevice;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
/** @author iotos */
@@ -43,26 +43,6 @@ public class UdpServerService {
};
}
- @Scheduled(fixedDelay = 10 * 1000, initialDelay = 0)
- public void syncDeviceStatus() {
- List devices =
- JsonUtil.fromJson(
- udpClient.send("getAllStatus"), new TypeReference>() {});
-
- for (RadioDevice d : devices) {
-
- // 如果是离线,设置iot的设备离线
- if (d.getStatus() == 0) {
- klinkService.devLogout(d);
- continue;
- }
-
- ModelData data =
- ModelData.cmd("report").param("vol", d.getVol()).param("playStat", d.getPlayStat());
- klinkService.devSend(d, data);
- }
- }
-
public void start() {
startServer();
startClient();
@@ -123,6 +103,19 @@ public class UdpServerService {
}
public void setVol(String radioDevId, Integer vol) {
- System.out.println(udpClient.send("setVol:" + radioDevId + ":" + vol));
+ String resp = udpClient.send("setVol:" + radioDevId + ":" + vol);
+ RadioDevice d = new RadioDevice(radioDevId);
+ if ("OK".equals(resp)) {
+ klinkService.devSend(d, ModelData.cmd("report").param("vol", vol));
+ klinkService.sendCloudSendResp(d, ErrorCode.SUCCESS);
+ } else {
+ log.error("控制失败 radioDevId: {}" + radioDevId);
+ klinkService.sendCloudSendResp(d, 2000, "unknown");
+ }
+ }
+
+ public List getAllStatus() {
+ return JsonUtil.fromJson(
+ udpClient.send("getAllStatus"), new TypeReference>() {});
}
}