import asyncio import os import io import requests from PIL import ImageDraw, ImageFont, Image import qrcode from bleak import BleakClient, BleakScanner # BLE Config DEVICE_NAME = "Bonrix-DQR-222" WRITE_UUID = "87654321-4321-4321-4321-cba987654321" NOTIFY_UUID = "98765432-1234-1234-1234-123456789abc" # Transfer settings CHUNK_SIZE = 512 MTU_SIZE = 517 BLE_PACKET_SZ = 512 # Image & MP3 mappings # User can change path on your image folder IMAGE_PATHS = { "welcome": r"D:\abhi\JPEG_Device_test\DQR222\BLE_Device\images\home.jpg", "success": r"D:\abhi\JPEG_Device_test\DQR222\BLE_Device\images\success.jpg", "pending": r"D:\abhi\JPEG_Device_test\DQR222\BLE_Device\images\pending.jpg", "cancelled": r"D:\abhi\JPEG_Device_test\DQR222\BLE_Device\images\cancelled.jpg", "fail": r"D:\abhi\JPEG_Device_test\DQR222\BLE_Device\images\fail.jpg", "background":r"D:\abhi\JPEG_Device_test\DQR222\BLE_Device\images\background.jpg", } # When you send an image named X, play X.mp3 (for QR use displayqr.mp3) MP3_MAP = { "welcome": "welcome.mp3", "success": "success.mp3", "pending": "pending.mp3", "cancelled": "cancel.mp3", "fail": "fail.mp3", "background":"displayqr.mp3", } async def find_device(): print("🔍 Scanning for ESP32 BLE…") devices = await BleakScanner.discover() for d in devices: if d.name and DEVICE_NAME in d.name: print(f"✅ Found {d.name} [{d.address}]") return d.address print("❌ Device not found") return None def download_image(name): path = IMAGE_PATHS.get(name) if not path or not os.path.isfile(path): raise FileNotFoundError(f"Image for '{name}' not found at {path}") return Image.open(path) def make_background_with_qr(text, amount): bg = download_image("background").convert("RGB") draw = ImageDraw.Draw(bg) font = ImageFont.truetype("arial.ttf", 42) amt = f"₹ {amount}" w, h = draw.textbbox((0,0), amt, font=font)[2:] x = (bg.width - w)//2; y = 80 draw.text((x,y), amt, fill="black", font=font) qr_str = text # exclude amount from QR qr = qrcode.make(qr_str).resize((320,320)) bg.paste(qr, ((bg.width-320)//2, y+h+20)) return bg async def send_file_ram(client, img): buf = io.BytesIO() img.save(buf, format="JPEG") data = buf.getvalue() size = len(data) print(f"📁 Sending image of size {size} bytes") cmd = f"ssf image.jpg {size}\n" await client.write_gatt_char(WRITE_UUID, cmd.encode(), response=True) await asyncio.sleep(0.5) sent = 0 while sent < size: chunk = data[sent:sent+CHUNK_SIZE] for i in range(0, len(chunk), BLE_PACKET_SZ): await client.write_gatt_char(WRITE_UUID, chunk[i:i+BLE_PACKET_SZ], response=False) await asyncio.sleep(0) sent += len(chunk) print(f"📤 {sent}/{size} bytes ({sent/size*100:.1f}%)") print("✅ Image transmission complete!") async def send_rotation(client): await asyncio.sleep(10) print("▶️ Sending command: startrotation") await client.write_gatt_char(WRITE_UUID, b"startrotation\n", response=True) print("✅ Rotation started") async def play_mp3(client, mp3_filename): # simply ask the device to play the known mp3 file print(f"▶️ Playing MP3: {mp3_filename}") await client.write_gatt_char(WRITE_UUID, f"play**{mp3_filename}\n".encode(), response=True) await asyncio.sleep(1) async def ble_console(): addr = await find_device() if not addr: return async with BleakClient(addr) as client: print("🔗 Connected. Starting notifications…") await client.start_notify(NOTIFY_UUID, lambda s, d: print("🔔", d.decode(errors='ignore').strip())) await asyncio.sleep(1) while True: print("\n📋 Choose an action:") print(" 1. Home image") print(" 2. Success image") print(" 3. Generate & upload BACKGROUND + QR") print(" 4. Pending image") print(" 5. Cancelled image") print(" 6. Fail image") print(" 0. Exit") choice = input("Enter choice [0–6]: ").strip() if choice == "0": break static_map = { "1":"welcome", "2":"success", "4":"pending", "5":"cancelled", "6":"fail" } if choice in static_map: key = static_map[choice] img = download_image(key) await send_file_ram(client, img) await asyncio.sleep(1) await play_mp3(client, MP3_MAP[key]) await send_rotation(client) elif choice == "3": text = input("Enter string for QR: ") amount = input("Enter amount: ") img = make_background_with_qr(text, amount) # for the QR background we use 'background' key await send_file_ram(client, img) await asyncio.sleep(1) await play_mp3(client, MP3_MAP["background"]) else: print("❗ Invalid choice; please enter 0–6.") await client.stop_notify(NOTIFY_UUID) print("🔌 Disconnected.") if __name__ == "__main__": asyncio.run(ble_console())