bolai_ten.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import copy
  4. import logging
  5. import datetime
  6. import time
  7. from typing import TYPE_CHECKING
  8. from apps.web.constant import Const
  9. from apps.web.core.exceptions import ServiceException
  10. from apps.web.core.adapter.base import SmartBox, start_error_timer
  11. from apps.web.core.device_define.baolai import send_request
  12. from apps.web.device.models import Device
  13. from apps.web.user.models import ConsumeRecord
  14. if TYPE_CHECKING:
  15. pass
  16. logger = logging.getLogger(__name__)
  17. # 2.4 , 2.6 , 2.12 , 2.14 , 2.15 , 3.2 , 3.3 , 3.4 , 3.5 , 3.6 , 3.7 , 3.9
  18. class SampleData:
  19. """
  20. sampleMap = {
  21. "max_power":200, # 单路最大充电功率,单位W
  22. "charge_full_power_threshold":10, # 充满阈值,单位W,默认10W
  23. "charge_full_time_threshold":7200, # 浮充时间,单位s,默认7200s
  24. "charge_single_amount":100, # 单次按键金额,单位分,默认1.00
  25. "max_time":900, # 最大充电时间,单位分,默认600分
  26. "trickle_threshold":10, # 未开放,暂勿需对接
  27. "no_load_power_threshold":2.5, # 空载阈值,单位W,默认0.8W
  28. "high_temperature_threshold":85, # 过温阈值,单位℃,默认60℃
  29. "max_current":12, # 单路最大电流,单位A
  30. "no_load_time_threshold":45 # 空载时间,单位s,默认45s
  31. }
  32. """
  33. sampleMap = {
  34. 'max_power': 0,
  35. 'charge_full_power_threshold': 0,
  36. 'charge_full_time_threshold': 0,
  37. 'charge_single_amount': 0,
  38. 'max_time': 0,
  39. 'trickle_threshold': 0,
  40. 'no_load_power_threshold': 0,
  41. 'high_temperature_threshold': 0,
  42. 'max_current': 0,
  43. 'no_load_time_threshold': 0,
  44. }
  45. class BoLaiTenCharge(SmartBox):
  46. def __init__(self, device):
  47. super(BoLaiTenCharge, self).__init__(device)
  48. devObj = self.device.my_obj
  49. self.billingType = devObj.otherConf.get('billingType', 'time')
  50. self.config_list = devObj.otherConf.get('config_list', [])
  51. self.onceCard = devObj.otherConf.get('onceCard', 100)
  52. self.cardTime = devObj.otherConf.get('cardTime', 180)
  53. self.cardElec = devObj.otherConf.get('cardElec', 1)
  54. # 2.4 配置节点最大充电功率
  55. def _set_dev_max_power(self, portConfig):
  56. for port,conf in portConfig.items():
  57. setInfo = {'gateway_id': self.device.devNo,
  58. 'node_index': 0,
  59. 'port_index': int(port)-1,
  60. 'max_current': conf['max_current'],
  61. 'max_power': conf['max_max_power'],
  62. 'timeout': 5}
  63. devInfo = self._send_request("cmd/set-node-config", setInfo,"2")
  64. if devInfo['data']['code'] != 0:
  65. raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
  66. def _send_request(self, cmdPath, jsonPara, cmdKind):
  67. return send_request(self.device.devNo, self.device.devNo, cmdPath, jsonPara,cmdKind)
  68. # 2.6 获取节点最大充电功率 /2/cmd/get-node-config
  69. def _get_dev_max_power(self):
  70. portConfig = {}
  71. for i in range(12):
  72. setConf = {"gateway_id": self.device.devNo,
  73. "node_index": 0,
  74. "port_index": i}
  75. devInfo = self._send_request("cmd/get-node-config", setConf,"2")
  76. if devInfo['data']['code'] != 0:
  77. raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
  78. config = devInfo['data']['data']
  79. portConfig.update({str(i+1):{"max_current": config['max_current'], "max_max_power": config['max_power']}})
  80. return portConfig
  81. # 2.12 控制节点(充电柜/十二路/十路机/六路机/独立版) /3/cmd/control,
  82. def _start_device(self, jsonPara):
  83. return self._send_request("cmd/control", jsonPara,"3")
  84. # 2.14 设置系统参数 /3/cmd/set-node-config,
  85. def _set_dev_setting(self, setConf):
  86. setConf.update({'node_index': 0})
  87. devObj = Device.objects.get(devNo=self._device['devNo'])
  88. devObj.otherConf.update({
  89. 'billingType': setConf['chargeType'], # 前端直接传elec,time,power
  90. 'onceCard': int(float(setConf['onceCard'])),
  91. 'cardTime': int(setConf['cardTime']),
  92. 'cardElec': float(setConf['cardElec']),
  93. 'config_list': setConf['config_list'],
  94. })
  95. devObj.save()
  96. setConf.pop('chargeType')
  97. setConf.pop('onceCard')
  98. setConf.pop('cardTime')
  99. setConf.pop('cardElec')
  100. setConf.pop('config_list')
  101. setConf['charge_single_amount'] = int(setConf['charge_single_amount']) * 100
  102. setConf.update({
  103. 'charge_full_time_threshold': int(setConf['charge_full_timeout']),
  104. 'no_load_time_threshold': int(setConf['no_load_timeout'])
  105. })
  106. setConf.pop('charge_full_timeout')
  107. setConf.pop('no_load_timeout')
  108. devInfo = self._send_request('cmd/set-node-config', setConf, 3)
  109. if devInfo['data']['code'] != 0:
  110. raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
  111. return devInfo
  112. # 2.15 读取系统参数 /3/cmd/get-node-config,
  113. def get_dev_setting(self):
  114. setConf = {
  115. "gateway_id": self.device.devNo,
  116. "node_index": 0,
  117. }
  118. devInfo = self._send_request("cmd/get-node-config", setConf,3)
  119. if devInfo['data']['code'] != 0:
  120. raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
  121. config = devInfo['data']['data']
  122. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE:
  123. portConfig = self._get_dev_max_power()
  124. config.update({'portConfig':portConfig})
  125. config.update({
  126. 'chargeType': str(self.billingType),
  127. 'onceCard': self.onceCard,
  128. 'cardTime': self.cardTime,
  129. 'cardElec': self.cardElec,
  130. 'config_list': self.config_list,
  131. 'charge_full_timeout': config['charge_full_time_threshold'],
  132. 'no_load_timeout': config['no_load_time_threshold']
  133. })
  134. config['charge_single_amount'] = config['charge_single_amount'] * 0.01
  135. return config
  136. # 3.2 , 3.3 , 3.4 , 3.5 , 3.6 , 3.7 , 3.9
  137. @start_error_timer(
  138. missMessages=[u"请您选择合适的充电线路、电池类型信息", u"请您选择合适的充电线路", u"该端口正在使用中"])
  139. def start_device(self, package, openId, attachParas):
  140. if attachParas is None:
  141. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  142. if not attachParas.has_key('chargeIndex'):
  143. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  144. # 端口从0开始
  145. port = int(attachParas['chargeIndex'])
  146. # attachParas['chargeIndex'] = port
  147. unit = package.get('unit', u'分钟')
  148. needTime, needElec = None, None
  149. jsonPara = {'gateway_id': self.device.devNo, 'node_index': 0, 'port_index': port-1, \
  150. 'switch_state': 1, 'control__type': 1, 'timeout': 10,'charge_energy': 0,\
  151. 'charge_time': 0}
  152. # 按时充电
  153. if self.billingType == 'time':
  154. if unit == u'秒':
  155. if int(package['time']) < 60:
  156. raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'})
  157. needTime = int(float(package['time']) / 60.0)
  158. jsonPara.update({'charge_time': needTime, 'charge_type': 1})
  159. elif unit == u'分钟':
  160. needTime = int(float(package['time']))
  161. jsonPara.update({'charge_time': needTime, 'charge_type': 1})
  162. elif unit == u'小时':
  163. needTime = int(float(package['time']) * 60)
  164. jsonPara.update({'charge_time': needTime, 'charge_type': 1})
  165. elif unit == u'天':
  166. needTime = int(float(package['time']) * 60 * 24)
  167. jsonPara.update({'charge_time': needTime, 'charge_type': 1})
  168. else:
  169. raise ServiceException({'result': 2, 'description': u'运营商没有配置正确的套餐,请运营商配置正确的套餐'})
  170. # 按量充电
  171. elif self.billingType == 'elec':
  172. if unit == u'度':
  173. needElec = int(float(package['time']) * 1000) # 微度
  174. jsonPara.update({'charge_energy': needElec, 'charge_type': 2})
  175. else:
  176. raise ServiceException({'result': 2, 'description': u'运营商没有配置正确的套餐,请运营商配置正确的套餐'})
  177. # 按功率充电
  178. else:
  179. if not self.config_list:
  180. raise ServiceException(
  181. {'result': 2, 'description': u'运营商没有配置正确的分档功率,请运营商配置正确的分档功率'})
  182. """
  183. charge_power = {
  184. "money":"",
  185. "config_list":[{
  186. "power":"",
  187. "price":"",
  188. "time":"",
  189. }]
  190. }
  191. """
  192. needTime = int(float(package['time']))
  193. coins = int(float(package['coins']) * 100) # 单位为分
  194. jsonPara.update({'charge_power': {'money': coins, 'config_list': self.config_list}})
  195. jsonPara.update({'charge_type': 3})
  196. jsonPara.pop('charge_energy')
  197. jsonPara.pop('charge_time')
  198. devInfo = self._send_request("cmd/control", jsonPara,"3")
  199. if devInfo['data']['code'] != 0:
  200. raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
  201. if devInfo['rst'] == 0: # 成功
  202. newValue = {
  203. str(port): {
  204. 'status': Const.DEV_WORK_STATUS_WORKING,
  205. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  206. 'controlType': 1
  207. }
  208. }
  209. else:
  210. raise ServiceException({'result': 2, 'description': u'充电插座响应异常,请您稍后再试哦'})
  211. servicedInfo = {}
  212. if self.billingType == 'time':
  213. finishedTime = int(time.time()) + needTime * 60
  214. devInfo['needTime'] = needTime
  215. servicedInfo.update({'needTime': needTime, 'billingType': 'time'})
  216. elif self.billingType == 'elec':
  217. finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束
  218. devInfo['needElec'] = float(package['time'])
  219. servicedInfo.update({'needElec': float(package['time']), 'billingType': 'elec'})
  220. else:
  221. finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束
  222. servicedInfo.update({'billingType': 'power'})
  223. newValue[str(port)].update({'power': 10}) # 端口下的数据依赖心跳上报,但是心跳有时间间隔,这样查看服务的时候,因为功率是0,会认为已经结束,这里给一个初始值
  224. sequanceNo = devInfo['data']['data']['transaction_id']
  225. newValue[str(port)].update({'finishedTime': finishedTime,'sequanceNo':sequanceNo})
  226. Device.clear_port_control_cache(self._device['devNo'], port)
  227. Device.update_dev_control_cache(self._device['devNo'], newValue)
  228. devInfo['finishedTime'] = finishedTime
  229. devInfo['sequanceNo'] = sequanceNo
  230. devInfo['servicedInfo'] = servicedInfo
  231. return devInfo
  232. def stop_charging_port(self,port):
  233. portInfo = self.get_port_info(port)
  234. controlType = portInfo.get('controlType', 1)
  235. jsonPara = {'node_index': 0, 'port_index': port, 'charge_type': 3, 'switch_state': 0,'control__type':controlType}
  236. if self.billingType == 'power':
  237. jsonPara.update({'charge_power': {'money': 0,'config_list': self.config_list}})
  238. devInfo = self._send_request('cmd/control', jsonPara, 3)
  239. elif self.billingType == 'time':
  240. jsonPara.update({'charge_time': 0, 'charge_type': 1})
  241. devInfo = self._send_request('cmd/control', jsonPara, 3)
  242. else:
  243. jsonPara.update({'charge_energy': 0, 'charge_type': 2})
  244. devInfo = self._send_request('cmd/control', jsonPara, 3)
  245. if devInfo['data']['code'] != 0:
  246. raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'})
  247. if devInfo['rst'] == 0:
  248. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  249. return True if devInfo['rst'] == 0 else False
  250. def get_port_status_from_dev(self):
  251. # 解析缓存
  252. return self.get_port_status()
  253. def get_port_info(self, port):
  254. '''
  255. 获取 端口的详细信息
  256. :param port:
  257. :return:
  258. '''
  259. port=int(port)
  260. devCache = Device.get_dev_control_cache(self.device.devNo)
  261. return devCache.get(str(port), dict())
  262. def get_port_status(self, force=False):
  263. '''
  264. 获取设备状态
  265. :param force:
  266. :return:
  267. '''
  268. statusDict = dict()
  269. devCache = Device.get_dev_control_cache(self._device['devNo'])
  270. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE:
  271. allPorts = devCache.get('allPorts', 12)
  272. else:
  273. allPorts = devCache.get('allPorts', 10)
  274. for portNum in range(allPorts):
  275. tempDict = devCache.get(str(portNum + 1), {})
  276. if 'status' in tempDict:
  277. statusDict[str(portNum + 1)] = {'status': tempDict.get('status')}
  278. if tempDict['status'] == 1:
  279. try:
  280. order = ConsumeRecord.get_consumed_records(sequanceNo=tempDict['sequanceNo'])[0]
  281. startTime = order.dateTimeAdded
  282. usedTime = (datetime.datetime.now() - startTime).seconds / 60
  283. statusDict[str(portNum + 1)].update({'usedTime':usedTime})
  284. except:
  285. pass
  286. elif 'isStart' in tempDict:
  287. if tempDict['isStart']:
  288. statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  289. else:
  290. statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  291. else:
  292. statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  293. Device.update_dev_control_cache(self._device['devNo'],statusDict)
  294. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  295. Device.update_dev_control_cache(self._device['devNo'],
  296. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  297. return statusDict
  298. def set_device_function_param(self, request, lastSetConf):
  299. newConf = copy.deepcopy(request.POST)
  300. newConf.pop('logicalCode', None)
  301. if 'portConfig' in newConf:
  302. portConfig = newConf.pop('portConfig')
  303. self._set_dev_setting(newConf)
  304. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE:
  305. self._set_dev_max_power(portConfig)
  306. Device.invalid_device_cache(self.device.devNo)
  307. def active_deactive_port(self, port, active):
  308. port = int(port)-1
  309. if active:
  310. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  311. return self.stop_charging_port(port)
  312. def get_server_setting(self):
  313. refundProtectionTime = self.device.otherConf.get('refundProtectionTime',5)
  314. return refundProtectionTime
  315. def set_server_setting(self,payload):
  316. refundProtectionTime = int(payload['refundProtectionTime'])
  317. self.device.update_other_conf(refundProtectionTime=refundProtectionTime)