platform.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. # -*- coding: utf-8 -*-
  2. from enum import Enum
  3. from typing import Dict, List, Tuple
  4. import arrow
  5. import numpy as np
  6. from httpx import AsyncClient, URL
  7. from loguru import logger
  8. from app.core.config import settings
  9. from app.services.service import Service
  10. from app.utils.date import get_time_str, TIME_FMT
  11. from app.utils.math import round_half_up
  12. class InfoCode(str, Enum):
  13. temperature = 'Tdb'
  14. co2 = 'CO2'
  15. hcho = 'HCHO'
  16. pm2d5 = 'PM2d5'
  17. humidity = 'RH'
  18. supply_air_flow = 'SupplyAirFlow'
  19. supply_air_temperature = 'SupplyAirTemp'
  20. supply_air_temperature_set = 'SupplyAirTempSet'
  21. fan_speed = 'FanGear'
  22. fan_freq = 'FanFreq'
  23. fan_freq_set = 'FanFreqSet'
  24. supply_static_press = 'SupplyStaticPress'
  25. supply_static_press_set = 'SupplyStaticPressSet'
  26. running_status = 'RunStatus'
  27. cloud_status = 'InCloudStatus'
  28. equip_switch_set = 'EquipSwitchSet'
  29. class DataPlatformService(Service):
  30. def __init__(
  31. self,
  32. client: AsyncClient,
  33. project_id: str,
  34. server_settings=settings
  35. ):
  36. super(DataPlatformService, self).__init__(client)
  37. self._project_id = project_id
  38. self._base_url = URL(server_settings.PLATFORM_HOST)
  39. self._now_time = get_time_str()
  40. self._secret = server_settings.PLATFORM_SECRET
  41. def _common_parameters(self) -> Dict:
  42. return {'projectId': self._project_id, 'secret': self._secret}
  43. async def get_realtime_data(self, code: InfoCode, object_id: str) -> float:
  44. url = self._base_url.join('data-platform-3/hisdata/query_by_obj')
  45. params = self._common_parameters()
  46. start_time = get_time_str(60 * 60, flag='ago')
  47. payload = {
  48. 'criteria': {
  49. 'id': object_id,
  50. 'code': code.value,
  51. 'receivetime': {
  52. '$gte': start_time,
  53. '$lte': self._now_time,
  54. }
  55. }
  56. }
  57. raw_info = await self._post(url, params, payload)
  58. try:
  59. latest_data = raw_info.get('Content')[-1].get('data')
  60. latest_time = raw_info.get('Content')[-1].get('receivetime')
  61. if arrow.get(latest_time, TIME_FMT).shift(minutes=15) < arrow.get(self._now_time, TIME_FMT):
  62. logger.info(f'delayed data - {object_id}: ({latest_time}, {latest_data})')
  63. value = round_half_up(latest_data, 2)
  64. except KeyError and IndexError:
  65. value = np.NAN
  66. except TypeError:
  67. value = -1.0
  68. return value
  69. async def get_duration(self, code: InfoCode, object_id: str, duration: int) -> List[Dict]:
  70. url = self._base_url.join('data-platform-3/hisdata/query_by_obj')
  71. params = self._common_parameters()
  72. start_time = get_time_str(duration, flag='ago')
  73. payload = {
  74. 'criteria': {
  75. 'id': object_id,
  76. 'code': code.value,
  77. 'receivetime': {
  78. '$gte': start_time,
  79. '$lte': self._now_time,
  80. }
  81. }
  82. }
  83. raw_info = await self._post(url, params, payload)
  84. try:
  85. content = raw_info.get('Content')
  86. latest_time = content[-1].get('receivetime')
  87. if arrow.get(latest_time, TIME_FMT).shift(minutes=15) < arrow.get(self._now_time, TIME_FMT):
  88. result = []
  89. logger.info(f'delayed data - {object_id}: ({latest_time})')
  90. else:
  91. result = [
  92. {
  93. 'timestamp': item['receivetime'],
  94. 'value': item['data']
  95. }
  96. for item in content
  97. ]
  98. except KeyError:
  99. result = []
  100. return result
  101. async def get_past_data(self, code: InfoCode, object_id: str, interval: int) -> float:
  102. """
  103. Query past data from data platform.
  104. :param code: Info code
  105. :param object_id:
  106. :param interval: time interval(seconds) from now to past
  107. :return: a past value
  108. """
  109. url = self._base_url.join('data-platform-3/hisdata/query_by_obj')
  110. params = self._common_parameters()
  111. start_time = get_time_str(60 * 60 + interval, flag='ago')
  112. end_time = get_time_str(interval, flag='ago')
  113. payload = {
  114. 'criteria': {
  115. 'id': object_id,
  116. 'code': code.value,
  117. 'receivetime': {
  118. '$gte': start_time,
  119. '$lte': end_time,
  120. }
  121. }
  122. }
  123. raw_info = await self._post(url, params, payload)
  124. try:
  125. latest_data = raw_info.get('Content')[-1].get('data')
  126. latest_time = raw_info.get('Content')[-1].get('receivetime')
  127. if arrow.get(latest_time, TIME_FMT).shift(minutes=15) < arrow.get(end_time, TIME_FMT):
  128. logger.info(f'delayed data - {object_id}: ({latest_time}, {latest_data})')
  129. value = round_half_up(latest_data, 2)
  130. except KeyError and IndexError:
  131. value = np.NAN
  132. except TypeError:
  133. value = -1.0
  134. return value
  135. async def get_realtime_temperature(self, space_id: str) -> float:
  136. return await self.get_realtime_data(InfoCode.temperature, space_id)
  137. async def get_past_temperature(self, space_id: str, interval: int) -> float:
  138. return await self.get_past_data(InfoCode.temperature, space_id, interval)
  139. async def get_realtime_co2(self, space_id: str) -> float:
  140. return await self.get_realtime_data(InfoCode.co2, space_id)
  141. async def get_realtime_hcho(self, space_id: str) -> float:
  142. return await self.get_realtime_data(InfoCode.hcho, space_id)
  143. async def get_realtime_pm2d5(self, space_id: str) -> float:
  144. return await self.get_realtime_data(InfoCode.pm2d5, space_id)
  145. async def get_realtime_humidity(self, space_id: str) -> float:
  146. return await self.get_realtime_data(InfoCode.humidity, space_id)
  147. async def get_realtime_supply_air_flow(self, equipment_id: str) -> float:
  148. return await self.get_realtime_data(InfoCode.supply_air_flow, equipment_id)
  149. async def get_realtime_supply_air_temperature(self, equipment_id: str) -> float:
  150. return await self.get_realtime_data(InfoCode.supply_air_temperature, equipment_id)
  151. async def get_realtime_supply_air_temperature_set(self, equipment_id: str) -> float:
  152. return await self.get_realtime_data(InfoCode.supply_air_temperature_set, equipment_id)
  153. async def get_fan_speed(self, equipment_id: str) -> float:
  154. return await self.get_realtime_data(InfoCode.fan_speed, equipment_id)
  155. async def get_static_info(self, code: str, object_id: str):
  156. url = self._base_url.join('data-platform-3/object/batch_query')
  157. params = self._common_parameters()
  158. payload = {
  159. 'customInfo': True,
  160. 'criterias': [
  161. {
  162. 'id': object_id
  163. }
  164. ]
  165. }
  166. raw_info = await self._post(url, params, payload)
  167. try:
  168. info = raw_info['Content'][0]['infos'][code]
  169. except KeyError as e:
  170. logger.error(f'id: {object_id}, details: {e}')
  171. info = None
  172. return info
  173. async def get_air_flow_limit(self, equipment_id: str) -> Tuple[float, float]:
  174. lower = await self.get_static_info('MinAirFlow', equipment_id)
  175. upper = await self.get_static_info('MaxAirFlow', equipment_id)
  176. if not lower:
  177. lower = 150.0
  178. if not upper:
  179. upper = 2000.0
  180. return lower, upper
  181. async def get_schedule(self, equipment_id: str) -> Tuple[str, str]:
  182. on_time = await self.get_static_info('ctm-OnTime', equipment_id)
  183. off_time = await self.get_static_info('ctm-OffTime', equipment_id)
  184. if not on_time:
  185. on_time = '080000'
  186. if not off_time:
  187. off_time = '190000'
  188. return on_time, off_time
  189. async def get_realtime_fan_freq_set(self, equipment_id: str) -> float:
  190. return await self.get_realtime_data(InfoCode.fan_freq_set, equipment_id)
  191. async def get_realtime_supply_static_press(self, system_id: str) -> float:
  192. return await self.get_realtime_data(InfoCode.supply_static_press, system_id)
  193. async def get_realtime_supply_static_press_set(self, system_id: str) -> float:
  194. return await self.get_realtime_data(InfoCode.supply_static_press_set, system_id)
  195. async def get_realtime_running_status(self, equipment_id: str) -> float:
  196. return await self.get_realtime_data(InfoCode.running_status, equipment_id)
  197. async def get_cloud_status(self, equipment_id: str) -> float:
  198. return await self.get_realtime_data(InfoCode.cloud_status, equipment_id)
  199. async def set_code_value(self, object_id: str, code: InfoCode, value: float):
  200. url = self._base_url.join('data-platform-3/parameter/setting')
  201. params = self._common_parameters()
  202. payload = {
  203. 'id': object_id,
  204. 'code': code.value,
  205. 'value': value
  206. }
  207. await self._post(url, params, payload)
  208. async def get_items_by_category(self, code) -> List:
  209. url = self._base_url.join('data-platform-3/object/subset_query')
  210. params = self._common_parameters()
  211. payload = {
  212. 'criteria': {
  213. 'type': [code]
  214. }
  215. }
  216. raw_info = await self._post(url, params, payload)
  217. items_id_list = [item['id'] for item in raw_info['Content']]
  218. return items_id_list