Ceci est une continuation de # 1 qui notifie LINE de la température corporelle du thermomètre BLE avec tarte à la râpe. Cette fois, nous allons l'implémenter avec python. GATT avec python. La bibliothèque BLE utilise bluepy.
La bibliothèque BLE utilise bluepy. Installez bluepy.
$ sudo apt-get update
$ sudo apt-get -y upgrade
$ sudo apt-get -y install python3-pip libglib2.0-dev
$ sudo pip3 install bluepy
>Successfully installed bluepy-1.3.0
$ reboot
Parlez à un appareil BLE avec bluepy.
Tout d'abord, analysez le paquet de publicité.
from bluepy import btle
scanner = btle.Scanner(0)
devices = scanner.scan(3.0)
for device in devices:
print(f'BLE Address:{device.addr}')
for (adTypeCode, description, valueText) in device.getScanData():
print(f'- {description}:{valueText}')
Le code est simple, mais il a des pièges et nécessite des ** privilèges sudo ** pour exécuter une analyse avec bluepy. Si vous ne disposez pas des autorisations suffisantes, vous obtiendrez une erreur avec scanner.scan ()
.
Mettez le thermomètre en ** mode d'appairage **, puis exécutez py.
$ sudo python3 bluepyadv.py
BLE Address:18:93:d7:76:c9:b8
- Flags:05
- Incomplete 16b Services:00001809-0000-1000-8000-00805f9b34fb
- 0x12:5000a000
- Tx Power:00
- Complete Local Name:A&D_UT201BLE_76C9B8
BLE Address:6f:1a:a5:25:58:55
- Flags:06
- Manufacturer:4c001005571cf70bed
Adresse BLE: 18: 93: d7: 76: c9: b8
est l'information du dispositif de thermomètre. Il a été scanné correctement.
Obtenez une liste de services en vous connectant à un thermomètre. L'adresse BLE est comme une adresse MAC, elle dépend donc de l'appareil. Veuillez indiquer l'adresse BLE de votre appareil. L'adresse BLE de mon thermomètre est «18: 93: D7: 76: C9: B8».
from bluepy import btle
BLE_ADDRESS="18:93:D7:76:C9:B8"
peripheral = btle.Peripheral()
peripheral.connect(BLE_ADDRESS)
for service in peripheral.getServices():
print(f'Service UUID:{service.uuid}')
for characteristic in service.getCharacteristics():
print(f'- Characteristic UUID:{characteristic.uuid} , Handle:{hex(characteristic.getHandle())} , Property:{characteristic.propertiesToString()}')
Mesurez avec un thermomètre et exécutez py lorsqu'il est en ** mode de transmission **. Puisqu'il se connecte, il est en mode de transmission, pas en mode d'appairage. Vous n'avez pas besoin d'avoir les privilèges sudo comme avant.
$ python3 bluepyconnect.py
Service UUID:00001800-0000-1000-8000-00805f9b34fb
- Characteristic UUID:00002a00-0000-1000-8000-00805f9b34fb , Handle:0x3 , Property:READ
- Characteristic UUID:00002a01-0000-1000-8000-00805f9b34fb , Handle:0x5 , Property:READ
- Characteristic UUID:00002a02-0000-1000-8000-00805f9b34fb , Handle:0x7 , Property:READ WRITE
- Characteristic UUID:00002a03-0000-1000-8000-00805f9b34fb , Handle:0x9 , Property:WRITE
- Characteristic UUID:00002a04-0000-1000-8000-00805f9b34fb , Handle:0xb , Property:READ
Service UUID:00001801-0000-1000-8000-00805f9b34fb
- Characteristic UUID:00002a05-0000-1000-8000-00805f9b34fb , Handle:0xe , Property:INDICATE
Service UUID:00001809-0000-1000-8000-00805f9b34fb
- Characteristic UUID:00002a1c-0000-1000-8000-00805f9b34fb , Handle:0x12 , Property:INDICATE
- Characteristic UUID:00002a1d-0000-1000-8000-00805f9b34fb , Handle:0x15 , Property:READ
- Characteristic UUID:00002a08-0000-1000-8000-00805f9b34fb , Handle:0x17 , Property:READ WRITE
Service UUID:0000180a-0000-1000-8000-00805f9b34fb
- Characteristic UUID:00002a29-0000-1000-8000-00805f9b34fb , Handle:0x1a , Property:READ
- Characteristic UUID:00002a24-0000-1000-8000-00805f9b34fb , Handle:0x1c , Property:READ
- Characteristic UUID:00002a25-0000-1000-8000-00805f9b34fb , Handle:0x1e , Property:READ
- Characteristic UUID:00002a27-0000-1000-8000-00805f9b34fb , Handle:0x20 , Property:READ
- Characteristic UUID:00002a26-0000-1000-8000-00805f9b34fb , Handle:0x22 , Property:READ
- Characteristic UUID:00002a28-0000-1000-8000-00805f9b34fb , Handle:0x24 , Property:READ
- Characteristic UUID:00002a23-0000-1000-8000-00805f9b34fb , Handle:0x26 , Property:READ
- Characteristic UUID:00002a2a-0000-1000-8000-00805f9b34fb , Handle:0x28 , Property:READ
Service UUID:0000180f-0000-1000-8000-00805f9b34fb
- Characteristic UUID:00002a19-0000-1000-8000-00805f9b34fb , Handle:0x2b , Property:READ
Service UUID:233bf000-5a34-1b6d-975c-000d5690abe4
- Characteristic UUID:233bf001-5a34-1b6d-975c-000d5690abe4 , Handle:0x2e , Property:READ WRITE
Essayez de recevoir les données mesurées.
import sys
from bluepy import btle
BLE_ADDRESS="18:93:D7:76:C9:B8"
SERVICE_UUID="00001809-0000-1000-8000-00805f9b34fb"
class MyDelegate(btle.DefaultDelegate):
def __init__(self):
btle.DefaultDelegate.__init__(self)
def handleNotification(self, cHandle, data):
print("Handle = " + hex(cHandle))
print("- Flags = " + hex(data[0]))
print("- C1:Temperature Measurement Value(Celsius) = " + hex(data[1])+":"+hex(data[2])+":"+hex(data[3])+":"+hex(data[4]))
print("- C3:Time Stamp = " + hex(data[5])+":"+hex(data[6])+":"+hex(data[7])+":"+hex(data[8])+":"+hex(data[9])+":"+hex(data[10])+":"+hex(data[11]))
if __name__ == '__main__':
print("Start")
print("Connecting Wait...")
try:
peripheral = btle.Peripheral()
peripheral.connect(BLE_ADDRESS)
except:
print("connect Error!")
sys.exit(0)
print("Connected!")
peripheral.withDelegate(MyDelegate())
# Enable Indicate
peripheral.writeCharacteristic(0x13, b'\x02\x00', True)
#Attendez la notification
print("Indicate Wait...")
try:
TIMEOUT = 3.0
while True:
if peripheral.waitForNotifications(TIMEOUT):
# handleNotification()A été appelé
continue
# handleNotification()N'a pas été appelé même après avoir attendu TIME OUT secondes
print("wait...")
except:
#Viens ici une fois déconnecté
print("except!")
print("end")
Le fait est que le gestionnaire d'événements est enregistré avec périphérique.withDelegate (MyDelegate ())
et périphérique.writeCharacteristic (0x13, b '\ x02 \ x00', True)
est terminé.
** Indiquer démarre lorsque vous définissez 0200 sur la caractéristique du handle 0x13 ** est comme dans Description précédente. L'événement handleNotification ()
est déclenché lorsque des données sont reçues. Les données reçues sont bloquées dans les données.
Mise en garde La valeur de handle de 0x13 peut différer selon le périphérique (non confirmé), vérifiez donc la valeur de handle avec gatttool et spécifiez la valeur de votre périphérique.
pi@raspberrypi:~/work/git/BLEThermometer/src $ python3 bluepygatt.py
Start
Connecting Wait...
Connected!
Indicate Wait...
Handle = 0x12
- Flags = 0x6
- C1:Temperature Measurement Value(Celsius) = 0x73:0x1:0x0:0xff
- C3:Time Stamp = 0xe4:0x7:0x5:0x4:0xa:0x7:0x2f
wait...
wait...
except!
end
Dans ce journal d'exécution
Vous pouvez voir qu'il a été supprimé.
J'ai découvert plus tôt que "température corporelle = 0x73: 0x1: 0x0: 0xff", mais ces données de 4 octets sont un binaire au format ** IEEE 11073 32 bits float **. Je n'ai pas trouvé de moyen facile de convertir un binaire flottant IEEE 11073 32 bits en une variable de type flottant en python. Je ne pouvais pas m'en empêcher, alors je l'ai fait moi-même.
import numpy as np
def to_float_from_11073_32bit_float(data):
tmp = int.from_bytes(data,'little')
uint32val = np.array([tmp],dtype=np.uint32)
#Trouvez la pièce inappropriée(0-24bit)
tmp = bin(uint32val[0] & 0xffffff)
mantissa = int(tmp,0)
#Trouvez la partie index(25-32bit)
tmp = int(data[3])
tmp2 = np.array([tmp],dtype=np.byte)
exponent = int(tmp2[0])
#Calculer des nombres réels
ret = round(mantissa * pow(10,exponent),1)
return ret
# 37.1
temp = to_float_from_11073_32bit_float(b'\x73\x01\x00\xff')
print("temp = " + str(temp) + " C")
Je le ferai.
$ python3 to_float_from_11073_32bit_float.py
temp = 37.1 C
0x73: 0x1: 0x0: 0xff
est maintenant ** 37.1 **. Très bien.
L'horodatage est de 7 octets. Format de mesure de température C3.
def to_date_time(data):
tmp = data[0:2]
yyyy = int.from_bytes(tmp,'little')
mm = int(data[2])
dd = int(data[3])
hh = int(data[4])
min = int(data[5])
ss = int(data[6])
strdate_time=str(yyyy)+"/"+str(mm)+"/"+str(dd)+" "+str(hh)+":"+str(min)+":"+str(ss)
return strdate_time
# 2020/5/4 10:07:47
date_time = to_date_time(b'\xe4\x07\x05\x04\x0a\x07\x2f')
print("date_time = " + date_time)
Je le ferai.
$ python3 to_date_time.py
date_time = 2020/5/4 10:7:47
Jusqu'à présent, vous pouvez faire la même chose avec bulepy que la dernière fois avec gatttool.
Au fait, j'ai dû notifier le résultat de la mesure sur LINE. Les notifications LINE sont faciles avec LINE Notify.
Mettez en œuvre la notification LINE en vous référant à l'article suivant.
Le jeton écrit dans cette source n'est pas valide, alors émettez-le et utilisez-en un valide.
import requests
#Notification LINE
def send_notify(access_token,comment):
if( len(access_token) <= 0 ):
return
url = "https://notify-api.line.me/api/notify"
headers = {'Authorization': 'Bearer ' + access_token}
message = comment
payload = {'message': message}
print(message)
requests.post(url, headers=headers, params=payload,)
send_notify("token xxx","comment")
Je le ferai.
$ python3 sendline.py
comment
Kita.
De là, c'est la production. C'est facile car tout ce que vous avez à faire est de faire ce que vous avez recherché jusqu'à présent dans l'ordre.
Le code source python est un peu long.
#Vous avez besoin de l'autorisation sudo pour exécuter ce py.
#Si vous n'avez pas la permission, scanner.scan()Entraînera une erreur.
from bluepy import btle
import sys
import time
import to_float_from_11073_32bit_float as tofl
import to_date_time as todt
import sendline as line
# define
SERVICE_UUID="00001809-0000-1000-8000-00805f9b34fb"
# global
BLE_ADDRESS="xx:xx:xx:xx:xx:xx"
TOKEN = "this is token"
def scan():
try:
scanner = btle.Scanner(0)
devices = scanner.scan(3.0)
for device in devices:
print(f'SCAN BLE_ADDR:{device.addr}')
if(device.addr.lower()==BLE_ADDRESS.lower()):
print("Find!")
return True
except:
print("scan Error!")
return False
print("---")
return False
class MyDelegate(btle.DefaultDelegate):
def __init__(self):
btle.DefaultDelegate.__init__(self)
def handleNotification(self, cHandle, data):
print("Indicate Handle = " + hex(cHandle))
print("Flags = " + hex(data[0]))
print("C1:Temperature Measurement Value(Celsius) = " + hex(data[1])+":"+hex(data[2])+":"+hex(data[3])+":"+hex(data[4]))
print("C3:Time Stamp = " + hex(data[5])+":"+hex(data[6])+":"+hex(data[7])+":"+hex(data[8])+":"+hex(data[9])+":"+hex(data[10])+":"+hex(data[11]))
temp = tofl.to_float_from_11073_32bit_float(data[1:5])
print("temp = " + str(temp))
timestamp = todt.to_date_time(data[5:12])
print("timestamp = " + timestamp)
line.send_notify(TOKEN,str(temp)+" C "+timestamp)
def main():
#
# Scan
#
print("<Scan Start>")
while True:
scanresult = scan()
if( scanresult==True):
break
time.sleep(3)
print("Scan End")
#
# Connect
#
print("Connect Start")
try:
peripheral = btle.Peripheral()
peripheral.connect(BLE_ADDRESS)
except:
print("connect Error!")
sys.exit(0)
print("Connected!")
service = peripheral.getServiceByUUID(SERVICE_UUID)
peripheral.withDelegate(MyDelegate())
# Enable Indicate
peripheral.writeCharacteristic(0x0013, b'\x02\x00', True)
#Attendez la notification
print("Indicate Wait...")
try:
TIMEOUT = 3.0
while True:
if peripheral.waitForNotifications(TIMEOUT):
# handleNotification()A été appelé
continue
# handleNotification()N'a pas été appelé même après avoir attendu TIME OUT secondes
print("wait...")
except:
print("except!")
print("<end>")
if __name__ == '__main__':
print(sys.argv[0])
#global TOKEN
TOKEN = sys.argv[1]
print("token = " + TOKEN)
#gloval BLE_ADDRESS
BLE_ADDRESS = sys.argv[2]
print("BLE device = " + BLE_ADDRESS)
while True:
main()
time.sleep(3)
Lorsque vous exécutez py, l'analyse démarre et vous mesurez votre température corporelle. Lorsque la mesure est terminée, elle sera automatiquement reçue et la température corporelle et l'horodatage (date et heure de la mesure) seront notifiés à LINE.
$ sudo python3 bluepythermo.py [token] 18:93:D7:76:C9:B8
bluepythermo.py
token = [token]
BLE device = 18:93:D7:76:C9:B8
<Scan Start>
SCAN BLE_ADDR:18:93:d7:76:c9:b8
Find!
Scan End
Connect Start
Connected!
Indicate Wait...
Indicate Handle = 0x12
Flags = 0x6
C1:Temperature Measurement Value(Celsius) = 0x72:0x1:0x0:0xff
C3:Time Stamp = 0xe4:0x7:0x5:0x4:0xa:0x16:0x1c
temp = 37.0
timestamp = 2020/5/4 10:22:28
37.0 C 2020/5/4 10:22:28
wait...
wait...
except!
<end>
J'ai bien reçu une notification sur LINE.
Si vous mettez une tarte à la râpe dans la pièce et exécutez py, elle se comportera comme prévu en répétant scan → notification LINE. Si vous installez un thermomètre et une tarte à la râpe, vous pouvez également notifier la température corporelle d'une personne éloignée, afin de pouvoir l'utiliser pour vérifier votre survie.
** Il n'y a aucun doute sur l'enregistrement de la température corporelle! ** **
Je ne peux pas acheter un thermomètre ou une tarte aux râpes pour le moment ...