cmCZ.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. # coding=utf-8
  2. import logging
  3. from apps.web.constant import MQTT_TIMEOUT, DeviceCmdCode, Const
  4. from apps.web.core.adapter.base import SmartBox
  5. from apps.web.core.device_define.cmCZ import PORT_STATUS_MAP, DEV_PREFIX
  6. from apps.web.core.exceptions import ServiceException
  7. from apps.web.core.networking import MessageSender
  8. from apps.web.device.models import DeviceDict, Device
  9. logger = logging.getLogger(__name__)
  10. class CZGateway(SmartBox):
  11. """
  12. 诚马插座的网络代理
  13. """
  14. def _send_data(self, funCode, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=MQTT_TIMEOUT.NORMAL, addr=None):
  15. # 若是网关发送 则addr地址填充为0
  16. payload = {
  17. "IMEI": self.device.devNo,
  18. "funCode": funCode
  19. }
  20. if isinstance(data, dict):
  21. payload.update(data)
  22. payload.update({"addr": addr})
  23. else:
  24. addr = "{:08X}".format(addr or 0)
  25. payload["data"] = "{}{}".format(data, addr)
  26. result = MessageSender.send(
  27. device=self.device,
  28. cmd=cmd,
  29. payload=payload,
  30. timeout=timeout
  31. )
  32. if "rst" not in result:
  33. raise ServiceException({"result": 2, "description": u"串口通信异常(10001)"})
  34. if result["rst"] != 0:
  35. if result["rst"] == -1:
  36. raise ServiceException({"result": 2, "description": u"网络通信异常"})
  37. if result["rst"] == 1:
  38. raise ServiceException({"result": 2, "description": u"串口通信异常(10002)"})
  39. return result
  40. def _add_sub_device(self, subAddr):
  41. """
  42. 添加一台从机
  43. """
  44. _type, data = 0x01, int(subAddr)
  45. data = "{:02X}{:08X}".format(_type, data)
  46. result = self._send_data(funCode="37", data=data)
  47. if int(result["data"][16: 18], 16) == 0x01:
  48. raise ServiceException({"result": 2, "description": u"新增节点数量达到上限,添加失败"})
  49. if int(result["data"][16: 18], 16) == 0x02:
  50. raise ServiceException({"result": 2, "description": u"该节点已经存在,无需重复添加"})
  51. def _remove_sub_device(self, subAddr):
  52. _type, data = 0x02, int(subAddr)
  53. data = "{:02X}{:08X}".format(_type, data)
  54. result = self._send_data(funCode="37", data=data)
  55. # if int(result["data"][16: 18], 16) == 0x01:
  56. # raise ServiceException({"result": 2, "description": u"没有节点数量,删除失败"})
  57. # if int(result["data"][16: 18], 16) == 0x02:
  58. # raise ServiceException({"result": 2, "description": u"该设备尚未添加,删除失败"})
  59. def _read_sub_device(self):
  60. """
  61. 读取所有的从机
  62. """
  63. result = self._send_data(funCode="38", data="00")
  64. content = result["data"][16: -2]
  65. num = int(content[: 2], 16)
  66. offset = 2
  67. subs = list()
  68. for _subIndex in range(num):
  69. _sub = int(content[offset: offset+8], 16)
  70. subs.append(_sub)
  71. offset += 8
  72. return subs
  73. def _add_sub_device_many(self, subs):
  74. """
  75. 批量的同步从机地址
  76. """
  77. num = len(subs)
  78. data = "{:02X}".format(num)
  79. for _sub in subs:
  80. data += "{:08X}".format(_sub.addr)
  81. return self._send_data(funCode="39", data=data)
  82. def _get_gateway_channel(self):
  83. """
  84. 读取设备的信道
  85. """
  86. result = self._send_data(funCode="42", data="00")
  87. channel = int(result["data"][16: 20], 16)
  88. return channel
  89. def _set_gateway_channel(self, channel):
  90. """
  91. 设置设备的信道值
  92. """
  93. data = "{:04X}".format(int(channel))
  94. self._send_data(funCode="43", data=data)
  95. @staticmethod
  96. def _parse_40(data):
  97. """
  98. 解析从机的端口状态同步 经过实际测试 此指令不支持
  99. """
  100. subNums, content = int(data[16: 18], 16), data[18: -2]
  101. portContentLen = 13 * 2
  102. result = dict()
  103. # 一共两个循环 第一层循环解析从机 第二层循环解析端口
  104. for _subIndex in range(subNums):
  105. _subAddr = str(int(content[: 8], 16))
  106. _portNums = int(content[8: 10], 16)
  107. _portContent = content[10: portContentLen*_portNums+10]
  108. result[_subAddr] = dict()
  109. for _portIndex in range(_portNums):
  110. _port = str(int(_portContent[portContentLen*_portIndex: portContentLen*_portIndex+2], 16))
  111. result[_subAddr][_port]["status"] = PORT_STATUS_MAP.get(_portContent[portContentLen*_portIndex+4: portContentLen*_portIndex+6], Const.DEV_WORK_STATUS_IDLE)
  112. result[_subAddr][_port]["leftTime"] = int(_portContent[portContentLen*_portIndex+6: portContentLen*_portIndex+10], 16)
  113. result[_subAddr][_port]["power"] = int(_portContent[portContentLen*_portIndex+10: portContentLen*_portIndex+14], 16)
  114. result[_subAddr][_port]["leftElec"] = int(bin(int(_portContent[portContentLen*_portIndex+14: portContentLen*_portIndex+18], 16))[2:][1:], 2) * 0.01
  115. result[_subAddr][_port]["V"] = int(_portContent[portContentLen*_portIndex+18: portContentLen*_portIndex+22], 16) * 0.1
  116. result[_subAddr][_port]["A"] = int(_portContent[portContentLen*_portIndex+22: portContentLen*_portIndex+26], 16) * 0.01
  117. content = content[portContentLen*_portNums+10:]
  118. return result
  119. def add_node(self, sub): # type:(DeviceDict) -> None
  120. self._add_sub_device(sub.deviceAdapter.addr)
  121. other = sub.otherConf
  122. other["master"] = self.device.devNo
  123. # 将子节点的信息同步一次
  124. Device.objects.filter(devNo=sub.devNo).first().update(
  125. otherConf=other,
  126. coreVer=self.device.coreVer,
  127. softVer=self.device.softVer,
  128. hwVer=self.device.hwVer,
  129. driverCode=self.device.driverCode,
  130. driverVersion=self.device.driverVersion
  131. )
  132. Device.invalid_device_cache(sub.devNo)
  133. def get_dev_setting(self):
  134. channel = self._get_gateway_channel()
  135. return {"channel": channel}
  136. def set_device_function_param(self, request, lastSetConf):
  137. channel = request.POST.get("channel")
  138. if not channel or int(channel) > 440 or int(channel) < 430:
  139. raise ServiceException({"result": 0, "description": u"信道值错误,范围430---440"})
  140. self._set_gateway_channel(int(channel))
  141. def get_node_list(self):
  142. subNos = self._read_sub_device()
  143. subs = list()
  144. for _subNo in subNos:
  145. _dev = Device.get_dev("{}{}".format(DEV_PREFIX, _subNo))
  146. if not _dev:
  147. continue
  148. subs.append(_dev)
  149. return subs
  150. def remove_node(self, sub):
  151. self._remove_sub_device(sub.deviceAdapter.addr)
  152. def analyze_event_data(self, data):
  153. funCode = data[4: 6]
  154. eventData = dict()
  155. if funCode == "40":
  156. result = self._parse_40(data)
  157. eventData["subInfo"] = result
  158. else:
  159. logger.info("[CZGateway analyze_event_data] device <{}> get un parse event data = {}".format(self.device.devNo, data))
  160. return
  161. eventData.update({"cmdCode": funCode})
  162. return eventData
  163. def get_event_analyze_parser(self, data):
  164. """AA 22 26 055D 5515 010201000100000000800000000000020001000000008000000000001C"""
  165. if int(data[6: 14], 16) == 0:
  166. return self
  167. addr = data[6: 14]
  168. devNo = "{}{}".format(DEV_PREFIX, int(addr, 16))
  169. return Device.get_dev(devNo).deviceAdapter