1 /** 2 * Copyright © 2021 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "count_state_floor.hpp" 17 18 #include "../manager.hpp" 19 #include "../zone.hpp" 20 #include "action.hpp" 21 #include "group.hpp" 22 #include "sdeventplus.hpp" 23 24 namespace phosphor::fan::control::json 25 { 26 27 CountStateFloor::CountStateFloor(const json& jsonObj, 28 const std::vector<Group>& groups) : 29 ActionBase(jsonObj, groups) 30 { 31 setCount(jsonObj); 32 setState(jsonObj); 33 setFloor(jsonObj); 34 setDelayTime(jsonObj); 35 } 36 37 void CountStateFloor::run(Zone& zone) 38 { 39 auto countReached = doCount(); 40 41 if (_delayTime == std::chrono::seconds::zero()) 42 { 43 // If no delay time configured, can immediately update the hold. 44 zone.setFloorHold(getUniqueName(), _floor, countReached); 45 return; 46 } 47 48 if (!countReached) 49 { 50 if (_timer && _timer->isEnabled()) 51 { 52 record("Stopping delay timer"); 53 _timer->setEnabled(false); 54 } 55 56 zone.setFloorHold(getUniqueName(), _floor, countReached); 57 return; 58 } 59 60 // The count has been reached and a delay is configured, so either: 61 // 1. This hold has already been set, so don't need to do anything else. 62 // 2. The timer hasn't been started yet, so start it (May need to create 63 // it first). 64 // 3. The timer is already running, don't need to do anything else. 65 // When the timer expires, then count again and set the hold. 66 67 if (zone.hasFloorHold(getUniqueName())) 68 { 69 return; 70 } 71 72 if (!_timer) 73 { 74 _timer = std::make_unique<Timer>(util::SDEventPlus::getEvent(), 75 [&zone, this](Timer&) { 76 zone.setFloorHold(getUniqueName(), _floor, doCount()); 77 }); 78 } 79 80 if (!_timer->isEnabled()) 81 { 82 record("Starting delay timer"); 83 _timer->restartOnce(_delayTime); 84 } 85 } 86 87 bool CountStateFloor::doCount() 88 { 89 size_t numAtState = 0; 90 91 for (const auto& group : _groups) 92 { 93 for (const auto& member : group.getMembers()) 94 { 95 try 96 { 97 if (Manager::getObjValueVariant(member, group.getInterface(), 98 group.getProperty()) == _state) 99 { 100 numAtState++; 101 if (numAtState >= _count) 102 { 103 return true; 104 } 105 } 106 } 107 catch (const std::out_of_range& oore) 108 { 109 // Default to property not equal when not found 110 } 111 } 112 } 113 114 return false; 115 } 116 117 void CountStateFloor::setCount(const json& jsonObj) 118 { 119 if (!jsonObj.contains("count")) 120 { 121 throw ActionParseError{ActionBase::getName(), 122 "Missing required count value"}; 123 } 124 _count = jsonObj["count"].get<size_t>(); 125 } 126 127 void CountStateFloor::setState(const json& jsonObj) 128 { 129 if (!jsonObj.contains("state")) 130 { 131 throw ActionParseError{ActionBase::getName(), 132 "Missing required state value"}; 133 } 134 _state = getJsonValue(jsonObj["state"]); 135 } 136 137 void CountStateFloor::setFloor(const json& jsonObj) 138 { 139 if (!jsonObj.contains("floor")) 140 { 141 throw ActionParseError{ActionBase::getName(), 142 "Missing required floor value"}; 143 } 144 _floor = jsonObj["floor"].get<uint64_t>(); 145 } 146 147 void CountStateFloor::setDelayTime(const json& jsonObj) 148 { 149 if (jsonObj.contains("delay")) 150 { 151 _delayTime = std::chrono::seconds(jsonObj["delay"].get<size_t>()); 152 } 153 } 154 155 } // namespace phosphor::fan::control::json 156