[PYTHON] Avertir LINE de la température corporelle du thermomètre BLE avec la tarte à la râpe n ° 2

introduction

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.

installation de 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

Essayez différentes choses avec bluepy

Parlez à un appareil BLE avec bluepy.

Rechercher les paquets publicitaires

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.

Connectez-vous et obtenez une liste de services

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 

Obtenir des données d'un thermomètre

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é.

Analyse des données reçues

Point de vue des valeurs mesurées

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.

Point de vue de l'horodatage

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.

Notifier par LINE

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.

IMG_6943.png

Production

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.

memo_04.png

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.

IMG_6944.png

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! ** **

Merci pour votre soutien

Je ne peux pas acheter un thermomètre ou une tarte aux râpes pour le moment ...

Recommended Posts

Notifier LINE de la température corporelle du thermomètre BLE avec la tarte à la râpe # 1
Avertir LINE de la température corporelle du thermomètre BLE avec la tarte à la râpe n ° 2
Mesurer la température du processeur de Raspeye avec Python
Informer périodiquement l'état de traitement de Raspberry Pi avec python → Google Spreadsheet → LINE
Production de système de contrôle de température avec tarte aux framboises et ESP32 (1)
Sortie du Raspberry Pi vers la ligne
Production d'un système de contrôle de température avec tarte aux framboises et ESP32 (2) Production d'un appareil de transmission
Sortie CSV des données d'impulsion avec Raspberry Pi (sortie CSV)
Obtenez des informations sur le processeur de Raspberry Pi avec Python
Obtenez la température et l'humidité avec DHT11 et Raspberry Pi
Enregistrez la température et l'humidité avec systemd sur Raspberry Pi
GPGPU avec Raspberry Pi
Prenez la valeur du thermo-hygromètre SwitchBot avec Raspberry Pi
Changer les valeurs du thermo-hygromètre Bot avec Raspberry Pi
DigitalSignage avec Raspberry Pi
Exploitons GPIO de Raspeye avec Python CGI
Simulez la mesure de température avec Raspberry Pi + Flask + SQLite + Ajax
Créez facilement un TweetBot qui vous informe de la température et de l'humidité avec Raspberry Pi + DHT11.
Jouez pour informer Slack des données environnementales de SensorTag à l'aide d'AWS PaaS via Raspberry Pi3
J'ai essayé d'exécuter Movidius NCS avec python de Raspberry Pi3
[RaspberryPi] [python] Informer LINE de la température ambiante avec capteur de température + IFTTT
Mesurez et comparez les températures avec Raspberry Pi et générez automatiquement des graphiques
Comment obtenir la température du thermo-hygromètre SwitchBot à l'aide de Raspberry Pi
Fabriquez un thermomètre BLE et obtenez la température avec Pythonista3
Plantes Mutter avec Raspberry Pi
Avec skype, notifiez avec skype de python!
Reconnaissance d'image des déchets avec Edge (Raspberry Pi) à partir de zéro connaissance en utilisant AutoML Vsion et TPU
Créez un thermomètre avec Raspberry Pi et rendez-le visible sur le navigateur Partie 4
Affichage graphique de la consommation électrique des ménages avec 3GPI et Raspeye
[Remarque] Utilisation d'un écran LCD à 16 caractères à 2 chiffres (1602A) de Python avec Raspeye
Consigner périodiquement les valeurs des capteurs d'environnement Omron avec Raspberry Pi
Utilisez vl53l0x avec RaspberryPi (python)
Commande de servomoteur avec Raspberry Pi
Communication série avec Raspberry Pi + PySerial
Configuration du système d'exploitation avec Raspberry Pi Imager
Essayez L Chika avec raspberrypi
Construire un serveur VPN avec Raspberry Pie
Notifier LINE des informations sur l'exploitation du train
Essayez de déplacer 3 servos avec Raspeye
Utiliser une webcam avec Raspberry Pi
Sortie CSV des données d'impulsion avec Raspberry Pi (vérifier l'entrée analogique avec python)
Essayez de tweeter le flux RSS d'arXiv sur Twitter avec python de Raspeye
[Python + PHP] Créez un moniteur de température / humidité / pression avec Raspberry Pi
Notifier LINE des informations de localisation (Google map) avec GPS Multi-Unit SORACOM Edition
Enregistrement des valeurs du capteur d'environnement Omron avec Raspberry Pi (type USB)