shanghai_urban_data_collection_platform.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. """
  4. 上海城运充电桩数据采集公共平台
  5. 接口ip与端口:http://211.136.105.235:8081/ljzwsq
  6. parentId:XJCLvU7Q2qJFYLkG
  7. secret:5cgj1M7YNMDvXlA7
  8. """
  9. import datetime
  10. import json
  11. import logging
  12. import traceback
  13. import requests
  14. from Crypto.Util.Padding import pad, unpad
  15. from Crypto.Cipher import AES
  16. from mongoengine import StringField
  17. from apps.web.constant import Const
  18. from apps.web.core.db import Searchable
  19. from apps.web.device.models import DeviceDict, Device
  20. SERVER_HOST = 'http://211.136.105.235:8081/ljzwsq'
  21. PARENT_ID = 'XJCLvU7Q2qJFYLkG'
  22. SECRET = '5cgj1M7YNMDvXlA7'
  23. logger = logging.getLogger(__name__)
  24. class AesUtil(object):
  25. def __init__(self, key=None):
  26. self.key = key or SECRET # 初始化密钥
  27. self.length = AES.block_size # 初始化数据块大小
  28. self.aes = AES.new(self.key.encode('utf-8'), AES.MODE_ECB) # 初始化AES,ECB模式的实例
  29. def encrypt(self, encrData): # 加密函数
  30. res = self.aes.encrypt(pad(encrData, self.length))
  31. return res.encode('hex')
  32. def decrypt(self, decrData): # 解密函数
  33. res = decrData.decode("hex")
  34. try:
  35. msg = self.aes.decrypt(res)
  36. return unpad(msg, self.length)
  37. except Exception, e:
  38. return None
  39. class ShangHaiUrbanDataCollectionPlatformModel(Searchable):
  40. dealerId = StringField(verbose_name='经销商')
  41. parentId = StringField(verbose_name='合作方认证 key')
  42. serverHost = StringField(verbose_name='接口地址')
  43. secret = StringField(verbose_name='密钥')
  44. meta = {
  45. 'collection': 'shanghai_urban_data_collection_platform'
  46. }
  47. @classmethod
  48. def get_dealer_info(cls, dealerId):
  49. obj = cls.objects.filter(dealerId=dealerId).first()
  50. if not obj:
  51. return {}
  52. else:
  53. return {
  54. 'dealerId': obj.dealerId,
  55. 'parentId': obj.parentId,
  56. 'serverHost': obj.serverHost,
  57. 'secret': obj.secret,
  58. }
  59. @classmethod
  60. def all_dealers(cls):
  61. objs = cls.objects.all()
  62. return map(lambda obj: {
  63. 'dealerId': obj.dealerId,
  64. 'parentId': obj.parentId,
  65. 'serverHost': obj.serverHost,
  66. 'secret': obj.secret,
  67. }, objs)
  68. class ShangHaiUrbanDataCollectionPlatform:
  69. def __init__(self, dev, serverHost, parentId, secret, **kw):
  70. self.device = dev # type: DeviceDict
  71. self.serverHost = serverHost
  72. self.parentId = parentId
  73. self.AES = AesUtil(secret)
  74. def post(self, url, data):
  75. try:
  76. kw = {
  77. 'parentId': self.parentId,
  78. 'data': data
  79. }
  80. logger.info(
  81. 'send to shanghai urban data collection platform url=< {} > data=< {} >'.format(url, json.dumps(data)))
  82. url = self.serverHost + url
  83. return requests.post(url=url, json=kw, timeout=3).json()
  84. except:
  85. logger.error(traceback.format_exc())
  86. return {}
  87. # 新增充电桩基础信息
  88. def add_dev_info(self):
  89. url = '/power/api/PushPowerBasicDataSave'
  90. data = {
  91. # "powerCode": self.device.logicalCode,
  92. "powerName": self.device.devTypeName,
  93. "code": self.device.logicalCode,
  94. "address": self.device.group.get('address', ''),
  95. "longitude": '{:0.3f}'.format(self.device.get('lng', 0.0)),
  96. "latitude": '{:0.3f}'.format(self.device.get('lat', 0.0)),
  97. "powerNodeList": [{'nodeIndex': '{}'.format(k), 'code': '{}-{}'.format(self.device.logicalCode, k)} for k in
  98. self.device.deviceAdapter.get_port_status() if k.isdigit()]
  99. }
  100. logger.info(
  101. 'send to shanghai urban data collection platform url=< {} > source=< {} >'.format(url, json.dumps(data,
  102. ensure_ascii=False)))
  103. data = self.AES.encrypt(json.dumps(data))
  104. res = self.post(url, data)
  105. logger.info(json.dumps(res, ensure_ascii=False))
  106. return res
  107. # 更新充电桩基础信息
  108. def update_dev_info(self):
  109. url = '/power/api/PushPowerBasicDataUpdate'
  110. data = {
  111. # "powerCode": self.device.logicalCode,
  112. "powerName": self.device.devTypeName,
  113. "code": self.device.logicalCode,
  114. "longitude": '{:0.3f}'.format(self.device.get('lng', 0.0)),
  115. "latitude": '{:0.3f}'.format(self.device.get('lat', 0.0)),
  116. "powerNodeList": [{'nodeIndex': '{}'.format(k), 'code': '{}-{}'.format(self.device.logicalCode, k)} for k in
  117. self.device.deviceAdapter.get_port_status() if k.isdigit()]
  118. }
  119. logger.info(
  120. 'send to shanghai urban data collection platform url=< {} > source=< {} >'.format(url, json.dumps(data,
  121. ensure_ascii=False)))
  122. data = self.AES.encrypt(json.dumps(data))
  123. res = self.post(url, data)
  124. logger.info(json.dumps(res, ensure_ascii=False))
  125. return res
  126. # 充电桩状态心跳
  127. def push_heatbeat(self):
  128. url = '/power/api/PowerNodeStatusBeat'
  129. powerNodeList = []
  130. ports_info = self.device.deviceAdapter.get_port_status()
  131. for k, v in ports_info.items():
  132. if k.isdigit():
  133. powerNodeList.append(
  134. {
  135. "powerCode": self.device.logicalCode, # 充电桩
  136. "code": '{}-{}'.format(self.device.logicalCode, k), # 端口
  137. "isOnline": "在线" if self.device.online else "离线",
  138. "status": "充电中" if v.get('status') == Const.DEV_WORK_STATUS_WORKING else "空闲",
  139. "normalStatus": "故障" if v.get('status') == Const.DEV_WORK_STATUS_FAULT else "正常",
  140. "powerAlarmDetailList": [
  141. {
  142. "powerCode": self.device.logicalCode, # 充电桩
  143. "nodeCode": '{}-{}'.format(self.device.logicalCode, k), # 端口
  144. "alarmType": "端口故障",
  145. "alarmContent": "端口故障",
  146. "alarmCreateDate": datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  147. }
  148. ] if v.get('status') == Const.DEV_WORK_STATUS_FAULT else []
  149. }
  150. )
  151. data = {'powerNodeList': powerNodeList}
  152. logger.info(
  153. 'send to shanghai urban data collection platform url=< {} > source=< {} >'.format(url, json.dumps(data,
  154. ensure_ascii=False)))
  155. data = self.AES.encrypt(json.dumps(data))
  156. res = self.post(url, data)
  157. logger.info(json.dumps(res, ensure_ascii=False))
  158. return res
  159. def celery_push_heatbeat(self):
  160. res = self.push_heatbeat()
  161. if res['success'] == True:
  162. return
  163. else:
  164. if '不存在' in res.get('msg', ''):
  165. self.add_dev_info()
  166. self.update_dev_info()
  167. self.push_heatbeat()
  168. else:
  169. pass