xref: /openbmc/bmcweb/features/redfish/lib/power.hpp (revision 271584ab78b4c1926f766aa26ddfde7da329059f)
12474adfaSEd Tanous /*
22474adfaSEd Tanous // Copyright (c) 2018 Intel Corporation
32474adfaSEd Tanous // Copyright (c) 2018 Ampere Computing LLC
42474adfaSEd Tanous /
52474adfaSEd Tanous // Licensed under the Apache License, Version 2.0 (the "License");
62474adfaSEd Tanous // you may not use this file except in compliance with the License.
72474adfaSEd Tanous // You may obtain a copy of the License at
82474adfaSEd Tanous //
92474adfaSEd Tanous //      http://www.apache.org/licenses/LICENSE-2.0
102474adfaSEd Tanous //
112474adfaSEd Tanous // Unless required by applicable law or agreed to in writing, software
122474adfaSEd Tanous // distributed under the License is distributed on an "AS IS" BASIS,
132474adfaSEd Tanous // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
142474adfaSEd Tanous // See the License for the specific language governing permissions and
152474adfaSEd Tanous // limitations under the License.
162474adfaSEd Tanous */
172474adfaSEd Tanous #pragma once
182474adfaSEd Tanous 
192474adfaSEd Tanous #include "node.hpp"
202474adfaSEd Tanous #include "sensors.hpp"
212474adfaSEd Tanous 
222474adfaSEd Tanous namespace redfish
232474adfaSEd Tanous {
242474adfaSEd Tanous 
252474adfaSEd Tanous class Power : public Node
262474adfaSEd Tanous {
272474adfaSEd Tanous   public:
282474adfaSEd Tanous     Power(CrowApp& app) :
292474adfaSEd Tanous         Node((app), "/redfish/v1/Chassis/<str>/Power/", std::string())
302474adfaSEd Tanous     {
312474adfaSEd Tanous         entityPrivileges = {
322474adfaSEd Tanous             {boost::beast::http::verb::get, {{"Login"}}},
332474adfaSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
346f4fd479SRichard Marian Thomaiyar             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
352474adfaSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
362474adfaSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
372474adfaSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
382474adfaSEd Tanous     }
392474adfaSEd Tanous 
402474adfaSEd Tanous   private:
4185e1424fSEd Tanous     std::vector<const char*> typeList = {"/xyz/openbmc_project/sensors/voltage",
42413961deSRichard Marian Thomaiyar                                          "/xyz/openbmc_project/sensors/power"};
432474adfaSEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
442474adfaSEd Tanous                const std::vector<std::string>& params) override
452474adfaSEd Tanous     {
462474adfaSEd Tanous         if (params.size() != 1)
472474adfaSEd Tanous         {
482474adfaSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
492474adfaSEd Tanous             res.end();
502474adfaSEd Tanous             return;
512474adfaSEd Tanous         }
522474adfaSEd Tanous         const std::string& chassis_name = params[0];
532474adfaSEd Tanous 
54c5d03ff4SJennifer Lee         res.jsonValue["PowerControl"] = nlohmann::json::array();
55c5d03ff4SJennifer Lee 
562474adfaSEd Tanous         auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
57413961deSRichard Marian Thomaiyar             res, chassis_name, typeList, "Power");
58028f7ebcSEddie James 
592474adfaSEd Tanous         getChassisData(sensorAsyncResp);
60028f7ebcSEddie James 
61028f7ebcSEddie James         // This callback verifies that the power limit is only provided for the
62028f7ebcSEddie James         // chassis that implements the Chassis inventory item. This prevents
63028f7ebcSEddie James         // things like power supplies providing the chassis power limit
64028f7ebcSEddie James         auto chassisHandler = [sensorAsyncResp](
65*271584abSEd Tanous                                   const boost::system::error_code e,
66028f7ebcSEddie James                                   const std::vector<std::string>&
67028f7ebcSEddie James                                       chassisPaths) {
68*271584abSEd Tanous             if (e)
69028f7ebcSEddie James             {
70028f7ebcSEddie James                 BMCWEB_LOG_ERROR
71*271584abSEd Tanous                     << "Power Limit GetSubTreePaths handler Dbus error " << e;
72028f7ebcSEddie James                 return;
73028f7ebcSEddie James             }
74028f7ebcSEddie James 
75028f7ebcSEddie James             bool found = false;
76028f7ebcSEddie James             for (const std::string& chassis : chassisPaths)
77028f7ebcSEddie James             {
78028f7ebcSEddie James                 size_t len = std::string::npos;
79028f7ebcSEddie James                 size_t lastPos = chassis.rfind("/");
80028f7ebcSEddie James                 if (lastPos == std::string::npos)
81028f7ebcSEddie James                 {
82028f7ebcSEddie James                     continue;
83028f7ebcSEddie James                 }
84028f7ebcSEddie James 
85028f7ebcSEddie James                 if (lastPos == chassis.size() - 1)
86028f7ebcSEddie James                 {
87028f7ebcSEddie James                     size_t end = lastPos;
88028f7ebcSEddie James                     lastPos = chassis.rfind("/", lastPos - 1);
89028f7ebcSEddie James                     if (lastPos == std::string::npos)
90028f7ebcSEddie James                     {
91028f7ebcSEddie James                         continue;
92028f7ebcSEddie James                     }
93028f7ebcSEddie James 
94028f7ebcSEddie James                     len = end - (lastPos + 1);
95028f7ebcSEddie James                 }
96028f7ebcSEddie James 
97028f7ebcSEddie James                 std::string interfaceChassisName =
98028f7ebcSEddie James                     chassis.substr(lastPos + 1, len);
99028f7ebcSEddie James                 if (!interfaceChassisName.compare(sensorAsyncResp->chassisId))
100028f7ebcSEddie James                 {
101028f7ebcSEddie James                     found = true;
102028f7ebcSEddie James                     break;
103028f7ebcSEddie James                 }
104028f7ebcSEddie James             }
105028f7ebcSEddie James 
106028f7ebcSEddie James             if (!found)
107028f7ebcSEddie James             {
108028f7ebcSEddie James                 BMCWEB_LOG_DEBUG << "Power Limit not present for "
109028f7ebcSEddie James                                  << sensorAsyncResp->chassisId;
110028f7ebcSEddie James                 return;
111028f7ebcSEddie James             }
112028f7ebcSEddie James 
113028f7ebcSEddie James             auto valueHandler =
114028f7ebcSEddie James                 [sensorAsyncResp](
115028f7ebcSEddie James                     const boost::system::error_code ec,
116028f7ebcSEddie James                     const std::vector<std::pair<std::string, SensorVariant>>&
117028f7ebcSEddie James                         properties) {
118028f7ebcSEddie James                     if (ec)
119028f7ebcSEddie James                     {
120028f7ebcSEddie James                         messages::internalError(sensorAsyncResp->res);
121028f7ebcSEddie James                         BMCWEB_LOG_ERROR
122028f7ebcSEddie James                             << "Power Limit GetAll handler: Dbus error " << ec;
123028f7ebcSEddie James                         return;
124028f7ebcSEddie James                     }
125028f7ebcSEddie James 
126028f7ebcSEddie James                     nlohmann::json& tempArray =
1277ab06f49SGunnar Mills                         sensorAsyncResp->res.jsonValue["PowerControl"];
128028f7ebcSEddie James 
1297ab06f49SGunnar Mills                     // Put multiple "sensors" into a single PowerControl, 0, so
1307ab06f49SGunnar Mills                     // only create the first one
131028f7ebcSEddie James                     if (tempArray.empty())
132028f7ebcSEddie James                     {
1337ab06f49SGunnar Mills                         // Mandatory properties odata.id and MemberId
1347ab06f49SGunnar Mills                         // A warning without a odata.type
1357ab06f49SGunnar Mills                         tempArray.push_back(
1367ab06f49SGunnar Mills                             {{"@odata.type", "#Power.v1_0_0.PowerControl"},
1377ab06f49SGunnar Mills                              {"@odata.id", "/redfish/v1/Chassis/" +
1387ab06f49SGunnar Mills                                                sensorAsyncResp->chassisId +
1397ab06f49SGunnar Mills                                                "/Power#/PowerControl/0"},
1407ab06f49SGunnar Mills                              {"Name", "Chassis Power Control"},
1417ab06f49SGunnar Mills                              {"MemberId", "0"}});
142028f7ebcSEddie James                     }
143028f7ebcSEddie James 
144028f7ebcSEddie James                     nlohmann::json& sensorJson = tempArray.back();
145028f7ebcSEddie James                     bool enabled = false;
146028f7ebcSEddie James                     double powerCap = 0.0;
147028f7ebcSEddie James                     int64_t scale = 0;
148028f7ebcSEddie James 
149028f7ebcSEddie James                     for (const std::pair<std::string, SensorVariant>& property :
150028f7ebcSEddie James                          properties)
151028f7ebcSEddie James                     {
152028f7ebcSEddie James                         if (!property.first.compare("Scale"))
153028f7ebcSEddie James                         {
154028f7ebcSEddie James                             const int64_t* i =
155028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<int64_t>(
156028f7ebcSEddie James                                     &property.second);
157028f7ebcSEddie James 
158028f7ebcSEddie James                             if (i)
159028f7ebcSEddie James                             {
160028f7ebcSEddie James                                 scale = *i;
161028f7ebcSEddie James                             }
162028f7ebcSEddie James                         }
163028f7ebcSEddie James                         else if (!property.first.compare("PowerCap"))
164028f7ebcSEddie James                         {
165028f7ebcSEddie James                             const double* d =
166028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<double>(
167028f7ebcSEddie James                                     &property.second);
168028f7ebcSEddie James                             const int64_t* i =
169028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<int64_t>(
170028f7ebcSEddie James                                     &property.second);
171028f7ebcSEddie James                             const uint32_t* u =
172028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<
173028f7ebcSEddie James                                     uint32_t>(&property.second);
174028f7ebcSEddie James 
175028f7ebcSEddie James                             if (d)
176028f7ebcSEddie James                             {
177028f7ebcSEddie James                                 powerCap = *d;
178028f7ebcSEddie James                             }
179028f7ebcSEddie James                             else if (i)
180028f7ebcSEddie James                             {
181*271584abSEd Tanous                                 powerCap = static_cast<double>(*i);
182028f7ebcSEddie James                             }
183028f7ebcSEddie James                             else if (u)
184028f7ebcSEddie James                             {
185028f7ebcSEddie James                                 powerCap = *u;
186028f7ebcSEddie James                             }
187028f7ebcSEddie James                         }
188028f7ebcSEddie James                         else if (!property.first.compare("PowerCapEnable"))
189028f7ebcSEddie James                         {
190028f7ebcSEddie James                             const bool* b =
191028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<bool>(
192028f7ebcSEddie James                                     &property.second);
193028f7ebcSEddie James 
194028f7ebcSEddie James                             if (b)
195028f7ebcSEddie James                             {
196028f7ebcSEddie James                                 enabled = *b;
197028f7ebcSEddie James                             }
198028f7ebcSEddie James                         }
199028f7ebcSEddie James                     }
200028f7ebcSEddie James 
2017ab06f49SGunnar Mills                     nlohmann::json& value =
2027ab06f49SGunnar Mills                         sensorJson["PowerLimit"]["LimitInWatts"];
203028f7ebcSEddie James 
204028f7ebcSEddie James                     if (enabled)
205028f7ebcSEddie James                     {
206028f7ebcSEddie James                         // Redfish specification indicates PowerLimit should be
207028f7ebcSEddie James                         // null if the limit is not enabled.
208028f7ebcSEddie James                         value = powerCap * std::pow(10, scale);
209028f7ebcSEddie James                     }
210028f7ebcSEddie James                 };
211028f7ebcSEddie James 
212028f7ebcSEddie James             crow::connections::systemBus->async_method_call(
213028f7ebcSEddie James                 std::move(valueHandler), "xyz.openbmc_project.Settings",
214028f7ebcSEddie James                 "/xyz/openbmc_project/control/host0/power_cap",
215028f7ebcSEddie James                 "org.freedesktop.DBus.Properties", "GetAll",
216028f7ebcSEddie James                 "xyz.openbmc_project.Control.Power.Cap");
217028f7ebcSEddie James         };
218028f7ebcSEddie James 
219028f7ebcSEddie James         crow::connections::systemBus->async_method_call(
220028f7ebcSEddie James             std::move(chassisHandler), "xyz.openbmc_project.ObjectMapper",
221028f7ebcSEddie James             "/xyz/openbmc_project/object_mapper",
222028f7ebcSEddie James             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
223*271584abSEd Tanous             "/xyz/openbmc_project/inventory", 0,
224028f7ebcSEddie James             std::array<const char*, 1>{
225028f7ebcSEddie James                 "xyz.openbmc_project.Inventory.Item.Chassis"});
2262474adfaSEd Tanous     }
227413961deSRichard Marian Thomaiyar     void doPatch(crow::Response& res, const crow::Request& req,
228413961deSRichard Marian Thomaiyar                  const std::vector<std::string>& params) override
229413961deSRichard Marian Thomaiyar     {
230413961deSRichard Marian Thomaiyar         setSensorOverride(res, req, params, typeList, "Power");
231413961deSRichard Marian Thomaiyar     }
2322474adfaSEd Tanous };
2332474adfaSEd Tanous 
2342474adfaSEd Tanous } // namespace redfish
235