2 * Copyright (c) 2010-2024 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.denonmarantz.internal.connector;
15 import static org.openhab.binding.denonmarantz.internal.DenonMarantzBindingConstants.DB_OFFSET;
17 import java.math.BigDecimal;
18 import java.math.RoundingMode;
19 import java.util.concurrent.ScheduledExecutorService;
21 import org.openhab.binding.denonmarantz.internal.DenonMarantzState;
22 import org.openhab.binding.denonmarantz.internal.UnsupportedCommandTypeException;
23 import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
24 import org.openhab.core.library.types.DecimalType;
25 import org.openhab.core.library.types.IncreaseDecreaseType;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.library.types.PercentType;
28 import org.openhab.core.library.types.StringType;
29 import org.openhab.core.types.Command;
30 import org.openhab.core.types.RefreshType;
33 * Abstract class containing common functionality for the connectors.
35 * @author Jan-Willem Veldhuis - Initial contribution
37 public abstract class DenonMarantzConnector {
39 private static final BigDecimal POINTFIVE = new BigDecimal("0.5");
40 protected ScheduledExecutorService scheduler;
41 protected DenonMarantzState state;
42 protected DenonMarantzConfiguration config;
44 public abstract void connect();
46 public abstract void dispose();
48 protected abstract void internalSendCommand(String command);
50 public void sendCustomCommand(Command command) throws UnsupportedCommandTypeException {
52 if (command instanceof StringType) {
53 cmd = command.toString();
55 throw new UnsupportedCommandTypeException();
57 internalSendCommand(cmd);
60 public void sendInputCommand(Command command, int zone) throws UnsupportedCommandTypeException {
69 zonePrefix = "Z" + zone;
72 throw new UnsupportedCommandTypeException("Zone must be in range [1-4], zone: " + zone);
74 String cmd = zonePrefix;
75 if (command instanceof StringType) {
76 cmd += command.toString();
77 } else if (command instanceof RefreshType) {
80 throw new UnsupportedCommandTypeException();
82 internalSendCommand(cmd);
85 public void sendSurroundProgramCommand(Command command) throws UnsupportedCommandTypeException {
87 if (command instanceof RefreshType) {
90 throw new UnsupportedCommandTypeException();
92 internalSendCommand(cmd);
95 public void sendMuteCommand(Command command, int zone) throws UnsupportedCommandTypeException {
96 if (zone < 1 || zone > 4) {
97 throw new UnsupportedCommandTypeException("Zone must be in range [1-4], zone: " + zone);
99 StringBuilder sb = new StringBuilder();
101 sb.append("Z").append(zone);
104 String cmd = sb.toString();
105 if (command == OnOffType.ON) {
107 } else if (command == OnOffType.OFF) {
109 } else if (command instanceof RefreshType) {
112 throw new UnsupportedCommandTypeException();
114 internalSendCommand(cmd);
117 public void sendPowerCommand(Command command, int zone) throws UnsupportedCommandTypeException {
129 zonePrefix = "Z" + zone;
132 throw new UnsupportedCommandTypeException("Zone must be in range [0-4], zone: " + zone);
134 String cmd = zonePrefix;
135 if (command == OnOffType.ON) {
137 } else if (command == OnOffType.OFF) {
138 cmd += (zone == 0) ? "STANDBY" : "OFF";
139 } else if (command instanceof RefreshType) {
142 throw new UnsupportedCommandTypeException();
144 internalSendCommand(cmd);
147 public void sendVolumeCommand(Command command, int zone) throws UnsupportedCommandTypeException {
156 zonePrefix = "Z" + zone;
159 throw new UnsupportedCommandTypeException("Zone must be in range [1-4], zone: " + zone);
161 String cmd = zonePrefix;
162 if (command instanceof RefreshType) {
164 } else if (command == IncreaseDecreaseType.INCREASE) {
166 } else if (command == IncreaseDecreaseType.DECREASE) {
168 } else if (command instanceof DecimalType decimalCommand) {
169 cmd += toDenonValue(decimalCommand);
170 } else if (command instanceof PercentType percentCommand) {
171 cmd += percentToDenonValue(percentCommand.toBigDecimal());
173 throw new UnsupportedCommandTypeException();
175 internalSendCommand(cmd);
178 public void sendVolumeDbCommand(Command command, int zone) throws UnsupportedCommandTypeException {
179 Command dbCommand = command;
180 if (dbCommand instanceof PercentType) {
181 throw new UnsupportedCommandTypeException();
182 } else if (dbCommand instanceof DecimalType) {
183 // convert dB to 'normal' volume by adding the offset of 80
184 dbCommand = new DecimalType(((DecimalType) command).toBigDecimal().add(DB_OFFSET));
186 sendVolumeCommand(dbCommand, zone);
189 protected String toDenonValue(DecimalType number) {
190 String dbString = String.valueOf(number.intValue());
191 BigDecimal num = number.toBigDecimal();
192 if (num.compareTo(BigDecimal.TEN) == -1) {
193 dbString = "0" + dbString;
195 if (num.remainder(BigDecimal.ONE).equals(POINTFIVE)) {
196 dbString = dbString + "5";
201 protected String percentToDenonValue(BigDecimal pct) {
202 // Round to nearest number divisible by 0.5
203 BigDecimal percent = pct.divide(POINTFIVE).setScale(0, RoundingMode.UP).multiply(POINTFIVE)
204 .min(config.getMainVolumeMax()).max(BigDecimal.ZERO);
206 return toDenonValue(new DecimalType(percent));