⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractzonecontroller.java

📁 这是一个以JAVA编写的程序,本人还没有试过,是一个简单的温度控制系统
💻 JAVA
字号:
package net.sf.dz.device.model.impl;import java.io.IOException;import java.util.Iterator;import java.util.Map;import java.util.HashMap;import java.util.Set;import java.util.HashSet;import org.freehold.jukebox.conf.Configurable;import org.freehold.jukebox.conf.Configuration;import org.freehold.jukebox.logger.LogAware;import org.freehold.jukebox.logger.LogChannel;import net.sf.dz.device.actuator.AC;import net.sf.dz.device.actuator.Damper;import net.sf.dz.device.model.DamperController;import net.sf.dz.device.model.Thermostat;import net.sf.dz.device.model.Unit;import net.sf.dz.device.model.ZoneController;/** * The zone controller abstraction. * * Implements the behavior common for all the zone controller, and provides * the template methods for the rest. * * @author Copyright &copy; <a href="mailto:vt@freehold.crocodile.org">Vadim Tkachenko</a> 2001-2002 * @version $Id: AbstractZoneController.java,v 1.12 2004/01/20 02:40:34 vtt Exp $ */abstract public class AbstractZoneController extends LogAware implements ZoneController {    public static final LogChannel CH_AZC = new LogChannel("ZC");    /**     * The unit to serve.     */    protected Unit unit;        /**     * The HVAC unit to control.     */    protected AC ac;        /**     * The damper controller.     */    protected DamperController damperController;        /**     * "Unhappy" controller signal.     *     * If the controller signal goes above this value, the signal source is     * considered "unhappy".     */    protected double ctl_unhappy;        /**     * "Happy" controller signal.     *     * If the controller signal goes below this value, the signal source is     * considered "happy".     */    protected double ctl_happy;        /**     * Mapping from the thermostat to its last known output signal.     *     * Required so we know whether the value changed since the last     * iteration. Error conditions are not registered in this map, but in     * {@link #tsFailureMap tsFailureMap}.     */    protected Map tsSignalMap = new HashMap();        /**     * Thermostats that aren't satisfied with the temperature in their     * rooms.     *     * Having this allows better control over starting and stopping the A/C.     */    protected Set unhappyTs = new HashSet();        /**     * Mapping from the thermostat to its current failure condition.     *     * As soon as a valid signal arrives from the thermostat, its entry is     * removed from this map.     */    protected Map tsFailureMap = new HashMap();        /**     * When do we start thinking about dumping excess static pressure.     *     * <p>     *     * If the total area of open dampers vs. all the dampers is more than     * this, no big deal. Otherwise, we start opening the dump zone dampers     * and otherwise fiddle with them.     *     * <p>     *     * The closer is this value to 1.0, the better from the A/C unit point     * of view. However, this has to be modified for the case of the     * variable speed fan, it is not yet clear how, though.     *     * <p>     *      * Rough model shows that the dump threshold more than 0.4 is     * unacceptable from the comfort point of view. In real life, the dump     * threshold may be even lower because the dampers are not ideal and     * leak a lot.     */    protected double dumpThreshold = 0.3;        public double getDumpThreshold() {            return dumpThreshold;    }        public void setDumpThreshold(double dumpThreshold) {            if ( dumpThreshold < 0 || dumpThreshold > 1 ) {                    throw new IllegalArgumentException("Invalid value " + dumpThreshold + " (should be in 0..1 range)");        }                this.dumpThreshold = dumpThreshold;                // VT: FIXME: Propagate immediately?    }        protected void configure() throws Throwable {            if ( unit == null ) {                    throw new IllegalStateException("Unit must be attached first");        }        dumpThreshold = getConfiguration().getDouble(getConfigurationRoot() + ".dump_threshold", 0.3);        ctl_unhappy = getConfiguration().getDouble(getConfigurationRoot() + ".unhappy", 1);        ctl_happy = getConfiguration().getDouble(getConfigurationRoot() + ".happy", -ctl_unhappy);                // Let's see that they're not out of their mind                if ( ctl_unhappy <= ctl_happy ) {                    throw new IllegalArgumentException("Bad values for ctl_unhappy and ctl_happy (the former must be greater than latter): " + ctl_unhappy + ", " + ctl_happy);        }    }        public void attach(Unit unit) {            this.unit = unit;        this.ac = unit.getAC();        this.damperController = unit.getDamperController();                if ( unit == null || ac == null || damperController == null ) {                    throw new IllegalStateException("Unit being connected is not completely initialized");        }    }        /**     * Accept the notification about the change in the thermostat process     * controller output.     *     * @param source Thermostat whose signal has changed.     *     * @param signal The current value of the thermostat process controller signal.     */    public final synchronized void controlSignalChanged(Thermostat source, Object signalObject) {            // First of all, let's figure if the signal is a temperature value        // or an error condition.                if ( signalObject instanceof Double ) {                    clearFailure(source);            controlSignalChanged(source, ((Double)signalObject).doubleValue());        } else {                        // Since there's no signal from this thermostat, it will not            // participate in calculating the demand - with any luck, the            // damper will just stay open                        tsSignalMap.remove(source);                        processFailure(source, signalObject);        }    }        private final synchronized void controlSignalChanged(Thermostat source, double signal) {            //complain(LOG_DEBUG, CH_AZC, "Control signal changed: " + source.getName() + ": " + signal);            int mode = unit.getAC().getMode();                if ( mode == 0 ) {                    // A/C is off, nothing to do                        return;        }                // Adjust the signal according to the A/C running mode. Happy is        // negative, unhappy is positive, regardless of the mode.                signal *= -mode;                if ( !source.isOn() ) {                    // Fake the happy signal so they shut up                        // VT: FIXME: If we get smart about happy/unhappy limits, the            // signal value here has to be faked keeping those values in            // mind.                        signal = ctl_happy;                        // At this point, the signal is such that the rest of the            // controller logic believes that this room is happy and            // processes the rest of the framework accordingly, including            // shutting the dampers and switching off the A/C, if            // required. Simple ;)        }                // Check if the signal value has changed                Double old = (Double)tsSignalMap.get(source);                if ( old != null ) {                    if ( old.compareTo(new Double(signal)) == 0 ) {                            // Nothing happened                                //complain(LOG_DEBUG, CH_AZC, source.getName() + ": signal not changed");                                return;            }        }            // Record the value so it is available in the later calculations                tsSignalMap.put(source, new Double(signal));                    Double demand = new Double(computeDemand());                // Adjust the demand according to the signal value.                demand = controlSignalChanged(source, signal, demand);                if ( demand != null ) {                    if ( demand.doubleValue() < 0 ) {                            throw new IllegalStateException("Negative demand???");            }                        ac.demand(demand.doubleValue());        }    }        public void enabledStateChanged(Thermostat source, boolean enabled) {            if ( enabled ) {                    reset(source);        }    }        public void votingStateChanged(Thermostat source, boolean voting) {            if ( source.isOn() ) {                    reset(source);        }    }        private void reset(Thermostat source) {            // Regardless of actual signal value, mark this thermostat as        // unhappy. It's quite possible that it is within the controller        // hysteresis zone, which will cause the HVAC to be turned on, but        // the damper will stay closed.                unhappyTs.add(source);        //complain(LOG_DEBUG, CH_AZC, source.getName() + ": made unhappy");                // Also, the old signal value has to be expired from the signal        // cache, lest controlSignalChanged() thinks that nothing happened                tsSignalMap.remove(source);                // Let's now force the signal to be processed        controlSignalChanged(source, source.getControlSignal());    }        public void holdStateChanged(Thermostat source, boolean hold) {            controlSignalChanged(source, source.getControlSignal());    }        /**     * Make a decision about the A/C operating mode.     *     * The processing done here will determine whether the A/C has to be     * switched on, off, or the stage has to be changed.     *     * @param source Thermostat whose signal has changed.     *     * @param signal The signal, adjusted according to current A/C mode     * (happy is negative, unhappy is positive).     *     * @param currentDemand Total heating/cooling demand from all the rooms     * (see {@link #computeDemand computeDemand()}).     *     * @return Adjusted demand. Null value means that there will be no     * changes to the current A/C operation, anything else will be passed on     * to the A/C unit to carry out.     */    abstract protected Double controlSignalChanged(Thermostat source, double signal, Double currentDemand);        /**     * Compute the total demand for A/C.     *     * @return Sum of all non-negative signal values taken from each     * thermostat. This may not be appropriate for all subclasses.     */    protected double computeDemand() {            int mode = unit.getAC().getMode();                double demand = 0;                for ( Iterator i = tsSignalMap.keySet().iterator(); i.hasNext(); ) {                    double signal = ((Double)tsSignalMap.get(i.next())).doubleValue() * ((mode == 0) ? 0 : 1);                        if ( signal > 0 ) {                            demand += signal;            }        }                //complain(LOG_DEBUG, CH_AZC, "Total demand: " + demand);                return demand;    }        private synchronized void clearFailure(Thermostat source) {            if ( tsFailureMap.containsKey(source) ) {                    tsFailureMap.remove(source);                        complain(LOG_NOTICE, CH_AZC, "Cleared failure condition for " + source.getName());            // VT: FIXME: Make sure the system is put back in order.            // Possibly, this will be achieved automatically since right            // after this call the normal control flow will be executed                        if ( tsFailureMap.isEmpty() ) {                            complain(LOG_NOTICE, CH_AZC, "Normal operation restored: all zones operable");            }        }    }        private synchronized void processFailure(Thermostat source, Object failureData) {            if ( !tsFailureMap.containsKey(source) ) {                    tsFailureMap.put(source, failureData);                        complain(LOG_WARNING, CH_AZC, "Registered failure condition for " + source.getName() + ": " + failureData);                        // VT: FIXME: Send a notification to the user, whether this is            // all of the zones or just one. Think about how not to make            // ourselves an annoyance for the case of things like 1-Wire            // glitches.                        // VT: NOTE: This is the only place where the dampers for faulty            // zones are handled. No subclasses should be bothered with            // that, because the logic is identical.                         // VT: NOTE: The dampers should be taken care of before the HVAC            // because it is possible that the dampers will stay operable            // even if the HVAC controls are not - for example, the case            // when both the sensors and the HVAC actuators are located on            // the same 1-Wire network. In this case, the 1-Wire network            // failure may make HVAC controls inoperable and the unit will            // stay on, however, the possible damage will be minimized since            // all the dampers will be fully open.                        Damper d = damperController.getDamper(source);                        try {                            d.set(1);                            } catch ( IOException ioex ) {                            complain(LOG_WARNING, CH_AZC, "Can set the throttle, cause:", ioex);            }                                    if ( tsFailureMap.size() == unit.getZoneCount() ) {                            // Oh shit, all the zones have failed                                complain(LOG_ALERT, CH_AZC, "ALL ZONES REPORTED FAILURE");                                // Take care of the HVAC, if possible.                                ac.demand(0);                                // VT: FIXME: Tell the user (via notification) what the last                // known HVAC state was, and whether an attempt to shut it                // off (if any) was successful or not) - this will make                // their life easier.                //                // Currently, this is not possible because the HVAC control                // is asynchronous, so the code handling this condition will                // have to be moved there, or, as alternative, a special                // synchronous piece of code must be added to provide                // emergency shutoff.            }                    }    }        protected final synchronized boolean isFailing(Thermostat source) {            return tsFailureMap.containsKey(source);    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -