How to broadcast data from one IoT to another IoT or BLE Sense via bluetooth

Hello,

I have an Arduino 33 IoT and I want to broadcast or transfer the data from it to another IoT or BLE Sense via bluetooth. But I don't know how to start with it. I've looked up some of the examples available for the ArduinoBLE library, but they don't make sense to me at all.

Say I want the time from the IoT synced to the other IoT / BLE Sense every 12 hours. How can I do that? Can anyone help me write the basic codes for transferring the data via bluetooth?

Thanks.

crispywisp:
I have an Arduino 33 IoT and I want to broadcast or transfer the data from it to another IoT or BLE Sense via bluetooth.

That is not how BLE is designed to work. BLE is more like the internet. A server called peripheral provides data and a client called central can read the data whenever it wants to. Broadcasting is bad for low power. BLE uses advertisement which only "broadcast" the advert but not the data.

In BLE a protocol called GATT is used to exchange data. Data is described as services and characteristics. Services contain characteristics. Both are identified by a number called UUID. UUIDs specified by the Bluetooth SiG are 16-bit long and you can create your own, but they must be 128-bit long and need to be random numbers.

Here you can look up the 16-bit UUID defined by the Bluetooth SiG

Use the following example and load it into your Arduino Nano 33 IoT or BLE and start the Serial Monitor (important otherwise sketch does not start):

File -> Examples -> ArduinoBLE -> Peripheral -> Battery Monitor

Use a smartphone app for BLE. I use BLE Scanner on iPhone (it might be available on Android as well). There are others with similar functionality. Do not try to pair the Arduino, this does not work. Just start the app and connect to the Arduino.

Now look at the source code and the information the app shows you. You should see the UUIDs, service and characteristic.

All you need to do now, is write the time to the characteristic and change the UUIDs. Then you will have a BLE time server. Do not worry about the correct time for now. Just write some random time to it and increment it.

If you get stuck please post your code (use code tags). If you have any questions about the code do not hesitate to ask.

Hello Klaus,

Thanks for responding. While I was waiting for some responses here, I was able to get the two BLEs work by using the LED Control and LED examples of the ArduinoBLE. I added an OLED screen to both to see what's happening and I can clearly see they are working together perfectly.

Now when I looked at the LED Control example, I was wondering how I can pass the time from the Control to the other BLE when I press a button for example.

By the way, the time I wanna push or send is from the NTP server -- which I already have working on my other Arduino IoT.

I'm not familiar with bytes and I see the default for the LED is 0x01 and 0x00. I checked your link for the GATT table and the time broadcast that's on there is 0x2A15. Should I try using that?

I tried doing your suggestion with the Battery Monitor. I was able to get it working on the phone. But I don’t know where to copy the UUID and the characteristics.

I’m trying to output the battery level to the other BLE by editing the LED example. But I’m just making guesses to get it to show up on the OLED display.

Modified LED example of ArduinoBLE.

#include <ArduinoBLE.h>
#include <Adafruit_SSD1306.h> //OLED Display Library.

#define SCREEN_WIDTH 128 //OLED Display Width.
#define SCREEN_HEIGHT 64 //OLED Display Height.

//Declaration for an SSD1306 display connected to I2C (SDA, SCL pins).
#define OLED_RESET 4 //Reset pin # (or -1 if sharing Arduino reset pin).
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

BLEService batteryService("2A19"); // BLE LED Service

// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic batteryLevelChar("5B4CAF3C-AB5D-2461-0180-1651CBB72C04", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Initialize with I2c addres 0x3C.
  display.clearDisplay(); //Clear buffer.
  display.display();
  Serial.begin(9600);

  // set LED pin to output mode
  pinMode(ledPin, OUTPUT);

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  // set advertised local name and service UUID:
  BLE.setLocalName("LED");
  BLE.setAdvertisedService(batteryService);

  // add the characteristic to the service
  batteryService.addCharacteristic(batteryLevelChar);

  // add service
  BLE.addService(batteryService);

  // set the initial value for the characeristic:
  batteryLevelChar.writeValue(0);

  // start advertising
  BLE.advertise();

  Serial.println("BLE LED Peripheral");
}

