action.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. import math
  2. import time
  3. import requests
  4. class Fetcher:
  5. def __init__(self, farmId: "str" = "330110004"):
  6. self._farm: "str" = farmId
  7. self._sess: "requests.Session" = requests.session()
  8. def _login(self) -> "None":
  9. url = "http://119.3.44.183:8016/admin/my/loginMultilevel"
  10. payload = {"accountName": "superadmin", "password": "hm123456", "farmId": self._farm}
  11. resp = self._sess.post(url=url, json=payload)
  12. assert resp.status_code == 200, f"login failed: {resp.status_code}"
  13. self._sess.headers.setdefault("Accesstoken", resp.json()["data"]["token"])
  14. @staticmethod
  15. def _time(ts: "str") -> "int":
  16. return int(time.mktime(time.strptime(ts, "%Y-%m-%d %H:%M:%S")))
  17. @staticmethod
  18. def _num(data):
  19. return data if data is not None else 0
  20. def _clean(self, data: "list[dict]") -> "list[tuple]":
  21. # envTemp, earTemp1, earTemp2, act, timestamp
  22. return [(
  23. self._num(itr["envTemp1"]), self._num(itr["earTemp1"]),
  24. self._num(itr["earTemp2"]), self._num(itr["act1"]), self._time(itr["addTime"])
  25. ) for itr in data]
  26. def fetch(self, tagId: "str", start: "str", end: "str") -> "list[tuple]":
  27. self._login()
  28. url = "http://119.3.44.183:8016/manage2/eartagData/getEnvByTime"
  29. payload = {"earmark": tagId, "startDate": start, "endDate": end, "farmId": self._farm}
  30. resp = self._sess.post(url=url, json=payload)
  31. assert resp.status_code == 200, f"> ERROR: fetch <{tagId}> failed!"
  32. return self._clean(resp.json()["data"])
  33. class Proxy:
  34. def __init__(self):
  35. self._data = None
  36. def get(self):
  37. return self._data
  38. def set(self, data):
  39. self._data = data
  40. # 分类多
  41. class Result:
  42. __m = {
  43. 1: (1, "温度稳定于体温,运动量小", "睡眠状态"), # 1
  44. 2: (2, "温度稳定于体温,运动量大", "异常状态"), # 4
  45. 3: (3, "温度稳定于室温,运动量小", "侧躺状态"), # 2
  46. 4: (4, "温度稳定于室温,运动量大", "异常状态"), # 4
  47. 5: (5, "温度稳定,运动量小", "异常状态"), # 4
  48. 6: (6, "温度稳定,运动量大", "异常状态"), # 4
  49. 7: (7, "温度在体温附近不稳定,运动量小", "异常状态"), # 4
  50. 8: (8, "温度在体温附近不稳定,运动量大", "活跃状态"), # 3
  51. 9: (9, "温度在室温附近不稳定,运动量小", "异常状态"), # 4
  52. 10: (10, "温度在室温附近不稳定,运动量大", "活跃状态"), # 3
  53. 11: (11, "温度不稳定,运动量小", "异常状态"), # 4
  54. 12: (12, "温度不稳定,运动量大", "活跃状态") # 3
  55. }
  56. @staticmethod
  57. def kind(t: "int") -> "int":
  58. if t == 1:
  59. return 1
  60. if t == 3:
  61. return 2
  62. if t in [8, 10, 12]:
  63. return 3
  64. return 4
  65. @staticmethod
  66. def _time(sec: "int") -> "str":
  67. return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(sec))
  68. def _info(self, _type: "int") -> "tuple":
  69. return self.__m.get(_type, (-1, "unrecognized type", "unknown"))
  70. def __init__(self, _type: "int", start: "int", end: "int"):
  71. self.start, self.end = start, end
  72. self.id, self.desc, self.type = self._info(_type)
  73. self.sTime, self.eTime = self._time(start), self._time(end)
  74. def __repr__(self):
  75. return (
  76. f"<id:{self.id}, desc:\"{self.desc}\", "
  77. f"type:\"{self.type}\", start:\"{self.sTime}\", end:\"{self.eTime}\">"
  78. )
  79. class Action:
  80. def __init__(
  81. self,
  82. body: "float" = 35.5,
  83. actHold: "tuple[int, int]" = (8, 10),
  84. tempHold: "tuple[float, float]" = (5.5, 6.0)
  85. ):
  86. self._bodyTemp: "float" = body
  87. self._actMin: "int" = actHold[0]
  88. self._actMax: "int" = actHold[1]
  89. self._tempMin: "float" = tempHold[0]
  90. self._tempMax: "float" = tempHold[1]
  91. @staticmethod
  92. def _handle(arr: "list[Result]", data: "tuple", curr: "int", state: "Proxy", start: "Proxy"):
  93. if curr != state.get():
  94. if state.get() is not None:
  95. arr.append(Result(state.get(), start.get(), data[-1]))
  96. state.set(curr)
  97. start.set(data[-1])
  98. def analyze(self, data: "list[tuple]") -> "list[Result]":
  99. result, state, start = [], Proxy(), Proxy()
  100. for itr in data:
  101. envT, earT1, earT2, act, secs = itr
  102. if abs(earT1 - earT2) < self._tempMin: # 温度稳定
  103. if abs(earT1 - self._bodyTemp) < self._tempMin: # 在体温附近稳定
  104. if act < self._actMax:
  105. self._handle(result, itr, 1, state, start)
  106. else:
  107. self._handle(result, itr, 2, state, start)
  108. elif abs(earT1 - envT) < self._tempMin: # 在环境温度附近稳定
  109. if act < self._actMax:
  110. self._handle(result, itr, 3, state, start)
  111. else:
  112. self._handle(result, itr, 4, state, start)
  113. else: # 其余稳定
  114. if act < self._actMax:
  115. self._handle(result, itr, 5, state, start)
  116. else:
  117. self._handle(result, itr, 6, state, start)
  118. else:
  119. if abs(earT1 - self._bodyTemp) < self._tempMax: # 在体温附近不稳定
  120. if act < self._actMin:
  121. self._handle(result, itr, 7, state, start)
  122. else:
  123. self._handle(result, itr, 8, state, start)
  124. elif abs(earT1 - envT) < self._tempMax: # 在环境温度附近不稳定
  125. if act < self._actMin:
  126. self._handle(result, itr, 9, state, start)
  127. else:
  128. self._handle(result, itr, 10, state, start)
  129. else: # 其余不稳定
  130. if act < self._actMin:
  131. self._handle(result, itr, 11, state, start)
  132. else:
  133. self._handle(result, itr, 12, state, start)
  134. return result
  135. # 聚合为4类
  136. class Join:
  137. __m = {1: "睡眠状态", 2: "侧躺状态", 3: "活跃状态", 4: "其它状态"}
  138. def __init__(self, data: "list[Result]"):
  139. self.data = data
  140. @staticmethod
  141. def _type(_id: "int") -> "str":
  142. return Join.__m.get(_id, "unknown")
  143. @staticmethod
  144. def _make(old: "Result") -> "Result":
  145. cid = Result.kind(old.id)
  146. new = Result(1, old.start, old.end)
  147. new.id, new.desc, new.type = cid, "-", Join._type(cid)
  148. return new
  149. def run(self) -> "list[Result]":
  150. res = []
  151. cur = self._make(self.data[0])
  152. for i in range(1, len(self.data)):
  153. cid = Result.kind(self.data[i].id)
  154. if cid != cur.id:
  155. cur.end, cur.eTime = self.data[i].start, self.data[i].sTime
  156. res.append(cur)
  157. cur = self._make(self.data[i])
  158. cur.end, cur.eTime = self.data[-1].end, self.data[-1].eTime
  159. res.append(cur)
  160. return res
  161. class RespItem:
  162. def __init__(self, _id: "int", _type: "str", _time: "str", width: "int"):
  163. self.id, self.type, self.time, self.width = _id, _type, _time, width
  164. def __repr__(self):
  165. return f"<id: {self.id}, type: \"{self.type}\", time: \"{self.time}\", width: {self.width}>"
  166. class Calc:
  167. def __init__(self, data: "list[Result]"):
  168. self.sum = {}
  169. self.data = data
  170. self.total: "int" = data[-1].end - data[0].start
  171. def run(self):
  172. result = []
  173. for itr in self.data:
  174. key = itr.sTime[:10]
  175. if key not in self.sum.keys():
  176. self.sum[key] = {1: 0, 2: 0, 3: 0, 4: 0}
  177. self.sum[key][itr.id] += itr.end - itr.start
  178. result.append(RespItem(itr.id, itr.type, itr.sTime, math.ceil((itr.end - itr.start) * 100 / self.total)))
  179. return result
  180. def show(data: "list"):
  181. print("[")
  182. [print(f"\t{itr},") for itr in data]
  183. print("]")
  184. def main():
  185. fetcher = Fetcher()
  186. data = fetcher.fetch("133202311130004", "2023-12-1 00:00:00", "2023-12-10 00:00:00")
  187. print(data)
  188. action = Action()
  189. state = action.analyze(data)
  190. show(state)
  191. join = Join(state)
  192. new = join.run()
  193. show(new)
  194. calc = Calc(new)
  195. resp = calc.run()
  196. show(resp)
  197. print(calc.sum)
  198. if __name__ == "__main__":
  199. main()