shake_hand.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import struct
  6. from typing import TYPE_CHECKING
  7. from apps.web.core.accounting import Accounting
  8. from apps.web.device.models import Device
  9. from apps.web.device.timescale import FluentedEngine, OfflineManager
  10. from script.eventer.handlers import Handler
  11. logger = logging.getLogger(__name__)
  12. if TYPE_CHECKING:
  13. pass
  14. class ShakeHandHandler(Handler):
  15. def parse(self):
  16. logger.debug('orginal payload len: {}'.format(len(self.payload)))
  17. payload = struct.pack('<{}s4s'.format(len(self.payload)), self.payload, '0000')
  18. logger.debug('now payload len: {}'.format(len(payload)))
  19. offset = 0
  20. ts = struct.unpack_from('<I', payload, offset = offset)[0]
  21. offset = offset + 4
  22. signal = struct.unpack_from('<B', payload, offset = offset)[0]
  23. offset = offset + 1
  24. logger.debug('ts = {}; signal = {}'.format(ts, signal))
  25. rv = {
  26. 'ts': ts,
  27. 'signal': signal
  28. }
  29. while offset < (len(payload) - 4):
  30. _type = struct.unpack_from('<B', payload, offset = offset)[0]
  31. offset = offset + 1
  32. if _type == 0x01:
  33. # coins: 2
  34. coins = struct.unpack_from('<H', payload, offset = offset)[0]
  35. offset = offset + 2
  36. logger.debug('coins = {}'.format(coins))
  37. rv.update({'today_coins': coins})
  38. elif _type == 0x02:
  39. # start_no:1, end_no:1, used_ports: 1, [port:1, power:2]*
  40. rv.update({'powers': {}})
  41. start_no = struct.unpack_from('<B', payload, offset = offset)[0]
  42. offset = offset + 1
  43. end_no = struct.unpack_from('<B', payload, offset = offset)[0]
  44. offset = offset + 1
  45. used = struct.unpack_from('<B', payload, offset = offset)[0]
  46. offset = offset + 1
  47. logger.debug('start_no = {}; end_no = {}; used ports = {}'.format(start_no, end_no, used))
  48. for i in range(0, used):
  49. port, power = struct.unpack_from('<BH', payload, offset = offset)
  50. offset = offset + 3
  51. logger.debug('port = {}, power = {}'.format(port, power))
  52. rv['powers'][str(port)] = {
  53. 'power': power
  54. # 'voltage': '-',
  55. # 'current': '-'
  56. }
  57. for i in range(start_no, end_no + 1):
  58. if str(i) not in rv['powers']:
  59. rv['powers'][str(i)] = {
  60. 'power': 0
  61. # 'voltage': '-',
  62. # 'current': '-'
  63. }
  64. elif _type == 0x03:
  65. # voltage: 2, start_no:1, end_no:1, used_ports: 1, [port:1, power:2, current:2]*
  66. rv.update({'powers': {}})
  67. voltage = struct.unpack_from('<H', payload, offset = offset)[0]
  68. voltage = str(round(float(voltage) / 10, 2))
  69. offset = offset + 2
  70. logger.debug('voltage = {}'.format(voltage))
  71. start_no = struct.unpack_from('<B', payload, offset = offset)[0]
  72. offset = offset + 1
  73. end_no = struct.unpack_from('<B', payload, offset = offset)[0]
  74. offset = offset + 1
  75. used = struct.unpack_from('<B', payload, offset = offset)[0]
  76. offset = offset + 1
  77. logger.debug('start_no = {}; end_no = {}; used ports = {}'.format(start_no, end_no, used))
  78. for i in range(0, used):
  79. port, power, current = struct.unpack_from('<BHH', payload, offset = offset)
  80. offset = offset + 5
  81. logger.debug('port = {}, power = {}, current = {}'.format(port, power, current))
  82. rv['powers'][str(port)] = {
  83. 'power': power,
  84. 'voltage': voltage,
  85. 'current': current
  86. }
  87. for i in range(start_no, end_no + 1):
  88. if str(i) not in rv['powers']:
  89. rv['powers'][str(i)] = {
  90. 'power': 0,
  91. 'voltage': voltage,
  92. 'current': 0
  93. }
  94. elif _type == 0x05:
  95. # start_no:1, end_no:1, used_ports: 1, [port:1, power:2]*
  96. rv.update({'powers': {}})
  97. start_no = struct.unpack_from('<B', payload, offset = offset)[0]
  98. offset = offset + 1
  99. end_no = struct.unpack_from('<B', payload, offset = offset)[0]
  100. offset = offset + 1
  101. used = struct.unpack_from('<B', payload, offset = offset)[0]
  102. offset = offset + 1
  103. logger.debug('start_no = {}; end_no = {}; used ports = {}'.format(start_no, end_no, used))
  104. for i in range(0, used):
  105. port, power = struct.unpack_from('<BH', payload, offset = offset)
  106. offset = offset + 3
  107. logger.debug('port = {}, power = {}'.format(port, power))
  108. rv['powers'][str(port)] = {
  109. 'power': self.dev.deviceAdapter.format_upload_power(power)
  110. # 'voltage': '-',
  111. # 'current': '-'
  112. }
  113. for i in range(start_no, end_no + 1):
  114. if str(i) not in rv['powers']:
  115. rv['powers'][str(i)] = {
  116. 'power': 0
  117. # 'voltage': '-',
  118. # 'current': '-'
  119. }
  120. # weifule 的设备
  121. elif _type == 0x06: # 订单号 + 已用金额
  122. length = struct.unpack_from('b', payload, offset=offset)[0]
  123. offset += 1
  124. order_id = struct.unpack_from('{}s'.format(length), payload, offset=offset)[0]
  125. offset += length
  126. money = struct.unpack_from('<H', payload, offset=offset)[0]
  127. offset += 2
  128. logger.info('upload heartbeat order=<{}>, money=<{}>'.format(order_id, money))
  129. from apps.web.user.models import ConsumeRecord
  130. from mongoengine import Q
  131. order = ConsumeRecord.objects.filter(Q(orderNo=order_id) | Q(startKey=order_id)).first()
  132. if not order:
  133. continue
  134. lts = order.servicedInfo.get('lts')
  135. if lts and lts['ts'] >= ts:
  136. continue
  137. else:
  138. order.servicedInfo['lts'] = {
  139. 'ts': ts,
  140. 'money': money
  141. }
  142. order.save()
  143. continue
  144. elif _type == 0x00:
  145. # 定制设备类型同步.由各设备类型自己解析和处理数据
  146. length = struct.unpack_from('<H', payload, offset = offset)[0]
  147. offset = offset + 2
  148. value = struct.unpack_from('{}s'.format(length), payload, offset = offset)[0]
  149. offset = offset + length
  150. self.dev.deviceAdapter.do_heartbeat(value, ts)
  151. if 'powers' in rv and not self.dev.support_power_graph:
  152. Device.get_collection().update_one({'devNo': self.dev.devNo}, {'$set': {'otherConf.supportPG': True}})
  153. Device.invalid_device_cache(self.dev.devNo)
  154. return rv
  155. def do(self):
  156. rv = self.parse()
  157. OfflineManager.discard_device_offline_notify(devNo = self.dev.devNo)
  158. ts = rv['ts']
  159. signal = rv['signal']
  160. FluentedEngine().in_signal_udp(devNo = self.dev.devNo, ts = ts, signal = signal, cmd = self.cmd)
  161. if 'today_coins' in rv:
  162. Accounting.syncOfflineCoin(self.dev,
  163. datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d'),
  164. int(rv['today_coins']))
  165. for port, item in rv.get('powers', {}).iteritems():
  166. FluentedEngine().in_power_udp(devNo = self.dev.devNo,
  167. port = str(port),
  168. ts = ts,
  169. power = item['power'],
  170. voltage = item.get('voltage', None),
  171. current = item.get('current', None))