void loop() {
  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();

  // if a central is connected to peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's MAC address:
    Serial.println(central.address());

    // while the central is still connected to peripheral:
    while (central.connected()) {
      // if the remote device wrote to the characteristic,
      // use the value to control the LED:
      if (batteryLevelChar.written()) {
        if (batteryLevelChar.value()) {   // any value other than 0
          Serial.println("LED on");
          display.clearDisplay();
          display.display();
          display.setTextSize(1);
          display.setTextColor(WHITE, BLACK);
          display.setCursor(2, 18);
          display.print(batteryLevelChar);
          display.display();
        }
      }
    }

    // when the central disconnects, print it out:
    Serial.print(F("Disconnected from central: "));
    Serial.println(central.address());
  }
}

Can you help me output the battery level on the display? Maybe once you’ve shown me the structure, I can figure out what to do next.

This is what’s showing up on the BLE Scanner on my phone (Battery Monitor):

  • Device UUID = 5B4CAF3C-AB5D-2461-0180-1651CBB72C04
  • Battery Service = 0x180F
  • UUID = 2A19 (in the Battery Service)

(I’m not sure which UUID I should use but I tried both and nothing works. I’m sure I don’t know what I’m doing at this point.)

This is the Battery Monitor sketch.

#include <ArduinoBLE.h>

 // BLE Battery Service
BLEService batteryService("180F");

// BLE Battery Level Characteristic
BLEUnsignedCharCharacteristic batteryLevelChar("2A19",  // standard 16-bit characteristic UUID
    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes

int oldBatteryLevel = 0;  // last battery level reading from analog input
long previousMillis = 0;  // last time the battery level was checked, in ms

void setup() {
  Serial.begin(9600);    // initialize serial communication
  while (!Serial);

  pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  /* Set a local name for the BLE device
     This name will appear in advertising packets
     and can be used by remote devices to identify this BLE device
     The name can be changed but maybe be truncated based on space left in advertisement packet
  */
  BLE.setLocalName("BatteryMonitor");
  BLE.setAdvertisedService(batteryService); // add the service UUID
  batteryService.addCharacteristic(batteryLevelChar); // add the battery level characteristic
  BLE.addService(batteryService); // Add the battery service
  batteryLevelChar.writeValue(oldBatteryLevel); // set initial value for this characteristic

  /* Start advertising BLE.  It will start continuously transmitting BLE
     advertising packets and will be visible to remote BLE central devices
     until it receives a new connection */

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // wait for a BLE central
  BLEDevice central = BLE.central();

  // if a central is connected to the peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
    // turn on the LED to indicate the connection:
    digitalWrite(LED_BUILTIN, HIGH);

    // check the battery level every 200ms
    // while the central is connected:
    while (central.connected()) {
      long currentMillis = millis();
      // if 200ms have passed, check the battery level:
      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
        updateBatteryLevel();
      }
    }
    // when the central disconnects, turn off the LED:
    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

void updateBatteryLevel() {
  /* Read the current voltage level on the A0 analog input pin.
     This is used here to simulate the charge level of a battery.
  */
  int battery = analogRead(A0);
  int batteryLevel = map(battery, 0, 1023, 0, 100);

  if (batteryLevel != oldBatteryLevel) {      // if the battery level has changed
    Serial.print("Battery Level % is now: "); // print it
    Serial.println(batteryLevel);
    batteryLevelChar.writeValue(batteryLevel);  // and update the battery level characteristic
    oldBatteryLevel = batteryLevel;           // save the level for next comparison
  }
}

I have written an example using the Bluetooth service and characteristic for current time. It needs a little bit of cleaning and a central to send the actual time.

The code looks a tiny bit more complex then what I would like but it uses mbedOS time and is fully decoded by the WirelessGecko Bluetooth app. Which suggests it should be fully compatible with anything that implements/uses this service.

Could you post the code you have written for the Arduino Nano 33 IoT? Then I do not need to reinvent the code for the NTP and add the code to send the time.

Could you please modify your post and replace the quote tags by code tags? This make the window for the code smaller and leaves more place for comments. It also has a select function and allows copy. e.g.

Your source code

crispywisp:
(I'm not sure which UUID I should use but I tried both and nothing works. I'm sure I don't know what I'm doing at this point.)

The UUIDs are just numbers in your code. But we will use the numbers to identify the information between the devices. And the numbers are public, so when you use a app or a device that knows the numbers it might be able to display them correctly or use it.

Sorry. I didn’t notice there’s a code tag here. I modified it already.

And here is the sketch I have on my IoT.

#include <SPI.h>
#include <Wire.h> 
#include <WiFiNINA.h> 
#include <WiFiUdp.h> 
#include <ArduinoBLE.h> 
#include <Adafruit_SSD1306.h> 

#define SCREEN_WIDTH 128 
#define SCREEN_HEIGHT 64 

//Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 //Reset pin # (or -1 if sharing Arduino reset pin).
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

//Variables.
int ntpHour; //Hour received from NTP server.
int ntpMin;  //Minute received from NTP server.

int status = WL_IDLE_STATUS;

//Store SSID information securely.
#include "arduino_secrets.h"
char ssid[] = SECRET_SSID; //SSID.
char pass[] = SECRET_PASS; //Password.
int keyIndex = 0; 

unsigned int localPort = 2390;  //Local port to listen for UDP packets.

IPAddress timeServer(129, 6, 15, 28);  //time.nist.gov NTP server.

//Constant.
const int NTP_PACKET_SIZE = 48;  //NTP time stamp is in the first 48 bytes of the message.

byte packetBuffer[NTP_PACKET_SIZE];  //Buffer to hold incoming and outgoing packets.

WiFiUDP Udp; //A UDP instance to let us send and receive packets over UDP.

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Initialize with I2c addres 0x3C.
  display.clearDisplay(); //Clear buffer.
  display.display();

  Serial.begin(9600); //Initialize serial communication.
  
  //Check for the WiFi module.
  if (WiFi.status() == WL_NO_MODULE) {
    display.setTextSize(1);
    display.setTextColor(WHITE, BLACK);
    display.setCursor(2, 3);
    display.println("Communication with WiFi");
    display.setCursor(45, 15);
    display.println("FAILED");
    display.display();
    delay(1500); //Wait for 1.5 seconds.
    display.clearDisplay();
    display.display();
    //Don't continue
    while (true);
  }

  //Attempt to connect to Wifi network.
  while (status != WL_CONNECTED) {
    display.setTextSize(1);
    display.setTextColor(WHITE, BLACK);
    display.setCursor(2, 3);
    display.println("Connecting to WiFi...");
    display.setTextSize(2);
    display.setCursor(2, 25);
    display.println(ssid);
    display.display();
    
    status = WiFi.begin(ssid, pass); //Connect to WPA/WPA2 network.

    //Wait 10 seconds for connection.
    delay(10000);
    display.clearDisplay();
    display.display();
  }

  display.setTextSize(1);
  display.setTextColor(WHITE, BLACK);
  display.setCursor(15, 25);
  display.println("Connected to WiFi");
  display.display();
  delay(2500);

  Udp.begin(localPort);

  display.clearDisplay();
  display.display();
}

