# -*- coding: utf-8 -*- # !/usr/bin/env python import base64 import time import itsdangerous import requests import logging from django.conf import settings from apps.web.api.ft_north.models import FengTuTechnologyNorther from apps.web.constant import DeviceOnlineStatus from apps.web.device.models import Device, Group from apps.web.api.ft_north.constant import PORT_WORK_STATUS from apps.web.api.utils import bd09_to_gcj02, get_coordinates_and_nums logger = logging.getLogger(__name__) def get_coding_info_by_device(devNo): dev = Device.get_dev(devNo) box = dev.deviceAdapter try: devStatusDict = box.get_port_status() except: return codingInfos = list() for k,v in devStatusDict.items(): codingInfo = {} codingInfo['coding'] = k if v['status'] != PORT_WORK_STATUS.PORT_WORKING and v['status'] != PORT_WORK_STATUS.PORT_WORKING: v['status'] = PORT_WORK_STATUS.PORT_FAULT codingInfo['status'] = v['status'] codingInfos.append(codingInfo) return codingInfos def get_coding_info(devNo): """ 获取端口状态,先找缓存,缓存中没有直接从设备里拿 :param devNo: :return: """ ctrInfo = Device.get_dev_control_cache(devNo) codingInfo = [] if 'allPorts' not in ctrInfo: ctrInfo = get_coding_info_by_device(devNo) if ctrInfo: return ctrInfo else: return [{"coding":"0","status":0}] else: allPorts = ctrInfo.get('allPorts', 10) # allPorts 有的时候会为0, 这个时候强制设置为10 if allPorts == 0: allPorts = 10 for ii in range(allPorts): statusDict = {} tempDict = ctrInfo.get(str(ii + 1), {}) if tempDict.has_key('status'): statusDict['coding'] = str(ii + 1) statusDict['status'] = tempDict.get('status') elif tempDict.has_key('isStart'): if tempDict['isStart']: statusDict['coding'] = str(ii + 1) statusDict['status'] = PORT_WORK_STATUS.PORT_WORKING else: statusDict['coding'] = str(ii + 1) statusDict['status'] = PORT_WORK_STATUS.PORT_IDLE else: statusDict['coding'] = str(ii + 1) statusDict['status'] = PORT_WORK_STATUS.PORT_IDLE codingInfo.append(statusDict) return codingInfo def get_device_status(devNo): """ 获取设备状态 :param devNo: :return: """ dev = Device.get_dev(devNo) devOnline = dev.online if devOnline == DeviceOnlineStatus.DEV_STATUS_ONLINE: devStatus = '1' elif devOnline == DeviceOnlineStatus.DEV_STATUS_OFFLINE: devStatus = '0' else: devStatus = '-1' return devStatus def get_station_Info(groupIds): """ 推送站点信息 :param groupIds: :return: """ stationInfoList = list() groups = Group.get_groups_by_group_ids(groupIds) for group in groups.values(): # 获取经纬度 获取设备数量 经纬度使用火星坐标系转换 lng, lat, count = get_coordinates_and_nums(group.groupId) lng, lat = bd09_to_gcj02(lng, lat) stationInfoDict = { "stationId" : group.groupId, # 厂商站点ID "name" : group.groupName, # 充电站名称 "brand" : "", # 品牌名称 "longitude" : "{:.6f}".format(float(lng)), # 经度(6位小数), "latitude" : "{:.6f}".format(float(lat)), # 维度(6位小数) "address" : group.address, # 具体地址 "socketNumber" : 0, # 设备路数 "hasRainshed" : "", # 是否有雨棚 "hasMonitor" : "", # 是否覆盖视频监控 "fireFacilities" : "", # 是否配置消防设施 "buildingTime" : group.get('dateTimeAdded').get('val').split(" ")[0], # 建设时间 "picture" : "", # 站点图片 "deviceList" : get_dev_info([group.groupId],group), # 站点下的设备列表 } stationInfoList.append(stationInfoDict) return stationInfoList def get_dev_info(groupIds,group): devices = Device.get_devices_by_group(groupIds) deviceInfo = list() for devNo,devInfo in devices.items(): devDict = { 'stationId':groupIds[0], # 厂商站点ID 'deviceNo':devNo, # 设备编号 'deviceType':devInfo['devType']["majorDeviceType"], # 设备类型:充电柜、充电桩、桩柜一体、摄像头、烟感、消防器(栓)、喷淋 'simCardNo':"", # SIM卡号 'wateringPortNum':"", # 浇水口数量 'brand':devInfo['devType']["name"], # 品牌名称 'useStationInfo':1, # 是否与充电站公用一个位置: 0.否, 1.是 'deviceLocation':group.address, # 设备地址,省市区街道+详细地址 'longitude':devInfo['lng'], # 径度 'latitude':devInfo['lat'], # 纬度 'socketNumber':Device.get_dev_control_cache(devNo).get('allPorts'), # 设备路数,充电口数量 'buildingYear':devInfo['dateTimeAdded'].split('-')[0] # 建设年份,格式:yyyy } deviceInfo.append(devDict) return deviceInfo def send_request(url,mode='POST',**kwargs): """ 主动发送HTTP请求获取数据 密钥及签名 :return: """ headers = {"Content-Type": "application/json;charset=utf-8"} token = kwargs.pop("token", None) if token:headers.update({"Authorization": "Basic {}".format(token)}) timeout = kwargs.pop("timeout", 5) data = kwargs try: if mode == 'POST': response = requests.post(url=url, json=data, headers=headers, timeout=timeout) else: response = requests.get(url=url, headers=headers, timeout=timeout) except requests.Timeout: return dict() except Exception as e: logger.exception(e) return dict() if response.status_code != 200: return dict() return response.json() def get_token(norther): # if norther.token and norther.tokenExpiredTime > int(time.time()) * 1000: # return norther.token timestamp = int(time.time()*1000) url = norther.join_url("getToken") sign = norther.get_sig(timestamp) result = send_request(url,appid=norther.appId,timestamp=timestamp,sign=sign) ret = result.get("code") logger.info(ret) if ret != 200: return responseJson = result.get("data") tokenAvailableTime = responseJson.get("expireTime", 120) token = responseJson.get("token", "") # 数据库更新 # norther.update( # token=token, # tokenExpiredTime=tokenAvailableTime # ) # # norther.save() return token def get_station_Info_manage(groupId): """ 推送站点信息 :param groupId: :return: """ group = Group.get_group(groupId) # 获取经纬度 获取设备数量 经纬度使用火星坐标系转换 lng, lat, count = get_coordinates_and_nums(group.groupId) lng, lat = bd09_to_gcj02(lng, lat) stationInfoDict = { "stationId" : group.groupId, # 厂商站点ID "name" : group.groupName, # 充电站名称 "chargingType":"", # 充电站类型 "brand":"", "longitude":lng, "latitude":lat, "address":group.address, "socketNumber":0, "hasRainshed":"", "hasMonitor":"", "fireFacilities":"", "buildingTime":group.get('dateTimeAdded').strftime('%Y-%m-%d'), "picture":"", } return stationInfoDict def get_device_info_manage(devNo): dev = Device.get_dev(devNo) deviceInfo = { "stationId":dev["groupId"], # 厂商站点ID "deviceNo":devNo, # 设备编号 "deviceType":dev['devType']["majorDeviceType"], # 设备类型 "brand":dev['devType']["name"], # 品牌名称 "deviceLocation":Group.get_group(dev["groupId"]).get("address"), # 设备地址 "longitude":dev['lng'], # 经度 "latitude":dev['lat'], # 纬度 "socketNumber":Device.get_dev_control_cache(devNo).get('allPorts',10), # 设备路数 } return deviceInfo def get_alarm_report(devNo,alarmType): dev = Device.get_dev(devNo) data = { "stationId":dev.get('groupId'), # 充电站编号 "deviceNo" : devNo, "codingNo" : "", "eventId" : base64.b64encode(dev.get('groupId')+devNo+str(time.time())), "outSourceId" : "", "alarmType":alarmType } return data def generate_json_token(data, expire=None): salt = settings.FENG_TU_TOKEN_SECRET its = itsdangerous.TimedJSONWebSignatureSerializer(salt, expire) return its.dumps(data) def parse_json_token(s, expire=None): salt = settings.FENG_TU_TOKEN_SECRET its = itsdangerous.TimedJSONWebSignatureSerializer(salt, expire) try: result = its.loads(s) except itsdangerous.BadData: return dict() return result def batchStationInfoReport(groupIds): """ 主动推送站点信息 :param groupIds: :return: """ try: north = FengTuTechnologyNorther.objects.filter().first() data = get_station_Info(groupIds) url = north.join_url("batchStationInfo") token = get_token(north) return send_request(url=url, token=token, stationInfoList=data) except Exception as e: logger.exception(e) def addStationReport(groupId): try: north = FengTuTechnologyNorther.objects.filter().first() data = get_station_Info_manage(groupId) url = north.join_url("station/add") token = get_token(north) return send_request(url=url, token=token, **data) except Exception as e: logger.exception(e) def deleteStationReport(groupId): try: north = FengTuTechnologyNorther.objects.filter().first() data = groupId url = north.join_url("station/delete/{}".format(data)) token = get_token(north) return send_request(url=url, mode='GET', token=token) except Exception as e: logger.exception(e) def updateStationReport(groupId): try: north = FengTuTechnologyNorther.objects.filter().first() data = get_station_Info_manage(groupId) url = north.join_url("station/update") token = get_token(north) return send_request(url=url, token=token, **data) except Exception as e: logger.exception(e) def addDeviceReport(devNo): try: north = FengTuTechnologyNorther.objects.filter().first() data = get_device_info_manage(devNo) url = north.join_url("device/add") token = get_token(north) return send_request(url=url, token=token, **data) except Exception as e: logger.exception(e) def deleteDeviceReport(devNo): try: north = FengTuTechnologyNorther.objects.filter().first() groupId = Device.get_dev(devNo).get("groupId") url = north.join_url("device/delete/{}/{}".format(groupId,devNo)) token = get_token(north) return send_request(url=url, mode='GET', token=token) except Exception as e: logger.exception(e) def updateDeviceReport(devNo): try: north = FengTuTechnologyNorther.objects.filter().first() data = get_device_info_manage(devNo) url = north.join_url("device/update") token = get_token(north) return send_request(url=url, token=token, **data) except Exception as e: logger.exception(e) def devHeartbeatReport(devNo): try: data = { "deviceNo":devNo, "deviceStatus":get_device_status(devNo), "codings":get_coding_info(devNo), "eventId": base64.b64encode(devNo+str(time.time())) } north = FengTuTechnologyNorther.objects.filter().first() url = north.join_url("device/heartbeat") token = get_token(north) send_request(url=url, token=token, **data) except Exception as e: logger.exception(e) def alarmReport(devNo,faultName): try: north = FengTuTechnologyNorther.objects.filter().first() data = get_alarm_report(devNo,faultName) url = north.join_url("alarm") token = get_token(north) send_request(url=url, token=token, **data) except Exception as e: logger.exception(e)