SimplePyBLE - Python bindings for SimpleBLE

Overview

SimplePyBLE - Python bindings for SimpleBLE

The ultimate fully-fledged cross-platform BLE library, designed for simplicity and ease of use.

All specific operating system quirks are handled to provide a consistent behavior across all platforms. Each major version of the library will have a stable API that will be fully forwards compatible.

If you want to use the library and need help. Please reach out! You can find me at: kevin at dewald dot me

Instalation

pip install simplepyble

Usage

Please review the provided examples in the source code. They are all self-contained and can be run from the command line. More documentation will be available soon.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

License

All components within this project that have not been bundled from external creators, are licensed under the terms of the MIT Licence.

Comments
  • Repeated read gives always the same value

    Repeated read gives always the same value

    It seems that reading value from characteristic from peripheral never gets updated during one connection, multiple reads during the same connection always give me the same value, even when the characteristic is updated on the service side. I did a test, I created a peripheral with service with 2 text characteristics, A for writing and B for reading. On the service side, when A is written , B is updated. When I do the the connection to this peripheral and then the sequence: write - read - write different value - read, the second read gives me the value from the first read, it never gets updated. When I disconnect from peripheral and connect again, read gives me updated second value. Is this a "feature" or the bug?

    opened by piotromt 11
  • peripheral.identifier() in the scan example always return an empty string.

    peripheral.identifier() in the scan example always return an empty string.

    I am running the scan.py example on windows 10 pro, Python 3.9.5. Everything works well except that the device names are not printed. I think it's supposed to come from peripheral.identifier() but it seems to return an empty string for all devices.

    By device name I mean the human friendly name that we see in the bluetooth device setting screens of Windows, iPhone, etc.

    opened by zapta 5
  • Please expose the pairing related methods in the Python API

    Please expose the pairing related methods in the Python API

    These two pairing related methods are not reflected in the Python API.

    Please add them there.

    https://github.com/OpenBluetoothToolbox/SimpleBLE/blob/main/include/simpleble/Peripheral.h#L32

    opened by zapta 3
  • peripheral.read: UnicodeDecodeError: 'utf-8' codec can't decode byte

    peripheral.read: UnicodeDecodeError: 'utf-8' codec can't decode byte

    Windows 10; python 3.9.7

    import simplepyble
    import random
    import threading
    import time
    from Crypto.Cipher import AES
    from Crypto.Random import get_random_bytes
    
    def encrypt(key, data):
      k = AES.new(bytes(reversed(key)), AES.MODE_ECB)
      data = reversed(list(k.encrypt(bytes(reversed(data)))))
      rev = []
      for d in data:
        rev.append(d)
      return rev
    
    
    def key_encrypt(name, password, key):
      name = name.ljust(16, chr(0))
      password = password.ljust(16, chr(0))
      data = [ord(a) ^ ord(b) for a,b in zip(name,password)]
      return encrypt(key, data)
    
    class dimond:
      def __init__(self, vendor, mac, name, password, mesh=None, callback=None):
        self.vendor = vendor
        self.mac = mac
        self.macarray = mac.split(':')
        self.name = name
        self.password = password
        self.callback = callback
        self.mesh = mesh
        self.packet_count = random.randrange(0xffff)
        self.macdata = [int(self.macarray[5], 16), int(self.macarray[4], 16), int(self.macarray[3], 16), int(self.macarray[2], 16), int(self.macarray[1], 16), int(self.macarray[0], 16)]
      
      def __done__(self):
        self.peripheral.disconnect()
    
      def set_sk(self, sk):
        self.sk = sk
    
      def connect(self):
        #self.device = btle.Peripheral(self.mac, addrType=btle.ADDR_TYPE_PUBLIC)
        adapters = simplepyble.Adapter.get_adapters()
    
        if len(adapters) == 0:
            print("No adapters found")
    
        # Query the user to pick an adapter
        adapter = adapters[0]
    
        print(f"Selected adapter: {adapter.identifier()} [{adapter.address()}]")
    
        adapter.set_callback_on_scan_start(lambda: print("Scan started."))
        adapter.set_callback_on_scan_stop(lambda: print("Scan complete."))
        adapter.set_callback_on_scan_found(lambda peripheral: (peripheral.address() == self.mac) and print(f"Found {peripheral.identifier()} [{peripheral.address()}]"))
    
        # Scan for 5 seconds
        adapter.scan_for(5000)
        peripherals = adapter.scan_get_results()
        
        self.peripheral = None
        # Query the user to pick a peripheral
        for i, p in enumerate(peripherals):
            if p.address() == self.mac:
                self.peripheral = p
                break
    
        if (self.peripheral):
            connectable_str = "Connectable" if self.peripheral.is_connectable() else "Non-Connectable"
            print(f"{self.peripheral.identifier()} [{self.peripheral.address()}] - {connectable_str}")
    
            manufacturer_data = self.peripheral.manufacturer_data()
            for manufacturer_id, value in manufacturer_data.items():
                print(f"    Manufacturer ID: {manufacturer_id}")
                print(f"    Manufacturer data: {value}")
    
            print(f"Connecting to: {self.peripheral.identifier()} [{self.peripheral.address()}]")
            self.peripheral.connect()
            '''
            print("Successfully connected, listing services...")
            services = self.peripheral.services()
            for service in services:
                print(f"Service: {service.uuid}")
                for characteristic in service.characteristics:
                    print(f"    Characteristic: {characteristic}")
            '''
            self.notification = '00010203-0405-0607-0809-0a0b0c0d1911'
            self.control = '00010203-0405-0607-0809-0a0b0c0d1912'
            self.pairing = '00010203-0405-0607-0809-0a0b0c0d1914'
           
            data = [0] * 16
            random_data = get_random_bytes(8)
            for i in range(8):
              data[i] = random_data[i]
            enc_data = key_encrypt(self.name, self.password, data)
            packet = [0x0c]
            packet += data[0:8]
            packet += enc_data[0:8]
            try:
              self.peripheral.write_request('00010203-0405-0607-0809-0a0b0c0d1910', self.pairing, bytes(packet))
              time.sleep(0.3)
              data2 = self.peripheral.read('00010203-0405-0607-0809-0a0b0c0d1910', self.pairing)
            except:
              raise Exception("Unable to connect")
            
            print('Ok!')
    
        else:
            print('BT device "{}" not found!'.format(target_mac))
    
    target_mac = '08:65:f0:04:04:e1'
    
    if __name__ == "__main__":
        network = dimond(0x0211, target_mac, "ZenggeMesh", "ZenggeTechnology")#, callback=callback)
        network.connect()
    
    (base) D:\work\btdimmer>python btdimmer.py
    Selected adapter: dongle [00:1a:7d:da:71:12]
    Scan started.
    Found abd8302448845239 [08:65:f0:04:04:e1]
    Scan complete.
    abd8302448845239 [08:65:f0:04:04:e1] - Connectable
        Manufacturer ID: 529
        Manufacturer data: b'\x11\x02\xe1\x04\x04\xf0\x02\x0f\x01\x02\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
    Connecting to: abd8302448845239 [08:65:f0:04:04:e1]
    Traceback (most recent call last):
      File "D:\work\btdimmer\btdimmer.py", line 109, in connect
        data2 = self.peripheral.read('00010203-0405-0607-0809-0a0b0c0d1910', self.pairing)
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0x86 in position 1: invalid start byte
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "D:\work\btdimmer\btdimmer.py", line 122, in <module>
        network.connect()
      File "D:\work\btdimmer\btdimmer.py", line 111, in connect
        raise Exception("Unable to connect")
    Exception: Unable to connect
    
    (base) D:\work\btdimmer>
    
    opened by zenbooster 2
  • How to pair with BLE device?

    How to pair with BLE device?

    Hi, I am using Library "simplepyble". It is looking very simple and easy to use but I didn't find any method or syntax for pairing or bonding in the examples. Can you please guide me on how I can pair my PC with my BLE device using "simplepyble". Thanks.

    opened by inamghouss 1
  • run example scan.py error: Process finished with exit code -1073741819 (0xC0000005)

    run example scan.py error: Process finished with exit code -1073741819 (0xC0000005)

    some details window10 python => 3.8.5 simplepyble => 0.0.5

    sometimes return an empty string for all devices, sometimes return error Process finished with exit code -1073741819 (0xC0000005)

    opened by fanleung 0