void loop() {
  sendNTPpacket(timeServer); //Send an NTP packet to a time server.
    delay(250); //Wait to see if a reply is available.
  if (Udp.parsePacket()) { //We've received a packet, read the data from it.
    Udp.read(packetBuffer, NTP_PACKET_SIZE); //Read the packet into the buffer.

    //The timestamp starts at byte 40 of the received packet and is four bytes, or two words long.
    //First, extract the two words.
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  
    //Combine the four bytes (two words) into a long integer.
    //This is NTP time (seconds since January 1, 1900).
    unsigned long secsSince1900 = highWord << 16 | lowWord;

    //Now convert NTP time into everyday time.
    //Unix time starts on January 1, 1970. In seconds, that's 2208988800.
    const unsigned long seventyYears = 2208988800UL;
    
    //Subtract seventy years.
    unsigned long epoch = ((secsSince1900 - seventyYears) - 17998); //17998 = CST time minus two seconds.

    ntpHour = ((epoch % 86400L) / 3600);
    ntpMin = ((epoch  % 3600) / 60);

    //Display the hour and minute.
    display.setTextSize(1);
    display.setTextColor(WHITE, BLACK);
    display.setCursor(32, 3);
    display.print("Current Time");
    display.setTextSize(3);
    display.setCursor(21, 25);
    if (ntpHour == 0) {
      display.print("12");
      display.display();
    } else if (ntpHour >= 13) {
      display.print(ntpHour - 12);
    } else if (ntpHour <= 13) {
      display.print(ntpHour);
    }
    display.print(":");
    // In the first 10 minutes of each hour, we'll want a leading '0'.
    if (ntpMin < 10) {
      display.print("0");
    }
    display.print(ntpMin);
    display.setTextSize(1);
    if (ntpHour >= 0 && ntpHour <= 11) {
      display.setCursor(115, 36);
      display.print("  ");
      display.setCursor(115, 26);
      display.print("am");
    }
    else if (ntpHour <= 23) {
      display.setCursor(115, 36);
      display.print("pm");
      display.setCursor(115, 26);
      display.print("  ");
    }
    display.display();
  }
  //Wait half a second before asking for the time again.
  delay(500);
}

  //Send an NTP request to the time server at the given address
  unsigned long sendNTPpacket(IPAddress& address) {
  //Serial.println("1");
  //Set all bytes in the buffer to 0.
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  //Initialize values needed to form NTP request.
  //(see URL above for details on the packets).
  //Serial.println("2");
  packetBuffer[0] = 0b11100011;  //LI, Version, Mode.
  packetBuffer[1] = 0;  //Stratum, or type of clock.
  packetBuffer[2] = 6;  //Polling Interval.
  packetBuffer[3] = 0xEC;  //Peer Clock Precision.
  //8 bytes of zero for Root Delay & Root Dispersion.
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  //Serial.println("3");

  //All NTP fields have been given values, now.
  //You can send a packet requesting a timestamp.
  Udp.beginPacket(address, 123); //NTP requests are to port 123.
  //Serial.println("4");
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  //Serial.println("5");
  Udp.endPacket();
  //Serial.println("6");
  }

