diff --git a/README.md b/README.md index 9f02093..0a2ee70 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,78 @@ Messages are prefixed with the topic for context: ### Webhook returns 401 - Token mismatch — check `hooks.token` in Clawdbot config matches `CLAWDBOT_TOKEN` +--- + +## Tesla Arrival Notifier + +A specialized component that monitors TeslaMate MQTT for car state changes and notifies Clawdbot when you arrive somewhere. + +### How It Works + +1. Subscribes to TeslaMate MQTT topics (`teslamate/cars//state`, `geofence`, `latitude`, `longitude`) +2. Detects when car state transitions from `driving` → any stationary state (`online`, `parked`, `charging`, `suspended`, `asleep`, `offline`) +3. Sends arrival notification to Clawdbot with geofence name (or reverse-geocoded address) +4. Clawdbot checks `location-reminders.json` for location-specific reminders + +### Installation + +```bash +# Install to /opt +sudo mkdir -p /opt/mqtt-clawdbot-bridge +sudo cp arrival-notifier.js package*.json /opt/mqtt-clawdbot-bridge/ +cd /opt/mqtt-clawdbot-bridge && npm install + +# Install systemd service +sudo cp arrival-notifier.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable arrival-notifier +sudo systemctl start arrival-notifier +``` + +### Configuration + +Environment variables (configured in the systemd service file): + +| Variable | Default | Description | +|----------|---------|-------------| +| `MQTT_URL` | `mqtts://mqtt.teslamate.olex.me:8883` | TeslaMate MQTT broker | +| `MQTT_USERNAME` | `olex` | MQTT username | +| `MQTT_PASSWORD` | — | MQTT password (**required**) | +| `CLAWDBOT_URL` | `http://127.0.0.1:18789` | Clawdbot gateway URL | +| `CLAWDBOT_TOKEN` | — | Webhook token (**required**) | +| `CAR_ID` | `14` | TeslaMate car ID | +| `LOG_LEVEL` | `info` | `debug` for verbose output | + +### Managing the Service + +```bash +# Check status +sudo systemctl status arrival-notifier + +# View logs +journalctl -u arrival-notifier -f + +# Restart after config changes +sudo systemctl restart arrival-notifier +``` + +### Location Reminders + +Create `~/clawd/location-reminders.json`: + +```json +{ + "Zuhause (Geißberg 31)": [ + "Reminder: Check the mailbox!" + ], + "Arbeit (GUDE)": [ + "Remember to submit timesheet on Fridays" + ] +} +``` + +Geofence names must match exactly as shown in TeslaMate. + ## License MIT diff --git a/arrival-notifier.js b/arrival-notifier.js index b2e1c7d..48f2b5f 100644 --- a/arrival-notifier.js +++ b/arrival-notifier.js @@ -188,12 +188,17 @@ async function main() { username: config.mqtt.username, password: config.mqtt.password, rejectUnauthorized: true, + keepalive: 60, // Send ping every 60s + reconnectPeriod: 5000, // Retry every 5s on disconnect + connectTimeout: 30000, // 30s connection timeout }; const client = mqtt.connect(config.mqtt.url, mqttOptions); const prefix = `teslamate/cars/${config.carId}`; + let isConnected = false; client.on('connect', () => { + isConnected = true; log.info('Connected to MQTT'); // Subscribe to relevant topics @@ -235,7 +240,22 @@ async function main() { }); client.on('error', (err) => log.error('MQTT error:', err.message)); - client.on('reconnect', () => log.info('Reconnecting...')); + + client.on('reconnect', () => { + log.info('Reconnecting to MQTT...'); + }); + + client.on('close', () => { + if (isConnected) { + log.info('MQTT connection closed'); + isConnected = false; + } + }); + + client.on('offline', () => { + log.info('MQTT client offline'); + isConnected = false; + }); // Graceful shutdown process.on('SIGINT', () => {