2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.monopriceaudio.internal.communication;
15 import java.util.HashMap;
16 import java.util.List;
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.monopriceaudio.internal.configuration.MonopriceAudioThingConfiguration;
23 import org.openhab.binding.monopriceaudio.internal.dto.MonopriceAudioZoneDTO;
24 import org.openhab.core.types.StateOption;
27 * The {@link AmplifierModel} is responsible for mapping low level communications for each supported amplifier model.
29 * @author Michael Lobstein - Initial contribution
32 public enum AmplifierModel {
34 // Monoprice 10761/Dayton Audio DAX66
35 MONOPRICE("<", "\r", "?", "", "#>", "PR", "CH", "VO", "MU", "TR", "BS", "BL", "DT", 38, -7, 7, 7, -10, 10, 10, 18,
36 6, true, List.of("11", "12", "13", "14", "15", "16", "21", "22", "23", "24", "25", "26", "31", "32", "33",
39 public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
40 return getMonopriceZoneData(newZoneData);
44 public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
45 return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
46 new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
47 new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6));
50 // Monoprice 44519 4 zone variant
51 MONOPRICE4("<", "\r", "?", "", "#>", "PR", "CH", "VO", "MU", "TR", "BS", "BL", "DT", 38, -7, 7, 7, -10, 10, 10, 12,
52 6, true, List.of("11", "12", "13", "14", "21", "22", "23", "24", "31", "32", "33", "34")) {
54 public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
55 return getMonopriceZoneData(newZoneData);
59 public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
60 return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
61 new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
62 new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6));
66 DAX88("<", "\r", "?", "", ">", "PR", "CH", "VO", "MU", "TR", "BS", "BL", "DT", 38, -12, 12, 12, -10, 10, 10, 8, 8,
67 true, List.of("01", "02", "03", "04", "05", "06", "07", "08")) {
69 public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
70 return getMonopriceZoneData(newZoneData);
74 public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
75 return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
76 new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
77 new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6),
78 new StateOption("7", config.inputLabel7), new StateOption("8", config.inputLabel8));
81 MONOPRICE70("!", "+\r", "?", "ZS", "?", "PR", "IS", "VO", "MU", "TR", "BS", "BA", "", 38, -7, 7, 7, -32, 31, 32, 6,
82 2, false, List.of("1", "2", "3", "4", "5", "6")) {
84 public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
85 MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
87 Matcher matcher = MONOPRICE70_PATTERN.matcher(newZoneData);
89 zoneData.setZone(matcher.group(1));
90 zoneData.setVolume(Integer.parseInt(matcher.group(2)));
91 zoneData.setPower(matcher.group(3));
92 zoneData.setMute(matcher.group(4));
93 zoneData.setSource(matcher.group(5));
97 matcher = MONOPRICE70_TREB_PATTERN.matcher(newZoneData);
99 zoneData.setZone(matcher.group(1));
100 zoneData.setTreble(Integer.parseInt(matcher.group(2)));
104 matcher = MONOPRICE70_BASS_PATTERN.matcher(newZoneData);
105 if (matcher.find()) {
106 zoneData.setZone(matcher.group(1));
107 zoneData.setBass(Integer.parseInt(matcher.group(2)));
111 matcher = MONOPRICE70_BALN_PATTERN.matcher(newZoneData);
112 if (matcher.find()) {
113 zoneData.setZone(matcher.group(1));
114 zoneData.setBalance(Integer.parseInt(matcher.group(2)));
122 public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
123 return List.of(new StateOption("0", config.inputLabel1), new StateOption("1", config.inputLabel2));
126 XANTECH("!", "+\r", "?", "ZD", "#", "PR", "SS", "VO", "MU", "TR", "BS", "BL", "", 38, -7, 7, 7, -32, 31, 32, 16, 8,
127 false, List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16")) {
129 public MonopriceAudioZoneDTO getZoneData(String newZoneData) {
130 MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
131 Matcher matcher = XANTECH_PATTERN.matcher(newZoneData);
133 if (matcher.find()) {
134 zoneData.setZone(matcher.group(1));
135 zoneData.setPower(matcher.group(2));
136 zoneData.setSource(matcher.group(3));
137 zoneData.setVolume(Integer.parseInt(matcher.group(4)));
138 zoneData.setMute(matcher.group(5));
139 zoneData.setTreble(Integer.parseInt(matcher.group(6)));
140 zoneData.setBass(Integer.parseInt(matcher.group(7)));
141 zoneData.setBalance(Integer.parseInt(matcher.group(8)));
142 zoneData.setKeypad(matcher.group(9));
143 zoneData.setPage(matcher.group(10));
149 public List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config) {
150 return List.of(new StateOption("1", config.inputLabel1), new StateOption("2", config.inputLabel2),
151 new StateOption("3", config.inputLabel3), new StateOption("4", config.inputLabel4),
152 new StateOption("5", config.inputLabel5), new StateOption("6", config.inputLabel6),
153 new StateOption("7", config.inputLabel7), new StateOption("8", config.inputLabel8));
157 // Used by 10761/DAX66 and DAX88
158 private static MonopriceAudioZoneDTO getMonopriceZoneData(String newZoneData) {
159 MonopriceAudioZoneDTO zoneData = new MonopriceAudioZoneDTO();
160 Matcher matcher = MONOPRICE_PATTERN.matcher(newZoneData);
162 if (matcher.find()) {
163 zoneData.setZone(matcher.group(1));
164 zoneData.setPage(matcher.group(2));
165 zoneData.setPower(matcher.group(3));
166 zoneData.setMute(matcher.group(4));
167 zoneData.setDnd(matcher.group(5));
168 zoneData.setVolume(Integer.parseInt(matcher.group(6)));
169 zoneData.setTreble(Integer.parseInt(matcher.group(7)));
170 zoneData.setBass(Integer.parseInt(matcher.group(8)));
171 zoneData.setBalance(Integer.parseInt(matcher.group(9)));
172 zoneData.setSource(matcher.group(10));
173 zoneData.setKeypad(matcher.group(11));
178 // Monoprice 10761/DAX66 status string: #>1200010000130809100601
179 // DAX88 status string is the same but does not have leading '#': >xxaabbccddeeffgghhiijj
180 private static final Pattern MONOPRICE_PATTERN = Pattern
181 .compile("^#?>(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})");
183 // Monoprice 31028 / PAM1270 status string: ?6ZS VO8 PO1 MU0 IS0+ (does not include treble, bass & balance)
184 private static final Pattern MONOPRICE70_PATTERN = Pattern
185 .compile("^\\?(\\d{1})ZS VO(\\d{1,2}) PO(\\d{1}) MU(\\d{1}) IS(\\d{1})+");
186 private static final Pattern MONOPRICE70_TREB_PATTERN = Pattern.compile("^\\?(\\d{1})TR(\\d{1,2})+");
187 private static final Pattern MONOPRICE70_BASS_PATTERN = Pattern.compile("^\\?(\\d{1})BS(\\d{1,2})+");
188 private static final Pattern MONOPRICE70_BALN_PATTERN = Pattern.compile("^\\?(\\d{1})BA(\\d{1,2})+");
190 // Xantech status string: #1ZS PR0 SS1 VO0 MU1 TR7 BS7 BA32 LS0 PS0+
191 private static final Pattern XANTECH_PATTERN = Pattern.compile(
192 "^#(\\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})+");
194 private String cmdPrefix;
195 private String cmdSuffix;
196 private String queryPrefix;
197 private String querySuffix;
198 private String respPrefix;
199 private String powerCmd;
200 private String sourceCmd;
201 private String volumeCmd;
202 private String muteCmd;
203 private String trebleCmd;
204 private String bassCmd;
205 private String balanceCmd;
206 private String dndCmd;
210 private int toneOffset;
213 private int balOffset;
214 private int maxZones;
215 private int numSources;
216 private boolean padNumbers;
217 private List<String> zoneIds;
218 private Map<String, String> zoneIdMap = new HashMap<>();
220 private static final String ON_STR = "1";
221 private static final String OFF_STR = "0";
223 private static final String ON_STR_PAD = "01";
224 private static final String OFF_STR_PAD = "00";
227 * Constructor for all the enum parameters
230 AmplifierModel(String cmdPrefix, String cmdSuffix, String queryPrefix, String querySuffix, String respPrefix,
231 String powerCmd, String sourceCmd, String volumeCmd, String muteCmd, String trebleCmd, String bassCmd,
232 String balanceCmd, String dndCmd, int maxVol, int minTone, int maxTone, int toneOffset, int minBal,
233 int maxBal, int balOffset, int maxZones, int numSources, boolean padNumbers, List<String> zoneIds) {
234 this.cmdPrefix = cmdPrefix;
235 this.cmdSuffix = cmdSuffix;
236 this.queryPrefix = queryPrefix;
237 this.querySuffix = querySuffix;
238 this.respPrefix = respPrefix;
239 this.powerCmd = powerCmd;
240 this.sourceCmd = sourceCmd;
241 this.volumeCmd = volumeCmd;
242 this.muteCmd = muteCmd;
243 this.trebleCmd = trebleCmd;
244 this.bassCmd = bassCmd;
245 this.balanceCmd = balanceCmd;
246 this.dndCmd = dndCmd;
247 this.maxVol = maxVol;
248 this.minTone = minTone;
249 this.maxTone = maxTone;
250 this.toneOffset = toneOffset;
251 this.minBal = minBal;
252 this.maxBal = maxBal;
253 this.balOffset = balOffset;
254 this.maxZones = maxZones;
255 this.numSources = numSources;
256 this.padNumbers = padNumbers;
257 this.zoneIds = zoneIds;
260 for (String zoneId : zoneIds) {
261 zoneIdMap.put(zoneId, "zone" + i);
266 public abstract MonopriceAudioZoneDTO getZoneData(String newZoneData);
268 public abstract List<StateOption> getSourceLabels(MonopriceAudioThingConfiguration config);
270 public String getZoneIdFromZoneName(String zoneName) {
271 for (String zoneId : zoneIdMap.keySet()) {
272 if (zoneIdMap.get(zoneId).equals(zoneName)) {
279 public String getZoneName(String zoneId) {
280 String zoneName = zoneIdMap.get(zoneId);
281 if (zoneName != null) {
288 public String getCmdPrefix() {
292 public String getQueryPrefix() {
296 public String getQuerySuffix() {
300 public String getRespPrefix() {
304 public String getPowerCmd() {
308 public String getSourceCmd() {
312 public String getVolumeCmd() {
316 public String getMuteCmd() {
320 public String getTrebleCmd() {
324 public String getBassCmd() {
328 public String getBalanceCmd() {
332 public String getDndCmd() {
336 public int getMaxVol() {
340 public int getMinTone() {
344 public int getMaxTone() {
348 public int getMinBal() {
352 public int getMaxBal() {
356 public int getBalOffset() {
360 public int getToneOffset() {
364 public int getMaxZones() {
368 public int getNumSources() {
372 public String getCmdSuffix() {
376 public List<String> getZoneIds() {
380 public String getFormattedValue(Integer value) {
382 return String.format("%02d", value);
384 return value.toString();
388 public String getOnStr() {
396 public String getOffStr() {