Looking forward to your codes / sketch so I can understand how this wireless connectivity works.

Thanks again.

Here are two example sketches that work together demonstration the Bluetooth Current Time Service.

BLE_Time.ino

  • runs on an Arduino Nano 33 BLE or BLE Sense
  • can be powered by a USB battery pack for the demo
  • has a Current Time service and characteristic as defined by the Bluetooth SiG
  • you can read them with a smartphone app
  • the WirelessGecko app from Silicon Labs can decode the data most other apps will only show you the bytes

BLE_TimeCentral.ino

  • runs on an Arduino Nano 33 IoT
  • requires an arduino_secrets.h file
  • The Serial Monitor needs to be connected for the sketch to run (disable while ( !Serial ); otherwise)
  • connects to WiFi every hour
  • when the NTP request is successful BLE will be activated
  • the sketch scans for the Current Time service and writes the new time
  • the wifiTask and bleTask need to be called on a regular basis and handle all the communication
  • each of them will only run when the other is inactive
  • both tasks use a state machine to allow the loop() to continue executing other code

A few notes:

  • WiFi and BLE cannot be active at the same time (this is a limitation of the module)
  • the structs could be simplified but I wanted to ensure it reflects the documentation from Bluetooth SiG

You do not have to use the current time service and could create your own time service with your own 128-bit UUIDs and simply send the UNIX time. It would make the code a little bit simpler but less compatible.

Edit: In the BLE_Time.ino the mbed.h file needs to be included with mbedOS version 1.1.6. See below reply’s #10 and #11 for more information.

BLE_Time.ino (7.04 KB)

BLE_TimeCentral.ino (14.4 KB)

Hello Klaus,

Thanks for your effort. I really appreciate it. I actually had to walk away for a bit when I saw the structure of the Central sketch. It was way beyond my skills. But, I’m trying to learn and understand every bit of it. Thanks again.

I have a couple of questions with the Central sketch.

What does this actually do especially the fractions256 and the Manual Time Update?

  currentTimeData.currentTime.exactTime256.dayDateTime.dateTime = dateTime;
  currentTimeData.currentTime.exactTime256.dayDateTime.dayOfWeek.dayOfWeek = getTime->tm_wday + 1;
  currentTimeData.currentTime.exactTime256.fractions256 = 0;
  currentTimeData.currentTime.adjustReason = 0; // 0 - Manual Time Update

Also for the LoopAnalysis part. This really goes beyond me. But how were you able to update the time by incrementing the loop?

