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.binding.omnilink.internal.exceptions.BridgeOfflineException;
26 import org.openhab.core.library.types.DecimalType;
27 import org.openhab.core.library.types.NextPreviousType;
28 import org.openhab.core.library.types.OnOffType;
29 import org.openhab.core.library.types.PercentType;
30 import org.openhab.core.library.types.PlayPauseType;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.ThingStatusDetail;
35 import org.openhab.core.types.Command;
36 import org.openhab.core.types.RefreshType;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 import com.digitaldan.jomnilinkII.Message;
41 import com.digitaldan.jomnilinkII.MessageTypes.CommandMessage;
42 import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
43 import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioZoneProperties;
44 import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAudioZoneStatus;
45 import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
46 import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
49 * The {@link AudioZoneHandler} defines some methods that are used to
50 * interface with an OmniLink Audio Zone. This by extension also defines the
51 * Audio Zone thing that openHAB will be able to pick up and interface with.
53 * @author Craig Hamilton - Initial contribution
54 * @author Ethan Dye - openHAB3 rewrite
57 public class AudioZoneHandler extends AbstractOmnilinkStatusHandler<ExtendedAudioZoneStatus> {
58 private final Logger logger = LoggerFactory.getLogger(AudioZoneHandler.class);
59 private final int thingID = getThingNumber();
60 public @Nullable String number;
62 public AudioZoneHandler(Thing thing) {
67 public void initialize() {
69 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
70 if (bridgeHandler != null) {
71 updateAudioZoneProperties(bridgeHandler);
73 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
74 "Received null bridge while initializing Audio Zone!");
78 private void updateAudioZoneProperties(OmnilinkBridgeHandler bridgeHandler) {
79 ObjectPropertyRequest<AudioZoneProperties> objectPropertyRequest = ObjectPropertyRequest
80 .builder(bridgeHandler, ObjectPropertyRequests.AUDIO_ZONE, thingID, 0).selectNamed().build();
82 for (AudioZoneProperties audioZoneProperties : objectPropertyRequest) {
83 Map<String, String> properties = editProperties();
84 properties.put(THING_PROPERTIES_NAME, audioZoneProperties.getName());
85 updateProperties(properties);
90 public void handleCommand(ChannelUID channelUID, Command command) {
91 logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
93 if (command instanceof RefreshType) {
94 retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
95 ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null status update!"));
99 switch (channelUID.getId()) {
100 case CHANNEL_AUDIO_ZONE_POWER:
101 if (command instanceof OnOffType) {
102 sendOmnilinkCommand(CommandMessage.CMD_AUDIO_ZONE_SET_ON_AND_MUTE,
103 OnOffType.OFF.equals(command) ? 0 : 1, thingID);
105 logger.debug("Invalid command: {}, must be OnOffType", command);
108 case CHANNEL_AUDIO_ZONE_MUTE:
109 if (command instanceof OnOffType) {
110 sendOmnilinkCommand(CommandMessage.CMD_AUDIO_ZONE_SET_ON_AND_MUTE,
111 OnOffType.OFF.equals(command) ? 2 : 3, thingID);
113 logger.debug("Invalid command: {}, must be OnOffType", command);
116 case CHANNEL_AUDIO_ZONE_VOLUME:
117 if (command instanceof PercentType) {
118 sendOmnilinkCommand(CommandMessage.CMD_AUDIO_ZONE_SET_VOLUME, ((PercentType) command).intValue(),
121 logger.debug("Invalid command: {}, must be PercentType", command);
124 case CHANNEL_AUDIO_ZONE_SOURCE:
125 if (command instanceof DecimalType) {
126 sendOmnilinkCommand(CommandMessage.CMD_AUDIO_ZONE_SET_SOURCE, ((DecimalType) command).intValue(),
129 logger.debug("Invalid command: {}, must be DecimalType", command);
132 case CHANNEL_AUDIO_ZONE_CONTROL:
133 if (command instanceof PlayPauseType) {
134 handlePlayPauseCommand(channelUID, (PlayPauseType) command);
135 } else if (command instanceof NextPreviousType) {
136 handleNextPreviousCommand(channelUID, (NextPreviousType) command);
138 logger.debug("Invalid command: {}, must be PlayPauseType or NextPreviousType", command);
142 logger.warn("Unknown channel for Audio Zone thing: {}", channelUID);
146 private void handlePlayPauseCommand(ChannelUID channelUID, PlayPauseType command) {
147 logger.debug("handlePlayPauseCommand called for channel: {}, command: {}", channelUID, command);
148 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
150 if (bridgeHandler != null) {
151 Optional<AudioPlayer> audioPlayer = bridgeHandler.getAudioPlayer();
152 if (audioPlayer.isPresent()) {
153 AudioPlayer player = audioPlayer.get();
154 sendOmnilinkCommand(CommandMessage.CMD_AUDIO_ZONE_SET_SOURCE,
155 PlayPauseType.PLAY.equals(command) ? player.getPlayCommand() : player.getPauseCommand(),
158 logger.warn("No Audio Player was detected!");
161 logger.debug("Received null bridge while sending Audio Zone command!");
165 private void handleNextPreviousCommand(ChannelUID channelUID, NextPreviousType command) {
166 logger.debug("handleNextPreviousCommand called for channel: {}, command: {}", channelUID, command);
167 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
169 if (bridgeHandler != null) {
170 Optional<AudioPlayer> audioPlayer = bridgeHandler.getAudioPlayer();
171 if (audioPlayer.isPresent()) {
172 AudioPlayer player = audioPlayer.get();
173 sendOmnilinkCommand(CommandMessage.CMD_AUDIO_ZONE_SET_SOURCE,
174 NextPreviousType.NEXT.equals(command) ? player.getNextCommand() : player.getPreviousCommand(),
177 logger.warn("Audio Player could not be found!");
180 logger.debug("Received null bridge while sending Audio Zone command!");
185 public void updateChannels(ExtendedAudioZoneStatus status) {
186 logger.debug("updateChannels called for Audio Zone status: {}", status);
187 updateState(CHANNEL_AUDIO_ZONE_POWER, OnOffType.from(status.isPower()));
188 updateState(CHANNEL_AUDIO_ZONE_MUTE, OnOffType.from(status.isMute()));
189 updateState(CHANNEL_AUDIO_ZONE_VOLUME, new PercentType(status.getVolume()));
190 updateState(CHANNEL_AUDIO_ZONE_SOURCE, new DecimalType(status.getSource()));
194 protected Optional<ExtendedAudioZoneStatus> retrieveStatus() {
196 final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
197 if (bridgeHandler != null) {
198 ObjectStatus objStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_AUDIO_ZONE, thingID,
200 return Optional.of((ExtendedAudioZoneStatus) objStatus.getStatuses()[0]);
202 logger.debug("Received null bridge while updating Audio Zone status!");
203 return Optional.empty();
205 } catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
206 logger.debug("Received exception while refreshing Audio Zone status: {}", e.getMessage());
207 return Optional.empty();