Releases(v0.0.5)
  • v0.0.5(Jun 13, 2022)

    [0.0.5] - 2022-06-12

    Added

    • Python's Global Interpreter Lock (GIL) will be released during Peripheral.connect()
    • Keep-alive policies for function objects passed into SimplePyBLE.
    Source code(tar.gz)
    Source code(zip)
  • v0.0.4(Feb 14, 2022)

  • v0.0.3(Feb 13, 2022)

    [0.0.3] - 2022-01-22

    Fixed

    • write_request and write_command functions would accept strings instead of bytes as payloads. (Thanks kaedenbrinkman!)
    Source code(tar.gz)
    Source code(zip)
  • v0.0.2(Jan 16, 2022)

  • v0.0.1(Jan 11, 2022)

Owner
Open Bluetooth Toolbox
Tools and code for Bluetooth development
Open Bluetooth Toolbox
Python library for creating PEG parsers

PyParsing -- A Python Parsing Module Introduction The pyparsing module is an alternative approach to creating and executing simple grammars, vs. the t

Pyparsing 1.7k Jan 03, 2023
Open Source Repository for CFD Solvers

Background and Validation This wiki is built in Notion. Here are all the tips you need to contribute. General Background Flow over a cylinder The proj

1 Dec 30, 2021
Project 2 for Microsoft Azure on WUT