void loopAnalysis()
{
  static unsigned long previousMillis = 0;
  static unsigned long lastMillis = 0;
  static unsigned long minLoopTime = 0xFFFFFFFF;
  static unsigned long maxLoopTime = 0;
  static unsigned long loopCounter = 0;

#define LOOP_ANALYSIS_INTERVAL 1000

  unsigned long currentMillis = millis();
  if ( currentMillis - previousMillis > LOOP_ANALYSIS_INTERVAL )
  {
    Serial.print( "Loops: " );
    Serial.print( loopCounter );
    Serial.print( " ( " );
    Serial.print( minLoopTime );
    Serial.print( " / " );
    Serial.print( maxLoopTime );
    Serial.println( " )" );
    previousMillis = currentMillis;
    loopCounter = 0;
    minLoopTime = 0xFFFFFFFF;
    maxLoopTime = 0;
  }
  loopCounter++;
  unsigned long loopTime = currentMillis - lastMillis;
  lastMillis = currentMillis;
  if ( loopTime < minLoopTime )
  {
    minLoopTime = loopTime;
  }
  if ( loopTime > maxLoopTime )
  {
    maxLoopTime = loopTime;
  }
}

I mean I can see you’re incrementing the loop counter, but how were you able to update the epoch time with it? And what does the min and max loop time do?

And lastly, I tried uploading the BLE sketch to my Arduino BLE but I had an error with this part for both the setupTime and setCurrentTime voids. It says it was not declared in the scope.

set_time( mktime( &setTime ) );

I commented it out to be able to upload it. But will it cause any issues? It can still get the time from the IoT though. But I honestly have no clew what this part does.

crispywisp:
What does this actually do especially the fractions256 and the Manual Time Update?

The currentTimeData contains the data for the Current Time characteristic. We are not using the fractions256 and adjustReason. I just filled the bytes out with some default values. The fractions256 would allow to send a time with fractions of a second. Instead of dividing a second into 10, 100 or 1000 parts it uses 256 (8-bits) parts (internally computers use binary clocks).

crispywisp:
Also for the LoopAnalysis part. This really goes beyond me. But how were you able to update the time by incrementing the loop? And what does the min and max loop time do?

The loop analysis is completely independent and not needed. It uses local static variables. They are not valid outside the function. I just used it to see how the main loop function runs. The goal is to make sure the main loop can run all kinds of other code and as often as possible.
loopCounter shows you how many times per second the loop function was executed. You want that number to stay large. With more code it will go down. If the number is too low your code will no longer be responsive.
minLoopTime shows you the shortest loop within the last second. You want this number to stay low. As long as this number is low you can add new functionality to your sketch.
maxLoopTime shows you the longest loop within the last second. You want this number to stay low as well, but as long as loopCounter is high you do not need to worry too much.

crispywisp:
I mean I can see you're incrementing the loop counter, but how were you able to update the epoch time with it?

The timeEpoch (this is a software clock using UNIX time) variable is incremented in the main loop every 1000ms.

crispywisp:
And lastly, I tried uploading the BLE sketch to my Arduino BLE but I had an error with this part for both the setupTime and setCurrentTime voids. It says it was not declared in the scope.
set_time( mktime( &setTime ) );

Are you sure you set the board to be an Arduino Nano 33 BLE with mbedOS? This only works for mbedOS. mbedOS has a timer for measuring the actual time. The other Arduinos do not have the set_time function. That is why I created the timeEpoch variable in the Central sketch (the IoT does not use mbedOS).

https://os.mbed.com/docs/mbed-os/v6.3/apis/time.html

crispywisp:
But will it cause any issues? It can still get the time from the IoT though. But I honestly have no clew what this part does.

The "clock" will stop working.
setupTime will only set the "clock" to January 1st 2020 00:00:00. This function is not strictly necessary, but I think a clock should not start decades before the invention of the product. :slight_smile:
setCurrentTime is needed to set the internal clock to the time send by the central.

Before you remove any code feel free to ask me. There are a couple of things in the code that are necessary for things to work. I have played with both boards for quite a while.

Hello Klaus,

I'm sure I set the board to BLE mbedOS. I always make sure I have the right board set before uploading, because one time I bricked an IoT when I uploaded something with an mbed board selected. I don't know how it happened, but it happened.

Anyway, I screenshot what was showing up when I upload it on the BLE.


Imgur

And this is the error message I'm getting.

