001package jmri.jmrix.powerline.simulator; 002 003import jmri.Sensor; 004import jmri.jmrix.powerline.SerialReply; 005import jmri.jmrix.powerline.SerialTrafficController; 006import jmri.jmrix.powerline.X10Sequence; 007import jmri.util.StringUtil; 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011/** 012 * Manage the system-specific Sensor implementation. 013 * <p> 014 * System names are "PSann", where a is the unit id, nn is the unit number 015 * without padding. 016 * <p> 017 * Sensors are numbered from 1. 018 * 019 * @author Bob Jacobsen Copyright (C) 2003, 2006, 2007, 2008, 2009 020 * @author Ken Cameron, (C) 2009, 2010 sensors from poll replies Converted to 021 * multiple connection 022 * @author kcameron Copyright (C) 2011 023 */ 024public class SpecificSensorManager extends jmri.jmrix.powerline.SerialSensorManager { 025 026 public SpecificSensorManager(SerialTrafficController tc) { 027 super(tc); 028 this.tc = tc; 029 } 030 031 SerialTrafficController tc = null; 032 033 /** 034 * Process a reply to a poll of Sensors of one node 035 */ 036 @Override 037 public synchronized void reply(SerialReply r) { 038 // process for updates 039 processForPollReq(r); 040 } 041 042 private void processForPollReq(SerialReply l) { 043 if ((l.getElement(0) & 0xFF) == Constants.HEAD_STX) { 044 // process the POLL_REQ_X10 and update/create sensors as needed 045 if (((l.getElement(1) & 0xFF) == Constants.POLL_REQ_X10) && l.getNumDataElements() == 4) { 046 // valid poll of X10 message 047 int dat = l.getElement(2) & 0xFF; 048 int flag = l.getElement(3) & 0xFF; 049 String newHouseCode = X10Sequence.houseValueToText(X10Sequence.decode((dat >> 4) & 0x0F)); 050 int newCmdCode = dat & 0x0F; 051 int newAddrCode = -1; 052 Sensor sensor = null; 053 if ((flag & Constants.FLAG_BIT_X10_CMDUNIT) == Constants.FLAG_X10_RECV_CMD) { 054 if ((newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_ON)) { 055 // some sort of 'global' command, process for all matching the house code 056 057 getNamedBeanSet().forEach(sensorInSet -> { 058 String sName = sensorInSet.getSystemName(); 059 if (newHouseCode.compareTo(tc.getAdapterMemo().getSerialAddress().houseCodeFromSystemName(sName)) == 0) { 060 try { 061 if (newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF) { 062 sensorInSet.setKnownState(Sensor.INACTIVE); 063 } else { 064 sensorInSet.setKnownState(Sensor.ACTIVE); 065 } 066 } catch (jmri.JmriException e) { 067 if (newCmdCode == X10Sequence.FUNCTION_ALL_LIGHTS_OFF || newCmdCode == X10Sequence.FUNCTION_ALL_UNITS_OFF) { 068 log.error("Exception setting {} sensor INACTIVE", sName, e); 069 } else { 070 log.error("Exception setting {} sensor ACTIVE", sName, e); 071 } 072 } 073 } 074 }); 075 } else { 076 if (newHouseCode != null && newAddrCode > 0) { 077 String sysName = getSystemPrefix() + "S" + newHouseCode + newAddrCode; 078 sensor = provideSensor(sysName); 079 if (newCmdCode == X10Sequence.FUNCTION_ON || newCmdCode == X10Sequence.FUNCTION_BRIGHT || newCmdCode == X10Sequence.FUNCTION_STATUS_ON) { 080 try { 081 sensor.setKnownState(Sensor.ACTIVE); 082 } catch (jmri.JmriException e) { 083 log.error("Exception setting {} sensor ACTIVE", sysName, e); 084 } 085 } 086 if (newCmdCode == X10Sequence.FUNCTION_OFF || newCmdCode == X10Sequence.FUNCTION_DIM || newCmdCode == X10Sequence.FUNCTION_STATUS_OFF) { 087 try { 088 sensor.setKnownState(Sensor.INACTIVE); 089 } catch (jmri.JmriException e) { 090 log.error("Exception setting {} sensor INACTIVE", sysName, e); 091 } 092 } 093 } 094 } 095 } 096 } else if (((l.getElement(1) & 0xFF) == Constants.POLL_REQ_STD) && l.getNumDataElements() == 11) { 097 // figure how to decode an standard Insteon poll command 098 int highAddr = l.getElement(5) & 0xFF; 099 int middleAddr = l.getElement(6) & 0xFF; 100 int lowAddr = l.getElement(7) & 0xFF; 101 int cmd1 = l.getElement(9) & 0xFF; 102 StringBuilder sysName = new StringBuilder(); 103 sysName.append(getSystemPrefix()); 104 sysName.append("S"); 105 sysName.append(StringUtil.twoHexFromInt(highAddr)); 106 sysName.append("."); 107 sysName.append(StringUtil.twoHexFromInt(middleAddr)); 108 sysName.append("."); 109 sysName.append(StringUtil.twoHexFromInt(lowAddr)); 110 Sensor sensor = null; 111 try { 112 sensor = provideSensor(new String(sysName)); 113 } catch(java.lang.IllegalArgumentException iae){ 114 // if provideSensor fails, it will throw an IllegalArgumentException, so catch that,log it if debugging is enabled, and then re-throw it. 115 log.debug("Attempt access sensor {} failed", sysName); 116 throw iae; 117 } 118 if (cmd1 == Constants.CMD_LIGHT_ON_FAST || cmd1 == Constants.CMD_LIGHT_ON_RAMP) { 119 try { 120 sensor.setKnownState(Sensor.ACTIVE); 121 } catch (jmri.JmriException e) { 122 log.error("Exception setting {} sensor ACTIVE", sysName, e); 123 } 124 } 125 if (cmd1 == Constants.CMD_LIGHT_OFF_FAST || cmd1 == Constants.CMD_LIGHT_OFF_RAMP) { 126 try { 127 sensor.setKnownState(Sensor.INACTIVE); 128 } catch (jmri.JmriException e) { 129 log.error("Exception setting {} sensor INACTIVE", sysName, e); 130 } 131 } 132 } 133 } 134 } 135 136 private final static Logger log = LoggerFactory.getLogger(SpecificSensorManager.class); 137} 138