fwh_pro.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. package fwh_pro
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "net/url"
  10. "strconv"
  11. "strings"
  12. "time"
  13. )
  14. var loginInfo LoginData = LoginData{
  15. UserId: 0,
  16. Token: "",
  17. }
  18. type LoginPayload struct {
  19. LoginName string `json:"loginName"`
  20. Password string `json:"password"`
  21. Type int `json:"type"`
  22. Lang string `json:"lang"`
  23. }
  24. type LoginData struct {
  25. UserId uint `json:"userId"`
  26. Token string `json:"token"`
  27. }
  28. type LoginResponse struct {
  29. Code int `json:"code"`
  30. Msg string `json:"msg"`
  31. Data LoginData `json:"data"`
  32. Success bool `json:"success"`
  33. }
  34. type SiteInfoListPayload struct {
  35. Search *string `json:"search,omitempty"` // 只能搜索单条SN
  36. Serials *string `json:"serials,omitempty"` // 可搜索多条SN,SN之间以‘,’隔开
  37. CountryId *int `json:"countryId,omitempty"`
  38. ProvinceId *int `json:"provinceId,omitempty"`
  39. CityId *int `json:"cityId,omitempty"`
  40. NetworkStatus *int `json:"networkStatus,omitempty"`
  41. DeviceStatus *int `json:"deviceStatus,omitempty"`
  42. OnOffStatus *int `json:"onOffStatus,omitempty"`
  43. PageSize uint `json:"pageSize"`
  44. PageNum uint `json:"pageNum"`
  45. Lang string `json:"lang"`
  46. }
  47. type SiteModeInfoPayload struct {
  48. GatewayId string `json:"gatewayId"`
  49. ShowType int `json:"showType"`
  50. Lang string `json:"lang"`
  51. }
  52. func Login() error {
  53. // 要发送的 JSON
  54. payload := LoginPayload{
  55. LoginName: "FMH001",
  56. Password: "cfd9d803fafcf2c7a832bfba5d039512",
  57. Type: 1,
  58. Lang: "ZH_CN",
  59. }
  60. jsonData, _ := json.Marshal(payload)
  61. // 创建请求
  62. req, err := http.NewRequest(
  63. http.MethodPost,
  64. "https://oss.franklinwh.com/api-user/user/login",
  65. bytes.NewBuffer(jsonData))
  66. if err != nil {
  67. fmt.Println(err.Error())
  68. return err
  69. }
  70. // 设置 Content-Type 和 Authorization
  71. req.Header.Set("Content-Type", "application/json")
  72. // 发送请求
  73. client := &http.Client{Timeout: 5 * time.Second}
  74. resp, err := client.Do(req)
  75. if err != nil {
  76. fmt.Println(err.Error())
  77. return err
  78. }
  79. defer resp.Body.Close()
  80. body, _ := io.ReadAll(resp.Body)
  81. // fmt.Printf("Status: %s\nBody: %s", resp.Status, body)
  82. var loginRes LoginResponse
  83. // 反序列化(unmarshal)
  84. jsonErr := json.Unmarshal(body, &loginRes)
  85. if jsonErr != nil {
  86. return jsonErr
  87. }
  88. loginInfo.UserId = loginRes.Data.UserId
  89. loginInfo.Token = loginRes.Data.Token
  90. return nil
  91. }
  92. func isTokenExpired(token string) (bool, error) {
  93. parts := strings.Split(token, ".")
  94. if len(parts) != 3 {
  95. return false, fmt.Errorf("token 格式错误")
  96. }
  97. payloadSegment := parts[1]
  98. // JWT 使用 base64 URL encoding
  99. payloadBytes, err := base64.RawURLEncoding.DecodeString(payloadSegment)
  100. if err != nil {
  101. return false, err
  102. }
  103. var payload map[string]interface{}
  104. if err := json.Unmarshal(payloadBytes, &payload); err != nil {
  105. return false, err
  106. }
  107. expFloat, ok := payload["exp"].(float64)
  108. if !ok {
  109. return false, fmt.Errorf("token payload 中没有 exp")
  110. }
  111. expTime := time.Unix(int64(expFloat), 0)
  112. return time.Now().After(expTime), nil
  113. }
  114. func getLoginToken() string {
  115. // 判断是否已经有token
  116. if loginInfo.Token != "" {
  117. // 判断token是否过期
  118. expired, err := isTokenExpired(loginInfo.Token)
  119. if err != nil {
  120. fmt.Println("loginInfo.Token 解析出错:", err)
  121. return ""
  122. }
  123. if expired {
  124. fmt.Println("Token 已过期")
  125. } else {
  126. // fmt.Println("Token 有效")
  127. return loginInfo.Token
  128. }
  129. }
  130. // 重新登录
  131. Login()
  132. return loginInfo.Token
  133. }
  134. // 清空token
  135. func ClearToken() {
  136. loginInfo.UserId = 0
  137. loginInfo.Token = ""
  138. }
  139. // 查询站点基本信息
  140. func QuerySiteInfoList(sn []string, pageSize uint, pageNum uint) ([]byte, error) {
  141. snList := strings.Join(sn, ",")
  142. token := getLoginToken()
  143. // 要发送的 JSON
  144. payload := SiteInfoListPayload{
  145. Serials: &snList,
  146. PageSize: pageSize,
  147. PageNum: pageNum,
  148. Lang: "ZH_CN",
  149. }
  150. // 要发送的表单数据
  151. form := url.Values{}
  152. form.Set("serials", *payload.Serials) // *string 转 string
  153. form.Set("pageSize", fmt.Sprintf("%d", payload.PageSize))
  154. form.Set("pageNum", fmt.Sprintf("%d", payload.PageNum))
  155. form.Set("lang", payload.Lang)
  156. // 创建请求
  157. req, err := http.NewRequest(
  158. http.MethodPost,
  159. "https://energy.franklinwh.com/hes-gateway/manage/selectIotFirmwareGatewayList",
  160. strings.NewReader(form.Encode()))
  161. if err != nil {
  162. fmt.Println(err.Error())
  163. return nil, err
  164. }
  165. // 设置 Content-Type 和 Authorization
  166. req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
  167. req.Header.Set("Logintoken", token)
  168. // 发送请求
  169. client := &http.Client{Timeout: 5 * time.Second}
  170. resp, err := client.Do(req)
  171. if err != nil {
  172. fmt.Println(err.Error())
  173. return nil, err
  174. }
  175. defer resp.Body.Close()
  176. body, _ := io.ReadAll(resp.Body)
  177. // fmt.Printf("Status: %s\nBody: %s\n", resp.Status, body)
  178. return body, nil
  179. }
  180. // 查询站点工作模式信息
  181. func QuerySiteModeInfo(sn string) ([]byte, error) {
  182. token := getLoginToken()
  183. // 要发送的 JSON
  184. payload := SiteModeInfoPayload{
  185. GatewayId: sn,
  186. ShowType: 1,
  187. Lang: "ZH_CN",
  188. }
  189. // 要发送的表单数据
  190. form := url.Values{}
  191. form.Set("gatewayId", payload.GatewayId)
  192. form.Set("showType", strconv.Itoa(payload.ShowType))
  193. form.Set("lang", payload.Lang)
  194. // 创建请求
  195. req, err := http.NewRequest(
  196. http.MethodPost,
  197. "https://energy.franklinwh.com/hes-gateway/manage/tou/getGatewayTouListV2",
  198. strings.NewReader(form.Encode()))
  199. if err != nil {
  200. fmt.Println(err.Error())
  201. return nil, err
  202. }
  203. // 设置 Content-Type 和 Authorization
  204. req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
  205. req.Header.Set("Logintoken", token)
  206. // fmt.Println(req.Header)
  207. // 发送请求
  208. client := &http.Client{Timeout: 5 * time.Second}
  209. resp, err := client.Do(req)
  210. if err != nil {
  211. fmt.Println(err.Error())
  212. return nil, err
  213. }
  214. defer resp.Body.Close()
  215. body, _ := io.ReadAll(resp.Body)
  216. // fmt.Printf("Status: %s\nBody: %s\n", resp.Status, body)
  217. return body, nil
  218. }
  219. // 查询站点功率流信息
  220. func QuerySitePowerFlow(sn string, day time.Time) ([]byte, error) {
  221. baseURL := "https://energy.franklinwh.com/api-energy/power/getFhpPowerByDayOld"
  222. token := getLoginToken()
  223. // 构造 query 参数
  224. params := url.Values{}
  225. params.Add("gatewayId", sn)
  226. params.Add("dayTime", day.Format(time.DateOnly)) // 会自动 URL 编码
  227. // 拼接到 URL
  228. finalURL := baseURL + "?" + params.Encode()
  229. // 创建请求
  230. req, err := http.NewRequest(
  231. http.MethodGet,
  232. finalURL,
  233. nil)
  234. if err != nil {
  235. fmt.Println(err.Error())
  236. return nil, err
  237. }
  238. // 设置 Content-Type 和 Authorization
  239. req.Header.Set("Content-Type", "application/json")
  240. req.Header.Set("Logintoken", token)
  241. // fmt.Println(req.Header)
  242. // 发送请求
  243. client := &http.Client{Timeout: 5 * time.Second}
  244. resp, err := client.Do(req)
  245. if err != nil {
  246. fmt.Println(err.Error())
  247. return nil, err
  248. }
  249. defer resp.Body.Close()
  250. body, _ := io.ReadAll(resp.Body)
  251. // fmt.Printf("Status: %s\nBody: %s\n", resp.Status, body)
  252. return body, nil
  253. }
  254. // 查询站点告警信息
  255. func QuerySiteAlarmList(sn string) ([]byte, error) {
  256. baseURL := "https://energy.franklinwh.com/hes-gateway/manage/getEquipmentAlarm"
  257. token := getLoginToken()
  258. // 构造 query 参数
  259. params := url.Values{}
  260. params.Add("gatewayId", sn)
  261. params.Add("land", "ZH_CN")
  262. // 拼接到 URL
  263. finalURL := baseURL + "?" + params.Encode()
  264. // 创建请求
  265. req, err := http.NewRequest(
  266. http.MethodGet,
  267. finalURL,
  268. nil)
  269. if err != nil {
  270. fmt.Println(err.Error())
  271. return nil, err
  272. }
  273. // 设置 Content-Type 和 Authorization
  274. req.Header.Set("Content-Type", "application/json")
  275. req.Header.Set("Logintoken", token)
  276. // fmt.Println(req.Header)
  277. // 发送请求
  278. client := &http.Client{Timeout: 5 * time.Second}
  279. resp, err := client.Do(req)
  280. if err != nil {
  281. fmt.Println(err.Error())
  282. return nil, err
  283. }
  284. defer resp.Body.Close()
  285. body, _ := io.ReadAll(resp.Body)
  286. // fmt.Printf("Status: %s\nBody: %s\n", resp.Status, body)
  287. return body, nil
  288. }