Files
Button/collector/config.py
T
GrigoandClaude Opus 5.5 115879ab67 collector: survive bluetoothd hangs and restarts
- every BlueZ call runs off the asyncio thread with a timeout; if bluetoothd
  stays unresponsive for 30 s the collector restarts bluetooth.service and
  exits for a clean re-registration
- Type=notify + WatchdogSec for buttontask-collector, never give up restarting
- bluetooth.service drop-in: Restart=always (BlueZ 5.55 crashes on assert/SEGV),
  installed by device-install.sh and OTA (bt-update)
- bt-service: bluez-restart action for the collector

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 07:10:02 +00:00

84 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""Collector constants and filesystem paths."""
import os
from pathlib import Path
N = 4
DEFAULT_REPORT_INTERVAL_MIN = 30
STALE_PERIODS = 3 # k: silence for k*period → stale; another k → lost
TICK_INTERVAL_S = 0.5 # connect poll + flush cadence
ADV_DEBOUNCE_S = 1.0
UI_LOG_LIMIT = 200
# BlueZ health. Every BlueZ call gets a timeout; if bluetoothd keeps failing
# for BLUEZ_HANG_S, the collector restarts bluetooth.service and exits so
# systemd starts it again with a clean registration.
BLUEZ_CALL_TIMEOUT_S = 8.0 # wrapper timeout around one blocking/async BlueZ call
BLUEZ_START_TIMEOUT_S = 30.0 # GATT server start
BLUEZ_HANG_S = 30.0
BLUEZ_OWNER_CHECK_S = 2.0
BT_SERVICE_HELPER = "/opt/buttontask/scripts/bt-service"
SERVICE_UUID = "0000a000-0000-1000-8000-00805f9b34fb"
CHAR_REPORT_UUID = "0000a001-0000-1000-8000-00805f9b34fb"
CHAR_INTERVAL_UUID = "0000a002-0000-1000-8000-00805f9b34fb"
CHAR_SLOT_UUID = "0000a011-0000-1000-8000-00805f9b34fb"
# 16-bit forms for advertising
SERVICE_UUID_16 = 0xA000
COMPANY_ID = 0xFFFF # placeholder manufacturer id
ADV_VERSION = 1
LOCAL_NAME = "BTCollector"
def install_root() -> Path:
env = os.environ.get("BUTTONTASK_ROOT")
if env:
return Path(env)
return Path("/opt/buttontask")
def config_dir() -> Path:
p = install_root() / "config"
p.mkdir(parents=True, exist_ok=True)
return p
def run_dir() -> Path:
p = install_root() / "run"
p.mkdir(parents=True, exist_ok=True)
return p
def registry_path() -> Path:
return config_dir() / "sensors-registry.json"
def names_path() -> Path:
return config_dir() / "sensors-names.json"
def settings_path() -> Path:
return config_dir() / "sensors-settings.json"
def status_path() -> Path:
return run_dir() / "sensors-status.json"
def ui_log_path() -> Path:
return run_dir() / "sensors-ui.log"
def cmd_path() -> Path:
return run_dir() / "sensors-cmd"
def history_path() -> Path:
return run_dir() / "sensors-history.json"
def collector_log_path() -> Path:
return run_dir() / "collector.log"