]> git.basschouten.com Git - openhab-addons.git/blob
e8dc992e515c6d6eb49cf79d3b1c850ef97dff1e
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.russound.internal.rio.controller;
14
15 import java.util.regex.Matcher;
16 import java.util.regex.Pattern;
17
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.openhab.binding.russound.internal.net.SocketSession;
20 import org.openhab.binding.russound.internal.net.SocketSessionListener;
21 import org.openhab.binding.russound.internal.rio.AbstractRioProtocol;
22 import org.openhab.binding.russound.internal.rio.RioConstants;
23 import org.openhab.binding.russound.internal.rio.RioHandlerCallback;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * This is the protocol handler for the Russound controller. This handler will issue the protocol commands and will
29  * process the responses from the Russound system.
30  *
31  * @author Tim Roberts - Initial contribution
32  */
33 class RioControllerProtocol extends AbstractRioProtocol {
34     // logger
35     private final Logger logger = LoggerFactory.getLogger(RioControllerProtocol.class);
36
37     /**
38      * The controller identifier
39      */
40     private final int controller;
41
42     // Protocol constants
43     private static final String CTL_TYPE = "type";
44     private static final String CTL_IPADDRESS = "ipaddress";
45     private static final String CTL_MACADDRESS = "macaddress";
46
47     // Response patterns
48     private static final Pattern RSP_CONTROLLERNOTIFICATION = Pattern
49             .compile("(?i)^[SN] C\\[(\\d+)\\]\\.(\\w+)=\"(.*)\"$");
50
51     /**
52      * Constructs the protocol handler from given parameters
53      *
54      * @param controller the controller identifier
55      * @param session a non-null {@link SocketSession} (may be connected or disconnected)
56      * @param callback a non-null {@link RioHandlerCallback} to callback
57      */
58     RioControllerProtocol(int controller, SocketSession session, RioHandlerCallback callback) {
59         super(session, callback);
60         this.controller = controller;
61     }
62
63     /**
64      * Helper method to issue post online commands
65      */
66     void postOnline() {
67         refreshControllerType();
68         refreshControllerIpAddress();
69         refreshControllerMacAddress();
70     }
71
72     /**
73      * Issues a get command for the controller given the keyname
74      *
75      * @param keyName a non-null, non-empty keyname to get
76      * @throws IllegalArgumentException if name is null or an empty string
77      */
78     private void refreshControllerKey(String keyName) {
79         if (keyName == null || keyName.trim().length() == 0) {
80             throw new IllegalArgumentException("keyName cannot be null or empty");
81         }
82         sendCommand("GET C[" + controller + "]." + keyName);
83     }
84
85     /**
86      * Refreshes the controller IP address
87      */
88     void refreshControllerIpAddress() {
89         refreshControllerKey(CTL_IPADDRESS);
90     }
91
92     /**
93      * Refreshes the controller MAC address
94      */
95     void refreshControllerMacAddress() {
96         refreshControllerKey(CTL_MACADDRESS);
97     }
98
99     /**
100      * Refreshes the controller Model Type
101      */
102     void refreshControllerType() {
103         refreshControllerKey(CTL_TYPE);
104     }
105
106     /**
107      * Handles any controller notifications returned by the russound system
108      *
109      * @param m a non-null matcher
110      * @param resp a possibly null, possibly empty response
111      */
112     private void handleControllerNotification(Matcher m, String resp) {
113         if (m == null) {
114             throw new IllegalArgumentException("m (matcher) cannot be null");
115         }
116         if (m.groupCount() == 3) {
117             try {
118                 final int notifyController = Integer.parseInt(m.group(1));
119                 if (notifyController != controller) {
120                     return;
121                 }
122
123                 final String key = m.group(2).toLowerCase();
124                 final String value = m.group(3);
125
126                 switch (key) {
127                     case CTL_TYPE:
128                         setProperty(RioConstants.PROPERTY_CTLTYPE, value);
129                         break;
130
131                     case CTL_IPADDRESS:
132                         setProperty(RioConstants.PROPERTY_CTLIPADDRESS, value);
133                         break;
134
135                     case CTL_MACADDRESS:
136                         setProperty(RioConstants.PROPERTY_CTLMACADDRESS, value);
137                         break;
138
139                     default:
140                         logger.debug("Unknown controller notification: '{}'", resp);
141                         break;
142                 }
143             } catch (NumberFormatException e) {
144                 logger.debug("Invalid Controller Notification (controller not a parsable integer): '{}')", resp);
145             }
146         } else {
147             logger.debug("Invalid Controller Notification response: '{}'", resp);
148         }
149     }
150
151     /**
152      * Implements {@link SocketSessionListener#responseReceived(String)} to try to process the response from the
153      * russound system. This response may be for other protocol handler - so ignore if we don't recognize the response.
154      *
155      * @param a possibly null, possibly empty response
156      */
157     @Override
158     public void responseReceived(@Nullable String response) {
159         if (response == null || response.isEmpty()) {
160             return;
161         }
162
163         final Matcher m = RSP_CONTROLLERNOTIFICATION.matcher(response);
164         if (m.matches()) {
165             handleControllerNotification(m, response);
166             return;
167         }
168     }
169 }