123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- # coding=utf-8
- import logging
- from apps.web.constant import MQTT_TIMEOUT, DeviceCmdCode, Const
- from apps.web.core.adapter.base import SmartBox
- from apps.web.core.device_define.cmCZ import PORT_STATUS_MAP, DEV_PREFIX
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.networking import MessageSender
- from apps.web.device.models import DeviceDict, Device
- logger = logging.getLogger(__name__)
- class CZGateway(SmartBox):
- """
- 诚马插座的网络代理
- """
- def _send_data(self, funCode, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=MQTT_TIMEOUT.NORMAL, addr=None):
- # 若是网关发送 则addr地址填充为0
- payload = {
- "IMEI": self.device.devNo,
- "funCode": funCode
- }
- if isinstance(data, dict):
- payload.update(data)
- payload.update({"addr": addr})
- else:
- addr = "{:08X}".format(addr or 0)
- payload["data"] = "{}{}".format(data, addr)
- result = MessageSender.send(
- device=self.device,
- cmd=cmd,
- payload=payload,
- timeout=timeout
- )
- if "rst" not in result:
- raise ServiceException({"result": 2, "description": u"串口通信异常(10001)"})
- if result["rst"] != 0:
- if result["rst"] == -1:
- raise ServiceException({"result": 2, "description": u"网络通信异常"})
- if result["rst"] == 1:
- raise ServiceException({"result": 2, "description": u"串口通信异常(10002)"})
- return result
- def _add_sub_device(self, subAddr):
- """
- 添加一台从机
- """
- _type, data = 0x01, int(subAddr)
- data = "{:02X}{:08X}".format(_type, data)
- result = self._send_data(funCode="37", data=data)
- if int(result["data"][16: 18], 16) == 0x01:
- raise ServiceException({"result": 2, "description": u"新增节点数量达到上限,添加失败"})
- if int(result["data"][16: 18], 16) == 0x02:
- raise ServiceException({"result": 2, "description": u"该节点已经存在,无需重复添加"})
- def _remove_sub_device(self, subAddr):
- _type, data = 0x02, int(subAddr)
- data = "{:02X}{:08X}".format(_type, data)
- result = self._send_data(funCode="37", data=data)
- # if int(result["data"][16: 18], 16) == 0x01:
- # raise ServiceException({"result": 2, "description": u"没有节点数量,删除失败"})
- # if int(result["data"][16: 18], 16) == 0x02:
- # raise ServiceException({"result": 2, "description": u"该设备尚未添加,删除失败"})
- def _read_sub_device(self):
- """
- 读取所有的从机
- """
- result = self._send_data(funCode="38", data="00")
- content = result["data"][16: -2]
- num = int(content[: 2], 16)
- offset = 2
- subs = list()
- for _subIndex in range(num):
- _sub = int(content[offset: offset+8], 16)
- subs.append(_sub)
- offset += 8
- return subs
- def _add_sub_device_many(self, subs):
- """
- 批量的同步从机地址
- """
- num = len(subs)
- data = "{:02X}".format(num)
- for _sub in subs:
- data += "{:08X}".format(_sub.addr)
- return self._send_data(funCode="39", data=data)
- def _get_gateway_channel(self):
- """
- 读取设备的信道
- """
- result = self._send_data(funCode="42", data="00")
- channel = int(result["data"][16: 20], 16)
- return channel
- def _set_gateway_channel(self, channel):
- """
- 设置设备的信道值
- """
- data = "{:04X}".format(int(channel))
- self._send_data(funCode="43", data=data)
- @staticmethod
- def _parse_40(data):
- """
- 解析从机的端口状态同步 经过实际测试 此指令不支持
- """
- subNums, content = int(data[16: 18], 16), data[18: -2]
- portContentLen = 13 * 2
- result = dict()
- # 一共两个循环 第一层循环解析从机 第二层循环解析端口
- for _subIndex in range(subNums):
- _subAddr = str(int(content[: 8], 16))
- _portNums = int(content[8: 10], 16)
- _portContent = content[10: portContentLen*_portNums+10]
- result[_subAddr] = dict()
- for _portIndex in range(_portNums):
- _port = str(int(_portContent[portContentLen*_portIndex: portContentLen*_portIndex+2], 16))
- result[_subAddr][_port]["status"] = PORT_STATUS_MAP.get(_portContent[portContentLen*_portIndex+4: portContentLen*_portIndex+6], Const.DEV_WORK_STATUS_IDLE)
- result[_subAddr][_port]["leftTime"] = int(_portContent[portContentLen*_portIndex+6: portContentLen*_portIndex+10], 16)
- result[_subAddr][_port]["power"] = int(_portContent[portContentLen*_portIndex+10: portContentLen*_portIndex+14], 16)
- result[_subAddr][_port]["leftElec"] = int(bin(int(_portContent[portContentLen*_portIndex+14: portContentLen*_portIndex+18], 16))[2:][1:], 2) * 0.01
- result[_subAddr][_port]["V"] = int(_portContent[portContentLen*_portIndex+18: portContentLen*_portIndex+22], 16) * 0.1
- result[_subAddr][_port]["A"] = int(_portContent[portContentLen*_portIndex+22: portContentLen*_portIndex+26], 16) * 0.01
- content = content[portContentLen*_portNums+10:]
- return result
- def add_node(self, sub): # type:(DeviceDict) -> None
- self._add_sub_device(sub.deviceAdapter.addr)
- other = sub.otherConf
- other["master"] = self.device.devNo
- # 将子节点的信息同步一次
- Device.objects.filter(devNo=sub.devNo).first().update(
- otherConf=other,
- coreVer=self.device.coreVer,
- softVer=self.device.softVer,
- hwVer=self.device.hwVer,
- driverCode=self.device.driverCode,
- driverVersion=self.device.driverVersion
- )
- Device.invalid_device_cache(sub.devNo)
- def get_dev_setting(self):
- channel = self._get_gateway_channel()
- return {"channel": channel}
- def set_device_function_param(self, request, lastSetConf):
- channel = request.POST.get("channel")
- if not channel or int(channel) > 440 or int(channel) < 430:
- raise ServiceException({"result": 0, "description": u"信道值错误,范围430---440"})
- self._set_gateway_channel(int(channel))
- def get_node_list(self):
- subNos = self._read_sub_device()
- subs = list()
- for _subNo in subNos:
- _dev = Device.get_dev("{}{}".format(DEV_PREFIX, _subNo))
- if not _dev:
- continue
- subs.append(_dev)
- return subs
- def remove_node(self, sub):
- self._remove_sub_device(sub.deviceAdapter.addr)
- def analyze_event_data(self, data):
- funCode = data[4: 6]
- eventData = dict()
- if funCode == "40":
- result = self._parse_40(data)
- eventData["subInfo"] = result
- else:
- logger.info("[CZGateway analyze_event_data] device <{}> get un parse event data = {}".format(self.device.devNo, data))
- return
- eventData.update({"cmdCode": funCode})
- return eventData
- def get_event_analyze_parser(self, data):
- """AA 22 26 055D 5515 010201000100000000800000000000020001000000008000000000001C"""
- if int(data[6: 14], 16) == 0:
- return self
- addr = data[6: 14]
- devNo = "{}{}".format(DEV_PREFIX, int(addr, 16))
- return Device.get_dev(devNo).deviceAdapter
|