Skip to content
This repository has been archived by the owner on May 17, 2021. It is now read-only.

Commit

Permalink
Add functionality to show and adjust XBMC volume through an item of t…
Browse files Browse the repository at this point in the history
…ype Dimmer.
  • Loading branch information
avdleeuw committed Aug 25, 2014
1 parent 06e3c83 commit 7581af2
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ public interface XbmcBindingProvider extends BindingProvider {
String getXbmcInstance(String itemname);
String getProperty(String itemname);
boolean isInBound(String itemname);
boolean isOutBound(String itemname);
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ private void registerWatch(XbmcBindingProvider xbmcProvider, String itemName) {
// update the player status so any current value is initialised
if (connector.isConnected())
connector.updatePlayerStatus();

if (property.startsWith("Application")) {
connector.requestApplicationUpdate();
}
}
}

Expand Down Expand Up @@ -170,6 +174,18 @@ private boolean isInBound(String itemName) {
return false;
}

private boolean isOutBound(String itemName) {
for (BindingProvider provider : providers) {
if (provider instanceof XbmcBindingProvider) {
XbmcBindingProvider xbmcProvider = (XbmcBindingProvider) provider;
if (xbmcProvider.getItemNames().contains(itemName)) {
return xbmcProvider.isOutBound(itemName);
}
}
}
return false;
}

