Tello-Renewal
中文版 | English Version
Automatic renewal system for Tello mobile plans. Uses CloakBrowser (headless Chromium with 57 source-level patches) to bypass Cloudflare managed challenges on Tello's checkout endpoint.
Features
- 🔄 Automatic plan renewal via CloakBrowser
- 🛡️ Cloudflare bypass via real browser fingerprinting (CloakBrowser)
- 📋 Plan catalog check — monitor available plans without login
- 📧 Email notifications for success / failure
- 🧪 Dry-run mode for safe testing
- 📡 JSON-first CLI output — machine-readable by default,
--humanfor text - ⚙️ YAML configuration with pydantic validation
- 📊 Structured logging with rotation
- 🐳 Docker support — single image with CloakBrowser pre-bundled
Installation
From PyPI
pip install tello-renewal
python -m cloakbrowser install # download patched Chromium (~200 MB, one-time)
Requirements
- Python 3.10+
- CloakBrowser's Chromium is self-contained (downloaded via
python -m cloakbrowser install)
Quick Start
-
Create configuration file:
tello-renewal config-init -
Edit
config.yamlwith your Tello credentials:tello: email: "you@example.com" password: "your_password" card_expiration: "1/27" # MM/YY
-
Test:
tello-renewal config-validate tello-renewal email-test tello-renewal status
-
Renew:
tello-renewal renew --dry-run # test without charging tello-renewal renew # real renewal
Configuration Reference
tello:
email: "you@example.com"
password: "your_password"
card_expiration: "1/27" # MM/YY, MM/YYYY, or YYYY-MM-DD
base_url: "https://tello.com"
login_timeout: 30
browser:
browser_type: "cloakbrowser"
headless: true # false for headed mode (helps with CF)
timeout: 60
# proxy_server: "http://10.0.0.1:7890"
# Expected plan (optional) — status/renew warn on mismatch
plan:
data: "2 GB" # "2 GB", "10 GB", "20 GB", "Unlimited"
call: "Unlimited" # "300 min", "Unlimited"
renewal:
auto_renew: true
days_before_renewal: 1 # start attempting N days before due date
max_retries: 3
retry_delay: 300 # seconds between retries
dry_run: false
state_folder_path: ".tello_state"
smtp:
server: "smtp.gmail.com"
port: 587
username: "you@gmail.com"
password: "app_password"
from_email: '"Tello Renewal" <you@gmail.com>'
use_tls: true
notifications:
email_enabled: true
recipients:
- "admin@example.com"
send_on_success: true
send_on_failure: true
send_on_not_due: false
logging:
level: "INFO"
format: "detailed" # simple | detailed | json
file: "tello_renewal.log"
max_size: "10MB"
backup_count: 5
console_output: true
CLI Commands
tello-renewal renew [--dry-run] [--force] # execute renewal
tello-renewal status # account status and balance
tello-renewal plan-check # list available plan options
tello-renewal config-init [--output FILE] # generate example config
tello-renewal config-validate # validate config file
tello-renewal email-test # send test notification
Global options: --config FILE, --verbose, --human, --version
Output is JSON by default (machine-readable). Add --human for a
human-friendly table/text view:
tello-renewal status # JSON output
tello-renewal --human status # human-readable text
tello-renewal --human plan-check # plan table
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Configuration error |
| 5 | Renewal failed |
| 6 | Not due for renewal |
| 7 | Skipped (cached) |
Docker
The Docker image (python:3.12-slim base) includes CloakBrowser's Chromium pre-downloaded.
docker run --rm --shm-size=256m \
-v /path/to/config:/app/config:ro \
-v /path/to/logs:/app/logs \
oaklight/tello-renewal:latest \
tello-renewal --config /app/config/config.yaml renew
--shm-size=256mis required — Chromium uses/dev/shmfor IPC and crashes with the default 64 MB Docker limit.
Build from source
make build-package # build Python wheel
make build-docker # build Docker image from local wheel
# Optional overrides
make build-docker MIRROR=https://pypi.tuna.tsinghua.edu.cn/simple
make build-docker REGISTRY_MIRROR=docker.1ms.run
Cron with Docker
0 0 * * * docker run --rm --shm-size=256m \
-v ~/.config/tello-renewal:/app/config:ro \
-v /var/log/tello-renewal:/app/logs \
oaklight/tello-renewal:latest \
tello-renewal --config /app/config/config.yaml renew >/dev/null 2>&1
Scheduling (without Docker)
Cron
0 0 * * * /path/to/venv/bin/tello-renewal renew >> /var/log/tello-renewal.log 2>&1
Systemd timer
# /etc/systemd/system/tello-renewal.service
[Unit]
Description=Tello Plan Auto Renewal
After=network.target
[Service]
Type=oneshot
User=tello
ExecStart=/opt/tello-renewal/venv/bin/tello-renewal renew
# /etc/systemd/system/tello-renewal.timer
[Unit]
Description=Run Tello renewal daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl enable --now tello-renewal.timer
Troubleshooting
CloakBrowser binary missing:
python -m cloakbrowser install
Email sending failures:
Use app-specific passwords. Test with tello-renewal email-test.
Debug mode:
tello-renewal --verbose renew --dry-run
Development
git clone https://github.com/Oaklight/Tello-Renewal.git
cd Tello-Renewal
pip install -e ".[dev]"
python -m cloakbrowser install
pytest
ruff check src/
Changelog
See CHANGELOG.md.
License
MIT — see LICENSE.
Disclaimer
Provided as-is for personal automation. You are responsible for complying with Tello's terms of service and for the security of your credentials. The authors are not liable for failed renewals or service interruptions.
Metadata
Release files for tello-renewal 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tello_renewal-0.6.0.tar.gz | 76.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tello_renewal-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 155.2 kB
Release files / tello_renewal-0.6.0.tar.gz
| Download URL | tello_renewal-0.6.0.tar.gz |
|---|---|
| Size | 76.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
76ffa001dbc9a35239273d9a16417e787289f7c59e14e946d1e20eb95325bc72
|
|
BLAKE2b-256 checksum How to use checksums |
a5a6d3691f47bcc58621bac5d629a7f962737dc31d41d5c22c7dbcf6bce5c3a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logRelease files / tello_renewal-0.6.0-py3-none-any.whl
| Download URL | tello_renewal-0.6.0-py3-none-any.whl |
|---|---|
| Size | 78.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ac1fbe5c5c69e8a90411b75253a36e9cf1f1b6edf854801b3da0fdf9cc508457
|
|
BLAKE2b-256 checksum How to use checksums |
b3f894f0324879aa47e70bb627e7d7a8f3849c72ed4c42fc3c7a0c046d259108
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency log