001package jmri.jmrix.powerline;
002
003import jmri.implementation.AbstractVariableLight;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Implementation of the Light Object for Powerline devices.
009 * <p>
010 * For X10 devices, uses dimming commands to set intensity unless the value is
011 * 0.0 or 1.0, in which case it uses on/off commands only.
012 * <p>
013 * For Insteon devices, uses direct setting of intensity level unless the value
014 * is 0.0 or 1.0, in which case it uses on/off commands only.
015 * <p>
016 * For DMX devices, use direct setting of the intensity level. But an on/off
017 * will skip any stepping of the change.
018 * <p>
019 * For X10, since the dim/bright step of the hardware is unknown then the Light
020 * object is first created, the first time the intensity (not state) is set to
021 * other than 0.0 or 1.0, the output is run to it's maximum dim or bright step
022 * so that we know the count is right.
023 * <p>
024 * For X10, keeps track of the controller's "dim count", and if not certain
025 * forces it to zero to be sure.
026 *
027 * @author Dave Duchamp Copyright (C) 2004
028 * @author Bob Jacobsen Copyright (C) 2006, 2007, 2008
029 * @author Ken Cameron Copyright (C) 2009, 2010 Converted to multiple connection
030 * @author kcameron Copyright (C) 2011
031 */
032abstract public class SerialLight extends AbstractVariableLight {
033
034    /**
035     * Create a Light object, with only system name.
036     * <p>
037     * 'systemName' was previously validated in SerialLightManager
038     * @param systemName system name for light
039     * @param tc traffic controller
040     */
041    public SerialLight(String systemName, SerialTrafficController tc) {
042        super(systemName);
043        this.tc = tc;
044        // Initialize the Light
045        initializeLight();
046    }
047
048    /**
049     * Create a Light object, with both system and user names.
050     * <p>
051     * 'systemName' was previously validated in SerialLightManager
052     * @param systemName system name for light
053     * @param tc traffic controller
054     * @param userName user name for light
055     */
056    public SerialLight(String systemName, SerialTrafficController tc, String userName) {
057        super(systemName, userName);
058        this.tc = tc;
059        initializeLight();
060    }
061
062    SerialTrafficController tc = null;
063
064    /**
065     * Invoked from constructors to set up details. Note: most instance
066     * variables are in AbstractLight and AbstractVariableLight base classes.
067     */
068    protected void initializeLight() {
069        // Convert to the two-part X10 address
070        housecode = tc.getAdapterMemo().getSerialAddress().x10HouseCodeAsValueFromSystemName(getSystemName());
071        devicecode = tc.getAdapterMemo().getSerialAddress().x10DeviceCodeAsValueFromSystemName(getSystemName());
072        // not an X10, try Insteon
073        if (housecode == -1) {
074            idhighbyte = tc.getAdapterMemo().getSerialAddress().insteonIdHighCodeAsValueFromSystemName(getSystemName());
075            idmiddlebyte = tc.getAdapterMemo().getSerialAddress().insteonIdMiddleCodeAsValueFromSystemName(getSystemName());
076            idlowbyte = tc.getAdapterMemo().getSerialAddress().insteonIdLowCodeAsValueFromSystemName(getSystemName());
077            // if not Insteon, try DMX
078            if (idhighbyte == -1) {
079                unitid = tc.getAdapterMemo().getSerialAddress().dmxUnitIdCodeAsValueFromSystemName(getSystemName());
080            }
081        }
082    }
083
084    /**
085     * Optionally, force control to a known "dim count".
086     * <p>
087     * Invoked the first time intensity is set.
088     * <p>
089     * Default implementation doesn't do anything.
090     * @param intensity float for 0-&gt;1.0
091     */
092    protected void initIntensity(double intensity) {
093    }
094
095    // data members holding the address forms
096    protected int housecode = -1;
097    protected int devicecode = -1;
098    protected int idhighbyte = -1;
099    protected int idmiddlebyte = -1;
100    protected int idlowbyte = -1;
101    protected int unitid = -1;
102
103    /**
104     * Send a On/Off Command to the hardware
105     */
106    @Override
107    protected void sendOnOffCommand(int newState) {
108        if (log.isDebugEnabled()) {
109            log.debug("sendOnOff({}) Current: {}", newState, mState);
110        }
111
112        // figure out command 
113        int function;
114        double newDim;
115        if (newState == ON) {
116            function = X10Sequence.FUNCTION_ON;
117            newDim = 1;
118        } else if (newState == OFF) {
119            function = X10Sequence.FUNCTION_OFF;
120            newDim = 0;
121        } else {
122            log.warn("illegal state requested for Light: {}", getSystemName());
123            return;
124        }
125
126        if (log.isDebugEnabled()) {
127            log.debug("set state {} house {} device {}", newState, X10Sequence.houseCodeToText(housecode), devicecode);
128        }
129
130        // create output sequence of address, then function
131        X10Sequence out = new X10Sequence();
132        out.addAddress(housecode, devicecode);
133        out.addFunction(housecode, function, 0);
134        // send
135        tc.sendX10Sequence(out, null);
136
137        if (log.isDebugEnabled()) {
138            log.debug("sendOnOff({})  house {} device {} funct: {}", newDim, X10Sequence.houseValueToText(housecode), devicecode, function);
139        }
140    }
141
142    private final static Logger log = LoggerFactory.getLogger(SerialLight.class);
143}
144
145