This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Best way to send data from many sensors

Hi,

For an application I have a nRF51 at my disposal and I need to transfer about 3'000Bytes. I found in the documentation that the nRF51 can use the S130 SoftDevice which support BLE 4.2. The data I have to transfer come from 1 to 50 sensors and are divided in 2 categories with 3 respective 6 parameters each as follow:

Sensor No1

  • Data type A
  • --Parameter A1
  • --Parameter A2
  • --Parameter A3
  • Data type B
  • --Parameter B1
  • --Parameter B2
  • --Parameter B3
  • --Parameter B4
  • --Parameter B5
  • --Parameter B6

Sensor No2

  • Data type A
  • --Parameter A1
  • --Parameter A2
  • --Parameter A3
  • Data type B
  • --Parameter B1
  • --Parameter B2
  • --Parameter B3
  • --Parameter B4
  • --Parameter B5
  • --Parameter B6

Sensor NoX

  • Data type A
  • --Parameter A1
  • --Parameter A2
  • --Parameter A3
  • Data type B
  • --Parameter B1
  • --Parameter B2
  • --Parameter B3
  • --Parameter B4
  • --Parameter B5
  • --Parameter B6

I thought that a way to transfer these results would be to use 2 customized services (a service for type A and a service for type B) with 3 respective 6 characteristics (A1-A3 and B1-B6) each. Each characteristic should have up to 50 values. The number of values in each characteristic would indicate the number of sensors.

Has someone a better / a more suitable solution for this use case?

Thanks in advance for you ideas.

Parents
  • Hi,

    Thanks endnode for your answer.

    I'm not sure that I understand what you mean correctly. The solution you propose uses 1 custom profile with 2 services and 1 characteristic each containing structured defined data as follow, is that right?

    Custom Profile

    • Service with data type A
    • --Characteristic A
    • -- --Protocol version 1
    • -- --Sensor No1 Parameter A1
    • -- --Sensor No1 Parameter A2
    • -- --Sensor No1 Parameter A3
    • -- --Sensor No2 Parameter A1
    • -- --Sensor No2 Parameter A2
    • -- --Sensor No2 Parameter A3
    • -- --Sensor NoX Parameter A1
    • -- --Sensor NoX Parameter A2
    • -- --Sensor NoX Parameter A3
    • Service with data type B
    • --Characteristic B
    • -- --Protocol version 1
    • -- --Sensor No1 Parameter B1
    • -- --Sensor No1 Parameter B2
    • -- --Sensor No1 Parameter B3
    • -- --Sensor No1 Parameter B4
    • -- --Sensor No1 Parameter B5
    • -- --Sensor No1 Parameter B6
    • -- --Sensor No2 Parameter B1
    • -- --Sensor No2 Parameter B2
    • -- --Sensor No2 Parameter B3
    • -- --Sensor No2 Parameter B4
    • -- --Sensor No2 Parameter B5
    • -- --Sensor No2 Parameter B6
    • -- --Sensor NoX Parameter B1
    • -- --Sensor NoX Parameter B2
    • -- --Sensor NoX Parameter B3
    • -- --Sensor NoX Parameter B4
    • -- --Sensor NoX Parameter B5
    • -- --Sensor NoX Parameter B6

    The Protocoll version would allow to change the content or the formating without changing anything else. Your proposition is indeed very interesting! Thank you!

    -------- UPDATE 24.05.2017

    Hi,

    Thanks endnode for your explanations.

    The solution you propose uses then only 1 custom profile with 1 services and 1 characteristic containing structured defined data as follow, is that right?

    Custom Profile

    • Service type A
    • --Characteristic A
    • -- --Protocol Header containing: protocol version XY (1B), data type (1B), size (1B), sensor number/status (1B)
    • -- --|Sensor No1 Parameter A1|
    • -- --|Sensor No1 Parameter A2|
    • -- --|Sensor No1 Parameter A3|
    • -- --|Sensor No1 Parameter B1|
    • -- --|Sensor No1 Parameter B2|
    • -- --|Sensor No1 Parameter B3|
    • -- --|Sensor No1 Parameter B4|
    • -- --|Sensor No1 Parameter B5|
    • -- --|Sensor No1 Parameter B6|
    • -- --|Sensor No2 Parameter A1|
    • -- --|Sensor No2 Parameter A2|
    • -- --|Sensor No2 Parameter A3|
    • -- --|Sensor No2 Parameter B1|
    • -- --|Sensor No2 Parameter B2|-- DATA
    • -- --|Sensor No2 Parameter B3|
    • -- --|Sensor No2 Parameter B4|
    • -- --|Sensor No2 Parameter B5|
    • -- --|Sensor No2 Parameter B6|
    • -- --|Sensor NoX Parameter A1|
    • -- --|Sensor NoX Parameter A2|
    • -- --|Sensor NoX Parameter A3|
    • -- --|Sensor NoX Parameter B1|
    • -- --|Sensor NoX Parameter B2|
    • -- --|Sensor NoX Parameter B3|
    • -- --|Sensor NoX Parameter B4|
    • -- --|Sensor NoX Parameter B5|
    • -- --|Sensor NoX Parameter B6|

    Yes I have indeed one GATT Server, so Notifications seems to be the appropriate way to solve this. Furthermore some of the sensor data are already available in the Server but some other data need to be requested and would be delayed, so using Notification shouldn't be a problem. Using the Notifications automatically activate the CCCD (Client Characteristic Configuration Descriptor -> Core Specification, Volume 3, Part G, section 3.3.3.3) in the Server (Slave) nRF51+S130 Stack which need to be activated by the Client (Master) in order to enable the notifications, right? Update : Using the Notifications automatically create the CCCD without activating it allowing the Client to write (0x0001) in the Server to enable the Notification.

    A) You mentioned that if the Client need to send data in the Server it should use Write without confirmation method. Do you mean to enable the Notification Characteristic or to write in the Server? Update : Client to Server transport through Write methods (two types) and from Server to Client through Notify/Indicate (async) methods (Read methods is kind of old-fashion "pull" model).

    B) You said that with the same Characteristic I can make the communication bi-directional. If the Client Write data in the Server in Characteristic A, will the Client received the data it just sent over Notify or these are two different memory regions? I though that if I want to offer the possibility that the Client can send data in the Server I will have to create a new Characteristic B which is writable with Normal Write, Write without response or Signed Write. It not true then. Update : In terms of "performance" of connection time and throughput the experience is suggesting to design single "tube" (or pair of Tx/Rx buffers) on top of some Characteristic Value and then define more condensed protocol with Write/Notify methods.

    C) In the Nordic Stack how are Notifications sent? I simply have to set a table, its length and call the function notify? What if the table length is bigger than one BLE packet? Update : The Notify method provides ATT_MTU-3 values with ATT_MTU equals 23 by default and can be negotiated once per connection to minimum from Server and Client max values.

    D) The solution you propose is to encapsulate "data"/"data stream" into BLE using only one Characteristic basically? Using Notify for Server -> Client communication and Write or Write without response for Client -> Server communication.

    E) For now I plan to have a header containing: protocol version XY (1B), data type (1B), size (1B), sensor number/status (1B) making 4Bytes overhead. Why do you mention 0-125B (1B is 0-255)? BLE 4.2 should be able to transfers up to 247B L2CAP Payload, so about 244B data.

    Yes I need a very scalable solution and your proposition seems indeed very flexible and interesting! Thank you very much for your help!

    -------- UPDATE 07.06.2017

    Hi,

    Thanks endnode for your explanations and rct42 for your comment.

    Finally I will start with the NUS (Nordic UART Service) example which uses one custom profile with two services (one for Write and one Notify) and I will implement my own data protocol inside as follow:

    Custom Profile

    • Service 1 (Notify)
    • --Characteristic 1
    • -- --Protocol version
    • -- --Header
    • -- --DATA Header - Sensor 1
    • -- --DATA Sensor 1
    • -- --DATA Header - Sensor 2
    • -- --DATA Sensor 2
    • -- --DATA Header - Sensor X
    • -- --DATA Sensor X
    • Service 2 (Write)
    • --Characteristic 1
    • -- --Protocol version
    • -- --Header
    • -- --DATA Header - Sensor 1
    • -- --DATA Sensor 1
    • -- --DATA Header - Sensor 2
    • -- --DATA Sensor 2
    • -- --DATA Header - Sensor X
    • -- --DATA Sensor X

    Thank you very much for your help!

Reply
  • Hi,

    Thanks endnode for your answer.

    I'm not sure that I understand what you mean correctly. The solution you propose uses 1 custom profile with 2 services and 1 characteristic each containing structured defined data as follow, is that right?

    Custom Profile

    • Service with data type A
    • --Characteristic A
    • -- --Protocol version 1
    • -- --Sensor No1 Parameter A1
    • -- --Sensor No1 Parameter A2
    • -- --Sensor No1 Parameter A3
    • -- --Sensor No2 Parameter A1
    • -- --Sensor No2 Parameter A2
    • -- --Sensor No2 Parameter A3
    • -- --Sensor NoX Parameter A1
    • -- --Sensor NoX Parameter A2
    • -- --Sensor NoX Parameter A3
    • Service with data type B
    • --Characteristic B
    • -- --Protocol version 1
    • -- --Sensor No1 Parameter B1
    • -- --Sensor No1 Parameter B2
    • -- --Sensor No1 Parameter B3
    • -- --Sensor No1 Parameter B4
    • -- --Sensor No1 Parameter B5
    • -- --Sensor No1 Parameter B6
    • -- --Sensor No2 Parameter B1
    • -- --Sensor No2 Parameter B2
    • -- --Sensor No2 Parameter B3
    • -- --Sensor No2 Parameter B4
    • -- --Sensor No2 Parameter B5
    • -- --Sensor No2 Parameter B6
    • -- --Sensor NoX Parameter B1
    • -- --Sensor NoX Parameter B2
    • -- --Sensor NoX Parameter B3
    • -- --Sensor NoX Parameter B4
    • -- --Sensor NoX Parameter B5
    • -- --Sensor NoX Parameter B6

    The Protocoll version would allow to change the content or the formating without changing anything else. Your proposition is indeed very interesting! Thank you!

    -------- UPDATE 24.05.2017

    Hi,

    Thanks endnode for your explanations.

    The solution you propose uses then only 1 custom profile with 1 services and 1 characteristic containing structured defined data as follow, is that right?

    Custom Profile

    • Service type A
    • --Characteristic A
    • -- --Protocol Header containing: protocol version XY (1B), data type (1B), size (1B), sensor number/status (1B)
    • -- --|Sensor No1 Parameter A1|
    • -- --|Sensor No1 Parameter A2|
    • -- --|Sensor No1 Parameter A3|
    • -- --|Sensor No1 Parameter B1|
    • -- --|Sensor No1 Parameter B2|
    • -- --|Sensor No1 Parameter B3|
    • -- --|Sensor No1 Parameter B4|
    • -- --|Sensor No1 Parameter B5|
    • -- --|Sensor No1 Parameter B6|
    • -- --|Sensor No2 Parameter A1|
    • -- --|Sensor No2 Parameter A2|
    • -- --|Sensor No2 Parameter A3|
    • -- --|Sensor No2 Parameter B1|
    • -- --|Sensor No2 Parameter B2|-- DATA
    • -- --|Sensor No2 Parameter B3|
    • -- --|Sensor No2 Parameter B4|
    • -- --|Sensor No2 Parameter B5|
    • -- --|Sensor No2 Parameter B6|
    • -- --|Sensor NoX Parameter A1|
    • -- --|Sensor NoX Parameter A2|
    • -- --|Sensor NoX Parameter A3|
    • -- --|Sensor NoX Parameter B1|
    • -- --|Sensor NoX Parameter B2|
    • -- --|Sensor NoX Parameter B3|
    • -- --|Sensor NoX Parameter B4|
    • -- --|Sensor NoX Parameter B5|
    • -- --|Sensor NoX Parameter B6|

    Yes I have indeed one GATT Server, so Notifications seems to be the appropriate way to solve this. Furthermore some of the sensor data are already available in the Server but some other data need to be requested and would be delayed, so using Notification shouldn't be a problem. Using the Notifications automatically activate the CCCD (Client Characteristic Configuration Descriptor -> Core Specification, Volume 3, Part G, section 3.3.3.3) in the Server (Slave) nRF51+S130 Stack which need to be activated by the Client (Master) in order to enable the notifications, right? Update : Using the Notifications automatically create the CCCD without activating it allowing the Client to write (0x0001) in the Server to enable the Notification.

    A) You mentioned that if the Client need to send data in the Server it should use Write without confirmation method. Do you mean to enable the Notification Characteristic or to write in the Server? Update : Client to Server transport through Write methods (two types) and from Server to Client through Notify/Indicate (async) methods (Read methods is kind of old-fashion "pull" model).

    B) You said that with the same Characteristic I can make the communication bi-directional. If the Client Write data in the Server in Characteristic A, will the Client received the data it just sent over Notify or these are two different memory regions? I though that if I want to offer the possibility that the Client can send data in the Server I will have to create a new Characteristic B which is writable with Normal Write, Write without response or Signed Write. It not true then. Update : In terms of "performance" of connection time and throughput the experience is suggesting to design single "tube" (or pair of Tx/Rx buffers) on top of some Characteristic Value and then define more condensed protocol with Write/Notify methods.

    C) In the Nordic Stack how are Notifications sent? I simply have to set a table, its length and call the function notify? What if the table length is bigger than one BLE packet? Update : The Notify method provides ATT_MTU-3 values with ATT_MTU equals 23 by default and can be negotiated once per connection to minimum from Server and Client max values.

    D) The solution you propose is to encapsulate "data"/"data stream" into BLE using only one Characteristic basically? Using Notify for Server -> Client communication and Write or Write without response for Client -> Server communication.

    E) For now I plan to have a header containing: protocol version XY (1B), data type (1B), size (1B), sensor number/status (1B) making 4Bytes overhead. Why do you mention 0-125B (1B is 0-255)? BLE 4.2 should be able to transfers up to 247B L2CAP Payload, so about 244B data.

    Yes I need a very scalable solution and your proposition seems indeed very flexible and interesting! Thank you very much for your help!

    -------- UPDATE 07.06.2017

    Hi,

    Thanks endnode for your explanations and rct42 for your comment.

    Finally I will start with the NUS (Nordic UART Service) example which uses one custom profile with two services (one for Write and one Notify) and I will implement my own data protocol inside as follow:

    Custom Profile

    • Service 1 (Notify)
    • --Characteristic 1
    • -- --Protocol version
    • -- --Header
    • -- --DATA Header - Sensor 1
    • -- --DATA Sensor 1
    • -- --DATA Header - Sensor 2
    • -- --DATA Sensor 2
    • -- --DATA Header - Sensor X
    • -- --DATA Sensor X
    • Service 2 (Write)
    • --Characteristic 1
    • -- --Protocol version
    • -- --Header
    • -- --DATA Header - Sensor 1
    • -- --DATA Sensor 1
    • -- --DATA Header - Sensor 2
    • -- --DATA Sensor 2
    • -- --DATA Header - Sensor X
    • -- --DATA Sensor X

    Thank you very much for your help!

