Getting Time Zone and Daylight Savings info out of CTS

I'm currently getting the CTS info out of my iPhone and storing it in my RTC, that talks with my nRF52832 via I2C.  All seems to work.

But my Dev Team are now wanting the time in UTC, which means I also need Time Zone and Daylight Savings Time info.  The standard API's that Nordic provide only seems to extract the Current Time:

/**@brief "Exact Time 256" field of the Current Time characteristic. */
struct bt_cts_exact_time_256 {
	uint16_t year;
	uint8_t month;
	uint8_t day;
	uint8_t hours;
	uint8_t minutes;
	uint8_t seconds;
	uint8_t day_of_week;
	uint8_t fractions256;
};

/**@brief "Adjust Reason" field of the Current Time characteristic. */
struct bt_cts_adjust_reason {
	uint8_t manual_time_update : 1;
	uint8_t external_reference_time_update : 1;
	uint8_t change_of_time_zone : 1;
	uint8_t change_of_daylight_savings_time : 1;
};

/**@brief Data structure for the Current Time characteristic. */
struct bt_cts_current_time {
	struct bt_cts_exact_time_256 exact_time_256;
	struct bt_cts_adjust_reason adjust_reason;
};

What I also need is the Local Time info.

Has anyone done this before, and if so, can you give me a bit of guidance on how to go about this?

I assume I need to create a new struct, a-la:

/** Local Time Information Characteristic structure */
struct bt_cts_local_time
{
    int8_t timeZone;           /**< Current Time Zone */
    uint8_t dst;               /**< Daylight Saving Time value */
};

And then when I read the CTS from my phone, I need to index the Local Time characteristic from the CTS and copy it into an instance of the above struct.  Does that sound correct?

Its this last step I'm not 100% sure of, nor how to go about implementing it, so any guidance will be warmly received :-)

Cheers,

Mike

Parents
  • I looked into this.

    Looking at this document: Current Time Service.

    I see that the CTS Service can contain both a Current Time characterstic and a Local Time information characterstic.

    The Current Time characteristic contains the time local time, adjusted for DST and time zone. See 3.1.1 in the attached document:

    "The date and time values returned shall be the local date and time of the server device (the time the server device would display to the user, which is normally the correct time for the location adjusted for time zone and DST)."

    Next, you would then need to include the Local Time Information characterstic, and use that to get the Time zone field and the DST offset field

    Then you can get the UTC time by subtracting the DST offset field and Time zone field from the current local time you got from the Current Time characteristic.

    I've not gone into the speficics of how to do this, but try to check out the Peripheral CTS client sample, it demonstrates how to get all these fields: Peripheral CTS Client

    Best regards,

    Simon

Reply
  • I looked into this.

    Looking at this document: Current Time Service.

    I see that the CTS Service can contain both a Current Time characterstic and a Local Time information characterstic.

    The Current Time characteristic contains the time local time, adjusted for DST and time zone. See 3.1.1 in the attached document:

    "The date and time values returned shall be the local date and time of the server device (the time the server device would display to the user, which is normally the correct time for the location adjusted for time zone and DST)."

    Next, you would then need to include the Local Time Information characterstic, and use that to get the Time zone field and the DST offset field

    Then you can get the UTC time by subtracting the DST offset field and Time zone field from the current local time you got from the Current Time characteristic.

    I've not gone into the speficics of how to do this, but try to check out the Peripheral CTS client sample, it demonstrates how to get all these fields: Peripheral CTS Client

    Best regards,

    Simon

