fwt_software/include/fgc/mock/MockEnvSensor.h

60 lines
2.2 KiB
C++

#pragma once
#include "fgc/IEnvSensor.h"
#include "fgc/Logger.h"
#include <chrono>
#include <cmath>
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<EnvSample> 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<double>(now - start_).count();
latest_.valid = true;
latest_.temp_c = static_cast<float>(22.0 + 3.0 * std::sin(t * 0.02));
latest_.humidity_pct = static_cast<float>(45.0 + 10.0 * std::sin(t * 0.013 + 1.0));
latest_.timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
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