package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" "net/http" "rain_monitor/models" "strconv" "strings" "time" "github.com/google/uuid" ) const ( // 涂鸦开发者账号中获取的信息 clientID = "nwmdye9c8ejymu9ge5kf" // 授权密钥对 key secret = "658733ea78624cd4b63bae6083cd3fae" // 授权密钥对 value baseURL = "https://openapi.tuyacn.com" deviceID = "6cbbf72843839b6157wfb2" ) // 计算HMAC-SHA256签名 func calculateSignature(secret, stringToSign string) string { h := hmac.New(sha256.New, []byte(secret)) h.Write([]byte(stringToSign)) return hex.EncodeToString(h.Sum(nil)) } // 获取访问令牌 func getAccessToken() (string, error) { t := strconv.FormatInt(time.Now().UnixNano()/1e6, 10) // 13位时间戳 nonce := uuid.New().String() // 生成随机UUID url := "/v1.0/token?grant_type=1" // 构建stringToSign contentSHA256 := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // 空body的SHA256值 stringToSign := fmt.Sprintf("GET\n%s\n\n%s", contentSHA256, url) // 构建待签名字符串 strToHash := clientID + t + nonce + stringToSign // 使用HMAC-SHA256计算签名 signature := calculateSignature(secret, strToHash) signatureUpper := fmt.Sprintf("%s", signature) signatureUpper = strings.ToUpper(signatureUpper) // 构建请求头 req, err := http.NewRequest("GET", baseURL+url, nil) if err != nil { return "", err } req.Header.Set("client_id", clientID) req.Header.Set("sign", signatureUpper) req.Header.Set("sign_method", "HMAC-SHA256") req.Header.Set("t", t) req.Header.Set("nonce", nonce) // 发起GET请求 client := &http.Client{} resp, err := client.Do(req) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", err } // 解析响应 var tokenResp models.PWS01TokenResponse if err := json.Unmarshal(body, &tokenResp); err != nil { return "", err } if !tokenResp.Success { return "", fmt.Errorf("获取token失败: %s", string(body)) } return tokenResp.Result.AccessToken, nil } // 获取设备信息 func getDeviceInfo(accessToken string) (*models.PWS01DeviceInfo, error) { t := strconv.FormatInt(time.Now().UnixNano()/1e6, 10) // 13位时间戳 nonce := uuid.New().String() // 生成随机UUID url := fmt.Sprintf("/v2.0/cloud/thing/%s", deviceID) // 构建stringToSign contentSHA256 := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // 空body的SHA256值 stringToSign := fmt.Sprintf("GET\n%s\n\n%s", contentSHA256, url) // 构建待签名字符串 strToHash := clientID + accessToken + t + nonce + stringToSign // 使用HMAC-SHA256计算签名 signature := calculateSignature(secret, strToHash) signatureUpper := fmt.Sprintf("%s", signature) signatureUpper = strings.ToUpper(signatureUpper) // 构建请求头 req, err := http.NewRequest("GET", baseURL+url, nil) if err != nil { return nil, err } req.Header.Set("client_id", clientID) req.Header.Set("access_token", accessToken) req.Header.Set("sign", signatureUpper) req.Header.Set("sign_method", "HMAC-SHA256") req.Header.Set("t", t) req.Header.Set("nonce", nonce) // 发起GET请求 client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } // 解析响应 var deviceInfo models.PWS01DeviceInfo if err := json.Unmarshal(body, &deviceInfo); err != nil { return nil, err } return &deviceInfo, nil } // 获取设备状态 func getDeviceStatus(accessToken string) (*models.PWS01DeviceStatus, error) { t := strconv.FormatInt(time.Now().UnixNano()/1e6, 10) // 13位时间戳 nonce := uuid.New().String() // 生成随机UUID url := fmt.Sprintf("/v1.0/iot-03/devices/%s/status", deviceID) // 构建stringToSign contentSHA256 := "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // 空body的SHA256值 stringToSign := fmt.Sprintf("GET\n%s\n\n%s", contentSHA256, url) // 构建待签名字符串 strToHash := clientID + accessToken + t + nonce + stringToSign // 使用HMAC-SHA256计算签名 signature := calculateSignature(secret, strToHash) signatureUpper := fmt.Sprintf("%s", signature) signatureUpper = strings.ToUpper(signatureUpper) // 构建请求头 req, err := http.NewRequest("GET", baseURL+url, nil) if err != nil { return nil, err } req.Header.Set("client_id", clientID) req.Header.Set("access_token", accessToken) req.Header.Set("sign", signatureUpper) req.Header.Set("sign_method", "HMAC-SHA256") req.Header.Set("t", t) req.Header.Set("nonce", nonce) // 发起GET请求 client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } // 首先解析为临时结构 var tempResponse struct { Result []models.PWS01StatusItem `json:"result"` Success bool `json:"success"` T int64 `json:"t"` TID string `json:"tid"` } if err := json.Unmarshal(body, &tempResponse); err != nil { return nil, err } // 创建最终响应 deviceStatus := &models.PWS01DeviceStatus{ Success: tempResponse.Success, T: tempResponse.T, TID: tempResponse.TID, } // 将临时结构中的数据转换为我们的结构化数据 statusData := models.PWS01StatusData{} // 遍历状态项并填充结构体 for _, item := range tempResponse.Result { switch item.Code { case "temp_current": if val, ok := item.Value.(float64); ok { statusData.TempCurrent = int(val) } case "humidity_value": if val, ok := item.Value.(float64); ok { statusData.HumidityValue = int(val) } case "battery_percentage": if val, ok := item.Value.(float64); ok { statusData.BatteryPercentage = int(val) } case "temp_unit_convert": if val, ok := item.Value.(string); ok { statusData.TempUnitConvert = val } case "windspeed_unit_convert": if val, ok := item.Value.(string); ok { statusData.WindspeedUnitConvert = val } case "pressure_unit_convert": if val, ok := item.Value.(string); ok { statusData.PressureUnitConvert = val } case "rain_unit_convert": if val, ok := item.Value.(string); ok { statusData.RainUnitConvert = val } case "bright_unit_convert": if val, ok := item.Value.(string); ok { statusData.BrightUnitConvert = val } case "temp_current_external": if val, ok := item.Value.(float64); ok { statusData.TempCurrentExternal = int(val) } case "humidity_outdoor": if val, ok := item.Value.(float64); ok { statusData.HumidityOutdoor = int(val) } case "temp_current_external_1": if val, ok := item.Value.(float64); ok { statusData.TempCurrentExternal1 = int(val) } case "humidity_outdoor_1": if val, ok := item.Value.(float64); ok { statusData.HumidityOutdoor1 = int(val) } case "temp_current_external_2": if val, ok := item.Value.(float64); ok { statusData.TempCurrentExternal2 = int(val) } case "humidity_outdoor_2": if val, ok := item.Value.(float64); ok { statusData.HumidityOutdoor2 = int(val) } case "temp_current_external_3": if val, ok := item.Value.(float64); ok { statusData.TempCurrentExternal3 = int(val) } case "humidity_outdoor_3": if val, ok := item.Value.(float64); ok { statusData.HumidityOutdoor3 = int(val) } case "atmospheric_pressture": if val, ok := item.Value.(float64); ok { statusData.AtmosphericPressure = int(val) } case "pressure_drop": if val, ok := item.Value.(float64); ok { statusData.PressureDrop = int(val) } case "windspeed_avg": if val, ok := item.Value.(float64); ok { statusData.WindspeedAvg = int(val) } case "windspeed_gust": if val, ok := item.Value.(float64); ok { statusData.WindspeedGust = int(val) } case "rain_1h": if val, ok := item.Value.(float64); ok { statusData.Rain1h = int(val) } case "rain_24h": if val, ok := item.Value.(float64); ok { statusData.Rain24h = int(val) } case "rain_rate": if val, ok := item.Value.(float64); ok { statusData.RainRate = int(val) } case "uv_index": if val, ok := item.Value.(float64); ok { statusData.UVIndex = int(val) } case "dew_point_temp": if val, ok := item.Value.(float64); ok { statusData.DewPointTemp = int(val) } case "feellike_temp": if val, ok := item.Value.(float64); ok { statusData.FeellikeTemp = int(val) } case "heat_index": if val, ok := item.Value.(float64); ok { statusData.HeatIndex = int(val) } case "windchill_index": if val, ok := item.Value.(float64); ok { statusData.WindchillIndex = int(val) } } } deviceStatus.Result = statusData return deviceStatus, nil } // 打印设备信息 func printDeviceInfo(info *models.PWS01DeviceInfo) { fmt.Println("========== 设备信息 ==========") fmt.Printf("设备ID: %s\n", info.Result.ID) fmt.Printf("设备名称: %s\n", info.Result.Name) fmt.Printf("设备型号: %s\n", info.Result.Model) fmt.Printf("IP地址: %s\n", info.Result.IP) fmt.Printf("在线状态: %v\n", info.Result.IsOnline) fmt.Printf("经度: %s\n", info.Result.Lon) fmt.Printf("纬度: %s\n", info.Result.Lat) fmt.Printf("时区: %s\n", info.Result.TimeZone) fmt.Printf("激活时间: %d\n", info.Result.ActiveTime) fmt.Printf("更新时间: %d\n", info.Result.UpdateTime) fmt.Println("============================") } // 打印设备状态 func printDeviceStatus(status *models.PWS01DeviceStatus) { fmt.Println("========== 设备状态 ==========") fmt.Printf("室内温度: %.1f℃\n", float64(status.Result.TempCurrent)/10.0) fmt.Printf("室内湿度: %d%%\n", status.Result.HumidityValue) fmt.Printf("电池电量: %d%%\n", status.Result.BatteryPercentage) fmt.Printf("温度单位: %s\n", status.Result.TempUnitConvert) fmt.Printf("风速单位: %s\n", status.Result.WindspeedUnitConvert) fmt.Printf("气压单位: %s\n", status.Result.PressureUnitConvert) fmt.Printf("雨量单位: %s\n", status.Result.RainUnitConvert) fmt.Printf("亮度单位: %s\n", status.Result.BrightUnitConvert) fmt.Printf("室外温度: %.1f℃\n", float64(status.Result.TempCurrentExternal)/10.0) fmt.Printf("室外湿度: %d%%\n", status.Result.HumidityOutdoor) fmt.Printf("大气压力: %d hPa\n", status.Result.AtmosphericPressure) fmt.Printf("压降: %d hPa\n", status.Result.PressureDrop) fmt.Printf("平均风速: %.1f m/s\n", float64(status.Result.WindspeedAvg)/10.0) fmt.Printf("阵风风速: %.1f m/s\n", float64(status.Result.WindspeedGust)/10.0) fmt.Printf("一小时降雨量: %.1f mm\n", float64(status.Result.Rain1h)/10.0) fmt.Printf("24小时降雨量: %.1f mm\n", float64(status.Result.Rain24h)/10.0) fmt.Printf("雨率: %.1f mm\n", float64(status.Result.RainRate)/10.0) fmt.Printf("紫外线指数: %d\n", status.Result.UVIndex) fmt.Printf("露点温度: %.1f℃\n", float64(status.Result.DewPointTemp)/10.0) fmt.Printf("体感温度: %.1f℃\n", float64(status.Result.FeellikeTemp)/10.0) fmt.Printf("酷热指数: %.1f℃\n", float64(status.Result.HeatIndex)/10.0) fmt.Printf("风寒指数: %.1f℃\n", float64(status.Result.WindchillIndex)/10.0) fmt.Println("============================") } func main() { // 获取访问令牌 fmt.Println("正在获取访问令牌...") accessToken, err := getAccessToken() if err != nil { fmt.Printf("获取访问令牌失败: %v\n", err) return } fmt.Printf("成功获取访问令牌: %s\n", accessToken) // 获取设备信息 fmt.Println("\n正在获取设备信息...") deviceInfo, err := getDeviceInfo(accessToken) if err != nil { fmt.Printf("获取设备信息失败: %v\n", err) return } printDeviceInfo(deviceInfo) // 获取设备状态 fmt.Println("\n正在获取设备状态...") deviceStatus, err := getDeviceStatus(accessToken) if err != nil { fmt.Printf("获取设备状态失败: %v\n", err) return } printDeviceStatus(deviceStatus) // 打印原始JSON数据 fmt.Println("\n========== 原始设备信息JSON ==========") infoJSON, _ := json.MarshalIndent(deviceInfo, "", " ") fmt.Println(string(infoJSON)) fmt.Println("\n========== 原始设备状态JSON ==========") statusJSON, _ := json.MarshalIndent(deviceStatus, "", " ") fmt.Println(string(statusJSON)) }