aoqiang.py 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import time
  6. from django.core.cache import caches
  7. from typing import Optional, Dict, TYPE_CHECKING
  8. from apilib.utils_datetime import timestamp_to_dt
  9. from apps.web.agent.models import Agent
  10. from apps.web.constant import DeviceCmdCode, Const, MQTT_TIMEOUT
  11. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, start_error_timer
  12. from apps.web.core.exceptions import ServiceException
  13. from apps.web.core.networking import MessageSender
  14. from apps.web.dealer.models import Dealer
  15. from apps.web.device.models import Device, Group, DeviceType
  16. from apps.web.core.device_define.jndz import CMD_CODE
  17. from apps.web.user.models import MyUser
  18. from taskmanager.mediator import task_caller
  19. if TYPE_CHECKING:
  20. from apps.web.api.models import APIStartDeviceRecord
  21. logger = logging.getLogger(__name__)
  22. class ChargingAOQIANGBox(SmartBox):
  23. """
  24. 久恒协议和劲能一致,业务修改和功能扩充需要确定是否两边都修改
  25. """
  26. def __init__(self, device):
  27. super(ChargingAOQIANGBox, self).__init__(device)
  28. @property
  29. def isHaveStopEvent(self):
  30. return True
  31. def translate_funcode(self, funCode):
  32. funCodeDict = {
  33. '01': u'获取端口数量',
  34. '02': u'获取端口数据',
  35. '14': u'移动支付',
  36. '07': u'获取刷卡投币统计数据',
  37. '15': u'获取设备端口详情',
  38. '0F': u'获取端口状态',
  39. '0C': u'端口锁操作',
  40. '0D': u'端口开关',
  41. '1E': u'获取设备设置',
  42. '18': u'设置设备参数',
  43. '10': u'回复卡余额',
  44. }
  45. return funCodeDict.get(funCode, '')
  46. def translate_event_cmdcode(self, cmdCode):
  47. cmdDict = {
  48. '06': u'充电结束',
  49. '16': u'充电结束',
  50. '0A': u'故障',
  51. '10': u'刷卡上报',
  52. '20': u'启动设备',
  53. }
  54. return cmdDict.get(cmdCode, '')
  55. def test(self, coins):
  56. hexElec = fill_2_hexByte(hex(0), 4)
  57. hexPort = fill_2_hexByte(hex(1), 2)
  58. hexCoins = fill_2_hexByte(hex(1))
  59. hexTime = fill_2_hexByte(hex(60))
  60. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  61. {'IMEI': self._device['devNo'], "funCode": '14',
  62. 'data': hexPort + hexCoins + hexTime + hexElec})
  63. return devInfo
  64. def stop(self, port = None):
  65. infoDict = self.stop_charging_port(port)
  66. infoDict['remainder_time'] = infoDict['leftTime']
  67. return infoDict
  68. @start_error_timer(missMessages = [u"请您选择合适的充电线路、电池类型信息", u"请您选择合适的充电线路", u"该端口正在使用中"])
  69. def start_device(self, package, openId, attachParas):
  70. if attachParas is None:
  71. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  72. if not attachParas.has_key('chargeIndex'):
  73. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  74. devConf = caches['devmgr'].get('settingConf_%s' % (self._device['devNo']))
  75. if devConf is None:
  76. conf = self.get_dev_setting()
  77. caches['devmgr'].set('settingConf_%s' % (self._device['devNo']), conf, 24 * 3600)
  78. coinElec = conf.get('coinElec', 0.9)
  79. refundProtection = conf.get('refundProtection', 0)
  80. refundProtectionTime = conf.get('refundProtectionTime', 5)
  81. lowPowerDetectionTime = conf.get('lowPowerDetectionTime', 60)
  82. lowPowerDetectionSwitch = conf.get('lowPowerDetectionSwitch', 0)
  83. else:
  84. coinElec = devConf.get('coinElec', 0.9)
  85. refundProtection = devConf.get('refundProtection', 0)
  86. refundProtectionTime = devConf.get('refundProtectionTime', 5)
  87. lowPowerDetectionTime = devConf.get('lowPowerDetectionTime', 60)
  88. lowPowerDetectionSwitch = devConf.get('lowPowerDetectionSwitch', 0)
  89. price = float(package['price'])
  90. port = hex(int(attachParas['chargeIndex']))
  91. hexPort = fill_2_hexByte(port, 2)
  92. coins = float(package['coins'])
  93. hexCoins = fill_2_hexByte(hex(int(coins * 10))) # 注意单位是角
  94. needElec = round((coins * coinElec) / 10.0, 2) # 单位是0.01度电(配置中每次投币的最大用电量单位却是0.1度电,这里要乘以10)
  95. hexElec = fill_2_hexByte(hex(int(needElec * 100)), 4)
  96. unit = package.get('unit', u'分钟')
  97. needTime = int(package['time'])
  98. if unit in [u'分钟', u'小时', u'天']:
  99. billingType = 'time'
  100. if unit == u'小时':
  101. needTime = int(package['time']) * 60
  102. elif unit == u'天':
  103. needTime = int(package['time']) * 1440
  104. hexTime = fill_2_hexByte(hex(needTime))
  105. elif unit == u'度':
  106. billingType = 'elec'
  107. needElec = round((package['time']), 2)
  108. hexElec = fill_2_hexByte(hex(int(needElec * 100)), 4)
  109. hexTime = fill_2_hexByte(hex(12 * 60))
  110. else:
  111. billingType = 'elec'
  112. devObj = Device.objects.get(devNo = self._device['devNo'])
  113. elecFee = float(devObj.otherConf.get('elecFee', 0.9))
  114. needElec = round(min(float(coins / elecFee), needElec), 2)
  115. hexElec = fill_2_hexByte(hex(int(needElec * 100)), 4)
  116. hexTime = fill_2_hexByte(hex(12 * 60))
  117. # 在启动设备前,如果可能是续充,需要获取下设备端口状态,便于后面核实。防止结束报文丢包导致数据不准确
  118. # 重新把设备上的状态取回来,可以保证needTime数据不出错,正在服务显示也不会有问题
  119. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  120. lastPortInfo = ctrInfo.get(str(attachParas['chargeIndex']), None)
  121. if (lastPortInfo is not None) and lastPortInfo.get('status', '') == Const.DEV_WORK_STATUS_WORKING:
  122. self.get_port_status_from_dev()
  123. orderNo = attachParas.get('orderNo')
  124. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  125. 'IMEI': self._device['devNo'],
  126. "funCode": '14',
  127. 'data': hexPort + hexCoins + hexTime + hexElec
  128. }, timeout = MQTT_TIMEOUT.START_DEVICE)
  129. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  130. if devInfo['rst'] == -1:
  131. raise ServiceException(
  132. {
  133. 'result': 2,
  134. 'description': u'充电桩正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'
  135. }
  136. )
  137. elif devInfo['rst'] == 1:
  138. self.check_serial_port_for_startcmd(attachParas['chargeIndex'])
  139. data = devInfo['data'][6::]
  140. if data[0:2] == '01': # 表示成功
  141. pass
  142. else:
  143. raise ServiceException({'result': 2, 'description': u'获取端口数据失败,请重试看能否解决'})
  144. usePort = int(attachParas['chargeIndex'])
  145. result = data[4:6]
  146. if result == '01': # 成功
  147. pass
  148. elif result == '0B':
  149. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'充电站故障'}}
  150. Device.update_dev_control_cache(self._device['devNo'], newValue)
  151. raise ServiceException({'result': 2, 'description': u'充电站故障'})
  152. elif result == '0C':
  153. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_WORKING, 'statusInfo': u''}}
  154. Device.update_dev_control_cache(self._device['devNo'], newValue)
  155. raise ServiceException({'result': 2, 'description': u'该端口正在使用中'})
  156. start_timestamp = int(time.time())
  157. portDict = {
  158. 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'),
  159. 'status': Const.DEV_WORK_STATUS_WORKING,
  160. 'coins': float(coins),
  161. 'isStart': True,
  162. 'price': price,
  163. 'openId': openId, 'refunded': False,
  164. 'billingType': billingType,
  165. 'refundProtection': refundProtection,
  166. 'refundProtectionTime': refundProtectionTime,
  167. 'vCardId': self._vcard_id
  168. }
  169. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  170. lastPortInfo = ctrInfo.get(str(usePort), None)
  171. if lastPortInfo is not None and lastPortInfo.get('status', '') == Const.DEV_WORK_STATUS_WORKING:
  172. if lastPortInfo.has_key('coins'):
  173. portDict['coins'] = float(coins) + lastPortInfo['coins']
  174. if lastPortInfo.has_key('price'):
  175. portDict['price'] = price + lastPortInfo['price']
  176. if unit in [u'分钟', u'小时', u'天']:
  177. portDict.update({'needTime': needTime, 'needElec': needElec})
  178. if (lastPortInfo is not None) and lastPortInfo.get('status', '') == Const.DEV_WORK_STATUS_WORKING:
  179. if lastPortInfo.has_key('needTime'):
  180. portDict['needTime'] = needTime + lastPortInfo['needTime']
  181. if lastPortInfo.has_key('needElec'):
  182. portDict['needElec'] = needElec + lastPortInfo['needElec']
  183. finishedTime = int(time.time()) + portDict['needTime'] * 60
  184. else:
  185. portDict.update({'needElec': needElec})
  186. if (lastPortInfo is not None) and lastPortInfo.has_key('needElec') and lastPortInfo.get('status',
  187. '') == Const.DEV_WORK_STATUS_WORKING:
  188. lastPortInfo['needElec'] = needElec + lastPortInfo['needElec']
  189. finishedTime = 12 * 60 * 60
  190. if attachParas.has_key('orderNo'):
  191. portDict.update({'orderNo': attachParas['orderNo']})
  192. if 'extOrderNo' in attachParas:
  193. portDict['extOrderNo'] = attachParas.get('extOrderNo')
  194. devInfo['finishedTime'] = finishedTime
  195. portDict.update({'finishedTime': finishedTime})
  196. Device.update_dev_control_cache(self._device['devNo'], {str(usePort): portDict})
  197. # begin: 低功率检测逻辑
  198. try:
  199. if lowPowerDetectionSwitch == 1:
  200. if openId is not None:
  201. user = MyUser.objects(openId = openId, groupId = self._device['groupId']).first()
  202. dealer = Dealer.get_dealer_from_groupId(self._device['groupId'])
  203. port = str(attachParas['chargeIndex'])
  204. self.notify_low_power_to_user(user, dealer, port, int(lowPowerDetectionTime))
  205. except Exception as e:
  206. logger.error(e)
  207. # end: 低功率检测逻辑
  208. return devInfo
  209. def start_from_api(self, record):
  210. # type: (APIStartDeviceRecord)->Optional[Dict]
  211. if 'chargeIndex' not in record.attachParas:
  212. from apps.web.api.exceptions import ApiParameterError
  213. raise ApiParameterError(u'请传入充电桩端口号chargeIndex参数')
  214. return super(ChargingAOQIANGBox, self).start_from_api(record)
  215. def analyze_event_data(self, data):
  216. cmdCode = data[4:6]
  217. #: 提交充电结束状态 (06)
  218. #: 老版本
  219. if cmdCode == CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_06:
  220. port = int(data[8:10], 16)
  221. leftTime = int(data[10:14], 16)
  222. reasonCode = data[14:16]
  223. desc_map = {
  224. '00': u'购买的充电时间或电量用完了。',
  225. '01': u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。',
  226. '02': u'恭喜您!电池已经充满电!',
  227. '0B': u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
  228. }
  229. return {
  230. 'status': Const.DEV_WORK_STATUS_IDLE,
  231. 'cmdCode': cmdCode,
  232. 'port': port,
  233. 'leftTime': leftTime,
  234. 'reason': desc_map[reasonCode],
  235. 'reasonCode': reasonCode
  236. }
  237. #: (高版本的) 提交充电结束状态 (16)
  238. elif cmdCode == CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_v2_16:
  239. port = int(data[8:10], 16)
  240. leftTime = int(data[10:14], 16)
  241. elec = int(data[14:18], 16) / 100.0
  242. reasonCode = data[18:20]
  243. desc_map = {
  244. '00': u'购买的充电时间或电量用完了。',
  245. '01': u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。',
  246. '02': u'恭喜您!电池已经充满电!',
  247. '03': u'警告!您的电池超功率,已经停止充电,为了公共安全,不建议您在该充电桩充电!提醒您,为了安全大功率的电池不要放入楼道、室内等位置充电哦',
  248. '04': u'远程断电。',
  249. '0B': u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
  250. }
  251. desc = desc_map.get(reasonCode, u'电池没有充满!原因未知。')
  252. return {
  253. 'status': Const.DEV_WORK_STATUS_IDLE,
  254. 'cmdCode': cmdCode,
  255. 'port': port,
  256. 'leftTime': leftTime,
  257. 'elec': elec,
  258. 'reason': desc,
  259. 'reasonCode': reasonCode
  260. }
  261. #: 上传设备故障
  262. elif cmdCode == CMD_CODE.DEVICE_SUBMIT_DEVICE_FAULT_0A:
  263. port = int(data[8:10], 16)
  264. errCode = str(data[10:12]).upper()
  265. desc = u'设备故障'
  266. if errCode == 'A0':
  267. desc = u'停止充电异常,可能是继电器粘连、短路'
  268. elif errCode == 'A1':
  269. desc = u'高温'
  270. elif errCode == 'A2':
  271. desc = u'低温'
  272. elif errCode == 'A3':
  273. desc = u'空载'
  274. elif errCode == 'A4':
  275. desc = u'消防(烟感)'
  276. elif errCode == 'A5':
  277. desc = u'过载'
  278. elif errCode == 'A6':
  279. desc = u'倾斜'
  280. elif errCode == 'A7':
  281. desc = u'水压高'
  282. elif errCode == 'A8':
  283. desc = u'水压低'
  284. elif errCode == 'A9':
  285. desc = u'过压'
  286. elif errCode == 'AA':
  287. desc = u'欠压'
  288. return {
  289. 'status': Const.DEV_WORK_STATUS_FAULT,
  290. 'statusInfo': desc,
  291. 'cmdCode': cmdCode,
  292. 'port': port,
  293. 'FaultCode': errCode
  294. }
  295. # 用户刷卡上报的信息
  296. #: 在线卡上传卡号,预扣费
  297. #: 示例:
  298. #: CARD_ID CARD_CST CARD_OPE
  299. #: 0x00000000 0x00 0x00
  300. #: 参数
  301. #: CARD_ID : IC 卡卡号
  302. #: CARD_SURP: 卡片需要改变的金额信息(以角为单位)
  303. #: CARD_OPE: 0x00 是扣费(减少),0x01 是充值(增加)。
  304. #: 回复
  305. #: RES: 0x00,表示扣费成功,0x01 表示余额不足,0x02 表示非法卡。
  306. #: CARD_SURP: 表示卡余额(以角为单位)。
  307. elif cmdCode == CMD_CODE.SWIPE_CARD_10:
  308. group = Group.get_group(self._device['groupId'])
  309. dealer = Dealer.get_dealer(group['ownerId'])
  310. agent = Agent.objects(id=dealer['agentId']).first()
  311. device = Device.objects(devNo=self._device['devNo']).first()
  312. devType = DeviceType.objects(id=device['devType']['id']).first()
  313. cardNo = str(int(data[8:16], 16))
  314. # 兼容以前的老代码, 先走以前的老代码, 如果有新代码再走新的.
  315. if agent is not None and 'cardNoReverse' in agent.features:
  316. cardData = data[14:16] + data[12:14] + data[10:12] + data[8:10]
  317. cardNo = str(int(cardData, 16))
  318. if 'cardNoReverse' in devType.features:
  319. if devType.features['cardNoReverse'] is True:
  320. cardData = data[14:16] + data[12:14] + data[10:12] + data[8:10]
  321. cardNo = str(int(cardData, 16))
  322. else:
  323. cardNo = str(int(data[8:16], 16))
  324. else:
  325. pass
  326. #: 卡里的余额,以角为单位
  327. preFee = int(data[16:18], 16) / 10.0
  328. #: 操作符 00(增加) | 01(减少)
  329. oper = data[18:20]
  330. return {'cardNo': cardNo, 'preFee': preFee, 'cmdCode': cmdCode, 'oper': oper}
  331. #: 上报投币打开的信息
  332. elif cmdCode == CMD_CODE.DEVICE_SUBMIT_OFFLINE_COINS_20: # 启动设备
  333. port = int(data[8:10], 16)
  334. needTime = int(data[10:14], 16)
  335. elec = int(data[14:18], 16) / 100.0
  336. consumeTypeTemp = data[18:20]
  337. if consumeTypeTemp == '00':
  338. consumeType = 'coin'
  339. elif consumeTypeTemp == '01':
  340. consumeType = 'card'
  341. elif consumeTypeTemp == '03':
  342. consumeType = 'server'
  343. else:
  344. consumeType = 'other'
  345. money = int(data[20:22], 16) / 10.0
  346. return {
  347. 'cmdCode': cmdCode,
  348. 'port': port,
  349. 'needTime': needTime,
  350. 'elec': elec,
  351. 'consumeType': consumeType,
  352. 'coins': money
  353. }
  354. # 4个故障的告警
  355. elif cmdCode == CMD_CODE.DEVICE_FAULT_FIRE:
  356. return {"cmdCode": cmdCode, "fault": u"火灾报警"}
  357. elif cmdCode == CMD_CODE.DEVICE_FAULT_SMOKE:
  358. return {"cmdCode": cmdCode, "fault": "烟雾报警"}
  359. elif cmdCode == CMD_CODE.DEVICE_FAULT_TEMPERATURE:
  360. return {"cmdCode": cmdCode, "fault": "温度超限告警"}
  361. elif cmdCode == CMD_CODE.DEVICE_FAULT_POWER:
  362. return {"cmdCode": cmdCode, "fault": "功率超线告警"}
  363. # 2个状态量上报
  364. elif cmdCode == CMD_CODE.DEVICE_ELEC:
  365. elec = int(data[8:12], 16)
  366. return {"cmdCode": cmdCode, "elec": elec}
  367. elif cmdCode == CMD_CODE.DEVICE_TEMPERATURE:
  368. temperature = int(data[8:12], 16)
  369. return {"cmdCode": cmdCode, "temperature": temperature}
  370. def get_dev_consume_count(self):
  371. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  372. {'IMEI': self._device['devNo'], "funCode": '07', 'data': '00'})
  373. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  374. if devInfo['rst'] == -1:
  375. raise ServiceException(
  376. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  377. elif devInfo['rst'] == 1:
  378. raise ServiceException(
  379. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  380. data = devInfo['data'][6::]
  381. if data[0:2] == '01': # 表示成功
  382. pass
  383. else:
  384. raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
  385. cardFee = int(data[2:6], 16) / 10.0 # 以角为单位
  386. coinFee = int(data[6:10], 16) # 以元为单位
  387. return {'cardFee': cardFee, 'coinFee': coinFee}
  388. def get_port_info(self, line):
  389. data = fill_2_hexByte(hex(int(line)), 2)
  390. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  391. {'IMEI': self._device['devNo'], "funCode": '15', 'data': data})
  392. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  393. if devInfo['rst'] == -1:
  394. raise ServiceException(
  395. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  396. elif devInfo['rst'] == 1:
  397. raise ServiceException(
  398. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  399. data = devInfo['data'][6::]
  400. if data[0:2] == '01': # 表示成功
  401. pass
  402. else:
  403. raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
  404. leftTime = int(data[4:8], 16)
  405. if data[8:12] == 'FFFF':
  406. power = 0
  407. else:
  408. power = int(data[8:12], 16)
  409. if data[12:16] == 'FFFF':
  410. elec = 0
  411. else:
  412. elec = int(data[12:16], 16)
  413. if data[16:20] == 'FFFF':
  414. surp = 0
  415. else:
  416. surp = int(data[16:20], 16)
  417. # return {'port':line,'leftTime':leftTime,'power':power,'leftElec':round(elec*0.01,2),'surp':surp}#剩余电量先不上,客户反馈有点不准
  418. return {'port': line, 'leftTime': leftTime, 'power': power, 'surp': surp}
  419. def get_port_status(self, force = False):
  420. if force:
  421. return self.get_port_status_from_dev()
  422. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  423. statusDict = {}
  424. if not ctrInfo.has_key('allPorts'):
  425. self.get_port_status_from_dev()
  426. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  427. allPorts = ctrInfo.get('allPorts', 10)
  428. # allPorts 有的时候会为0, 这个时候强制设置为10
  429. if allPorts == 0:
  430. allPorts = 10
  431. for ii in range(allPorts):
  432. tempDict = ctrInfo.get(str(ii + 1), {})
  433. if tempDict.has_key('status'):
  434. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  435. elif tempDict.has_key('isStart'):
  436. if tempDict['isStart']:
  437. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  438. else:
  439. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  440. else:
  441. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  442. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  443. Device.update_dev_control_cache(self._device['devNo'],
  444. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  445. return statusDict
  446. def get_port_status_from_dev(self):
  447. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  448. {'IMEI': self._device['devNo'], "funCode": '0F', 'data': '00'})
  449. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  450. if devInfo['rst'] == -1:
  451. raise ServiceException(
  452. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  453. elif devInfo['rst'] == 1:
  454. raise ServiceException(
  455. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  456. data = devInfo['data'][6::]
  457. if data[0:2] == '01': # 表示成功
  458. pass
  459. else:
  460. raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
  461. result = {}
  462. portNum = int(data[2:4], 16)
  463. portData = data[4::]
  464. ii = 0
  465. while ii < portNum:
  466. port = int(portData[ii * 4:ii * 4 + 2], 16)
  467. statusTemp = portData[ii * 4 + 2:ii * 4 + 4]
  468. if statusTemp == '01':
  469. status = {'status': Const.DEV_WORK_STATUS_IDLE}
  470. elif statusTemp == '02':
  471. status = {'status': Const.DEV_WORK_STATUS_WORKING}
  472. elif statusTemp == '03':
  473. status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN}
  474. elif statusTemp == '04':
  475. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  476. ii += 1
  477. result[str(port)] = status
  478. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  479. Device.update_dev_control_cache(self._device['devNo'],
  480. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  481. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  482. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  483. for strPort, info in result.items():
  484. if ctrInfo.has_key(strPort):
  485. ctrInfo[strPort].update({'status': info['status']})
  486. else:
  487. ctrInfo[strPort] = info
  488. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  489. return result
  490. def lock_unlock_port(self, port, lock = True):
  491. lockStr = '00' if lock else '01'
  492. portStr = fill_2_hexByte(hex(int(port)), 2)
  493. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  494. {'IMEI': self._device['devNo'], "funCode": '0C', 'data': portStr + lockStr})
  495. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  496. if devInfo['rst'] == -1:
  497. raise ServiceException(
  498. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  499. elif devInfo['rst'] == 1:
  500. raise ServiceException(
  501. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  502. data = devInfo['data'][6::]
  503. if data[0:2] == '01': # 表示成功
  504. pass
  505. else:
  506. raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
  507. if lock:
  508. Device.update_dev_control_cache(self._device['devNo'],
  509. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  510. else:
  511. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  512. def active_deactive_port(self, port, active):
  513. if not active:
  514. self.stop_charging_port(port)
  515. devInfo = Device.get_dev_control_cache(self._device['devNo'])
  516. portCtrInfo = devInfo.get(str(port), {})
  517. portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE,
  518. 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  519. newValue = {str(port): portCtrInfo}
  520. Device.update_dev_control_cache(self._device['devNo'], newValue)
  521. else:
  522. raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'})
  523. def stop_charging_port(self, port):
  524. portStr = fill_2_hexByte(hex(int(port)), 2)
  525. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  526. {'IMEI': self._device['devNo'], "funCode": '0D', 'data': portStr + '00'})
  527. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  528. if devInfo['rst'] == -1:
  529. raise ServiceException(
  530. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  531. elif devInfo['rst'] == 1:
  532. raise ServiceException(
  533. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  534. data = devInfo['data'][6::]
  535. if data[0:2] == '01': # 表示成功
  536. pass
  537. else:
  538. raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
  539. port = int(data[2:4], 16)
  540. leftTime = int(data[4:8], 16)
  541. return {'port': port, 'leftTime': leftTime}
  542. # 获取设备配置参数
  543. def get_dev_setting(self):
  544. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  545. {'IMEI': self._device['devNo'], "funCode": '1E', 'data': '00'})
  546. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  547. if devInfo['rst'] == -1:
  548. raise ServiceException(
  549. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  550. elif devInfo['rst'] == 1:
  551. raise ServiceException(
  552. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  553. data = devInfo['data'][6::]
  554. if data[0:2] == '01': # 表示成功
  555. pass
  556. else:
  557. raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
  558. confData = data[2:-2]
  559. coinMin = int(confData[0:4], 16)
  560. cardMin = int(confData[4:8], 16)
  561. coinElec = int(confData[8:10], 16)
  562. cardElec = int(confData[10:12], 16)
  563. cst = int(confData[12:14], 16)
  564. powerMax1 = int(confData[14:18], 16)
  565. powerMax2 = int(confData[18:22], 16)
  566. powerMax3 = int(confData[22:26], 16)
  567. powerMax4 = int(confData[26:30], 16)
  568. power2Ti = int(confData[30:32], 16)
  569. power3Ti = int(confData[32:34], 16)
  570. power4Ti = int(confData[34:36], 16)
  571. spRecMon = int(confData[36:38], 16)
  572. spFullEmpty = int(confData[38:40], 16)
  573. fullPowerMin = int(confData[40:42], 16)
  574. fullChargeTime = int(confData[42:44], 16) * 10
  575. elecTimeFirst = int(confData[44:46], 16)
  576. dev = Device.objects.get(devNo = self._device['devNo'])
  577. billingType = dev.otherConf.get('billingType', 'time')
  578. elecFee = dev.otherConf.get('elecFee', 0.9)
  579. refundProtection = dev.otherConf.get('refundProtection', 0)
  580. refundProtectionTime = dev.otherConf.get('refundProtectionTime', 5)
  581. lowPowerDetectionTime = dev.otherConf.get('lowPowerDetectionTime', 60)
  582. lowPowerDetectionSwitch = dev.otherConf.get('lowPowerDetectionSwitch', 0)
  583. lowPowerDetectionPower = dev.otherConf.get('lowPowerDetectionPower', 50)
  584. # 为了预防万一,这里顺便把数据库的数据也更新一下,主要是以设备为准的数据,更新下
  585. dev.otherConf.update({'cardMin': cardMin})
  586. try:
  587. dev.save()
  588. except Exception, e:
  589. pass
  590. resultDict = {
  591. 'coinMin': coinMin,
  592. 'cardMin': cardMin,
  593. 'coinElec': coinElec,
  594. 'cardElec': cardElec,
  595. 'cst': cst,
  596. 'powerMax1': powerMax1,
  597. 'powerMax2': powerMax2,
  598. 'powerMax3': powerMax3,
  599. 'powerMax4': powerMax4,
  600. 'power2Ti': power2Ti,
  601. 'power3Ti': power3Ti,
  602. 'power4Ti': power4Ti,
  603. 'spRecMon': spRecMon,
  604. 'spFullEmpty': spFullEmpty,
  605. 'fullPowerMin': fullPowerMin,
  606. 'fullChargeTime': fullChargeTime,
  607. 'elecTimeFirst': elecTimeFirst,
  608. 'billingType': billingType,
  609. 'elecFee': elecFee,
  610. 'refundProtection': refundProtection,
  611. 'refundProtectionTime': refundProtectionTime,
  612. 'lowPowerDetectionTime': lowPowerDetectionTime,
  613. 'lowPowerDetectionSwitch': lowPowerDetectionSwitch,
  614. 'lowPowerDetectionPower': lowPowerDetectionPower
  615. }
  616. consumeInfo = self.get_dev_consume_count()
  617. resultDict.update(consumeInfo)
  618. setting2Info = self.get_dev_settings2()
  619. resultDict.update(setting2Info)
  620. return resultDict
  621. # 设置设备配置参数
  622. def set_dev_setting(self, setConf):
  623. data = ''
  624. data += fill_2_hexByte(hex(int(setConf['coinMin'])), 4)
  625. data += fill_2_hexByte(hex(int(setConf['cardMin'])), 4)
  626. data += fill_2_hexByte(hex(int(setConf['coinElec'])), 2)
  627. data += fill_2_hexByte(hex(int(setConf['cardElec'])), 2)
  628. data += fill_2_hexByte(hex(int(setConf['cst'])), 2)
  629. data += fill_2_hexByte(hex(int(setConf['powerMax1'])), 4)
  630. data += fill_2_hexByte(hex(int(setConf['powerMax2'])), 4)
  631. data += fill_2_hexByte(hex(int(setConf['powerMax3'])), 4)
  632. data += fill_2_hexByte(hex(int(setConf['powerMax4'])), 4)
  633. data += fill_2_hexByte(hex(int(setConf['power2Ti'])), 2)
  634. data += fill_2_hexByte(hex(int(setConf['power3Ti'])), 2)
  635. data += fill_2_hexByte(hex(int(setConf['power4Ti'])), 2)
  636. data += fill_2_hexByte(hex(int(setConf['spRecMon'])), 2)
  637. data += fill_2_hexByte(hex(int(setConf['spFullEmpty'])), 2)
  638. data += fill_2_hexByte(hex(int(setConf['fullPowerMin'])), 2)
  639. data += fill_2_hexByte(hex(int(setConf['fullChargeTime'])), 2)
  640. data += fill_2_hexByte(hex(int(setConf['elecTimeFirst'])), 2)
  641. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  642. {'IMEI': self._device['devNo'], "funCode": '18', 'data': data})
  643. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  644. if devInfo['rst'] == -1:
  645. raise ServiceException(
  646. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  647. elif devInfo['rst'] == 1:
  648. raise ServiceException(
  649. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  650. data = devInfo['data'][6::]
  651. if data[0:2] == '01': # 表示成功
  652. dev = Device.objects.get(devNo = self._device['devNo'])
  653. dev.otherConf.update({'billingType': setConf['billingType']})
  654. dev.otherConf.update({'elecFee': setConf['elecFee']})
  655. dev.otherConf.update({'refundProtection': setConf['refundProtection']})
  656. dev.otherConf.update({'refundProtectionTime': setConf['refundProtectionTime']})
  657. dev.otherConf.update({'cardMin': setConf['cardMin']})
  658. dev.otherConf.update({'lowPowerDetectionTime': setConf['lowPowerDetectionTime']})
  659. dev.otherConf.update({'lowPowerDetectionSwitch': setConf['lowPowerDetectionSwitch']})
  660. dev.otherConf.update({'lowPowerDetectionPower': setConf['lowPowerDetectionPower']})
  661. dev.save()
  662. else:
  663. raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
  664. # 设置额外的参数
  665. def set_dev_setting2(self, setConf):
  666. data = fill_2_hexByte(hex(int(setConf['stopDelay'])), 2)
  667. data += fill_2_hexByte(hex(int(setConf['maxTotalTime']) / 10), 2)
  668. data += fill_2_hexByte(hex(int(setConf['overVoltage'])), 4)
  669. data += fill_2_hexByte(hex(int(setConf['lowVoltage'])), 4)
  670. data += fill_2_hexByte(hex(int(setConf['overTemp'])), 2)
  671. data += fill_2_hexByte(hex(int(setConf['overTempDelayTime'])), 2)
  672. data += str(setConf['timeDspOn']).replace(':', '')
  673. data += str(setConf['timeDspOff']).replace(':', '')
  674. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  675. {'IMEI': self._device['devNo'], "funCode": '22', 'data': data})
  676. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  677. if devInfo['rst'] == -1:
  678. raise ServiceException(
  679. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  680. elif devInfo['rst'] == 1:
  681. raise ServiceException(
  682. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  683. def get_dev_settings2(self):
  684. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  685. {'IMEI': self._device['devNo'], "funCode": '23', 'data': '00'})
  686. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  687. if devInfo['rst'] == -1:
  688. raise ServiceException(
  689. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  690. elif devInfo['rst'] == 1:
  691. raise ServiceException(
  692. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  693. data = devInfo['data']
  694. result = {}
  695. result['stopDelay'] = int(data[8:10], 16)
  696. result['maxTotalTime'] = int(data[10:12], 16) * 10
  697. result['overVoltage'] = int(data[12:16], 16)
  698. result['lowVoltage'] = int(data[16:20], 16)
  699. result['overTemp'] = int(data[20:22], 16)
  700. result['overTempDelayTime'] = int(data[22:24], 16)
  701. # 处理返回数据为 'HH:MM' 格式的字符串
  702. timeDspOn = int(data[24:28]) if data[24:28].isdigit() is True else None
  703. timeDspOff = int(data[28:32]) if data[28:32].isdigit() is True else None
  704. timeDspOnList = list(str(timeDspOn))
  705. timeDspOffList = list(str(timeDspOff))
  706. timeDspOnList.insert(-2, ':')
  707. timeDspOffList.insert(-2, ':')
  708. result['timeDspOn'] = ''.join(timeDspOnList) if len(timeDspOnList) == 5 else '0' + ''.join(timeDspOnList)
  709. result['timeDspOff'] = ''.join(timeDspOffList) if len(timeDspOffList) == 5 else '0' + ''.join(timeDspOffList)
  710. return result
  711. def response_use_card(self, res, balance):
  712. data = '55061001'
  713. data = data + res + fill_2_hexByte(hex(int(balance * 10)), 4)
  714. devInfo = MessageSender.send(device = self.device,
  715. cmd = DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
  716. payload = {
  717. 'IMEI': self._device['devNo'], "funCode": '10', 'data': data
  718. })
  719. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  720. if devInfo['rst'] == -1:
  721. raise ServiceException(
  722. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  723. elif devInfo['rst'] == 1: # 等于1的时候,说明服务器和远程模块通讯OK,响应已经收到,不需要异常处理
  724. pass
  725. def set_device_function_param(self, request, lastSetConf):
  726. coinMin = request.POST.get('coinMin', None)
  727. cardMin = request.POST.get('cardMin', None)
  728. coinElec = request.POST.get('coinElec', None)
  729. cardElec = request.POST.get('cardElec', None)
  730. cst = request.POST.get('cst', None)
  731. powerMax1 = request.POST.get('powerMax1', None)
  732. powerMax2 = request.POST.get('powerMax2', None)
  733. powerMax3 = request.POST.get('powerMax3', None)
  734. powerMax4 = request.POST.get('powerMax4', None)
  735. power2Ti = request.POST.get('power2Ti', None)
  736. power3Ti = request.POST.get('power3Ti', None)
  737. power4Ti = request.POST.get('power4Ti', None)
  738. spRecMon = request.POST.get('spRecMon', None)
  739. spFullEmpty = request.POST.get('spFullEmpty', None)
  740. fullPowerMin = request.POST.get('fullPowerMin', None)
  741. fullChargeTime = request.POST.get('fullChargeTime', None)
  742. elecTimeFirst = request.POST.get('elecTimeFirst', None)
  743. billingType = request.POST.get('billingType', None)
  744. elecFee = request.POST.get('elecFee', None)
  745. refundProtection = request.POST.get('refundProtection', None)
  746. refundProtectionTime = request.POST.get('refundProtectionTime', None)
  747. lowPowerDetectionTime = request.POST.get('lowPowerDetectionTime', None)
  748. lowPowerDetectionSwitch = request.POST.get('lowPowerDetectionSwitch', None)
  749. lowPowerDetectionPower = request.POST.get('lowPowerDetectionPower', None)
  750. # 这几个是参数是奥强特有的
  751. stopDelay = request.POST.get('stopDelay', None)
  752. maxTotalTime = request.POST.get('maxTotalTime', None)
  753. overVoltage = request.POST.get('overVoltage', None)
  754. lowVoltage = request.POST.get('lowVoltage', None)
  755. overTemp = request.POST.get('overTemp', None)
  756. overTempDelayTime = request.POST.get('overTempDelayTime', None)
  757. timeDspOn = request.POST.get('timeDspOn', None)
  758. timeDspOff = request.POST.get('timeDspOff', None)
  759. # 这几个参数是墨小智V3特有的
  760. stWTime = request.POST.get('stWTime', None)
  761. temThre = request.POST.get('temThre', None)
  762. freeUse = request.POST.get('freeUse', None)
  763. if coinMin:
  764. lastSetConf.update({'coinMin': int(coinMin)})
  765. if cardMin:
  766. lastSetConf.update({'cardMin': int(cardMin)})
  767. if coinElec:
  768. lastSetConf.update({'coinElec': int(coinElec)})
  769. if cardElec:
  770. lastSetConf.update({'cardElec': int(cardElec)})
  771. if cst:
  772. lastSetConf.update({'cst': int(cst)})
  773. if powerMax1:
  774. lastSetConf.update({'powerMax1': int(powerMax1)})
  775. if powerMax2:
  776. lastSetConf.update({'powerMax2': int(powerMax2)})
  777. if powerMax3:
  778. lastSetConf.update({'powerMax3': int(powerMax3)})
  779. if powerMax4:
  780. lastSetConf.update({'powerMax4': int(powerMax4)})
  781. if power2Ti:
  782. lastSetConf.update({'power2Ti': int(power2Ti)})
  783. if power3Ti:
  784. lastSetConf.update({'power3Ti': int(power3Ti)})
  785. if power4Ti:
  786. lastSetConf.update({'power4Ti': int(power4Ti)})
  787. if spRecMon:
  788. lastSetConf.update({'spRecMon': int(spRecMon)})
  789. if spFullEmpty:
  790. lastSetConf.update({'spFullEmpty': int(spFullEmpty)})
  791. if fullPowerMin:
  792. lastSetConf.update({'fullPowerMin': int(fullPowerMin)})
  793. if fullChargeTime:
  794. lastSetConf.update({'fullChargeTime': int(fullChargeTime)})
  795. if elecTimeFirst:
  796. lastSetConf.update({'elecTimeFirst': int(elecTimeFirst)})
  797. if billingType:
  798. lastSetConf.update({'billingType': billingType})
  799. if elecFee:
  800. lastSetConf.update({'elecFee': elecFee})
  801. if refundProtection:
  802. lastSetConf.update({'refundProtection': int(refundProtection)})
  803. if refundProtectionTime:
  804. lastSetConf.update({'refundProtectionTime': int(refundProtectionTime)})
  805. if lowPowerDetectionTime:
  806. lastSetConf.update({'lowPowerDetectionTime': int(lowPowerDetectionTime)})
  807. if lowPowerDetectionSwitch:
  808. lastSetConf.update({'lowPowerDetectionSwitch': int(lowPowerDetectionSwitch)})
  809. if lowPowerDetectionPower:
  810. lastSetConf.update({'lowPowerDetectionPower': int(lowPowerDetectionPower)})
  811. # 这几个参数是奥强特有的
  812. if stopDelay:
  813. lastSetConf.update({'stopDelay': stopDelay})
  814. if maxTotalTime:
  815. lastSetConf.update({'maxTotalTime': maxTotalTime})
  816. if overVoltage:
  817. lastSetConf.update({'overVoltage': overVoltage})
  818. if lowVoltage:
  819. lastSetConf.update({'lowVoltage': lowVoltage})
  820. if overTemp:
  821. lastSetConf.update({'overTemp': overTemp})
  822. if overTempDelayTime:
  823. lastSetConf.update({'overTempDelayTime': overTempDelayTime})
  824. if timeDspOn:
  825. lastSetConf.update({'timeDspOn': timeDspOn})
  826. if timeDspOff:
  827. lastSetConf.update({'timeDspOff': timeDspOff})
  828. # 这几个参数是墨小智V3特有的
  829. if stWTime:
  830. lastSetConf.update({'stWTime': int(stWTime)})
  831. if temThre:
  832. lastSetConf.update({'temThre': int(temThre)})
  833. if freeUse:
  834. lastSetConf.update({'freeUse': int(freeUse)})
  835. self.set_dev_setting(lastSetConf)
  836. self.set_dev_setting2(lastSetConf)
  837. def handle_clear_start_error(self, port):
  838. dealer = Dealer.objects.get(id = self._device["ownerId"])
  839. if not dealer or not dealer.managerialOpenId:
  840. return
  841. group = Group.get_group(self._device["groupId"])
  842. self.lock_unlock_port(port, lock = False)
  843. notifyData = {
  844. "title": "设备故障报警解除",
  845. "device": u"{gNum}组-{lc}-{port}端口".format(gNum = self._device["groupNumber"],
  846. lc = self._device["logicalCode"],
  847. port = port),
  848. "location": u"{address}-{groupName}".format(address = group["address"], groupName = group["groupName"]),
  849. "fault": u"当前端口已被正常启动,端口故障解除",
  850. "notifyTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  851. }
  852. task_caller(
  853. func_name = 'report_to_dealer_via_wechat',
  854. openId = dealer.managerialOpenId,
  855. dealerId = str(dealer.id),
  856. templateName = "device_fault",
  857. **notifyData
  858. )
  859. self.lock_unlock_port(port, lock = False)
  860. def handle_out_start_error(self, port):
  861. dealer = Dealer.objects.get(id = self._device["ownerId"])
  862. if not dealer or not dealer.managerialOpenId:
  863. return
  864. group = Group.get_group(self._device["groupId"])
  865. times = Device.get_error_start_times(self._device["devNo"], port)
  866. self.lock_unlock_port(port, lock = True)
  867. notifyData = {
  868. "title": u"注意,您的设备可能发生故障!",
  869. "device": u"{gNum}组-{lc}-{port}端口".format(gNum = self._device["groupNumber"],
  870. lc = self._device["logicalCode"],
  871. port = port),
  872. "location": u"{address}-{groupName}".format(address = group["address"], groupName = group["groupName"]),
  873. "fault": u"当前设备端口连续启动 {times} 失败,目前该端口已经被自动禁用,请注意该端口是否发生故障".format(times = times),
  874. "notifyTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  875. }
  876. task_caller(
  877. func_name = 'report_to_dealer_via_wechat',
  878. openId = dealer.managerialOpenId,
  879. dealerId = str(dealer.id),
  880. templateName = "device_fault",
  881. **notifyData
  882. )
  883. # 麦总的告警3次触发,同时锁定设备,为避免解锁设备之后 再次触发 这个地方需要将其缓存清空
  884. Device.delete_error_start_times(self._device["devNo"], port)