blob: 10c7aee25983be4c3e1940135dd6941ca6ace237 [file] [edit]
#ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_EAT_CONTROLLER_H_
#define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_EAT_CONTROLLER_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/base/attributes.h"
#include "absl/base/nullability.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include <nlohmann/json_fwd.hpp>
#include "thermal_config.pb.h"
#include "thermal_controller_specification.pb.h"
#include "tlbmc/thermal/controller/algorithm/eat.h"
#include "tlbmc/thermal/controller/controller.h"
#include "tlbmc/thermal/zone_manager.h"
namespace milotic_tlbmc::thermal {
struct EatControllerParameters {
std::string id;
ZoneManager* absl_nonnull zone_manager ABSL_REQUIRE_EXPLICIT_INIT;
std::unique_ptr<EatThermalLoop> absl_nonnull eat_loop
ABSL_REQUIRE_EXPLICIT_INIT;
// Normally, EAT controller will take in readings from a single sensor.
// However, it is totally reasonable for it to utilize multiple sensors and
// take the average reading as the input.
std::vector<std::string> input_sensors;
std::vector<ZoneManager*> affected_zones;
std::vector<int> affected_zone_ids;
};
/**
* `EatController` reads from ambient temperature sensors and adjusts the
* setpoints of the affected thermal controllers.
*
* This is a special supportive controller, which does not directly control any
* actuators, or directly contribute to the thermal output. Instead, it adjusts
* the input setpoint of the other thermal controllers.
*
* Due to its slow process rate (e.g., once per day), it is, usually, better to
* create a separated thermal zone for this controller, with a large thermal
* cycle interval.
*
* This class is not thread-safe.
*/
class EatController : public ThermalController {
public:
~EatController() final = default;
static absl::StatusOr<std::unique_ptr<EatController>> Create(
EatControllerParameters params);
void ProcessThermalLoop() final;
double ProcessInput() final;
void ProcessOutput(double output) final;
ZoneManager* GetZoneManager() const { return zone_owner_; }
EatThermalLoop* GetEatLoop() const { return eat_loop_.get(); }
std::string GetId() const final { return id_; }
bool IsFanController() const final { return false; }
bool IsSupportiveController() const final { return true; }
// EAT controller has no setpoint to be adjusted.
void AdjustSetpoint([[maybe_unused]] double offset) final {}
absl::Status SetAffectedZones(std::vector<ZoneManager*> affected_zones) {
if (affected_zones.empty()) {
return absl::InvalidArgumentError(absl::StrFormat(
"No affected zone is assigned to EAT controller `%s`!", id_));
}
affected_zones_ = std::move(affected_zones);
affected_zone_ids_.clear();
for (const ZoneManager* zone : affected_zones_) {
affected_zone_ids_.push_back(zone->GetId());
}
return absl::OkStatus();
}
const std::vector<int>& GetAffectedZoneIds() const {
return affected_zone_ids_;
}
const std::vector<std::string>& GetAffectedControllerIds() const final {
return empty_affected_controller_ids_;
}
nlohmann::json ToJson() const;
protected:
explicit EatController(absl::string_view id, ZoneManager* zone_manager,
std::unique_ptr<EatThermalLoop> absl_nonnull eat_loop,
std::vector<std::string> input_sensors,
std::vector<ZoneManager*> affected_zones,
std::vector<int> affected_zone_ids)
: ThermalController(),
id_(id),
zone_owner_(zone_manager),
eat_loop_(std::move(eat_loop)),
input_sensors_(std::move(input_sensors)),
affected_zones_(std::move(affected_zones)),
affected_zone_ids_(std::move(affected_zone_ids)) {}
private:
const std::string id_;
// Use a raw pointer here to avoid circular dependency, as `ZoneManager`
// depends on `EatController` with `std::unique_ptr`.
// Every `ZoneManager` will be owned by the thermal control collector of
// tlBMC, and will live as long as the thermal control service is on.
ZoneManager* zone_owner_ = nullptr;
// Every `EatThermalLoop` will be owned by its thermal controller, and will
// live as long as the thermal control service is on.
std::unique_ptr<EatThermalLoop> eat_loop_;
std::vector<std::string> input_sensors_;
std::vector<ZoneManager*> affected_zones_;
std::vector<int> affected_zone_ids_;
// An empty vector to return by reference for `GetAffectedControllerIds`.
const std::vector<std::string> empty_affected_controller_ids_;
};
} // namespace milotic_tlbmc::thermal
#endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_THERMAL_EAT_CONTROLLER_H_