device.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import logging
  4. import datetime
  5. import struct
  6. from ctypes import create_string_buffer
  7. from apilib.utils import xor_encrypt_buffer
  8. from apps.web.core.exceptions import ServiceException
  9. from .utils import pollDeviceInfo
  10. logger = logging.getLogger(__name__)
  11. class BtSmartBox(object):
  12. def __init__(self, device):
  13. self._device = device
  14. super(BtSmartBox, self).__init__()
  15. def support_count_down(self):
  16. return False
  17. def encode_cmd(self, cmdId, **kwargs):
  18. pass
  19. def decode_cmd(self, cmdId, command):
  20. pass
  21. def poll_notify(self, payload, **kwargs):
  22. return 1, ''
  23. def encrypt(self, buffer, offset = 4):
  24. xor_encrypt_buffer(buffer, offset, self._device['devNo'])
  25. for index in range(offset, offset + (20 - offset + 1) / 2):
  26. swap_index = 20 + offset - 1 - index
  27. left = ord(buffer.raw[index])
  28. right = ord(buffer.raw[swap_index])
  29. struct.pack_into('<B', buffer, index, right)
  30. struct.pack_into('<B', buffer, swap_index, left)
  31. return buffer
  32. def decrypt(self, buffer, offset = 4):
  33. for index in range(offset, offset + (20 - offset + 1) / 2):
  34. swap_index = 20 + offset - 1 - index
  35. left = ord(buffer.raw[index])
  36. right = ord(buffer.raw[swap_index])
  37. struct.pack_into('<B', buffer, index, right)
  38. struct.pack_into('<B', buffer, swap_index, left)
  39. return xor_encrypt_buffer(buffer, offset, self._device['devNo'])
  40. class BtChargingSocket(BtSmartBox):
  41. def __init__(self, device):
  42. super(BtChargingSocket, self).__init__(device)
  43. def poll_notify(self, payload, **kwargs):
  44. return 1, ''
  45. def encode_cmd(self, cmdId, **kwargs):
  46. package = kwargs['attachParas']['package']
  47. if cmdId == 1:
  48. time = int(package['time'])
  49. buf = create_string_buffer(20)
  50. struct.pack_into('<BH', buf, 0, 1, time)
  51. return ''.join('{:02x}'.format(ord(c)) for c in buf.raw)
  52. class BtPulseDevice(BtSmartBox):
  53. def __init__(self, device):
  54. super(BtPulseDevice, self).__init__(device)
  55. """
  56. 脉冲设备支持命令
  57. cmdId = 1, 编码格式为 seqNo: 4, cmdId: 1, pulse: 2, pulseWidth: 2, pulseInterval: 2, battery: 1, year: 2, month: 1, day: 1
  58. """
  59. def encode_cmd(self, cmdId, **kwargs):
  60. if cmdId == 1:
  61. nowTime = datetime.datetime.now()
  62. year = int(nowTime.year)
  63. month = int(nowTime.month)
  64. day = int(nowTime.day)
  65. package = kwargs['attachParas']['package']
  66. pulse = int(package['coins'])
  67. buf = create_string_buffer(20)
  68. if self._device['major'] > 1 or self._device['minor'] > 1: # 从第二个版本开始支持加密功能
  69. if 'chargeIndex' in kwargs['attachParas'] and kwargs['attachParas']['chargeIndex'] and \
  70. kwargs['attachParas']['chargeIndex'] != 'undefined':
  71. s = struct.Struct('<IBHHHBHBBc')
  72. s.pack_into(buf, 0,
  73. int(kwargs['seqNo']), cmdId, pulse,
  74. int(self._device['pulseWidth1']),
  75. int(self._device['pulseInterval1']),
  76. int(self._device['battery']),
  77. year, month, day, kwargs['attachParas']['chargeIndex'])
  78. else:
  79. s = struct.Struct('<IBHHHBHBB')
  80. s.pack_into(buf, 0,
  81. int(kwargs['seqNo']), cmdId, pulse,
  82. int(self._device['pulseWidth1']),
  83. int(self._device['pulseInterval1']),
  84. int(self._device['battery']),
  85. year, month, day)
  86. if self._device['major'] > 2 or (self._device['major'] == 2 and self._device['minor'] >= 2):
  87. buf = self.encrypt(buf, 5)
  88. else:
  89. buf = self.encrypt(buf)
  90. else:
  91. s = struct.Struct('<BHHHHBB')
  92. s.pack_into(buf, 0, cmdId, pulse, int(self._device['pulseWidth1']),
  93. int(self._device['pulseInterval1']), year, month, day)
  94. return ''.join('{:02x}'.format(ord(c)) for c in buf.raw)
  95. else:
  96. raise Exception(u'不支持的命令')
  97. def poll_notify(self, payload, **kwargs):
  98. try:
  99. if len(payload) % 2 != 0:
  100. raise ServiceException({'result': 0, 'description': u'参数不正确'})
  101. buf = create_string_buffer(len(payload) / 2)
  102. index = 0
  103. step = 0
  104. token = '0x'
  105. for c in payload:
  106. if index != 0 and index % 2 == 0:
  107. struct.pack_into('<B', buf, step, int(token, 16))
  108. token = '0x'
  109. step += 1
  110. token += c
  111. index += 1
  112. year, month, day, coins = struct.unpack_from('<HBBL', buf, 0)
  113. pollDeviceInfo(self._device, kwargs['major'], kwargs['minor'], year, month, day, coins)
  114. except Exception, e:
  115. logger.exception(e)
  116. return 1, ''
  117. class BtSoftSwitch(BtSmartBox):
  118. def __init__(self, device):
  119. super(BtSoftSwitch, self).__init__(device)
  120. def encode_cmd(self, cmdId, **kwargs):
  121. if cmdId == 1:
  122. nowTime = datetime.datetime.now()
  123. year = int(nowTime.year)
  124. month = int(nowTime.month)
  125. day = int(nowTime.day)
  126. package = kwargs['attachParas']['package']
  127. time = long(package['time'])
  128. unit = package.get('unit', u'分钟')
  129. if unit == u'分钟':
  130. time = int(time * 60)
  131. elif unit == u'小时':
  132. time = int(time * 3600)
  133. elif unit == u'天':
  134. time = int(time * 24 * 3600)
  135. buf = create_string_buffer(20)
  136. s = struct.Struct('<IBHBBIB')
  137. s.pack_into(buf, 0,
  138. int(kwargs['seqNo']), cmdId, year, month, day, time, 1)
  139. buf = self.encrypt(buf)
  140. return ''.join('{:02x}'.format(ord(c)) for c in buf.raw)
  141. elif cmdId == 2:
  142. if self._device['major'] > 1 or self._device['minor'] > 1: # 从第二个版本开始支持确认功能
  143. buf = create_string_buffer(20)
  144. s = struct.Struct('<IB')
  145. s.pack_into(buf, 0,
  146. int(kwargs['seqNo']), cmdId)
  147. return self.encrypt(buf)
  148. raise ServiceException({'result': 0, 'description': u'参数不正确'})
  149. class BtTimeSwitchIR(BtSmartBox):
  150. class HOT(object):
  151. NO_HEAT = 0x0
  152. HEAT = 0x08
  153. NOT_ASSIGNED = 0x0
  154. class STRENGTH(object):
  155. STRENGTH_1 = 0x0
  156. STRENGTH_2 = 0x10
  157. STRENGTH_3 = 0x20
  158. STRENGTH_4 = 0x30
  159. NOT_ASSIGNED = 0x0
  160. class MODE(object):
  161. MODE_1 = 0x80
  162. MODE_2 = 0x40
  163. MODE_3 = 0xC0
  164. NOT_ASSIGNED = 0x0
  165. def __init__(self, device):
  166. super(BtTimeSwitchIR, self).__init__(device)
  167. def support_count_down(self):
  168. return True
  169. def encode_cmd(self, cmdId, **kwargs):
  170. if cmdId == 1:
  171. now_time = datetime.datetime.now()
  172. year = int(now_time.year)
  173. month = int(now_time.month)
  174. day = int(now_time.day)
  175. package = kwargs['attachParas']['package']
  176. time = long(package['time'])
  177. unit = package.get('unit', u'分钟')
  178. if unit == u'分钟':
  179. time = int(time * 60)
  180. elif unit == u'小时':
  181. time = int(time * 3600)
  182. elif unit == u'天':
  183. time = int(time * 24 * 3600)
  184. mode = BtTimeSwitchIR.MODE.MODE_1
  185. strength = BtTimeSwitchIR.STRENGTH.STRENGTH_1
  186. is_hot = BtTimeSwitchIR.HOT.NO_HEAT
  187. attachParas = kwargs['attachParas']
  188. if 'isHot' in attachParas:
  189. is_hot = attachParas['isHot']
  190. if 'strength' in attachParas:
  191. strength = attachParas['strength']
  192. if 'mode' in attachParas:
  193. mode = attachParas['mode']
  194. buf = create_string_buffer(20)
  195. s = struct.Struct('<IBHBBIBBBB')
  196. s.pack_into(buf, 0,
  197. int(kwargs['seqNo']), cmdId, year, month, day, time, mode, strength, is_hot, 0)
  198. buf = self.encrypt(buf, 5)
  199. return ''.join('{:02x}'.format(ord(c)) for c in buf.raw)
  200. raise ServiceException({'result': 0, 'description': u'参数不正确'})
  201. class BtClothesTree(BtSmartBox):
  202. class MODE(object):
  203. MODE_COLD = 0x01
  204. MODE_HOT = 0x02
  205. def __init__(self, device):
  206. super(BtClothesTree, self).__init__(device)
  207. def support_count_down(self):
  208. return False
  209. def encode_cmd(self, cmdId, **kwargs):
  210. if cmdId == 1:
  211. now_time = datetime.datetime.now()
  212. year = int(now_time.year)
  213. month = int(now_time.month)
  214. day = int(now_time.day)
  215. package = kwargs['attachParas']['package']
  216. left_time = long(package['time'])
  217. unit = package.get('unit', u'分钟')
  218. if unit == u'分钟':
  219. left_time = int(left_time * 60)
  220. elif unit == u'小时':
  221. left_time = int(left_time * 3600)
  222. elif unit == u'天':
  223. left_time = int(left_time * 24 * 3600)
  224. mode = BtClothesTree.MODE.MODE_HOT
  225. attachParas = kwargs['attachParas']
  226. if 'mode' in attachParas:
  227. mode = attachParas['mode']
  228. is_cut_memory = 0
  229. buf = create_string_buffer(20)
  230. s = struct.Struct('<IBHBBIBB')
  231. s.pack_into(buf, 0,
  232. int(kwargs['seqNo']), cmdId, year, month, day, left_time, mode, is_cut_memory)
  233. buf = self.encrypt(buf, 5)
  234. return ''.join('{:02x}'.format(ord(c)) for c in buf.raw)
  235. raise ServiceException({'result': 0, 'description': u'参数不正确'})