Arduino: 1.8.13 (Windows Store 1.8.42.0) (Windows 10), Board: "Arduino Nano 33 BLE"

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino: In function 'void updateTimeData()':

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:198:45: warning: narrowing conversion of '(getTime->tm::tm_year + 1900)' from 'int' to 'uint16_t {aka short unsigned int}' inside { } [-Wnarrowing]

   date_time_t dateTime = { getTime->tm_year + 1900,

                            ~~~~~~~~~~~~~~~~~^~~~~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:199:44: warning: narrowing conversion of '(getTime->tm::tm_mon + 1)' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

                            getTime->tm_mon + 1,

                            ~~~~~~~~~~~~~~~~^~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:200:37: warning: narrowing conversion of 'getTime->tm::tm_mday' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

                            getTime->tm_mday,

                            ~~~~~~~~~^~~~~~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:201:37: warning: narrowing conversion of 'getTime->tm::tm_hour' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

                            getTime->tm_hour,

                            ~~~~~~~~~^~~~~~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:202:37: warning: narrowing conversion of 'getTime->tm::tm_min' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

                            getTime->tm_min,

                            ~~~~~~~~~^~~~~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:203:37: warning: narrowing conversion of 'getTime->tm::tm_sec' from 'int' to 'uint8_t {aka unsigned char}' inside { } [-Wnarrowing]

                            getTime->tm_sec };

                            ~~~~~~~~~^~~~~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino: In function 'void setupTime()':

BLE_Time:222:3: error: 'set_time' was not declared in this scope

   set_time( mktime( &setTime ) );

   ^~~~~~~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:222:3: note: suggested alternative: 'setTime'

   set_time( mktime( &setTime ) );

   ^~~~~~~~

   setTime

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino: In function 'void setCurrentTime(date_time_t)':

BLE_Time:238:3: error: 'set_time' was not declared in this scope

   set_time( mktime( &setTime ) );

   ^~~~~~~~

C:\Users\Chris\Desktop\BLE_Time\BLE_Time.ino:238:3: note: suggested alternative: 'setTime'

   set_time( mktime( &setTime ) );

   ^~~~~~~~

   setTime

exit status 1

'set_time' was not declared in this scope



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

I tried adding this in the sketch. And it let me upload it to the BLE.

#include "mbed.h"

But I had to removed the F in the serial.print which in part of the void loop...

Serial.print( F( "Disconnected from central: " ) );

But I'm not sure how to check if this is working how you've written it.

I was just writing a post saying my mbedOS version is 1.1.4 and the board files seem to have been changed. You likely already use 1.1.6. I got the same error message when I upgraded the board files.

Your workaround works with a small test sketch I wrote. Well done. :slight_smile:

Removing the F is fine. It is an Arduino macro to tell the compiler to load the String from Flash memory instead of RAM. We do not need that; we have enough memory. :slight_smile:

Regarding the warning: narrowing conversion. I think we can ignore that. Our numbers are small enough and will stay that way. The year will not be larger than a 16-bit int in our lifetime and the other time elements (day, month, hour, ...) will never be larger than 255 by definition. We could add type casting, but I am not sure that would make the code easier to read.

Thanks again Klaus, I've uploaded it on both BLE and IoT I'm gonna study the sketch works. Hopefully from these examples, I can learn how to advertise other data aside from time -- Like temperature, humidity, etc.

I will most likely ask you more questions along the way regarding this sketch so I can fully understand it.

Thanks again!

crispywisp:
Hopefully from these examples, I can learn how to advertise other data aside from time -- Like temperature, humidity, etc.

There is an example for Environmental Sensing Service in reply #3 in the following post.

crispywisp:
I will most likely ask you more questions along the way regarding this sketch so I can fully understand it.

No problem. If it is a new subject not related to this sketch please create a new post. You can send me a message with the link to the post.

crispywisp:
Thanks again!

You are welcome

Ok, I think I found something with the BLE sketch. I think the time doesn't update every hour. I tried adding the OLED display so I can easily monitor the time. I mean it updates at startup, but that's it. I think it just connects to the Central on the consecutive updates, but it doesn't really update the time.

Also the display doesn't update. I added it in the...

void printDateTime( date_time_t dateTime )

section.

I think the time doesn't update every minute. If it doesn't it's ok, because I can use the time it receives every hour from the IoT and copy it to update the RTC time in my other Arduinos.

But I think it's not updating every hour? Or if it does, how can I print the time? It's not as easy as in IoT where I can just serial.print or display.print the epochTime.

