xref: /openbmc/bmcweb/redfish-core/lib/power.hpp (revision cb103130)
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 // Copyright (c) 2018 Ampere Computing LLC
4 /
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 */
17 #pragma once
18 
19 #include "node.hpp"
20 #include "sensors.hpp"
21 
22 namespace redfish
23 {
24 
25 class Power : public Node
26 {
27   public:
28     Power(CrowApp& app) :
29         Node((app), "/redfish/v1/Chassis/<str>/Power/", std::string())
30     {
31         entityPrivileges = {
32             {boost::beast::http::verb::get, {{"Login"}}},
33             {boost::beast::http::verb::head, {{"Login"}}},
34             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
35             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
36             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
37             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
38     }
39 
40   private:
41     std::vector<const char*> typeList = {"/xyz/openbmc_project/sensors/voltage",
42                                          "/xyz/openbmc_project/sensors/power"};
43     void doGet(crow::Response& res, const crow::Request& req,
44                const std::vector<std::string>& params) override
45     {
46         if (params.size() != 1)
47         {
48             res.result(boost::beast::http::status::internal_server_error);
49             res.end();
50             return;
51         }
52         const std::string& chassis_name = params[0];
53 
54         res.jsonValue["PowerControl"] = nlohmann::json::array();
55 
56         auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
57             res, chassis_name, typeList, "Power");
58 
59         getChassisData(sensorAsyncResp);
60 
61         // This callback verifies that the power limit is only provided for the
62         // chassis that implements the Chassis inventory item. This prevents
63         // things like power supplies providing the chassis power limit
64         auto chassisHandler = [sensorAsyncResp](
65                                   const boost::system::error_code e,
66                                   const std::vector<std::string>&
67                                       chassisPaths) {
68             if (e)
69             {
70                 BMCWEB_LOG_ERROR
71                     << "Power Limit GetSubTreePaths handler Dbus error " << e;
72                 return;
73             }
74 
75             bool found = false;
76             for (const std::string& chassis : chassisPaths)
77             {
78                 size_t len = std::string::npos;
79                 size_t lastPos = chassis.rfind("/");
80                 if (lastPos == std::string::npos)
81                 {
82                     continue;
83                 }
84 
85                 if (lastPos == chassis.size() - 1)
86                 {
87                     size_t end = lastPos;
88                     lastPos = chassis.rfind("/", lastPos - 1);
89                     if (lastPos == std::string::npos)
90                     {
91                         continue;
92                     }
93 
94                     len = end - (lastPos + 1);
95                 }
96 
97                 std::string interfaceChassisName =
98                     chassis.substr(lastPos + 1, len);
99                 if (!interfaceChassisName.compare(sensorAsyncResp->chassisId))
100                 {
101                     found = true;
102                     break;
103                 }
104             }
105 
106             if (!found)
107             {
108                 BMCWEB_LOG_DEBUG << "Power Limit not present for "
109                                  << sensorAsyncResp->chassisId;
110                 return;
111             }
112 
113             auto valueHandler =
114                 [sensorAsyncResp](
115                     const boost::system::error_code ec,
116                     const std::vector<std::pair<std::string, SensorVariant>>&
117                         properties) {
118                     if (ec)
119                     {
120                         messages::internalError(sensorAsyncResp->res);
121                         BMCWEB_LOG_ERROR
122                             << "Power Limit GetAll handler: Dbus error " << ec;
123                         return;
124                     }
125 
126                     nlohmann::json& tempArray =
127                         sensorAsyncResp->res.jsonValue["PowerControl"];
128 
129                     // Put multiple "sensors" into a single PowerControl, 0, so
130                     // only create the first one
131                     if (tempArray.empty())
132                     {
133                         // Mandatory properties odata.id and MemberId
134                         // A warning without a odata.type
135                         tempArray.push_back(
136                             {{"@odata.type", "#Power.v1_0_0.PowerControl"},
137                              {"@odata.id", "/redfish/v1/Chassis/" +
138                                                sensorAsyncResp->chassisId +
139                                                "/Power#/PowerControl/0"},
140                              {"Name", "Chassis Power Control"},
141                              {"MemberId", "0"}});
142                     }
143 
144                     nlohmann::json& sensorJson = tempArray.back();
145                     bool enabled = false;
146                     double powerCap = 0.0;
147                     int64_t scale = 0;
148 
149                     for (const std::pair<std::string, SensorVariant>& property :
150                          properties)
151                     {
152                         if (!property.first.compare("Scale"))
153                         {
154                             const int64_t* i =
155                                 sdbusplus::message::variant_ns::get_if<int64_t>(
156                                     &property.second);
157 
158                             if (i)
159                             {
160                                 scale = *i;
161                             }
162                         }
163                         else if (!property.first.compare("PowerCap"))
164                         {
165                             const double* d =
166                                 sdbusplus::message::variant_ns::get_if<double>(
167                                     &property.second);
168                             const int64_t* i =
169                                 sdbusplus::message::variant_ns::get_if<int64_t>(
170                                     &property.second);
171                             const uint32_t* u =
172                                 sdbusplus::message::variant_ns::get_if<
173                                     uint32_t>(&property.second);
174 
175                             if (d)
176                             {
177                                 powerCap = *d;
178                             }
179                             else if (i)
180                             {
181                                 powerCap = static_cast<double>(*i);
182                             }
183                             else if (u)
184                             {
185                                 powerCap = *u;
186                             }
187                         }
188                         else if (!property.first.compare("PowerCapEnable"))
189                         {
190                             const bool* b =
191                                 sdbusplus::message::variant_ns::get_if<bool>(
192                                     &property.second);
193 
194                             if (b)
195                             {
196                                 enabled = *b;
197                             }
198                         }
199                     }
200 
201                     nlohmann::json& value =
202                         sensorJson["PowerLimit"]["LimitInWatts"];
203 
204                     if (enabled)
205                     {
206                         // Redfish specification indicates PowerLimit should be
207                         // null if the limit is not enabled.
208                         value = powerCap * std::pow(10, scale);
209                     }
210                 };
211 
212             crow::connections::systemBus->async_method_call(
213                 std::move(valueHandler), "xyz.openbmc_project.Settings",
214                 "/xyz/openbmc_project/control/host0/power_cap",
215                 "org.freedesktop.DBus.Properties", "GetAll",
216                 "xyz.openbmc_project.Control.Power.Cap");
217         };
218 
219         crow::connections::systemBus->async_method_call(
220             std::move(chassisHandler), "xyz.openbmc_project.ObjectMapper",
221             "/xyz/openbmc_project/object_mapper",
222             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
223             "/xyz/openbmc_project/inventory", 0,
224             std::array<const char*, 1>{
225                 "xyz.openbmc_project.Inventory.Item.Chassis"});
226     }
227     void doPatch(crow::Response& res, const crow::Request& req,
228                  const std::vector<std::string>& params) override
229     {
230         setSensorOverride(res, req, params, typeList, "Power");
231     }
232 };
233 
234 } // namespace redfish
235