changyuanSix.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import time
  6. import uuid
  7. import re
  8. from decimal import Decimal
  9. from apilib.monetary import RMB
  10. from apilib.utils_datetime import timestamp_to_dt, to_datetime
  11. from bson import ObjectId
  12. from apps.web.constant import MQTT_TIMEOUT, DeviceCmdCode, Const
  13. from apps.web.common.models import TempValues
  14. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, start_error_timer
  15. from apps.web.core.exceptions import ServiceException
  16. from apps.web.core.networking import MessageSender
  17. from apps.web.dealer.models import Dealer
  18. from apps.web.device.models import Device, Group
  19. from apps.web.user.models import MyUser, Card
  20. from taskmanager.mediator import task_caller
  21. logger = logging.getLogger(__name__)
  22. class ChargingCY6Box(SmartBox):
  23. def __init__(self, device):
  24. super(ChargingCY6Box, self).__init__(device)
  25. @staticmethod
  26. def encode_str(data, length=2, ratio=1.0, base=16):
  27. # type:(any,int,float,int) -> str
  28. if not isinstance(data, Decimal):
  29. data = Decimal(data)
  30. if not isinstance(length, str):
  31. length = str(length)
  32. if not isinstance(ratio, Decimal):
  33. ratio = Decimal(ratio)
  34. end = 'X' if base == 16 else 'd'
  35. encodeStr = '%.' + length + end
  36. encodeStr = encodeStr % (data * ratio)
  37. return encodeStr
  38. @staticmethod
  39. def transform_password(password):
  40. passwordHex = ''
  41. while password:
  42. passwordHex += fill_2_hexByte(hex(int(password[: 2])), 2)
  43. password = password[2:]
  44. return passwordHex
  45. @staticmethod
  46. def check_params_range(params, minData=None, maxData=None, desc=''):
  47. # type:(str,float,float,str) -> str
  48. '''
  49. 检查参数,返回字符串参数
  50. '''
  51. if params is None:
  52. raise ServiceException({'result': 2, 'description': u'参数错误.'})
  53. if not isinstance(params, Decimal):
  54. params = Decimal(params)
  55. if not minData and maxData:
  56. if not isinstance(maxData, Decimal):
  57. maxData = Decimal(maxData)
  58. if params <= maxData:
  59. return '%g' % params
  60. else:
  61. raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最大值为%g' % (desc, maxData)})
  62. if not maxData and minData:
  63. if not isinstance(minData, Decimal):
  64. minData = Decimal(minData)
  65. if minData <= params:
  66. return '%g' % params
  67. else:
  68. raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最小值为%g' % (desc, minData)})
  69. if not minData and not maxData:
  70. return '%g' % params
  71. else:
  72. if not isinstance(minData, Decimal):
  73. minData = Decimal(minData)
  74. if not isinstance(maxData, Decimal):
  75. maxData = Decimal(maxData)
  76. if minData <= params <= maxData:
  77. return '%g' % params
  78. else:
  79. raise ServiceException(
  80. {'result': 2, 'description': u'%s参数超出可选范围,可取范围为%g-%g' % (desc, minData, maxData)})
  81. def __check_device_uart_status(self, devInfo):
  82. if devInfo['rst'] != 0:
  83. if devInfo['rst'] == -1:
  84. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请稍候再试'})
  85. elif devInfo['rst'] == 1:
  86. raise ServiceException({'result': 2, 'description': u'充电桩主板连接故障'})
  87. else:
  88. raise ServiceException({'result': 2, 'description': u'系统错误'})
  89. def _ack(self, ack_id):
  90. MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload={
  91. 'IMEI': self.device.devNo,
  92. 'funCode': 'AK',
  93. 'data': ack_id
  94. }, timeout=15)
  95. def start_device(self, package, openId, attachParas):
  96. if attachParas is None or 'chargeIndex' not in attachParas:
  97. raise ServiceException({'result': 2, 'description': u'请您选择合适的端口'})
  98. rechargeRcdId = str(attachParas.get('linkedRechargeRecordId', ''))
  99. price = float(package['price'])
  100. coins = float(package['coins'])
  101. hexCoins = fill_2_hexByte(hex(int(coins * 100)), 4)
  102. hexReserveByte = '0000'
  103. port = hex(int(attachParas['chargeIndex']))
  104. hexPort = fill_2_hexByte(port, 2)
  105. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  106. 'IMEI': self._device['devNo'],
  107. 'funCode': 'D2',
  108. 'data': hexCoins + hexReserveByte + hexPort
  109. }, timeout=15)
  110. self.__check_device_uart_status(devInfo)
  111. data = devInfo['data']
  112. if data[6: 8] != '4F':
  113. raise ServiceException({'result': 2, 'description': u'启动端口失败,您的金币还在,您重新启动试试看'})
  114. devCache = Device.get_dev_control_cache(self._device["devNo"])
  115. portCache = devCache.get(str(attachParas['chargeIndex']))
  116. start_timestamp = int(time.time())
  117. devInfo['finishedTime'] = start_timestamp + 12 * 60 * 60
  118. if portCache is not None and portCache.get('status', '') == Const.DEV_WORK_STATUS_WORKING and portCache.get('openId') == openId:
  119. payInfo = portCache.get("payInfo", list())
  120. if not payInfo:
  121. logger.error("miss payInfo! {}-{}".format(self._device["devNo"], str(attachParas['chargeIndex'])))
  122. payInfo.append({
  123. "vCardId": self._vcard_id,
  124. "coins": float(coins),
  125. "price": float(price),
  126. "rechargeRcdId": rechargeRcdId,
  127. "needTime": 0,
  128. })
  129. coins = portCache.get("coins") + float(coins)
  130. price = portCache.get("price") + float(price)
  131. cacheDict = {
  132. "startTime": portCache.get("startTime", ""),
  133. "status": Const.DEV_WORK_STATUS_WORKING,
  134. 'finishedTime': devInfo['finishedTime'],
  135. "coins": coins,
  136. "price": price,
  137. "openId": openId,
  138. 'waitD9': True,
  139. 'port': str(attachParas['chargeIndex']),
  140. 'payType': '01'
  141. }
  142. if rechargeRcdId != '':
  143. cacheDict.update({'payInfo': payInfo})
  144. else:
  145. cacheDict = {
  146. "startTime": timestamp_to_dt(start_timestamp).strftime("%Y-%m-%d %H:%M:%S"),
  147. "status": Const.DEV_WORK_STATUS_WORKING,
  148. 'finishedTime': devInfo['finishedTime'],
  149. "coins": float(coins),
  150. "price": float(price),
  151. "openId": openId,
  152. "consumeType": "mobile",
  153. 'waitD9': True,
  154. 'port': str(attachParas['chargeIndex']),
  155. 'payType': '01'
  156. }
  157. if rechargeRcdId != '':
  158. cacheDict.update({'payInfo': [{
  159. "vCardId": self._vcard_id,
  160. "coins": float(coins),
  161. "price": float(price),
  162. "rechargeRcdId": rechargeRcdId,
  163. "needTime": 0,
  164. }]})
  165. Device.update_dev_control_cache(self._device["devNo"], {str(attachParas['chargeIndex']): cacheDict})
  166. if openId:
  167. devInfo['rechargeRcdId'] = rechargeRcdId
  168. return devInfo
  169. def get_port_status(self, force=False):
  170. '''
  171. 获取设备状态 昌原的状态都是被动获取的
  172. :param force:
  173. :return:
  174. '''
  175. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {
  176. 'IMEI': self._device['devNo'],
  177. 'funCode': 'E1',
  178. 'data': '0000'
  179. }, timeout=15)
  180. # 不修改100267的驱动基础上做延时处理
  181. time.sleep(1)
  182. devCache = Device.get_dev_control_cache(self._device['devNo'])
  183. statusDict = dict()
  184. allPorts = devCache.get('allPorts', 10)
  185. for portNum in range(allPorts):
  186. tempDict = devCache.get(str(portNum + 1), {})
  187. if 'status' in tempDict:
  188. statusDict[str(portNum + 1)] = {'status': tempDict.get('status')}
  189. elif 'isStart' in tempDict:
  190. if tempDict['isStart']:
  191. statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  192. else:
  193. statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  194. else:
  195. statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  196. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  197. Device.update_dev_control_cache(self._device['devNo'],
  198. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  199. return statusDict
  200. def get_port_status_from_dev(self):
  201. return self.get_port_status(False)
  202. def _async_card_balance(self, cardType, cardNo, asyncMoney):
  203. """
  204. 同步卡内余额
  205. :param cardType:
  206. :param cardNo:
  207. :param asyncMoney:
  208. :return:
  209. """
  210. # 如果是预付费的卡 同步的金额需要变换为分
  211. balance = asyncMoney if cardType == '00' else asyncMoney * 100
  212. # 获取随机流水号
  213. sidKey = '{}-{}'.format(self.device.devNo, cardNo)
  214. sid = TempValues.get(sidKey)
  215. balanceHex = self.encode_str(int(balance), length=6)
  216. sidHex = self.encode_str(sid, length=4)
  217. MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload={
  218. 'IMEI': self.device.devNo,
  219. 'funCode': 'D3',
  220. 'data': cardType + balanceHex + sidHex + cardNo
  221. })
  222. def get_dev_setting(self):
  223. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  224. 'IMEI': self._device['devNo'],
  225. 'funCode': 'D0',
  226. 'data': '00'
  227. }, timeout=15)
  228. self.__check_device_uart_status(devInfo)
  229. data = devInfo['data'][6:]
  230. powerTime1 = str(int(data[0:4], 16))
  231. powerTime2 = str(int(data[4:8], 16))
  232. powerTime3 = str(int(data[8:12], 16))
  233. powerTime4 = str(int(data[12:16], 16))
  234. power1 = str(int(data[16:20], 16))
  235. power2 = str(int(data[20:24], 16))
  236. power3 = str(int(data[24:28], 16))
  237. power4 = str(int(data[28:32], 16))
  238. noloadPower = str(int(data[32:34], 16))
  239. noloadTime = str(int(data[34:36], 16))
  240. volume = str(int(data[36:38], 16))
  241. cardFee = str(float(int(data[38:42], 16)) / 100)
  242. floatPower = str(int(data[42:44], 16))
  243. floatTime = str(int(data[44:48], 16))
  244. cardFree = False if data[48:50] == u'00' else True
  245. powerTime5 = str(int(data[50:54], 16))
  246. powerTime6 = str(int(data[54:58], 16))
  247. power5 = str(int(data[58:62], 16))
  248. power6 = str(int(data[62:66], 16))
  249. elecPrice = str(float(int(data[66:68], 16)) / 100)
  250. consumeTypeStr = data[68:70]
  251. cardRefund = False if data[70:72] == u'00' else True
  252. if consumeTypeStr == u'00':
  253. consumeType = 'elec'
  254. elif consumeTypeStr == u'01':
  255. consumeType = 'power'
  256. elif consumeTypeStr == u'02':
  257. consumeType = 'time'
  258. else:
  259. consumeType = 'free'
  260. devCache = Device.get_dev_control_cache(self._device['devNo'])
  261. temperature = devCache.get('temperature', '获取中...')
  262. disable = self.device.get('otherConf', {}).get('disableDevice', False)
  263. needBindCard = self.device.get("otherConf", {}).get('needBindCard', True)
  264. vCardTime = self.device.get("otherConf", {}).get('vCardTime', 300)
  265. return {
  266. 'noloadPower': noloadPower,
  267. 'noloadTime': noloadTime,
  268. 'cardFee': cardFee,
  269. 'temperature': temperature,
  270. 'elecPrice': elecPrice,
  271. 'power5': power5,
  272. 'power6': power6,
  273. 'power4': power4,
  274. 'power3': power3,
  275. 'power2': power2,
  276. 'power1': power1,
  277. 'vCardTime': vCardTime,
  278. 'disable': disable,
  279. 'volume': volume,
  280. 'needBindCard': needBindCard,
  281. 'powerTime1': powerTime1,
  282. 'powerTime2': powerTime2,
  283. 'powerTime3': powerTime3,
  284. 'powerTime4': powerTime4,
  285. 'powerTime5': powerTime5,
  286. 'powerTime6': powerTime6,
  287. 'floatTime': floatTime,
  288. 'floatPower': floatPower,
  289. 'cardFree': cardFree,
  290. 'consumeType': consumeType,
  291. 'cardRefund': cardRefund
  292. }
  293. def _set_password(self, password):
  294. """
  295. 设置设备的小区密码
  296. 密码是否还需要再校验,以及是否是0开头
  297. """
  298. if not password.isdigit():
  299. raise ServiceException({'result': '2', 'description': u'密码必须必须为0-9数字'})
  300. if len(password) != 10:
  301. raise ServiceException({'result': 0, 'description': u'密码长度必须为10位'})
  302. passwordHex = self.transform_password(password)
  303. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  304. 'IMEI': self._device['devNo'],
  305. 'funCode': 'DB',
  306. 'data': passwordHex
  307. }, timeout=15)
  308. self.__check_device_uart_status(devInfo)
  309. if 'data' not in devInfo:
  310. raise ServiceException({'result': '2', 'description': u'设置小区密码失败,请重新试试'})
  311. return devInfo
  312. def _set_send_card(self, oldPassword, newPassword, FaKacardType):
  313. '''
  314. 设置卡机模式 用于重置 实体卡的小区密码
  315. '''
  316. if not oldPassword.isdigit() or not newPassword.isdigit():
  317. raise ServiceException({'result': '2', 'description': u'密码必须必须为0-9数字'})
  318. if len(oldPassword) != 10 or len(newPassword) != 10:
  319. raise ServiceException({'result': 0, 'description': u'密码长度必须为10位'})
  320. if not FaKacardType:
  321. raise ServiceException({'result': 0, 'description': u'请选择要发行卡的类型'})
  322. oldPasswordHex = self.transform_password(oldPassword)
  323. newPasswordHex = self.transform_password(newPassword)
  324. FaKacardType = self.encode_str(FaKacardType)
  325. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  326. 'IMEI': self._device['devNo'],
  327. 'funCode': 'DC',
  328. 'data': oldPasswordHex + newPasswordHex + FaKacardType
  329. }, timeout=15)
  330. self.__check_device_uart_status(devInfo)
  331. if 'data' not in devInfo:
  332. raise ServiceException({'result': '2', 'description': u'设置发卡机模式失败,请重新试试'})
  333. return devInfo
  334. def _set_elec_price(self, elecPrice):
  335. """
  336. 设置电量单价 这个参数是模块侧的 只下发到模块驱动 不到主板
  337. :param elecPrice:
  338. :return:
  339. """
  340. elecPriceHex = "{:0>8X}".format(int(3600 * 1000 * float(elecPrice)))
  341. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  342. 'IMEI': self._device['devNo'],
  343. 'funCode': 'EP',
  344. 'data': elecPriceHex
  345. }, timeout=15)
  346. self.__check_device_uart_status(devInfo)
  347. # 更新参数设置
  348. Device.get_collection().update_one({'devNo': self.device['devNo']}, {'$set': {'otherConf.elecPrice': elecPrice}})
  349. Device.invalid_device_cache(self.device.devNo)
  350. def _reboot_device(self):
  351. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  352. 'IMEI': self._device['devNo'],
  353. 'funCode': 'D5',
  354. 'data': '0000'
  355. }, timeout=15)
  356. self.__check_device_uart_status(devInfo)
  357. if 'data' not in devInfo:
  358. raise ServiceException({'result': '2', 'description': u'设备复位错误,请重新试试'})
  359. return devInfo
  360. def set_dev_disable(self, disable):
  361. if disable:
  362. status = '00AA'
  363. else:
  364. status = '0055'
  365. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  366. 'IMEI': self._device['devNo'],
  367. 'funCode': 'DD',
  368. 'data': status
  369. }, timeout=15)
  370. self.__check_device_uart_status(devInfo)
  371. if 'data' not in devInfo:
  372. raise ServiceException({'result': '2', 'description': u'设备停用错误,请联系厂商协助解决'})
  373. otherConf = self._device.get('otherConf', {})
  374. otherConf['disableDevice'] = disable
  375. Device.objects.filter(devNo=self._device['devNo']).update(otherConf=otherConf)
  376. Device.invalid_device_cache(self._device['devNo'])
  377. def _set_all_settings(self, settings):
  378. powerTime1 = settings.get('powerTime1')
  379. powerTime2 = settings.get('powerTime2')
  380. powerTime3 = settings.get('powerTime3')
  381. powerTime4 = settings.get('powerTime4')
  382. power1 = settings.get('power1')
  383. power2 = settings.get('power2')
  384. power3 = settings.get('power3')
  385. power4 = settings.get('power4')
  386. noloadPower = settings.get('noloadPower')
  387. noloadTime = settings.get('noloadTime')
  388. volume = settings.get('volume')
  389. cardFee = settings.get('cardFee')
  390. floatPower = settings.get('floatPower')
  391. floatTime = settings.get('floatTime')
  392. cardFree = settings.get('cardFree')
  393. powerTime5 = settings.get('powerTime5')
  394. powerTime6 = settings.get('powerTime6')
  395. power5 = settings.get('power5')
  396. power6 = settings.get('power6')
  397. elecPrice = settings.get('elecPrice')
  398. consumeType = settings.get('consumeType')
  399. cardRefund = settings.get('cardRefund')
  400. #
  401. powerTime1 = self.check_params_range(params=powerTime1, minData=0, maxData=999, desc='第1段功率时间')
  402. powerTime2 = self.check_params_range(params=powerTime2, minData=0, maxData=999, desc='第2段功率时间')
  403. powerTime3 = self.check_params_range(params=powerTime3, minData=0, maxData=999, desc='第3段功率时间')
  404. powerTime4 = self.check_params_range(params=powerTime4, minData=0, maxData=999, desc='第4段功率时间')
  405. power1 = self.check_params_range(params=power1, minData=0, maxData=999, desc='第1段功率值')
  406. power2 = self.check_params_range(params=power2, minData=0, maxData=999, desc='第2段功率值')
  407. power3 = self.check_params_range(params=power3, minData=0, maxData=999, desc='第3段功率值')
  408. power4 = self.check_params_range(params=power4, minData=0, maxData=999, desc='第4段功率值')
  409. noloadPower = self.check_params_range(params=noloadPower, minData=0, maxData=50, desc='空载检测功率')
  410. noloadTime = self.check_params_range(params=noloadTime, minData=0, maxData=255, desc='空载功率检测时间')
  411. volume = self.check_params_range(params=volume, minData=0, maxData=8, desc='音量')
  412. cardFee = self.check_params_range(params=cardFee, minData=0, maxData=655, desc='预付卡预扣金额')
  413. floatPower = self.check_params_range(params=floatPower, minData=0, maxData=50, desc='浮动功率')
  414. floatTime = self.check_params_range(params=floatTime, minData=0, maxData=60000, desc='浮动功率延长时间')
  415. powerTime5 = self.check_params_range(params=powerTime5, minData=0, maxData=999, desc='第5段功率时间')
  416. powerTime6 = self.check_params_range(params=powerTime6, minData=0, maxData=999, desc='第6段功率时间')
  417. power5 = self.check_params_range(params=power5, minData=0, maxData=999, desc='第5段功率值')
  418. power6 = self.check_params_range(params=power6, minData=0, maxData=999, desc='第6段功率值')
  419. elecPrice = self.check_params_range(params=elecPrice, minData=0, maxData=2.5, desc='电价')
  420. if consumeType == 'elec':
  421. consumeTypeStr = '00'
  422. elif consumeType == 'power':
  423. consumeTypeStr = '01'
  424. elif consumeType == 'time':
  425. consumeTypeStr = '02'
  426. elif consumeType == 'free':
  427. consumeTypeStr = '03'
  428. else:
  429. consumeTypeStr = '00'
  430. data = ''
  431. data += self.encode_str(powerTime1, length=4)
  432. data += self.encode_str(powerTime2, length=4)
  433. data += self.encode_str(powerTime3, length=4)
  434. data += self.encode_str(powerTime4, length=4)
  435. data += self.encode_str(power1, length=4)
  436. data += self.encode_str(power2, length=4)
  437. data += self.encode_str(power3, length=4)
  438. data += self.encode_str(power4, length=4)
  439. data += self.encode_str(noloadPower, length=2)
  440. data += self.encode_str(noloadTime, length=2)
  441. data += self.encode_str(volume, length=2)
  442. data += self.encode_str(cardFee, length=4, ratio=100)
  443. data += self.encode_str(floatPower, length=2)
  444. data += self.encode_str(floatTime, length=4)
  445. data += "AA" if cardFree is True else "00"
  446. data += self.encode_str(powerTime5, length=4)
  447. data += self.encode_str(powerTime6, length=4)
  448. data += self.encode_str(power5, length=4)
  449. data += self.encode_str(power6, length=4)
  450. data += self.encode_str(elecPrice, length=2, ratio=100)
  451. data += consumeTypeStr
  452. data += "01" if cardRefund is True else "00"
  453. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  454. 'IMEI': self._device['devNo'],
  455. 'funCode': 'D1',
  456. 'data': data
  457. }, timeout=15)
  458. self.__check_device_uart_status(devInfo)
  459. if 'data' not in devInfo:
  460. raise ServiceException({'result': '2', 'description': u'设置设备参数错误,请联系经销商协助解决'})
  461. return devInfo
  462. def set_device_function_param(self, request, lastSetConf):
  463. """设备设备的参数"""
  464. if "pwd" in request.POST:
  465. return self._set_password(request.POST["pwd"])
  466. if "old_pwd" in request.POST:
  467. old_pwd = request.POST["old_pwd"]
  468. new_pwd = request.POST["new_pwd"]
  469. cardType = request.POST["FaKacardType"]
  470. return self._set_send_card(old_pwd, new_pwd, cardType)
  471. # 卡券启动时间
  472. if 'vCardTime' in request.POST:
  473. vCardTime = int(request.POST.get('vCardTime'))
  474. if vCardTime != int(self.device['otherConf'].get('vCardTime', 300)):
  475. Device.get_collection().update_one({'devNo': self.device['devNo']},
  476. {'$set': {'otherConf.vCardTime': vCardTime}})
  477. Device.invalid_device_cache(self.device.devNo)
  478. # 对一下参数的设置
  479. new_settings = dict()
  480. for _paramKey, _paramValue in lastSetConf.items():
  481. if request.POST.get(_paramKey) is not None:
  482. _paramValue = request.POST[_paramKey]
  483. new_settings[_paramKey] = _paramValue
  484. cardFree = "AA" if new_settings["cardFree"] else "00"
  485. new_settings.update({"cardFree": cardFree})
  486. self._set_all_settings(new_settings)
  487. def set_device_function(self, request, lastSetConf):
  488. """开关类参数配置"""
  489. if 'disable' in request.POST:
  490. return self.set_dev_disable(request.POST.get('disable'))
  491. if 'reboot' in request.POST:
  492. return self._reboot_device()
  493. if 'cardFree' in request.POST:
  494. cardFree = request.POST["cardFree"]
  495. lastSetConf.update({"cardFree": cardFree})
  496. return self._set_all_settings(lastSetConf)
  497. if 'cardRefund' in request.POST:
  498. cardRefund = request.POST["cardRefund"]
  499. lastSetConf.update({'cardRefund': cardRefund})
  500. return self._set_all_settings(lastSetConf)
  501. if 'needBindCard' in request.POST:
  502. needBindCard = request.POST.get('needBindCard')
  503. otherConf = self.device.get('otherConf', dict())
  504. otherConf.update({'needBindCard': needBindCard})
  505. Device.objects.get(devNo=self.device.devNo).update(otherConf=otherConf)
  506. Device.invalid_device_cache(self.device.devNo)
  507. def analyze_event_data(self, data):
  508. cmdCode = data[2:4]
  509. if cmdCode == 'D8':
  510. tempData = data[6:170]
  511. portStatusData = tempData[0:20]
  512. portPowerData = tempData[20:60]
  513. portLeftMoneyData = tempData[60:100]
  514. portErrorData = tempData[100:120]
  515. temperature = tempData[120:124]
  516. portSpendElecData = tempData[124:164]
  517. portInfo = {}
  518. for _ in range(10):
  519. currentPortStatusData = portStatusData[(_ * 2):(_ + 1) * 2]
  520. if currentPortStatusData == '00':
  521. tempPortStatusData = Const.DEV_WORK_STATUS_IDLE
  522. elif currentPortStatusData in ['01', '11']:
  523. tempPortStatusData = Const.DEV_WORK_STATUS_WORKING
  524. else:
  525. tempPortStatusData = Const.DEV_WORK_STATUS_FAULT
  526. currentPortErrorMessage = portErrorData[(_ * 2):(_ + 1) * 2]
  527. if currentPortErrorMessage == '00':
  528. tempPortErrorMessage = 'normal'
  529. elif currentPortErrorMessage == '01':
  530. tempPortErrorMessage = 'elecRelayAdhesion'
  531. tempPortStatusData = Const.DEV_WORK_STATUS_FAULT
  532. else:
  533. tempPortErrorMessage = 'unknownError'
  534. tempPortStatusData = Const.DEV_WORK_STATUS_FAULT
  535. portInfo[str(_ + 1)] = {'status': tempPortStatusData}
  536. portInfo[str(_ + 1)].update({'power': str(int(portPowerData[(_ * 4):(_ + 1) * 4], 16))})
  537. portInfo[str(_ + 1)].update({'leftMoney': str(float(int(portLeftMoneyData[(_ * 4):(_ + 1) * 4], 16)) / 100)})
  538. portInfo[str(_ + 1)].update({'errorMessage': tempPortErrorMessage})
  539. portInfo[str(_ + 1)].update({'spendElec': str(float(int(portSpendElecData[(_ * 4):(_ + 1) * 4], 16)) / 100)})
  540. # 首先依据上报的状态获取已使用未使用端口数量
  541. allPorts, usedPorts, usePorts = self.get_port_static_info(portInfo)
  542. devCache = Device.get_dev_control_cache(self.device.devNo) or dict()
  543. for portStr, value in devCache.items():
  544. if not portStr.isdigit() or not isinstance(value, dict):
  545. continue
  546. # 更新每个端口的信息
  547. tempPortInfo = portInfo.get(portStr, dict())
  548. value.update(tempPortInfo)
  549. devCache[portStr] = value
  550. devCache['temperature'] = ('+' if temperature[0:2] == '00' else '-') + str(int(temperature[2:4], 16)) + ' degrees'
  551. devCache['allPorts'] = allPorts
  552. devCache['usedPorts'] = usedPorts
  553. devCache['usePorts'] = usePorts
  554. Device.update_dev_control_cache(self.device.devNo, devCache)
  555. return {}
  556. elif cmdCode == 'DA':
  557. tempData = data[6:18]
  558. port = str(int(tempData[0:2], 16))
  559. reasonCode = tempData[2:4]
  560. if reasonCode == '01':
  561. reason = '设备充满自停或拔掉插头'
  562. elif reasonCode == '02':
  563. reason = '超功率停止'
  564. elif reasonCode == '03':
  565. reason = '时间用完停止'
  566. elif reasonCode == '04':
  567. reason = '远程停止'
  568. elif reasonCode == '05':
  569. reason = '预付卡的扣费金额用完'
  570. else:
  571. reason = '电量超限'
  572. spendElec = str(float(int(tempData[4:8], 16)) / 100)
  573. leftMoney = str(float(int(tempData[8:12], 16)) / 100)
  574. return {'cmdCode': cmdCode, 'port': port, 'reason': reason, 'spendElec': spendElec, 'leftMoney': leftMoney}
  575. elif cmdCode == 'D9':
  576. power = str(int(data[20:24], 16))
  577. coins = float(int(data[24:28], 16)) / 100
  578. port = str(int(data[28:30], 16))
  579. payType = data[30:32]
  580. if payType == '00': # 次卡
  581. cardNo = data[6:14]
  582. cardType = '00'
  583. cardBalance = str(int(data[14:20], 16))
  584. needTime = int(data[32:36], 16)
  585. elif payType == '01': # 扫码
  586. needTime = int(data[32:36], 16)
  587. elif payType == '02': # 投币
  588. needTime = int(data[32:36], 16)
  589. elif payType == '03': # 预付卡
  590. cardNo = data[6:14]
  591. cardType = '01'
  592. cardBalance = str(float(int(data[14:20], 16)) / 100)
  593. leftMoney = str(float(int(data[32:36], 16)) / 100)
  594. else:
  595. pass
  596. return locals()
  597. elif cmdCode == 'D4':
  598. cardType = data[6:8]
  599. cardNo = data[8:16]
  600. cardBalance = RMB(int(data[16:22], 16))
  601. if cardType == '01':
  602. cardBalance = cardBalance * 0.01
  603. return {
  604. "cardType": cardType,
  605. "cardNo": cardNo,
  606. "cardBalance": cardBalance,
  607. 'cmdCode': cmdCode
  608. }
  609. elif cmdCode == 'D3':
  610. cardType = data[6:8]
  611. cardNo = data[8:16]
  612. cardBalance = RMB(int(data[16:22], 16))
  613. result = True if data[22:24] == 'AA' else False
  614. sid = int(data[24:28], 16)
  615. if cardType == '01':
  616. cardBalance = cardBalance * 0.01
  617. return {
  618. "cardType": cardType,
  619. "cardNo": cardNo,
  620. "cardBalance": cardBalance,
  621. "result": result,
  622. "sid": sid,
  623. 'cmdCode': cmdCode
  624. }
  625. elif cmdCode == 'D7':
  626. return {'data': data[6:8], 'cmdCode': cmdCode}
  627. elif cmdCode == 'DE':
  628. cardNo = data[6:14]
  629. beforeRefund = float(int(data[14:20], 16)) / 100.0
  630. refund = float(int(data[20:24], 16)) / 100.0
  631. afterRefund = float(int(data[24:30], 16)) / 100.0
  632. return {'cardNo': cardNo, 'beforeRefund': beforeRefund, 'refund': refund, 'afterRefund': afterRefund, 'cmdCode': cmdCode}
  633. @property
  634. def isHaveStopEvent(self):
  635. return True
  636. def stop(self, port=None):
  637. if not port:
  638. raise ServiceException({"result": "2", "description": u"请选择停止端口!"})
  639. self.stop_charging_port(port)
  640. def stop_charging_port(self, port):
  641. portHex = fill_2_hexByte(hex(int(port)), 2)
  642. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  643. 'IMEI': self._device['devNo'],
  644. 'funCode': 'D6',
  645. 'data': portHex
  646. }, timeout=15)
  647. self.__check_device_uart_status(devInfo)
  648. data = devInfo.get('data')
  649. if data[6: 8] != '4F':
  650. raise ServiceException({'result': 2, 'description': u'停止充电失败,请重新试试'})
  651. # 这里只下发命令 不清理端口缓存,等上报事件清除
  652. # Device.clear_port_control_cache(self.device.devNo, int(port))
  653. def check_dev_status(self, attachParas = None):
  654. pass
  655. def get_port_info(self, port):
  656. '''
  657. 获取 端口的详细信息
  658. :param port:
  659. :return:
  660. '''
  661. time.sleep(2)
  662. data = fill_2_hexByte(hex(int(port)), 2)
  663. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  664. 'IMEI': self._device['devNo'],
  665. 'funCode': 'E0',
  666. 'data': '00' + data
  667. }, timeout=15)
  668. self.__check_device_uart_status(devInfo)
  669. data = devInfo['data'][6::]
  670. line = str(int(data[0:2], 16))
  671. lineStatus = str(int(data[2:4], 16))
  672. power = str(int(data[4:8], 16))
  673. leftMoney = str(float(int(data[8:12], 16)) / 100)
  674. temperatureStr = data[12:16]
  675. temperature = ('+' if temperatureStr[0:2] == '00' else '-') + str(int(temperatureStr[2:4], 16)) + ' degrees'
  676. spendElec = str(float(int(data[16:20], 16)) / 100)
  677. errorCode = data[20:22]
  678. return {'port': line, 'portStatus': lineStatus, 'power': power, 'leftMoney': leftMoney, 'temperature': temperature, 'spendElec': spendElec, 'errorCode': errorCode}
  679. def active_deactive_port(self, port, active):
  680. if not active:
  681. self.stop_charging_port(port)
  682. else:
  683. raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'})
  684. def format_port_using_detail(self, detailDict):
  685. portData = {}
  686. startTimeStr = detailDict.get('startTime', None)
  687. if startTimeStr is not None and "usedTime" not in detailDict:
  688. startTime = to_datetime(startTimeStr)
  689. usedTime = int(round((datetime.datetime.now() - startTime).total_seconds() / 60.0))
  690. portData['usedTime'] = usedTime
  691. elif detailDict.get("usedTime"):
  692. usedTime = detailDict.get("usedTime")
  693. portData['usedTime'] = usedTime
  694. else:
  695. usedTime = None
  696. if detailDict.has_key('needTime'):
  697. if detailDict['needTime'] == 999:
  698. portData['needTime'] = u'充满自停'
  699. else:
  700. portData['needTime'] = detailDict['needTime']
  701. if detailDict.has_key('leftTime') and (usedTime > 0):
  702. if detailDict['leftTime'] == 65535:
  703. portData['leftTime'] = 65535
  704. detailDict['usedTime'] = 0
  705. detailDict['actualNeedTime'] = 0
  706. else:
  707. portData['actualNeedTime'] = int(detailDict['leftTime']) + int(usedTime)
  708. if detailDict.has_key('needTime') and portData['actualNeedTime'] > detailDict['needTime']:
  709. portData['actualNeedTime'] = portData['needTime']
  710. portData['leftTime'] = detailDict['leftTime']
  711. if detailDict.has_key('coins'):
  712. portData['leftMoney'] = detailDict['leftMoney']
  713. portData['consumeMoney'] = str(float(detailDict['price']) - float(detailDict['leftMoney']))
  714. elif detailDict.has_key('leftTime'):
  715. portData['leftTime'] = detailDict['leftTime']
  716. if (not detailDict.has_key('leftTime')) and (usedTime is not None):
  717. if detailDict.has_key('needTime'):
  718. portData['leftTime'] = detailDict['needTime'] - usedTime
  719. if detailDict.has_key('coins') and float(detailDict['coins']) != 0:
  720. portData['leftMoney'] = detailDict['leftMoney']
  721. portData['consumeMoney'] = str(float(detailDict['price']) - float(detailDict['leftMoney']))
  722. if detailDict.has_key('openId'):
  723. user = MyUser.objects(openId=detailDict['openId'], groupId=self.device.groupId).first()
  724. if user:
  725. portData['nickName'] = user.nickname
  726. if detailDict.has_key('cardId'):
  727. if not detailDict.has_key('consumeType'):
  728. portData['consumeType'] = 'card'
  729. card = Card.objects.get(id=ObjectId(detailDict['cardId']))
  730. if card.cardName:
  731. portData['cardName'] = card.cardName
  732. portData['cardNo'] = card.cardNo
  733. # 注意,如果是IC卡,不支持余额回收,这里也不要显示出来
  734. if card.cardType == 'IC' and portData.has_key('leftMoney'):
  735. portData.pop('leftMoney')
  736. elif detailDict.has_key('openId') and (not detailDict.has_key('consumeType')):
  737. if detailDict.get('vCardId'):
  738. portData['consumeType'] = 'mobile_vcard'
  739. else:
  740. portData['consumeType'] = 'mobile'
  741. elif detailDict.has_key('consumeType') and detailDict['consumeType'] == 'coin':
  742. portData['consumeType'] = 'coin' # 硬币的都无法退费
  743. if portData.has_key('leftMoney'):
  744. portData.pop('leftMoney')
  745. # 做个特殊处理
  746. if portData.has_key('needTime'):
  747. if portData['needTime'] == '999' or portData['needTime'] == '充满自停':
  748. portData['needTime'] = u'充满自停'
  749. else:
  750. portData['needTime'] = u'%s分钟' % portData['needTime']
  751. # 如果剩余时间为65535,表示未接插头
  752. if portData.has_key('leftTime') and portData['leftTime'] == 65535:
  753. portData['leftTime'] = u'(线路空载)'
  754. portData['usedTime'] = 0
  755. portData['needTime'] = 0
  756. detailDict.update(portData)
  757. for k, v in detailDict.items():
  758. if v < 0:
  759. detailDict.pop(k)
  760. # 因为前台显示的开始时间如果带年,就显示不下,这里做个切割
  761. if detailDict.has_key('startTime') and detailDict['startTime'].count('-') == 2:
  762. detailDict['startTime'] = to_datetime(detailDict['startTime']).strftime('%m-%d %H:%M:%S')
  763. return detailDict