A clock that speaks the current time using ElevenLabs API
Project description
Speaking Clock
A small utility that speaks (usually current) time in specified language. Uses ElevenLabs API to generate the speech. Supports caching and reusing audio files so free ElevenLabs access is more than enough. Handy to sit in cron jobs to periodically announce the time.
Features
- Gets the current time and speaks it in specified language
- Uses ElevenLabs API for high-quality text-to-speech
- Caches generated audio files for quick reuse
- Supports both 12-hour and 24-hour time formats
- Optional audio chime before speaking the time
- Parallel processing - prepares audio while chime is playing
- Overlaid audio playback with configurable timing offset
- Command-line interface driven, perfect for background jobs like cron
Installation
This app is regular Python package and is also hosted
on PyPi so you can install it as usual. But because this
one is supposed to rather act as the application, I strongly recommend to
use pipx to install this tool in isolated environment be it on Linux,
Windows or MacOS machines. Once you got pipx up and running, install the package:
$ pipx install speaking-clock
Usage
Once installed, you can use the command-line interface:
$ speak-time
Configuration
The speaking-clock looks for configuration in the following places:
- Command-line specified config (if provided)
- User config file at
~/.config/speaking-clock/config.yml - Default configuration built into the package
You can create a config file at ~/.config/speaking-clock/config.yml with the following structure:
language:
code: "pl" # Language code matching a file in 'languages/' directory
use_24h_clock: true # Use 24-hour (true) or 12-hour (false) format
elevenlabs:
api_key: "your-api-key-here" # Your ElevenLabs API key
voice_id: "voice-id-here" # ElevenLabs voice name or ID
model_id: "eleven_multilingual_v2" # TTS model to use
audio:
play_chime: true # Play a chime before speaking the time
chime_file: "clock-chime.mp3" # Path to the chime audio file
overlay_speech: true # Overlay speech over the chime sound
speech_offset_ms: 1000 # Milliseconds to wait before starting speech
cache:
enabled: true # Read and write cached announcements
directory: "~/.cache/speaking-clock" # Optional. Overrides the XDG default location
Voice fallbacks
voice_id also takes a list, which turns each entry into a fallback for the one before it:
elevenlabs:
voice_id:
- "Bratanek"
- "George"
Voices are tried in order, and each one is tried in full before the next: its cached announcements first, then the API. So a voice that has become unavailable - one that moved behind a paid tier, say - keeps playing back whatever was cached while it still worked, and announcements it never cached come from the next voice in the list. The run fails only when every voice misses both its cache and the API.
You can also set your ElevenLabs API key as an environment variable:
export ELEVENLABS_API_KEY="your-api-key-here"
Using custom configuration file
You can specify a custom config file:
speak-time --config /path/to/your/config.yml
Language Support
The application supports multiple languages through YAML language definition files. These files are
stored in the languages/ directory with filenames matching their language code (e.g., pl.yml
for Polish).
To add support for a new language:
- Create a new YAML file in the
languages/directory (e.g.,en.ymlfor English) - Define the language elements following the structure in the existing language files
- Update the
language.codevalue inconfig.ymlto match your new language file
Example language file structure:
days_of_week:
- poniedziałek # Monday
- wtorek # Tuesday
# ...
hours:
0: dwudziesta czwarta
1: pierwsza
# ...
special_minutes:
0: ""
15: piętnaście
# ...
special_times:
midnight: północ, nastał {day_name}
Cache Files
Audio files are automatically cached in $XDG_CACHE_HOME/speaking-clock, falling back to
~/.cache/speaking-clock when XDG_CACHE_HOME is unset (or holds a relative path). Set
cache.directory in the config file, or pass --cache <DIR>, to use another location.
Cached files follow the naming convention:
LANG-VOICE-HH-MM.mp3
For example:
pl-voice_id-13-05.mp3 # Polish, voice_id, 13:05
This caching system ensures that each unique time announcement is only generated once, reducing API calls to ElevenLabs and improving response time for frequently requested times.
Pass --no-cache to bypass the cache for a single run - the announcement is then generated fresh
and is not written to disk:
speak-time --no-cache
Set cache.enabled: false in the config file to disable caching permanently. Note that with the
cache off, a voice that is no longer available from the API can no longer fall back to what it
cached earlier, so a voice chain loses that safety net.
Audio Support for Cron Jobs in KDE 5
Problem
When running Python applications from cron jobs in KDE 5, audio playback doesn't work automatically. This is because cron jobs run in a separate environment without access to your desktop session's audio system.
Solution
Configure the cron job with specific environment variables to access your KDE desktop session's audio services.
Required Environment Variables
For audio playback in KDE 5, your cron job needs these key environment variables:
DISPLAY: Points to your X server displayDBUS_SESSION_BUS_ADDRESS: Connects to your D-Bus sessionXDG_RUNTIME_DIR: Required for PulseAudio/PipeWire access
Setting Up the Cron Job
Edit your crontab:
crontab -e
Add your job using this template:
# Run every hour at minute 0
0 * * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME plasma-session)/environ | cut -d= -f2-) XDG_RUNTIME_DIR=/run/user/$(id -u) python /path/to/your/script.py
Testing Your Configuration
To test without waiting for the scheduled time:
# Test the exact command that cron will run
DISPLAY=:0 \
DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS \
/proc/$(pgrep -u $LOGNAME plasma-session)/environ | cut -d= -f2-) \
XDG_RUNTIME_DIR=/run/user/$(id -u) \
python /path/to/your/script.py
Troubleshooting
Common Issues and Solutions
- No audio despite correct configuration:
- Ensure PulseAudio is running:
pulseaudio --check - Try adding
PULSE_SERVER=unix:${XDG_RUNTIME_DIR}/pulse/nativeto your environment variables
- D-Bus address not found:
- If plasma-session isn't found, try:
pgrep -u $LOGNAME plasmashellinstead
- Permission issues:
- Check audio group membership:
groups | grep audio - Add yourself if needed:
sudo usermod -a -G audio $USER
- Application-specific audio servers:
- For PipeWire: Add
PIPEWIRE_RUNTIME_DIR=${XDG_RUNTIME_DIR}/pipewire-0
Limitations
This solution only works when:
- You are logged into your KDE session
- You are using the same user account for both KDE and the cron job
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file speaking_clock-1.1.0.tar.gz.
File metadata
- Download URL: speaking_clock-1.1.0.tar.gz
- Upload date:
- Size: 108.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ecd7bb28fc80a21a3a2876a5c1d5aff5aa59c1530c60dc06aa07c77b296028c1
|
|
| MD5 |
537aa304ced2fb7e42dd1a99f934340e
|
|
| BLAKE2b-256 |
deb58524e3ff29973e2264203f2def18f36e022f4b3790766e11cb3cd80d2548
|
File details
Details for the file speaking_clock-1.1.0-py3-none-any.whl.
File metadata
- Download URL: speaking_clock-1.1.0-py3-none-any.whl
- Upload date:
- Size: 108.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cae033b0c3e86afb54bcebabd118fecaa7c9a0252bf8e93252cf998f528adcdc
|
|
| MD5 |
4a59385bbe95640b843df19041b265f0
|
|
| BLAKE2b-256 |
714c4dcad732196d66659235666156e8700e5e675bf21c27354aa88b007dfc1f
|