Children
  • Next, you would then need to include the Local Time Information characterstic, and use that to get the Time zone field and the DST offset field

    That's the issue.  The Nordic API's only extract the Current Time characteristic, and don't include the Local Time characteristic.  And I can't work out how I can get that info myself.

    My code that extracts the Current Time characteristic is based on that Peripheral CTS Client example.

    I "think" all I need to do is read a Gatt characteristic, and use the Local Time characteristic handle to reference that, but I'm floundering around trying to work out how to do that.

    BTW - think I've nailed the Local->UTC conversion thing myself.

    Cheers,

    Mike

  • Yep, happy to close off  Converting local time from CTS to UTC time  

    Still not sure how to get the Time Zone and DST info out of the CTS though

    Cheers,

    Mike

  • Hi Simon,

    Still struggling with this (getting the Local Time info out of the CTS).

    From the looks of the nRF5 SDK code, the process to get the Current Time info out of the CTS involves:

    1.  A call to err = bt_cts_read_current_time(&cts_c, func);  Here, the func is the callback function that you can define, and that is called when the read operation is completed

    2. The bt_cts_read_current_time call then sets up a bunch of parameters, via:

    cts_c->read_cb = func;

    cts_c->read_params.func = bt_cts_read_callback;

    cts_c->read_params.handle_count = 1;

    cts_c->read_params.single.handle = cts_c->handle_ct;cts_c->read_params.single.offset = 0;

    Not sure what this is all doing, but I'm guessing its setting things up so that the GATT read that comes next knows what characteristic it needs to access.  The bt_cts_read_callback function listed amongst all of this seems to do a bunch of data decoding, and validation, and I'm guessing this gets called once the next step below has been implemented.

    3.  It then makes a call to err = bt_gatt_read(cts_c->conn, &cts_c->read_params); which looks to be Nordics general GATT read API

    What I'm trying to do is work out what I need to add to my code, along the lines of the above, to enable me to access the Local Time info.

    I'm thinking I need to define my own bt_cts_read_local_time() API (to emulate the bt_cts_read_current_time(&cts_c, func) one from Nordic), and then set up the parameters listed above to access the Local Time info characteristic, and include my own version of the bt_cts_read_callback API, which will no doubt need my own data decoding and data validation API's.  I can then just make the same call to bt_gatt_read and I "should" now have the Local Time info.

    Does that sound right to you?

    Seems weird that Nordic wouldn't have done the heavy lifting and write a bunch of API's to extract the Local Time info as well as the Current Time info, but c'est la vie!

    Cheers,

    Mike

  • You are right, similar to the nRF5 SDK, the nRF Connect SDK has not implemented capablitiy to read the Local Time Information Characteristic (LTIC). Like Terje explains here  mktime() in nordic calendar example is not taking local time into account?  

    It seems like your thinking is correct, regarding how to read the LTIC. Let me go through what I think needs to be done

    I think you'll need to do the following:

    • 1. Define the LTIC UUID

    Do it similar to how it's done for the Current Time Characteristic (CTC): https://github.com/nrfconnect/sdk-zephyr/blob/main/include/zephyr/bluetooth/uuid.h#L864-L872 

    Call it BT_UUID_CTS_LOCAL_TIME_INFORMATION and use the UUID 0x2A0F (I got this value from the nRF5 SDK documentation).

    • 2. Modify the bt_cts_client struct

    Add a handle for the LTIC similar for how it's done for the CTC: https://github.com/nrfconnect/sdk-nrf/blob/v2.0.2/include/bluetooth/services/cts_client.h#L82-L83 

    You can call the LTIC handle field handle_lti

    I'm not sure if the LTIC has notify-capabilities, in that case add a CCCD handle as well.

    • 3. Assign the handle

    In the function bt_cts_handles_assign(), copy these lines and do the same thing for the LTIC. You will end up with assigning the LTIC handle to cts_c->handle_lti. If the LTIC has notify-capablities, copy these lines as well and modify them accordingly.

    • 4. Create a function bt_cts_read_local_time()

    Copy the function bt_cts_read_current_time() and modify it to use the LTIC handle instead.

    If the LTIC has notify-capabilities, copy the function bt_cts_subscribe_current_time() as well and modify it accordingly.

    Also you should check if the iPhone you're getting the CTS info from actually has the LTIC characteristics, if not you will not be able to read it.


    Be aware that I have not tested this myself, and I might have forgotten something. I just looked quickly into it and wrote down how I understood it before I now take vacation for two weeks.

    I will make sure someone else takes over and watches this case, in case you got any follow-up questions.

    Best regards,

    Simon

Related