IoT平台设计文档


目 录

一、 产品管理 4

1. 产品管理 4

2. 功能定义 4

3. 版本升级 6

4. 设备统计 6

二、 设备管理 6

1. 设备管理 6

2. 令牌管理 8

3. 设备分组 8

4. 设备在线 8

5. 下行指令 8

6. 设备历史 9

7. 子设备 9

三、 系统架构图 9

四、 核心功能 10

1. 数据处理流程 10

2. 产品模板 12

3. 产品定义 18

4. 设备配置 18

5. 设备在线 19

6. 设备统计 20

7. 设备分组 20

8. 规则策略 21

9. 数据推送配置 22

10. 设备数据 24

11. 设备历史 25

12. 设备事件 25

13. 设备服务 26

14. 设备影子 27

15. 设备信息 28

五、 应用管理 30

1. 应用系统 30

2. 应用钩子 30

六、 边缘网关 30

1. 客户端配置 30

2. 设备登录 31

3. 设备心跳 32

4. 自动更新 32

5. 物模型管理 33

6. 子设备管理 33

7. Modbus协议 33

8. 自定义协议 33

七、 数据平台 33

1. 原始数据接口 33

2. 降采样算法 33

3. 插值算法 33

4. 数据清洗 33

5. 标准数据接口 34

6. 通用数据接口 34

7. 消息队列实时推送 34

八、 部署安装 35

1. SSO统一登录 35

2. 星尘服务端 37

3. 星尘代理 39

4. 蚂蚁调度 41

5. IoT平台 42

九、 相关资料 44

附件1:Server_Api.html 平台服务端接口资料 44


1 产品管理

设备的集合,通常指一组具有相同功能的设备。物联网平台为每个产品颁发全局唯一的ProductKey。

1.1 产品管理

产品作为设备的集合,决定了设备所具有的功能,主要字段如下:

参数

描述

名称

产品的友好显示名称

编码

即ProductKey,全局唯一

密钥

即ProductSecret,用于一型一密的认证方案

分类

比如边缘网关、大气监测设备

节点类型

分为直连设备、网关设备、网关子设备

数据格式

数据传输格式,Json

协议

设备接入网关的协议类型,ModbusRTU、ModbusTCP、OPC-UA、BLE、SRMP

连网方式

MQTT、WiFi、蜂窝Cellular(2G/3G/4G/5G)、以太网、LoRaWAN、其它

动态注册

每台设备烧录相同的产品证书,即ProductKey和ProductSecret,云端鉴权通过后下发设备证书

固定编码

UUID相同,设备编码不同,且固定编码,则认为是全新设备

认证类型

支持DTU直传

描述

用来描述产品信息

产品下可查看该产品所有设备、进行功能定义、版本升级、以及设备统计。

1.2 功能定义

产品所具有的功能,类似于其它平台的物模型。

功能定义,多属性的数据格式,决定如何解析生成属性数据。可以从标准物模型导入。

功能定义分为两层,一个产品包含若干个模块,模块可以导入,也可以自定义模块。每个模块包含多个属性、事件、服务。

请注意,网关型产品,因为不确定会添加什么设备,因此没有功能定义。而连接网关的设备,通过配置通道,来定义如何采集数据以及解析,通道仅用于自动采集。

功能定义的主要字段如下:

参数

描述

产品

功能所属产品

模块

功能分组,分为默认模块和自定义模块

种类

分为属性、事件、服务

名称

功能名称

标识

功能唯一标识,比如Temperature

访问模式

只读、读写、只写

必填

可用于服务的参数校验

数据类型

可以是基础数据类型或子设备产品。基础数据类型有小数、整数、文本。选择子设备产品时,将本产品按照子设备产品去解析

长度

文本类型的最大长度

最小值

数字类型的最小值,比如-40

最大值

数字类型的最大值,比如120

步长

数值类型的最小间隔

最大间隔

数值类型的最大间隔,超过该值时被抛弃

单位

数据的单位,比如℃

单位名称

数据单位名称,比如摄氏度

调用方式

服务的调用方式,同步sync,异步async

地址

用于解析原始数据,原始数据的第几个字节

大小

用于解析原始数据,占原始数据几个字节

交换16

用于解析原始数据,字节交换,12转21,默认为false,大端字节序

交换32

