qlsdk2 0.3.0a2__py3-none-any.whl → 0.4.0a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qlsdk/__init__.py +1 -0
- qlsdk/core/__init__.py +4 -0
- qlsdk/core/crc/__init__.py +5 -0
- qlsdk/core/crc/crctools.py +95 -0
- qlsdk/core/device.py +25 -0
- qlsdk/core/entity/__init__.py +92 -0
- qlsdk/core/exception.py +0 -0
- qlsdk/core/filter/__init__.py +1 -0
- qlsdk/core/filter/norch.py +59 -0
- qlsdk/core/local.py +34 -0
- qlsdk/core/message/__init__.py +2 -0
- qlsdk/core/message/command.py +293 -0
- qlsdk/core/message/tcp.py +0 -0
- qlsdk/core/message/udp.py +96 -0
- qlsdk/core/utils.py +68 -0
- qlsdk/persist/__init__.py +2 -1
- qlsdk/{ar4m/persist.py → persist/rsc_edf.py} +139 -81
- qlsdk/rsc/__init__.py +7 -0
- qlsdk/rsc/command/__init__.py +214 -0
- qlsdk/rsc/command/message.py +239 -0
- qlsdk/rsc/device_manager.py +96 -0
- qlsdk/rsc/discover.py +86 -0
- qlsdk/rsc/eegion.py +360 -0
- qlsdk/rsc/entity.py +552 -0
- qlsdk/rsc/paradigm.py +310 -0
- qlsdk/rsc/proxy.py +76 -0
- {qlsdk2-0.3.0a2.dist-info → qlsdk2-0.4.0a1.dist-info}/METADATA +1 -1
- qlsdk2-0.4.0a1.dist-info/RECORD +40 -0
- qlsdk/ar4m/ar4sdk.py +0 -1011
- qlsdk2-0.3.0a2.dist-info/RECORD +0 -18
- /qlsdk/{ar4m → sdk}/libs/libAr4SDK.dll +0 -0
- /qlsdk/{ar4m → sdk}/libs/libwinpthread-1.dll +0 -0
- {qlsdk2-0.3.0a2.dist-info → qlsdk2-0.4.0a1.dist-info}/WHEEL +0 -0
- {qlsdk2-0.3.0a2.dist-info → qlsdk2-0.4.0a1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from typing import Dict, Type
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from rsc.core.crctools import crc16
|
|
6
|
+
|
|
7
|
+
class DeviceCommand(abc.ABC):
|
|
8
|
+
# 消息头
|
|
9
|
+
HEADER_PREFIX = b'\x5A\xA5'
|
|
10
|
+
# 消息头总长度 2(prefix) +1(pkgType) +1(deviceType) +4(deviceId) +4(len) +2(cmd)
|
|
11
|
+
HEADER_LEN = 14
|
|
12
|
+
# 消息指令码位置
|
|
13
|
+
CMD_POS = 12
|
|
14
|
+
|
|
15
|
+
def __init__(self, device):
|
|
16
|
+
self.device = device
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def build(cls, device) :
|
|
20
|
+
return cls(device)
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
@abc.abstractmethod
|
|
24
|
+
def cmd_code(self) -> int:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def checksum(data: bytes) -> bytes:
|
|
29
|
+
return crc16(data).to_bytes(2, 'little')
|
|
30
|
+
|
|
31
|
+
def pack(self, body=b'') -> bytes:
|
|
32
|
+
# header+body+checksum
|
|
33
|
+
header = self.header_pack(len(body))
|
|
34
|
+
payload = header + body
|
|
35
|
+
return payload + DeviceCommand.checksum(payload)
|
|
36
|
+
|
|
37
|
+
def header_pack(self, body_len: int) -> bytes:
|
|
38
|
+
"""构建消息头"""
|
|
39
|
+
return (
|
|
40
|
+
DeviceCommand.HEADER_PREFIX
|
|
41
|
+
+ self.device.pkg_type.to_bytes(1, 'little')
|
|
42
|
+
+ self.device.device_type.to_bytes(1, 'little')
|
|
43
|
+
+ self.device.device_id.to_bytes(4, 'little')
|
|
44
|
+
+ (DeviceCommand.HEADER_LEN + body_len + 2).to_bytes(4, 'little') # +1 for checksum
|
|
45
|
+
+ self.cmd_code.to_bytes(2, 'little')
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
def unpack(self, payload: bytes) -> bytes:
|
|
49
|
+
"""解析消息体"""
|
|
50
|
+
# 解析消息体
|
|
51
|
+
body = payload[self.HEADER_LEN:-2]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DeviceInfoCommand(DeviceCommand):
|
|
55
|
+
"""设备信息指令"""
|
|
56
|
+
cmd_code = 0x01
|
|
57
|
+
|
|
58
|
+
def parse_body(self, body: bytes):
|
|
59
|
+
# 解析设备信息
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
class SignalDataCommand(DeviceCommand):
|
|
63
|
+
"""设备信息指令"""
|
|
64
|
+
cmd_code = 0x02
|
|
65
|
+
|
|
66
|
+
def parse_body(self, body: bytes):
|
|
67
|
+
# 解析设备信息
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
if __name__ == "__main__":
|
|
71
|
+
# 测试代码
|
|
72
|
+
device = None # 这里应该是设备实例
|
|
73
|
+
command1 = DeviceInfoCommand.build(device)
|
|
74
|
+
logger.debug(command1.cmd_code)
|
|
75
|
+
command2 = SignalDataCommand.build(device)
|
|
76
|
+
logger.debug(command2.cmd_code)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class CommandFactory:
|
|
81
|
+
"""Registry for command implementations"""
|
|
82
|
+
_commands: Dict[int, Type[DeviceCommand]] = {}
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def register_command(cls, code: int, command: Type[DeviceCommand]):
|
|
86
|
+
cls._commands[code] = command
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def create_command(cls, code: int) -> Type[DeviceCommand]:
|
|
90
|
+
logger.debug(f"Creating command for code: {hex(code)}")
|
|
91
|
+
if code not in cls._commands:
|
|
92
|
+
logger.warning(f"Unsupported command code: {hex(code)}")
|
|
93
|
+
return cls._commands[DefaultCommand.cmd_code]
|
|
94
|
+
return cls._commands[code]
|
|
95
|
+
|
|
96
|
+
# =============================================================================
|
|
97
|
+
class DefaultCommand(DeviceCommand):
|
|
98
|
+
cmd_code = 0x00
|
|
99
|
+
|
|
100
|
+
def parse_body(self, body: bytes):
|
|
101
|
+
# Response parsing example: 2 bytes version + 4 bytes serial
|
|
102
|
+
logger.info(f"Received body len: {len(body)}")
|
|
103
|
+
|
|
104
|
+
class GetDeviceInfoCommand(DeviceCommand):
|
|
105
|
+
cmd_code = 0x17
|
|
106
|
+
|
|
107
|
+
def parse_body(self, body: bytes):
|
|
108
|
+
logger.info(f"Received GetDeviceInfoCommand body len: {len(body)}")
|
|
109
|
+
# time - 8b
|
|
110
|
+
self.device.connect_time = int.from_bytes(body[0:8], 'little')
|
|
111
|
+
self.device.current_time = self.device.connect_time
|
|
112
|
+
# result - 1b
|
|
113
|
+
result = body[8]
|
|
114
|
+
# deviceId - 4b
|
|
115
|
+
self.device.device_id = body[9:13].hex()
|
|
116
|
+
# deviceType - 4b
|
|
117
|
+
self.device.device_type = body[13:17].hex()
|
|
118
|
+
# softVersion - 4b
|
|
119
|
+
self.device.software_version = body[17:21].hex()
|
|
120
|
+
# hardVersion - 4b
|
|
121
|
+
self.device.hardware_version = body[21:25].hex()
|
|
122
|
+
# deviceName - 16b
|
|
123
|
+
self.device.device_name = body[25:41].decode('utf-8').rstrip('\x00')
|
|
124
|
+
# flag - 4b
|
|
125
|
+
flag = int.from_bytes(body[41:45], 'little')
|
|
126
|
+
logger.debug(f"Received device info: {result}, {flag}, {self.device}")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# 握手
|
|
130
|
+
class HandshakeCommand(DeviceCommand):
|
|
131
|
+
cmd_code = 0x01
|
|
132
|
+
|
|
133
|
+
def parse_body(self, body: bytes):
|
|
134
|
+
logger.info(f"Received handshake response: {body.hex()}")
|
|
135
|
+
|
|
136
|
+
# 查询电量
|
|
137
|
+
class QueryBatteryCommand(DeviceCommand):
|
|
138
|
+
cmd_code = 0x16
|
|
139
|
+
def parse_body(self, body: bytes):
|
|
140
|
+
logger.info(f"Received QueryBatteryCommand body len: {len(body)}")
|
|
141
|
+
# time - 8b
|
|
142
|
+
self.device.current_time = int.from_bytes(body[0:8], 'little')
|
|
143
|
+
# result - 1b
|
|
144
|
+
result = body[8]
|
|
145
|
+
# 更新设备信息
|
|
146
|
+
if result == 0:
|
|
147
|
+
# voltage - 2b mV
|
|
148
|
+
self.device.voltage = int.from_bytes(body[9:11], 'little')
|
|
149
|
+
# soc - 1b
|
|
150
|
+
self.device.battery_remain = body[11]
|
|
151
|
+
# soh - 1b
|
|
152
|
+
self.device.battery_total = body[12]
|
|
153
|
+
# state - 1b
|
|
154
|
+
# state = body[13]
|
|
155
|
+
else:
|
|
156
|
+
logger.warning(f"QueryBatteryCommand message received but result is failed.")
|
|
157
|
+
|
|
158
|
+
# 设置采集参数
|
|
159
|
+
class SetAcquisitionParamCommand(DeviceCommand):
|
|
160
|
+
cmd_code = 0x451
|
|
161
|
+
def parse_body(self, body: bytes):
|
|
162
|
+
logger.info(f"Received SetAcquisitionParam response: {body.hex()}")
|
|
163
|
+
|
|
164
|
+
# 启动采集
|
|
165
|
+
class StartAcquisitionCommand(DeviceCommand):
|
|
166
|
+
cmd_code = 0x452
|
|
167
|
+
def parse_body(self, body: bytes):
|
|
168
|
+
logger.info(f"Received acquisition start response: {body.hex()}")
|
|
169
|
+
|
|
170
|
+
# 停止采集
|
|
171
|
+
class StopAcquisitionCommand(DeviceCommand):
|
|
172
|
+
cmd_code = 0x453
|
|
173
|
+
|
|
174
|
+
def parse_body(self, body: bytes):
|
|
175
|
+
logger.info(f"Received acquisition stop response: {body.hex()}")
|
|
176
|
+
# 设置阻抗采集参数
|
|
177
|
+
class SetImpedanceParamCommand(DeviceCommand):
|
|
178
|
+
cmd_code = 0x411
|
|
179
|
+
def parse_body(self, body: bytes):
|
|
180
|
+
logger.info(f"Received SetImpedanceParamCommand response: {body.hex()}")
|
|
181
|
+
# 启动采集
|
|
182
|
+
class StartImpedanceCommand(DeviceCommand):
|
|
183
|
+
cmd_code = 0x412
|
|
184
|
+
def parse_body(self, body: bytes):
|
|
185
|
+
logger.info(f"Received StartImpedanceCommand response: {body.hex()}")
|
|
186
|
+
|
|
187
|
+
# 停止采集
|
|
188
|
+
class StopImpedanceCommand(DeviceCommand):
|
|
189
|
+
cmd_code = 0x413
|
|
190
|
+
|
|
191
|
+
def parse_body(self, body: bytes):
|
|
192
|
+
logger.info(f"Received StopImpedanceCommand response: {body.hex()}")
|
|
193
|
+
|
|
194
|
+
# 启动采集
|
|
195
|
+
class StartStimulationCommand(DeviceCommand):
|
|
196
|
+
cmd_code = 0x48C
|
|
197
|
+
def parse_body(self, body: bytes):
|
|
198
|
+
logger.info(f"Received acquisition start response: {body.hex()}")
|
|
199
|
+
|
|
200
|
+
# 停止采集
|
|
201
|
+
class StopStimulationCommand(DeviceCommand):
|
|
202
|
+
cmd_code = 0x488
|
|
203
|
+
|
|
204
|
+
def parse_body(self, body: bytes):
|
|
205
|
+
logger.info(f"Received acquisition stop response: {body.hex()}")
|
|
206
|
+
|
|
207
|
+
# 阻抗数据
|
|
208
|
+
class ImpedanceDataCommand(DeviceCommand):
|
|
209
|
+
cmd_code = 0x415
|
|
210
|
+
|
|
211
|
+
def parse_body(self, body: bytes):
|
|
212
|
+
logger.info(f"Received impedance data: {body.hex()}")
|
|
213
|
+
|
|
214
|
+
# 信号数据
|
|
215
|
+
class SignalDataCommand(DeviceCommand):
|
|
216
|
+
cmd_code = 0x455
|
|
217
|
+
|
|
218
|
+
def parse_body(self, body: bytes):
|
|
219
|
+
logger.info(f"Received signal data: {len(body)}字节, the subscribe is {self.device.signal_consumers}")
|
|
220
|
+
for q in list(self.device.signal_consumers.values()):
|
|
221
|
+
q.put(body)
|
|
222
|
+
|
|
223
|
+
# =============================================================================
|
|
224
|
+
# Command Registration
|
|
225
|
+
# =============================================================================
|
|
226
|
+
|
|
227
|
+
CommandFactory.register_command(DefaultCommand.cmd_code, DefaultCommand)
|
|
228
|
+
CommandFactory.register_command(GetDeviceInfoCommand.cmd_code, GetDeviceInfoCommand)
|
|
229
|
+
CommandFactory.register_command(HandshakeCommand.cmd_code, HandshakeCommand)
|
|
230
|
+
CommandFactory.register_command(QueryBatteryCommand.cmd_code, QueryBatteryCommand)
|
|
231
|
+
CommandFactory.register_command(SetAcquisitionParamCommand.cmd_code, SetAcquisitionParamCommand)
|
|
232
|
+
CommandFactory.register_command(StartAcquisitionCommand.cmd_code, StartAcquisitionCommand)
|
|
233
|
+
CommandFactory.register_command(StopAcquisitionCommand.cmd_code, StopAcquisitionCommand)
|
|
234
|
+
CommandFactory.register_command(SetImpedanceParamCommand.cmd_code, SetImpedanceParamCommand)
|
|
235
|
+
CommandFactory.register_command(StartImpedanceCommand.cmd_code, StartImpedanceCommand)
|
|
236
|
+
CommandFactory.register_command(StopImpedanceCommand.cmd_code, StopImpedanceCommand)
|
|
237
|
+
CommandFactory.register_command(StartStimulationCommand.cmd_code, StartStimulationCommand)
|
|
238
|
+
CommandFactory.register_command(ImpedanceDataCommand.cmd_code, ImpedanceDataCommand)
|
|
239
|
+
CommandFactory.register_command(SignalDataCommand.cmd_code, SignalDataCommand)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
from loguru import logger
|
|
3
|
+
from qlsdk.rsc.discover import UdpBroadcaster
|
|
4
|
+
from threading import Thread
|
|
5
|
+
from qlsdk.core import *
|
|
6
|
+
from qlsdk.rsc.entity import QLDevice
|
|
7
|
+
from qlsdk.rsc.proxy import DeviceProxy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DeviceContainer(object):
|
|
11
|
+
def __init__(self, proxy_enabled=False):
|
|
12
|
+
self._devices = {}
|
|
13
|
+
self._tcp_port = 19216
|
|
14
|
+
self._proxy_enabled = proxy_enabled
|
|
15
|
+
|
|
16
|
+
# 设备搜索广播器
|
|
17
|
+
self._broadcaster = UdpBroadcaster()
|
|
18
|
+
self._broadcaster.start()
|
|
19
|
+
|
|
20
|
+
# 监听设备连接
|
|
21
|
+
self._listening_thread = Thread(target=self._listening)
|
|
22
|
+
self._listening_thread.daemon = True
|
|
23
|
+
self._listening_thread.start()
|
|
24
|
+
|
|
25
|
+
def _listening(self):
|
|
26
|
+
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
27
|
+
tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
28
|
+
try:
|
|
29
|
+
# 绑定到所有接口的19216端口
|
|
30
|
+
tcp_socket.bind(('0.0.0.0', self._tcp_port))
|
|
31
|
+
tcp_socket.listen(5)
|
|
32
|
+
logger.info(f"端口[{self._tcp_port}]监听服务已启动")
|
|
33
|
+
|
|
34
|
+
while True:
|
|
35
|
+
client_socket, addr = tcp_socket.accept()
|
|
36
|
+
logger.info(f"接收到来自 {addr[0]}:{addr[1]} 的连接")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# 为每个新连接创建线程处理
|
|
40
|
+
client_handler = Thread(
|
|
41
|
+
target=self.client_handler,
|
|
42
|
+
args=(client_socket,)
|
|
43
|
+
)
|
|
44
|
+
client_handler.daemon = True
|
|
45
|
+
client_handler.start()
|
|
46
|
+
|
|
47
|
+
except KeyboardInterrupt:
|
|
48
|
+
logger.error(f"端口[{self._tcp_port}]监听服务异常关闭")
|
|
49
|
+
finally:
|
|
50
|
+
logger.error(f"端口[{self._tcp_port}]监听服务关闭")
|
|
51
|
+
tcp_socket.close()
|
|
52
|
+
|
|
53
|
+
def client_handler(self, client_socket):
|
|
54
|
+
|
|
55
|
+
if self._proxy_enabled:
|
|
56
|
+
proxy = DeviceProxy(client_socket)
|
|
57
|
+
proxy.start()
|
|
58
|
+
else:
|
|
59
|
+
# 数据监听
|
|
60
|
+
device = QLDevice(client_socket)
|
|
61
|
+
# GET_DEVICE_INFO
|
|
62
|
+
msg = GetDeviceInfoCommand.build(device).pack()
|
|
63
|
+
logger.info(f"发送获取设备信息命令: {msg.hex()}")
|
|
64
|
+
device.send(msg)
|
|
65
|
+
# 添加设备
|
|
66
|
+
while True:
|
|
67
|
+
if device.device_name:
|
|
68
|
+
self.add_device(device)
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# 搜寻设备
|
|
73
|
+
def add_search(self, device_id):
|
|
74
|
+
self._broadcaster.add_device(device_id)
|
|
75
|
+
|
|
76
|
+
def add_device(self, device: QLDevice):
|
|
77
|
+
if device is None or device.device_name is None:
|
|
78
|
+
logger.warning("无效的设备")
|
|
79
|
+
|
|
80
|
+
self._devices.update({device.device_name: device})
|
|
81
|
+
logger.debug(f"add_device {device.device_name} then has devices {self._devices}")
|
|
82
|
+
|
|
83
|
+
self._broadcaster.remove_device(device.device_name)
|
|
84
|
+
logger.debug(f"add_device {device.device_name} then has broadcaster {self._broadcaster}")
|
|
85
|
+
|
|
86
|
+
def get_device(self, device_id=None)->QLDevice:
|
|
87
|
+
logger.debug(f"已连接设备数量:{len(self._devices)}")
|
|
88
|
+
if len(self._devices) == 0:
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
# 未指定device_id,返回第一个设备
|
|
92
|
+
if device_id is None:
|
|
93
|
+
return list(self._devices.values())[0]
|
|
94
|
+
|
|
95
|
+
return self._devices.get(device_id)
|
|
96
|
+
|
qlsdk/rsc/discover.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import time
|
|
3
|
+
from threading import Thread, Lock
|
|
4
|
+
from loguru import logger
|
|
5
|
+
|
|
6
|
+
from qlsdk.core.message import UDPMessage
|
|
7
|
+
|
|
8
|
+
class UdpBroadcaster:
|
|
9
|
+
def __init__(self, port=54366):
|
|
10
|
+
self.broadcast_port = port
|
|
11
|
+
self.devices_to_broadcast = [] # 待广播的设备序列号列表
|
|
12
|
+
self.connected_devices = set() # 已连接的设备序列号集合
|
|
13
|
+
self.lock = Lock() # 用于线程安全的锁
|
|
14
|
+
self.running = True
|
|
15
|
+
|
|
16
|
+
# 创建UDP socket
|
|
17
|
+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
18
|
+
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
19
|
+
|
|
20
|
+
def add_device(self, device_id):
|
|
21
|
+
"""添加设备序列号到待广播列表"""
|
|
22
|
+
with self.lock:
|
|
23
|
+
if device_id not in self.devices_to_broadcast:
|
|
24
|
+
self.devices_to_broadcast.append(device_id)
|
|
25
|
+
logger.info(f"Added device {device_id} to broadcast list.")
|
|
26
|
+
|
|
27
|
+
def remove_device(self, device_id):
|
|
28
|
+
"""从待广播列表中移除设备序列号"""
|
|
29
|
+
with self.lock:
|
|
30
|
+
if device_id in self.devices_to_broadcast:
|
|
31
|
+
self.devices_to_broadcast.remove(device_id)
|
|
32
|
+
logger.info(f"Removed device {device_id} from broadcast list.")
|
|
33
|
+
|
|
34
|
+
def mark_device_as_connected(self, device_id):
|
|
35
|
+
"""将设备标记为已连接,并从未广播列表中移除"""
|
|
36
|
+
with self.lock:
|
|
37
|
+
if device_id in self.devices_to_broadcast:
|
|
38
|
+
self.devices_to_broadcast.remove(device_id)
|
|
39
|
+
self.connected_devices.add(device_id)
|
|
40
|
+
logger.info(f"Device {device_id} is now connected.")
|
|
41
|
+
|
|
42
|
+
def broadcast_devices(self):
|
|
43
|
+
"""轮询发送广播"""
|
|
44
|
+
while self.running:
|
|
45
|
+
with self.lock:
|
|
46
|
+
for device_id in self.devices_to_broadcast:
|
|
47
|
+
message = UDPMessage.search(device_id)
|
|
48
|
+
self.sock.sendto(message, ('<broadcast>', self.broadcast_port))
|
|
49
|
+
logger.info(f"Broadcasting device ID: {device_id}")
|
|
50
|
+
time.sleep(1) # 每隔1秒发送一次广播
|
|
51
|
+
|
|
52
|
+
def start(self):
|
|
53
|
+
"""启动广播线程"""
|
|
54
|
+
self.broadcast_thread = Thread(target=self.broadcast_devices)
|
|
55
|
+
self.broadcast_thread.setDaemon(True)
|
|
56
|
+
self.broadcast_thread.start()
|
|
57
|
+
|
|
58
|
+
def stop(self):
|
|
59
|
+
"""停止广播"""
|
|
60
|
+
self.running = False
|
|
61
|
+
self.broadcast_thread.join()
|
|
62
|
+
self.sock.close()
|
|
63
|
+
|
|
64
|
+
# 示例使用
|
|
65
|
+
if __name__ == "__main__":
|
|
66
|
+
broadcaster = UdpBroadcaster()
|
|
67
|
+
|
|
68
|
+
# 添加设备序列号到待广播列表
|
|
69
|
+
broadcaster.add_device_to_broadcast("390024130032")
|
|
70
|
+
|
|
71
|
+
# 启动广播
|
|
72
|
+
broadcaster.start()
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
# 模拟运行一段时间
|
|
76
|
+
time.sleep(10)
|
|
77
|
+
|
|
78
|
+
# 标记设备为已连接
|
|
79
|
+
broadcaster.mark_device_as_connected("390024130032")
|
|
80
|
+
|
|
81
|
+
# 继续运行一段时间
|
|
82
|
+
time.sleep(10)
|
|
83
|
+
|
|
84
|
+
finally:
|
|
85
|
+
# 停止广播
|
|
86
|
+
broadcaster.stop()
|