2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.sonyprojector.internal.handler;
15 import static org.openhab.binding.sonyprojector.internal.SonyProjectorBindingConstants.*;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.sonyprojector.internal.SonyProjectorCommandDescriptionOptionProvider;
23 import org.openhab.binding.sonyprojector.internal.SonyProjectorException;
24 import org.openhab.binding.sonyprojector.internal.SonyProjectorModel;
25 import org.openhab.binding.sonyprojector.internal.SonyProjectorStateDescriptionOptionProvider;
26 import org.openhab.binding.sonyprojector.internal.communication.SonyProjectorConnector;
27 import org.openhab.binding.sonyprojector.internal.communication.SonyProjectorItem;
28 import org.openhab.binding.sonyprojector.internal.communication.SonyProjectorStatusPower;
29 import org.openhab.binding.sonyprojector.internal.communication.sdcp.SonyProjectorSdcpConnector;
30 import org.openhab.binding.sonyprojector.internal.communication.sdcp.SonyProjectorSdcpSimuConnector;
31 import org.openhab.binding.sonyprojector.internal.communication.serial.SonyProjectorSerialConnector;
32 import org.openhab.binding.sonyprojector.internal.communication.serial.SonyProjectorSerialOverIpConnector;
33 import org.openhab.binding.sonyprojector.internal.communication.serial.SonyProjectorSerialSimuConnector;
34 import org.openhab.binding.sonyprojector.internal.configuration.SonyProjectorEthernetConfiguration;
35 import org.openhab.binding.sonyprojector.internal.configuration.SonyProjectorSerialConfiguration;
36 import org.openhab.binding.sonyprojector.internal.configuration.SonyProjectorSerialOverIpConfiguration;
37 import org.openhab.core.cache.ExpiringCacheMap;
38 import org.openhab.core.i18n.ConnectionException;
39 import org.openhab.core.i18n.TranslationProvider;
40 import org.openhab.core.io.transport.serial.SerialPortManager;
41 import org.openhab.core.library.types.DecimalType;
42 import org.openhab.core.library.types.OnOffType;
43 import org.openhab.core.library.types.PercentType;
44 import org.openhab.core.library.types.StringType;
45 import org.openhab.core.thing.ChannelUID;
46 import org.openhab.core.thing.Thing;
47 import org.openhab.core.thing.ThingStatus;
48 import org.openhab.core.thing.ThingStatusDetail;
49 import org.openhab.core.thing.binding.BaseThingHandler;
50 import org.openhab.core.types.Command;
51 import org.openhab.core.types.RefreshType;
52 import org.openhab.core.types.State;
53 import org.openhab.core.types.UnDefType;
54 import org.osgi.framework.Bundle;
55 import org.osgi.framework.FrameworkUtil;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
60 * The {@link SonyProjectorHandler} is responsible for handling commands, which are
61 * sent to one of the channels.
63 * @author Markus Wehrle - Initial contribution
64 * @author Laurent Garnier - Refactoring, poll thread for regular channels updates, new serial thing type, new channels
65 * @author Laurent Garnier - Add new channel "ircommand"
68 public class SonyProjectorHandler extends BaseThingHandler {
70 private static final SonyProjectorModel DEFAULT_MODEL = SonyProjectorModel.VW520;
71 private static final long POLLING_INTERVAL = TimeUnit.SECONDS.toSeconds(15);
73 private final Logger logger = LoggerFactory.getLogger(SonyProjectorHandler.class);
75 private final SonyProjectorStateDescriptionOptionProvider stateDescriptionProvider;
76 private final SonyProjectorCommandDescriptionOptionProvider commandDescriptionProvider;
77 private final SerialPortManager serialPortManager;
78 private final TranslationProvider i18nProvider;
80 private final Bundle bundle;
82 private final ExpiringCacheMap<String, State> cache;
84 private @Nullable ScheduledFuture<?> refreshJob;
86 private boolean identifyProjector;
87 private SonyProjectorModel projectorModel = DEFAULT_MODEL;
88 private SonyProjectorConnector connector = new SonyProjectorSdcpSimuConnector(DEFAULT_MODEL);
92 private final Object commandLock = new Object();
94 public SonyProjectorHandler(Thing thing, SonyProjectorStateDescriptionOptionProvider stateDescriptionProvider,
95 SonyProjectorCommandDescriptionOptionProvider commandDescriptionProvider,
96 SerialPortManager serialPortManager, TranslationProvider i18nProvider) {
98 this.stateDescriptionProvider = stateDescriptionProvider;
99 this.commandDescriptionProvider = commandDescriptionProvider;
100 this.serialPortManager = serialPortManager;
101 this.i18nProvider = i18nProvider;
102 this.bundle = FrameworkUtil.getBundle(this.getClass());
103 this.cache = new ExpiringCacheMap<>(TimeUnit.SECONDS.toMillis(POLLING_INTERVAL));
107 public void handleCommand(ChannelUID channelUID, Command command) {
108 String channel = channelUID.getId();
109 if (command instanceof RefreshType) {
110 State state = cache.get(channel);
112 updateState(channel, state);
117 synchronized (commandLock) {
120 } catch (ConnectionException e) {
121 logger.debug("Command {} from channel {} failed: {}", command, channel,
122 e.getMessage(bundle, i18nProvider));
123 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getRawMessage());
129 if (command == OnOffType.ON) {
131 } else if (command == OnOffType.OFF) {
132 connector.powerOff();
134 throw new SonyProjectorException("Invalid command value");
138 connector.setInput(command.toString());
140 case CHANNEL_CALIBRATION_PRESET:
141 connector.setCalibrationPreset(command.toString());
142 refreshChannel(CHANNEL_CONTRAST, true);
143 refreshChannel(CHANNEL_BRIGHTNESS, true);
144 refreshChannel(CHANNEL_COLOR, true);
145 refreshChannel(CHANNEL_HUE, true);
146 refreshChannel(CHANNEL_SHARPNESS, true);
147 refreshChannel(CHANNEL_COLOR_TEMP, true);
148 refreshChannel(CHANNEL_IRIS_MODE, true);
149 refreshChannel(CHANNEL_IRIS_MANUAL, true);
150 refreshChannel(CHANNEL_IRIS_SENSITIVITY, true);
151 refreshChannel(CHANNEL_LAMP_CONTROL, true);
152 refreshChannel(CHANNEL_FILM_PROJECTION, true);
153 refreshChannel(CHANNEL_MOTION_ENHANCER, true);
154 refreshChannel(CHANNEL_CONTRAST_ENHANCER, true);
155 refreshChannel(CHANNEL_FILM_MODE, true);
156 refreshChannel(CHANNEL_GAMMA_CORRECTION, true);
157 refreshChannel(CHANNEL_COLOR_SPACE, true);
158 refreshChannel(CHANNEL_NR, true);
159 refreshChannel(CHANNEL_BLOCK_NR, true);
160 refreshChannel(CHANNEL_MOSQUITO_NR, true);
161 refreshChannel(CHANNEL_MPEG_NR, true);
162 refreshChannel(CHANNEL_XVCOLOR, true);
164 case CHANNEL_CONTRAST:
165 if (command instanceof DecimalType decimalCommand) {
166 connector.setContrast(decimalCommand.intValue());
167 } else if (command instanceof PercentType percentCommand) {
168 connector.setContrast(percentCommand.intValue());
170 throw new SonyProjectorException("Invalid command value");
173 case CHANNEL_BRIGHTNESS:
174 if (command instanceof DecimalType decimalCommand) {
175 connector.setBrightness(decimalCommand.intValue());
176 } else if (command instanceof PercentType percentCommand2) {
177 connector.setBrightness(percentCommand2.intValue());
179 throw new SonyProjectorException("Invalid command value");
183 if (command instanceof DecimalType decimalCommand) {
184 connector.setColor(decimalCommand.intValue());
185 } else if (command instanceof PercentType percentCommand3) {
186 connector.setColor(percentCommand3.intValue());
188 throw new SonyProjectorException("Invalid command value");
192 if (command instanceof DecimalType decimalCommand) {
193 connector.setHue(decimalCommand.intValue());
194 } else if (command instanceof PercentType percentCommand4) {
195 connector.setHue(percentCommand4.intValue());
197 throw new SonyProjectorException("Invalid command value");
200 case CHANNEL_SHARPNESS:
201 if (command instanceof DecimalType decimalCommand) {
202 connector.setSharpness(decimalCommand.intValue());
203 } else if (command instanceof PercentType percentCommand5) {
204 connector.setSharpness(percentCommand5.intValue());
206 throw new SonyProjectorException("Invalid command value");
209 case CHANNEL_COLOR_TEMP:
210 connector.setColorTemperature(command.toString());
212 case CHANNEL_IRIS_MODE:
213 connector.setIrisMode(command.toString());
214 refreshChannel(CHANNEL_IRIS_MANUAL, true);
216 case CHANNEL_IRIS_MANUAL:
217 if (command instanceof DecimalType decimalCommand) {
218 connector.setIrisManual(decimalCommand.intValue());
219 } else if (command instanceof PercentType percentCommand6) {
220 connector.setIrisManual(percentCommand6.intValue());
222 throw new SonyProjectorException("Invalid command value");
225 case CHANNEL_IRIS_SENSITIVITY:
226 connector.setIrisSensitivity(command.toString());
228 case CHANNEL_LAMP_CONTROL:
229 connector.setLampControl(command.toString());
231 case CHANNEL_FILM_PROJECTION:
232 connector.setFilmProjection(command.toString());
234 case CHANNEL_MOTION_ENHANCER:
235 connector.setMotionEnhancer(command.toString());
237 case CHANNEL_CONTRAST_ENHANCER:
238 connector.setContrastEnhancer(command.toString());
240 case CHANNEL_FILM_MODE:
241 connector.setFilmMode(command.toString());
243 case CHANNEL_GAMMA_CORRECTION:
244 connector.setGammaCorrection(command.toString());
246 case CHANNEL_COLOR_SPACE:
247 connector.setColorSpace(command.toString());
250 connector.setNr(command.toString());
252 case CHANNEL_BLOCK_NR:
253 connector.setBlockNr(command.toString());
255 case CHANNEL_MOSQUITO_NR:
256 connector.setMosquitoNr(command.toString());
258 case CHANNEL_MPEG_NR:
259 connector.setMpegNr(command.toString());
261 case CHANNEL_XVCOLOR:
262 if (command == OnOffType.ON) {
263 connector.enableXvColor();
264 refreshChannel(CHANNEL_GAMMA_CORRECTION, true);
265 } else if (command == OnOffType.OFF) {
266 connector.disableXvColor();
267 refreshChannel(CHANNEL_GAMMA_CORRECTION, true);
269 throw new SonyProjectorException("Invalid command value");
272 case CHANNEL_PICTURE_MUTING:
273 if (command == OnOffType.ON) {
274 connector.mutePicture();
275 } else if (command == OnOffType.OFF) {
276 connector.unmutePicture();
278 throw new SonyProjectorException("Invalid command value");
282 connector.setAspect(command.toString());
284 case CHANNEL_OVERSCAN:
285 if (command == OnOffType.ON) {
286 connector.enableOverscan();
287 } else if (command == OnOffType.OFF) {
288 connector.disableOverscan();
290 throw new SonyProjectorException("Invalid command value");
293 case CHANNEL_PICTURE_POSITION:
294 connector.setPicturePosition(command.toString());
296 case CHANNEL_IR_COMMAND:
297 connector.sendIrCommand(command.toString());
300 throw new SonyProjectorException("Unexpected command");
302 logger.debug("Command {} from channel {} succeeded", command, channel);
303 } catch (SonyProjectorException e) {
304 logger.debug("Command {} from channel {} failed: {}", command, channel, e.getMessage());
305 refreshChannel(channel, true);
312 public void initialize() {
313 logger.debug("Start initializing handler for thing {}", getThing().getUID());
315 boolean configOk = false;
317 if (getThing().getThingTypeUID().equals(THING_TYPE_ETHERNET)) {
318 SonyProjectorEthernetConfiguration config = getConfigAs(SonyProjectorEthernetConfiguration.class);
319 String configModel = config.model;
320 logger.debug("Ethernet config host {}", config.host);
321 logger.debug("Ethernet config port {}", config.port);
322 logger.debug("Ethernet config model {}", configModel);
323 logger.debug("Ethernet config community {}", config.community);
324 if (config.host == null || config.host.isEmpty()) {
325 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
326 "@text/offline.config-error-unknown-host");
327 } else if (configModel == null || configModel.isEmpty()) {
328 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
329 "@text/offline.config-error-unknown-model");
333 connector = simu ? new SonyProjectorSdcpSimuConnector(DEFAULT_MODEL)
334 : new SonyProjectorSdcpConnector(config.host, config.port, config.community, DEFAULT_MODEL);
335 identifyProjector = "AUTO".equals(configModel);
336 projectorModel = switchToModel("AUTO".equals(configModel) ? null : configModel, true);
338 updateStatus(ThingStatus.UNKNOWN);
340 } else if (getThing().getThingTypeUID().equals(THING_TYPE_SERIAL)) {
341 SonyProjectorSerialConfiguration config = getConfigAs(SonyProjectorSerialConfiguration.class);
342 String configModel = config.model;
343 logger.debug("Serial config port {}", config.port);
344 logger.debug("Serial config model {}", configModel);
345 if (config.port == null || config.port.isEmpty()) {
346 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
347 "@text/offline.config-error-unknown-port");
348 } else if (config.port.toLowerCase().startsWith("rfc2217")) {
349 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
350 "@text/offline.config-error-invalid-thing-type");
351 } else if (configModel == null || configModel.isEmpty()) {
352 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
353 "@text/offline.config-error-unknown-model");
357 connector = simu ? new SonyProjectorSerialSimuConnector(serialPortManager, DEFAULT_MODEL)
358 : new SonyProjectorSerialConnector(serialPortManager, config.port, DEFAULT_MODEL);
359 identifyProjector = false;
360 projectorModel = switchToModel(configModel, true);
362 updateStatus(ThingStatus.UNKNOWN);
364 } else if (getThing().getThingTypeUID().equals(THING_TYPE_SERIAL_OVER_IP)) {
365 SonyProjectorSerialOverIpConfiguration config = getConfigAs(SonyProjectorSerialOverIpConfiguration.class);
366 String configModel = config.model;
367 logger.debug("Serial over IP config host {}", config.host);
368 logger.debug("Serial over IP config port {}", config.port);
369 logger.debug("Serial over IP config model {}", configModel);
370 if (config.host == null || config.host.isEmpty()) {
371 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
372 "@text/offline.config-error-unknown-host");
373 } else if (config.port == null) {
374 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
375 "@text/offline.config-error-unknown-port");
376 } else if (config.port <= 0) {
377 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
378 "@text/offline.config-error-invalid-port");
379 } else if (configModel == null || configModel.isEmpty()) {
380 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
381 "@text/offline.config-error-unknown-model");
385 connector = simu ? new SonyProjectorSerialSimuConnector(serialPortManager, DEFAULT_MODEL)
386 : new SonyProjectorSerialOverIpConnector(serialPortManager, config.host, config.port,
388 identifyProjector = false;
389 projectorModel = switchToModel(configModel, true);
391 updateStatus(ThingStatus.UNKNOWN);
396 connector = new SonyProjectorSdcpSimuConnector(DEFAULT_MODEL);
398 ScheduledFuture<?> refreshJob = this.refreshJob;
399 if (refreshJob == null || refreshJob.isCancelled()) {
400 this.refreshJob = scheduler.scheduleWithFixedDelay(() -> {
402 }, 1, POLLING_INTERVAL, TimeUnit.SECONDS);
406 logger.debug("Finished initializing!");
410 public void dispose() {
411 logger.debug("Disposing handler for thing {}", getThing().getUID());
412 ScheduledFuture<?> refreshJob = this.refreshJob;
413 if (refreshJob != null && !refreshJob.isCancelled()) {
414 refreshJob.cancel(true);
415 this.refreshJob = null;
421 private void pollProjector() {
422 synchronized (commandLock) {
423 logger.debug("Polling the projector to refresh the channels...");
427 } catch (ConnectionException e) {
428 logger.debug("Poll projector failed: {}", e.getMessage(bundle, i18nProvider), e);
429 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getRawMessage());
433 boolean isOn = refreshPowerState();
435 refreshChannel(CHANNEL_INPUT, isOn);
436 refreshChannel(CHANNEL_CALIBRATION_PRESET, isOn);
437 refreshChannel(CHANNEL_CONTRAST, isOn);
438 refreshChannel(CHANNEL_BRIGHTNESS, isOn);
439 refreshChannel(CHANNEL_COLOR, isOn);
440 refreshChannel(CHANNEL_HUE, isOn);
441 refreshChannel(CHANNEL_SHARPNESS, isOn);
442 refreshChannel(CHANNEL_COLOR_TEMP, isOn);
443 refreshChannel(CHANNEL_IRIS_MODE, isOn);
444 refreshChannel(CHANNEL_IRIS_MANUAL, isOn);
445 refreshChannel(CHANNEL_IRIS_SENSITIVITY, isOn);
446 refreshChannel(CHANNEL_LAMP_CONTROL, isOn);
447 refreshChannel(CHANNEL_FILM_PROJECTION, isOn);
448 refreshChannel(CHANNEL_MOTION_ENHANCER, isOn);
449 refreshChannel(CHANNEL_CONTRAST_ENHANCER, isOn);
450 refreshChannel(CHANNEL_FILM_MODE, isOn);
451 refreshChannel(CHANNEL_GAMMA_CORRECTION, isOn);
452 refreshChannel(CHANNEL_COLOR_SPACE, isOn);
453 refreshChannel(CHANNEL_NR, isOn);
454 refreshChannel(CHANNEL_BLOCK_NR, isOn);
455 refreshChannel(CHANNEL_MOSQUITO_NR, isOn);
456 refreshChannel(CHANNEL_MPEG_NR, isOn);
457 refreshChannel(CHANNEL_XVCOLOR, isOn);
458 refreshChannel(CHANNEL_PICTURE_MUTING, isOn);
459 refreshChannel(CHANNEL_ASPECT, isOn);
460 refreshChannel(CHANNEL_OVERSCAN, isOn);
461 refreshChannel(CHANNEL_PICTURE_POSITION, isOn);
462 refreshChannel(CHANNEL_LAMP_USE_TIME, isOn);
466 updateStatus(ThingStatus.ONLINE);
468 logger.debug("End of the polling thread");
472 private void refreshModel() {
473 if (identifyProjector && getThing().getThingTypeUID().equals(THING_TYPE_ETHERNET)) {
475 String modelName = ((SonyProjectorSdcpConnector) connector).getModelName();
476 logger.debug("getModelName returned {}", modelName);
477 identifyProjector = false;
478 switchToModel(modelName, false);
479 } catch (SonyProjectorException e) {
480 logger.debug("getModelName failed: {}", e.getMessage());
485 private SonyProjectorModel switchToModel(@Nullable String modelName, boolean force) {
486 SonyProjectorModel model = DEFAULT_MODEL;
487 if (modelName != null && !modelName.isEmpty()) {
489 model = SonyProjectorModel.getFromName(modelName, false);
490 logger.debug("Model found: {}", model.getName());
491 } catch (SonyProjectorException e) {
492 logger.info("Model {} is unknow; consider {} by default", modelName, DEFAULT_MODEL.getName());
495 if (force || !model.getName().equals(projectorModel.getName())) {
496 connector.setModel(model);
497 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_INPUT),
498 model.getInputStateOptions());
499 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_CALIBRATION_PRESET),
500 model.getCalibrPresetStateOptions());
501 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_COLOR_TEMP),
502 model.getColorTempStateOptions());
503 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_IRIS_MODE),
504 model.getIrisModeStateOptions());
505 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_IRIS_SENSITIVITY),
506 model.getIrisSensitivityStateOptions());
507 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_LAMP_CONTROL),
508 model.getLampControlStateOptions());
509 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_FILM_PROJECTION),
510 model.getFilmProjectionStateOptions());
511 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_MOTION_ENHANCER),
512 model.getMotionEnhancerStateOptions());
513 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_CONTRAST_ENHANCER),
514 model.getContrastEnhancerStateOptions());
515 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_FILM_MODE),
516 model.getFilmModeStateOptions());
517 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_GAMMA_CORRECTION),
518 model.getGammaCorrectionStateOptions());
519 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_COLOR_SPACE),
520 model.getColorSpaceStateOptions());
521 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_NR),
522 model.getNrStateOptions());
523 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_BLOCK_NR),
524 model.getBlockNrStateOptions());
525 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_MOSQUITO_NR),
526 model.getMosquitoNrStateOptions());
527 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_MPEG_NR),
528 model.getMpegNrStateOptions());
529 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_ASPECT),
530 model.getAspectStateOptions());
531 stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_PICTURE_POSITION),
532 model.getPicturePositionStateOptions());
533 commandDescriptionProvider.setCommandOptions(new ChannelUID(getThing().getUID(), CHANNEL_IR_COMMAND),
534 SonyProjectorItem.getIRCommandOptions(model.getInputCommandOptions(),
535 model.getCalibrPresetCommandOptions(), model.getAspectCommandOptions()));
540 private boolean refreshPowerState() {
542 State state = UnDefType.UNDEF;
544 SonyProjectorStatusPower value = connector.getStatusPower();
545 logger.debug("Get Status Power returned {}", value);
547 state = new StringType(value.name());
548 } catch (SonyProjectorException e) {
549 logger.debug("Get Status Power failed: {}", e.getMessage());
551 updateChannelStateAndCache(CHANNEL_POWER, on ? OnOffType.ON : OnOffType.OFF);
552 updateChannelStateAndCache(CHANNEL_POWERSTATE, state);
556 private @Nullable State requestProjectorValue(String channel, boolean requestValue) {
561 case CHANNEL_POWERSTATE:
563 case CHANNEL_CALIBRATION_PRESET:
564 case CHANNEL_CONTRAST:
565 case CHANNEL_BRIGHTNESS:
568 case CHANNEL_SHARPNESS:
569 case CHANNEL_COLOR_TEMP:
570 case CHANNEL_CONTRAST_ENHANCER:
571 case CHANNEL_GAMMA_CORRECTION:
572 case CHANNEL_COLOR_SPACE:
574 case CHANNEL_PICTURE_MUTING:
578 case CHANNEL_IRIS_MODE:
579 precond = projectorModel.isIrisModeAvailable();
581 case CHANNEL_IRIS_MANUAL:
582 precond = projectorModel.isIrisManualAvailable();
584 case CHANNEL_IRIS_SENSITIVITY:
585 precond = projectorModel.isIrisSensitivityAvailable();
587 case CHANNEL_LAMP_CONTROL:
588 precond = projectorModel.isLampControlAvailable();
590 case CHANNEL_FILM_PROJECTION:
591 precond = projectorModel.isFilmProjectionAvailable();
593 case CHANNEL_MOTION_ENHANCER:
594 precond = projectorModel.isMotionEnhancerAvailable();
596 case CHANNEL_FILM_MODE:
597 precond = projectorModel.isFilmModeAvailable();
599 case CHANNEL_BLOCK_NR:
600 precond = projectorModel.isBlockNrAvailable();
602 case CHANNEL_MOSQUITO_NR:
603 precond = projectorModel.isMosquitoNrAvailable();
605 case CHANNEL_MPEG_NR:
606 precond = projectorModel.isMpegNrAvailable();
608 case CHANNEL_XVCOLOR:
609 precond = projectorModel.isXvColorAvailable();
611 case CHANNEL_OVERSCAN:
612 precond = projectorModel.isOverscanAvailable();
614 case CHANNEL_PICTURE_POSITION:
615 precond = projectorModel.isPicturePositionAvailable();
617 case CHANNEL_LAMP_USE_TIME:
618 precond = requestValue;
624 if (isLinked(channel) && precond) {
625 state = UnDefType.UNDEF;
630 state = connector.getStatusPower().isOn() ? OnOffType.ON : OnOffType.OFF;
632 case CHANNEL_POWERSTATE:
633 state = new StringType(connector.getStatusPower().name());
636 state = new StringType(connector.getInput());
638 case CHANNEL_CALIBRATION_PRESET:
639 state = new StringType(connector.getCalibrationPreset());
641 case CHANNEL_CONTRAST:
642 state = new PercentType(connector.getContrast());
644 case CHANNEL_BRIGHTNESS:
645 state = new PercentType(connector.getBrightness());
648 state = new PercentType(connector.getColor());
651 state = new PercentType(connector.getHue());
653 case CHANNEL_SHARPNESS:
654 state = new PercentType(connector.getSharpness());
656 case CHANNEL_COLOR_TEMP:
657 state = new StringType(connector.getColorTemperature());
659 case CHANNEL_IRIS_MODE:
660 state = new StringType(connector.getIrisMode());
662 case CHANNEL_IRIS_MANUAL:
663 state = new PercentType(connector.getIrisManual());
665 case CHANNEL_IRIS_SENSITIVITY:
666 state = new StringType(connector.getIrisSensitivity());
668 case CHANNEL_LAMP_CONTROL:
669 state = new StringType(connector.getLampControl());
671 case CHANNEL_FILM_PROJECTION:
672 state = new StringType(connector.getFilmProjection());
674 case CHANNEL_MOTION_ENHANCER:
675 state = new StringType(connector.getMotionEnhancer());
677 case CHANNEL_CONTRAST_ENHANCER:
678 state = new StringType(connector.getContrastEnhancer());
680 case CHANNEL_FILM_MODE:
681 state = new StringType(connector.getFilmMode());
683 case CHANNEL_GAMMA_CORRECTION:
684 state = new StringType(connector.getGammaCorrection());
686 case CHANNEL_COLOR_SPACE:
687 state = new StringType(connector.getColorSpace());
690 state = new StringType(connector.getNr());
692 case CHANNEL_BLOCK_NR:
693 state = new StringType(connector.getBlockNr());
695 case CHANNEL_MOSQUITO_NR:
696 state = new StringType(connector.getMosquitoNr());
698 case CHANNEL_MPEG_NR:
699 state = new StringType(connector.getMpegNr());
701 case CHANNEL_XVCOLOR:
702 state = connector.getXvColor();
704 case CHANNEL_PICTURE_MUTING:
705 state = connector.getPictureMuting();
708 state = new StringType(connector.getAspect());
710 case CHANNEL_OVERSCAN:
711 state = connector.getOverscan();
713 case CHANNEL_PICTURE_POSITION:
714 state = new StringType(connector.getPicturePosition());
716 case CHANNEL_LAMP_USE_TIME:
717 state = new DecimalType(connector.getLampUseTime());
722 logger.debug("Refresh channel {} with value {}", channel, state);
723 } catch (SonyProjectorException e) {
724 logger.debug("Refresh channel {} failed: {}", channel, e.getMessage());
731 private void refreshChannel(String channel, boolean requestValue) {
732 updateChannelStateAndCache(channel, requestProjectorValue(channel, requestValue));
735 private void updateChannelStateAndCache(String channel, @Nullable State state) {
737 updateState(channel, state);
739 if (!cache.containsKey(channel)) {
740 cache.put(channel, () -> {
741 synchronized (commandLock) {
742 return requestProjectorValue(channel, true);
746 cache.putValue(channel, state);