Files
bellsystems-cp/backend/config.py
T
bonaminandClaude Opus 5.5 82cf95a9af feat(firmware): ELF symbol store for server-side crash decoding
Crash reports carry elf_sha256 (first 16 hex chars of the crashing build's
ELF SHA-256). ELFs are now stored under that key in
{firmware_storage_path}/elf/, uploaded either with a firmware release
(optional elf_file on POST /upload and PUT /{id}) or standalone via
POST /api/firmware/elf. The ELF is validated before the release is created.

GET /api/firmware/elf/{sha} reports whether that build's ELF exists and
whether the decoder is available; POST /api/firmware/elf/{sha}/decode runs
xtensa-esp32-elf-addr2line -pfiaC over the addresses. The decoder is looked
up via settings.addr2line_path or PATH. It is NOT in the Docker image yet,
so decoding reports "not installed" until the toolchain is added; the
console falls back to a copy-paste addr2line command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 16:28:41 +03:00

97 lines
3.4 KiB
Python

from pydantic_settings import BaseSettings
from typing import List, Dict, Any
import json
class Settings(BaseSettings):
# Firebase
firebase_service_account_path: str = "./firebase-service-account.json"
firebase_storage_bucket: str = ""
# JWT
jwt_secret_key: str = "change-me-in-production"
jwt_algorithm: str = "HS256"
jwt_expiration_minutes: int = 480
# MQTT
mqtt_broker_host: str = "localhost"
mqtt_broker_port: int = 1883
mqtt_admin_username: str = "admin"
mqtt_admin_password: str = ""
mqtt_secret: str = "change-me-in-production"
# Accept the old shared "vesper" password for device-shaped usernames
# (boards on pre-HMAC firmware). Turn off once the logs show no users.
mqtt_allow_legacy_password: bool = True
mosquitto_password_file: str = "/etc/mosquitto/passwd"
mqtt_client_id: str = "bellsystems-admin-panel"
# SQLite (local application database)
sqlite_db_path: str = "./data/database.db"
mqtt_data_retention_days: int = 90
# Postgres
database_url: str = "postgresql+asyncpg://bellsystems_user:password@postgres:5432/bellsystems_db"
# Local file storage
built_melodies_storage_path: str = "./storage/built_melodies"
firmware_storage_path: str = "./storage/firmware"
# xtensa-esp32-elf-addr2line for server-side crash decoding (firmware/elf_store.py).
# Empty = look it up on PATH; if absent, the console shows a copy-paste command instead.
addr2line_path: str = ""
flash_assets_storage_path: str = "./storage/flash_assets"
melody_binaries_storage_path: str = "./storage/melody_binaries"
melody_download_base_url: str = "http://melodies.bellsystems.net/download"
# Email (Resend)
resend_api_key: str = "re_placeholder_change_me"
email_from: str = "noreply@yourdomain.com"
# App
backend_cors_origins: str = '["http://localhost:5173"]'
debug: bool = True
# Nextcloud WebDAV
nextcloud_url: str = ""
nextcloud_username: str = "" # WebDAV login & URL path username
nextcloud_password: str = "" # Use an app password for better security
nextcloud_dav_user: str = "" # Override URL path username if different from login
nextcloud_base_path: str = "BellSystems"
# IMAP/SMTP Email
imap_host: str = ""
imap_port: int = 993
imap_username: str = ""
imap_password: str = ""
imap_use_ssl: bool = True
smtp_host: str = ""
smtp_port: int = 587
smtp_username: str = ""
smtp_password: str = ""
smtp_use_tls: bool = True
email_sync_interval_minutes: int = 15
# Multi-mailbox config (JSON array). If empty, legacy single-account IMAP/SMTP is used.
# Example item:
# {"key":"sales","label":"Sales","email":"sales@bellsystems.gr","imap_host":"...","imap_username":"...","imap_password":"...","smtp_host":"...","smtp_username":"...","smtp_password":"...","sync_inbound":true,"allow_send":true}
mail_accounts_json: str = "[]"
# Auto-deploy (Gitea webhook)
deploy_secret: str = ""
deploy_project_path: str = "/app"
@property
def cors_origins(self) -> List[str]:
return json.loads(self.backend_cors_origins)
@property
def mail_accounts(self) -> List[Dict[str, Any]]:
try:
raw = json.loads(self.mail_accounts_json or "[]")
return raw if isinstance(raw, list) else []
except Exception:
return []
model_config = {"env_file": ".env", "extra": "ignore"}
settings = Settings()