private XbmcConnector getXbmcConnector(String xbmcInstance) {
// sanity check
if (xbmcInstance == null)
Expand Down Expand Up @@ -249,7 +265,7 @@ protected void execute() {
@Override
protected void internalReceiveCommand(String itemName, Command command) {
// only interested in 'outbound' items
if (isInBound(itemName)) {
if (!isOutBound(itemName)) {
logger.warn("Received command ({}) for item {} which is configured as 'in-bound', ignoring", command.toString(), itemName);
return;
}
Expand Down Expand Up @@ -280,6 +296,8 @@ protected void internalReceiveCommand(String itemName, Command command) {
connector.showNotification("openHAB", command.toString());
if (property.equals("System.Shutdown") && command == OnOffType.OFF)
connector.systemShutdown();
if (property.equals("Application.Volume"))
connector.applicationSetVolume(command.toString());
} catch (Exception e) {
logger.error("Error handling command", e);
}
Expand All @@ -292,23 +310,29 @@ protected void internalReceiveCommand(String itemName, Command command) {
protected void internalReceiveUpdate(String itemName, State newState) {
try {
String property = getProperty(itemName);

// TODO: handle other updates
if (property.equals("GUI.ShowNotification")) {
String xbmcInstance = getXbmcInstance(itemName);
XbmcConnector connector = getXbmcConnector(xbmcInstance);

if (connector == null) {
logger.warn("Received update ({}) for item {} but no XBMC connector found for {}, ignoring", newState.toString(), itemName, xbmcInstance);
return;
}
if (!connector.isConnected()) {
logger.warn("Received update ({}) for item {} but the connection to the XBMC instance {} is down, ignoring", newState.toString(), itemName, xbmcInstance);
return;
}
String xbmcInstance = getXbmcInstance(itemName);
XbmcConnector connector = getXbmcConnector(xbmcInstance);

connector.showNotification("openHAB", newState.toString());
if (connector == null) {
logger.warn("Received update ({}) for item {} but no XBMC connector found for {}, ignoring", newState.toString(), itemName, xbmcInstance);
return;
}
if (!connector.isConnected()) {
logger.warn("Received update ({}) for item {} but the connection to the XBMC instance {} is down, ignoring", newState.toString(), itemName, xbmcInstance);
return;
}

// TODO: handle other updates
if (property.equals("GUI.ShowNotification"))
connector.showNotification("openHAB", newState.toString());

if (property.equals("Player.Open"))
connector.playerOpen(newState.toString());

if (property.equals("Application.SetVolume"))
connector.applicationSetVolume(newState.toString());

} catch (Exception e) {
logger.error("Error handling update", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.openhab.binding.xbmc.XbmcBindingProvider;
import org.openhab.core.binding.BindingConfig;
import org.openhab.core.items.Item;
import org.openhab.core.library.items.DimmerItem;
import org.openhab.core.library.items.StringItem;
import org.openhab.core.library.items.SwitchItem;
import org.openhab.model.item.binding.AbstractGenericBindingProvider;
Expand All @@ -35,10 +36,11 @@ public String getBindingType() {

@Override
public void validateItemType(Item item, String bindingConfig) throws BindingConfigParseException {
if (!(item instanceof StringItem) && !(item instanceof SwitchItem)){
if (!(item instanceof StringItem) && !(item instanceof SwitchItem) &&
!(item instanceof DimmerItem)){
throw new BindingConfigParseException( "item '"+item.getName()
+ "' is of type '" + item.getClass().getSimpleName()
+ "', but only String or Switch items are allowed.");
+ "', but only String, Switch or Dimmer items are allowed.");
}
}

Expand All @@ -55,11 +57,26 @@ public void processBindingConfiguration(String context, Item item, String bindin
} else if (bindingConfig.startsWith(">")) {
XbmcBindingConfig config = parseOutgoingBindingConfig(item, bindingConfig);
addBindingConfig(item, config);
} else if (bindingConfig.startsWith("=")) {
XbmcBindingConfig config = parseBidirectionalBindingConfig(item, bindingConfig);
addBindingConfig(item, config);
} else {
throw new BindingConfigParseException("Item '"+item.getName()+"' does not start with < or >.");
throw new BindingConfigParseException("Item '"+item.getName()+"' does not start with <, > or =.");
}
}

private XbmcBindingConfig parseBidirectionalBindingConfig( Item item, String bindingConfig) throws BindingConfigParseException{
Matcher matcher = CONFIG_PATTERN.matcher(bindingConfig);

if( !matcher.matches())
throw new BindingConfigParseException("Config for item '"+item.getName()+"' could not be parsed.");

String xbmcInstance = matcher.group(1);
String property = matcher.group(2);

return new XbmcBindingConfig(xbmcInstance, property, true, true);
}

private XbmcBindingConfig parseIncomingBindingConfig( Item item, String bindingConfig) throws BindingConfigParseException{
Matcher matcher = CONFIG_PATTERN.matcher(bindingConfig);

Expand All @@ -69,7 +86,7 @@ private XbmcBindingConfig parseIncomingBindingConfig( Item item, String bindingC
String xbmcInstance = matcher.group(1);
String property = matcher.group(2);

return new XbmcBindingConfig(xbmcInstance, property, true);
return new XbmcBindingConfig(xbmcInstance, property, true, false);
}

private XbmcBindingConfig parseOutgoingBindingConfig( Item item, String bindingConfig) throws BindingConfigParseException{
Expand All @@ -81,7 +98,7 @@ private XbmcBindingConfig parseOutgoingBindingConfig( Item item, String bindingC
String xbmcInstance = matcher.group(1);
String property = matcher.group(2);

return new XbmcBindingConfig(xbmcInstance, property, false);
return new XbmcBindingConfig(xbmcInstance, property, false, true);
}

@Override
Expand All @@ -102,18 +119,32 @@ public boolean isInBound(String itemname) {
return bindingConfig != null ? bindingConfig.isInBound(): false;
}

@Override
public boolean isOutBound(String itemname) {
XbmcBindingConfig bindingConfig = (XbmcBindingConfig) bindingConfigs.get(itemname);
return bindingConfig != null ? bindingConfig.isOutBound(): false;
}

class XbmcBindingConfig implements BindingConfig {

private String xbmcInstance;
private String property;
private boolean inBound;
private boolean inBound = false;
private boolean outBound = false;

public XbmcBindingConfig(String xbmcInstance, String property, boolean inBound) {
this.xbmcInstance = xbmcInstance;
this.property = property;
this.inBound = inBound;
}


public XbmcBindingConfig(String xbmcInstance, String property, boolean inBound, boolean outBound) {
this.xbmcInstance = xbmcInstance;
this.property = property;
this.inBound = inBound;
this.outBound = outBound;
}

public String getXbmcInstance() {
return xbmcInstance;
}
Expand All @@ -125,5 +156,9 @@ public String getProperty() {
public boolean isInBound() {
return inBound;
}

public boolean isOutBound() {
return outBound;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.openhab.binding.xbmc.rpc;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -19,6 +20,8 @@
import java.util.concurrent.TimeoutException;

import org.openhab.binding.xbmc.internal.XbmcHost;
import org.openhab.binding.xbmc.rpc.calls.ApplicationGetProperties;
import org.openhab.binding.xbmc.rpc.calls.ApplicationSetVolume;
import org.openhab.binding.xbmc.rpc.calls.FilesPrepareDownload;
import org.openhab.binding.xbmc.rpc.calls.GUIShowNotification;
import org.openhab.binding.xbmc.rpc.calls.JSONRPCPing;
Expand All @@ -29,6 +32,7 @@
import org.openhab.binding.xbmc.rpc.calls.PlayerStop;
import org.openhab.binding.xbmc.rpc.calls.SystemShutdown;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StringType;

import org.slf4j.Logger;
Expand All @@ -52,7 +56,7 @@
/**
* Manages the web socket connection for a single XBMC instance.
*
* @author tlan, Ben Jones
* @author tlan, Ben Jones, Ard van der Leeuw
* @since 1.5.0
*/
public class XbmcConnector {
Expand All @@ -78,6 +82,9 @@ public class XbmcConnector {
private WebSocket webSocket;
private boolean connected = false;

// the current volume
private BigDecimal volume = new BigDecimal(0);

// the current player state
private State currentState = State.Stop;

Expand Down Expand Up @@ -220,6 +227,9 @@ public void onMessage(String message) {
if (method.startsWith("Player.On")) {
processPlayerStateChanged(method, json);
}
if (method.startsWith("Application.On")) {
processApplicationStateChanged(method, json);
}
}
} catch (Exception e) {
logger.error("Error handling player state change message", e);
Expand Down Expand Up @@ -319,6 +329,31 @@ public void playerOpen(String file) {
playeropen.execute();
}

public void applicationSetVolume(String volume) {
final ApplicationSetVolume applicationsetvolume = new ApplicationSetVolume(client, httpUri);
if (volume.equals("ON"))
{
volume = "100";
}
if (volume.equals("OFF"))
{
volume = "0";
}
if (volume.equals("DECREASE"))
{
volume = this.volume.subtract(new BigDecimal(10)).toString();
}
if (volume.equals("INCREASE"))
{
volume = this.volume.add(new BigDecimal(10)).toString();
}


this.volume = new BigDecimal(volume);
applicationsetvolume.setVolume(this.volume.intValue());
applicationsetvolume.execute();
}

private void processPlayerStateChanged(String method, Map<String, Object> json) {
if ("Player.OnPlay".equals(method)) {
// get the player id and make a new request for the media details
Expand Down Expand Up @@ -347,6 +382,38 @@ private void processPlayerStateChanged(String method, Map<String, Object> json)
}
}

private void processApplicationStateChanged(String method, Map<String, Object> json) {
if ("Application.OnVolumeChanged".equals(method)) {
// get the player id and make a new request for the media details
Map<String, Object> params = RpcCall.getMap(json, "params");
Map<String, Object> data = RpcCall.getMap(params, "data");

Object o = data.get("volume");
PercentType volume = new PercentType(0);

if (o instanceof Integer)
{
volume = new PercentType((Integer)o);
}
else
{
if (o instanceof Double)
{
volume = new PercentType(((Double)o).intValue());
}
else
{

}
}
//updateProperty("Application.Volume", volume.toString());

updateProperty("Application.Volume", volume);
this.volume = new BigDecimal(volume.intValue());
}

}

private void updateState(State state) {
// sometimes get a Pause immediately after a Stop - so just ignore
if (currentState.equals(State.Stop) && state.equals(State.Pause))
Expand All @@ -358,14 +425,26 @@ private void updateState(State state) {
// if this is a Stop then clear everything else
if (state == State.Stop) {
for (String property : getPlayerProperties()) {
updateProperty(property, null);
updateProperty(property, (String)null);
}
}

// keep track of our current state
currentState = state;
}


public void requestApplicationUpdate() {
final ApplicationGetProperties app = new ApplicationGetProperties(client, httpUri);

app.execute(new Runnable() {
public void run() {
// now update each of the openHAB items for each property
updateProperty("Application.Volume", new PercentType(app.getVolume()));
}
});

}

private void requestPlayerUpdate(int playerId) {
// CRIT: if a PVR recording is played in XBMC the playerId is reported as -1
if (playerId == -1) {
Expand Down Expand Up @@ -425,6 +504,16 @@ private void updateProperty(String property, String value) {
}
}
}

private void updateProperty(String property, PercentType value) {
value = (value == null ? new PercentType(0) : value);

for (Entry<String, String> e : watches.entrySet()) {
if (property.equals(e.getValue())) {
eventPublisher.postUpdate(e.getKey(), value);
}
}
}

private List<String> getPlayerProperties() {
// get a distinct list of player properties we have items configured for
Expand Down
Loading

0 comments on commit 7581af2

Please sign in to comment.