liangxi_fire.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import uuid
  6. import requests
  7. from django.conf import settings
  8. from mongoengine import StringField, BooleanField
  9. from typing import TYPE_CHECKING
  10. from apps.web.core.db import Searchable
  11. from apps.web.agent.models import Agent
  12. from apps.web.common.models import District
  13. if TYPE_CHECKING:
  14. from apps.web.dealer.models import Dealer
  15. from apps.web.device.models import DeviceDict, FaultRecord
  16. logger = logging.getLogger(__name__)
  17. class LiangXiXiaoFang(object):
  18. # ipPort = "lxzhyd.idea-sf.com:82/safe"
  19. ipPort = "114.216.202.169:82/safe" # 测试使用ip
  20. faultMap = {
  21. "01": u"温度故障",
  22. "02": u"烟感故障",
  23. "03": u"插座功率过载故障",
  24. "04": u"充电器故障",
  25. "05": u"电池故障",
  26. "06": u"设备功率过载",
  27. "07": u"网络故障"
  28. }
  29. devNos = [
  30. ['869300033348255', # 尚城公寓
  31. '869300033348370', ],
  32. ['868575025762834', # 金科观天下
  33. '868575025758550',
  34. '868575025756588', ],
  35. ['869300039898691', ], # 水榭新大陆
  36. ['869300039913326', ], # 观天下
  37. ['869300039911593', # 东方水榭
  38. '860344042976259', ],
  39. ['860344042561788', # 东方王谢洋房
  40. '860344046870920', ],
  41. ['868575025757818', # 水榭七号楼
  42. '868575025738909', ],
  43. ['868575025757776', # 水榭2号楼
  44. '868575025738842',
  45. '868575025752900',
  46. '868575025746233',
  47. '868575025766181', ],
  48. ['868575025747926', # 观天下 (助力充电桩)
  49. '868575025756844',
  50. '868575025754179',
  51. '868575025757735',
  52. '868575025739063',
  53. '868575025758410',
  54. '868575025738677',
  55. '868575025753593', ],
  56. ['869300033357249', # 尚城绿园
  57. '869300033346705',
  58. '869300033369673',
  59. '869300033347687',
  60. '869300033353941',
  61. '869300033354360',
  62. '869300033357579',
  63. '869300033383831',
  64. '869300033357637',
  65. '869300033356480', ]
  66. ]
  67. # # 测试的devNOs
  68. # devNos = [
  69. # ["862285036747669"]
  70. # ]
  71. PLOTFORM = "XCKJ"
  72. BELOBG_TO = u"商品房"
  73. FAULT_STATUS = 3
  74. FREE_STATUS = 0
  75. @staticmethod
  76. def gen_uuid():
  77. u = str(uuid.uuid4())
  78. return "".join(u.split('-'))
  79. @staticmethod
  80. def send_to_xf_ini(dev, districtInfo):
  81. province, city, block = districtInfo.split(" ")
  82. data = {
  83. "platform": "XCKJ",
  84. "province": province,
  85. "city": city,
  86. "block": block,
  87. "chargerList": []
  88. }
  89. setupDate = datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")
  90. # 物业相关信息暂时不需要上传
  91. devData = {
  92. "id": dev['logicalCode'],
  93. "chargerName": u"%s 充电桩 -%s" % (dev.get('groupInfo', {}).get("address", ""), dev.get("groupNumber")),
  94. "belongTo": LiangXiXiaoFang.BELOBG_TO,
  95. "lng": dev["lng"],
  96. "lat": dev["lat"],
  97. "supplierName": u"信长科技",
  98. "supplierPerson": dev['supplierPerson'],
  99. "supplierTel": dev["supplierTel"],
  100. "street": dev.get('groupInfo', {}).get("address", ""),
  101. "status": LiangXiXiaoFang.FAULT_STATUS if dev["isFault"] else LiangXiXiaoFang.FREE_STATUS,
  102. "chargeNum": len(dev['pileList']),
  103. "isOnline": int(not dev["isFault"]),
  104. "setupDate": setupDate,
  105. "pileList": dev["pileList"]
  106. }
  107. data['chargerList'].append(devData)
  108. url = "http://%s/charger/device.json" % LiangXiXiaoFang.ipPort
  109. try:
  110. result = LiangXiXiaoFang.send_request_to_xf(url, [data])
  111. except Exception as e:
  112. logger.exception(e)
  113. if result.get("msgCode") != '0':
  114. logger.info("send to xiaofang deviceinfo filed, the reason is %s" % result.get("msg", ""))
  115. @staticmethod
  116. def send_to_xf_fault(dev, faultCode, faultContent, pileNum = None):
  117. """ 判断需要上报的设备 """
  118. devNos = [item.devNo for item in LiangXiXiaoFangDev.objects(needSend = True).all()]
  119. if dev['devNo'] not in devNos:
  120. return
  121. plotform = LiangXiXiaoFang.PLOTFORM
  122. faultname = LiangXiXiaoFang.faultMap.get(faultCode, "")
  123. districtInfo = dev.get("districtInfo", "")
  124. pilenum = pileNum or 0
  125. _id = LiangXiXiaoFang.gen_uuid()
  126. province, city, block = districtInfo.split(" ")
  127. data = [{
  128. "province": province,
  129. "city": city,
  130. "block": block,
  131. "platform": plotform,
  132. "realTimeAlarmList": [{
  133. "id": _id,
  134. "chargerId": dev['logicalCode'],
  135. "chargerName": u"%s 充电桩 -%s" % (dev["groupAddr"], dev.get("groupNumber")),
  136. "pileNum": int(pilenum),
  137. "faultName": faultname,
  138. "faultContent": faultContent,
  139. "createTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")
  140. }]
  141. }]
  142. url = "http://%s/charger/faultList.json" % LiangXiXiaoFang.ipPort
  143. try:
  144. result = LiangXiXiaoFang.send_request_to_xf(url, data)
  145. except Exception as e:
  146. logger.exception(e)
  147. if result.get("msgCode") != '0':
  148. logger.info("send to xiaofang fault filed, the reason is %s" % result.get("msg", ""))
  149. # 上报处理信息
  150. LiangXiXiaoFang.send_to_xf_handle(_id)
  151. @staticmethod
  152. def send_to_xf_handle(_id):
  153. data = [{
  154. "id": _id,
  155. "platform": "XCKJ",
  156. "handleMemo": u"故障已经处理",
  157. "handleTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S"),
  158. "handleName": u"徐应金"
  159. }]
  160. url = "http://%s/charger/faultHandlerList.json" % LiangXiXiaoFang.ipPort
  161. try:
  162. result = LiangXiXiaoFang.send_request_to_xf(url, data)
  163. except Exception as e:
  164. logger.exception(e)
  165. if result.get("msgCode") != '0':
  166. logger.info("send to xiaofang handle filed, the reason is %s" % result.get("msg", ""))
  167. @staticmethod
  168. def send_request_to_xf(url, data):
  169. res = requests.post(url, json = data, timeout = 15)
  170. if res.status_code == 200:
  171. return res.json()
  172. return {}
  173. class LiangXiXiaoFangDev(Searchable):
  174. devNo = StringField(verbose_name = "设备编号", min_length = 1, unique = True)
  175. needSend = BooleanField(verbose_name = "是否需要上报", default = True)
  176. meta = {
  177. "collection": "LiangXiXiaoFangDev",
  178. "db_alias": "default"
  179. }
  180. class ToXiaoFang(object):
  181. """
  182. 经销商需要配置属性 特性 LXXF
  183. """
  184. FAULT_MAP = {
  185. "01": u"温度故障",
  186. "02": u"烟感故障",
  187. "03": u"插座功率过载故障",
  188. "04": u"充电器故障",
  189. "05": u"电池故障",
  190. "06": u"设备功率过载",
  191. "07": u"网络故障"
  192. }
  193. # 对不同的设备的告警故障进行处理
  194. FAULT_CODE_MAP = {
  195. # TODO zjl 新电川 记得合并到100210
  196. "100252": {
  197. "41": "02",
  198. "47": "01",
  199. "01": "07",
  200. "02": "03",
  201. "03": "05"
  202. },
  203. "100210": {
  204. "01": "07",
  205. "02": "03",
  206. "03": "05",
  207. "41": "02"
  208. },
  209. "100206": {
  210. "B3": "03",
  211. "B4": "02",
  212. "B8": "01",
  213. "B7": "06",
  214. "B2": "01",
  215. "B201": "01",
  216. "B202": "02",
  217. "B203": "06",
  218. "1603": "03",
  219. "160B": "04"
  220. },
  221. "100202": {
  222. "B3": "03",
  223. "B4": "02",
  224. "B8": "01",
  225. "B7": "06",
  226. "B201": "01",
  227. "B202": "02",
  228. "B203": "06",
  229. "1603": "03",
  230. "160B": "04"
  231. }
  232. }
  233. PLATFORM_MAP = {
  234. u'全城': u'PQC',
  235. u'粤万通': u'YWT',
  236. u'雪影': u'XY'
  237. }
  238. SUPPORT_ADDRESS = u"梁溪区"
  239. def __init__(self, device, platformName = None):
  240. # type: (DeviceDict, str) -> None
  241. """
  242. :param device: 设备
  243. :param platformName: 平台
  244. """
  245. dealer = device.owner # type: Dealer
  246. # 获取平台代码
  247. if not platformName or platformName not in ToXiaoFang.PLATFORM_MAP.values():
  248. agent = Agent.objects.get(id = dealer.agentId)
  249. for _name, _key in ToXiaoFang.PLATFORM_MAP.items():
  250. if _name in agent.productName:
  251. platformName = _key
  252. break
  253. else:
  254. platformName = ""
  255. self._platform = platformName
  256. self._device = device
  257. self._dealer = dealer
  258. # 是否支持
  259. dealerSupport = "LXXF" in dealer.features
  260. devTypeSupport = self._device.devTypeCode in ToXiaoFang.FAULT_CODE_MAP
  261. deviceSupport = District.get_district(self._device.group['districtId']).endswith(ToXiaoFang.SUPPORT_ADDRESS)
  262. self._support = dealerSupport and devTypeSupport and deviceSupport
  263. if settings.MY_DOMAIN == "develop.5tao5ai.com":
  264. self.ipPort = "http://lxzhyd.idea-sf.com:82/safe"
  265. else:
  266. self.ipPort = "https://lxzhyd.idea-sf.com/safe"
  267. def send_request_to_xf(self, url, data):
  268. res = requests.post(url, json = data, timeout = 15)
  269. if res.status_code != 200:
  270. logger.info(
  271. "dev {} send to liangxi {} data = {} error, status code = {}".format(self._device.devNo, url, data,
  272. res.status_code))
  273. return
  274. responseData = res.json()
  275. logger.info(
  276. "dev {} send to liangxi {} data = {}, response = {}".format(self._device.devNo, url, data, responseData))
  277. @staticmethod
  278. def get_fault(devTypeCode, faultCode):
  279. """
  280. 获取相应的code
  281. :param devTypeCode:
  282. :param faultCode:
  283. :return:
  284. """
  285. typeMap = ToXiaoFang.FAULT_CODE_MAP.get(devTypeCode)
  286. code = typeMap.get(faultCode, "01")
  287. return ToXiaoFang.FAULT_MAP.get(code)
  288. def send_to_xf_ini(self):
  289. """
  290. 初始化设备
  291. :return:
  292. """
  293. if not self._support:
  294. return
  295. logger.info("device <{}> send to liangxi xiaofang init".format(self._device.devNo))
  296. from apps.web.core.helpers import ActionDeviceBuilder
  297. # 端口状态
  298. pileList = list()
  299. try:
  300. box = ActionDeviceBuilder.create_action_device(self._device)
  301. portStatus = box.get_port_status() or dict()
  302. except Exception as e:
  303. logger.exception("send liangxi xf error, device={}, e={}".format(self._device, e))
  304. return
  305. devStatus = 1
  306. for _portStr, _portInfo in portStatus.items():
  307. pileList.append({
  308. "num": int(_portStr),
  309. # 梁溪消防的定义状态数量值 比我们系统的 多 1
  310. "status": int(_portInfo.get("status", 0)) + 1
  311. })
  312. if _portInfo.get("status", 0) == 1:
  313. devStatus = 2
  314. # 设备的状态
  315. chargerList = {
  316. "id": self._device.logicalCode,
  317. "chargerName": u"%s 充电桩 -%s" % (self._device.group.get("address", ""), self._device.get("groupNumber")),
  318. "belongTo": u"商品房",
  319. "lng": self._device.lng,
  320. "lat": self._device.lat,
  321. "supplierName": self._dealer.nickname,
  322. "street": self._device.group.get("address", ""),
  323. "status": devStatus,
  324. "chargeNum": len(pileList),
  325. "isOnline": int(self._device.online),
  326. "setupDate": datetime.datetime.now().strftime("%Y-%m-%d"),
  327. "pileList": pileList
  328. }
  329. # 整状态
  330. group = self._device.group
  331. districtInfo = District.get_district(group['districtId'])
  332. province, city, block = districtInfo.split()
  333. data = {
  334. "platform": self._platform,
  335. "province": province,
  336. "city": city,
  337. "block": block,
  338. "chargerList": [chargerList]
  339. }
  340. url = "{}/charger/device.json".format(self.ipPort)
  341. try:
  342. self.send_request_to_xf(url, [data])
  343. except Exception as e:
  344. logger.error("device {} send to xiaofang init error = {}".format(self._device.devNo, e))
  345. return
  346. def send_to_xf_fault(self, faultRecord): # type:(FaultRecord) -> None
  347. """
  348. 故障告警到消防局
  349. :param faultRecord:
  350. :return:
  351. """
  352. if not self._support:
  353. return
  354. logger.info("device <{}> send to liangxi xiaofang fault <{}>".format(self._device.devNo, faultRecord.id))
  355. realTimeAlarm = {
  356. "id": str(faultRecord.id),
  357. "chargerId": self._device.logicalCode,
  358. "chargerName": u"%s 充电桩 -%s" % (self._device.group.get("address", ""), self._device.get("groupNumber")),
  359. "pileNum": int(faultRecord.portNo),
  360. "faultName": ToXiaoFang.get_fault(self._device.devTypeCode, faultRecord.detail.get("errorCode", "")),
  361. "faultContent": faultRecord.description,
  362. "createTime": faultRecord.createdTime.strftime("%Y-%m-%d %H:%M:%S")
  363. }
  364. group = self._device.group
  365. districtInfo = District.get_district(group['districtId'])
  366. province, city, block = districtInfo.split()
  367. data = {
  368. "platform": self._platform,
  369. "province": province,
  370. "city": city,
  371. "block": block,
  372. "realTimeAlarmList": [realTimeAlarm]
  373. }
  374. url = "{}/charger/faultList.json".format(self.ipPort)
  375. try:
  376. self.send_request_to_xf(url, [data])
  377. except Exception as e:
  378. logger.error("device {} send to xiaofang fault {} error = {}".format(self._device.devNo, faultRecord.id, e))
  379. return
  380. def send_to_xf_handle(self, faultRecord): # type:(FaultRecord) -> None
  381. """
  382. 发送处理的结束的消息
  383. :param faultRecord:
  384. :return:
  385. """
  386. if not self._support:
  387. return
  388. logger.info("device <{}> send to liangxi xiaofang handle <{}>".format(self._device.devNo, faultRecord.id))
  389. faultHandler = {
  390. "id": str(faultRecord.id),
  391. "platform": self._platform,
  392. "handleMemo": faultRecord.dealedDetail or u"故障已处理",
  393. "handleTime": faultRecord.dealedTime.strftime("%Y-%m-%d %H:%M:%S"),
  394. "handlerTel": self._dealer.username,
  395. "handleType": "1",
  396. "handlerName": self._dealer.nickname
  397. }
  398. url = "{}/charger/faultHandlerList.json".format(self.ipPort)
  399. try:
  400. self.send_request_to_xf(url, [faultHandler])
  401. except Exception as e:
  402. logger.error(
  403. "device {} send to xiaofang handle {} error = {}".format(self._device.devNo, faultRecord.id, e))
  404. return