]> git.basschouten.com Git - openhab-addons.git/blob
1c030f19518bf7c36ad8d8242a7fef4a7d5ed3a1
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.monopriceaudio.internal.communication;
14
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.regex.Matcher;
20 import java.util.regex.Pattern;
21 import java.util.stream.IntStream;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.binding.monopriceaudio.internal.configuration.MonopriceAudioThingConfiguration;
25 import org.openhab.binding.monopriceaudio.internal.dto.MonopriceAudioZoneDTO;
26 import org.openhab.core.types.StateOption;
27
28 /**
29  * The {@link AmplifierModel} is responsible for mapping low level communications for each supported amplifier model.
30  *
31  * @author Michael Lobstein - Initial contribution
32  */
33 @NonNullByDefault
34 public enum AmplifierModel {
35
36     // Monoprice 10761/Dayton Audio DAX66
37     MONOPRICE("<", "\r", "?", "", "#>", "PR", "CH", "VO", "MU", "TR", "BS", "BL", "DT", 38, -7, 7, 7, -10, 10, 10, 18,
38             6, true, List.of("11", "12", "13", "14", "15", "16", "21", "22", "23", "24", "25", "26", "31", "32", "33",
39                     "34", "35", "36")) {
40         @Override
41         public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
42             return getMonopriceZoneData(newZoneData);
43         }
44
45         @Override
46         public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
47             return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
48                     new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
49                     new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6));
50         }
51     },
52     // Monoprice 44519 4 zone variant
53     MONOPRICE4("<", "\r", "?", "", "#>", "PR", "CH", "VO", "MU", "TR", "BS", "BL", "DT", 38, -7, 7, 7, -10, 10, 10, 12,
54             6, true, List.of("11", "12", "13", "14", "21", "22", "23", "24", "31", "32", "33", "34")) {
55         @Override
56         public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
57             return getMonopriceZoneData(newZoneData);
58         }
59
60         @Override
61         public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
62             return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
63                     new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
64                     new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6));
65         }
66     },
67     // Dayton Audio DAX88
68     DAX88("<", "\r", "?", "", ">", "PR", "CH", "VO", "MU", "TR", "BS", "BL", "DT", 38, -12, 12, 12, -10, 10, 10, 8, 8,
69             true, List.of("01", "02", "03", "04", "05", "06", "07", "08")) {
70         @Override
71         public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
72             return getMonopriceZoneData(newZoneData);
73         }
74
75         @Override
76         public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
77             return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
78                     new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
79                     new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6),
80                     new StateOption("7", config.inputLabel7), new StateOption("8", config.inputLabel8));
81         }
82     },
83     MONOPRICE70("!", "+\r", "?", "ZS", "?", "PR", "IS", "VO", "MU", "TR", "BS", "BA", "", 38, -7, 7, 7, -32, 31, 32, 6,
84             2, false, List.of("1", "2", "3", "4", "5", "6")) {
85         @Override
86         public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
87             final MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
88
89             Matcher matcher = MONOPRICE70_PATTERN.matcher(newZoneData);
90             if (matcher.find()) {
91                 zoneData.setZone(matcher.group(1));
92                 zoneData.setVolume(Integer.parseInt(matcher.group(2)));
93                 zoneData.setPower(matcher.group(3));
94                 zoneData.setMute(matcher.group(4));
95                 zoneData.setSource(matcher.group(5));
96                 return zoneData;
97             }
98
99             matcher = MONOPRICE70_TREB_PATTERN.matcher(newZoneData);
100             if (matcher.find()) {
101                 zoneData.setZone(matcher.group(1));
102                 zoneData.setTreble(Integer.parseInt(matcher.group(2)));
103                 return zoneData;
104             }
105
106             matcher = MONOPRICE70_BASS_PATTERN.matcher(newZoneData);
107             if (matcher.find()) {
108                 zoneData.setZone(matcher.group(1));
109                 zoneData.setBass(Integer.parseInt(matcher.group(2)));
110                 return zoneData;
111             }
112
113             matcher = MONOPRICE70_BALN_PATTERN.matcher(newZoneData);
114             if (matcher.find()) {
115                 zoneData.setZone(matcher.group(1));
116                 zoneData.setBalance(Integer.parseInt(matcher.group(2)));
117                 return zoneData;
118             }
119
120             return zoneData;
121         }
122
123         @Override
124         public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
125             return List.of(new StateOption("0", config.inputLabel1), new StateOption("1", config.inputLabel2));
126         }
127     },
128     XANTECH("!", "+\r", "?", "ZD", "#", "PR", "SS", "VO", "MU", "TR", "BS", "BL", "", 38, -7, 7, 7, -32, 31, 32, 16, 8,
129             false, List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16")) {
130         @Override
131         public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
132             final MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
133             final Matcher matcher = XANTECH_PATTERN.matcher(newZoneData);
134
135             if (matcher.find()) {
136                 zoneData.setZone(matcher.group(1));
137                 zoneData.setPower(matcher.group(2));
138                 zoneData.setSource(matcher.group(3));
139                 zoneData.setVolume(Integer.parseInt(matcher.group(4)));
140                 zoneData.setMute(matcher.group(5));
141                 zoneData.setTreble(Integer.parseInt(matcher.group(6)));
142                 zoneData.setBass(Integer.parseInt(matcher.group(7)));
143                 zoneData.setBalance(Integer.parseInt(matcher.group(8)));
144                 zoneData.setKeypad(matcher.group(9));
145                 zoneData.setPage(matcher.group(10));
146             }
147             return zoneData;
148         }
149
150         @Override
151         public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
152             return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
153                     new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
154                     new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6),
155                     new StateOption("7", config.inputLabel7), new StateOption("8", config.inputLabel8));
156         }
157     };
158
159     // Used by 10761/DAX66 and DAX88
160     private static MonopriceAudioZoneDTO getMonopriceZoneData(String newZoneData) {
161         final MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
162         final Matcher matcher = MONOPRICE_PATTERN.matcher(newZoneData);
163
164         if (matcher.find()) {
165             zoneData.setZone(matcher.group(1));
166             zoneData.setPage(matcher.group(2));
167             zoneData.setPower(matcher.group(3));
168             zoneData.setMute(matcher.group(4));
169             zoneData.setDnd(matcher.group(5));
170             zoneData.setVolume(Integer.parseInt(matcher.group(6)));
171             zoneData.setTreble(Integer.parseInt(matcher.group(7)));
172             zoneData.setBass(Integer.parseInt(matcher.group(8)));
173             zoneData.setBalance(Integer.parseInt(matcher.group(9)));
174             zoneData.setSource(matcher.group(10));
175             zoneData.setKeypad(matcher.group(11));
176         }
177         return zoneData;
178     }
179
180     // Monoprice 10761/DAX66 status string: #>1200010000130809100601
181     // DAX88 status string is the same but does not have leading '#': >xxaabbccddeeffgghhiijj
182     private static final Pattern MONOPRICE_PATTERN = Pattern
183             .compile("^#?>(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})");
184
185     // Monoprice 31028 / PAM1270 status string: ?6ZS VO8 PO1 MU0 IS0+ (does not include treble, bass & balance)
186     private static final Pattern MONOPRICE70_PATTERN = Pattern
187             .compile("^\\?(\\d{1})ZS VO(\\d{1,2}) PO(\\d{1}) MU(\\d{1}) IS(\\d{1})+");
188     private static final Pattern MONOPRICE70_TREB_PATTERN = Pattern.compile("^\\?(\\d{1})TR(\\d{1,2})+");
189     private static final Pattern MONOPRICE70_BASS_PATTERN = Pattern.compile("^\\?(\\d{1})BS(\\d{1,2})+");
190     private static final Pattern MONOPRICE70_BALN_PATTERN = Pattern.compile("^\\?(\\d{1})BA(\\d{1,2})+");
191
192     // Xantech status string: #1ZS PR0 SS1 VO0 MU1 TR7 BS7 BA32 LS0 PS0+
193     private static final Pattern XANTECH_PATTERN = Pattern.compile(
194             "^#(\\d{1,2})ZS PR(\\d{1}) SS(\\d{1}) VO(\\d{1,2}) MU(\\d{1}) TR(\\d{1,2}) BS(\\d{1,2}) BA(\\d{1,2}) LS(\\d{1}) PS(\\d{1})+");
195
196     private final String cmdPrefix;
197     private final String cmdSuffix;
198     private final String queryPrefix;
199     private final String querySuffix;
200     private final String respPrefix;
201     private final String powerCmd;
202     private final String sourceCmd;
203     private final String volumeCmd;
204     private final String muteCmd;
205     private final String trebleCmd;
206     private final String bassCmd;
207     private final String balanceCmd;
208     private final String dndCmd;
209     private final int maxVol;
210     private final int minTone;
211     private final int maxTone;
212     private final int toneOffset;
213     private final int minBal;
214     private final int maxBal;
215     private final int balOffset;
216     private final int maxZones;
217     private final int numSources;
218     private final boolean padNumbers;
219     private final List<String> zoneIds;
220     private final Map<String, String> zoneIdMap;
221
222     private static final String ON_STR = "1";
223     private static final String OFF_STR = "0";
224
225     private static final String ON_STR_PAD = "01";
226     private static final String OFF_STR_PAD = "00";
227
228     /**
229      * Constructor for all the enum parameters
230      *
231      **/
232     AmplifierModel(String cmdPrefix, String cmdSuffix, String queryPrefix, String querySuffix, String respPrefix,
233             String powerCmd, String sourceCmd, String volumeCmd, String muteCmd, String trebleCmd, String bassCmd,
234             String balanceCmd, String dndCmd, int maxVol, int minTone, int maxTone, int toneOffset, int minBal,
235             int maxBal, int balOffset, int maxZones, int numSources, boolean padNumbers, List<String> zoneIds) {
236         this.cmdPrefix = cmdPrefix;
237         this.cmdSuffix = cmdSuffix;
238         this.queryPrefix = queryPrefix;
239         this.querySuffix = querySuffix;
240         this.respPrefix = respPrefix;
241         this.powerCmd = powerCmd;
242         this.sourceCmd = sourceCmd;
243         this.volumeCmd = volumeCmd;
244         this.muteCmd = muteCmd;
245         this.trebleCmd = trebleCmd;
246         this.bassCmd = bassCmd;
247         this.balanceCmd = balanceCmd;
248         this.dndCmd = dndCmd;
249         this.maxVol = maxVol;
250         this.minTone = minTone;
251         this.maxTone = maxTone;
252         this.toneOffset = toneOffset;
253         this.minBal = minBal;
254         this.maxBal = maxBal;
255         this.balOffset = balOffset;
256         this.maxZones = maxZones;
257         this.numSources = numSources;
258         this.padNumbers = padNumbers;
259         this.zoneIds = zoneIds;
260
261         // Build a map between the amp's physical zone IDs and the thing's logical zone names
262         final Map<String, String> zoneIdMap = new HashMap<>();
263         IntStream.range(0, zoneIds.size()).forEach(i -> zoneIdMap.put(zoneIds.get(i), "zone" + (i + 1)));
264         this.zoneIdMap = Collections.unmodifiableMap(zoneIdMap);
265     }
266
267     public abstract MonopriceAudioZoneDTO getZoneData(String newZoneData);
268
269     public abstract List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config);
270
271     public String getZoneIdFromZoneName(String zoneName) {
272         for (String zoneId : zoneIdMap.keySet()) {
273             if (zoneIdMap.get(zoneId).equals(zoneName)) {
274                 return zoneId;
275             }
276         }
277         return "";
278     }
279
280     public String getZoneName(String zoneId) {
281         String zoneName = zoneIdMap.get(zoneId);
282         if (zoneName != null) {
283             return zoneName;
284         } else {
285             return "";
286         }
287     }
288
289     public String getCmdPrefix() {
290         return cmdPrefix;
291     }
292
293     public String getQueryPrefix() {
294         return queryPrefix;
295     }
296
297     public String getQuerySuffix() {
298         return querySuffix;
299     }
300
301     public String getRespPrefix() {
302         return respPrefix;
303     }
304
305     public String getPowerCmd() {
306         return powerCmd;
307     }
308
309     public String getSourceCmd() {
310         return sourceCmd;
311     }
312
313     public String getVolumeCmd() {
314         return volumeCmd;
315     }
316
317     public String getMuteCmd() {
318         return muteCmd;
319     }
320
321     public String getTrebleCmd() {
322         return trebleCmd;
323     }
324
325     public String getBassCmd() {
326         return bassCmd;
327     }
328
329     public String getBalanceCmd() {
330         return balanceCmd;
331     }
332
333     public String getDndCmd() {
334         return dndCmd;
335     }
336
337     public int getMaxVol() {
338         return maxVol;
339     }
340
341     public int getMinTone() {
342         return minTone;
343     }
344
345     public int getMaxTone() {
346         return maxTone;
347     }
348
349     public int getMinBal() {
350         return minBal;
351     }
352
353     public int getMaxBal() {
354         return maxBal;
355     }
356
357     public int getBalOffset() {
358         return balOffset;
359     }
360
361     public int getToneOffset() {
362         return toneOffset;
363     }
364
365     public int getMaxZones() {
366         return maxZones;
367     }
368
369     public int getNumSources() {
370         return numSources;
371     }
372
373     public String getCmdSuffix() {
374         return cmdSuffix;
375     }
376
377     public List<String> getZoneIds() {
378         return zoneIds;
379     }
380
381     public String getFormattedValue(Integer value) {
382         return padNumbers ? String.format("%02d", value) : value.toString();
383     }
384
385     public String getOnStr() {
386         return padNumbers ? ON_STR_PAD : ON_STR;
387     }
388
389     public String getOffStr() {
390         return padNumbers ? OFF_STR_PAD : OFF_STR;
391     }
392 }