omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Using cb library to connect simultaneously multiple TI SensorTag via Bluetooth Low Energy

    Pythonista
    4
    37
    20346
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ccc
      ccc last edited by ccc

      This is exactly what I anticipated that you would find... All these devices share a common name but each one has a unique UUID.

      import cb
      
      
      class MultipleCC2650Manager(object):
          name = 'CC2650 SensorTag'  # we only care about devices with this name
      
          def __init__(self):
              self.devices = {}  # dict of peripheral uuids and peripheral objects
      
          def did_discover_peripheral(self, p):
              if p.name != self.name:
                  return  # ignore devices do not have the name 'CC2650 SensorTag'
              if p.uuid in self.devices:
                  return  # ignore devices that we have already discovered/registered
              self.devices[p.uuid] = p
              print(f'Connecting to a new device: {p.uuid}...')
              cb.connect_peripheral(p)
              print(f'{len(self.devices)} unique {self.name} devices')
      
          def connect_to_device(self, device_uuid):
              cb.connect_peripheral(self.devices[device_uuid])
      
      ProgrammingGo 1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by

        One thing you have to watch out for is that if you are trying to do notify in characteristics, the callbacks dont tell you whch peripheral it came from. That is a major shortcoming in my mind of the cb implementation. You might be better off going to an objc_util based solution

        ProgrammingGo 1 Reply Last reply Reply Quote 0
        • ProgrammingGo
          ProgrammingGo @ccc last edited by ProgrammingGo

          @ccc Yeah thanks a lot. I understood it very well with your example. Thank you so much. So I need to work with the uuid of the devices. A question regarding the example given : you call cb.connect_peripheral(p) in did_discover_peripheral and then in def connect_to_device again,why?

          delegate = MyCentralManagerDelegate()
          print('Scanning for peripherals...')
          cb.set_central_delegate(delegate)
          cb.scan_for_peripherals()
          
          # Keep the connection alive until the 'Stop' button is pressed:
          try:
              while True: pass
          except KeyboardInterrupt:
              # Disconnect everything:
              cb.reset()
          

          This part is still needed right?

          1 Reply Last reply Reply Quote 0
          • ProgrammingGo
            ProgrammingGo @JonB last edited by

            @JonB Ok thank you for your hint

            1 Reply Last reply Reply Quote 0
            • ccc
              ccc last edited by ccc

              did_discover_peripheral() will always leave you connected to the last device that it discovered. So when you want to chose which device that you want to connect to, you call connect_to_device().

              ProgrammingGo 1 Reply Last reply Reply Quote 0
              • ProgrammingGo
                ProgrammingGo @ccc last edited by ProgrammingGo

                @ccc Hi sorry for the question I am a bit confused. It is not clear to me how do you mean that :(. Can you explain it may be again? My target is to be connected to 3 SensorTags at the same time to receive data.

                1 Reply Last reply Reply Quote 0
                • ccc
                  ccc last edited by

                  Let's say that you have 3 CC2650 SensorTags and their UUIDs are 0, 1, 2... Getting data would be:

                  data = []  # empty list
                  for device_uuid in (0, 1, 2):
                      cc2650_manager.connect_to_device(device_uuid)
                      data.append(get_data())
                  print(data)
                  

                  You can only talk to one device at a time but you can loop thru all the devices and call connect_to_device() and then get the data from that device.

                  ProgrammingGo 1 Reply Last reply Reply Quote 0
                  • ccc
                    ccc last edited by

                    Do you have GitHub, GitLab, or BitBucket? It would probably be easier to collaborate on a repo.

                    1 Reply Last reply Reply Quote 0
                    • ProgrammingGo
                      ProgrammingGo @ccc last edited by ProgrammingGo

                      @ccc Ok that means I am using a loop to read node by node. But for me, it is not so clear how to use connect_to_periphera to connect to the next. - How can I call it? For my understanding normally at first, I would call connect_to_peripheral and then did_discover_peripheral.
                      I gave a look in the example given for SensorTag and calling the callback functions is a bit different ---> it happens inside the cb lib.

                      No Iam not using GitHub or the other tools.

                      1 Reply Last reply Reply Quote 0
                      • JonB
                        JonB last edited by

                        You can connect to each device once, as long as you hang into references to the peripheral object and Characteristic.

                        The trick is then keeping track of the reads, since did_update_value does not include the peripheral, so you cannot tell which is which.

                        so pseudo code would be:

                        1. discover devices
                        2. connect to devices, storing peripheral in a list or dict
                        3. discover service/characteristic, and store the characteristic
                        4. once you have a characteristic, i would have a loop that pools:
                        for p in peripherals:
                           current_p=p (store as a global)
                           p.read_characteristic_value(C)
                           (sleep for a while p, or use threading Event etc to await did_update_value)
                        

                        in did_update_value, check current_p to get uuid, then store the read value somewhere, print it out, whatever, and set the Event flag to awake the main loop

                        ProgrammingGo 3 Replies Last reply Reply Quote 0
                        • ProgrammingGo
                          ProgrammingGo @JonB last edited by ProgrammingGo

                          @JonB Hi thanks for the nice description: I tried to work with the structure of the given example for the sensortag Example and try it out to adapt it. But Iam getting stuck. Iam not able to read out the data from all 3 sensortags. When I try to register for characteristics nothing worked. I tried several things out but without success.

                          1 Reply Last reply Reply Quote 0
                          • ProgrammingGo
                            ProgrammingGo @JonB last edited by ProgrammingGo

                            @JonB said:

                            You can connect to each device once, as long as you hang into references to the peripheral object and Characteristic.

                            The trick is then keeping track of the reads, since did_update_value does not include the peripheral, so you cannot tell which is which.

                            so pseudo code would be:

                            1. discover devices
                            2. connect to devices, storing peripheral in a list or dict
                            3. discover service/characteristic, and store the characteristic
                            4. once you have a characteristic, i would have a loop that pools:
                            for p in peripherals:
                               current_p=p (store as a global)
                               p.read_characteristic_value(C)
                               (sleep for a while p, or use threading Event etc to await did_update_value)
                            

                            in did_update_value, check current_p to get uuid, then store the read value somewhere, print it out, whatever, and set the Event flag to awake the main loop

                            The steps from the pseudo code are understandable but do you mean storing the discovered peripherals in a list and use a for loop to connect one by one and read the data or do you mean connect to all and use a for loop to read out the data of one device per time`?

                            1 Reply Last reply Reply Quote 0
                            • JonB
                              JonB last edited by

                              https://gist.github.com/f734504daa44d0cb0621ba47c2caabb0
                              Here is a working example which:
                              tries to connects to every peripheral discovered
                              discovers all characteristics of all services found
                              polls all characteristics every 6 seconds, and displays the results

                              type stop() to stop the polling. then you can access peripherals via
                              m[uuid] or m[index]. the cb.peripheral is in the peripheral field.

                              i.e
                              m[0].peripheral.read_characteristic_value(m[0]['180A']['2A24'].characteristic)

                              print(m[0]['180A']['2A24'].characteristic)

                              or, use m.update_all() to poll all characteristics, and print(m) to show them all.

                              1 Reply Last reply Reply Quote 0
                              • JonB
                                JonB last edited by

                                what i have found is that you can indeed connect to multiple peripherals. but sometimes cb decides to disconnect. or sometimes decides not to discover a peripheral at all. cb.reset() can help, but things just seem really flaky, and a pythonista reset might be better. for instance, it seems like if a connection fails enough times, it is hidden from the app and wont be discovered again.

                                1 Reply Last reply Reply Quote 0
                                • ProgrammingGo
                                  ProgrammingGo @JonB last edited by ProgrammingGo

                                  @JonB said:

                                  You can connect to each device once, as long as you hang into references to the peripheral object and Characteristic.

                                  The trick is then keeping track of the reads, since did_update_value does not include the peripheral, so you cannot tell which is which.

                                  so pseudo code would be:

                                  1. discover devices
                                  2. connect to devices, storing peripheral in a list or dict
                                  3. discover service/characteristic, and store the characteristic
                                  4. once you have a characteristic, i would have a loop that pools:
                                  for p in peripherals:
                                     current_p=p (store as a global)
                                     p.read_characteristic_value(C)
                                     (sleep for a while p, or use threading Event etc to await did_update_value)
                                  

                                  in did_update_value, check current_p to get uuid, then store the read value somewhere, print it out, whatever, and set the Event flag to awake the main loop

                                  Hi JonB thanks a lot for your last reply with the nice example. I wanted to ask regarding the above-quoted idea. Till step 2 it is okay. So I stored a list with all the peripherals objects, In step 3 when I am discovering the services and then the characteristics you wrote that I should store the characteristics and use the stated for loop. How does it help me when did_discover_characteristics (self, c, error) has no reference to the peripheral? Where do I need to use the for loop that you stated ? Is there maybe another way to get the new values without using did_update value?

                                  1 Reply Last reply Reply Quote 0
                                  • JonB
                                    JonB last edited by

                                    it is true that
                                    did_discover_characteristics(self,s,error):

                                    does not tell you what peripheral you are looking at. in my solution, i simply map the discovered characteristics to each peripheral with a matching service.

                                    Technically, that could be a problem if two peripherals have the same service but different characteristics. But if you have two of the same devices, i think it is not a problem, generally.

                                    To be truly accurate, you would have to take the approach that i take in update_all: namely, i
                                    set an instance variable indicating which peripheral that you are dealing with, call p.discover_characteristics(s), and so when did_discover_characteristics is called, you know which peripheral it is referring to. the tricky part is that you generally would discover_characteristics from within did_discover_services, and you don't necessarily want to block (like i do in update_all) inside one of those callbacks.

                                    probably what you might do is have a round where you discover peripherals, but only find and store them, do not discover services. when you have found the ones you want, you would then call out to a separate thread loop through and discover services/characteristics, using an Event to ensure that you do one at a time, the way i do in update_all and did_update__value

                                    1 Reply Last reply Reply Quote 0
                                    • ProgrammingGo
                                      ProgrammingGo last edited by

                                      Hi Jon oka<y thank you very much for the effort and nice explanation. I was quite curious and I found out that the Service and Charact. UUIDs can be changes in the firmware code of the Sensortag. Changing the UUID of the Service and Charac. for every node could be another approach as well. I checked it with BTool and it works. Problem is when I try to discover it via Pythonista on the iPhone it does not recognize the new UUID. I read that it helps to clear the Bluetooth cache, but in my case, it does not work cause I am discovering it via Pythonista and not directly via the iPhone 5. Do you know maybe something about that?

                                      1 Reply Last reply Reply Quote 0
                                      • First post
                                        Last post
                                      Powered by NodeBB Forums | Contributors