blob: 3ecad0b2b9c6be5b3874ca410812842aaf9d0bb6 [file] [log] [blame]
#include "tlbmc/redfish/routes/sensor.h"
#include <algorithm>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/functional/bind_front.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "nlohmann/json.hpp"
#include "entity_common_config.pb.h"
#include "reading_range_config.pb.h"
#include "threshold_config.pb.h"
#include "tlbmc/redfish/app.h"
#include "tlbmc/redfish/request.h"
#include "tlbmc/redfish/response.h"
#include "tlbmc/redfish/url.h"
#include "resource.pb.h"
#include "sensor.pb.h"
#include "tlbmc/sensors/sensor.h"
#include "tlbmc/store/store.h"
namespace milotic_tlbmc::sensor {
namespace {
void HandleSensorCollection(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp,
const std::string& chassis_id) {
std::string sensor_collection_url =
absl::Substitute("/redfish/v1/Chassis/$0/Sensors", chassis_id);
resp.SetKeyInJsonBody("/@odata.id", sensor_collection_url);
resp.SetKeyInJsonBody("/@odata.type", "#SensorCollection.SensorCollection");
resp.SetKeyInJsonBody("/Name", "Sensors");
resp.SetKeyInJsonBody("/Description",
"Collection of Sensors for this Chassis");
const Store& store = *app.GetStore();
std::vector<std::string> sensor_keys =
store.GetAllSensorKeysByConfigName(chassis_id);
std::sort(sensor_keys.begin(), sensor_keys.end());
nlohmann::json::array_t members;
for (const auto& key : sensor_keys) {
nlohmann::json::object_t member;
member["@odata.id"] = absl::StrCat(sensor_collection_url, "/", key);
members.push_back(std::move(member));
}
resp.SetKeyInJsonBody("/Members@odata.count", members.size());
resp.SetKeyInJsonBody("/Members", members);
}
void HandleSensor(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp, const std::string& chassis_id,
const std::string& sensor_id) {
const Store& store = *app.GetStore();
std::shared_ptr<const Sensor> sensor =
store.GetSensorByConfigNameAndSensorKey(chassis_id, sensor_id);
if (sensor == nullptr) {
resp.SetToNotFound();
return;
}
nlohmann::json::json_pointer sensor_pointer("");
FillResponseWithSensorData(sensor, sensor_pointer, resp);
}
} // namespace
void FillResponseWithSensorData(
const std::shared_ptr<const Sensor>& sensor,
const nlohmann::json::json_pointer& sensor_pointer, RedfishResponse& resp) {
if (sensor->GetSensorAttributesDynamic().state().status() != STATUS_READY) {
resp.SetToNotReady(
sensor->GetSensorAttributesDynamic().state().status_message());
return;
}
const SensorAttributesStatic& attributes_static =
sensor->GetSensorAttributesStatic();
std::string chassis_id =
attributes_static.entity_common_config().board_config_name();
std::string sensor_url =
absl::Substitute("/redfish/v1/Chassis/$0/Sensors/$1", chassis_id,
attributes_static.attributes().key());
resp.SetKeyInJsonBody(sensor_pointer / "@odata.id", sensor_url);
resp.SetKeyInJsonBody(sensor_pointer / "@odata.type",
"#Sensor.v1_2_0.Sensor");
std::string sensor_name =
GetTrimmedSensorName(attributes_static.attributes().key());
resp.SetKeyInJsonBody(sensor_pointer / "Name", sensor_name);
resp.SetKeyInJsonBody(sensor_pointer / "Id",
attributes_static.attributes().key());
resp.SetKeyInJsonBody(sensor_pointer / "Description", "Sensor");
resp.SetKeyInJsonBody(sensor_pointer / "Reading",
sensor->GetSensorData()->reading());
if (!attributes_static.entity_common_config().related_item().id().empty()) {
nlohmann::json::array_t related_items;
nlohmann::json::object_t related_item;
switch (attributes_static.entity_common_config().related_item().type()) {
case RESOURCE_TYPE_FAN:
related_item["@odata.id"] = CreateUrl(
{"redfish", "v1", "Chassis", chassis_id, "ThermalSubsystem", "Fans",
attributes_static.entity_common_config().related_item().id()});
break;
case RESOURCE_TYPE_BOARD:
related_item["@odata.id"] = CreateUrl(
{"redfish", "v1", "Chassis",
attributes_static.entity_common_config().related_item().id()});
break;
default:
break;
}
related_items.emplace_back(std::move(related_item));
resp.SetKeyInJsonBody(sensor_pointer / "RelatedItem", related_items);
}
std::string reading_units;
std::string reading_type;
// Reference: https://redfish.dmtf.org/schemas/v1/Sensor.v1_10_0.json
switch (attributes_static.unit()) {
case UNIT_UNKNOWN:
break;
case UNIT_DEGREE_CELSIUS:
reading_type = "Temperature";
reading_units = "Cel";
break;
case UNIT_VOLT:
reading_type = "Voltage";
reading_units = "V";
break;
case UNIT_WATT:
reading_type = "Power";
reading_units = "W";
break;
case UNIT_AMPERE:
reading_type = "Current";
reading_units = "A";
break;
case UNIT_REVOLUTION_PER_MINUTE:
reading_type = "Rotational";
reading_units = "RPM";
break;
case UNIT_PERCENT:
reading_type = "Percent";
reading_units = "%";
break;
default:
break;
}
if (!reading_type.empty()) {
resp.SetKeyInJsonBody(sensor_pointer / "ReadingType", reading_type);
}
if (!reading_units.empty()) {
resp.SetKeyInJsonBody(sensor_pointer / "ReadingUnits", reading_units);
}
resp.SetBodyToJson();
if (attributes_static.has_reading_ranges()) {
for (const auto& reading_range :
attributes_static.reading_ranges().reading_range_configs()) {
if (reading_range.type() == READING_RANGE_TYPE_MAX) {
resp.SetKeyInJsonBody(sensor_pointer / "ReadingRangeMax",
reading_range.reading());
} else if (reading_range.type() == READING_RANGE_TYPE_MIN) {
resp.SetKeyInJsonBody(sensor_pointer / "ReadingRangeMin",
reading_range.reading());
}
}
}
if (attributes_static.has_thresholds()) {
for (const auto& threshold :
attributes_static.thresholds().threshold_configs()) {
switch (threshold.type()) {
case THRESHOLD_TYPE_LOWER_CRITICAL:
resp.SetKeyInJsonBody(
sensor_pointer / "Thresholds" / "LowerCritical" / "Reading",
threshold.value());
break;
case THRESHOLD_TYPE_LOWER_NON_CRITICAL:
resp.SetKeyInJsonBody(
sensor_pointer / "Thresholds" / "LowerCaution" / "Reading",
threshold.value());
break;
case THRESHOLD_TYPE_UPPER_NON_CRITICAL:
resp.SetKeyInJsonBody(
sensor_pointer / "Thresholds" / "UpperCaution" / "Reading",
threshold.value());
break;
case THRESHOLD_TYPE_UPPER_CRITICAL:
resp.SetKeyInJsonBody(
sensor_pointer / "Thresholds" / "UpperCritical" / "Reading",
threshold.value());
break;
default:
break;
}
}
}
// At this point, sensor is healthy, a problematic sensor will return error
// early based on SensorAttributesDynamic state status.
resp.SetKeyInJsonBody(sensor_pointer / "Status" / "Health", "OK");
resp.SetKeyInJsonBody(sensor_pointer / "Status" / "State", "Enabled");
}
void RegisterRoutes(RedfishApp& app) {
TLBMC_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleSensorCollection, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleSensor, std::cref(app)));
}
} // namespace milotic_tlbmc::sensor