diff --git a/bundles/org.openhab.binding.epsonprojector/README.md b/bundles/org.openhab.binding.epsonprojector/README.md index 267218070792e..e121b4016e5ef 100644 --- a/bundles/org.openhab.binding.epsonprojector/README.md +++ b/bundles/org.openhab.binding.epsonprojector/README.md @@ -25,14 +25,16 @@ The `projector-serial` thing has the following configuration parameters: |-----------------|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|----------| | serialPort | Serial Port | Serial port device name that is connected to the Epson projector to control, e.g. COM1 on Windows, /dev/ttyS0 on Linux or /dev/tty.PL2303-0000103D on Mac. | yes | | pollingInterval | Polling Interval | Polling interval in seconds to update channel states, range 5-60 seconds; default 10 seconds. | no | +| maxVolume | Max Volume Range | Set to the maximum volume level available in the projector's OSD to select the correct range for the volume control. e.g. 20 or 40; default 20 | no | The `projector-tcp` thing has the following configuration parameters: -| Parameter | Name | Description | Required | -|-----------------|------------------|-------------------------------------------------------------------------------------------------------------------------|----------| -| host | Host Name | Host Name or IP address for the projector or serial over IP device. | yes | -| port | Port | Port for the projector or serial over IP device; default 3629 for projectors with built-in ethernet connector or Wi-Fi. | yes | -| pollingInterval | Polling Interval | Polling interval in seconds to update channel states, range 5-60 seconds; default 10 seconds. | no | +| Parameter | Name | Description | Required | +|-----------------|------------------|------------------------------------------------------------------------------------------------------------------------------------------------|----------| +| host | Host Name | Host Name or IP address for the projector or serial over IP device. | yes | +| port | Port | Port for the projector or serial over IP device; default 3629 for projectors with built-in ethernet connector or Wi-Fi. | yes | +| pollingInterval | Polling Interval | Polling interval in seconds to update channel states, range 5-60 seconds; default 10 seconds. | no | +| maxVolume | Max Volume Range | Set to the maximum volume level available in the projector's OSD to select the correct range for the volume control. e.g. 20 or 40; default 20 | no | Some notes: @@ -40,8 +42,9 @@ Some notes: * The _source_ channel includes a dropdown with the most common source inputs. * If your projector has a source input that is not in the dropdown, the two digit hex code to access that input will be displayed by the _source_ channel when that input is selected by the remote control. * By using the sitemap mapping or a rule to send the input's code back to the _source_ channel, any source on the projector can be accessed by the binding. -* The following channels _aspectratio_, _colormode_, _luminance_, _gamma_ and _background_ are pre-populated with a full set of options and not every option will be useable on all projectors. +* The following channels _aspectratio_, _colormode_, _luminance_, _gamma_ and _background_ are pre-populated with a full set of options but not every option will be useable on all projectors. * If your projector has an option in one of the above mentioned channels that is not recognized by the binding, the channel will display 'UNKNOWN' if that un-recognized option is selected by the remote control. +* The volume channel is a dimmer (0-100%) that is scaled to the range on the projector, either 0-20 or 0-40 per the maxVolume configuration setting. If your projector uses a different range, then the volume channel will not work. * If the projector power is switched to off in the middle of a polling operation, some of the channel values may become undefined until the projector is switched on again. * If the binding fails to connect to the projector using the direct IP connection, ensure that no password is configured on the projctor. @@ -56,36 +59,36 @@ Some notes: ## Channels -| Channel | Item Type | Purpose | Values | -| ------------------ | --------- | ----------------------------------------------------------------- | --------- | -| power | Switch | Powers the projector on or off. | | -| powerstate | String | Retrieves the textual power state of the projector. | Read only | -| source | String | Retrieve or set the input source. | See above | -| aspectratio | String | Retrieve or set the aspect ratio. | See above | -| colormode | String | Retrieve or set the color mode. | See above | -| freeze | Switch | Turn the freeze screen mode on or off. | | -| mute | Switch | Turn the AV mute on or off. | | -| volume | Number | Retrieve or set the volume. | 0 - +20 | -| luminance | String | Retrieve or set the lamp mode. | See above | -| brightness | Number | Retrieve or set the brightness. | -24 - +24 | -| contrast | Number | Retrieve or set the contrast. | -24 - +24 | -| density | Number | Retrieve or set the density (color saturation). | -32 - +32 | -| tint | Number | Retrieve or set the tint. | -32 - +32 | -| colortemperature | Number | Retrieve or set the color temperature. | 0 - +9 | -| fleshtemperature | Number | Retrieve or set the flesh temperature. | 0 - +6 | -| gamma | String | Retrieve or set the gamma setting. | See above | -| autokeystone | Switch | Turn the auto keystone mode on or off. | | -| verticalkeystone | Number | Retrieve or set the vertical keystone. | -30 - +30 | -| horizontalkeystone | Number | Retrieve or set the horizontal keystone. | -30 - +30 | -| verticalposition | Number | Retrieve or set the vertical position. | -8 - +10 | -| horizontalposition | Number | Retrieve or set the horizontal position. | -23 - +26 | -| verticalreverse | Switch | Turn the vertical reverse mode on or off. | | -| horizontalreverse | Switch | Turn the horizontal reverse mode on or off. | | -| background | String | Retrieve or set the background color/logo. | See above | -| keycode | String | Send a key operation command to the projector. (2 character code) | Send only | -| lamptime | Number | Retrieves the lamp hours. | Read only | -| errcode | Number | Retrieves the last error code. | Read only | -| errmessage | String | Retrieves the description of the last error. | Read only | +| Channel | Item Type | Purpose | Values | +| ------------------ | --------- | ------------------------------------------------------------------------------------------ | --------- | +| power | Switch | Powers the projector on or off. | | +| powerstate | String | Retrieves the textual power state of the projector. | Read only | +| source | String | Retrieve or set the input source. | See above | +| aspectratio | String | Retrieve or set the aspect ratio. | See above | +| colormode | String | Retrieve or set the color mode. | See above | +| freeze | Switch | Turn the freeze screen mode on or off. | | +| mute | Switch | Turn the AV mute on or off. | | +| volume | Dimmer | Retrieve or set the volume. Scaled to 0-20 or 0-40 on the projector per maxVolume setting. | 0% - 100% | +| luminance | String | Retrieve or set the lamp mode. | See above | +| brightness | Number | Retrieve or set the brightness. | -24 - +24 | +| contrast | Number | Retrieve or set the contrast. | -24 - +24 | +| density | Number | Retrieve or set the density (color saturation). | -32 - +32 | +| tint | Number | Retrieve or set the tint. | -32 - +32 | +| colortemperature | Number | Retrieve or set the color temperature. | 0 - +9 | +| fleshtemperature | Number | Retrieve or set the flesh temperature. | 0 - +6 | +| gamma | String | Retrieve or set the gamma setting. | See above | +| autokeystone | Switch | Turn the auto keystone mode on or off. | | +| verticalkeystone | Number | Retrieve or set the vertical keystone. | -30 - +30 | +| horizontalkeystone | Number | Retrieve or set the horizontal keystone. | -30 - +30 | +| verticalposition | Number | Retrieve or set the vertical position. | -8 - +10 | +| horizontalposition | Number | Retrieve or set the horizontal position. | -23 - +26 | +| verticalreverse | Switch | Turn the vertical reverse mode on or off. | | +| horizontalreverse | Switch | Turn the horizontal reverse mode on or off. | | +| background | String | Retrieve or set the background color/logo. | See above | +| keycode | String | Send a key operation command to the projector. (2 character code) | Send only | +| lamptime | Number | Retrieves the lamp hours. | Read only | +| errcode | Number | Retrieves the last error code. | Read only | +| errmessage | String | Retrieves the description of the last error. | Read only | ## Full Example @@ -93,10 +96,10 @@ things/epson.things: ``` // serial port connection -epsonprojector:projector-serial:hometheater "Projector" [ serialPort="COM5", pollingInterval=10 ] +epsonprojector:projector-serial:hometheater "Projector" [ serialPort="COM5", pollingInterval=10, maxVolume=20 ] // direct IP or serial over IP connection -epsonprojector:projector-tcp:hometheater "Projector" [ host="192.168.0.10", port=3629, pollingInterval=10 ] +epsonprojector:projector-tcp:hometheater "Projector" [ host="192.168.0.10", port=3629, pollingInterval=10, maxVolume=20 ] ``` @@ -109,7 +112,7 @@ String epsonAspectRatio "Aspect Ratio [%s]" { channel="epsonprojector String epsonColorMode "Color Mode [%s]" { channel="epsonprojector:projector-serial:hometheater:colormode" } Switch epsonFreeze { channel="epsonprojector:projector-serial:hometheater:freeze" } Switch epsonMute { channel="epsonprojector:projector-serial:hometheater:mute" } -Number epsonVolume { channel="epsonprojector:projector-serial:hometheater:volume" } +Dimmer epsonVolume { channel="epsonprojector:projector-serial:hometheater:volume" } String epsonLuminance "Lamp Mode [%s]" { channel="epsonprojector:projector-serial:hometheater:luminance" } Number epsonBrightness { channel="epsonprojector:projector-serial:hometheater:brightness" } @@ -139,14 +142,15 @@ String epsonErrMessage "Error Message [%s]" <"siren-off"> { channel="epsonproj sitemaps/epson.sitemap ``` -sitemap epson label="Epson Projector Demo" +sitemap epson label="Epson Projector" { Frame label="Controls" { Switch item=epsonPower label="Power" Selection item=epsonSource label="Source" mappings=["30"="HDMI1", "A0"="HDMI2", "14"="Component", "20"="PC DSUB", "41"="Video", "42"="S-Video"] Switch item=epsonFreeze label="Freeze" Switch item=epsonMute label="AV Mute" - Setpoint item=epsonVolume label="Volume" + // Volume can be a Setpoint also + Slider item=epsonVolume label="Volume" minValue=0 maxValue=100 step=1 icon="soundvolume" Switch item=epsonKeyCode label="Navigation" icon="screen" mappings=["03"="Menu", "35"="˄", "36"="˅", "37"="<", "38"=">", "16"="Enter"] } Frame label="Adjust Image" { diff --git a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorCommandType.java b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorCommandType.java index 0f9156b6c0604..7a9ac00ef8259 100644 --- a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorCommandType.java +++ b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorCommandType.java @@ -16,6 +16,7 @@ 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), diff --git a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorDevice.java b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorDevice.java index f1679c5c8bc47..6c6277497640f 100644 --- a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorDevice.java +++ b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/EpsonProjectorDevice.java @@ -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 void setScheduler(ScheduledExecutorService scheduler) { 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 void setGamma(Gamma value) throws EpsonProjectorCommandException, EpsonPr /* * 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; + } } } diff --git a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/configuration/EpsonProjectorConfiguration.java b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/configuration/EpsonProjectorConfiguration.java index 35d5327857625..78e2d4bf0f204 100644 --- a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/configuration/EpsonProjectorConfiguration.java +++ b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/configuration/EpsonProjectorConfiguration.java @@ -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; } diff --git a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/handler/EpsonProjectorHandler.java b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/handler/EpsonProjectorHandler.java index 2d8cc2ca41497..30cd57c77775d 100644 --- a/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/handler/EpsonProjectorHandler.java +++ b/bundles/org.openhab.binding.epsonprojector/src/main/java/org/openhab/binding/epsonprojector/internal/handler/EpsonProjectorHandler.java @@ -14,6 +14,7 @@ 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.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 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 void initialize() { 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 @@ private State queryDataFromDevice(EpsonProjectorCommandType commandType) { 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 @@ private void sendDataToDevice(EpsonProjectorCommandType commandType, Command com 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()); diff --git a/bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/thing/thing-types.xml index 6fb3e30778b52..afcc25e589b4b 100644 --- a/bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.epsonprojector/src/main/resources/OH-INF/thing/thing-types.xml @@ -9,14 +9,14 @@ An Epson projector which supports the ESC/VP21 protocol via a serial port connection - + - + @@ -50,6 +50,16 @@ Configures How Often to Poll the Projector for Updates (5-60; Default 10) 10 + + + Set to Match the Volume Range Seen in the Projector's OSD + true + + + + + 20 + @@ -60,14 +70,14 @@ IP connection - + - + @@ -108,15 +118,20 @@ Configures How Often to Poll the Projector for Updates (5-60; Default 10) 10 + + + Set to Match the Volume Range Seen in the Projector's OSD + true + + + + + 20 + - - Switch - - Powers the Projector On or Off - String @@ -302,12 +317,6 @@ - - Number - - Retrieve or Set the Volume - - Switch