用于解析原始数据,字节交换,1234转3412,默认为false,大端字节序

掩码

读取线圈时使用

缩放因子

n*scaling+constant

常量因子

n*scaling+constant

描述

功能描述

功能定义不仅描述了产品应该具有什么属性、事件、服务,还描述了使用者应该怎么去使用。对接物联网平台的客户端,可以导出产品的物模型,根据定义好的属性和相应格式上报数据,可上报的事件以及提供的服务,都按照物模型来定义。

用于数据采集类的网关,可以根据设备关联的通道,设置采集通道,以便传感器数据能正常采集并上报至平台。

1.3 版本升级

边缘网关客户端自动更新,升级管理。

平台维护产品版本,可上传新的版本,通过指令下发至客户端进行升级,客户端收到升级包下载url,自行下载升级。如果处于业务高峰期,可在空闲时间进行下载升级。

1.4 设备统计

对每个产品下设备进行每日统计,统计维度包括以下几点:

属性

描述

总数

截止今天的全部设备数

活跃数

最后登录位于今天设备数

7天活跃数

最后登录位于7天内的设备数

30天活跃数

最后登录位于30天内的设备数

新增数

今天创建的设备数

7天新增数

7天内创建的设备数

30天新增数

30天内创建的设备数

注册数

今天激活或重新激活的设备数

最高在线

今天在线设备最高数量

最高在线时间

最高在线发生时间点

2 设备管理

2.1 设备管理

归属于某个产品下的具体设备。物联网平台为设备颁发产品内唯一的证书DeviceName。设备可以直接连接物联网平台,也可以作为子设备通过网关连接物联网平台。

设备接入平台之前,需要通过注册和认证。接入物联网平台的设备身份注册方式有两种。

  • 一型一密:同一产品下设备烧录相同产品证书(ProductKey和ProductSecret)。需要开通产品动态注册功能,如果没有开启此功能,设备会注册到平台,但是设备状态是禁用状态。动态注册又分为以下两种情况:
  • 预注册:需要在平台创建设备,这种认证类型的设备在注册到物联网平台需要携带ProductKey、ProductSecret、DeviceName三个参数,平台检验通过后,为设备颁发DeviceSecret。此后,设备就可通过设备证书ProductKey、DeviceName和DeviceSecret进行登录,登陆成功平台会下发令牌即DeviceToken。设备与平台的后续通信通过令牌来鉴别身份。
  • 免预注册:不需要在物联网平台预先创建设备,DeviceName可以直接从设备中读取到的ID,如设备的MAC地址、IMEI或SN码等。平台发现该设备为注册,则会进行自动注册,并颁发DeviceSecret。设备再通过ProductKey、DeviceName和DeviceSecret进行登录获取令牌。
  • 一机一密:这种方式要求预先在平台注册设备,获取设备证书信息(ProductKey、DeviceName、DeviceSecret)。然后将设备证书烧录到设备固件,设备联网后直接通过设备证书进行登录获取设备令牌。此方式安全性最高,推荐使用。

设备与云端通信携带令牌,通过设备鉴权后接入平台,后续也可进行设备注销。

2.2 令牌管理

设备连接平台,通过鉴权后,会得到一个token令牌。此令牌用于访问平台的各个接口。设备后续的通信均需携带令牌进行认证。当令牌过期,客户端可通过心跳机制对令牌进行更新。平台会记录每个设备使用的token,以及刷新记录。

通过使用令牌,可以防止非法设备访问,有效保护通信安全。

2.3 设备分组

物联网平台支持建立设备分组,分组中可包含不同产品下的设备。通过设备组来进行跨产品管理设备。

2.4 设备在线

设备接入平台之后,设备在平台的状态显示为在线,建立连接后需要一个心跳机制来保持这种状态,设备需要定时发送心跳消息到平台以保持活跃。

心跳周期一般设置为60秒,心跳除了刷新在线状态,还会刷新令牌。如果超过1.5倍心跳时间没有心跳,平台会将设备置为下线状态。

2.5 下行指令

所有下行指令由平台下发至设备,设备与平台之间有WebSocket长连接,基于消息队列实时向终端设备推送指令。每条消息均有唯一消息标id,指令响应结果也包含下行指令携带的消息id,确保响应消息与下行指令一一对应。

2.6 设备历史

