10029f9f by huangyf2

update

1 parent 26c8727b
dist
build
__pycache__
exe
\ No newline at end of file
__pycache__
\ No newline at end of file
......
This diff could not be displayed because it is too large.
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": null, "peripheralId": "68:67:11:27:78:49", "rssi": -28}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 1}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 2}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -36}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -36}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
下发: {"jsonrpc": "2.0", "result": null, "id": 1}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
下发: {"jsonrpc": "2.0", "result": {"message": "Device with address 68:67:11:27:78:49 was not found."}, "id": 2}
接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01b6c4bc-8170-268e-4627-e07f37ed6744"},"id":3}
下发: {"jsonrpc": "2.0", "result": {"message": "Not connected"}, "id": 3}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"01b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01B6C4BC-8170-268E-4627-E07F37ED6744","message":"WwEAXF0=","encoding":"base64"},"id":4}
下发: {"jsonrpc": "2.0", "result": {"message": "Service Discovery has not been performed yet"}, "id": 4}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -28}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -28}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 1}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
下发: {"jsonrpc": "2.0", "result": {"message": ""}, "id": 2}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:49", "rssi": -34}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":1}
下发: {"jsonrpc": "2.0", "result": null, "id": 1}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:49"},"id":2}
下发: {"jsonrpc": "2.0", "result": {"message": "Device with address 68:67:11:27:78:49 was not found."}, "id": 2}
接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01b6c4bc-8170-268e-4627-e07f37ed6744"},"id":3}
下发: {"jsonrpc": "2.0", "result": {"message": "Not connected"}, "id": 3}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"01b6c4bc-8170-268e-4627-e07f37ed6744","characteristicId":"01B6C4BC-8170-268E-4627-E07F37ED6744","message":"WwEAXF0=","encoding":"base64"},"id":4}
下发: {"jsonrpc": "2.0", "result": {"message": "Service Discovery has not been performed yet"}, "id": 4}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -30}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"68:67:11:27:78:4D"},"id":1}
下发: {"jsonrpc": "2.0", "result": null, "id": 1}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001563-1212-efde-1523-785feabcd123 was not found!"}, "id": 2}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001565-1212-efde-1523-785feabcd123 was not found!"}, "id": 3}
接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001527-1212-efde-1523-785feabcd123 was not found!"}, "id": 4}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001528-1212-efde-1523-785feabcd123 was not found!"}, "id": 5}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001528-1212-efde-1523-785feabcd123 was not found!"}, "id": 6}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
下发: {"jsonrpc": "2.0", "result": {"message": "Characteristic 00001528-1212-efde-1523-785feabcd123 was not found!"}, "id": 7}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -26}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -26}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "LPF2 Smart Hub", "peripheralId": "3D:6F:89:AB:DA:FE", "rssi": -24}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"3D:6F:89:AB:DA:FE"},"id":1}
下发: {"jsonrpc": "2.0", "result": null, "id": 1}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
下发: {"jsonrpc": "2.0", "result": null, "id": 2}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
下发: {"jsonrpc": "2.0", "result": null, "id": 3}
接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
下发: {"jsonrpc": "2.0", "result": null, "id": 4}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AwEzFQEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BQE1FgEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BAE0FAEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BgE2FwEAAAABAAAA"}}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 5}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 6}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 7}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":8}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 8}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":9}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 9}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":10}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 10}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":11}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 11}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":12}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 12}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":13}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 13}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":14}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 14}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":15}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 15}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":16}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 16}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":17}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 17}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -28}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -28}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "Chinese_spik", "peripheralId": "68:67:11:27:78:4D", "rssi": -30}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "LPF2 Smart Hub", "peripheralId": "3D:6F:89:AB:DA:FE", "rssi": -26}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"3D:6F:89:AB:DA:FE"},"id":1}
下发: {"jsonrpc": "2.0", "result": null, "id": 1}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
下发: {"jsonrpc": "2.0", "result": null, "id": 2}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
下发: {"jsonrpc": "2.0", "result": null, "id": 3}
接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AwEzFQEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BAE0FAEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "result": null, "id": 4}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BQE1FgEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BgE2FwEAAAABAAAA"}}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 5}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 6}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 7}
接收: {"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}
下发: {"jsonrpc": "2.0", "method": "didDiscoverPeripheral", "params": {"name": "ccc", "peripheralId": "07:00:00:00:00:00", "rssi": -34}}
下发: {"jsonrpc": "2.0", "result": null, "id": 0}
接收: {"jsonrpc":"2.0","method":"connect","params":{"peripheralId":"07:00:00:00:00:00"},"id":1}
下发: {"jsonrpc": "2.0", "result": null, "id": 1}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001563-1212-efde-1523-785feabcd123","message":"AQIGFwEAAAAAAAA=","encoding":"base64"},"id":2}
下发: {"jsonrpc": "2.0", "result": null, "id": 2}
接收: {"jsonrpc":"2.0","method":"write","params":{"serviceId":"00004f0e-1212-efde-1523-785feabcd123","characteristicId":"00001565-1212-efde-1523-785feabcd123","message":"BgQDAAD/","encoding":"base64"},"id":3}
下发: {"jsonrpc": "2.0", "result": null, "id": 3}
接收: {"jsonrpc":"2.0","method":"startNotifications","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001527-1212-efde-1523-785feabcd123"},"id":4}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AgEBAQEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AQEAAQEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "AwEzFQEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "result": null, "id": 4}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BAE0FAEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BQE1FgEAAAABAAAA"}}
下发: {"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001527-1212-efde-1523-785feabcd123", "message": "BgE2FwEAAAABAAAA"}}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":5}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 5}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":6}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 6}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":7}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 7}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":8}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 8}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":9}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 9}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":10}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 10}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":11}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 11}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":12}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 12}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":13}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 13}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":14}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 14}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":15}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 15}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":16}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 16}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":17}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 17}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":18}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 18}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":19}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 19}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":20}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 20}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":21}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 21}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":22}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 22}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":23}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 23}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":24}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 24}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":25}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 25}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":26}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 26}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":27}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 27}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":28}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 28}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":29}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 29}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":30}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 30}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":31}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 31}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":32}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 32}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":33}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 33}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":34}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 34}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":35}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 35}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":36}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 36}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":37}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 37}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":38}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 38}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":39}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 39}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":40}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 40}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":41}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 41}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":42}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 42}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":43}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 43}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":44}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 44}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":45}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 45}
接收: {"jsonrpc":"2.0","method":"read","params":{"serviceId":"00001523-1212-efde-1523-785feabcd123","characteristicId":"00001528-1212-efde-1523-785feabcd123"},"id":46}
下发: {"jsonrpc": "2.0", "result": {"serviceId": "00001523-1212-efde-1523-785feabcd123", "characteristicId": "00001528-1212-efde-1523-785feabcd123", "message": "AA=="}, "id": 46}
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['we.py'],
pathex=[],
binaries=[],
datas=[('data', 'data')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='ble_client',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['data\\app.ico'],
)
import asyncio
import json
import websockets
# 预定义的下发通知列表
NOTIFICATIONS = [
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W1EDAVwADF0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALQAvAC8ALV0="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "W4ECAgDgXQ=="}},
{"jsonrpc": "2.0", "method": "characteristicDidChange", "params": {"serviceId": "00b6c4bc-8170-268e-4627-e07f37ed6744", "characteristicId": "01b6c4bc-8170-268e-4627-e07f37ed6744", "message": "WzEJAwkALgAvAC8ALF0="}}
]
async def handle_client(websocket):
"""处理客户端连接"""
client_ip = websocket.remote_address[0]
print(f"客户端 {client_ip} 已连接")
try:
async for message in websocket:
# 解析接收到的JSON消息
try:
data = json.loads(message)
except json.JSONDecodeError:
print(f"无效的JSON数据: {message}")
continue
print(f"收到请求:\n{json.dumps(data, indent=2)}")
# 提取请求参数
method = data.get("method")
req_id = data.get("id")
params = data.get("params", {})
# 请求路由处理
if method == "discover" and req_id == 0:
# 处理设备发现请求
await websocket.send(json.dumps({
"jsonrpc": "2.0",
"method": "didDiscoverPeripheral",
"params": {
"name": "12345",
"peripheralId": "E68744E9-02D5-42C1-AD3F-6BF6A7D4A5EC",
"rssi": -76
}
}))
await send_response(websocket, None, 0)
elif method == "connect" and req_id == 1:
# 处理连接请求
print(f"正在连接设备: {params.get('peripheralId')}")
await send_response(websocket, None, 1)
elif method == "write" and req_id == 2:
# 处理数据写入请求
print(f"写入数据到特征: {params.get('characteristicId')}")
await send_response(websocket, None, 2)
elif method == "startNotifications" and req_id == 3:
# 处理通知订阅请求
print("已启动特征通知")
await send_response(websocket, None, 3)
# 发送预定义通知流
for idx, notification in enumerate(NOTIFICATIONS):
await websocket.send(json.dumps(notification))
print(f"已发送通知 #{idx+1}")
await asyncio.sleep(1) # 每秒发送一个通知
except websockets.exceptions.ConnectionClosed:
print(f"客户端 {client_ip} 已断开连接")
async def send_response(websocket, result, req_id):
"""发送标准响应"""
response = {
"jsonrpc": "2.0",
"result": result,
"id": req_id
}
await websocket.send(json.dumps(response))
print(f"已发送响应 ID {req_id}")
async def main():
"""启动WebSocket服务器"""
server = await websockets.serve(
handle_client,
host="0.0.0.0",
port=20111,
ping_interval=None
)
print(f"WebSocket服务器已启动,监听 ws://0.0.0.0:20111")
print("按 Ctrl+C 停止服务器")
await server.wait_closed()
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n服务器已关闭")
\ No newline at end of file
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['m.py'],
pathex=[],
binaries=[],
datas=[('data', 'data')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='m',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['data\\app.ico'],
)
pythonserver @ 65948850
Subproject commit 659488506d3926a24a8012358231b8345c52e618
from PyQt5.QtCore import pyqtSlot, QObject, QTimer, pyqtSignal, QMutex, QMutexLocker, QThread, QEvent
from PyQt5.QtBluetooth import (QBluetoothDeviceDiscoveryAgent, QLowEnergyController,
QBluetoothUuid, QLowEnergyService, QLowEnergyCharacteristic,
QLowEnergyDescriptor, QBluetoothDeviceInfo, QBluetoothServiceDiscoveryAgent,
QBluetoothSocket, QBluetoothServiceInfo)
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QWidget, QPushButton, QHBoxLayout
from PyQt5.QtWebSockets import QWebSocketServer, QWebSocket
from PyQt5.QtNetwork import QHostAddress
class BluetoothDeviceScanner(QObject):
deviceDiscovered = pyqtSignal(QBluetoothDeviceInfo)
scanFinished = pyqtSignal()
deviceConnected = pyqtSignal(QLowEnergyController)
def __init__(self, parent=None, target_uuid="00001523-1212-efde-1523-785feabcd123"):
super().__init__(parent)
self.target_uuid = target_uuid
self.discovery_agent = QBluetoothDeviceDiscoveryAgent(self)
# 配置扫描参数 - 低功耗设备需要更长的扫描时间
self.discovery_agent.setLowEnergyDiscoveryTimeout(10000) # 10秒的扫描时间
# 配置扫描方式,包括低功耗设备和经典蓝牙设备
self.discovery_agent.setInquiryType(QBluetoothDeviceDiscoveryAgent.GeneralUnlimitedInquiry)
# 连接信号
self.discovery_agent.deviceDiscovered.connect(self.on_device_discovered)
self.discovery_agent.finished.connect(self.on_scan_finished)
self.discovery_agent.error.connect(self.on_error)
self.controllers = {} # Store controllers by device address
self.target_device = None
self.discovered_devices = {} # 存储所有发现的设备,避免重复处理
# 添加自动重试机制
self.scan_retry_count = 0
self.max_scan_retries = 2 # 最多重试2次,加上第一次共3次
self.connection_retry_count = 0
self.max_connection_retries = 2
# 创建计时器用于延迟重试
self.retry_timer = QTimer(self)
self.retry_timer.setSingleShot(True)
self.retry_timer.timeout.connect(self.retry_scan)
# 记录已经尝试过连接的设备
self.connection_attempts = set()
def start_scan(self):
"""开始扫描蓝牙设备"""
print("开始蓝牙设备扫描...")
self.scan_retry_count = 0
self.discovered_devices.clear()
self.connection_attempts.clear()
self.target_device = None
# 设置更广泛的设备类型过滤
self.discovery_agent.start()
def stop_scan(self):
"""停止设备扫描"""
self.discovery_agent.stop()
self.retry_timer.stop()
print("蓝牙设备扫描已停止")
def retry_scan(self):
"""重试扫描,用于当扫描失败或未找到目标设备时"""
if self.scan_retry_count < self.max_scan_retries and not self.target_device:
self.scan_retry_count += 1
print(f"重试扫描 ({self.scan_retry_count}/{self.max_scan_retries})...")
self.discovery_agent.start()
@pyqtSlot(QBluetoothDeviceInfo)
def on_device_discovered(self, device_info):
"""当发现蓝牙设备时调用"""
device_name = device_info.name() or "未命名设备"
device_address = device_info.address().toString()
# 如果已经处理过这个设备,则直接返回,除非是我们感兴趣的目标设备
if device_address in self.discovered_devices and "LPF2" not in device_name:
return
# 存储设备信息
self.discovered_devices[device_address] = device_info
# 分析设备类型
device_type = "未知"
# 获取主要和次要设备类别
major_class = device_info.majorDeviceClass()
minor_class = device_info.minorDeviceClass()
print(f"调试信息 - 主类别: {major_class}, 次类别: {minor_class}")
# 识别设备类别
if (major_class == QBluetoothDeviceInfo.MiscellaneousDevice or major_class == 0) and "LPF2" in device_name:
device_type = "LEGO智能集线器"
elif major_class == QBluetoothDeviceInfo.ToyDevice:
if minor_class == 0x01:
device_type = "玩具机器人"
elif minor_class == 0x02:
device_type = "玩具车辆"
else:
device_type = "玩具"
elif major_class == QBluetoothDeviceInfo.ComputerDevice:
device_type = "电脑"
elif major_class == QBluetoothDeviceInfo.PhoneDevice:
device_type = "手机"
elif major_class == QBluetoothDeviceInfo.AudioVideoDevice:
device_type = "音频/视频设备"
elif major_class == QBluetoothDeviceInfo.NetworkDevice:
device_type = "网络设备"
elif major_class == QBluetoothDeviceInfo.PeripheralDevice:
if minor_class & 0x04: # 键盘
device_type = "键盘"
elif minor_class & 0x08: # 鼠标
device_type = "鼠标"
elif minor_class & 0x10: # 组合键盘/鼠标
device_type = "键盘/鼠标组合"
elif minor_class & 0x40: # 游戏杆
device_type = "游戏杆"
elif minor_class & 0x80: # 游戏手柄
device_type = "游戏手柄"
else:
device_type = "外围设备"
elif major_class == QBluetoothDeviceInfo.ImagingDevice:
device_type = "成像设备"
elif major_class == QBluetoothDeviceInfo.WearableDevice:
device_type = "可穿戴设备"
elif major_class == QBluetoothDeviceInfo.HealthDevice:
device_type = "健康设备"
# 基于设备名称的额外分类
if device_type == "未知":
if "lego" in device_name.lower() or "lpf2" in device_name.lower():
device_type = "LEGO智能集线器"
elif "hub" in device_name.lower():
device_type = "智能集线器"
elif "watch" in device_name.lower():
device_type = "智能手表"
elif "speaker" in device_name.lower() or "headphone" in device_name.lower() or "airpod" in device_name.lower():
device_type = "音频设备"
elif "fitness" in device_name.lower() or "band" in device_name.lower():
device_type = "健身追踪器"
print(f"发现设备: {device_name} ({device_address}) - 类型: {device_type}")
# 获取额外的设备信息
rssi = device_info.rssi()
if rssi != 0:
print(f"信号强度 (RSSI): {rssi} dBm")
# 检查制造商特定数据
manufacturer_data = device_info.manufacturerData()
if manufacturer_data:
print(f"制造商数据可用: {len(manufacturer_data)} 字节")
for manufacturer_id, data in manufacturer_data.items():
# 将QByteArray转换为十六进制字符串
data_bytes = bytes(data)
hex_string = data_bytes.hex() if hasattr(data_bytes, 'hex') else ' '.join([f'{b:02x}' for b in data_bytes])
print(f"制造商ID: {manufacturer_id:04x}, 数据: {hex_string}")
# 获取服务UUID(如果可用)
service_uuids = device_info.serviceUuids()
if service_uuids:
print(f"服务UUID数量: {len(service_uuids)}")
for uuid_obj in service_uuids:
if isinstance(uuid_obj, QBluetoothUuid):
uuid_str = uuid_obj.toString()
print(f" - {uuid_str}")
# 连接决策逻辑 - 优先级从高到低
should_connect = False
connection_reason = ""
# 优先级1: 检查设备是否有与目标UUID匹配的服务
if service_uuids:
for uuid_obj in service_uuids:
if isinstance(uuid_obj, QBluetoothUuid):
uuid_str = uuid_obj.toString().lower()
if uuid_str == self.target_uuid.lower():
should_connect = True
connection_reason = "匹配服务UUID"
break
# 优先级2: 特别处理LEGO设备 - 通常只是基于名称
if not should_connect and "LPF2" in device_name:
should_connect = True
connection_reason = "LEGO智能集线器"
# 优先级3: 设备地址或名称包含目标UUID前缀
if not should_connect and self.target_uuid:
if (self.target_uuid[:8].lower() in device_address.lower() or
(device_name and self.target_uuid[:8].lower() in device_name.lower())):
should_connect = True
connection_reason = "UUID前缀匹配名称/地址"
# 优先级4: 如果信号强度很好,并且是玩具类型设备
if not should_connect and rssi > -60 and (device_type.startswith("玩具") or device_type.startswith("LEGO")):
should_connect = True
connection_reason = "强信号玩具设备"
# 如果决定连接,并且之前没有尝试过
if should_connect and device_address not in self.connection_attempts:
print(f"尝试连接设备: {device_name} (原因: {connection_reason})")
self.connection_attempts.add(device_address) # 标记为已尝试
self.target_device = device_info
self.connect_to_device(device_info)
# 找到了可能的目标,停止扫描
if "LPF2" in device_name:
self.discovery_agent.stop()
self.deviceDiscovered.emit(device_info)
@pyqtSlot()
def on_scan_finished(self):
"""当设备扫描完成时调用"""
print("蓝牙扫描完成")
# 如果我们还没有找到目标设备,但又发现了一些设备,则选择一个尝试连接
if not self.target_device and self.discovered_devices:
print("没有通过UUID找到目标设备,尝试连接发现的设备...")
# 首先尝试连接任何包含"LPF2"的设备
for addr, device_info in self.discovered_devices.items():
if "LPF2" in device_info.name() and addr not in self.connection_attempts:
print(f"尝试连接: {device_info.name()} (LEGO设备)")
self.connection_attempts.add(addr)
self.target_device = device_info
self.connect_to_device(device_info)
break
# 如果还没有目标设备,尝试基于信号强度来选择设备
if not self.target_device:
# 按信号强度排序设备
devices_by_signal = sorted(
[(addr, info) for addr, info in self.discovered_devices.items() if addr not in self.connection_attempts],
key=lambda x: x[1].rssi(), reverse=True # 最强信号优先
)
if devices_by_signal:
addr, device_info = devices_by_signal[0]
print(f"尝试连接: {device_info.name()} (最强信号设备)")
self.connection_attempts.add(addr)
self.target_device = device_info
self.connect_to_device(device_info)
# 如果仍未找到设备,考虑重试扫描
if not self.target_device and self.scan_retry_count < self.max_scan_retries:
print(f"没有找到合适的设备,将在2秒后重试扫描... (已尝试 {self.scan_retry_count+1}/{self.max_scan_retries+1})")
self.retry_timer.start(2000) # 2秒后重试
else:
if not self.target_device:
print("经过多次尝试后仍未找到目标设备。")
self.scanFinished.emit()
@pyqtSlot(QBluetoothDeviceDiscoveryAgent.Error)
def on_error(self, error):
"""处理发现错误"""
error_str = "未知错误"
if error == QBluetoothDeviceDiscoveryAgent.PoweredOffError:
error_str = "蓝牙已关闭"
elif error == QBluetoothDeviceDiscoveryAgent.InputOutputError:
error_str = "蓝牙I/O错误"
elif error == QBluetoothDeviceDiscoveryAgent.InvalidBluetoothAdapterError:
error_str = "无效的蓝牙适配器"
elif error == QBluetoothDeviceDiscoveryAgent.UnsupportedPlatformError:
error_str = "不支持的平台"
elif error == QBluetoothDeviceDiscoveryAgent.UnsupportedDiscoveryMethod:
error_str = "不支持的发现方法"
elif error == QBluetoothDeviceDiscoveryAgent.ResourceError:
error_str = "资源错误"
print(f"蓝牙发现错误: {error_str}")
# 如果遇到错误,也考虑重试
if self.scan_retry_count < self.max_scan_retries:
print(f"因错误将在3秒后重试扫描...")
self.retry_timer.start(3000) # 3秒后重试
def connect_to_device(self, device_info):
"""连接到指定设备"""
print(f"正在连接 {device_info.name()}...")
# 创建设备控制器
controller = QLowEnergyController.createCentral(device_info)
device_address = device_info.address().toString()
self.controllers[device_address] = controller
# 连接控制器信号
controller.connected.connect(self.on_device_connected)
controller.disconnected.connect(self.on_device_disconnected)
controller.error.connect(self.on_controller_error)
controller.serviceDiscovered.connect(self.on_service_discovered)
controller.discoveryFinished.connect(self.on_service_discovery_finished)
# 连接超时计时器
connection_timer = QTimer(self)
connection_timer.setSingleShot(True)
connection_timer.timeout.connect(lambda: self.on_connection_timeout(device_address, connection_timer))
connection_timer.start(5000) # 5秒连接超时
# 存储计时器以便稍后引用
controller.property_connection_timer = connection_timer
# 连接到设备
controller.connectToDevice()
def on_connection_timeout(self, device_address, timer):
"""处理连接超时"""
if device_address in self.controllers:
controller = self.controllers[device_address]
# 在PyQt5中,QLowEnergyController没有isConnected()方法
# 改用state()方法检查连接状态
if controller.state() != QLowEnergyController.ConnectedState:
print(f"连接到 {controller.remoteName()} 超时")
# 删除连接尝试记录,以便后续可以再次尝试
if device_address in self.connection_attempts:
self.connection_attempts.remove(device_address)
# 设置为null,这样我们可以尝试其他设备
if self.target_device and self.target_device.address().toString() == device_address:
self.target_device = None
# 重新开始扫描,如果我们已经尝试了最大重试次数
if not self.discovery_agent.isActive() and self.scan_retry_count < self.max_scan_retries:
print("将重新开始扫描...")
self.retry_timer.start(1000) # 1秒后重试
@pyqtSlot()
def on_device_connected(self):
"""当连接到设备时调用"""
controller = self.sender()
print(f"已连接到 {controller.remoteName()}")
self.deviceConnected.emit(controller)
# 停止连接超时计时器
if hasattr(controller, 'property_connection_timer'):
controller.property_connection_timer.stop()
# 发现服务
controller.discoverServices()
@pyqtSlot()
def on_device_disconnected(self):
"""当从设备断开连接时调用"""
controller = self.sender()
device_address = ""
# 找到这个控制器的地址
for addr, ctrl in self.controllers.items():
if ctrl == controller:
device_address = addr
break
print(f"从 {controller.remoteName()} 断开连接")
# 如果这是我们当前的目标设备,清除它,以便我们可以尝试另一个
if self.target_device and self.target_device.address().toString() == device_address:
self.target_device = None
# 如果当前没有在扫描,并且我们还有剩余的重试次数,则重新开始扫描
if not self.discovery_agent.isActive() and self.scan_retry_count < self.max_scan_retries:
print("设备断开连接,将重新开始扫描...")
self.retry_timer.start(1000) # 1秒后重试
@pyqtSlot(QLowEnergyController.Error)
def on_controller_error(self, error):
"""处理控制器错误"""
controller = self.sender()
device_address = ""
# 找到这个控制器的地址
for addr, ctrl in self.controllers.items():
if ctrl == controller:
device_address = addr
break
error_str = "未知错误"
if error == QLowEnergyController.UnknownError:
error_str = "未知错误"
elif error == QLowEnergyController.RemoteHostClosedError:
error_str = "远程主机关闭了连接"
elif error == QLowEnergyController.ConnectionError:
error_str = "连接错误"
print(f"控制器错误 ({controller.remoteName()}): {error_str}")
# 如果是我们当前的目标设备,清除它并尝试另一个
if self.target_device and self.target_device.address().toString() == device_address:
# 从尝试列表中移除,以便后续可以重新尝试
if device_address in self.connection_attempts:
self.connection_attempts.remove(device_address)
self.target_device = None
# 如果当前没有在扫描,并且我们还有剩余的重试次数,则重新开始扫描
if not self.discovery_agent.isActive() and self.scan_retry_count < self.max_scan_retries:
print("因控制器错误将重新开始扫描...")
self.retry_timer.start(1000) # 1秒后重试
@pyqtSlot(QBluetoothUuid)
def on_service_discovered(self, uuid):
"""当在连接的设备上发现服务时调用"""
controller = self.sender()
print(f"在 {controller.remoteName()} 上发现服务: {uuid.toString()}")
@pyqtSlot()
def on_service_discovery_finished(self):
"""当服务发现完成时调用"""
controller = self.sender()
print(f"{controller.remoteName()} 的服务发现完成")
# 处理发现的服务
services_found = False
for service_uuid in controller.services():
service = controller.createServiceObject(service_uuid)
if service:
services_found = True
print(f"处理服务: {service_uuid.toString()}")
service.stateChanged.connect(self.on_service_state_changed)
service.characteristicChanged.connect(
lambda characteristic, value, service=service:
self.on_characteristic_changed(characteristic, value)
)
service.discoverDetails()
if not services_found:
print("未发现服务,可能需要特定的连接协议")
@pyqtSlot(QLowEnergyService.ServiceState)
def on_service_state_changed(self, state):
"""当服务状态改变时调用"""
service = self.sender()
if state == QLowEnergyService.ServiceDiscovered:
print(f"服务详情已发现: {service.serviceUuid().toString()}")
# 处理特性
for characteristic in service.characteristics():
print(f"发现特性: {characteristic.uuid().toString()}")
print(f" - 特性属性: {characteristic.properties()}")
# 如果这是一个可读特性,尝试读取它
if characteristic.properties() & QLowEnergyCharacteristic.Read:
print(f" - 读取特性值...")
service.readCharacteristic(characteristic)
# 如果这是一个可通知特性,尝试开启通知
if characteristic.properties() & QLowEnergyCharacteristic.Notify:
print(f" - 启用通知...")
try:
# PyQt5的QLowEnergyService没有descriptors()方法
# 我们可以直接尝试获取CCCD描述符
# 或者尝试直接写入特征来启用通知
descriptor = characteristic.descriptor(QBluetoothUuid(QBluetoothUuid.ClientCharacteristicConfiguration))
if descriptor.isValid():
print(f" - 找到客户端特性配置描述符")
service.writeDescriptor(descriptor, b"\x01\x00") # 启用通知
else:
print(f" - 未找到有效的客户端特性配置描述符")
# 某些实现可能支持以下方法
if hasattr(service, 'setNotifyValue'):
print(f" - 尝试使用setNotifyValue方法")
service.setNotifyValue(characteristic, True)
except Exception as e:
print(f" - 启用通知时出错: {e}")
print(f" - 将尝试特殊处理LEGO设备...")
# LEGO设备特殊处理 - 这是一种常见的方法
try:
if "LPF2" in service.controller().remoteName():
print(f" - 检测到LEGO设备,尝试特殊处理")
# 有些LEGO设备需要写入一个特定值到特性以启用通知
if characteristic.properties() & QLowEnergyCharacteristic.Write:
print(f" - 尝试写入特性来启用通知")
service.writeCharacteristic(characteristic, b"\x01\x00")
except Exception as e2:
print(f" - LEGO设备特殊处理失败: {e2}")
def on_characteristic_changed(self, characteristic, value):
"""当特性值改变时调用"""
try:
# 将QByteArray转换为十六进制字符串
if hasattr(value, 'data'): # 它是一个QByteArray
data_bytes = bytes(value)
hex_string = data_bytes.hex() if hasattr(data_bytes, 'hex') else ' '.join([f'{b:02x}' for b in data_bytes])
else: # 它可能已经是bytes
hex_string = value.hex() if hasattr(value, 'hex') else ' '.join([f'{b:02x}' for b in value])
print(f"特性 {characteristic.uuid().toString()} 值改变: {hex_string}")
# 解析数据 (示例)
print(f"数据解析: {' '.join([f'{b:02x}' for b in data_bytes])}")
except Exception as e:
print(f"处理特性变化时出错: {e}")
def main():
"""运行蓝牙扫描器的主函数"""
import sys
app = QApplication(sys.argv)
# 创建带有目标UUID的扫描器
scanner = BluetoothDeviceScanner(target_uuid="00001523-1212-efde-1523-785feabcd123")
# 创建简单的UI
window = QMainWindow()
window.setWindowTitle("蓝牙扫描器")
window.resize(700, 500)
central_widget = QWidget()
layout = QVBoxLayout(central_widget)
# 添加文本编辑框
text_edit = QTextEdit()
text_edit.setReadOnly(True)
layout.addWidget(text_edit)
# 添加按钮布局
button_layout = QHBoxLayout()
# 开始扫描按钮
start_scan_button = QPushButton("开始扫描")
start_scan_button.clicked.connect(scanner.start_scan)
button_layout.addWidget(start_scan_button)
# 停止扫描按钮
stop_scan_button = QPushButton("停止扫描")
stop_scan_button.clicked.connect(scanner.stop_scan)
button_layout.addWidget(stop_scan_button)
# 清除按钮
clear_button = QPushButton("清除日志")
clear_button.clicked.connect(text_edit.clear)
button_layout.addWidget(clear_button)
layout.addLayout(button_layout)
window.setCentralWidget(central_widget)
window.show()
# 重定向print语句到文本编辑框
import sys
original_stdout = sys.stdout
class TextEditRedirector:
def __init__(self, text_edit):
self.text_edit = text_edit
def write(self, text):
self.text_edit.append(text)
original_stdout.write(text)
def flush(self):
pass
sys.stdout = TextEditRedirector(text_edit)
# 自动开始第一次扫描
scanner.start_scan()
return app.exec_()
if __name__ == "__main__":
main()
\ No newline at end of file
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['qt5.py'],
pathex=[],
binaries=[],
datas=[('data', 'data')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='qt5',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['data\\app.ico'],
)
......@@ -27,7 +27,9 @@ pip install pystray pillow
##
打包指令 产生一个带窗口的程序 打包完后可以随便改exe 名字
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"
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"
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"
##
端口占用
......
# -*- coding: utf-8 -*-
import sys
import asyncio
import websockets
from bleak import BleakScanner, BleakClient
import json
import base64
import threading
from collections import defaultdict
import platform
# 方法1:通过sys模块快速判断(推荐)
if sys.platform.startswith('win32'):
import winrt.windows.foundation.collections # noqa
import winrt.windows.devices.bluetooth # noqa
import winrt.windows.devices.bluetooth.advertisement # noq
print("当前运行在Windows系统")
elif sys.platform.startswith('linux'):
print("当前运行在Linux系统")
elif sys.platform.startswith('darwin'):
print("当前运行在macOS系统")
# 添加线程锁以确保日志写入的原子性
write_lock = threading.Lock()
def log_message_sync(direction, message):
"""同步日志记录函数"""
log_entry = f"{direction}: {message}\n"
print(log_entry, end='') # 控制台仍然输出
with write_lock:
with open('b.log', 'a', encoding='utf-8') as f:
f.write(log_entry)
async def log_message(direction, message):
"""异步封装日志记录"""
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, log_message_sync, direction, message)
class BLEClient:
def __init__(self):
self.target_device = None
self.client = None
self.services = []
self.optional_services = []
self.websocket = None
self.notification_records = defaultdict(lambda: (None, 0)) # 特征ID: (最后消息, 时间戳)
def on_disconnect(self, client):
print("BLE连接断开,关闭WebSocket")
if self.websocket and not self.websocket.closed:
asyncio.create_task(self.close_websocket())
async def close_websocket(self):
await self.websocket.close()
self.websocket = None
def detection_callback(self, device, advertisement_data):
if any(service_uuid in advertisement_data.service_uuids for service_uuid in self.services):
self.target_device = (device, advertisement_data)
if not self.target_device:
print("未找到匹配设备")
return
else:
device, adv_data = self.target_device
print("\n找到目标设备:")
print(f"设备名称: {device.name}")
print(f"设备地址: {device.address}")
print(f"信号强度: {device.rssi} dBm")
print("\n广播信息:")
print(f"服务UUID列表: {adv_data.service_uuids}")
print(f"制造商数据: {adv_data.manufacturer_data}")
print(f"服务数据: {adv_data.service_data}")
print(f"本地名称: {adv_data.local_name}")
return self.target_device
async def handle_client(self, websocket, path):
self.websocket = websocket
if path != "/scratch/ble":
await websocket.close(code=1003, reason="Path not allowed")
return
try:
async for message in websocket:
try:
await log_message("接收", message)
request = json.loads(message)
if request["jsonrpc"] != "2.0":
continue
method = request.get("method")
params = request.get("params", {})
request_id = request.get("id")
if method == "discover":
self.services = []
for filt in params.get("filters", [{}]):
self.services.extend(filt.get("services", []))
self.optional_services = params.get("optionalServices", [])
scanner = BleakScanner(scanning_mode="active")
scanner.register_detection_callback(self.detection_callback)
max_retries = 3
found = False
for attempt in range(max_retries):
self.target_device = None
await scanner.start()
await asyncio.sleep(5)
await scanner.stop()
if self.target_device:
found = True
break
if attempt < max_retries - 1:
print(f"未找到设备,第{attempt+1}次重试...")
await asyncio.sleep(3)
if found:
device, adv_data = self.target_device
discover_response = json.dumps({
"jsonrpc": "2.0",
"method": "didDiscoverPeripheral",
"params": {
"name": device.name,
"peripheralId": device.address,
"rssi": device.rssi
}
})
await log_message("下发", discover_response)
await websocket.send(discover_response)
result_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", result_response)
await websocket.send(result_response)
elif method == "connect":
peripheral_id = params.get("peripheralId")
if peripheral_id:
self.client = BleakClient(peripheral_id)
self.client.set_disconnected_callback(self.on_disconnect)
await self.client.connect()
if self.client.is_connected:
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "write":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
message = params.get("message")
encoding = params.get("encoding", "utf-8")
if all([service_id, characteristic_id, message]):
if encoding == "base64":
message_bytes = base64.b64decode(message)
else:
message_bytes = message.encode(encoding)
await self.client.write_gatt_char(characteristic_id, message_bytes)
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "read":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
if all([service_id, characteristic_id]):
data = await self.client.read_gatt_char(characteristic_id)
response = json.dumps({
"jsonrpc": "2.0",
"result": {
"serviceId": service_id,
"characteristicId": characteristic_id,
"message": base64.b64encode(data).decode("utf-8")
},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "startNotifications":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
if all([service_id, characteristic_id]):
await self.client.start_notify(
characteristic_id,
self.notification_handler(websocket, service_id, characteristic_id)
)
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
except json.JSONDecodeError:
error_msg = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Parse error"},
"id": None
})
await log_message("下发", error_msg)
except Exception as e:
error_msg = json.dumps({
"jsonrpc": "2.0",
"result": {"message": str(e)},
"id": request.get("id") if request else None
})
await log_message("下发", error_msg)
except websockets.exceptions.ConnectionClosed:
print("WebSocket连接关闭")
finally:
if self.client and self.client.is_connected:
await self.client.disconnect()
self.client = None
self.target_device = None
def notification_handler(self, websocket, service_id, characteristic_id):
async def callback(sender, data):
current_time = asyncio.get_event_loop().time()
last_message, last_time = self.notification_records[characteristic_id]
# 解码当前数据用于比较
current_message = base64.b64encode(data).decode('utf-8')
# 过滤逻辑
if current_message == last_message and (current_time - last_time) < 0.5:
return
# 更新记录
self.notification_records[characteristic_id] = (current_message, current_time)
response = json.dumps({
"jsonrpc": "2.0",
"method": "characteristicDidChange",
"params": {
"serviceId": service_id,
"characteristicId": characteristic_id,
"message": current_message
}
})
await log_message("下发", response)
await websocket.send(response)
return callback
async def main():
async with websockets.serve(
lambda websocket, path: BLEClient().handle_client(websocket, path),
"localhost", 20111
):
print("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
print("日志文件路径: ./b.log")
await asyncio.Future()
if __name__ == "__main__":
asyncio.run(main())
\ No newline at end of file
# -*- coding: utf-8 -*-
import asyncio
import websockets
from bleak import BleakScanner, BleakClient
import json
import base64
import threading
import winrt.windows.foundation.collections # noqa
import winrt.windows.devices.bluetooth # noqa
import winrt.windows.devices.bluetooth.advertisement # noqa
# 添加线程锁以确保日志写入的原子性
write_lock = threading.Lock()
def log_message_sync(direction, message):
"""同步日志记录函数"""
log_entry = f"{direction}: {message}\n"
print(log_entry, end='') # 控制台仍然输出
with write_lock:
with open('a.log', 'a', encoding='utf-8') as f:
f.write(log_entry)
async def log_message(direction, message):
"""异步封装日志记录"""
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, log_message_sync, direction, message)
class BLEClient:
def __init__(self):
self.target_device = None
self.client = None
self.services = []
self.optional_services = []
self.websocket = None
def on_disconnect(self, client):
print("BLE连接断开,关闭WebSocket")
if self.websocket and not self.websocket.closed:
asyncio.create_task(self.close_websocket())
async def close_websocket(self):
await self.websocket.close()
self.websocket = None
def detection_callback(self, device, advertisement_data):
if any(service_uuid in advertisement_data.service_uuids for service_uuid in self.services):
self.target_device = (device, advertisement_data)
if not self.target_device:
print("未找到匹配设备")
return
else:
device, adv_data = self.target_device
print("\n找到目标设备:")
print(f"设备名称: {device.name}")
print(f"设备地址: {device.address}")
print(f"信号强度: {device.rssi} dBm")
print("\n广播信息:")
print(f"服务UUID列表: {adv_data.service_uuids}")
print(f"制造商数据: {adv_data.manufacturer_data}")
print(f"服务数据: {adv_data.service_data}")
print(f"本地名称: {adv_data.local_name}")
return self.target_device
async def handle_client(self, websocket, path):
self.websocket = websocket
if path != "/scratch/ble":
await websocket.close(code=1003, reason="Path not allowed")
return
try:
async for message in websocket:
try:
# 记录接收到的消息
await log_message("接收", message)
request = json.loads(message)
if request["jsonrpc"] != "2.0":
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Invalid Request"},
"id": request.get("id", None)
})
await log_message("下发", response)
await websocket.send(response)
continue
method = request.get("method")
params = request.get("params", {})
request_id = request.get("id")
if method == "discover":
self.services = params.get("filters", [{}])[1].get("services", [])
self.optional_services = params.get("optionalServices", [])
scanner = BleakScanner()
scanner.register_detection_callback(self.detection_callback)
# 添加重试机制
max_retries = 3
found = False
for attempt in range(max_retries):
self.target_device = None # 重置目标设备
await scanner.start()
await asyncio.sleep(5)
await scanner.stop()
if self.target_device:
found = True
break
if attempt < max_retries - 1: # 最后一次不等待
print(f"未找到设备,第{attempt+1}次重试...")
await asyncio.sleep(3)
if not found:
# response = json.dumps({
# "jsonrpc": "2.0",
# "result": {"message": "Device not found"},
# "id": request_id
# })
# await log_message("下发", response)
# await websocket.send(response)
continue
device, adv_data = self.target_device
discover_response = json.dumps({
"jsonrpc": "2.0",
"method": "didDiscoverPeripheral",
"params": {
"name": device.name,
"peripheralId": device.address,
"rssi": device.rssi
}
})
await log_message("下发", discover_response)
await websocket.send(discover_response)
result_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", result_response)
await websocket.send(result_response)
elif method == "connect":
peripheral_id = params.get("peripheralId")
if not peripheral_id:
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
continue
self.client = BleakClient(peripheral_id)
self.client.set_disconnected_callback(self.on_disconnect)
await self.client.connect()
if self.client.is_connected:
print(f"已连接至设备: {peripheral_id}")
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
else:
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Failed to connect"},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "write":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
message = params.get("message")
encoding = params.get("encoding", "utf-8")
if not all([service_id, characteristic_id, message]):
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
continue
if encoding == "base64":
message_bytes = base64.b64decode(message)
else:
message_bytes = message.encode(encoding)
await self.client.write_gatt_char(characteristic_id, message_bytes)
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "read":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
if not all([service_id, characteristic_id]):
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
continue
data = await self.client.read_gatt_char(characteristic_id)
response = json.dumps({
"jsonrpc": "2.0",
"result": {
"serviceId": service_id,
"characteristicId": characteristic_id,
"message": base64.b64encode(data).decode("utf-8")
},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "startNotifications":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
if not all([service_id, characteristic_id]):
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
continue
await self.client.start_notify(
characteristic_id,
self.notification_handler(websocket, service_id, characteristic_id)
)
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
else:
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Method not found"},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
except json.JSONDecodeError:
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Parse error"},
"id": None
})
await log_message("下发", response)
await websocket.send(response)
except Exception as e:
response = json.dumps({
"jsonrpc": "2.0",
"result": {"message": str(e)},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
except websockets.exceptions.ConnectionClosedOK:
print("WebSocket客户端正常断开")
except websockets.exceptions.ConnectionClosedError as e:
print(f"WebSocket客户端异常断开: {e.code} - {e.reason}")
finally:
if self.client and self.client.is_connected:
await self.client.disconnect()
print("BLE设备已主动断开")
self.client = None
self.target_device = None
def notification_handler(self, websocket, service_id, characteristic_id):
async def callback(sender, data):
response = json.dumps({
"jsonrpc": "2.0",
"method": "characteristicDidChange",
"params": {
"serviceId": service_id,
"characteristicId": characteristic_id,
"message": base64.b64encode(data).decode("utf-8")
}
})
await log_message("下发", response)
await websocket.send(response)
return callback
async def main():
async with websockets.serve(
lambda websocket, path: BLEClient().handle_client(websocket, path),
"localhost", 20111
):
print("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
print("日志文件路径: ./b.log")
await asyncio.Future() # 永久运行
if __name__ == "__main__":
asyncio.run(main())
\ No newline at end of file
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['s6.9.2.py'],
pathex=[],
binaries=[],
datas=[('data', 'data')],
hiddenimports=['bleak.backends', 'asyncio'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='s6.9.2',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['data\\app.ico'],
)
import pystray
from PIL import Image, ImageDraw
from PIL import Image
import threading
import os
import sys
def create_image(width, height, color1, color2):
image = Image.new("RGB", (width, height), color1)
dc = ImageDraw.Draw(image)
dc.rectangle((width // 2, 0, width, height // 2), fill=color2)
return image
def load_icon(icon_path):
"""加载图标文件"""
try:
return Image.open(icon_path)
except FileNotFoundError:
print(f"Icon file not found at {icon_path}")
return None
def on_exit(icon, item):
"""退出程序的回调函数"""
icon.stop() # 停止托盘图标
print("Exiting program...")
os._exit(0) # 强制退出程序
def run_icon(icon_path):
image = Image.open(icon_path) # 加载自定义图标
icon = pystray.Icon("test_icon", image, "My System Tray Icon")
icon.run()
"""运行系统托盘图标"""
image = load_icon(icon_path)
if not image:
print("Failed to load icon. Exiting...")
return
# 创建系统托盘图标
icon = pystray.Icon(
name="test_icon",
icon=image,
title="My System Tray Icon",
menu=pystray.Menu(
pystray.MenuItem("Exit", on_exit) # 添加右键菜单项
)
)
icon.run() # 运行托盘图标
def start_tray_icon(icon_path):
"""在新线程中启动系统托盘图标"""
threading.Thread(target=run_icon, args=(icon_path,), daemon=True).start()
\ No newline at end of file
......
# -*- coding: utf-8 -*--
import sys
import asyncio
import websockets
from bleak import BleakScanner, BleakClient
import json
import base64
import threading
from tray_icon import start_tray_icon
import os
import sys
def resource_path(relative_path):
try:
base_path = sys._MEIPASS # 打包后运行时的临时路径
except AttributeError:
base_path = os.path.dirname(os.path.abspath(__file__)) # 开发环境下的路径
# 使用 os.path.join 拼接路径,并通过 os.path.abspath 转换为绝对路径
return os.path.abspath(os.path.join(base_path, relative_path))
def resource_path(relative_path):
"""获取资源文件的绝对路径,适用于打包后的程序"""
try:
base_path = sys._MEIPASS # 打包后运行时的临时路径
except AttributeError:
base_path = os.path.abspath(".") # 开发环境下的路径
return os.path.join(base_path, relative_path)
# 获取图标路径
icon_path = resource_path(resource_path("data/app.ico"))
# 调用系统托盘图标函数
start_tray_icon(icon_path)
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QPushButton, QVBoxLayout, QWidget
from PyQt5.QtCore import QThread, pyqtSignal
from bleak import BleakScanner, BleakClient
import websockets
# 添加线程锁以确保日志写入的原子性
write_lock = threading.Lock()
def log_message_sync(direction, message):
"""同步日志记录函数"""
def log_message_sync(direction, message, log_signal=None):
"""同步日志记录函数(支持信号传递)"""
log_entry = f"{direction}: {message}\n"
print(log_entry, end='') # 控制台仍然输出
print(log_entry, end='') # 控制台输出
with write_lock:
with open('a.log', 'a', encoding='utf-8') as f:
f.write(log_entry)
if log_signal:
log_signal.emit(log_entry) # 发射信号到GUI
async def log_message(direction, message):
async def log_message(direction, message, log_signal=None):
"""异步封装日志记录"""
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, log_message_sync, direction, message)
await loop.run_in_executor(None, log_message_sync, direction, message, log_signal)
class BLEClient:
def __init__(self):
def __init__(self, log_signal=None):
self.target_device = None
self.client = None
self.services = []
self.optional_services = []
self.websocket = None
self.log_signal = log_signal # 绑定日志信号
def on_disconnect(self, client):
print("BLE连接断开,关闭WebSocket")
......@@ -93,7 +73,7 @@ class BLEClient:
async for message in websocket:
try:
# 记录接收到的消息
await log_message("接收", message)
await log_message("接收", message, self.log_signal)
request = json.loads(message)
if request["jsonrpc"] != "2.0":
......@@ -102,7 +82,7 @@ class BLEClient:
"result": {"message": "Invalid Request"},
"id": request.get("id", None)
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
continue
......@@ -116,7 +96,7 @@ class BLEClient:
scanner = BleakScanner()
scanner.register_detection_callback(self.detection_callback)
# 添加重试机制
max_retries = 3
found = False
......@@ -125,25 +105,18 @@ class BLEClient:
await scanner.start()
await asyncio.sleep(5)
await scanner.stop()
if self.target_device:
found = True
break
if attempt < max_retries - 1: # 最后一次不等待
print(f"未找到设备,第{attempt+1}次重试...")
await asyncio.sleep(3)
if not found:
# response = json.dumps({
# "jsonrpc": "2.0",
# "result": {"message": "Device not found"},
# "id": request_id
# })
# await log_message("下发", response)
# await websocket.send(response)
continue
device, adv_data = self.target_device
discover_response = json.dumps({
"jsonrpc": "2.0",
......@@ -154,7 +127,7 @@ class BLEClient:
"rssi": device.rssi
}
})
await log_message("下发", discover_response)
await log_message("下发", discover_response, self.log_signal)
await websocket.send(discover_response)
result_response = json.dumps({
......@@ -162,9 +135,9 @@ class BLEClient:
"result": None,
"id": request_id
})
await log_message("下发", result_response)
await log_message("下发", result_response, self.log_signal)
await websocket.send(result_response)
elif method == "connect":
peripheral_id = params.get("peripheralId")
if not peripheral_id:
......@@ -173,7 +146,7 @@ class BLEClient:
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
continue
......@@ -187,7 +160,7 @@ class BLEClient:
"result": None,
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
else:
response = json.dumps({
......@@ -195,7 +168,7 @@ class BLEClient:
"result": {"message": "Failed to connect"},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
elif method == "write":
......@@ -210,7 +183,7 @@ class BLEClient:
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
continue
......@@ -225,7 +198,7 @@ class BLEClient:
"result": None,
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
elif method == "read":
......@@ -238,7 +211,7 @@ class BLEClient:
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
continue
......@@ -252,7 +225,7 @@ class BLEClient:
},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
elif method == "startNotifications":
......@@ -265,7 +238,7 @@ class BLEClient:
"result": {"message": "Invalid params"},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
continue
......@@ -278,7 +251,7 @@ class BLEClient:
"result": None,
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
else:
......@@ -287,7 +260,7 @@ class BLEClient:
"result": {"message": "Method not found"},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
except json.JSONDecodeError:
......@@ -296,7 +269,7 @@ class BLEClient:
"result": {"message": "Parse error"},
"id": None
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
except Exception as e:
response = json.dumps({
......@@ -304,7 +277,7 @@ class BLEClient:
"result": {"message": str(e)},
"id": request_id
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
except websockets.exceptions.ConnectionClosedOK:
......@@ -329,18 +302,54 @@ class BLEClient:
"message": base64.b64encode(data).decode("utf-8")
}
})
await log_message("下发", response)
await log_message("下发", response, self.log_signal)
await websocket.send(response)
return callback
async def main():
async with websockets.serve(
lambda websocket, path: BLEClient().handle_client(websocket, path),
"localhost", 20111
):
print("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
print("日志文件路径: ./b.log")
await asyncio.Future() # 永久运行
class WebSocketThread(QThread):
log_signal = pyqtSignal(str)
def run(self):
async def start_server():
ble_client = BLEClient(self.log_signal) # 绑定日志信号
async with websockets.serve(
lambda websocket, path: ble_client.handle_client(websocket, path),
"localhost", 20111
):
self.log_signal.emit("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
await asyncio.Future() # 永久运行
asyncio.run(start_server())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("BLE WebSocket Server")
self.setGeometry(100, 100, 600, 400)
self.text_edit = QTextEdit(self)
self.text_edit.setReadOnly(True)
self.start_button = QPushButton("启动服务", self)
self.start_button.clicked.connect(self.start_server)
layout = QVBoxLayout()
layout.addWidget(self.text_edit)
layout.addWidget(self.start_button)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.websocket_thread = WebSocketThread()
self.websocket_thread.log_signal.connect(self.text_edit.append)
def start_server(self):
self.websocket_thread.start()
if __name__ == "__main__":
asyncio.run(main())
\ No newline at end of file
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
\ No newline at end of file
......
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['we.py'],
pathex=[],
binaries=[],
datas=[('data', 'data')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='we',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['data\\app.ico'],
)
import sys
import asyncio
import websockets
from bleak import BleakScanner, BleakClient
import json
import base64
import threading
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QWidget
from PyQt5.QtCore import QThread, pyqtSignal
# 添加线程锁以确保日志写入的原子性
write_lock = threading.Lock()
def log_message_sync(direction, message):
"""同步日志记录函数"""
log_entry = f"{direction}: {message}\n"
print(log_entry, end='') # 控制台仍然输出
with write_lock:
with open('b.log', 'a', encoding='utf-8') as f:
f.write(log_entry)
async def log_message(direction, message):
"""异步封装日志记录"""
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, log_message_sync, direction, message)
class BLEClient:
def __init__(self):
self.target_device = None
self.client = None
self.services = []
self.optional_services = []
self.websocket = None
def on_disconnect(self, client):
print("BLE连接断开,关闭WebSocket")
if self.websocket and not self.websocket.closed:
asyncio.create_task(self.close_websocket())
async def close_websocket(self):
await self.websocket.close()
self.websocket = None
def detection_callback(self, device, advertisement_data):
# 合并所有过滤条件的services进行匹配
if any(service_uuid in advertisement_data.service_uuids for service_uuid in self.services):
self.target_device = (device, advertisement_data)
if not self.target_device:
print("未找到匹配设备")
return
else:
device, adv_data = self.target_device
print("\n找到目标设备:")
print(f"设备名称: {device.name}")
print(f"设备地址: {device.address}")
print(f"信号强度: {device.rssi} dBm")
print("\n广播信息:")
print(f"服务UUID列表: {adv_data.service_uuids}")
print(f"制造商数据: {adv_data.manufacturer_data}")
print(f"服务数据: {adv_data.service_data}")
print(f"本地名称: {adv_data.local_name}")
return self.target_device
async def handle_client(self, websocket, path):
self.websocket = websocket
if path != "/scratch/ble":
await websocket.close(code=1003, reason="Path not allowed")
return
try:
async for message in websocket:
try:
await log_message("接收", message)
request = json.loads(message)
if request["jsonrpc"] != "2.0":
continue # 跳过无效协议版本
method = request.get("method")
params = request.get("params", {})
request_id = request.get("id")
if method == "discover":
# 合并所有过滤条件的services
self.services = []
for filt in params.get("filters", [{}]):
self.services.extend(filt.get("services", []))
self.optional_services = params.get("optionalServices", [])
scanner = BleakScanner()
scanner.register_detection_callback(self.detection_callback)
# 带重试的扫描逻辑
max_retries = 3
found = False
for attempt in range(max_retries):
self.target_device = None
await scanner.start()
await asyncio.sleep(5)
await scanner.stop()
if self.target_device:
found = True
break
if attempt < max_retries - 1:
print(f"未找到设备,第{attempt+1}次重试...")
await asyncio.sleep(3)
if found:
device, adv_data = self.target_device
discover_response = json.dumps({
"jsonrpc": "2.0",
"method": "didDiscoverPeripheral",
"params": {
"name": device.name,
"peripheralId": device.address,
"rssi": device.rssi
}
})
await log_message("下发", discover_response)
await websocket.send(discover_response)
result_response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", result_response)
await websocket.send(result_response)
elif method == "connect":
peripheral_id = params.get("peripheralId")
if peripheral_id:
self.client = BleakClient(peripheral_id)
self.client.set_disconnected_callback(self.on_disconnect)
await self.client.connect()
if self.client.is_connected:
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "write":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
message = params.get("message")
encoding = params.get("encoding", "utf-8")
if all([service_id, characteristic_id, message]):
if encoding == "base64":
message_bytes = base64.b64decode(message)
else:
message_bytes = message.encode(encoding)
await self.client.write_gatt_char(characteristic_id, message_bytes)
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "read":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
if all([service_id, characteristic_id]):
data = await self.client.read_gatt_char(characteristic_id)
response = json.dumps({
"jsonrpc": "2.0",
"result": {
"serviceId": service_id,
"characteristicId": characteristic_id,
"message": base64.b64encode(data).decode("utf-8")
},
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
elif method == "startNotifications":
service_id = params.get("serviceId")
characteristic_id = params.get("characteristicId")
if all([service_id, characteristic_id]):
await self.client.start_notify(
characteristic_id,
self.notification_handler(websocket, service_id, characteristic_id)
)
response = json.dumps({
"jsonrpc": "2.0",
"result": None,
"id": request_id
})
await log_message("下发", response)
await websocket.send(response)
except json.JSONDecodeError:
error_msg = json.dumps({
"jsonrpc": "2.0",
"result": {"message": "Parse error"},
"id": None
})
await log_message("下发", error_msg)
except Exception as e:
error_msg = json.dumps({
"jsonrpc": "2.0",
"result": {"message": str(e)},
"id": request.get("id") if request else None
})
await log_message("下发", error_msg)
except websockets.exceptions.ConnectionClosed:
print("WebSocket连接关闭")
finally:
if self.client and self.client.is_connected:
await self.client.disconnect()
self.client = None
self.target_device = None
def notification_handler(self, websocket, service_id, characteristic_id):
async def callback(sender, data):
response = json.dumps({
"jsonrpc": "2.0",
"method": "characteristicDidChange",
"params": {
"serviceId": service_id,
"characteristicId": characteristic_id,
"message": base64.b64encode(data).decode("utf-8")
}
})
await log_message("下发", response)
await websocket.send(response)
return callback
class WebSocketServerThread(QThread):
log_signal = pyqtSignal(str)
def run(self):
async def main():
async with websockets.serve(
lambda websocket, path: BLEClient().handle_client(websocket, path),
"localhost", 20111
):
self.log_signal.emit("WebSocket服务已启动: ws://localhost:20111/scratch/ble")
self.log_signal.emit("日志文件路径: ./b.log")
await asyncio.Future() # 永久运行
asyncio.run(main())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("BLE WebSocket Server")
self.setGeometry(100, 100, 800, 600)
self.text_edit = QTextEdit(self)
self.text_edit.setReadOnly(True)
layout = QVBoxLayout()
layout.addWidget(self.text_edit)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.websocket_thread = WebSocketServerThread()
self.websocket_thread.log_signal.connect(self.update_log)
self.websocket_thread.start()
def update_log(self, message):
self.text_edit.append(message)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
\ No newline at end of file
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['we1.py'],
pathex=[],
binaries=[],
datas=[('data', 'data')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='we1',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['data\\app.ico'],
)
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!