control: Add count state floor action
This action is similar to the count_state_target action except it sets
the fan floor instead of fan target.
It sets the zone to a configured floor with a hold when a number of
members within the group are at a configured state. Once the number of
members at the given state falls below the configured count, the floor
hold is released.
Example JSON is:
{
"name": "count_state_floor",
"count": 1,
"state": false,
"floor": 5000
}
This will set the floor hold to 5000 when at least 1 member of the
configured group has a value of false.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ie67314ad0221264a7a3ee634728e8216cb0a16cd
diff --git a/control/Makefile.am b/control/Makefile.am
index 3b52e47..77a4006 100644
--- a/control/Makefile.am
+++ b/control/Makefile.am
@@ -85,6 +85,7 @@
json/actions/timer_based_actions.cpp \
json/actions/mapped_floor.cpp \
json/actions/set_parameter_from_group_max.cpp \
+ json/actions/count_state_floor.cpp \
json/utils/flight_recorder.cpp \
json/utils/modifier.cpp
else
diff --git a/control/json/actions/count_state_floor.cpp b/control/json/actions/count_state_floor.cpp
new file mode 100644
index 0000000..da5bddf
--- /dev/null
+++ b/control/json/actions/count_state_floor.cpp
@@ -0,0 +1,99 @@
+/**
+ * Copyright © 2021 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "count_state_floor.hpp"
+
+#include "../manager.hpp"
+#include "../zone.hpp"
+#include "action.hpp"
+#include "group.hpp"
+
+namespace phosphor::fan::control::json
+{
+
+CountStateFloor::CountStateFloor(const json& jsonObj,
+ const std::vector<Group>& groups) :
+ ActionBase(jsonObj, groups)
+{
+ setCount(jsonObj);
+ setState(jsonObj);
+ setFloor(jsonObj);
+}
+
+void CountStateFloor::run(Zone& zone)
+{
+ size_t numAtState = 0;
+ for (const auto& group : _groups)
+ {
+ for (const auto& member : group.getMembers())
+ {
+ try
+ {
+ if (Manager::getObjValueVariant(member, group.getInterface(),
+ group.getProperty()) == _state)
+ {
+ numAtState++;
+ }
+ }
+ catch (const std::out_of_range& oore)
+ {
+ // Default to property not equal when not found
+ }
+ if (numAtState >= _count)
+ {
+ break;
+ }
+ }
+ if (numAtState >= _count)
+ {
+ break;
+ }
+ }
+
+ // Update zone's floor hold based on action results
+ zone.setFloorHold(getUniqueName(), _floor, (numAtState >= _count));
+}
+
+void CountStateFloor::setCount(const json& jsonObj)
+{
+ if (!jsonObj.contains("count"))
+ {
+ throw ActionParseError{ActionBase::getName(),
+ "Missing required count value"};
+ }
+ _count = jsonObj["count"].get<size_t>();
+}
+
+void CountStateFloor::setState(const json& jsonObj)
+{
+ if (!jsonObj.contains("state"))
+ {
+ throw ActionParseError{ActionBase::getName(),
+ "Missing required state value"};
+ }
+ _state = getJsonValue(jsonObj["state"]);
+}
+
+void CountStateFloor::setFloor(const json& jsonObj)
+{
+ if (!jsonObj.contains("floor"))
+ {
+ throw ActionParseError{ActionBase::getName(),
+ "Missing required floor value"};
+ }
+ _floor = jsonObj["floor"].get<uint64_t>();
+}
+
+} // namespace phosphor::fan::control::json
diff --git a/control/json/actions/count_state_floor.hpp b/control/json/actions/count_state_floor.hpp
new file mode 100644
index 0000000..99aa13d
--- /dev/null
+++ b/control/json/actions/count_state_floor.hpp
@@ -0,0 +1,117 @@
+/**
+ * Copyright © 2021 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "../zone.hpp"
+#include "action.hpp"
+#include "group.hpp"
+
+#include <nlohmann/json.hpp>
+
+namespace phosphor::fan::control::json
+{
+
+using json = nlohmann::json;
+
+/**
+ * @class CountStateFloor - Action to set a floor when members are at a state
+ *
+ * Sets the fans to a configured floor when a number of members within the
+ * group are at a configured state. Once the number of members at the given
+ * state falls below the configured count, the floor hold is released.
+ *
+ * Example JSON:
+ * {
+ * "name": "count_state_floor",
+ * "count": 1,
+ * "state": false,
+ * "floor": 5000
+ * }
+ */
+class CountStateFloor :
+ public ActionBase,
+ public ActionRegister<CountStateFloor>
+{
+ public:
+ /* Name of this action */
+ static constexpr auto name = "count_state_floor";
+
+ CountStateFloor() = delete;
+ CountStateFloor(const CountStateFloor&) = delete;
+ CountStateFloor(CountStateFloor&&) = delete;
+ CountStateFloor& operator=(const CountStateFloor&) = delete;
+ CountStateFloor& operator=(CountStateFloor&&) = delete;
+ ~CountStateFloor() = default;
+
+ /**
+ * @brief Set floor when a number of members are at a given state
+ *
+ * @param[in] jsonObj - JSON configuration of this action
+ * @param[in] groups - Groups of dbus objects the action uses
+ */
+ CountStateFloor(const json& jsonObj, const std::vector<Group>& groups);
+
+ /**
+ * @brief Run the action
+ *
+ * Counts the number of members within a group are equal to a given state
+ * and when the number of members are at or above the given state, the
+ * zone is set to the configured floor, with a hold. The hold is released
+ * when the number of members goes below the configured count.
+ *
+ * @param[in] zone - Zone to run the action on
+ */
+ void run(Zone& zone) override;
+
+ private:
+ /**
+ * @brief Parse and set the count
+ *
+ * @param[in] jsonObj - JSON object for the action
+ *
+ * Sets the number of members that must equal the state
+ */
+ void setCount(const json& jsonObj);
+
+ /**
+ * @brief Parse and set the state
+ *
+ * @param[in] jsonObj - JSON object for the action
+ *
+ * Sets the state for each member to equal to set the floor
+ */
+ void setState(const json& jsonObj);
+
+ /**
+ * @brief Parse and set the floor
+ *
+ * @param[in] jsonObj - JSON object for the action
+ *
+ * Sets the floor to use when running the action
+ */
+ void setFloor(const json& jsonObj);
+
+ /* Number of group members */
+ size_t _count;
+
+ /* State the members must be at to set the floor */
+ PropertyVariantType _state;
+
+ /* Floor for this action */
+ uint64_t _floor;
+};
+
+} // namespace phosphor::fan::control::json