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.omnilink.internal.handler;
15 import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
18 import java.util.Optional;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.omnilink.internal.AudioPlayer;
23 import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
24 import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
25 import org.openhab.core.library.types.DecimalType;
26 import org.openhab.core.library.types.NextPreviousType;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.PercentType;
29 import org.openhab.core.library.types.PlayPauseType;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.Thing;
32 import org.openhab.core.thing.ThingStatus;
33 import org.openhab.core.thing.ThingStatusDetail;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.RefreshType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.digitaldan.jomnilinkII.Message;
40 import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
41 import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioZoneProperties;
42 import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAudioZoneStatus;
43 import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
44 import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
47 * The {@link AudioZoneHandler} defines some methods that are used to
48 * interface with an OmniLink Audio Zone. This by extension also defines the
49 * Audio Zone thing that openHAB will be able to pick up and interface with.
51 * @author Craig Hamilton - Initial contribution
52 * @author Ethan Dye - openHAB3 rewrite
55 public class AudioZoneHandler extends AbstractOmnilinkStatusHandler<ExtendedAudioZoneStatus> {
56 private final Logger logger = LoggerFactory.getLogger(AudioZoneHandler.class);
57 private final int thingID = getThingNumber();
58 public @Nullable String number;
60 public AudioZoneHandler(Thing thing) {
65 public void initialize() {
67 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
68 if (bridgeHandler != null) {
69 updateAudioZoneProperties(bridgeHandler);
71 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
72 "Received null bridge while initializing Audio Zone!");
76 private void updateAudioZoneProperties(OmnilinkBridgeHandler bridgeHandler) {
77 ObjectPropertyRequest<AudioZoneProperties> objectPropertyRequest = ObjectPropertyRequest
78 .builder(bridgeHandler, ObjectPropertyRequests.AUDIO_ZONE, thingID, 0).selectNamed().build();
80 for (AudioZoneProperties audioZoneProperties : objectPropertyRequest) {
81 Map<String, String> properties = editProperties();
82 properties.put(THING_PROPERTIES_NAME, audioZoneProperties.getName());
83 updateProperties(properties);
88 public void handleCommand(ChannelUID channelUID, Command command) {
89 logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
91 if (command instanceof RefreshType) {
92 retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
93 ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
97 switch (channelUID.getId()) {
98 case CHANNEL_AUDIO_ZONE_POWER:
99 if (command instanceof OnOffType) {
100 sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_ON_MUTE.getNumber(),
101 OnOffType.OFF.equals(command) ? 0 : 1, thingID);
103 logger.debug("Invalid command: {}, must be OnOffType", command);
106 case CHANNEL_AUDIO_ZONE_MUTE:
107 if (command instanceof OnOffType) {
108 sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_ON_MUTE.getNumber(),
109 OnOffType.OFF.equals(command) ? 2 : 3, thingID);
111 logger.debug("Invalid command: {}, must be OnOffType", command);
114 case CHANNEL_AUDIO_ZONE_VOLUME:
115 if (command instanceof PercentType) {
116 sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_VOLUME.getNumber(),
117 ((PercentType) command).intValue(), thingID);
119 logger.debug("Invalid command: {}, must be PercentType", command);
122 case CHANNEL_AUDIO_ZONE_SOURCE:
123 if (command instanceof DecimalType) {
124 sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_SOURCE.getNumber(),
125 ((DecimalType) command).intValue(), thingID);
127 logger.debug("Invalid command: {}, must be DecimalType", command);
130 case CHANNEL_AUDIO_ZONE_CONTROL:
131 if (command instanceof PlayPauseType) {
132 handlePlayPauseCommand(channelUID, (PlayPauseType) command);
133 } else if (command instanceof NextPreviousType) {
134 handleNextPreviousCommand(channelUID, (NextPreviousType) command);
136 logger.debug("Invalid command: {}, must be PlayPauseType or NextPreviousType", command);
140 logger.warn("Unknown channel for Audio Zone thing: {}", channelUID);
144 private void handlePlayPauseCommand(ChannelUID channelUID, PlayPauseType command) {
145 logger.debug("handlePlayPauseCommand called for channel: {}, command: {}", channelUID, command);
146 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
148 if (bridgeHandler != null) {
149 Optional<AudioPlayer> audioPlayer = bridgeHandler.getAudioPlayer();
150 if (audioPlayer.isPresent()) {
151 AudioPlayer player = audioPlayer.get();
152 sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_SOURCE.getNumber(),
153 PlayPauseType.PLAY.equals(command) ? player.getPlayCommand() : player.getPauseCommand(),
156 logger.warn("No Audio Player was detected!");
159 logger.debug("Received null bridge while sending Audio Zone command!");
163 private void handleNextPreviousCommand(ChannelUID channelUID, NextPreviousType command) {
164 logger.debug("handleNextPreviousCommand called for channel: {}, command: {}", channelUID, command);
165 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
167 if (bridgeHandler != null) {
168 Optional<AudioPlayer> audioPlayer = bridgeHandler.getAudioPlayer();
169 if (audioPlayer.isPresent()) {
170 AudioPlayer player = audioPlayer.get();
171 sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_SOURCE.getNumber(),
172 NextPreviousType.NEXT.equals(command) ? player.getNextCommand() : player.getPreviousCommand(),
175 logger.warn("Audio Player could not be found!");
178 logger.debug("Received null bridge while sending Audio Zone command!");
183 public void updateChannels(ExtendedAudioZoneStatus status) {
184 logger.debug("updateChannels called for Audio Zone status: {}", status);
185 updateState(CHANNEL_AUDIO_ZONE_POWER, OnOffType.from(status.isPower()));
186 updateState(CHANNEL_AUDIO_ZONE_MUTE, OnOffType.from(status.isMute()));
187 updateState(CHANNEL_AUDIO_ZONE_VOLUME, new PercentType(status.getVolume()));
188 updateState(CHANNEL_AUDIO_ZONE_SOURCE, new DecimalType(status.getSource()));
192 protected Optional<ExtendedAudioZoneStatus> retrieveStatus() {
194 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
195 if (bridgeHandler != null) {
196 ObjectStatus objStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_AUDIO_ZONE, thingID,
198 return Optional.of((ExtendedAudioZoneStatus) objStatus.getStatuses()[0]);
200 logger.debug("Received null bridge while updating Audio Zone status!");
201 return Optional.empty();
203 } catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
204 logger.debug("Received exception while refreshing Audio Zone status: {}", e.getMessage());
205 return Optional.empty();