Files
smartphone-n8n-tracking/CLAUDE.md
Joachim Hummel 59c46a023b Überarbeite Dokumentation auf aktuellen MQTT-only Stand
- README.md komplett neu geschrieben:
  - Fokus auf n8n-tracker.json (MQTT-only)
  - Entfernt: Telegram-Workflows, Datei-basierte Speicherung
  - Hinzugefügt: OwnTracks-Setup, Geräte-Mapping, erweiterte Features
  - Neue Sektionen: Sicherheitshinweise, DSGVO-Compliance
  - Praktische Code-Beispiele für Customization

- CLAUDE.md aktualisiert:
  - Neue Workflow-Architektur dokumentiert
  - NocoDB-Schema mit battery/speed Feldern
  - Web-Interface Details (Filter, Kartenebenen, Marker)
  - Wichtige Gotchas und Edge Cases hinzugefügt

- Dateien bereinigt:
  - Gelöscht: tracker.json, tracker-db.json, tracker-mqtt.json
  - Gelöscht: index_owntrack.html, locations-example.csv
  - Hinzugefügt: n8n-tracker.json (aktueller Workflow)
  - Hinzugefügt: database-example.csv (aktuelles Schema)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 18:47:05 +00:00

13 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

This repository contains an MQTT-based location tracking system using n8n and NocoDB:

  • n8n-tracker.json - MQTT/OwnTracks workflow with NocoDB storage
  • index.html - Web interface with device filtering, time-based filtering, and multiple map layers

The system subscribes to MQTT topics (OwnTracks-compatible), processes location data, stores it in NocoDB, and provides both a REST API and web visualization.

Workflow Architecture

The n8n-tracker.json workflow contains two independent execution flows:

1. MQTT Location Capture Flow

