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