Shell scripts for controlling Tedee Smart Locks via the Tedee Bridge API.
Perfect for automating your lock with crontab or handling webhook events.
- Quick Start
- Project Structure
- Usage
- Automation with Crontab
- Telegram Notifications (Optional)
- Configuration Reference
- Lock States Reference
- Webhook Events
- Troubleshooting
- Tips & Best Practices
- Requirements
- Development
- License
The interactive setup script will guide you through all configuration:
./setup.shThe setup script will:
- Guide you through entering all required settings
- Validate mandatory parameters (Bridge IP, API Token, Device ID)
- Optionally configure Telegram notifications
- Configure your preferred language (English or Spanish)
- Create the configuration file automatically
- Make all scripts executable
To reconfigure later, simply run ./setup.sh again.
Close/lock the door manually to verify everything works:
./bin/closeAdd to crontab to automatically close the door at a specific time:
crontab -e
# Close door every night at 10 PM
0 22 * * * /path/to/tedee-scripts/bin/closeThat's it! π
tedee-scripts/
βββ bin/ # Executable scripts
β βββ callback # Webhook event handler
β βββ close # Close/lock the door
β βββ update # Update repository
βββ config/ # Configuration files
β βββ tedee.conf # Your config (not in git, generated by setup)
βββ lib/ # Shared libraries
β βββ tedee-common.sh # Common functions
βββ locales/ # Internationalization (i18n)
β βββ en.sh # English messages
β βββ es.sh # Spanish messages
βββ setup.sh # Interactive setup
βββ README.md
βββ LICENSE
./bin/closeThe close script will:
- Check bridge connectivity before attempting to close
- Close/lock the door
- Retry on failure (configurable)
- Report lock status
- Send Telegram notification (if configured)
- Validate door state before and after closing
For Tedee Bridge API webhooks:
./bin/callback <event> <timestamp> <data>Example:
./bin/callback "lock-status-changed" "2023-07-25T14:41:48.825Z" '{"deviceType":2,"deviceId":33819,"serialNumber":"19420103-000006","state":6,"jammed":0,"doorState":2}'Update to the latest version from GitHub:
# Update from main branch
./bin/update
# Update from a specific branch
./bin/update developNote: The update script uses curl and tar (no Git required). Perfect for Docker/minimal environments.
This is the main use case for these scripts. Schedule automatic door locking/closing at specific times.
# Edit your crontab
crontab -e
# Close door every night at 10 PM
0 22 * * * /path/to/tedee-scripts/bin/close
# Close every weekday at 11 PM
0 23 * * 1-5 /path/to/tedee-scripts/bin/close
# Close on weekends at midnight
0 0 * * 6,0 /path/to/tedee-scripts/bin/close
# With logging
0 22 * * * /path/to/tedee-scripts/bin/close >> /tmp/tedee-close.log 2>&1Important: Always use absolute paths in crontab!
# Test manually first
./bin/close
# Check crontab logs (macOS)
log show --predicate 'process == "cron"' --last 1h
# Check system log (Linux)
grep CRON /var/log/syslogSchedule automatic script updates:
# Update weekly on Sunday at 3 AM
0 3 * * 0 /path/to/tedee-scripts/bin/update >> /tmp/tedee-update.log 2>&1For easier management of cron jobs through a web interface, you can use crontab-ui with Docker Compose.
Create a docker-compose.yml file in your preferred location:
services:
crontab-ui:
image: alseambusher/crontab-ui:latest
container_name: crontab-ui
restart: unless-stopped
environment:
- TZ=Europe/Madrid # Set your timezone
- BASIC_AUTH_USER= # Set your username for web interface
- BASIC_AUTH_PWD= # Set your password for web interface
ports:
- "8000:8000"
volumes:
- /path/to/tedee:/scripts/tedee # Mount your tedee-scripts directory
# Health check to ensure the service is running
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s- TZ: Set your timezone (e.g.,
Europe/Madrid,America/New_York) - BASIC_AUTH_USER: Username for web interface authentication
- BASIC_AUTH_PWD: Password for web interface authentication
- volumes: Mount the tedee-scripts directory to
/scripts/tedeein the container- Replace
/path/to/tedeewith the absolute path to your tedee-scripts directory
- Replace
# Start the container
docker compose up -d
# Check the logs
docker compose logs -f
# Stop the container
docker compose downNote: On older setups, you may need to use docker-compose instead of docker compose.
Open your browser and navigate to: http://localhost:8000
Login with the credentials you set in BASIC_AUTH_USER and BASIC_AUTH_PWD.
In the web interface, you can add cron jobs that run your tedee scripts:
- Expression:
0 22 * * *(10 PM every day) - Command:
/scripts/tedee/bin/close - Name: Auto-close door at night
The UI provides a visual cron expression builder and validation to make scheduling easier.
To receive notifications about lock events via Telegram, you need to create a Telegram bot and obtain the necessary credentials.
- Open Telegram and search for @BotFather (the official bot for creating bots)
- Start a chat with BotFather and send the command:
/newbot - Follow the prompts:
- Choose a name for your bot (e.g., "My Tedee Lock Bot")
- Choose a username for your bot (must end in 'bot', e.g., "my_tedee_lock_bot")
- BotFather will respond with a message containing your Bot Token
- It looks like:
123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ - Save this token - you'll need it for configuration
- It looks like:
To find your Chat ID (the ID of the chat where notifications will be sent):
Method 1: Using userinfobot
- Search for @userinfobot in Telegram
- Start a chat and send any message
- The bot will reply with your user information, including your Chat ID
- It looks like:
123456789
- It looks like:
Method 2: Using your bot and the Telegram API
- Send a message to your newly created bot (any message works)
- Open this URL in your browser (replace
YOUR_BOT_TOKENwith your actual token):https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates - Look for the
"chat":{"id":field in the JSON response- Example:
"chat":{"id":123456789,...}
- Example:
Once you have your Bot Token and Chat ID:
- Run the setup script:
./setup.sh - When prompted for Telegram configuration:
- Enter your Bot Token when asked
- Enter your Chat ID when asked
- The setup will save these credentials to your config file
Alternatively, you can manually add them to config/tedee.conf:
TELEGRAM_TOKEN="123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ"
CHAT_ID="123456789"Test that notifications work:
# The close script will send a Telegram notification if configured
./bin/closeYou should receive a notification in your Telegram chat!
Note: Telegram notifications are optional. If not configured, the scripts will work normally without sending notifications.
Configuration is stored in config/tedee.conf (automatically created by ./setup.sh).
| Variable | Required | Default | Description |
|---|---|---|---|
BRIDGE_IP |
β Yes | - | Tedee Bridge IP address |
TEDEE_TOKEN |
β Yes | - | Tedee API token |
AUTH_TYPE |
β Yes | encrypted |
Authentication type: encrypted or non-encrypted |
DEVICE_ID |
β Yes | - | Lock device ID |
TELEGRAM_TOKEN |
β No | - | Telegram bot token (for notifications) |
CHAT_ID |
β No | - | Telegram chat ID (for notifications) |
MAX_RETRIES |
β Yes | 3 |
Number of retry attempts |
SLEEP_BETWEEN |
β Yes | 5 |
Seconds between retries |
LOCALE |
β Yes | en |
Language for notifications: en or es |
BRIDGE_IP="192.168.1.100"
TEDEE_TOKEN="your-api-token-here"
AUTH_TYPE="encrypted"
DEVICE_ID="289001"
TELEGRAM_TOKEN="123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ"
CHAT_ID="123456789"
MAX_RETRIES=3
SLEEP_BETWEEN=5
LOCALE="en"Understanding lock states helps with debugging and webhook event handling.
| Code | State | Description |
|---|---|---|
| 0 | Uncalibrated | Lock needs calibration |
| 1 | Calibration | Lock is calibrating |
| 2 | Open | π Door is open/unlocked |
| 3 | Partially Open | Partially open |
| 4 | Opening | π Currently opening |
| 5 | Closing | π Currently closing |
| 6 | Closed | π Door is closed/locked |
| 7 | Pull Spring | Pull spring mode |
| 8 | Pulling | Currently pulling |
| 9 | Unknown | Unknown state |
| 255 | Unpulling | Currently unpulling |
The callback script handles all event types from the Tedee Bridge API and sends Telegram notifications for lock events.
Note: Webhook setup requires Telegram notifications to be configured. The callback script sends notifications about lock events, so it makes no sense to set up webhooks if you haven't configured Telegram notifications first. See Telegram Notifications section.
To receive webhook events from your Tedee Bridge, you need:
- A server that can receive POST HTTP requests - This can be any server accessible from your local network
- A webhook handler - A service that receives HTTP requests and executes the callback script
- Telegram notifications configured - The callback script sends notifications via Telegram
The easiest way to set up a webhook server is using TheCatLady/docker-webhook with Docker Compose.
Create a docker-compose.yml file in your preferred location:
services:
webhook:
image: thecatlady/webhook:latest
container_name: webhook
command: -verbose -hooks=/config/hooks.yml -hotreload
restart: unless-stopped
environment:
- TZ=Europe/Madrid # Set your timezone
ports:
- "9000:9000"
volumes:
- /path/to/webhook/config:/config
# Mount your tedee-scripts directory
- /path/to/tedee-scripts:/scripts/tedeeConfiguration:
- TZ: Set your timezone (e.g.,
Europe/Madrid,America/New_York) - ports: Exposes webhook server on port 9000 (change if needed)
- volumes:
- Mount a config directory for
hooks.yml - Mount your tedee-scripts directory to
/scripts/tedee
- Mount a config directory for
Create a hooks.yml file in your webhook config directory:
- id: tedee/callback
execute-command: /scripts/tedee/bin/callback
command-working-directory: /scripts/tedee
pass-arguments-to-command:
- source: payload
name: event
- source: payload
name: timestamp
- source: payload
name: dataThis configuration:
- Creates a webhook endpoint at
/hooks/tedee/callback - Executes the callback script when triggered
- Passes event data from the payload to the script
# Start the container
docker compose up -d
# Check the logs to verify it's running
docker compose logs -f webhook
# You should see something like:
# [webhook] 2024/01/08 10:00:00 [webhook] version 2.x.x starting
# [webhook] 2024/01/08 10:00:00 [webhook] serving hooks on http://0.0.0.0:9000/hooks/{id}Note: On older setups, you may need to use docker-compose instead of docker compose.
Once your webhook server is running, you need to register it with your Tedee Bridge.
The Tedee Bridge provides a Swagger UI for API operations:
http://your-bridge-local-ip
Example: http://192.168.1.100
- Open the Swagger UI in your browser
- Look for the authentication section
- Enter your API token (from
config/tedee.conf->TEDEE_TOKEN)
Note: If you have encryption enabled, you may need to temporarily disable it for easier Swagger UI access. After registering the callback, it's recommended to re-enable token encryption for security.
- Find the
POST /callbackendpoint in the Swagger UI - Click "Try it out"
- Use this request body:
{
"url": "http://your-webhook-server-ip:9000/hooks/tedee/callback",
"method": "POST"
}Example:
{
"url": "http://192.168.1.50:9000/hooks/tedee/callback",
"method": "POST"
}- Click "Execute"
- Verify the response is successful (200 OK)
Important: Make sure to use the correct IP address of the machine running your webhook server, not localhost or 127.0.0.1.
After registering, test that webhooks are working:
- Perform an action on your lock (open/close via app)
- Check webhook server logs:
docker compose logs -f webhook - You should see incoming POST requests
- Check that you receive Telegram notifications
The callback script handles all event types from the Tedee Bridge API:
backend-connection-changed- Bridge connection to backend changes (connected/disconnected)device-connection-changed- Device connection status to bridge changes (connected/disconnected)device-settings-changed- Device settings are modifiedlock-status-changed- Lock state changes (includes lock status, jammed status, and door state)device-battery-level-changed- Battery level changes significantlydevice-battery-fully-charged- Battery reaches 100%device-battery-start-charging- Device starts chargingdevice-battery-stop-charging- Device stops charging
You can test the callback script manually without webhooks:
# Timestamp format: ISO 8601 (e.g., 2023-07-25T14:41:48.825Z)
./bin/callback "lock-status-changed" "2023-07-25T14:41:48.825Z" '{"deviceId":289001,"state":6}'This is useful for:
- Testing your Telegram notification setup
- Debugging callback script behavior
- Understanding event data structures
Solutions:
-
Verify webhook server is running:
docker compose ps docker compose logs webhook
-
Test webhook endpoint manually:
curl -X POST http://your-webhook-server-ip:9000/hooks/tedee/callback \ -H "Content-Type: application/json" \ -d '{"event":"test","timestamp":"2024-01-08T10:00:00Z","data":"{}"}' -
Check that callback is registered in Bridge Swagger UI (GET /callback endpoint)
-
Verify network connectivity between Bridge and webhook server:
# From the machine running the bridge ping your-webhook-server-ip
Solutions:
-
Check webhook logs for errors:
docker compose logs -f webhook
-
Verify script permissions inside container:
docker compose exec webhook ls -la /scripts/tedee/bin/callback -
Verify tedee-scripts directory is mounted correctly:
docker compose exec webhook ls -la /scripts/tedee/ -
Test callback script manually from host:
./bin/callback "test" "2024-01-08T10:00:00Z" "{}"
Solutions:
-
Verify Telegram is configured in
config/tedee.conf:grep 'TELEGRAM_TOKEN|CHAT_ID' config/tedee.conf -
Test Telegram notifications work:
./bin/close # Should send a notification -
Check callback script has access to config:
docker compose exec webhook cat /scripts/tedee/config/tedee.conf
If you prefer not to use Docker, you can set up webhooks using:
- webhook binary directly: https://github.com/adnanh/webhook
- nginx + CGI script
- Node.js express server
- Any HTTP server that can execute shell scripts on POST requests
The key requirement is that your server must:
- Accept POST requests at a specific endpoint
- Extract
event,timestamp, anddatafrom the request payload - Execute:
/path/to/tedee-scripts/bin/callback "$event" "$timestamp" "$data"
For complete event documentation and payload structures, see the official Tedee webhook events documentation.
Possible causes:
- Bridge is powered off
- Bridge is not connected to the network
- Wrong IP address in configuration
Solutions:
- Check if bridge is powered on and connected
- Verify
BRIDGE_IPinconfig/tedee.conf - Test connectivity:
ping <BRIDGE_IP> - Check your router to confirm the bridge's IP address
Solution: Run the setup script to create the configuration file:
./setup.shOr verify that config/tedee.conf exists in the correct location.
Solution: Make scripts executable:
chmod +x bin/*
chmod +x setup.shThe setup script should do this automatically, but you can run it manually if needed.
Possible causes:
- Incorrect bot token
- Incorrect chat ID
- Bot hasn't been started (need to send
/startto the bot first)
Solutions:
- Verify
TELEGRAM_TOKENis correct inconfig/tedee.conf - Verify
CHAT_IDis correct - Send
/startto your bot in Telegram - Test with a simple curl command:
curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/sendMessage" \ -d "chat_id=<YOUR_CHAT_ID>" \ -d "text=Test message"
Note: Telegram notifications are optional - scripts work fine without them.
Possible causes:
- Using relative paths instead of absolute paths
- Scripts not executable
- Environment variables not set in cron context
Solutions:
-
Always use absolute paths in crontab:
# Good 0 22 * * * /home/user/tedee-scripts/bin/close # Bad 0 22 * * * ~/tedee-scripts/bin/close 0 22 * * * close
-
Add logging to debug:
0 22 * * * /path/to/tedee-scripts/bin/close >> /tmp/tedee.log 2>&1
-
Check cron logs:
# macOS log show --predicate 'process == "cron"' --last 1h # Linux grep CRON /var/log/syslog
Solution: The close script waits for the lock to reach the closed state. If it times out:
- Check if the lock is physically working (battery, calibration)
- Increase retry attempts in
config/tedee.conf:MAX_RETRIES=5 SLEEP_BETWEEN=10
- Check lock state manually via Tedee app
Always run scripts manually first to verify behavior before adding to crontab:
./bin/close
# Verify it worked, then add to crontabKeep a backup of your config/tedee.conf:
cp config/tedee.conf config/tedee.conf.backupAlways add logging when running from crontab:
0 22 * * * /path/to/tedee-scripts/bin/close >> /tmp/tedee.log 2>&1This helps with debugging if something goes wrong.
Always use absolute paths in crontab to avoid issues:
# Good
0 22 * * * /home/user/tedee-scripts/bin/close
# Also good (if added to PATH)
0 22 * * * closeDon't worry if you don't need notifications - the scripts work perfectly without Telegram.
Run ./setup.sh again to switch between English and Spanish notifications.
Keep your scripts up to date:
./bin/updateOr automate it:
# Update weekly on Sunday at 3 AM
0 3 * * 0 /path/to/tedee-scripts/bin/updateThe close script checks bridge connectivity before each operation, but you can also:
# Add this to crontab to get notified if bridge is down
*/30 * * * * ping -c 1 <BRIDGE_IP> || echo "Bridge is down" | mail -s "Tedee Alert" your@email.comcurl- For API requests and downloading updatessha256sum- For API token generation (orshasum -a 256on macOS)ping- For bridge connectivity checkstar- For extracting updates (usually pre-installed)
All these tools are typically pre-installed on macOS and Linux systems.
The project is structured to make it easy to add new scripts.
- bin/ - Executable scripts that users run directly
- lib/ - Shared library functions (API communication, state checking, notifications)
- locales/ - Internationalization support (en, es)
- config/ - User configuration (generated, not in git)
-
Create a new script in
bin/:touch bin/my-script chmod +x bin/my-script
-
Source the common library:
#!/bin/bash SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" . "$SCRIPT_DIR/../lib/tedee-common.sh"
-
Use shared functions:
load_config get_lock_state "$DEVICE_ID" send_telegram_notification "Your message"
-
Test it:
./bin/my-script
The lib/tedee-common.sh library provides:
load_config()- Load and validate configurationget_lock_state()- Get current lock statewait_for_state()- Wait for lock to reach a specific stateclose_lock()- Close/lock the doorsend_telegram_notification()- Send Telegram messagegenerate_api_key()- Generate API authentication keycheck_bridge_connectivity()- Test bridge connection
See lib/tedee-common.sh for complete function list and documentation.
- Tedee Bridge API Documentation
- Tedee Webhook Events Documentation
- Telegram Bot API
- Crontab Guru - Cron expression generator and explainer
See LICENSE file for details.