// Package monitor provides a persistent monitor-only mode toggle. // When active, the EMS continues polling and showing the status page // but suppresses all actuator calls (Shelly switches, Viessmann API). // State is stored as a flag file: presence = active, absence = normal. package monitor import ( "os" "sync" ) // Mode is a thread-safe, file-backed monitor-only flag. type Mode struct { mu sync.RWMutex active bool filePath string } // New creates a Mode and loads the current state from the flag file. // If filePath is empty, the mode is in-memory only (not persistent). func New(filePath string) *Mode { m := &Mode{filePath: filePath} if filePath != "" { _, err := os.Stat(filePath) m.active = err == nil // file exists → monitor-only } return m } // IsActive reports whether monitor-only mode is currently enabled. func (m *Mode) IsActive() bool { m.mu.RLock() defer m.mu.RUnlock() return m.active } // Set enables or disables monitor-only mode and persists the change to disk. func (m *Mode) Set(active bool) error { m.mu.Lock() defer m.mu.Unlock() m.active = active if m.filePath == "" { return nil // in-memory only } if active { f, err := os.Create(m.filePath) if err != nil { return err } return f.Close() } err := os.Remove(m.filePath) if os.IsNotExist(err) { return nil } return err }