跳到主要内容

一般情况下,您不用修改三三平台的核心组件,你只需要把三三当作物联网底座或中台,利用三三平台提供的灵活而强大的协议、丰富的 API、强大的应用管理机制,去构建您的物联网应用。

如果您一定要修改核心组件,三三平台采用微服务架构实现了各组件的完全解耦,您可以基于三三已有的组件修改,或用自己编写并替换三三平台的某个组件实现您的需求。

三三的开发遵循一系列规范和协议,包括 API 接口规范、 MQTT 接口、目录规范、配置文件规范。另外,我们还提供了方便您开发服务的核心库。

API 接口规范​

请求响应​

主要介绍API的请求结构

1、请求URI {URI-scheme}://{Endpoint}/api/{micro-server}/{resource-path} 例:http://ssiot.cc:9000/api/device/find http://ssiot.cc:9000/api/alarm/find

参数说明
URI-scheme请求协议,http/https
Endpoint提供REST服务的端点域名/ip+端口,三三云平台为 ssiot.cc:9000
micro-server微服务节点名称,参考前面章节的系统模块说明(少量接口特例,具体以接口文档为准)
resource-path资源路径,按实际业务访问不同,如对配置的查列表/详情、增、改、删,定义为config/find、get、add、modify、remove

2、请求方法

方法说明
GET查询,请求服务器或返回特定资源
POST增删改,修改或删除特定资源,或执行特殊操作如设备控制下发

3、响应内容

{
"code": 200,
"message": "操作成功",
"result": {},
"success": true,
"timestamp": 1684823798374
}
字段说明
code错误码
message成功/失败消息
result响应结果,json对象,可为空,也可包含分页信息
success成功/失败标志
timestamp响应时间戳

错误码​

错误码说明
200成功
0自定义异常
201操作失败
202请求参数错误
203用户名不正确
204密码不正确
205添加失败
206更新失败
207删除失败
208修改失败
209查找失败
210上传失败
211不被识别的手机号
300创建进程失败
301进程启动失败
302进程重复
303进程不存在
304进程删除失败
305缺少进程文件或目录

API 接口清单​

三三 API 接口文档

MQTT 接口​

业务主题​

主题说明
/san/data/handle已处理消息数据流转
/san/event/device/login、/san/event/device/logout上线触发业务
/san/event/device/delete设备操作触发业务
/san/event/device/add设备操作触发业务
/san/alarm/notify告警通知主题
/san/data/forward数据mq转发主题

三三物联协议​

详见三三物联协议

SDK​

我们提供了 ssiot-core, 高效便捷的开发框架ssiot-core,方便开发者完成集成开发

项目结构​

下载源代码, 除了 ui 目录外,其它目录均为后端模块目录

# Gitee仓库

git clone https://gitee.com/sansaniot/ssiot.git

以下以 device 模块为例说明项目目录结果

./
├─cmd # 服务命令
│ └─system # 系统服务模块,如系统初始化
├─common # 通用模块
│ ├─constant # 常量
│ ├─database # 数据库通用业务,如数据初始化、自动生成表
│ ├─dto # 业务DTO数据定义
│ ├─enums # 系统枚举
│ ├─middleware # 应用中间件
│ │ ├─jwt # JWT 鉴权中间
│ │ ├─log # Log中间件
│ │ └─secure # Secure认证中间
│ └─utils # Util工具包
├─config # 配置管理
│ └─settings.yml # 统一配置文件(微服务端口、数据库、MQTT、Redis等)
├─internal # 业务应用模块
│ ├─device # 模块入口
│ │ ├─router # HTTP router
│ │ ├─apis # 业务 API逻辑
│ │ ├─models # 业务model(数据库模型处理,完成前端页面与数据库接口对象转换)
│ │ ├─service # 业务Service,对接apis,调用各models进行业务整合,返回业务数据
│ │ ├─ws # WebSocket API
│ | └─start.go # 模块启动入口
| ├─data # 模块数据处理
├─ Makefile # Makefile文件
├─ README.md # README 介绍
├─ main.go # 程序入口

配置文件​

