]> git.basschouten.com Git - openhab-addons.git/blob
706254da1f2bd91e8771572904b1e1da1ce88959
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.yamahareceiver.internal.protocol.xml;
14
15 import static org.openhab.binding.yamahareceiver.internal.YamahaReceiverBindingConstants.*;
16 import static org.openhab.binding.yamahareceiver.internal.YamahaReceiverBindingConstants.Models.RX_A2000;
17 import static org.openhab.binding.yamahareceiver.internal.protocol.xml.XMLConstants.*;
18 import static org.openhab.binding.yamahareceiver.internal.protocol.xml.XMLProtocolService.getResponse;
19
20 import java.io.IOException;
21 import java.lang.ref.WeakReference;
22 import java.util.Arrays;
23 import java.util.HashSet;
24 import java.util.Set;
25
26 import org.openhab.binding.yamahareceiver.internal.protocol.AbstractConnection;
27 import org.openhab.binding.yamahareceiver.internal.protocol.ReceivedMessageParseException;
28 import org.openhab.binding.yamahareceiver.internal.protocol.SystemControl;
29 import org.openhab.binding.yamahareceiver.internal.state.DeviceInformationState;
30 import org.openhab.binding.yamahareceiver.internal.state.SystemControlState;
31 import org.openhab.binding.yamahareceiver.internal.state.SystemControlStateListener;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.w3c.dom.Node;
35
36 /**
37  * The system control protocol class is used to control basic non-zone functionality
38  * of a Yamaha receiver with HTTP/xml.
39  * No state will be saved in here, but in {@link SystemControlState} instead.
40  *
41  * @author David Gräff - Initial contribution
42  * @author Tomasz Maruszak - refactoring, HTR-xxxx Zone_2 compatibility
43  */
44 public class SystemControlXML implements SystemControl {
45
46     private final Logger logger = LoggerFactory.getLogger(SystemControlXML.class);
47
48     private static final Set<String> MODELS_WITH_PARTY_SUPPORT = new HashSet<>(Arrays.asList(RX_A2000));
49
50     private WeakReference<AbstractConnection> comReference;
51     private SystemControlStateListener observer;
52     private final DeviceDescriptorXML descriptorXML;
53
54     protected CommandTemplate power = new CommandTemplate(
55             "<System><Power_Control><Power>%s</Power></Power_Control></System>", "System/Power_Control/Power");
56     protected CommandTemplate partyMode = new CommandTemplate(
57             "<System><Party_Mode><Mode>%s</Mode></Party_Mode></System>", "System/Party_Mode/Mode");
58     protected boolean partyModeSupported;
59     protected CommandTemplate partyModeMute = new CommandTemplate(
60             "<System><Party_Mode><Volume><Mute>%s</Mute></Volume></Party_Mode></System>");
61     protected boolean partyModeMuteSupported;
62     protected CommandTemplate partyModeVolume = new CommandTemplate(
63             "<System><Party_Mode><Volume><Lvl>%s</Lvl></Volume></Party_Mode></System>");
64     protected boolean partyModeVolumeSupported;
65
66     public SystemControlXML(AbstractConnection xml, SystemControlStateListener observer,
67             DeviceInformationState deviceInformationState) {
68         this.comReference = new WeakReference<>(xml);
69         this.observer = observer;
70         this.descriptorXML = DeviceDescriptorXML.getAttached(deviceInformationState);
71
72         this.applyModelVariations();
73     }
74
75     /**
76      * Apply command changes to ensure compatibility with all supported models
77      */
78     protected void applyModelVariations() {
79         if (descriptorXML == null) {
80             logger.trace("Device descriptor not available");
81             return;
82         }
83
84         logger.trace("Compatibility detection");
85
86         partyModeSupported = descriptorXML.hasFeature(
87                 d -> MODELS_WITH_PARTY_SUPPORT.contains(d.getUnitName())
88                         || d.system.hasCommandEnding("System,Party_Mode,Mode"),
89                 () -> logger.debug("The {} channel is not supported on your model", CHANNEL_PARTY_MODE));
90
91         partyModeMuteSupported = descriptorXML.hasFeature(
92                 d -> MODELS_WITH_PARTY_SUPPORT.contains(d.getUnitName())
93                         || d.system.hasCommandEnding("System,Party_Mode,Volume,Mute"),
94                 () -> logger.debug("The {} channel is not supported on your model", CHANNEL_PARTY_MODE_MUTE));
95
96         partyModeVolumeSupported = descriptorXML.hasFeature(
97                 d -> MODELS_WITH_PARTY_SUPPORT.contains(d.getUnitName())
98                         || d.system.hasCommandEnding("System,Party_Mode,Volume,Lvl"),
99                 () -> logger.debug("The {} channel is not supported on your model", CHANNEL_PARTY_MODE_VOLUME));
100     }
101
102     @Override
103     public void setPower(boolean power) throws IOException, ReceivedMessageParseException {
104         String cmd = this.power.apply(power ? ON : POWER_STANDBY);
105         comReference.get().send(cmd);
106         update();
107     }
108
109     @Override
110     public void setPartyMode(boolean on) throws IOException, ReceivedMessageParseException {
111         if (!partyModeSupported) {
112             return;
113         }
114         String cmd = this.partyMode.apply(on ? ON : OFF);
115         comReference.get().send(cmd);
116         update();
117     }
118
119     @Override
120     public void setPartyModeMute(boolean on) throws IOException, ReceivedMessageParseException {
121         if (!partyModeMuteSupported) {
122             return;
123         }
124         String cmd = this.partyModeMute.apply(on ? ON : OFF);
125         comReference.get().send(cmd);
126         update();
127     }
128
129     @Override
130     public void setPartyModeVolume(boolean increment) throws IOException, ReceivedMessageParseException {
131         if (!partyModeVolumeSupported) {
132             return;
133         }
134         String cmd = this.partyModeVolume.apply(increment ? UP : DOWN);
135         comReference.get().send(cmd);
136         update();
137     }
138
139     @Override
140     public void update() throws IOException, ReceivedMessageParseException {
141         if (observer == null) {
142             return;
143         }
144
145         AbstractConnection conn = comReference.get();
146
147         SystemControlState state = new SystemControlState();
148
149         Node node = getResponse(conn, power.apply(GET_PARAM), power.getPath());
150         state.power = node != null && ON.equals(node.getTextContent());
151
152         if (partyModeSupported) {
153             // prevent an unnecessary call
154             node = getResponse(conn, partyMode.apply(GET_PARAM), partyMode.getPath());
155             state.partyMode = node != null && ON.equals(node.getTextContent());
156         }
157
158         logger.debug("System state - power: {}, partyMode: {}", state.power, state.partyMode);
159
160         observer.systemControlStateChanged(state);
161     }
162 }