Browse Source

add:新网关,双人对抗

zzf 1 year ago
parent
commit
5497242b02

+ 48 - 3
api/gateway/device.go

@@ -8,6 +8,7 @@ import (
 	deviceService "confrontation-training/service/device"
 	"fmt"
 	"github.com/gin-gonic/gin"
+	"reflect"
 	"strings"
 )
 
@@ -43,6 +44,16 @@ func (d *DeviceService) DeviceAdd(c *gin.Context) {
 		return
 	}
 	if result := d.CreateDevice(param); result.Error == nil {
+		deviceInfo := deviceModel.DeviceInfo{
+			Type: param.Type,
+			Mac:  param.Mac,
+		}
+		if param.Type == "0" {
+			deviceInfo.Name = "MIND" + strings.ReplaceAll(param.Mac[len(param.Mac)-5:], ":", "")
+		} else {
+			deviceInfo.Name = "BW-ECG-01"
+		}
+		global.DeviceMap[param.Mac] = deviceInfo
 		response.Success(errors.DeviceAddSuccess, result.RowsAffected, c)
 		return
 	} else {
@@ -69,6 +80,7 @@ func (d *DeviceService) DeviceRemove(c *gin.Context) {
 	} else {
 		response.Success(errors.DeviceRemoveSuccess, count, c)
 	}
+	delete(global.DeviceMap, mac)
 	return
 }
 