azure-proj2 Project 2 for Microsoft Azure on WUT Table of contents Team Tematyka projektu Architektura Opis rozwiązania Demo dzałania The Team Krzyszt

1 Dec 07, 2021
Speed up your typing by some exercises in the multi-platform(Windows/Ubuntu).

Introduction This project purpose is speed up your typing by some exercises in the multi-platform(Windows/Ubuntu). Build Environment Software Environm

lyfer233 1 Mar 24, 2022
Script em python, utilizando PySimpleGUI, para a geração de arquivo txt a ser importado no sistema de Bilhetagem Eletrônica da RioCard, no Estado do Rio de Janeiro.

pedido-vt-riocard Script em python, utilizando PySimpleGUI, para a geração de arquivo txt a ser importado no sistema de Bilhetagem Eletrônica da RioCa

Carlos Bruno Gomes 1 Dec 01, 2021
A password genarator/manager for passwords uesing a pseudorandom number genarator

pseudorandom-password-genarator a password genarator/manager for passwords uesing a pseudorandom number genarator when you give the program a word eg

1 Nov 18, 2021
Install JetBrains Toolbox

ansible-role-jetbrains-toolbox Install JetBrains Toolbox Example Playbook This example is taken from molecule/default/converge.yml and is tested on ea

Antoine Mace 2 Feb 04, 2022
This is the course project of AI3602: Data Mining of SJTU

This is the course project of AI3602: Data Mining of SJTU. Group Members include Jinghao Feng, Mingyang Jiang and Wenzhong Zheng.

2 Jan 13, 2022
Calc.py - A powerful Python REPL calculator

Calc - A powerful Python REPL calculator This is a calculator with a complex sou

Alejandro 8 Oct 22, 2022
More granular intermediaries for legacy Minecraft versions

Orinthe/Intermediary mappings This repository contains the match information between different versions of Minecraft created by the Orinthe project, a

4 Jan 11, 2022
Nfog - Scriptable Database-Driven NFO Generator for Movies and TV

nfog Scriptable Database-Driven NFO Generator for Movies and TV. Installation pi

6 Oct 08, 2022
An kind of operating system portal to a variety of apps with pure python

pyos An kind of operating system portal to a variety of apps. Installation Run this on your terminal: git clone https://github.com/arjunj132/pyos.git

1 Jan 22, 2022
VHDL to Discrete Logic on PCB Flow

PCBFlow Highly experimental set of scripts to transform a digital circuit described in a hardware description language (VHDL or Verilog) into a discre

Tim 77 Nov 04, 2022
Data and analysis relating to the 5.8M Melbourne quake of 2021

quake2021 Data and analysis relating to the 5.8M Melbourne quake of 2021 Monash University Woodside Living Lab Building The building is located here T

Colin Caprani 6 May 16, 2022
Functional collections extension functions for Python

pyfuncol pyfuncol Installation Usage API Documentation Compatibility Contributing License A Python functional collections library. It extends collecti

Andrea Veneziano 32 Nov 16, 2022
A simply program to find active jackbox.tv game codes

PeepingJack A simply program to find active jackbox.tv game codes How does this work? It uses a threadpool to loop through all possible codes in a ran

3 Mar 20, 2022
Width-customizer-for-streamlit-apps - Width customizer for Streamlit Apps

🎈 Width customizer for Streamlit Apps As of now, you can only change your Strea

Charly Wargnier 5 Aug 09, 2022
Advanced Keylogger in Python

Advanced Keylogger in Python Important Disclaimer: The author will not be held r

Suvanth Erranki 1 Feb 07, 2022
A data driven app for bicycle hiring in London(UK)

bicycle_hiring_app_deployed A data driven app for bicycle hiring in London(UK). It predicts expected number of bicycle hire in London. It asks users t

Rajarshi Roy Raju 1 Dec 10, 2021
Pampy: The Pattern Matching for Python you always dreamed of.

Pampy: Pattern Matching for Python Pampy is pretty small (150 lines), reasonably fast, and often makes your code more readable and hence easier to rea

Claudio Santini 3.5k Dec 30, 2022