2 * Copyright (c) 2010-2021 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.yamahareceiver.internal.protocol.xml;
15 import static org.openhab.binding.yamahareceiver.internal.protocol.xml.XMLUtils.*;
17 import java.io.IOException;
19 import org.apache.commons.lang.StringUtils;
20 import org.openhab.binding.yamahareceiver.internal.protocol.AbstractConnection;
21 import org.openhab.binding.yamahareceiver.internal.protocol.InputWithPresetControl;
22 import org.openhab.binding.yamahareceiver.internal.protocol.InputWithTunerBandControl;
23 import org.openhab.binding.yamahareceiver.internal.protocol.ReceivedMessageParseException;
24 import org.openhab.binding.yamahareceiver.internal.state.DabBandState;
25 import org.openhab.binding.yamahareceiver.internal.state.DabBandStateListener;
26 import org.openhab.binding.yamahareceiver.internal.state.DeviceInformationState;
27 import org.openhab.binding.yamahareceiver.internal.state.PlayInfoState;
28 import org.openhab.binding.yamahareceiver.internal.state.PlayInfoStateListener;
29 import org.openhab.binding.yamahareceiver.internal.state.PresetInfoState;
30 import org.openhab.binding.yamahareceiver.internal.state.PresetInfoStateListener;
31 import org.slf4j.LoggerFactory;
32 import org.w3c.dom.Node;
35 * This class implements the Yamaha Receiver protocol related to DAB tuners which allows to control band and preset.
36 * This control is specific to dual band tuners only.
38 * Note that yamaha maintains separate presets for each band.
40 * The XML nodes <DAB><Play_Control><Band>FM</Band></Play_Control></DAB> are used.
42 * No state will be saved in here, but in {@link DabBandState}, {@link PresetInfoState} and {@link PlayInfoState}
45 * @author Tomasz Maruszak - [yamaha] Tuner band selection and preset feature for dual band models (RX-S601D)
47 public class InputWithTunerDABControlXML extends AbstractInputControlXML
48 implements InputWithTunerBandControl, InputWithPresetControl {
50 private static final String BAND_FM = "FM";
51 private static final String BAND_DAB = "DAB";
53 private final DabBandStateListener observerForBand;
54 private final PresetInfoStateListener observerForPreset;
55 private final PlayInfoStateListener observerForPlayInfo;
57 protected CommandTemplate band = new CommandTemplate("<Play_Control><Band>%s</Band></Play_Control>",
59 protected CommandTemplate preset = new CommandTemplate(
60 "<Play_Control><%s><Preset><Preset_Sel>%d</Preset_Sel></Preset></%s></Play_Control>", "");
63 * Need to remember last band state to drive the preset
65 private DabBandState bandState;
68 * Create a InputWithPlayControl object for altering menu positions and requesting current menu information as well
69 * as controlling the playback and choosing a preset item.
71 * @param inputID The input ID - TUNER is going to be used here.
72 * @param con The Yamaha communication object to send http requests.
74 public InputWithTunerDABControlXML(String inputID, AbstractConnection con, DabBandStateListener observerForBand,
75 PresetInfoStateListener observerForPreset, PlayInfoStateListener observerForPlayInfo,
76 DeviceInformationState deviceInformationState) {
77 super(LoggerFactory.getLogger(InputWithTunerDABControlXML.class), inputID, con, deviceInformationState);
79 this.inputElement = "DAB";
81 this.observerForBand = observerForBand;
82 this.observerForPreset = observerForPreset;
83 this.observerForPlayInfo = observerForPlayInfo;
85 if (observerForBand == null && observerForPreset == null && observerForPlayInfo == null) {
86 throw new IllegalArgumentException("At least one observer has to be provided");
91 public void update() throws IOException, ReceivedMessageParseException {
92 Node responseNode = XMLProtocolService.getResponse(comReference.get(),
93 wrInput("<Play_Info>GetParam</Play_Info>"), inputElement);
98 //<YAMAHA_AV rsp="GET" RC="0">
101 // <Feature_Availability>Ready</Feature_Availability>
104 // <Preset_Sel>1</Preset_Sel>
113 // <FM_Mode>Auto</FM_Mode>
115 // <Tuned>Assert</Tuned>
116 // <Stereo>Assert</Stereo>
119 // <Program_Type>POP M</Program_Type>
120 // <Program_Service> 22:59</Program_Service>
121 // <Radio_Text>tel. 22 333 33 33 * Trojka * e-mail: trojka@polskieradio.pl</Radio_Text>
122 // <Clock_Time>22:59</Clock_Time>
126 // <Status>Ready</Status>
128 // <Preset_Sel>No Preset</Preset_Sel>
137 // <Category>Primary</Category>
138 // <Audio_Mode>Stereo</Audio_Mode>
144 // <Quality>82</Quality>
145 // <Tune_Aid>45</Tune_Aid>
146 // <Off_Air>Negate</Off_Air>
147 // <DAB_PLUS>Assert</DAB_PLUS>
150 // <Ch_Label>11B</Ch_Label>
151 // <Service_Label>PR Czwórka</Service_Label>
152 // <DLS>Kluboteka Polskie Radio S.A.</DLS>
153 // <Ensemble_Label>Polskie Radio</Ensemble_Label>
154 // <Program_Type>Pop</Program_Type>
155 // <Date_and_Time>12AUG'17 23:47</Date_and_Time>
165 DabBandState msgForBand = new DabBandState();
166 PresetInfoState msgForPreset = new PresetInfoState();
167 PlayInfoState msgForPlayInfo = new PlayInfoState();
169 msgForBand.band = getNodeContentOrDefault(responseNode, "Play_Info/Band", msgForBand.band);
170 logger.debug("Band set to {} for input {}", msgForBand.band, inputID);
172 // store last state of band
173 bandState = msgForBand;
175 if (StringUtils.isEmpty(msgForBand.band)) {
176 logger.warn("Band is unknown for input {}, therefore preset and playback information will not be available",
179 Node playInfoNode = getNode(responseNode, "Play_Info/" + msgForBand.band);
181 msgForPreset.presetChannel = getNodeContentOrDefault(playInfoNode, "Preset/Preset_Sel", -1);
182 logger.debug("Preset set to {} for input {}", msgForPreset.presetChannel, inputID);
184 Node metaInfoNode = getNode(playInfoNode, "Meta_Info");
185 if (metaInfoNode != null) {
186 msgForPlayInfo.album = getNodeContentOrDefault(metaInfoNode, "Program_Type", msgForPlayInfo.album);
187 if (BAND_DAB.equals(msgForBand.band)) {
188 msgForPlayInfo.station = getNodeContentOrDefault(metaInfoNode, "Service_Label",
189 msgForPlayInfo.station);
190 msgForPlayInfo.artist = getNodeContentOrDefault(metaInfoNode, "Ensemble_Label",
191 msgForPlayInfo.artist);
192 msgForPlayInfo.song = getNodeContentOrDefault(metaInfoNode, "DLS", msgForPlayInfo.song);
194 msgForPlayInfo.station = getNodeContentOrDefault(metaInfoNode, "Program_Service",
195 msgForPlayInfo.station);
196 msgForPlayInfo.artist = getNodeContentOrDefault(metaInfoNode, "Station", msgForPlayInfo.artist);
197 msgForPlayInfo.song = getNodeContentOrDefault(metaInfoNode, "Radio_Text", msgForPlayInfo.song);
202 // DAB does not provide channel names, the channel list will be empty
203 msgForPreset.presetChannelNamesChanged = true;
205 if (observerForBand != null) {
206 observerForBand.dabBandUpdated(msgForBand);
208 if (observerForPreset != null) {
209 observerForPreset.presetInfoUpdated(msgForPreset);
211 if (observerForPlayInfo != null) {
212 observerForPlayInfo.playInfoUpdated(msgForPlayInfo);
217 public void selectBandByName(String band) throws IOException, ReceivedMessageParseException {
218 // Example: <Play_Control><Band>FM</Band></Play_Control>
219 String cmd = this.band.apply(band);
220 comReference.get().send(wrInput(cmd));
225 public void selectItemByPresetNumber(int presetChannel) throws IOException, ReceivedMessageParseException {
226 if (bandState == null || bandState.band == null || bandState.band.isEmpty()) {
227 logger.warn("Cannot change preset because the band is unknown for input {}", inputID);
231 // Example: <Play_Control><FM><Preset><Preset_Sel>2</Preset_Sel></Preset></FM></Play_Control>
232 String cmd = this.preset.apply(bandState.band, presetChannel, bandState.band);
233 comReference.get().send(wrInput(cmd));