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