diff --git a/CHANGES.md b/CHANGES.md
index a3a55a290..400e99ae2 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,35 @@
## Fixes
* Log accessory names instead of futures. [#150](https://github.com/hap-java/HAP-Java/issues/150)
* Fix rotation speed data type (BREAKING API CHANGE). According to HAP specification it must be float
+* Close JsonWriters [#149](https://github.com/hap-java/HAP-Java/issues/149)
+* Fix UUID of HAP Version characteristic
+* Add Mute characteristic to Doorbell service
+
+## New
+* New characteristics:
+ * Identifier
+ * Input Device Type
+ * Input Source Type
+ * Configured Name
+ * Current Visibility State
+ * Target Visibility State
+ * Sleep Discovery Mode
+ * Active Identifier
+ * Closed Captions
+ * Current Media State
+ * Target Media State
+ * Picture Mode
+ * Power Mode
+ * Remote Key
+ * Volume Control Type
+ * Volume Selector
+ * AirPlay Enable
+
+* New services
+ * Input Source
+ * Television
+ * Television Speaker
+ * Smart Speaker
# HAP-Java 2.0.0
* major refactoring to support optional characteristics
diff --git a/README.md b/README.md
index 03fb0aaba..6d1f88458 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ Include HAP-Java in your project using maven:
io.github.hap-java
hap
- 2.0.0-SNAPSHOT
+ 2.0.1-SNAPSHOT
```
@@ -28,7 +28,7 @@ read the [Javadoc](https://hap-java.github.io/HAP-Java/apidocs/index.html)
Supported HomeKit Accessories
=========
-Current implementation fully supports 38 HomeKit accessory/services.
+Current implementation fully supports 42 HomeKit accessory/services.
| HomeKit Accessory & Service type | Supported by Java-HAP |
|--------------------|--------------------|
@@ -52,6 +52,7 @@ Current implementation fully supports 38 HomeKit accessory/services.
| Heater Cooler | :white_check_mark: |
| Humidifier Dehumidifier | :white_check_mark: |
| Humidity Sensor | :white_check_mark: |
+| Input Source | :white_check_mark: |
| Irrigation System | :white_check_mark: |
| Leak Sensor | :white_check_mark: |
| Light Bulb | :white_check_mark: |
@@ -66,12 +67,15 @@ Current implementation fully supports 38 HomeKit accessory/services.
| Service Label | :white_check_mark: |
| Siri | :x: |
| Slat | :white_check_mark: |
+| Smart Speaker | :white_check_mark: |
| Smoke Sensor | :white_check_mark: |
| Speaker | :white_check_mark: |
| Stateless Programmable Switch | :white_check_mark: |
| Switch | :white_check_mark: |
| Target Control | :x: |
| Target Control Management | :x: |
+| Television | :white_check_mark: |
+| Television Speaker | :white_check_mark: |
| Temperature Sensor | :white_check_mark: |
| Thermostat | :white_check_mark: |
| Valve | :white_check_mark: |
diff --git a/src/main/java/io/github/hapjava/accessories/InputSourceAccessory.java b/src/main/java/io/github/hapjava/accessories/InputSourceAccessory.java
new file mode 100644
index 000000000..cfa5ae3d6
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/InputSourceAccessory.java
@@ -0,0 +1,104 @@
+package io.github.hapjava.accessories;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.common.IsConfiguredEnum;
+import io.github.hapjava.characteristics.impl.inputsource.CurrentVisibilityStateEnum;
+import io.github.hapjava.characteristics.impl.inputsource.InputSourceTypeEnum;
+import io.github.hapjava.services.Service;
+import io.github.hapjava.services.impl.InputSourceService;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+
+/** Input Source accessory. */
+public interface InputSourceAccessory extends HomekitAccessory {
+
+ /**
+ * Retrieves configured name of input source.
+ *
+ * @return configured name of input source
+ */
+ CompletableFuture getConfiguredName();
+
+ /**
+ * Sets the configured name.
+ *
+ * @param name configured name
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setConfiguredName(String name) throws Exception;
+
+ /**
+ * Subscribes to changes in configured name.
+ *
+ * @param callback the function to call when the configured name changes.
+ */
+ void subscribeConfiguredName(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the configured name. */
+ void unsubscribeConfiguredName();
+
+ /**
+ * Retrieves the flag whether input source is configured.
+ *
+ * @return a future that will contain the flag .
+ */
+ CompletableFuture isConfigured();
+ /**
+ * set the flag whether input source is configured.
+ *
+ * @param state is configured state
+ * @return a future that completes when the change is made
+ */
+ CompletableFuture setIsConfigured(IsConfiguredEnum state);
+
+ /**
+ * Subscribes to changes in isConfigured.
+ *
+ * @param callback the function to call when the state changes.
+ */
+ void subscribeIsConfigured(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in isConfigured. */
+ void unsubscribeIsConfigured();
+
+ /**
+ * Retrieves the input source type.
+ *
+ * @return a future that will contain the input source type.
+ */
+ CompletableFuture getInputSourceType();
+
+ /**
+ * Subscribes to changes in input source type.
+ *
+ * @param callback the function to call when the type changes.
+ */
+ void subscribeInputSourceType(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the input source type. */
+ void unsubscribeInputSourceType();
+
+ /**
+ * Retrieves the current visibility state.
+ *
+ * @return a future that will contain the current visibility state.
+ */
+ CompletableFuture getCurrentVisibilityState();
+
+ /**
+ * Subscribes to changes in current visibility state.
+ *
+ * @param callback the function to call when the state changes.
+ */
+ void subscribeCurrentVisibilityState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the current visibility state. */
+ void unsubscribeCurrentVisibilityState();
+
+ @Override
+ default Collection getServices() {
+ return Collections.singleton(new InputSourceService(this));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/accessories/SmartSpeakerAccessory.java b/src/main/java/io/github/hapjava/accessories/SmartSpeakerAccessory.java
new file mode 100644
index 000000000..9f70af2be
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/SmartSpeakerAccessory.java
@@ -0,0 +1,62 @@
+package io.github.hapjava.accessories;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.television.CurrentMediaStateEnum;
+import io.github.hapjava.characteristics.impl.television.TargetMediaStateEnum;
+import io.github.hapjava.services.Service;
+import io.github.hapjava.services.impl.SmartSpeakerService;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+
+/** Smart Speaker accessory. */
+public interface SmartSpeakerAccessory extends HomekitAccessory {
+
+ /**
+ * Retrieves the current media state (see {@link
+ * io.github.hapjava.characteristics.impl.television.CurrentMediaStateEnum} for supported values).
+ *
+ * @return a future that will contain the current media state
+ */
+ CompletableFuture getCurrentMediaState();
+
+ /**
+ * Subscribes to changes in the current media state.
+ *
+ * @param callback the function to call when the current media state changes.
+ */
+ void subscribeCurrentMediaState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the current media state. */
+ void unsubscribeCurrentMediaState();
+
+ /**
+ * Retrieves the target media state (see {@link TargetMediaStateEnum} for supported values).
+ *
+ * @return a future that will contain the target media state
+ */
+ CompletableFuture getTargetMediaState();
+
+ /**
+ * Set the target media state (see {@link TargetMediaStateEnum} for supported values).
+ *
+ * @param targetMediaState target media state
+ * @return a future that completes when the change is made
+ */
+ CompletableFuture setTargetMediaState(TargetMediaStateEnum targetMediaState);
+
+ /**
+ * Subscribes to changes in the target media state.
+ *
+ * @param callback the function to call when the target media state changes.
+ */
+ void subscribeTargetMediaState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the target media state. */
+ void unsubscribeTargetMediaState();
+
+ @Override
+ default Collection getServices() {
+ return Collections.singleton(new SmartSpeakerService(this));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/accessories/TelevisionAccessory.java b/src/main/java/io/github/hapjava/accessories/TelevisionAccessory.java
new file mode 100644
index 000000000..b51efe319
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/TelevisionAccessory.java
@@ -0,0 +1,123 @@
+package io.github.hapjava.accessories;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.television.RemoteKeyEnum;
+import io.github.hapjava.characteristics.impl.television.SleepDiscoveryModeEnum;
+import io.github.hapjava.services.Service;
+import io.github.hapjava.services.impl.TelevisionService;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+
+/** Television accessory. */
+public interface TelevisionAccessory extends HomekitAccessory {
+
+ /**
+ * Retrieves the current active state of the TV.
+ *
+ * @return a future that will contain the state
+ */
+ CompletableFuture isActive();
+
+ /**
+ * Sets the active state of the TV
+ *
+ * @param state the state to set
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setActive(boolean state) throws Exception;
+
+ /**
+ * Subscribes to changes in the active state of the TV .
+ *
+ * @param callback the function to call when the active state changes.
+ */
+ void subscribeActive(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the active state of the TV. */
+ void unsubscribeActive();
+
+ /**
+ * Retrieves the active identifier
+ *
+ * @return a future that will contain the active identifier.
+ */
+ CompletableFuture getActiveIdentifier();
+
+ /**
+ * Sets the active identifier
+ *
+ * @param identifier the active identifier
+ * @return a future that completes when the active identifier is changed
+ * @throws Exception when the active identifier cannot be set
+ */
+ CompletableFuture setActiveIdentifier(Integer identifier) throws Exception;
+
+ /**
+ * Subscribes to changes in the active identifier.
+ *
+ * @param callback the function to call when the active identifier changes.
+ */
+ void subscribeActiveIdentifier(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the active identifier. */
+ void unsubscribeActiveIdentifier();
+
+ /**
+ * Retrieves configured name.
+ *
+ * @return configured name
+ */
+ CompletableFuture getConfiguredName();
+
+ /**
+ * Sets the configured name
+ *
+ * @param name configured name
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setConfiguredName(String name) throws Exception;
+
+ /**
+ * Subscribes to changes in configured name.
+ *
+ * @param callback the function to call when the configureed name changes.
+ */
+ void subscribeConfiguredName(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the configured name state. */
+ void unsubscribeConfiguredName();
+
+ /**
+ * Sends the remote key.
+ *
+ * @param key remote key
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setRemoteKey(RemoteKeyEnum key) throws Exception;
+
+ /**
+ * Retrieves the sleep discovery mode.
+ *
+ * @return a future that will contain the sleep discovery mode .
+ */
+ CompletableFuture getSleepDiscoveryMode();
+
+ /**
+ * Subscribes to changes in sleep discovery mode.
+ *
+ * @param callback the function to call when the sleep discovery mode changes.
+ */
+ void subscribeSleepDiscoveryMode(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the sleep discovery mode. */
+ void unsubscribeSleepDiscoveryMode();
+
+ @Override
+ default Collection getServices() {
+ return Collections.singleton(new TelevisionService(this));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/accessories/TelevisionSpeakerAccessory.java b/src/main/java/io/github/hapjava/accessories/TelevisionSpeakerAccessory.java
new file mode 100644
index 000000000..28df1437d
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/TelevisionSpeakerAccessory.java
@@ -0,0 +1,43 @@
+package io.github.hapjava.accessories;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.services.Service;
+import io.github.hapjava.services.impl.TelevisionSpeakerService;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+
+/** Television speaker accessory. */
+public interface TelevisionSpeakerAccessory extends HomekitAccessory {
+
+ /**
+ * Retrieves mute status.
+ *
+ * @return true if accessory is muted
+ */
+ CompletableFuture isMuted();
+
+ /**
+ * Sets the mute status
+ *
+ * @param mute true if accessory should be muted
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setMute(boolean mute) throws Exception;
+
+ /**
+ * Subscribes to changes in mute state.
+ *
+ * @param callback the function to call when the state changes.
+ */
+ void subscribeMuteState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the mute state. */
+ void unsubscribeMuteState();
+
+ @Override
+ default Collection getServices() {
+ return Collections.singleton(new TelevisionSpeakerService(this));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithActive.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithActive.java
new file mode 100644
index 000000000..4ad11be63
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithActive.java
@@ -0,0 +1,38 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.common.ActiveEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with active characteristic {@link
+ * io.github.hapjava.characteristics.impl.common.ActiveCharacteristic}.
+ */
+public interface AccessoryWithActive {
+
+ /**
+ * Retrieves the active state (see {@link
+ * io.github.hapjava.characteristics.impl.common.ActiveEnum} for supported values).
+ *
+ * @return a future that will contain the active state
+ */
+ CompletableFuture getActive();
+
+ /**
+ * Set the active state (see {@link ActiveEnum} for supported values).
+ *
+ * @param active active state
+ * @return a future that completes when the change is made
+ */
+ CompletableFuture setActive(ActiveEnum active);
+
+ /**
+ * Subscribes to changes in the active state.
+ *
+ * @param callback the function to call when the active state changes.
+ */
+ void subscribeActive(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the active state. */
+ void unsubscribeActive();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithAirPlayEnable.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithAirPlayEnable.java
new file mode 100644
index 000000000..76b90b43f
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithAirPlayEnable.java
@@ -0,0 +1,37 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with AirPlay enable characteristic {@link
+ * io.github.hapjava.characteristics.impl.common.AirPlayEnableCharacteristic}.
+ */
+public interface AccessoryWithAirPlayEnable {
+
+ /**
+ * Retrieves the AirPlay enable state
+ *
+ * @return a future that will contain the AirPlay enable state.
+ */
+ CompletableFuture getAirPlayEnable();
+
+ /**
+ * Sets the AirPlay enable state
+ *
+ * @param state AirPlay enable state
+ * @return a future that completes when the AirPlay enable is changed
+ * @throws Exception when the AirPlay enable cannot be set
+ */
+ CompletableFuture setAirPlayEnable(Integer state) throws Exception;
+
+ /**
+ * Subscribes to changes in the AirPlay enable state.
+ *
+ * @param callback the function to call when the AirPlay enable state changes.
+ */
+ void subscribeAirPlayEnable(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the AirPlay enable state. */
+ void unsubscribeAirPlayEnable();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithClosedCaptions.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithClosedCaptions.java
new file mode 100644
index 000000000..c13da3289
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithClosedCaptions.java
@@ -0,0 +1,37 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.television.ClosedCaptionsEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with closed captions characteristic {@link
+ * io.github.hapjava.characteristics.impl.television.ClosedCaptionsCharacteristic}.
+ */
+public interface AccessoryWithClosedCaptions {
+
+ /**
+ * Retrieves the closed captions state (see {@link ClosedCaptionsEnum} for supported values).
+ *
+ * @return a future that will contain the closed captions
+ */
+ CompletableFuture getClosedCaptions();
+
+ /**
+ * Set the closed captions state (see {@link ClosedCaptionsEnum} for supported values).
+ *
+ * @param closedCaptions closed captions
+ * @return a future that completes when the change is made
+ */
+ CompletableFuture setClosedCaptions(ClosedCaptionsEnum closedCaptions);
+
+ /**
+ * Subscribes to changes in the closed captions.
+ *
+ * @param callback the function to call when the closed captions changes.
+ */
+ void subscribeClosedCaptions(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the closed captions. */
+ void unsubscribeClosedCaptions();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithConfiguredName.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithConfiguredName.java
new file mode 100644
index 000000000..0c9528130
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithConfiguredName.java
@@ -0,0 +1,34 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import java.util.concurrent.CompletableFuture;
+
+/** Accessory with configured name. */
+public interface AccessoryWithConfiguredName {
+
+ /**
+ * Retrieves configured name.
+ *
+ * @return configured name
+ */
+ CompletableFuture getConfiguredName();
+
+ /**
+ * Sets the configured name
+ *
+ * @param name configured name
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setConfiguredName(String name) throws Exception;
+
+ /**
+ * Subscribes to changes in configured name.
+ *
+ * @param callback the function to call when the configureed name changes.
+ */
+ void subscribeConfiguredName(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the configured name state. */
+ void unsubscribeConfiguredName();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCurrentMediaState.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCurrentMediaState.java
new file mode 100644
index 000000000..22350d9b4
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithCurrentMediaState.java
@@ -0,0 +1,30 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.television.CurrentMediaStateEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with current media state characteristic {@link
+ * io.github.hapjava.characteristics.impl.television.CurrentMediaStateCharacteristic}.
+ */
+public interface AccessoryWithCurrentMediaState {
+
+ /**
+ * Retrieves the current media state (see {@link
+ * io.github.hapjava.characteristics.impl.television.CurrentMediaStateEnum} for supported values).
+ *
+ * @return a future that will contain the current media state
+ */
+ CompletableFuture getCurrentMediaState();
+
+ /**
+ * Subscribes to changes in the current media state.
+ *
+ * @param callback the function to call when the current media state changes.
+ */
+ void subscribeCurrentMediaState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the current media state. */
+ void unsubscribeCurrentMediaState();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithIdentifier.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithIdentifier.java
new file mode 100644
index 000000000..b181d4d99
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithIdentifier.java
@@ -0,0 +1,17 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with identifier characteristic {@link
+ * io.github.hapjava.characteristics.impl.common.IdentifierCharacteristic}.
+ */
+public interface AccessoryWithIdentifier {
+
+ /**
+ * Retrieves the identifier of service.
+ *
+ * @return a future with the identifier
+ */
+ CompletableFuture getIdentifier();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithInputDeviceType.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithInputDeviceType.java
new file mode 100644
index 000000000..fca5f5df1
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithInputDeviceType.java
@@ -0,0 +1,29 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.inputsource.InputDeviceTypeEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with input devices, e.g. television. {@link
+ * io.github.hapjava.characteristics.impl.inputsource.InputDeviceTypeCharacteristic}
+ */
+public interface AccessoryWithInputDeviceType {
+
+ /**
+ * Retrieves the input device type. See {@link InputDeviceTypeEnum} for supported values.
+ *
+ * @return a future with the value
+ */
+ CompletableFuture getInputDeviceType();
+
+ /**
+ * Subscribes to changes in input device type.
+ *
+ * @param callback the function when the input device type changes
+ */
+ void subscribeInputDeviceType(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes */
+ void unsubscribeInputDeviceType();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithMute.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithMute.java
new file mode 100644
index 000000000..a0bb08579
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithMute.java
@@ -0,0 +1,37 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with mute characteristic {@link
+ * io.github.hapjava.characteristics.impl.audio.MuteCharacteristic}.
+ */
+public interface AccessoryWithMute {
+
+ /**
+ * Retrieves mute status.
+ *
+ * @return true if accessory is muted
+ */
+ CompletableFuture isMuted();
+
+ /**
+ * Sets the mute status
+ *
+ * @param mute true if accessory should be muted
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setMute(boolean mute) throws Exception;
+
+ /**
+ * Subscribes to changes in mute state.
+ *
+ * @param callback the function to call when the state changes.
+ */
+ void subscribeMuteState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the mute state. */
+ void unsubscribeMuteState();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPictureMode.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPictureMode.java
new file mode 100644
index 000000000..b369b98bf
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPictureMode.java
@@ -0,0 +1,39 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.television.PictureModeEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with picture mode characteristic {@link
+ * io.github.hapjava.characteristics.impl.television.PictureModeCharacteristic}.
+ */
+public interface AccessoryWithPictureMode {
+
+ /**
+ * Retrieves the picture mode (see {@link
+ * io.github.hapjava.characteristics.impl.television.PictureModeEnum} for supported values).
+ *
+ * @return a future that will contain the picture mode
+ */
+ CompletableFuture getPictureMode();
+
+ /**
+ * Set the picture mode (see {@link
+ * io.github.hapjava.characteristics.impl.television.PictureModeEnum} for supported values).
+ *
+ * @param pictureMode picture mode
+ * @return a future that completes when the change is made
+ */
+ CompletableFuture setPictureMode(PictureModeEnum pictureMode);
+
+ /**
+ * Subscribes to changes in the picture mode.
+ *
+ * @param callback the function to call when the picture mode changes.
+ */
+ void subscribePictureMode(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the picture mode. */
+ void unsubscribePictureMode();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPowerMode.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPowerMode.java
new file mode 100644
index 000000000..5abb7e6f1
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithPowerMode.java
@@ -0,0 +1,16 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.impl.television.PowerModeEnum;
+import java.util.concurrent.CompletableFuture;
+
+/** An accessory with power mode. */
+public interface AccessoryWithPowerMode {
+
+ /**
+ * Set the power mode. See {@link PowerModeEnum} for supported values
+ *
+ * @param mode target power mode
+ * @return a future that completes when the change is made
+ */
+ CompletableFuture setPowerMode(PowerModeEnum mode);
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithTargetMediaState.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithTargetMediaState.java
new file mode 100644
index 000000000..e1f1a34bd
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithTargetMediaState.java
@@ -0,0 +1,37 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.television.TargetMediaStateEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with target media state characteristic {@link
+ * io.github.hapjava.characteristics.impl.television.TargetMediaStateCharacteristic}.
+ */
+public interface AccessoryWithTargetMediaState {
+
+ /**
+ * Retrieves the target media state (see {@link TargetMediaStateEnum} for supported values).
+ *
+ * @return a future that will contain the target media state
+ */
+ CompletableFuture getTargetMediaState();
+
+ /**
+ * Set the target media state (see {@link TargetMediaStateEnum} for supported values).
+ *
+ * @param targetMediaState target media state
+ * @return a future that completes when the change is made
+ */
+ CompletableFuture setTargetMediaState(TargetMediaStateEnum targetMediaState);
+
+ /**
+ * Subscribes to changes in the target media state.
+ *
+ * @param callback the function to call when the target media state changes.
+ */
+ void subscribeTargetMediaState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the target media state. */
+ void unsubscribeTargetMediaState();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithTargetVisibilityState.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithTargetVisibilityState.java
new file mode 100644
index 000000000..dcadd1cc5
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithTargetVisibilityState.java
@@ -0,0 +1,36 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.inputsource.TargetVisibilityStateEnum;
+import java.util.concurrent.CompletableFuture;
+
+/** accessory with target visibility state characteristics. */
+public interface AccessoryWithTargetVisibilityState {
+
+ /**
+ * Retrieves the target visibility state.
+ *
+ * @return a future that will contain the target visibility state
+ */
+ CompletableFuture getTargetVisibilityState();
+
+ /**
+ * Sets the target visibility state
+ *
+ * @param state the target visibility state to set
+ * @return a future that completes when the change is made
+ * @throws Exception when the change cannot be made
+ */
+ CompletableFuture setTargetVisibilityState(TargetVisibilityStateEnum state)
+ throws Exception;
+
+ /**
+ * Subscribes to changes in t target visibility state.
+ *
+ * @param callback the function to call when the target visibility state changes.
+ */
+ void subscribeTargetVisibilityState(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the target visibility state. */
+ void unsubscribeTargetVisibilityState();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVolumeControlType.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVolumeControlType.java
new file mode 100644
index 000000000..21a6f6c66
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVolumeControlType.java
@@ -0,0 +1,30 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeControlTypeEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with volume control type {@link
+ * io.github.hapjava.characteristics.impl.televisionspeaker.VolumeControlTypeCharacteristic}
+ */
+public interface AccessoryWithVolumeControlType {
+
+ /**
+ * Retrieves the current volume control type. see {@link VolumeControlTypeEnum} for possible
+ * values
+ *
+ * @return a future that will contain the type.
+ */
+ CompletableFuture getVolumeControlType();
+
+ /**
+ * Subscribes to changes in the volume.
+ *
+ * @param callback the function to call when the state changes.
+ */
+ void subscribeVolumeControlType(HomekitCharacteristicChangeCallback callback);
+
+ /** Unsubscribes from changes in the volume. */
+ void unsubscribeVolumeControlType();
+}
diff --git a/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVolumeSelector.java b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVolumeSelector.java
new file mode 100644
index 000000000..0c2a2890f
--- /dev/null
+++ b/src/main/java/io/github/hapjava/accessories/optionalcharacteristic/AccessoryWithVolumeSelector.java
@@ -0,0 +1,20 @@
+package io.github.hapjava.accessories.optionalcharacteristic;
+
+import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeSelectorEnum;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Accessory with volume selector {@link
+ * io.github.hapjava.characteristics.impl.televisionspeaker.VolumeSelectorCharacteristic}
+ */
+public interface AccessoryWithVolumeSelector {
+
+ /**
+ * Sets the volume selector
+ *
+ * @param value the volume selector
+ * @return a future that completes when the volume selector is changed
+ * @throws Exception when the volume selector cannot be set
+ */
+ CompletableFuture setVolumeSelector(VolumeSelectorEnum value) throws Exception;
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/base/StringCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/base/StringCharacteristic.java
new file mode 100644
index 000000000..4373b06c9
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/base/StringCharacteristic.java
@@ -0,0 +1,80 @@
+package io.github.hapjava.characteristics.impl.base;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+
+/**
+ * A characteristic that provides an string value.
+ *
+ * @author Eugen Freiter
+ */
+public class StringCharacteristic extends BaseCharacteristic {
+ private final Optional>> getter;
+ private final Optional> setter;
+ /**
+ * Default constructor
+ *
+ * @param type a string containing a UUID that indicates the type of characteristic. Apple defines
+ * a set of these, however implementors can create their own as well.
+ * @param description a description of the characteristic to be passed to the consuming device.
+ * @param getter getter to retrieve the value
+ * @param setter setter for value
+ * @param subscriber subscriber to subscribe to changes
+ * @param unsubscriber unsubscriber to unsubscribe from chnages
+ */
+ public StringCharacteristic(
+ String type,
+ String description,
+ Optional>> getter,
+ Optional> setter,
+ Optional> subscriber,
+ Optional unsubscriber) {
+ super(
+ type,
+ "string",
+ description,
+ getter.isPresent(),
+ setter.isPresent(),
+ subscriber,
+ unsubscriber);
+ this.getter = getter;
+ this.setter = setter;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected CompletableFuture makeBuilder(int iid) {
+ return super.makeBuilder(iid);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String convert(JsonValue jsonValue) {
+ return ((JsonString) jsonValue).getString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setValue(String value) throws Exception {
+ setter.get().accept(value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected CompletableFuture getValue() {
+ return getter.map(stringGetter -> stringGetter.get()).get();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getDefault() {
+ return "Unknown";
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/common/ActiveIdentifierCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/common/ActiveIdentifierCharacteristic.java
new file mode 100644
index 000000000..587c1b666
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/common/ActiveIdentifierCharacteristic.java
@@ -0,0 +1,29 @@
+package io.github.hapjava.characteristics.impl.common;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.IntegerCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class ActiveIdentifierCharacteristic extends IntegerCharacteristic {
+
+ public ActiveIdentifierCharacteristic(
+ Supplier> getter,
+ ExceptionalConsumer setter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000E7-0000-1000-8000-0026BB765291",
+ "active identifier",
+ 0,
+ 1000,
+ "",
+ Optional.of(getter),
+ Optional.of(setter),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/common/AirPlayEnableCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/common/AirPlayEnableCharacteristic.java
new file mode 100644
index 000000000..6158f13be
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/common/AirPlayEnableCharacteristic.java
@@ -0,0 +1,32 @@
+package io.github.hapjava.characteristics.impl.common;
+
+import io.github.hapjava.characteristics.EventableCharacteristic;
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.IntegerCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** characteristic to control air play. */
+public class AirPlayEnableCharacteristic extends IntegerCharacteristic
+ implements EventableCharacteristic {
+
+ public AirPlayEnableCharacteristic(
+ Supplier> getter,
+ ExceptionalConsumer setter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "0000025B-0000-1000-8000-0026BB765291",
+ "AirPlay enable",
+ 0,
+ 1,
+ "",
+ Optional.of(getter),
+ Optional.of(setter),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/common/ConfiguredNameCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/common/ConfiguredNameCharacteristic.java
new file mode 100644
index 000000000..471d5a368
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/common/ConfiguredNameCharacteristic.java
@@ -0,0 +1,27 @@
+package io.github.hapjava.characteristics.impl.common;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.StringCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** This characteristic describes a configured name. */
+public class ConfiguredNameCharacteristic extends StringCharacteristic {
+
+ public ConfiguredNameCharacteristic(
+ Supplier> getter,
+ ExceptionalConsumer setter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000E3-0000-1000-8000-0026BB765291",
+ "configured name",
+ Optional.of(getter),
+ Optional.of(setter),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/common/IdentifierCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/common/IdentifierCharacteristic.java
new file mode 100644
index 000000000..4b8f7613c
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/common/IdentifierCharacteristic.java
@@ -0,0 +1,22 @@
+package io.github.hapjava.characteristics.impl.common;
+
+import io.github.hapjava.characteristics.impl.base.IntegerCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Supplier;
+
+public class IdentifierCharacteristic extends IntegerCharacteristic {
+
+ public IdentifierCharacteristic(Supplier> getter) {
+ super(
+ "000000E6-0000-1000-8000-0026BB765291",
+ "identifier",
+ 0,
+ 1000,
+ "",
+ Optional.of(getter),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty());
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/common/VersionCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/common/VersionCharacteristic.java
index 038c46c5c..75c8aaf9e 100644
--- a/src/main/java/io/github/hapjava/characteristics/impl/common/VersionCharacteristic.java
+++ b/src/main/java/io/github/hapjava/characteristics/impl/common/VersionCharacteristic.java
@@ -10,7 +10,7 @@ public class VersionCharacteristic extends StaticStringCharacteristic {
public VersionCharacteristic(Supplier> getter) {
super(
- "00000023-0000-1000-8000-0026BB765291",
+ "00000037-0000-1000-8000-0026BB765291",
"HAP version",
Optional.of(getter),
Optional.empty(),
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/CurrentVisibilityStateCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/CurrentVisibilityStateCharacteristic.java
new file mode 100644
index 000000000..65c358a3f
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/CurrentVisibilityStateCharacteristic.java
@@ -0,0 +1,27 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** This characteristic describes current visibility state. */
+public class CurrentVisibilityStateCharacteristic
+ extends EnumCharacteristic {
+
+ public CurrentVisibilityStateCharacteristic(
+ Supplier> getter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "00000135-0000-1000-8000-0026BB765291",
+ "current visibility state",
+ CurrentVisibilityStateEnum.values(),
+ Optional.of(getter),
+ Optional.empty(),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/CurrentVisibilityStateEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/CurrentVisibilityStateEnum.java
new file mode 100644
index 000000000..2159393d8
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/CurrentVisibilityStateEnum.java
@@ -0,0 +1,36 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public enum CurrentVisibilityStateEnum implements CharacteristicEnum {
+ SHOWN(0),
+ HIDDEN(1),
+ UNKNOWN_1(2),
+ UNKNOWN_2(3);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(CurrentVisibilityStateEnum.values())
+ .collect(Collectors.toMap(CurrentVisibilityStateEnum::getCode, t -> t));
+ }
+
+ public static CurrentVisibilityStateEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ CurrentVisibilityStateEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputDeviceTypeCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputDeviceTypeCharacteristic.java
new file mode 100644
index 000000000..51a6fbde5
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputDeviceTypeCharacteristic.java
@@ -0,0 +1,26 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** This characteristic describes input device type. */
+public class InputDeviceTypeCharacteristic extends EnumCharacteristic {
+
+ public InputDeviceTypeCharacteristic(
+ Supplier> getter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000DC-0000-1000-8000-0026BB765291",
+ "input device type",
+ InputDeviceTypeEnum.values(),
+ Optional.of(getter),
+ Optional.empty(),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputDeviceTypeEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputDeviceTypeEnum.java
new file mode 100644
index 000000000..5c7337174
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputDeviceTypeEnum.java
@@ -0,0 +1,38 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public enum InputDeviceTypeEnum implements CharacteristicEnum {
+ OTHER(0),
+ TV(1),
+ RECORDING(2),
+ TUNER(3),
+ PLAYBACK(4),
+ AUDIO_SYSTEM(5);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(InputDeviceTypeEnum.values())
+ .collect(Collectors.toMap(InputDeviceTypeEnum::getCode, t -> t));
+ }
+
+ public static InputDeviceTypeEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ InputDeviceTypeEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputSourceTypeCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputSourceTypeCharacteristic.java
new file mode 100644
index 000000000..91134891b
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputSourceTypeCharacteristic.java
@@ -0,0 +1,26 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** This characteristic describes input source type. */
+public class InputSourceTypeCharacteristic extends EnumCharacteristic {
+
+ public InputSourceTypeCharacteristic(
+ Supplier> getter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000DB-0000-1000-8000-0026BB765291",
+ "input source type",
+ InputSourceTypeEnum.values(),
+ Optional.of(getter),
+ Optional.empty(),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputSourceTypeEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputSourceTypeEnum.java
new file mode 100644
index 000000000..94545ec18
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/InputSourceTypeEnum.java
@@ -0,0 +1,43 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public enum InputSourceTypeEnum implements CharacteristicEnum {
+ OTHER(0),
+ HOME_SCREEN(1),
+ TUNER(2),
+ HDMI(3),
+ COMPOSITE_VIDEO(4),
+ S_VIDEO(5),
+ COMPONENT_VIDEO(6),
+ DVI(7),
+ AIRPLAY(8),
+ USB(9),
+ APPLICATION(10);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(InputSourceTypeEnum.values())
+ .collect(Collectors.toMap(InputSourceTypeEnum::getCode, t -> t));
+ }
+
+ public static InputSourceTypeEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ InputSourceTypeEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/TargetVisibilityStateCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/TargetVisibilityStateCharacteristic.java
new file mode 100644
index 000000000..ea466d182
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/TargetVisibilityStateCharacteristic.java
@@ -0,0 +1,29 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** This characteristic describes target visibility state. */
+public class TargetVisibilityStateCharacteristic
+ extends EnumCharacteristic {
+
+ public TargetVisibilityStateCharacteristic(
+ Supplier> getter,
+ ExceptionalConsumer setter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "00000134-0000-1000-8000-0026BB765291",
+ "target visibility state",
+ TargetVisibilityStateEnum.values(),
+ Optional.of(getter),
+ Optional.of(setter),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/inputsource/TargetVisibilityStateEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/TargetVisibilityStateEnum.java
new file mode 100644
index 000000000..6a75b0c30
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/inputsource/TargetVisibilityStateEnum.java
@@ -0,0 +1,34 @@
+package io.github.hapjava.characteristics.impl.inputsource;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public enum TargetVisibilityStateEnum implements CharacteristicEnum {
+ SHOWN(0),
+ HIDDEN(1);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(TargetVisibilityStateEnum.values())
+ .collect(Collectors.toMap(TargetVisibilityStateEnum::getCode, t -> t));
+ }
+
+ public static TargetVisibilityStateEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ TargetVisibilityStateEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/ClosedCaptionsCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/television/ClosedCaptionsCharacteristic.java
new file mode 100644
index 000000000..a963ca222
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/ClosedCaptionsCharacteristic.java
@@ -0,0 +1,31 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Characteristic indicates whether the service provides closed captions. See {@link
+ * ClosedCaptionsEnum} for possible values.
+ */
+public class ClosedCaptionsCharacteristic extends EnumCharacteristic {
+
+ public ClosedCaptionsCharacteristic(
+ Supplier> getter,
+ ExceptionalConsumer setter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000DD-0000-1000-8000-0026BB765291",
+ "closed captions",
+ ClosedCaptionsEnum.values(),
+ Optional.of(getter),
+ Optional.of(setter),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/ClosedCaptionsEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/television/ClosedCaptionsEnum.java
new file mode 100644
index 000000000..2eb994149
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/ClosedCaptionsEnum.java
@@ -0,0 +1,35 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/** 0 ”Disabled” 1 ”Enabled” 2-255 ”Reserved” */
+public enum ClosedCaptionsEnum implements CharacteristicEnum {
+ DISABLED(0),
+ ENABLED(1);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(ClosedCaptionsEnum.values())
+ .collect(Collectors.toMap(ClosedCaptionsEnum::getCode, t -> t));
+ }
+
+ public static ClosedCaptionsEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ ClosedCaptionsEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/CurrentMediaStateCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/television/CurrentMediaStateCharacteristic.java
new file mode 100644
index 000000000..ca72c4ee9
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/CurrentMediaStateCharacteristic.java
@@ -0,0 +1,28 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * This characteristic indicates current media state. See {@link CurrentMediaStateEnum} for possible
+ * values.
+ */
+public class CurrentMediaStateCharacteristic extends EnumCharacteristic {
+ public CurrentMediaStateCharacteristic(
+ Supplier> getter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000E0-0000-1000-8000-0026BB765291",
+ "current media state",
+ CurrentMediaStateEnum.values(),
+ Optional.of(getter),
+ Optional.empty(),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/CurrentMediaStateEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/television/CurrentMediaStateEnum.java
new file mode 100644
index 000000000..83836c4c6
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/CurrentMediaStateEnum.java
@@ -0,0 +1,37 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/** 0 ”Play” 1 ”Pause” 2 "Stop" 3 "Unknown" 4-255 ”Reserved” */
+public enum CurrentMediaStateEnum implements CharacteristicEnum {
+ PLAY(0),
+ PAUSE(1),
+ STOP(2),
+ UNKNOWN(3);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(CurrentMediaStateEnum.values())
+ .collect(Collectors.toMap(CurrentMediaStateEnum::getCode, t -> t));
+ }
+
+ public static CurrentMediaStateEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ CurrentMediaStateEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/PictureModeCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/television/PictureModeCharacteristic.java
new file mode 100644
index 000000000..7efefa23a
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/PictureModeCharacteristic.java
@@ -0,0 +1,30 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * This characteristic retrieves / sets picture mode. See {@link PictureModeEnum} for possible
+ * values.
+ */
+public class PictureModeCharacteristic extends EnumCharacteristic {
+ public PictureModeCharacteristic(
+ Supplier> getter,
+ ExceptionalConsumer setter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000E2-0000-1000-8000-0026BB765291",
+ "picture mode",
+ PictureModeEnum.values(),
+ Optional.of(getter),
+ Optional.of(setter),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/PictureModeEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/television/PictureModeEnum.java
new file mode 100644
index 000000000..ac387cf65
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/PictureModeEnum.java
@@ -0,0 +1,44 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 0 ”Other” 1 ”Standard” 2 "Calibrated" 3 "CalibratedDark" 4 "Vivid" 5 "Game" 6 "Computer" 7
+ * "Custom" 8-255 ”Reserved”
+ */
+public enum PictureModeEnum implements CharacteristicEnum {
+ OTHER(0),
+ STANDARD(1),
+ CALIBRATED(2),
+ CALIBRATED_DARK(3),
+ VIVID(4),
+ GAME(5),
+ COMPUTER(6),
+ CUSTOM(7);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(PictureModeEnum.values())
+ .collect(Collectors.toMap(PictureModeEnum::getCode, t -> t));
+ }
+
+ public static PictureModeEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ PictureModeEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/PowerModeCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/television/PowerModeCharacteristic.java
new file mode 100644
index 000000000..cebbe4124
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/PowerModeCharacteristic.java
@@ -0,0 +1,20 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+
+/** characteristic sets power mode. See {@link PowerModeEnum} for possible values. */
+public class PowerModeCharacteristic extends EnumCharacteristic {
+
+ public PowerModeCharacteristic(ExceptionalConsumer setter) {
+ super(
+ "000000DF-0000-1000-8000-0026BB765291",
+ "power mode selection",
+ PowerModeEnum.values(),
+ Optional.empty(),
+ Optional.of(setter),
+ Optional.empty(),
+ Optional.empty());
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/PowerModeEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/television/PowerModeEnum.java
new file mode 100644
index 000000000..a171ba135
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/PowerModeEnum.java
@@ -0,0 +1,35 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/** 0 ”Show” 1 ”Hide” 2-255 ”Reserved” */
+public enum PowerModeEnum implements CharacteristicEnum {
+ SHOW(0),
+ HIDE(1);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(PowerModeEnum.values())
+ .collect(Collectors.toMap(PowerModeEnum::getCode, t -> t));
+ }
+
+ public static PowerModeEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ PowerModeEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/RemoteKeyCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/television/RemoteKeyCharacteristic.java
new file mode 100644
index 000000000..fe028d10d
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/RemoteKeyCharacteristic.java
@@ -0,0 +1,22 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+
+/**
+ * This characteristic sends information about pressed key on tv remote. See {@link RemoteKeyEnum}
+ * for possible values.
+ */
+public class RemoteKeyCharacteristic extends EnumCharacteristic {
+ public RemoteKeyCharacteristic(ExceptionalConsumer setter) {
+ super(
+ "000000E1-0000-1000-8000-0026BB765291",
+ "remote key",
+ RemoteKeyEnum.values(),
+ Optional.empty(),
+ Optional.of(setter),
+ Optional.empty(),
+ Optional.empty());
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/RemoteKeyEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/television/RemoteKeyEnum.java
new file mode 100644
index 000000000..443c23644
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/RemoteKeyEnum.java
@@ -0,0 +1,45 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public enum RemoteKeyEnum implements CharacteristicEnum {
+ REWIND(0),
+ FAST_FORWARD(1),
+ NEXT_TRACK(2),
+ PREV_TRACK(3),
+ ARROW_UP(4),
+ ARROW_DOWN(5),
+ ARROW_LEFT(6),
+ ARROW_RIGHT(7),
+ SELECT(8),
+ BACK(9),
+ EXIT(10),
+ PLAY_PAUSE(11),
+ INFO(115);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(RemoteKeyEnum.values())
+ .collect(Collectors.toMap(RemoteKeyEnum::getCode, t -> t));
+ }
+
+ public static RemoteKeyEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ RemoteKeyEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/SleepDiscoveryModeCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/television/SleepDiscoveryModeCharacteristic.java
new file mode 100644
index 000000000..2a7f41829
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/SleepDiscoveryModeCharacteristic.java
@@ -0,0 +1,28 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * This characteristic indicates whether the service can be discovered. See {@link
+ * SleepDiscoveryModeEnum} for possible values.
+ */
+public class SleepDiscoveryModeCharacteristic extends EnumCharacteristic {
+ public SleepDiscoveryModeCharacteristic(
+ Supplier> getter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000E8-0000-1000-8000-0026BB765291",
+ "sleep discovery mode",
+ SleepDiscoveryModeEnum.values(),
+ Optional.of(getter),
+ Optional.empty(),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/SleepDiscoveryModeEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/television/SleepDiscoveryModeEnum.java
new file mode 100644
index 000000000..da1377b9a
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/SleepDiscoveryModeEnum.java
@@ -0,0 +1,35 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/** 0 ”Not discoverable” 1 ”Always discoverable” 2-255 ”Reserved” */
+public enum SleepDiscoveryModeEnum implements CharacteristicEnum {
+ NOT_DISCOVERABLE(0),
+ ALWAYS_DISCOVERABLE(1);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(SleepDiscoveryModeEnum.values())
+ .collect(Collectors.toMap(SleepDiscoveryModeEnum::getCode, t -> t));
+ }
+
+ public static SleepDiscoveryModeEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ SleepDiscoveryModeEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/TargetMediaStateCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/television/TargetMediaStateCharacteristic.java
new file mode 100644
index 000000000..8909bb1ea
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/TargetMediaStateCharacteristic.java
@@ -0,0 +1,27 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/** This characteristic sets media state. See {@link TargetMediaStateEnum} for possible values. */
+public class TargetMediaStateCharacteristic extends EnumCharacteristic {
+ public TargetMediaStateCharacteristic(
+ Supplier> getter,
+ ExceptionalConsumer setter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "00000137-0000-1000-8000-0026BB765291",
+ "current media state",
+ TargetMediaStateEnum.values(),
+ Optional.of(getter),
+ Optional.of(setter),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/television/TargetMediaStateEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/television/TargetMediaStateEnum.java
new file mode 100644
index 000000000..b6f6633ff
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/television/TargetMediaStateEnum.java
@@ -0,0 +1,36 @@
+package io.github.hapjava.characteristics.impl.television;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/** 0 ”Play” 1 ”Pause” 2 "Stop" 3-255 ”Reserved” */
+public enum TargetMediaStateEnum implements CharacteristicEnum {
+ PLAY(0),
+ PAUSE(1),
+ STOP(2);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(TargetMediaStateEnum.values())
+ .collect(Collectors.toMap(TargetMediaStateEnum::getCode, t -> t));
+ }
+
+ public static TargetMediaStateEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ TargetMediaStateEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeControlTypeCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeControlTypeCharacteristic.java
new file mode 100644
index 000000000..c6d18a858
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeControlTypeCharacteristic.java
@@ -0,0 +1,28 @@
+package io.github.hapjava.characteristics.impl.televisionspeaker;
+
+import io.github.hapjava.characteristics.HomekitCharacteristicChangeCallback;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * This characteristic indicates volume control type. See {@link VolumeControlTypeEnum} for possible
+ * values.
+ */
+public class VolumeControlTypeCharacteristic extends EnumCharacteristic {
+ public VolumeControlTypeCharacteristic(
+ Supplier> getter,
+ Consumer subscriber,
+ Runnable unsubscriber) {
+ super(
+ "000000E9-0000-1000-8000-0026BB765291",
+ "volume control type",
+ VolumeControlTypeEnum.values(),
+ Optional.of(getter),
+ Optional.empty(),
+ Optional.of(subscriber),
+ Optional.of(unsubscriber));
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeControlTypeEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeControlTypeEnum.java
new file mode 100644
index 000000000..dfeb24636
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeControlTypeEnum.java
@@ -0,0 +1,36 @@
+package io.github.hapjava.characteristics.impl.televisionspeaker;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public enum VolumeControlTypeEnum implements CharacteristicEnum {
+ NONE(0),
+ RELATIVE(1),
+ RELATIVE_WITH_CURRENT(2),
+ ABSOLUTE(3);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(VolumeControlTypeEnum.values())
+ .collect(Collectors.toMap(VolumeControlTypeEnum::getCode, t -> t));
+ }
+
+ public static VolumeControlTypeEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ VolumeControlTypeEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeSelectorCharacteristic.java b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeSelectorCharacteristic.java
new file mode 100644
index 000000000..8f2f84e7b
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeSelectorCharacteristic.java
@@ -0,0 +1,22 @@
+package io.github.hapjava.characteristics.impl.televisionspeaker;
+
+import io.github.hapjava.characteristics.ExceptionalConsumer;
+import io.github.hapjava.characteristics.impl.base.EnumCharacteristic;
+import java.util.Optional;
+
+/**
+ * This characteristic sends information about volume changes. See {@link VolumeSelectorEnum} for
+ * possible values.
+ */
+public class VolumeSelectorCharacteristic extends EnumCharacteristic {
+ public VolumeSelectorCharacteristic(ExceptionalConsumer setter) {
+ super(
+ "000000EA-0000-1000-8000-0026BB765291",
+ "volume selector",
+ VolumeSelectorEnum.values(),
+ Optional.empty(),
+ Optional.of(setter),
+ Optional.empty(),
+ Optional.empty());
+ }
+}
diff --git a/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeSelectorEnum.java b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeSelectorEnum.java
new file mode 100644
index 000000000..63bc60e50
--- /dev/null
+++ b/src/main/java/io/github/hapjava/characteristics/impl/televisionspeaker/VolumeSelectorEnum.java
@@ -0,0 +1,34 @@
+package io.github.hapjava.characteristics.impl.televisionspeaker;
+
+import io.github.hapjava.characteristics.CharacteristicEnum;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public enum VolumeSelectorEnum implements CharacteristicEnum {
+ INCREMENT(0),
+ DECREMENT(1);
+
+ private static final Map reverse;
+
+ static {
+ reverse =
+ Arrays.stream(VolumeSelectorEnum.values())
+ .collect(Collectors.toMap(VolumeSelectorEnum::getCode, t -> t));
+ }
+
+ public static VolumeSelectorEnum fromCode(Integer code) {
+ return reverse.get(code);
+ }
+
+ private final int code;
+
+ VolumeSelectorEnum(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java b/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java
index 98e6cd266..ef21422af 100644
--- a/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java
+++ b/src/main/java/io/github/hapjava/server/impl/json/AccessoryController.java
@@ -18,6 +18,7 @@
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
+import javax.json.JsonWriter;
public class AccessoryController {
@@ -64,9 +65,9 @@ public HttpResponse listing() throws Exception {
.add("services", serviceArrayBuilders.get(accessory.getId())));
}
- try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
- Json.createWriter(baos)
- .write(Json.createObjectBuilder().add("accessories", accessories).build());
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ JsonWriter jsonWriter = Json.createWriter(baos)) {
+ jsonWriter.write(Json.createObjectBuilder().add("accessories", accessories).build());
return new HapJsonResponse(baos.toByteArray());
}
}
diff --git a/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java b/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java
index df5509dda..4d20a0c6b 100644
--- a/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java
+++ b/src/main/java/io/github/hapjava/server/impl/json/CharacteristicsController.java
@@ -58,10 +58,10 @@ public HttpResponse get(HttpRequest request) throws Exception {
"Accessory " + aid + " has no characteristics or does not exist. Request: " + uri);
}
}
- try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
- Json.createWriter(baos)
- .write(
- Json.createObjectBuilder().add("characteristics", characteristics.build()).build());
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ JsonWriter jsonWriter = Json.createWriter(baos)) {
+ jsonWriter.write(
+ Json.createObjectBuilder().add("characteristics", characteristics.build()).build());
return new HapJsonResponse(baos.toByteArray());
}
}
diff --git a/src/main/java/io/github/hapjava/server/impl/json/EventController.java b/src/main/java/io/github/hapjava/server/impl/json/EventController.java
index 80be265ae..41473f716 100644
--- a/src/main/java/io/github/hapjava/server/impl/json/EventController.java
+++ b/src/main/java/io/github/hapjava/server/impl/json/EventController.java
@@ -9,6 +9,7 @@
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
+import javax.json.JsonWriter;
public class EventController {
@@ -24,8 +25,9 @@ public HttpResponse getMessage(int accessoryId, int iid, EventableCharacteristic
JsonObject data = Json.createObjectBuilder().add("characteristics", characteristics).build();
- try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
- Json.createWriter(baos).write(data);
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ JsonWriter jsonWriter = Json.createWriter(baos)) {
+ jsonWriter.write(data);
byte[] dataBytes = baos.toByteArray();
return new EventResponse(dataBytes);
@@ -44,9 +46,9 @@ public HttpResponse getMessage(ArrayList notifications) thr
}
JsonObject data = Json.createObjectBuilder().add("characteristics", characteristics).build();
-
- try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
- Json.createWriter(baos).write(data);
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ JsonWriter jsonWriter = Json.createWriter(baos)) {
+ jsonWriter.write(data);
byte[] dataBytes = baos.toByteArray();
return new EventResponse(dataBytes);
diff --git a/src/main/java/io/github/hapjava/services/impl/AbstractServiceImpl.java b/src/main/java/io/github/hapjava/services/impl/AbstractServiceImpl.java
index 25a44099d..4dfd9f5f6 100644
--- a/src/main/java/io/github/hapjava/services/impl/AbstractServiceImpl.java
+++ b/src/main/java/io/github/hapjava/services/impl/AbstractServiceImpl.java
@@ -5,11 +5,14 @@
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
abstract class AbstractServiceImpl implements Service {
private final String type;
private final List characteristics = new LinkedList<>();
private final List linkedServices = new LinkedList<>();
+ private static final Logger logger = LoggerFactory.getLogger(AbstractServiceImpl.class);
/** @param type unique UUID of the service according to HAP specification. */
public AbstractServiceImpl(String type) {
diff --git a/src/main/java/io/github/hapjava/services/impl/DoorService.java b/src/main/java/io/github/hapjava/services/impl/DoorService.java
index c4c3b40b3..51f956f5f 100644
--- a/src/main/java/io/github/hapjava/services/impl/DoorService.java
+++ b/src/main/java/io/github/hapjava/services/impl/DoorService.java
@@ -2,8 +2,10 @@
import io.github.hapjava.accessories.DoorAccessory;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithHoldPosition;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithMute;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithName;
import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithObstructionDetection;
+import io.github.hapjava.characteristics.impl.audio.MuteCharacteristic;
import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
import io.github.hapjava.characteristics.impl.common.ObstructionDetectedCharacteristic;
import io.github.hapjava.characteristics.impl.windowcovering.CurrentPositionCharacteristic;
@@ -53,6 +55,14 @@ public DoorService(DoorAccessory accessory) {
((AccessoryWithObstructionDetection) accessory)::subscribeObstructionDetected,
((AccessoryWithObstructionDetection) accessory)::unsubscribeObstructionDetected));
}
+ if (accessory instanceof AccessoryWithMute) {
+ addOptionalCharacteristic(
+ new MuteCharacteristic(
+ ((AccessoryWithMute) accessory)::isMuted,
+ ((AccessoryWithMute) accessory)::setMute,
+ ((AccessoryWithMute) accessory)::subscribeMuteState,
+ ((AccessoryWithMute) accessory)::unsubscribeMuteState));
+ }
}
public void addOptionalCharacteristic(NameCharacteristic name) {
@@ -67,4 +77,8 @@ public void addOptionalCharacteristic(
ObstructionDetectedCharacteristic obstructionDetectedCharacteristic) {
addCharacteristic(obstructionDetectedCharacteristic);
}
+
+ public void addOptionalCharacteristic(MuteCharacteristic muteCharacteristic) {
+ addCharacteristic(muteCharacteristic);
+ }
}
diff --git a/src/main/java/io/github/hapjava/services/impl/InputSourceService.java b/src/main/java/io/github/hapjava/services/impl/InputSourceService.java
new file mode 100644
index 000000000..4af2736a2
--- /dev/null
+++ b/src/main/java/io/github/hapjava/services/impl/InputSourceService.java
@@ -0,0 +1,91 @@
+package io.github.hapjava.services.impl;
+
+import io.github.hapjava.accessories.InputSourceAccessory;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithIdentifier;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithInputDeviceType;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithName;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithTargetVisibilityState;
+import io.github.hapjava.characteristics.impl.common.ConfiguredNameCharacteristic;
+import io.github.hapjava.characteristics.impl.common.IdentifierCharacteristic;
+import io.github.hapjava.characteristics.impl.common.IsConfiguredCharacteristic;
+import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
+import io.github.hapjava.characteristics.impl.inputsource.CurrentVisibilityStateCharacteristic;
+import io.github.hapjava.characteristics.impl.inputsource.InputDeviceTypeCharacteristic;
+import io.github.hapjava.characteristics.impl.inputsource.InputSourceTypeCharacteristic;
+import io.github.hapjava.characteristics.impl.inputsource.TargetVisibilityStateCharacteristic;
+
+/** This service describes a input source. */
+public class InputSourceService extends AbstractServiceImpl {
+
+ public InputSourceService(
+ ConfiguredNameCharacteristic configuredNameCharacteristic,
+ InputSourceTypeCharacteristic inputSourceTypeCharacteristic,
+ IsConfiguredCharacteristic isConfiguredCharacteristic,
+ CurrentVisibilityStateCharacteristic currentVisibilityStateCharacteristic) {
+ super("000000D9-0000-1000-8000-0026BB765291");
+ addCharacteristic(configuredNameCharacteristic);
+ addCharacteristic(inputSourceTypeCharacteristic);
+ addCharacteristic(isConfiguredCharacteristic);
+ addCharacteristic(currentVisibilityStateCharacteristic);
+ }
+
+ public InputSourceService(InputSourceAccessory accessory) {
+ this(
+ new ConfiguredNameCharacteristic(
+ accessory::getConfiguredName,
+ accessory::setConfiguredName,
+ accessory::subscribeConfiguredName,
+ accessory::unsubscribeConfiguredName),
+ new InputSourceTypeCharacteristic(
+ accessory::getInputSourceType,
+ accessory::subscribeInputSourceType,
+ accessory::unsubscribeInputSourceType),
+ new IsConfiguredCharacteristic(
+ accessory::isConfigured,
+ accessory::setIsConfigured,
+ accessory::subscribeIsConfigured,
+ accessory::unsubscribeIsConfigured),
+ new CurrentVisibilityStateCharacteristic(
+ accessory::getCurrentVisibilityState,
+ accessory::subscribeCurrentVisibilityState,
+ accessory::unsubscribeCurrentVisibilityState));
+ if (accessory instanceof AccessoryWithName) {
+ addOptionalCharacteristic(new NameCharacteristic(((AccessoryWithName) accessory)::getName));
+ }
+ if (accessory instanceof AccessoryWithIdentifier) {
+ addOptionalCharacteristic(
+ new IdentifierCharacteristic(((AccessoryWithIdentifier) accessory)::getIdentifier));
+ }
+ if (accessory instanceof AccessoryWithInputDeviceType) {
+ addOptionalCharacteristic(
+ new InputDeviceTypeCharacteristic(
+ ((AccessoryWithInputDeviceType) accessory)::getInputDeviceType,
+ ((AccessoryWithInputDeviceType) accessory)::subscribeInputDeviceType,
+ ((AccessoryWithInputDeviceType) accessory)::unsubscribeInputDeviceType));
+ }
+ if (accessory instanceof AccessoryWithTargetVisibilityState) {
+ addOptionalCharacteristic(
+ new TargetVisibilityStateCharacteristic(
+ ((AccessoryWithTargetVisibilityState) accessory)::getTargetVisibilityState,
+ ((AccessoryWithTargetVisibilityState) accessory)::setTargetVisibilityState,
+ ((AccessoryWithTargetVisibilityState) accessory)::subscribeTargetVisibilityState,
+ ((AccessoryWithTargetVisibilityState) accessory)::unsubscribeTargetVisibilityState));
+ }
+ }
+
+ public void addOptionalCharacteristic(NameCharacteristic name) {
+ addCharacteristic(name);
+ }
+
+ public void addOptionalCharacteristic(IdentifierCharacteristic identifier) {
+ addCharacteristic(identifier);
+ }
+
+ public void addOptionalCharacteristic(InputDeviceTypeCharacteristic inputDeviceType) {
+ addCharacteristic(inputDeviceType);
+ }
+
+ public void addOptionalCharacteristic(TargetVisibilityStateCharacteristic targetVisibilityState) {
+ addCharacteristic(targetVisibilityState);
+ }
+}
diff --git a/src/main/java/io/github/hapjava/services/impl/SmartSpeakerService.java b/src/main/java/io/github/hapjava/services/impl/SmartSpeakerService.java
new file mode 100644
index 000000000..e5f57eff4
--- /dev/null
+++ b/src/main/java/io/github/hapjava/services/impl/SmartSpeakerService.java
@@ -0,0 +1,95 @@
+package io.github.hapjava.services.impl;
+
+import io.github.hapjava.accessories.SmartSpeakerAccessory;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithAirPlayEnable;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithConfiguredName;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithMute;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithName;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithVolume;
+import io.github.hapjava.characteristics.impl.audio.MuteCharacteristic;
+import io.github.hapjava.characteristics.impl.audio.VolumeCharacteristic;
+import io.github.hapjava.characteristics.impl.common.AirPlayEnableCharacteristic;
+import io.github.hapjava.characteristics.impl.common.ConfiguredNameCharacteristic;
+import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
+import io.github.hapjava.characteristics.impl.television.CurrentMediaStateCharacteristic;
+import io.github.hapjava.characteristics.impl.television.TargetMediaStateCharacteristic;
+
+/** A smart speaker service can be used to control the audio output settings on a speaker device. */
+public class SmartSpeakerService extends AbstractServiceImpl {
+
+ public SmartSpeakerService(
+ CurrentMediaStateCharacteristic currentMediaStateCharacteristic,
+ TargetMediaStateCharacteristic targetMediaStateCharacteristic) {
+ super("00000228-0000-1000-8000-0026BB765291");
+ addCharacteristic(currentMediaStateCharacteristic);
+ addCharacteristic(targetMediaStateCharacteristic);
+ }
+
+ public SmartSpeakerService(SmartSpeakerAccessory accessory) {
+ this(
+ new CurrentMediaStateCharacteristic(
+ accessory::getCurrentMediaState,
+ accessory::subscribeCurrentMediaState,
+ accessory::unsubscribeCurrentMediaState),
+ new TargetMediaStateCharacteristic(
+ accessory::getTargetMediaState,
+ accessory::setTargetMediaState,
+ accessory::subscribeTargetMediaState,
+ accessory::unsubscribeTargetMediaState));
+ if (accessory instanceof AccessoryWithName) {
+ addOptionalCharacteristic(new NameCharacteristic(((AccessoryWithName) accessory)::getName));
+ }
+ if (accessory instanceof AccessoryWithVolume) {
+ addOptionalCharacteristic(
+ new VolumeCharacteristic(
+ ((AccessoryWithVolume) accessory)::getVolume,
+ ((AccessoryWithVolume) accessory)::setVolume,
+ ((AccessoryWithVolume) accessory)::subscribeVolume,
+ ((AccessoryWithVolume) accessory)::unsubscribeVolume));
+ }
+ if (accessory instanceof AccessoryWithConfiguredName) {
+ addOptionalCharacteristic(
+ new ConfiguredNameCharacteristic(
+ ((AccessoryWithConfiguredName) accessory)::getConfiguredName,
+ ((AccessoryWithConfiguredName) accessory)::setConfiguredName,
+ ((AccessoryWithConfiguredName) accessory)::subscribeConfiguredName,
+ ((AccessoryWithConfiguredName) accessory)::unsubscribeConfiguredName));
+ }
+ if (accessory instanceof AccessoryWithMute) {
+ addOptionalCharacteristic(
+ new MuteCharacteristic(
+ ((AccessoryWithMute) accessory)::isMuted,
+ ((AccessoryWithMute) accessory)::setMute,
+ ((AccessoryWithMute) accessory)::subscribeMuteState,
+ ((AccessoryWithMute) accessory)::unsubscribeMuteState));
+ }
+ if (accessory instanceof AccessoryWithAirPlayEnable) {
+ addOptionalCharacteristic(
+ new AirPlayEnableCharacteristic(
+ ((AccessoryWithAirPlayEnable) accessory)::getAirPlayEnable,
+ ((AccessoryWithAirPlayEnable) accessory)::setAirPlayEnable,
+ ((AccessoryWithAirPlayEnable) accessory)::subscribeAirPlayEnable,
+ ((AccessoryWithAirPlayEnable) accessory)::unsubscribeAirPlayEnable));
+ }
+ }
+
+ public void addOptionalCharacteristic(NameCharacteristic name) {
+ addCharacteristic(name);
+ }
+
+ public void addOptionalCharacteristic(VolumeCharacteristic volume) {
+ addCharacteristic(volume);
+ }
+
+ public void addOptionalCharacteristic(ConfiguredNameCharacteristic configuredNameCharacteristic) {
+ addCharacteristic(configuredNameCharacteristic);
+ }
+
+ public void addOptionalCharacteristic(MuteCharacteristic muteCharacteristic) {
+ addCharacteristic(muteCharacteristic);
+ }
+
+ public void addOptionalCharacteristic(AirPlayEnableCharacteristic airPlayEnableCharacteristic) {
+ addCharacteristic(airPlayEnableCharacteristic);
+ }
+}
diff --git a/src/main/java/io/github/hapjava/services/impl/TelevisionService.java b/src/main/java/io/github/hapjava/services/impl/TelevisionService.java
new file mode 100644
index 000000000..8846cffe1
--- /dev/null
+++ b/src/main/java/io/github/hapjava/services/impl/TelevisionService.java
@@ -0,0 +1,139 @@
+package io.github.hapjava.services.impl;
+
+import io.github.hapjava.accessories.TelevisionAccessory;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithBrightness;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithClosedCaptions;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithCurrentMediaState;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithName;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithPictureMode;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithPowerMode;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithTargetMediaState;
+import io.github.hapjava.characteristics.impl.common.ActiveCharacteristic;
+import io.github.hapjava.characteristics.impl.common.ActiveEnum;
+import io.github.hapjava.characteristics.impl.common.ActiveIdentifierCharacteristic;
+import io.github.hapjava.characteristics.impl.common.ConfiguredNameCharacteristic;
+import io.github.hapjava.characteristics.impl.common.NameCharacteristic;
+import io.github.hapjava.characteristics.impl.lightbulb.BrightnessCharacteristic;
+import io.github.hapjava.characteristics.impl.television.ClosedCaptionsCharacteristic;
+import io.github.hapjava.characteristics.impl.television.CurrentMediaStateCharacteristic;
+import io.github.hapjava.characteristics.impl.television.PictureModeCharacteristic;
+import io.github.hapjava.characteristics.impl.television.PowerModeCharacteristic;
+import io.github.hapjava.characteristics.impl.television.RemoteKeyCharacteristic;
+import io.github.hapjava.characteristics.impl.television.SleepDiscoveryModeCharacteristic;
+import io.github.hapjava.characteristics.impl.television.TargetMediaStateCharacteristic;
+
+/** This service describes a television. */
+public class TelevisionService extends AbstractServiceImpl {
+
+ public TelevisionService(
+ ActiveCharacteristic activeCharacteristic,
+ ActiveIdentifierCharacteristic activeIdentifierCharacteristic,
+ ConfiguredNameCharacteristic configuredNameCharacteristic,
+ RemoteKeyCharacteristic remoteKeyCharacteristic,
+ SleepDiscoveryModeCharacteristic sleepDiscoveryModeCharacteristic) {
+ super("000000D8-0000-1000-8000-0026BB765291");
+ addCharacteristic(activeCharacteristic);
+ addCharacteristic(activeIdentifierCharacteristic);
+ addCharacteristic(configuredNameCharacteristic);
+ addCharacteristic(remoteKeyCharacteristic);
+ addCharacteristic(sleepDiscoveryModeCharacteristic);
+ }
+
+ public TelevisionService(TelevisionAccessory accessory) {
+ this(
+ new ActiveCharacteristic(
+ () -> accessory.isActive().thenApply(s -> s ? ActiveEnum.ACTIVE : ActiveEnum.INACTIVE),
+ (v) -> accessory.setActive(v == ActiveEnum.ACTIVE),
+ accessory::subscribeActive,
+ accessory::unsubscribeActive),
+ new ActiveIdentifierCharacteristic(
+ accessory::getActiveIdentifier,
+ accessory::setActiveIdentifier,
+ accessory::subscribeActiveIdentifier,
+ accessory::unsubscribeActiveIdentifier),
+ new ConfiguredNameCharacteristic(
+ accessory::getConfiguredName,
+ accessory::setConfiguredName,
+ accessory::subscribeConfiguredName,
+ accessory::unsubscribeConfiguredName),
+ new RemoteKeyCharacteristic(accessory::setRemoteKey),
+ new SleepDiscoveryModeCharacteristic(
+ accessory::getSleepDiscoveryMode,
+ accessory::subscribeSleepDiscoveryMode,
+ accessory::unsubscribeSleepDiscoveryMode));
+ if (accessory instanceof AccessoryWithName) {
+ addOptionalCharacteristic(new NameCharacteristic(((AccessoryWithName) accessory)::getName));
+ }
+ if (accessory instanceof AccessoryWithBrightness) {
+ addOptionalCharacteristic(
+ new BrightnessCharacteristic(
+ ((AccessoryWithBrightness) accessory)::getBrightness,
+ ((AccessoryWithBrightness) accessory)::setBrightness,
+ ((AccessoryWithBrightness) accessory)::subscribeBrightness,
+ ((AccessoryWithBrightness) accessory)::unsubscribeBrightness));
+ }
+ if (accessory instanceof AccessoryWithPowerMode) {
+ addOptionalCharacteristic(
+ new PowerModeCharacteristic(((AccessoryWithPowerMode) accessory)::setPowerMode));
+ }
+ if (accessory instanceof AccessoryWithClosedCaptions) {
+ addOptionalCharacteristic(
+ new ClosedCaptionsCharacteristic(
+ ((AccessoryWithClosedCaptions) accessory)::getClosedCaptions,
+ ((AccessoryWithClosedCaptions) accessory)::setClosedCaptions,
+ ((AccessoryWithClosedCaptions) accessory)::subscribeClosedCaptions,
+ ((AccessoryWithClosedCaptions) accessory)::unsubscribeClosedCaptions));
+ }
+ if (accessory instanceof AccessoryWithCurrentMediaState) {
+ addOptionalCharacteristic(
+ new CurrentMediaStateCharacteristic(
+ ((AccessoryWithCurrentMediaState) accessory)::getCurrentMediaState,
+ ((AccessoryWithCurrentMediaState) accessory)::subscribeCurrentMediaState,
+ ((AccessoryWithCurrentMediaState) accessory)::unsubscribeCurrentMediaState));
+ }
+ if (accessory instanceof AccessoryWithTargetMediaState) {
+ addOptionalCharacteristic(
+ new TargetMediaStateCharacteristic(
+ ((AccessoryWithTargetMediaState) accessory)::getTargetMediaState,
+ ((AccessoryWithTargetMediaState) accessory)::setTargetMediaState,
+ ((AccessoryWithTargetMediaState) accessory)::subscribeTargetMediaState,
+ ((AccessoryWithTargetMediaState) accessory)::unsubscribeTargetMediaState));
+ }
+ if (accessory instanceof AccessoryWithPictureMode) {
+ addOptionalCharacteristic(
+ new PictureModeCharacteristic(
+ ((AccessoryWithPictureMode) accessory)::getPictureMode,
+ ((AccessoryWithPictureMode) accessory)::setPictureMode,
+ ((AccessoryWithPictureMode) accessory)::subscribePictureMode,
+ ((AccessoryWithPictureMode) accessory)::unsubscribePictureMode));
+ }
+ }
+
+ public void addOptionalCharacteristic(NameCharacteristic name) {
+ addCharacteristic(name);
+ }
+
+ public void addOptionalCharacteristic(PowerModeCharacteristic powerMode) {
+ addCharacteristic(powerMode);
+ }
+
+ public void addOptionalCharacteristic(ClosedCaptionsCharacteristic closedCaptions) {
+ addCharacteristic(closedCaptions);
+ }
+
+ public void addOptionalCharacteristic(CurrentMediaStateCharacteristic currentMediaState) {
+ addCharacteristic(currentMediaState);
+ }
+
+ public void addOptionalCharacteristic(TargetMediaStateCharacteristic targetMediaState) {
+ addCharacteristic(targetMediaState);
+ }
+
+ public void addOptionalCharacteristic(PictureModeCharacteristic pictureMode) {
+ addCharacteristic(pictureMode);
+ }
+
+ public void addOptionalCharacteristic(BrightnessCharacteristic brightness) {
+ addCharacteristic(brightness);
+ }
+}
diff --git a/src/main/java/io/github/hapjava/services/impl/TelevisionSpeakerService.java b/src/main/java/io/github/hapjava/services/impl/TelevisionSpeakerService.java
new file mode 100644
index 000000000..b53fb81bd
--- /dev/null
+++ b/src/main/java/io/github/hapjava/services/impl/TelevisionSpeakerService.java
@@ -0,0 +1,75 @@
+package io.github.hapjava.services.impl;
+
+import io.github.hapjava.accessories.TelevisionSpeakerAccessory;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithActive;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithVolume;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithVolumeControlType;
+import io.github.hapjava.accessories.optionalcharacteristic.AccessoryWithVolumeSelector;
+import io.github.hapjava.characteristics.impl.audio.MuteCharacteristic;
+import io.github.hapjava.characteristics.impl.audio.VolumeCharacteristic;
+import io.github.hapjava.characteristics.impl.common.ActiveCharacteristic;
+import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeControlTypeCharacteristic;
+import io.github.hapjava.characteristics.impl.televisionspeaker.VolumeSelectorCharacteristic;
+
+/** This service describes a television. */
+public class TelevisionSpeakerService extends AbstractServiceImpl {
+
+ public TelevisionSpeakerService(MuteCharacteristic muteCharacteristic) {
+ super("00000113-0000-1000-8000-0026BB765291");
+ addCharacteristic(muteCharacteristic);
+ }
+
+ public TelevisionSpeakerService(TelevisionSpeakerAccessory accessory) {
+ this(
+ new MuteCharacteristic(
+ accessory::isMuted,
+ accessory::setMute,
+ accessory::subscribeMuteState,
+ accessory::unsubscribeMuteState));
+ if (accessory instanceof AccessoryWithActive) {
+ addOptionalCharacteristic(
+ new ActiveCharacteristic(
+ ((AccessoryWithActive) accessory)::getActive,
+ ((AccessoryWithActive) accessory)::setActive,
+ ((AccessoryWithActive) accessory)::subscribeActive,
+ ((AccessoryWithActive) accessory)::unsubscribeActive));
+ }
+ if (accessory instanceof AccessoryWithVolume) {
+ addOptionalCharacteristic(
+ new VolumeCharacteristic(
+ ((AccessoryWithVolume) accessory)::getVolume,
+ ((AccessoryWithVolume) accessory)::setVolume,
+ ((AccessoryWithVolume) accessory)::subscribeVolume,
+ ((AccessoryWithVolume) accessory)::unsubscribeVolume));
+ }
+ if (accessory instanceof AccessoryWithVolumeSelector) {
+ addOptionalCharacteristic(
+ new VolumeSelectorCharacteristic(
+ ((AccessoryWithVolumeSelector) accessory)::setVolumeSelector));
+ }
+ if (accessory instanceof AccessoryWithVolumeControlType) {
+ addOptionalCharacteristic(
+ new VolumeControlTypeCharacteristic(
+ ((AccessoryWithVolumeControlType) accessory)::getVolumeControlType,
+ ((AccessoryWithVolumeControlType) accessory)::subscribeVolumeControlType,
+ ((AccessoryWithVolumeControlType) accessory)::unsubscribeVolumeControlType));
+ ;
+ }
+ }
+
+ public void addOptionalCharacteristic(ActiveCharacteristic activeCharacteristic) {
+ addCharacteristic(activeCharacteristic);
+ }
+
+ public void addOptionalCharacteristic(VolumeCharacteristic volume) {
+ addCharacteristic(volume);
+ }
+
+ public void addOptionalCharacteristic(VolumeSelectorCharacteristic volumeSelector) {
+ addCharacteristic(volumeSelector);
+ }
+
+ public void addOptionalCharacteristic(VolumeControlTypeCharacteristic volumeControlType) {
+ addCharacteristic(volumeControlType);
+ }
+}