"""Настройки весов в hardware_settings (симуляция, калибровка).""" from __future__ import annotations import os import platform from typing import Any, Dict, Optional, Tuple from app import db from app.models import HardwareSetting def _env_simulation_override() -> Optional[bool]: raw = os.getenv("WESP_SIMULATION_MODE") if raw is None or not str(raw).strip(): return None return str(raw).strip().lower() in {"1", "true", "yes", "on"} def is_scale_hardware_platform() -> bool: """ Целевая платформа для HX711: Linux на ARM (Raspberry Pi и аналоги). На x86/macOS — False (без опроса датчика и без журнала ошибок). WESP_FORCE_HX711=1|0 — принудительно для отладки. """ force = (os.getenv("WESP_FORCE_HX711") or "").strip().lower() if force in {"1", "true", "yes", "on"}: return True if force in {"0", "false", "no", "off"}: return False if platform.system().lower() != "linux": return False machine = platform.machine().lower() return "arm" in machine or "aarch64" in machine def default_app_landing_path() -> str: """Куда вести после /starting и с корня / на этой машине.""" return "/scales" if is_scale_hardware_platform() else "/login" def setup_complete_redirect(device_role: str | None) -> str: """Куда вести после завершения мастера настройки.""" role = (device_role or "").strip().lower() if role == "client" and is_scale_hardware_platform(): return "/scales" return "/login" def default_simulation_mode_for_platform() -> bool: """ Стартовое значение simulation_mode для новой строки hardware_settings. Везде выкл.; на dev (не ARM) весы работают только после включения симуляции в админке. WESP_SIMULATION_MODE переопределяет платформенный дефолт. """ env = _env_simulation_override() if env is not None: return env return False def ensure_hardware_settings_row() -> HardwareSetting: row = db.session.get(HardwareSetting, 1) if row is None: row = HardwareSetting( id=1, counts_per_kg=1.0, tare_raw=0.0, simulation_mode=default_simulation_mode_for_platform(), simulation_weight_kg=0.0, ) db.session.add(row) db.session.commit() return row def hardware_settings_payload(row: Optional[HardwareSetting] = None) -> Dict[str, Any]: row = row or ensure_hardware_settings_row() return { "simulation_mode": bool(row.simulation_mode), "simulation_weight_kg": float(row.simulation_weight_kg or 0.0), "counts_per_kg": float(row.counts_per_kg or 1.0), "tare_raw": float(row.tare_raw or 0.0), "platform_default_simulation": default_simulation_mode_for_platform(), "platform_machine": platform.machine(), "scale_hardware_platform": is_scale_hardware_platform(), } def set_simulation_mode(enabled: bool) -> Dict[str, Any]: row = ensure_hardware_settings_row() row.simulation_mode = bool(enabled) db.session.commit() return hardware_settings_payload(row) def adjust_simulation_weight(delta_kg: int) -> Tuple[Dict[str, Any], int]: row = ensure_hardware_settings_row() if not row.simulation_mode: raise ValueError("Симуляция выключена — включите её перед изменением веса") current = int(round(float(row.simulation_weight_kg or 0.0))) new_kg = max(0, current + int(delta_kg)) row.simulation_weight_kg = float(new_kg) db.session.commit() return hardware_settings_payload(row), new_kg