001package jmri.jmrix.powerline.simulator;
002
003import jmri.jmrix.powerline.InsteonSequence;
004import jmri.jmrix.powerline.SerialTrafficController;
005import jmri.util.StringUtil;
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009/**
010 * Implementation of the Light Object for Insteon receivers on Insteon 2412S
011 * interfaces.
012 * <p>
013 * Uses X10 dimming commands to set intensity unless the value is 0.0 or 1.0, in
014 * which case it uses on/off commands only.
015 * <p>
016 * Since the dim/bright step of the hardware is unknown then the Light object is
017 * first created, the first time the intensity (not state) is set to other than
018 * 0.0 or 1.0, the output is run to it's maximum dim or bright step so that we
019 * know the count is right.
020 * <p>
021 * Keeps track of the controller's "dim count", and if not certain forces it to
022 * zero to be sure.
023 *
024 *
025 * @author Dave Duchamp Copyright (C) 2004
026 * @author Bob Jacobsen Copyright (C) 2006, 2007, 2008, 2009, 2010
027 * @author Ken Cameron Copyright (C) 2009, 2010 Converted to multiple connection
028 * @author kcameron Copyright (C) 2011
029 */
030public class SpecificInsteonLight extends jmri.jmrix.powerline.SerialLight {
031
032    // System-dependent instance variables
033    /**
034     * Current output step 0 to maxDimStep.
035     * <p>
036     * -1 means unknown
037     */
038    int lastOutputStep = -1;
039
040    /**
041     * Largest Insteon dim step number available.
042     */
043    int maxDimStep = 255;
044
045    /**
046     * Create a Light object, with only system name.
047     * <p>
048     * 'systemName' was previously validated in SerialLightManager
049     * @param systemName text for systemName of light
050     * @param tc         tc for connection
051     */
052    public SpecificInsteonLight(String systemName, SerialTrafficController tc) {
053        super(systemName, tc);
054        this.tc = tc;
055        // maxDimStep = tc.getNumberOfIntensitySteps();
056    }
057
058    /**
059     * Create a Light object, with both system and user names.
060     * <p>
061     * 'systemName' was previously validated in SerialLightManager
062     * @param systemName text for systemName of light
063     * @param tc         tc for connection
064     * @param userName   text for userName of light
065     */
066    public SpecificInsteonLight(String systemName, SerialTrafficController tc, String userName) {
067        super(systemName, tc, userName);
068        this.tc = tc;
069        //maxDimStep = tc.getNumberOfIntensitySteps();
070    }
071
072    SerialTrafficController tc = null;
073
074    /**
075     * Invoked the first time intensity is set.
076     *
077     * @param intensity The next intensity value that will be set
078     */
079    @Override
080    protected void initIntensity(double intensity) {
081        if (log.isDebugEnabled()) {
082            log.debug("initIntensity({})", intensity);
083        }
084    }
085
086    /**
087     * Send a Dim/Bright command to the Insteon hardware to reach a specific
088     * intensity. Acts immediately, and changes no general state.
089     * <p>
090     * This sends "Dim" commands.
091     */
092    @Override
093    protected void sendIntensity(double intensity) {
094        if (log.isDebugEnabled()) {
095            log.debug("sendIntensity({}) lastOutputStep: {} maxDimStep: {}", intensity, lastOutputStep, maxDimStep);
096        }
097
098        // find the new correct dim count
099        int newStep = (int) Math.round(intensity * maxDimStep);  // maxDimStep is full on, 0 is full off, etc
100
101        // check for errors
102        if ((newStep < 0) || (newStep > maxDimStep)) {
103            log.error("newStep wrong: {} intensity: {}", newStep, intensity);
104        }
105
106        // do we have any change to make
107        if (newStep == lastOutputStep) {
108            // nothing to do!
109            if (log.isDebugEnabled()) {
110                log.debug("intensity {} within current step, return", intensity);
111            }
112            return;
113        }
114
115        if (log.isDebugEnabled()) {
116            log.debug("function set Intensity {}", intensity);
117        }
118
119        // create output sequence of address, then function
120        InsteonSequence out = new InsteonSequence();
121        out.addFunction(idhighbyte, idmiddlebyte, idlowbyte, Constants.FUNCTION_REQ_STD, Constants.FLAG_STD, Constants.CMD_LIGHT_CHG, newStep);
122        // send
123        tc.sendInsteonSequence(out, null);
124
125        if (log.isDebugEnabled()) {
126            log.debug("sendIntensity({}) addr {}{}{} newStep {}", intensity, idhighbyte, idmiddlebyte, idlowbyte, newStep);
127        }
128
129        lastOutputStep = newStep;
130    }
131
132    /**
133     * Number of steps from dim to bright is maintained in specific
134     * SerialTrafficController implementation
135     */
136    @Override
137    protected int getNumberOfSteps() {
138        return maxDimStep;
139    }
140
141    /**
142     * Send a On/Off Command to the hardware
143     */
144    @Override
145    protected void sendOnOffCommand(int newState) {
146        if (log.isDebugEnabled()) {
147            log.debug("start sendOnOff({}) Current: {}", newState, mState);
148        }
149
150        // figure out command 
151        int command1;
152        if (newState == ON) {
153            command1 = Constants.CMD_LIGHT_ON_FAST;
154        } else if (newState == OFF) {
155            command1 = Constants.CMD_LIGHT_OFF_FAST;
156        } else {
157            log.warn("illegal state requested for Light: {}", getSystemName());
158            return;
159        }
160
161        if (log.isDebugEnabled()) {
162            log.debug("set state {} {}", newState, getSystemName());
163        }
164
165        // create output sequence of just address and function together
166        InsteonSequence out = new InsteonSequence();
167        out.addFunction(idhighbyte, idmiddlebyte, idlowbyte, Constants.FUNCTION_REQ_STD, Constants.FLAG_STD, command1, 0);
168        // send
169        tc.sendInsteonSequence(out, null);
170
171        if (log.isDebugEnabled()) {
172            log.debug("end sendOnOff({})  insteon {}.{}.{} cmd1: {}", newState, StringUtil.twoHexFromInt(idhighbyte), StringUtil.twoHexFromInt(idmiddlebyte), StringUtil.twoHexFromInt(idlowbyte), command1);
173        }
174    }
175
176    private final static Logger log = LoggerFactory.getLogger(SpecificInsteonLight.class);
177}
178
179