10029f9f by huangyf2

update

1 parent 26c8727b
1 dist 1 dist
2 build 2 build
3 __pycache__ 3 __pycache__
...\ No newline at end of file ...\ No newline at end of file
4 exe
...\ No newline at end of file ...\ No newline at end of file
......
This diff could not be displayed because it is too large.
1 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
2 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": null, "peripheralId": "68:67:11:27:78:49", "rssi": -28}}
3 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
4 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
5 下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 1}
6 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
7 下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 2}
8 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
9 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -36}}
10 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
11 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
12 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -36}}
13 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
14 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
15 下发: {"jsonrpc": "2.0", "result": null, "id": 1}
16 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
17 下发: {"jsonrpc": "2.0", "result": {"message": "Device with address 68:67:11:27:78:49 was not found."}, "id": 2}
18 接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01b6c4bc-8170-268e-4627-e07f37ed6744"},"id":3}
19 下发: {"jsonrpc": "2.0", "result": {"message": "Not connected"}, "id": 3}
20 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"01b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01B6C4BC-8170-268E-4627-E07F37ED6744","message":"WwEAXF0=","encoding":"base64"},"id":4}
21 下发: {"jsonrpc": "2.0", "result": {"message": "Service Discovery has not been performed yet"}, "id": 4}
22 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
23 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -28}}
24 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
25 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
26 下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 1}
27 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
28 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -28}}
29 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
30 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
31 下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 1}
32 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
33 下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 2}
34 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
35 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -34}}
36 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
37 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
38 下发: {"jsonrpc": "2.0", "result": null, "id": 1}
39 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
40 下发: {"jsonrpc": "2.0", "result": {"message": "Device with address 68:67:11:27:78:49 was not found."}, "id": 2}
41 接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01b6c4bc-8170-268e-4627-e07f37ed6744"},"id":3}
42 下发: {"jsonrpc": "2.0", "result": {"message": "Not connected"}, "id": 3}
43 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"01b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01B6C4BC-8170-268E-4627-E07F37ED6744","message":"WwEAXF0=","encoding":"base64"},"id":4}
44 下发: {"jsonrpc": "2.0", "result": {"message": "Service Discovery has not been performed yet"}, "id": 4}
45 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
46 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -30}}
47 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
48 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:4D"},"id":1}
49 下发: {"jsonrpc": "2.0", "result": null, "id": 1}
50 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
51 下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001563-1212-efde-1523-785feabcd123 was not found!"}, "id": 2}
52 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
53 下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001565-1212-efde-1523-785feabcd123 was not found!"}, "id": 3}
54 接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
55 下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001527-1212-efde-1523-785feabcd123 was not found!"}, "id": 4}
56 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
57 下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001528-1212-efde-1523-785feabcd123 was not found!"}, "id": 5}
58 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
59 下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001528-1212-efde-1523-785feabcd123 was not found!"}, "id": 6}
60 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
61 下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001528-1212-efde-1523-785feabcd123 was not found!"}, "id": 7}
62 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
63 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -26}}
64 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
65 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
66 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -26}}
67 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
68 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
69 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "LPF2 Smart Hub", "peripheralId": "3D:6F:89:AB:DA:FE", "rssi": -24}}
70 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
71 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"3D:6F:89:AB:DA:FE"},"id":1}
72 下发: {"jsonrpc": "2.0", "result": null, "id": 1}
73 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
74 下发: {"jsonrpc": "2.0", "result": null, "id": 2}
75 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
76 下发: {"jsonrpc": "2.0", "result": null, "id": 3}
77 接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
78 下发: {"jsonrpc": "2.0", "result": null, "id": 4}
79 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AwEzFQEAAAABAAAA"}}
80 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BQE1FgEAAAABAAAA"}}
81 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BAE0FAEAAAABAAAA"}}
82 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BgE2FwEAAAABAAAA"}}
83 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
84 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 5}
85 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
86 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 6}
87 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
88 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 7}
89 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":8}
90 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 8}
91 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":9}
92 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 9}
93 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":10}
94 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 10}
95 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":11}
96 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 11}
97 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":12}
98 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 12}
99 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":13}
100 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 13}
101 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":14}
102 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 14}
103 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":15}
104 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 15}
105 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":16}
106 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 16}
107 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":17}
108 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 17}
109 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
110 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -28}}
111 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
112 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
113 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -28}}
114 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
115 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
116 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -30}}
117 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
118 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
119 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "LPF2 Smart Hub", "peripheralId": "3D:6F:89:AB:DA:FE", "rssi": -26}}
120 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
121 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"3D:6F:89:AB:DA:FE"},"id":1}
122 下发: {"jsonrpc": "2.0", "result": null, "id": 1}
123 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
124 下发: {"jsonrpc": "2.0", "result": null, "id": 2}
125 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
126 下发: {"jsonrpc": "2.0", "result": null, "id": 3}
127 接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
128 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AwEzFQEAAAABAAAA"}}
129 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BAE0FAEAAAABAAAA"}}
130 下发: {"jsonrpc": "2.0", "result": null, "id": 4}
131 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BQE1FgEAAAABAAAA"}}
132 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BgE2FwEAAAABAAAA"}}
133 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
134 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 5}
135 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
136 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 6}
137 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
138 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 7}
139 接收: {"jsonrpc":"2.0","method":"discover","params":{"filters":[{"services":["00001523-1212-efde-1523-785feabcd123"]},{"services":["00b6c4bc-8170-268e-4627-e07f37ed6744"]}],"optionalServices":["00004f0e-1212-efde-1523-785feabcd123","00001524-1212-efde-1523-785feabcd123","00001527-1212-efde-1523-785feabcd123","00001528-1212-efde-1523-785feabcd123","00001560-1212-efde-1523-785feabcd123","00001563-1212-efde-1523-785feabcd123","00001565-1212-efde-1523-785feabcd123","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","01b6c4bc-8170-268e-4627-e07f37ed6744","02b6c4bc-8170-268e-4627-e07f37ed6744","01B6C4BC-8170-268E-4627-E07F37ED6744","02B6C4BC-8170-268E-4627-E07F37ED6744"]},"id":0}
140 下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "ccc", "peripheralId": "07:00:00:00:00:00", "rssi": -34}}
141 下发: {"jsonrpc": "2.0", "result": null, "id": 0}
142 接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"07:00:00:00:00:00"},"id":1}
143 下发: {"jsonrpc": "2.0", "result": null, "id": 1}
144 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
145 下发: {"jsonrpc": "2.0", "result": null, "id": 2}
146 接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
147 下发: {"jsonrpc": "2.0", "result": null, "id": 3}
148 接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
149 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AgEBAQEAAAABAAAA"}}
150 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AQEAAQEAAAABAAAA"}}
151 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AwEzFQEAAAABAAAA"}}
152 下发: {"jsonrpc": "2.0", "result": null, "id": 4}
153 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BAE0FAEAAAABAAAA"}}
154 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BQE1FgEAAAABAAAA"}}
155 下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BgE2FwEAAAABAAAA"}}
156 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
157 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 5}
158 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
159 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 6}
160 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
161 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 7}
162 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":8}
163 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 8}
164 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":9}
165 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 9}
166 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":10}
167 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 10}
168 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":11}
169 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 11}
170 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":12}
171 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 12}
172 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":13}
173 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 13}
174 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":14}
175 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 14}
176 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":15}
177 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 15}
178 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":16}
179 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 16}
180 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":17}
181 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 17}
182 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":18}
183 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 18}
184 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":19}
185 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 19}
186 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":20}
187 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 20}
188 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":21}
189 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 21}
190 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":22}
191 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 22}
192 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":23}
193 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 23}
194 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":24}
195 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 24}
196 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":25}
197 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 25}
198 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":26}
199 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 26}
200 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":27}
201 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 27}
202 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":28}
203 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 28}
204 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":29}
205 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 29}
206 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":30}
207 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 30}
208 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":31}
209 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 31}
210 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":32}
211 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 32}
212 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":33}
213 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 33}
214 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":34}
215 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 34}
216 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":35}
217 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 35}
218 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":36}
219 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 36}
220 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":37}
221 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 37}
222 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":38}
223 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 38}
224 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":39}
225 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 39}
226 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":40}
227 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 40}
228 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":41}
229 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 41}
230 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":42}
231 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 42}
232 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":43}
233 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 43}
234 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":44}
235 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 44}
236 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":45}
237 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 45}
238 接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":46}
239 下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 46}
1 # -*- mode: python ; coding: utf-8 -*-
2
3
4 a = Analysis(
5 ['we.py'],
6 pathex=[],
7 binaries=[],
8 datas=[('data', 'data')],
9 hiddenimports=[],
10 hookspath=[],
11 hooksconfig={},
12 runtime_hooks=[],
13 excludes=[],
14 noarchive=False,
15 optimize=0,
16 )
17 pyz = PYZ(a.pure)
18
19 exe = EXE(
20 pyz,
21 a.scripts,
22 a.binaries,
23 a.datas,
24 [],
25 name='ble_client',
26 debug=False,
27 bootloader_ignore_signals=False,
28 strip=False,
29 upx=True,
30 upx_exclude=[],
31 runtime_tmpdir=None,
32 console=True,
33 disable_windowed_traceback=False,
34 argv_emulation=False,
35 target_arch=None,
36 codesign_identity=None,
37 entitlements_file=None,
38 icon=['data\\app.ico'],
39 )
1 import asyncio
2 import json
3 import websockets
4
5 # 预定义的下发通知列表
6 NOTIFICATIONS = [
7 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
8 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
9 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
10 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
11 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
12 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
13 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALF0="}},
14 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
15 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALF0="}},
16 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
17 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
18 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
19 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
20 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
21 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
22 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
23 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
24 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
25 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
26 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
27 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
28 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
29 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
30 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
31 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
32 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALF0="}},
33 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
34 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
35 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
36 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
37 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
38 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
39 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
40 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
41 {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}}
42 ]
43 async def handle_client(websocket):
44 """处理客户端连接"""
45 client_ip = websocket.remote_address[0]
46 print(f"客户端 {client_ip} 已连接")
47
48 try:
49 async for message in websocket:
50 # 解析接收到的JSON消息
51 try:
52 data = json.loads(message)
53 except json.JSONDecodeError:
54 print(f"无效的JSON数据: {message}")
55 continue
56
57 print(f"收到请求:\n{json.dumps(data, indent=2)}")
58
59 # 提取请求参数
60 method = data.get("method")
61 req_id = data.get("id")
62 params = data.get("params", {})
63
64 # 请求路由处理
65 if method == "discover" and req_id == 0:
66 # 处理设备发现请求
67 await websocket.send(json.dumps({
68 "jsonrpc": "2.0",
69 "method": "didDiscoverPeripheral",
70 "params": {
71 "name": "12345",
72 "peripheralId": "E68744E9-02D5-42C1-AD3F-6BF6A7D4A5EC",
73 "rssi": -76
74 }
75 }))
76 await send_response(websocket, None, 0)
77
78 elif method == "connect" and req_id == 1:
79 # 处理连接请求
80 print(f"正在连接设备: {params.get('peripheralId')}")
81 await send_response(websocket, None, 1)
82
83 elif method == "write" and req_id == 2:
84 # 处理数据写入请求
85 print(f"写入数据到特征: {params.get('characteristicId')}")
86 await send_response(websocket, None, 2)
87
88 elif method == "startNotifications" and req_id == 3:
89 # 处理通知订阅请求
90 print("已启动特征通知")
91 await send_response(websocket, None, 3)
92
93 # 发送预定义通知流
94 for idx, notification in enumerate(NOTIFICATIONS):
95 await websocket.send(json.dumps(notification))
96 print(f"已发送通知 #{idx+1}")
97 await asyncio.sleep(1) # 每秒发送一个通知
98
99 except websockets.exceptions.ConnectionClosed:
100 print(f"客户端 {client_ip} 已断开连接")
101
102 async def send_response(websocket, result, req_id):
103 """发送标准响应"""
104 response = {
105 "jsonrpc": "2.0",
106 "result": result,
107 "id": req_id
108 }
109 await websocket.send(json.dumps(response))
110 print(f"已发送响应 ID {req_id}")
111
112 async def main():
113 """启动WebSocket服务器"""
114 server = await websockets.serve(
115 handle_client,
116 host="0.0.0.0",
117 port=20111,
118 ping_interval=None
119 )
120
121 print(f"WebSocket服务器已启动,监听 ws://0.0.0.0:20111")
122 print("按 Ctrl+C 停止服务器")
123
124 await server.wait_closed()
125
126 if __name__ == "__main__":
127 try:
128 asyncio.run(main())
129 except KeyboardInterrupt:
130 print("\n服务器已关闭")
...\ No newline at end of file ...\ No newline at end of file
1 # -*- mode: python ; coding: utf-8 -*-
2
3
4 a = Analysis(
5 ['m.py'],
6 pathex=[],
7 binaries=[],
8 datas=[('data', 'data')],
9 hiddenimports=[],
10 hookspath=[],
11 hooksconfig={},
12 runtime_hooks=[],
13 excludes=[],
14 noarchive=False,
15 optimize=0,
16 )
17 pyz = PYZ(a.pure)
18
19 exe = EXE(
20 pyz,
21 a.scripts,
22 a.binaries,
23 a.datas,
24 [],
25 name='m',
26 debug=False,
27 bootloader_ignore_signals=False,
28 strip=False,
29 upx=True,
30 upx_exclude=[],
31 runtime_tmpdir=None,
32 console=True,
33 disable_windowed_traceback=False,
34 argv_emulation=False,
35 target_arch=None,
36 codesign_identity=None,
37 entitlements_file=None,
38 icon=['data\\app.ico'],
39 )
pythonserver @ 65948850
1 Subproject commit 659488506d3926a24a8012358231b8345c52e618
1 from PyQt5.QtCore import pyqtSlot, QObject, QTimer, pyqtSignal, QMutex, QMutexLocker, QThread, QEvent
2 from PyQt5.QtBluetooth import (QBluetoothDeviceDiscoveryAgent, QLowEnergyController,
3 QBluetoothUuid, QLowEnergyService, QLowEnergyCharacteristic,
4 QLowEnergyDescriptor, QBluetoothDeviceInfo, QBluetoothServiceDiscoveryAgent,
5 QBluetoothSocket, QBluetoothServiceInfo)
6 from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QWidget, QPushButton, QHBoxLayout
7 from PyQt5.QtWebSockets import QWebSocketServer, QWebSocket
8 from PyQt5.QtNetwork import QHostAddress
9
10 class BluetoothDeviceScanner(QObject):
11 deviceDiscovered = pyqtSignal(QBluetoothDeviceInfo)
12 scanFinished = pyqtSignal()
13 deviceConnected = pyqtSignal(QLowEnergyController)
14
15 def __init__(self, parent=None, target_uuid="00001523-1212-efde-1523-785feabcd123"):
16 super().__init__(parent)
17 self.target_uuid = target_uuid
18 self.discovery_agent = QBluetoothDeviceDiscoveryAgent(self)
19
20 # 配置扫描参数 - 低功耗设备需要更长的扫描时间
21 self.discovery_agent.setLowEnergyDiscoveryTimeout(10000) # 10秒的扫描时间
22
23 # 配置扫描方式,包括低功耗设备和经典蓝牙设备
24 self.discovery_agent.setInquiryType(QBluetoothDeviceDiscoveryAgent.GeneralUnlimitedInquiry)
25
26 # 连接信号
27 self.discovery_agent.deviceDiscovered.connect(self.on_device_discovered)
28 self.discovery_agent.finished.connect(self.on_scan_finished)
29 self.discovery_agent.error.connect(self.on_error)
30
31 self.controllers = {} # Store controllers by device address
32 self.target_device = None
33 self.discovered_devices = {} # 存储所有发现的设备,避免重复处理
34
35 # 添加自动重试机制
36 self.scan_retry_count = 0
37 self.max_scan_retries = 2 # 最多重试2次,加上第一次共3次
38 self.connection_retry_count = 0
39 self.max_connection_retries = 2
40
41 # 创建计时器用于延迟重试
42 self.retry_timer = QTimer(self)
43 self.retry_timer.setSingleShot(True)
44 self.retry_timer.timeout.connect(self.retry_scan)
45
46 # 记录已经尝试过连接的设备
47 self.connection_attempts = set()
48
49 def start_scan(self):
50 """开始扫描蓝牙设备"""
51 print("开始蓝牙设备扫描...")
52 self.scan_retry_count = 0
53 self.discovered_devices.clear()
54 self.connection_attempts.clear()
55 self.target_device = None
56
57 # 设置更广泛的设备类型过滤
58 self.discovery_agent.start()
59
60 def stop_scan(self):
61 """停止设备扫描"""
62 self.discovery_agent.stop()
63 self.retry_timer.stop()
64 print("蓝牙设备扫描已停止")
65
66 def retry_scan(self):
67 """重试扫描,用于当扫描失败或未找到目标设备时"""
68 if self.scan_retry_count < self.max_scan_retries and not self.target_device:
69 self.scan_retry_count += 1
70 print(f"重试扫描 ({self.scan_retry_count}/{self.max_scan_retries})...")
71 self.discovery_agent.start()
72
73 @pyqtSlot(QBluetoothDeviceInfo)
74 def on_device_discovered(self, device_info):
75 """当发现蓝牙设备时调用"""
76 device_name = device_info.name() or "未命名设备"
77 device_address = device_info.address().toString()
78
79 # 如果已经处理过这个设备,则直接返回,除非是我们感兴趣的目标设备
80 if device_address in self.discovered_devices and "LPF2" not in device_name:
81 return
82
83 # 存储设备信息
84 self.discovered_devices[device_address] = device_info
85
86 # 分析设备类型
87 device_type = "未知"
88 # 获取主要和次要设备类别
89 major_class = device_info.majorDeviceClass()
90 minor_class = device_info.minorDeviceClass()
91
92 print(f"调试信息 - 主类别: {major_class}, 次类别: {minor_class}")
93
94 # 识别设备类别
95 if (major_class == QBluetoothDeviceInfo.MiscellaneousDevice or major_class == 0) and "LPF2" in device_name:
96 device_type = "LEGO智能集线器"
97 elif major_class == QBluetoothDeviceInfo.ToyDevice:
98 if minor_class == 0x01:
99 device_type = "玩具机器人"
100 elif minor_class == 0x02:
101 device_type = "玩具车辆"
102 else:
103 device_type = "玩具"
104 elif major_class == QBluetoothDeviceInfo.ComputerDevice:
105 device_type = "电脑"
106 elif major_class == QBluetoothDeviceInfo.PhoneDevice:
107 device_type = "手机"
108 elif major_class == QBluetoothDeviceInfo.AudioVideoDevice:
109 device_type = "音频/视频设备"
110 elif major_class == QBluetoothDeviceInfo.NetworkDevice:
111 device_type = "网络设备"
112 elif major_class == QBluetoothDeviceInfo.PeripheralDevice:
113 if minor_class & 0x04: # 键盘
114 device_type = "键盘"
115 elif minor_class & 0x08: # 鼠标
116 device_type = "鼠标"
117 elif minor_class & 0x10: # 组合键盘/鼠标
118 device_type = "键盘/鼠标组合"
119 elif minor_class & 0x40: # 游戏杆
120 device_type = "游戏杆"
121 elif minor_class & 0x80: # 游戏手柄
122 device_type = "游戏手柄"
123 else:
124 device_type = "外围设备"
125 elif major_class == QBluetoothDeviceInfo.ImagingDevice:
126 device_type = "成像设备"
127 elif major_class == QBluetoothDeviceInfo.WearableDevice:
128 device_type = "可穿戴设备"
129 elif major_class == QBluetoothDeviceInfo.HealthDevice:
130 device_type = "健康设备"
131
132 # 基于设备名称的额外分类
133 if device_type == "未知":
134 if "lego" in device_name.lower() or "lpf2" in device_name.lower():
135 device_type = "LEGO智能集线器"
136 elif "hub" in device_name.lower():
137 device_type = "智能集线器"
138 elif "watch" in device_name.lower():
139 device_type = "智能手表"
140 elif "speaker" in device_name.lower() or "headphone" in device_name.lower() or "airpod" in device_name.lower():
141 device_type = "音频设备"
142 elif "fitness" in device_name.lower() or "band" in device_name.lower():
143 device_type = "健身追踪器"
144
145 print(f"发现设备: {device_name} ({device_address}) - 类型: {device_type}")
146
147 # 获取额外的设备信息
148 rssi = device_info.rssi()
149 if rssi != 0:
150 print(f"信号强度 (RSSI): {rssi} dBm")
151
152 # 检查制造商特定数据
153 manufacturer_data = device_info.manufacturerData()
154 if manufacturer_data:
155 print(f"制造商数据可用: {len(manufacturer_data)} 字节")
156 for manufacturer_id, data in manufacturer_data.items():
157 # 将QByteArray转换为十六进制字符串
158 data_bytes = bytes(data)
159 hex_string = data_bytes.hex() if hasattr(data_bytes, 'hex') else ' '.join([f'{b:02x}' for b in data_bytes])
160 print(f"制造商ID: {manufacturer_id:04x}, 数据: {hex_string}")
161
162 # 获取服务UUID(如果可用)
163 service_uuids = device_info.serviceUuids()
164 if service_uuids:
165 print(f"服务UUID数量: {len(service_uuids)}")
166 for uuid_obj in service_uuids:
167 if isinstance(uuid_obj, QBluetoothUuid):
168 uuid_str = uuid_obj.toString()
169 print(f" - {uuid_str}")
170
171 # 连接决策逻辑 - 优先级从高到低
172 should_connect = False
173 connection_reason = ""
174
175 # 优先级1: 检查设备是否有与目标UUID匹配的服务
176 if service_uuids:
177 for uuid_obj in service_uuids:
178 if isinstance(uuid_obj, QBluetoothUuid):
179 uuid_str = uuid_obj.toString().lower()
180 if uuid_str == self.target_uuid.lower():
181 should_connect = True
182 connection_reason = "匹配服务UUID"
183 break
184
185 # 优先级2: 特别处理LEGO设备 - 通常只是基于名称
186 if not should_connect and "LPF2" in device_name:
187 should_connect = True
188 connection_reason = "LEGO智能集线器"
189
190 # 优先级3: 设备地址或名称包含目标UUID前缀
191 if not should_connect and self.target_uuid:
192 if (self.target_uuid[:8].lower() in device_address.lower() or
193 (device_name and self.target_uuid[:8].lower() in device_name.lower())):
194 should_connect = True
195 connection_reason = "UUID前缀匹配名称/地址"
196
197 # 优先级4: 如果信号强度很好,并且是玩具类型设备
198 if not should_connect and rssi > -60 and (device_type.startswith("玩具") or device_type.startswith("LEGO")):
199 should_connect = True
200 connection_reason = "强信号玩具设备"
201
202 # 如果决定连接,并且之前没有尝试过
203 if should_connect and device_address not in self.connection_attempts:
204 print(f"尝试连接设备: {device_name} (原因: {connection_reason})")
205 self.connection_attempts.add(device_address) # 标记为已尝试
206 self.target_device = device_info
207 self.connect_to_device(device_info)
208
209 # 找到了可能的目标,停止扫描
210 if "LPF2" in device_name:
211 self.discovery_agent.stop()
212
213 self.deviceDiscovered.emit(device_info)
214
215 @pyqtSlot()
216 def on_scan_finished(self):
217 """当设备扫描完成时调用"""
218 print("蓝牙扫描完成")
219
220 # 如果我们还没有找到目标设备,但又发现了一些设备,则选择一个尝试连接
221 if not self.target_device and self.discovered_devices:
222 print("没有通过UUID找到目标设备,尝试连接发现的设备...")
223
224 # 首先尝试连接任何包含"LPF2"的设备
225 for addr, device_info in self.discovered_devices.items():
226 if "LPF2" in device_info.name() and addr not in self.connection_attempts:
227 print(f"尝试连接: {device_info.name()} (LEGO设备)")
228 self.connection_attempts.add(addr)
229 self.target_device = device_info
230 self.connect_to_device(device_info)
231 break
232
233 # 如果还没有目标设备,尝试基于信号强度来选择设备
234 if not self.target_device:
235 # 按信号强度排序设备
236 devices_by_signal = sorted(
237 [(addr, info) for addr, info in self.discovered_devices.items() if addr not in self.connection_attempts],
238 key=lambda x: x[1].rssi(), reverse=True # 最强信号优先
239 )
240
241 if devices_by_signal:
242 addr, device_info = devices_by_signal[0]
243 print(f"尝试连接: {device_info.name()} (最强信号设备)")
244 self.connection_attempts.add(addr)
245 self.target_device = device_info
246 self.connect_to_device(device_info)
247
248 # 如果仍未找到设备,考虑重试扫描
249 if not self.target_device and self.scan_retry_count < self.max_scan_retries:
250 print(f"没有找到合适的设备,将在2秒后重试扫描... (已尝试 {self.scan_retry_count+1}/{self.max_scan_retries+1})")
251 self.retry_timer.start(2000) # 2秒后重试
252 else:
253 if not self.target_device:
254 print("经过多次尝试后仍未找到目标设备。")
255 self.scanFinished.emit()
256
257 @pyqtSlot(QBluetoothDeviceDiscoveryAgent.Error)
258 def on_error(self, error):
259 """处理发现错误"""
260 error_str = "未知错误"
261 if error == QBluetoothDeviceDiscoveryAgent.PoweredOffError:
262 error_str = "蓝牙已关闭"
263 elif error == QBluetoothDeviceDiscoveryAgent.InputOutputError:
264 error_str = "蓝牙I/O错误"
265 elif error == QBluetoothDeviceDiscoveryAgent.InvalidBluetoothAdapterError:
266 error_str = "无效的蓝牙适配器"
267 elif error == QBluetoothDeviceDiscoveryAgent.UnsupportedPlatformError:
268 error_str = "不支持的平台"
269 elif error == QBluetoothDeviceDiscoveryAgent.UnsupportedDiscoveryMethod:
270 error_str = "不支持的发现方法"
271 elif error == QBluetoothDeviceDiscoveryAgent.ResourceError:
272 error_str = "资源错误"
273
274 print(f"蓝牙发现错误: {error_str}")
275
276 # 如果遇到错误,也考虑重试
277 if self.scan_retry_count < self.max_scan_retries:
278 print(f"因错误将在3秒后重试扫描...")
279 self.retry_timer.start(3000) # 3秒后重试
280
281 def connect_to_device(self, device_info):
282 """连接到指定设备"""
283 print(f"正在连接 {device_info.name()}...")
284
285 # 创建设备控制器
286 controller = QLowEnergyController.createCentral(device_info)
287 device_address = device_info.address().toString()
288 self.controllers[device_address] = controller
289
290 # 连接控制器信号
291 controller.connected.connect(self.on_device_connected)
292 controller.disconnected.connect(self.on_device_disconnected)
293 controller.error.connect(self.on_controller_error)
294 controller.serviceDiscovered.connect(self.on_service_discovered)
295 controller.discoveryFinished.connect(self.on_service_discovery_finished)
296
297 # 连接超时计时器
298 connection_timer = QTimer(self)
299 connection_timer.setSingleShot(True)
300 connection_timer.timeout.connect(lambda: self.on_connection_timeout(device_address, connection_timer))
301 connection_timer.start(5000) # 5秒连接超时
302
303 # 存储计时器以便稍后引用
304 controller.property_connection_timer = connection_timer
305
306 # 连接到设备
307 controller.connectToDevice()
308
309 def on_connection_timeout(self, device_address, timer):
310 """处理连接超时"""
311 if device_address in self.controllers:
312 controller = self.controllers[device_address]
313 # 在PyQt5中,QLowEnergyController没有isConnected()方法
314 # 改用state()方法检查连接状态
315 if controller.state() != QLowEnergyController.ConnectedState:
316 print(f"连接到 {controller.remoteName()} 超时")
317
318 # 删除连接尝试记录,以便后续可以再次尝试
319 if device_address in self.connection_attempts:
320 self.connection_attempts.remove(device_address)
321
322 # 设置为null,这样我们可以尝试其他设备
323 if self.target_device and self.target_device.address().toString() == device_address:
324 self.target_device = None
325
326 # 重新开始扫描,如果我们已经尝试了最大重试次数
327 if not self.discovery_agent.isActive() and self.scan_retry_count < self.max_scan_retries:
328 print("将重新开始扫描...")
329 self.retry_timer.start(1000) # 1秒后重试
330
331 @pyqtSlot()
332 def on_device_connected(self):
333 """当连接到设备时调用"""
334 controller = self.sender()
335 print(f"已连接到 {controller.remoteName()}")
336 self.deviceConnected.emit(controller)
337
338 # 停止连接超时计时器
339 if hasattr(controller, 'property_connection_timer'):
340 controller.property_connection_timer.stop()
341
342 # 发现服务
343 controller.discoverServices()
344
345 @pyqtSlot()
346 def on_device_disconnected(self):
347 """当从设备断开连接时调用"""
348 controller = self.sender()
349 device_address = ""
350
351 # 找到这个控制器的地址
352 for addr, ctrl in self.controllers.items():
353 if ctrl == controller:
354 device_address = addr
355 break
356
357 print(f"从 {controller.remoteName()} 断开连接")
358
359 # 如果这是我们当前的目标设备,清除它,以便我们可以尝试另一个
360 if self.target_device and self.target_device.address().toString() == device_address:
361 self.target_device = None
362
363 # 如果当前没有在扫描,并且我们还有剩余的重试次数,则重新开始扫描
364 if not self.discovery_agent.isActive() and self.scan_retry_count < self.max_scan_retries:
365 print("设备断开连接,将重新开始扫描...")
366 self.retry_timer.start(1000) # 1秒后重试
367
368 @pyqtSlot(QLowEnergyController.Error)
369 def on_controller_error(self, error):
370 """处理控制器错误"""
371 controller = self.sender()
372 device_address = ""
373
374 # 找到这个控制器的地址
375 for addr, ctrl in self.controllers.items():
376 if ctrl == controller:
377 device_address = addr
378 break
379
380 error_str = "未知错误"
381 if error == QLowEnergyController.UnknownError:
382 error_str = "未知错误"
383 elif error == QLowEnergyController.RemoteHostClosedError:
384 error_str = "远程主机关闭了连接"
385 elif error == QLowEnergyController.ConnectionError:
386 error_str = "连接错误"
387
388 print(f"控制器错误 ({controller.remoteName()}): {error_str}")
389
390 # 如果是我们当前的目标设备,清除它并尝试另一个
391 if self.target_device and self.target_device.address().toString() == device_address:
392 # 从尝试列表中移除,以便后续可以重新尝试
393 if device_address in self.connection_attempts:
394 self.connection_attempts.remove(device_address)
395
396 self.target_device = None
397
398 # 如果当前没有在扫描,并且我们还有剩余的重试次数,则重新开始扫描
399 if not self.discovery_agent.isActive() and self.scan_retry_count < self.max_scan_retries:
400 print("因控制器错误将重新开始扫描...")
401 self.retry_timer.start(1000) # 1秒后重试
402
403 @pyqtSlot(QBluetoothUuid)
404 def on_service_discovered(self, uuid):
405 """当在连接的设备上发现服务时调用"""
406 controller = self.sender()
407 print(f"在 {controller.remoteName()} 上发现服务: {uuid.toString()}")
408
409 @pyqtSlot()
410 def on_service_discovery_finished(self):
411 """当服务发现完成时调用"""
412 controller = self.sender()
413 print(f"{controller.remoteName()} 的服务发现完成")
414
415 # 处理发现的服务
416 services_found = False
417 for service_uuid in controller.services():
418 service = controller.createServiceObject(service_uuid)
419 if service:
420 services_found = True
421 print(f"处理服务: {service_uuid.toString()}")
422 service.stateChanged.connect(self.on_service_state_changed)
423 service.characteristicChanged.connect(
424 lambda characteristic, value, service=service:
425 self.on_characteristic_changed(characteristic, value)
426 )
427 service.discoverDetails()
428
429 if not services_found:
430 print("未发现服务,可能需要特定的连接协议")
431
432 @pyqtSlot(QLowEnergyService.ServiceState)
433 def on_service_state_changed(self, state):
434 """当服务状态改变时调用"""
435 service = self.sender()
436 if state == QLowEnergyService.ServiceDiscovered:
437 print(f"服务详情已发现: {service.serviceUuid().toString()}")
438
439 # 处理特性
440 for characteristic in service.characteristics():
441 print(f"发现特性: {characteristic.uuid().toString()}")
442 print(f" - 特性属性: {characteristic.properties()}")
443
444 # 如果这是一个可读特性,尝试读取它
445 if characteristic.properties() & QLowEnergyCharacteristic.Read:
446 print(f" - 读取特性值...")
447 service.readCharacteristic(characteristic)
448
449 # 如果这是一个可通知特性,尝试开启通知
450 if characteristic.properties() & QLowEnergyCharacteristic.Notify:
451 print(f" - 启用通知...")
452 try:
453 # PyQt5的QLowEnergyService没有descriptors()方法
454 # 我们可以直接尝试获取CCCD描述符
455 # 或者尝试直接写入特征来启用通知
456 descriptor = characteristic.descriptor(QBluetoothUuid(QBluetoothUuid.ClientCharacteristicConfiguration))
457 if descriptor.isValid():
458 print(f" - 找到客户端特性配置描述符")
459 service.writeDescriptor(descriptor, b"\x01\x00") # 启用通知
460 else:
461 print(f" - 未找到有效的客户端特性配置描述符")
462 # 某些实现可能支持以下方法
463 if hasattr(service, 'setNotifyValue'):
464 print(f" - 尝试使用setNotifyValue方法")
465 service.setNotifyValue(characteristic, True)
466 except Exception as e:
467 print(f" - 启用通知时出错: {e}")
468 print(f" - 将尝试特殊处理LEGO设备...")
469
470 # LEGO设备特殊处理 - 这是一种常见的方法
471 try:
472 if "LPF2" in service.controller().remoteName():
473 print(f" - 检测到LEGO设备,尝试特殊处理")
474 # 有些LEGO设备需要写入一个特定值到特性以启用通知
475 if characteristic.properties() & QLowEnergyCharacteristic.Write:
476 print(f" - 尝试写入特性来启用通知")
477 service.writeCharacteristic(characteristic, b"\x01\x00")
478 except Exception as e2:
479 print(f" - LEGO设备特殊处理失败: {e2}")
480
481 def on_characteristic_changed(self, characteristic, value):
482 """当特性值改变时调用"""
483 try:
484 # 将QByteArray转换为十六进制字符串
485 if hasattr(value, 'data'): # 它是一个QByteArray
486 data_bytes = bytes(value)
487 hex_string = data_bytes.hex() if hasattr(data_bytes, 'hex') else ' '.join([f'{b:02x}' for b in data_bytes])
488 else: # 它可能已经是bytes
489 hex_string = value.hex() if hasattr(value, 'hex') else ' '.join([f'{b:02x}' for b in value])
490
491 print(f"特性 {characteristic.uuid().toString()} 值改变: {hex_string}")
492
493 # 解析数据 (示例)
494 print(f"数据解析: {' '.join([f'{b:02x}' for b in data_bytes])}")
495 except Exception as e:
496 print(f"处理特性变化时出错: {e}")
497
498
499 def main():
500 """运行蓝牙扫描器的主函数"""
501 import sys
502
503 app = QApplication(sys.argv)
504
505 # 创建带有目标UUID的扫描器
506 scanner = BluetoothDeviceScanner(target_uuid="00001523-1212-efde-1523-785feabcd123")
507
508 # 创建简单的UI
509 window = QMainWindow()
510 window.setWindowTitle("蓝牙扫描器")
511 window.resize(700, 500)
512
513 central_widget = QWidget()
514 layout = QVBoxLayout(central_widget)
515
516 # 添加文本编辑框
517 text_edit = QTextEdit()
518 text_edit.setReadOnly(True)
519 layout.addWidget(text_edit)
520
521 # 添加按钮布局
522 button_layout = QHBoxLayout()
523
524 # 开始扫描按钮
525 start_scan_button = QPushButton("开始扫描")
526 start_scan_button.clicked.connect(scanner.start_scan)
527 button_layout.addWidget(start_scan_button)
528
529 # 停止扫描按钮
530 stop_scan_button = QPushButton("停止扫描")
531 stop_scan_button.clicked.connect(scanner.stop_scan)
532 button_layout.addWidget(stop_scan_button)
533
534 # 清除按钮
535 clear_button = QPushButton("清除日志")
536 clear_button.clicked.connect(text_edit.clear)
537 button_layout.addWidget(clear_button)
538
539 layout.addLayout(button_layout)
540
541 window.setCentralWidget(central_widget)
542 window.show()
543
544 # 重定向print语句到文本编辑框
545 import sys
546 original_stdout = sys.stdout
547
548 class TextEditRedirector:
549 def __init__(self, text_edit):
550 self.text_edit = text_edit
551
552 def write(self, text):
553 self.text_edit.append(text)
554 original_stdout.write(text)
555
556 def flush(self):
557 pass
558
559 sys.stdout = TextEditRedirector(text_edit)
560
561 # 自动开始第一次扫描
562 scanner.start_scan()
563
564 return app.exec_()
565
566
567 if __name__ == "__main__":
568 main()
...\ No newline at end of file ...\ No newline at end of file
1 # -*- mode: python ; coding: utf-8 -*-
2
3
4 a = Analysis(
5 ['qt5.py'],
6 pathex=[],
7 binaries=[],
8 datas=[('data', 'data')],
9 hiddenimports=[],
10 hookspath=[],
11 hooksconfig={},
12 runtime_hooks=[],
13 excludes=[],
14 noarchive=False,
15 optimize=0,
16 )
17 pyz = PYZ(a.pure)
18
19 exe = EXE(
20 pyz,
21 a.scripts,
22 a.binaries,
23 a.datas,
24 [],
25 name='qt5',
26 debug=False,
27 bootloader_ignore_signals=False,
28 strip=False,
29 upx=True,
30 upx_exclude=[],
31 runtime_tmpdir=None,
32 console=True,
33 disable_windowed_traceback=False,
34 argv_emulation=False,
35 target_arch=None,
36 codesign_identity=None,
37 entitlements_file=None,
38 icon=['data\\app.ico'],
39 )
...@@ -27,7 +27,9 @@ pip install pystray pillow ...@@ -27,7 +27,9 @@ pip install pystray pillow
27 27
28 ## 28 ##
29 打包指令 产生一个带窗口的程序 打包完后可以随便改exe 名字 29 打包指令 产生一个带窗口的程序 打包完后可以随便改exe 名字
30 C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\Scripts\pyinstaller.exe --onefile --icon=data\app.ico we.py --add-data "data;data" 30 C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\Scripts\pyinstaller.exe -F --hidden-import=bleak.backends --hidden-import=asyncio --win-private-assemblies --onefile --icon=data\app.ico we.py --add-data "data;data"
31
32 C:\Users\Admin\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0\LocalCache\local-packages\Python313\Scripts\pyinstaller.exe --onefile --windowed --name=ble_client --icon=data\app.ico we.py --add-data "data;data"
31 33
32 ## 34 ##
33 端口占用 35 端口占用
......
1 # -*- coding: utf-8 -*-
2 import sys
3 import asyncio
4 import websockets
5 from bleak import BleakScanner, BleakClient
6 import json
7 import base64
8 import threading
9 from collections import defaultdict
10
11 import platform
12
13 # 方法1:通过sys模块快速判断(推荐)
14 if sys.platform.startswith('win32'):
15 import winrt.windows.foundation.collections # noqa
16 import winrt.windows.devices.bluetooth # noqa
17 import winrt.windows.devices.bluetooth.advertisement # noq
18 print("当前运行在Windows系统")
19 elif sys.platform.startswith('linux'):
20 print("当前运行在Linux系统")
21 elif sys.platform.startswith('darwin'):
22 print("当前运行在macOS系统")
23 # 添加线程锁以确保日志写入的原子性
24 write_lock = threading.Lock()
25
26 def log_message_sync(direction, message):
27 """同步日志记录函数"""
28 log_entry = f"{direction}: {message}\n"
29 print(log_entry, end='') # 控制台仍然输出
30 with write_lock:
31 with open('b.log', 'a', encoding='utf-8') as f:
32 f.write(log_entry)
33
34 async def log_message(direction, message):
35 """异步封装日志记录"""
36 loop = asyncio.get_event_loop()
37 await loop.run_in_executor(None, log_message_sync, direction, message)
38
39 class BLEClient:
40 def __init__(self):
41 self.target_device = None
42 self.client = None
43 self.services = []
44 self.optional_services = []
45 self.websocket = None
46 self.notification_records = defaultdict(lambda: (None, 0)) # 特征ID: (最后消息, 时间戳)
47
48 def on_disconnect(self, client):
49 print("BLE连接断开,关闭WebSocket")
50 if self.websocket and not self.websocket.closed:
51 asyncio.create_task(self.close_websocket())
52
53 async def close_websocket(self):
54 await self.websocket.close()
55 self.websocket = None
56
57 def detection_callback(self, device, advertisement_data):
58 if any(service_uuid in advertisement_data.service_uuids for service_uuid in self.services):
59 self.target_device = (device, advertisement_data)
60 if not self.target_device:
61 print("未找到匹配设备")
62 return
63 else:
64 device, adv_data = self.target_device
65 print("\n找到目标设备:")
66 print(f"设备名称: {device.name}")
67 print(f"设备地址: {device.address}")
68 print(f"信号强度: {device.rssi} dBm")
69 print("\n广播信息:")
70 print(f"服务UUID列表: {adv_data.service_uuids}")
71 print(f"制造商数据: {adv_data.manufacturer_data}")
72 print(f"服务数据: {adv_data.service_data}")
73 print(f"本地名称: {adv_data.local_name}")
74 return self.target_device
75
76 async def handle_client(self, websocket, path):
77 self.websocket = websocket
78 if path != "/scratch/ble":
79 await websocket.close(code=1003, reason="Path not allowed")
80 return
81
82 try:
83 async for message in websocket:
84 try:
85 await log_message("接收", message)
86 request = json.loads(message)
87
88 if request["jsonrpc"] != "2.0":
89 continue
90
91 method = request.get("method")
92 params = request.get("params", {})
93 request_id = request.get("id")
94
95 if method == "discover":
96 self.services = []
97 for filt in params.get("filters", [{}]):
98 self.services.extend(filt.get("services", []))
99 self.optional_services = params.get("optionalServices", [])
100
101 scanner = BleakScanner(scanning_mode="active")
102 scanner.register_detection_callback(self.detection_callback)
103
104 max_retries = 3
105 found = False
106 for attempt in range(max_retries):
107 self.target_device = None
108 await scanner.start()
109 await asyncio.sleep(5)
110 await scanner.stop()
111
112 if self.target_device:
113 found = True
114 break
115
116 if attempt < max_retries - 1:
117 print(f"未找到设备,第{attempt+1}次重试...")
118 await asyncio.sleep(3)
119
120 if found:
121 device, adv_data = self.target_device
122 discover_response = json.dumps({
123 "jsonrpc": "2.0",
124 "method": "didDiscoverPeripheral",
125 "params": {
126 "name": device.name,
127 "peripheralId": device.address,
128 "rssi": device.rssi
129 }
130 })
131 await log_message("下发", discover_response)
132 await websocket.send(discover_response)
133
134 result_response = json.dumps({
135 "jsonrpc": "2.0",
136 "result": None,
137 "id": request_id
138 })
139 await log_message("下发", result_response)
140 await websocket.send(result_response)
141
142 elif method == "connect":
143 peripheral_id = params.get("peripheralId")
144 if peripheral_id:
145 self.client = BleakClient(peripheral_id)
146 self.client.set_disconnected_callback(self.on_disconnect)
147 await self.client.connect()
148
149 if self.client.is_connected:
150 response = json.dumps({
151 "jsonrpc": "2.0",
152 "result": None,
153 "id": request_id
154 })
155 await log_message("下发", response)
156 await websocket.send(response)
157
158 elif method == "write":
159 service_id = params.get("serviceId")
160 characteristic_id = params.get("characteristicId")
161 message = params.get("message")
162 encoding = params.get("encoding", "utf-8")
163
164 if all([service_id, characteristic_id, message]):
165 if encoding == "base64":
166 message_bytes = base64.b64decode(message)
167 else:
168 message_bytes = message.encode(encoding)
169
170 await self.client.write_gatt_char(characteristic_id, message_bytes)
171 response = json.dumps({
172 "jsonrpc": "2.0",
173 "result": None,
174 "id": request_id
175 })
176 await log_message("下发", response)
177 await websocket.send(response)
178
179 elif method == "read":
180 service_id = params.get("serviceId")
181 characteristic_id = params.get("characteristicId")
182
183 if all([service_id, characteristic_id]):
184 data = await self.client.read_gatt_char(characteristic_id)
185 response = json.dumps({
186 "jsonrpc": "2.0",
187 "result": {
188 "serviceId": service_id,
189 "characteristicId": characteristic_id,
190 "message": base64.b64encode(data).decode("utf-8")
191 },
192 "id": request_id
193 })
194 await log_message("下发", response)
195 await websocket.send(response)
196
197 elif method == "startNotifications":
198 service_id = params.get("serviceId")
199 characteristic_id = params.get("characteristicId")
200
201 if all([service_id, characteristic_id]):
202 await self.client.start_notify(
203 characteristic_id,
204 self.notification_handler(websocket, service_id, characteristic_id)
205 )
206 response = json.dumps({
207 "jsonrpc": "2.0",
208 "result": None,
209 "id": request_id
210 })
211 await log_message("下发", response)
212 await websocket.send(response)
213
214 except json.JSONDecodeError:
215 error_msg = json.dumps({
216 "jsonrpc": "2.0",
217 "result": {"message": "Parse error"},
218 "id": None
219 })
220 await log_message("下发", error_msg)
221 except Exception as e:
222 error_msg = json.dumps({
223 "jsonrpc": "2.0",
224 "result": {"message": str(e)},
225 "id": request.get("id") if request else None
226 })
227 await log_message("下发", error_msg)
228
229 except websockets.exceptions.ConnectionClosed:
230 print("WebSocket连接关闭")
231 finally:
232 if self.client and self.client.is_connected:
233 await self.client.disconnect()
234 self.client = None
235 self.target_device = None
236
237 def notification_handler(self, websocket, service_id, characteristic_id):
238 async def callback(sender, data):
239 current_time = asyncio.get_event_loop().time()
240 last_message, last_time = self.notification_records[characteristic_id]
241
242 # 解码当前数据用于比较
243 current_message = base64.b64encode(data).decode('utf-8')
244
245 # 过滤逻辑
246 if current_message == last_message and (current_time - last_time) < 0.5:
247 return
248
249 # 更新记录
250 self.notification_records[characteristic_id] = (current_message, current_time)
251
252 response = json.dumps({
253 "jsonrpc": "2.0",
254 "method": "characteristicDidChange",
255 "params": {
256 "serviceId": service_id,
257 "characteristicId": characteristic_id,
258 "message": current_message
259 }
260 })
261 await log_message("下发", response)
262 await websocket.send(response)
263 return callback
264
265 async def main():
266 async with websockets.serve(
267 lambda websocket, path: BLEClient().handle_client(websocket, path),
268 "localhost", 20111
269 ):
270 print("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
271 print("日志文件路径: ./b.log")
272 await asyncio.Future()
273
274 if __name__ == "__main__":
275 asyncio.run(main())
...\ No newline at end of file ...\ No newline at end of file
1 # -*- coding: utf-8 -*-
2
3 import asyncio
4 import websockets
5 from bleak import BleakScanner, BleakClient
6 import json
7 import base64
8 import threading
9 import winrt.windows.foundation.collections # noqa
10 import winrt.windows.devices.bluetooth # noqa
11 import winrt.windows.devices.bluetooth.advertisement # noqa
12
13 # 添加线程锁以确保日志写入的原子性
14 write_lock = threading.Lock()
15
16 def log_message_sync(direction, message):
17 """同步日志记录函数"""
18 log_entry = f"{direction}: {message}\n"
19 print(log_entry, end='') # 控制台仍然输出
20 with write_lock:
21 with open('a.log', 'a', encoding='utf-8') as f:
22 f.write(log_entry)
23
24 async def log_message(direction, message):
25 """异步封装日志记录"""
26 loop = asyncio.get_event_loop()
27 await loop.run_in_executor(None, log_message_sync, direction, message)
28
29 class BLEClient:
30 def __init__(self):
31 self.target_device = None
32 self.client = None
33 self.services = []
34 self.optional_services = []
35 self.websocket = None
36
37 def on_disconnect(self, client):
38 print("BLE连接断开,关闭WebSocket")
39 if self.websocket and not self.websocket.closed:
40 asyncio.create_task(self.close_websocket())
41
42 async def close_websocket(self):
43 await self.websocket.close()
44 self.websocket = None
45
46 def detection_callback(self, device, advertisement_data):
47 if any(service_uuid in advertisement_data.service_uuids for service_uuid in self.services):
48 self.target_device = (device, advertisement_data)
49 if not self.target_device:
50 print("未找到匹配设备")
51 return
52 else:
53 device, adv_data = self.target_device
54 print("\n找到目标设备:")
55 print(f"设备名称: {device.name}")
56 print(f"设备地址: {device.address}")
57 print(f"信号强度: {device.rssi} dBm")
58 print("\n广播信息:")
59 print(f"服务UUID列表: {adv_data.service_uuids}")
60 print(f"制造商数据: {adv_data.manufacturer_data}")
61 print(f"服务数据: {adv_data.service_data}")
62 print(f"本地名称: {adv_data.local_name}")
63 return self.target_device
64
65 async def handle_client(self, websocket, path):
66 self.websocket = websocket
67 if path != "/scratch/ble":
68 await websocket.close(code=1003, reason="Path not allowed")
69 return
70
71 try:
72 async for message in websocket:
73 try:
74 # 记录接收到的消息
75 await log_message("接收", message)
76
77 request = json.loads(message)
78 if request["jsonrpc"] != "2.0":
79 response = json.dumps({
80 "jsonrpc": "2.0",
81 "result": {"message": "Invalid Request"},
82 "id": request.get("id", None)
83 })
84 await log_message("下发", response)
85 await websocket.send(response)
86 continue
87
88 method = request.get("method")
89 params = request.get("params", {})
90 request_id = request.get("id")
91
92 if method == "discover":
93 self.services = params.get("filters", [{}])[1].get("services", [])
94 self.optional_services = params.get("optionalServices", [])
95
96 scanner = BleakScanner()
97 scanner.register_detection_callback(self.detection_callback)
98
99 # 添加重试机制
100 max_retries = 3
101 found = False
102 for attempt in range(max_retries):
103 self.target_device = None # 重置目标设备
104 await scanner.start()
105 await asyncio.sleep(5)
106 await scanner.stop()
107
108 if self.target_device:
109 found = True
110 break
111
112 if attempt < max_retries - 1: # 最后一次不等待
113 print(f"未找到设备,第{attempt+1}次重试...")
114 await asyncio.sleep(3)
115
116 if not found:
117 # response = json.dumps({
118 # "jsonrpc": "2.0",
119 # "result": {"message": "Device not found"},
120 # "id": request_id
121 # })
122 # await log_message("下发", response)
123 # await websocket.send(response)
124 continue
125
126 device, adv_data = self.target_device
127 discover_response = json.dumps({
128 "jsonrpc": "2.0",
129 "method": "didDiscoverPeripheral",
130 "params": {
131 "name": device.name,
132 "peripheralId": device.address,
133 "rssi": device.rssi
134 }
135 })
136 await log_message("下发", discover_response)
137 await websocket.send(discover_response)
138
139 result_response = json.dumps({
140 "jsonrpc": "2.0",
141 "result": None,
142 "id": request_id
143 })
144 await log_message("下发", result_response)
145 await websocket.send(result_response)
146
147 elif method == "connect":
148 peripheral_id = params.get("peripheralId")
149 if not peripheral_id:
150 response = json.dumps({
151 "jsonrpc": "2.0",
152 "result": {"message": "Invalid params"},
153 "id": request_id
154 })
155 await log_message("下发", response)
156 await websocket.send(response)
157 continue
158
159 self.client = BleakClient(peripheral_id)
160 self.client.set_disconnected_callback(self.on_disconnect)
161 await self.client.connect()
162 if self.client.is_connected:
163 print(f"已连接至设备: {peripheral_id}")
164 response = json.dumps({
165 "jsonrpc": "2.0",
166 "result": None,
167 "id": request_id
168 })
169 await log_message("下发", response)
170 await websocket.send(response)
171 else:
172 response = json.dumps({
173 "jsonrpc": "2.0",
174 "result": {"message": "Failed to connect"},
175 "id": request_id
176 })
177 await log_message("下发", response)
178 await websocket.send(response)
179
180 elif method == "write":
181 service_id = params.get("serviceId")
182 characteristic_id = params.get("characteristicId")
183 message = params.get("message")
184 encoding = params.get("encoding", "utf-8")
185
186 if not all([service_id, characteristic_id, message]):
187 response = json.dumps({
188 "jsonrpc": "2.0",
189 "result": {"message": "Invalid params"},
190 "id": request_id
191 })
192 await log_message("下发", response)
193 await websocket.send(response)
194 continue
195
196 if encoding == "base64":
197 message_bytes = base64.b64decode(message)
198 else:
199 message_bytes = message.encode(encoding)
200
201 await self.client.write_gatt_char(characteristic_id, message_bytes)
202 response = json.dumps({
203 "jsonrpc": "2.0",
204 "result": None,
205 "id": request_id
206 })
207 await log_message("下发", response)
208 await websocket.send(response)
209
210 elif method == "read":
211 service_id = params.get("serviceId")
212 characteristic_id = params.get("characteristicId")
213
214 if not all([service_id, characteristic_id]):
215 response = json.dumps({
216 "jsonrpc": "2.0",
217 "result": {"message": "Invalid params"},
218 "id": request_id
219 })
220 await log_message("下发", response)
221 await websocket.send(response)
222 continue
223
224 data = await self.client.read_gatt_char(characteristic_id)
225 response = json.dumps({
226 "jsonrpc": "2.0",
227 "result": {
228 "serviceId": service_id,
229 "characteristicId": characteristic_id,
230 "message": base64.b64encode(data).decode("utf-8")
231 },
232 "id": request_id
233 })
234 await log_message("下发", response)
235 await websocket.send(response)
236
237 elif method == "startNotifications":
238 service_id = params.get("serviceId")
239 characteristic_id = params.get("characteristicId")
240
241 if not all([service_id, characteristic_id]):
242 response = json.dumps({
243 "jsonrpc": "2.0",
244 "result": {"message": "Invalid params"},
245 "id": request_id
246 })
247 await log_message("下发", response)
248 await websocket.send(response)
249 continue
250
251 await self.client.start_notify(
252 characteristic_id,
253 self.notification_handler(websocket, service_id, characteristic_id)
254 )
255 response = json.dumps({
256 "jsonrpc": "2.0",
257 "result": None,
258 "id": request_id
259 })
260 await log_message("下发", response)
261 await websocket.send(response)
262
263 else:
264 response = json.dumps({
265 "jsonrpc": "2.0",
266 "result": {"message": "Method not found"},
267 "id": request_id
268 })
269 await log_message("下发", response)
270 await websocket.send(response)
271
272 except json.JSONDecodeError:
273 response = json.dumps({
274 "jsonrpc": "2.0",
275 "result": {"message": "Parse error"},
276 "id": None
277 })
278 await log_message("下发", response)
279 await websocket.send(response)
280 except Exception as e:
281 response = json.dumps({
282 "jsonrpc": "2.0",
283 "result": {"message": str(e)},
284 "id": request_id
285 })
286 await log_message("下发", response)
287 await websocket.send(response)
288
289 except websockets.exceptions.ConnectionClosedOK:
290 print("WebSocket客户端正常断开")
291 except websockets.exceptions.ConnectionClosedError as e:
292 print(f"WebSocket客户端异常断开: {e.code} - {e.reason}")
293 finally:
294 if self.client and self.client.is_connected:
295 await self.client.disconnect()
296 print("BLE设备已主动断开")
297 self.client = None
298 self.target_device = None
299
300 def notification_handler(self, websocket, service_id, characteristic_id):
301 async def callback(sender, data):
302 response = json.dumps({
303 "jsonrpc": "2.0",
304 "method": "characteristicDidChange",
305 "params": {
306 "serviceId": service_id,
307 "characteristicId": characteristic_id,
308 "message": base64.b64encode(data).decode("utf-8")
309 }
310 })
311 await log_message("下发", response)
312 await websocket.send(response)
313 return callback
314
315 async def main():
316 async with websockets.serve(
317 lambda websocket, path: BLEClient().handle_client(websocket, path),
318 "localhost", 20111
319 ):
320 print("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
321 print("日志文件路径: ./b.log")
322 await asyncio.Future() # 永久运行
323
324 if __name__ == "__main__":
325 asyncio.run(main())
...\ No newline at end of file ...\ No newline at end of file
1 # -*- mode: python ; coding: utf-8 -*-
2
3
4 a = Analysis(
5 ['s6.9.2.py'],
6 pathex=[],
7 binaries=[],
8 datas=[('data', 'data')],
9 hiddenimports=['bleak.backends', 'asyncio'],
10 hookspath=[],
11 hooksconfig={},
12 runtime_hooks=[],
13 excludes=[],
14 noarchive=False,
15 optimize=0,
16 )
17 pyz = PYZ(a.pure)
18
19 exe = EXE(
20 pyz,
21 a.scripts,
22 a.binaries,
23 a.datas,
24 [],
25 name='s6.9.2',
26 debug=False,
27 bootloader_ignore_signals=False,
28 strip=False,
29 upx=True,
30 upx_exclude=[],
31 runtime_tmpdir=None,
32 console=True,
33 disable_windowed_traceback=False,
34 argv_emulation=False,
35 target_arch=None,
36 codesign_identity=None,
37 entitlements_file=None,
38 icon=['data\\app.ico'],
39 )
1 import pystray 1 import pystray
2 from PIL import Image, ImageDraw 2 from PIL import Image
3 import threading 3 import threading
4 import os
5 import sys
4 6
5 def create_image(width, height, color1, color2): 7 def load_icon(icon_path):
6 image = Image.new("RGB", (width, height), color1) 8 """加载图标文件"""
7 dc = ImageDraw.Draw(image) 9 try:
8 dc.rectangle((width // 2, 0, width, height // 2), fill=color2) 10 return Image.open(icon_path)
9 return image 11 except FileNotFoundError:
12 print(f"Icon file not found at {icon_path}")
13 return None
14
15 def on_exit(icon, item):
16 """退出程序的回调函数"""
17 icon.stop() # 停止托盘图标
18 print("Exiting program...")
19 os._exit(0) # 强制退出程序
10 20
11 def run_icon(icon_path): 21 def run_icon(icon_path):
12 image = Image.open(icon_path) # 加载自定义图标 22 """运行系统托盘图标"""
13 icon = pystray.Icon("test_icon", image, "My System Tray Icon") 23 image = load_icon(icon_path)
14 icon.run() 24 if not image:
25 print("Failed to load icon. Exiting...")
26 return
27
28 # 创建系统托盘图标
29 icon = pystray.Icon(
30 name="test_icon",
31 icon=image,
32 title="My System Tray Icon",
33 menu=pystray.Menu(
34 pystray.MenuItem("Exit", on_exit) # 添加右键菜单项
35 )
36 )
37 icon.run() # 运行托盘图标
15 38
16 def start_tray_icon(icon_path): 39 def start_tray_icon(icon_path):
40 """在新线程中启动系统托盘图标"""
17 threading.Thread(target=run_icon, args=(icon_path,), daemon=True).start() 41 threading.Thread(target=run_icon, args=(icon_path,), daemon=True).start()
...\ No newline at end of file ...\ No newline at end of file
......
1 # -*- coding: utf-8 -*-- 1 import sys
2 import asyncio 2 import asyncio
3 import websockets
4 from bleak import BleakScanner, BleakClient
5 import json 3 import json
6 import base64 4 import base64
7 import threading 5 import threading
8 from tray_icon import start_tray_icon 6 from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QPushButton, QVBoxLayout, QWidget
9 import os 7 from PyQt5.QtCore import QThread, pyqtSignal
10 import sys 8 from bleak import BleakScanner, BleakClient
11 9 import websockets
12 def resource_path(relative_path):
13 try:
14 base_path = sys._MEIPASS # 打包后运行时的临时路径
15 except AttributeError:
16 base_path = os.path.dirname(os.path.abspath(__file__)) # 开发环境下的路径
17 # 使用 os.path.join 拼接路径,并通过 os.path.abspath 转换为绝对路径
18 return os.path.abspath(os.path.join(base_path, relative_path))
19
20 def resource_path(relative_path):
21 """获取资源文件的绝对路径,适用于打包后的程序"""
22 try:
23 base_path = sys._MEIPASS # 打包后运行时的临时路径
24 except AttributeError:
25 base_path = os.path.abspath(".") # 开发环境下的路径
26 return os.path.join(base_path, relative_path)
27
28 # 获取图标路径
29 icon_path = resource_path(resource_path("data/app.ico"))
30
31 # 调用系统托盘图标函数
32 start_tray_icon(icon_path)
33 10
34 # 添加线程锁以确保日志写入的原子性 11 # 添加线程锁以确保日志写入的原子性
35 write_lock = threading.Lock() 12 write_lock = threading.Lock()
36 13
37 def log_message_sync(direction, message): 14 def log_message_sync(direction, message, log_signal=None):
38 """同步日志记录函数""" 15 """同步日志记录函数(支持信号传递)"""
39 log_entry = f"{direction}: {message}\n" 16 log_entry = f"{direction}: {message}\n"
40 print(log_entry, end='') # 控制台仍然输出 17 print(log_entry, end='') # 控制台输出
41 with write_lock: 18 with write_lock:
42 with open('a.log', 'a', encoding='utf-8') as f: 19 with open('a.log', 'a', encoding='utf-8') as f:
43 f.write(log_entry) 20 f.write(log_entry)
21 if log_signal:
22 log_signal.emit(log_entry) # 发射信号到GUI
44 23
45 async def log_message(direction, message): 24 async def log_message(direction, message, log_signal=None):
46 """异步封装日志记录""" 25 """异步封装日志记录"""
47 loop = asyncio.get_event_loop() 26 loop = asyncio.get_event_loop()
48 await loop.run_in_executor(None, log_message_sync, direction, message) 27 await loop.run_in_executor(None, log_message_sync, direction, message, log_signal)
49 28
50 class BLEClient: 29 class BLEClient:
51 def __init__(self): 30 def __init__(self, log_signal=None):
52 self.target_device = None 31 self.target_device = None
53 self.client = None 32 self.client = None
54 self.services = [] 33 self.services = []
55 self.optional_services = [] 34 self.optional_services = []
56 self.websocket = None 35 self.websocket = None
36 self.log_signal = log_signal # 绑定日志信号
57 37
58 def on_disconnect(self, client): 38 def on_disconnect(self, client):
59 print("BLE连接断开,关闭WebSocket") 39 print("BLE连接断开,关闭WebSocket")
...@@ -93,7 +73,7 @@ class BLEClient: ...@@ -93,7 +73,7 @@ class BLEClient:
93 async for message in websocket: 73 async for message in websocket:
94 try: 74 try:
95 # 记录接收到的消息 75 # 记录接收到的消息
96 await log_message("接收", message) 76 await log_message("接收", message, self.log_signal)
97 77
98 request = json.loads(message) 78 request = json.loads(message)
99 if request["jsonrpc"] != "2.0": 79 if request["jsonrpc"] != "2.0":
...@@ -102,7 +82,7 @@ class BLEClient: ...@@ -102,7 +82,7 @@ class BLEClient:
102 "result": {"message": "Invalid Request"}, 82 "result": {"message": "Invalid Request"},
103 "id": request.get("id", None) 83 "id": request.get("id", None)
104 }) 84 })
105 await log_message("下发", response) 85 await log_message("下发", response, self.log_signal)
106 await websocket.send(response) 86 await websocket.send(response)
107 continue 87 continue
108 88
...@@ -135,13 +115,6 @@ class BLEClient: ...@@ -135,13 +115,6 @@ class BLEClient:
135 await asyncio.sleep(3) 115 await asyncio.sleep(3)
136 116
137 if not found: 117 if not found:
138 # response = json.dumps({
139 # "jsonrpc": "2.0",
140 # "result": {"message": "Device not found"},
141 # "id": request_id
142 # })
143 # await log_message("下发", response)
144 # await websocket.send(response)
145 continue 118 continue
146 119
147 device, adv_data = self.target_device 120 device, adv_data = self.target_device
...@@ -154,7 +127,7 @@ class BLEClient: ...@@ -154,7 +127,7 @@ class BLEClient:
154 "rssi": device.rssi 127 "rssi": device.rssi
155 } 128 }
156 }) 129 })
157 await log_message("下发", discover_response) 130 await log_message("下发", discover_response, self.log_signal)
158 await websocket.send(discover_response) 131 await websocket.send(discover_response)
159 132
160 result_response = json.dumps({ 133 result_response = json.dumps({
...@@ -162,7 +135,7 @@ class BLEClient: ...@@ -162,7 +135,7 @@ class BLEClient:
162 "result": None, 135 "result": None,
163 "id": request_id 136 "id": request_id
164 }) 137 })
165 await log_message("下发", result_response) 138 await log_message("下发", result_response, self.log_signal)
166 await websocket.send(result_response) 139 await websocket.send(result_response)
167 140
168 elif method == "connect": 141 elif method == "connect":
...@@ -173,7 +146,7 @@ class BLEClient: ...@@ -173,7 +146,7 @@ class BLEClient:
173 "result": {"message": "Invalid params"}, 146 "result": {"message": "Invalid params"},
174 "id": request_id 147 "id": request_id
175 }) 148 })
176 await log_message("下发", response) 149 await log_message("下发", response, self.log_signal)
177 await websocket.send(response) 150 await websocket.send(response)
178 continue 151 continue
179 152
...@@ -187,7 +160,7 @@ class BLEClient: ...@@ -187,7 +160,7 @@ class BLEClient:
187 "result": None, 160 "result": None,
188 "id": request_id 161 "id": request_id
189 }) 162 })
190 await log_message("下发", response) 163 await log_message("下发", response, self.log_signal)
191 await websocket.send(response) 164 await websocket.send(response)
192 else: 165 else:
193 response = json.dumps({ 166 response = json.dumps({
...@@ -195,7 +168,7 @@ class BLEClient: ...@@ -195,7 +168,7 @@ class BLEClient:
195 "result": {"message": "Failed to connect"}, 168 "result": {"message": "Failed to connect"},
196 "id": request_id 169 "id": request_id
197 }) 170 })
198 await log_message("下发", response) 171 await log_message("下发", response, self.log_signal)
199 await websocket.send(response) 172 await websocket.send(response)
200 173
201 elif method == "write": 174 elif method == "write":
...@@ -210,7 +183,7 @@ class BLEClient: ...@@ -210,7 +183,7 @@ class BLEClient:
210 "result": {"message": "Invalid params"}, 183 "result": {"message": "Invalid params"},
211 "id": request_id 184 "id": request_id
212 }) 185 })
213 await log_message("下发", response) 186 await log_message("下发", response, self.log_signal)
214 await websocket.send(response) 187 await websocket.send(response)
215 continue 188 continue
216 189
...@@ -225,7 +198,7 @@ class BLEClient: ...@@ -225,7 +198,7 @@ class BLEClient:
225 "result": None, 198 "result": None,
226 "id": request_id 199 "id": request_id
227 }) 200 })
228 await log_message("下发", response) 201 await log_message("下发", response, self.log_signal)
229 await websocket.send(response) 202 await websocket.send(response)
230 203
231 elif method == "read": 204 elif method == "read":
...@@ -238,7 +211,7 @@ class BLEClient: ...@@ -238,7 +211,7 @@ class BLEClient:
238 "result": {"message": "Invalid params"}, 211 "result": {"message": "Invalid params"},
239 "id": request_id 212 "id": request_id
240 }) 213 })
241 await log_message("下发", response) 214 await log_message("下发", response, self.log_signal)
242 await websocket.send(response) 215 await websocket.send(response)
243 continue 216 continue
244 217
...@@ -252,7 +225,7 @@ class BLEClient: ...@@ -252,7 +225,7 @@ class BLEClient:
252 }, 225 },
253 "id": request_id 226 "id": request_id
254 }) 227 })
255 await log_message("下发", response) 228 await log_message("下发", response, self.log_signal)
256 await websocket.send(response) 229 await websocket.send(response)
257 230
258 elif method == "startNotifications": 231 elif method == "startNotifications":
...@@ -265,7 +238,7 @@ class BLEClient: ...@@ -265,7 +238,7 @@ class BLEClient:
265 "result": {"message": "Invalid params"}, 238 "result": {"message": "Invalid params"},
266 "id": request_id 239 "id": request_id
267 }) 240 })
268 await log_message("下发", response) 241 await log_message("下发", response, self.log_signal)
269 await websocket.send(response) 242 await websocket.send(response)
270 continue 243 continue
271 244
...@@ -278,7 +251,7 @@ class BLEClient: ...@@ -278,7 +251,7 @@ class BLEClient:
278 "result": None, 251 "result": None,
279 "id": request_id 252 "id": request_id
280 }) 253 })
281 await log_message("下发", response) 254 await log_message("下发", response, self.log_signal)
282 await websocket.send(response) 255 await websocket.send(response)
283 256
284 else: 257 else:
...@@ -287,7 +260,7 @@ class BLEClient: ...@@ -287,7 +260,7 @@ class BLEClient:
287 "result": {"message": "Method not found"}, 260 "result": {"message": "Method not found"},
288 "id": request_id 261 "id": request_id
289 }) 262 })
290 await log_message("下发", response) 263 await log_message("下发", response, self.log_signal)
291 await websocket.send(response) 264 await websocket.send(response)
292 265
293 except json.JSONDecodeError: 266 except json.JSONDecodeError:
...@@ -296,7 +269,7 @@ class BLEClient: ...@@ -296,7 +269,7 @@ class BLEClient:
296 "result": {"message": "Parse error"}, 269 "result": {"message": "Parse error"},
297 "id": None 270 "id": None
298 }) 271 })
299 await log_message("下发", response) 272 await log_message("下发", response, self.log_signal)
300 await websocket.send(response) 273 await websocket.send(response)
301 except Exception as e: 274 except Exception as e:
302 response = json.dumps({ 275 response = json.dumps({
...@@ -304,7 +277,7 @@ class BLEClient: ...@@ -304,7 +277,7 @@ class BLEClient:
304 "result": {"message": str(e)}, 277 "result": {"message": str(e)},
305 "id": request_id 278 "id": request_id
306 }) 279 })
307 await log_message("下发", response) 280 await log_message("下发", response, self.log_signal)
308 await websocket.send(response) 281 await websocket.send(response)
309 282
310 except websockets.exceptions.ConnectionClosedOK: 283 except websockets.exceptions.ConnectionClosedOK:
...@@ -329,18 +302,54 @@ class BLEClient: ...@@ -329,18 +302,54 @@ class BLEClient:
329 "message": base64.b64encode(data).decode("utf-8") 302 "message": base64.b64encode(data).decode("utf-8")
330 } 303 }
331 }) 304 })
332 await log_message("下发", response) 305 await log_message("下发", response, self.log_signal)
333 await websocket.send(response) 306 await websocket.send(response)
334 return callback 307 return callback
335 308
336 async def main(): 309 class WebSocketThread(QThread):
310 log_signal = pyqtSignal(str)
311
312 def run(self):
313 async def start_server():
314 ble_client = BLEClient(self.log_signal) # 绑定日志信号
337 async with websockets.serve( 315 async with websockets.serve(
338 lambda websocket, path: BLEClient().handle_client(websocket, path), 316 lambda websocket, path: ble_client.handle_client(websocket, path),
339 "localhost", 20111 317 "localhost", 20111
340 ): 318 ):
341 print("WebSocket服务已启动: ws://localhost:20111/scratch/ble") 319 self.log_signal.emit("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
342 print("日志文件路径: ./b.log")
343 await asyncio.Future() # 永久运行 320 await asyncio.Future() # 永久运行
344 321
322 asyncio.run(start_server())
323
324 class MainWindow(QMainWindow):
325 def __init__(self):
326 super().__init__()
327
328 self.setWindowTitle("BLE WebSocket Server")
329 self.setGeometry(100, 100, 600, 400)
330
331 self.text_edit = QTextEdit(self)
332 self.text_edit.setReadOnly(True)
333
334 self.start_button = QPushButton("启动服务", self)
335 self.start_button.clicked.connect(self.start_server)
336
337 layout = QVBoxLayout()
338 layout.addWidget(self.text_edit)
339 layout.addWidget(self.start_button)
340
341 container = QWidget()
342 container.setLayout(layout)
343 self.setCentralWidget(container)
344
345 self.websocket_thread = WebSocketThread()
346 self.websocket_thread.log_signal.connect(self.text_edit.append)
347
348 def start_server(self):
349 self.websocket_thread.start()
350
345 if __name__ == "__main__": 351 if __name__ == "__main__":
346 asyncio.run(main())
...\ No newline at end of file ...\ No newline at end of file
352 app = QApplication(sys.argv)
353 window = MainWindow()
354 window.show()
355 sys.exit(app.exec_())
...\ No newline at end of file ...\ No newline at end of file
......
1 # -*- mode: python ; coding: utf-8 -*-
2
3
4 a = Analysis(
5 ['we.py'],
6 pathex=[],
7 binaries=[],
8 datas=[('data', 'data')],
9 hiddenimports=[],
10 hookspath=[],
11 hooksconfig={},
12 runtime_hooks=[],
13 excludes=[],
14 noarchive=False,
15 optimize=0,
16 )
17 pyz = PYZ(a.pure)
18
19 exe = EXE(
20 pyz,
21 a.scripts,
22 a.binaries,
23 a.datas,
24 [],
25 name='we',
26 debug=False,
27 bootloader_ignore_signals=False,
28 strip=False,
29 upx=True,
30 upx_exclude=[],
31 runtime_tmpdir=None,
32 console=False,
33 disable_windowed_traceback=False,
34 argv_emulation=False,
35 target_arch=None,
36 codesign_identity=None,
37 entitlements_file=None,
38 icon=['data\\app.ico'],
39 )
1 import sys
2 import asyncio
3 import websockets
4 from bleak import BleakScanner, BleakClient
5 import json
6 import base64
7 import threading
8 from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QWidget
9 from PyQt5.QtCore import QThread, pyqtSignal
10
11 # 添加线程锁以确保日志写入的原子性
12 write_lock = threading.Lock()
13
14 def log_message_sync(direction, message):
15 """同步日志记录函数"""
16 log_entry = f"{direction}: {message}\n"
17 print(log_entry, end='') # 控制台仍然输出
18 with write_lock:
19 with open('b.log', 'a', encoding='utf-8') as f:
20 f.write(log_entry)
21
22 async def log_message(direction, message):
23 """异步封装日志记录"""
24 loop = asyncio.get_event_loop()
25 await loop.run_in_executor(None, log_message_sync, direction, message)
26
27 class BLEClient:
28 def __init__(self):
29 self.target_device = None
30 self.client = None
31 self.services = []
32 self.optional_services = []
33 self.websocket = None
34
35 def on_disconnect(self, client):
36 print("BLE连接断开,关闭WebSocket")
37 if self.websocket and not self.websocket.closed:
38 asyncio.create_task(self.close_websocket())
39
40 async def close_websocket(self):
41 await self.websocket.close()
42 self.websocket = None
43
44 def detection_callback(self, device, advertisement_data):
45 # 合并所有过滤条件的services进行匹配
46 if any(service_uuid in advertisement_data.service_uuids for service_uuid in self.services):
47 self.target_device = (device, advertisement_data)
48 if not self.target_device:
49 print("未找到匹配设备")
50 return
51 else:
52 device, adv_data = self.target_device
53 print("\n找到目标设备:")
54 print(f"设备名称: {device.name}")
55 print(f"设备地址: {device.address}")
56 print(f"信号强度: {device.rssi} dBm")
57 print("\n广播信息:")
58 print(f"服务UUID列表: {adv_data.service_uuids}")
59 print(f"制造商数据: {adv_data.manufacturer_data}")
60 print(f"服务数据: {adv_data.service_data}")
61 print(f"本地名称: {adv_data.local_name}")
62 return self.target_device
63
64 async def handle_client(self, websocket, path):
65 self.websocket = websocket
66 if path != "/scratch/ble":
67 await websocket.close(code=1003, reason="Path not allowed")
68 return
69
70 try:
71 async for message in websocket:
72 try:
73 await log_message("接收", message)
74 request = json.loads(message)
75
76 if request["jsonrpc"] != "2.0":
77 continue # 跳过无效协议版本
78
79 method = request.get("method")
80 params = request.get("params", {})
81 request_id = request.get("id")
82
83 if method == "discover":
84 # 合并所有过滤条件的services
85 self.services = []
86 for filt in params.get("filters", [{}]):
87 self.services.extend(filt.get("services", []))
88 self.optional_services = params.get("optionalServices", [])
89
90 scanner = BleakScanner()
91 scanner.register_detection_callback(self.detection_callback)
92
93 # 带重试的扫描逻辑
94 max_retries = 3
95 found = False
96 for attempt in range(max_retries):
97 self.target_device = None
98 await scanner.start()
99 await asyncio.sleep(5)
100 await scanner.stop()
101
102 if self.target_device:
103 found = True
104 break
105
106 if attempt < max_retries - 1:
107 print(f"未找到设备,第{attempt+1}次重试...")
108 await asyncio.sleep(3)
109
110 if found:
111 device, adv_data = self.target_device
112 discover_response = json.dumps({
113 "jsonrpc": "2.0",
114 "method": "didDiscoverPeripheral",
115 "params": {
116 "name": device.name,
117 "peripheralId": device.address,
118 "rssi": device.rssi
119 }
120 })
121 await log_message("下发", discover_response)
122 await websocket.send(discover_response)
123
124 result_response = json.dumps({
125 "jsonrpc": "2.0",
126 "result": None,
127 "id": request_id
128 })
129 await log_message("下发", result_response)
130 await websocket.send(result_response)
131
132 elif method == "connect":
133 peripheral_id = params.get("peripheralId")
134 if peripheral_id:
135 self.client = BleakClient(peripheral_id)
136 self.client.set_disconnected_callback(self.on_disconnect)
137 await self.client.connect()
138
139 if self.client.is_connected:
140 response = json.dumps({
141 "jsonrpc": "2.0",
142 "result": None,
143 "id": request_id
144 })
145 await log_message("下发", response)
146 await websocket.send(response)
147
148 elif method == "write":
149 service_id = params.get("serviceId")
150 characteristic_id = params.get("characteristicId")
151 message = params.get("message")
152 encoding = params.get("encoding", "utf-8")
153
154 if all([service_id, characteristic_id, message]):
155 if encoding == "base64":
156 message_bytes = base64.b64decode(message)
157 else:
158 message_bytes = message.encode(encoding)
159
160 await self.client.write_gatt_char(characteristic_id, message_bytes)
161 response = json.dumps({
162 "jsonrpc": "2.0",
163 "result": None,
164 "id": request_id
165 })
166 await log_message("下发", response)
167 await websocket.send(response)
168
169 elif method == "read":
170 service_id = params.get("serviceId")
171 characteristic_id = params.get("characteristicId")
172
173 if all([service_id, characteristic_id]):
174 data = await self.client.read_gatt_char(characteristic_id)
175 response = json.dumps({
176 "jsonrpc": "2.0",
177 "result": {
178 "serviceId": service_id,
179 "characteristicId": characteristic_id,
180 "message": base64.b64encode(data).decode("utf-8")
181 },
182 "id": request_id
183 })
184 await log_message("下发", response)
185 await websocket.send(response)
186
187 elif method == "startNotifications":
188 service_id = params.get("serviceId")
189 characteristic_id = params.get("characteristicId")
190
191 if all([service_id, characteristic_id]):
192 await self.client.start_notify(
193 characteristic_id,
194 self.notification_handler(websocket, service_id, characteristic_id)
195 )
196 response = json.dumps({
197 "jsonrpc": "2.0",
198 "result": None,
199 "id": request_id
200 })
201 await log_message("下发", response)
202 await websocket.send(response)
203
204 except json.JSONDecodeError:
205 error_msg = json.dumps({
206 "jsonrpc": "2.0",
207 "result": {"message": "Parse error"},
208 "id": None
209 })
210 await log_message("下发", error_msg)
211 except Exception as e:
212 error_msg = json.dumps({
213 "jsonrpc": "2.0",
214 "result": {"message": str(e)},
215 "id": request.get("id") if request else None
216 })
217 await log_message("下发", error_msg)
218
219 except websockets.exceptions.ConnectionClosed:
220 print("WebSocket连接关闭")
221 finally:
222 if self.client and self.client.is_connected:
223 await self.client.disconnect()
224 self.client = None
225 self.target_device = None
226
227 def notification_handler(self, websocket, service_id, characteristic_id):
228 async def callback(sender, data):
229 response = json.dumps({
230 "jsonrpc": "2.0",
231 "method": "characteristicDidChange",
232 "params": {
233 "serviceId": service_id,
234 "characteristicId": characteristic_id,
235 "message": base64.b64encode(data).decode("utf-8")
236 }
237 })
238 await log_message("下发", response)
239 await websocket.send(response)
240 return callback
241
242 class WebSocketServerThread(QThread):
243 log_signal = pyqtSignal(str)
244
245 def run(self):
246 async def main():
247 async with websockets.serve(
248 lambda websocket, path: BLEClient().handle_client(websocket, path),
249 "localhost", 20111
250 ):
251 self.log_signal.emit("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
252 self.log_signal.emit("日志文件路径: ./b.log")
253 await asyncio.Future() # 永久运行
254
255 asyncio.run(main())
256
257 class MainWindow(QMainWindow):
258 def __init__(self):
259 super().__init__()
260 self.initUI()
261
262 def initUI(self):
263 self.setWindowTitle("BLE WebSocket Server")
264 self.setGeometry(100, 100, 800, 600)
265
266 self.text_edit = QTextEdit(self)
267 self.text_edit.setReadOnly(True)
268
269 layout = QVBoxLayout()
270 layout.addWidget(self.text_edit)
271
272 container = QWidget()
273 container.setLayout(layout)
274 self.setCentralWidget(container)
275
276 self.websocket_thread = WebSocketServerThread()
277 self.websocket_thread.log_signal.connect(self.update_log)
278 self.websocket_thread.start()
279
280 def update_log(self, message):
281 self.text_edit.append(message)
282
283 if __name__ == "__main__":
284 app = QApplication(sys.argv)
285 window = MainWindow()
286 window.show()
287 sys.exit(app.exec_())
...\ No newline at end of file ...\ No newline at end of file
1 # -*- mode: python ; coding: utf-8 -*-
2
3
4 a = Analysis(
5 ['we1.py'],
6 pathex=[],
7 binaries=[],
8 datas=[('data', 'data')],
9 hiddenimports=[],
10 hookspath=[],
11 hooksconfig={},
12 runtime_hooks=[],
13 excludes=[],
14 noarchive=False,
15 optimize=0,
16 )
17 pyz = PYZ(a.pure)
18
19 exe = EXE(
20 pyz,
21 a.scripts,
22 a.binaries,
23 a.datas,
24 [],
25 name='we1',
26 debug=False,
27 bootloader_ignore_signals=False,
28 strip=False,
29 upx=True,
30 upx_exclude=[],
31 runtime_tmpdir=None,
32 console=True,
33 disable_windowed_traceback=False,
34 argv_emulation=False,
35 target_arch=None,
36 codesign_identity=None,
37 entitlements_file=None,
38 icon=['data\\app.ico'],
39 )
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!