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