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