Children
  • No. Profile is set of GATT and GAP rules. So I propose to define your profile with one Service, that contains one Characteristic. If you only need to transmit the data from that GATT Server then you allow Notification method on that Characteristic (which will create automatically CCCD handle attached to it on the stack), if you need to transport data from GATT Client side then you will use Write without confirmation method. If you need bi-directional communication you combine it, still single Service with single Characteristic is enough. And now on top of Value handle of that Characteristic you play with your protocol: that side which has the sensors and transmits data simply reads the sensor data, encapsulate them with some TAG and Length envelopes and transmit. On the receiver side you can see (by pre-defined TAGs) which data value belongs to which sensor.

  • Your proposal is like for 60 sensors to design 60 different URLs on the server instead of single page which displays everything. The principles of GATT Server/Client are pretty similar to any other Server/Client architecture you know from other technologies.

  • Then for "protocol" version: you simply allocate some TAGs in your first protocol version, is formatting of the content of particular TLV object is to be changed in any next version you can simply define new TAG and its formatting. If you arrive to device which supports newer version (= will send TLVs with new TAGs) and older version (= won't understand these TAGs) then receiver simply ignores any TLV which has unknown TAG.

  • Btw. I'm still assuming these sensor numbers have some significance in your architecture but I might be wrong;) So in very general protocol you can only define certain data object which will have 3 sub-objects:

    1. What is the sensor number encapsulated in this object
    2. What type of sensor data this is (needs to be known to receiver to decode them of course)
    3. Sensor data itself (whatever length you need, previous item should fully describe the format).

    Now it depends how scalable your solution must be vs. how much you want to reduce overhead. In the first case you would make ASN.1 BER-TLV from all these objects (so you would have typically 2 + 3 + 3 + 2 bytes of overhead to transfer one sensor data blob in the length of 0-127 Bytes) or similar, second case would make it enough to do TAG (1B) + LENGTH (1B for data length 0-125B) + 1B (sensor number) + 1B (data type) + ACTUAL_DATA.

  • ... so the second notation provides 4B of overhead to each data blob which has length 0-125B (if longer then you simply have +1 or +2 bytes because length element will be longer then 1B).

Related