aoqiang_socket_node.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import copy
  4. import datetime
  5. import time
  6. from apps.web.constant import DeviceCmdCode, Const, MQTT_TIMEOUT
  7. from apps.web.core.adapter.base import SmartBox
  8. from apps.web.core.exceptions import ServiceException
  9. from apps.web.core.networking import MessageSender
  10. from apps.web.device.models import Device
  11. from apps.web.user.models import ServiceProgress
  12. class AoQiangSocketNodeBox(SmartBox):
  13. def __init__(self, device):
  14. super(AoQiangSocketNodeBox, self).__init__(device)
  15. def translate_funcode(self, fun_code):
  16. fun_codeDict = {
  17. '01': u'查询所有子设备状态',
  18. '02': u'查询全部端口详情',
  19. '03': u'绑定设备',
  20. '04': u'重启设备',
  21. '05': u'解绑设备',
  22. '07': u'启动端口',
  23. '08': u'查询设备信息',
  24. '09': u'查询端口信息',
  25. '0B': u'设置设备配置',
  26. '0C': u'查询设备配置',
  27. }
  28. return fun_codeDict.get(fun_code, '')
  29. def translate_event_cmdcode(self, cmdCode):
  30. cmdDict = {
  31. }
  32. return cmdDict.get(cmdCode, '')
  33. def test(self, coins):
  34. data = {'fun_code': 0x07, 'order_id': '1111', 'chrmt': 0, 'port_id': 1, 'amount': 60}
  35. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  36. {'IMEI': self._device['devNo'], 'data': data})
  37. return devInfo
  38. def check_feedback_result(self, devInfo):
  39. if not devInfo.has_key('rst'):
  40. raise ServiceException({'result': 2, 'description': u'报文异常'})
  41. if devInfo['rst'] == -1:
  42. raise ServiceException({'result': 2, 'description': u'充电插座正在玩命找网络,请您稍候再试'})
  43. if devInfo['rst'] == 1:
  44. raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'})
  45. if devInfo['rst'] == 2:
  46. raise ServiceException({'result': 2, 'description': u'设备启动超时'})
  47. # result = devInfo['data']['result']
  48. # if result == 0:
  49. # return
  50. # else:#等待设备的错误码进行细化
  51. # raise ServiceException({'result': 2, 'description': u'充电插座返回了错误,请您重试看看能否解决问题'})
  52. def get_port_from_ab(self, portAB):
  53. portConf = {'A': 1, 'B': 2, 'C': 3}
  54. if portAB in portConf:
  55. return portConf[portAB]
  56. return portAB
  57. def get_abport_from_index(self, port):
  58. portConf = {'1': 'A', '2': 'B', '3': 'C'}
  59. return portConf.get(port)
  60. def start_device(self, package, openId, attachParas):
  61. if attachParas is None:
  62. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  63. if not attachParas.has_key('chargeIndex'):
  64. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  65. attachParas['chargeIndex'] = self.get_port_from_ab(attachParas['chargeIndex'])
  66. port = attachParas['chargeIndex']
  67. unit = package.get('unit', u'分钟')
  68. needTime, needElec = 0, 0
  69. orderNo = attachParas.get('orderNo')
  70. if unit == u'秒':
  71. if int(package['time']) < 60:
  72. raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'})
  73. needTime = int(float(package['time'])) / 60
  74. data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime}
  75. elif unit == u'分钟':
  76. needTime = int(package['time'])
  77. data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime}
  78. elif unit == u'小时':
  79. needTime = int(float(package['time']) * 60)
  80. data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime}
  81. elif unit == u'天':
  82. needTime = int(float(package['time']) * 60 * 24)
  83. data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime}
  84. elif unit == u'度':
  85. needElec = int(float(package['time'])) * 1000
  86. data = {'fun_code': 0x07, 'chrmt': 2, 'port_id': port, 'amount': needElec}
  87. else:
  88. raise ServiceException({'result': 2, 'description': u'套餐配置错误'})
  89. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  90. {'IMEI': self._device['devNo'], 'data': data}, timeout=MQTT_TIMEOUT.START_DEVICE)
  91. self.check_feedback_result(devInfo)
  92. if devInfo['rst'] == 0: # 成功
  93. newValue = {
  94. 'port': str(port),
  95. 'status': Const.DEV_WORK_STATUS_WORKING,
  96. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  97. 'orderNo': orderNo,
  98. 'coins': round(package.get('coins'), 2),
  99. 'isStart': True,
  100. 'openId': openId,
  101. 'chrmt': data.get('chrmt'),
  102. }
  103. if data.get('chrmt') == 1:
  104. newValue.update({'needTime': data.get('amount')})
  105. elif data.get('chrmt') == 2:
  106. newValue.update({'needElec': data.get('amount')})
  107. else: # TODO result的枚举列出原因
  108. raise ServiceException({'result': 2, 'description': u'充电插座响应异常,请您稍后再试哦'})
  109. if needTime:
  110. finishedTime = int(time.time()) + needTime * 60
  111. devInfo['needTime'] = needTime
  112. elif needElec:
  113. finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束
  114. devInfo['needElec'] = float(package['time'])
  115. else:
  116. finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束
  117. pass
  118. Device.update_port_control_cache(self._device['devNo'], newValue)
  119. devInfo.update({'finishedTime': finishedTime})
  120. devInfo['consumeOrderNo'] = orderNo
  121. return devInfo
  122. def analyze_event_data(self, data):
  123. if data['fun_code'] == '34': # 如果是结束事件,需要把reason翻译出来
  124. descDict = {
  125. '5': u'支付的金额已经使用完毕',
  126. '6': u'用户手工停止了充电',
  127. '7': u'电池充满自停',
  128. '8': u'故障导致充电停止',
  129. '9': u'本端口功率过载,主动关闭',
  130. '10': u'没有连接充电器,主动关闭',
  131. '11': u'远程关闭',
  132. '12': u'检测到烟雾告警,主动关闭'
  133. }
  134. order = data['order']
  135. order['reason'] = descDict.get(str(order['closeType']), u'')
  136. data['order'] = order
  137. return data
  138. def get_port_status_from_dev(self):
  139. # 先到设备上,把所有子节点的信息取出来,记录到主节点的缓存
  140. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  141. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x02}})
  142. self.check_feedback_result(devInfo)
  143. allPorts, usedPorts = 0, 0
  144. result = {}
  145. ctrInfo = Device.get_dev_control_cache(self._device.devNo)
  146. for portId, portInfo in devInfo['data']['ports'].items():
  147. portDict = {
  148. 'status': self.__translate_status_from_str(str(portInfo['port_status'])),
  149. 'power': round(portInfo['watt'], 2),
  150. 'leftTime': round(portInfo['left_time'], 2),
  151. }
  152. lineInfo = ctrInfo.get(portId, {})
  153. if lineInfo.get('status') == 1:
  154. if portDict['status'] == 1:
  155. lineInfo.update(portDict)
  156. if portDict['status'] == 0:
  157. ServiceProgress.objects.filter(**{
  158. 'device_imei': self.device['devNo'],
  159. 'port': int(portId), 'isFinished': False
  160. }).update(isFinished=True, expireAt = datetime.datetime.now())
  161. lineInfo.update(portDict)
  162. else:
  163. lineInfo['status'] = portDict['status']
  164. result[portId] = lineInfo
  165. else:
  166. Device.clear_port_control_cache(self._device['devNo'], portId)
  167. result[portId] = portDict
  168. allPorts += 1
  169. result.update({'usedPorts': usedPorts, 'allPorts': allPorts, 'usePorts': allPorts - usedPorts})
  170. Device.update_dev_control_cache(self._device['devNo'], result)
  171. return result
  172. def get_port_info(self, line):
  173. line = self.get_port_from_ab(line)
  174. portCache = self.get_port_status_from_dev()
  175. return portCache.get(str(line), {})
  176. def __translate_status_from_str(self, status):
  177. dictConf = {
  178. '0': Const.DEV_WORK_STATUS_IDLE,
  179. '1': Const.DEV_WORK_STATUS_WORKING,
  180. '2': Const.DEV_WORK_STATUS_FAULT,
  181. '3': Const.DEV_WORK_STATUS_FORBIDDEN,
  182. }
  183. return dictConf.get(status, Const.DEV_WORK_STATUS_FAULT)
  184. def get_port_status(self, force=False):
  185. if force:
  186. self.get_port_status_from_dev()
  187. portCache = Device.get_dev_control_cache(self._device['devNo'])
  188. result = {}
  189. for ii in range(5):
  190. if str(ii) in portCache:
  191. if ii == 1:
  192. result['A'] = portCache[str(ii)]
  193. elif ii == 2:
  194. result['B'] = portCache[str(ii)]
  195. elif ii == 3:
  196. result['C'] = portCache[str(ii)]
  197. return result
  198. def lock_unlock_port(self, port, lock=True):
  199. port = self.get_port_from_ab(port)
  200. portInfo = self.get_port_info(port)
  201. if portInfo['status'] == Const.DEV_WORK_STATUS_WORKING:
  202. raise ServiceException({'result': 2, 'description': u'当前端口正在使用,请您先关闭掉后,再操作'})
  203. if lock:
  204. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  205. {'IMEI': self._device['devNo'],
  206. 'data': {'fun_code': 0x60, 'port_id': port, 'action': 1}})
  207. else:
  208. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  209. {'IMEI': self._device['devNo'],
  210. 'data': {'fun_code': 0x60, 'port_id': port, 'action': 0}})
  211. self.check_feedback_result(devInfo)
  212. if lock:
  213. Device.update_dev_control_cache(self._device['devNo'],
  214. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  215. else:
  216. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  217. # 停止该端口下的所有任务
  218. def stop_charging_port(self, port):
  219. port = self.get_port_from_ab(port)
  220. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  221. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x06, 'port_id': port}})
  222. self.check_feedback_result(devInfo)
  223. if devInfo['rst'] == 0:
  224. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  225. return True if devInfo['rst'] == 0 else False
  226. def add_to_gateway(self, gatewayDevNo):
  227. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  228. {'IMEI': gatewayDevNo,
  229. 'data': {'fun_code': 0x03, 'sub_id': self._device['devNo']}})
  230. self.check_feedback_result(devInfo)
  231. # 子节点的父节点也要更新
  232. devObj = Device.objects.get(devNo=self._device['devNo'])
  233. devObj.gatewayNode = gatewayDevNo
  234. devObj.save()
  235. def remove_from_gateway(self, gatewayDevNo):
  236. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  237. {'IMEI': gatewayDevNo,
  238. 'data': {'fun_code': 0x05, 'sub_id': self._device['devNo']}})
  239. self.check_feedback_result(devInfo)
  240. # 子节点的父节点也要更新
  241. devObj = Device.objects.get(devNo=self._device['devNo'])
  242. devObj.gatewayNode = ''
  243. devObj.save()
  244. # 获取设备配置参数
  245. def get_dev_setting(self):
  246. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  247. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x12}})
  248. self.check_feedback_result(devInfo)
  249. configs = devInfo['data']['configs']
  250. modeDict = {'0': 'time', '1': 'power', '2': 'elec'}
  251. configs['chrmt_mode'] = modeDict.get(str(configs['chrmt_mode']))
  252. online_card_chrmt = str(self.device['otherConf'].get('online_card_chrmt', 1))
  253. configs['online_card_chrmt'] = modeDict.get(online_card_chrmt)
  254. configs['online_card_cost'] = self.device['otherConf'].get('online_card_cost', 10)
  255. configs['online_card_val'] = self.device['otherConf'].get('online_card_val', 240)
  256. configs['refundProtectionTime'] = self.device['otherConf'].get('refundProtectionTime', 5)
  257. return configs
  258. # 获取设备配置参数
  259. def set_dev_setting(self, setConf):
  260. configs = {'fun_code': 0x11}
  261. configs['mach_max_watt'] = int(setConf['mach_max_watt'])
  262. configs['port_max_watt'] = int(setConf['port_max_watt'])
  263. configs['noload_check_watt'] = int(setConf['noload_check_watt'])
  264. configs['noload_check_time'] = int(setConf['noload_check_time'])
  265. configs['float_charge_watt'] = int(setConf['float_charge_watt'])
  266. configs['float_charge_time'] = int(setConf['float_charge_time'])
  267. configs['power_lev_max'] = int(setConf['power_lev_max'])
  268. configs['power_lv1_watt'] = int(setConf['power_lv1_watt'])
  269. configs['power_lv1_time'] = int(setConf['power_lv1_time'])
  270. configs['power_lv2_watt'] = int(setConf['power_lv2_watt'])
  271. configs['power_lv2_time'] = int(setConf['power_lv2_time'])
  272. configs['power_lv3_watt'] = int(setConf['power_lv3_watt'])
  273. configs['power_lv3_time'] = int(setConf['power_lv3_time'])
  274. configs['once_card_cost'] = int(setConf['once_card_cost'])
  275. configs['card_lv1_val'] = int(setConf['card_lv1_val'])
  276. configs['card_lev_max'] = int(setConf['card_lev_max'])
  277. configs['card_refund_en'] = int(setConf['card_refund_en'])
  278. configs['coin_en'] = int(setConf['coin_en'])
  279. configs['volume'] = int(setConf['volume'])
  280. configs['temp_threshold'] = int(setConf['temp_threshold'])
  281. configs['close_for_full'] = int(setConf['close_for_full'])
  282. configs['chrmt_mode'] = {'time': 0, 'power': 1, 'elec': 2}.get(setConf['chrmt_mode'])
  283. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  284. {'IMEI': self._device['devNo'], 'data': configs})
  285. self.check_feedback_result(devInfo)
  286. billingType = setConf['chrmt_mode']
  287. online_card_chrmt = {'time': 0, 'power': 1, 'elec': 2}.get(setConf['online_card_chrmt'])
  288. online_card_cost = int(setConf['online_card_cost'])
  289. online_card_val = int(setConf['online_card_val'])
  290. refundProtectionTime = int(setConf.get('refundProtectionTime', 5))
  291. Device.get_collection().update_one({'devNo': self.device['devNo']},
  292. {'$set': {
  293. 'otherConf.billingType': billingType,
  294. 'otherConf.online_card_chrmt': online_card_chrmt,
  295. 'otherConf.online_card_cost': online_card_cost,
  296. 'otherConf.online_card_val': online_card_val,
  297. 'otherConf.refundProtectionTime': refundProtectionTime,
  298. }})
  299. Device.invalid_device_cache(self.device.devNo)
  300. def ack_event(self, orderNo, funCode):
  301. devInfo = MessageSender.send(self.device, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
  302. {'IMEI': self._device['devNo'],
  303. 'data': {'fun_code': funCode, 'order_id': orderNo}})
  304. self.check_feedback_result(devInfo)
  305. def reboot_device(self):
  306. data = {'fun_code': 0x04}
  307. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'], 'data': data})
  308. def active_deactive_port(self, port, active):
  309. port = self.get_port_from_ab(port)
  310. if active:
  311. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  312. return self.stop_charging_port(port)
  313. def set_device_function(self,request, lastSetConf):
  314. print request.POST
  315. if request.POST.get('reboot', False) == True:
  316. self.reboot_device()
  317. def set_device_function_param(self, request, lastSetConf):
  318. newConf = copy.deepcopy(request.POST)
  319. lastSetConf.update(newConf)
  320. self.set_dev_setting(lastSetConf)
  321. def isHaveStopEvent(self):
  322. return True
  323. def stop(self, port=None):
  324. return self.stop_charging_port(port)
  325. def set_dev_disable(self, disable):
  326. """
  327. 设备端锁定解锁设备
  328. :param disable:
  329. :return:
  330. """
  331. Device.get_collection().update_one({'devNo': self._device['devNo']}, {
  332. '$set': {'otherConf.disableDevice': disable}})
  333. Device.invalid_device_cache(self.device.devNo)