108777fb0SLewanczyk, Dawid /* 208777fb0SLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation 308777fb0SLewanczyk, Dawid // 408777fb0SLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License"); 508777fb0SLewanczyk, Dawid // you may not use this file except in compliance with the License. 608777fb0SLewanczyk, Dawid // You may obtain a copy of the License at 708777fb0SLewanczyk, Dawid // 808777fb0SLewanczyk, Dawid // http://www.apache.org/licenses/LICENSE-2.0 908777fb0SLewanczyk, Dawid // 1008777fb0SLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software 1108777fb0SLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS, 1208777fb0SLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1308777fb0SLewanczyk, Dawid // See the License for the specific language governing permissions and 1408777fb0SLewanczyk, Dawid // limitations under the License. 1508777fb0SLewanczyk, Dawid */ 1608777fb0SLewanczyk, Dawid #pragma once 1708777fb0SLewanczyk, Dawid 187e860f15SJohn Edward Broadbent #include <app.hpp> 1911ba3979SEd Tanous #include <boost/algorithm/string/classification.hpp> 201d7c0054SEd Tanous #include <boost/algorithm/string/find.hpp> 211d7c0054SEd Tanous #include <boost/algorithm/string/predicate.hpp> 2208777fb0SLewanczyk, Dawid #include <boost/algorithm/string/split.hpp> 2308777fb0SLewanczyk, Dawid #include <boost/range/algorithm/replace_copy_if.hpp> 241abe55efSEd Tanous #include <dbus_singleton.hpp> 25168e20c1SEd Tanous #include <dbus_utility.hpp> 2645ca1b86SEd Tanous #include <query.hpp> 27ed398213SEd Tanous #include <registries/privilege_registry.hpp> 281e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 2986d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 3086d89ed7SKrzysztof Grobelny #include <utils/dbus_utils.hpp> 31413961deSRichard Marian Thomaiyar #include <utils/json_utils.hpp> 32928fefb9SNan Zhou #include <utils/query_param.hpp> 331214b7e7SGunnar Mills 341214b7e7SGunnar Mills #include <cmath> 35fe04d49cSNan Zhou #include <iterator> 36fe04d49cSNan Zhou #include <map> 37fe04d49cSNan Zhou #include <set> 38b5a76932SEd Tanous #include <utility> 39abf2add6SEd Tanous #include <variant> 4008777fb0SLewanczyk, Dawid 411abe55efSEd Tanous namespace redfish 421abe55efSEd Tanous { 4308777fb0SLewanczyk, Dawid 44a0ec28b6SAdrian Ambrożewicz namespace sensors 45a0ec28b6SAdrian Ambrożewicz { 46a0ec28b6SAdrian Ambrożewicz namespace node 47a0ec28b6SAdrian Ambrożewicz { 48a0ec28b6SAdrian Ambrożewicz static constexpr std::string_view power = "Power"; 49a0ec28b6SAdrian Ambrożewicz static constexpr std::string_view sensors = "Sensors"; 50a0ec28b6SAdrian Ambrożewicz static constexpr std::string_view thermal = "Thermal"; 51a0ec28b6SAdrian Ambrożewicz } // namespace node 52a0ec28b6SAdrian Ambrożewicz 5302da7c5aSEd Tanous // clang-format off 54a0ec28b6SAdrian Ambrożewicz namespace dbus 55a0ec28b6SAdrian Ambrożewicz { 564ee8e211SEd Tanous static auto powerPaths = std::to_array<std::string_view>({ 5702da7c5aSEd Tanous "/xyz/openbmc_project/sensors/voltage", 5802da7c5aSEd Tanous "/xyz/openbmc_project/sensors/power" 5902da7c5aSEd Tanous }); 60c2bf7f99SWludzik, Jozef 614ee8e211SEd Tanous static auto sensorPaths = std::to_array<std::string_view>({ 6202da7c5aSEd Tanous "/xyz/openbmc_project/sensors/power", 63a0ec28b6SAdrian Ambrożewicz "/xyz/openbmc_project/sensors/current", 647088690cSBasheer Ahmed Muddebihal "/xyz/openbmc_project/sensors/airflow", 655deabed9SGunnar Mills "/xyz/openbmc_project/sensors/humidity", 66e8204933SGeorge Liu #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM 67e8204933SGeorge Liu "/xyz/openbmc_project/sensors/voltage", 68e8204933SGeorge Liu "/xyz/openbmc_project/sensors/fan_tach", 69e8204933SGeorge Liu "/xyz/openbmc_project/sensors/temperature", 70e8204933SGeorge Liu "/xyz/openbmc_project/sensors/fan_pwm", 71e8204933SGeorge Liu "/xyz/openbmc_project/sensors/altitude", 72e8204933SGeorge Liu "/xyz/openbmc_project/sensors/energy", 73e8204933SGeorge Liu #endif 7402da7c5aSEd Tanous "/xyz/openbmc_project/sensors/utilization" 7502da7c5aSEd Tanous }); 7602da7c5aSEd Tanous 774ee8e211SEd Tanous static auto thermalPaths = std::to_array<std::string_view>({ 7802da7c5aSEd Tanous "/xyz/openbmc_project/sensors/fan_tach", 79a0ec28b6SAdrian Ambrożewicz "/xyz/openbmc_project/sensors/temperature", 8002da7c5aSEd Tanous "/xyz/openbmc_project/sensors/fan_pwm" 8102da7c5aSEd Tanous }); 8202da7c5aSEd Tanous 83c2bf7f99SWludzik, Jozef } // namespace dbus 8402da7c5aSEd Tanous // clang-format on 8502da7c5aSEd Tanous 8602da7c5aSEd Tanous using sensorPair = std::pair<std::string_view, std::span<std::string_view>>; 8702da7c5aSEd Tanous static constexpr std::array<sensorPair, 3> paths = { 8802da7c5aSEd Tanous {{node::power, std::span<std::string_view>(dbus::powerPaths)}, 8902da7c5aSEd Tanous {node::sensors, std::span<std::string_view>(dbus::sensorPaths)}, 9002da7c5aSEd Tanous {node::thermal, std::span<std::string_view>(dbus::thermalPaths)}}}; 91c2bf7f99SWludzik, Jozef 921d7c0054SEd Tanous inline std::string_view toReadingType(std::string_view sensorType) 93c2bf7f99SWludzik, Jozef { 94c2bf7f99SWludzik, Jozef if (sensorType == "voltage") 95c2bf7f99SWludzik, Jozef { 96c2bf7f99SWludzik, Jozef return "Voltage"; 97c2bf7f99SWludzik, Jozef } 98c2bf7f99SWludzik, Jozef if (sensorType == "power") 99c2bf7f99SWludzik, Jozef { 100c2bf7f99SWludzik, Jozef return "Power"; 101c2bf7f99SWludzik, Jozef } 102c2bf7f99SWludzik, Jozef if (sensorType == "current") 103c2bf7f99SWludzik, Jozef { 104c2bf7f99SWludzik, Jozef return "Current"; 105c2bf7f99SWludzik, Jozef } 106c2bf7f99SWludzik, Jozef if (sensorType == "fan_tach") 107c2bf7f99SWludzik, Jozef { 108c2bf7f99SWludzik, Jozef return "Rotational"; 109c2bf7f99SWludzik, Jozef } 110c2bf7f99SWludzik, Jozef if (sensorType == "temperature") 111c2bf7f99SWludzik, Jozef { 112c2bf7f99SWludzik, Jozef return "Temperature"; 113c2bf7f99SWludzik, Jozef } 114c2bf7f99SWludzik, Jozef if (sensorType == "fan_pwm" || sensorType == "utilization") 115c2bf7f99SWludzik, Jozef { 116c2bf7f99SWludzik, Jozef return "Percent"; 117c2bf7f99SWludzik, Jozef } 1185deabed9SGunnar Mills if (sensorType == "humidity") 1195deabed9SGunnar Mills { 1205deabed9SGunnar Mills return "Humidity"; 1215deabed9SGunnar Mills } 122c2bf7f99SWludzik, Jozef if (sensorType == "altitude") 123c2bf7f99SWludzik, Jozef { 124c2bf7f99SWludzik, Jozef return "Altitude"; 125c2bf7f99SWludzik, Jozef } 126c2bf7f99SWludzik, Jozef if (sensorType == "airflow") 127c2bf7f99SWludzik, Jozef { 128c2bf7f99SWludzik, Jozef return "AirFlow"; 129c2bf7f99SWludzik, Jozef } 130c2bf7f99SWludzik, Jozef if (sensorType == "energy") 131c2bf7f99SWludzik, Jozef { 132c2bf7f99SWludzik, Jozef return "EnergyJoules"; 133c2bf7f99SWludzik, Jozef } 134c2bf7f99SWludzik, Jozef return ""; 135c2bf7f99SWludzik, Jozef } 136c2bf7f99SWludzik, Jozef 1371d7c0054SEd Tanous inline std::string_view toReadingUnits(std::string_view sensorType) 138c2bf7f99SWludzik, Jozef { 139c2bf7f99SWludzik, Jozef if (sensorType == "voltage") 140c2bf7f99SWludzik, Jozef { 141c2bf7f99SWludzik, Jozef return "V"; 142c2bf7f99SWludzik, Jozef } 143c2bf7f99SWludzik, Jozef if (sensorType == "power") 144c2bf7f99SWludzik, Jozef { 145c2bf7f99SWludzik, Jozef return "W"; 146c2bf7f99SWludzik, Jozef } 147c2bf7f99SWludzik, Jozef if (sensorType == "current") 148c2bf7f99SWludzik, Jozef { 149c2bf7f99SWludzik, Jozef return "A"; 150c2bf7f99SWludzik, Jozef } 151c2bf7f99SWludzik, Jozef if (sensorType == "fan_tach") 152c2bf7f99SWludzik, Jozef { 153c2bf7f99SWludzik, Jozef return "RPM"; 154c2bf7f99SWludzik, Jozef } 155c2bf7f99SWludzik, Jozef if (sensorType == "temperature") 156c2bf7f99SWludzik, Jozef { 157c2bf7f99SWludzik, Jozef return "Cel"; 158c2bf7f99SWludzik, Jozef } 1595deabed9SGunnar Mills if (sensorType == "fan_pwm" || sensorType == "utilization" || 1605deabed9SGunnar Mills sensorType == "humidity") 161c2bf7f99SWludzik, Jozef { 162c2bf7f99SWludzik, Jozef return "%"; 163c2bf7f99SWludzik, Jozef } 164c2bf7f99SWludzik, Jozef if (sensorType == "altitude") 165c2bf7f99SWludzik, Jozef { 166c2bf7f99SWludzik, Jozef return "m"; 167c2bf7f99SWludzik, Jozef } 168c2bf7f99SWludzik, Jozef if (sensorType == "airflow") 169c2bf7f99SWludzik, Jozef { 170c2bf7f99SWludzik, Jozef return "cft_i/min"; 171c2bf7f99SWludzik, Jozef } 172c2bf7f99SWludzik, Jozef if (sensorType == "energy") 173c2bf7f99SWludzik, Jozef { 174c2bf7f99SWludzik, Jozef return "J"; 175c2bf7f99SWludzik, Jozef } 176c2bf7f99SWludzik, Jozef return ""; 177a0ec28b6SAdrian Ambrożewicz } 178a0ec28b6SAdrian Ambrożewicz } // namespace sensors 179a0ec28b6SAdrian Ambrożewicz 18008777fb0SLewanczyk, Dawid /** 181588c3f0dSKowalski, Kamil * SensorsAsyncResp 18208777fb0SLewanczyk, Dawid * Gathers data needed for response processing after async calls are done 18308777fb0SLewanczyk, Dawid */ 1841abe55efSEd Tanous class SensorsAsyncResp 1851abe55efSEd Tanous { 18608777fb0SLewanczyk, Dawid public: 187a0ec28b6SAdrian Ambrożewicz using DataCompleteCb = std::function<void( 188a0ec28b6SAdrian Ambrożewicz const boost::beast::http::status status, 189fe04d49cSNan Zhou const std::map<std::string, std::string>& uriToDbus)>; 190a0ec28b6SAdrian Ambrożewicz 191a0ec28b6SAdrian Ambrożewicz struct SensorData 192a0ec28b6SAdrian Ambrożewicz { 193a0ec28b6SAdrian Ambrożewicz const std::string name; 194a0ec28b6SAdrian Ambrożewicz std::string uri; 195a0ec28b6SAdrian Ambrożewicz const std::string dbusPath; 196a0ec28b6SAdrian Ambrożewicz }; 197a0ec28b6SAdrian Ambrożewicz 1988a592810SEd Tanous SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, 1998d1b46d7Szhanghch05 const std::string& chassisIdIn, 20002da7c5aSEd Tanous std::span<std::string_view> typesIn, 20102da7c5aSEd Tanous std::string_view subNode) : 2028a592810SEd Tanous asyncResp(asyncRespIn), 203928fefb9SNan Zhou chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode), 204928fefb9SNan Zhou efficientExpand(false) 2051214b7e7SGunnar Mills {} 20608777fb0SLewanczyk, Dawid 207a0ec28b6SAdrian Ambrożewicz // Store extra data about sensor mapping and return it in callback 2088a592810SEd Tanous SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, 2098d1b46d7Szhanghch05 const std::string& chassisIdIn, 21002da7c5aSEd Tanous std::span<std::string_view> typesIn, 21102da7c5aSEd Tanous std::string_view subNode, 212a0ec28b6SAdrian Ambrożewicz DataCompleteCb&& creationComplete) : 2138a592810SEd Tanous asyncResp(asyncRespIn), 214928fefb9SNan Zhou chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode), 215928fefb9SNan Zhou efficientExpand(false), metadata{std::vector<SensorData>()}, 216a0ec28b6SAdrian Ambrożewicz dataComplete{std::move(creationComplete)} 217a0ec28b6SAdrian Ambrożewicz {} 218a0ec28b6SAdrian Ambrożewicz 219928fefb9SNan Zhou // sensor collections expand 2208a592810SEd Tanous SensorsAsyncResp(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, 221928fefb9SNan Zhou const std::string& chassisIdIn, 22202da7c5aSEd Tanous const std::span<std::string_view> typesIn, 2238a592810SEd Tanous const std::string_view& subNode, bool efficientExpandIn) : 2248a592810SEd Tanous asyncResp(asyncRespIn), 225928fefb9SNan Zhou chassisId(chassisIdIn), types(typesIn), chassisSubNode(subNode), 2268a592810SEd Tanous efficientExpand(efficientExpandIn) 227928fefb9SNan Zhou {} 228928fefb9SNan Zhou 2291abe55efSEd Tanous ~SensorsAsyncResp() 2301abe55efSEd Tanous { 2318d1b46d7Szhanghch05 if (asyncResp->res.result() == 2328d1b46d7Szhanghch05 boost::beast::http::status::internal_server_error) 2331abe55efSEd Tanous { 2341abe55efSEd Tanous // Reset the json object to clear out any data that made it in 2351abe55efSEd Tanous // before the error happened todo(ed) handle error condition with 2361abe55efSEd Tanous // proper code 2378d1b46d7Szhanghch05 asyncResp->res.jsonValue = nlohmann::json::object(); 23808777fb0SLewanczyk, Dawid } 239a0ec28b6SAdrian Ambrożewicz 240a0ec28b6SAdrian Ambrożewicz if (dataComplete && metadata) 241a0ec28b6SAdrian Ambrożewicz { 242fe04d49cSNan Zhou std::map<std::string, std::string> map; 2438d1b46d7Szhanghch05 if (asyncResp->res.result() == boost::beast::http::status::ok) 244a0ec28b6SAdrian Ambrożewicz { 245a0ec28b6SAdrian Ambrożewicz for (auto& sensor : *metadata) 246a0ec28b6SAdrian Ambrożewicz { 247*c1d019a6SEd Tanous map.emplace(sensor.uri, sensor.dbusPath); 248a0ec28b6SAdrian Ambrożewicz } 249a0ec28b6SAdrian Ambrożewicz } 2508d1b46d7Szhanghch05 dataComplete(asyncResp->res.result(), map); 251a0ec28b6SAdrian Ambrożewicz } 25208777fb0SLewanczyk, Dawid } 253588c3f0dSKowalski, Kamil 254ecd6a3a2SEd Tanous SensorsAsyncResp(const SensorsAsyncResp&) = delete; 255ecd6a3a2SEd Tanous SensorsAsyncResp(SensorsAsyncResp&&) = delete; 256ecd6a3a2SEd Tanous SensorsAsyncResp& operator=(const SensorsAsyncResp&) = delete; 257ecd6a3a2SEd Tanous SensorsAsyncResp& operator=(SensorsAsyncResp&&) = delete; 258ecd6a3a2SEd Tanous 259a0ec28b6SAdrian Ambrożewicz void addMetadata(const nlohmann::json& sensorObject, 260*c1d019a6SEd Tanous const std::string& dbusPath) 261a0ec28b6SAdrian Ambrożewicz { 262a0ec28b6SAdrian Ambrożewicz if (metadata) 263a0ec28b6SAdrian Ambrożewicz { 264*c1d019a6SEd Tanous metadata->emplace_back(SensorData{ 265*c1d019a6SEd Tanous sensorObject["Name"], sensorObject["@odata.id"], dbusPath}); 266a0ec28b6SAdrian Ambrożewicz } 267a0ec28b6SAdrian Ambrożewicz } 268a0ec28b6SAdrian Ambrożewicz 269a0ec28b6SAdrian Ambrożewicz void updateUri(const std::string& name, const std::string& uri) 270a0ec28b6SAdrian Ambrożewicz { 271a0ec28b6SAdrian Ambrożewicz if (metadata) 272a0ec28b6SAdrian Ambrożewicz { 273a0ec28b6SAdrian Ambrożewicz for (auto& sensor : *metadata) 274a0ec28b6SAdrian Ambrożewicz { 275a0ec28b6SAdrian Ambrożewicz if (sensor.name == name) 276a0ec28b6SAdrian Ambrożewicz { 277a0ec28b6SAdrian Ambrożewicz sensor.uri = uri; 278a0ec28b6SAdrian Ambrożewicz } 279a0ec28b6SAdrian Ambrożewicz } 280a0ec28b6SAdrian Ambrożewicz } 281a0ec28b6SAdrian Ambrożewicz } 282a0ec28b6SAdrian Ambrożewicz 2838d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp> asyncResp; 284a0ec28b6SAdrian Ambrożewicz const std::string chassisId; 28502da7c5aSEd Tanous const std::span<std::string_view> types; 286a0ec28b6SAdrian Ambrożewicz const std::string chassisSubNode; 287928fefb9SNan Zhou const bool efficientExpand; 288a0ec28b6SAdrian Ambrożewicz 289a0ec28b6SAdrian Ambrożewicz private: 290a0ec28b6SAdrian Ambrożewicz std::optional<std::vector<SensorData>> metadata; 291a0ec28b6SAdrian Ambrożewicz DataCompleteCb dataComplete; 29208777fb0SLewanczyk, Dawid }; 29308777fb0SLewanczyk, Dawid 29408777fb0SLewanczyk, Dawid /** 295d500549bSAnthony Wilson * Possible states for physical inventory leds 296d500549bSAnthony Wilson */ 297d500549bSAnthony Wilson enum class LedState 298d500549bSAnthony Wilson { 299d500549bSAnthony Wilson OFF, 300d500549bSAnthony Wilson ON, 301d500549bSAnthony Wilson BLINK, 302d500549bSAnthony Wilson UNKNOWN 303d500549bSAnthony Wilson }; 304d500549bSAnthony Wilson 305d500549bSAnthony Wilson /** 306adc4f0dbSShawn McCarney * D-Bus inventory item associated with one or more sensors. 307adc4f0dbSShawn McCarney */ 308adc4f0dbSShawn McCarney class InventoryItem 309adc4f0dbSShawn McCarney { 310adc4f0dbSShawn McCarney public: 3114e23a444SEd Tanous explicit InventoryItem(const std::string& objPath) : objectPath(objPath) 312adc4f0dbSShawn McCarney { 313adc4f0dbSShawn McCarney // Set inventory item name to last node of object path 31428aa8de5SGeorge Liu sdbusplus::message::object_path path(objectPath); 31528aa8de5SGeorge Liu name = path.filename(); 31628aa8de5SGeorge Liu if (name.empty()) 317adc4f0dbSShawn McCarney { 31828aa8de5SGeorge Liu BMCWEB_LOG_ERROR << "Failed to find '/' in " << objectPath; 319adc4f0dbSShawn McCarney } 320adc4f0dbSShawn McCarney } 321adc4f0dbSShawn McCarney 322adc4f0dbSShawn McCarney std::string objectPath; 323adc4f0dbSShawn McCarney std::string name; 324e05aec50SEd Tanous bool isPresent = true; 325e05aec50SEd Tanous bool isFunctional = true; 326e05aec50SEd Tanous bool isPowerSupply = false; 327e05aec50SEd Tanous int powerSupplyEfficiencyPercent = -1; 328adc4f0dbSShawn McCarney std::string manufacturer; 329adc4f0dbSShawn McCarney std::string model; 330adc4f0dbSShawn McCarney std::string partNumber; 331adc4f0dbSShawn McCarney std::string serialNumber; 332adc4f0dbSShawn McCarney std::set<std::string> sensors; 333d500549bSAnthony Wilson std::string ledObjectPath; 334e05aec50SEd Tanous LedState ledState = LedState::UNKNOWN; 335adc4f0dbSShawn McCarney }; 336adc4f0dbSShawn McCarney 337adc4f0dbSShawn McCarney /** 338413961deSRichard Marian Thomaiyar * @brief Get objects with connection necessary for sensors 339588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 34008777fb0SLewanczyk, Dawid * @param sensorNames Sensors retrieved from chassis 34108777fb0SLewanczyk, Dawid * @param callback Callback for processing gathered connections 34208777fb0SLewanczyk, Dawid */ 34308777fb0SLewanczyk, Dawid template <typename Callback> 344413961deSRichard Marian Thomaiyar void getObjectsWithConnection( 34581ce609eSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 346fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames, 3471abe55efSEd Tanous Callback&& callback) 3481abe55efSEd Tanous { 349413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection enter"; 35003b5bae3SJames Feist const std::string path = "/xyz/openbmc_project/sensors"; 35108777fb0SLewanczyk, Dawid const std::array<std::string, 1> interfaces = { 35208777fb0SLewanczyk, Dawid "xyz.openbmc_project.Sensor.Value"}; 35308777fb0SLewanczyk, Dawid 35408777fb0SLewanczyk, Dawid // Response handler for parsing objects subtree 355002d39b4SEd Tanous auto respHandler = 356002d39b4SEd Tanous [callback{std::forward<Callback>(callback)}, sensorsAsyncResp, 357002d39b4SEd Tanous sensorNames](const boost::system::error_code ec, 358002d39b4SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 359413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler enter"; 3601abe55efSEd Tanous if (ec) 3611abe55efSEd Tanous { 3628d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 363413961deSRichard Marian Thomaiyar BMCWEB_LOG_ERROR 364413961deSRichard Marian Thomaiyar << "getObjectsWithConnection resp_handler: Dbus error " << ec; 36508777fb0SLewanczyk, Dawid return; 36608777fb0SLewanczyk, Dawid } 36708777fb0SLewanczyk, Dawid 36855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees"; 36908777fb0SLewanczyk, Dawid 37008777fb0SLewanczyk, Dawid // Make unique list of connections only for requested sensor types and 37108777fb0SLewanczyk, Dawid // found in the chassis 372fe04d49cSNan Zhou std::set<std::string> connections; 373413961deSRichard Marian Thomaiyar std::set<std::pair<std::string, std::string>> objectsWithConnection; 37408777fb0SLewanczyk, Dawid 37549c53ac9SJohnathan Mantey BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames->size(); 37649c53ac9SJohnathan Mantey for (const std::string& tsensor : *sensorNames) 3771abe55efSEd Tanous { 37855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor; 37908777fb0SLewanczyk, Dawid } 38008777fb0SLewanczyk, Dawid 38108777fb0SLewanczyk, Dawid for (const std::pair< 38208777fb0SLewanczyk, Dawid std::string, 38308777fb0SLewanczyk, Dawid std::vector<std::pair<std::string, std::vector<std::string>>>>& 3841abe55efSEd Tanous object : subtree) 3851abe55efSEd Tanous { 38649c53ac9SJohnathan Mantey if (sensorNames->find(object.first) != sensorNames->end()) 3871abe55efSEd Tanous { 38849c53ac9SJohnathan Mantey for (const std::pair<std::string, std::vector<std::string>>& 3891abe55efSEd Tanous objData : object.second) 3901abe55efSEd Tanous { 39149c53ac9SJohnathan Mantey BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first; 39208777fb0SLewanczyk, Dawid connections.insert(objData.first); 393de629b6eSShawn McCarney objectsWithConnection.insert( 394de629b6eSShawn McCarney std::make_pair(object.first, objData.first)); 39508777fb0SLewanczyk, Dawid } 39608777fb0SLewanczyk, Dawid } 39708777fb0SLewanczyk, Dawid } 39855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections"; 399413961deSRichard Marian Thomaiyar callback(std::move(connections), std::move(objectsWithConnection)); 400413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection resp_handler exit"; 40108777fb0SLewanczyk, Dawid }; 40208777fb0SLewanczyk, Dawid // Make call to ObjectMapper to find all sensors objects 40355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 40455c7b7a2SEd Tanous std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 4051abe55efSEd Tanous "/xyz/openbmc_project/object_mapper", 4061abe55efSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces); 407413961deSRichard Marian Thomaiyar BMCWEB_LOG_DEBUG << "getObjectsWithConnection exit"; 408413961deSRichard Marian Thomaiyar } 409413961deSRichard Marian Thomaiyar 410413961deSRichard Marian Thomaiyar /** 411413961deSRichard Marian Thomaiyar * @brief Create connections necessary for sensors 412413961deSRichard Marian Thomaiyar * @param SensorsAsyncResp Pointer to object holding response data 413413961deSRichard Marian Thomaiyar * @param sensorNames Sensors retrieved from chassis 414413961deSRichard Marian Thomaiyar * @param callback Callback for processing gathered connections 415413961deSRichard Marian Thomaiyar */ 416413961deSRichard Marian Thomaiyar template <typename Callback> 417fe04d49cSNan Zhou void getConnections(std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 418fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames, 419413961deSRichard Marian Thomaiyar Callback&& callback) 420413961deSRichard Marian Thomaiyar { 421413961deSRichard Marian Thomaiyar auto objectsWithConnectionCb = 422fe04d49cSNan Zhou [callback](const std::set<std::string>& connections, 423413961deSRichard Marian Thomaiyar const std::set<std::pair<std::string, std::string>>& 4243174e4dfSEd Tanous /*objectsWithConnection*/) { callback(connections); }; 42581ce609eSEd Tanous getObjectsWithConnection(sensorsAsyncResp, sensorNames, 426413961deSRichard Marian Thomaiyar std::move(objectsWithConnectionCb)); 42708777fb0SLewanczyk, Dawid } 42808777fb0SLewanczyk, Dawid 42908777fb0SLewanczyk, Dawid /** 43049c53ac9SJohnathan Mantey * @brief Shrinks the list of sensors for processing 43149c53ac9SJohnathan Mantey * @param SensorsAysncResp The class holding the Redfish response 43249c53ac9SJohnathan Mantey * @param allSensors A list of all the sensors associated to the 43349c53ac9SJohnathan Mantey * chassis element (i.e. baseboard, front panel, etc...) 43449c53ac9SJohnathan Mantey * @param activeSensors A list that is a reduction of the incoming 43549c53ac9SJohnathan Mantey * allSensors list. Eliminate Thermal sensors when a Power request is 43649c53ac9SJohnathan Mantey * made, and eliminate Power sensors when a Thermal request is made. 43749c53ac9SJohnathan Mantey */ 43823a21a1cSEd Tanous inline void reduceSensorList( 4397f1cc26dSEd Tanous crow::Response& res, std::string_view chassisSubNode, 4407f1cc26dSEd Tanous std::span<std::string_view> sensorTypes, 44149c53ac9SJohnathan Mantey const std::vector<std::string>* allSensors, 442fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& activeSensors) 44349c53ac9SJohnathan Mantey { 44449c53ac9SJohnathan Mantey if ((allSensors == nullptr) || (activeSensors == nullptr)) 44549c53ac9SJohnathan Mantey { 4467f1cc26dSEd Tanous messages::resourceNotFound(res, chassisSubNode, 4477f1cc26dSEd Tanous chassisSubNode == sensors::node::thermal 448a0ec28b6SAdrian Ambrożewicz ? "Temperatures" 44949c53ac9SJohnathan Mantey : "Voltages"); 45049c53ac9SJohnathan Mantey 45149c53ac9SJohnathan Mantey return; 45249c53ac9SJohnathan Mantey } 45349c53ac9SJohnathan Mantey if (allSensors->empty()) 45449c53ac9SJohnathan Mantey { 45549c53ac9SJohnathan Mantey // Nothing to do, the activeSensors object is also empty 45649c53ac9SJohnathan Mantey return; 45749c53ac9SJohnathan Mantey } 45849c53ac9SJohnathan Mantey 4597f1cc26dSEd Tanous for (std::string_view type : sensorTypes) 46049c53ac9SJohnathan Mantey { 46149c53ac9SJohnathan Mantey for (const std::string& sensor : *allSensors) 46249c53ac9SJohnathan Mantey { 46311ba3979SEd Tanous if (sensor.starts_with(type)) 46449c53ac9SJohnathan Mantey { 46549c53ac9SJohnathan Mantey activeSensors->emplace(sensor); 46649c53ac9SJohnathan Mantey } 46749c53ac9SJohnathan Mantey } 46849c53ac9SJohnathan Mantey } 46949c53ac9SJohnathan Mantey } 47049c53ac9SJohnathan Mantey 4717f1cc26dSEd Tanous /* 4727f1cc26dSEd Tanous *Populates the top level collection for a given subnode. Populates 4737f1cc26dSEd Tanous *SensorCollection, Power, or Thermal schemas. 4747f1cc26dSEd Tanous * 4757f1cc26dSEd Tanous * */ 4767f1cc26dSEd Tanous inline void populateChassisNode(nlohmann::json& jsonValue, 4777f1cc26dSEd Tanous std::string_view chassisSubNode) 4787f1cc26dSEd Tanous { 4797f1cc26dSEd Tanous if (chassisSubNode == sensors::node::power) 4807f1cc26dSEd Tanous { 4817f1cc26dSEd Tanous jsonValue["@odata.type"] = "#Power.v1_5_2.Power"; 4827f1cc26dSEd Tanous } 4837f1cc26dSEd Tanous else if (chassisSubNode == sensors::node::thermal) 4847f1cc26dSEd Tanous { 4857f1cc26dSEd Tanous jsonValue["@odata.type"] = "#Thermal.v1_4_0.Thermal"; 4867f1cc26dSEd Tanous jsonValue["Fans"] = nlohmann::json::array(); 4877f1cc26dSEd Tanous jsonValue["Temperatures"] = nlohmann::json::array(); 4887f1cc26dSEd Tanous } 4897f1cc26dSEd Tanous else if (chassisSubNode == sensors::node::sensors) 4907f1cc26dSEd Tanous { 4917f1cc26dSEd Tanous jsonValue["@odata.type"] = "#SensorCollection.SensorCollection"; 4927f1cc26dSEd Tanous jsonValue["Description"] = "Collection of Sensors for this Chassis"; 4937f1cc26dSEd Tanous jsonValue["Members"] = nlohmann::json::array(); 4947f1cc26dSEd Tanous jsonValue["Members@odata.count"] = 0; 4957f1cc26dSEd Tanous } 4967f1cc26dSEd Tanous 4977f1cc26dSEd Tanous if (chassisSubNode != sensors::node::sensors) 4987f1cc26dSEd Tanous { 4997f1cc26dSEd Tanous jsonValue["Id"] = chassisSubNode; 5007f1cc26dSEd Tanous } 5017f1cc26dSEd Tanous jsonValue["Name"] = chassisSubNode; 5027f1cc26dSEd Tanous } 5037f1cc26dSEd Tanous 50449c53ac9SJohnathan Mantey /** 50508777fb0SLewanczyk, Dawid * @brief Retrieves requested chassis sensors and redundancy data from DBus . 506588c3f0dSKowalski, Kamil * @param SensorsAsyncResp Pointer to object holding response data 50708777fb0SLewanczyk, Dawid * @param callback Callback for next step in gathered sensor processing 50808777fb0SLewanczyk, Dawid */ 50908777fb0SLewanczyk, Dawid template <typename Callback> 5107f1cc26dSEd Tanous void getChassis(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 5117f1cc26dSEd Tanous std::string_view chassisId, std::string_view chassisSubNode, 5127f1cc26dSEd Tanous std::span<std::string_view> sensorTypes, Callback&& callback) 5131abe55efSEd Tanous { 51455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis enter"; 515adc4f0dbSShawn McCarney const std::array<const char*, 2> interfaces = { 51649c53ac9SJohnathan Mantey "xyz.openbmc_project.Inventory.Item.Board", 517adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.Chassis"}; 518002d39b4SEd Tanous auto respHandler = 5197f1cc26dSEd Tanous [callback{std::forward<Callback>(callback)}, asyncResp, 5207f1cc26dSEd Tanous chassisIdStr{std::string(chassisId)}, 5217f1cc26dSEd Tanous chassisSubNode{std::string(chassisSubNode)}, sensorTypes]( 52249c53ac9SJohnathan Mantey const boost::system::error_code ec, 523002d39b4SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisPaths) { 52455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis respHandler enter"; 5251abe55efSEd Tanous if (ec) 5261abe55efSEd Tanous { 52755c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec; 5287f1cc26dSEd Tanous messages::internalError(asyncResp->res); 52908777fb0SLewanczyk, Dawid return; 53008777fb0SLewanczyk, Dawid } 53149c53ac9SJohnathan Mantey const std::string* chassisPath = nullptr; 53249c53ac9SJohnathan Mantey std::string chassisName; 53349c53ac9SJohnathan Mantey for (const std::string& chassis : chassisPaths) 5341abe55efSEd Tanous { 53528aa8de5SGeorge Liu sdbusplus::message::object_path path(chassis); 53628aa8de5SGeorge Liu chassisName = path.filename(); 53728aa8de5SGeorge Liu if (chassisName.empty()) 5381abe55efSEd Tanous { 53949c53ac9SJohnathan Mantey BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis; 540daf36e2eSEd Tanous continue; 541daf36e2eSEd Tanous } 5427f1cc26dSEd Tanous if (chassisName == chassisIdStr) 5431abe55efSEd Tanous { 54449c53ac9SJohnathan Mantey chassisPath = &chassis; 54549c53ac9SJohnathan Mantey break; 546daf36e2eSEd Tanous } 54749c53ac9SJohnathan Mantey } 54849c53ac9SJohnathan Mantey if (chassisPath == nullptr) 5491abe55efSEd Tanous { 5507f1cc26dSEd Tanous messages::resourceNotFound(asyncResp->res, "Chassis", chassisIdStr); 55149c53ac9SJohnathan Mantey return; 5521abe55efSEd Tanous } 5537f1cc26dSEd Tanous populateChassisNode(asyncResp->res.jsonValue, chassisSubNode); 55408777fb0SLewanczyk, Dawid 5557f1cc26dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 5567f1cc26dSEd Tanous "/redfish/v1/Chassis/" + chassisIdStr + "/" + chassisSubNode; 55795a3ecadSAnthony Wilson 5588fb49dd6SShawn McCarney // Get the list of all sensors for this Chassis element 5598fb49dd6SShawn McCarney std::string sensorPath = *chassisPath + "/all_sensors"; 5601e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::vector<std::string>>( 5611e1e598dSJonathan Doman *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper", 5621e1e598dSJonathan Doman sensorPath, "xyz.openbmc_project.Association", "endpoints", 5637f1cc26dSEd Tanous [asyncResp, chassisSubNode, sensorTypes, 564f94c4ecfSEd Tanous callback{std::forward<const Callback>(callback)}]( 565271584abSEd Tanous const boost::system::error_code& e, 5661e1e598dSJonathan Doman const std::vector<std::string>& nodeSensorList) { 567271584abSEd Tanous if (e) 56849c53ac9SJohnathan Mantey { 569271584abSEd Tanous if (e.value() != EBADR) 57049c53ac9SJohnathan Mantey { 5717f1cc26dSEd Tanous messages::internalError(asyncResp->res); 57249c53ac9SJohnathan Mantey return; 57349c53ac9SJohnathan Mantey } 57449c53ac9SJohnathan Mantey } 575fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> culledSensorList = 576fe04d49cSNan Zhou std::make_shared<std::set<std::string>>(); 5777f1cc26dSEd Tanous reduceSensorList(asyncResp->res, chassisSubNode, sensorTypes, 5787f1cc26dSEd Tanous &nodeSensorList, culledSensorList); 5797f1cc26dSEd Tanous BMCWEB_LOG_DEBUG << "Finishing with " << culledSensorList->size(); 58049c53ac9SJohnathan Mantey callback(culledSensorList); 5811e1e598dSJonathan Doman }); 58249c53ac9SJohnathan Mantey }; 58349c53ac9SJohnathan Mantey 58449c53ac9SJohnathan Mantey // Get the Chassis Collection 58549c53ac9SJohnathan Mantey crow::connections::systemBus->async_method_call( 58649c53ac9SJohnathan Mantey respHandler, "xyz.openbmc_project.ObjectMapper", 58749c53ac9SJohnathan Mantey "/xyz/openbmc_project/object_mapper", 58849c53ac9SJohnathan Mantey "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 589271584abSEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces); 59055c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassis exit"; 59108777fb0SLewanczyk, Dawid } 59208777fb0SLewanczyk, Dawid 59308777fb0SLewanczyk, Dawid /** 594de629b6eSShawn McCarney * @brief Finds all DBus object paths that implement ObjectManager. 595de629b6eSShawn McCarney * 596de629b6eSShawn McCarney * Creates a mapping from the associated connection name to the object path. 597de629b6eSShawn McCarney * 598de629b6eSShawn McCarney * Finds the object paths asynchronously. Invokes callback when information has 599de629b6eSShawn McCarney * been obtained. 600de629b6eSShawn McCarney * 601de629b6eSShawn McCarney * The callback must have the following signature: 602de629b6eSShawn McCarney * @code 603fe04d49cSNan Zhou * callback(std::shared_ptr<std::map<std::string,std::string>> objectMgrPaths) 604de629b6eSShawn McCarney * @endcode 605de629b6eSShawn McCarney * 60649c53ac9SJohnathan Mantey * @param sensorsAsyncResp Pointer to object holding response data. 607de629b6eSShawn McCarney * @param callback Callback to invoke when object paths obtained. 608de629b6eSShawn McCarney */ 609de629b6eSShawn McCarney template <typename Callback> 610b5a76932SEd Tanous void getObjectManagerPaths( 61181ce609eSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 612de629b6eSShawn McCarney Callback&& callback) 613de629b6eSShawn McCarney { 614de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths enter"; 615de629b6eSShawn McCarney const std::array<std::string, 1> interfaces = { 616de629b6eSShawn McCarney "org.freedesktop.DBus.ObjectManager"}; 617de629b6eSShawn McCarney 618de629b6eSShawn McCarney // Response handler for GetSubTree DBus method 619002d39b4SEd Tanous auto respHandler = 620002d39b4SEd Tanous [callback{std::forward<Callback>(callback)}, sensorsAsyncResp]( 621b9d36b47SEd Tanous const boost::system::error_code ec, 622002d39b4SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 623de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler enter"; 624de629b6eSShawn McCarney if (ec) 625de629b6eSShawn McCarney { 6268d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 627de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "getObjectManagerPaths respHandler: DBus error " 628de629b6eSShawn McCarney << ec; 629de629b6eSShawn McCarney return; 630de629b6eSShawn McCarney } 631de629b6eSShawn McCarney 632de629b6eSShawn McCarney // Loop over returned object paths 633fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> objectMgrPaths = 634fe04d49cSNan Zhou std::make_shared<std::map<std::string, std::string>>(); 635de629b6eSShawn McCarney for (const std::pair< 636de629b6eSShawn McCarney std::string, 637de629b6eSShawn McCarney std::vector<std::pair<std::string, std::vector<std::string>>>>& 638de629b6eSShawn McCarney object : subtree) 639de629b6eSShawn McCarney { 640de629b6eSShawn McCarney // Loop over connections for current object path 641de629b6eSShawn McCarney const std::string& objectPath = object.first; 642de629b6eSShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 643de629b6eSShawn McCarney objData : object.second) 644de629b6eSShawn McCarney { 645de629b6eSShawn McCarney // Add mapping from connection to object path 646de629b6eSShawn McCarney const std::string& connection = objData.first; 6478fb49dd6SShawn McCarney (*objectMgrPaths)[connection] = objectPath; 648de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "Added mapping " << connection << " -> " 649de629b6eSShawn McCarney << objectPath; 650de629b6eSShawn McCarney } 651de629b6eSShawn McCarney } 6528fb49dd6SShawn McCarney callback(objectMgrPaths); 653de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths respHandler exit"; 654de629b6eSShawn McCarney }; 655de629b6eSShawn McCarney 656de629b6eSShawn McCarney // Query mapper for all DBus object paths that implement ObjectManager 657de629b6eSShawn McCarney crow::connections::systemBus->async_method_call( 658de629b6eSShawn McCarney std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 659de629b6eSShawn McCarney "/xyz/openbmc_project/object_mapper", 660271584abSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, interfaces); 661de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPaths exit"; 662de629b6eSShawn McCarney } 663de629b6eSShawn McCarney 664de629b6eSShawn McCarney /** 665adc4f0dbSShawn McCarney * @brief Returns the Redfish State value for the specified inventory item. 666adc4f0dbSShawn McCarney * @param inventoryItem D-Bus inventory item associated with a sensor. 667adc4f0dbSShawn McCarney * @return State value for inventory item. 66834dd179eSJames Feist */ 66923a21a1cSEd Tanous inline std::string getState(const InventoryItem* inventoryItem) 670adc4f0dbSShawn McCarney { 671adc4f0dbSShawn McCarney if ((inventoryItem != nullptr) && !(inventoryItem->isPresent)) 672adc4f0dbSShawn McCarney { 673adc4f0dbSShawn McCarney return "Absent"; 674adc4f0dbSShawn McCarney } 67534dd179eSJames Feist 676adc4f0dbSShawn McCarney return "Enabled"; 677adc4f0dbSShawn McCarney } 678adc4f0dbSShawn McCarney 679adc4f0dbSShawn McCarney /** 680adc4f0dbSShawn McCarney * @brief Returns the Redfish Health value for the specified sensor. 681adc4f0dbSShawn McCarney * @param sensorJson Sensor JSON object. 6821d7c0054SEd Tanous * @param valuesDict Map of all sensor DBus values. 683adc4f0dbSShawn McCarney * @param inventoryItem D-Bus inventory item associated with the sensor. Will 684adc4f0dbSShawn McCarney * be nullptr if no associated inventory item was found. 685adc4f0dbSShawn McCarney * @return Health value for sensor. 686adc4f0dbSShawn McCarney */ 6871d7c0054SEd Tanous inline std::string getHealth(nlohmann::json& sensorJson, 6881d7c0054SEd Tanous const dbus::utility::DBusPropertiesMap& valuesDict, 689adc4f0dbSShawn McCarney const InventoryItem* inventoryItem) 69034dd179eSJames Feist { 691adc4f0dbSShawn McCarney // Get current health value (if any) in the sensor JSON object. Some JSON 692adc4f0dbSShawn McCarney // objects contain multiple sensors (such as PowerSupplies). We want to set 693adc4f0dbSShawn McCarney // the overall health to be the most severe of any of the sensors. 694adc4f0dbSShawn McCarney std::string currentHealth; 695adc4f0dbSShawn McCarney auto statusIt = sensorJson.find("Status"); 696adc4f0dbSShawn McCarney if (statusIt != sensorJson.end()) 697adc4f0dbSShawn McCarney { 698adc4f0dbSShawn McCarney auto healthIt = statusIt->find("Health"); 699adc4f0dbSShawn McCarney if (healthIt != statusIt->end()) 700adc4f0dbSShawn McCarney { 701adc4f0dbSShawn McCarney std::string* health = healthIt->get_ptr<std::string*>(); 702adc4f0dbSShawn McCarney if (health != nullptr) 703adc4f0dbSShawn McCarney { 704adc4f0dbSShawn McCarney currentHealth = *health; 705adc4f0dbSShawn McCarney } 706adc4f0dbSShawn McCarney } 707adc4f0dbSShawn McCarney } 708adc4f0dbSShawn McCarney 709adc4f0dbSShawn McCarney // If current health in JSON object is already Critical, return that. This 710adc4f0dbSShawn McCarney // should override the sensor health, which might be less severe. 711adc4f0dbSShawn McCarney if (currentHealth == "Critical") 712adc4f0dbSShawn McCarney { 713adc4f0dbSShawn McCarney return "Critical"; 714adc4f0dbSShawn McCarney } 715adc4f0dbSShawn McCarney 716adc4f0dbSShawn McCarney // Check if sensor has critical threshold alarm 717711ac7a9SEd Tanous 7181d7c0054SEd Tanous for (const auto& [valueName, value] : valuesDict) 71934dd179eSJames Feist { 7201d7c0054SEd Tanous if (valueName == "CriticalAlarmHigh" || valueName == "CriticalAlarmLow") 721711ac7a9SEd Tanous { 722711ac7a9SEd Tanous const bool* asserted = std::get_if<bool>(&value); 72334dd179eSJames Feist if (asserted == nullptr) 72434dd179eSJames Feist { 72534dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 72634dd179eSJames Feist } 72734dd179eSJames Feist else if (*asserted) 72834dd179eSJames Feist { 72934dd179eSJames Feist return "Critical"; 73034dd179eSJames Feist } 73134dd179eSJames Feist } 73234dd179eSJames Feist } 73334dd179eSJames Feist 734adc4f0dbSShawn McCarney // Check if associated inventory item is not functional 735adc4f0dbSShawn McCarney if ((inventoryItem != nullptr) && !(inventoryItem->isFunctional)) 736adc4f0dbSShawn McCarney { 737adc4f0dbSShawn McCarney return "Critical"; 738adc4f0dbSShawn McCarney } 739adc4f0dbSShawn McCarney 740adc4f0dbSShawn McCarney // If current health in JSON object is already Warning, return that. This 741adc4f0dbSShawn McCarney // should override the sensor status, which might be less severe. 742adc4f0dbSShawn McCarney if (currentHealth == "Warning") 743adc4f0dbSShawn McCarney { 744adc4f0dbSShawn McCarney return "Warning"; 745adc4f0dbSShawn McCarney } 746adc4f0dbSShawn McCarney 747adc4f0dbSShawn McCarney // Check if sensor has warning threshold alarm 7481d7c0054SEd Tanous for (const auto& [valueName, value] : valuesDict) 74934dd179eSJames Feist { 7501d7c0054SEd Tanous if (valueName == "WarningAlarmHigh" || valueName == "WarningAlarmLow") 751711ac7a9SEd Tanous { 752711ac7a9SEd Tanous const bool* asserted = std::get_if<bool>(&value); 75334dd179eSJames Feist if (asserted == nullptr) 75434dd179eSJames Feist { 75534dd179eSJames Feist BMCWEB_LOG_ERROR << "Illegal sensor threshold"; 75634dd179eSJames Feist } 75734dd179eSJames Feist else if (*asserted) 75834dd179eSJames Feist { 759ebe4d91eSEd Tanous return "Warning"; 76034dd179eSJames Feist } 76134dd179eSJames Feist } 76234dd179eSJames Feist } 763adc4f0dbSShawn McCarney 76434dd179eSJames Feist return "OK"; 76534dd179eSJames Feist } 76634dd179eSJames Feist 76723a21a1cSEd Tanous inline void setLedState(nlohmann::json& sensorJson, 768d500549bSAnthony Wilson const InventoryItem* inventoryItem) 769d500549bSAnthony Wilson { 770d500549bSAnthony Wilson if (inventoryItem != nullptr && !inventoryItem->ledObjectPath.empty()) 771d500549bSAnthony Wilson { 772d500549bSAnthony Wilson switch (inventoryItem->ledState) 773d500549bSAnthony Wilson { 774d500549bSAnthony Wilson case LedState::OFF: 775d500549bSAnthony Wilson sensorJson["IndicatorLED"] = "Off"; 776d500549bSAnthony Wilson break; 777d500549bSAnthony Wilson case LedState::ON: 778d500549bSAnthony Wilson sensorJson["IndicatorLED"] = "Lit"; 779d500549bSAnthony Wilson break; 780d500549bSAnthony Wilson case LedState::BLINK: 781d500549bSAnthony Wilson sensorJson["IndicatorLED"] = "Blinking"; 782d500549bSAnthony Wilson break; 78323a21a1cSEd Tanous case LedState::UNKNOWN: 784d500549bSAnthony Wilson break; 785d500549bSAnthony Wilson } 786d500549bSAnthony Wilson } 787d500549bSAnthony Wilson } 788d500549bSAnthony Wilson 78934dd179eSJames Feist /** 79008777fb0SLewanczyk, Dawid * @brief Builds a json sensor representation of a sensor. 79108777fb0SLewanczyk, Dawid * @param sensorName The name of the sensor to be built 792274fad5aSGunnar Mills * @param sensorType The type (temperature, fan_tach, etc) of the sensor to 79308777fb0SLewanczyk, Dawid * build 7941d7c0054SEd Tanous * @param chassisSubNode The subnode (thermal, sensor, ect) of the sensor 7951d7c0054SEd Tanous * @param propertiesDict A dictionary of the properties to build the sensor 7961d7c0054SEd Tanous * from. 7971d7c0054SEd Tanous * @param sensorJson The json object to fill 798adc4f0dbSShawn McCarney * @param inventoryItem D-Bus inventory item associated with the sensor. Will 799adc4f0dbSShawn McCarney * be nullptr if no associated inventory item was found. 80008777fb0SLewanczyk, Dawid */ 8011d7c0054SEd Tanous inline void objectPropertiesToJson( 8021d7c0054SEd Tanous std::string_view sensorName, std::string_view sensorType, 8031d7c0054SEd Tanous std::string_view chassisSubNode, 8041d7c0054SEd Tanous const dbus::utility::DBusPropertiesMap& propertiesDict, 80581ce609eSEd Tanous nlohmann::json& sensorJson, InventoryItem* inventoryItem) 8061abe55efSEd Tanous { 80708777fb0SLewanczyk, Dawid // Assume values exist as is (10^0 == 1) if no scale exists 80808777fb0SLewanczyk, Dawid int64_t scaleMultiplier = 0; 8091d7c0054SEd Tanous for (const auto& [valueName, value] : propertiesDict) 810711ac7a9SEd Tanous { 811711ac7a9SEd Tanous if (valueName == "Scale") 812711ac7a9SEd Tanous { 813711ac7a9SEd Tanous const int64_t* int64Value = std::get_if<int64_t>(&value); 8141abe55efSEd Tanous if (int64Value != nullptr) 8151abe55efSEd Tanous { 81608777fb0SLewanczyk, Dawid scaleMultiplier = *int64Value; 81708777fb0SLewanczyk, Dawid } 81808777fb0SLewanczyk, Dawid } 819711ac7a9SEd Tanous } 82008777fb0SLewanczyk, Dawid 8211d7c0054SEd Tanous if (chassisSubNode == sensors::node::sensors) 822adc4f0dbSShawn McCarney { 823*c1d019a6SEd Tanous std::string subNodeEscaped(chassisSubNode); 824*c1d019a6SEd Tanous subNodeEscaped.erase( 825*c1d019a6SEd Tanous std::remove(subNodeEscaped.begin(), subNodeEscaped.end(), '_'), 826*c1d019a6SEd Tanous subNodeEscaped.end()); 827*c1d019a6SEd Tanous 828*c1d019a6SEd Tanous // For sensors in SensorCollection we set Id instead of MemberId, 829*c1d019a6SEd Tanous // including power sensors. 830*c1d019a6SEd Tanous subNodeEscaped += '_'; 831*c1d019a6SEd Tanous subNodeEscaped += sensorName; 832*c1d019a6SEd Tanous sensorJson["Id"] = std::move(subNodeEscaped); 833*c1d019a6SEd Tanous 8341d7c0054SEd Tanous std::string sensorNameEs(sensorName); 8351d7c0054SEd Tanous std::replace(sensorNameEs.begin(), sensorNameEs.end(), '_', ' '); 8361d7c0054SEd Tanous sensorJson["Name"] = std::move(sensorNameEs); 83795a3ecadSAnthony Wilson } 83895a3ecadSAnthony Wilson else if (sensorType != "power") 83995a3ecadSAnthony Wilson { 84095a3ecadSAnthony Wilson // Set MemberId and Name for non-power sensors. For PowerSupplies and 84195a3ecadSAnthony Wilson // PowerControl, those properties have more general values because 84295a3ecadSAnthony Wilson // multiple sensors can be stored in the same JSON object. 84381ce609eSEd Tanous sensorJson["MemberId"] = sensorName; 8441d7c0054SEd Tanous std::string sensorNameEs(sensorName); 8451d7c0054SEd Tanous std::replace(sensorNameEs.begin(), sensorNameEs.end(), '_', ' '); 8461d7c0054SEd Tanous sensorJson["Name"] = std::move(sensorNameEs); 847adc4f0dbSShawn McCarney } 848e742b6ccSEd Tanous 84981ce609eSEd Tanous sensorJson["Status"]["State"] = getState(inventoryItem); 85081ce609eSEd Tanous sensorJson["Status"]["Health"] = 8511d7c0054SEd Tanous getHealth(sensorJson, propertiesDict, inventoryItem); 85208777fb0SLewanczyk, Dawid 85308777fb0SLewanczyk, Dawid // Parameter to set to override the type we get from dbus, and force it to 85408777fb0SLewanczyk, Dawid // int, regardless of what is available. This is used for schemas like fan, 85508777fb0SLewanczyk, Dawid // that require integers, not floats. 85608777fb0SLewanczyk, Dawid bool forceToInt = false; 85708777fb0SLewanczyk, Dawid 8583929aca1SAnthony Wilson nlohmann::json::json_pointer unit("/Reading"); 8591d7c0054SEd Tanous if (chassisSubNode == sensors::node::sensors) 86095a3ecadSAnthony Wilson { 8612a4ba195SShounak Mitra sensorJson["@odata.type"] = "#Sensor.v1_2_0.Sensor"; 862c2bf7f99SWludzik, Jozef 8631d7c0054SEd Tanous std::string_view readingType = sensors::toReadingType(sensorType); 864c2bf7f99SWludzik, Jozef if (readingType.empty()) 86595a3ecadSAnthony Wilson { 866c2bf7f99SWludzik, Jozef BMCWEB_LOG_ERROR << "Redfish cannot map reading type for " 867c2bf7f99SWludzik, Jozef << sensorType; 86895a3ecadSAnthony Wilson } 869c2bf7f99SWludzik, Jozef else 87095a3ecadSAnthony Wilson { 871c2bf7f99SWludzik, Jozef sensorJson["ReadingType"] = readingType; 87295a3ecadSAnthony Wilson } 873c2bf7f99SWludzik, Jozef 8741d7c0054SEd Tanous std::string_view readingUnits = sensors::toReadingUnits(sensorType); 875c2bf7f99SWludzik, Jozef if (readingUnits.empty()) 876f8ede15eSAdrian Ambrożewicz { 877c2bf7f99SWludzik, Jozef BMCWEB_LOG_ERROR << "Redfish cannot map reading unit for " 878c2bf7f99SWludzik, Jozef << sensorType; 879c2bf7f99SWludzik, Jozef } 880c2bf7f99SWludzik, Jozef else 881c2bf7f99SWludzik, Jozef { 882c2bf7f99SWludzik, Jozef sensorJson["ReadingUnits"] = readingUnits; 883f8ede15eSAdrian Ambrożewicz } 88495a3ecadSAnthony Wilson } 88595a3ecadSAnthony Wilson else if (sensorType == "temperature") 8861abe55efSEd Tanous { 8873929aca1SAnthony Wilson unit = "/ReadingCelsius"_json_pointer; 88881ce609eSEd Tanous sensorJson["@odata.type"] = "#Thermal.v1_3_0.Temperature"; 88908777fb0SLewanczyk, Dawid // TODO(ed) Documentation says that path should be type fan_tach, 89008777fb0SLewanczyk, Dawid // implementation seems to implement fan 8911abe55efSEd Tanous } 8921abe55efSEd Tanous else if (sensorType == "fan" || sensorType == "fan_tach") 8931abe55efSEd Tanous { 8943929aca1SAnthony Wilson unit = "/Reading"_json_pointer; 89581ce609eSEd Tanous sensorJson["ReadingUnits"] = "RPM"; 89681ce609eSEd Tanous sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan"; 89781ce609eSEd Tanous setLedState(sensorJson, inventoryItem); 89808777fb0SLewanczyk, Dawid forceToInt = true; 8991abe55efSEd Tanous } 9006f6d0d32SEd Tanous else if (sensorType == "fan_pwm") 9016f6d0d32SEd Tanous { 9023929aca1SAnthony Wilson unit = "/Reading"_json_pointer; 90381ce609eSEd Tanous sensorJson["ReadingUnits"] = "Percent"; 90481ce609eSEd Tanous sensorJson["@odata.type"] = "#Thermal.v1_3_0.Fan"; 90581ce609eSEd Tanous setLedState(sensorJson, inventoryItem); 9066f6d0d32SEd Tanous forceToInt = true; 9076f6d0d32SEd Tanous } 9081abe55efSEd Tanous else if (sensorType == "voltage") 9091abe55efSEd Tanous { 9103929aca1SAnthony Wilson unit = "/ReadingVolts"_json_pointer; 91181ce609eSEd Tanous sensorJson["@odata.type"] = "#Power.v1_0_0.Voltage"; 9121abe55efSEd Tanous } 9132474adfaSEd Tanous else if (sensorType == "power") 9142474adfaSEd Tanous { 9151d7c0054SEd Tanous if (boost::iequals(sensorName, "total_power")) 916028f7ebcSEddie James { 91781ce609eSEd Tanous sensorJson["@odata.type"] = "#Power.v1_0_0.PowerControl"; 9187ab06f49SGunnar Mills // Put multiple "sensors" into a single PowerControl, so have 9197ab06f49SGunnar Mills // generic names for MemberId and Name. Follows Redfish mockup. 92081ce609eSEd Tanous sensorJson["MemberId"] = "0"; 92181ce609eSEd Tanous sensorJson["Name"] = "Chassis Power Control"; 9223929aca1SAnthony Wilson unit = "/PowerConsumedWatts"_json_pointer; 923028f7ebcSEddie James } 9241d7c0054SEd Tanous else if (boost::ifind_first(sensorName, "input").empty()) 92549c53ac9SJohnathan Mantey { 9263929aca1SAnthony Wilson unit = "/PowerInputWatts"_json_pointer; 92749c53ac9SJohnathan Mantey } 92849c53ac9SJohnathan Mantey else 92949c53ac9SJohnathan Mantey { 9303929aca1SAnthony Wilson unit = "/PowerOutputWatts"_json_pointer; 93149c53ac9SJohnathan Mantey } 9322474adfaSEd Tanous } 9331abe55efSEd Tanous else 9341abe55efSEd Tanous { 93555c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName; 93608777fb0SLewanczyk, Dawid return; 93708777fb0SLewanczyk, Dawid } 93808777fb0SLewanczyk, Dawid // Map of dbus interface name, dbus property name and redfish property_name 9393929aca1SAnthony Wilson std::vector< 9403929aca1SAnthony Wilson std::tuple<const char*, const char*, nlohmann::json::json_pointer>> 9413929aca1SAnthony Wilson properties; 94208777fb0SLewanczyk, Dawid properties.reserve(7); 94308777fb0SLewanczyk, Dawid 94408777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit); 945de629b6eSShawn McCarney 9461d7c0054SEd Tanous if (chassisSubNode == sensors::node::sensors) 9473929aca1SAnthony Wilson { 9483929aca1SAnthony Wilson properties.emplace_back( 9493929aca1SAnthony Wilson "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningHigh", 9503929aca1SAnthony Wilson "/Thresholds/UpperCaution/Reading"_json_pointer); 9513929aca1SAnthony Wilson properties.emplace_back( 9523929aca1SAnthony Wilson "xyz.openbmc_project.Sensor.Threshold.Warning", "WarningLow", 9533929aca1SAnthony Wilson "/Thresholds/LowerCaution/Reading"_json_pointer); 9543929aca1SAnthony Wilson properties.emplace_back( 9553929aca1SAnthony Wilson "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalHigh", 9563929aca1SAnthony Wilson "/Thresholds/UpperCritical/Reading"_json_pointer); 9573929aca1SAnthony Wilson properties.emplace_back( 9583929aca1SAnthony Wilson "xyz.openbmc_project.Sensor.Threshold.Critical", "CriticalLow", 9593929aca1SAnthony Wilson "/Thresholds/LowerCritical/Reading"_json_pointer); 9603929aca1SAnthony Wilson } 9613929aca1SAnthony Wilson else if (sensorType != "power") 962de629b6eSShawn McCarney { 96308777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 9643929aca1SAnthony Wilson "WarningHigh", 9653929aca1SAnthony Wilson "/UpperThresholdNonCritical"_json_pointer); 96608777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning", 9673929aca1SAnthony Wilson "WarningLow", 9683929aca1SAnthony Wilson "/LowerThresholdNonCritical"_json_pointer); 96908777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 9703929aca1SAnthony Wilson "CriticalHigh", 9713929aca1SAnthony Wilson "/UpperThresholdCritical"_json_pointer); 97208777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical", 9733929aca1SAnthony Wilson "CriticalLow", 9743929aca1SAnthony Wilson "/LowerThresholdCritical"_json_pointer); 975de629b6eSShawn McCarney } 97608777fb0SLewanczyk, Dawid 9772474adfaSEd Tanous // TODO Need to get UpperThresholdFatal and LowerThresholdFatal 9782474adfaSEd Tanous 9791d7c0054SEd Tanous if (chassisSubNode == sensors::node::sensors) 98095a3ecadSAnthony Wilson { 98195a3ecadSAnthony Wilson properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 9823929aca1SAnthony Wilson "/ReadingRangeMin"_json_pointer); 98395a3ecadSAnthony Wilson properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 9843929aca1SAnthony Wilson "/ReadingRangeMax"_json_pointer); 98595a3ecadSAnthony Wilson } 98695a3ecadSAnthony Wilson else if (sensorType == "temperature") 9871abe55efSEd Tanous { 98808777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 9893929aca1SAnthony Wilson "/MinReadingRangeTemp"_json_pointer); 99008777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 9913929aca1SAnthony Wilson "/MaxReadingRangeTemp"_json_pointer); 9921abe55efSEd Tanous } 993adc4f0dbSShawn McCarney else if (sensorType != "power") 9941abe55efSEd Tanous { 99508777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue", 9963929aca1SAnthony Wilson "/MinReadingRange"_json_pointer); 99708777fb0SLewanczyk, Dawid properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue", 9983929aca1SAnthony Wilson "/MaxReadingRange"_json_pointer); 99908777fb0SLewanczyk, Dawid } 100008777fb0SLewanczyk, Dawid 10013929aca1SAnthony Wilson for (const std::tuple<const char*, const char*, 10023929aca1SAnthony Wilson nlohmann::json::json_pointer>& p : properties) 10031abe55efSEd Tanous { 10041d7c0054SEd Tanous for (const auto& [valueName, valueVariant] : propertiesDict) 1005711ac7a9SEd Tanous { 1006711ac7a9SEd Tanous if (valueName != std::get<1>(p)) 1007711ac7a9SEd Tanous { 1008711ac7a9SEd Tanous continue; 1009711ac7a9SEd Tanous } 10103929aca1SAnthony Wilson 10113929aca1SAnthony Wilson // The property we want to set may be nested json, so use 10123929aca1SAnthony Wilson // a json_pointer for easy indexing into the json structure. 10133929aca1SAnthony Wilson const nlohmann::json::json_pointer& key = std::get<2>(p); 10143929aca1SAnthony Wilson 101508777fb0SLewanczyk, Dawid // Attempt to pull the int64 directly 1016abf2add6SEd Tanous const int64_t* int64Value = std::get_if<int64_t>(&valueVariant); 101708777fb0SLewanczyk, Dawid 1018abf2add6SEd Tanous const double* doubleValue = std::get_if<double>(&valueVariant); 1019028f7ebcSEddie James const uint32_t* uValue = std::get_if<uint32_t>(&valueVariant); 10206f6d0d32SEd Tanous double temp = 0.0; 10216f6d0d32SEd Tanous if (int64Value != nullptr) 10221abe55efSEd Tanous { 1023271584abSEd Tanous temp = static_cast<double>(*int64Value); 10246f6d0d32SEd Tanous } 10256f6d0d32SEd Tanous else if (doubleValue != nullptr) 10261abe55efSEd Tanous { 10276f6d0d32SEd Tanous temp = *doubleValue; 10281abe55efSEd Tanous } 1029028f7ebcSEddie James else if (uValue != nullptr) 1030028f7ebcSEddie James { 1031028f7ebcSEddie James temp = *uValue; 1032028f7ebcSEddie James } 10331abe55efSEd Tanous else 10341abe55efSEd Tanous { 10356f6d0d32SEd Tanous BMCWEB_LOG_ERROR 10366f6d0d32SEd Tanous << "Got value interface that wasn't int or double"; 10376f6d0d32SEd Tanous continue; 103808777fb0SLewanczyk, Dawid } 10396f6d0d32SEd Tanous temp = temp * std::pow(10, scaleMultiplier); 10406f6d0d32SEd Tanous if (forceToInt) 10416f6d0d32SEd Tanous { 104281ce609eSEd Tanous sensorJson[key] = static_cast<int64_t>(temp); 10436f6d0d32SEd Tanous } 10446f6d0d32SEd Tanous else 10456f6d0d32SEd Tanous { 104681ce609eSEd Tanous sensorJson[key] = temp; 104708777fb0SLewanczyk, Dawid } 104808777fb0SLewanczyk, Dawid } 104908777fb0SLewanczyk, Dawid } 105008777fb0SLewanczyk, Dawid } 105108777fb0SLewanczyk, Dawid 10521d7c0054SEd Tanous /** 10531d7c0054SEd Tanous * @brief Builds a json sensor representation of a sensor. 10541d7c0054SEd Tanous * @param sensorName The name of the sensor to be built 10551d7c0054SEd Tanous * @param sensorType The type (temperature, fan_tach, etc) of the sensor to 10561d7c0054SEd Tanous * build 10571d7c0054SEd Tanous * @param chassisSubNode The subnode (thermal, sensor, ect) of the sensor 10581d7c0054SEd Tanous * @param interfacesDict A dictionary of the interfaces and properties of said 10591d7c0054SEd Tanous * interfaces to be built from 10601d7c0054SEd Tanous * @param sensorJson The json object to fill 10611d7c0054SEd Tanous * @param inventoryItem D-Bus inventory item associated with the sensor. Will 10621d7c0054SEd Tanous * be nullptr if no associated inventory item was found. 10631d7c0054SEd Tanous */ 10641d7c0054SEd Tanous inline void objectInterfacesToJson( 10651d7c0054SEd Tanous const std::string& sensorName, const std::string& sensorType, 10661d7c0054SEd Tanous const std::string& chassisSubNode, 10671d7c0054SEd Tanous const dbus::utility::DBusInteracesMap& interfacesDict, 10681d7c0054SEd Tanous nlohmann::json& sensorJson, InventoryItem* inventoryItem) 10691d7c0054SEd Tanous { 10701d7c0054SEd Tanous 10711d7c0054SEd Tanous for (const auto& [interface, valuesDict] : interfacesDict) 10721d7c0054SEd Tanous { 10731d7c0054SEd Tanous objectPropertiesToJson(sensorName, sensorType, chassisSubNode, 10741d7c0054SEd Tanous valuesDict, sensorJson, inventoryItem); 10751d7c0054SEd Tanous } 1076*c1d019a6SEd Tanous BMCWEB_LOG_DEBUG << "Added sensor " << sensorName; 10771d7c0054SEd Tanous } 10781d7c0054SEd Tanous 1079b5a76932SEd Tanous inline void populateFanRedundancy( 1080b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp) 10818bd25ccdSJames Feist { 10828bd25ccdSJames Feist crow::connections::systemBus->async_method_call( 1083b9d36b47SEd Tanous [sensorsAsyncResp]( 1084b9d36b47SEd Tanous const boost::system::error_code ec, 1085b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& resp) { 10868bd25ccdSJames Feist if (ec) 10878bd25ccdSJames Feist { 10888bd25ccdSJames Feist return; // don't have to have this interface 10898bd25ccdSJames Feist } 1090002d39b4SEd Tanous for (const std::pair< 1091002d39b4SEd Tanous std::string, 1092002d39b4SEd Tanous std::vector<std::pair<std::string, std::vector<std::string>>>>& 1093e278c18fSEd Tanous pathPair : resp) 10948bd25ccdSJames Feist { 1095e278c18fSEd Tanous const std::string& path = pathPair.first; 1096002d39b4SEd Tanous const std::vector<std::pair<std::string, std::vector<std::string>>>& 1097002d39b4SEd Tanous objDict = pathPair.second; 10988bd25ccdSJames Feist if (objDict.empty()) 10998bd25ccdSJames Feist { 11008bd25ccdSJames Feist continue; // this should be impossible 11018bd25ccdSJames Feist } 11028bd25ccdSJames Feist 11038bd25ccdSJames Feist const std::string& owner = objDict.begin()->first; 11041e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::vector<std::string>>( 11051e1e598dSJonathan Doman *crow::connections::systemBus, 11061e1e598dSJonathan Doman "xyz.openbmc_project.ObjectMapper", path + "/chassis", 11071e1e598dSJonathan Doman "xyz.openbmc_project.Association", "endpoints", 1108002d39b4SEd Tanous [path, owner, 1109002d39b4SEd Tanous sensorsAsyncResp](const boost::system::error_code e, 11101e1e598dSJonathan Doman const std::vector<std::string>& endpoints) { 1111271584abSEd Tanous if (e) 11128bd25ccdSJames Feist { 11138bd25ccdSJames Feist return; // if they don't have an association we 11148bd25ccdSJames Feist // can't tell what chassis is 11158bd25ccdSJames Feist } 1116002d39b4SEd Tanous auto found = 1117002d39b4SEd Tanous std::find_if(endpoints.begin(), endpoints.end(), 11188bd25ccdSJames Feist [sensorsAsyncResp](const std::string& entry) { 1119002d39b4SEd Tanous return entry.find(sensorsAsyncResp->chassisId) != 11208bd25ccdSJames Feist std::string::npos; 11218bd25ccdSJames Feist }); 11228bd25ccdSJames Feist 11231e1e598dSJonathan Doman if (found == endpoints.end()) 11248bd25ccdSJames Feist { 11258bd25ccdSJames Feist return; 11268bd25ccdSJames Feist } 112786d89ed7SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 112886d89ed7SKrzysztof Grobelny *crow::connections::systemBus, owner, path, 112986d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Control.FanRedundancy", 11308bd25ccdSJames Feist [path, sensorsAsyncResp]( 1131271584abSEd Tanous const boost::system::error_code& err, 113286d89ed7SKrzysztof Grobelny const dbus::utility::DBusPropertiesMap& ret) { 1133271584abSEd Tanous if (err) 11348bd25ccdSJames Feist { 11358bd25ccdSJames Feist return; // don't have to have this 11368bd25ccdSJames Feist // interface 11378bd25ccdSJames Feist } 11388bd25ccdSJames Feist 113986d89ed7SKrzysztof Grobelny const uint8_t* allowedFailures = nullptr; 114086d89ed7SKrzysztof Grobelny const std::vector<std::string>* collection = nullptr; 114186d89ed7SKrzysztof Grobelny const std::string* status = nullptr; 114286d89ed7SKrzysztof Grobelny 114386d89ed7SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 114486d89ed7SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), ret, 114586d89ed7SKrzysztof Grobelny "AllowedFailures", allowedFailures, "Collection", 114686d89ed7SKrzysztof Grobelny collection, "Status", status); 114786d89ed7SKrzysztof Grobelny 114886d89ed7SKrzysztof Grobelny if (!success) 114986d89ed7SKrzysztof Grobelny { 115086d89ed7SKrzysztof Grobelny messages::internalError( 115186d89ed7SKrzysztof Grobelny sensorsAsyncResp->asyncResp->res); 115286d89ed7SKrzysztof Grobelny return; 115386d89ed7SKrzysztof Grobelny } 115486d89ed7SKrzysztof Grobelny 115586d89ed7SKrzysztof Grobelny if (allowedFailures == nullptr || collection == nullptr || 115686d89ed7SKrzysztof Grobelny status == nullptr) 11578bd25ccdSJames Feist { 1158002d39b4SEd Tanous BMCWEB_LOG_ERROR << "Invalid redundancy interface"; 11598bd25ccdSJames Feist messages::internalError( 11608d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res); 11618bd25ccdSJames Feist return; 11628bd25ccdSJames Feist } 11638bd25ccdSJames Feist 1164002d39b4SEd Tanous sdbusplus::message::object_path objectPath(path); 116528aa8de5SGeorge Liu std::string name = objectPath.filename(); 116628aa8de5SGeorge Liu if (name.empty()) 11678bd25ccdSJames Feist { 11688bd25ccdSJames Feist // this should be impossible 11698bd25ccdSJames Feist messages::internalError( 11708d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res); 11718bd25ccdSJames Feist return; 11728bd25ccdSJames Feist } 1173002d39b4SEd Tanous std::replace(name.begin(), name.end(), '_', ' '); 11748bd25ccdSJames Feist 11758bd25ccdSJames Feist std::string health; 11768bd25ccdSJames Feist 117711ba3979SEd Tanous if (status->ends_with("Full")) 11788bd25ccdSJames Feist { 11798bd25ccdSJames Feist health = "OK"; 11808bd25ccdSJames Feist } 118111ba3979SEd Tanous else if (status->ends_with("Degraded")) 11828bd25ccdSJames Feist { 11838bd25ccdSJames Feist health = "Warning"; 11848bd25ccdSJames Feist } 11858bd25ccdSJames Feist else 11868bd25ccdSJames Feist { 11878bd25ccdSJames Feist health = "Critical"; 11888bd25ccdSJames Feist } 11891476687dSEd Tanous nlohmann::json::array_t redfishCollection; 11908bd25ccdSJames Feist const auto& fanRedfish = 1191002d39b4SEd Tanous sensorsAsyncResp->asyncResp->res.jsonValue["Fans"]; 11928bd25ccdSJames Feist for (const std::string& item : *collection) 11938bd25ccdSJames Feist { 11948a592810SEd Tanous sdbusplus::message::object_path itemPath(item); 11958a592810SEd Tanous std::string itemName = itemPath.filename(); 119628aa8de5SGeorge Liu if (itemName.empty()) 119728aa8de5SGeorge Liu { 119828aa8de5SGeorge Liu continue; 119928aa8de5SGeorge Liu } 12008bd25ccdSJames Feist /* 12018bd25ccdSJames Feist todo(ed): merge patch that fixes the names 12028bd25ccdSJames Feist std::replace(itemName.begin(), 12038bd25ccdSJames Feist itemName.end(), '_', ' ');*/ 1204002d39b4SEd Tanous auto schemaItem = 1205002d39b4SEd Tanous std::find_if(fanRedfish.begin(), fanRedfish.end(), 12068bd25ccdSJames Feist [itemName](const nlohmann::json& fan) { 12078bd25ccdSJames Feist return fan["MemberId"] == itemName; 12088bd25ccdSJames Feist }); 12098bd25ccdSJames Feist if (schemaItem != fanRedfish.end()) 12108bd25ccdSJames Feist { 12118a592810SEd Tanous nlohmann::json::object_t collectionId; 12128a592810SEd Tanous collectionId["@odata.id"] = 12131476687dSEd Tanous (*schemaItem)["@odata.id"]; 12141476687dSEd Tanous redfishCollection.emplace_back( 12158a592810SEd Tanous std::move(collectionId)); 12168bd25ccdSJames Feist } 12178bd25ccdSJames Feist else 12188bd25ccdSJames Feist { 1219002d39b4SEd Tanous BMCWEB_LOG_ERROR << "failed to find fan in schema"; 12208bd25ccdSJames Feist messages::internalError( 12218d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res); 12228bd25ccdSJames Feist return; 12238bd25ccdSJames Feist } 12248bd25ccdSJames Feist } 12258bd25ccdSJames Feist 12263e9e72ebSKuiying Wang size_t minNumNeeded = 122726f6976fSEd Tanous collection->empty() 122826f6976fSEd Tanous ? 0 122926f6976fSEd Tanous : collection->size() - *allowedFailures; 1230002d39b4SEd Tanous nlohmann::json& jResp = sensorsAsyncResp->asyncResp->res 12318bd25ccdSJames Feist .jsonValue["Redundancy"]; 12321476687dSEd Tanous 12331476687dSEd Tanous nlohmann::json::object_t redundancy; 12341476687dSEd Tanous redundancy["@odata.id"] = 1235002d39b4SEd Tanous "/redfish/v1/Chassis/" + sensorsAsyncResp->chassisId + 1236002d39b4SEd Tanous "/" + sensorsAsyncResp->chassisSubNode + 1237002d39b4SEd Tanous "#/Redundancy/" + std::to_string(jResp.size()); 1238002d39b4SEd Tanous redundancy["@odata.type"] = "#Redundancy.v1_3_2.Redundancy"; 12391476687dSEd Tanous redundancy["MinNumNeeded"] = minNumNeeded; 12401476687dSEd Tanous redundancy["MemberId"] = name; 12411476687dSEd Tanous redundancy["Mode"] = "N+m"; 12421476687dSEd Tanous redundancy["Name"] = name; 12431476687dSEd Tanous redundancy["RedundancySet"] = redfishCollection; 12441476687dSEd Tanous redundancy["Status"]["Health"] = health; 12451476687dSEd Tanous redundancy["Status"]["State"] = "Enabled"; 12461476687dSEd Tanous 12471476687dSEd Tanous jResp.push_back(std::move(redundancy)); 124886d89ed7SKrzysztof Grobelny }); 12491e1e598dSJonathan Doman }); 12508bd25ccdSJames Feist } 12518bd25ccdSJames Feist }, 12528bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", 12538bd25ccdSJames Feist "/xyz/openbmc_project/object_mapper", 12548bd25ccdSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", 12558bd25ccdSJames Feist "/xyz/openbmc_project/control", 2, 12568bd25ccdSJames Feist std::array<const char*, 1>{ 12578bd25ccdSJames Feist "xyz.openbmc_project.Control.FanRedundancy"}); 12588bd25ccdSJames Feist } 12598bd25ccdSJames Feist 1260b5a76932SEd Tanous inline void 126181ce609eSEd Tanous sortJSONResponse(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp) 126249c53ac9SJohnathan Mantey { 12638d1b46d7Szhanghch05 nlohmann::json& response = sensorsAsyncResp->asyncResp->res.jsonValue; 126449c53ac9SJohnathan Mantey std::array<std::string, 2> sensorHeaders{"Temperatures", "Fans"}; 126581ce609eSEd Tanous if (sensorsAsyncResp->chassisSubNode == sensors::node::power) 126649c53ac9SJohnathan Mantey { 126749c53ac9SJohnathan Mantey sensorHeaders = {"Voltages", "PowerSupplies"}; 126849c53ac9SJohnathan Mantey } 126949c53ac9SJohnathan Mantey for (const std::string& sensorGroup : sensorHeaders) 127049c53ac9SJohnathan Mantey { 127149c53ac9SJohnathan Mantey nlohmann::json::iterator entry = response.find(sensorGroup); 127249c53ac9SJohnathan Mantey if (entry != response.end()) 127349c53ac9SJohnathan Mantey { 127449c53ac9SJohnathan Mantey std::sort(entry->begin(), entry->end(), 127502cad96eSEd Tanous [](const nlohmann::json& c1, const nlohmann::json& c2) { 127649c53ac9SJohnathan Mantey return c1["Name"] < c2["Name"]; 127749c53ac9SJohnathan Mantey }); 127849c53ac9SJohnathan Mantey 127949c53ac9SJohnathan Mantey // add the index counts to the end of each entry 128049c53ac9SJohnathan Mantey size_t count = 0; 128149c53ac9SJohnathan Mantey for (nlohmann::json& sensorJson : *entry) 128249c53ac9SJohnathan Mantey { 128349c53ac9SJohnathan Mantey nlohmann::json::iterator odata = sensorJson.find("@odata.id"); 128449c53ac9SJohnathan Mantey if (odata == sensorJson.end()) 128549c53ac9SJohnathan Mantey { 128649c53ac9SJohnathan Mantey continue; 128749c53ac9SJohnathan Mantey } 128849c53ac9SJohnathan Mantey std::string* value = odata->get_ptr<std::string*>(); 128949c53ac9SJohnathan Mantey if (value != nullptr) 129049c53ac9SJohnathan Mantey { 129149c53ac9SJohnathan Mantey *value += std::to_string(count); 129249c53ac9SJohnathan Mantey count++; 129381ce609eSEd Tanous sensorsAsyncResp->updateUri(sensorJson["Name"], *value); 129449c53ac9SJohnathan Mantey } 129549c53ac9SJohnathan Mantey } 129649c53ac9SJohnathan Mantey } 129749c53ac9SJohnathan Mantey } 129849c53ac9SJohnathan Mantey } 129949c53ac9SJohnathan Mantey 130008777fb0SLewanczyk, Dawid /** 1301adc4f0dbSShawn McCarney * @brief Finds the inventory item with the specified object path. 1302adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 1303adc4f0dbSShawn McCarney * @param invItemObjPath D-Bus object path of inventory item. 1304adc4f0dbSShawn McCarney * @return Inventory item within vector, or nullptr if no match found. 13058fb49dd6SShawn McCarney */ 130623a21a1cSEd Tanous inline InventoryItem* findInventoryItem( 1307b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 1308adc4f0dbSShawn McCarney const std::string& invItemObjPath) 13098fb49dd6SShawn McCarney { 1310adc4f0dbSShawn McCarney for (InventoryItem& inventoryItem : *inventoryItems) 13118fb49dd6SShawn McCarney { 1312adc4f0dbSShawn McCarney if (inventoryItem.objectPath == invItemObjPath) 13138fb49dd6SShawn McCarney { 1314adc4f0dbSShawn McCarney return &inventoryItem; 13158fb49dd6SShawn McCarney } 13168fb49dd6SShawn McCarney } 13178fb49dd6SShawn McCarney return nullptr; 13188fb49dd6SShawn McCarney } 13198fb49dd6SShawn McCarney 13208fb49dd6SShawn McCarney /** 1321adc4f0dbSShawn McCarney * @brief Finds the inventory item associated with the specified sensor. 1322adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 1323adc4f0dbSShawn McCarney * @param sensorObjPath D-Bus object path of sensor. 1324adc4f0dbSShawn McCarney * @return Inventory item within vector, or nullptr if no match found. 13258fb49dd6SShawn McCarney */ 132623a21a1cSEd Tanous inline InventoryItem* findInventoryItemForSensor( 1327b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 1328adc4f0dbSShawn McCarney const std::string& sensorObjPath) 1329adc4f0dbSShawn McCarney { 1330adc4f0dbSShawn McCarney for (InventoryItem& inventoryItem : *inventoryItems) 1331adc4f0dbSShawn McCarney { 1332adc4f0dbSShawn McCarney if (inventoryItem.sensors.count(sensorObjPath) > 0) 1333adc4f0dbSShawn McCarney { 1334adc4f0dbSShawn McCarney return &inventoryItem; 1335adc4f0dbSShawn McCarney } 1336adc4f0dbSShawn McCarney } 1337adc4f0dbSShawn McCarney return nullptr; 1338adc4f0dbSShawn McCarney } 1339adc4f0dbSShawn McCarney 1340adc4f0dbSShawn McCarney /** 1341d500549bSAnthony Wilson * @brief Finds the inventory item associated with the specified led path. 1342d500549bSAnthony Wilson * @param inventoryItems D-Bus inventory items associated with sensors. 1343d500549bSAnthony Wilson * @param ledObjPath D-Bus object path of led. 1344d500549bSAnthony Wilson * @return Inventory item within vector, or nullptr if no match found. 1345d500549bSAnthony Wilson */ 1346d500549bSAnthony Wilson inline InventoryItem* 1347d500549bSAnthony Wilson findInventoryItemForLed(std::vector<InventoryItem>& inventoryItems, 1348d500549bSAnthony Wilson const std::string& ledObjPath) 1349d500549bSAnthony Wilson { 1350d500549bSAnthony Wilson for (InventoryItem& inventoryItem : inventoryItems) 1351d500549bSAnthony Wilson { 1352d500549bSAnthony Wilson if (inventoryItem.ledObjectPath == ledObjPath) 1353d500549bSAnthony Wilson { 1354d500549bSAnthony Wilson return &inventoryItem; 1355d500549bSAnthony Wilson } 1356d500549bSAnthony Wilson } 1357d500549bSAnthony Wilson return nullptr; 1358d500549bSAnthony Wilson } 1359d500549bSAnthony Wilson 1360d500549bSAnthony Wilson /** 1361adc4f0dbSShawn McCarney * @brief Adds inventory item and associated sensor to specified vector. 1362adc4f0dbSShawn McCarney * 1363adc4f0dbSShawn McCarney * Adds a new InventoryItem to the vector if necessary. Searches for an 1364adc4f0dbSShawn McCarney * existing InventoryItem with the specified object path. If not found, one is 1365adc4f0dbSShawn McCarney * added to the vector. 1366adc4f0dbSShawn McCarney * 1367adc4f0dbSShawn McCarney * Next, the specified sensor is added to the set of sensors associated with the 1368adc4f0dbSShawn McCarney * InventoryItem. 1369adc4f0dbSShawn McCarney * 1370adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 1371adc4f0dbSShawn McCarney * @param invItemObjPath D-Bus object path of inventory item. 1372adc4f0dbSShawn McCarney * @param sensorObjPath D-Bus object path of sensor 1373adc4f0dbSShawn McCarney */ 1374b5a76932SEd Tanous inline void addInventoryItem( 1375b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 1376b5a76932SEd Tanous const std::string& invItemObjPath, const std::string& sensorObjPath) 1377adc4f0dbSShawn McCarney { 1378adc4f0dbSShawn McCarney // Look for inventory item in vector 1379adc4f0dbSShawn McCarney InventoryItem* inventoryItem = 1380adc4f0dbSShawn McCarney findInventoryItem(inventoryItems, invItemObjPath); 1381adc4f0dbSShawn McCarney 1382adc4f0dbSShawn McCarney // If inventory item doesn't exist in vector, add it 1383adc4f0dbSShawn McCarney if (inventoryItem == nullptr) 1384adc4f0dbSShawn McCarney { 1385adc4f0dbSShawn McCarney inventoryItems->emplace_back(invItemObjPath); 1386adc4f0dbSShawn McCarney inventoryItem = &(inventoryItems->back()); 1387adc4f0dbSShawn McCarney } 1388adc4f0dbSShawn McCarney 1389adc4f0dbSShawn McCarney // Add sensor to set of sensors associated with inventory item 1390adc4f0dbSShawn McCarney inventoryItem->sensors.emplace(sensorObjPath); 1391adc4f0dbSShawn McCarney } 1392adc4f0dbSShawn McCarney 1393adc4f0dbSShawn McCarney /** 1394adc4f0dbSShawn McCarney * @brief Stores D-Bus data in the specified inventory item. 1395adc4f0dbSShawn McCarney * 1396adc4f0dbSShawn McCarney * Finds D-Bus data in the specified map of interfaces. Stores the data in the 1397adc4f0dbSShawn McCarney * specified InventoryItem. 1398adc4f0dbSShawn McCarney * 1399adc4f0dbSShawn McCarney * This data is later used to provide sensor property values in the JSON 1400adc4f0dbSShawn McCarney * response. 1401adc4f0dbSShawn McCarney * 1402adc4f0dbSShawn McCarney * @param inventoryItem Inventory item where data will be stored. 1403adc4f0dbSShawn McCarney * @param interfacesDict Map containing D-Bus interfaces and their properties 1404adc4f0dbSShawn McCarney * for the specified inventory item. 1405adc4f0dbSShawn McCarney */ 140623a21a1cSEd Tanous inline void storeInventoryItemData( 1407adc4f0dbSShawn McCarney InventoryItem& inventoryItem, 1408711ac7a9SEd Tanous const dbus::utility::DBusInteracesMap& interfacesDict) 14098fb49dd6SShawn McCarney { 1410adc4f0dbSShawn McCarney // Get properties from Inventory.Item interface 1411711ac7a9SEd Tanous 14129eb808c1SEd Tanous for (const auto& [interface, values] : interfacesDict) 14138fb49dd6SShawn McCarney { 1414711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Inventory.Item") 14158fb49dd6SShawn McCarney { 14169eb808c1SEd Tanous for (const auto& [name, dbusValue] : values) 1417711ac7a9SEd Tanous { 1418711ac7a9SEd Tanous if (name == "Present") 1419711ac7a9SEd Tanous { 1420711ac7a9SEd Tanous const bool* value = std::get_if<bool>(&dbusValue); 1421adc4f0dbSShawn McCarney if (value != nullptr) 14228fb49dd6SShawn McCarney { 1423adc4f0dbSShawn McCarney inventoryItem.isPresent = *value; 14248fb49dd6SShawn McCarney } 14258fb49dd6SShawn McCarney } 14268fb49dd6SShawn McCarney } 1427711ac7a9SEd Tanous } 1428adc4f0dbSShawn McCarney // Check if Inventory.Item.PowerSupply interface is present 1429711ac7a9SEd Tanous 1430711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Inventory.Item.PowerSupply") 14318fb49dd6SShawn McCarney { 1432adc4f0dbSShawn McCarney inventoryItem.isPowerSupply = true; 14338fb49dd6SShawn McCarney } 1434adc4f0dbSShawn McCarney 1435adc4f0dbSShawn McCarney // Get properties from Inventory.Decorator.Asset interface 1436711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset") 1437adc4f0dbSShawn McCarney { 14389eb808c1SEd Tanous for (const auto& [name, dbusValue] : values) 1439711ac7a9SEd Tanous { 1440711ac7a9SEd Tanous if (name == "Manufacturer") 1441adc4f0dbSShawn McCarney { 1442adc4f0dbSShawn McCarney const std::string* value = 1443711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 1444adc4f0dbSShawn McCarney if (value != nullptr) 1445adc4f0dbSShawn McCarney { 1446adc4f0dbSShawn McCarney inventoryItem.manufacturer = *value; 1447adc4f0dbSShawn McCarney } 1448adc4f0dbSShawn McCarney } 1449711ac7a9SEd Tanous if (name == "Model") 1450adc4f0dbSShawn McCarney { 1451adc4f0dbSShawn McCarney const std::string* value = 1452711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 1453adc4f0dbSShawn McCarney if (value != nullptr) 1454adc4f0dbSShawn McCarney { 1455adc4f0dbSShawn McCarney inventoryItem.model = *value; 1456adc4f0dbSShawn McCarney } 1457adc4f0dbSShawn McCarney } 1458711ac7a9SEd Tanous if (name == "SerialNumber") 1459adc4f0dbSShawn McCarney { 1460adc4f0dbSShawn McCarney const std::string* value = 1461711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 1462adc4f0dbSShawn McCarney if (value != nullptr) 1463adc4f0dbSShawn McCarney { 1464adc4f0dbSShawn McCarney inventoryItem.serialNumber = *value; 1465adc4f0dbSShawn McCarney } 1466adc4f0dbSShawn McCarney } 1467711ac7a9SEd Tanous if (name == "PartNumber") 1468711ac7a9SEd Tanous { 1469711ac7a9SEd Tanous const std::string* value = 1470711ac7a9SEd Tanous std::get_if<std::string>(&dbusValue); 1471711ac7a9SEd Tanous if (value != nullptr) 1472711ac7a9SEd Tanous { 1473711ac7a9SEd Tanous inventoryItem.partNumber = *value; 1474711ac7a9SEd Tanous } 1475711ac7a9SEd Tanous } 1476711ac7a9SEd Tanous } 1477adc4f0dbSShawn McCarney } 1478adc4f0dbSShawn McCarney 1479711ac7a9SEd Tanous if (interface == 1480711ac7a9SEd Tanous "xyz.openbmc_project.State.Decorator.OperationalStatus") 1481adc4f0dbSShawn McCarney { 14829eb808c1SEd Tanous for (const auto& [name, dbusValue] : values) 1483adc4f0dbSShawn McCarney { 1484711ac7a9SEd Tanous if (name == "Functional") 1485711ac7a9SEd Tanous { 1486711ac7a9SEd Tanous const bool* value = std::get_if<bool>(&dbusValue); 1487adc4f0dbSShawn McCarney if (value != nullptr) 1488adc4f0dbSShawn McCarney { 1489adc4f0dbSShawn McCarney inventoryItem.isFunctional = *value; 14908fb49dd6SShawn McCarney } 14918fb49dd6SShawn McCarney } 14928fb49dd6SShawn McCarney } 14938fb49dd6SShawn McCarney } 1494711ac7a9SEd Tanous } 1495711ac7a9SEd Tanous } 14968fb49dd6SShawn McCarney 14978fb49dd6SShawn McCarney /** 1498adc4f0dbSShawn McCarney * @brief Gets D-Bus data for inventory items associated with sensors. 14998fb49dd6SShawn McCarney * 1500adc4f0dbSShawn McCarney * Uses the specified connections (services) to obtain D-Bus data for inventory 1501adc4f0dbSShawn McCarney * items associated with sensors. Stores the resulting data in the 1502adc4f0dbSShawn McCarney * inventoryItems vector. 15038fb49dd6SShawn McCarney * 1504adc4f0dbSShawn McCarney * This data is later used to provide sensor property values in the JSON 1505adc4f0dbSShawn McCarney * response. 1506adc4f0dbSShawn McCarney * 1507adc4f0dbSShawn McCarney * Finds the inventory item data asynchronously. Invokes callback when data has 1508adc4f0dbSShawn McCarney * been obtained. 1509adc4f0dbSShawn McCarney * 1510adc4f0dbSShawn McCarney * The callback must have the following signature: 1511adc4f0dbSShawn McCarney * @code 1512d500549bSAnthony Wilson * callback(void) 1513adc4f0dbSShawn McCarney * @endcode 1514adc4f0dbSShawn McCarney * 1515adc4f0dbSShawn McCarney * This function is called recursively, obtaining data asynchronously from one 1516adc4f0dbSShawn McCarney * connection in each call. This ensures the callback is not invoked until the 1517adc4f0dbSShawn McCarney * last asynchronous function has completed. 15188fb49dd6SShawn McCarney * 15198fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 1520adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 1521adc4f0dbSShawn McCarney * @param invConnections Connections that provide data for the inventory items. 15228fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 15238fb49dd6SShawn McCarney * implements ObjectManager. 1524adc4f0dbSShawn McCarney * @param callback Callback to invoke when inventory data has been obtained. 1525adc4f0dbSShawn McCarney * @param invConnectionsIndex Current index in invConnections. Only specified 1526adc4f0dbSShawn McCarney * in recursive calls to this function. 15278fb49dd6SShawn McCarney */ 1528adc4f0dbSShawn McCarney template <typename Callback> 1529adc4f0dbSShawn McCarney static void getInventoryItemsData( 15308fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1531adc4f0dbSShawn McCarney std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1532fe04d49cSNan Zhou std::shared_ptr<std::set<std::string>> invConnections, 1533fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> objectMgrPaths, 1534271584abSEd Tanous Callback&& callback, size_t invConnectionsIndex = 0) 15358fb49dd6SShawn McCarney { 1536adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsData enter"; 15378fb49dd6SShawn McCarney 1538adc4f0dbSShawn McCarney // If no more connections left, call callback 1539adc4f0dbSShawn McCarney if (invConnectionsIndex >= invConnections->size()) 15408fb49dd6SShawn McCarney { 1541d500549bSAnthony Wilson callback(); 1542adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsData exit"; 1543adc4f0dbSShawn McCarney return; 1544adc4f0dbSShawn McCarney } 1545adc4f0dbSShawn McCarney 1546adc4f0dbSShawn McCarney // Get inventory item data from current connection 1547fe04d49cSNan Zhou auto it = invConnections->begin(); 1548fe04d49cSNan Zhou std::advance(it, invConnectionsIndex); 1549adc4f0dbSShawn McCarney if (it != invConnections->end()) 1550adc4f0dbSShawn McCarney { 1551adc4f0dbSShawn McCarney const std::string& invConnection = *it; 1552adc4f0dbSShawn McCarney 15538fb49dd6SShawn McCarney // Response handler for GetManagedObjects 1554002d39b4SEd Tanous auto respHandler = 1555002d39b4SEd Tanous [sensorsAsyncResp, inventoryItems, invConnections, objectMgrPaths, 155602cad96eSEd Tanous callback{std::forward<Callback>(callback)}, invConnectionsIndex]( 155702cad96eSEd Tanous const boost::system::error_code ec, 155802cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1559adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler enter"; 15608fb49dd6SShawn McCarney if (ec) 15618fb49dd6SShawn McCarney { 15628fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 1563adc4f0dbSShawn McCarney << "getInventoryItemsData respHandler DBus error " << ec; 15648d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 15658fb49dd6SShawn McCarney return; 15668fb49dd6SShawn McCarney } 15678fb49dd6SShawn McCarney 15688fb49dd6SShawn McCarney // Loop through returned object paths 15698fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 15708fb49dd6SShawn McCarney { 15718fb49dd6SShawn McCarney const std::string& objPath = 15728fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 15738fb49dd6SShawn McCarney 1574adc4f0dbSShawn McCarney // If this object path is one of the specified inventory items 1575adc4f0dbSShawn McCarney InventoryItem* inventoryItem = 1576adc4f0dbSShawn McCarney findInventoryItem(inventoryItems, objPath); 1577adc4f0dbSShawn McCarney if (inventoryItem != nullptr) 15788fb49dd6SShawn McCarney { 1579adc4f0dbSShawn McCarney // Store inventory data in InventoryItem 1580adc4f0dbSShawn McCarney storeInventoryItemData(*inventoryItem, objDictEntry.second); 15818fb49dd6SShawn McCarney } 15828fb49dd6SShawn McCarney } 15838fb49dd6SShawn McCarney 1584adc4f0dbSShawn McCarney // Recurse to get inventory item data from next connection 1585adc4f0dbSShawn McCarney getInventoryItemsData(sensorsAsyncResp, inventoryItems, 1586adc4f0dbSShawn McCarney invConnections, objectMgrPaths, 1587adc4f0dbSShawn McCarney std::move(callback), invConnectionsIndex + 1); 1588adc4f0dbSShawn McCarney 1589adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsData respHandler exit"; 15908fb49dd6SShawn McCarney }; 15918fb49dd6SShawn McCarney 15928fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for the current 15938fb49dd6SShawn McCarney // connection. If no mapping found, default to "/". 15948fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(invConnection); 15958fb49dd6SShawn McCarney const std::string& objectMgrPath = 15968fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 15978fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << invConnection << " is " 15988fb49dd6SShawn McCarney << objectMgrPath; 15998fb49dd6SShawn McCarney 16008fb49dd6SShawn McCarney // Get all object paths and their interfaces for current connection 16018fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 16028fb49dd6SShawn McCarney std::move(respHandler), invConnection, objectMgrPath, 16038fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 16048fb49dd6SShawn McCarney } 16058fb49dd6SShawn McCarney 1606adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsData exit"; 16078fb49dd6SShawn McCarney } 16088fb49dd6SShawn McCarney 16098fb49dd6SShawn McCarney /** 1610adc4f0dbSShawn McCarney * @brief Gets connections that provide D-Bus data for inventory items. 16118fb49dd6SShawn McCarney * 1612adc4f0dbSShawn McCarney * Gets the D-Bus connections (services) that provide data for the inventory 1613adc4f0dbSShawn McCarney * items that are associated with sensors. 16148fb49dd6SShawn McCarney * 16158fb49dd6SShawn McCarney * Finds the connections asynchronously. Invokes callback when information has 16168fb49dd6SShawn McCarney * been obtained. 16178fb49dd6SShawn McCarney * 16188fb49dd6SShawn McCarney * The callback must have the following signature: 16198fb49dd6SShawn McCarney * @code 1620fe04d49cSNan Zhou * callback(std::shared_ptr<std::set<std::string>> invConnections) 16218fb49dd6SShawn McCarney * @endcode 16228fb49dd6SShawn McCarney * 16238fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 1624adc4f0dbSShawn McCarney * @param inventoryItems D-Bus inventory items associated with sensors. 16258fb49dd6SShawn McCarney * @param callback Callback to invoke when connections have been obtained. 16268fb49dd6SShawn McCarney */ 16278fb49dd6SShawn McCarney template <typename Callback> 16288fb49dd6SShawn McCarney static void getInventoryItemsConnections( 1629b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 1630b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems, 16318fb49dd6SShawn McCarney Callback&& callback) 16328fb49dd6SShawn McCarney { 16338fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections enter"; 16348fb49dd6SShawn McCarney 16358fb49dd6SShawn McCarney const std::string path = "/xyz/openbmc_project/inventory"; 1636adc4f0dbSShawn McCarney const std::array<std::string, 4> interfaces = { 16378fb49dd6SShawn McCarney "xyz.openbmc_project.Inventory.Item", 1638adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.PowerSupply", 1639adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Decorator.Asset", 16408fb49dd6SShawn McCarney "xyz.openbmc_project.State.Decorator.OperationalStatus"}; 16418fb49dd6SShawn McCarney 16428fb49dd6SShawn McCarney // Response handler for parsing output from GetSubTree 1643002d39b4SEd Tanous auto respHandler = 1644002d39b4SEd Tanous [callback{std::forward<Callback>(callback)}, sensorsAsyncResp, 1645002d39b4SEd Tanous inventoryItems]( 1646b9d36b47SEd Tanous const boost::system::error_code ec, 1647002d39b4SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 16488fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler enter"; 16498fb49dd6SShawn McCarney if (ec) 16508fb49dd6SShawn McCarney { 16518d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 16528fb49dd6SShawn McCarney BMCWEB_LOG_ERROR 16538fb49dd6SShawn McCarney << "getInventoryItemsConnections respHandler DBus error " << ec; 16548fb49dd6SShawn McCarney return; 16558fb49dd6SShawn McCarney } 16568fb49dd6SShawn McCarney 16578fb49dd6SShawn McCarney // Make unique list of connections for desired inventory items 1658fe04d49cSNan Zhou std::shared_ptr<std::set<std::string>> invConnections = 1659fe04d49cSNan Zhou std::make_shared<std::set<std::string>>(); 16608fb49dd6SShawn McCarney 16618fb49dd6SShawn McCarney // Loop through objects from GetSubTree 16628fb49dd6SShawn McCarney for (const std::pair< 16638fb49dd6SShawn McCarney std::string, 16648fb49dd6SShawn McCarney std::vector<std::pair<std::string, std::vector<std::string>>>>& 16658fb49dd6SShawn McCarney object : subtree) 16668fb49dd6SShawn McCarney { 1667adc4f0dbSShawn McCarney // Check if object path is one of the specified inventory items 16688fb49dd6SShawn McCarney const std::string& objPath = object.first; 1669adc4f0dbSShawn McCarney if (findInventoryItem(inventoryItems, objPath) != nullptr) 16708fb49dd6SShawn McCarney { 16718fb49dd6SShawn McCarney // Store all connections to inventory item 16728fb49dd6SShawn McCarney for (const std::pair<std::string, std::vector<std::string>>& 16738fb49dd6SShawn McCarney objData : object.second) 16748fb49dd6SShawn McCarney { 16758fb49dd6SShawn McCarney const std::string& invConnection = objData.first; 16768fb49dd6SShawn McCarney invConnections->insert(invConnection); 16778fb49dd6SShawn McCarney } 16788fb49dd6SShawn McCarney } 16798fb49dd6SShawn McCarney } 1680d500549bSAnthony Wilson 16818fb49dd6SShawn McCarney callback(invConnections); 16828fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections respHandler exit"; 16838fb49dd6SShawn McCarney }; 16848fb49dd6SShawn McCarney 16858fb49dd6SShawn McCarney // Make call to ObjectMapper to find all inventory items 16868fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 16878fb49dd6SShawn McCarney std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 16888fb49dd6SShawn McCarney "/xyz/openbmc_project/object_mapper", 16898fb49dd6SShawn McCarney "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces); 16908fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnections exit"; 16918fb49dd6SShawn McCarney } 16928fb49dd6SShawn McCarney 16938fb49dd6SShawn McCarney /** 1694adc4f0dbSShawn McCarney * @brief Gets associations from sensors to inventory items. 16958fb49dd6SShawn McCarney * 16968fb49dd6SShawn McCarney * Looks for ObjectMapper associations from the specified sensors to related 1697d500549bSAnthony Wilson * inventory items. Then finds the associations from those inventory items to 1698d500549bSAnthony Wilson * their LEDs, if any. 16998fb49dd6SShawn McCarney * 17008fb49dd6SShawn McCarney * Finds the inventory items asynchronously. Invokes callback when information 17018fb49dd6SShawn McCarney * has been obtained. 17028fb49dd6SShawn McCarney * 17038fb49dd6SShawn McCarney * The callback must have the following signature: 17048fb49dd6SShawn McCarney * @code 1705adc4f0dbSShawn McCarney * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 17068fb49dd6SShawn McCarney * @endcode 17078fb49dd6SShawn McCarney * 17088fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 17098fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 17108fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 17118fb49dd6SShawn McCarney * implements ObjectManager. 17128fb49dd6SShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 17138fb49dd6SShawn McCarney */ 17148fb49dd6SShawn McCarney template <typename Callback> 1715adc4f0dbSShawn McCarney static void getInventoryItemAssociations( 1716b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 1717fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames, 1718fe04d49cSNan Zhou const std::shared_ptr<std::map<std::string, std::string>>& objectMgrPaths, 17198fb49dd6SShawn McCarney Callback&& callback) 17208fb49dd6SShawn McCarney { 1721adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemAssociations enter"; 17228fb49dd6SShawn McCarney 17238fb49dd6SShawn McCarney // Response handler for GetManagedObjects 172402cad96eSEd Tanous auto respHandler = 172502cad96eSEd Tanous [callback{std::forward<Callback>(callback)}, sensorsAsyncResp, 17268fb49dd6SShawn McCarney sensorNames](const boost::system::error_code ec, 172702cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 1728adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler enter"; 17298fb49dd6SShawn McCarney if (ec) 17308fb49dd6SShawn McCarney { 1731adc4f0dbSShawn McCarney BMCWEB_LOG_ERROR 1732adc4f0dbSShawn McCarney << "getInventoryItemAssociations respHandler DBus error " << ec; 17338d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 17348fb49dd6SShawn McCarney return; 17358fb49dd6SShawn McCarney } 17368fb49dd6SShawn McCarney 1737adc4f0dbSShawn McCarney // Create vector to hold list of inventory items 1738adc4f0dbSShawn McCarney std::shared_ptr<std::vector<InventoryItem>> inventoryItems = 1739adc4f0dbSShawn McCarney std::make_shared<std::vector<InventoryItem>>(); 1740adc4f0dbSShawn McCarney 17418fb49dd6SShawn McCarney // Loop through returned object paths 17428fb49dd6SShawn McCarney std::string sensorAssocPath; 17438fb49dd6SShawn McCarney sensorAssocPath.reserve(128); // avoid memory allocations 17448fb49dd6SShawn McCarney for (const auto& objDictEntry : resp) 17458fb49dd6SShawn McCarney { 17468fb49dd6SShawn McCarney const std::string& objPath = 17478fb49dd6SShawn McCarney static_cast<const std::string&>(objDictEntry.first); 17488fb49dd6SShawn McCarney 17498fb49dd6SShawn McCarney // If path is inventory association for one of the specified sensors 17508fb49dd6SShawn McCarney for (const std::string& sensorName : *sensorNames) 17518fb49dd6SShawn McCarney { 17528fb49dd6SShawn McCarney sensorAssocPath = sensorName; 17538fb49dd6SShawn McCarney sensorAssocPath += "/inventory"; 17548fb49dd6SShawn McCarney if (objPath == sensorAssocPath) 17558fb49dd6SShawn McCarney { 17568fb49dd6SShawn McCarney // Get Association interface for object path 1757711ac7a9SEd Tanous for (const auto& [interface, values] : objDictEntry.second) 17588fb49dd6SShawn McCarney { 1759711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Association") 1760711ac7a9SEd Tanous { 1761711ac7a9SEd Tanous for (const auto& [valueName, value] : values) 1762711ac7a9SEd Tanous { 1763711ac7a9SEd Tanous if (valueName == "endpoints") 17648fb49dd6SShawn McCarney { 17658fb49dd6SShawn McCarney const std::vector<std::string>* endpoints = 17668fb49dd6SShawn McCarney std::get_if<std::vector<std::string>>( 1767711ac7a9SEd Tanous &value); 1768711ac7a9SEd Tanous if ((endpoints != nullptr) && 1769711ac7a9SEd Tanous !endpoints->empty()) 17708fb49dd6SShawn McCarney { 1771adc4f0dbSShawn McCarney // Add inventory item to vector 1772adc4f0dbSShawn McCarney const std::string& invItemPath = 1773adc4f0dbSShawn McCarney endpoints->front(); 1774711ac7a9SEd Tanous addInventoryItem(inventoryItems, 1775711ac7a9SEd Tanous invItemPath, 1776adc4f0dbSShawn McCarney sensorName); 17778fb49dd6SShawn McCarney } 17788fb49dd6SShawn McCarney } 17798fb49dd6SShawn McCarney } 1780711ac7a9SEd Tanous } 1781711ac7a9SEd Tanous } 17828fb49dd6SShawn McCarney break; 17838fb49dd6SShawn McCarney } 17848fb49dd6SShawn McCarney } 17858fb49dd6SShawn McCarney } 17868fb49dd6SShawn McCarney 1787d500549bSAnthony Wilson // Now loop through the returned object paths again, this time to 1788d500549bSAnthony Wilson // find the leds associated with the inventory items we just found 1789d500549bSAnthony Wilson std::string inventoryAssocPath; 1790d500549bSAnthony Wilson inventoryAssocPath.reserve(128); // avoid memory allocations 1791d500549bSAnthony Wilson for (const auto& objDictEntry : resp) 1792d500549bSAnthony Wilson { 1793d500549bSAnthony Wilson const std::string& objPath = 1794d500549bSAnthony Wilson static_cast<const std::string&>(objDictEntry.first); 1795d500549bSAnthony Wilson 1796d500549bSAnthony Wilson for (InventoryItem& inventoryItem : *inventoryItems) 1797d500549bSAnthony Wilson { 1798d500549bSAnthony Wilson inventoryAssocPath = inventoryItem.objectPath; 1799d500549bSAnthony Wilson inventoryAssocPath += "/leds"; 1800d500549bSAnthony Wilson if (objPath == inventoryAssocPath) 1801d500549bSAnthony Wilson { 1802711ac7a9SEd Tanous for (const auto& [interface, values] : objDictEntry.second) 1803d500549bSAnthony Wilson { 1804711ac7a9SEd Tanous if (interface == "xyz.openbmc_project.Association") 1805711ac7a9SEd Tanous { 1806711ac7a9SEd Tanous for (const auto& [valueName, value] : values) 1807711ac7a9SEd Tanous { 1808711ac7a9SEd Tanous if (valueName == "endpoints") 1809d500549bSAnthony Wilson { 1810d500549bSAnthony Wilson const std::vector<std::string>* endpoints = 1811d500549bSAnthony Wilson std::get_if<std::vector<std::string>>( 1812711ac7a9SEd Tanous &value); 1813711ac7a9SEd Tanous if ((endpoints != nullptr) && 1814711ac7a9SEd Tanous !endpoints->empty()) 1815d500549bSAnthony Wilson { 1816711ac7a9SEd Tanous // Add inventory item to vector 1817d500549bSAnthony Wilson // Store LED path in inventory item 1818711ac7a9SEd Tanous const std::string& ledPath = 1819711ac7a9SEd Tanous endpoints->front(); 1820d500549bSAnthony Wilson inventoryItem.ledObjectPath = ledPath; 1821d500549bSAnthony Wilson } 1822d500549bSAnthony Wilson } 1823d500549bSAnthony Wilson } 1824711ac7a9SEd Tanous } 1825711ac7a9SEd Tanous } 1826711ac7a9SEd Tanous 1827d500549bSAnthony Wilson break; 1828d500549bSAnthony Wilson } 1829d500549bSAnthony Wilson } 1830d500549bSAnthony Wilson } 1831adc4f0dbSShawn McCarney callback(inventoryItems); 1832adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemAssociations respHandler exit"; 18338fb49dd6SShawn McCarney }; 18348fb49dd6SShawn McCarney 18358fb49dd6SShawn McCarney // Find DBus object path that implements ObjectManager for ObjectMapper 18368fb49dd6SShawn McCarney std::string connection = "xyz.openbmc_project.ObjectMapper"; 18378fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 18388fb49dd6SShawn McCarney const std::string& objectMgrPath = 18398fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 18408fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 18418fb49dd6SShawn McCarney << objectMgrPath; 18428fb49dd6SShawn McCarney 18438fb49dd6SShawn McCarney // Call GetManagedObjects on the ObjectMapper to get all associations 18448fb49dd6SShawn McCarney crow::connections::systemBus->async_method_call( 18458fb49dd6SShawn McCarney std::move(respHandler), connection, objectMgrPath, 18468fb49dd6SShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 18478fb49dd6SShawn McCarney 1848adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemAssociations exit"; 18498fb49dd6SShawn McCarney } 18508fb49dd6SShawn McCarney 18518fb49dd6SShawn McCarney /** 1852d500549bSAnthony Wilson * @brief Gets D-Bus data for inventory item leds associated with sensors. 1853d500549bSAnthony Wilson * 1854d500549bSAnthony Wilson * Uses the specified connections (services) to obtain D-Bus data for inventory 1855d500549bSAnthony Wilson * item leds associated with sensors. Stores the resulting data in the 1856d500549bSAnthony Wilson * inventoryItems vector. 1857d500549bSAnthony Wilson * 1858d500549bSAnthony Wilson * This data is later used to provide sensor property values in the JSON 1859d500549bSAnthony Wilson * response. 1860d500549bSAnthony Wilson * 1861d500549bSAnthony Wilson * Finds the inventory item led data asynchronously. Invokes callback when data 1862d500549bSAnthony Wilson * has been obtained. 1863d500549bSAnthony Wilson * 1864d500549bSAnthony Wilson * The callback must have the following signature: 1865d500549bSAnthony Wilson * @code 186642cbe538SGunnar Mills * callback() 1867d500549bSAnthony Wilson * @endcode 1868d500549bSAnthony Wilson * 1869d500549bSAnthony Wilson * This function is called recursively, obtaining data asynchronously from one 1870d500549bSAnthony Wilson * connection in each call. This ensures the callback is not invoked until the 1871d500549bSAnthony Wilson * last asynchronous function has completed. 1872d500549bSAnthony Wilson * 1873d500549bSAnthony Wilson * @param sensorsAsyncResp Pointer to object holding response data. 1874d500549bSAnthony Wilson * @param inventoryItems D-Bus inventory items associated with sensors. 1875d500549bSAnthony Wilson * @param ledConnections Connections that provide data for the inventory leds. 1876d500549bSAnthony Wilson * @param callback Callback to invoke when inventory data has been obtained. 1877d500549bSAnthony Wilson * @param ledConnectionsIndex Current index in ledConnections. Only specified 1878d500549bSAnthony Wilson * in recursive calls to this function. 1879d500549bSAnthony Wilson */ 1880d500549bSAnthony Wilson template <typename Callback> 1881d500549bSAnthony Wilson void getInventoryLedData( 1882d500549bSAnthony Wilson std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1883d500549bSAnthony Wilson std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1884fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> ledConnections, 1885d500549bSAnthony Wilson Callback&& callback, size_t ledConnectionsIndex = 0) 1886d500549bSAnthony Wilson { 1887d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLedData enter"; 1888d500549bSAnthony Wilson 1889d500549bSAnthony Wilson // If no more connections left, call callback 1890d500549bSAnthony Wilson if (ledConnectionsIndex >= ledConnections->size()) 1891d500549bSAnthony Wilson { 189242cbe538SGunnar Mills callback(); 1893d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLedData exit"; 1894d500549bSAnthony Wilson return; 1895d500549bSAnthony Wilson } 1896d500549bSAnthony Wilson 1897d500549bSAnthony Wilson // Get inventory item data from current connection 1898fe04d49cSNan Zhou auto it = ledConnections->begin(); 1899fe04d49cSNan Zhou std::advance(it, ledConnectionsIndex); 1900d500549bSAnthony Wilson if (it != ledConnections->end()) 1901d500549bSAnthony Wilson { 1902d500549bSAnthony Wilson const std::string& ledPath = (*it).first; 1903d500549bSAnthony Wilson const std::string& ledConnection = (*it).second; 1904d500549bSAnthony Wilson // Response handler for Get State property 19051e1e598dSJonathan Doman auto respHandler = 19061e1e598dSJonathan Doman [sensorsAsyncResp, inventoryItems, ledConnections, ledPath, 1907f94c4ecfSEd Tanous callback{std::forward<Callback>(callback)}, ledConnectionsIndex]( 19081e1e598dSJonathan Doman const boost::system::error_code ec, const std::string& state) { 1909d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler enter"; 1910d500549bSAnthony Wilson if (ec) 1911d500549bSAnthony Wilson { 1912d500549bSAnthony Wilson BMCWEB_LOG_ERROR 1913d500549bSAnthony Wilson << "getInventoryLedData respHandler DBus error " << ec; 19148d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 1915d500549bSAnthony Wilson return; 1916d500549bSAnthony Wilson } 1917d500549bSAnthony Wilson 19181e1e598dSJonathan Doman BMCWEB_LOG_DEBUG << "Led state: " << state; 1919d500549bSAnthony Wilson // Find inventory item with this LED object path 1920d500549bSAnthony Wilson InventoryItem* inventoryItem = 1921d500549bSAnthony Wilson findInventoryItemForLed(*inventoryItems, ledPath); 1922d500549bSAnthony Wilson if (inventoryItem != nullptr) 1923d500549bSAnthony Wilson { 1924d500549bSAnthony Wilson // Store LED state in InventoryItem 192511ba3979SEd Tanous if (state.ends_with("On")) 1926d500549bSAnthony Wilson { 1927d500549bSAnthony Wilson inventoryItem->ledState = LedState::ON; 1928d500549bSAnthony Wilson } 192911ba3979SEd Tanous else if (state.ends_with("Blink")) 1930d500549bSAnthony Wilson { 1931d500549bSAnthony Wilson inventoryItem->ledState = LedState::BLINK; 1932d500549bSAnthony Wilson } 193311ba3979SEd Tanous else if (state.ends_with("Off")) 1934d500549bSAnthony Wilson { 1935d500549bSAnthony Wilson inventoryItem->ledState = LedState::OFF; 1936d500549bSAnthony Wilson } 1937d500549bSAnthony Wilson else 1938d500549bSAnthony Wilson { 1939d500549bSAnthony Wilson inventoryItem->ledState = LedState::UNKNOWN; 1940d500549bSAnthony Wilson } 1941d500549bSAnthony Wilson } 1942d500549bSAnthony Wilson 1943d500549bSAnthony Wilson // Recurse to get LED data from next connection 1944d500549bSAnthony Wilson getInventoryLedData(sensorsAsyncResp, inventoryItems, 1945d500549bSAnthony Wilson ledConnections, std::move(callback), 1946d500549bSAnthony Wilson ledConnectionsIndex + 1); 1947d500549bSAnthony Wilson 1948d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLedData respHandler exit"; 1949d500549bSAnthony Wilson }; 1950d500549bSAnthony Wilson 1951d500549bSAnthony Wilson // Get the State property for the current LED 19521e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 19531e1e598dSJonathan Doman *crow::connections::systemBus, ledConnection, ledPath, 19541e1e598dSJonathan Doman "xyz.openbmc_project.Led.Physical", "State", 19551e1e598dSJonathan Doman std::move(respHandler)); 1956d500549bSAnthony Wilson } 1957d500549bSAnthony Wilson 1958d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLedData exit"; 1959d500549bSAnthony Wilson } 1960d500549bSAnthony Wilson 1961d500549bSAnthony Wilson /** 1962d500549bSAnthony Wilson * @brief Gets LED data for LEDs associated with given inventory items. 1963d500549bSAnthony Wilson * 1964d500549bSAnthony Wilson * Gets the D-Bus connections (services) that provide LED data for the LEDs 1965d500549bSAnthony Wilson * associated with the specified inventory items. Then gets the LED data from 1966d500549bSAnthony Wilson * each connection and stores it in the inventory item. 1967d500549bSAnthony Wilson * 1968d500549bSAnthony Wilson * This data is later used to provide sensor property values in the JSON 1969d500549bSAnthony Wilson * response. 1970d500549bSAnthony Wilson * 1971d500549bSAnthony Wilson * Finds the LED data asynchronously. Invokes callback when information has 1972d500549bSAnthony Wilson * been obtained. 1973d500549bSAnthony Wilson * 1974d500549bSAnthony Wilson * The callback must have the following signature: 1975d500549bSAnthony Wilson * @code 197642cbe538SGunnar Mills * callback() 1977d500549bSAnthony Wilson * @endcode 1978d500549bSAnthony Wilson * 1979d500549bSAnthony Wilson * @param sensorsAsyncResp Pointer to object holding response data. 1980d500549bSAnthony Wilson * @param inventoryItems D-Bus inventory items associated with sensors. 1981d500549bSAnthony Wilson * @param callback Callback to invoke when inventory items have been obtained. 1982d500549bSAnthony Wilson */ 1983d500549bSAnthony Wilson template <typename Callback> 1984d500549bSAnthony Wilson void getInventoryLeds( 1985d500549bSAnthony Wilson std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 1986d500549bSAnthony Wilson std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 1987d500549bSAnthony Wilson Callback&& callback) 1988d500549bSAnthony Wilson { 1989d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLeds enter"; 1990d500549bSAnthony Wilson 1991d500549bSAnthony Wilson const std::string path = "/xyz/openbmc_project"; 1992d500549bSAnthony Wilson const std::array<std::string, 1> interfaces = { 1993d500549bSAnthony Wilson "xyz.openbmc_project.Led.Physical"}; 1994d500549bSAnthony Wilson 1995d500549bSAnthony Wilson // Response handler for parsing output from GetSubTree 1996002d39b4SEd Tanous auto respHandler = 1997002d39b4SEd Tanous [callback{std::forward<Callback>(callback)}, sensorsAsyncResp, 1998002d39b4SEd Tanous inventoryItems]( 1999b9d36b47SEd Tanous const boost::system::error_code ec, 2000002d39b4SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 2001d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler enter"; 2002d500549bSAnthony Wilson if (ec) 2003d500549bSAnthony Wilson { 20048d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 2005d500549bSAnthony Wilson BMCWEB_LOG_ERROR << "getInventoryLeds respHandler DBus error " 2006d500549bSAnthony Wilson << ec; 2007d500549bSAnthony Wilson return; 2008d500549bSAnthony Wilson } 2009d500549bSAnthony Wilson 2010d500549bSAnthony Wilson // Build map of LED object paths to connections 2011fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> ledConnections = 2012fe04d49cSNan Zhou std::make_shared<std::map<std::string, std::string>>(); 2013d500549bSAnthony Wilson 2014d500549bSAnthony Wilson // Loop through objects from GetSubTree 2015d500549bSAnthony Wilson for (const std::pair< 2016d500549bSAnthony Wilson std::string, 2017d500549bSAnthony Wilson std::vector<std::pair<std::string, std::vector<std::string>>>>& 2018d500549bSAnthony Wilson object : subtree) 2019d500549bSAnthony Wilson { 2020d500549bSAnthony Wilson // Check if object path is LED for one of the specified inventory 2021d500549bSAnthony Wilson // items 2022d500549bSAnthony Wilson const std::string& ledPath = object.first; 2023d500549bSAnthony Wilson if (findInventoryItemForLed(*inventoryItems, ledPath) != nullptr) 2024d500549bSAnthony Wilson { 2025d500549bSAnthony Wilson // Add mapping from ledPath to connection 2026d500549bSAnthony Wilson const std::string& connection = object.second.begin()->first; 2027d500549bSAnthony Wilson (*ledConnections)[ledPath] = connection; 2028d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "Added mapping " << ledPath << " -> " 2029d500549bSAnthony Wilson << connection; 2030d500549bSAnthony Wilson } 2031d500549bSAnthony Wilson } 2032d500549bSAnthony Wilson 2033d500549bSAnthony Wilson getInventoryLedData(sensorsAsyncResp, inventoryItems, ledConnections, 2034d500549bSAnthony Wilson std::move(callback)); 2035d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLeds respHandler exit"; 2036d500549bSAnthony Wilson }; 2037d500549bSAnthony Wilson // Make call to ObjectMapper to find all inventory items 2038d500549bSAnthony Wilson crow::connections::systemBus->async_method_call( 2039d500549bSAnthony Wilson std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 2040d500549bSAnthony Wilson "/xyz/openbmc_project/object_mapper", 2041d500549bSAnthony Wilson "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 0, interfaces); 2042d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryLeds exit"; 2043d500549bSAnthony Wilson } 2044d500549bSAnthony Wilson 2045d500549bSAnthony Wilson /** 204642cbe538SGunnar Mills * @brief Gets D-Bus data for Power Supply Attributes such as EfficiencyPercent 204742cbe538SGunnar Mills * 204842cbe538SGunnar Mills * Uses the specified connections (services) (currently assumes just one) to 204942cbe538SGunnar Mills * obtain D-Bus data for Power Supply Attributes. Stores the resulting data in 205042cbe538SGunnar Mills * the inventoryItems vector. Only stores data in Power Supply inventoryItems. 205142cbe538SGunnar Mills * 205242cbe538SGunnar Mills * This data is later used to provide sensor property values in the JSON 205342cbe538SGunnar Mills * response. 205442cbe538SGunnar Mills * 205542cbe538SGunnar Mills * Finds the Power Supply Attributes data asynchronously. Invokes callback 205642cbe538SGunnar Mills * when data has been obtained. 205742cbe538SGunnar Mills * 205842cbe538SGunnar Mills * The callback must have the following signature: 205942cbe538SGunnar Mills * @code 206042cbe538SGunnar Mills * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 206142cbe538SGunnar Mills * @endcode 206242cbe538SGunnar Mills * 206342cbe538SGunnar Mills * @param sensorsAsyncResp Pointer to object holding response data. 206442cbe538SGunnar Mills * @param inventoryItems D-Bus inventory items associated with sensors. 206542cbe538SGunnar Mills * @param psAttributesConnections Connections that provide data for the Power 206642cbe538SGunnar Mills * Supply Attributes 206742cbe538SGunnar Mills * @param callback Callback to invoke when data has been obtained. 206842cbe538SGunnar Mills */ 206942cbe538SGunnar Mills template <typename Callback> 207042cbe538SGunnar Mills void getPowerSupplyAttributesData( 2071b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 207242cbe538SGunnar Mills std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 2073fe04d49cSNan Zhou const std::map<std::string, std::string>& psAttributesConnections, 207442cbe538SGunnar Mills Callback&& callback) 207542cbe538SGunnar Mills { 207642cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData enter"; 207742cbe538SGunnar Mills 207842cbe538SGunnar Mills if (psAttributesConnections.empty()) 207942cbe538SGunnar Mills { 208042cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "Can't find PowerSupplyAttributes, no connections!"; 208142cbe538SGunnar Mills callback(inventoryItems); 208242cbe538SGunnar Mills return; 208342cbe538SGunnar Mills } 208442cbe538SGunnar Mills 208542cbe538SGunnar Mills // Assuming just one connection (service) for now 2086fe04d49cSNan Zhou auto it = psAttributesConnections.begin(); 208742cbe538SGunnar Mills 208842cbe538SGunnar Mills const std::string& psAttributesPath = (*it).first; 208942cbe538SGunnar Mills const std::string& psAttributesConnection = (*it).second; 209042cbe538SGunnar Mills 209142cbe538SGunnar Mills // Response handler for Get DeratingFactor property 2092002d39b4SEd Tanous auto respHandler = 2093002d39b4SEd Tanous [sensorsAsyncResp, inventoryItems, 2094f94c4ecfSEd Tanous callback{std::forward<Callback>(callback)}]( 2095002d39b4SEd Tanous const boost::system::error_code ec, const uint32_t value) { 209642cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler enter"; 209742cbe538SGunnar Mills if (ec) 209842cbe538SGunnar Mills { 209942cbe538SGunnar Mills BMCWEB_LOG_ERROR 210042cbe538SGunnar Mills << "getPowerSupplyAttributesData respHandler DBus error " << ec; 21018d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 210242cbe538SGunnar Mills return; 210342cbe538SGunnar Mills } 210442cbe538SGunnar Mills 21051e1e598dSJonathan Doman BMCWEB_LOG_DEBUG << "PS EfficiencyPercent value: " << value; 210642cbe538SGunnar Mills // Store value in Power Supply Inventory Items 210742cbe538SGunnar Mills for (InventoryItem& inventoryItem : *inventoryItems) 210842cbe538SGunnar Mills { 210955f79e6fSEd Tanous if (inventoryItem.isPowerSupply) 211042cbe538SGunnar Mills { 211142cbe538SGunnar Mills inventoryItem.powerSupplyEfficiencyPercent = 21121e1e598dSJonathan Doman static_cast<int>(value); 211342cbe538SGunnar Mills } 211442cbe538SGunnar Mills } 211542cbe538SGunnar Mills 211642cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData respHandler exit"; 211742cbe538SGunnar Mills callback(inventoryItems); 211842cbe538SGunnar Mills }; 211942cbe538SGunnar Mills 212042cbe538SGunnar Mills // Get the DeratingFactor property for the PowerSupplyAttributes 212142cbe538SGunnar Mills // Currently only property on the interface/only one we care about 21221e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint32_t>( 21231e1e598dSJonathan Doman *crow::connections::systemBus, psAttributesConnection, psAttributesPath, 21241e1e598dSJonathan Doman "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor", 21251e1e598dSJonathan Doman std::move(respHandler)); 212642cbe538SGunnar Mills 212742cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributesData exit"; 212842cbe538SGunnar Mills } 212942cbe538SGunnar Mills 213042cbe538SGunnar Mills /** 213142cbe538SGunnar Mills * @brief Gets the Power Supply Attributes such as EfficiencyPercent 213242cbe538SGunnar Mills * 213342cbe538SGunnar Mills * Gets the D-Bus connection (service) that provides Power Supply Attributes 213442cbe538SGunnar Mills * data. Then gets the Power Supply Attributes data from the connection 213542cbe538SGunnar Mills * (currently just assumes 1 connection) and stores the data in the inventory 213642cbe538SGunnar Mills * item. 213742cbe538SGunnar Mills * 213842cbe538SGunnar Mills * This data is later used to provide sensor property values in the JSON 213942cbe538SGunnar Mills * response. DeratingFactor on D-Bus is mapped to EfficiencyPercent on Redfish. 214042cbe538SGunnar Mills * 214142cbe538SGunnar Mills * Finds the Power Supply Attributes data asynchronously. Invokes callback 214242cbe538SGunnar Mills * when information has been obtained. 214342cbe538SGunnar Mills * 214442cbe538SGunnar Mills * The callback must have the following signature: 214542cbe538SGunnar Mills * @code 214642cbe538SGunnar Mills * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 214742cbe538SGunnar Mills * @endcode 214842cbe538SGunnar Mills * 214942cbe538SGunnar Mills * @param sensorsAsyncResp Pointer to object holding response data. 215042cbe538SGunnar Mills * @param inventoryItems D-Bus inventory items associated with sensors. 215142cbe538SGunnar Mills * @param callback Callback to invoke when data has been obtained. 215242cbe538SGunnar Mills */ 215342cbe538SGunnar Mills template <typename Callback> 215442cbe538SGunnar Mills void getPowerSupplyAttributes( 215542cbe538SGunnar Mills std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 215642cbe538SGunnar Mills std::shared_ptr<std::vector<InventoryItem>> inventoryItems, 215742cbe538SGunnar Mills Callback&& callback) 215842cbe538SGunnar Mills { 215942cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes enter"; 216042cbe538SGunnar Mills 216142cbe538SGunnar Mills // Only need the power supply attributes when the Power Schema 2162a0ec28b6SAdrian Ambrożewicz if (sensorsAsyncResp->chassisSubNode != sensors::node::power) 216342cbe538SGunnar Mills { 216442cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit since not Power"; 216542cbe538SGunnar Mills callback(inventoryItems); 216642cbe538SGunnar Mills return; 216742cbe538SGunnar Mills } 216842cbe538SGunnar Mills 216942cbe538SGunnar Mills const std::array<std::string, 1> interfaces = { 217042cbe538SGunnar Mills "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 217142cbe538SGunnar Mills 217242cbe538SGunnar Mills // Response handler for parsing output from GetSubTree 2173b9d36b47SEd Tanous auto respHandler = 2174b9d36b47SEd Tanous [callback{std::forward<Callback>(callback)}, sensorsAsyncResp, 2175b9d36b47SEd Tanous inventoryItems]( 2176b9d36b47SEd Tanous const boost::system::error_code ec, 2177b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 217842cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler enter"; 217942cbe538SGunnar Mills if (ec) 218042cbe538SGunnar Mills { 21818d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 218242cbe538SGunnar Mills BMCWEB_LOG_ERROR 218342cbe538SGunnar Mills << "getPowerSupplyAttributes respHandler DBus error " << ec; 218442cbe538SGunnar Mills return; 218542cbe538SGunnar Mills } 218626f6976fSEd Tanous if (subtree.empty()) 218742cbe538SGunnar Mills { 218842cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "Can't find Power Supply Attributes!"; 218942cbe538SGunnar Mills callback(inventoryItems); 219042cbe538SGunnar Mills return; 219142cbe538SGunnar Mills } 219242cbe538SGunnar Mills 219342cbe538SGunnar Mills // Currently we only support 1 power supply attribute, use this for 219442cbe538SGunnar Mills // all the power supplies. Build map of object path to connection. 219542cbe538SGunnar Mills // Assume just 1 connection and 1 path for now. 2196fe04d49cSNan Zhou std::map<std::string, std::string> psAttributesConnections; 219742cbe538SGunnar Mills 219842cbe538SGunnar Mills if (subtree[0].first.empty() || subtree[0].second.empty()) 219942cbe538SGunnar Mills { 220042cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!"; 220142cbe538SGunnar Mills callback(inventoryItems); 220242cbe538SGunnar Mills return; 220342cbe538SGunnar Mills } 220442cbe538SGunnar Mills 220542cbe538SGunnar Mills const std::string& psAttributesPath = subtree[0].first; 220642cbe538SGunnar Mills const std::string& connection = subtree[0].second.begin()->first; 220742cbe538SGunnar Mills 220842cbe538SGunnar Mills if (connection.empty()) 220942cbe538SGunnar Mills { 221042cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "Power Supply Attributes mapper error!"; 221142cbe538SGunnar Mills callback(inventoryItems); 221242cbe538SGunnar Mills return; 221342cbe538SGunnar Mills } 221442cbe538SGunnar Mills 221542cbe538SGunnar Mills psAttributesConnections[psAttributesPath] = connection; 221642cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "Added mapping " << psAttributesPath << " -> " 221742cbe538SGunnar Mills << connection; 221842cbe538SGunnar Mills 221942cbe538SGunnar Mills getPowerSupplyAttributesData(sensorsAsyncResp, inventoryItems, 222042cbe538SGunnar Mills psAttributesConnections, 222142cbe538SGunnar Mills std::move(callback)); 222242cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes respHandler exit"; 222342cbe538SGunnar Mills }; 222442cbe538SGunnar Mills // Make call to ObjectMapper to find the PowerSupplyAttributes service 222542cbe538SGunnar Mills crow::connections::systemBus->async_method_call( 222642cbe538SGunnar Mills std::move(respHandler), "xyz.openbmc_project.ObjectMapper", 222742cbe538SGunnar Mills "/xyz/openbmc_project/object_mapper", 222842cbe538SGunnar Mills "xyz.openbmc_project.ObjectMapper", "GetSubTree", 222942cbe538SGunnar Mills "/xyz/openbmc_project", 0, interfaces); 223042cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getPowerSupplyAttributes exit"; 223142cbe538SGunnar Mills } 223242cbe538SGunnar Mills 223342cbe538SGunnar Mills /** 2234adc4f0dbSShawn McCarney * @brief Gets inventory items associated with sensors. 22358fb49dd6SShawn McCarney * 22368fb49dd6SShawn McCarney * Finds the inventory items that are associated with the specified sensors. 2237adc4f0dbSShawn McCarney * Then gets D-Bus data for the inventory items, such as presence and VPD. 22388fb49dd6SShawn McCarney * 2239adc4f0dbSShawn McCarney * This data is later used to provide sensor property values in the JSON 2240adc4f0dbSShawn McCarney * response. 22418fb49dd6SShawn McCarney * 2242adc4f0dbSShawn McCarney * Finds the inventory items asynchronously. Invokes callback when the 2243adc4f0dbSShawn McCarney * inventory items have been obtained. 2244adc4f0dbSShawn McCarney * 2245adc4f0dbSShawn McCarney * The callback must have the following signature: 2246adc4f0dbSShawn McCarney * @code 2247adc4f0dbSShawn McCarney * callback(std::shared_ptr<std::vector<InventoryItem>> inventoryItems) 2248adc4f0dbSShawn McCarney * @endcode 22498fb49dd6SShawn McCarney * 22508fb49dd6SShawn McCarney * @param sensorsAsyncResp Pointer to object holding response data. 22518fb49dd6SShawn McCarney * @param sensorNames All sensors within the current chassis. 22528fb49dd6SShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 22538fb49dd6SShawn McCarney * implements ObjectManager. 2254adc4f0dbSShawn McCarney * @param callback Callback to invoke when inventory items have been obtained. 22558fb49dd6SShawn McCarney */ 2256adc4f0dbSShawn McCarney template <typename Callback> 2257adc4f0dbSShawn McCarney static void getInventoryItems( 22588fb49dd6SShawn McCarney std::shared_ptr<SensorsAsyncResp> sensorsAsyncResp, 2259fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames, 2260fe04d49cSNan Zhou std::shared_ptr<std::map<std::string, std::string>> objectMgrPaths, 2261adc4f0dbSShawn McCarney Callback&& callback) 22628fb49dd6SShawn McCarney { 2263adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems enter"; 2264adc4f0dbSShawn McCarney auto getInventoryItemAssociationsCb = 2265f94c4ecfSEd Tanous [sensorsAsyncResp, objectMgrPaths, 2266f94c4ecfSEd Tanous callback{std::forward<Callback>(callback)}]( 2267adc4f0dbSShawn McCarney std::shared_ptr<std::vector<InventoryItem>> inventoryItems) { 2268adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb enter"; 22698fb49dd6SShawn McCarney auto getInventoryItemsConnectionsCb = 2270adc4f0dbSShawn McCarney [sensorsAsyncResp, inventoryItems, objectMgrPaths, 2271f94c4ecfSEd Tanous callback{std::forward<const Callback>(callback)}]( 2272fe04d49cSNan Zhou std::shared_ptr<std::set<std::string>> invConnections) { 22738fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb enter"; 2274002d39b4SEd Tanous auto getInventoryItemsDataCb = [sensorsAsyncResp, inventoryItems, 2275d500549bSAnthony Wilson callback{std::move(callback)}]() { 2276d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb enter"; 227742cbe538SGunnar Mills 2278002d39b4SEd Tanous auto getInventoryLedsCb = [sensorsAsyncResp, inventoryItems, 2279002d39b4SEd Tanous callback{std::move(callback)}]() { 228042cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getInventoryLedsCb enter"; 228142cbe538SGunnar Mills // Find Power Supply Attributes and get the data 2282002d39b4SEd Tanous getPowerSupplyAttributes(sensorsAsyncResp, inventoryItems, 228342cbe538SGunnar Mills std::move(callback)); 228442cbe538SGunnar Mills BMCWEB_LOG_DEBUG << "getInventoryLedsCb exit"; 228542cbe538SGunnar Mills }; 228642cbe538SGunnar Mills 2287d500549bSAnthony Wilson // Find led connections and get the data 2288d500549bSAnthony Wilson getInventoryLeds(sensorsAsyncResp, inventoryItems, 228942cbe538SGunnar Mills std::move(getInventoryLedsCb)); 2290d500549bSAnthony Wilson BMCWEB_LOG_DEBUG << "getInventoryItemsDataCb exit"; 2291d500549bSAnthony Wilson }; 22928fb49dd6SShawn McCarney 2293adc4f0dbSShawn McCarney // Get inventory item data from connections 2294adc4f0dbSShawn McCarney getInventoryItemsData(sensorsAsyncResp, inventoryItems, 2295adc4f0dbSShawn McCarney invConnections, objectMgrPaths, 2296d500549bSAnthony Wilson std::move(getInventoryItemsDataCb)); 22978fb49dd6SShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsConnectionsCb exit"; 22988fb49dd6SShawn McCarney }; 22998fb49dd6SShawn McCarney 2300adc4f0dbSShawn McCarney // Get connections that provide inventory item data 2301002d39b4SEd Tanous getInventoryItemsConnections(sensorsAsyncResp, inventoryItems, 23028fb49dd6SShawn McCarney std::move(getInventoryItemsConnectionsCb)); 2303adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemAssociationsCb exit"; 23048fb49dd6SShawn McCarney }; 23058fb49dd6SShawn McCarney 2306adc4f0dbSShawn McCarney // Get associations from sensors to inventory items 2307adc4f0dbSShawn McCarney getInventoryItemAssociations(sensorsAsyncResp, sensorNames, objectMgrPaths, 2308adc4f0dbSShawn McCarney std::move(getInventoryItemAssociationsCb)); 2309adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItems exit"; 2310adc4f0dbSShawn McCarney } 2311adc4f0dbSShawn McCarney 2312adc4f0dbSShawn McCarney /** 2313adc4f0dbSShawn McCarney * @brief Returns JSON PowerSupply object for the specified inventory item. 2314adc4f0dbSShawn McCarney * 2315adc4f0dbSShawn McCarney * Searches for a JSON PowerSupply object that matches the specified inventory 2316adc4f0dbSShawn McCarney * item. If one is not found, a new PowerSupply object is added to the JSON 2317adc4f0dbSShawn McCarney * array. 2318adc4f0dbSShawn McCarney * 2319adc4f0dbSShawn McCarney * Multiple sensors are often associated with one power supply inventory item. 2320adc4f0dbSShawn McCarney * As a result, multiple sensor values are stored in one JSON PowerSupply 2321adc4f0dbSShawn McCarney * object. 2322adc4f0dbSShawn McCarney * 2323adc4f0dbSShawn McCarney * @param powerSupplyArray JSON array containing Redfish PowerSupply objects. 2324adc4f0dbSShawn McCarney * @param inventoryItem Inventory item for the power supply. 2325adc4f0dbSShawn McCarney * @param chassisId Chassis that contains the power supply. 2326adc4f0dbSShawn McCarney * @return JSON PowerSupply object for the specified inventory item. 2327adc4f0dbSShawn McCarney */ 232823a21a1cSEd Tanous inline nlohmann::json& getPowerSupply(nlohmann::json& powerSupplyArray, 2329adc4f0dbSShawn McCarney const InventoryItem& inventoryItem, 2330adc4f0dbSShawn McCarney const std::string& chassisId) 2331adc4f0dbSShawn McCarney { 2332adc4f0dbSShawn McCarney // Check if matching PowerSupply object already exists in JSON array 2333adc4f0dbSShawn McCarney for (nlohmann::json& powerSupply : powerSupplyArray) 2334adc4f0dbSShawn McCarney { 2335adc4f0dbSShawn McCarney if (powerSupply["MemberId"] == inventoryItem.name) 2336adc4f0dbSShawn McCarney { 2337adc4f0dbSShawn McCarney return powerSupply; 2338adc4f0dbSShawn McCarney } 2339adc4f0dbSShawn McCarney } 2340adc4f0dbSShawn McCarney 2341adc4f0dbSShawn McCarney // Add new PowerSupply object to JSON array 2342adc4f0dbSShawn McCarney powerSupplyArray.push_back({}); 2343adc4f0dbSShawn McCarney nlohmann::json& powerSupply = powerSupplyArray.back(); 2344adc4f0dbSShawn McCarney powerSupply["@odata.id"] = 2345adc4f0dbSShawn McCarney "/redfish/v1/Chassis/" + chassisId + "/Power#/PowerSupplies/"; 2346adc4f0dbSShawn McCarney powerSupply["MemberId"] = inventoryItem.name; 2347adc4f0dbSShawn McCarney powerSupply["Name"] = boost::replace_all_copy(inventoryItem.name, "_", " "); 2348adc4f0dbSShawn McCarney powerSupply["Manufacturer"] = inventoryItem.manufacturer; 2349adc4f0dbSShawn McCarney powerSupply["Model"] = inventoryItem.model; 2350adc4f0dbSShawn McCarney powerSupply["PartNumber"] = inventoryItem.partNumber; 2351adc4f0dbSShawn McCarney powerSupply["SerialNumber"] = inventoryItem.serialNumber; 2352d500549bSAnthony Wilson setLedState(powerSupply, &inventoryItem); 2353adc4f0dbSShawn McCarney 235442cbe538SGunnar Mills if (inventoryItem.powerSupplyEfficiencyPercent >= 0) 235542cbe538SGunnar Mills { 235642cbe538SGunnar Mills powerSupply["EfficiencyPercent"] = 235742cbe538SGunnar Mills inventoryItem.powerSupplyEfficiencyPercent; 235842cbe538SGunnar Mills } 235942cbe538SGunnar Mills 236042cbe538SGunnar Mills powerSupply["Status"]["State"] = getState(&inventoryItem); 2361adc4f0dbSShawn McCarney const char* health = inventoryItem.isFunctional ? "OK" : "Critical"; 2362adc4f0dbSShawn McCarney powerSupply["Status"]["Health"] = health; 2363adc4f0dbSShawn McCarney 2364adc4f0dbSShawn McCarney return powerSupply; 23658fb49dd6SShawn McCarney } 23668fb49dd6SShawn McCarney 23678fb49dd6SShawn McCarney /** 2368de629b6eSShawn McCarney * @brief Gets the values of the specified sensors. 2369de629b6eSShawn McCarney * 2370de629b6eSShawn McCarney * Stores the results as JSON in the SensorsAsyncResp. 2371de629b6eSShawn McCarney * 2372de629b6eSShawn McCarney * Gets the sensor values asynchronously. Stores the results later when the 2373de629b6eSShawn McCarney * information has been obtained. 2374de629b6eSShawn McCarney * 2375adc4f0dbSShawn McCarney * The sensorNames set contains all requested sensors for the current chassis. 2376de629b6eSShawn McCarney * 2377de629b6eSShawn McCarney * To minimize the number of DBus calls, the DBus method 2378de629b6eSShawn McCarney * org.freedesktop.DBus.ObjectManager.GetManagedObjects() is used to get the 2379de629b6eSShawn McCarney * values of all sensors provided by a connection (service). 2380de629b6eSShawn McCarney * 2381de629b6eSShawn McCarney * The connections set contains all the connections that provide sensor values. 2382de629b6eSShawn McCarney * 2383de629b6eSShawn McCarney * The objectMgrPaths map contains mappings from a connection name to the 2384de629b6eSShawn McCarney * corresponding DBus object path that implements ObjectManager. 2385de629b6eSShawn McCarney * 2386adc4f0dbSShawn McCarney * The InventoryItem vector contains D-Bus inventory items associated with the 2387adc4f0dbSShawn McCarney * sensors. Inventory item data is needed for some Redfish sensor properties. 2388adc4f0dbSShawn McCarney * 2389de629b6eSShawn McCarney * @param SensorsAsyncResp Pointer to object holding response data. 2390adc4f0dbSShawn McCarney * @param sensorNames All requested sensors within the current chassis. 2391de629b6eSShawn McCarney * @param connections Connections that provide sensor values. 2392de629b6eSShawn McCarney * @param objectMgrPaths Mappings from connection name to DBus object path that 2393de629b6eSShawn McCarney * implements ObjectManager. 2394adc4f0dbSShawn McCarney * @param inventoryItems Inventory items associated with the sensors. 2395de629b6eSShawn McCarney */ 239623a21a1cSEd Tanous inline void getSensorData( 239781ce609eSEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 2398fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames, 2399fe04d49cSNan Zhou const std::set<std::string>& connections, 2400fe04d49cSNan Zhou const std::shared_ptr<std::map<std::string, std::string>>& objectMgrPaths, 2401b5a76932SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& inventoryItems) 2402de629b6eSShawn McCarney { 2403de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData enter"; 2404de629b6eSShawn McCarney // Get managed objects from all services exposing sensors 2405de629b6eSShawn McCarney for (const std::string& connection : connections) 2406de629b6eSShawn McCarney { 2407de629b6eSShawn McCarney // Response handler to process managed objects 2408002d39b4SEd Tanous auto getManagedObjectsCb = 2409002d39b4SEd Tanous [sensorsAsyncResp, sensorNames, 2410002d39b4SEd Tanous inventoryItems](const boost::system::error_code ec, 241102cad96eSEd Tanous const dbus::utility::ManagedObjectType& resp) { 2412de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter"; 2413de629b6eSShawn McCarney if (ec) 2414de629b6eSShawn McCarney { 2415de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec; 24168d1b46d7Szhanghch05 messages::internalError(sensorsAsyncResp->asyncResp->res); 2417de629b6eSShawn McCarney return; 2418de629b6eSShawn McCarney } 2419de629b6eSShawn McCarney // Go through all objects and update response with sensor data 2420de629b6eSShawn McCarney for (const auto& objDictEntry : resp) 2421de629b6eSShawn McCarney { 2422de629b6eSShawn McCarney const std::string& objPath = 2423de629b6eSShawn McCarney static_cast<const std::string&>(objDictEntry.first); 2424de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object " 2425de629b6eSShawn McCarney << objPath; 2426de629b6eSShawn McCarney 2427de629b6eSShawn McCarney std::vector<std::string> split; 2428de629b6eSShawn McCarney // Reserve space for 2429de629b6eSShawn McCarney // /xyz/openbmc_project/sensors/<name>/<subname> 2430de629b6eSShawn McCarney split.reserve(6); 2431de629b6eSShawn McCarney boost::algorithm::split(split, objPath, boost::is_any_of("/")); 2432de629b6eSShawn McCarney if (split.size() < 6) 2433de629b6eSShawn McCarney { 2434de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Got path that isn't long enough " 2435de629b6eSShawn McCarney << objPath; 2436de629b6eSShawn McCarney continue; 2437de629b6eSShawn McCarney } 2438de629b6eSShawn McCarney // These indexes aren't intuitive, as boost::split puts an empty 2439de629b6eSShawn McCarney // string at the beginning 2440de629b6eSShawn McCarney const std::string& sensorType = split[4]; 2441de629b6eSShawn McCarney const std::string& sensorName = split[5]; 2442de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "sensorName " << sensorName 2443de629b6eSShawn McCarney << " sensorType " << sensorType; 244449c53ac9SJohnathan Mantey if (sensorNames->find(objPath) == sensorNames->end()) 2445de629b6eSShawn McCarney { 2446accdbb2cSAndrew Geissler BMCWEB_LOG_DEBUG << sensorName << " not in sensor list "; 2447de629b6eSShawn McCarney continue; 2448de629b6eSShawn McCarney } 2449de629b6eSShawn McCarney 2450adc4f0dbSShawn McCarney // Find inventory item (if any) associated with sensor 2451adc4f0dbSShawn McCarney InventoryItem* inventoryItem = 2452adc4f0dbSShawn McCarney findInventoryItemForSensor(inventoryItems, objPath); 2453adc4f0dbSShawn McCarney 245495a3ecadSAnthony Wilson const std::string& sensorSchema = 245581ce609eSEd Tanous sensorsAsyncResp->chassisSubNode; 245695a3ecadSAnthony Wilson 245795a3ecadSAnthony Wilson nlohmann::json* sensorJson = nullptr; 245895a3ecadSAnthony Wilson 2459928fefb9SNan Zhou if (sensorSchema == sensors::node::sensors && 2460928fefb9SNan Zhou !sensorsAsyncResp->efficientExpand) 246195a3ecadSAnthony Wilson { 2462*c1d019a6SEd Tanous std::string sensorTypeEscaped(sensorType); 2463*c1d019a6SEd Tanous sensorTypeEscaped.erase( 2464*c1d019a6SEd Tanous std::remove(sensorTypeEscaped.begin(), 2465*c1d019a6SEd Tanous sensorTypeEscaped.end(), '_'), 2466*c1d019a6SEd Tanous sensorTypeEscaped.end()); 2467*c1d019a6SEd Tanous std::string sensorId(sensorTypeEscaped); 2468*c1d019a6SEd Tanous sensorId += "_"; 2469*c1d019a6SEd Tanous sensorId += sensorName; 2470*c1d019a6SEd Tanous 24718d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res.jsonValue["@odata.id"] = 2472*c1d019a6SEd Tanous crow::utility::urlFromPieces( 2473*c1d019a6SEd Tanous "redfish", "v1", "Chassis", 2474*c1d019a6SEd Tanous sensorsAsyncResp->chassisId, 2475*c1d019a6SEd Tanous sensorsAsyncResp->chassisSubNode, sensorId); 24768d1b46d7Szhanghch05 sensorJson = &(sensorsAsyncResp->asyncResp->res.jsonValue); 247795a3ecadSAnthony Wilson } 247895a3ecadSAnthony Wilson else 247995a3ecadSAnthony Wilson { 2480271584abSEd Tanous std::string fieldName; 2481928fefb9SNan Zhou if (sensorsAsyncResp->efficientExpand) 2482928fefb9SNan Zhou { 2483928fefb9SNan Zhou fieldName = "Members"; 2484928fefb9SNan Zhou } 2485928fefb9SNan Zhou else if (sensorType == "temperature") 2486de629b6eSShawn McCarney { 2487de629b6eSShawn McCarney fieldName = "Temperatures"; 2488de629b6eSShawn McCarney } 2489de629b6eSShawn McCarney else if (sensorType == "fan" || sensorType == "fan_tach" || 2490de629b6eSShawn McCarney sensorType == "fan_pwm") 2491de629b6eSShawn McCarney { 2492de629b6eSShawn McCarney fieldName = "Fans"; 2493de629b6eSShawn McCarney } 2494de629b6eSShawn McCarney else if (sensorType == "voltage") 2495de629b6eSShawn McCarney { 2496de629b6eSShawn McCarney fieldName = "Voltages"; 2497de629b6eSShawn McCarney } 2498de629b6eSShawn McCarney else if (sensorType == "power") 2499de629b6eSShawn McCarney { 250055f79e6fSEd Tanous if (sensorName == "total_power") 2501028f7ebcSEddie James { 2502028f7ebcSEddie James fieldName = "PowerControl"; 2503028f7ebcSEddie James } 2504adc4f0dbSShawn McCarney else if ((inventoryItem != nullptr) && 2505adc4f0dbSShawn McCarney (inventoryItem->isPowerSupply)) 2506028f7ebcSEddie James { 2507de629b6eSShawn McCarney fieldName = "PowerSupplies"; 2508de629b6eSShawn McCarney } 2509adc4f0dbSShawn McCarney else 2510adc4f0dbSShawn McCarney { 2511adc4f0dbSShawn McCarney // Other power sensors are in SensorCollection 2512adc4f0dbSShawn McCarney continue; 2513adc4f0dbSShawn McCarney } 2514028f7ebcSEddie James } 2515de629b6eSShawn McCarney else 2516de629b6eSShawn McCarney { 2517de629b6eSShawn McCarney BMCWEB_LOG_ERROR << "Unsure how to handle sensorType " 2518de629b6eSShawn McCarney << sensorType; 2519de629b6eSShawn McCarney continue; 2520de629b6eSShawn McCarney } 2521de629b6eSShawn McCarney 2522de629b6eSShawn McCarney nlohmann::json& tempArray = 25238d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res.jsonValue[fieldName]; 2524adc4f0dbSShawn McCarney if (fieldName == "PowerControl") 252549c53ac9SJohnathan Mantey { 2526adc4f0dbSShawn McCarney if (tempArray.empty()) 25277ab06f49SGunnar Mills { 252895a3ecadSAnthony Wilson // Put multiple "sensors" into a single 252995a3ecadSAnthony Wilson // PowerControl. Follows MemberId naming and 253095a3ecadSAnthony Wilson // naming in power.hpp. 25311476687dSEd Tanous nlohmann::json::object_t power; 25321476687dSEd Tanous power["@odata.id"] = 2533adc4f0dbSShawn McCarney "/redfish/v1/Chassis/" + 253481ce609eSEd Tanous sensorsAsyncResp->chassisId + "/" + 253581ce609eSEd Tanous sensorsAsyncResp->chassisSubNode + "#/" + 25361476687dSEd Tanous fieldName + "/0"; 25371476687dSEd Tanous tempArray.push_back(std::move(power)); 2538adc4f0dbSShawn McCarney } 2539adc4f0dbSShawn McCarney sensorJson = &(tempArray.back()); 2540adc4f0dbSShawn McCarney } 2541adc4f0dbSShawn McCarney else if (fieldName == "PowerSupplies") 2542adc4f0dbSShawn McCarney { 2543adc4f0dbSShawn McCarney if (inventoryItem != nullptr) 2544adc4f0dbSShawn McCarney { 2545adc4f0dbSShawn McCarney sensorJson = 2546adc4f0dbSShawn McCarney &(getPowerSupply(tempArray, *inventoryItem, 254781ce609eSEd Tanous sensorsAsyncResp->chassisId)); 2548adc4f0dbSShawn McCarney } 254949c53ac9SJohnathan Mantey } 2550928fefb9SNan Zhou else if (fieldName == "Members") 2551928fefb9SNan Zhou { 25521476687dSEd Tanous nlohmann::json::object_t member; 25531476687dSEd Tanous member["@odata.id"] = 2554928fefb9SNan Zhou "/redfish/v1/Chassis/" + 2555928fefb9SNan Zhou sensorsAsyncResp->chassisId + "/" + 25561476687dSEd Tanous sensorsAsyncResp->chassisSubNode + "/" + sensorName; 25571476687dSEd Tanous tempArray.push_back(std::move(member)); 2558928fefb9SNan Zhou sensorJson = &(tempArray.back()); 2559928fefb9SNan Zhou } 256049c53ac9SJohnathan Mantey else 256149c53ac9SJohnathan Mantey { 25621476687dSEd Tanous nlohmann::json::object_t member; 25631476687dSEd Tanous member["@odata.id"] = "/redfish/v1/Chassis/" + 25641476687dSEd Tanous sensorsAsyncResp->chassisId + 25651476687dSEd Tanous "/" + 25661476687dSEd Tanous sensorsAsyncResp->chassisSubNode + 25671476687dSEd Tanous "#/" + fieldName + "/"; 25681476687dSEd Tanous tempArray.push_back(std::move(member)); 2569adc4f0dbSShawn McCarney sensorJson = &(tempArray.back()); 257049c53ac9SJohnathan Mantey } 257195a3ecadSAnthony Wilson } 2572de629b6eSShawn McCarney 2573adc4f0dbSShawn McCarney if (sensorJson != nullptr) 2574adc4f0dbSShawn McCarney { 25751d7c0054SEd Tanous objectInterfacesToJson(sensorName, sensorType, 25761d7c0054SEd Tanous sensorsAsyncResp->chassisSubNode, 25771d7c0054SEd Tanous objDictEntry.second, *sensorJson, 25781d7c0054SEd Tanous inventoryItem); 25791d7c0054SEd Tanous 25801d7c0054SEd Tanous std::string path = "/xyz/openbmc_project/sensors/"; 25811d7c0054SEd Tanous path += sensorType; 25821d7c0054SEd Tanous path += "/"; 25831d7c0054SEd Tanous path += sensorName; 2584*c1d019a6SEd Tanous sensorsAsyncResp->addMetadata(*sensorJson, path); 2585adc4f0dbSShawn McCarney } 2586de629b6eSShawn McCarney } 258781ce609eSEd Tanous if (sensorsAsyncResp.use_count() == 1) 258849c53ac9SJohnathan Mantey { 258981ce609eSEd Tanous sortJSONResponse(sensorsAsyncResp); 2590928fefb9SNan Zhou if (sensorsAsyncResp->chassisSubNode == 2591928fefb9SNan Zhou sensors::node::sensors && 2592928fefb9SNan Zhou sensorsAsyncResp->efficientExpand) 2593928fefb9SNan Zhou { 2594928fefb9SNan Zhou sensorsAsyncResp->asyncResp->res 2595928fefb9SNan Zhou .jsonValue["Members@odata.count"] = 2596928fefb9SNan Zhou sensorsAsyncResp->asyncResp->res.jsonValue["Members"] 2597928fefb9SNan Zhou .size(); 2598928fefb9SNan Zhou } 2599928fefb9SNan Zhou else if (sensorsAsyncResp->chassisSubNode == 2600928fefb9SNan Zhou sensors::node::thermal) 26018bd25ccdSJames Feist { 260281ce609eSEd Tanous populateFanRedundancy(sensorsAsyncResp); 26038bd25ccdSJames Feist } 260449c53ac9SJohnathan Mantey } 2605de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit"; 2606de629b6eSShawn McCarney }; 2607de629b6eSShawn McCarney 2608de629b6eSShawn McCarney // Find DBus object path that implements ObjectManager for the current 2609de629b6eSShawn McCarney // connection. If no mapping found, default to "/". 26108fb49dd6SShawn McCarney auto iter = objectMgrPaths->find(connection); 2611de629b6eSShawn McCarney const std::string& objectMgrPath = 26128fb49dd6SShawn McCarney (iter != objectMgrPaths->end()) ? iter->second : "/"; 2613de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "ObjectManager path for " << connection << " is " 2614de629b6eSShawn McCarney << objectMgrPath; 2615de629b6eSShawn McCarney 2616de629b6eSShawn McCarney crow::connections::systemBus->async_method_call( 2617de629b6eSShawn McCarney getManagedObjectsCb, connection, objectMgrPath, 2618de629b6eSShawn McCarney "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 261923a21a1cSEd Tanous } 2620de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getSensorData exit"; 2621de629b6eSShawn McCarney } 2622de629b6eSShawn McCarney 2623fe04d49cSNan Zhou inline void 2624fe04d49cSNan Zhou processSensorList(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp, 2625fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) 26261abe55efSEd Tanous { 2627fe04d49cSNan Zhou auto getConnectionCb = [sensorsAsyncResp, sensorNames]( 2628fe04d49cSNan Zhou const std::set<std::string>& connections) { 262955c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb enter"; 2630de629b6eSShawn McCarney auto getObjectManagerPathsCb = 2631fe04d49cSNan Zhou [sensorsAsyncResp, sensorNames, connections]( 2632fe04d49cSNan Zhou const std::shared_ptr<std::map<std::string, std::string>>& 2633fe04d49cSNan Zhou objectMgrPaths) { 2634de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb enter"; 2635adc4f0dbSShawn McCarney auto getInventoryItemsCb = 2636002d39b4SEd Tanous [sensorsAsyncResp, sensorNames, connections, objectMgrPaths]( 2637f23b7296SEd Tanous const std::shared_ptr<std::vector<InventoryItem>>& 2638adc4f0dbSShawn McCarney inventoryItems) { 2639adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb enter"; 264049c53ac9SJohnathan Mantey // Get sensor data and store results in JSON 2641002d39b4SEd Tanous getSensorData(sensorsAsyncResp, sensorNames, connections, 2642002d39b4SEd Tanous objectMgrPaths, inventoryItems); 2643adc4f0dbSShawn McCarney BMCWEB_LOG_DEBUG << "getInventoryItemsCb exit"; 2644adc4f0dbSShawn McCarney }; 2645adc4f0dbSShawn McCarney 2646adc4f0dbSShawn McCarney // Get inventory items associated with sensors 2647002d39b4SEd Tanous getInventoryItems(sensorsAsyncResp, sensorNames, objectMgrPaths, 2648adc4f0dbSShawn McCarney std::move(getInventoryItemsCb)); 2649adc4f0dbSShawn McCarney 2650de629b6eSShawn McCarney BMCWEB_LOG_DEBUG << "getObjectManagerPathsCb exit"; 265108777fb0SLewanczyk, Dawid }; 2652de629b6eSShawn McCarney 265349c53ac9SJohnathan Mantey // Get mapping from connection names to the DBus object 265449c53ac9SJohnathan Mantey // paths that implement the ObjectManager interface 265581ce609eSEd Tanous getObjectManagerPaths(sensorsAsyncResp, 2656de629b6eSShawn McCarney std::move(getObjectManagerPathsCb)); 265755c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getConnectionCb exit"; 265808777fb0SLewanczyk, Dawid }; 2659de629b6eSShawn McCarney 2660de629b6eSShawn McCarney // Get set of connections that provide sensor values 266181ce609eSEd Tanous getConnections(sensorsAsyncResp, sensorNames, std::move(getConnectionCb)); 266295a3ecadSAnthony Wilson } 266395a3ecadSAnthony Wilson 266495a3ecadSAnthony Wilson /** 266595a3ecadSAnthony Wilson * @brief Entry point for retrieving sensors data related to requested 266695a3ecadSAnthony Wilson * chassis. 266795a3ecadSAnthony Wilson * @param SensorsAsyncResp Pointer to object holding response data 266895a3ecadSAnthony Wilson */ 2669b5a76932SEd Tanous inline void 267081ce609eSEd Tanous getChassisData(const std::shared_ptr<SensorsAsyncResp>& sensorsAsyncResp) 267195a3ecadSAnthony Wilson { 267295a3ecadSAnthony Wilson BMCWEB_LOG_DEBUG << "getChassisData enter"; 267395a3ecadSAnthony Wilson auto getChassisCb = 267481ce609eSEd Tanous [sensorsAsyncResp]( 2675fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) { 267695a3ecadSAnthony Wilson BMCWEB_LOG_DEBUG << "getChassisCb enter"; 267781ce609eSEd Tanous processSensorList(sensorsAsyncResp, sensorNames); 267855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisCb exit"; 267908777fb0SLewanczyk, Dawid }; 2680928fefb9SNan Zhou // SensorCollection doesn't contain the Redundancy property 2681928fefb9SNan Zhou if (sensorsAsyncResp->chassisSubNode != sensors::node::sensors) 2682928fefb9SNan Zhou { 26838d1b46d7Szhanghch05 sensorsAsyncResp->asyncResp->res.jsonValue["Redundancy"] = 26848d1b46d7Szhanghch05 nlohmann::json::array(); 2685928fefb9SNan Zhou } 268626f03899SShawn McCarney // Get set of sensors in chassis 26877f1cc26dSEd Tanous getChassis(sensorsAsyncResp->asyncResp, sensorsAsyncResp->chassisId, 26887f1cc26dSEd Tanous sensorsAsyncResp->chassisSubNode, sensorsAsyncResp->types, 26897f1cc26dSEd Tanous std::move(getChassisCb)); 269055c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "getChassisData exit"; 2691271584abSEd Tanous } 269208777fb0SLewanczyk, Dawid 2693413961deSRichard Marian Thomaiyar /** 269449c53ac9SJohnathan Mantey * @brief Find the requested sensorName in the list of all sensors supplied by 269549c53ac9SJohnathan Mantey * the chassis node 269649c53ac9SJohnathan Mantey * 269749c53ac9SJohnathan Mantey * @param sensorName The sensor name supplied in the PATCH request 269849c53ac9SJohnathan Mantey * @param sensorsList The list of sensors managed by the chassis node 269949c53ac9SJohnathan Mantey * @param sensorsModified The list of sensors that were found as a result of 270049c53ac9SJohnathan Mantey * repeated calls to this function 270149c53ac9SJohnathan Mantey */ 2702fe04d49cSNan Zhou inline bool 2703fe04d49cSNan Zhou findSensorNameUsingSensorPath(std::string_view sensorName, 270402cad96eSEd Tanous const std::set<std::string>& sensorsList, 2705fe04d49cSNan Zhou std::set<std::string>& sensorsModified) 270649c53ac9SJohnathan Mantey { 2707fe04d49cSNan Zhou for (const auto& chassisSensor : sensorsList) 270849c53ac9SJohnathan Mantey { 270928aa8de5SGeorge Liu sdbusplus::message::object_path path(chassisSensor); 2710b00dcc27SEd Tanous std::string thisSensorName = path.filename(); 271128aa8de5SGeorge Liu if (thisSensorName.empty()) 271249c53ac9SJohnathan Mantey { 271349c53ac9SJohnathan Mantey continue; 271449c53ac9SJohnathan Mantey } 271549c53ac9SJohnathan Mantey if (thisSensorName == sensorName) 271649c53ac9SJohnathan Mantey { 271749c53ac9SJohnathan Mantey sensorsModified.emplace(chassisSensor); 271849c53ac9SJohnathan Mantey return true; 271949c53ac9SJohnathan Mantey } 272049c53ac9SJohnathan Mantey } 272149c53ac9SJohnathan Mantey return false; 272249c53ac9SJohnathan Mantey } 272349c53ac9SJohnathan Mantey 272449c53ac9SJohnathan Mantey /** 2725413961deSRichard Marian Thomaiyar * @brief Entry point for overriding sensor values of given sensor 2726413961deSRichard Marian Thomaiyar * 27278d1b46d7Szhanghch05 * @param sensorAsyncResp response object 27284bb3dc34SCarol Wang * @param allCollections Collections extract from sensors' request patch info 2729413961deSRichard Marian Thomaiyar * @param chassisSubNode Chassis Node for which the query has to happen 2730413961deSRichard Marian Thomaiyar */ 273123a21a1cSEd Tanous inline void setSensorsOverride( 2732b5a76932SEd Tanous const std::shared_ptr<SensorsAsyncResp>& sensorAsyncResp, 27334bb3dc34SCarol Wang std::unordered_map<std::string, std::vector<nlohmann::json>>& 2734397fd61fSjayaprakash Mutyala allCollections) 2735413961deSRichard Marian Thomaiyar { 273670d1d0aaSjayaprakash Mutyala BMCWEB_LOG_INFO << "setSensorsOverride for subNode" 27374bb3dc34SCarol Wang << sensorAsyncResp->chassisSubNode << "\n"; 2738413961deSRichard Marian Thomaiyar 2739543f4400SEd Tanous const char* propertyValueName = nullptr; 2740f65af9e8SRichard Marian Thomaiyar std::unordered_map<std::string, std::pair<double, std::string>> overrideMap; 2741413961deSRichard Marian Thomaiyar std::string memberId; 2742543f4400SEd Tanous double value = 0.0; 2743f65af9e8SRichard Marian Thomaiyar for (auto& collectionItems : allCollections) 2744f65af9e8SRichard Marian Thomaiyar { 2745f65af9e8SRichard Marian Thomaiyar if (collectionItems.first == "Temperatures") 2746f65af9e8SRichard Marian Thomaiyar { 2747f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingCelsius"; 2748f65af9e8SRichard Marian Thomaiyar } 2749f65af9e8SRichard Marian Thomaiyar else if (collectionItems.first == "Fans") 2750f65af9e8SRichard Marian Thomaiyar { 2751f65af9e8SRichard Marian Thomaiyar propertyValueName = "Reading"; 2752f65af9e8SRichard Marian Thomaiyar } 2753f65af9e8SRichard Marian Thomaiyar else 2754f65af9e8SRichard Marian Thomaiyar { 2755f65af9e8SRichard Marian Thomaiyar propertyValueName = "ReadingVolts"; 2756f65af9e8SRichard Marian Thomaiyar } 2757f65af9e8SRichard Marian Thomaiyar for (auto& item : collectionItems.second) 2758f65af9e8SRichard Marian Thomaiyar { 27598d1b46d7Szhanghch05 if (!json_util::readJson(item, sensorAsyncResp->asyncResp->res, 27608d1b46d7Szhanghch05 "MemberId", memberId, propertyValueName, 27618d1b46d7Szhanghch05 value)) 2762413961deSRichard Marian Thomaiyar { 2763413961deSRichard Marian Thomaiyar return; 2764413961deSRichard Marian Thomaiyar } 2765f65af9e8SRichard Marian Thomaiyar overrideMap.emplace(memberId, 2766f65af9e8SRichard Marian Thomaiyar std::make_pair(value, collectionItems.first)); 2767f65af9e8SRichard Marian Thomaiyar } 2768f65af9e8SRichard Marian Thomaiyar } 27694bb3dc34SCarol Wang 2770002d39b4SEd Tanous auto getChassisSensorListCb = 2771002d39b4SEd Tanous [sensorAsyncResp, overrideMap]( 2772fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorsList) { 277349c53ac9SJohnathan Mantey // Match sensor names in the PATCH request to those managed by the 277449c53ac9SJohnathan Mantey // chassis node 2775fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>> sensorNames = 2776fe04d49cSNan Zhou std::make_shared<std::set<std::string>>(); 2777f65af9e8SRichard Marian Thomaiyar for (const auto& item : overrideMap) 2778413961deSRichard Marian Thomaiyar { 2779f65af9e8SRichard Marian Thomaiyar const auto& sensor = item.first; 278049c53ac9SJohnathan Mantey if (!findSensorNameUsingSensorPath(sensor, *sensorsList, 278149c53ac9SJohnathan Mantey *sensorNames)) 2782f65af9e8SRichard Marian Thomaiyar { 2783f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find memberId " << item.first; 27848d1b46d7Szhanghch05 messages::resourceNotFound(sensorAsyncResp->asyncResp->res, 2785f65af9e8SRichard Marian Thomaiyar item.second.second, item.first); 2786413961deSRichard Marian Thomaiyar return; 2787413961deSRichard Marian Thomaiyar } 2788f65af9e8SRichard Marian Thomaiyar } 2789413961deSRichard Marian Thomaiyar // Get the connection to which the memberId belongs 2790002d39b4SEd Tanous auto getObjectsWithConnectionCb = 2791fe04d49cSNan Zhou [sensorAsyncResp, 2792fe04d49cSNan Zhou overrideMap](const std::set<std::string>& /*connections*/, 2793002d39b4SEd Tanous const std::set<std::pair<std::string, std::string>>& 2794413961deSRichard Marian Thomaiyar objectsWithConnection) { 2795f65af9e8SRichard Marian Thomaiyar if (objectsWithConnection.size() != overrideMap.size()) 2796413961deSRichard Marian Thomaiyar { 2797413961deSRichard Marian Thomaiyar BMCWEB_LOG_INFO 2798f65af9e8SRichard Marian Thomaiyar << "Unable to find all objects with proper connection " 2799f65af9e8SRichard Marian Thomaiyar << objectsWithConnection.size() << " requested " 2800f65af9e8SRichard Marian Thomaiyar << overrideMap.size() << "\n"; 28014f277b54SJayaprakash Mutyala messages::resourceNotFound(sensorAsyncResp->asyncResp->res, 2802a0ec28b6SAdrian Ambrożewicz sensorAsyncResp->chassisSubNode == 2803a0ec28b6SAdrian Ambrożewicz sensors::node::thermal 2804413961deSRichard Marian Thomaiyar ? "Temperatures" 2805413961deSRichard Marian Thomaiyar : "Voltages", 2806f65af9e8SRichard Marian Thomaiyar "Count"); 2807f65af9e8SRichard Marian Thomaiyar return; 2808f65af9e8SRichard Marian Thomaiyar } 2809f65af9e8SRichard Marian Thomaiyar for (const auto& item : objectsWithConnection) 2810f65af9e8SRichard Marian Thomaiyar { 281128aa8de5SGeorge Liu sdbusplus::message::object_path path(item.first); 281228aa8de5SGeorge Liu std::string sensorName = path.filename(); 281328aa8de5SGeorge Liu if (sensorName.empty()) 2814f65af9e8SRichard Marian Thomaiyar { 28154f277b54SJayaprakash Mutyala messages::internalError(sensorAsyncResp->asyncResp->res); 2816f65af9e8SRichard Marian Thomaiyar return; 2817f65af9e8SRichard Marian Thomaiyar } 2818f65af9e8SRichard Marian Thomaiyar 2819f65af9e8SRichard Marian Thomaiyar const auto& iterator = overrideMap.find(sensorName); 2820f65af9e8SRichard Marian Thomaiyar if (iterator == overrideMap.end()) 2821f65af9e8SRichard Marian Thomaiyar { 2822f65af9e8SRichard Marian Thomaiyar BMCWEB_LOG_INFO << "Unable to find sensor object" 2823f65af9e8SRichard Marian Thomaiyar << item.first << "\n"; 28244f277b54SJayaprakash Mutyala messages::internalError(sensorAsyncResp->asyncResp->res); 2825413961deSRichard Marian Thomaiyar return; 2826413961deSRichard Marian Thomaiyar } 2827413961deSRichard Marian Thomaiyar crow::connections::systemBus->async_method_call( 2828f65af9e8SRichard Marian Thomaiyar [sensorAsyncResp](const boost::system::error_code ec) { 2829413961deSRichard Marian Thomaiyar if (ec) 2830413961deSRichard Marian Thomaiyar { 28314f277b54SJayaprakash Mutyala if (ec.value() == 28324f277b54SJayaprakash Mutyala boost::system::errc::permission_denied) 28334f277b54SJayaprakash Mutyala { 28344f277b54SJayaprakash Mutyala BMCWEB_LOG_WARNING 28354f277b54SJayaprakash Mutyala << "Manufacturing mode is not Enabled...can't " 28364f277b54SJayaprakash Mutyala "Override the sensor value. "; 28374f277b54SJayaprakash Mutyala 28384f277b54SJayaprakash Mutyala messages::insufficientPrivilege( 28398d1b46d7Szhanghch05 sensorAsyncResp->asyncResp->res); 2840413961deSRichard Marian Thomaiyar return; 2841413961deSRichard Marian Thomaiyar } 28424f277b54SJayaprakash Mutyala BMCWEB_LOG_DEBUG 28434f277b54SJayaprakash Mutyala << "setOverrideValueStatus DBUS error: " << ec; 28444f277b54SJayaprakash Mutyala messages::internalError( 28454f277b54SJayaprakash Mutyala sensorAsyncResp->asyncResp->res); 28464f277b54SJayaprakash Mutyala } 2847413961deSRichard Marian Thomaiyar }, 28484f277b54SJayaprakash Mutyala item.second, item.first, "org.freedesktop.DBus.Properties", 28494f277b54SJayaprakash Mutyala "Set", "xyz.openbmc_project.Sensor.Value", "Value", 2850168e20c1SEd Tanous dbus::utility::DbusVariantType(iterator->second.first)); 2851f65af9e8SRichard Marian Thomaiyar } 2852413961deSRichard Marian Thomaiyar }; 2853413961deSRichard Marian Thomaiyar // Get object with connection for the given sensor name 2854413961deSRichard Marian Thomaiyar getObjectsWithConnection(sensorAsyncResp, sensorNames, 2855413961deSRichard Marian Thomaiyar std::move(getObjectsWithConnectionCb)); 2856413961deSRichard Marian Thomaiyar }; 2857413961deSRichard Marian Thomaiyar // get full sensor list for the given chassisId and cross verify the sensor. 28587f1cc26dSEd Tanous getChassis(sensorAsyncResp->asyncResp, sensorAsyncResp->chassisId, 28597f1cc26dSEd Tanous sensorAsyncResp->chassisSubNode, sensorAsyncResp->types, 28607f1cc26dSEd Tanous std::move(getChassisSensorListCb)); 2861413961deSRichard Marian Thomaiyar } 2862413961deSRichard Marian Thomaiyar 2863a0ec28b6SAdrian Ambrożewicz /** 2864a0ec28b6SAdrian Ambrożewicz * @brief Retrieves mapping of Redfish URIs to sensor value property to D-Bus 2865a0ec28b6SAdrian Ambrożewicz * path of the sensor. 2866a0ec28b6SAdrian Ambrożewicz * 2867a0ec28b6SAdrian Ambrożewicz * Function builds valid Redfish response for sensor query of given chassis and 2868a0ec28b6SAdrian Ambrożewicz * node. It then builds metadata about Redfish<->D-Bus correlations and provides 2869a0ec28b6SAdrian Ambrożewicz * it to caller in a callback. 2870a0ec28b6SAdrian Ambrożewicz * 2871a0ec28b6SAdrian Ambrożewicz * @param chassis Chassis for which retrieval should be performed 2872a0ec28b6SAdrian Ambrożewicz * @param node Node (group) of sensors. See sensors::node for supported values 2873a0ec28b6SAdrian Ambrożewicz * @param mapComplete Callback to be called with retrieval result 2874a0ec28b6SAdrian Ambrożewicz */ 2875021d32cfSKrzysztof Grobelny inline void retrieveUriToDbusMap(const std::string& chassis, 2876021d32cfSKrzysztof Grobelny const std::string& node, 2877a0ec28b6SAdrian Ambrożewicz SensorsAsyncResp::DataCompleteCb&& mapComplete) 2878a0ec28b6SAdrian Ambrożewicz { 287902da7c5aSEd Tanous decltype(sensors::paths)::const_iterator pathIt = 288002da7c5aSEd Tanous std::find_if(sensors::paths.cbegin(), sensors::paths.cend(), 288102da7c5aSEd Tanous [&node](auto&& val) { return val.first == node; }); 288202da7c5aSEd Tanous if (pathIt == sensors::paths.cend()) 2883a0ec28b6SAdrian Ambrożewicz { 2884a0ec28b6SAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Wrong node provided : " << node; 2885a0ec28b6SAdrian Ambrożewicz mapComplete(boost::beast::http::status::bad_request, {}); 2886a0ec28b6SAdrian Ambrożewicz return; 2887a0ec28b6SAdrian Ambrożewicz } 2888d51e072fSKrzysztof Grobelny 288972374eb7SNan Zhou auto asyncResp = std::make_shared<bmcweb::AsyncResp>(); 2890fe04d49cSNan Zhou auto callback = [asyncResp, mapCompleteCb{std::move(mapComplete)}]( 2891a0ec28b6SAdrian Ambrożewicz const boost::beast::http::status status, 2892fe04d49cSNan Zhou const std::map<std::string, std::string>& uriToDbus) { 2893fe04d49cSNan Zhou mapCompleteCb(status, uriToDbus); 2894fe04d49cSNan Zhou }; 2895a0ec28b6SAdrian Ambrożewicz 2896a0ec28b6SAdrian Ambrożewicz auto resp = std::make_shared<SensorsAsyncResp>( 2897d51e072fSKrzysztof Grobelny asyncResp, chassis, pathIt->second, node, std::move(callback)); 2898a0ec28b6SAdrian Ambrożewicz getChassisData(resp); 2899a0ec28b6SAdrian Ambrożewicz } 2900a0ec28b6SAdrian Ambrożewicz 2901bacb2162SNan Zhou namespace sensors 2902bacb2162SNan Zhou { 2903928fefb9SNan Zhou 2904bacb2162SNan Zhou inline void getChassisCallback( 2905*c1d019a6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2906*c1d019a6SEd Tanous std::string_view chassisId, std::string_view chassisSubNode, 2907fe04d49cSNan Zhou const std::shared_ptr<std::set<std::string>>& sensorNames) 2908bacb2162SNan Zhou { 2909bacb2162SNan Zhou BMCWEB_LOG_DEBUG << "getChassisCallback enter "; 2910bacb2162SNan Zhou 2911*c1d019a6SEd Tanous nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"]; 2912*c1d019a6SEd Tanous for (const std::string& sensor : *sensorNames) 2913bacb2162SNan Zhou { 2914bacb2162SNan Zhou BMCWEB_LOG_DEBUG << "Adding sensor: " << sensor; 2915bacb2162SNan Zhou 2916bacb2162SNan Zhou sdbusplus::message::object_path path(sensor); 2917bacb2162SNan Zhou std::string sensorName = path.filename(); 2918bacb2162SNan Zhou if (sensorName.empty()) 2919bacb2162SNan Zhou { 2920bacb2162SNan Zhou BMCWEB_LOG_ERROR << "Invalid sensor path: " << sensor; 2921*c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2922bacb2162SNan Zhou return; 2923bacb2162SNan Zhou } 2924*c1d019a6SEd Tanous std::string type = path.parent_path().filename(); 2925*c1d019a6SEd Tanous // fan_tach has an underscore in it, so remove it to "normalize" the 2926*c1d019a6SEd Tanous // type in the URI 2927*c1d019a6SEd Tanous type.erase(std::remove(type.begin(), type.end(), '_'), type.end()); 2928*c1d019a6SEd Tanous 29291476687dSEd Tanous nlohmann::json::object_t member; 2930*c1d019a6SEd Tanous std::string id = type; 2931*c1d019a6SEd Tanous id += "_"; 2932*c1d019a6SEd Tanous id += sensorName; 2933*c1d019a6SEd Tanous member["@odata.id"] = crow::utility::urlFromPieces( 2934*c1d019a6SEd Tanous "redfish", "v1", "Chassis", chassisId, chassisSubNode, id); 2935*c1d019a6SEd Tanous 29361476687dSEd Tanous entriesArray.push_back(std::move(member)); 2937bacb2162SNan Zhou } 2938bacb2162SNan Zhou 2939*c1d019a6SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size(); 2940bacb2162SNan Zhou BMCWEB_LOG_DEBUG << "getChassisCallback exit"; 2941bacb2162SNan Zhou } 2942e6bd846dSNan Zhou 2943de167a6fSNan Zhou inline void 2944de167a6fSNan Zhou handleSensorCollectionGet(App& app, const crow::Request& req, 2945de167a6fSNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2946de167a6fSNan Zhou const std::string& chassisId) 2947de167a6fSNan Zhou { 2948de167a6fSNan Zhou query_param::QueryCapabilities capabilities = { 2949de167a6fSNan Zhou .canDelegateExpandLevel = 1, 2950de167a6fSNan Zhou }; 2951de167a6fSNan Zhou query_param::Query delegatedQuery; 29523ba00073SCarson Labrado if (!redfish::setUpRedfishRouteWithDelegation(app, req, aResp, 2953de167a6fSNan Zhou delegatedQuery, capabilities)) 2954de167a6fSNan Zhou { 2955de167a6fSNan Zhou return; 2956de167a6fSNan Zhou } 2957de167a6fSNan Zhou 2958de167a6fSNan Zhou if (delegatedQuery.expandType != query_param::ExpandType::None) 2959de167a6fSNan Zhou { 2960de167a6fSNan Zhou // we perform efficient expand. 2961de167a6fSNan Zhou auto asyncResp = std::make_shared<SensorsAsyncResp>( 2962de167a6fSNan Zhou aResp, chassisId, sensors::dbus::sensorPaths, 2963de167a6fSNan Zhou sensors::node::sensors, 2964de167a6fSNan Zhou /*efficientExpand=*/true); 2965de167a6fSNan Zhou getChassisData(asyncResp); 2966de167a6fSNan Zhou 2967de167a6fSNan Zhou BMCWEB_LOG_DEBUG 2968de167a6fSNan Zhou << "SensorCollection doGet exit via efficient expand handler"; 2969de167a6fSNan Zhou return; 29700bad320cSEd Tanous } 2971de167a6fSNan Zhou 2972de167a6fSNan Zhou // We get all sensors as hyperlinkes in the chassis (this 2973de167a6fSNan Zhou // implies we reply on the default query parameters handler) 2974*c1d019a6SEd Tanous getChassis(aResp, chassisId, sensors::node::sensors, dbus::sensorPaths, 2975*c1d019a6SEd Tanous std::bind_front(sensors::getChassisCallback, aResp, chassisId, 2976*c1d019a6SEd Tanous sensors::node::sensors)); 2977*c1d019a6SEd Tanous } 29787f1cc26dSEd Tanous 2979*c1d019a6SEd Tanous inline void 2980*c1d019a6SEd Tanous getSensorFromDbus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2981*c1d019a6SEd Tanous const std::string& sensorPath, 2982*c1d019a6SEd Tanous const ::dbus::utility::MapperGetObject& mapperResponse) 2983*c1d019a6SEd Tanous { 2984*c1d019a6SEd Tanous if (mapperResponse.size() != 1) 2985*c1d019a6SEd Tanous { 2986*c1d019a6SEd Tanous messages::internalError(asyncResp->res); 2987*c1d019a6SEd Tanous return; 2988*c1d019a6SEd Tanous } 2989*c1d019a6SEd Tanous const auto& valueIface = *mapperResponse.begin(); 2990*c1d019a6SEd Tanous const std::string& connectionName = valueIface.first; 2991*c1d019a6SEd Tanous BMCWEB_LOG_DEBUG << "Looking up " << connectionName; 2992*c1d019a6SEd Tanous BMCWEB_LOG_DEBUG << "Path " << sensorPath; 2993*c1d019a6SEd Tanous crow::connections::systemBus->async_method_call( 2994*c1d019a6SEd Tanous [asyncResp, 2995*c1d019a6SEd Tanous sensorPath](const boost::system::error_code ec, 2996*c1d019a6SEd Tanous const ::dbus::utility::DBusPropertiesMap& valuesDict) { 2997*c1d019a6SEd Tanous if (ec) 2998*c1d019a6SEd Tanous { 2999*c1d019a6SEd Tanous messages::internalError(asyncResp->res); 3000*c1d019a6SEd Tanous return; 3001*c1d019a6SEd Tanous } 3002*c1d019a6SEd Tanous sdbusplus::message::object_path path(sensorPath); 3003*c1d019a6SEd Tanous std::string name = path.filename(); 3004*c1d019a6SEd Tanous path = path.parent_path(); 3005*c1d019a6SEd Tanous std::string type = path.filename(); 3006*c1d019a6SEd Tanous objectPropertiesToJson(name, type, sensors::node::sensors, valuesDict, 3007*c1d019a6SEd Tanous asyncResp->res.jsonValue, nullptr); 3008*c1d019a6SEd Tanous }, 3009*c1d019a6SEd Tanous connectionName, sensorPath, "org.freedesktop.DBus.Properties", "GetAll", 3010*c1d019a6SEd Tanous ""); 3011de167a6fSNan Zhou } 3012de167a6fSNan Zhou 3013e6bd846dSNan Zhou inline void handleSensorGet(App& app, const crow::Request& req, 3014*c1d019a6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3015*c1d019a6SEd Tanous const std::string& /*chassisId*/, 3016*c1d019a6SEd Tanous const std::string& sensorId) 3017e6bd846dSNan Zhou { 3018*c1d019a6SEd Tanous if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3019e6bd846dSNan Zhou { 3020e6bd846dSNan Zhou return; 3021e6bd846dSNan Zhou } 3022*c1d019a6SEd Tanous size_t index = sensorId.find('_'); 3023*c1d019a6SEd Tanous if (index == std::string::npos) 3024*c1d019a6SEd Tanous { 3025*c1d019a6SEd Tanous messages::resourceNotFound(asyncResp->res, sensorId, "Sensor"); 3026*c1d019a6SEd Tanous return; 3027*c1d019a6SEd Tanous } 3028*c1d019a6SEd Tanous std::string sensorType = sensorId.substr(0, index); 3029*c1d019a6SEd Tanous std::string sensorName = sensorId.substr(index + 1); 3030*c1d019a6SEd Tanous // fan_pwm and fan_tach need special handling 3031*c1d019a6SEd Tanous if (sensorType == "fantach" || sensorType == "fanpwm") 3032*c1d019a6SEd Tanous { 3033*c1d019a6SEd Tanous sensorType.insert(3, 1, '_'); 3034*c1d019a6SEd Tanous } 3035*c1d019a6SEd Tanous 3036e6bd846dSNan Zhou BMCWEB_LOG_DEBUG << "Sensor doGet enter"; 3037e6bd846dSNan Zhou 3038e6bd846dSNan Zhou const std::array<const char*, 1> interfaces = { 3039e6bd846dSNan Zhou "xyz.openbmc_project.Sensor.Value"}; 3040*c1d019a6SEd Tanous std::string sensorPath = 3041*c1d019a6SEd Tanous "/xyz/openbmc_project/sensors/" + sensorType + '/' + sensorName; 3042e6bd846dSNan Zhou // Get a list of all of the sensors that implement Sensor.Value 3043e6bd846dSNan Zhou // and get the path and service name associated with the sensor 3044e6bd846dSNan Zhou crow::connections::systemBus->async_method_call( 3045*c1d019a6SEd Tanous [asyncResp, sensorPath, 3046e6bd846dSNan Zhou sensorName](const boost::system::error_code ec, 3047*c1d019a6SEd Tanous const ::dbus::utility::MapperGetObject& subtree) { 3048e6bd846dSNan Zhou BMCWEB_LOG_DEBUG << "respHandler1 enter"; 3049e6bd846dSNan Zhou if (ec) 3050e6bd846dSNan Zhou { 3051*c1d019a6SEd Tanous messages::internalError(asyncResp->res); 3052e6bd846dSNan Zhou BMCWEB_LOG_ERROR << "Sensor getSensorPaths resp_handler: " 3053e6bd846dSNan Zhou << "Dbus error " << ec; 3054e6bd846dSNan Zhou return; 3055e6bd846dSNan Zhou } 3056*c1d019a6SEd Tanous getSensorFromDbus(asyncResp, sensorPath, subtree); 3057e6bd846dSNan Zhou BMCWEB_LOG_DEBUG << "respHandler1 exit"; 3058e6bd846dSNan Zhou }, 3059e6bd846dSNan Zhou "xyz.openbmc_project.ObjectMapper", 3060e6bd846dSNan Zhou "/xyz/openbmc_project/object_mapper", 3061*c1d019a6SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", sensorPath, 3062*c1d019a6SEd Tanous interfaces); 3063e6bd846dSNan Zhou } 3064e6bd846dSNan Zhou 3065bacb2162SNan Zhou } // namespace sensors 3066bacb2162SNan Zhou 30677e860f15SJohn Edward Broadbent inline void requestRoutesSensorCollection(App& app) 306895a3ecadSAnthony Wilson { 30697e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/") 3070ed398213SEd Tanous .privileges(redfish::privileges::getSensorCollection) 3071002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3072de167a6fSNan Zhou std::bind_front(sensors::handleSensorCollectionGet, std::ref(app))); 307395a3ecadSAnthony Wilson } 307495a3ecadSAnthony Wilson 30757e860f15SJohn Edward Broadbent inline void requestRoutesSensor(App& app) 307695a3ecadSAnthony Wilson { 30777e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Sensors/<str>/") 3078ed398213SEd Tanous .privileges(redfish::privileges::getSensor) 3079002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 3080e6bd846dSNan Zhou std::bind_front(sensors::handleSensorGet, std::ref(app))); 308195a3ecadSAnthony Wilson } 308295a3ecadSAnthony Wilson 308308777fb0SLewanczyk, Dawid } // namespace redfish 3084