service:                                   #微服务地址
sansan: #微服务管理服务
port: 9500
ipdb: ./config/ip2region.xdb #ip解析数据库
admin: #权限服务
port: 9510
filepath: ./data/assets #资源文件路径
device: #设备管理服务
port: 9520
alarm: #告警服务
port: 9530
notify: #通知服务
port: 9540
forward: #转发服务
port: 9550
ssiot: #公共配置
http: #http应用访问地址
host: 0.0.0.0
logger: #日志配置
path: ./log
stdout: ''
level: trace
enableddb: true #系统日志记录
mqtt: #后台mqtt服务地址
host: 127.0.0.1
port: 9010
user:
passwd:
timeout: 3
database: #数据库连接
driver: postgres
source: host=127.0.0.1 user=postgres password=123456 dbname=sansaniot port=9020 sslmode=disable TimeZone=Asia/Shanghai
cache: #缓存中间件
redis: #redis
addr: 127.0.0.1:9030
password: '123456'
db: 0
jwt: #接口鉴权jwt配置
secret: ssiot2023
timeout: 3600

代码示例​

internal/device/start.go

import (
"gitee.com/sansaniot/ssiot-core/facade/env"
"gitee.com/sansaniot/ssiot-core/facade/httpserver"
"gitee.com/sansaniot/ssiot-core/httpmvc"
"gitee.com/sansaniot/ssiot-core/httpmvc/api"
"github.com/shafreeck/cortana"
...
)
func Start() error {
// 启动参数格式自定义, 如./device -c config/settings.yml
args := struct {
CfgFile string `cortana:"--config, -c, , config file"`
}{}
cortana.Parse(&args)
if args.CfgFile != "" {
constant.ConfigFile = args.CfgFile
}
// 如有需要,向内核注册自己需要的中间件
// 限流
httpserver.RegisterMiddlewareFunction(secure.Sentinel())
// 自动增加requestId
httpserver.RegisterMiddlewareFunction(secure.RequestId(httpmvc.TrafficKey))
// 获取上下文提供的日志
httpserver.RegisterMiddlewareFunction(api.SetRequestLogger)
// 请求日志记录到文件
//httpserver.RegisterMiddlewareFunction(log.LoggerToFile())
// 自定义错误处理
httpserver.RegisterMiddlewareFunction(log.CustomError)
// NoCache is a middleware function that appends headers
httpserver.RegisterMiddlewareFunction(secure.NoCache)
// 跨域处理
httpserver.RegisterMiddlewareFunction(secure.Options)
// Secure is a middleware function that appends security
httpserver.RegisterMiddlewareFunction(secure.Secure)

// 必须,初始化引擎
httpserver.InitEngine(constant.ConfigFile)
env.DefaultConfig.Http.Port = env.ConfigOperator.GetInt64("service.device.port")

// 启动系统业务
system.InitSystemBiz()

// 可选,初始化JWT验证方法组
jwtMiddleware, _ := jwt.AuthInit()
// 必须,向内核注册自己的业务模块路由,如不使用中间件,则使用InitRouters方法
httpserver.InitAuthRouters(router.RouterCheckRole, jwtMiddleware)
httpserver.InitAuthRouters(ruleRouter.RuleRouters, jwtMiddleware)
httpserver.InitRouters(router.RouterNoCheckRole)
// 启动HTTP服务器
_ = httpserver.Run()

return nil
}

internal/device/router/device.go

import (
jwt "gitee.com/sansaniot/ssiot-core/httpmvc/jwtauth"
"github.com/gin-gonic/gin"

"ssdevice/internal/device/apis"
)
func init() {
RouterCheckRole = append(RouterCheckRole, registerDeviceRouter)
}

// v1 注册系统路由, authMiddleware jwt鉴权
func registerDeviceRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
api := apis.Device{}
// 设备
r := v1.Group("/api/device").Use(authMiddleware.MiddlewareFuncWithOutValidate())
{
r.GET("/find", api.FindList)
...
}

internal/device/apis/device.go

import (
"gitee.com/sansaniot/ssiot-core/httpmvc/api"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"

"ssdevice/common/enums"
"ssdevice/internal/device/models"
"ssdevice/internal/device/models/command"
"ssdevice/internal/device/models/query"
"ssdevice/internal/device/service"
)
// 添加设备
func (e Device) AddDevice(c *gin.Context) {
// 请求参数
req := command.DeviceInsertReq{}
// 业务service
s := &service.Device{}
// 上下文
err := e.MakeContext(c).
MakeOrm().
Bind(&req, binding.JSON).
MakeService(&s.Service).
Errors
if err != nil {
e.Logger.Error(err)
e.Fail(0, err.Error())
return
}
// service注入实体
s.SetAllModel()
// 用户信息
req.LoadUser(c)
// 执行
var result models.SysDev
if err, result = s.AddDevice(&req); err != nil {
e.Logger.Error(err)
e.Fail(0, err.Error())
return
}
// 返回
e.Data(result)
}