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