001package jmri.jmrix.powerline.insteon2412s; 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 * Value for retransmission 048 */ 049 int maxHops = Constants.FLAG_MAXHOPS_DEFAULT; 050 051 public int getMaxHops() { 052 return maxHops; 053 } 054 055 public void setMaxHops(int maxHops) { 056 if (maxHops <= Constants.FLAG_MASK_MAXHOPS && maxHops >= 0) { 057 this.maxHops = maxHops; 058 } else { 059 log.error("setMaxHops out of range: {}", maxHops); 060 } 061 } 062 063 /** 064 * Create a Light object, with only system name. 065 * <p> 066 * 'systemName' was previously validated in SerialLightManager 067 * @param systemName text for systemName of light 068 * @param tc tc for connection 069 */ 070 public SpecificInsteonLight(String systemName, SerialTrafficController tc) { 071 super(systemName, tc); 072 this.tc = tc; 073 // maxDimStep = tc.getNumberOfIntensitySteps(); 074 } 075 076 /** 077 * Create a Light object, with both system and user names. 078 * <p> 079 * 'systemName' was previously validated in SerialLightManager 080 * @param systemName text for systemName of light 081 * @param tc tc for connection 082 * @param userName text for userName of light 083 */ 084 public SpecificInsteonLight(String systemName, SerialTrafficController tc, String userName) { 085 super(systemName, tc, userName); 086 this.tc = tc; 087 //maxDimStep = tc.getNumberOfIntensitySteps(); 088 } 089 090 SerialTrafficController tc = null; 091 092 /** 093 * Invoked the first time intensity is set. 094 * 095 * @param intensity The next intensity value that will be set 096 */ 097 @Override 098 protected void initIntensity(double intensity) { 099 if (log.isDebugEnabled()) { 100 log.debug("initIntensity({})", intensity); 101 } 102 } 103 104 /** 105 * Send a Dim/Bright command to the Insteon hardware to reach a specific 106 * intensity. Acts immediately, and changes no general state. 107 * <p> 108 * This sends "Dim" commands. 109 */ 110 @Override 111 protected void sendIntensity(double intensity) { 112 if (log.isDebugEnabled()) { 113 log.debug("sendIntensity({}) lastOutputStep: {} maxDimStep: {}", intensity, lastOutputStep, maxDimStep); 114 } 115 116 // find the new correct dim count 117 int newStep = (int) Math.round(intensity * maxDimStep); // maxDimStep is full on, 0 is full off, etc 118 119 // check for errors 120 if ((newStep < 0) || (newStep > maxDimStep)) { 121 log.error("newStep wrong: {} intensity: {}", newStep, intensity); 122 } 123 124 // do we have any change to make 125 if (newStep == lastOutputStep) { 126 // nothing to do! 127 if (log.isDebugEnabled()) { 128 log.debug("intensity {} within current step, return", intensity); 129 } 130 return; 131 } 132 133 if (log.isDebugEnabled()) { 134 log.debug("function set Intensity {}", intensity); 135 } 136 137 // create output sequence of address, then function 138 InsteonSequence out = new InsteonSequence(); 139 out.addFunction(idhighbyte, idmiddlebyte, idlowbyte, Constants.FUNCTION_REQ_STD, (Constants.FLAG_STD | (maxHops << Constants.FLAG_SHIFT_HOPSLEFT) | maxHops), Constants.CMD_LIGHT_CHG, newStep); 140 // send 141 tc.sendInsteonSequence(out, null); 142 143 if (log.isDebugEnabled()) { 144 log.debug("sendIntensity({}) addr {}{}{} newStep {}", intensity, idhighbyte, idmiddlebyte, idlowbyte, newStep); 145 } 146 147 lastOutputStep = newStep; 148 } 149 150 /** 151 * Number of steps from dim to bright is maintained in specific 152 * SerialTrafficController implementation 153 */ 154 @Override 155 protected int getNumberOfSteps() { 156 return maxDimStep; 157 } 158 159 /** 160 * Send a On/Off Command to the hardware 161 */ 162 @Override 163 protected void sendOnOffCommand(int newState) { 164 if (log.isDebugEnabled()) { 165 log.debug("start sendOnOff({}) Current: {}", newState, mState); 166 } 167 168 // figure out command 169 int command1; 170 if (newState == ON) { 171 command1 = Constants.CMD_LIGHT_ON_FAST; 172 } else if (newState == OFF) { 173 command1 = Constants.CMD_LIGHT_OFF_FAST; 174 } else { 175 log.warn("illegal state requested for Light: {}", getSystemName()); 176 return; 177 } 178 179 if (log.isDebugEnabled()) { 180 log.debug("set state {} {}", newState, getSystemName()); 181 } 182 183 // create output sequence of just address and function together 184 InsteonSequence out = new InsteonSequence(); 185 out.addFunction(idhighbyte, idmiddlebyte, idlowbyte, Constants.FUNCTION_REQ_STD, (Constants.FLAG_STD | (maxHops << Constants.FLAG_SHIFT_HOPSLEFT) | maxHops), command1, 0); 186 // send 187 tc.sendInsteonSequence(out, null); 188 189 if (log.isDebugEnabled()) { 190 log.debug("end sendOnOff({}) insteon {}.{}.{} cmd1: {}", newState, StringUtil.twoHexFromInt(idhighbyte), StringUtil.twoHexFromInt(idmiddlebyte), StringUtil.twoHexFromInt(idlowbyte), command1); 191 } 192 } 193 194 private final static Logger log = LoggerFactory.getLogger(SpecificInsteonLight.class); 195}