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>