# How Settings Are Managed in TeslaMate: A Deep Dive into the Configuration Layer

> Discover how TeslaMate manages settings using Ecto schemas, PostgreSQL, and side effects. Understand the configuration layer for efficient data persistence and updates.

- Repository: [TeslaMate/teslamate](https://github.com/teslamate-org/teslamate)
- Tags: deep-dive
- Published: 2026-06-18

---

**TeslaMate organizes all configuration within a dedicated Settings context that uses two Ecto schemas—GlobalSettings and CarSettings—to persist data in PostgreSQL and trigger side effects like efficiency recalculation and geocoder refreshes.**

TeslaMate, the open-source Tesla data logger built with Elixir and Phoenix, implements a robust settings management layer that separates global application preferences from per-vehicle configurations. All settings are managed through the `TeslaMate.Settings` context module, which provides a transactional API for reading, updating, and validating configuration data while coordinating side effects across the application's logging, location, and vehicle supervision subsystems.

## The Settings Context Architecture

The settings layer is organized around two distinct Ecto schemas defined in [`lib/teslamate/settings/global_settings.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/settings/global_settings.ex) and [`lib/teslamate/settings/car_settings.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/settings/car_settings.ex).

### GlobalSettings Schema

The **GlobalSettings** schema maps to the `settings` table and stores application-wide options that affect the entire TeslaMate instance. This includes unit preferences (kilometers vs. miles), UI language, theme selection, and base URLs for external services. The schema is defined with strict validation rules and default values to ensure data integrity across the application.

### CarSettings Schema

The **CarSettings** schema persists per-vehicle configuration in the `car_settings` table. These records store charging behavior preferences, streaming API toggles, and an enable/disable flag that controls whether TeslaMate actively monitors a specific vehicle. Each CarSettings record maintains a foreign key relationship to its associated Car record, allowing the context to preload vehicle data when retrieving configuration.

## Reading and Updating Settings via the Public API

The `TeslaMate.Settings` module in [`lib/teslamate/settings.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/settings.ex) exposes a clean public API for interacting with configuration data. All database operations are wrapped in transactions to maintain consistency.

### Retrieving Current Configuration

To fetch the global configuration, use `get_global_settings!/0`, which returns the single global row:

```elixir
global = TeslaMate.Settings.get_global_settings!()
IO.inspect(global.unit_of_length)   # :km or :mi

IO.inspect(global.language)         # e.g., "en"

```

For per-vehicle settings, `get_car_settings/0` returns all car settings pre-loaded with their associated Car records:

```elixir
car_settings = TeslaMate.Settings.get_car_settings()

```

### Updating Settings with Side Effects

The `update_global_settings/2` and `update_car_settings/2` functions wrap changeset-driven updates in transactions and automatically trigger side effects. For example, changing the UI language refreshes geocoded addresses:

```elixir
{:ok, new_global} =
  TeslaMate.Settings.update_global_settings(
    global,
    %{language: "de"}          # change to German

  )

```

Similarly, updating car-specific behavior like the suspend interval uses the car settings changeset:

```elixir
car_settings = Enum.find(TeslaMate.Settings.get_car_settings(), &(&1.car.id == 1))

{:ok, updated} =
  TeslaMate.Settings.update_car_settings(
    car_settings,
    %{suspend_min: 30}         # suspend after 30 minutes of idle

  )

```

### Building Changesets for Forms

For UI forms that require validation before submission, the context exposes `change_global_settings/2` and `change_car_settings/2` to generate raw changesets:

```elixir
changeset = TeslaMate.Settings.change_global_settings(global)

```

## Side Effects and Change Propagation

When settings change, the context module coordinates with other TeslaMate subsystems to ensure data consistency. The `update_global_settings/2` function invokes `on_language_change/2` to trigger `Locations.refresh_addresses/1`, re-geocoding stored locations when the display language changes.

Changing the preferred range setting (ideal vs. rated) automatically calls `Log.recalculate_efficiencies/1` to update efficiency calculations across historical drives. If the `enabled` flag on a car toggles, the context invokes `Vehicles.restart/0` to restart the vehicle supervision tree, immediately applying the new monitoring state.

## The Web Interface

The settings UI is implemented as a Phoenix LiveView module located at [`lib/teslamate_web/live/settings_live/index.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/live/settings_live/index.ex). This component loads current settings, builds changesets for validation, and dispatches updates to the Settings context upon form submission.

The route is mounted at `/settings` in [`lib/teslamate_web/router.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate_web/router.ex), providing a real-time interface where changes are validated and persisted immediately without page reloads.

## Database Persistence and Migrations

All settings are stored in PostgreSQL with standard Ecto migrations. The `settings` table was created in [`priv/repo/migrations/20190731154452_create_settings.exs`](https://github.com/teslamate-org/teslamate/blob/main/priv/repo/migrations/20190731154452_create_settings.exs), while the `car_settings` table added per-vehicle configuration including the `enabled` column in [`priv/repo/migrations/20240603152807_add_enabled_to_car_settings.exs`](https://github.com/teslamate-org/teslamate/blob/main/priv/repo/migrations/20240603152807_add_enabled_to_car_settings.exs).

This migration-based approach ensures that schema changes are version-controlled and deployable across different environments.

## Summary

- **Dual-schema architecture**: TeslaMate separates global preferences (`GlobalSettings`) from per-vehicle options (`CarSettings`) using distinct Ecto schemas.
- **Transactional API**: The `TeslaMate.Settings` context provides `get_global_settings!/0`, `update_global_settings/2`, and car-specific equivalents that wrap database operations in transactions.
- **Automatic side effects**: Changing language refreshes addresses, modifying range preference recalculates efficiencies, and toggling car enabled status restarts vehicle processes.
- **LiveView interface**: The `/settings` route renders a real-time configuration interface using `SettingsLive.Index`.
- **PostgreSQL persistence**: Settings migrate through standard Ecto migration files and maintain relational integrity with the cars table.

## Frequently Asked Questions

### Where are TeslaMate settings stored?

TeslaMate persists all configuration in a PostgreSQL database using two tables: `settings` for global application preferences and `car_settings` for per-vehicle configurations. These tables are managed by Ecto schemas defined in [`lib/teslamate/settings/global_settings.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/settings/global_settings.ex) and [`lib/teslamate/settings/car_settings.ex`](https://github.com/teslamate-org/teslamate/blob/main/lib/teslamate/settings/car_settings.ex), with migrations located in `priv/repo/migrations/`.

### What happens when I change the preferred range setting in TeslaMate?

When you update the preferred range from ideal to rated (or vice versa) via `update_global_settings/2`, the Settings context automatically triggers `Log.recalculate_efficiencies/1`. This function recalculates efficiency metrics across your historical drive data to ensure consistency with the new range preference.

### How can I programmatically subscribe to settings changes for a specific car?

You can subscribe to settings changes using the `subscribe_to_changes/1` function in the Settings context. Pass the car struct as an argument, and your process will receive messages whenever that vehicle's settings are updated:

```elixir
TeslaMate.Settings.subscribe_to_changes(car)

```

### Why does TeslaMate restart vehicle processes when I disable a car?

The `update_car_settings/2` function detects changes to the `enabled` flag and invokes `Vehicles.restart/0` to restart the vehicle supervision tree. This ensures that the streaming API connection and data collection processes are immediately terminated for disabled vehicles or restarted for newly enabled ones, maintaining proper resource management and API rate limit compliance.