[epsonprojector] Add configurable volume channel (#10988)
Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import java.io.InvalidClassException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.items.Item;
|
||||
import org.openhab.core.library.items.DimmerItem;
|
||||
import org.openhab.core.library.items.NumberItem;
|
||||
import org.openhab.core.library.items.StringItem;
|
||||
import org.openhab.core.library.items.SwitchItem;
|
||||
@@ -49,7 +50,7 @@ public enum EpsonProjectorCommandType {
|
||||
HPOSITION("HorizontalPosition", NumberItem.class),
|
||||
VPOSITION("VerticalPosition", NumberItem.class),
|
||||
GAMMA("Gamma", StringItem.class),
|
||||
VOLUME("Volume", NumberItem.class),
|
||||
VOLUME("Volume", DimmerItem.class),
|
||||
MUTE("Mute", SwitchItem.class),
|
||||
HREVERSE("HorizontalReverse", SwitchItem.class),
|
||||
VREVERSE("VerticalReverse", SwitchItem.class),
|
||||
|
||||
@@ -62,6 +62,10 @@ public class EpsonProjectorDevice {
|
||||
94, 99, 104, 109, 114, 120, 125, 130, 135, 141, 146, 151, 156, 161, 167, 172, 177, 182, 188, 193, 198, 203,
|
||||
208, 214, 219, 224, 229, 235, 240, 245, 250 };
|
||||
|
||||
private static final int[] MAP40 = new int[] { 0, 6, 12, 18, 24, 31, 37, 43, 49, 56, 62, 68, 74, 81, 87, 93, 99,
|
||||
106, 112, 118, 124, 131, 137, 143, 149, 156, 162, 168, 174, 181, 187, 193, 199, 206, 212, 218, 224, 231,
|
||||
237, 243, 249 };
|
||||
|
||||
private static final int[] MAP20 = new int[] { 0, 12, 24, 36, 48, 60, 73, 85, 97, 109, 121, 134, 146, 158, 170, 182,
|
||||
195, 207, 219, 231, 243 };
|
||||
|
||||
@@ -78,6 +82,7 @@ public class EpsonProjectorDevice {
|
||||
|
||||
private static final String ON = "ON";
|
||||
private static final String ERR = "ERR";
|
||||
private static final String IMEVENT = "IMEVENT";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(EpsonProjectorDevice.class);
|
||||
|
||||
@@ -118,7 +123,7 @@ public class EpsonProjectorDevice {
|
||||
response = response.replace("\r:", "");
|
||||
logger.debug("Response: '{}'", response);
|
||||
|
||||
if (ERR.equals(response)) {
|
||||
if (ERR.equals(response) || response.startsWith(IMEVENT)) {
|
||||
throw new EpsonProjectorCommandException("Error response received for command: " + query);
|
||||
}
|
||||
|
||||
@@ -522,19 +527,36 @@ public class EpsonProjectorDevice {
|
||||
/*
|
||||
* Volume
|
||||
*/
|
||||
public int getVolume() throws EpsonProjectorCommandException, EpsonProjectorException {
|
||||
int vol = queryInt("VOL?");
|
||||
for (int i = 0; i < MAP20.length; i++) {
|
||||
if (vol == MAP20[i]) {
|
||||
public int getVolume(int maxVolume) throws EpsonProjectorCommandException, EpsonProjectorException {
|
||||
int vol = this.queryInt("VOL?");
|
||||
switch (maxVolume) {
|
||||
case 20:
|
||||
return this.getMappingValue(MAP20, vol);
|
||||
case 40:
|
||||
return this.getMappingValue(MAP40, vol);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int getMappingValue(int[] map, int value) {
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
if (value == map[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setVolume(int value) throws EpsonProjectorCommandException, EpsonProjectorException {
|
||||
if (value >= 0 && value <= 20) {
|
||||
sendCommand(String.format("VOL %d", MAP20[value]));
|
||||
public void setVolume(int value, int maxVolume) throws EpsonProjectorCommandException, EpsonProjectorException {
|
||||
if (value >= 0 && value <= maxVolume) {
|
||||
switch (maxVolume) {
|
||||
case 20:
|
||||
this.sendCommand(String.format("VOL %d", MAP20[value]));
|
||||
return;
|
||||
case 40:
|
||||
this.sendCommand(String.format("VOL %d", MAP40[value]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,4 +41,9 @@ public class EpsonProjectorConfiguration {
|
||||
* Polling interval to refresh states.
|
||||
*/
|
||||
public int pollingInterval;
|
||||
|
||||
/**
|
||||
* Maximum volume setting of this projector, ie 20, 40, etc.
|
||||
*/
|
||||
public int maxVolume = 20;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ package org.openhab.binding.epsonprojector.internal.handler;
|
||||
|
||||
import static org.openhab.binding.epsonprojector.internal.EpsonProjectorBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@@ -36,6 +37,7 @@ import org.openhab.binding.epsonprojector.internal.enums.Switch;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
@@ -69,6 +71,8 @@ public class EpsonProjectorHandler extends BaseThingHandler {
|
||||
private Optional<EpsonProjectorDevice> device = Optional.empty();
|
||||
|
||||
private boolean isPowerOn = false;
|
||||
private int maxVolume = 20;
|
||||
private int curVolumeStep = -1;
|
||||
private int pollingInterval = DEFAULT_POLLING_INTERVAL_SEC;
|
||||
|
||||
public EpsonProjectorHandler(Thing thing, SerialPortManager serialPortManager) {
|
||||
@@ -103,6 +107,7 @@ public class EpsonProjectorHandler extends BaseThingHandler {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
|
||||
}
|
||||
|
||||
maxVolume = config.maxVolume;
|
||||
pollingInterval = config.pollingInterval;
|
||||
device.ifPresent(dev -> dev.setScheduler(scheduler));
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
@@ -267,8 +272,17 @@ public class EpsonProjectorHandler extends BaseThingHandler {
|
||||
int vKeystone = remoteController.getVerticalKeystone();
|
||||
return new DecimalType(vKeystone);
|
||||
case VOLUME:
|
||||
int volume = remoteController.getVolume();
|
||||
return new DecimalType(volume);
|
||||
// Each volume step falls within several percentage values, only change the UI if the polled step is
|
||||
// different than the step of the current percent. Without this logic the UI would snap back to the
|
||||
// closest whole % value for that step. e.g., UI set to 51% would snap back to 50% on the next
|
||||
// polling update.
|
||||
int volumeStep = remoteController.getVolume(maxVolume);
|
||||
if (curVolumeStep != volumeStep) {
|
||||
curVolumeStep = volumeStep;
|
||||
return new PercentType(
|
||||
BigDecimal.valueOf(Math.round(curVolumeStep / (double) maxVolume * 100.0)));
|
||||
}
|
||||
return null;
|
||||
case VPOSITION:
|
||||
int vPosition = remoteController.getVerticalPosition();
|
||||
return new DecimalType(vPosition);
|
||||
@@ -387,7 +401,11 @@ public class EpsonProjectorHandler extends BaseThingHandler {
|
||||
remoteController.setVerticalKeystone(((DecimalType) command).intValue());
|
||||
break;
|
||||
case VOLUME:
|
||||
remoteController.setVolume(((DecimalType) command).intValue());
|
||||
int newVolumeStep = (int) Math.round(((PercentType) command).doubleValue() / 100.0 * maxVolume);
|
||||
if (curVolumeStep != newVolumeStep) {
|
||||
curVolumeStep = newVolumeStep;
|
||||
remoteController.setVolume(curVolumeStep, maxVolume);
|
||||
}
|
||||
break;
|
||||
case VPOSITION:
|
||||
remoteController.setVerticalPosition(((DecimalType) command).intValue());
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<description>An Epson projector which supports the ESC/VP21 protocol via a serial port connection</description>
|
||||
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="power" typeId="system.power"/>
|
||||
<channel id="powerstate" typeId="powerstate"/>
|
||||
<channel id="source" typeId="source"/>
|
||||
<channel id="aspectratio" typeId="aspectratio"/>
|
||||
<channel id="colormode" typeId="colormode"/>
|
||||
<channel id="freeze" typeId="freeze"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="volume" typeId="system.volume"/>
|
||||
<channel id="luminance" typeId="luminance"/>
|
||||
<channel id="brightness" typeId="brightness"/>
|
||||
<channel id="contrast" typeId="contrast"/>
|
||||
@@ -50,6 +50,16 @@
|
||||
<description>Configures How Often to Poll the Projector for Updates (5-60; Default 10)</description>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
<parameter name="maxVolume" type="integer">
|
||||
<label>Volume Range</label>
|
||||
<description>Set to Match the Volume Range Seen in the Projector's OSD</description>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<options>
|
||||
<option value="20">Volume range is 0-20</option>
|
||||
<option value="40">Volume range is 0-40</option>
|
||||
</options>
|
||||
<default>20</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
@@ -60,14 +70,14 @@
|
||||
IP connection</description>
|
||||
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="power" typeId="system.power"/>
|
||||
<channel id="powerstate" typeId="powerstate"/>
|
||||
<channel id="source" typeId="source"/>
|
||||
<channel id="aspectratio" typeId="aspectratio"/>
|
||||
<channel id="colormode" typeId="colormode"/>
|
||||
<channel id="freeze" typeId="freeze"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="volume" typeId="system.volume"/>
|
||||
<channel id="luminance" typeId="luminance"/>
|
||||
<channel id="brightness" typeId="brightness"/>
|
||||
<channel id="contrast" typeId="contrast"/>
|
||||
@@ -108,15 +118,20 @@
|
||||
<description>Configures How Often to Poll the Projector for Updates (5-60; Default 10)</description>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
<parameter name="maxVolume" type="integer">
|
||||
<label>Volume Range</label>
|
||||
<description>Set to Match the Volume Range Seen in the Projector's OSD</description>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<options>
|
||||
<option value="20">Volume range is 0-20</option>
|
||||
<option value="40">Volume range is 0-40</option>
|
||||
</options>
|
||||
<default>20</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="power">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Power</label>
|
||||
<description>Powers the Projector On or Off</description>
|
||||
</channel-type>
|
||||
<channel-type id="powerstate">
|
||||
<item-type>String</item-type>
|
||||
<label>Power State</label>
|
||||
@@ -302,12 +317,6 @@
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
<channel-type id="volume">
|
||||
<item-type>Number</item-type>
|
||||
<label>Volume</label>
|
||||
<description>Retrieve or Set the Volume</description>
|
||||
<state min="0" max="20" step="1" pattern="%d"/>
|
||||
</channel-type>
|
||||
<channel-type id="mute">
|
||||
<item-type>Switch</item-type>
|
||||
<label>AV Mute</label>
|
||||
|
||||
Reference in New Issue
Block a user