Created
January 11, 2018 02:25
-
-
Save timawesomeness/8e9eac54603aa54c320d7daff25cdd09 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
################################################################# | |
# Simple script to generate an Eddystone URL beacon as Bluetooth data readable by btmgmt | |
# | |
# To use: ./geneddystonebeacon.py [-p POWER] URL where POWER is an optional integer from -100 to 20 (per the Bluetooth spec) and | |
# URL is a URL including http(s):// to be broadcast by the beacon. Be aware that Physical Web (specifically Google Nearby) | |
# will not show the beacon unless you use https. | |
# | |
# To broadcast a beacon with that string: (as root) | |
# btmgmt add-adv -d INSERT-STRING-HERE 1 | |
# To stop broadcasting: (again, as root) | |
# btmgmt rm-adv 1 | |
################################################################# | |
import binascii, sys, argparse, re, struct | |
MAX_LENGTH = 31 | |
BLE_HEADER = "020106" # 02 = length, 01 = flags, 06 = discovery flag | |
EDDYSTONE_SERVICE_UUID = "0303AAFE" # 03 length, 03 = Complete List of 16-bit Service Class UUIDs, AAFE = reversed eddystone UUID | |
EDDYSTONE_DATA_UUID_URL = "16AAFE10" # 16 = service data, AAFE = reversed eddystone UUID, 10 = eddystone URL frame type | |
parser = argparse.ArgumentParser(description="Convert a URL (and optional TX power) into BLE beacon data compatible with Google's Eddystone format.") | |
parser.add_argument("url", metavar="URL", type=str, nargs=1, help="A URL, including http(s)://, with a max length of 18 characters.") | |
parser.add_argument("-p", "--power", type=int, help="Calibrated TX power at 0m (defaults to 0)", default=0, choices=range(-100, 21), metavar="POWER") | |
args = parser.parse_args() | |
if not re.fullmatch(r"https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)", args.url[0]): | |
print("Not a valid url with http(s)://") | |
sys.exit(1) | |
url_prefix = "" | |
url = "" | |
if args.url[0].startswith("http://www."): | |
url_prefix = "00" | |
url = args.url[0].split("http://www.", 2)[1] | |
elif args.url[0].startswith("https://www."): | |
url_prefix = "01" | |
url = args.url[0].split("https://www.", 2)[1] | |
elif args.url[0].startswith("http://"): | |
url_prefix = "02" | |
url = args.url[0].split("http://", 2)[1] | |
elif args.url[0].startswith("https://"): | |
url_prefix = "03" | |
url = args.url[0].split("https://", 2)[1] | |
url = url_prefix + binascii.hexlify(url.encode("ascii")).decode("ascii") | |
# because I hate everything | |
url = url.replace("2e636f6d2f", "00").replace("2e6f72672f", "01").replace("2e6564752f", "02").replace("2e6e65742f", "03").replace("2e696e666f2f", "04").replace("2e62697a2f", "05").replace("2e676f762f", "06") | |
url = url.replace("2e636f6d", "07").replace("2e6f7267", "08").replace("2e656475", "09").replace("2e6e6574", "0a").replace("2e696e666f", "0b").replace("2e62697a", "0c").replace("2e676f76", "0d") | |
power = bytearray(struct.pack("!b", args.power)).hex() # stupid hacky way of converting int to hex the way bluetooth wants it | |
eddystone_length = int((len(EDDYSTONE_DATA_UUID_URL) + len(power) + len(url)) / 2) | |
full_ble_data = BLE_HEADER + EDDYSTONE_SERVICE_UUID + "{:02x}".format(eddystone_length) + EDDYSTONE_DATA_UUID_URL + power + url | |
if int(len(full_ble_data) / 2) > MAX_LENGTH: | |
print("URL is too long.") | |
sys.exit(1) | |
print(full_ble_data.upper()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment