Setting the Hand Controller Time on Boot

A project log for Raspberry Pi Driven Telescope Mount

full telescope control over WiFi using INDI on a RPi Zero W

Dane GardnerDane Gardner 11/03/2018 at 08:430 Comments

After upgrading to the latest version of Raspbian, I took a look through my notes on future work, and realized I could immediately do part of a requirement I set out to do with this project.  My hand controller for my Nexstar 6se doesn't have a real time clock (RTC) built into it, which means that every time it loses power, I have to manually reset the time.  I'm also lazy, and I don't accurately set the time when I have to enter it by hand, so I could easily be off by a minute or two.  To remedy this, I would like to set the time automatically when the Raspberry Pi first starts, allowing me to skip this manual process.

Unfortunately, RPis don't have RTCs either!  I can however use my WiFi connection to discover the time using the Network Time Protocol (NTP), and in the future I could add a hardware RTC, or use a GPS module, to keep track of time when a network connection isn't readily available.

Forcing NTP Update

The NTP service can take several minutes after a reboot to synchronize the time with an external server.  In this case, however, we want an immediate time sync.  To do this, we will momentarily disable the NTP client daemon, force the update via `ntpd`, and then start the client again.  I've added this near the top of my `/etc/rc.local` script which runs at startup.

service ntp stop   # stop the client
ntpd -gq           # force the update
service ntp start  # start things again

Observation shows that this reduces the typical sync time from over three minutes, to less than 15 seconds after startup.  I can now inspect get the time from the OS, and then set it on my hand controller using the serial port.

Setting the HC Time

Celestron has published the HC serial protocol, and reading through that I found the following regarding the format of the time when setting it, such that each value is a binary formatted byte.

The format of the time commands is: QRSTUVWX, where:
  Q is the hour (24 hour clock).
  R is the minutes.
  S is the seconds.
  T is the month.
  U is the day.
  V is the year (century assumed as 20).
  W is the offset from GMT for the time zone. Note: if zone is negative, use 256-zone.
  X is 1 to enable Daylight Savings and 0 for Standard Time.

Easy enough; I can actually knock that out with just Bash!

# set the serial port speed
stty -F ${serial} 9600

# get the date in the order the protocol calls for
dtm="$(date -u '+%_H %_M %_S %_m %_d %_y 0 0')"

# H is the command char; the following 8 bytes are the date/time
unset FORMAT
for i in {1..8}; do FORMAT="${FORMAT}${HEX}"; done
hex_text="$(printf "H${FORMAT}" ${dtm})"

# send it to the serial port
echo -ne "${hex_text}" > ${serial}

NOTE: I am using the UTC timezone so that I don't have to fuss with daylight savings and whatnot.  I don't use my hand controller to look at the local time, so there's no need to go through the extra effort.

Using my Bus Pirate, I was able to confirm that this functioned as expected, so I wrapped everything up into a tidy little script, and I am executing it from the top of my `/etc/rc.local`.  I sealed up the HC again, and tested out the timing to ensure that I didn't try to set the time before the HC was ready for serial communications, and haven't seen any problems yet!  If I find that I need it in the future, I can probably set up a button on my joystick controller to force an update of the HC time.

EDIT (20181208): I've updated the script to include space padded date components.  It was pointed out to me by [ChrisG71] that printf was interpreting anything with a zero in front as an octal character.