001 package dk.deepthought.sidious.greenhouse;
002
003 import java.util.ArrayList;
004 import java.util.Collection;
005
006 import net.jcip.annotations.Immutable;
007
008 import org.apache.commons.logging.Log;
009 import org.apache.commons.logging.LogFactory;
010
011 import dk.deepthought.sidious.supportsystem.Adjustable;
012 import dk.deepthought.sidious.supportsystem.State;
013 import dk.deepthought.sidious.supportsystem.SuperLinkID;
014 import dk.deepthought.sidious.supportsystem.SystemSettings;
015
016 /**
017 * This class represents the setpoint for the greenhouse windows.
018 *
019 * @author Deepthought
020 *
021 */
022 @Immutable
023 public class WindowSetPoint implements Adjustable {
024 /**
025 * Logger for this class
026 */
027 private static final Log logger = LogFactory.getLog(WindowSetPoint.class);
028
029 /**
030 * The setting of this setpoint.
031 */
032 private final double setting;
033
034 /**
035 * The id of the temperature sensor.
036 */
037 private final SuperLinkID temperatureID;
038
039 /**
040 * The id of the humidity sensor.
041 */
042 private final SuperLinkID humidityID;
043
044 /**
045 * The id of the outside temperature sensor.
046 */
047 private final SuperLinkID outsideTemperatureID;
048
049 /**
050 * The id of the outside humidity sensor.
051 */
052 private final SuperLinkID outsideHumidityID;
053
054 /**
055 * Approximate window surface percentage.
056 */
057 private static final int windowAreaPercentage = 10;
058
059 /**
060 * Internal enum to describe possible adjustments.
061 */
062 private enum WindowStep {
063 OPEN(5d), CLOSE(-5d);
064
065 private double increment;
066
067 WindowStep(double increment) {
068 this.increment = increment;
069 }
070
071 public double getIncrement() {
072 return increment;
073 }
074 }
075
076 /**
077 * Creates a new <code>ScreenSetPoint</code> with the specified setting.
078 * <p>
079 * Input parameters should be between 0 and 100 percent. Parameters outside
080 * this will be rounded to nearest limit.
081 *
082 * @param setting
083 * the setting
084 */
085 public WindowSetPoint(double setting) {
086 humidityID = SystemSettings.getHumidityID();
087 temperatureID = SystemSettings.getTemperatureID();
088 outsideHumidityID = SystemSettings.getOutsideHumidityID();
089 outsideTemperatureID = SystemSettings.getOutsideTemperatureID();
090 if (setting > 100) {
091 setting = 100;
092 }
093 if (setting < 0) {
094 setting = 0;
095 }
096 this.setting = setting;
097 }
098
099 /*
100 * (non-Javadoc)
101 *
102 * @see dk.deepthought.sidious.supportsystem.Adjustable#consequence(dk.deepthought.sidious.supportsystem.State)
103 */
104 public State consequence(State state) {
105 if (logger.isDebugEnabled()) {
106 logger.debug("consequence(State state=" + state + ") - start");
107 }
108 if (!(state instanceof ClimaticState)) {
109 String fail = "Input state must be a climatic state. - state=" + state;
110 logger.error(fail);
111 throw new IllegalArgumentException(fail);
112 }
113 ClimaticState clima = (ClimaticState) state;
114 Collection<SensorInput> sensors = clima.getSensors();
115 if (sensors.isEmpty()) {
116 String fail = "Sensors cannot be empty";
117 logger.error(fail);
118 throw new IllegalArgumentException(fail);
119 }
120 ArrayList<SensorInput> newSensorList = new ArrayList<SensorInput>();
121 SensorInput temperature = null;
122 SensorInput humidity = null;
123 SensorInput outsideTemperature = null;
124 SensorInput outsideHumidity = null;
125 for (SensorInput input : sensors) {
126 if (input.getID().equals(temperatureID)) {
127 temperature = input;
128 } else if (input.getID().equals(humidityID)) {
129 humidity = input;
130 } else if (input.getID().equals(outsideTemperatureID)) {
131 outsideTemperature = input;
132 newSensorList.add(input);
133 } else if (input.getID().equals(outsideHumidityID)) {
134 outsideHumidity = input;
135 newSensorList.add(input);
136 } else {
137 newSensorList.add(input);
138 }
139 }
140 if (temperature == null || humidity == null
141 || outsideTemperature == null || outsideHumidity == null) {
142 logger.error("consequence(State state=" + state
143 + ") - temperature=" + temperature + ", humidity="
144 + humidity + ", outsideTemp=" + outsideTemperature
145 + ", outsideHum=" + outsideHumidity
146 + " - needed sensor was null. "
147 + "Returning original input state");
148 return state;
149 }
150 double deltaTemperature = outsideTemperature.getValue()
151 - temperature.getValue();
152 double deltaHumidity = outsideHumidity.getValue() - humidity.getValue();
153 double newFactor = windowAreaPercentage * (setting / 100)
154 * SystemSettings.getTimestep();
155 if (Math.abs(newFactor) > 1) {
156 newFactor = Math.signum(newFactor);
157 }
158 double newTemperatureValue = temperature.getValue() + deltaTemperature
159 * newFactor;
160 newSensorList.add(temperature
161 .newInstanceWithNewValue(newTemperatureValue));
162 double newHumidityValue = humidity.getValue() + deltaHumidity
163 * newFactor;
164 newSensorList.add(humidity.newInstanceWithNewValue(newHumidityValue));
165
166 State returnState = new ClimaticState(newSensorList);
167 if (logger.isDebugEnabled()) {
168 logger.debug("consequence(State state=" + state
169 + ") - end - return value=" + returnState);
170 }
171 return returnState;
172 }
173
174 /*
175 * (non-Javadoc)
176 *
177 * @see dk.deepthought.sidious.supportsystem.Adjustable#possibleAdjustments()
178 */
179 public Collection<Adjustable> possibleAdjustments() {
180 Collection<Adjustable> setpoints = new ArrayList<Adjustable>();
181 for (WindowStep possibleDirection : WindowStep.values()) {
182 double result = setting + possibleDirection.getIncrement();
183 assert result != Float.MAX_VALUE : "result exceeded Float.MAX_VALUE";
184 int min = 0; // Minimum value (windows closed)
185 int max = 100; // Maximum value (windows opened up all the way)
186 if (result < min) {
187 result = min;
188 if (setting != min) {
189 setpoints.add(new WindowSetPoint(result));
190 }
191 } else if (result > max) {
192 result = max;
193 if (setting != max) {
194 setpoints.add(new WindowSetPoint(result));
195 }
196 } else {
197 setpoints.add(new WindowSetPoint(result));
198 }
199 }
200 return setpoints;
201 }
202
203 /*
204 * (non-Javadoc)
205 *
206 * @see dk.deepthought.sidious.supportsystem.Adjustable#getID()
207 */
208 public SuperLinkID getID() {
209 return SystemSettings.getWindowSetPointID();
210 }
211
212 /*
213 * (non-Javadoc)
214 *
215 * @see dk.deepthought.sidious.supportsystem.Adjustable#getSetting()
216 */
217 public double getSetting() {
218 return setting;
219 }
220
221 /*
222 * (non-Javadoc)
223 *
224 * @see java.lang.Object#hashCode()
225 */
226 @Override
227 public int hashCode() {
228 final int PRIME = 31;
229 int result = 1;
230 long temp;
231 temp = Double.doubleToLongBits(setting);
232 result = PRIME * result + (int) (temp ^ (temp >>> 32));
233 return result;
234 }
235
236 /*
237 * (non-Javadoc)
238 *
239 * @see java.lang.Object#equals(java.lang.Object)
240 */
241 @Override
242 public boolean equals(Object obj) {
243 if (this == obj)
244 return true;
245 if (obj == null)
246 return false;
247 if (getClass() != obj.getClass())
248 return false;
249 final WindowSetPoint other = (WindowSetPoint) obj;
250 if (Double.doubleToLongBits(setting) != Double
251 .doubleToLongBits(other.setting))
252 return false;
253 return true;
254 }
255
256 /*
257 * (non-Javadoc)
258 *
259 * @see java.lang.Object#toString()
260 */
261 @Override
262 public String toString() {
263 return getClass().getSimpleName() + "[setting=" + setting + "]";
264 }
265
266 }
|