@@ -83,7 +95,8 @@ func (d *DeviceService) DeviceRemove(c *gin.Context) {
 // @Success 200 {string} string "ok"
 // @Router /v1/device/list/:type [get]
 func (d *DeviceService) DeviceList(c *gin.Context) {
-	deviceInfos, _ := d.FindDeviceByType(c.Param("type"))
+
+	deviceInfos, _ := d.FindDeviceByType(c.Query("type"))
 	response.Success(errors.FindSuccess, deviceInfos, c)
 }
 
@@ -100,11 +113,43 @@ func (d *DeviceService) DeviceList(c *gin.Context) {
 func (d *DeviceService) DeviceConnected(c *gin.Context) {
 
 	url := global.Config.Gateway.BaseUrl + global.Config.Gateway.ConnectedUrl
-	list, err := d.DeviceConnectedList(url)
+	listResult, err := d.DeviceConnectedList(url)
 	if err != nil {
 		response.Failed("查询失败", c)
 	}
-	response.Success(errors.FindSuccess, list, c)
+	a := make(map[string]interface{})
+	a = listResult
+	b := a["nodes"]
+	var list []map[string]interface{}
+	var connectedList []deviceModel.ConnectedDevice
+	if reflect.ValueOf(b).Kind() == reflect.Slice {
+		s := reflect.ValueOf(b)
+		for i := 0; i < s.Len(); i++ {
+			ele := s.Index(i)
+			list = append(list, ele.Interface().(map[string]interface{}))
+		}
+		for _, m := range list {
+			mm := make(map[string]interface{})
+			mm = m
+			mac := mm["id"]
+			if device, count := d.FindDeviceByMac(mac.(string)); count > 0 {
+				var connDevice = deviceModel.ConnectedDevice{
+					MAC:        mac.(string),
+					DeviceType: device.Type,
+					Name:       device.Name,
+				}
+				if connDevice.Name == "" {
+					if device.Type == "1" {
+						connDevice.Name = "BW-EGC-01"
+					} else if device.Type == "0" {
+						connDevice.Name = "MIND" + strings.ReplaceAll(connDevice.MAC[len(connDevice.MAC)-6:], ":", "")
+					}
+				}
+				connectedList = append(connectedList, connDevice)
+			}
+		}
+	}
+	response.Success(errors.FindSuccess, connectedList, c)
 	return
 }
 

+ 224 - 6
api/gateway/gateway.go

@@ -14,6 +14,7 @@ import (
 	"fmt"
 	"github.com/gin-gonic/gin"
 	"io/ioutil"
+	"strconv"
 	"strings"
 )
 
@@ -75,7 +76,8 @@ func ScanDevice(c *gin.Context) {
 	}
 	paramMap["active"] = "1"
 	paramMap["event"] = "1"
-	SseScanDevice(paramMap, param.FilterType)
+	param.FilterType = "1"
+	go SseScanDevice(paramMap, param.FilterType)
 	response.Success("扫描完成", "", c)
 	return
 }
@@ -107,13 +109,14 @@ func ConnectDevice(c *gin.Context) {
 	}
 	url := global.Config.Gateway.BaseUrl + global.Config.Gateway.ConnUrl
 	url = strings.Replace(url, "MAC", param.Mac, -1)
-	url = strings.Replace(url, "chip", "chip="+param.Chip, -1)
+	if param.FilterName == "0" {
+		url = strings.Replace(url, "chip", "chip=0", -1)
+	} else if param.FilterName == "1" {
+		url = strings.Replace(url, "chip", "chip=1", -1)
+	}
 	httpResponse := http.PostReqJson(url, jsonParam)
 	status := httpResponse.StatusCode
-	fmt.Println("status", status)
-	fmt.Println("response:", httpResponse.Header)
 	body, _ := ioutil.ReadAll(httpResponse.Body)
-	fmt.Println("response Body:", string(body))
 	if status != 200 {
 		response.Failed(errors.DeviceConnectError+string(body), c)
 		return
@@ -121,7 +124,6 @@ func ConnectDevice(c *gin.Context) {
 	if param.FilterName == "1" {
 		openChannelUrl := global.Config.Gateway.BaseUrl + global.Config.Gateway.OpenChannel
 		openChannelUrl = strings.Replace(openChannelUrl, "MAC", param.Mac, -1)
-		fmt.Println("openChannelUrl===" + openChannelUrl)
 		httpResponse = http.GetReq(openChannelUrl)
 		if httpResponse.StatusCode != 200 {
 			fmt.Printf("%s:%s", errors.OpenChannelError, httpResponse.Body)
@@ -129,6 +131,7 @@ func ConnectDevice(c *gin.Context) {
 			return
 		}
 	}
+	go StopScan(c.Writer, c.Request)
 	response.Success(errors.DeviceConnectSuccess, param.Mac, c)
 	return
 }
@@ -306,3 +309,218 @@ func StopCollect(c *gin.Context) {
 	response.Success("停止采集", "", c)
 	return
 }
+
+// ScanDeviceEmq
+// PingExample confrontation-training
+// @Summary 扫描设备
+// @Schemes
+// @Description 扫描设备
+// @Tags 设备管理
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v2/device/scan [get]
+func ScanDeviceEmq(c *gin.Context) {
+	topic := "/" + global.Config.EmqConfig.GatewayMac + constant.TopicConnectSub
+	client := global.EmqClient
+	//停止扫描
+	fmt.Println("停止扫描")
+	fmt.Println(constant.CmdStopScan)
+	Publish(client, topic, constant.CmdStopScan)
+	//添加过滤
+	fmt.Println("添加设备过滤:")
+	filterCmd := "[{\"cmd\":\"AT+FLT=\",\"total\":\"2\"}"
+	for _, filter := range global.EmqConfig.Filter {
+		filterCmd = filterCmd + ",{\"t\":\"0\",\"d\":\"" + filter + "\"}"
+	}
+	filterCmd = filterCmd + "]"
+	fmt.Println(filterCmd)
+	//filterCmd = "[{\"cmd\":\"AT+FLT=\",\"total\":\"2\"},{\"t\":\"0\",\"d\":\"MIND\"},{\"t\":\"0\",\"d\":\"BW-ECG\"}]"
+	Publish(client, topic, filterCmd)
+	//开启扫描
+	//Publish(client, "/EE3870DA24C4/connect_packet/connect1_subscribe", "[{\"cmd\":\"AT+SCAN=\",\"s\":\"1\"}]")
+	//停止扫描
+	//Publish(client, "/EE3870DA24C4/connect_packet/connect1_subscribe", "[{\"cmd\":\"AT+SCAN=\",\"s\":\"0\"}]")
+	//设置设备服务UUID
+	fmt.Println("设置设备服务UUID")
+	SendUUID(client, topic)
+	Publish(global.EmqClient, topic, constant.CmdStartScan)
+	response.Success("开启扫描完成", "", c)
+	return
+}
+
+// StopScanDeviceEmq
+// PingExample confrontation-training
+// @Summary 停止扫描设备
+// @Schemes
+// @Description 停止扫描设备
+// @Tags 设备管理
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v2/device/stop/scan [get]
+func StopScanDeviceEmq(c *gin.Context) {
+	topic := "/" + global.Config.EmqConfig.GatewayMac + constant.TopicConnectSub
+	Publish(global.EmqClient, topic, constant.CmdStopScan)
+	response.Success("关闭扫描完成", "", c)
+	return
+}
+
+// ConnectDevice2
+// PingExample confrontation-training
+// @Summary 连接设备
+// @Schemes
+// @Description 连接设备
+// @Tags 设备管理
+// @Param device body string true "mac:设备MAC地址 ai:终端BLE设备的地址ID  at:终端BLE设备的地址类型 "
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v2/device/conn [post]
+func ConnectDevice2(c *gin.Context) {
+	var param gateway.ConnectDevice
+	err := c.ShouldBindJSON(&param)
+	if err != nil {
+		fmt.Printf("参数格式化异常:%s", err.Error())
+		response.Failed(errors.ParamInvalid, c)
+		return
+	}
+	topic := "/" + global.Config.EmqConfig.GatewayMac + constant.TopicConnectSub
+	ConnectDeviceEmq(global.EmqClient, topic, param.Mac, "0", param.Ai, param.At)
+	response.Success("连接设备完成", "", c)
+	return
+}
+
+// DisConnect
+// PingExample confrontation-training
+// @Summary 断开连接设备
+// @Schemes
+// @Description 断开连接设备
+// @Tags 设备管理
+// @Param device body string true "mac:设备MAC地址 "
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v2/device/dis/conn [post]
+func DisConnect(c *gin.Context) {
+	var param gateway.ConnectDevice
+	err := c.ShouldBindJSON(&param)
+	if err != nil {
+		fmt.Printf("参数格式化异常:%s", err.Error())
+		response.Failed(errors.ParamInvalid, c)
+		return
+	}
+	topic := "/" + global.Config.EmqConfig.GatewayMac + constant.TopicConnectSub
+	DisConnectDeviceEmq(global.EmqClient, topic, param.Mac)
+	response.Success("断开设备连接成功", "", c)
+	return
+}
+
+// ConnectList
+// PingExample confrontation-training
+// @Summary 已连接列表
+// @Schemes
+// @Description 已连接列表
+// @Tags 设备管理
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v2/device/connected/list [get]
+func ConnectList(c *gin.Context) {
+	topic := "/" + global.Config.EmqConfig.GatewayMac + constant.TopicConnectSub
+	//ConnectedListEmq(global.EmqClient, topic)
+	//ConnectedNumber(global.EmqClient, topic)
+	for i := 0; i < 6; i++ {
+		ConnectedListEmq(global.EmqClient, topic, strconv.Itoa(i))
+	}
+	response.Success("查询连接列表完成", "", c)
+	return
+}
+
+// WriteDataEmq
+// PingExample confrontation-training
+// @Summary 写入数据-脑电写入指令
+// @Schemes
+// @Description 写入数据-脑电写入指令
+// @Tags 设备管理
+// @Param mac body string true "mac:设备MAC地址 userName:用户姓名 gender:性别 age:年龄 height:身高 weight:体重"
+// @Accept json
+// @Produce json
+// @Success 200 {string} string "ok"
+// @Router /v2/device/write/data [post]
+func WriteDataEmq(c *gin.Context) {
+	var param models.WriteData
+	err := c.ShouldBindJSON(&param)
+	if err != nil {
+		fmt.Printf("参数格式化异常:%s", err.Error())
+		response.Failed(errors.ParamInvalid, c)
+		return
+	}
+	userNameHex := hex.EncodeToString([]byte(param.UserName))
+	topic := "/" + global.Config.EmqConfig.GatewayMac + constant.TopicConnectSub
+	//写入
+	//1 绑定用户指令
+	//指令头(E841) + user信息前缀(AA)+姓名(姓名字节长度+姓名+姓名不足12字节占位符)+性别+年龄+身高+体重
+	var stringBuild strings.Builder
+	stringBuild.WriteString(constant.BindUserInfoCmdPrefix)
+	length := len(userNameHex) / 2
+
+	bytes := common.Int2Bytes(length)
+	result := common.Bytes2HexStr(bytes)
+	result = common.Int2Byte(int64(length))
+	if result == "" {
+		response.Failed("用户名处理异常", c)
+		return
+	}
+	result = result[len(result)-2:]
+	stringBuild.WriteString(result)
+	stringBuild.WriteString(userNameHex)
+	placeHolder := common.GenerateHexStringCmdPlaceHolder(constant.MaxNameByteLength - length)
+	stringBuild.WriteString(placeHolder)
+	hexGender := common.Int2Byte(param.Gender)
+	stringBuild.WriteString(hexGender[len(hexGender)-2:])
+	if param.Age == 0 {
+		param.Age = constant.EcgDefaultAge
+	}
+	hexAge := common.Int2Byte(param.Age)
+	stringBuild.WriteString(hexAge[len(hexAge)-2:])
+	if param.Height == 0 {
+		param.Height = constant.EcgDefaultHeight
+	}
+	hexHeight := common.Int2Byte(param.Height)
+	stringBuild.WriteString(hexHeight[len(hexHeight)-2:])
+
+	if param.Weight == 0 {
+		param.Weight = constant.EcgDefaultWeight
+	}
+	hexWeight := common.Int2Byte(param.Weight)
+	stringBuild.WriteString(hexWeight[len(hexWeight)-2:])
+	bindUserCmdByte := []byte(stringBuild.String())
+	bindUserCmd := string(bindUserCmdByte)
+
+	fmt.Println(bindUserCmd)
+
+	//2.授时指令
+	//timeCmd := common.GetTimeCmd()
+	timeCmd := common.GetHexTimeStr()
+	//timeCmd = fmt.Sprintf("%s%s", "0x", timeCmd)
+	setTimeCmd := fmt.Sprintf("%s%s", constant.SetTimeCmdPrefix, timeCmd)
+	fmt.Println(setTimeCmd)
+	//3.开始收集指令
+	startCollectCmd := fmt.Sprintf("%s%s", constant.StartCollectCmdPrefix, timeCmd)
+	fmt.Println(startCollectCmd)
+	//发送指令
+	//绑定用户
+	WNP(global.EmqClient, topic, param.Mac, "FFF1", bindUserCmd)
+	//授时
+	WNP(global.EmqClient, topic, param.Mac, "FFF1", setTimeCmd)
+	//开始收集
+	WNP(global.EmqClient, topic, param.Mac, "FFF1", startCollectCmd)
+	//开始传输指令
+	WNP(global.EmqClient, topic, param.Mac, "FFF1", constant.StartTransCmd)
+	response.Success(errors.WriteDataSuccess, nil, c)
+	return
+}
+func OpenNotifyEmq(c *gin.Context) {
+
+}

+ 120 - 0
api/gateway/gatewayEmp.go

@@ -0,0 +1,120 @@
+package gateway
+
+import (
+	"confrontation-training/constant"
+	"confrontation-training/global"
+	"fmt"
+	mqtt "github.com/eclipse/paho.mqtt.golang"
+	"time"
+)
+
+func Publish(client mqtt.Client, topic string, message string) {
+
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+
+func SendUUID(client mqtt.Client, topic string) {
+
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, constant.CmdSetUUID); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, constant.CmdSetUUID)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, constant.CmdSetUUID)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+
+func ReadUUID(client mqtt.Client, topic string) {
+	message := "[{\"cmd\":\"AT+SUUID=\",\"param\":\"?\",\"i\":\"0\"}]"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+
+func ConnectDeviceEmq(client mqtt.Client, topic string, mac string, index string, ai string, at string) {
+	message := "[{\"cmd\":\"AT+CNN=\",\"m\":\"" + mac + "\",\"i\":\"" + index + "\",\"ai\":\"" + ai + "\",\"at\":\"" + at + "\",\"l\":\"1\",\"x\":\"251\",\"relink\":\"1\",\"timeout\":\"12000\"}]"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+func DisConnectDeviceEmq(client mqtt.Client, topic string, mac string) {
+	message := "[{\"cmd\":\"AT+DISCNN=\",\"m\":\"" + mac + "\"}]"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+func ConnectedNumber(client mqtt.Client, topic string) {
+	message := "{\"cmd\":\"AT+CNB=\",\"param\":\"?\"}"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+func ConnectedListEmq(client mqtt.Client, topic string, index string) {
+
+	message := "{\"cmd\":\"AT+QUE=\",\"param\":\"?\",\"h\":\"" + index + "\"}"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+
+// WNP 写入指令 write no response
+func WNP(client mqtt.Client, topic string, mac string, uuid string, data string) {
+	message := "[{\"cmd\":\"AT+WNP=\",\"m\":\"" + mac + "\",\"s\":\"FFF0\",\"u\":\"" + uuid + "\",\"d\":\"" + data + "\"}]"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+
+// W 写入数据
+func W(client mqtt.Client, topic string, mac string, uuid string, data string) {
+	message := "[{\"cmd\":\"AT+W=\",\"m\":\"" + mac + "\",\"s\":\"FFF1\",\"u\":\"" + uuid + "\",\"d\":\"" + data + "\"}]"
+	//messagee = "[{\"cmd\":\"AT+W=\",\"m\":\"" + mac + "\",\"s\":\"FFF1\",\"u\":\"" + uuid + "\",\"d\":\"" + data + "\"}]"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+
+func Read(client mqtt.Client, topic string, mac string, uuid string) {
+	message := "[{\"cmd\":\"AT+W=\",\"m\":\"" + mac + "\",\"s\":\"FFF0\",\"u\":\"" + uuid + "\"]"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}

+ 11 - 2
api/gateway/sse.go

@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"github.com/gorilla/websocket"
 	"github.com/r3labs/sse/v2"
+	"net/http"
 	"strconv"
 	"strings"
 	"time"
@@ -17,7 +18,6 @@ import (
 // SseScanDevice 扫描设备
 func SseScanDevice(paramMap map[string]string, filterType string) {
 	var scanUrl = global.Config.Gateway.BaseUrl + global.Config.Gateway.ScanUrl
-
 	deviceMap := make(map[string]gateway.DeviceScanned)
 	if len(paramMap) > 0 {
 		for key, value := range paramMap {
@@ -38,6 +38,7 @@ func SseScanDevice(paramMap map[string]string, filterType string) {
 		return
 	}
 	fmt.Println("开始SSE")
+
 	err = client.SubscribeRaw(func(msg *sse.Event) {
 		var data gateway.DeviceScannedFromGateway
 		err := json.Unmarshal(msg.Data, &data)
@@ -50,12 +51,13 @@ func SseScanDevice(paramMap map[string]string, filterType string) {
 		//库中存在的设备
 		if filterType == "1" {
 			deviceService := GetDeviceService()
-			_, i := deviceService.FindDeviceByMac(deviceScanned.MAC)
+			d, i := deviceService.FindDeviceByMac(deviceScanned.MAC)
 			if i > 0 {
 				deviceScanned.Name = data.Name
 				deviceScanned.Rssi = data.Rssi
 				deviceScanned.BdadrType = data.Bdaddrs[0].BdaddrType
 				deviceScanned.Chip = data.ChipId
+				deviceScanned.DeviceType = d.Type
 				deviceMap[deviceScanned.MAC] = deviceScanned
 				fmt.Println(deviceScanned)
 			}
@@ -102,6 +104,13 @@ func SseScanDevice(paramMap map[string]string, filterType string) {
 		time.Sleep(200 * time.Millisecond)
 	})
 }
+func StopScan(w http.ResponseWriter, r *http.Request) {
+	go func() {
+		<-r.Context().Done()
+		println("The client is disconnected here")
+		return
+	}()
+}
 
 // SseOpenNotify 开启通知
 func SseOpenNotify() {

+ 3 - 0
common/utils.go

@@ -14,6 +14,7 @@ import (
 )
 
 // GenerateUUID 生成UUID
+//Deprecated
 func GenerateUUID() string {
 	UUID, err := uuid.NewRandom()
 	if err != nil {
@@ -24,6 +25,7 @@ func GenerateUUID() string {
 }
 
 // CheckFile 检查文件扩展名
+//Deprecated
 func CheckFile(fileName string) string {
 
 	fileNames := []string{"json", "txt", "wav", "npy", "xlsx", "xls"}
@@ -36,6 +38,7 @@ func CheckFile(fileName string) string {
 }
 
 // GetCurrentAbPathByExecutable 获取当前执行程序所在的绝对路径
+//Deprecated
 func GetCurrentAbPathByExecutable() string {
 	exePath, err := os.Executable()
 	if err != nil {

+ 23 - 1
config/application.yaml

@@ -24,7 +24,7 @@ cron:
 #蓝牙网关地址
 gateway:
   baseUrl: http://192.168.2.254
-  scanUrl: /gap/nodes?active=1&event=1
+  scanUrl: /gap/nodes?active=1&event=1&filter_name=BW-ECG*,MIND*&chip=1
   connUrl: /gap/nodes/MAC/connection?chip
   notifyUrl: /gatt/nodes?event=1
   writeDataUrl: /gatt/nodes/MAC/handle/32/value/DATA
@@ -40,6 +40,28 @@ log2file:
 #第一次打开
 param:
   firstOpen : 1
+emq:
+  protocol: tcp
+  port: 1883
+  topic:
+#  - /EE3870DA24C4/connect_packet/hds_subscribe
+#  - /EE3870DA24C4/connect_packet/connect3_subscribe
+#  - /EE3870DA24C4/connect_packet/connect1_subscribe
+#  - /EE3870DA24C4/connect_packet/cfg_param_subscribe
+#  - /EE3870DA24C4/connect_packet/connect2_subscribe
+#  - /EE3870DA24C4/connect_packet/connect4_subscribe
+  - /connect_packet/connect1_publish
+  userName: admin
+  password: Psychical_admin502
+  clientId: emqClientCT
+  qos: 0
+  broker: emqx@127.0.0.1
+  filter:
+  - MIND
+  - BW-ECG
+  gatewayMac: EE3870DA24C4
+
+#  [{"cmd":"AT+FLT=","total":"2"},{"t":"0","d":"MIND"},{"t":"0","d":"BW-ECG"}]
 
 
 

+ 14 - 0
config/config.go

@@ -26,6 +26,7 @@ type Config struct {
 	Gateway   Gateway   `mapstructure:"gateway"`
 	Log2File  Log2File  `mapstructure:"log2file"`
 	Param     Param     `mapstructure:"Param"`
+	EmqConfig EmqConfig `mapstructure:"emq"`
 }
 
 // Server 服务启动端口配置
@@ -58,3 +59,16 @@ type Log2File struct {
 	FileName   string `mapstructure:"FileName"`
 	FileSuffix string `mapstructure:"FileSuffix"`
 }
+
+type EmqConfig struct {
+	Protocol   string   `mapstructure:"protocol"`
+	Port       int      `mapstructure:"port"`
+	Topic      []string `mapstructure:"topic"`
+	UserName   string   `mapstructure:"userName"`
+	Password   string   `mapstructure:"password"`
+	ClientId   string   `mapstructure:"clientId"`
+	Qos        int      `mapstructure:"qos"`
+	Broker     string   `mapstructure:"broker"`
+	Filter     []string `mapstructure:"filter"`
+	GatewayMac string   `mapstructure:"gatewayMac"`
+}

+ 26 - 2
constant/constant.go

@@ -21,10 +21,34 @@ const (
 	DefaultPlaceHolder = "00"
 
 	// MessageTypeDeviceScanned websocket 消息类型 扫描到设备
+	MessageTypePayload       = "payload"
 	MessageTypeDeviceScanned = "device"
 	MessageTypeEEGData       = "eegData"
 	MessageTypeECGData       = "ecgData"
+	MessageTypeCloseScan     = "closeScan"
+	MessageTypeStartScan     = "startScan"
+	MessageTypeFilter        = "filter"
+	MessageTypeSUUID         = "suuid"
+	MessageTypeConnect       = "connect"
+	MessageTypeDisConnect    = "disConnect"
+	MessageTypeConnectList   = "connectedList"
 	// DefaultKey 3des
-	DefaultKey = "240262447423713749922240"
-	DefaultIv  = "12345678"
+	DefaultKey      = "240262447423713749922240"
+	DefaultIv       = "12345678"
+	TopicConnectSub = "/connect_packet/connect1_subscribe"
+
+	/*V2指令*/
+	CmdStopScan  = "[{\"cmd\":\"AT+SCAN=\",\"s\":\"0\"}]"
+	CmdStartScan = "[{\"cmd\":\"AT+SCAN=\",\"s\":\"1\"}]"
+	CmdSetUUID   = "[{\"cmd\":\"AT+SUUID=\",\"total\":\"1\"},{\"a\":\"FFF0\"}]"
+	Success      = "SUCCESS"
+	//v2 payload case
+	PayloadScan       = "SCAN"        //扫描|关闭扫描响应
+	PayloadFLT        = "FLT"         //设置过滤
+	PayloadSUUID      = "SUUID"       //设置服务UUID
+	PayloadConnect    = "CONNECT"     //连接设备
+	PayloadDisConnect = "DISSCONNECT" //断开连接设备
+	PayloadQuenue     = "QUENUE"      //已连接设备
+	PayloadCNB        = "CNB"         //连接个数
+	PayloadNotify     = "NOTIFY"
 )

BIN
db/confrontation-training.db


+ 171 - 0
docs/docs.go

@@ -614,6 +614,177 @@ const docTemplate = `{
                     }
                 }
             }
+        },
+        "/v2/device/conn": {
+            "post": {
+                "description": "连接设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "连接设备",
+                "parameters": [
+                    {
+                        "description": "mac:设备MAC地址 ai:终端BLE设备的地址ID  at:终端BLE设备的地址类型 ",
+                        "name": "device",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/connected/list": {
+            "get": {
+                "description": "已连接列表",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "已连接列表",
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/dis/conn": {
+            "post": {
+                "description": "断开连接设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "断开连接设备",
+                "parameters": [
+                    {
+                        "description": "mac:设备MAC地址 ",
+                        "name": "device",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/scan": {
+            "get": {
+                "description": "扫描设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "扫描设备",
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/stop/scan": {
+            "get": {
+                "description": "停止扫描设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "停止扫描设备",
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/write/data": {
+            "post": {
+                "description": "写入数据-脑电写入指令",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "写入数据-脑电写入指令",
+                "parameters": [
+                    {
+                        "description": "mac:设备MAC地址 userName:用户姓名 gender:性别 age:年龄 height:身高 weight:体重",
+                        "name": "mac",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
         }
     }
 }`

+ 171 - 0
docs/swagger.json

@@ -605,6 +605,177 @@
                     }
                 }
             }
+        },
+        "/v2/device/conn": {
+            "post": {
+                "description": "连接设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "连接设备",
+                "parameters": [
+                    {
+                        "description": "mac:设备MAC地址 ai:终端BLE设备的地址ID  at:终端BLE设备的地址类型 ",
+                        "name": "device",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/connected/list": {
+            "get": {
+                "description": "已连接列表",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "已连接列表",
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/dis/conn": {
+            "post": {
+                "description": "断开连接设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "断开连接设备",
+                "parameters": [
+                    {
+                        "description": "mac:设备MAC地址 ",
+                        "name": "device",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/scan": {
+            "get": {
+                "description": "扫描设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "扫描设备",
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/stop/scan": {
+            "get": {
+                "description": "停止扫描设备",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "停止扫描设备",
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
+        },
+        "/v2/device/write/data": {
+            "post": {
+                "description": "写入数据-脑电写入指令",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "设备管理"
+                ],
+                "summary": "写入数据-脑电写入指令",
+                "parameters": [
+                    {
+                        "description": "mac:设备MAC地址 userName:用户姓名 gender:性别 age:年龄 height:身高 weight:体重",
+                        "name": "mac",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "ok",
+                        "schema": {
+                            "type": "string"
+                        }
+                    }
+                }
+            }
         }
     }
 }

+ 111 - 0
docs/swagger.yaml

@@ -392,4 +392,115 @@ paths:
       summary: 管理员重置普通用户密码
       tags:
       - 用户管理
+  /v2/device/conn:
+    post:
+      consumes:
+      - application/json
+      description: 连接设备
+      parameters:
+      - description: 'mac:设备MAC地址 ai:终端BLE设备的地址ID  at:终端BLE设备的地址类型 '
+        in: body
+        name: device
+        required: true
+        schema:
+          type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: ok
+          schema:
+            type: string
+      summary: 连接设备
+      tags:
+      - 设备管理
+  /v2/device/connected/list:
+    get:
+      consumes:
+      - application/json
+      description: 已连接列表
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: ok
+          schema:
+            type: string
+      summary: 已连接列表
+      tags:
+      - 设备管理
+  /v2/device/dis/conn:
+    post:
+      consumes:
+      - application/json
+      description: 断开连接设备
+      parameters:
+      - description: 'mac:设备MAC地址 '
+        in: body
+        name: device
+        required: true
+        schema:
+          type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: ok
+          schema:
+            type: string
+      summary: 断开连接设备
+      tags:
+      - 设备管理
+  /v2/device/scan:
+    get:
+      consumes:
+      - application/json
+      description: 扫描设备
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: ok
+          schema:
+            type: string
+      summary: 扫描设备
+      tags:
+      - 设备管理
+  /v2/device/stop/scan:
+    get:
+      consumes:
+      - application/json
+      description: 停止扫描设备
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: ok
+          schema:
+            type: string
+      summary: 停止扫描设备
+      tags:
+      - 设备管理
+  /v2/device/write/data:
+    post:
+      consumes:
+      - application/json
+      description: 写入数据-脑电写入指令
+      parameters:
+      - description: mac:设备MAC地址 userName:用户姓名 gender:性别 age:年龄 height:身高 weight:体重
+        in: body
+        name: mac
+        required: true
+        schema:
+          type: string
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: ok
+          schema:
+            type: string
+      summary: 写入数据-脑电写入指令
+      tags:
+      - 设备管理
 swagger: "2.0"

+ 5 - 1
global/global.go

@@ -2,6 +2,8 @@ package global
 
 import (
 	"confrontation-training/config"
+	"confrontation-training/models/gateway"
+	mqtt "github.com/eclipse/paho.mqtt.golang"
 	"github.com/r3labs/sse/v2"
 	"gorm.io/gorm"
 )
@@ -11,5 +13,7 @@ var (
 	Db              *gorm.DB
 	SseClientDevice *sse.Client
 	SseClientData   *sse.Client
-	//EcgDataMap      map[string][]byte
+	DeviceMap       map[string]gateway.DeviceInfo
+	EmqClient       mqtt.Client
+	EmqConfig       config.EmqConfig
 )

+ 4 - 0
go.mod

@@ -3,6 +3,7 @@ module confrontation-training
 go 1.18
 
 require (
+	github.com/eclipse/paho.mqtt.golang v1.4.3
 	github.com/forgoer/openssl v1.6.0
 	github.com/gin-gonic/gin v1.9.1
 	github.com/golang-jwt/jwt v3.2.2+incompatible
@@ -11,6 +12,7 @@ require (
 	github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
 	github.com/r3labs/sse/v2 v2.10.0
 	github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
+	github.com/rosshemsley/kalman v0.0.0-20190615074247-f4b900823fd1
 	github.com/sirupsen/logrus v1.9.3
 	github.com/spf13/viper v1.16.0
 	github.com/swaggo/files v1.0.1
@@ -64,9 +66,11 @@ require (
 	golang.org/x/arch v0.4.0 // indirect
 	golang.org/x/crypto v0.12.0 // indirect
 	golang.org/x/net v0.14.0 // indirect
+	golang.org/x/sync v0.3.0 // indirect
 	golang.org/x/sys v0.11.0 // indirect
 	golang.org/x/text v0.12.0 // indirect
 	golang.org/x/tools v0.12.0 // indirect
+	gonum.org/v1/gonum v0.0.0-20190606121551-14af50e936aa // indirect
 	google.golang.org/protobuf v1.31.0 // indirect
 	gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect

+ 24 - 0
go.sum

@@ -40,6 +40,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
+github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
 github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
 github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk=
@@ -62,12 +63,16 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik=
+github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
 github.com/forgoer/openssl v1.6.0 h1:IueL+UfH0hKo99xFPojHLlO3QzRBQqFY+Cht0WwtOC0=
 github.com/forgoer/openssl v1.6.0/go.mod h1:9DZ4yOsQmveP0aXC/BpQ++Y5TKaz5yR9+emcxmIZNZs=
 github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
@@ -109,6 +114,7 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
 github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -188,6 +194,7 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
@@ -242,6 +249,8 @@ github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnH
 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rosshemsley/kalman v0.0.0-20190615074247-f4b900823fd1 h1:TXlq7Zcp2DDUSx4IOFZsnI1lxgmzohi+a6VUuVq96h4=
+github.com/rosshemsley/kalman v0.0.0-20190615074247-f4b900823fd1/go.mod h1:dHizxAEL44JWT1mY21IGabhibfrRkDvWKVaP7I7W4z4=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
@@ -305,7 +314,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
+golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
@@ -314,7 +326,9 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -397,6 +411,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -457,8 +473,10 @@ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@@ -511,6 +529,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
+gonum.org/v1/gonum v0.0.0-20190606121551-14af50e936aa h1:v7uN4OlNuZOfC/1xsGuO9c4KiSHMqQaHSc//AQvMBtg=
+gonum.org/v1/gonum v0.0.0-20190606121551-14af50e936aa/go.mod h1:zXcK6UmEkbNk22MqyPrZPx3T6fsE/O56XzkDfeYUF+Y=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
+gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=

+ 4 - 2
http/http.go

@@ -15,11 +15,13 @@ func GetReq(url string) *http.Response {
 
 	req, err := http.NewRequest("GET", url, nil)
 	if err != nil {
-		panic(err)
+		//panic(err)
+		fmt.Println(err.Error())
 	}
 	resp, err := client.Do(req)
 	if err != nil {
-		panic(err)
+		//panic(err)
+		fmt.Println(err.Error())
 	}
 	//defer func(Body io.ReadCloser) {
 	//	err := Body.Close()

+ 260 - 0
initialize/emq.go

@@ -0,0 +1,260 @@
+package initialize
+
+import (
+	gateway2 "confrontation-training/api/gateway"
+	"confrontation-training/constant"
+	"confrontation-training/global"
+	"confrontation-training/models/emq"
+	"confrontation-training/models/gateway"
+	"encoding/json"
+	"fmt"
+	mqtt "github.com/eclipse/paho.mqtt.golang"
+	"github.com/gorilla/websocket"
+	"log"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func CreateEmqClient() {
+
+	config := global.Config
+	global.EmqConfig.ClientId = config.EmqConfig.ClientId
+	global.EmqConfig.Qos = config.EmqConfig.Qos
+	global.EmqConfig.Topic = config.EmqConfig.Topic
+	global.EmqConfig.UserName = config.EmqConfig.UserName
+	global.EmqConfig.Password = config.EmqConfig.Password
+	global.EmqConfig.Protocol = config.EmqConfig.Protocol
+	global.EmqConfig.Port = config.EmqConfig.Port
+	global.EmqConfig.Broker = config.EmqConfig.Broker
+	global.EmqConfig.Filter = config.EmqConfig.Filter
+	global.EmqConfig.GatewayMac = config.EmqConfig.GatewayMac
+	emqConfig := global.EmqConfig
+	connectAddress := fmt.Sprintf("%s://%s:%d", emqConfig.Protocol, emqConfig.Broker, emqConfig.Port)
+	fmt.Println("connect address:", connectAddress)
+	opts := mqtt.NewClientOptions()
+	opts.AddBroker(connectAddress)
+	opts.SetUsername(emqConfig.UserName)
+	opts.SetPassword(emqConfig.Password)
+	opts.SetClientID(emqConfig.ClientId)
+	opts.SetKeepAlive(time.Second * 60)
+	global.EmqClient = mqtt.NewClient(opts)
+	client := global.EmqClient
+	token := client.Connect()
+	if token.WaitTimeout(time.Second*3) && token.Error() != nil {
+		log.Fatal(token.Error())
+	}
+	SubScribe(client)
+	//SendUUID(client, "/EE3870DA24C4/connect_packet/connect1_subscribe")
+	//Publish(client, "/EE3870DA24C4/connect_packet/connect1_subscribe", constant.CmdStartScan)
+	//SendUUID(client, "/EE3870DA24C4/connect_packet/connect1_subscribe")
+	//读取UUID
+	//ReadUUID(client, "/EE3870DA24C4/connect_packet/connect1_subscribe")
+	//连接设备
+	//ConnectDevice(client, "/EE3870DA24C4/connect_packet/connect1_subscribe", "DC0D30033AF0", "0", "0", "0")
+
+	//fmt.Println("link device DC0D30033AF0 over")
+	//ConnectDevice(client, "/EE3870DA24C4/connect_packet/connect1_subscribe", "DC0D300335FC", "0", "0", "0")
+}
+
+func Publish(client mqtt.Client, topic string, message string) {
+
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+func SendUUID(client mqtt.Client, topic string) {
+
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, constant.CmdSetUUID); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, constant.CmdSetUUID)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, constant.CmdSetUUID)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+func ConnectDevice(client mqtt.Client, topic string, mac string, index string, ai string, at string) {
+	message := "[{\"cmd\":\"AT+CNN=\",\"m\":\"" + mac + "\",\"i\":\"" + index + "\",\"ai\":\"" + ai + "\",\"at\":\"" + at + "\",\"l\":\"1\",\"x\":\"251\",\"relink\":\"1\",\"timeout\":\"12000\"}]"
+	if token := client.Publish(topic, byte(global.EmqConfig.Qos), false, message); token.Wait() && token.Error() != nil {
+		fmt.Printf("publish failed, topic: %s, payload: %s\n", topic, message)
+	} else {
+		fmt.Printf("publish success, topic: %s, payload: %s\n", topic, message)
+	}
+	//time.Sleep(time.Second * 1)
+	time.Sleep(time.Millisecond * 100)
+}
+func SubScribe(client mqtt.Client) {
+	emqConfig := global.EmqConfig
+	ws, _, err := websocket.DefaultDialer.Dial(global.Config.Websocket.WSUrl, nil)
+	if err != nil {
+		fmt.Println("socket通道初始化失败")
+		panic(err)
+		return
+	}
+	deviceService := GetDeviceService()
+	d, i := deviceService.FindDeviceByType("")
+	global.DeviceMap = make(map[string]gateway.DeviceInfo)
+	if i > 0 {
+		for j := 0; j < len(d); j++ {
+			global.DeviceMap[d[j].Mac] = d[j]
+		}
+	}
+	for _, topic := range emqConfig.Topic {
+		topic = "/" + global.EmqConfig.GatewayMac + topic
+		client.Subscribe(topic, byte(emqConfig.Qos), func(client mqtt.Client, message mqtt.Message) {
+			//fmt.Printf("`%s` Received `%s` from `%s` topic\n", common.NowTime("2006-01-02 15:04:05"), message.Payload(), message.Topic())
+			messageMap := make(map[string]string)
+			var payloads []emq.Payload
+			err := json.Unmarshal(message.Payload(), &payloads)
+			if err != nil {
+				_ = fmt.Errorf("%s", err.Error())
+				return
+			}
+			for _, payload := range payloads {
+				messageMap["state"] = payload.State
+				content := ""
+				sendFlag := true
+				switch payload.Cmd {
+				case constant.PayloadScan:
+					{
+						//关闭扫描
+						if payload.S == "0" {
+							messageMap["msgType"] = constant.MessageTypeCloseScan
+							content = "关闭扫描"
+							//开启扫描
+						} else if payload.S == "1" {
+							messageMap["msgType"] = constant.MessageTypeStartScan
+							content = "开启扫描"
+						} else if payload.S == "" { //接收到蓝牙扫描数据
+							if strings.HasPrefix(payload.N, "MIND") {
+								payload.T = "0"
+							} else if strings.HasPrefix(payload.N, "BW-ECG") {
+								payload.T = "1"
+							}
+							messageMap["msgType"] = constant.MessageTypeDeviceScanned
+							marshal, _ := json.Marshal(payload)
+							content = string(marshal)
+						}
+					}
+
+				case constant.PayloadFLT:
+					messageMap["msgType"] = constant.MessageTypeFilter
+					content = "设置过滤"
+				case constant.PayloadSUUID:
+					messageMap["msgType"] = constant.MessageTypeSUUID
+					content = "设置UUID"
+				case constant.PayloadConnect:
+					messageMap["msgType"] = constant.MessageTypeConnect
+					content = "设备连接"
+				case constant.PayloadDisConnect:
+					messageMap["msgType"] = constant.MessageTypeDisConnect
+					//content = "断开设备连接"
+					marshal, _ := json.Marshal(payload)
+					content = string(marshal)
+				case constant.PayloadQuenue:
+					messageMap["msgType"] = constant.MessageTypeConnectList
+					if payload.M == "" {
+						sendFlag = false
+					} else {
+						realMac := transMac(payload.M)
+						deviceInfo := global.DeviceMap[realMac]
+						if deviceInfo.ID == 0 {
+							continue
+						} else {
+							payload.T = deviceInfo.Type
+							payload.N = deviceInfo.Name
+							marshal, _ := json.Marshal(payload)
+							content = string(marshal)
+						}
+
+					}
+				case constant.PayloadCNB:
+					connectedNum, _ := strconv.Atoi(payload.N)
+					for i := 0; i < connectedNum; i++ {
+						topic := "/" + global.Config.EmqConfig.GatewayMac + constant.TopicConnectSub
+						gateway2.ConnectedListEmq(global.EmqClient, topic, strconv.Itoa(i))
+					}
+				case constant.PayloadNotify: //接收到蓝牙通知数据
+					//1.判断是脑电数据还是心电数据
+					//1.1脑电数据直接转发
+					//1.2心电数据做处理
+					realMac := transMac(payload.M)
+					deviceInfo := global.DeviceMap[realMac]
+					var receiveData gateway.DeviceDataReceived
+					receiveData.Mac = payload.M
+					receiveData.Value = payload.D
+					if deviceInfo.Type == "0" { //脑电
+						messageMap["msgType"] = constant.MessageTypeEEGData
+						marshal, _ := json.Marshal(receiveData)
+						content = string(marshal)
+					} else if deviceInfo.Type == "1" { //心电
+						messageMap["msgType"] = constant.MessageTypeECGData
+						flag := strings.HasPrefix(receiveData.Value, "E840") || strings.HasPrefix(receiveData.Value, "E841") || strings.HasPrefix(receiveData.Value, "E823") || strings.HasPrefix(receiveData.Value, "E820") || strings.HasPrefix(receiveData.Value, "E81F") || strings.HasPrefix(receiveData.Value, "E813") || strings.HasPrefix(receiveData.Value, "E810") || strings.HasPrefix(receiveData.Value, "E822") || strings.HasPrefix(receiveData.Value, "E826") || strings.HasPrefix(receiveData.Value, "E8FF00000000")
+						if !flag {
+							//var ecgData []int
+							ecgData := [12]int{}
+							data := []byte(receiveData.Value[4:])
+							if len(data) == 36 {
+								for i := 0; i < 36; i += 3 {
+									ecgData[i/3] = int(16<<data[i]&0xFF | 8<<data[i+1]&0xFF | data[i+2]&0xFF)
+								}
+							} else {
+
+								for len(data) < 36 {
+									for i := len(data); i < 36; i++ {
+										data = append(data, data[i])
+									}
+								}
+								for i := 0; i < 36; i += 3 {
+									ecgData[i/3] = int(16<<data[i]&0xFF | 8<<data[i+1]&0xFF | data[i+2]&0xFF)
+								}
+							}
+							messageMap["msgType"] = constant.MessageTypeECGData
+							receiveData.Value = "["
+							for _, datum := range ecgData {
+								receiveData.Value = receiveData.Value + strconv.Itoa(datum) + ","
+							}
+							receiveData.Value = receiveData.Value + "]"
+							marshal, _ := json.Marshal(receiveData)
+							content = string(marshal)
+						}
+					}
+				}
+				if messageMap["msgType"] != constant.MessageTypeECGData && messageMap["msgType"] != constant.MessageTypeEEGData && messageMap["msgType"] != constant.MessageTypeDeviceScanned && messageMap["msgType"] != constant.MessageTypeConnectList && messageMap["msgType"] != constant.MessageTypeDisConnect {
+					if payload.State == constant.Success {
+						content = content + "成功"
+					} else {
+						content = content + "失败"
+					}
+				}
+
+				messageMap["content"] = content
+				messageMap["Sender"] = "server"
+				messageMap["Recipient"] = "client"
+				bytes, err := json.Marshal(messageMap)
+				if err != nil {
+					return
+				}
+				if sendFlag && content != "成功" && content != "失败" {
+					err = ws.WriteMessage(websocket.TextMessage, bytes)
+					if err != nil {
+						fmt.Println("消息发送异常:" + err.Error())
+					}
+				}
+				time.Sleep(time.Millisecond * 5)
+			}
+		})
+	}
+}
+
+func transMac(mac string) string {
+	result := ""
+	for i := 0; i < len(mac); i = i + 2 {
+		result = result + mac[i:i+2] + ":"
+	}
+	return result[0 : len(result)-1]
+}

+ 11 - 1
initialize/router.go

@@ -63,13 +63,23 @@ func Router() {
 	device.GET("/:mac/disconnect", gateway.GetDeviceService().Disconnect)
 	device.POST("/add/", gateway.GetDeviceService().DeviceAdd)
 	device.DELETE("/:mac/remove/", gateway.GetDeviceService().DeviceRemove)
-	device.GET("/list/:type", gateway.GetDeviceService().DeviceList)
+	device.GET("/list/", gateway.GetDeviceService().DeviceList)
 	device.GET("connected", gateway.GetDeviceService().DeviceConnected)
 	chats := v1.Group("/chat")
 	chats.GET("/get/chat/", chat.GetQuestionService().GetQuestion)
 	chats.POST("/create/chat/", chat.GetQuestionService().CreateQuestion)
 	chats.GET("/get/answer/", chat.GetAnswerService().GetAnswer)
 
+	v2 := engine.Group("/v2")
+	device2 := v2.Group("/device")
+	device2.GET("/scan", gateway.ScanDeviceEmq)
+	device2.GET("/stop/scan", gateway.StopScanDeviceEmq)
+	device2.POST("/conn", gateway.ConnectDevice2)
+	device2.POST("/dis/conn", gateway.DisConnect)
+	device2.GET("/connected/list", gateway.ConnectList)
+	device2.POST("/write/data", gateway.WriteDataEmq)
+	//初始化SSE
+
 	//
 	//record := v1.Group("/record")
 	//record.POST("/create", api.GetRecord().SaveRecord)

+ 4 - 1
initialize/run.go

@@ -4,7 +4,10 @@ func Run() {
 	SwagInit()
 	LoadConfig()
 	SQLite()
-	CreateSseClient()
+	//StartSSe()
 	go Manager.Start()
+	//go StartDataSSeClient()
+	//go StartScanSseClient()
+	go CreateEmqClient()
 	Router()
 }

+ 214 - 3
initialize/sseclient.go

@@ -1,11 +1,222 @@
 package initialize
 
 import (
+	"confrontation-training/common"
+	"confrontation-training/constant"
+	errors "confrontation-training/err"
 	"confrontation-training/global"
+	"confrontation-training/models/gateway"
+	deviceService "confrontation-training/service/device"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"github.com/gorilla/websocket"
 	"github.com/r3labs/sse/v2"
+	"github.com/rosshemsley/kalman"
+	"github.com/rosshemsley/kalman/models"
+	"strconv"
+	"strings"
+	"time"
 )
 
-func CreateSseClient() {
-	global.SseClientDevice = sse.NewClient("")
-	global.SseClientData = sse.NewClient("")
+type DeviceService struct {
+	deviceService.DeviceService
+}
+
+func GetDeviceService() *DeviceService {
+	return &DeviceService{}
+}
+func StartDataSSeClient() {
+	fmt.Println("start data sse")
+	var notifyUrl = global.Config.Gateway.BaseUrl + global.Config.Gateway.NotifyUrl
+	global.SseClientData = sse.NewClient(notifyUrl)
+	ws, _, err := websocket.DefaultDialer.Dial(global.Config.Websocket.WSUrl, nil)
+	if err != nil {
+		fmt.Println("Websocket client init error" + err.Error())
+		return
+	}
+	//client := global.SseClientData(notifyUrl)
+	client := global.SseClientData
+	client.URL = notifyUrl
+	//库中存在的设备
+	deviceService := GetDeviceService()
+	d, i := deviceService.FindDeviceByType("")
+	global.DeviceMap = make(map[string]gateway.DeviceInfo)
+	if i > 0 {
+		for j := 0; j < len(d); j++ {
+			global.DeviceMap[d[j].Mac] = d[j]
+		}
+	}
+	err = client.SubscribeRaw(func(msg *sse.Event) {
+		bytes := msg.Data
+		s := string(bytes)
+		nowTime := common.NowTime("2006-01-02 15:04:05")
+		fmt.Println(nowTime)
+		fmt.Println("notify receive data :" + s)
+		//脑电数据
+		var receiveData gateway.DeviceDataReceived
+		errJson := json.Unmarshal(msg.Data, &receiveData)
+		if errJson != nil {
+			fmt.Println("receive data parse error:" + errJson.Error())
+			return
+		}
+		deviceInfo := global.DeviceMap[receiveData.Mac]
+		messageMap := make(map[string]string)
+		if deviceInfo.Type == "0" {
+			messageMap["msgType"] = constant.MessageTypeEEGData
+			marshal, _ := json.Marshal(receiveData)
+			messageMap["content"] = string(marshal)
+		} else if deviceInfo.Type == "1" {
+			//心电数据
+			flag := strings.HasPrefix(receiveData.Value, "E840") || strings.HasPrefix(receiveData.Value, "E841") || strings.HasPrefix(receiveData.Value, "E823")
+			if !flag {
+				//var ecgData []int
+				ecgData := [6]int{}
+				fmt.Println("收到的心电数据:" + string(msg.Data))
+				fmt.Print("数据长度:")
+				fmt.Println(len(msg.Data))
+				data, _ := hex.DecodeString(receiveData.Value[4:])
+				//data := []byte(receiveData.Value[4:])
+				fmt.Println(len(data))
+				if len(data) == 18 {
+					for i := 0; i < 18; i += 3 {
+						ecgData[i/3] = int(int32(data[i]&255)<<16 | int32(data[i+1]&255)<<8 | int32(data[i+2]&255))
+						fmt.Print("ecgData:")
+						fmt.Println(ecgData[i/3])
+					}
+				} else {
+					for i := len(data); i < 18; i++ {
+						data = append(data, data[i])
+					}
+					for i := 0; i < 18; i += 3 {
+						ecgData[i/3] = int(int32(data[i]&255)<<16 | int32(data[i+1]&255)<<8 | int32(data[i+2]&255))
+						fmt.Print("ecgData:")
+						fmt.Println(ecgData[i/3])
+					}
+				}
+
+				messageMap["msgType"] = constant.MessageTypeECGData
+				var dataStr []string
+				var t time.Time
+				model := models.NewSimpleModel(t, float64(ecgData[0]), models.SimpleModelConfig{
+					InitialVariance:     1.0,
+					ProcessVariance:     1.0,
+					ObservationVariance: 2.0,
+				})
+				filter := kalman.NewKalmanFilter(model)
+				for _, v := range ecgData {
+					t = t.Add(time.Second)
+					filter.Update(t, model.NewMeasurement(float64(v)))
+					fmt.Printf("filtered value: %f\n", model.Value(filter.State()))
+					dataStr = append(dataStr, strconv.FormatFloat(model.Value(filter.State()), 'f', 2, 64))
+				}
+				//for _, v := range ecgData {
+				//	dataStr = append(dataStr, strconv.Itoa(v))
+				//}
+				receiveData.Value = strings.Join(dataStr, ",")
+				marshal, _ := json.Marshal(receiveData)
+				messageMap["content"] = string(marshal)
+			}
+		}
+
+		messageMap["Sender"] = "server"
+		messageMap["Recipient"] = "client"
+		bytes, err := json.Marshal(messageMap)
+		//fmt.Println("sendData:" + common.NowTime("2006-01-02 15:04:05"))
+		fmt.Println(messageMap)
+		err = ws.WriteMessage(websocket.TextMessage, bytes)
+		if err != nil {
+			fmt.Println(errors.SendMessageError + err.Error())
+			return
+		}
+	})
+}
+func StartScanSseClient() {
+	fmt.Println("start scan sse")
+	var baseUrl = global.Config.Gateway.BaseUrl
+	var deviceUrl = global.Config.Gateway.ScanUrl
+	global.SseClientDevice = sse.NewClient(baseUrl + deviceUrl)
+	deviceMap := make(map[string]gateway.DeviceScanned)
+	ws, _, err := websocket.DefaultDialer.Dial(global.Config.Websocket.WSUrl, nil)
+	if err != nil {
+		fmt.Println("websocket初始化异常:" + err.Error())
+		return
+	}
+	//库中存在的设备
+	deviceService := GetDeviceService()
+	d, i := deviceService.FindDeviceByType("")
+	temp := make(map[string]gateway.DeviceInfo)
+	if i > 0 {
+		for j := 0; j < len(d); j++ {
+			temp[d[j].Mac] = d[j]
+		}
+		err = global.SseClientDevice.SubscribeRaw(func(msg *sse.Event) {
+			fmt.Print("扫描数据:")
+			fmt.Print(string(msg.Data))
+			var data gateway.DeviceScannedFromGateway
+			err := json.Unmarshal(msg.Data, &data)
+			if err != nil {
+				fmt.Printf("SSE数据转换异常:%s", err.Error())
+			} else {
+				deviceScanned := gateway.DeviceScanned{}
+				deviceScanned.MAC = data.Bdaddrs[0].Bdaddr
+				d := temp[deviceScanned.MAC]
+				if d.ID > 0 {
+					deviceScanned.Name = d.Name
+					deviceScanned.Rssi = data.Rssi
+					deviceScanned.BdadrType = data.Bdaddrs[0].BdaddrType
+					deviceScanned.Chip = data.ChipId
+					deviceScanned.DeviceType = d.Type
+					deviceMap[deviceScanned.MAC] = deviceScanned
+				}
+				if deviceScanned.Name == "" {
+					if d.Type == "0" {
+						deviceScanned.Name = "MIND" + strings.ReplaceAll(deviceScanned.MAC[len(deviceScanned.MAC)-5:], ":", "")
+					} else {
+						deviceScanned.Name = "BW-ECG-01"
+					}
+				}
+
+				if len(deviceMap) > 0 {
+					//fmt.Print("deviceMap:")
+					//fmt.Println(deviceMap)
+					if err != nil {
+						fmt.Println("Websocket client init error" + err.Error())
+						return
+					}
+					messageMap := make(map[string]string)
+					messageMap["msgType"] = constant.MessageTypeDeviceScanned
+					marshal, err := json.Marshal(deviceMap)
+					if err != nil {
+						fmt.Println("data parse Error :" + err.Error())
+						return
+					}
+					messageMap["content"] = string(marshal)
+					messageMap["Sender"] = "server"
+					messageMap["Recipient"] = "client"
+					//fmt.Print("messageMap:")
+					//fmt.Println(messageMap)
+					bytes, err := json.Marshal(messageMap)
+					if err != nil {
+						fmt.Printf("json异常:%s", err.Error())
+						return
+					}
+					err = ws.WriteMessage(websocket.TextMessage, bytes)
+					if err != nil {
+						fmt.Println("消息发送异常:" + err.Error())
+						return
+					}
+				} else {
+					err := ws.WriteMessage(websocket.TextMessage, []byte("{}"))
+					if err != nil {
+						fmt.Println("消息发送异常:" + err.Error())
+						return
+					}
+				}
+				//time.Sleep(200 * time.Millisecond)
+			}
+
+		})
+	}
+
 }

+ 0 - 2
initialize/swag.go

@@ -10,7 +10,6 @@ import (
 // SwagInit 初始化swag  http://localhost:8000/swagger/index.html
 func SwagInit() {
 	cmd := exec.Command("swag", "init")
-	fmt.Println("Cmd", cmd.Args)
 	var out bytes.Buffer
 	cmd.Stdout = &out
 	cmd.Stderr = os.Stderr
@@ -18,5 +17,4 @@ func SwagInit() {
 	if err := cmd.Start(); err != nil {
 		fmt.Println(err)
 	}
-	fmt.Println(out.String())
 }

+ 10 - 8
initialize/ws.go

@@ -66,13 +66,15 @@ func (manager *ClientManager) Start() {
 			for id, conn := range Manager.Clients {
 				if id != creatId(MessageStruct.Recipient, MessageStruct.Sender) {
 					continue
+				} else {
+					select {
+					case conn.Send <- message:
+					default:
+						close(conn.Send)
+						delete(Manager.Clients, conn.ID)
+					}
 				}
-				select {
-				case conn.Send <- message:
-				default:
-					close(conn.Send)
-					delete(Manager.Clients, conn.ID)
-				}
+
 			}
 		}
 	}
@@ -94,7 +96,7 @@ func (c *Client) Read() {
 			c.Socket.Close()
 			break
 		}
-		log.Printf("读取到客户端的信息:%s", string(message))
+		//log.Printf("读取到客户端的信息:%s", string(message))
 		Manager.Broadcast <- message
 	}
 }
@@ -111,7 +113,7 @@ func (c *Client) Write() {
 				c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
 				return
 			}
-			log.Printf("发送到到客户端的信息:%s", string(message))
+			//log.Printf("发送到到客户端的信息:%s", string(message))
 
 			c.Socket.WriteMessage(websocket.TextMessage, message)
 		}

+ 0 - 2
main.go

@@ -8,8 +8,6 @@ import "confrontation-training/initialize"
 //@contact.name Develoven
 //contact.email develoven@163.com
 //contact.url https://www.cnblogs.com/wormworm
-var createNewSSeClient = true
-
 func main() {
 	initialize.Run()
 }

+ 44 - 0
models/emq/payload.go

@@ -0,0 +1,44 @@
+package emq
+
+type ScanDevice struct {
+	//Chip       string `json:"chip"`       //芯片 0和1
+	State   string `json:"state"`   //状态
+	Cmd     string `json:"cmd"`     //指令
+	L       string `json:"l"`       //网关mac
+	M       string `json:"m"`       //终端BLE设备MAC地址
+	Ai      int    `json:"ai"`      //终端BLE设备的地址ID
+	At      int    `json:"at"`      //终端BLE设备的地址类型
+	Rssi    int    `json:"rssi"`    //信号强度
+	Channel int    `json:"channel"` //信道
+	Pkg     int    `json:"pkg"`     //0表示广播包,1表示扫描回应包
+	A       string `json:"a"`
+	U       string `json:"u"`
+	F       string `json:"f"`
+	N       string `json:"n"`
+}
+type Payload struct {
+	State   string `json:"state"`   //状态
+	Cmd     string `json:"cmd"`     //指令
+	L       string `json:"l"`       //网关MAC
+	S       string `json:"s"`       //扫描|停止扫描
+	A       string `json:"a"`       //设置服务UUID
+	M       string `json:"m"`       //被链接设备的MAC
+	U       string `json:"u"`       //被链接设备的特征值UUID
+	D       string `json:"d"`       //数据
+	Ai      int    `json:"ai"`      //终端BLE设备的地址ID
+	At      int    `json:"at"`      //终端BLE设备的地址类型
+	Rssi    int    `json:"rssi"`    //信号强度
+	Channel int    `json:"channel"` //信道
+	Pkg     int    `json:"pkg"`     //0表示广播包,1表示扫描回应包
+	F       string `json:"f"`
+	N       string `json:"n"`
+	T       string `json:"t"` //0脑电1心电
+}
+
+type ReceiveData struct {
+	L   string `json:"l"` //网关MAC
+	M   string `json:"m"` //被链接设备的MAC
+	U   string `json:"u"` //被链接设备的特征值UUID
+	Cmd string `json:"cmd"`
+	D   string `json:"d"` //数据
+}

+ 19 - 5
models/gateway/device.go

@@ -18,6 +18,7 @@ type DeviceInfo struct {
 	gorm.Model
 	Type string `gorm:"type type:varchar(2) not null comment '分类:0脑电;1心电'"`
 	Mac  string `gorm:"mac type:varchar(20) not null comment 'Mac 地址'"`
+	Name string `gorm:"name type:varchar(50) not null comment '名称'"`
 }
 
 type DeviceConnParam struct {
@@ -41,11 +42,12 @@ type Bdaddrs struct {
 }
 
 type DeviceScanned struct {
-	MAC       string
-	Name      string
-	Rssi      int64
-	BdadrType string //地址类型
-	Chip      int64
+	MAC        string
+	Name       string
+	Rssi       int64
+	BdadrType  string //地址类型
+	Chip       int64
+	DeviceType string
 }
 
 type DeviceDataReceived struct {
@@ -54,3 +56,15 @@ type DeviceDataReceived struct {
 	Mac      string `json:"id"`
 	DataType string `json:"dataType"`
 }
+
+type ConnectedDevice struct {
+	MAC        string
+	Name       string
+	DeviceType string
+}
+
+type ConnectDevice struct {
+	Mac string `json:"mac"`
+	Ai  string `json:"ai"`
+	At  string `json:"at"`
+}

+ 19 - 18
service/device/device.go

@@ -1,14 +1,10 @@
 package device
 
 import (
-	errors "confrontation-training/err"
 	"confrontation-training/global"
 	"confrontation-training/http"
 	deviceModel "confrontation-training/models/gateway"
-	"encoding/json"
-	"fmt"
 	"gorm.io/gorm"
-	"io/ioutil"
 	netHttp "net/http"
 )
 
@@ -22,7 +18,12 @@ func (d *DeviceService) FindDeviceByMac(mac string) (deviceModel.DeviceInfo, int
 }
 func (d *DeviceService) FindDeviceByType(deviceType string) ([]deviceModel.DeviceInfo, int64) {
 	var deviceList = make([]deviceModel.DeviceInfo, 0)
-	count := global.Db.Where("type = ?", deviceType).Find(&deviceList).RowsAffected
+	var count int64
+	if deviceType == "" {
+		count = global.Db.Find(&deviceList).RowsAffected
+	} else {
+		count = global.Db.Where("type = ?", deviceType).Find(&deviceList).RowsAffected
+	}
 	return deviceList, count
 }
 func (d *DeviceService) CreateDevice(param deviceModel.DeviceAddParam) *gorm.DB {
@@ -42,20 +43,20 @@ func (d *DeviceService) RemoveDevice(mac string) int64 {
 }
 
 func (d *DeviceService) DeviceConnectedList(url string) (map[string]interface{}, error) {
-	httpResponse := http.GetReq(url)
+	//httpResponse := http.GetReq(url)
 	var result map[string]interface{}
-	if httpResponse.StatusCode != 200 {
-		fmt.Printf("%s:%s", errors.StartTransFailed, httpResponse.Body)
-		return result, nil
-	} else {
-		body, err := ioutil.ReadAll(httpResponse.Body)
-		if err == nil {
-			err = json.Unmarshal(body, &result)
-			return result, err
-		}
-		return result, err
-	}
-
+	//if httpResponse.StatusCode != 200 {
+	//	fmt.Printf("%s:%s", errors.StartTransFailed, httpResponse.Body)
+	//	return result, nil
+	//} else {
+	//	body, err := ioutil.ReadAll(httpResponse.Body)
+	//	if err == nil {
+	//		err = json.Unmarshal(body, &result)
+	//		return result, err
+	//	}
+	//	return result, err
+	//}
+	return result, nil
 }
 
 func (d *DeviceService) DisconnectDevice(url string) *netHttp.Response {