/** * Copyright (c) 2010-2018 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.heos.handler; import static org.openhab.binding.heos.HeosBindingConstants.*; import static org.openhab.binding.heos.internal.resources.HeosConstants.GID; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.types.PercentType; import org.eclipse.smarthome.core.library.types.PlayPauseType; import org.eclipse.smarthome.core.library.types.StringType; import org.eclipse.smarthome.core.thing.ChannelUID; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingStatus; import org.eclipse.smarthome.core.types.Command; import org.openhab.binding.heos.internal.api.HeosFacade; import org.openhab.binding.heos.internal.api.HeosSystem; import org.openhab.binding.heos.internal.resources.HeosConstants; import org.openhab.binding.heos.internal.resources.HeosGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The {@link HeosGroupHandler} handles the actions for a HEOS group. * Channel commands are received and send to the dedicated channels * * @author Johannes Einig - Initial contribution */ public class HeosGroupHandler extends HeosThingBaseHandler { private String gid; private HeosGroup heosGroup; private Logger logger = LoggerFactory.getLogger(this.getClass()); public HeosGroupHandler(Thing thing, HeosSystem heos, HeosFacade api) { super(thing, heos, api); gid = thing.getConfiguration().get(GID).toString(); this.heosGroup = new HeosGroup(); this.heosGroup.setGid(gid); this.heosGroup.setGroupMemberHash(thing.getConfiguration().get(GROUP_MEMBER_HASH).toString()); setGroupMemberPidList(); } @Override public void handleCommand(ChannelUID channelUID, @NonNull Command command) { super.handleCommand(channelUID, command); } /** * Init the HEOS group. Starts an extra thread to avoid blocking * during start up phase. Gathering all information can take longer * than 5 seconds which can throw an error within the openhab system. */ @Override public void initialize() { this.gid = this.thing.getConfiguration().get(GID).toString(); this.heosGroup.setGid(gid); api.registerforChangeEvents(this); ScheduledExecutorService executerPool = Executors.newScheduledThreadPool(1); executerPool.schedule(new InitializationRunnable(), 4, TimeUnit.SECONDS); } @Override public PercentType getNotificationSoundVolume() { return PercentType.valueOf(heosGroup.getLevel()); } @Override public void setNotificationSoundVolume(PercentType volume) { api.volumeGroup(volume.toString(), gid); } @Override public void playerStateChangeEvent(String pid, String event, String command) { if (this.getThing().getStatus().equals(ThingStatus.UNINITIALIZED)) { logger.info("Can't Handle Event. Group {} not initialized. Status is: {}", this.getConfig().get(NAME), this.getThing().getStatus().toString()); return; } if (pid.equals(this.gid)) { handleThingStateUpdate(event, command); } } @Override public void playerMediaChangeEvent(String pid, HashMap<String, String> info) { if (pid.equals(this.gid)) { handleThingMediaUpdate(info); } } @Override public void bridgeChangeEvent(String event, String result, String command) { // Do nothing } // Generates the groupMember from the properties. Is needed to generate group after restart of OpenHab. private void setGroupMemberPidList() { String memberListString = thing.getProperties().get(GROUP_MEMBER_PID_LIST); memberListString = memberListString.substring(1, memberListString.length() - 1); String array[] = memberListString.split(", "); // important: Keep the white space. List<String> memberPidList = Arrays.asList(array); heosGroup.setGroupMemberPidList(memberPidList); } /** * Sets the status of the HEOS group to OFFLINE. * Also sets the UNGROUP channel to OFF and the CONTROL * channel to PAUSE */ @Override public void setStatusOffline() { api.unregisterforChangeEvents(this); updateState(CH_ID_UNGROUP, OnOffType.OFF); updateState(CH_ID_CONTROL, PlayPauseType.PAUSE); updateStatus(ThingStatus.OFFLINE); } /** * * @return The instance of the HEOS group */ public HeosGroup getHeosGroup() { return heosGroup; } @Override protected void updateHeosThingState() { heosGroup = heos.getGroupState(heosGroup); } @Override protected void refreshChannels() { postCommand(CH_ID_UNGROUP, OnOffType.ON); updateState(CH_ID_VOLUME, PercentType.valueOf(heosGroup.getLevel())); if (heosGroup.getMute().equals(ON)) { updateState(CH_ID_MUTE, OnOffType.ON); } else { updateState(CH_ID_MUTE, OnOffType.OFF); } if (heosGroup.getState().equals(PLAY)) { updateState(CH_ID_CONTROL, PlayPauseType.PLAY); } if (heosGroup.getState().equals(PAUSE) || heosGroup.getState().equals(STOP)) { updateState(CH_ID_CONTROL, PlayPauseType.PAUSE); } if (heosGroup.getShuffle().equals(HeosConstants.HEOS_ON)) { updateState(CH_ID_SHUFFLE_MODE, OnOffType.ON); } if (heosGroup.getShuffle().equals(HeosConstants.HEOS_OFF)) { updateState(CH_ID_SHUFFLE_MODE, OnOffType.OFF); } updateState(CH_ID_SONG, StringType.valueOf(heosGroup.getSong())); updateState(CH_ID_ARTIST, StringType.valueOf(heosGroup.getArtist())); updateState(CH_ID_ALBUM, StringType.valueOf(heosGroup.getAlbum())); updateState(CH_ID_IMAGE_URL, StringType.valueOf(heosGroup.getImageUrl())); updateState(CH_ID_STATION, StringType.valueOf(heosGroup.getStation())); updateState(CH_ID_TYPE, StringType.valueOf(heosGroup.getType())); updateState(CH_ID_CUR_POS, StringType.valueOf("0")); updateState(CH_ID_DURATION, StringType.valueOf("0")); updateState(CH_ID_REPEAT_MODE, StringType.valueOf(heosGroup.getRepeatMode())); } public class InitializationRunnable implements Runnable { @SuppressWarnings("null") @Override public void run() { initChannelHandlerFatory(); heosGroup = heos.getGroupState(heosGroup); if (!heosGroup.isOnline() || !heosGroup.getGroupMemberHash() .equals(thing.getConfiguration().get(GROUP_MEMBER_HASH).toString())) { bridge.setThingStatusOffline(thing.getUID()); setStatusOffline(); return; } updateStatus(ThingStatus.ONLINE); bridge.setThingStatusOnline(thing.getUID()); // informs the System about the existing group HashMap<String, HeosGroup> usedToFillOldGroupMap = new HashMap<>(); usedToFillOldGroupMap.put(heosGroup.getNameHash(), heosGroup); heos.addHeosGroupToOldGroupMap(usedToFillOldGroupMap); id = heosGroup.getGid(); // Updates the id of the group. Needed if group leader has changed refreshChannels(); } } }