设备历史记录设备上线下线等操作,按年分表。该历史不仅详细记录了平台对设备的所有操作,同时还有操作详细内容,以及操作成功状态。甚至还有追踪标识,还原整个调用链。

2.7 子设备

由于传感器子设备不能直接连接平台,或者需要拓扑关系管理,这时候设备可以作为网关子设备,连入网关,由网关代理连接平台通信。业务平台给子设备发送消息时无需感知物理物理拓扑结构。

3 系统架构图

4 核心功能

4.1 数据处理流程

数据流程:IotClient => IotServer => IotData 分别是数据采集/上报,数据接收/解析/存储,数据转发 三个阶段。

4.2 产品模板

4.2.1 功能简介

预定义产品模板及产品功能模板,用户可以通过产品模板快速创建新的产品信息。

该功能以阿里云IOT平台的TSL为基础(参考1),并根据实际业务场景进行扩展,用户可以通过TSL快速编辑管理产品模板功能定义、产品功能定义(包括:属性、服务、事件)。

4.2.2 界面及功能要点说明

  • 模板信息列表

  • 新增产品模板信息

模板名称:基于当前模板生成的产品,名称会使用模板名称。

节点类型:主要分三类,分别为网关设备、子设备、直连设备,其中网关设备不能定义功能模板(物模型

数据格式:目前支持Json

协议类型:目前默认实现了Modbus相关协议,后续开发人员可以根据二次开发情况自行扩展。

启用:该产品是否启用以及参与数据解析。

固定编码:用户判断自动接入的设备是否被自动注册为新设备,主要用于设备的自动身份识别,配合一物一码使用。

校验:主要用于校验TSL模板与产品关联的物模型信息之间一致性,启用状态TSL模板导入过程会强制校验当前产品模板或产品所关联的功能模板/功能定义(物属性),TSL模板中不存在的功能定义将被停用;反之TSL模板导入只新增或更新TSL模板中涉及的功能模板/功能定义。

  • 模板类型说明

只有子设备和直连设备可以定义功能模板,网关设备不涉及数据采集及解析,所以不能定义功能模板。

  • 功能模板(物属性)列表

其中复制功能可以快速创建类型相同名称、标识不同的物属性。(建议:物模型的管理可以通过TSL模型管理)(参考1)


  • TSL模板管理(参考1)

注:如果产品模板开启校验功能,TSL模板导入到功能模板(物属性)中会自动停用TSL模板中没有包含的属性

  • 创建产品

点击创建产品连接,会自动基于当前产品模板相关信息以Copy的方式创建产品信息。

注:创建出来的产品编码会进行调整(由于产品编码全表唯一),运维人员可以根据实际部署情况进行对产品编码进行调整。

4.2.3 TSL操作流程

4.3 产品定义

4.4 设备配置

4.4.1 功能简介

对于设备物模型属性以及自定义模型属性管理,同时定义了数据解析模型,使用者可以通过属性的定义明确了解设备相关上报数据内容。

IOT平台为了满足复杂的生产环境需求,目前IOT平台设备属性数据采用客户端采集并解析,相关的解析信息是在客户端连接服务端时获取,并且后续的变更会定时推送到客户端。

4.4.2 解析规则

解析规则:客户端上报到服务端的数据是字节数组,解析规则采用DynamicExpresso.Core(参考2)

转换扩展参考

data.ToUInt16()

data.ToBase64()

data.ToUInt32()


data.ToUInt64()


data.ToDateTime()


data.ToBoolean()


data.ToDouble()


data.ToStr()


data.ToHex()


4.4.3 接口说明

接口信息 (参考:附件1)

Thing - 上报设备属性 接口

Thing - 获取设备属性 接口


4.5 设备在线

主要是展示当前各设备在线状态

4.6 设备统计

基于产品维度的日活、7日活、30日活以及日新增、7日新增、30日新增设备总数。

4.7 设备分组

编辑设备类型分组字典信息。

4.8 规则策略

4.8.1 功能介绍

用户可以从产品维度和设备纬度分别设置规则策略,系统会根据用户所设置的规则策略逐一校验设备属性字段是否符合预期阀值,并将达到阀值的数据以事件的方式发送到事件队列当中。由事件队列消费端对事件消息进行处理。

规则引擎方面,本系统引入了 DynamicExpresso.Core(参考地址:https://github.com/dynamicexpresso/DynamicExpresso)组件,规则表达式采用简单的c#表达式编写。例:@temp>5 表示temp属性的值大于5及满足规则要求。

4.8.2 界面及功能要点说明

  • 规则编辑页

名称:规则名称必填

产品信息:每个规则需要关联一个产品ID或设备ID(最高优先级),数据上报过程中会将上报的数据逐一校验规则,筛选符合规则的数据并进行相关操作,如果事件通知、事件报警或服务调用等;

设备信息:匹配设备的规则优先级最高。

表达式:规则判断逻辑

动作:符合规则的数据需要触发的后续操作;主要分为五类,事件通知、事件告警、事件错误、服务调用、设置属性。

数据:关联动作需要生成的消息通知模板,如发出事件报警,这里可以指定消息报警模板内容。

4.9 数据推送配置

4.9.1 功能介绍

主要对原始监测数据、报警数据、事件数据进行第三方转发,需要第三提供相应的数据接口。

数据推送具体模型取决于监测数据上传时数据模型,接口会将相应数据转换为json字符串作为三方接口入参。

用户根据实际需要指定topic并且支持基于产品、设备、事件名称、事件类型动态分发队列。

4.9.2 推送方式

主要支持:mqtt、http两种方案。

4.9.3 消息队列主题定义

序号

占位符号

名称

备注

1

{productCode}

产品编号


2

{deviceCode}

设备编号


3

{eventType}

事件类型

事件推送生效

4

{name}

事件名称

事件推送生效

4.9.4 系统界面

4.10 设备数据

4.10.1 功能介绍

备主要分为原始数据、计算修正后数据、分钟统计、15分钟统计、小时统计数据几个部分。设备上报的原始数据会经过特定的数据清洗规则进行分库、分表存储到指定库表当中,以便后续业务层系统进行使用。

4.10.2 主要信息

主要信息包括:设备编号、主题、数据原始报文

4.11 设备历史

主要记录了各个节点的上下线信息、更新信息、令牌刷新、Socket连接等等信息。


4.12 设备事件

4.12.1 功能介绍

主要记录由设备端主动发出的事件消息,主要包括 报警、通知、错误日志三个方面。

4.12.2 系统界面

4.13 设备服务

4.13.1 功能介绍

设备服务主要由用户通过接口或界面新增服务记录,系统会实时将服务指令下发给相关边缘网关系统。网关设备在执行完相关任务后将相关的执行结果通知服务端。

4.13.2 系统界面

客户端反馈时间

4.14 设备影子

4.14.1 功能介绍

对设备配置影子数据进行管理维护,可以记录设备最新的完整状态信息。

4.14.2 系统界面

4.15 设备信息

4.15.1 功能介绍

通过设备心跳将当前网关设备的实时运行状态信息上报至服务端,方便运维人员对网关设备运行状态进行实时监控。该功能主要结合星尘监控系统完成对系统的全链路监控。

4.15.2 系统界面

5 应用管理

5.1 应用系统

应用密钥管理,可调用应用层接口,读写数据

5.2 应用钩子

拦截产品或设备指定动作,如上线下线,回调外方接口

重要位置点的回调函数设置,触发某个动作时,回调业务层接口,可能需要令牌验证

6 边缘网关

NewLife.IoT

6.1 客户端配置

Iot.Client项目主要用于主设备对子设备的数据采集工作,支持Windows,Linux64,LinuxArm等系统运行,通过ModBus等协议主设备下挂子设备通道数据采集回来并上传至IotWeb平台。

使用配置:

  1. 找到IotClient运行目录对应的Config/ IoTClient.config文件
  2. 内容如下

  1. 其中配置支持一机一密和一型一密两种方式。

举例说明:当填写已创建主设备就直接填写设备的DeviceCode和DeviceSecret即可,系统会自动完成鉴权上线建立通讯,然后拉取设备对应产品属性及通道,进行数据采集及上传;如果设备未创建可以填写对应产品的ProductKey和ProductSecret,系统会自动创建产品的主设备,然后下发配置证书,修改配置文件。暂时为了系统安全,默认主设备启用状态为未启用,需要后台开启。

特别说明:为了系统通讯安全,当A设备初次鉴权成功,A设备的对应的唯一标识会进行IotClient的捆绑,此时即时别的设备拿到相同文件也无法通过鉴权。反之如果需要更换解绑,请清空唯一标识。


6.2 设备登录

设备连入系统需要进行安全认证,通过IotClient的DeviceCode和DeviceSecret及唯一标识进行鉴权,通过后可进行配置属性通道信息的下载进入采集工作和数据上传工作。

6.3 设备心跳

设备心跳跟据服务器采样周期,对设备运行健康参数进行采集,并回传至IotWeb。其中包括:设备内存,可用内存,应用所在磁盘容量,应用所在磁盘可用容量,Cpu使用率,温度,电量,开机时间,IP,设备UTC时间,延时信息。

6.4 自动更新

检查设备可用更新信息,发现更新,执行更新,实现自动更新下发的工作。

自动更新流程,下载Zip更新包,解Zip压缩包,备份当前程序,清理Exe、Dll等文件,覆盖更新文件,升级后附加命令,验证更新,成功清理备份文件,失败异常上报,停止更新。

6.5 物模型管理

属性集合,事件队列

6.6 子设备管理

子设备拉取,设备通道创建及维护

6.7 Modbus协议

目前支持ModbusRTU、ModbusTCP协议

6.8 自定义协议

如何根据协议接口,实现自定义协议

7 数据平台

主要对第三方应用系统提供一些基础的数据查询接口服务,同时集成了一些常用数据统计数据查询接口。数据统计依赖于蚂蚁调度服务平台。

7.1 原始数据接口

基于设备和时间区间查询原始数据,可选传感器

7.2 降采样算法

LTTB、LTOB、平均值采样、最大值采样、最小值采样

7.3 插值算法

线性插值、双线性插值、拉格朗日插值

7.4 数据清洗

蚂蚁调度清洗数据

7.5 标准数据接口

基于设备和时间区间查询MySql中清洗后数据,可选传感器

7.6 通用数据接口

基于设备和时间区间查询MySql设备数据,可选传感器

7.7 消息队列实时推送

实时推送设备数据、设备事件、设备上下线


8 部署安装

8.1 SSO统一登录

使用魔方作为SSO系统,用于统一控制IoT管理平台、星尘管理平台、蚂蚁管理平台等各个Web端的统一登录。同时,SSO也可能作为用户验证的链路,桥接到其它SSO登录中心。

部署要点:

  1. 编译最新魔方源码中的CubeDemoNC,直接作为应用部署,要求.NET6.0
  2. 配置文件appsettins.json,配置链接字符串 Membership 和 Log,指向MySql库的 Membership(新建库 )。

  1. 启动并访问SSO系统,首次登录可以用admin/admin进去,也可以使用第三方登录(新生命用户中心),第一个用户将会作为系统管理员,同时禁用admin
  2. 正式部署时,需要关闭SSO的第三方登录,魔方设置,OAuth设置,禁用所有

  1. 修改系统名称为XX用户中心,魔方设置,系统设置,显示名称
  2. 打开应用系统功能,菜单,找到App应用系统,修改为可见加必要,刷新后台。
  3. 新建三个应用(StarWeb/AntWeb/IoTWeb),并设置密钥,供后续使用。

8.2 星尘服务端

星尘主要用于应用性能监控以及节点监控,还有可能使用配置中心。

部署要点:

  1. 编译StarServer和StarWeb,部署到服务器,配置文件appsettings.json,配置连接字符串Stardust,指向MySql库的Stardust(新建库)。其它链接使用MapTo映射。

  1. StarServer默认端口6600,可在配置文件Config/StarServer.config中修改Port。记好服务端地址,其它多个项目需要用到。如果是多节点集群部署,需要修改TokenSecret为同一个。

  1. StarWeb启动时需要指定端口,例如 dotnet StarWeb.dll urls=http://*:6680/,根据实际情况使用域名和端口。
  2. StarServer和StarWeb可以不在同一台服务器,共用数据库即可。如果使用SQLite数据库,则需要在同一台服务器。如果是集群部署,需要确保各个节点的配置一致,特别是令牌密钥。
  3. StarServer的配置文件appsettings.json,其中StarServer项配置监控地址,默认指向自己 http://127.0.0.1:6600,如果前面修改了端口,则这里也要修改。
  4. StarWeb的配置文件appsettings.json,其中StarServer想配置监控地址,指向StarServer所在地址。这里也可以不配置,直接留空,此时将自动通过本机星尘代理StarAgent发现。
  5. StarServer的配置文件 Config/StarServer.config中的WebUrl,指向StarWeb所在地址,用于生成告警到钉钉群或企业微信群的消息链接。
  6. 访问StarWeb,首次使用第三方登录进入,然后配置SSO为前面SSO地址,以及StarWeb应用和密钥。

8.3 星尘代理

星尘代理用于守护应用进程、监控服务器节点性能。

部署要点:

  1. 编译StarAgent,或者在线下载 http://x.newlifex.com/star/staragent60.zip
  2. 部署到每一台服务器,以管理员(Linux上是sudo)启动

  1. 按键“s”使用星尘,输入StarServer服务端地址,例如 http://10.0.0.10:6600
  2. 按键“2”安装服务,Windows和Linux相同。
  3. 按键“3”启动服务,等同于Windows下在系统服务中找到StarAgent并启动,Linux下使用命令 sudo systemctl start StarAgent 启动。
  4. 访问星尘管理平台StarWeb,节点在线页面应该可以看到已安装节点。

  1. 配置守护。StarAgent具备守护本机应用的能力,修改配置文件Config/StarAgent.config,填写应用名、文件名、参数、工作目录、自动启动等。由于StarAgent已经安装成为系统服务,能够随系统启动。因此,被守护应用,在StarAgent启动时,也将会启动拉起。如果目标应用进程退出,在AutoRestart=true是,StarAgent将会再次拉起。

  1. 使用StarAgent守护所有应用!!!包括SSO、StarServer、StarWeb、AntServer、AntWeb、IoTServer、IoTWeb、IoTData等。

8.4 蚂蚁调度

蚂蚁调度用于数据计算。

部署要点:

  1. 编译AntServer,部署到服务器,默认端口9999,配置StarAgent守护,AntServer将会自动接入星尘监控。记住AntServer地址,计算型应用中需要使用。
  2. 编译AntWeb,部署到服务器,需要手工指定端口,配置StarAgent守护,AntWeb将会自动接入星尘监控。
  3. AntServer和AntWeb配置appsettings.json,指向同一个MySql库AntJob(新建库)。
  4. 访问AntWeb,首次使用第三方登录进入,然后配置SSO为前面SSO地址,以及AntWeb应用和密钥。



8.5 IoT平台

IoT平台包括服务平台、管理平台、数据平台和边缘网关。

部署要点:

  1. 编译IoTServer,并部署到服务器,默认端口1881,配置StarAgent守护。
  2. 编译IoTWeb,并部署到服务器,配置StarAgent守护。
  3. 编译IoTData,并部署到服务器,配置StarAgent守护。
  4. 编译IoTClient,并部署到服务器,配置StarAgent守护。
  5. IoTServer/IoTWeb/IoTData,配置文件appsettings.json使用相同的数据库链接IoT,指向MySql数据库IoT(新建库)。
  6. 访问IoTWeb,首次使用第三方登录进入,然后配置SSO为前面SSO地址,以及IoTWeb应用和密钥。

  1. IoTClient配置文件Config/IoTClient.config,修改Server指向IoTServer。
  2. IoTData配置,指向AntServer。

8.5.1 部署IoTServer

编译源码、修改配置、打包文件、发布应用、设置守护


8.5.2 部署IoTWeb

编译源码、修改配置、打包文件、发布应用、设置守护


8.5.3 部署IoTClient

编译源码、修改配置、打包文件、发布应用、设置守护


8.5.4 部署IoTData

编译源码、修改配置、打包文件、发布应用、设置守护



9 相关资料

附件1:Server_Api.html 平台服务端接口资料

附件2:SSO注册帐号说明


参考1:阿里云IOT平台TSL模板介绍

https://help.aliyun.com/document_detail/213902.html?spm=5176.21213303.J_6704733920.7.1c1e3eda3CMd1s&scm=20140722.S_help%40%40%E6%96%87%E6%A1%A3%40%40213902._.ID_help%40%40%E6%96%87%E6%A1%A3%40%40213902-RL_tsl-LOC_main-OR_ser-V_2-P0_0


参考2:DynamicExpresso.Core 规则引擎

https://github.com/dynamicexpresso/DynamicExpresso

作者:大石头 发布:2022-04-16 12:29:39 浏览:335)