Set an Embedded System Time with Web UI

·

2 min read

I needed to set the system time on an embedded device, through a web page. It's just a single button on a web page, click on it then the job done.

A Flask app is running on the embedded system, as the web server. I used web socket to handle the communication. To achieve this, install Flask-SocketIO for the server and socket.io Javascript lib for the client.

Click the button on the web page, then the timestamp of the client (my laptop) will be sent to Flask through websocket:

$('#btnSetTime').on('click', function () {
    socket.emit('fe_set_time', localTimestamp);
});

Note that the timestamp includes both date and time information. To know more, the Epoch Converter is a good place to find Epoch & Unix Timestamp conversion tools and other information.

Then Flask (Python) responds the "fe_set_time" event to set the system time:

@socketio.on('fe_set_time')
def set_sys_time(time):
    time_string = datetime.datetime.fromtimestamp(time / 1e9).isoformat()
    # Stop sync system time from internet
    # Needs to install policykit-1 for this operation
    # See https://askubuntu.com/questions/1113470/org-freedesktop-policykit1-was-not-provided-by-any-service-files
    subprocess.call(shlex.split("timedatectl set-ntp false"))

    # Yes it needs sudo
    # Run the Flask app with sudo or anything similar
    subprocess.call(shlex.split("sudo date -s '{}'".format(time_string)))
    subprocess.call(shlex.split("sudo hwclock -w"))

    # After settting, tell the client
    socketio.emit('be_time_set')

And one last thing. After successfully (or not) set, the web page should display the current time of the embedded system. I used a JavaScript timer, getting the server time every second, and display it. Inside the timer event, it's still the websocket being used:

function getSysTime() {
  socket.emit('fe_get_sys_time');
  setTimeout(updateLoop, 1000);
}

The Flask:

@socketio.on('fe_get_sys_time')
def get_sys_time():
  current_time = datetime.datetime.now().strftime("%d/%m/%Y, %H:%M:%S")
  socketio.emit('be_send_sys_time', str(current_time))

That's it. I don't really like this.