# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import uuid import requests from django.conf import settings from mongoengine import StringField, BooleanField from typing import TYPE_CHECKING from apps.web.core.db import Searchable from apps.web.agent.models import Agent from apps.web.common.models import District if TYPE_CHECKING: from apps.web.dealer.models import Dealer from apps.web.device.models import DeviceDict, FaultRecord logger = logging.getLogger(__name__) class LiangXiXiaoFang(object): # ipPort = "lxzhyd.idea-sf.com:82/safe" ipPort = "114.216.202.169:82/safe" # 测试使用ip faultMap = { "01": u"温度故障", "02": u"烟感故障", "03": u"插座功率过载故障", "04": u"充电器故障", "05": u"电池故障", "06": u"设备功率过载", "07": u"网络故障" } devNos = [ ['869300033348255', # 尚城公寓 '869300033348370', ], ['868575025762834', # 金科观天下 '868575025758550', '868575025756588', ], ['869300039898691', ], # 水榭新大陆 ['869300039913326', ], # 观天下 ['869300039911593', # 东方水榭 '860344042976259', ], ['860344042561788', # 东方王谢洋房 '860344046870920', ], ['868575025757818', # 水榭七号楼 '868575025738909', ], ['868575025757776', # 水榭2号楼 '868575025738842', '868575025752900', '868575025746233', '868575025766181', ], ['868575025747926', # 观天下 (助力充电桩) '868575025756844', '868575025754179', '868575025757735', '868575025739063', '868575025758410', '868575025738677', '868575025753593', ], ['869300033357249', # 尚城绿园 '869300033346705', '869300033369673', '869300033347687', '869300033353941', '869300033354360', '869300033357579', '869300033383831', '869300033357637', '869300033356480', ] ] # # 测试的devNOs # devNos = [ # ["862285036747669"] # ] PLOTFORM = "XCKJ" BELOBG_TO = u"商品房" FAULT_STATUS = 3 FREE_STATUS = 0 @staticmethod def gen_uuid(): u = str(uuid.uuid4()) return "".join(u.split('-')) @staticmethod def send_to_xf_ini(dev, districtInfo): province, city, block = districtInfo.split(" ") data = { "platform": "XCKJ", "province": province, "city": city, "block": block, "chargerList": [] } setupDate = datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S") # 物业相关信息暂时不需要上传 devData = { "id": dev['logicalCode'], "chargerName": u"%s 充电桩 -%s" % (dev.get('groupInfo', {}).get("address", ""), dev.get("groupNumber")), "belongTo": LiangXiXiaoFang.BELOBG_TO, "lng": dev["lng"], "lat": dev["lat"], "supplierName": u"信长科技", "supplierPerson": dev['supplierPerson'], "supplierTel": dev["supplierTel"], "street": dev.get('groupInfo', {}).get("address", ""), "status": LiangXiXiaoFang.FAULT_STATUS if dev["isFault"] else LiangXiXiaoFang.FREE_STATUS, "chargeNum": len(dev['pileList']), "isOnline": int(not dev["isFault"]), "setupDate": setupDate, "pileList": dev["pileList"] } data['chargerList'].append(devData) url = "http://%s/charger/device.json" % LiangXiXiaoFang.ipPort try: result = LiangXiXiaoFang.send_request_to_xf(url, [data]) except Exception as e: logger.exception(e) if result.get("msgCode") != '0': logger.info("send to xiaofang deviceinfo filed, the reason is %s" % result.get("msg", "")) @staticmethod def send_to_xf_fault(dev, faultCode, faultContent, pileNum = None): """ 判断需要上报的设备 """ devNos = [item.devNo for item in LiangXiXiaoFangDev.objects(needSend = True).all()] if dev['devNo'] not in devNos: return plotform = LiangXiXiaoFang.PLOTFORM faultname = LiangXiXiaoFang.faultMap.get(faultCode, "") districtInfo = dev.get("districtInfo", "") pilenum = pileNum or 0 _id = LiangXiXiaoFang.gen_uuid() province, city, block = districtInfo.split(" ") data = [{ "province": province, "city": city, "block": block, "platform": plotform, "realTimeAlarmList": [{ "id": _id, "chargerId": dev['logicalCode'], "chargerName": u"%s 充电桩 -%s" % (dev["groupAddr"], dev.get("groupNumber")), "pileNum": int(pilenum), "faultName": faultname, "faultContent": faultContent, "createTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S") }] }] url = "http://%s/charger/faultList.json" % LiangXiXiaoFang.ipPort try: result = LiangXiXiaoFang.send_request_to_xf(url, data) except Exception as e: logger.exception(e) if result.get("msgCode") != '0': logger.info("send to xiaofang fault filed, the reason is %s" % result.get("msg", "")) # 上报处理信息 LiangXiXiaoFang.send_to_xf_handle(_id) @staticmethod def send_to_xf_handle(_id): data = [{ "id": _id, "platform": "XCKJ", "handleMemo": u"故障已经处理", "handleTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S"), "handleName": u"徐应金" }] url = "http://%s/charger/faultHandlerList.json" % LiangXiXiaoFang.ipPort try: result = LiangXiXiaoFang.send_request_to_xf(url, data) except Exception as e: logger.exception(e) if result.get("msgCode") != '0': logger.info("send to xiaofang handle filed, the reason is %s" % result.get("msg", "")) @staticmethod def send_request_to_xf(url, data): res = requests.post(url, json = data, timeout = 15) if res.status_code == 200: return res.json() return {} class LiangXiXiaoFangDev(Searchable): devNo = StringField(verbose_name = "设备编号", min_length = 1, unique = True) needSend = BooleanField(verbose_name = "是否需要上报", default = True) meta = { "collection": "LiangXiXiaoFangDev", "db_alias": "default" } class ToXiaoFang(object): """ 经销商需要配置属性 特性 LXXF """ FAULT_MAP = { "01": u"温度故障", "02": u"烟感故障", "03": u"插座功率过载故障", "04": u"充电器故障", "05": u"电池故障", "06": u"设备功率过载", "07": u"网络故障" } # 对不同的设备的告警故障进行处理 FAULT_CODE_MAP = { # TODO zjl 新电川 记得合并到100210 "100252": { "41": "02", "47": "01", "01": "07", "02": "03", "03": "05" }, "100210": { "01": "07", "02": "03", "03": "05", "41": "02" }, "100206": { "B3": "03", "B4": "02", "B8": "01", "B7": "06", "B2": "01", "B201": "01", "B202": "02", "B203": "06", "1603": "03", "160B": "04" }, "100202": { "B3": "03", "B4": "02", "B8": "01", "B7": "06", "B201": "01", "B202": "02", "B203": "06", "1603": "03", "160B": "04" } } PLATFORM_MAP = { u'全城': u'PQC', u'粤万通': u'YWT', u'雪影': u'XY' } SUPPORT_ADDRESS = u"梁溪区" def __init__(self, device, platformName = None): # type: (DeviceDict, str) -> None """ :param device: 设备 :param platformName: 平台 """ dealer = device.owner # type: Dealer # 获取平台代码 if not platformName or platformName not in ToXiaoFang.PLATFORM_MAP.values(): agent = Agent.objects.get(id = dealer.agentId) for _name, _key in ToXiaoFang.PLATFORM_MAP.items(): if _name in agent.productName: platformName = _key break else: platformName = "" self._platform = platformName self._device = device self._dealer = dealer # 是否支持 dealerSupport = "LXXF" in dealer.features devTypeSupport = self._device.devTypeCode in ToXiaoFang.FAULT_CODE_MAP deviceSupport = District.get_district(self._device.group['districtId']).endswith(ToXiaoFang.SUPPORT_ADDRESS) self._support = dealerSupport and devTypeSupport and deviceSupport if settings.MY_DOMAIN == "develop.5tao5ai.com": self.ipPort = "http://lxzhyd.idea-sf.com:82/safe" else: self.ipPort = "https://lxzhyd.idea-sf.com/safe" def send_request_to_xf(self, url, data): res = requests.post(url, json = data, timeout = 15) if res.status_code != 200: logger.info( "dev {} send to liangxi {} data = {} error, status code = {}".format(self._device.devNo, url, data, res.status_code)) return responseData = res.json() logger.info( "dev {} send to liangxi {} data = {}, response = {}".format(self._device.devNo, url, data, responseData)) @staticmethod def get_fault(devTypeCode, faultCode): """ 获取相应的code :param devTypeCode: :param faultCode: :return: """ typeMap = ToXiaoFang.FAULT_CODE_MAP.get(devTypeCode) code = typeMap.get(faultCode, "01") return ToXiaoFang.FAULT_MAP.get(code) def send_to_xf_ini(self): """ 初始化设备 :return: """ if not self._support: return logger.info("device <{}> send to liangxi xiaofang init".format(self._device.devNo)) from apps.web.core.helpers import ActionDeviceBuilder # 端口状态 pileList = list() try: box = ActionDeviceBuilder.create_action_device(self._device) portStatus = box.get_port_status() or dict() except Exception as e: logger.exception("send liangxi xf error, device={}, e={}".format(self._device, e)) return devStatus = 1 for _portStr, _portInfo in portStatus.items(): pileList.append({ "num": int(_portStr), # 梁溪消防的定义状态数量值 比我们系统的 多 1 "status": int(_portInfo.get("status", 0)) + 1 }) if _portInfo.get("status", 0) == 1: devStatus = 2 # 设备的状态 chargerList = { "id": self._device.logicalCode, "chargerName": u"%s 充电桩 -%s" % (self._device.group.get("address", ""), self._device.get("groupNumber")), "belongTo": u"商品房", "lng": self._device.lng, "lat": self._device.lat, "supplierName": self._dealer.nickname, "street": self._device.group.get("address", ""), "status": devStatus, "chargeNum": len(pileList), "isOnline": int(self._device.online), "setupDate": datetime.datetime.now().strftime("%Y-%m-%d"), "pileList": pileList } # 整状态 group = self._device.group districtInfo = District.get_district(group['districtId']) province, city, block = districtInfo.split() data = { "platform": self._platform, "province": province, "city": city, "block": block, "chargerList": [chargerList] } url = "{}/charger/device.json".format(self.ipPort) try: self.send_request_to_xf(url, [data]) except Exception as e: logger.error("device {} send to xiaofang init error = {}".format(self._device.devNo, e)) return def send_to_xf_fault(self, faultRecord): # type:(FaultRecord) -> None """ 故障告警到消防局 :param faultRecord: :return: """ if not self._support: return logger.info("device <{}> send to liangxi xiaofang fault <{}>".format(self._device.devNo, faultRecord.id)) realTimeAlarm = { "id": str(faultRecord.id), "chargerId": self._device.logicalCode, "chargerName": u"%s 充电桩 -%s" % (self._device.group.get("address", ""), self._device.get("groupNumber")), "pileNum": int(faultRecord.portNo), "faultName": ToXiaoFang.get_fault(self._device.devTypeCode, faultRecord.detail.get("errorCode", "")), "faultContent": faultRecord.description, "createTime": faultRecord.createdTime.strftime("%Y-%m-%d %H:%M:%S") } group = self._device.group districtInfo = District.get_district(group['districtId']) province, city, block = districtInfo.split() data = { "platform": self._platform, "province": province, "city": city, "block": block, "realTimeAlarmList": [realTimeAlarm] } url = "{}/charger/faultList.json".format(self.ipPort) try: self.send_request_to_xf(url, [data]) except Exception as e: logger.error("device {} send to xiaofang fault {} error = {}".format(self._device.devNo, faultRecord.id, e)) return def send_to_xf_handle(self, faultRecord): # type:(FaultRecord) -> None """ 发送处理的结束的消息 :param faultRecord: :return: """ if not self._support: return logger.info("device <{}> send to liangxi xiaofang handle <{}>".format(self._device.devNo, faultRecord.id)) faultHandler = { "id": str(faultRecord.id), "platform": self._platform, "handleMemo": faultRecord.dealedDetail or u"故障已处理", "handleTime": faultRecord.dealedTime.strftime("%Y-%m-%d %H:%M:%S"), "handlerTel": self._dealer.username, "handleType": "1", "handlerName": self._dealer.nickname } url = "{}/charger/faultHandlerList.json".format(self.ipPort) try: self.send_request_to_xf(url, [faultHandler]) except Exception as e: logger.error( "device {} send to xiaofang handle {} error = {}".format(self._device.devNo, faultRecord.id, e)) return