From 1bcf20004a350daf5ab168eeb0d81eeac6eceee2 Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Mon, 2 Mar 2026 16:44:53 +0100 Subject: [PATCH 1/4] Add the setup-rtc and teardown-rtc commands --- simoc-sam.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/simoc-sam.py b/simoc-sam.py index 2eb589e5..db0750df 100644 --- a/simoc-sam.py +++ b/simoc-sam.py @@ -8,6 +8,7 @@ import socket import pathlib import argparse +import datetime import tempfile import functools import subprocess @@ -28,6 +29,7 @@ HOME = pathlib.Path.home() SIMOC_SAM_DIR = pathlib.Path(__file__).resolve().parent CONFIGS_DIR = SIMOC_SAM_DIR / 'configs' +RPI_CONFIG = pathlib.Path('/boot/firmware/config.txt') SYSTEMD_DIR = pathlib.Path('/etc/systemd/system') NM_DIR = pathlib.Path('/etc/NetworkManager/system-connections/') NM_TMPL = CONFIGS_DIR / 'nmconnection.tmpl' @@ -41,8 +43,8 @@ TMUX_SNAME = 'SAM' # tmux session name HOSTNAME = socket.gethostname() -APT_INSTALL = ['nmap', 'vim', 'tcpdump', 'tmux', 'nginx', - 'mosquitto', 'mosquitto-clients', 'avahi-utils'] +APT_INSTALL = ['nmap', 'vim', 'tcpdump', 'tmux', 'nginx', 'avahi-utils', + 'mosquitto', 'mosquitto-clients', 'util-linux-extra'] APT_REMOVE = ['chromium'] COMMANDS = {} @@ -595,6 +597,54 @@ def enable_i2c(): """Enable i2c using raspi-config.""" raspi_config('do_i2c', '0') + +@cmd +@needs_root +def setup_rtc(): + """Setup PCF8523 RTC by adding dtoverlay to config.txt.""" + if not RPI_CONFIG.exists(): + print(f'{RPI_CONFIG} not found. Are you on a Raspberry Pi?') + return False + overlay_line = 'dtoverlay=i2c-rtc,pcf8523' + # check if the overlay line already exists (uncommented) + with open(RPI_CONFIG) as f: + for line in f: + stripped = line.strip() + if stripped == overlay_line or stripped.startswith(overlay_line + ' '): + print(f'RTC already configured in {RPI_CONFIG}') + return True + # add the overlay line + with open(RPI_CONFIG, 'a') as f: + f.write(f'\n# PCF8523 RTC support\n{overlay_line}\n') + print(f'RTC overlay added to {RPI_CONFIG}') + print('\nRTC setup complete. Reboot for changes to take effect.') + print('After reboot, set the RTC time if this is the first setup:') + print(' 1. Set system time: sudo timedatectl set-time "YYYY-MM-DD HH:MM:SS"') + print(' 2. Sync to RTC: sudo hwclock --systohc') + return True + +@cmd +@needs_root +def teardown_rtc(): + """Revert the changes made by the setup-rtc command.""" + overlay_line = 'dtoverlay=i2c-rtc,pcf8523' + new_lines = [] + found = False + with open(RPI_CONFIG) as f: + for line in f: + if overlay_line in line or '# PCF8523 RTC support' in line: + found = True + continue # skip lines related to RTC overlay + new_lines.append(line) + if not found: + print(f'RTC overlay not found in {RPI_CONFIG}') + return False + RPI_CONFIG.write_text(''.join(new_lines)) + print(f'Removed RTC overlay from {RPI_CONFIG}') + print('Reboot for changes to take effect.') + return True + + @cmd def create_config(): """Create a user config file in ~/.config/simoc-sam/ and a symlink to it.""" From e93e0e0ad8f7a0dc8bc650c086ca7ea6c3e1925f Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Mon, 2 Mar 2026 16:48:46 +0100 Subject: [PATCH 2/4] Add the set-rtc-time command --- simoc-sam.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/simoc-sam.py b/simoc-sam.py index db0750df..76cbb756 100644 --- a/simoc-sam.py +++ b/simoc-sam.py @@ -597,6 +597,26 @@ def enable_i2c(): """Enable i2c using raspi-config.""" raspi_config('do_i2c', '0') +def parse_timestamp(timestamp): + """Parse a timestamp string (ISO format or Unix timestamp).""" + try: + return datetime.fromisoformat(timestamp) + except ValueError: + try: + return datetime.fromtimestamp(float(timestamp)) + except ValueError as e: + print(f'Error: Invalid timestamp format: {e}') + print('Use ISO format (YYYY-MM-DD HH:MM:SS) or Unix timestamp.') + return + +@cmd +def set_rtc_time(timestamp=None): + """Set the RTC time to the specified timestamp (ISO or Unix).""" + dt = parse_timestamp(timestamp) if timestamp else datetime.datetime.now() + if dt is None: + return False + formatted = dt.strftime("%Y-%m-%d %H:%M:%S") + return run(['sudo', 'hwclock', '--set', '--date', formatted]) @cmd @needs_root @@ -618,9 +638,7 @@ def setup_rtc(): f.write(f'\n# PCF8523 RTC support\n{overlay_line}\n') print(f'RTC overlay added to {RPI_CONFIG}') print('\nRTC setup complete. Reboot for changes to take effect.') - print('After reboot, set the RTC time if this is the first setup:') - print(' 1. Set system time: sudo timedatectl set-time "YYYY-MM-DD HH:MM:SS"') - print(' 2. Sync to RTC: sudo hwclock --systohc') + print('After reboot, use the `set-rtc-time` command to set the RTC time.') return True @cmd From 0e27f3e33741c08a7c28524cafadefffea45d374 Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Mon, 2 Mar 2026 17:47:38 +0100 Subject: [PATCH 3/4] Fix calls --- simoc-sam.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simoc-sam.py b/simoc-sam.py index 76cbb756..0d670aa5 100644 --- a/simoc-sam.py +++ b/simoc-sam.py @@ -600,10 +600,10 @@ def enable_i2c(): def parse_timestamp(timestamp): """Parse a timestamp string (ISO format or Unix timestamp).""" try: - return datetime.fromisoformat(timestamp) + return datetime.datetime.fromisoformat(timestamp) except ValueError: try: - return datetime.fromtimestamp(float(timestamp)) + return datetime.datetime.fromtimestamp(float(timestamp)) except ValueError as e: print(f'Error: Invalid timestamp format: {e}') print('Use ISO format (YYYY-MM-DD HH:MM:SS) or Unix timestamp.') From c70562f08e8b005fc4743e8dddf7b30b7ca7d1ab Mon Sep 17 00:00:00 2001 From: Ezio Melotti Date: Mon, 2 Mar 2026 18:15:53 +0100 Subject: [PATCH 4/4] Show the current times in set-rtc-time --- simoc-sam.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simoc-sam.py b/simoc-sam.py index 0d670aa5..6a3d8290 100644 --- a/simoc-sam.py +++ b/simoc-sam.py @@ -616,7 +616,8 @@ def set_rtc_time(timestamp=None): if dt is None: return False formatted = dt.strftime("%Y-%m-%d %H:%M:%S") - return run(['sudo', 'hwclock', '--set', '--date', formatted]) + return (run(['sudo', 'hwclock', '--set', '--date', formatted]) and + run(['timedatectl', 'status'])) @cmd @needs_root