From 2a283546a00d0e9c83653a92fbdac74343071ad6 Mon Sep 17 00:00:00 2001 From: Abdallah Abdelazim Date: Wed, 22 Jun 2022 21:20:37 +0200 Subject: [PATCH 1/9] Add python shebang line --- main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/main.py b/main.py index a6b2e4f..eedf494 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 from bleak import discover from asyncio import new_event_loop, set_event_loop, get_event_loop from time import sleep, time_ns From 2e09948af153dfbf7d26d4445d8d8552c376ff07 Mon Sep 17 00:00:00 2001 From: Abdallah Abdelazim Date: Wed, 22 Jun 2022 21:22:24 +0200 Subject: [PATCH 2/9] Fix deprecation warning on Python newer than v3.6 --- main.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/main.py b/main.py index eedf494..fe15c07 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,8 @@ from json import dumps from sys import argv from datetime import datetime +import sys +import asyncio # Configure update duration (update after n seconds) UPDATE_DURATION = 1 @@ -55,11 +57,14 @@ async def get_device(): # Same as get_device() but it's standalone method instead of async def get_data_hex(): - new_loop = new_event_loop() - set_event_loop(new_loop) - loop = get_event_loop() - a = loop.run_until_complete(get_device()) - loop.close() + if sys.version_info < (3, 7): + new_loop = new_event_loop() + set_event_loop(new_loop) + loop = get_event_loop() + a = loop.run_until_complete(get_device()) + loop.close() + else: + a = asyncio.run(get_device()) return a From 2446422d783e7d5c5d6f7b72d327db455032ec0a Mon Sep 17 00:00:00 2001 From: Abdallah Abdelazim Date: Wed, 22 Jun 2022 21:24:39 +0200 Subject: [PATCH 3/9] Support breaking of loop with CTRL-C with no exceptions --- main.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/main.py b/main.py index fe15c07..e79d566 100644 --- a/main.py +++ b/main.py @@ -134,19 +134,22 @@ def is_flipped(raw): def run(): output_file = argv[-1] - while True: - data = get_data() - - if data["status"] == 1: - json_data = dumps(data) - if len(argv) > 1: - f = open(output_file, "a") - f.write(json_data+"\n") - f.close() - else: - print(json_data) - - sleep(UPDATE_DURATION) + try: + while True: + data = get_data() + + if data["status"] == 1: + json_data = dumps(data) + if len(argv) > 1: + f = open(output_file, "a") + f.write(json_data+"\n") + f.close() + else: + print(json_data) + + sleep(UPDATE_DURATION) + except KeyboardInterrupt: + pass if __name__ == '__main__': From 2d31eda7a8f9ab501d4b7fdde68bbff2c2e461be Mon Sep 17 00:00:00 2001 From: Abdallah Abdelazim Date: Wed, 22 Jun 2022 21:31:01 +0200 Subject: [PATCH 4/9] Add execute permission to --- main.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 main.py diff --git a/main.py b/main.py old mode 100644 new mode 100755 From 6d37599a23ed221760a18691791138713418fbb1 Mon Sep 17 00:00:00 2001 From: Abdallah Abdelazim Date: Wed, 22 Jun 2022 21:51:33 +0200 Subject: [PATCH 5/9] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a7a2a95..ac9ae02 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # **AirStatus for Linux** #### Check your AirPods battery level on Linux -#### What is it? +### What is it? This is a Python 3.6 script, forked from [faglo/AirStatus](https://github.com/faglo/AirStatus) that allows you to check AirPods battery level from your terminal, as JSON output. ### Usage @@ -12,6 +12,8 @@ python3 main.py [output_file] Output will be stored in `output_file` if specified. +This script requires `bleak` package. Install it with: `pip3 install bleak`. + #### Example output ``` From 02f9d732f133f45fd84dc3187a6964b1e8a4dd60 Mon Sep 17 00:00:00 2001 From: Andrey Korotkiy Date: Mon, 7 Aug 2023 01:28:43 +0300 Subject: [PATCH 6/9] fix time_ns import error --- main.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index 438420d..1dc9f0e 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,6 @@ from bleak import discover from asyncio import new_event_loop, set_event_loop, get_event_loop -from time import sleep, time_ns +from time import sleep from binascii import hexlify from json import dumps from sys import argv @@ -17,6 +17,15 @@ def get_best_result(device): + try: + from time import time_ns + except ImportError: + from datetime import datetime + + def time_ns(): + now = datetime.now() + return int(now.timestamp() * 1e9) + recent_beacons.append({ "time": time_ns(), "device": device From dc46c1999e397e8d0adeebd6fb1bc50b7de80876 Mon Sep 17 00:00:00 2001 From: blackbunt Date: Tue, 24 Jan 2023 18:25:00 +0100 Subject: [PATCH 7/9] Add model recognition for AirPods Pro 2 --- main.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.py b/main.py index e442266..5e8c9d6 100755 --- a/main.py +++ b/main.py @@ -99,6 +99,8 @@ def get_data(): model = "AirPods1" elif chr(raw[7]) == 'a': model = "AirPodsMax" + elif chr(raw[7]) == '4': + model = "AirPodsPro2" else: model = "unknown" From 552c76fa88da28c7314cdf915bbac1732d94663e Mon Sep 17 00:00:00 2001 From: Ricky Cheung Date: Wed, 15 May 2024 16:18:37 +0800 Subject: [PATCH 8/9] Add support for Bleak version >=0.21 * Fixed deprecated warnings --- main.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/main.py b/main.py index 5e8c9d6..7d5ef37 100755 --- a/main.py +++ b/main.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -from bleak import discover +from bleak import BleakScanner from asyncio import new_event_loop, set_event_loop, get_event_loop from time import sleep from binascii import hexlify @@ -19,7 +19,7 @@ recent_beacons = [] -def get_best_result(device): +def get_best_result(device, adv_data): try: from time import time_ns except ImportError: @@ -28,37 +28,39 @@ def get_best_result(device): def time_ns(): now = datetime.now() return int(now.timestamp() * 1e9) - - recent_beacons.append({ + + current_beacon = { "time": time_ns(), - "device": device - }) + "device": device, + "adv_data": adv_data + } + recent_beacons.append(current_beacon) strongest_beacon = None i = 0 while i < len(recent_beacons): if(time_ns() - recent_beacons[i]["time"] > RECENT_BEACONS_MAX_T_NS): recent_beacons.pop(i) continue - if (strongest_beacon == None or strongest_beacon.rssi < recent_beacons[i]["device"].rssi): - strongest_beacon = recent_beacons[i]["device"] + if (strongest_beacon == None or strongest_beacon["adv_data"].rssi < recent_beacons[i]["adv_data"].rssi): + strongest_beacon = recent_beacons[i] i += 1 - if (strongest_beacon != None and strongest_beacon.address == device.address): - strongest_beacon = device + if (strongest_beacon != None and strongest_beacon["device"].address == device.address): + strongest_beacon = current_beacon - return strongest_beacon + return strongest_beacon["adv_data"] # Getting data with hex format async def get_device(): # Scanning for devices - devices = await discover() - for d in devices: + discovered_devices_and_advertisement_data = await BleakScanner.discover(return_adv=True) + for device, adv_data in discovered_devices_and_advertisement_data.values(): # Checking for AirPods - d = get_best_result(d) - if d.rssi >= MIN_RSSI and AIRPODS_MANUFACTURER in d.metadata['manufacturer_data']: - data_hex = hexlify(bytearray(d.metadata['manufacturer_data'][AIRPODS_MANUFACTURER])) - data_length = len(hexlify(bytearray(d.metadata['manufacturer_data'][AIRPODS_MANUFACTURER]))) + adv_data = get_best_result(device, adv_data) + if adv_data.rssi >= MIN_RSSI and AIRPODS_MANUFACTURER in adv_data.manufacturer_data: + data_hex = hexlify(bytearray(adv_data.manufacturer_data[AIRPODS_MANUFACTURER])) + data_length = len(hexlify(bytearray(adv_data.manufacturer_data[AIRPODS_MANUFACTURER]))) if data_length == AIRPODS_DATA_LENGTH: return data_hex return False From e20b82084f338f8139a227ee3010865f2690edd5 Mon Sep 17 00:00:00 2001 From: Ricky Cheung Date: Wed, 15 May 2024 17:24:57 +0800 Subject: [PATCH 9/9] Revert "Update README.md" * Use requirements.txt instead This reverts commit 6d37599a23ed221760a18691791138713418fbb1. --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index ac9ae02..a7a2a95 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # **AirStatus for Linux** #### Check your AirPods battery level on Linux -### What is it? +#### What is it? This is a Python 3.6 script, forked from [faglo/AirStatus](https://github.com/faglo/AirStatus) that allows you to check AirPods battery level from your terminal, as JSON output. ### Usage @@ -12,8 +12,6 @@ python3 main.py [output_file] Output will be stored in `output_file` if specified. -This script requires `bleak` package. Install it with: `pip3 install bleak`. - #### Example output ```