Skip to content

Commit

Permalink
Issue #1206 - Implementation of PioneerAVR multi-zone control. (#1340)
Browse files Browse the repository at this point in the history
* Implementation of PioneerAVR multi-zone control. (#1206)

Signed-off-by: Antoine Besnard <stratehm@hotmail.com>
  • Loading branch information
Stratehm authored and kaikreuzer committed Nov 25, 2016
1 parent a1d500c commit dc19df5
Show file tree
Hide file tree
Showing 11 changed files with 362 additions and 222 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="pioneeravr"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<thing:thing-descriptions bindingId="pioneeravr" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="http://eclipse.org/smarthome/schemas/thing-description/v1.0.0"
xsi:schemaLocation="http://eclipse.org/smarthome/schemas/thing-description/v1.0.0 http://eclipse.org/smarthome/schemas/thing-description-1.0.0.xsd">

Expand All @@ -9,14 +8,12 @@
<label>Pioneer AVR over IP</label>
<description>Control a Pioneer AVR over IP </description>

<channels>
<channel id="power" typeId="powerChannel" />
<channel id="volumeDimmer" typeId="volumeChannelDimmer" />
<channel id="volumeDb" typeId="volumeChannelDb" />
<channel id="mute" typeId="muteChannel" />
<channel id="setInputSource" typeId="setInputSourceChannel" />
<channel id="displayInformation" typeId="displayInformationChannel" />
</channels>
<channel-groups>
<channel-group typeId="displayInformationGroup" id="displayInformation" />
<channel-group typeId="zone1Controls" id="zone1" />
<channel-group typeId="zone2Controls" id="zone2" />
<channel-group typeId="zone3Controls" id="zone3" />
</channel-groups>

<config-description>
<parameter name="address" type="text" required="true">
Expand All @@ -37,14 +34,12 @@
<label>Pioneer AVR over IP (unsupported)</label>
<description>Control a Pioneer AVR over IP for models that are not officially supported. You may experience some odd behaviors.</description>

<channels>
<channel id="power" typeId="powerChannel" />
<channel id="volumeDimmer" typeId="volumeChannelDimmer" />
<channel id="volumeDb" typeId="volumeChannelDb" />
<channel id="mute" typeId="muteChannel" />
<channel id="setInputSource" typeId="setInputSourceChannel" />
<channel id="displayInformation" typeId="displayInformationChannel" />
</channels>
<channel-groups>
<channel-group typeId="displayInformationGroup" id="displayInformation" />
<channel-group typeId="zone1Controls" id="zone1" />
<channel-group typeId="zone2Controls" id="zone2" />
<channel-group typeId="zone3Controls" id="zone3" />
</channel-groups>

<config-description>
<parameter name="address" type="text" required="true">
Expand All @@ -65,14 +60,12 @@
<label>Pioneer AVR over Serial</label>
<description>Control a Pioneer AVR over a Serial port (RS-232).</description>

<channels>
<channel id="power" typeId="powerChannel" />
<channel id="volumeDimmer" typeId="volumeChannelDimmer" />
<channel id="volumeDb" typeId="volumeChannelDb" />
<channel id="mute" typeId="muteChannel" />
<channel id="setInputSource" typeId="setInputSourceChannel" />
<channel id="displayInformation" typeId="displayInformationChannel" />
</channels>
<channel-groups>
<channel-group typeId="displayInformationGroup" id="displayInformation" />
<channel-group typeId="zone1Controls" id="zone1" />
<channel-group typeId="zone2Controls" id="zone2" />
<channel-group typeId="zone3Controls" id="zone3" />
</channel-groups>

<config-description>
<parameter name="serialPort" type="text" required="true">
Expand All @@ -82,6 +75,46 @@
</config-description>
</thing-type>

<channel-group-type id="displayInformationGroup">
<label>Display</label>
<channels>
<channel id="displayInformation" typeId="displayInformationChannel" />
</channels>
</channel-group-type>

<channel-group-type id="zone1Controls">
<label>Zone 1</label>
<channels>
<channel id="power" typeId="powerChannel" />
<channel id="volumeDimmer" typeId="volumeChannelDimmer" />
<channel id="volumeDb" typeId="volumeChannelDb" />
<channel id="mute" typeId="muteChannel" />
<channel id="setInputSource" typeId="setInputSourceChannel" />
</channels>
</channel-group-type>

<channel-group-type id="zone2Controls">
<label>Zone 2</label>
<channels>
<channel id="power" typeId="powerChannel" />
<channel id="volumeDimmer" typeId="volumeChannelDimmer" />
<channel id="volumeDb" typeId="volumeChannelDb" />
<channel id="mute" typeId="muteChannel" />
<channel id="setInputSource" typeId="setInputSourceChannel" />
</channels>
</channel-group-type>

<channel-group-type id="zone3Controls">
<label>Zone 3</label>
<channels>
<channel id="power" typeId="powerChannel" />
<channel id="volumeDimmer" typeId="volumeChannelDimmer" />
<channel id="volumeDb" typeId="volumeChannelDb" />
<channel id="mute" typeId="muteChannel" />
<channel id="setInputSource" typeId="setInputSourceChannel" />
</channels>
</channel-group-type>

<channel-type id="powerChannel">
<item-type>Switch</item-type>
<label>Power</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@
package org.openhab.binding.pioneeravr;

import java.util.Set;
import java.util.regex.Pattern;

import org.eclipse.smarthome.core.thing.ThingTypeUID;

import com.google.common.collect.ImmutableSet;

/**
* The {@link PioneerAvrBinding} class defines common constants, which are used across the whole binding.
*
*
* @author Antoine Besnard - Initial contribution
*/
public class PioneerAvrBindingConstants {
Expand All @@ -41,13 +42,16 @@ public class PioneerAvrBindingConstants {
public final static String IP_PROTOCOL_NAME = "IP";
public final static String SERIAL_PROTOCOL_NAME = "serial";

// List of all Channel ids
// List of all Channel names
public final static String POWER_CHANNEL = "power";
public final static String VOLUME_DIMMER_CHANNEL = "volumeDimmer";
public final static String VOLUME_DB_CHANNEL = "volumeDb";
public final static String MUTE_CHANNEL = "mute";
public final static String SET_INPUT_SOURCE_CHANNEL = "setInputSource";
public final static String DISPLAY_INFORMATION_CHANNEL = "displayInformation";
public final static String DISPLAY_INFORMATION_CHANNEL = "displayInformation#displayInformation";

public final static String GROUP_CHANNEL_PATTERN = "zone%s#%s";
public final static Pattern GROUP_CHANNEL_ZONE_PATTERN = Pattern.compile("zone([0-1])#.*");

// Used for Discovery service
public final static String MANUFACTURER = "PIONEER";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;

import org.apache.commons.lang.StringUtils;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.OnOffType;
import org.eclipse.smarthome.core.library.types.PercentType;
Expand Down Expand Up @@ -42,7 +42,7 @@
/**
* The {@link AbstractAvrHandler} is responsible for handling commands, which are sent to one of the channels through an
* AVR connection.
*
*
* @author Antoine Besnard - Initial contribution
*/
public abstract class AbstractAvrHandler extends BaseThingHandler
Expand All @@ -63,7 +63,7 @@ public AbstractAvrHandler(Thing thing) {

/**
* Create a new connection to the AVR.
*
*
* @return
*/
protected abstract AvrConnection createConnection();
Expand Down Expand Up @@ -112,40 +112,44 @@ public void dispose() {
}

/**
* Called when a Power ON state update is received from the AVR.
* Called when a Power ON state update is received from the AVR for the given zone.
*/
public void onPowerOn() {
// When the AVR is Powered ON, query the volume, the mute state and the source input
connection.sendVolumeQuery();
connection.sendMuteQuery();
connection.sendSourceInputQuery();
public void onPowerOn(int zone) {
// When the AVR is Powered ON, query the volume, the mute state and the source input of the zone
connection.sendVolumeQuery(zone);
connection.sendMuteQuery(zone);
connection.sendSourceInputQuery(zone);

}

/**
* Called when a Power OFF state update is received from the AVR.
*/
public void onPowerOff() {
public void onPowerOff(int zone) {
// When the AVR is Powered OFF, update the status of channels to Undefined
updateState(PioneerAvrBindingConstants.MUTE_CHANNEL, UnDefType.UNDEF);
updateState(PioneerAvrBindingConstants.VOLUME_DB_CHANNEL, UnDefType.UNDEF);
updateState(PioneerAvrBindingConstants.VOLUME_DIMMER_CHANNEL, UnDefType.UNDEF);
updateState(PioneerAvrBindingConstants.DISPLAY_INFORMATION_CHANNEL, new StringType(StringUtils.EMPTY));
updateState(PioneerAvrBindingConstants.SET_INPUT_SOURCE_CHANNEL, new StringType(StringUtils.EMPTY));
updateState(getChannelUID(PioneerAvrBindingConstants.MUTE_CHANNEL, zone), UnDefType.UNDEF);
updateState(getChannelUID(PioneerAvrBindingConstants.VOLUME_DB_CHANNEL, zone), UnDefType.UNDEF);
updateState(getChannelUID(PioneerAvrBindingConstants.VOLUME_DIMMER_CHANNEL, zone), UnDefType.UNDEF);
updateState(getChannelUID(PioneerAvrBindingConstants.SET_INPUT_SOURCE_CHANNEL, zone), UnDefType.UNDEF);

}

/**
* Check the status of the AVR. Return true if the AVR is online, else return false.
*
*
* @return
*/
private void checkStatus() {
// If the power query request has not been sent, the connection to the
// AVR has failed. So update its status to OFFLINE.
if (!connection.sendPowerQuery()) {
if (!connection.sendPowerQuery(1)) {
updateStatus(ThingStatus.OFFLINE);
} else {
// IF the power query has succeeded, the AVR status is ONLINE.
// If the power query has succeeded, the AVR status is ONLINE.
updateStatus(ThingStatus.ONLINE);
// Then send a power query for zone 2 and 3
connection.sendPowerQuery(2);
connection.sendPowerQuery(3);
}
}

Expand All @@ -159,15 +163,15 @@ public void handleCommand(ChannelUID channelUID, Command command) {
boolean commandSent = false;
boolean unknownCommand = false;

if (channelUID.getId().equals(PioneerAvrBindingConstants.POWER_CHANNEL)) {
commandSent = connection.sendPowerCommand(command);
} else if (channelUID.getId().equals(PioneerAvrBindingConstants.VOLUME_DIMMER_CHANNEL)
|| channelUID.getId().equals(PioneerAvrBindingConstants.VOLUME_DB_CHANNEL)) {
commandSent = connection.sendVolumeCommand(command);
} else if (channelUID.getId().equals(PioneerAvrBindingConstants.SET_INPUT_SOURCE_CHANNEL)) {
commandSent = connection.sendInputSourceCommand(command);
} else if (channelUID.getId().equals(PioneerAvrBindingConstants.MUTE_CHANNEL)) {
commandSent = connection.sendMuteCommand(command);
if (channelUID.getId().contains(PioneerAvrBindingConstants.POWER_CHANNEL)) {
commandSent = connection.sendPowerCommand(command, getZoneFromChannelUID(channelUID.getId()));
} else if (channelUID.getId().contains(PioneerAvrBindingConstants.VOLUME_DIMMER_CHANNEL)
|| channelUID.getId().contains(PioneerAvrBindingConstants.VOLUME_DB_CHANNEL)) {
commandSent = connection.sendVolumeCommand(command, getZoneFromChannelUID(channelUID.getId()));
} else if (channelUID.getId().contains(PioneerAvrBindingConstants.SET_INPUT_SOURCE_CHANNEL)) {
commandSent = connection.sendInputSourceCommand(command, getZoneFromChannelUID(channelUID.getId()));
} else if (channelUID.getId().contains(PioneerAvrBindingConstants.MUTE_CHANNEL)) {
commandSent = connection.sendMuteCommand(command, getZoneFromChannelUID(channelUID.getId()));
} else {
unknownCommand = true;
}
Expand Down Expand Up @@ -238,61 +242,92 @@ private void onDisconnection() {

/**
* Notify an AVR power state update to OpenHAB
*
*
* @param response
*/
private void managePowerStateUpdate(AvrResponse response) {
OnOffType state = PowerStateValues.ON_VALUE.equals(response.getParameterValue()) ? OnOffType.ON : OnOffType.OFF;

// When a Power ON state update is received, call the onPowerOn method.
if (OnOffType.ON == state) {
onPowerOn();
onPowerOn(response.getZone());
} else {
onPowerOff();
onPowerOff(response.getZone());
}

updateState(PioneerAvrBindingConstants.POWER_CHANNEL, state);
updateState(getChannelUID(PioneerAvrBindingConstants.POWER_CHANNEL, response.getZone()), state);
}

/**
* Notify an AVR volume level update to OpenHAB
*
*
* @param response
*/
private void manageVolumeLevelUpdate(AvrResponse response) {
updateState(PioneerAvrBindingConstants.VOLUME_DB_CHANNEL,

updateState(getChannelUID(PioneerAvrBindingConstants.VOLUME_DB_CHANNEL, response.getZone()),
new DecimalType(VolumeConverter.convertFromIpControlVolumeToDb(response.getParameterValue())));
updateState(PioneerAvrBindingConstants.VOLUME_DIMMER_CHANNEL, new PercentType(
(int) VolumeConverter.convertFromIpControlVolumeToPercent(response.getParameterValue())));
updateState(getChannelUID(PioneerAvrBindingConstants.VOLUME_DIMMER_CHANNEL, response.getZone()),
new PercentType(
(int) VolumeConverter.convertFromIpControlVolumeToPercent(response.getParameterValue())));
}

/**
* Notify an AVR mute state update to OpenHAB
*
*
* @param response
*/
private void manageMuteStateUpdate(AvrResponse response) {
updateState(PioneerAvrBindingConstants.MUTE_CHANNEL,
updateState(getChannelUID(PioneerAvrBindingConstants.MUTE_CHANNEL, response.getZone()),
response.getParameterValue().equals(MuteStateValues.OFF_VALUE) ? OnOffType.OFF : OnOffType.ON);
}

/**
* Notify an AVR input source channel update to OpenHAB
*
*
* @param response
*/
private void manageInputSourceChannelUpdate(AvrResponse response) {
updateState(PioneerAvrBindingConstants.SET_INPUT_SOURCE_CHANNEL, new StringType(response.getParameterValue()));
updateState(getChannelUID(PioneerAvrBindingConstants.SET_INPUT_SOURCE_CHANNEL, response.getZone()),
new StringType(response.getParameterValue()));
}

/**
* Notify an AVR displayed information update to OpenHAB
*
*
* @param response
*/
private void manageDisplayedInformationUpdate(AvrResponse response) {
updateState(PioneerAvrBindingConstants.DISPLAY_INFORMATION_CHANNEL,
new StringType(DisplayInformationConverter.convertMessageFromIpControl(response.getParameterValue())));
}

/**
* Build the channelUID from the channel name and the zone number.
*
* @param channelName
* @param zone
* @return
*/
protected String getChannelUID(String channelName, int zone) {
return String.format(PioneerAvrBindingConstants.GROUP_CHANNEL_PATTERN, zone, channelName);
}

/**
* Return the zone from the given channelUID.
*
* Return 0 if the zone cannot be extracted from the channelUID.
*
* @param channelUID
* @return
*/
protected int getZoneFromChannelUID(String channelUID) {
int zone = 0;
Matcher matcher = PioneerAvrBindingConstants.GROUP_CHANNEL_ZONE_PATTERN.matcher(channelUID);
if (matcher.find()) {
zone = Integer.valueOf(matcher.group(1));
}
return zone;
}

}
Loading

0 comments on commit dc19df5

Please sign in to comment.