Method for syncing interval functions over separate devices

I am trying to get an interval function, pre-programmed on separate devices, to sync up with each other. So several mobile devices all running the same interval function in sync. At first I thought I could just use the devices internal clocks and start the functions on the 0 of the minute. I realize now that mobile clocks aren't really all that accurate and are not synced to each other. Now I need a new solution.

I'm using heroku, node.js, socket.io, and ionic if that helps at all.

Conceptually, you could do the following:

  1. Have each client establish a time reference vs. a common server.
  2. Send a color changing message to each client with a specific timestamp a short time in the future when the color changing effect is to be started.
  3. When each client receives the color changing message, it looks at the scheduled timestamp a short time in the future, corrects for the time reference and schedules the event vs. its own clock.
  4. When that time arrives at each client, each client starts playing the event.

This will be as accurate as the time reference you establish in step 1 and that's where the tricky portion is and where the accuracy of lack of accuracy is established. There's a description of one method for doing that in this post: Measuring time difference between networked devices.

Once you establish the time delta between the client clock and the reference clock, you store that delta locally and you can apply that delta to any future time directives from the server. So, if you receive a directive to carry out some operation at 12:30:05.00, but your client clock has been measured to be +12.33 seconds fast from the server reference, then you would subtract that +12.33 seconds from the scheduled time and set a timer that would fire at 12:29:52.67 on your local clock.

You handle the fact that the transit time to each client may not be the same by sending a directive for a specific time in the future. You can pick any time in the future, but it must not be a longer time into the future than the longest transit time to any client. You can also measure that from each client and report it to the server or if you have enough time to schedule in advance, you can just send the message with the directive at least several seconds ahead of time (longer than any transit time is likely to be in normal operating conditions).