MQTT Trigger (owntracks/#)
    ↓
MQTT Location verarbeiten (JavaScript: Parse JSON, transform data)
    ↓
Speichere in NocoDB (Create record with lat/lon, battery, speed, etc.)

Key nodes:

  • MQTT Trigger: Subscribes to owntracks/# topic, receives JSON messages from OwnTracks devices
  • MQTT Location verarbeiten:
    • Parses the message field (JSON string)
    • Validates required fields (lat, lon, tst)
    • Transforms OwnTracks format to NocoDB schema
    • Extracts telemetry data (battery, velocity, accuracy, altitude, etc.)
    • Converts Unix timestamp to ISO 8601 format
  • Speichere in NocoDB: Stores location with metadata in database

2. Location API Flow

Webhook - Location API (GET /webhook/location)
    ↓
Lade Daten aus NocoDB (Get all records)
    ↓
Format API Response (JavaScript: Sort, structure JSON)
    ↓
JSON Response (CORS-enabled)

Key nodes:

  • Webhook - Location API: Public endpoint at /webhook/location with CORS enabled
  • Lade Daten aus NocoDB: Fetches all location records from database
  • Format API Response: Sorts by timestamp (newest first), builds response structure
  • JSON Response: Returns structured JSON with CORS headers

Key Technical Details

Data Storage

NocoDB Database Configuration:

  • Project ID: pdxl4cx4dbu9nxi
  • Table ID: m8pqj5ixgnnrzkg
  • Credential ID: T9XuGr6CJD2W2BPO (NocoDB Token account)
  • Persistence: Full database persistence (no client-side limit)

NocoDB Schema

The database stores location records with the following fields:

latitude        (Decimal)     - Geographic latitude
longitude       (Decimal)     - Geographic longitude
timestamp       (DateTime)    - ISO 8601 timestamp
user_id         (Number)      - Always 0 for MQTT devices
first_name      (Text)        - Tracker ID (e.g., "10", "11")
last_name       (Text)        - Source type (e.g., "fused")
username        (Text)        - Same as tracker ID
marker_label    (Text)        - Display label for map markers
display_time    (Text)        - Formatted timestamp (de-DE locale)
chat_id         (Number)      - Always 0 for MQTT devices
battery         (Number)      - Battery percentage (0-100)
speed           (Decimal)     - Velocity in m/s

OwnTracks Data Mapping

The MQTT transformation node maps OwnTracks JSON fields to NocoDB schema:

NocoDB Field OwnTracks Field Transformation
latitude lat Direct mapping
longitude lon Direct mapping
timestamp tst Unix timestamp → ISO 8601
user_id - Static: 0
first_name tid Tracker ID (device identifier)
last_name source Location source (e.g., "fused")
username tid Same as tracker ID
marker_label tid Used for map display
display_time tst Formatted with de-DE locale
chat_id - Static: 0
battery batt Battery percentage
speed vel Velocity in m/s

Additional OwnTracks data available but NOT stored:

  • acc - Accuracy in meters
  • alt - Altitude
  • cog - Course over ground
  • conn - Connection type (w=WiFi, m=Mobile)
  • _id - Device identifier

API Response Structure

{
  "success": true,
  "current": <most recent location object>,
  "history": [<array of all location objects>],
  "total_points": number,
  "last_updated": "ISO 8601 string"
}

Web Interface (index.html)

The web interface is a single-page application built with Leaflet.js:

Configuration:

  • API Endpoint: https://n8n.unixweb.home64.de/webhook/location (line 178)
  • Default View: Munich (48.1351, 11.5820) at zoom level 12
  • Auto-refresh: 5 second interval (configurable)

Key Features:

  1. Multiple Map Layers (lines 158-171):

    • Standard (OpenStreetMap)
    • Satellite (Esri World Imagery)
    • Terrain (OpenTopoMap)
    • Dark Mode (CartoDB Dark)
  2. Device Mapping (lines 142-152):

    • Hardcoded device names: '10' → "Joachim Pixel", '11' → "Huawei Smartphone"
    • Device-specific colors: Red (#e74c3c) for device 10, Blue (#3498db) for device 11
    • Important: Device names are mapped from the username field (which contains the tracker ID)
  3. Filtering System:

    • Device Filter: Dropdown populated dynamically from available username values
    • Time Filter: 1h, 3h, 6h, 12h, 24h (default: 1 hour)
    • Filter logic: Always filters to user_id == 0 (MQTT-only), then applies device and time filters
  4. Visualization (lines 284-376):

    • Markers: Circular SVG icons with navigation-style clock hand
    • Size: Latest location = 32x32px, history = 16x16px
    • Colors: Device-specific colors from DEVICE_COLORS mapping
    • Polylines: Shows movement path per device, color-coded
    • Popups: Show device name, timestamp, battery %, speed (km/h)

Important Implementation Details:

  • The username field filter logic (line 267) filters MQTT data by checking user_id == 0
  • Device colors and names must be updated in the hardcoded mappings (lines 142-152)
  • Speed conversion: OwnTracks velocity (m/s) is converted to km/h with speed * 3.6 (line 329)

Workflow Configuration (n8n-tracker.json)

Workflow Settings:

  • Name: "Telegram Location Tracker - NocoDB"
  • Workflow ID: 6P6dKqi4IKcJ521m
  • Version ID: de17706a-a0ea-42ce-a069-dd09dce421d2
  • Execution Order: v1
  • Caller Policy: workflowsFromSameOwner
  • Status: active: true
  • Error Workflow: 0bBZzSE6SUzVsif5
  • Tags: "owntrack"

Credentials:

  • MQTT: Credential ID L07VVR2BDfDda6Zo ("MQTT account")
  • NocoDB: Credential ID T9XuGr6CJD2W2BPO ("NocoDB Token account")

Node Configuration:

  • MQTT Trigger:

    • Topic: owntracks/#
    • Subscribes to all OwnTracks topics
    • No message filtering at trigger level (all messages pass through)
  • MQTT Location verarbeiten (Code Node):

    • Parses JSON from message field
    • Validates required fields: lat, lon, tst
    • Skips invalid messages with continue
    • Sets alwaysOutputData: true to handle empty results
    • Timezone: Europe/Berlin for display_time
  • Speichere in NocoDB:

    • Operation: create
    • Maps 12 fields from JSON to NocoDB columns
    • Includes telemetry: battery (from mqtt_data.battery), speed (from mqtt_data.velocity)
  • Webhook - Location API:

    • Path: /location
    • Webhook ID: location-api-endpoint
    • Response Mode: lastNode
    • CORS: Allowed origins = *

Common Modifications

Adding a New Device

Step 1: Update index.html device mappings (lines 142-152)

const DEVICE_NAMES = {
    '10': 'Joachim Pixel',
    '11': 'Huawei Smartphone',
    '12': 'New Device Name'  // Add this line
};

const DEVICE_COLORS = {
    '10': '#e74c3c',
    '11': '#3498db',
    '12': '#2ecc71',  // Add this line (green)
    'default': '#95a5a6'
};

Step 2: Configure OwnTracks app

  • Set Tracker ID (tid) to match the key (e.g., "12")
  • Topic will be owntracks/user/12
  • The workflow automatically picks up new devices

Changing Date/Time Format

In n8n workflow node "MQTT Location verarbeiten" (line 124):

// Current: German format with Berlin timezone
const displayTime = new Date(timestampMs).toLocaleString('de-DE', { timeZone: 'Europe/Berlin' });

// Change to US format:
const displayTime = new Date(timestampMs).toLocaleString('en-US', { timeZone: 'America/New_York' });

// Change to ISO format:
const displayTime = new Date(timestampMs).toISOString();

Restricting CORS (Security)

In n8n workflow node "Webhook - Location API" (lines 65-75):

// Current (insecure):
{ "name": "Access-Control-Allow-Origin", "value": "*" }

// Change to specific domain:
{ "name": "Access-Control-Allow-Origin", "value": "https://web.unixweb.home64.de" }

Adding New NocoDB Fields

Example: Store accuracy and altitude

Step 1: Add columns in NocoDB:

  • accuracy (Number)
  • altitude (Number)

Step 2: Update "MQTT Location verarbeiten" node (line 124):

mqtt_data: {
    accuracy: mqttData.acc,
    altitude: mqttData.alt,
    battery: mqttData.batt,
    velocity: mqttData.vel,
    // ... existing fields
}

Step 3: Update "Speichere in NocoDB" node to map new fields:

{ "fieldName": "accuracy", "fieldValue": "={{ $json.mqtt_data.accuracy }}" },
{ "fieldName": "altitude", "fieldValue": "={{ $json.mqtt_data.altitude }}" }

Changing MQTT Topic Filter

In node "MQTT Trigger" (line 104):

// Current: All OwnTracks topics
topics: "owntracks/#"

// Change to specific user:
topics: "owntracks/joachim/#"

// Change to specific device:
topics: "owntracks/joachim/pixel"

// Multiple topics:
topics: "owntracks/joachim/#,owntracks/lisa/#"

Updating API Endpoint URL

In index.html (line 178):

// Current:
const API_URL = 'https://n8n.unixweb.home64.de/webhook/location';

// Change to your n8n instance:
const API_URL = 'https://your-n8n.example.com/webhook/location';

Changing Auto-Refresh Interval

In index.html (line 419):

// Current: 5 seconds
refreshInterval = setInterval(loadLocations, 5000);

// Change to 10 seconds:
refreshInterval = setInterval(loadLocations, 10000);

// Change to 30 seconds:
refreshInterval = setInterval(loadLocations, 30000);

Repository Contents

File Description
n8n-tracker.json n8n workflow - MQTT location capture + API endpoint
index.html Web interface with multi-layer maps and device filtering
database-example.csv Sample NocoDB export showing actual data structure
README.md Comprehensive German documentation (setup, usage, troubleshooting)
CLAUDE.md This file - technical architecture documentation

Important Gotchas and Edge Cases

1. Device Identification via username Field

  • The username field contains the OwnTracks tracker ID (tid), not a username
  • The web interface filters devices by username, not by first_name or marker_label
  • Example: Device with tid: "10" will have username: "10" in database
  • Device names are hardcoded in index.html (lines 142-145) - must be manually updated

2. MQTT Message Validation

  • The workflow does NOT filter by _type: "location" despite what older documentation says
  • All MQTT messages are processed; validation happens in the JavaScript code node
  • Messages missing lat, lon, or tst are silently skipped with continue
  • Result: Non-location MQTT messages don't cause errors, they're just ignored

3. Time Filter Default

  • The web interface defaults to 1 hour time filter (line 125)
  • This means newly deployed users won't see historical data unless they change the filter
  • Consider changing default to 24h or all for better initial experience

4. Circular Marker Icon Implementation

  • Markers use SVG divIcon with a navigation-style clock hand (lines 337-345)
  • The clock hand is purely decorative, does NOT represent actual direction/heading
  • This replaced standard Leaflet pin icons in recent commits (see commit 4bec87d)

5. Speed Unit Conversion

  • OwnTracks sends velocity in m/s (vel field)
  • Stored in database as m/s in speed column
  • Converted to km/h in web UI with speed * 3.6 (line 329)
  • Important: If you display speed elsewhere, remember to convert

6. Battery Data May Be Null

  • Not all OwnTracks messages include battery data
  • The code checks for battery !== undefined && battery !== null before displaying (line 323)
  • Same applies to speed field (line 328)

7. CORS Configuration

  • API has CORS set to * (all origins allowed)
  • This is intentional for development but insecure for production
  • See "Restricting CORS" section for how to fix

8. Error Workflow Reference

  • The workflow references error workflow ID 0bBZzSE6SUzVsif5
  • This error workflow is NOT included in the repository export
  • If importing to a new n8n instance, errors will fail silently without this workflow

9. Timezone Handling

  • All timestamps are converted to Europe/Berlin timezone (line 124 in workflow)
  • This is hardcoded in the JavaScript transformation
  • Database stores ISO 8601 UTC timestamps, but display_time is Berlin time