Ok, I've waited for an hour to see the update, but it didn't update the time.

Here is the screenshot of the serial of both the IoT and BLE.

https://www.imgurupload.com/uploads/20200928/e79e2894de2f6cd24dc3b9f6c151f03d94a7729e.png

I wanted to do some modifying, but I'm still trying to figure out how things work in both sketches. Better to leave this to you while I try to make guesses what's going on.

In the BLE_Time.ino sketch add the following line in line 144.

printDateTime( currentTimeData.currentTime.exactTime256.dayDateTime.dateTime );

This will print the time every second when you have a central connected.

In the BLE_TimeCentral.ino you can change the following statement to change the interval.

#define NTP_SYNC_INTERVAL 60 * 60 * 1000 // every 60 minutes

#define NTP_SYNC_INTERVAL 60 * 1000 // every 60 seconds

Please note, when you connect a smart phone to your Arduino Nano 33 BLE, the device will no longer be visible to the central and the time will not be updated.

Also, the BLE_Time sketch is written in the Arduino demo style (the program stays inside the while loop while connected). For a real application I would change it more into the style I used for the central where the loop() gets executed as often as possible.

I don't know why sometimes, or rather most of the time the bluetooth won't make a connection. The LED green light of the BLE stays on after the first time sync. And after the second time sync, it goes off and never gets the time updated. And I don't have a phone connected to the BLE and IoT.

Also can you help me point out the part or section where the time data gets sent in the IoT? And where it gets received in the BLE?

What I'd like to try is to copy the time it receives from the IoT and not create a new instance of time? Because I'd like to update the RTC from another Arduino?

newHour = dateTime.hours;
newMin = dateTime.minutes;
newSec = dateTime.seconds;
etc.

crispywisp:
Also can you help me point out the part or section where the time data gets sent in the IoT? And where it gets received in the BLE?

In the central the BLE state machine writes the data in the BLE_STATE_PERIPHERAL_WRITE.

currentTimeCharacteristic.writeValue( currentTimeData.bytes, sizeof currentTimeData.bytes );

The same is true for the peripheral. The exact same function is used to write the time into the characteristic so it could be read by a central.

In the peripheral the time is read using the readValue function. The time is stored in the currentTimeData and then the setCurrentTime function is used to update the internal clock.

currentTimeCharacteristic.readValue( currentTimeData.bytes, sizeof currentTimeData.bytes );

crispywisp:
What I’d like to try is to copy the time it receives from the IoT and not create a new instance of time?

What new instance of time?
Instead of setCurrentTime you can create your own function that writes the time to whatever clock, RTC you want. If you want the time of the Arduino Nano 33 BLE to be readable via BLE you need to update the currentTimeData. See the updateTimeData() function.

Sorry for the confusion, Klaus. I just thought the BLE has a "running" time, because when I connect to it with my phone, I could see the time gets updated every second - honest I don't know why the time is updated when I view it on the phone. But that was why I thought there's a time instance running in the BLE. I feel dumb.

But when I started playing with the codes more, and when I moved the print dayTime before the if (central) in the BLE sketch, I figured out that there's no time that's running, because the time doesn't update on it's own when I unplug the IoT.

I finally got the codes incorporated in my other Arduino that needs time updates. It works flawless. Thank you!

But lastly, some questions again regarding the BLE sketch. I hope you don't mind.

  1. Why is it that you separated the BLE.begin(); from the loop? Why you didn't include them together?
    1b. What's the difference between BLE.begin() from
if ( !BLE.begin() )
  {
    return false;
  }
  1. Can you please breakdown how the following works and what do they do?
    a. void updateTimeData()
    b. void setupTime(void) --> I don't understand this too. void setuptime(void)?? I mean too voids? this is the first time I saw this structure.
    c. void setCurrentTime(date_time_t dateTime); --> I just didn't know you can add something in the parenthesis too.

  2. Why is it that when I call printDateTime( date_time_t dateTime ), it wouldn't work? Like...

 void loop() {
  printDateTime( date_time_t dateTime );
}

And it has to be this code: serial.print(currentTimeData.currentTime.exactTime256.dayDateTime.dateTime);

I hope you don't mind the questions, I just learned something new from you with your sketches, and I'm amazed about it. I'm curious how they work.

Thanks again!