xref: /openbmc/bmcweb/features/redfish/lib/power.hpp (revision 028f7ebc6626f6b95251ce52a9ed9ed053e48a3e)
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:
41b01bf299SEd Tanous     std::initializer_list<const char*> typeList = {
42b01bf299SEd Tanous         "/xyz/openbmc_project/sensors/voltage",
43413961deSRichard Marian Thomaiyar         "/xyz/openbmc_project/sensors/power"};
442474adfaSEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
452474adfaSEd Tanous                const std::vector<std::string>& params) override
462474adfaSEd Tanous     {
472474adfaSEd Tanous         if (params.size() != 1)
482474adfaSEd Tanous         {
492474adfaSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
502474adfaSEd Tanous             res.end();
512474adfaSEd Tanous             return;
522474adfaSEd Tanous         }
532474adfaSEd Tanous         const std::string& chassis_name = params[0];
542474adfaSEd Tanous 
552474adfaSEd Tanous         auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
56413961deSRichard Marian Thomaiyar             res, chassis_name, typeList, "Power");
57*028f7ebcSEddie James 
582474adfaSEd Tanous         getChassisData(sensorAsyncResp);
59*028f7ebcSEddie James 
60*028f7ebcSEddie James         // This callback verifies that the power limit is only provided for the
61*028f7ebcSEddie James         // chassis that implements the Chassis inventory item. This prevents
62*028f7ebcSEddie James         // things like power supplies providing the chassis power limit
63*028f7ebcSEddie James         auto chassisHandler = [sensorAsyncResp](
64*028f7ebcSEddie James                                   const boost::system::error_code ec,
65*028f7ebcSEddie James                                   const std::vector<std::string>&
66*028f7ebcSEddie James                                       chassisPaths) {
67*028f7ebcSEddie James             if (ec)
68*028f7ebcSEddie James             {
69*028f7ebcSEddie James                 BMCWEB_LOG_ERROR
70*028f7ebcSEddie James                     << "Power Limit GetSubTreePaths handler Dbus error " << ec;
71*028f7ebcSEddie James                 return;
72*028f7ebcSEddie James             }
73*028f7ebcSEddie James 
74*028f7ebcSEddie James             bool found = false;
75*028f7ebcSEddie James             for (const std::string& chassis : chassisPaths)
76*028f7ebcSEddie James             {
77*028f7ebcSEddie James                 size_t len = std::string::npos;
78*028f7ebcSEddie James                 size_t lastPos = chassis.rfind("/");
79*028f7ebcSEddie James                 if (lastPos == std::string::npos)
80*028f7ebcSEddie James                 {
81*028f7ebcSEddie James                     continue;
82*028f7ebcSEddie James                 }
83*028f7ebcSEddie James 
84*028f7ebcSEddie James                 if (lastPos == chassis.size() - 1)
85*028f7ebcSEddie James                 {
86*028f7ebcSEddie James                     size_t end = lastPos;
87*028f7ebcSEddie James                     lastPos = chassis.rfind("/", lastPos - 1);
88*028f7ebcSEddie James                     if (lastPos == std::string::npos)
89*028f7ebcSEddie James                     {
90*028f7ebcSEddie James                         continue;
91*028f7ebcSEddie James                     }
92*028f7ebcSEddie James 
93*028f7ebcSEddie James                     len = end - (lastPos + 1);
94*028f7ebcSEddie James                 }
95*028f7ebcSEddie James 
96*028f7ebcSEddie James                 std::string interfaceChassisName =
97*028f7ebcSEddie James                     chassis.substr(lastPos + 1, len);
98*028f7ebcSEddie James                 if (!interfaceChassisName.compare(sensorAsyncResp->chassisId))
99*028f7ebcSEddie James                 {
100*028f7ebcSEddie James                     found = true;
101*028f7ebcSEddie James                     break;
102*028f7ebcSEddie James                 }
103*028f7ebcSEddie James             }
104*028f7ebcSEddie James 
105*028f7ebcSEddie James             if (!found)
106*028f7ebcSEddie James             {
107*028f7ebcSEddie James                 BMCWEB_LOG_DEBUG << "Power Limit not present for "
108*028f7ebcSEddie James                                  << sensorAsyncResp->chassisId;
109*028f7ebcSEddie James                 return;
110*028f7ebcSEddie James             }
111*028f7ebcSEddie James 
112*028f7ebcSEddie James             auto valueHandler =
113*028f7ebcSEddie James                 [sensorAsyncResp](
114*028f7ebcSEddie James                     const boost::system::error_code ec,
115*028f7ebcSEddie James                     const std::vector<std::pair<std::string, SensorVariant>>&
116*028f7ebcSEddie James                         properties) {
117*028f7ebcSEddie James                     if (ec)
118*028f7ebcSEddie James                     {
119*028f7ebcSEddie James                         messages::internalError(sensorAsyncResp->res);
120*028f7ebcSEddie James                         BMCWEB_LOG_ERROR
121*028f7ebcSEddie James                             << "Power Limit GetAll handler: Dbus error " << ec;
122*028f7ebcSEddie James                         return;
123*028f7ebcSEddie James                     }
124*028f7ebcSEddie James 
125*028f7ebcSEddie James                     nlohmann::json& tempArray =
126*028f7ebcSEddie James                         sensorAsyncResp->res.jsonValue["PowerLimit"];
127*028f7ebcSEddie James 
128*028f7ebcSEddie James                     if (tempArray.empty())
129*028f7ebcSEddie James                     {
130*028f7ebcSEddie James                         tempArray.push_back({});
131*028f7ebcSEddie James                     }
132*028f7ebcSEddie James 
133*028f7ebcSEddie James                     nlohmann::json& sensorJson = tempArray.back();
134*028f7ebcSEddie James                     bool enabled = false;
135*028f7ebcSEddie James                     double powerCap = 0.0;
136*028f7ebcSEddie James                     int64_t scale = 0;
137*028f7ebcSEddie James 
138*028f7ebcSEddie James                     for (const std::pair<std::string, SensorVariant>& property :
139*028f7ebcSEddie James                          properties)
140*028f7ebcSEddie James                     {
141*028f7ebcSEddie James                         if (!property.first.compare("Scale"))
142*028f7ebcSEddie James                         {
143*028f7ebcSEddie James                             const int64_t* i =
144*028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<int64_t>(
145*028f7ebcSEddie James                                     &property.second);
146*028f7ebcSEddie James 
147*028f7ebcSEddie James                             if (i)
148*028f7ebcSEddie James                             {
149*028f7ebcSEddie James                                 scale = *i;
150*028f7ebcSEddie James                             }
151*028f7ebcSEddie James                         }
152*028f7ebcSEddie James                         else if (!property.first.compare("PowerCap"))
153*028f7ebcSEddie James                         {
154*028f7ebcSEddie James                             const double* d =
155*028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<double>(
156*028f7ebcSEddie James                                     &property.second);
157*028f7ebcSEddie James                             const int64_t* i =
158*028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<int64_t>(
159*028f7ebcSEddie James                                     &property.second);
160*028f7ebcSEddie James                             const uint32_t* u =
161*028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<
162*028f7ebcSEddie James                                     uint32_t>(&property.second);
163*028f7ebcSEddie James 
164*028f7ebcSEddie James                             if (d)
165*028f7ebcSEddie James                             {
166*028f7ebcSEddie James                                 powerCap = *d;
167*028f7ebcSEddie James                             }
168*028f7ebcSEddie James                             else if (i)
169*028f7ebcSEddie James                             {
170*028f7ebcSEddie James                                 powerCap = *i;
171*028f7ebcSEddie James                             }
172*028f7ebcSEddie James                             else if (u)
173*028f7ebcSEddie James                             {
174*028f7ebcSEddie James                                 powerCap = *u;
175*028f7ebcSEddie James                             }
176*028f7ebcSEddie James                         }
177*028f7ebcSEddie James                         else if (!property.first.compare("PowerCapEnable"))
178*028f7ebcSEddie James                         {
179*028f7ebcSEddie James                             const bool* b =
180*028f7ebcSEddie James                                 sdbusplus::message::variant_ns::get_if<bool>(
181*028f7ebcSEddie James                                     &property.second);
182*028f7ebcSEddie James 
183*028f7ebcSEddie James                             if (b)
184*028f7ebcSEddie James                             {
185*028f7ebcSEddie James                                 enabled = *b;
186*028f7ebcSEddie James                             }
187*028f7ebcSEddie James                         }
188*028f7ebcSEddie James                     }
189*028f7ebcSEddie James 
190*028f7ebcSEddie James                     nlohmann::json& value = sensorJson["LimitInWatts"];
191*028f7ebcSEddie James 
192*028f7ebcSEddie James                     if (enabled)
193*028f7ebcSEddie James                     {
194*028f7ebcSEddie James                         // Redfish specification indicates PowerLimit should be
195*028f7ebcSEddie James                         // null if the limit is not enabled.
196*028f7ebcSEddie James                         value = powerCap * std::pow(10, scale);
197*028f7ebcSEddie James                     }
198*028f7ebcSEddie James                 };
199*028f7ebcSEddie James 
200*028f7ebcSEddie James             crow::connections::systemBus->async_method_call(
201*028f7ebcSEddie James                 std::move(valueHandler), "xyz.openbmc_project.Settings",
202*028f7ebcSEddie James                 "/xyz/openbmc_project/control/host0/power_cap",
203*028f7ebcSEddie James                 "org.freedesktop.DBus.Properties", "GetAll",
204*028f7ebcSEddie James                 "xyz.openbmc_project.Control.Power.Cap");
205*028f7ebcSEddie James         };
206*028f7ebcSEddie James 
207*028f7ebcSEddie James         crow::connections::systemBus->async_method_call(
208*028f7ebcSEddie James             std::move(chassisHandler), "xyz.openbmc_project.ObjectMapper",
209*028f7ebcSEddie James             "/xyz/openbmc_project/object_mapper",
210*028f7ebcSEddie James             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
211*028f7ebcSEddie James             "/xyz/openbmc_project/inventory", int32_t(0),
212*028f7ebcSEddie James             std::array<const char*, 1>{
213*028f7ebcSEddie James                 "xyz.openbmc_project.Inventory.Item.Chassis"});
2142474adfaSEd Tanous     }
215413961deSRichard Marian Thomaiyar     void doPatch(crow::Response& res, const crow::Request& req,
216413961deSRichard Marian Thomaiyar                  const std::vector<std::string>& params) override
217413961deSRichard Marian Thomaiyar     {
218413961deSRichard Marian Thomaiyar         setSensorOverride(res, req, params, typeList, "Power");
219413961deSRichard Marian Thomaiyar     }
2202474adfaSEd Tanous };
2212474adfaSEd Tanous 
2222474adfaSEd Tanous } // namespace redfish
223