water_controller.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python
  3. import time
  4. import logging
  5. import datetime
  6. from apilib.utils_datetime import timestamp_to_dt
  7. from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT
  8. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte
  9. from apps.web.core.exceptions import ServiceException
  10. from apps.web.core.networking import MessageSender
  11. from apps.web.dealer.models import Dealer
  12. from apps.web.device.models import Device, Group
  13. from apps.web.core.device_define.water_despenser import CMD_CODE
  14. from apps.web.helpers import get_wechat_manager_mp_proxy
  15. from apps.web.user.models import MyUser
  16. logger = logging.getLogger(__name__)
  17. class WaterControllerBox(SmartBox):
  18. def __init__(self, device):
  19. super(WaterControllerBox, self).__init__(device)
  20. def _refresh_device_uart(self):
  21. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  22. {'IMEI': self._device['devNo'], "funCode": 'E9', 'data': ''},
  23. timeout=15)
  24. self.__verify_device_operate_status(devInfo)
  25. def __verify_device_operate_status(self, devInfo):
  26. if 'rst' in devInfo and devInfo['rst'] != 0:
  27. if devInfo['rst'] == -1:
  28. raise ServiceException(
  29. {
  30. 'result': 2,
  31. 'description': u'当前设备信号弱无响应。本次操作没有扣除您的金额,您可以稍后重试或者试试附近其他设备。'
  32. }
  33. )
  34. elif devInfo['rst'] == 1:
  35. raise ServiceException(
  36. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能。'})
  37. def start_device(self, package, openId, attachParas):
  38. self._refresh_device_uart()
  39. if attachParas is None or 'chargeIndex' not in attachParas:
  40. raise ServiceException({'result': 2, 'description': u'请您选择合适的端口'})
  41. unit = package.get('unit', u'分钟')
  42. if unit not in [u'分钟', u'秒']:
  43. raise ServiceException({'result': 2, 'description': u'套餐错误,套餐只支持秒,分钟'})
  44. price = float(package['price'])
  45. coins = float(package['coins'])
  46. port = hex(int(attachParas['chargeIndex']))
  47. hexPort = fill_2_hexByte(port, 2)
  48. devPortInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  49. 'IMEI': self._device['devNo'],
  50. 'funCode': 'EF',
  51. 'data': hexPort
  52. }, timeout=15)
  53. self.__verify_device_operate_status(devPortInfo)
  54. portCanUse = True if devPortInfo['data'][2:6] == '0000' else False
  55. if portCanUse is False:
  56. raise ServiceException({'result': 2, 'description': u'端口繁忙,目前无法启动,请稍后再试。'})
  57. # 杜绝续充以及事件异常导致有缓存的情况
  58. Device.clear_port_control_cache(self._device['devNo'], str(attachParas['chargeIndex']))
  59. type = 'FE' if unit == u'秒' else 'FD'
  60. needTime = int(package['time'])
  61. hexTime = fill_2_hexByte(hex(needTime), 4)
  62. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {
  63. 'IMEI': self._device['devNo'],
  64. 'funCode': '55',
  65. 'data': hexPort + type + hexTime
  66. }, timeout=MQTT_TIMEOUT.START_DEVICE)
  67. self.__verify_device_operate_status(devInfo)
  68. usePort = int(attachParas['chargeIndex'])
  69. start_timestamp = int(time.time())
  70. if type == 'FE':
  71. finishedTime = start_timestamp + int(needTime)
  72. else:
  73. finishedTime = start_timestamp + (int(needTime) * 60)
  74. portDict = {
  75. 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'),
  76. 'status': Const.DEV_WORK_STATUS_WORKING,
  77. 'price': price,
  78. 'coins': coins,
  79. 'isStart': True,
  80. 'openId': openId,
  81. 'refunded': False,
  82. 'needTime': needTime,
  83. 'type': 'second' if type == 'FE' else 'minute',
  84. 'vCardId': self._vcard_id,
  85. 'finishedTime': finishedTime,
  86. 'isPause': False
  87. }
  88. if 'linkedRechargeRecordId' in attachParas:
  89. item = {
  90. 'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])
  91. }
  92. portDict['payInfo'] = [item]
  93. Device.update_dev_control_cache(self._device['devNo'], {str(usePort): portDict})
  94. return devInfo
  95. def get_port_status(self, force=True):
  96. # self._refresh_device_uart()
  97. # ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  98. # device = Device.objects(devNo=self._device['devNo']).first()
  99. # allPorts = ctrInfo.get('allPorts', device.otherConf.get('portNumber', 5))
  100. # statusDict = {}
  101. # for ii in range(allPorts):
  102. # tempDict = ctrInfo.get(str(ii + 1), {})
  103. # if tempDict.has_key('status'):
  104. # statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  105. # elif tempDict.has_key('isStart'):
  106. # if tempDict['isStart']:
  107. # statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  108. # else:
  109. # statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  110. # else:
  111. # statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  112. #
  113. # allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  114. # Device.update_dev_control_cache(self._device['devNo'],
  115. # {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  116. #
  117. # ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  118. # for strPort, info in statusDict.items():
  119. # if ctrInfo.has_key(strPort):
  120. # ctrInfo[strPort].update({'status': info['status']})
  121. # else:
  122. # ctrInfo[strPort] = info
  123. # Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  124. #
  125. # return statusDict
  126. self._refresh_device_uart()
  127. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  128. {'IMEI': self._device['devNo'], "funCode": 'EF', 'data': '55'},
  129. timeout=15)
  130. self.__verify_device_operate_status(devInfo)
  131. device = Device.objects(devNo=self._device['devNo']).first()
  132. result = {}
  133. portNum = device.otherConf.get('portNumber', 5) + 1
  134. portData = devInfo['data']
  135. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  136. ii = 1
  137. while ii < portNum:
  138. port = int(portData[ii * 8 - 2:ii * 8], 16)
  139. statusTemp = portData[ii * 8 - 6:ii * 8 - 2]
  140. if statusTemp == '0000':
  141. if str(port) in ctrInfo:
  142. if ctrInfo[str(port)].get('status', 0) == Const.DEV_WORK_STATUS_FORBIDDEN:
  143. status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN}
  144. else:
  145. status = {'status': Const.DEV_WORK_STATUS_IDLE}
  146. else:
  147. status = {'status': Const.DEV_WORK_STATUS_IDLE}
  148. else:
  149. status = {'status': Const.DEV_WORK_STATUS_WORKING}
  150. ii += 1
  151. result[str(port)] = status
  152. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  153. Device.update_dev_control_cache(self._device['devNo'],
  154. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  155. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  156. for strPort, info in result.items():
  157. if strPort in ctrInfo:
  158. ctrInfo[strPort].update({'status': info['status']})
  159. else:
  160. ctrInfo[strPort] = info
  161. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  162. return result
  163. def get_port_status_from_dev(self):
  164. return {}
  165. def pauseToUseDevice(self, port, oper):
  166. self._refresh_device_uart()
  167. ctrInfo = Device.get_dev_control_cache(self.device['devNo'])
  168. lineInfo = ctrInfo.get(str(port))
  169. funCode = 'EE' if lineInfo.get('isPause', True) is True else 'ED'
  170. hexPort = fill_2_hexByte(hex(int(port)), 2)
  171. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  172. {'IMEI': self._device['devNo'], "funCode": funCode, 'data': hexPort})
  173. if funCode == 'EE':
  174. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'isPause': False}})
  175. elif funCode == 'ED':
  176. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'isPause': True}})
  177. else:
  178. pass
  179. def active_deactive_port(self, port, active):
  180. if not active:
  181. self.stop_charging_port(port)
  182. devInfo = Device.get_dev_control_cache(self._device['devNo'])
  183. portCtrInfo = devInfo.get(str(port), {})
  184. portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE,
  185. 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  186. newValue = {str(port): portCtrInfo}
  187. Device.update_dev_control_cache(self._device['devNo'], newValue)
  188. else:
  189. raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'})
  190. def stop_charging_port(self, port):
  191. self._refresh_device_uart()
  192. hexPort = fill_2_hexByte(hex(int(port)), 2)
  193. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  194. {'IMEI': self._device['devNo'], "funCode": 'EC', 'data': hexPort}, timeout=7)
  195. self.__verify_device_operate_status(devInfo)
  196. leftTime = int(devInfo['data'][2:6], 16)
  197. port = int(devInfo['data'][6:8], 16)
  198. return {'leftTime': leftTime, 'port': str(port)}
  199. def stop(self, port = None):
  200. boardRefund = self.get_dev_setting()['boardRefund']
  201. if boardRefund is False:
  202. raise ServiceException({'result': 2, 'description': u'暂不支持用户远程停止设备'})
  203. self.stop_charging_port(port)
  204. infoDict = dict()
  205. infoDict['remainder_time'] = 0
  206. return infoDict
  207. @property
  208. def isHaveStopEvent(self):
  209. return True
  210. def analyze_event_data(self, data):
  211. cmdCode = data[0:2]
  212. if cmdCode == 'EB':
  213. port = str(int(data[2:4], 16))
  214. return {
  215. 'status': Const.DEV_WORK_STATUS_IDLE,
  216. 'cmdCode': cmdCode,
  217. 'port': port
  218. }
  219. elif cmdCode == 'EC':
  220. leftTime = str(int(data[2:6], 16))
  221. port = str(int(data[6:8], 16))
  222. return {
  223. 'status': Const.DEV_WORK_STATUS_IDLE,
  224. 'cmdCode': cmdCode,
  225. 'leftTime': leftTime,
  226. 'port': port
  227. }
  228. def get_dev_setting(self):
  229. device = Device.objects(devNo=self._device['devNo']).first()
  230. volumeControl = device.otherConf.get('volumeControl', 'medium')
  231. portNumber = device.otherConf.get('portNumber', 5)
  232. boardRefund = device.otherConf.get('boardRefund', False)
  233. return {'volumeControl': volumeControl, 'portNumber': portNumber, 'boardRefund': boardRefund}
  234. def set_device_function_param(self, request, lastSetConf):
  235. self._refresh_device_uart()
  236. portNumber = request.POST['portNumber']
  237. volumeControl = request.POST['volumeControl']
  238. boardRefund = request.POST['boardRefund']
  239. if volumeControl == 'high':
  240. volumeControl = '03'
  241. elif volumeControl == 'medium':
  242. volumeControl = '02'
  243. elif volumeControl == 'low':
  244. volumeControl = '01'
  245. else:
  246. pass
  247. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  248. {'IMEI': self._device['devNo'], "funCode": 'EA', 'data': volumeControl}, timeout=15)
  249. time.sleep(2)
  250. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  251. {'IMEI': self._device['devNo'], "funCode": 'F7' if boardRefund is True else 'F9', 'data': ''}, timeout=15)
  252. device = Device.objects(devNo=self._device['devNo']).first()
  253. device.otherConf.update({'volumeControl': request.POST['volumeControl']})
  254. device.otherConf.update({'boardRefund': request.POST['boardRefund']})
  255. device.otherConf.update({'portNumber': int(portNumber)})
  256. device.save()
  257. Device.invalid_device_cache(device.devNo)
  258. def lock_unlock_port(self, port, lock = True):
  259. if lock:
  260. Device.update_dev_control_cache(self._device['devNo'],
  261. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  262. else:
  263. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})