]> git.basschouten.com Git - openhab-addons.git/blob
c9d99c0d5917a4241bdbfae25eb88909d5de0cc1
[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.denonmarantz.internal.connector;
14
15 import static org.openhab.binding.denonmarantz.internal.DenonMarantzBindingConstants.DB_OFFSET;
16
17 import java.math.BigDecimal;
18 import java.math.RoundingMode;
19 import java.util.concurrent.ScheduledExecutorService;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.denonmarantz.internal.DenonMarantzState;
23 import org.openhab.binding.denonmarantz.internal.UnsupportedCommandTypeException;
24 import org.openhab.binding.denonmarantz.internal.config.DenonMarantzConfiguration;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.IncreaseDecreaseType;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.PercentType;
29 import org.openhab.core.library.types.StringType;
30 import org.openhab.core.types.Command;
31 import org.openhab.core.types.RefreshType;
32
33 /**
34  * Abstract class containing common functionality for the connectors.
35  *
36  * @author Jan-Willem Veldhuis - Initial contribution
37  */
38 @NonNullByDefault
39 public abstract class DenonMarantzConnector {
40
41     private static final BigDecimal POINTFIVE = new BigDecimal("0.5");
42     protected ScheduledExecutorService scheduler;
43     protected DenonMarantzState state;
44     protected DenonMarantzConfiguration config;
45
46     public abstract void connect();
47
48     public abstract void dispose();
49
50     protected abstract void internalSendCommand(String command);
51
52     public DenonMarantzConnector(DenonMarantzConfiguration config, ScheduledExecutorService scheduler,
53             DenonMarantzState state) {
54         this.config = config;
55         this.scheduler = scheduler;
56         this.state = state;
57     }
58
59     public void sendCustomCommand(Command command) throws UnsupportedCommandTypeException {
60         String cmd;
61         if (command instanceof StringType) {
62             cmd = command.toString();
63         } else {
64             throw new UnsupportedCommandTypeException();
65         }
66         internalSendCommand(cmd);
67     }
68
69     public void sendInputCommand(Command command, int zone) throws UnsupportedCommandTypeException {
70         String zonePrefix;
71         switch (zone) {
72             case 1:
73                 zonePrefix = "SI";
74                 break;
75             case 2:
76             case 3:
77             case 4:
78                 zonePrefix = "Z" + zone;
79                 break;
80             default:
81                 throw new UnsupportedCommandTypeException("Zone must be in range [1-4], zone: " + zone);
82         }
83         String cmd = zonePrefix;
84         if (command instanceof StringType) {
85             cmd += command.toString();
86         } else if (command instanceof RefreshType) {
87             cmd += "?";
88         } else {
89             throw new UnsupportedCommandTypeException();
90         }
91         internalSendCommand(cmd);
92     }
93
94     public void sendSurroundProgramCommand(Command command) throws UnsupportedCommandTypeException {
95         String cmd = "MS";
96         if (command instanceof RefreshType) {
97             cmd += "?";
98         } else {
99             throw new UnsupportedCommandTypeException();
100         }
101         internalSendCommand(cmd);
102     }
103
104     public void sendMuteCommand(Command command, int zone) throws UnsupportedCommandTypeException {
105         if (zone < 1 || zone > 4) {
106             throw new UnsupportedCommandTypeException("Zone must be in range [1-4], zone: " + zone);
107         }
108         StringBuilder sb = new StringBuilder();
109         if (zone != 1) {
110             sb.append("Z").append(zone);
111         }
112         sb.append("MU");
113         String cmd = sb.toString();
114         if (command == OnOffType.ON) {
115             cmd += "ON";
116         } else if (command == OnOffType.OFF) {
117             cmd += "OFF";
118         } else if (command instanceof RefreshType) {
119             cmd += "?";
120         } else {
121             throw new UnsupportedCommandTypeException();
122         }
123         internalSendCommand(cmd);
124     }
125
126     public void sendPowerCommand(Command command, int zone) throws UnsupportedCommandTypeException {
127         String zonePrefix;
128         switch (zone) {
129             case 0:
130                 zonePrefix = "PW";
131                 break;
132             case 1:
133                 zonePrefix = "ZM";
134                 break;
135             case 2:
136             case 3:
137             case 4:
138                 zonePrefix = "Z" + zone;
139                 break;
140             default:
141                 throw new UnsupportedCommandTypeException("Zone must be in range [0-4], zone: " + zone);
142         }
143         String cmd = zonePrefix;
144         if (command == OnOffType.ON) {
145             cmd += "ON";
146         } else if (command == OnOffType.OFF) {
147             cmd += (zone == 0) ? "STANDBY" : "OFF";
148         } else if (command instanceof RefreshType) {
149             cmd += "?";
150         } else {
151             throw new UnsupportedCommandTypeException();
152         }
153         internalSendCommand(cmd);
154     }
155
156     public void sendVolumeCommand(Command command, int zone) throws UnsupportedCommandTypeException {
157         String zonePrefix;
158         switch (zone) {
159             case 1:
160                 zonePrefix = "MV";
161                 break;
162             case 2:
163             case 3:
164             case 4:
165                 zonePrefix = "Z" + zone;
166                 break;
167             default:
168                 throw new UnsupportedCommandTypeException("Zone must be in range [1-4], zone: " + zone);
169         }
170         String cmd = zonePrefix;
171         if (command instanceof RefreshType) {
172             cmd += "?";
173         } else if (command == IncreaseDecreaseType.INCREASE) {
174             cmd += "UP";
175         } else if (command == IncreaseDecreaseType.DECREASE) {
176             cmd += "DOWN";
177         } else if (command instanceof DecimalType decimalCommand) {
178             cmd += toDenonValue(decimalCommand);
179         } else if (command instanceof PercentType percentCommand) {
180             cmd += percentToDenonValue(percentCommand.toBigDecimal());
181         } else {
182             throw new UnsupportedCommandTypeException();
183         }
184         internalSendCommand(cmd);
185     }
186
187     public void sendVolumeDbCommand(Command command, int zone) throws UnsupportedCommandTypeException {
188         Command dbCommand = command;
189         if (dbCommand instanceof PercentType) {
190             throw new UnsupportedCommandTypeException();
191         } else if (dbCommand instanceof DecimalType) {
192             // convert dB to 'normal' volume by adding the offset of 80
193             dbCommand = new DecimalType(((DecimalType) command).toBigDecimal().add(DB_OFFSET));
194         }
195         sendVolumeCommand(dbCommand, zone);
196     }
197
198     protected String toDenonValue(DecimalType number) {
199         String dbString = String.valueOf(number.intValue());
200         BigDecimal num = number.toBigDecimal();
201         if (num.compareTo(BigDecimal.TEN) == -1) {
202             dbString = "0" + dbString;
203         }
204         if (num.remainder(BigDecimal.ONE).equals(POINTFIVE)) {
205             dbString = dbString + "5";
206         }
207         return dbString;
208     }
209
210     protected String percentToDenonValue(BigDecimal pct) {
211         // Round to nearest number divisible by 0.5
212         BigDecimal percent = pct.divide(POINTFIVE).setScale(0, RoundingMode.UP).multiply(POINTFIVE)
213                 .min(config.getMainVolumeMax()).max(BigDecimal.ZERO);
214
215         return toDenonValue(new DecimalType(percent));
216     }
217 }