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