package main import ( "encoding/json" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" _ "github.com/mattn/go-sqlite3" "io/ioutil" "log" "math" "net/http" "strconv" "strings" "sync" "time" "bytes" "net" ) var router = gin.Default() // GW网关api路由 func gw_router() { router.Use(cors.Default()) v1 := router.Group("/api/v1") { v1.GET("/weather", gw_weather_api) v1.POST("/renliu", get_renliu_api) v1.POST("/feedback", get_pj_api) v1.GET("/totalWater", sb_api) v1.GET("/totalElectricity", db_api) v1.GET("/environmentDate", kq_api) v1.GET("/traffic", renliu_api) v1.GET("/stink", aq_api) v1.GET("/satisfaction", pj_api) v1.GET("/seat/:id", seat_api) v1.POST("/push", push) v1.GET("/getConf") } api_port := strconv.Itoa(conf.APIPORT) router.Run(":"+api_port) } type DparkConf struct { ExtensionInTime int `json:"in"` ExtensionOutTime int `json:"out"` ExtensionInTime2 int `json:"in2"` ExtensionOutTime2 int `json:"out2"` } var dparkConf DparkConf var connTest net.Conn //获取数据防抖配置时间 func getConf() { resp, err := http.Get("https://smartoilets.cn/socketServer/dpark/getConf") if err != nil { // handle error log.Println("getConf.get.err", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { // handle error log.Println("getConf.readData.err", err) return } if err := json.Unmarshal([]byte(body), &dparkConf); err == nil { log.Println("yunhorndebug.getConf.success:", dparkConf) } if err!=nil{ return } if dparkConf.ExtensionInTime == 0 && dparkConf.ExtensionOutTime == 0 { return } if dparkConf.ExtensionInTime < 0 { dparkConf.ExtensionInTime = 0 } if dparkConf.ExtensionOutTime < 0 { dparkConf.ExtensionOutTime = 0 } extensionInTime = dparkConf.ExtensionInTime extensionOutTime = dparkConf.ExtensionOutTime // check(err) } //距离有效判断 var reactTof = 1650 //数据防抖 进入时间 var extensionInTime = 6 //数据防抖 离开时间 var extensionOutTime = 15 var extensionInTime2 = 0 var extensionOutTime2 = 0 var oldData1 = "" var oldData2 = "" var oldData3 = "" var dataMap sync.Map //接收传感器push来的数据,解析并上传到云端 func push(c *gin.Context) { data := c.PostForm("d") // go dealData(data) log.Println("data:", data) c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) } func dealDatav3(data []byte) string{ nowtime := time.Now() log.Println("yunhorndeug.push.data|", data) strs := data buffer := new(bytes.Buffer) for _, b := range data[:4] { s := strconv.FormatInt(int64(b&0xff), 16) if len(s) == 1 { buffer.WriteString("0") } buffer.WriteString(s) } adr := buffer.String() var readyData bytes.Buffer datatype := data[5] //dpark 1-尿布台 2-吸顶 if datatype==1 || datatype==2{ //过滤无效数据 adr cs2001 := data[6] var R_data P1004_6 R_data.CODE = 1008 R_data.ID = adr //尿布台 R_data.VERSION = "yunhorn_2_v1" R_data.ONLINE = true R_data.DATA = make(map[string]interface{}) R_data.DATA["cs2001"]=cs2001 datatypeStr := strconv.FormatInt(int64(data[5]&0xff), 16) cs2001Str := strconv.FormatInt(int64(data[6]&0xff), 16) //地址 readyData.WriteString(buffer.String()) readyData.WriteString("#") //类型 readyData.WriteString(datatypeStr) readyData.WriteString("*") //红外人体感应 readyData.WriteString(cs2001Str) newdtype := strs[5] tmp := []byte{0, 0} tof := tmp[0] if newdtype==1{ tof = data[7] R_data.VERSION = "yunhorn_1_v1" R_data.DATA["tof"]=tof tofTmp := strconv.FormatInt(int64(data[7]&0xff), 10) readyData.WriteString("*") readyData.WriteString(tofTmp) } R_data.TIMESTAMP=time.Now().Unix() data_bufTmp, _ := json.Marshal(R_data) data_buf := string(data_bufTmp) go post_to_server(data_buf) // log.Println("readyData:",readyData.String()) // go pushCODE1007(data) //默认当前无人占用 current := 0 if datatype == 1 { //尿布台类型 if cs2001==1 || tof<130{ //有人占用 current = 1 } }else if datatype==2{ //吸顶类型 if cs2001 ==1 { //有人占用 current = 1 } } // log.Println("loraNodeMap:",loraNodeMap) loraNode, ok := loraNodeMap.Load(adr) if !ok { log.Println("load loraNode success ", ok) return "" } // log.Println("load loraNode:",loraNode) //log.Println("yunhorndeug.push.data.cuurent_data,current",loraNode.(LoraNode).CURRENT_DATA,current) if loraNode.(LoraNode).CURRENT_DATA != current{ //不相同,直接改变状态,更新时间 // loraNode.(LoraNode).CURRENT_DATA = current // loraNode.(LoraNode).TIME = time.Now() // loraNode.(LoraNode).CHECK_TIME = true newLoraNode := LoraNode{} newLoraNode.CURRENT_DATA = current newLoraNode.TIME = time.Now() newLoraNode.CHECK_TIME=true newLoraNode.LOCATION_TYPE = loraNode.(LoraNode).LOCATION_TYPE newLoraNode.LOCATION_CODE = loraNode.(LoraNode).LOCATION_CODE newLoraNode.LOCATION_DATA = loraNode.(LoraNode).LOCATION_DATA newLoraNode.DEVICE = loraNode.(LoraNode).DEVICE loraNodeMap.Store(adr,newLoraNode) //初次启动 if loraNode.(LoraNode).CURRENT_DATA == -1{ changeDataV2(newLoraNode) } if (datatype==2 && (extensionInTime2<=0 || extensionOutTime2<=0)){ newLoraNode.CURRENT_DATA = current changeDataV2(newLoraNode) } }else{ // 非首次 if loraNode.(LoraNode).CHECK_TIME { var duration = nowtime.Sub(loraNode.(LoraNode).TIME).Seconds() var durationAsInt64 = int(duration) // log.Println("yunhorndeug.push.data.durationAsInt64:",durationAsInt64) if current == 0 { //类型2 吸顶 if datatype==2{ if durationAsInt64 < extensionOutTime2 && extensionOutTime2>0 { return "" } }else{ if durationAsInt64 < extensionOutTime && extensionOutTime>0 { return "" } } }else{ //类型2 吸顶 if datatype==2{ if durationAsInt64 < extensionInTime2 && extensionInTime2>0 { return "" } }else{ if durationAsInt64 < extensionInTime && extensionInTime>0 { return "" } } } //改变状态 // loraNode.(LoraNode).CHECK_TIME = false newLoraNode := LoraNode{} newLoraNode.CURRENT_DATA = current newLoraNode.TIME = loraNode.(LoraNode).TIME newLoraNode.CHECK_TIME= false newLoraNode.LOCATION_TYPE = loraNode.(LoraNode).LOCATION_TYPE newLoraNode.LOCATION_CODE = loraNode.(LoraNode).LOCATION_CODE newLoraNode.LOCATION_DATA = loraNode.(LoraNode).LOCATION_DATA newLoraNode.DEVICE = loraNode.(LoraNode).DEVICE loraNodeMap.Store(adr,newLoraNode) changeDataV2(newLoraNode) }else{ // loraNode.(LoraNode).CHECK_TIME = true newLoraNode := LoraNode{} newLoraNode.CURRENT_DATA = loraNode.(LoraNode).CURRENT_DATA newLoraNode.TIME = time.Now() newLoraNode.CHECK_TIME= true newLoraNode.LOCATION_TYPE = loraNode.(LoraNode).LOCATION_TYPE newLoraNode.LOCATION_CODE = loraNode.(LoraNode).LOCATION_CODE newLoraNode.LOCATION_DATA = loraNode.(LoraNode).LOCATION_DATA newLoraNode.DEVICE = loraNode.(LoraNode).DEVICE if (datatype==2 && (extensionInTime2<=0 || extensionOutTime2<=0)){ newLoraNode.CURRENT_DATA = current changeDataV2(newLoraNode) } loraNodeMap.Store(adr,newLoraNode) } } }else if datatype==3{ var R_data P1004_6 R_data.CODE = 1010 R_data.ID = "853c0000" //尿布台 R_data.VERSION = "yunhorn_door_c_v1" R_data.ONLINE = true R_data.DATA = make(map[string]interface{}) R_data.DATA["data"]=int64(data[6]) data_bufTmp, _ := json.Marshal(R_data) data_buf := string(data_bufTmp) go post_to_server(data_buf) }else if datatype==4{ buffer := new(bytes.Buffer) // log.Println("data[9]",int64(data[9])) // log.Println("data[10]",int64(data[10])) if data[6] == 0{ buffer.WriteString("-") } wdint1 := strconv.FormatInt(int64(data[7]&0xff), 10) buffer.WriteString(wdint1) buffer.WriteString(".") wdfh := int(data[10]) wdint2 := strconv.FormatInt(int64(data[8]&0xff), 10) if wdfh<10{ buffer.WriteString("0") } buffer.WriteString(wdint2) log.Println("wdfh",data[6]) wddata := buffer.String() log.Println("wddata",wddata) buffer = new(bytes.Buffer) sdint1 := strconv.FormatInt(int64(data[9]&0xff), 10) buffer.WriteString(sdint1) buffer.WriteString(".") sdint2 := strconv.FormatInt(int64(data[10]&0xff), 10) if wdfh<10{ buffer.WriteString("0") } buffer.WriteString(sdint2) sddata := buffer.String() log.Println("sddata",sddata) buffer = new(bytes.Buffer) nh3int1 := strconv.Itoa(int(data[11])) buffer.WriteString(nh3int1) buffer.WriteString(".") nh3int2 := strconv.Itoa(int(data[12])) if int64(data[12])<10{ buffer.WriteString("0") } buffer.WriteString(nh3int2) nh3data := buffer.String() log.Println("nh3",nh3data) log.Println("h2s",data[13]) buffer = new(bytes.Buffer) ch2o1 := strconv.Itoa(int(data[14])) buffer.WriteString(ch2o1) buffer.WriteString(".") ch2o2 := strconv.Itoa(int(data[15])) if int64(data[15])<10{ buffer.WriteString("0") } buffer.WriteString(ch2o2) ch2o := buffer.String() // ch2o := uint32(data[14])*256+uint32(data[15]) log.Println("ch2o",ch2o) co2data := uint32(data[16])*256+uint32(data[17]) log.Println("co2data",co2data) tvocdata := data[18] log.Println("tvocdata",tvocdata) // log.Println("pm25data1",data[19]) // log.Println("pm25data2",data[20]) pm25data := uint32(data[19])*256+uint32(data[20]) log.Println("pm25data",pm25data) // log.Println("pm10data1",data[21]) // log.Println("pm10data2",data[22]) pm10data := uint32(data[21])*256+uint32(data[22]) log.Println("pm10data",pm10data) var R_data P1004_6 R_data.CODE = 1005 R_data.ID = "dc390000" //尿布台 R_data.VERSION = "yunhorn_kq_c_v1" R_data.ONLINE = true R_data.DATA = make(map[string]interface{}) R_data.DATA["temperature"]=wddata R_data.DATA["humidity"]=sddata R_data.DATA["nh3"]=nh3data R_data.DATA["h2s"]=data[13] R_data.DATA["ch2o"]=ch2o R_data.DATA["co2"]=co2data R_data.DATA["tvoc"]=tvocdata R_data.DATA["pm25"]=pm25data R_data.DATA["pm10"]=pm10data data_bufTmp, _ := json.Marshal(R_data) data_buf := string(data_bufTmp) go post_to_server(data_buf) } // log.Println("current:",current) // log.Println("loraNode:",loraNode) // log.Println("loraNode.time.is nil",(loraNode==nil)) return "" } //发送code1007数据到云端 func pushCODE1007(data string) { //resp, err := http.PostForm("https://smartoilets.cn/socketServer/static/push", // url.Values{"d": {data}}) resp, err := http.Post("https://smartoilets.cn/socketServer/statis/push", "application/x-www-form-urlencoded", strings.NewReader("d="+data)) if err != nil { log.Print("yunhorndebug.pushCODE1007.err", err) } defer resp.Body.Close() } func changeData(num int, device Device) { log.Println("device:", device) DEVICEDATAS.DATA[demoDevice.VERSION+"_"+strconv.Itoa(num)] = device } func changeDataV2(loraNode LoraNode){ // log.Println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@") // log.Println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@00000:",loraNode) // log.Println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@11111:",DEVICEDATAS.DATA[loraNode.DEVICE]) DEVICEDATAS.RLock() DEVICEDATAS.DATA[loraNode.DEVICE].DATA[loraNode.LOCATION_DATA] = loraNode.CURRENT_DATA DEVICEDATAS.RUnlock() log.Println("yunhorndeug.push.data.change:",DEVICEDATAS.DATA[loraNode.DEVICE]) // log.Println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@") } type EventNotificationAlert struct { IPADDRESS string `xml:"ipAddress" json:"ipAddress"` PROTOCOLTYPE string `xml:"protocolType" json:"protocolType"` MACADDRESS string `xml:"macAddress" json:"macAddress"` CHANNELID uint16 `xml:"channelID" json:"channelID"` DATETIME string `xml:"dateTime" json:"dateTime"` ACTIVEPOSTCOUNT uint16 `xml:"activePostCount" json:"activePostCount"` EVENTTYPE string `xml:"eventType" json:"eventType"` EVENTSTATE string `xml:"eventState" json:"eventState"` EVENTDESCRIPTION string `xml:"eventDescription" json:"eventDescription"` CHANNELNAME string `xml:"channelName" json:"channelName"` PEOPLECOUNTING PeopleCounting `xml:"peopleCounting" json:"peopleCounting"` } type PeopleCounting struct { STATISTICALMETHODS string `xml:"statisticalMethods" json:"statisticalMethods"` TIMERANGE Timerange `xml:"TimeRange" json:"TimeRange"` ENTER uint16 `xml:"enter" json:"enter"` EXIT uint16 `xml:"exit" json:"exit"` PASS uint16 `xml:"pass" json:"pass"` } type Timerange struct { STARTTIME string `xml:"startTime" json:"startTime"` ENDTIME string `xml:"endTime" json:"endTime"` } type FeedBack struct { FEEDBACK string `json:"feedback"` ID string `json:"id"` } var rl_data EventNotificationAlert // 提交人流量api func get_renliu_api(c *gin.Context) { err := c.Bind(&rl_data) if conf.DEBUG { log.Println(rl_data) } check(err) send_data(1004) c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": rl_data}) } var pj_data FeedBack // 提交评价api func get_pj_api(c *gin.Context) { err = c.Bind(&pj_data) check(err) send_data(1006) c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": pj_data}) } // 获取水表api func sb_api(c *gin.Context) { DEVICEDATAS.RLock() var data = make(map[string]uint16) for _, i := range conf.DEVICES_LIST { if i[2] == "yunhorn_sb_c_v1" { if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalWater"] != nil { data["totalWater"] = data["totalWater"] + DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalWater"].(uint16) } } } DEVICEDATAS.RUnlock() c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) } // 获取电表api func db_api(c *gin.Context) { DEVICEDATAS.RLock() var data = make(map[string]float32) for _, i := range conf.DEVICES_LIST { if i[2] == "yunhorn_db_c_v1" { if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalElectric"] != nil { data["totalElectric"] = data["totalElectric"] + DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["totalElectric"].(float32) } } } DEVICEDATAS.RUnlock() c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) } // 获取空气数据api func kq_api(c *gin.Context) { DEVICEDATAS.RLock() var sum float32 var toinitdata float32 = 0.0 var data = make(map[string]interface{}) for _, i := range conf.DEVICES_LIST { if i[2] == "yunhorn_kq_c_v1" { sum++ for k, j := range DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA { if j != nil { data[k] = toinitdata data[k] = (data[k].(float32) + j.(float32)) / sum } } } } DEVICEDATAS.RUnlock() c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) } // 获取氨气数据api func aq_api(c *gin.Context) { DEVICEDATAS.RLock() var sum uint16 var toinitdata uint16 = 0 var data_buf = make(map[string]interface{}) var data = make(map[string]interface{}) for _, i := range conf.DEVICES_LIST { if i[2] == "yunhorn_aq_c_v1" { sum++ if DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA["氨气"] != nil { data_buf["氨气"] = toinitdata data_buf["氨气"] = (data_buf["氨气"].(uint16) + DEVICEDATAS.DATA["yunhorn_aq_c_v1_"+i[3]].DATA["氨气"].(uint16)) / sum } } } if data_buf["氨气"] == nil { data["stink"] = "无味" } else { if data_buf["氨气"].(uint16) <= 1 { data["stink"] = "无味" } else if data_buf["氨气"].(uint16) > 1 && data_buf["氨气"].(uint16) <= 10 { data["stink"] = "有味" } else if data_buf["氨气"].(uint16) > 10 && data_buf["氨气"].(uint16) <= 40 { data["stink"] = "恶臭" } else if data_buf["氨气"].(uint16) > 40 && data_buf["氨气"].(uint16) <= 100 { data["stink"] = "超级恶臭" } } DEVICEDATAS.RUnlock() c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) } // 获取人流量api func renliu_api(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": traffic_data}) } // 获取评价api func pj_api(c *gin.Context) { var data float64 data = good / (good + bad) satisfaction_data.SATISFACTION = Round(data, 2) c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": satisfaction_data}) } // 精确到小数点后n位 func Round(f float64, n int) float64 { n10 := math.Pow10(n) return math.Trunc((f+0.5/n10)*n10) / n10 } type Seat_data struct { POSITIONLIST []interface{} `json:"positionList"` HASPERSONLIST []interface{} `json:"hasPersonList"` EMPTYPOSITION uint16 `json:"emptyPosition"` OCCUPYPOSITION uint16 `json:"occupyPosition"` } // 厕位占用api func seat_api(c *gin.Context) { DEVICEDATAS.RLock() type_id := c.Param("id") var data Seat_data var conf_data [][]interface{} //conf.GATEWAY_INFO.CONFIG 采集器配置信息 // log.Println("DEVICEDATAS.data:",DEVICEDATAS.DATA) for _, i := range conf.GATEWAY_INFO.CONFIG { arr := get_seat_device_data(i.ID) //获取到设备版本 version, num := arr[0], arr[1] if version=="null" || num == "null"{ continue } if DEVICEDATAS.DATA[version+"_"+num].DATA != nil { log.Println("^^^^^^^^^^^^^^^^^^DEVICEDATAS.DATA-version_num",DEVICEDATAS.DATA[version+"_"+num]) for k, j := range i.DATA { //log.Println("@@@@@@@@@@@@@@@@@@@@@@@@@@,i.DATA-j",j) // log.Println("============================devicedatas.data:", DEVICEDATAS.DATA[version+"_"+num].DATA) if DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)] != nil { //这里不会改变DEVICEDATAS.DATA的数据,只是判断一下有没有数据,如果有,则加上 // log.Println("==========================do.data:", DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)]) j = append(j, DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)]) } conf_data = append(conf_data, j) //log.Println("@@@@@@@@@@@@@@@@@@@@@@@@@@,i.DATA-j,appended.conf_data",conf_data) } } } log.Println("=================end conf.data:", conf_data) switch type_id { case "1": data = scan_seat_from_confdata("男厕位", conf_data) case "2": data = scan_seat_from_confdata("男便池", conf_data) case "3": data = scan_seat_from_confdata("女厕位", conf_data) case "4": data = scan_seat_from_confdata("母婴", conf_data) case "5": data = scan_seat_from_confdata("残卫", conf_data) } DEVICEDATAS.RUnlock() c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) } // 拼凑位置信息的数据 func get_seat_device_data(id string) []string { //log.Println("begin get_seat_device_data.id:", id) var data = make([]string, 2) //配置表中devices_list //例如["4E5D52DD-EB81-43C0-A2B6-04E432412EBA", "loraport", "yunhorn_kgl_l_v1", "1"], for _, i := range conf.DEVICES_LIST { if id == i[0] { data[0], data[1] = i[2], i[3] log.Println("get_seat_device_data",data) break } else { data[0], data[1] = "null", "null" } } //log.Println("get_seat_device_data:", data) return data } // 从配置文件中匹配对应的数据 func scan_seat_from_confdata(T string, conf_data [][]interface{}) Seat_data { var data Seat_data //实例化空集合 data.POSITIONLIST = make([]interface{}, 0) data.HASPERSONLIST = make([]interface{}, 0) for _, i := range conf_data { //T 男厕位 女厕位 //conf_data [[男厕位 1],[女厕位 1]] // 第一位是数据类型 第二位是位置 第三位是有无人占用 //conf_data [男厕位 1 0/1] //把当前符合类型的数据加入到返回集合中 if i[0] == T { data.POSITIONLIST = append(data.POSITIONLIST, i[1]) if len(i) < 3 { i = append(i, 0) } data.HASPERSONLIST = append(data.HASPERSONLIST, i[2]) switch i[2] { case 0: data.EMPTYPOSITION++ case 1: data.OCCUPYPOSITION++ } } } return data } type WEATHER struct { SKYCON string `json:"skycon"` ICON_URL string `json:"icon_url"` O3 float32 `json:"o3"` CO float32 `json:"co"` SO2 float32 `json:"so2"` NO2 float32 `json:"no2"` TEMPERATURE float32 `json:"temperature"` HUMIDITY float32 `json:"humidity"` PM25 float32 `json:"pm25"` PM10 float32 `json:"pm10"` CLOUDRATE float32 `json:"cloudrate"` AQI float32 `json:"aqi"` DSWRF float32 `json:"dswrf"` VISIBILITY float32 `json:"visibility"` ULTRAVIOLET_DESC string `json:"ultraviolet_desc"` PRES float32 `json:"pres"` COMFORT_DESC string `json:"comfort_desc"` WIND_DIRECTION float32 `json:"wind_direction"` WIND_SPEED float32 `json:"wind_speed"` TEMPERATURE_INDOOR interface{} `json:"temperature_indoor"` HUMIDITY_INDOOR interface{} `json:"humidity_indoor"` } // 获取天气情况api func gw_weather_api(c *gin.Context) { DEVICEDATAS.RLock() rows, _ := db.Query("SELECT skycon, icon_url, o3, co, so2, no2, temperature, humidity, pm25, pm10, cloudrate, aqi, dswrf, visibility, ultraviolet_desc, pres, comfort_desc, wind_direction, wind_speed FROM weather order by id DESC limit 1") var data WEATHER rows.Next() rows.Scan( &data.SKYCON, &data.ICON_URL, &data.O3, &data.CO, &data.SO2, &data.NO2, &data.TEMPERATURE, &data.HUMIDITY, &data.PM25, &data.PM10, &data.CLOUDRATE, &data.AQI, &data.DSWRF, &data.VISIBILITY, &data.ULTRAVIOLET_DESC, &data.PRES, &data.COMFORT_DESC, &data.WIND_DIRECTION, &data.WIND_SPEED) rows.Close() var sum float32 var toinitdata float32 = 0.0 var data_buf = make(map[string]interface{}) for _, i := range conf.DEVICES_LIST { if i[2] == "yunhorn_kq_c_v1" { sum++ for k, j := range DEVICEDATAS.DATA[i[2]+"_"+i[3]].DATA { if j != nil { data_buf[k] = toinitdata data_buf[k] = (data_buf[k].(float32) + j.(float32)) / sum } } } } data.TEMPERATURE_INDOOR = data_buf["温度"] data.HUMIDITY_INDOOR = data_buf["湿度"] DEVICEDATAS.RUnlock() c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) }