001package jmri.jmrix.powerline; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006/** 007 * Implementation of the Light class for X10-based subclasses. 008 * <p> 009 * Uses X10 dimming commands to set intensity unless the value is 0.0 or 1.0, in 010 * which case it uses on/off commands only. 011 * <p> 012 * Since the dim/bright step of the hardware is unknown then the Light object is 013 * first created, the first time the intensity (not state) is set to other than 014 * 0.0 or 1.0, the output is run to it's maximum dim or bright step so that we 015 * know the count is right. 016 * <p> 017 * Keeps track of the controller's "dim count", and if not certain forces it to 018 * zero to be sure. 019 * 020 * @author Dave Duchamp Copyright (C) 2004 021 * @author Bob Jacobsen Copyright (C) 2006, 2007, 2008, 2009, 2010 022 * @author Ken Cameron Copyright (C) 2009, 2010 Converted to multiple connection 023 * @author kcameron Copyright (C) 2011 024 */ 025public class SerialX10Light extends jmri.jmrix.powerline.SerialLight { 026 027 // System-dependent instance variables 028 /** 029 * Current output step 0 to maxDimStep. 030 * <p> 031 * -1 means unknown 032 */ 033 protected int lastOutputStep = -1; 034 035 /** 036 * Largest X10 dim step number available. 037 * <p> 038 * Loaded from SerialTrafficController.getNumberOfIntensitySteps(); 039 */ 040 protected int maxDimStep = 0; 041 042 /** 043 * Create a Light object, with only system name. 044 * <p> 045 * 'systemName' was previously validated in SerialLightManager 046 * @param systemName system name 047 * @param tc traffic controller 048 */ 049 public SerialX10Light(String systemName, SerialTrafficController tc) { 050 super(systemName, tc); 051 this.tc = tc; 052 maxDimStep = tc.getNumberOfIntensitySteps(); 053 } 054 055 /** 056 * Create a Light object, with both system and user names. 057 * <p> 058 * 'systemName' was previously validated in SerialLightManager 059 * @param systemName system name 060 * @param tc traffic controller 061 * @param userName user name 062 */ 063 public SerialX10Light(String systemName, SerialTrafficController tc, String userName) { 064 super(systemName, tc, userName); 065 this.tc = tc; 066 maxDimStep = tc.getNumberOfIntensitySteps(); 067 } 068 069 SerialTrafficController tc = null; 070 071 /** 072 * Optionally, force control to a known "dim count". 073 * <p> 074 * Invoked the first time intensity is set. 075 * 076 * @param intensity The next intensity value that will be set 077 */ 078 @Override 079 protected void initIntensity(double intensity) { 080 if (log.isDebugEnabled()) { 081 log.debug("initIntensity({})", intensity); 082 } 083 084 maxDimStep = tc.getNumberOfIntensitySteps(); 085 086 // Set initial state 087 // see if going to stabilize at on or off 088 if (intensity <= 0.5) { 089 // going to low, send a real off 090 X10Sequence out3 = new X10Sequence(); 091 out3.addAddress(housecode, devicecode); 092 out3.addFunction(housecode, X10Sequence.FUNCTION_OFF, 0); 093 tc.sendX10Sequence(out3, null); 094 // going to low, send max dim count low 095 X10Sequence out2 = new X10Sequence(); 096 out2.addAddress(housecode, devicecode); 097 out2.addFunction(housecode, X10Sequence.FUNCTION_DIM, maxDimStep); 098 tc.sendX10Sequence(out2, null); 099 100 lastOutputStep = 0; 101 102 if (log.isDebugEnabled()) { 103 log.debug("initIntensity: sent dim reset"); 104 } 105 } else { 106 // going to high, send a real on 107 X10Sequence out3 = new X10Sequence(); 108 out3.addAddress(housecode, devicecode); 109 out3.addFunction(housecode, X10Sequence.FUNCTION_ON, 0); 110 tc.sendX10Sequence(out3, null); 111 // going to high, send max dim count high 112 X10Sequence out2 = new X10Sequence(); 113 out2.addAddress(housecode, devicecode); 114 out2.addFunction(housecode, X10Sequence.FUNCTION_BRIGHT, maxDimStep); 115 // send 116 tc.sendX10Sequence(out2, null); 117 118 lastOutputStep = maxDimStep; 119 120 if (log.isDebugEnabled()) { 121 log.debug("initIntensity: sent bright reset"); 122 } 123 } 124 } 125 126 /** 127 * Send a Dim/Bright commands to the X10 hardware to reach a specific 128 * intensity. Acts immediately, and changes no general state. 129 * <p> 130 * This sends "Dim" commands. 131 */ 132 @Override 133 protected void sendIntensity(double intensity) { 134 if (log.isDebugEnabled()) { 135 log.debug("sendIntensity({}) lastOutputStep: {} maxDimStep: {}", intensity, lastOutputStep, maxDimStep); 136 } 137 138 // if we don't know the dim count, force it to a value. 139// if (lastOutputStep < 0) initIntensity(intensity); 140 // find the new correct dim count 141 int newStep = (int) Math.round(intensity * maxDimStep); // maxDimStep is full on, 0 is full off, etc 142 143 // check for errors 144 if ((newStep < 0) || (newStep > maxDimStep)) { 145 log.error("newStep wrong: {} intensity: {}", newStep, intensity); 146 } 147 148 if (newStep == 0) { 149 // nothing to do! 150 if (log.isDebugEnabled()) { 151 log.debug("intensity {} within current step, return", intensity); 152 } 153 return; 154 155 } 156 157 // create output sequence of address, then function 158 X10Sequence out = new X10Sequence(); 159 out.addExtData(housecode, devicecode, X10Sequence.EXTCMD_DIM, newStep); 160 // send 161 tc.sendX10Sequence(out, null); 162 lastOutputStep = newStep; 163 164 if (log.isDebugEnabled()) { 165 log.debug("sendIntensity({}) house {} device {} newStep: {}", intensity, X10Sequence.houseValueToText(housecode), devicecode, newStep); 166 } 167 } 168 169 /** 170 * Number of steps from dim to bright is maintained in specific 171 * SerialTrafficController implementation 172 */ 173 @Override 174 protected int getNumberOfSteps() { 175 return tc.getNumberOfIntensitySteps(); 176 } 177 178 /** 179 * Send a On/Off Command to the hardware 180 */ 181 @Override 182 protected void sendOnOffCommand(int newState) { 183 if (log.isDebugEnabled()) { 184 log.debug("sendOnOff({}) Current: {}", newState, mState); 185 } 186 187 // figure out command 188 int function; 189 double newDim; 190 if (newState == ON) { 191 function = X10Sequence.FUNCTION_ON; 192 newDim = 1; 193 } else if (newState == OFF) { 194 function = X10Sequence.FUNCTION_OFF; 195 newDim = 0; 196 } else { 197 log.warn("illegal state requested for Light: {}", getSystemName()); 198 return; 199 } 200 201 log.debug("set state {} house {} device {}", newState, housecode, devicecode); 202 203 // create output sequence of address, then function 204 X10Sequence out = new X10Sequence(); 205 out.addAddress(housecode, devicecode); 206 out.addFunction(housecode, function, 0); 207 // send 208 tc.sendX10Sequence(out, null); 209 210 if (log.isDebugEnabled()) { 211 log.debug("sendOnOff({}) house {} device {} funct: {}", newDim, X10Sequence.houseValueToText(housecode), devicecode, function); 212 } 213 } 214 215 private final static Logger log = LoggerFactory.getLogger(SerialX10Light.class); 216} 217 218