Is it possible to use LoPy as BLE GATT_Server and GATT_Client at the same time?



  • Hi,
    I'm working on a Farm Net project that tracking cows and build up their "social graph" for further research. I decided to use LoPy+Pytrack as the tracking and communication device for each cow. But right now I have one question about BLE module of LoPy:
    Can I use LoPy as BLE GATT_Server and GATT_Client at the same time?
    So the LoPy could advertise its device_id and also get the device_id from other LoPy, in this way I could build up a "social graph" for each cow.
    Is it possible?
    Because right now I have tested BLE communication between two LoPy, and each as GATT server and client at the same timeby merging the example code. The problem is when one node is connected to another one, the role of each device won't change anymore. The codes are shown below:

    1. Server code:
    #Global variables used in this file
    BLEConnectionCounter = 0 # count the connection by clients
    
    ################ BLE & LoRa Node ################
    # This node will act as both BLE client and a   # 
    # LoRa node device                              #
    #################################################
    ###### First, set up BLE server service ######
    def BLEServer():
        pycom.heartbeat(False)
        bluetooth = Bluetooth() #create a bluetooth object
        bluetooth.set_advertisement(name='LoPyServer'+str(globalvar.device_id), service_uuid=b'3333333333333333')  
        #using callback conn_cb to check client's connection
        ##Function:   conn_cb(callback for bluetooth object events checking)
        ##Description:check there is any client connected to the service
        def conn_cb (bt_o):
            events = bt_o.events()#using events to check if there is any client connected to the service      
            if  events & Bluetooth.CLIENT_CONNECTED:#2
                print("Client connected")
                pycom.rgbled(0x007f00) # green
            elif events & Bluetooth.CLIENT_DISCONNECTED:#4
                bt_o.disconnect_client()# in this way other client will have the chance to connect?
                print("Client disconnected")
                pycom.rgbled(0x7f0000) # red    
                time.sleep(3)       
        bluetooth.callback(trigger=Bluetooth.CLIENT_CONNECTED | Bluetooth.CLIENT_DISCONNECTED, handler=conn_cb)
        bluetooth.advertise(True)
        #set up BLE service
        srv1 = bluetooth.service(uuid=b'3333333333333333', isprimary=True)
        #set up service character
        chr1 = srv1.characteristic(uuid=b'3333333333333333', properties = Bluetooth.PROP_READ | Bluetooth.PROP_WRITE,value=5)
        def char1_cb_handler(chr):
            global BLEConnectionCounter
            events = chr.events()
            print('events is '+str(events))
            if  events & Bluetooth.CHAR_WRITE_EVENT:#16
                print("Write request with value = {}".format(chr.value()))
            elif events & Bluetooth.CHAR_READ_EVENT:#8
                #modify here to send its device_id to other clients
                BLEConnectionCounter += 1
                return str(globalvar.device_id)+' '+str(BLEConnectionCounter)
        #using the callback to send the data to other clients
        chr1.callback(trigger=Bluetooth.CHAR_WRITE_EVENT | Bluetooth.CHAR_READ_EVENT, handler=char1_cb_handler)
    
    1. Client code:
    ###### Second, initialize as one LoRa node device and BLE client ######
    def BLEClient():   
        ######  set up BLE client service ######
        bluetooth_client = Bluetooth()
        #bluetooth_client.init(id=0, mode=Bluetooth.BLE, antenna=None)
        bluetooth_client.start_scan(10)
        #server_name1 = bluetooth_client.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL) 
        counter = 50
        #while True:
        while counter > 0:
            print(counter)
            counter -= 1
            #Gets an named tuple with the advertisement data received during the scanning. 
            #The structure is (mac, addr_type, adv_type, rssi, data)
            adv = bluetooth_client.get_adv()
            #if get a valid advertisement from one server
            if adv:
                server_name = bluetooth_client.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL)
                if checkValidServer(server_name):
                    try:
                        #Opens a BLE connection with the device specified by the mac_addr argument
                        conn = bluetooth_client.connect(adv.mac)
                        services = conn.services()        
                        #Yunwei - it seems that only when the type of uuid is bytes then could read the data from server
                        for service in services:
                            time.sleep(0.050)
                            if type(service.uuid()) == bytes:
                                chars = service.characteristics()
                                for char in chars:                               
                                    print('char properties is '+str(properties))
                                    if (char.properties() & Bluetooth.PROP_READ):
                                        print('char {} value = {}'.format(char.uuid(), char.read()))                   
                                        #Use LoRa to send the data out
                                        #s.send(char.read())
                                        time.sleep(2)                            
                                    if (char.properties() & Bluetooth.PROP_WRITE):
                                        print('write to server!')
                                        char.write(b'x02')
                                        time.sleep(2)
                        #Yunwei
    					#Give other clients the chance to connect
                        conn.disconnect()
                        time.sleep(3)
                        bluetooth_client.start_scan(10)
                        print('connected?',conn.isconnected())
                        time.sleep(3)                   
                    except:
                        print("Error while connecting or reading from the BLE device")
                        time.sleep(1)
                        if(bluetooth_client.isscanning()):
                            bluetooth_client.stop_scan()
                            bluetooth_client.deinit()
                            time.sleep(1)
                            bluetooth_client.init()
                            time.sleep(1)
                            bluetooth_client.start_scan(10)
                        else:
                            bluetooth_client.deinit()
                            time.sleep(1)
                            bluetooth_client.init()
                            time.sleep(1)
                            bluetooth_client.start_scan(10)
                        print('Scan again')
            else:
                print('adv is None!')
                time.sleep(3)
    
        bluetooth_client.stop_scan()
        bluetooth_client.deinit()
        print('out of loop!')
    

    The firmware version is:
    sysname='LoPy', nodename='LoPy', release='1.17.5.b6', version='v1.8.6-849-56d00234 on 2018-05-18', machine='LoPy with ESP32', lorawan='1.0.2'

    Hope you guys could help me!


 

Pycom on Twitter