#pragma once #include "fgc/IEnvSensor.h" #include "fgc/Logger.h" #include #include namespace fgc { // Simulated ambient sensor for development without hardware: synthesizes a // slowly varying, plausible temp/humidity reading so the Sensors panel // animates without an SHT41 attached. // // It holds each reading for `period`, exactly as the real driver does (which // only refreshes latest/timestamp_ms once per [Env] period_ms). Stamping a new // timestamp on every sample() call would make every ~10 ms control tick look // like a fresh reading, and Application's "publish once per fresh sample" check // keys on that timestamp - so the mock would publish Env hundreds of times a // second where the real sensor publishes once every two seconds. class MockEnvSensor : public IEnvSensor { public: explicit MockEnvSensor(std::chrono::milliseconds period = std::chrono::milliseconds(2000)) : period_(period) {} void start() override { start_ = clock::now(); LOG_INFO << "[mock] env sensor started"; } void stop() override { LOG_INFO << "[mock] env sensor stopped"; } bool connected() const override { return true; } std::optional sample() override { const auto now = clock::now(); if (latest_.valid && (now - taken_) < period_) return latest_; // same reading as before const double t = std::chrono::duration(now - start_).count(); latest_.valid = true; latest_.temp_c = static_cast(22.0 + 3.0 * std::sin(t * 0.02)); latest_.humidity_pct = static_cast(45.0 + 10.0 * std::sin(t * 0.013 + 1.0)); latest_.timestamp_ms = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); taken_ = now; return latest_; } std::string name() const override { return "SHT41 (mock)"; } private: using clock = std::chrono::steady_clock; clock::time_point start_ = clock::now(); std::chrono::milliseconds period_; EnvSample latest_; clock::time_point taken_{}; }; } // namespace fgc