Charge Nudge checks Hyundai Bluelink's cached vehicle state during a configurable daily window and sends at most one Telegram alert per day when the EV battery is below a configurable threshold and the car is not plugged in.
It never requests a forced vehicle refresh, so polling does not deliberately wake the car.
The Hyundai dependency requires Python 3.12 or newer. On a Mac with Homebrew:
brew install python@3.12
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e '.[dev]'
cp .env.example .env
chmod 600 .envFill in .env with the same credentials used by the Hyundai Bluelink app. The
defaults select Europe (1) and Hyundai (2). .env and runtime state are
excluded from Git.
First prove read-only vehicle access:
charge-nudge statusExpected output resembles:
KONA
Battery: 47%
Range: 128 mi
Plugged in: No
Charging: No
Locked: Yes
Last updated: 2026-09-06 18:42 BST
Fields that the vehicle does not report are omitted, apart from plugged-in and
charging state where Unknown is shown explicitly.
To discover all populated fields exposed for this particular car, emit the normalized data as JSON:
charge-nudge status --all
charge-nudge status --all > vehicle-data.jsonThis excludes the vehicle ID, VIN, API key material, coordinates, geocoded location and Hyundai's raw vendor payload. They can be included deliberately for local investigation, but the resulting file should not be shared or committed:
charge-nudge status --all --include-sensitive > vehicle-data-sensitive.json- In Telegram, message
@BotFather, run/newbot, and keep the bot token safe. - Open the new bot's chat and send
/start. A bot cannot initiate the chat. - Send the bot any message, then retrieve its updates to find the numeric
message.chat.id:
read -rs "TELEGRAM_SETUP_TOKEN?Telegram bot token: "; echo
curl "https://api.telegram.org/bot${TELEGRAM_SETUP_TOKEN}/getUpdates"
unset TELEGRAM_SETUP_TOKENSet TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID in .env, then test Telegram
and run one alert evaluation:
charge-nudge test-notification
charge-nudge checkRun the test suite with pytest.
The ASUS needs Python 3.12+ (Ubuntu 24.04 already provides it), SSH access from
the Mac, and a server-only .env file.
Create a local, ignored deployment configuration:
cp .deploy.env.example .deploy.envSet its DEPLOY_HOST and DEPLOY_USER values for your Ubuntu server. These
machine-specific details are deliberately kept out of Git.
Bootstrap the first deployment from the Mac:
source .deploy.env
DEPLOY_PATH="${DEPLOY_PATH:-/home/${DEPLOY_USER}/charge-nudge}"
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '${DEPLOY_PATH}'"
rsync -av --exclude .git --exclude .venv --exclude '.env*' \
--exclude '.deploy.env*' \
./ "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/"
ssh "${DEPLOY_USER}@${DEPLOY_HOST}"
cd ~/charge-nudge
cp .env.example .env
chmod 600 .env
nano .env
python3 -m venv .venv
.venv/bin/python -m pip install --upgrade pip
.venv/bin/python -m pip install -e .
.venv/bin/charge-nudge status
./scripts/install-service.shAfter the service is installed, subsequent releases are simply:
./deploy.shValues supplied directly in the environment override .deploy.env. View
production logs with:
sudo journalctl -u charge-nudge -f- Queries Hyundai every
CHECK_INTERVAL_MINUTES(60 by default), only during the configured window. - The default window starts at
NOTIFY_AFTER=17:00and ends, exclusively, atNOTIFY_BEFORE=22:00. - Alerts only when the percentage is strictly below
BATTERY_THRESHOLD. - Stops querying for the rest of the day after an alert is delivered.
- Suppresses the alert when plugged-in state is
trueor unknown ifIGNORE_IF_PLUGGED_IN=true. - Writes
STATE_FILEonly after Telegram confirms delivery, preventing duplicate alerts while still retrying failed notifications. - Keeps a single Hyundai session alive while the service runs.
This uses an unofficial wrapper around Hyundai's private Bluelink API. Hyundai can change that API without notice, so pinning and deliberate upgrades are recommended.