0

this question is a continuation of the previous one on "How to read a string from a file and advertise as a beacon?". Link here: How to read a string from a file and advertise as a beacon?

Based on the solution shared there, I have come this far where a string stored in a file is being read and converted to bytes (for beacon advertising) and saved in a file. I tried the example given and things worked fine, I can advertise the message. However I can't advertise my own string (30 character long) and received an error message below. Where did I go wrong?

Output:

enter image description here

My code snippet for reading string and converting to bytes:

# ------------- for string processing ------------------ #

# Opening JSON file 
string_path = r'/home/pi/Desktop/string.json'

with open(string_path) as f:
    for jsonObj in f:
        string = json.loads(jsonObj)

        print("Opened string file: {}".format(string))
        string_str = string['String']
        print("String is:", string_str, type(string_str))   # string stored in variable uuid
        #print(type(string_str))

# convert string_str string to bytes
byte_list = []
for byte in string_str:
    byte_list.append(ord(byte))
print('String in bytes:', byte_list)


# assign a key to a list of byte values
byte_dict = dict()
byte_dict.setdefault('beacon_uuid', byte_list)   # beacon_uuid is the name of a key
print("String in bytes dictionary:", byte_dict)
print(type(byte_dict))


# write byte_dict to json
# ref: https://stackabuse.com/reading-and-writing-lists-to-a-file-in-python/
with open('beacon_string.json', 'w') as filehandle:
    #json.dump(byte_dict, filehandle)
    filehandle.write(json.dumps(byte_dict))
print("String bytes dictionary in beacon_string.json file has been generated")


# access bytes in json file
here = Path(__file__).parent
data_file = here.joinpath('beacon_string.json')
with data_file.open() as f:
    data = json.load(f)

#print('Json data:', data['beacon_uuid'], type(data['beacon_uuid']))


# --------------- End of string processing ---------------- #

and below is code snippet for advertising:

class TestAdvertisement(Advertisement):
    
    # advertising an ibeacon
    def __init__(self, bus, index):
        company_id =   0x004C
        beacon_type = [0x02, 0x15]
        beacon_uuid = data['beacon_uuid']
        #print(type(beacon_uuid[3]))
        # uuid =        [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
        #                0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16]
        # check = uuid[0]
        # print("uuid data type is:", type(check))

        major =       [0x11, 0x22]
        minor =       [0x33, 0x44]
        tx_power =    [0xB3]
        Advertisement.__init__(self, bus, index, 'peripheral')
        self.add_manufacturer_data(company_id, beacon_type + beacon_uuid + major + minor + tx_power)

My string: {"String":"helloworldiamrighthere12367"}

enter image description here

help is much appreciated!

3
  • Can you post the contents of the file /home/pi/Desktop/string.json as the error message is with trying to read that file. – ukBaz Oct 5 '20 at 5:50
  • 2
    @Milliways, I don't think this is a duplicate. The other question was too big and covered the whole project. This is a more focused question about reading json. I think this question has the wrong tags, but is easier to answer because it is more focused than the previous one. Just my 2 cents worth... – ukBaz Oct 5 '20 at 6:21
  • @ukBaz, appreciate the clarification. i've edited my question and added the string. what tags should i use for this qn btw ? – snowmanolaf Oct 5 '20 at 10:51
1

There are only 26 bytes available in advertising data. 2 bytes are used for the company ID. That leaves 24 bytes for data. enter image description here

When I try to use an advertisement that is too long I get the following error message:

Failed to register advertisement: org.bluez.Error.Failed: Failed to parse advertisement.

As an aside, there are more efficient ways to go from the string data in your file to bytes to send via the advertisement. Below is a function called data_from_file that returns the String value in your example file as bytes:

from pathlib import Path
import json


def data_from_file(data_file):
    with data_file.open() as f:
        data = json.loads(f.read())
    return [ord(letter) for letter in data['String']]

if __name__ == '__main__':
    string_data = Path(__file__).parent.joinpath('string.json')
    print(data_from_file(string_data))

This gives the output:

$ python3 read_json.py 
[104, 101, 108, 108, 111, 119, 111, 114, 108, 100, 105, 97, 109, 114, 105, 103, 104, 116, 104, 101, 114, 101, 49, 50, 51, 54, 55]
4
  • Ive also tried the bluetooth obex method to send the string file as object but the limitation is that i have to map the 2nd pi MAC address in the code. I don't prefer this as i am binding the 2nd pi to the 1st one. I'd like the 1st pi to broadcast its string so that any other pi can read and store that string for future use – snowmanolaf Oct 6 '20 at 1:41
  • Thanks! Now I am clear on the part where my string is too long to be advertised as the beacon max. length is only 24 bytes. How do I approach this if i still want to broadcast this long string as a beacon and make it readable by another bluetooth device? – snowmanolaf Oct 6 '20 at 1:46
  • @snowmanolaf: If your initial question has been answered & accepted by yourself, the protocol here is to mark that answer as accepted and upvote it. If you have follow-on questions along the same lines, you are also encouraged to submit those as new questions. The cost to you for asking two questions (or even 20) is the same as for one question :) – Seamus Mar 4 at 21:16
  • I tried but the score wont be displayed publicly as my reputation was less than 15 – snowmanolaf Mar 5 at 2:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.