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" ) 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") } router.Run(":10086") } type DparkConf struct { ExtensionInTime int `json:"in"` ExtensionOutTime int `json:"out"` } var dparkConf DparkConf //获取数据防抖配置时间 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 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 = 10 var oldData1 = "" var oldData2 = "" var oldData3 = "" var dataMap sync.Map //接收传感器push来的数据,解析并上传到云端 func push(c *gin.Context) { nowtime := time.Now() data := c.PostForm("d") log.Println("yunhorndeug.push.data|", data) go pushCODE1007(data) alldata := strings.Split(data, "#") if len(alldata) != 2 { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "ok"}) return } else { valuedata := strings.Split(alldata[1], "*") if len(valuedata) < 1 { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "ok"}) return } dtype, error := strconv.Atoi(valuedata[0]) if error != nil { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "errtype"}) return } var nowTmpData = "1#0" if dtype == 1 { if len(valuedata) != 3 { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "valuedata not 3"}) return } addr, error := strconv.Atoi(alldata[0]) if error != nil { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "erraddr"}) return } cs2001, error := strconv.Atoi(valuedata[1]) if error != nil { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "errcs2001"}) return } tof, error := strconv.Atoi(valuedata[2]) if error != nil { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "errtof"}) return } if addr == 1 { if cs2001 == 1 || tof < 1650 { nowTmpData = "1#1" } if oldData1 != nowTmpData { dataMap.Store(addr, nowtime) if oldData1 == "" { //为空 直接改变状态 maledemoDevice.DATA["data1"] = 0 if nowTmpData == "1#1" { maledemoDevice.DATA["data1"] = 1 } changeData(2, maledemoDevice) } //存储状态 oldData1 = nowTmpData } else { oldDevDataTime, ok := dataMap.Load(addr) if !ok { log.Println("load time err", ok) } if ok { if oldDevDataTime != nil { //log.Println("t2.Sub(t1)", nowtime.Sub(oldDevDataTime.(time.Time))) var duration = nowtime.Sub(oldDevDataTime.(time.Time)).Seconds() var durationAsInt64 = int(duration) log.Printf("yunhorndebug.origin.%s|%s|%d|%d|%d|%d|%d", oldData1, nowTmpData, addr, dtype, cs2001, tof, durationAsInt64) if nowTmpData == "1#0" { if durationAsInt64 < extensionOutTime { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "not enough time"}) return } } else { if durationAsInt64 < extensionInTime { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "not enough time"}) return } } maledemoDevice.DATA["data1"] = 0 if nowTmpData == "1#1" { maledemoDevice.DATA["data1"] = 1 } changeData(2, maledemoDevice) dataMap.Delete(addr) } } } } else if addr == 2 { if cs2001 == 1 || tof < 1650 { nowTmpData = "1#1" } if oldData2 != nowTmpData { dataMap.Store(addr, nowtime) if oldData2 == "" { //为空 直接改变状态 maledemoDevice.DATA["data2"] = 0 if nowTmpData == "1#1" { maledemoDevice.DATA["data2"] = 1 } changeData(2, maledemoDevice) } //存储状态 oldData2 = nowTmpData } else { oldDevDataTime, ok := dataMap.Load(addr) if !ok { log.Println("load time err", ok) } if ok { if oldDevDataTime != nil { //log.Println("t2.Sub(t1)", nowtime.Sub(oldDevDataTime.(time.Time))) var duration = nowtime.Sub(oldDevDataTime.(time.Time)).Seconds() var durationAsInt64 = int(duration) log.Printf("yunhorndebug.origin.%s|%s|%d|%d|%d|%d|%d", oldData2, nowTmpData, addr, dtype, cs2001, tof, durationAsInt64) if nowTmpData == "1#0" { if durationAsInt64 < extensionInTime { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "not enough time"}) return } } else { if durationAsInt64 < extensionOutTime { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "not enough time"}) return } } maledemoDevice.DATA["data2"] = 0 if nowTmpData == "1#1" { maledemoDevice.DATA["data2"] = 1 } changeData(2, maledemoDevice) dataMap.Delete(addr) } } } } } else if dtype == 2 { //吸顶传感器 没有距离数据 if len(valuedata) != 2 { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "valuedata not 2,type2"}) return } addr, error := strconv.Atoi(alldata[0]) if error != nil { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "erraddr"}) return } cs2001, error := strconv.Atoi(valuedata[1]) if error != nil { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "errcs2001"}) return } if cs2001 == 1 { nowTmpData = "1#1" } if oldData3 != nowTmpData { dataMap.Store(addr, nowtime) if oldData3 == "" { //为空 直接改变状态 femaledemoDevice.DATA["data1"] = 0 if nowTmpData == "1#1" { femaledemoDevice.DATA["data1"] = 1 } changeData(2, maledemoDevice) } //存储状态 oldData3 = nowTmpData } else { oldDevDataTime, ok := dataMap.Load(addr) if !ok { log.Println("load time err", ok) } if ok { if oldDevDataTime != nil { //log.Println("t2.Sub(t1)", nowtime.Sub(oldDevDataTime.(time.Time))) var duration = nowtime.Sub(oldDevDataTime.(time.Time)).Seconds() var durationAsInt64 = int(duration) var tof = 0 log.Printf("yunhorndebug.origin.%s|%s|%d|%d|%d|%d|%d", oldData3, nowTmpData, addr, dtype, cs2001, tof, durationAsInt64) if nowTmpData == "1#0" { if durationAsInt64 < extensionInTime { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "not enough time"}) return } } else { if durationAsInt64 < extensionOutTime { c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": "not enough time"}) return } } femaledemoDevice.DATA["data1"] = 0 if nowTmpData == "1#1" { femaledemoDevice.DATA["data1"] = 1 } changeData(3, femaledemoDevice) dataMap.Delete(addr) } } } } } log.Println("data:", data) c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": data}) } //发送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 } 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 采集器配置信息 for _, i := range conf.GATEWAY_INFO.CONFIG { //if i.ID == "deb03e28-ddcb-4e5d-aa31-d870a1f0f09b" { // log.Println("begin debug") //} arr := get_seat_device_data(i.ID) //获取到设备版本 version, num := arr[0], arr[1] //if i.ID == "deb03e28-ddcb-4e5d-aa31-d870a1f0f09b" { // log.Println("conf.data:", i.DATA) // log.Println("devicedatas.data:", DEVICEDATAS.DATA) //} for k, j := range i.DATA { if DEVICEDATAS.DATA[version+"_"+num].DATA != nil { //if i.ID == "deb03e28-ddcb-4e5d-aa31-d870a1f0f09b" { // log.Println("data:", DEVICEDATAS.DATA[version+"_"+num].DATA) //} log.Println("============================devicedatas.data:", DEVICEDATAS.DATA[version+"_"+num].DATA) if DEVICEDATAS.DATA[version+"_"+num].DATA["data"+strconv.Itoa(k+1)] != nil { 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("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 { // log.Println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") // log.Println(i) if id == i[0] { data[0], data[1] = i[2], i[3] log.Println(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 { 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}) }