mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[androidtv] Add PhilipsTV protocol
Signed-off-by: Ben Rosenblum <rosenblumb@gmail.com> Signed-off-by: morph166955 <53797132+morph166955@users.noreply.github.com>
This commit is contained in:
parent
dd6d8c1bd2
commit
e4d5ae0a87
@ -11,3 +11,21 @@ https://www.eclipse.org/legal/epl-2.0/.
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
|
||||
== Third-party Content
|
||||
|
||||
httpclient
|
||||
* License: Apache 2.0 License
|
||||
* Project: https://hc.apache.org/httpcomponents-client-ga
|
||||
* Source: https://hc.apache.org/httpcomponents-client-ga
|
||||
|
||||
httpcore
|
||||
* License: Apache 2.0 License
|
||||
* Project: http://hc.apache.org/httpcomponents-core-ga
|
||||
* Source: http://hc.apache.org/httpcomponents-core-ga
|
||||
|
||||
jackson
|
||||
* License: Apache 2.0 License
|
||||
* Project: https://github.com/FasterXML/jackson
|
||||
* Source: https://github.com/FasterXML/jackson
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
# AndroidTV Binding
|
||||
|
||||
This binding is designed to emulate different protocols to interact with the AndroidTV platform.
|
||||
Currently it emulates both the Google Video App to interact with a variety of AndroidTVs for purposes of remote control.
|
||||
Currently it emulates the Google Video App to interact with a variety of AndroidTVs for purposes of remote control.
|
||||
It also currently emulates the Nvidia ShieldTV Android App to interact with an Nvidia ShieldTV for purposes of remote control.
|
||||
It also currently emulates the PhilipsTV App to interact with a 2016+ PhilipsTV for purposes of remote control.
|
||||
|
||||
## Supported Things
|
||||
|
||||
@ -10,14 +11,15 @@ This binding supports two thing types:
|
||||
|
||||
- **googletv** - An AndroidTV running Google Video
|
||||
- **shieldtv** - An Nvidia ShieldTV
|
||||
- **philipstv** - A 2016+ Philips TV
|
||||
|
||||
## Discovery
|
||||
|
||||
Both GoogleTVs and ShieldTVs should be added automatically to the inbox through the mDNS discovery process.
|
||||
All relevant thing types should be added automatically to the inbox through the mDNS discovery process.
|
||||
|
||||
In the case of the ShieldTV, openHAB will likely create an inbox entry for both a GoogleTV and a ShieldTV device.
|
||||
Only the ShieldTV device should be configured, the GoogleTV can be ignored.
|
||||
There is no benefit to configuring two things for a ShieldTV device.
|
||||
In the case of the ShieldTV or PhilipsTV, openHAB will likely create an inbox entry for both a GoogleTV and a ShieldTV or PhilipsTV device.
|
||||
Only the ShieldTV or PhilipsTV device should be configured, the GoogleTV can be ignored.
|
||||
There is no benefit to configuring two things for a ShieldTV or PhilipsTV device.
|
||||
This could cause undesired effects.
|
||||
|
||||
## Binding Configuration
|
||||
@ -30,37 +32,58 @@ This binding requires GoogleTV to be installed on the device (https://play.googl
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
There are three required fields to connect successfully to a ShieldTV.
|
||||
The is one required field to connect to the devices. All other fields are optional.
|
||||
|
||||
| Name | Type | Description | Default | Required | Advanced |
|
||||
|------------------|---------|---------------------------------------|---------|----------|----------|
|
||||
| ipAddress | text | IP address of the device | N/A | yes | no |
|
||||
| googletvPort | text | TCP Port for GoogleTV | 6466 | no | no |
|
||||
| shieldtvPort | text | TCP Port for ShieldTV | 8987 | no | no |
|
||||
| keystore | text | Location of the Java Keystore | N/A | no | no |
|
||||
| keystorePassword | text | Password of the Java Keystore | N/A | no | no |
|
||||
| gtvEnabled | boolean | Enable/Disable the GoogleTV protocol | true | no | no |
|
||||
| googletvPort | text | TCP Port for GoogleTV | 6466 | no | yes |
|
||||
| shieldtvPort | text | TCP Port for ShieldTV | 8987 | no | yes |
|
||||
| philipstvPort | text | TCP Port for PhilipsTV | 1926 | no | yes |
|
||||
| keystoreFileName | text | Location of the Java Keystore | N/A | no | yes |
|
||||
| keystorePassword | text | Password of the Java Keystore | N/A | no | yes |
|
||||
| reconnect | text | Delay between reconnections | 60 | no | yes |
|
||||
| heartbeat | text | Frequency of heartbeats | 5 | no | yes |
|
||||
| delay | text | Delay between messages | 0 | no | yes |
|
||||
| refreshRate | text | Refresh interval of PhilipsTV | 10 | no | yes |
|
||||
| useUpnpDiscovery | boolean | Enables UPnP Discovery for PhilipsTV | true | no | yes |
|
||||
| gtvEnabled | boolean | Enable/Disable the GoogleTV protocol | true | no | yes |
|
||||
|
||||
```java
|
||||
Thing androidtv:shieldtv:livingroom [ ipAddress="192.168.1.2" ]
|
||||
Thing androidtv:googletv:theater [ ipAddress="192.168.1.3" ]
|
||||
Thing androidtv:philipstv:bedroom [ ipAddress="192.168.1.4" ]
|
||||
```
|
||||
|
||||
## Channels
|
||||
|
||||
| Channel | Type | Description | GoogleTV | ShieldTV |
|
||||
|------------|--------|-----------------------------|----------|----------|
|
||||
| keyboard | String | Keyboard Data Entry | RW | RW |
|
||||
| keypress | String | Manual Key Press Entry | RW | RW |
|
||||
| keycode | String | Direct KEYCODE Entry | RW | RW |
|
||||
| pincode | String | PIN Code Entry | RW | RW |
|
||||
| app | String | App Control | RO | RW |
|
||||
| appname | String | App Name | N/A | RW |
|
||||
| appurl | String | App URL | N/A | RW |
|
||||
| player | Player | Player Control | RW | RW |
|
||||
| power | Switch | Power Control | RW | RW |
|
||||
| volume | Dimmer | Volume Control | RO | RO |
|
||||
| mute | Switch | Mute Control | RW | RW |
|
||||
| Channel | Type | Description | GoogleTV | ShieldTV | PhilipsTV |
|
||||
|----------------------|--------|--------------------------------------|----------|----------|-----------|
|
||||
| keyboard | String | Keyboard Data Entry | RW | RW | RW |
|
||||
| keypress | String | Manual Key Press Entry | RW | RW | RW |
|
||||
| keycode | String | Direct KEYCODE Entry | RW | RW | RW |
|
||||
| pincode | String | PIN Code Entry | RW | RW | RW |
|
||||
| app | String | App Control | RO | RW | RW |
|
||||
| appname | String | App Name | N/A | RW | RW |
|
||||
| appurl | String | App URL | N/A | RO | N/A |
|
||||
| appicon | Image | App Icon | N/A | N/A | RO |
|
||||
| player | Player | Player Control | RW | RW | RW |
|
||||
| power | Switch | Power Control | RW | RW | RW |
|
||||
| volume | Dimmer | Volume Control | RO | RO | RW |
|
||||
| mute | Switch | Mute Control | RW | RW | RW |
|
||||
| tvChannel | String | TV Channel Control | N/A | N/A | RW |
|
||||
| brightness | Dimmer | Brightness Control | N/A | N/A | RW |
|
||||
| contrast | Dimmer | Contrast Control | N/A | N/A | RW |
|
||||
| sharpness | Dimmer | Sharpness Control | N/A | N/A | RW |
|
||||
| searchContent | String | Google Assistant search | N/A | N/A | RW |
|
||||
| ambilightPower | Switch | Ambilight power control | N/A | N/A | RW |
|
||||
| ambilightHuePower | Switch | Ambilight + Hue power control | N/A | N/A | RW |
|
||||
| ambilightStyle | String | Ambilight Style plus algorithm used | N/A | N/A | RW |
|
||||
| ambilightColor | Color | Color for all Ambilight Sides | N/A | N/A | RW |
|
||||
| ambilightLeftColor | Color | Color for left Ambilight Side | N/A | N/A | RW |
|
||||
| ambilightRightColor | Color | Color for right Ambilight Side | N/A | N/A | RW |
|
||||
| ambilightTopColor | Color | Color for top Ambilight Side | N/A | N/A | RW |
|
||||
| ambilightBottomColor | Color | Color for bottom Ambilight Side | N/A | N/A | RW |
|
||||
|
||||
|
||||
```java
|
||||
@ -76,6 +99,32 @@ Switch ShieldTV_POWER "POWER [%s]" { channel = "androidtv:shieldtv:livingroom:po
|
||||
Dimmer ShieldTV_VOLUME "VOLUME [%s]" { channel = "androidtv:shieldtv:livingroom:volume" }
|
||||
Switch ShieldTV_MUTE "MUTE [%s]" { channel = "androidtv:shieldtv:livingroom:mute" }
|
||||
|
||||
String PhilipsTV_KEYBOARD "KEYBOARD [%s]" { channel = "androidtv:philipstv:bedroom:keyboard" }
|
||||
String PhilipsTV_KEYPRESS "KEYPRESS [%s]" { channel = "androidtv:philipstv:bedroom:keypress" }
|
||||
String PhilipsTV_KEYCODE "KEYCODE [%s]" { channel = "androidtv:philipstv:bedroom:keycode" }
|
||||
String PhilipsTV_PINCODE "PINCODE [%s]" { channel = "androidtv:philipstv:bedroom:pincode" }
|
||||
String PhilipsTV_APP "APP [%s]" { channel = "androidtv:philipstv:bedroom:app" }
|
||||
String PhilipsTV_APPNAME "APPNAME [%s]" { channel = "androidtv:philipstv:bedroom:appname" }
|
||||
Image PhilipsTV_APPICON "APPICON [%s]" { channel = "androidtv:philipstv:bedroom:appicon" }
|
||||
Player PhilipsTV_PLAYER "PLAYER [%s]" { channel = "androidtv:philipstv:bedroom:player" }
|
||||
Switch PhilipsTV_POWER "POWER" { channel = "androidtv:philipstv:bedroom:power" }
|
||||
Dimmer PhilipsTV_VOLUME "VOLUME [%s]" { channel = "androidtv:philipstv:bedroom:volume" }
|
||||
Switch PhilipsTV_MUTE "MUTE [%s]" { channel = "androidtv:philipstv:bedroom:mute" }
|
||||
String PhilipsTV_TVCHANNEL "TVCHANNEL [%s]" { channel = "androidtv:philipstv:bedroom:tvChannel" }
|
||||
String PhilipsTV_SEARCHCONTENT "SEARCH CONTENT [%s]" { channel = "androidtv:philipstv:bedroom:searchContent" }
|
||||
Switch PhilipsTV_AMBILIGHTPOWER "AMBILIGHT POWER [%s]" { channel = "androidtv:philipstv:bedroom:ambilightPower" }
|
||||
Switch PhilipsTV_AMBILIGHTHUEPOWER "AMBILIGHT HUE POWER [%s]" { channel = "androidtv:philipstv:bedroom:ambilightHuePower" }
|
||||
Switch PhilipsTV_AMBILIGHTLOUNGEPOWER "AMBILIGHT LOUNGE POWER" { channel = "androidtv:philipstv:bedroom:ambilightLoungePower" }
|
||||
String PhilipsTV_AMBILIGHTSTYLE "AMBILIGHT STYLE" { channel = "androidtv:philipstv:bedroom:ambilightStyle" }
|
||||
Color PhilipsTV_AMBILIGHTALLCOLOR "ALL SIDES AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightColor" }
|
||||
Color PhilipsTV_AMBILIGHTLEFTCOLOR "LEFT SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightLeftColor" }
|
||||
Color PhilipsTV_AMBILIGHTRIGHTCOLOR "RIGHT SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightRightColor" }
|
||||
Color PhilipsTV_AMBILIGHTTOPCOLOR "TOP SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightTopColor" }
|
||||
Color PhilipsTV_AMBILIGHTBOTTOMCOLOR "BOTTOM SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightBottomColor" }
|
||||
Dimmer PhilipsTV_BRIGHTNESS "BRIGHTNESS [%s]" { channel = "androidtv:philipstv:bedroom:brightness" }
|
||||
Dimmer PhilipsTV_CONTRAST "CONTRAST [%s]" { channel = "androidtv:philipstv:bedroom:contrast" }
|
||||
Dimmer PhilipsTV_SHARPNESS "SHARPNESS [%s]" { channel = "androidtv:philipstv:bedroom:sharpness" }
|
||||
|
||||
String GoogleTV_KEYBOARD "KEYBOARD [%s]" { channel = "androidtv:googletv:theater:keyboard" }
|
||||
String GoogleTV_KEYPRESS "KEYPRESS [%s]" { channel = "androidtv:googletv:theater:keypress" }
|
||||
String GoogleTV_KEYCODE "KEYCODE [%s]" { channel = "androidtv:googletv:theater:keycode" }
|
||||
@ -168,7 +217,7 @@ openhab> openhab:androidtv androidtv:googletv:theater pincode abc123
|
||||
|
||||
The display should return back to where it was originally.
|
||||
|
||||
If you are on a ShieldTV you must run that process a second time to authenticate the GoogleTV protocol stack.
|
||||
If you are on a ShieldTV or PhilipsTV you must run that process a second time to authenticate the GoogleTV protocol stack.
|
||||
|
||||
This completes the PIN process.
|
||||
|
||||
@ -179,6 +228,7 @@ Upon reconnection (either from reconfiguration or a restart of OpenHAB), you sho
|
||||
```java
|
||||
Thing androidtv:shieldtv:livingroom [ ipAddress="192.168.1.2" ]
|
||||
Thing androidtv:googletv:theater [ ipAddress="192.168.1.3" ]
|
||||
Thing androidtv:philipstv:bedroom [ ipAddress="192.168.1.4" ]
|
||||
```
|
||||
|
||||
```java
|
||||
@ -194,6 +244,32 @@ Switch ShieldTV_POWER "POWER [%s]" { channel = "androidtv:shieldtv:livingroom:po
|
||||
Dimmer ShieldTV_VOLUME "VOLUME [%s]" { channel = "androidtv:shieldtv:livingroom:volume" }
|
||||
Switch ShieldTV_MUTE "MUTE [%s]" { channel = "androidtv:shieldtv:livingroom:mute" }
|
||||
|
||||
String PhilipsTV_KEYBOARD "KEYBOARD [%s]" { channel = "androidtv:philipstv:bedroom:keyboard" }
|
||||
String PhilipsTV_KEYPRESS "KEYPRESS [%s]" { channel = "androidtv:philipstv:bedroom:keypress" }
|
||||
String PhilipsTV_KEYCODE "KEYCODE [%s]" { channel = "androidtv:philipstv:bedroom:keycode" }
|
||||
String PhilipsTV_PINCODE "PINCODE [%s]" { channel = "androidtv:philipstv:bedroom:pincode" }
|
||||
String PhilipsTV_APP "APP [%s]" { channel = "androidtv:philipstv:bedroom:app" }
|
||||
String PhilipsTV_APPNAME "APPNAME [%s]" { channel = "androidtv:philipstv:bedroom:appname" }
|
||||
Image PhilipsTV_APPICON "APPICON [%s]" { channel = "androidtv:philipstv:bedroom:appicon" }
|
||||
Player PhilipsTV_PLAYER "PLAYER [%s]" { channel = "androidtv:philipstv:bedroom:player" }
|
||||
Switch PhilipsTV_POWER "POWER" { channel = "androidtv:philipstv:bedroom:power" }
|
||||
Dimmer PhilipsTV_VOLUME "VOLUME [%s]" { channel = "androidtv:philipstv:bedroom:volume" }
|
||||
Switch PhilipsTV_MUTE "MUTE [%s]" { channel = "androidtv:philipstv:bedroom:mute" }
|
||||
String PhilipsTV_TVCHANNEL "TVCHANNEL [%s]" { channel = "androidtv:philipstv:bedroom:tvChannel" }
|
||||
String PhilipsTV_SEARCHCONTENT "SEARCH CONTENT [%s]" { channel = "androidtv:philipstv:bedroom:searchContent" }
|
||||
Switch PhilipsTV_AMBILIGHTPOWER "AMBILIGHT POWER [%s]" { channel = "androidtv:philipstv:bedroom:ambilightPower" }
|
||||
Switch PhilipsTV_AMBILIGHTHUEPOWER "AMBILIGHT HUE POWER [%s]" { channel = "androidtv:philipstv:bedroom:ambilightHuePower" }
|
||||
Switch PhilipsTV_AMBILIGHTLOUNGEPOWER "AMBILIGHT LOUNGE POWER" { channel = "androidtv:philipstv:bedroom:ambilightLoungePower" }
|
||||
String PhilipsTV_AMBILIGHTSTYLE "AMBILIGHT STYLE" { channel = "androidtv:philipstv:bedroom:ambilightStyle" }
|
||||
Color PhilipsTV_AMBILIGHTALLCOLOR "ALL SIDES AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightColor" }
|
||||
Color PhilipsTV_AMBILIGHTLEFTCOLOR "LEFT SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightLeftColor" }
|
||||
Color PhilipsTV_AMBILIGHTRIGHTCOLOR "RIGHT SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightRightColor" }
|
||||
Color PhilipsTV_AMBILIGHTTOPCOLOR "TOP SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightTopColor" }
|
||||
Color PhilipsTV_AMBILIGHTBOTTOMCOLOR "BOTTOM SIDE AMBILIGHT COLOR [%s]" { channel = "androidtv:philipstv:bedroom:ambilightBottomColor" }
|
||||
Dimmer PhilipsTV_BRIGHTNESS "BRIGHTNESS [%s]" { channel = "androidtv:philipstv:bedroom:brightness" }
|
||||
Dimmer PhilipsTV_CONTRAST "CONTRAST [%s]" { channel = "androidtv:philipstv:bedroom:contrast" }
|
||||
Dimmer PhilipsTV_SHARPNESS "SHARPNESS [%s]" { channel = "androidtv:philipstv:bedroom:sharpness" }
|
||||
|
||||
String GoogleTV_KEYBOARD "KEYBOARD [%s]" { channel = "androidtv:googletv:theater:keyboard" }
|
||||
String GoogleTV_KEYPRESS "KEYPRESS [%s]" { channel = "androidtv:googletv:theater:keypress" }
|
||||
String GoogleTV_KEYCODE "KEYCODE [%s]" { channel = "androidtv:googletv:theater:keycode" }
|
||||
|
@ -14,6 +14,10 @@
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: AndroidTV Binding</name>
|
||||
|
||||
<properties>
|
||||
<bnd.importpackage>!net.sf.ehcache.*,!net.spy.*</bnd.importpackage>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
@ -33,6 +37,36 @@
|
||||
<version>1.75</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient-osgi</artifactId>
|
||||
<version>4.5.14</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore-osgi</artifactId>
|
||||
<version>4.4.16</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
<feature name="openhab-binding-androidtv" description="AndroidTV Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-upnp</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.androidtv/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
|
@ -31,8 +31,9 @@ public class AndroidTVBindingConstants {
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_GOOGLETV = new ThingTypeUID(BINDING_ID, "googletv");
|
||||
public static final ThingTypeUID THING_TYPE_SHIELDTV = new ThingTypeUID(BINDING_ID, "shieldtv");
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_GOOGLETV, THING_TYPE_SHIELDTV);
|
||||
public static final ThingTypeUID THING_TYPE_PHILIPSTV = new ThingTypeUID(BINDING_ID, "philipstv");
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_GOOGLETV, THING_TYPE_SHIELDTV,
|
||||
THING_TYPE_PHILIPSTV);
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_DEBUG = "debug";
|
||||
@ -43,15 +44,32 @@ public class AndroidTVBindingConstants {
|
||||
public static final String CHANNEL_APP = "app";
|
||||
public static final String CHANNEL_APPNAME = "appname";
|
||||
public static final String CHANNEL_APPURL = "appurl";
|
||||
public static final String CHANNEL_APP_ICON = "appicon";
|
||||
public static final String CHANNEL_POWER = "power";
|
||||
public static final String CHANNEL_VOLUME = "volume";
|
||||
public static final String CHANNEL_MUTE = "mute";
|
||||
public static final String CHANNEL_PLAYER = "player";
|
||||
public static final String CHANNEL_BRIGHTNESS = "brightness";
|
||||
public static final String CHANNEL_CONTRAST = "contrast";
|
||||
public static final String CHANNEL_SHARPNESS = "sharpness";
|
||||
public static final String CHANNEL_TV_CHANNEL = "tvChannel";
|
||||
public static final String CHANNEL_SEARCH_CONTENT = "searchContent";
|
||||
public static final String CHANNEL_AMBILIGHT = "ambilight";
|
||||
public static final String CHANNEL_AMBILIGHT_POWER = "ambilightPower";
|
||||
public static final String CHANNEL_AMBILIGHT_HUE_POWER = "ambilightHuePower";
|
||||
public static final String CHANNEL_AMBILIGHT_LOUNGE_POWER = "ambilightLoungePower";
|
||||
public static final String CHANNEL_AMBILIGHT_STYLE = "ambilightStyle";
|
||||
public static final String CHANNEL_AMBILIGHT_COLOR = "ambilightColor";
|
||||
public static final String CHANNEL_AMBILIGHT_LEFT_COLOR = "ambilightLeftColor";
|
||||
public static final String CHANNEL_AMBILIGHT_RIGHT_COLOR = "ambilightRightColor";
|
||||
public static final String CHANNEL_AMBILIGHT_TOP_COLOR = "ambilightTopColor";
|
||||
public static final String CHANNEL_AMBILIGHT_BOTTOM_COLOR = "ambilightBottomColor";
|
||||
|
||||
// List of all config properties
|
||||
public static final String PARAMETER_IP_ADDRESS = "ipAddress";
|
||||
public static final String PARAMETER_GOOGLETV_PORT = "googletvPort";
|
||||
public static final String PARAMETER_SHIELDTV_PORT = "shieldtvPort";
|
||||
public static final String PARAMETER_PHILIPSTV_PORT = "philipstvPort";
|
||||
public static final String PARAMETER_GTV_ENABLED = "gtvEnabled";
|
||||
|
||||
// List of all static String literals
|
||||
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.StateDescriptionFragmentBuilder;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
|
||||
/**
|
||||
* Dynamic provider of state options while leaving other state description fields as original.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
*/
|
||||
@Component(service = { DynamicStateDescriptionProvider.class,
|
||||
AndroidTVDynamicStateDescriptionProvider.class }, immediate = true)
|
||||
@NonNullByDefault
|
||||
public class AndroidTVDynamicStateDescriptionProvider implements DynamicStateDescriptionProvider {
|
||||
private final Map<ChannelUID, List<@NonNull StateOption>> channelOptionsMap = new ConcurrentHashMap<>();
|
||||
|
||||
public void setStateOptions(ChannelUID channelUID, List<StateOption> options) {
|
||||
channelOptionsMap.put(channelUID, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable StateDescription getStateDescription(Channel channel, @Nullable StateDescription original,
|
||||
@Nullable Locale locale) {
|
||||
List<StateOption> options = channelOptionsMap.get(channel.getUID());
|
||||
|
||||
if (options == null) {
|
||||
return null;
|
||||
}
|
||||
if (original != null) {
|
||||
return StateDescriptionFragmentBuilder.create(original).withOptions(options).build().toStateDescription();
|
||||
}
|
||||
|
||||
return StateDescriptionFragmentBuilder.create().withOptions(options).build().toStateDescription();
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
channelOptionsMap.clear();
|
||||
}
|
||||
}
|
@ -25,14 +25,19 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.androidtv.internal.protocol.googletv.GoogleTVConfiguration;
|
||||
import org.openhab.binding.androidtv.internal.protocol.googletv.GoogleTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConfiguration;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.shieldtv.ShieldTVConfiguration;
|
||||
import org.openhab.binding.androidtv.internal.protocol.shieldtv.ShieldTVConnectionManager;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.CommandOption;
|
||||
@ -55,6 +60,7 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
|
||||
private @Nullable ShieldTVConnectionManager shieldtvConnectionManager;
|
||||
private @Nullable GoogleTVConnectionManager googletvConnectionManager;
|
||||
private @Nullable PhilipsTVConnectionManager philipstvConnectionManager;
|
||||
|
||||
private @Nullable ScheduledFuture<?> monitorThingStatusJob;
|
||||
private final Object monitorThingStatusJobLock = new Object();
|
||||
@ -68,13 +74,20 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
private String currentThingStatus = "";
|
||||
private boolean currentThingFailed = false;
|
||||
|
||||
private DiscoveryServiceRegistry discoveryServiceRegistry;
|
||||
|
||||
private AndroidTVDynamicStateDescriptionProvider stateDescriptionProvider;
|
||||
|
||||
public AndroidTVHandler(Thing thing, AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider,
|
||||
AndroidTVTranslationProvider translationProvider, ThingTypeUID thingTypeUID) {
|
||||
AndroidTVTranslationProvider translationProvider, DiscoveryServiceRegistry discoveryServiceRegistry,
|
||||
AndroidTVDynamicStateDescriptionProvider stateDescriptionProvider, ThingTypeUID thingTypeUID) {
|
||||
super(thing);
|
||||
this.commandDescriptionProvider = commandDescriptionProvider;
|
||||
this.translationProvider = translationProvider;
|
||||
this.thingTypeUID = thingTypeUID;
|
||||
this.thingID = this.getThing().getUID().getId();
|
||||
this.discoveryServiceRegistry = discoveryServiceRegistry;
|
||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||
}
|
||||
|
||||
public void setThingProperty(String property, String value) {
|
||||
@ -89,6 +102,22 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
return this.thingID;
|
||||
}
|
||||
|
||||
public Configuration getThingConfig() {
|
||||
return getConfig();
|
||||
}
|
||||
|
||||
public DiscoveryServiceRegistry getDiscoveryServiceRegistry() {
|
||||
return discoveryServiceRegistry;
|
||||
}
|
||||
|
||||
public AndroidTVDynamicStateDescriptionProvider getStateDescriptionProvider() {
|
||||
return stateDescriptionProvider;
|
||||
}
|
||||
|
||||
public ThingUID getThingUID() {
|
||||
return getThing().getUID();
|
||||
}
|
||||
|
||||
public void updateChannelState(String channel, State state) {
|
||||
updateState(channel, state);
|
||||
}
|
||||
@ -122,6 +151,7 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
|
||||
GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
|
||||
ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
|
||||
PhilipsTVConnectionManager philipstvConnectionManager = this.philipstvConnectionManager;
|
||||
|
||||
if (googletvConnectionManager != null) {
|
||||
if (!googletvConnectionManager.getLoggedIn()) {
|
||||
@ -143,6 +173,15 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (THING_TYPE_PHILIPSTV.equals(thingTypeUID)) {
|
||||
if (philipstvConnectionManager != null) {
|
||||
if (!philipstvConnectionManager.getLoggedIn()) {
|
||||
failed = true;
|
||||
}
|
||||
statusMessage = statusMessage + "PhilipsTV: " + philipstvConnectionManager.getStatusMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentThingStatus.equals(statusMessage) || (currentThingFailed != failed)) {
|
||||
if (failed) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, statusMessage);
|
||||
@ -186,14 +225,30 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
|
||||
}
|
||||
|
||||
if (THING_TYPE_PHILIPSTV.equals(thingTypeUID)) {
|
||||
PhilipsTVConfiguration philipstvConfig = getConfigAs(PhilipsTVConfiguration.class);
|
||||
ipAddress = philipstvConfig.ipAddress;
|
||||
|
||||
if (ipAddress.isBlank()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.philipstv-address-not-specified");
|
||||
return;
|
||||
}
|
||||
|
||||
philipstvConnectionManager = new PhilipsTVConnectionManager(this, philipstvConfig);
|
||||
}
|
||||
|
||||
monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void sendCommandToProtocol(ChannelUID channelUID, Command command) {
|
||||
ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
|
||||
PhilipsTVConnectionManager philipstvConnectionManager = this.philipstvConnectionManager;
|
||||
if (THING_TYPE_SHIELDTV.equals(thingTypeUID) && (shieldtvConnectionManager != null)) {
|
||||
shieldtvConnectionManager.handleCommand(channelUID, command);
|
||||
} else if (THING_TYPE_PHILIPSTV.equals(thingTypeUID) && (philipstvConnectionManager != null)) {
|
||||
philipstvConnectionManager.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,6 +263,7 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
|
||||
GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
|
||||
ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
|
||||
PhilipsTVConnectionManager philipstvConnectionManager = this.philipstvConnectionManager;
|
||||
|
||||
if (CHANNEL_DEBUG.equals(channelUID.getId())) {
|
||||
if (command instanceof StringType) {
|
||||
@ -231,10 +287,18 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
|
||||
shieldtvConfig.shim = true;
|
||||
shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
|
||||
} else if (command.toString().equals("PHILIPSTV_HALT") && (philipstvConnectionManager != null)) {
|
||||
philipstvConnectionManager.dispose();
|
||||
philipstvConnectionManager = null;
|
||||
} else if (command.toString().equals("PHILIPSTV_START")) {
|
||||
PhilipsTVConfiguration philipstvConfig = getConfigAs(PhilipsTVConfiguration.class);
|
||||
philipstvConnectionManager = new PhilipsTVConnectionManager(this, philipstvConfig);
|
||||
} else if (command.toString().startsWith("GOOGLETV") && (googletvConnectionManager != null)) {
|
||||
googletvConnectionManager.handleCommand(channelUID, command);
|
||||
} else if (command.toString().startsWith("SHIELDTV") && (shieldtvConnectionManager != null)) {
|
||||
shieldtvConnectionManager.handleCommand(channelUID, command);
|
||||
} else if (command.toString().startsWith("PHILIPSTV") && (philipstvConnectionManager != null)) {
|
||||
philipstvConnectionManager.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -259,6 +323,33 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (THING_TYPE_PHILIPSTV.equals(thingTypeUID) && (philipstvConnectionManager != null)) {
|
||||
if (googletvConnectionManager != null) {
|
||||
if (CHANNEL_PINCODE.equals(channelUID.getId())) {
|
||||
if (command instanceof StringType) {
|
||||
if (!philipstvConnectionManager.getLoggedIn()) {
|
||||
philipstvConnectionManager.handleCommand(channelUID, command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (CHANNEL_POWER.equals(channelUID.getId()) && !googletvConnectionManager.getLoggedIn()) {
|
||||
philipstvConnectionManager.handleCommand(channelUID, command);
|
||||
return;
|
||||
} else if (CHANNEL_APP.equals(channelUID.getId()) || CHANNEL_APPNAME.equals(channelUID.getId())
|
||||
|| CHANNEL_TV_CHANNEL.equals(channelUID.getId()) || CHANNEL_VOLUME.equals(channelUID.getId())
|
||||
|| CHANNEL_MUTE.equals(channelUID.getId()) || CHANNEL_SEARCH_CONTENT.equals(channelUID.getId())
|
||||
|| CHANNEL_BRIGHTNESS.equals(channelUID.getId()) || CHANNEL_SHARPNESS.equals(channelUID.getId())
|
||||
|| CHANNEL_CONTRAST.equals(channelUID.getId())
|
||||
|| channelUID.getId().startsWith(CHANNEL_AMBILIGHT)) {
|
||||
philipstvConnectionManager.handleCommand(channelUID, command);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
philipstvConnectionManager.handleCommand(channelUID, command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (googletvConnectionManager != null) {
|
||||
googletvConnectionManager.handleCommand(channelUID, command);
|
||||
return;
|
||||
@ -279,11 +370,16 @@ public class AndroidTVHandler extends BaseThingHandler {
|
||||
|
||||
GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
|
||||
ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
|
||||
PhilipsTVConnectionManager philipstvConnectionManager = this.philipstvConnectionManager;
|
||||
|
||||
if (shieldtvConnectionManager != null) {
|
||||
shieldtvConnectionManager.dispose();
|
||||
}
|
||||
|
||||
if (philipstvConnectionManager != null) {
|
||||
philipstvConnectionManager.dispose();
|
||||
}
|
||||
|
||||
if (googletvConnectionManager != null) {
|
||||
googletvConnectionManager.dispose();
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.thing.Thing;
|
||||
@ -39,18 +40,24 @@ import org.osgi.service.component.annotations.Reference;
|
||||
@Component(configurationPid = "binding.androidtv", service = ThingHandlerFactory.class)
|
||||
public class AndroidTVHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_GOOGLETV,
|
||||
THING_TYPE_SHIELDTV);
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_GOOGLETV, THING_TYPE_SHIELDTV,
|
||||
THING_TYPE_PHILIPSTV);
|
||||
|
||||
private final AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider;
|
||||
private final AndroidTVTranslationProvider translationProvider;
|
||||
private final DiscoveryServiceRegistry discoveryServiceRegistry;
|
||||
private final AndroidTVDynamicStateDescriptionProvider stateDescriptionProvider;
|
||||
|
||||
@Activate
|
||||
public AndroidTVHandlerFactory(
|
||||
final @Reference AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider,
|
||||
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider) {
|
||||
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
|
||||
final @Reference DiscoveryServiceRegistry discoveryServiceRegistry,
|
||||
final @Reference AndroidTVDynamicStateDescriptionProvider stateDescriptionProvider) {
|
||||
this.commandDescriptionProvider = commandDescriptionProvider;
|
||||
this.translationProvider = new AndroidTVTranslationProvider(i18nProvider, localeProvider);
|
||||
this.discoveryServiceRegistry = discoveryServiceRegistry;
|
||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -61,6 +68,7 @@ public class AndroidTVHandlerFactory extends BaseThingHandlerFactory {
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
return new AndroidTVHandler(thing, commandDescriptionProvider, translationProvider, thingTypeUID);
|
||||
return new AndroidTVHandler(thing, commandDescriptionProvider, translationProvider, discoveryServiceRegistry,
|
||||
stateDescriptionProvider, thingTypeUID);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpResponseException;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.conn.HttpHostConnectException;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* The {@link ConnectionManager} is responsible for handling https GETs and POSTs to the Philips
|
||||
* TVs.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ConnectionManager {
|
||||
|
||||
private static final String TARGET_URI_MSG = "Target Uri is: {}";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
// Cannot use jetty in OH2.4 due to 9.4.11.v20180605 version with digest auth bug
|
||||
// https://github.com/eclipse/jetty.project/issues/1555
|
||||
private final CloseableHttpClient httpClient;
|
||||
|
||||
private final HttpHost httpHost;
|
||||
|
||||
public ConnectionManager(CloseableHttpClient httpClient, HttpHost httpHost) {
|
||||
this.httpClient = httpClient;
|
||||
this.httpHost = httpHost;
|
||||
OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
public String doHttpsGet(String path) throws IOException {
|
||||
String uri = httpHost.toURI() + path;
|
||||
logger.debug(TARGET_URI_MSG, uri);
|
||||
HttpGet httpGet = new HttpGet(uri);
|
||||
String jsonContent = "";
|
||||
try (CloseableHttpClient client = httpClient; //
|
||||
CloseableHttpResponse response = client.execute(httpHost, httpGet)) {
|
||||
validateResponse(response, uri);
|
||||
jsonContent = getJsonFromResponse(response);
|
||||
} catch (HttpHostConnectException e) {
|
||||
logger.debug("HttpHostConnectException when getting {}", uri);
|
||||
}
|
||||
return jsonContent;
|
||||
}
|
||||
|
||||
public String doHttpsPost(String path, String json) throws IOException {
|
||||
String uri = httpHost.toURI() + path;
|
||||
logger.debug(TARGET_URI_MSG, uri);
|
||||
HttpPost httpPost = new HttpPost(uri);
|
||||
httpPost.setHeader("Content-type", "application/json");
|
||||
httpPost.setEntity(new StringEntity(json));
|
||||
String jsonContent = "";
|
||||
try (CloseableHttpClient client = httpClient; //
|
||||
CloseableHttpResponse response = client.execute(httpHost, httpPost)) {
|
||||
validateResponse(response, uri);
|
||||
jsonContent = getJsonFromResponse(response);
|
||||
} catch (HttpHostConnectException e) {
|
||||
logger.debug("HttpHostConnectException when getting {}", uri);
|
||||
}
|
||||
return jsonContent;
|
||||
}
|
||||
|
||||
private void validateResponse(CloseableHttpResponse response, String uri) throws HttpResponseException {
|
||||
if (response == null) {
|
||||
throw new HttpResponseException(0, String.format("The response for the request to %s was empty.", uri));
|
||||
} else if (response.getStatusLine().getStatusCode() == 401) {
|
||||
throw new HttpResponseException(401, "The given username/password combination is invalid.");
|
||||
}
|
||||
}
|
||||
|
||||
private String getJsonFromResponse(HttpResponse response) throws IOException {
|
||||
String jsonContent = EntityUtils.toString(response.getEntity());
|
||||
logger.trace("----------------------------------------");
|
||||
logger.trace("{}", response.getStatusLine());
|
||||
logger.trace("{}", jsonContent);
|
||||
return jsonContent;
|
||||
}
|
||||
|
||||
public byte[] doHttpsGetForImage(String path) throws IOException {
|
||||
String uri = httpHost.toURI() + path;
|
||||
logger.debug(TARGET_URI_MSG, uri);
|
||||
HttpGet httpGet = new HttpGet(uri);
|
||||
try (CloseableHttpClient client = httpClient;
|
||||
CloseableHttpResponse response = client.execute(httpHost, httpGet)) {
|
||||
if ((response != null) && (response.getStatusLine().getStatusCode() == 401)) {
|
||||
throw new HttpResponseException(401, "The given username/password combination is invalid.");
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
if (response != null) {
|
||||
response.getEntity().writeTo(baos);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.CONNECT_TIMEOUT_MILLISECONDS;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.HTTPS;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.MAX_REQUEST_RETRIES;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.SOCKET_TIMEOUT_MILLISECONDS;
|
||||
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.HttpRequestRetryHandler;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.HttpHostConnectException;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link ConnectionManagerUtil} is offering methods for connection specific processes.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class ConnectionManagerUtil {
|
||||
|
||||
private ConnectionManagerUtil() {
|
||||
}
|
||||
|
||||
public static CloseableHttpClient createSharedHttpClient(HttpHost target, String username, String password)
|
||||
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
|
||||
CredentialsProvider credProvider = new BasicCredentialsProvider();
|
||||
credProvider.setCredentials(new AuthScope(target.getHostName(), target.getPort()),
|
||||
new UsernamePasswordCredentials(username, password));
|
||||
|
||||
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT_MILLISECONDS)
|
||||
.setSocketTimeout(SOCKET_TIMEOUT_MILLISECONDS).build();
|
||||
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(getSslConnectionWithoutCertValidation(),
|
||||
NoopHostnameVerifier.INSTANCE);
|
||||
|
||||
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
|
||||
.register(HTTPS, sslsf).build();
|
||||
|
||||
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
|
||||
|
||||
HttpRequestRetryHandler requestRetryHandler = (exception, executionCount, context) -> {
|
||||
if (exception instanceof NoRouteToHostException) {
|
||||
return false;
|
||||
}
|
||||
String message = Optional.ofNullable(exception.getMessage()).orElse("");
|
||||
if (!message.isEmpty()) {
|
||||
if ((exception instanceof HttpHostConnectException) && message.contains("Connection refused")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return executionCount < MAX_REQUEST_RETRIES;
|
||||
};
|
||||
|
||||
return HttpClients.custom().setDefaultRequestConfig(requestConfig).setSSLSocketFactory(sslsf)
|
||||
.setDefaultCredentialsProvider(credProvider).setConnectionManager(connManager)
|
||||
.setRetryHandler(requestRetryHandler).setConnectionManagerShared(true).build();
|
||||
}
|
||||
|
||||
private static SSLContext getSslConnectionWithoutCertValidation()
|
||||
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
|
||||
return new SSLContextBuilder().loadTrustMaterial(null, (certificate, authType) -> true).build();
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link PhilipsTVBindingConstants} class defines common constants, which are used across the
|
||||
* whole binding.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PhilipsTVBindingConstants {
|
||||
|
||||
// Config Parameters
|
||||
public static final String HOST = "host";
|
||||
|
||||
public static final String PORT = "philipstvPort";
|
||||
|
||||
public static final String MAC_ADDRESS = "macAddress";
|
||||
|
||||
public static final String USERNAME = "username";
|
||||
|
||||
public static final String PASSWORD = "password";
|
||||
|
||||
public static final String HTTPS = "https";
|
||||
|
||||
// Connection specific values
|
||||
static final int CONNECT_TIMEOUT_MILLISECONDS = 3 * 1000;
|
||||
|
||||
static final int SOCKET_TIMEOUT_MILLISECONDS = 1000;
|
||||
|
||||
static final int MAX_REQUEST_RETRIES = 3;
|
||||
|
||||
// Default port for jointspace v6
|
||||
public static final int DEFAULT_PORT = 1926;
|
||||
|
||||
// Powerstates
|
||||
public static final String POWER_ON = "On";
|
||||
|
||||
public static final String POWER_OFF = "Off";
|
||||
|
||||
public static final String STANDBY = "Standby";
|
||||
|
||||
public static final String STANDBYKEEP = "StandbyKeep";
|
||||
|
||||
public static final String STANDBY_MSG = "online.standby";
|
||||
|
||||
public static final String EMPTY = "";
|
||||
|
||||
// REST Paths
|
||||
public static final String SLASH = "/";
|
||||
|
||||
private static final String API_VERSION = "6";
|
||||
|
||||
public static final String BASE_PATH = SLASH + API_VERSION + SLASH;
|
||||
|
||||
public static final String VOLUME_PATH = BASE_PATH + "audio" + SLASH + "volume";
|
||||
|
||||
public static final String KEY_CODE_PATH = BASE_PATH + "input" + SLASH + "key";
|
||||
|
||||
public static final String TV_POWERSTATE_PATH = BASE_PATH + "powerstate";
|
||||
|
||||
public static final String GET_AVAILABLE_APP_LIST_PATH = BASE_PATH + "applications";
|
||||
|
||||
public static final String GET_NETWORK_DEVICES_PATH = BASE_PATH + "network" + SLASH + "devices";
|
||||
|
||||
private static final String ACTIVITIES_BASE_PATH = BASE_PATH + "activities" + SLASH;
|
||||
|
||||
public static final String GET_AVAILABLE_TV_CHANNEL_LIST_PATH = BASE_PATH + "channeldb" + SLASH + "tv" + SLASH
|
||||
+ "channelLists" + SLASH + "all";
|
||||
|
||||
public static final String TV_CHANNEL_PATH = ACTIVITIES_BASE_PATH + "tv";
|
||||
public static final String GET_CURRENT_APP_PATH = ACTIVITIES_BASE_PATH + "current";
|
||||
public static final String LAUNCH_APP_PATH = ACTIVITIES_BASE_PATH + "launch";
|
||||
|
||||
private static final String AMBILIGHT_BASE_PATH = BASE_PATH + "ambilight" + SLASH;
|
||||
public static final String AMBILIGHT_POWERSTATE_PATH = AMBILIGHT_BASE_PATH + "power";
|
||||
public static final String AMBILIGHT_CONFIG_PATH = AMBILIGHT_BASE_PATH + "currentconfiguration";
|
||||
public static final String AMBILIGHT_MODE_PATH = AMBILIGHT_BASE_PATH + "mode";
|
||||
public static final String AMBILIGHT_CACHED_PATH = AMBILIGHT_BASE_PATH + "cached";
|
||||
public static final String AMBILIGHT_TOPOLOGY_PATH = AMBILIGHT_BASE_PATH + "topology";
|
||||
public static final String AMBILIGHT_LOUNGE_PATH = AMBILIGHT_BASE_PATH + "lounge";
|
||||
|
||||
private static final String SETTINGS_BASE_PATH = BASE_PATH + "menuitems" + SLASH + "settings" + SLASH;
|
||||
public static final String UPDATE_SETTINGS_PATH = SETTINGS_BASE_PATH + "update";
|
||||
public static final String CURRENT_SETTINGS_PATH = SETTINGS_BASE_PATH + "current";
|
||||
public static final String STRUCTURE_SETTINGS_PATH = SETTINGS_BASE_PATH + "structure";
|
||||
|
||||
// Logging messages
|
||||
public static final String TV_OFFLINE_MSG = "offline.tv-is-not-reachable-and-should-therefore-be-off";
|
||||
public static final String TV_NOT_LISTENING_MSG = "offline.tv-does-not-accept-commands-at-the-moment";
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link PhilipsTVConfiguration} class contains fields for mapping thing configuration parameters.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PhilipsTVConfiguration {
|
||||
|
||||
public String ipAddress = "";
|
||||
public Integer philipstvPort = 1926;
|
||||
public Integer refreshRate = 10;
|
||||
public boolean useUpnpDiscovery = true;
|
||||
public String pairingCode = "";
|
||||
}
|
@ -0,0 +1,696 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.androidtv.internal.AndroidTVDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.androidtv.internal.AndroidTVHandler;
|
||||
import org.openhab.binding.androidtv.internal.AndroidTVTranslationProvider;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.PhilipsTVPairing;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.AmbilightService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.AppService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.KeyPressService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.PowerService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.SearchContentService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.TvChannelService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.TvPictureService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.VolumeService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.core.OpenHAB;
|
||||
import org.openhab.core.config.discovery.DiscoveryListener;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryServiceRegistry;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* The {@link PhilipsTVHandler} is responsible for handling commands, which are sent to one of the
|
||||
* channels.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PhilipsTVConnectionManager implements DiscoveryListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private AndroidTVHandler handler;
|
||||
|
||||
public PhilipsTVConfiguration config;
|
||||
|
||||
private ScheduledExecutorService scheduler;
|
||||
|
||||
private final AndroidTVTranslationProvider translationProvider;
|
||||
|
||||
private DiscoveryServiceRegistry discoveryServiceRegistry;
|
||||
|
||||
private AndroidTVDynamicStateDescriptionProvider stateDescriptionProvider;
|
||||
|
||||
private @Nullable ThingUID upnpThingUID;
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshScheduler;
|
||||
|
||||
private final Predicate<ScheduledFuture<?>> isRefreshSchedulerRunning = r -> (r != null) && !r.isCancelled();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private boolean isLoggedIn = false;
|
||||
|
||||
private String statusMessage = "";
|
||||
|
||||
private HttpHost target;
|
||||
|
||||
private String username = "";
|
||||
private String password = "";
|
||||
private String macAddress = "";
|
||||
|
||||
private @Nullable ScheduledFuture<?> deviceHealthJob;
|
||||
private boolean isOnline = true;
|
||||
private boolean pendingPowerOn = false;
|
||||
|
||||
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
/* Philips TV services */
|
||||
private Map<String, PhilipsTVService> channelServices = new HashMap<>();
|
||||
|
||||
public PhilipsTVConnectionManager(AndroidTVHandler handler, PhilipsTVConfiguration config) {
|
||||
logger.debug("Create a Philips TV Handler for thing '{}'", handler.getThingUID());
|
||||
this.handler = handler;
|
||||
this.config = config;
|
||||
this.scheduler = handler.getScheduler();
|
||||
this.translationProvider = handler.getTranslationProvider();
|
||||
this.discoveryServiceRegistry = handler.getDiscoveryServiceRegistry();
|
||||
this.stateDescriptionProvider = handler.getStateDescriptionProvider();
|
||||
this.target = new HttpHost(config.ipAddress, config.philipstvPort, HTTPS);
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void setStatus(boolean isLoggedIn) {
|
||||
if (isLoggedIn) {
|
||||
setStatus(isLoggedIn, "online.online");
|
||||
} else {
|
||||
setStatus(isLoggedIn, "offline.unknown");
|
||||
}
|
||||
}
|
||||
|
||||
private void setStatus(boolean isLoggedIn, String statusMessage) {
|
||||
String translatedMessage = translationProvider.getText(statusMessage);
|
||||
logger.trace("setStatus to {} {} {}", isLoggedIn, statusMessage, translatedMessage);
|
||||
if ((this.isLoggedIn != isLoggedIn) || (!this.statusMessage.equals(translatedMessage))) {
|
||||
this.isLoggedIn = isLoggedIn;
|
||||
this.statusMessage = translatedMessage;
|
||||
handler.checkThingStatus();
|
||||
}
|
||||
}
|
||||
|
||||
public String getStatusMessage() {
|
||||
return statusMessage;
|
||||
}
|
||||
|
||||
public void setLoggedIn(boolean isLoggedIn) {
|
||||
if (this.isLoggedIn != isLoggedIn) {
|
||||
setStatus(isLoggedIn);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getLoggedIn() {
|
||||
return isLoggedIn;
|
||||
}
|
||||
|
||||
public void updateStatus(ThingStatus thingStatus, ThingStatusDetail thingStatusDetail, String thingStatusMessage) {
|
||||
if (thingStatus == ThingStatus.ONLINE) {
|
||||
setLoggedIn(true);
|
||||
} else {
|
||||
logger.trace("Updating status to {} {} {}", thingStatus, thingStatusDetail, thingStatusMessage);
|
||||
setStatus(false, thingStatusMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public String getMacAddress() {
|
||||
return this.macAddress;
|
||||
}
|
||||
|
||||
public void saveConfigs() {
|
||||
String folderName = OpenHAB.getUserDataFolder() + "/androidtv";
|
||||
File folder = new File(folderName);
|
||||
|
||||
if (!folder.exists()) {
|
||||
logger.debug("Creating directory {}", folderName);
|
||||
folder.mkdirs();
|
||||
}
|
||||
|
||||
String fileName = folderName + "/philipstv." + handler.getThing().getUID().getId() + ".config";
|
||||
|
||||
Map<String, String> configMap = new HashMap<>();
|
||||
configMap.put("username", username);
|
||||
configMap.put("password", password);
|
||||
configMap.put("macAddress", macAddress);
|
||||
|
||||
try {
|
||||
String configJson = OBJECT_MAPPER.writeValueAsString(configMap);
|
||||
logger.debug("Writing configJson \"{}\" to {}", configJson, fileName);
|
||||
Files.write(Paths.get(fileName), configJson.getBytes());
|
||||
} catch (JsonProcessingException e) {
|
||||
logger.warn("JsonProcessingException trying to save configMap: {}", e.getMessage(), e);
|
||||
} catch (IOException ex) {
|
||||
logger.debug("IOException when writing configJson to file {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void readConfigs() {
|
||||
String folderName = OpenHAB.getUserDataFolder() + "/androidtv";
|
||||
String fileName = folderName + "/philipstv." + handler.getThing().getUID().getId() + ".config";
|
||||
File file = new File(fileName);
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final byte[] contents = Files.readAllBytes(Paths.get(fileName));
|
||||
String configJson = new String(contents);
|
||||
logger.debug("Read configJson \"{}\" from {}", configJson, fileName);
|
||||
Map<String, String> configMap = OBJECT_MAPPER.readValue(configJson,
|
||||
new TypeReference<HashMap<String, String>>() {
|
||||
});
|
||||
this.username = Optional.ofNullable(configMap.get("username")).orElse("");
|
||||
this.password = Optional.ofNullable(configMap.get("password")).orElse("");
|
||||
this.macAddress = Optional.ofNullable(configMap.get("macAddress")).orElse("");
|
||||
logger.debug("Processed configJson as {} {} {}", this.username, this.password, this.macAddress);
|
||||
} catch (IOException ex) {
|
||||
logger.debug("IOException when reading configJson from file {}", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void setCreds(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
saveConfigs();
|
||||
}
|
||||
|
||||
private boolean servicePing() {
|
||||
int timeout = 500;
|
||||
|
||||
SocketAddress socketAddress = new InetSocketAddress(config.ipAddress, config.philipstvPort);
|
||||
try (Socket socket = new Socket()) {
|
||||
socket.connect(socketAddress, timeout);
|
||||
return true;
|
||||
} catch (ConnectException | SocketTimeoutException | NoRouteToHostException ignored) {
|
||||
return false;
|
||||
} catch (IOException ignored) {
|
||||
// IOException is thrown by automatic close() of the socket.
|
||||
// This should actually never return a value as we should return true above already
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkHealth() {
|
||||
boolean isOnline = servicePing();
|
||||
logger.debug("{} - Device Health - Online: {} - Logged In: {}", handler.getThingID(), isOnline, isLoggedIn);
|
||||
if (isOnline != this.isOnline) {
|
||||
this.isOnline = isOnline;
|
||||
if (isOnline) {
|
||||
logger.debug("{} - Device is back online. Attempting reconnection.", handler.getThingID());
|
||||
connect();
|
||||
} else {
|
||||
logger.debug("{} - Device is offline.", handler.getThingID());
|
||||
postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"offline.communication-error-will-try-to-reconnect");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPendingPowerOn() {
|
||||
if (pendingPowerOn) {
|
||||
@Nullable
|
||||
PhilipsTVService powerService = channelServices.get(CHANNEL_POWER);
|
||||
if (powerService != null) {
|
||||
powerService.handleCommand(CHANNEL_POWER, OnOffType.ON);
|
||||
}
|
||||
pendingPowerOn = false;
|
||||
startDeviceHealthJob(5, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("Received channel: {}, command: {}", channelUID, command);
|
||||
String username = this.username;
|
||||
String password = this.password;
|
||||
|
||||
if (channelUID.getId().equals(CHANNEL_PINCODE)) {
|
||||
if (command instanceof StringType) {
|
||||
HttpHost target = new HttpHost(config.ipAddress, config.philipstvPort, HTTPS);
|
||||
if (command.toString().equals("REQUEST")) {
|
||||
try {
|
||||
initPairingCodeRetrieval(target);
|
||||
} catch (IOException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"offline.error-occured-while-presenting-pairing-code");
|
||||
}
|
||||
} else {
|
||||
boolean hasFailed = initCredentialsRetrieval(target, command.toString());
|
||||
if (hasFailed) {
|
||||
postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"offline.error-occured-during-retrieval-of-credentials");
|
||||
return;
|
||||
}
|
||||
readConfigs();
|
||||
username = this.username;
|
||||
password = this.password;
|
||||
|
||||
if ((username.isEmpty()) || (password.isEmpty())) {
|
||||
postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"offline.pairing-was-unsuccessful");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((username.isEmpty()) || (password.isEmpty())) {
|
||||
return; // pairing process is not finished
|
||||
}
|
||||
|
||||
boolean isLoggedIn = this.isLoggedIn;
|
||||
Map<String, PhilipsTVService> channelServices = this.channelServices;
|
||||
|
||||
if ((!isLoggedIn) && (!channelUID.getId().equals(CHANNEL_POWER)
|
||||
& !channelUID.getId().equals(CHANNEL_AMBILIGHT_LOUNGE_POWER))) {
|
||||
// Check if tv turned on meanwhile
|
||||
@Nullable
|
||||
PhilipsTVService powerService = channelServices.get(CHANNEL_POWER);
|
||||
if (powerService != null) {
|
||||
powerService.handleCommand(CHANNEL_POWER, RefreshType.REFRESH);
|
||||
}
|
||||
isLoggedIn = this.isLoggedIn;
|
||||
if (!isLoggedIn) {
|
||||
// still offline
|
||||
logger.warn(
|
||||
"Cannot execute command {} for channel {}: PowerState of TV was checked and resolved to offline.",
|
||||
command, channelUID.getId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String channel = channelUID.getId();
|
||||
long startTime = System.currentTimeMillis();
|
||||
// Delegate the other commands to correct channel service
|
||||
@Nullable
|
||||
PhilipsTVService philipsTvService = channelServices.get(channel);
|
||||
|
||||
if (philipsTvService == null) {
|
||||
logger.warn("Unknown channel for Philips TV Binding: {}", channel);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!isLoggedIn) && (channelUID.getId().equals(CHANNEL_POWER)) && (command.equals(OnOffType.ON))) {
|
||||
startDeviceHealthJob(1, TimeUnit.SECONDS);
|
||||
pendingPowerOn = true;
|
||||
}
|
||||
|
||||
philipsTvService.handleCommand(channel, command);
|
||||
long stopTime = System.currentTimeMillis();
|
||||
long elapsedTime = stopTime - startTime;
|
||||
logger.trace("The command {} took : {} nanoseconds", command.toFullString(), elapsedTime);
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
logger.debug("Init of handler for Thing: {}", handler.getThingID());
|
||||
|
||||
readConfigs();
|
||||
String username = this.username;
|
||||
String password = this.password;
|
||||
|
||||
if ((username.isEmpty()) || (password.isEmpty())) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
|
||||
"offline.pairing-is-not-configured-yet");
|
||||
return;
|
||||
}
|
||||
|
||||
connect();
|
||||
startDeviceHealthJob(5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void startDeviceHealthJob(int interval, TimeUnit unit) {
|
||||
ScheduledFuture<?> deviceHealthJob = this.deviceHealthJob;
|
||||
if (deviceHealthJob != null) {
|
||||
deviceHealthJob.cancel(true);
|
||||
}
|
||||
this.deviceHealthJob = scheduler.scheduleWithFixedDelay(this::checkHealth, interval, interval, unit);
|
||||
}
|
||||
|
||||
private void connect() {
|
||||
HttpHost target = this.target;
|
||||
String username = this.username;
|
||||
String password = this.password;
|
||||
String macAddress = this.macAddress;
|
||||
logger.debug("Starting connection to {} {} {}", username, password, macAddress);
|
||||
|
||||
if (!config.useUpnpDiscovery && isSchedulerInitializable()) {
|
||||
logger.debug("connect starting refresh scheduler");
|
||||
startRefreshScheduler();
|
||||
}
|
||||
|
||||
CloseableHttpClient httpClient;
|
||||
|
||||
try {
|
||||
httpClient = ConnectionManagerUtil.createSharedHttpClient(target, username, password);
|
||||
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
|
||||
postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
String.format("offline.error-occurred-during-creation-of-http-client: %s", e.getMessage()));
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionManager connectionManager = new ConnectionManager(httpClient, target);
|
||||
|
||||
if (macAddress.isEmpty()) {
|
||||
try {
|
||||
Optional<String> wolAddress = WakeOnLanUtil.getMacFromEnabledInterface(connectionManager);
|
||||
if (wolAddress.isPresent()) {
|
||||
this.macAddress = wolAddress.get();
|
||||
saveConfigs();
|
||||
} else {
|
||||
logger.debug("MAC Address could not be determined for Wake-On-LAN support, "
|
||||
+ "because Wake-On-LAN is not enabled on the TV.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.debug("Error occurred during retrieval of MAC Address: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
startServices(connectionManager);
|
||||
|
||||
discoveryServiceRegistry.addDiscoveryListener(this);
|
||||
|
||||
// Thing is initialized, check power state and available communication of the TV and set ONLINE or OFFLINE
|
||||
postUpdateThing(ThingStatus.ONLINE, ThingStatusDetail.NONE, "online.online");
|
||||
|
||||
Map<String, PhilipsTVService> channelServices = this.channelServices;
|
||||
@Nullable
|
||||
PhilipsTVService powerService = channelServices.get(CHANNEL_POWER);
|
||||
if (powerService != null) {
|
||||
powerService.handleCommand(CHANNEL_POWER, RefreshType.REFRESH);
|
||||
}
|
||||
}
|
||||
|
||||
private void startServices(ConnectionManager connectionManager) {
|
||||
Map<String, PhilipsTVService> services = new HashMap<>();
|
||||
|
||||
PhilipsTVService volumeService = new VolumeService(this, connectionManager);
|
||||
services.put(CHANNEL_VOLUME, volumeService);
|
||||
services.put(CHANNEL_MUTE, volumeService);
|
||||
|
||||
PhilipsTVService tvPictureService = new TvPictureService(this, connectionManager);
|
||||
services.put(CHANNEL_BRIGHTNESS, tvPictureService);
|
||||
services.put(CHANNEL_SHARPNESS, tvPictureService);
|
||||
services.put(CHANNEL_CONTRAST, tvPictureService);
|
||||
|
||||
PhilipsTVService keyPressService = new KeyPressService(this, connectionManager);
|
||||
services.put(CHANNEL_KEYPRESS, keyPressService);
|
||||
services.put(CHANNEL_PLAYER, keyPressService);
|
||||
|
||||
PhilipsTVService appService = new AppService(this, connectionManager);
|
||||
services.put(CHANNEL_APP, appService);
|
||||
services.put(CHANNEL_APPNAME, appService);
|
||||
services.put(CHANNEL_APP_ICON, appService);
|
||||
|
||||
PhilipsTVService ambilightService = new AmbilightService(this, connectionManager);
|
||||
services.put(CHANNEL_AMBILIGHT_POWER, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_HUE_POWER, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_LOUNGE_POWER, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_STYLE, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_COLOR, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_LEFT_COLOR, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_RIGHT_COLOR, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_TOP_COLOR, ambilightService);
|
||||
services.put(CHANNEL_AMBILIGHT_BOTTOM_COLOR, ambilightService);
|
||||
|
||||
services.put(CHANNEL_TV_CHANNEL, new TvChannelService(this, connectionManager));
|
||||
services.put(CHANNEL_POWER, new PowerService(this, connectionManager));
|
||||
services.put(CHANNEL_SEARCH_CONTENT, new SearchContentService(this, connectionManager));
|
||||
channelServices = Collections.unmodifiableMap(services);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the pairing Process with the TV, which results in a Pairing Code shown on TV.
|
||||
*/
|
||||
private void initPairingCodeRetrieval(HttpHost target)
|
||||
throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
|
||||
logger.info("Pairing code for tv authentication is missing. "
|
||||
+ "Starting initial pairing process. Please provide manually the pairing code shown on the tv at the configuration of the tv thing.");
|
||||
PhilipsTVPairing pairing = new PhilipsTVPairing();
|
||||
pairing.requestPairingPin(target);
|
||||
}
|
||||
|
||||
private boolean initCredentialsRetrieval(HttpHost target, String pincode) {
|
||||
boolean hasFailed = false;
|
||||
logger.info(
|
||||
"Pairing code is available, but username and/or password is missing. Therefore we try to grant authorization and retrieve username and password.");
|
||||
PhilipsTVPairing pairing = new PhilipsTVPairing();
|
||||
try {
|
||||
if (pincode.isEmpty()) {
|
||||
pairing.finishPairingWithTv(config.pairingCode, this, target);
|
||||
} else {
|
||||
pairing.finishPairingWithTv(pincode, this, target);
|
||||
}
|
||||
postUpdateThing(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
|
||||
"offline.authentication-with-philips-tv-device-was-successful-continuing-initialization-of-the-tv");
|
||||
} catch (Exception e) {
|
||||
postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
|
||||
"offline.could-not-successfully-finish-pairing-process-with-the-tv");
|
||||
logger.warn("Error during finishing pairing process with the TV: {}", e.getMessage(), e);
|
||||
hasFailed = true;
|
||||
}
|
||||
return hasFailed;
|
||||
}
|
||||
|
||||
// callback methods for channel services
|
||||
public void postUpdateChannel(String channelUID, State state) {
|
||||
handler.updateChannelState(channelUID, state);
|
||||
}
|
||||
|
||||
public synchronized void postUpdateThing(ThingStatus status, ThingStatusDetail statusDetail, String msg) {
|
||||
logger.trace("postUpdateThing {} {} {}", status, statusDetail, msg);
|
||||
if (status == ThingStatus.ONLINE) {
|
||||
if (msg.equalsIgnoreCase(STANDBY_MSG)) {
|
||||
handler.updateChannelState(CHANNEL_POWER, OnOffType.OFF);
|
||||
} else {
|
||||
handler.updateChannelState(CHANNEL_POWER, OnOffType.ON);
|
||||
startDeviceHealthJob(5, TimeUnit.SECONDS);
|
||||
pendingPowerOn = false;
|
||||
}
|
||||
if (isSchedulerInitializable()) { // Init refresh scheduler only, if pairing is completed
|
||||
startRefreshScheduler();
|
||||
}
|
||||
} else if (status == ThingStatus.OFFLINE) {
|
||||
handler.updateChannelState(CHANNEL_POWER, OnOffType.OFF);
|
||||
if (!TV_NOT_LISTENING_MSG.equals(msg)) { // avoid cancelling refresh if TV is temporarily not available
|
||||
ScheduledFuture<?> refreshScheduler = this.refreshScheduler;
|
||||
if (refreshScheduler != null) {
|
||||
if (config.useUpnpDiscovery && isRefreshSchedulerRunning.test(refreshScheduler)) {
|
||||
stopRefreshScheduler();
|
||||
}
|
||||
}
|
||||
// Reset app and channel list (if existing) for new retrieval during next startup
|
||||
Map<String, PhilipsTVService> channelServices = this.channelServices;
|
||||
@Nullable
|
||||
PhilipsTVService appnameService = channelServices.get(CHANNEL_APPNAME);
|
||||
if (appnameService != null) {
|
||||
((AppService) appnameService).clearAvailableAppList();
|
||||
}
|
||||
@Nullable
|
||||
PhilipsTVService tvchannelService = channelServices.get(CHANNEL_TV_CHANNEL);
|
||||
if (tvchannelService != null) {
|
||||
((TvChannelService) tvchannelService).clearAvailableTvChannelList();
|
||||
}
|
||||
}
|
||||
}
|
||||
updateStatus(status, statusDetail, msg);
|
||||
}
|
||||
|
||||
private boolean isSchedulerInitializable() {
|
||||
String username = this.username;
|
||||
String password = this.password;
|
||||
boolean schedulerIsDone = false;
|
||||
ScheduledFuture<?> refreshScheduler = this.refreshScheduler;
|
||||
if (refreshScheduler != null) {
|
||||
schedulerIsDone = refreshScheduler.isDone();
|
||||
}
|
||||
return (!username.isEmpty()) && (!password.isEmpty()) && ((refreshScheduler == null) || schedulerIsDone);
|
||||
}
|
||||
|
||||
private void startRefreshScheduler() {
|
||||
int configuredRefreshRateOrDefault = Optional.ofNullable(config.refreshRate).orElse(10);
|
||||
if (configuredRefreshRateOrDefault > 0) { // If value equals zero, refreshing should not be scheduled
|
||||
ScheduledFuture<?> refreshScheduler = this.refreshScheduler;
|
||||
if (refreshScheduler != null) {
|
||||
logger.debug("Refresh Scheduler already started for Philips TV {}, terminating.", handler.getThingID());
|
||||
if (isRefreshSchedulerRunning.test(refreshScheduler)) {
|
||||
stopRefreshScheduler();
|
||||
}
|
||||
}
|
||||
logger.debug("Starting Refresh Scheduler for Philips TV {} with refresh rate of {}.", handler.getThingID(),
|
||||
configuredRefreshRateOrDefault);
|
||||
this.refreshScheduler = scheduler.scheduleWithFixedDelay(this::refreshTvProperties, 10,
|
||||
configuredRefreshRateOrDefault, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopRefreshScheduler() {
|
||||
logger.debug("Stopping Refresh Scheduler for Philips TV: {}", handler.getThingID());
|
||||
ScheduledFuture<?> refreshScheduler = this.refreshScheduler;
|
||||
if (refreshScheduler != null) {
|
||||
refreshScheduler.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshTvProperties() {
|
||||
try {
|
||||
boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS);
|
||||
if (isLockAcquired) {
|
||||
try {
|
||||
if (isOnline) {
|
||||
Map<String, PhilipsTVService> channelServices = this.channelServices;
|
||||
@Nullable
|
||||
PhilipsTVService powerService = channelServices.get(CHANNEL_POWER);
|
||||
if (powerService != null) {
|
||||
powerService.handleCommand(CHANNEL_POWER, RefreshType.REFRESH);
|
||||
}
|
||||
@Nullable
|
||||
PhilipsTVService volumeService = channelServices.get(CHANNEL_VOLUME);
|
||||
if (volumeService != null) {
|
||||
volumeService.handleCommand(CHANNEL_VOLUME, RefreshType.REFRESH);
|
||||
}
|
||||
@Nullable
|
||||
PhilipsTVService appnameService = channelServices.get(CHANNEL_APPNAME);
|
||||
if (appnameService != null) {
|
||||
appnameService.handleCommand(CHANNEL_APPNAME, RefreshType.REFRESH);
|
||||
}
|
||||
@Nullable
|
||||
PhilipsTVService tvchannelService = channelServices.get(CHANNEL_TV_CHANNEL);
|
||||
if (tvchannelService != null) {
|
||||
tvchannelService.handleCommand(CHANNEL_TV_CHANNEL, RefreshType.REFRESH);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
logger.warn("Exception occurred during refreshing the tv properties: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateChannelStateDescription(final String channelId, Map<String, String> values) {
|
||||
AndroidTVDynamicStateDescriptionProvider stateDescriptionProvider = this.stateDescriptionProvider;
|
||||
List<StateOption> options = new ArrayList<>();
|
||||
if (!values.isEmpty()) {
|
||||
values.forEach((key, value) -> options.add(new StateOption(key, value)));
|
||||
stateDescriptionProvider.setStateOptions(new ChannelUID(handler.getThingUID(), channelId), options);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thingDiscovered(DiscoveryService source, DiscoveryResult result) {
|
||||
logger.debug("thingDiscovered: {}", result);
|
||||
|
||||
if (config.useUpnpDiscovery && config.ipAddress.equals(result.getProperties().get(HOST))) {
|
||||
upnpThingUID = result.getThingUID();
|
||||
logger.debug("thingDiscovered, thingUID={}, discoveredUID={}", handler.getThingUID(), upnpThingUID);
|
||||
Map<String, PhilipsTVService> channelServices = this.channelServices;
|
||||
@Nullable
|
||||
PhilipsTVService powerService = channelServices.get(CHANNEL_POWER);
|
||||
if (powerService != null) {
|
||||
powerService.handleCommand(CHANNEL_POWER, RefreshType.REFRESH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thingRemoved(DiscoveryService discoveryService, ThingUID thingUID) {
|
||||
logger.debug("thingRemoved: {}", thingUID);
|
||||
|
||||
if (thingUID.equals(upnpThingUID)) {
|
||||
postUpdateThing(ThingStatus.ONLINE, ThingStatusDetail.NONE, "online.standby");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Collection<ThingUID> removeOlderResults(DiscoveryService discoveryService, long l,
|
||||
@Nullable Collection<ThingTypeUID> collection, @Nullable ThingUID thingUID) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
discoveryServiceRegistry.removeDiscoveryListener(this);
|
||||
ScheduledFuture<?> refreshScheduler = this.refreshScheduler;
|
||||
if (refreshScheduler != null) {
|
||||
if (isRefreshSchedulerRunning.test(refreshScheduler)) {
|
||||
stopRefreshScheduler();
|
||||
}
|
||||
}
|
||||
ScheduledFuture<?> deviceHealthJob = this.deviceHealthJob;
|
||||
if (deviceHealthJob != null) {
|
||||
deviceHealthJob.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.GET_NETWORK_DEVICES_PATH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InterfaceAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
/**
|
||||
* The {@link WakeOnLanUtil} is offering methods for powering on TVs via Wake-On-LAN.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public final class WakeOnLanUtil {
|
||||
|
||||
private static final int MAX_WOL_RETRIES = 10;
|
||||
|
||||
private static final int WOL_PORT = 9;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(WakeOnLanUtil.class);
|
||||
|
||||
private static final Pattern MAC_PATTERN = Pattern.compile("([:\\-])");
|
||||
|
||||
private static final Predicate<JsonNode> IS_WOL_ENABLED = j -> j.get("wake-on-lan").asText()
|
||||
.equalsIgnoreCase("Enabled");
|
||||
|
||||
private static final Predicate<NetworkInterface> IS_NOT_LOOPBACK = ni -> {
|
||||
try {
|
||||
return !ni.isLoopback();
|
||||
} catch (SocketException e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private WakeOnLanUtil() {
|
||||
}
|
||||
|
||||
public static Optional<String> getMacFromEnabledInterface(ConnectionManager connectionManager) throws IOException {
|
||||
String jsonContent = connectionManager.doHttpsGet(GET_NETWORK_DEVICES_PATH);
|
||||
List<JsonNode> jsonNode = OBJECT_MAPPER.readValue(jsonContent, new TypeReference<List<JsonNode>>() {
|
||||
});
|
||||
|
||||
return jsonNode.stream().filter(IS_WOL_ENABLED).map(j -> j.get("mac").asText())
|
||||
.peek(m -> LOGGER.debug("Mac identified as: {}", m)).findFirst();
|
||||
}
|
||||
|
||||
public static void wakeOnLan(String ip, String mac) throws IOException, InterruptedException {
|
||||
for (int i = 0; i < MAX_WOL_RETRIES; i++) {
|
||||
if (isReachable(ip)) {
|
||||
Thread.sleep(2000);
|
||||
return;
|
||||
} else {
|
||||
Thread.sleep(100);
|
||||
sendWakeOnLanPackage(mac);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendWakeOnLanPackage(String mac) throws IOException {
|
||||
byte[] macBytes = getMacBytes(mac);
|
||||
byte[] bytes = new byte[6 + (16 * macBytes.length)];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
bytes[i] = (byte) 0xff;
|
||||
}
|
||||
for (int i = 6; i < bytes.length; i += macBytes.length) {
|
||||
System.arraycopy(macBytes, 0, bytes, i, macBytes.length);
|
||||
}
|
||||
|
||||
List<InetAddress> broadcastAddresses = Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
|
||||
.filter(IS_NOT_LOOPBACK).map(NetworkInterface::getInterfaceAddresses).flatMap(Collection::stream)
|
||||
.map(InterfaceAddress::getBroadcast).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
|
||||
for (InetAddress broadcast : broadcastAddresses) {
|
||||
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, broadcast, WOL_PORT);
|
||||
try (DatagramSocket socket = new DatagramSocket()) {
|
||||
LOGGER.debug("WOL sent to Broadcast-IP {} with MAC {}", broadcast, mac);
|
||||
socket.send(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getMacBytes(String mac) {
|
||||
byte[] bytes = new byte[6];
|
||||
String[] hex = MAC_PATTERN.split(mac);
|
||||
if (hex.length != 6) {
|
||||
throw new IllegalArgumentException("Invalid MAC address.");
|
||||
}
|
||||
try {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
bytes[i] = (byte) Integer.parseInt(hex[i], 16);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Invalid hex digit in MAC address.");
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static boolean isReachable(String ipAddress) throws IOException {
|
||||
InetAddress inetAddress = InetAddress.getByName(ipAddress);
|
||||
return inetAddress.isReachable(1000);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.discovery;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.jupnp.model.meta.DeviceDetails;
|
||||
import org.jupnp.model.meta.ModelDetails;
|
||||
import org.jupnp.model.meta.RemoteDevice;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link PhilipsTVDiscoveryParticipant} is responsible for discovering Philips TV devices through UPnP.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(immediate = true)
|
||||
public class PhilipsTVDiscoveryParticipant implements UpnpDiscoveryParticipant {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return Collections.singleton(THING_TYPE_PHILIPSTV);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
|
||||
final ThingUID uid = getThingUID(device);
|
||||
if (uid == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Map<String, Object> properties = new HashMap<>(2);
|
||||
String ipAddress = device.getIdentity().getDescriptorURL().getHost();
|
||||
properties.put(PARAMETER_IP_ADDRESS, ipAddress);
|
||||
properties.put(PARAMETER_PHILIPSTV_PORT, DEFAULT_PORT);
|
||||
logger.debug("Philips TV Found: {}, using default port {}", ipAddress, DEFAULT_PORT);
|
||||
String friendlyName = device.getDetails().getFriendlyName();
|
||||
if (friendlyName.length() > 0 && Character.isDigit(friendlyName.charAt(0))) {
|
||||
friendlyName = "_" + friendlyName; // label must not start with a digit
|
||||
}
|
||||
|
||||
return DiscoveryResultBuilder.create(uid).withThingType(THING_TYPE_PHILIPSTV).withProperties(properties)
|
||||
.withLabel(friendlyName).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
||||
DeviceDetails details = device.getDetails();
|
||||
if (details != null) {
|
||||
ModelDetails modelDetails = details.getModelDetails();
|
||||
if (modelDetails != null) {
|
||||
String modelName = modelDetails.getModelName();
|
||||
String modelDescription = modelDetails.getModelDescription();
|
||||
if (modelName != null && modelDescription != null) {
|
||||
if (modelName.contains("Philips TV")) {
|
||||
logger.debug("Device found: {} with desc {}", modelName, modelDescription);
|
||||
// One Philips TV contains several UPnP devices.
|
||||
// Create unique Philips TV thing for every Media Renderer
|
||||
// device and ignore rest of the UPnP devices.
|
||||
if (modelDescription.contains("Media")) {
|
||||
// UDN shouldn't contain '-' characters.
|
||||
String udn = device.getIdentity().getUdn().getIdentifierString().replace("-", "_");
|
||||
logger.debug("Discovered a Philips TV '{}' model '{}' thing with UDN '{}'",
|
||||
device.getDetails().getFriendlyName(), modelName, udn);
|
||||
|
||||
return new ThingUID(THING_TYPE_PHILIPSTV, udn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.pairing;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.BASE_PATH;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.EMPTY;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.SLASH;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Base64;
|
||||
import java.util.Formatter;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.MalformedChallengeException;
|
||||
import org.apache.http.client.AuthCache;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.auth.DigestScheme;
|
||||
import org.apache.http.impl.client.BasicAuthCache;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManagerUtil;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model.AuthDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model.DeviceDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model.FinishPairingDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model.PairingDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model.RequestCodeDTO;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link PhilipsTVPairing} is responsible for the initial pairing process with the Philips TV.
|
||||
* The outcome of this one-time pairing is a registered user with password, which will be used for
|
||||
* controlling the tv.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PhilipsTVPairing {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private static String authTimestamp = "";
|
||||
|
||||
private static String authKey = "";
|
||||
|
||||
private static String deviceId = "";
|
||||
|
||||
private final String pairingBasePath = BASE_PATH + "pair" + SLASH;
|
||||
|
||||
public void requestPairingPin(HttpHost target)
|
||||
throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
|
||||
RequestCodeDTO requestCodeDTO = new RequestCodeDTO(
|
||||
Stream.of("read", "write", "control").collect(Collectors.toList()), createDeviceSpecification());
|
||||
|
||||
CloseableHttpClient httpClient = ConnectionManagerUtil.createSharedHttpClient(target, EMPTY, EMPTY);
|
||||
ConnectionManager connectionManager = new ConnectionManager(httpClient, target);
|
||||
String requestCodeJson = OBJECT_MAPPER.writeValueAsString(requestCodeDTO);
|
||||
String requestPairingCodePath = pairingBasePath + "request";
|
||||
logger.debug("Request pairing code with json: {}", requestCodeJson);
|
||||
PairingDTO pairingDTO = OBJECT_MAPPER
|
||||
.readValue(connectionManager.doHttpsPost(requestPairingCodePath, requestCodeJson), PairingDTO.class);
|
||||
|
||||
authTimestamp = pairingDTO.getTimestamp();
|
||||
authKey = pairingDTO.getAuthKey();
|
||||
|
||||
logger.info("The pairing code is valid for {} seconds.", pairingDTO.getTimeout());
|
||||
}
|
||||
|
||||
public void finishPairingWithTv(String pairingCode, PhilipsTVConnectionManager handler, HttpHost target)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException, IOException, KeyStoreException,
|
||||
KeyManagementException {
|
||||
AuthDTO authDTO = new AuthDTO();
|
||||
authDTO.setAuthAppId("1");
|
||||
authDTO.setAuthSignature(calculateRFC2104HMAC(authTimestamp + pairingCode));
|
||||
authDTO.setAuthTimestamp(authTimestamp);
|
||||
authDTO.setPin(pairingCode);
|
||||
|
||||
FinishPairingDTO finishPairingDTO = new FinishPairingDTO(createDeviceSpecification(), authDTO);
|
||||
String grantPairingJson = OBJECT_MAPPER.writeValueAsString(finishPairingDTO);
|
||||
|
||||
Header challengeHeader = null;
|
||||
try (CloseableHttpClient httpClient = ConnectionManagerUtil.createSharedHttpClient(target, EMPTY, EMPTY)) {
|
||||
CloseableHttpResponse response = httpClient
|
||||
.execute(new HttpGet(target.toURI() + pairingBasePath + "grant"));
|
||||
challengeHeader = response.getFirstHeader("WWW-Authenticate");
|
||||
} catch (IOException e) {
|
||||
logger.debug("finishPairingWithTv: {}", e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
|
||||
try (CloseableHttpClient client = ConnectionManagerUtil.createSharedHttpClient(target, deviceId, authKey)) {
|
||||
logger.debug("{} and device id: {} and auth_key: {}", grantPairingJson, deviceId, authKey);
|
||||
|
||||
String grantPairingCodePath = pairingBasePath + "grant";
|
||||
HttpPost httpPost = new HttpPost(grantPairingCodePath);
|
||||
httpPost.setHeader("Content-type", "application/json");
|
||||
httpPost.setEntity(new StringEntity(grantPairingJson));
|
||||
|
||||
DigestScheme digestAuth = new DigestScheme();
|
||||
digestAuth.processChallenge(challengeHeader);
|
||||
|
||||
AuthCache authCache = new BasicAuthCache();
|
||||
authCache.put(target, digestAuth);
|
||||
|
||||
HttpClientContext localContext = HttpClientContext.create();
|
||||
localContext.setAuthCache(authCache);
|
||||
|
||||
try (CloseableHttpResponse response = client.execute(target, httpPost, localContext)) {
|
||||
String jsonContent = EntityUtils.toString(response.getEntity());
|
||||
logger.debug("----------------------------------------");
|
||||
logger.debug("{}", response.getStatusLine());
|
||||
logger.debug("{}", jsonContent);
|
||||
if (response.getStatusLine().getStatusCode() != 200) {
|
||||
throw new IOException("Pairing grant failed");
|
||||
}
|
||||
if (jsonContent.contains("INVALID_PIN")) {
|
||||
throw new IOException("Invalid PIN");
|
||||
}
|
||||
}
|
||||
handler.setCreds(deviceId, authKey);
|
||||
} catch (MalformedChallengeException e) {
|
||||
logger.debug("finishPairingWithTv: {}", e.getMessage());
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String createDeviceId() {
|
||||
StringBuilder deviceIdBuilder = new StringBuilder();
|
||||
String chars = "abcdefghkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int index = (int) Math.floor(Math.random() * chars.length());
|
||||
deviceIdBuilder.append(chars.charAt(index));
|
||||
}
|
||||
return deviceIdBuilder.toString();
|
||||
}
|
||||
|
||||
private DeviceDTO createDeviceSpecification() {
|
||||
DeviceDTO deviceDTO = new DeviceDTO();
|
||||
deviceDTO.setAppName("openHAB");
|
||||
deviceDTO.setAppId("app.id");
|
||||
deviceDTO.setDeviceName("heliotrope");
|
||||
deviceDTO.setDeviceOs("Android");
|
||||
deviceDTO.setType("native");
|
||||
if (deviceId.isEmpty()) {
|
||||
deviceId = createDeviceId();
|
||||
}
|
||||
deviceDTO.setId(deviceId);
|
||||
return deviceDTO;
|
||||
}
|
||||
|
||||
private String toHexString(byte[] bytes) {
|
||||
try (Formatter formatter = new Formatter()) {
|
||||
for (byte b : bytes) {
|
||||
formatter.format("%02x", b);
|
||||
}
|
||||
|
||||
return formatter.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String calculateRFC2104HMAC(String data)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
|
||||
String hmacSHA1 = "HmacSHA1";
|
||||
// Key used for generated the HMAC signature
|
||||
String secretKey = "ZmVay1EQVFOaZhwQ4Kv81ypLAZNczV9sG4KkseXWn1NEk6cXmPKO/MCa9sryslvLCFMnNe4Z4CPXzToowvhHvA==";
|
||||
Key signingKey = new SecretKeySpec(Base64.getDecoder().decode(secretKey), hmacSHA1);
|
||||
Mac mac = Mac.getInstance(hmacSHA1);
|
||||
mac.init(signingKey);
|
||||
return Base64.getEncoder().encodeToString(toHexString(mac.doFinal(data.getBytes(StandardCharsets.UTF_8.name())))
|
||||
.getBytes(StandardCharsets.UTF_8.name()));
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link FinishPairingDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AuthDTO {
|
||||
|
||||
@JsonProperty("auth_signature")
|
||||
private String authSignature = "";
|
||||
|
||||
@JsonProperty("auth_timestamp")
|
||||
private String authTimestamp = "";
|
||||
|
||||
@JsonProperty("pin")
|
||||
private String pin = "";
|
||||
|
||||
@JsonProperty("auth_AppId")
|
||||
private String authAppId = "";
|
||||
|
||||
public void setAuthSignature(String authSignature) {
|
||||
this.authSignature = authSignature;
|
||||
}
|
||||
|
||||
public String getAuthSignature() {
|
||||
return authSignature;
|
||||
}
|
||||
|
||||
public void setAuthTimestamp(String authTimestamp) {
|
||||
this.authTimestamp = authTimestamp;
|
||||
}
|
||||
|
||||
public String getAuthTimestamp() {
|
||||
return authTimestamp;
|
||||
}
|
||||
|
||||
public void setPin(String pin) {
|
||||
this.pin = pin;
|
||||
}
|
||||
|
||||
public String getPin() {
|
||||
return pin;
|
||||
}
|
||||
|
||||
public void setAuthAppId(String authAppId) {
|
||||
this.authAppId = authAppId;
|
||||
}
|
||||
|
||||
public String getAuthAppId() {
|
||||
return authAppId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Auth{" + "auth_signature = '" + authSignature + '\'' + ",auth_timestamp = '" + authTimestamp + '\''
|
||||
+ ",pin = '" + pin + '\'' + ",auth_AppId = '" + authAppId + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link RequestCodeDTO} and {@link FinishPairingDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DeviceDTO {
|
||||
|
||||
@JsonProperty("app_name")
|
||||
private String appName = "";
|
||||
|
||||
@JsonProperty("device_name")
|
||||
private String deviceName = "";
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id = "";
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type = "";
|
||||
|
||||
@JsonProperty("app_id")
|
||||
private String appId = "";
|
||||
|
||||
@JsonProperty("device_os")
|
||||
private String deviceOs = "";
|
||||
|
||||
public void setAppName(String appName) {
|
||||
this.appName = appName;
|
||||
}
|
||||
|
||||
public String getAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setDeviceOs(String deviceOs) {
|
||||
this.deviceOs = deviceOs;
|
||||
}
|
||||
|
||||
public String getDeviceOs() {
|
||||
return deviceOs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Device{" + "app_name = '" + appName + '\'' + ",device_name = '" + deviceName + '\'' + ",id = '" + id
|
||||
+ '\'' + ",type = '" + type + '\'' + ",app_id = '" + appId + '\'' + ",device_os = '" + deviceOs + '\''
|
||||
+ "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link FinishPairingDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /pair/grant endpoint to finish pairing.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FinishPairingDTO {
|
||||
|
||||
@JsonProperty("auth")
|
||||
private AuthDTO auth;
|
||||
|
||||
@JsonProperty("device")
|
||||
private DeviceDTO device;
|
||||
|
||||
public FinishPairingDTO(DeviceDTO device, AuthDTO auth) {
|
||||
this.device = device;
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
public void setAuth(AuthDTO auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
public AuthDTO getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
public void setDevice(DeviceDTO device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public DeviceDTO getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FinishPairingDTO{" + "auth = '" + auth + '\'' + ",device = '" + device + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Response Data Transfer Object of {@link RequestCodeDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PairingDTO {
|
||||
|
||||
@JsonProperty("auth_key")
|
||||
private String authKey = "";
|
||||
|
||||
@JsonProperty("timestamp")
|
||||
private String timestamp = "";
|
||||
|
||||
@JsonProperty("timeout")
|
||||
private String timeout = "";
|
||||
|
||||
public String getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(String timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public void setAuthKey(String authKey) {
|
||||
this.authKey = authKey;
|
||||
}
|
||||
|
||||
public String getAuthKey() {
|
||||
return authKey;
|
||||
}
|
||||
|
||||
public void setTimestamp(String timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PairingCodeDTO{" + "auth_key = '" + authKey + '\'' + ",timestamp = '" + timestamp + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.pairing.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link RequestCodeDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /pair/request endpoint to request a pairing code.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class RequestCodeDTO {
|
||||
|
||||
@JsonProperty("scope")
|
||||
private List<String> scope;
|
||||
|
||||
@JsonProperty("device")
|
||||
private DeviceDTO device;
|
||||
|
||||
public RequestCodeDTO(List<String> scope, DeviceDTO device) {
|
||||
this.scope = scope;
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public void setScope(List<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public List<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void setDevice(DeviceDTO device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public DeviceDTO getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RequestPinDTO{" + "scope = '" + scope + '\'' + ",device = '" + device + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,316 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.WakeOnLanUtil;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.DataDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.TvSettingsUpdateDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ValueDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ValuesDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightColorDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightColorDeltaDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightColorSettingsDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightConfigDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightLoungeDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightModeDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightPowerDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight.AmbilightTopologyDTO;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
/**
|
||||
* Service for handling commands regarding Ambilight settings of the TV
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AmbilightService implements PhilipsTVService {
|
||||
|
||||
private static final List<String> AMBILIGHT_COLOR_CHANNELS = Stream
|
||||
.of(CHANNEL_AMBILIGHT_COLOR, CHANNEL_AMBILIGHT_LEFT_COLOR, CHANNEL_AMBILIGHT_RIGHT_COLOR,
|
||||
CHANNEL_AMBILIGHT_TOP_COLOR, CHANNEL_AMBILIGHT_BOTTOM_COLOR)
|
||||
.collect(Collectors.toList());
|
||||
private static final int AMBILIGHT_HUE_NODE_ID = 2131230774;
|
||||
private static final int AMBILIGHT_BRIGHTNESS_NODE_ID = 2131230769;
|
||||
private static final String AMBILIGHT_MODE_MANUAL = "manual";
|
||||
private static final String AMBILIGHT_STYLE_FOLLOW_VIDEO = "FOLLOW_VIDEO";
|
||||
private static final String AMBILIGHT_STYLE_FOLLOW_COLOR = "FOLLOW_COLOR";
|
||||
private static final String AMBILIGHT_ALGORITHM_MANUAL_HUE = "MANUAL HUE";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final boolean isWakeOnLanEnabled;
|
||||
|
||||
private @Nullable AmbilightTopologyDTO ambilightTopology;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public AmbilightService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
this.isWakeOnLanEnabled = handler.getMacAddress().isEmpty() ? false : true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
try {
|
||||
if (CHANNEL_AMBILIGHT_POWER.equals(channel) && (command instanceof OnOffType)) {
|
||||
setAmbilightPowerState(command);
|
||||
} else if (CHANNEL_AMBILIGHT_POWER.equals(channel) && (command instanceof RefreshType)) {
|
||||
AmbilightPowerDTO ambilightPowerDTO = getAmbilightPowerState();
|
||||
handler.postUpdateChannel(CHANNEL_AMBILIGHT_POWER,
|
||||
ambilightPowerDTO.isPoweredOn() ? OnOffType.ON : OnOffType.OFF);
|
||||
} else if (CHANNEL_AMBILIGHT_HUE_POWER.equals(channel) && (command instanceof OnOffType)) {
|
||||
setAmbilightHuePowerState(command);
|
||||
} else if (CHANNEL_AMBILIGHT_LOUNGE_POWER.equals(channel) && (command instanceof OnOffType)) {
|
||||
setAmbilightLoungePowerState(command);
|
||||
} else if (CHANNEL_AMBILIGHT_STYLE.equals(channel) && (command instanceof StringType)) {
|
||||
setAmbilightStyle(command.toString());
|
||||
} else if (CHANNEL_AMBILIGHT_STYLE.equals(channel) && (command instanceof RefreshType)) {
|
||||
AmbilightConfigDTO config = getAmbilightConfig();
|
||||
String styleWithAlgorithm = String.format("%s %s", config.getStyleName(), config.getMenuSetting());
|
||||
handler.postUpdateChannel(CHANNEL_AMBILIGHT_STYLE, new StringType(styleWithAlgorithm));
|
||||
} else if (CHANNEL_AMBILIGHT_COLOR.equals(channel) && (command instanceof HSBType)) {
|
||||
setAllAmbilightColors((HSBType) command);
|
||||
} else if ((CHANNEL_AMBILIGHT_LEFT_COLOR.equals(channel) || CHANNEL_AMBILIGHT_RIGHT_COLOR.equals(channel)
|
||||
|| CHANNEL_AMBILIGHT_TOP_COLOR.equals(channel) || CHANNEL_AMBILIGHT_BOTTOM_COLOR.equals(channel))
|
||||
&& (command instanceof HSBType)) {
|
||||
setAmbilightPixel((HSBType) command, channel);
|
||||
} else if (AMBILIGHT_COLOR_CHANNELS.contains(channel) && (command instanceof PercentType)) {
|
||||
setAmbilightBrightness(((PercentType) command).intValue());
|
||||
} else {
|
||||
if (!(command instanceof RefreshType)) {
|
||||
logger.warn("Unknown command: {} for Channel {}", command, channel);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Error during handling the Ambilight command {} for Channel {}: {}", command, channel,
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AmbilightPowerDTO getAmbilightPowerState() throws IOException {
|
||||
return OBJECT_MAPPER.readValue(connectionManager.doHttpsGet(AMBILIGHT_POWERSTATE_PATH),
|
||||
AmbilightPowerDTO.class);
|
||||
}
|
||||
|
||||
private void setAmbilightPowerState(Command command) throws IOException {
|
||||
if (command.equals(OnOffType.OFF)) {
|
||||
AmbilightPowerDTO ambilightPower = new AmbilightPowerDTO();
|
||||
ambilightPower.setPower(POWER_OFF);
|
||||
String powerStateJson = OBJECT_MAPPER.writeValueAsString(ambilightPower);
|
||||
logger.debug("Post Ambilight power state json: {}", powerStateJson);
|
||||
connectionManager.doHttpsPost(AMBILIGHT_POWERSTATE_PATH, powerStateJson);
|
||||
} else { // power on via setting FOLLOW_VIDEO instead through POWERSTATE_PATH which sets FOLLOW_COLOR
|
||||
setAmbilightStyle(String.format("%s %s", AMBILIGHT_STYLE_FOLLOW_VIDEO, "STANDARD"));
|
||||
}
|
||||
}
|
||||
|
||||
private void setAmbilightHuePowerState(Command command) throws IOException {
|
||||
DataDTO data = new DataDTO((command.equals(OnOffType.ON) ? "true" : "false"));
|
||||
|
||||
ValueDTO value = new ValueDTO(data);
|
||||
value.setNodeid(AMBILIGHT_HUE_NODE_ID);
|
||||
value.setAvailable("true");
|
||||
value.setControllable("true");
|
||||
|
||||
ValuesDTO values = new ValuesDTO(value);
|
||||
TvSettingsUpdateDTO ambilightHuePower = new TvSettingsUpdateDTO(Collections.singletonList(values));
|
||||
|
||||
String ambilightHuePowerJson = OBJECT_MAPPER.writeValueAsString(ambilightHuePower);
|
||||
logger.debug("Post Ambilight hue power state json: {}", ambilightHuePowerJson);
|
||||
connectionManager.doHttpsPost(UPDATE_SETTINGS_PATH, ambilightHuePowerJson);
|
||||
}
|
||||
|
||||
private void setAmbilightLoungePowerState(Command command) throws IOException, InterruptedException {
|
||||
AmbilightColorDTO ambilightColorDTO = new AmbilightColorDTO();
|
||||
if (command.equals(OnOffType.ON)) {
|
||||
if (isWakeOnLanEnabled && !WakeOnLanUtil.isReachable(handler.config.ipAddress)) {
|
||||
WakeOnLanUtil.wakeOnLan(handler.config.ipAddress, handler.getMacAddress());
|
||||
}
|
||||
ambilightColorDTO.setHue(0);
|
||||
} else {
|
||||
ambilightColorDTO.setHue(255);
|
||||
}
|
||||
AmbilightLoungeDTO ambilightLoungeDTO = new AmbilightLoungeDTO(ambilightColorDTO);
|
||||
|
||||
String setAmbilightLoungeJson = OBJECT_MAPPER.writeValueAsString(ambilightLoungeDTO);
|
||||
logger.debug("Setting ambilight lounge power state json: {}", setAmbilightLoungeJson);
|
||||
connectionManager.doHttpsPost(AMBILIGHT_LOUNGE_PATH, setAmbilightLoungeJson);
|
||||
}
|
||||
|
||||
private void setAmbilightStyle(String styleToSet) throws IOException {
|
||||
String[] styleWithAlgorithm = styleToSet.split(" ");
|
||||
if (styleWithAlgorithm.length != 2) {
|
||||
throw new IllegalStateException("Style and/or algorithm is missing.");
|
||||
}
|
||||
String style = styleWithAlgorithm[0];
|
||||
String algorithm = styleWithAlgorithm[1];
|
||||
AmbilightConfigDTO ambilightConfig = new AmbilightConfigDTO(
|
||||
new AmbilightColorSettingsDTO(new AmbilightColorDTO(), new AmbilightColorDeltaDTO()));
|
||||
ambilightConfig.setStyleName(style);
|
||||
ambilightConfig.setMenuSetting(algorithm);
|
||||
if (style.equals(AMBILIGHT_STYLE_FOLLOW_COLOR) && algorithm.equals(AMBILIGHT_ALGORITHM_MANUAL_HUE)) {
|
||||
ambilightConfig.setAlgorithm(algorithm);
|
||||
ambilightConfig.setIsExpert(true);
|
||||
AmbilightColorDeltaDTO ambilightColorDeltaDTO = new AmbilightColorDeltaDTO();
|
||||
ambilightColorDeltaDTO.setHue(0);
|
||||
ambilightColorDeltaDTO.setBrightness(0);
|
||||
ambilightColorDeltaDTO.setSaturation(0);
|
||||
AmbilightColorSettingsDTO ambilightColorSettingsDTO = new AmbilightColorSettingsDTO(new AmbilightColorDTO(),
|
||||
ambilightColorDeltaDTO);
|
||||
ambilightColorSettingsDTO.setSpeed(255);
|
||||
ambilightConfig.setColorSettings(ambilightColorSettingsDTO);
|
||||
}
|
||||
String ambilightConfigJson = OBJECT_MAPPER.writeValueAsString(ambilightConfig);
|
||||
logger.debug("Post config for Ambilight style json: {}", ambilightConfigJson);
|
||||
connectionManager.doHttpsPost(AMBILIGHT_CONFIG_PATH, ambilightConfigJson);
|
||||
}
|
||||
|
||||
private AmbilightConfigDTO getAmbilightConfig() throws IOException {
|
||||
return OBJECT_MAPPER.readValue(connectionManager.doHttpsGet(AMBILIGHT_CONFIG_PATH), AmbilightConfigDTO.class);
|
||||
}
|
||||
|
||||
private void setAmbilightMode(String mode) throws IOException {
|
||||
AmbilightModeDTO ambilightMode = new AmbilightModeDTO();
|
||||
ambilightMode.setCurrent(mode);
|
||||
String ambilightModeJson = OBJECT_MAPPER.writeValueAsString(ambilightMode);
|
||||
logger.debug("Post ambilight mode json: {}", ambilightModeJson);
|
||||
connectionManager.doHttpsPost(AMBILIGHT_MODE_PATH, ambilightModeJson);
|
||||
}
|
||||
|
||||
// private AmbilightModeDTO getAmbilightMode() throws IOException {
|
||||
// return OBJECT_MAPPER.readValue(connectionManager.doHttpsGet(AMBILIGHT_MODE_PATH), AmbilightModeDTO.class);
|
||||
// }
|
||||
|
||||
private void setAmbilightBrightness(int brightnessToSet) throws IOException {
|
||||
String ambilightBrightnessJson = ServiceUtil.createTvSettingsUpdateJson(AMBILIGHT_BRIGHTNESS_NODE_ID,
|
||||
brightnessToSet / 10);
|
||||
logger.debug("Post Ambilight brightness json: {}", ambilightBrightnessJson);
|
||||
connectionManager.doHttpsPost(UPDATE_SETTINGS_PATH, ambilightBrightnessJson);
|
||||
}
|
||||
|
||||
private void setAmbilightPixel(HSBType hsb, String channel) throws IOException {
|
||||
if (ambilightTopology == null) {
|
||||
ambilightTopology = getAmbilightTopology();
|
||||
}
|
||||
setAmbilightMode(AMBILIGHT_MODE_MANUAL); // activates the usage of cached values
|
||||
String sideToSet = determineAmbilightSide(channel);
|
||||
int pixelSize = ambilightTopology.getPixelSizeForGivenSide(sideToSet);
|
||||
|
||||
ObjectNode rootNode = OBJECT_MAPPER.createObjectNode();
|
||||
|
||||
ObjectNode pixel = OBJECT_MAPPER.createObjectNode();
|
||||
pixel.put("r", hsb.getRed().intValue());
|
||||
pixel.put("g", hsb.getGreen().intValue());
|
||||
pixel.put("b", hsb.getBlue().intValue());
|
||||
|
||||
ObjectNode sidePixels = OBJECT_MAPPER.createObjectNode();
|
||||
// pixel declaration in json start with 0
|
||||
IntStream.range(0, pixelSize).forEach(i -> sidePixels.set(Integer.toString(i), pixel));
|
||||
|
||||
IntStream.rangeClosed(1, ambilightTopology.getLayers()).forEach(i -> {
|
||||
ObjectNode layerX = OBJECT_MAPPER.createObjectNode();
|
||||
layerX.set(sideToSet, sidePixels);
|
||||
|
||||
rootNode.set("layer" + i, layerX);
|
||||
});
|
||||
|
||||
String ambilightPixelJson = OBJECT_MAPPER.writeValueAsString(rootNode);
|
||||
logger.debug("Sending {} Ambilight pixel json: {}", sideToSet, ambilightPixelJson);
|
||||
connectionManager.doHttpsPost(AMBILIGHT_CACHED_PATH, ambilightPixelJson);
|
||||
}
|
||||
|
||||
private AmbilightTopologyDTO getAmbilightTopology() throws IOException {
|
||||
return OBJECT_MAPPER.readValue(connectionManager.doHttpsGet(AMBILIGHT_TOPOLOGY_PATH),
|
||||
AmbilightTopologyDTO.class);
|
||||
}
|
||||
|
||||
private String determineAmbilightSide(String channel) {
|
||||
String sideToSet;
|
||||
switch (channel) {
|
||||
case CHANNEL_AMBILIGHT_LEFT_COLOR:
|
||||
sideToSet = "left";
|
||||
break;
|
||||
case CHANNEL_AMBILIGHT_RIGHT_COLOR:
|
||||
sideToSet = "right";
|
||||
break;
|
||||
case CHANNEL_AMBILIGHT_TOP_COLOR:
|
||||
sideToSet = "top";
|
||||
break;
|
||||
case CHANNEL_AMBILIGHT_BOTTOM_COLOR:
|
||||
sideToSet = "bottom";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected channel for ambilight pixel set: " + channel);
|
||||
}
|
||||
return sideToSet;
|
||||
}
|
||||
|
||||
private void setAllAmbilightColors(HSBType hsb) throws IOException {
|
||||
AmbilightColorDTO ambilightColor = new AmbilightColorDTO(hsb);
|
||||
AmbilightColorDeltaDTO ambilightColorDelta = new AmbilightColorDeltaDTO();
|
||||
ambilightColorDelta.setHue(0);
|
||||
ambilightColorDelta.setSaturation(0);
|
||||
ambilightColorDelta.setBrightness(0);
|
||||
|
||||
AmbilightColorSettingsDTO ambilightColorSettings = new AmbilightColorSettingsDTO(ambilightColor,
|
||||
ambilightColorDelta);
|
||||
ambilightColorSettings.setSpeed(255);
|
||||
|
||||
AmbilightConfigDTO ambilightConfig = new AmbilightConfigDTO(ambilightColorSettings);
|
||||
ambilightConfig.setIsExpert(true);
|
||||
ambilightConfig.setStyleName("FOLLOW_COLOR");
|
||||
ambilightConfig.setAlgorithm("MANUAL_HUE");
|
||||
|
||||
String setAmbilightColorsJson = OBJECT_MAPPER.writeValueAsString(ambilightConfig);
|
||||
logger.debug("Setting ambilight colors json: {}", setAmbilightColorsJson);
|
||||
connectionManager.doHttpsPost(AMBILIGHT_CONFIG_PATH, setAmbilightColorsJson);
|
||||
}
|
||||
}
|
@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.http.ParseException;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.ApplicationsDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.AvailableAppsDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.ComponentDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.CurrentAppDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.ExtrasDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.IntentDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.LaunchAppDTO;
|
||||
import org.openhab.core.library.types.RawType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AppService} is responsible for handling key code commands, which emulate a button
|
||||
* press on a remote control.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AppService implements PhilipsTVService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
// Label , Entry<PackageName,ClassName> of App
|
||||
private @Nullable Map<String, AbstractMap.SimpleEntry<String, String>> availableApps;
|
||||
|
||||
private String currentPackageName = "";
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public AppService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (isAvailableAppListEmpty()) {
|
||||
getAvailableAppListFromTv();
|
||||
handler.updateChannelStateDescription(CHANNEL_APPNAME, availableApps.keySet().stream()
|
||||
.collect(Collectors.toMap(Function.identity(), Function.identity())));
|
||||
}
|
||||
}
|
||||
if (command instanceof RefreshType) {
|
||||
// Get current App name
|
||||
String packageName = getCurrentApp();
|
||||
if (currentPackageName.equals(packageName)) {
|
||||
return;
|
||||
} else {
|
||||
currentPackageName = packageName;
|
||||
}
|
||||
Optional<Map.Entry<String, AbstractMap.SimpleEntry<String, String>>> app = availableApps.entrySet()
|
||||
.stream().filter(e -> e.getValue().getKey().equalsIgnoreCase(packageName)).findFirst();
|
||||
if (app.isPresent()) {
|
||||
handler.postUpdateChannel(CHANNEL_APP, new StringType(packageName));
|
||||
Map.Entry<String, AbstractMap.SimpleEntry<String, String>> appEntry = app.get();
|
||||
handler.postUpdateChannel(CHANNEL_APPNAME, new StringType(appEntry.getKey()));
|
||||
// Get icon for current App
|
||||
RawType image = getIconForApp(appEntry.getValue().getKey(), appEntry.getValue().getValue());
|
||||
handler.postUpdateChannel(CHANNEL_APP_ICON, (image != null) ? image : UnDefType.UNDEF);
|
||||
} else { // NA
|
||||
handler.postUpdateChannel(CHANNEL_APP, new StringType(packageName));
|
||||
handler.postUpdateChannel(CHANNEL_APPNAME, new StringType(packageName));
|
||||
handler.postUpdateChannel(CHANNEL_APP_ICON, UnDefType.UNDEF);
|
||||
}
|
||||
} else if (command instanceof StringType) {
|
||||
String appName = "";
|
||||
if (CHANNEL_APPNAME.equals(channel) && availableApps.containsKey(command.toString())) {
|
||||
launchApp(command.toString());
|
||||
} else if (CHANNEL_APP.equals(channel)) {
|
||||
launchDNApp(command.toString());
|
||||
} else {
|
||||
logger.warn("The given App with Name: {} {} couldn't be found in the local App List from the tv.",
|
||||
command, appName);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Unknown command: {} for Channel {}", command, channel);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
logger.debug("Could not execute command for apps, the TV is offline.");
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Error occurred during handling of command for apps: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAvailableAppListEmpty() {
|
||||
return (availableApps == null) || availableApps.isEmpty();
|
||||
}
|
||||
|
||||
private void launchDNApp(String appName) throws IOException {
|
||||
for (Map.Entry<String, AbstractMap.SimpleEntry<String, String>> entry : availableApps.entrySet()) {
|
||||
Map.Entry<String, String> app = entry.getValue();
|
||||
if (app.getKey().equals(appName)) {
|
||||
logger.debug("Found app by dn: {} {} {}", entry.getKey(), app.getKey(), app.getValue());
|
||||
launchApp(entry.getKey());
|
||||
return;
|
||||
}
|
||||
}
|
||||
logger.warn("The given App with DN: {} couldn't be found in the local App List from the tv.", appName);
|
||||
}
|
||||
|
||||
private void launchApp(String appName) throws IOException {
|
||||
Map.Entry<String, String> app = availableApps.get(appName);
|
||||
|
||||
ComponentDTO componentDTO = new ComponentDTO();
|
||||
componentDTO.setPackageName(app.getKey());
|
||||
componentDTO.setClassName(app.getValue());
|
||||
|
||||
IntentDTO intentDTO = new IntentDTO(componentDTO, new ExtrasDTO());
|
||||
intentDTO.setAction("empty");
|
||||
LaunchAppDTO launchAppDTO = new LaunchAppDTO(intentDTO);
|
||||
String appLaunchJson = OBJECT_MAPPER.writeValueAsString(launchAppDTO);
|
||||
|
||||
logger.debug("App Launch json: {}", appLaunchJson);
|
||||
connectionManager.doHttpsPost(LAUNCH_APP_PATH, appLaunchJson);
|
||||
}
|
||||
|
||||
private String getCurrentApp() throws IOException, ParseException {
|
||||
CurrentAppDTO currentAppDTO = OBJECT_MAPPER.readValue(connectionManager.doHttpsGet(GET_CURRENT_APP_PATH),
|
||||
CurrentAppDTO.class);
|
||||
return currentAppDTO.getComponent().getPackageName();
|
||||
}
|
||||
|
||||
private @Nullable RawType getIconForApp(String packageName, String className) throws IOException {
|
||||
String pathForIcon = String.format("%s%s-%s%sicon", SLASH, className, packageName, SLASH);
|
||||
byte[] icon = connectionManager
|
||||
.doHttpsGetForImage(String.format("%s%s", GET_AVAILABLE_APP_LIST_PATH, pathForIcon));
|
||||
if ((icon != null) && (icon.length > 0)) {
|
||||
return new RawType(icon, "image/png");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void getAvailableAppListFromTv() throws IOException {
|
||||
AvailableAppsDTO availableAppsDTO = OBJECT_MAPPER
|
||||
.readValue(connectionManager.doHttpsGet(GET_AVAILABLE_APP_LIST_PATH), AvailableAppsDTO.class);
|
||||
|
||||
ConcurrentMap<String, AbstractMap.SimpleEntry<String, String>> appsMap = availableAppsDTO.getApplications()
|
||||
.stream()
|
||||
.collect(Collectors.toConcurrentMap(ApplicationsDTO::getLabel,
|
||||
a -> new AbstractMap.SimpleEntry<>(a.getIntent().getComponent().getPackageName(),
|
||||
a.getIntent().getComponent().getClassName()),
|
||||
(a1, a2) -> a1));
|
||||
|
||||
logger.debug("appsMap - Apps added: {}", appsMap.size());
|
||||
if (logger.isTraceEnabled()) {
|
||||
appsMap.keySet().forEach(app -> logger.trace("appsMap - App found: {}", app));
|
||||
}
|
||||
|
||||
this.availableApps = appsMap;
|
||||
}
|
||||
|
||||
public void clearAvailableAppList() {
|
||||
if (availableApps != null) {
|
||||
availableApps.clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
/**
|
||||
* The {@link KeyPress} presents all available key codes of Philips TV.
|
||||
*
|
||||
* @see <a
|
||||
* href=
|
||||
* "http://jointspace.sourceforge.net/projectdata/documentation/jasonApi/1/doc/API-Method-input-key-POST.html">http://jointspace.sourceforge.net/projectdata/documentation/jasonApi/1/doc/API-Method-input-key-POST.html
|
||||
* </a>
|
||||
*
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum KeyPress {
|
||||
|
||||
KEY_STANDBY("Standby"),
|
||||
KEY_BACK("Back"),
|
||||
KEY_FIND("Find"),
|
||||
KEY_RED_COLOR("RedColour"),
|
||||
KEY_GREEN_COLOR("GreenColour"),
|
||||
KEY_YELLOW_COLOR("YellowColour"),
|
||||
KEY_BLUE_COLOR("BlueColour"),
|
||||
KEY_HOME("Home"),
|
||||
KEY_VOLUME_UP("VolumeUp"),
|
||||
KEY_VOLUME_DOWN("VolumeDown"),
|
||||
KEY_MUTE("Mute"),
|
||||
KEY_OPTIONS("Options"),
|
||||
KEY_DOT("Dot"),
|
||||
KEY_0("Digit0"),
|
||||
KEY_1("Digit1"),
|
||||
KEY_2("Digit2"),
|
||||
KEY_3("Digit3"),
|
||||
KEY_4("Digit4"),
|
||||
KEY_5("Digit5"),
|
||||
KEY_6("Digit6"),
|
||||
KEY_7("Digit7"),
|
||||
KEY_8("Digit8"),
|
||||
KEY_9("Digit9"),
|
||||
KEY_INFO("Info"),
|
||||
KEY_CURSOR_UP("CursorUp"),
|
||||
KEY_CURSOR_DOWN("CursorDown"),
|
||||
KEY_CURSOR_LEFT("CursorLeft"),
|
||||
KEY_CURSOR_RIGHT("CursorRight"),
|
||||
KEY_CONFIRM("Confirm"),
|
||||
KEY_NEXT("Next"),
|
||||
KEY_PREVIOUS("Previous"),
|
||||
KEY_ADJUST("Adjust"),
|
||||
KEY_WATCH_TV("WatchTV"),
|
||||
KEY_VIEW_MODE("Viewmode"),
|
||||
KEY_TELETEXT("Teletext"),
|
||||
KEY_SUBTITLE("Subtitle"),
|
||||
KEY_CHANNEL_STEP_UP("ChannelStepUp"),
|
||||
KEY_CHANNEL_STEP_DOWN("ChannelStepDown"),
|
||||
KEY_SOURCE("Source"),
|
||||
KEY_AMBILIGHT_ON_OFF("AmbilightOnOff"),
|
||||
KEY_PLAY("Play"),
|
||||
KEY_PAUSE("Pause"),
|
||||
KEY_FAST_FORWARD("FastForward"),
|
||||
KEY_STOP("Stop"),
|
||||
KEY_REWIND("Rewind"),
|
||||
KEY_RECORD("Record"),
|
||||
KEY_ONLINE("Online");
|
||||
|
||||
private final String value;
|
||||
|
||||
KeyPress(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static KeyPress getKeyPressForValue(String value) throws IllegalArgumentException {
|
||||
return Arrays.stream(values()).filter(v -> v.value.equalsIgnoreCase(value)).findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Key code could not be recognized: " + value));
|
||||
}
|
||||
|
||||
@JsonValue
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.keypress.KeyPressDTO;
|
||||
import org.openhab.core.library.types.NextPreviousType;
|
||||
import org.openhab.core.library.types.PlayPauseType;
|
||||
import org.openhab.core.library.types.RewindFastforwardType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link KeyPressService} is responsible for handling key code commands, which emulate a button
|
||||
* press on a remote control.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class KeyPressService implements PhilipsTVService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public KeyPressService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
KeyPress keyPress = null;
|
||||
if (isSupportedCommand(command)) {
|
||||
// Three approaches to resolve the KEY_CODE
|
||||
try {
|
||||
keyPress = KeyPress.valueOf(command.toString().toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
try {
|
||||
keyPress = KeyPress.valueOf("KEY_" + command.toString().toUpperCase());
|
||||
} catch (IllegalArgumentException e2) {
|
||||
try {
|
||||
keyPress = KeyPress.getKeyPressForValue(command.toString());
|
||||
} catch (IllegalArgumentException e3) {
|
||||
logger.trace("KeyPress threw IllegalArgumentException", e3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keyPress != null) {
|
||||
try {
|
||||
sendKeyPress(keyPress);
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
logger.debug("Could not execute command for key code, the TV is offline.");
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Unknown error occurred while sending keyPress code {}: {}", keyPress,
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warn("Command '{}' not a supported keyPress code.", command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSupportedCommand(Command command) {
|
||||
return (command instanceof StringType) || (command instanceof NextPreviousType)
|
||||
|| (command instanceof PlayPauseType) || (command instanceof RewindFastforwardType);
|
||||
}
|
||||
|
||||
private void sendKeyPress(KeyPress key) throws IOException {
|
||||
KeyPressDTO keyPressDTO = new KeyPressDTO(key);
|
||||
String keyPressJson = OBJECT_MAPPER.writeValueAsString(keyPressDTO);
|
||||
logger.debug("KeyPress Json sent: {}", keyPressJson);
|
||||
connectionManager.doHttpsPost(KEY_CODE_PATH, keyPressJson);
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.ParseException;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.WakeOnLanUtil;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.power.PowerStateDTO;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link PowerService} is responsible for handling power states commands, which are sent to the
|
||||
* power channel.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PowerService implements PhilipsTVService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
private final boolean isWakeOnLanEnabled;
|
||||
|
||||
public PowerService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
this.isWakeOnLanEnabled = handler.getMacAddress().isEmpty() ? false : true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
try {
|
||||
if (command instanceof RefreshType) {
|
||||
PowerStateDTO powerStateDTO = getPowerState();
|
||||
if (powerStateDTO.isPoweredOn()) {
|
||||
handler.postUpdateThing(ThingStatus.ONLINE, ThingStatusDetail.NONE, "online.online");
|
||||
} else if (powerStateDTO.isStandby()) {
|
||||
handler.postUpdateThing(ThingStatus.ONLINE, ThingStatusDetail.NONE, "online.standby");
|
||||
if (powerStateDTO.isStandbyKeep()) {
|
||||
handler.checkPendingPowerOn();
|
||||
}
|
||||
} else {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, EMPTY);
|
||||
}
|
||||
} else if (command instanceof OnOffType) {
|
||||
setPowerState((OnOffType) command);
|
||||
if (command == OnOffType.ON) {
|
||||
handler.postUpdateThing(ThingStatus.ONLINE, ThingStatusDetail.NONE, "online.online");
|
||||
} else {
|
||||
handler.postUpdateThing(ThingStatus.ONLINE, ThingStatusDetail.NONE, "online.standby");
|
||||
}
|
||||
} else {
|
||||
logger.warn("Unknown command: {} for Channel {}", command, channel);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Unexpected Error handling the PowerState command {} for Channel {}: {}", command, channel,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PowerStateDTO getPowerState() throws IOException, ParseException {
|
||||
return OBJECT_MAPPER.readValue(connectionManager.doHttpsGet(TV_POWERSTATE_PATH), PowerStateDTO.class);
|
||||
}
|
||||
|
||||
private void setPowerState(OnOffType onOffType) throws IOException, InterruptedException {
|
||||
PowerStateDTO powerStateDTO = new PowerStateDTO();
|
||||
if (onOffType == OnOffType.ON) {
|
||||
if (isWakeOnLanEnabled && !WakeOnLanUtil.isReachable(handler.config.ipAddress)) {
|
||||
WakeOnLanUtil.wakeOnLan(handler.config.ipAddress, handler.getMacAddress());
|
||||
}
|
||||
powerStateDTO.setPowerState(POWER_ON);
|
||||
} else {
|
||||
powerStateDTO.setPowerState(STANDBY);
|
||||
}
|
||||
|
||||
String powerStateJson = OBJECT_MAPPER.writeValueAsString(powerStateDTO);
|
||||
logger.debug("PowerState Json sent: {}", powerStateJson);
|
||||
connectionManager.doHttpsPost(TV_POWERSTATE_PATH, powerStateJson);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.ComponentDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.ExtrasDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.IntentDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application.LaunchAppDTO;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service for toggling the Google Assistant on the Philips TV
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SearchContentService implements PhilipsTVService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public SearchContentService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
if (command instanceof StringType) {
|
||||
try {
|
||||
searchForContentOnTv(command.toString());
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
logger.warn("Could not search content on Philips TV: TV is offline.");
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Error during the launch of search content on Philips TV: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} else if (!(command instanceof RefreshType)) {
|
||||
logger.warn("Unknown command: {} for Channel {}", command, channel);
|
||||
}
|
||||
}
|
||||
|
||||
private void searchForContentOnTv(String searchContent) throws IOException {
|
||||
ExtrasDTO extrasDTO = new ExtrasDTO();
|
||||
extrasDTO.setQuery(searchContent);
|
||||
|
||||
IntentDTO intentDTO = new IntentDTO(new ComponentDTO(), extrasDTO);
|
||||
intentDTO.setAction("android.search.action.GLOBAL_SEARCH");
|
||||
LaunchAppDTO launchAppDTO = new LaunchAppDTO(intentDTO);
|
||||
|
||||
String searchContentLaunch = OBJECT_MAPPER.writeValueAsString(launchAppDTO);
|
||||
|
||||
logger.debug("Search Content Launch json: {}", searchContentLaunch);
|
||||
connectionManager.doHttpsPost(LAUNCH_APP_PATH, searchContentLaunch);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.DataDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.NodesDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.TvSettingsCurrentDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.TvSettingsUpdateDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ValueDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ValuesDTO;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
/**
|
||||
* Util class for common used methods from philips tv services
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
final class ServiceUtil {
|
||||
|
||||
private ServiceUtil() {
|
||||
}
|
||||
|
||||
static String createTvSettingsRetrievalJson(int nodeId) throws JsonProcessingException {
|
||||
NodesDTO nodes = new NodesDTO();
|
||||
nodes.setNodeid(nodeId);
|
||||
TvSettingsCurrentDTO tvSettingCurrent = new TvSettingsCurrentDTO(Collections.singletonList(nodes));
|
||||
return OBJECT_MAPPER.writeValueAsString(tvSettingCurrent);
|
||||
}
|
||||
|
||||
static String createTvSettingsUpdateJson(int nodeId, int valueToSet) throws JsonProcessingException {
|
||||
DataDTO data = new DataDTO(valueToSet);
|
||||
ValueDTO value = new ValueDTO(data);
|
||||
value.setNodeid(nodeId);
|
||||
ValuesDTO values = new ValuesDTO(value);
|
||||
values.setValue(value);
|
||||
TvSettingsUpdateDTO tvSetting = new TvSettingsUpdateDTO(Collections.singletonList(values));
|
||||
return OBJECT_MAPPER.writeValueAsString(tvSetting);
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel.AvailableTvChannelsDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel.ChannelDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel.ChannelListDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel.TvChannelDTO;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service for handling commands regarding setting or retrieving the TV channel
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TvChannelService implements PhilipsTVService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
// Name , ccid of TV Channel
|
||||
private @Nullable Map<String, String> availableTvChannels;
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public TvChannelService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (isTvChannelListEmpty()) {
|
||||
availableTvChannels = getAvailableTvChannelListFromTv();
|
||||
handler.updateChannelStateDescription(CHANNEL_TV_CHANNEL, availableTvChannels.keySet().stream()
|
||||
.collect(Collectors.toMap(Function.identity(), Function.identity())));
|
||||
}
|
||||
}
|
||||
if (command instanceof RefreshType) {
|
||||
// Get current tv channel name
|
||||
String tvChannelName = getCurrentTvChannel();
|
||||
handler.postUpdateChannel(CHANNEL_TV_CHANNEL, new StringType(tvChannelName));
|
||||
} else if (command instanceof StringType) {
|
||||
if (availableTvChannels.containsKey(command.toString())) {
|
||||
switchTvChannel(command);
|
||||
} else {
|
||||
logger.warn(
|
||||
"The given TV Channel with Name: {} couldn't be found in the local Channel List from the TV.",
|
||||
command);
|
||||
}
|
||||
} else {
|
||||
logger.warn("Unknown command: {} for Channel {}", command, channel);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
logger.warn("Could not execute command for TV Channels, the TV is offline.");
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Error occurred during handling of command for TV Channels: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTvChannelListEmpty() {
|
||||
return (availableTvChannels == null) || availableTvChannels.isEmpty();
|
||||
}
|
||||
|
||||
private Map<String, String> getAvailableTvChannelListFromTv() throws IOException {
|
||||
AvailableTvChannelsDTO availableTvChannelsDTO = OBJECT_MAPPER.readValue(
|
||||
connectionManager.doHttpsGet(GET_AVAILABLE_TV_CHANNEL_LIST_PATH), AvailableTvChannelsDTO.class);
|
||||
|
||||
ConcurrentMap<String, String> tvChannelsMap = availableTvChannelsDTO.getChannel().stream()
|
||||
.collect(Collectors.toConcurrentMap(ChannelDTO::getName, ChannelDTO::getCcid, (c1, c2) -> c1));
|
||||
|
||||
logger.debug("TV Channels added: {}", tvChannelsMap.size());
|
||||
if (logger.isTraceEnabled()) {
|
||||
tvChannelsMap.keySet().forEach(app -> logger.trace("TV Channel found: {}", app));
|
||||
}
|
||||
return tvChannelsMap;
|
||||
}
|
||||
|
||||
private String getCurrentTvChannel() throws IOException {
|
||||
TvChannelDTO tvChannelDTO = OBJECT_MAPPER.readValue(connectionManager.doHttpsGet(TV_CHANNEL_PATH),
|
||||
TvChannelDTO.class);
|
||||
return Optional.ofNullable(tvChannelDTO.getChannel()).map(ChannelDTO::getName).orElse("NA");
|
||||
}
|
||||
|
||||
private void switchTvChannel(Command command) throws IOException {
|
||||
ChannelDTO channelDTO = new ChannelDTO();
|
||||
channelDTO.setCcid(availableTvChannels.get(command.toString()));
|
||||
|
||||
ChannelListDTO channelListDTO = new ChannelListDTO();
|
||||
channelListDTO.setId("allter");
|
||||
channelListDTO.setVersion("30");
|
||||
|
||||
TvChannelDTO tvChannelDTO = new TvChannelDTO(channelDTO, channelListDTO);
|
||||
String switchTvChannelJson = OBJECT_MAPPER.writeValueAsString(tvChannelDTO);
|
||||
logger.debug("Switch TV Channel json: {}", switchTvChannelJson);
|
||||
connectionManager.doHttpsPost(TV_CHANNEL_PATH, switchTvChannelJson);
|
||||
}
|
||||
|
||||
public void clearAvailableTvChannelList() {
|
||||
if (availableTvChannels != null) {
|
||||
availableTvChannels.clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.TvSettingsUpdateDTO;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service for handling commands regarding the TV picture settings
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TvPictureService implements PhilipsTVService {
|
||||
|
||||
private static final int SHARPNESS_NODE_ID = 2131230851;
|
||||
private static final int CONTRAST_NODE_ID = 2131230850;
|
||||
private static final int BRIGHTNESS_NODE_ID = 2131230852;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public TvPictureService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
try {
|
||||
if (CHANNEL_BRIGHTNESS.equals(channel) && command instanceof PercentType) {
|
||||
setBrightness(((PercentType) command).intValue());
|
||||
} else if (CHANNEL_BRIGHTNESS.equals(channel) && command instanceof RefreshType) {
|
||||
int currentBrightness = getBrightness();
|
||||
handler.postUpdateChannel(CHANNEL_BRIGHTNESS, new PercentType(currentBrightness));
|
||||
} else if (CHANNEL_CONTRAST.equals(channel) && command instanceof PercentType) {
|
||||
setContrast(((PercentType) command).intValue());
|
||||
} else if (CHANNEL_CONTRAST.equals(channel) && command instanceof RefreshType) {
|
||||
int currentContrast = getContrast();
|
||||
handler.postUpdateChannel(CHANNEL_CONTRAST, new PercentType(currentContrast));
|
||||
} else if (CHANNEL_SHARPNESS.equals(channel) && command instanceof PercentType) {
|
||||
setSharpness(((PercentType) command).intValue());
|
||||
} else if (CHANNEL_SHARPNESS.equals(channel) && command instanceof RefreshType) {
|
||||
int currentSharpness = getSharpness();
|
||||
handler.postUpdateChannel(CHANNEL_SHARPNESS, new PercentType(currentSharpness));
|
||||
} else {
|
||||
if (!(command instanceof RefreshType)) {
|
||||
logger.warn("Unknown command: {} for Channel {}", command, channel);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Error during handling the TvPicture command {} for Channel {}: {}", command, channel,
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getBrightness() throws IOException {
|
||||
String getBrightnessJson = ServiceUtil.createTvSettingsRetrievalJson(BRIGHTNESS_NODE_ID);
|
||||
logger.debug("Post Tv Picture retrieval brightness json: {}", getBrightnessJson);
|
||||
return (int) OBJECT_MAPPER.readValue(connectionManager.doHttpsPost(CURRENT_SETTINGS_PATH, getBrightnessJson),
|
||||
TvSettingsUpdateDTO.class).getValues().get(0).getValue().getData().getValue();
|
||||
}
|
||||
|
||||
private void setBrightness(int brightness) throws IOException {
|
||||
String tvPictureBrightnessJson = ServiceUtil.createTvSettingsUpdateJson(BRIGHTNESS_NODE_ID, brightness);
|
||||
logger.debug("Post Tv Picture brightness json: {}", tvPictureBrightnessJson);
|
||||
connectionManager.doHttpsPost(UPDATE_SETTINGS_PATH, tvPictureBrightnessJson);
|
||||
}
|
||||
|
||||
private int getContrast() throws IOException {
|
||||
String getContrastJson = ServiceUtil.createTvSettingsRetrievalJson(CONTRAST_NODE_ID);
|
||||
logger.debug("Post Tv Picture retrieval contrast json: {}", getContrastJson);
|
||||
return (int) OBJECT_MAPPER.readValue(connectionManager.doHttpsPost(CURRENT_SETTINGS_PATH, getContrastJson),
|
||||
TvSettingsUpdateDTO.class).getValues().get(0).getValue().getData().getValue();
|
||||
}
|
||||
|
||||
private void setContrast(int contrast) throws IOException {
|
||||
String tvPictureContrastJson = ServiceUtil.createTvSettingsUpdateJson(CONTRAST_NODE_ID, contrast);
|
||||
logger.debug("Post Tv Picture contrast json: {}", tvPictureContrastJson);
|
||||
connectionManager.doHttpsPost(UPDATE_SETTINGS_PATH, tvPictureContrastJson);
|
||||
}
|
||||
|
||||
private int getSharpness() throws IOException {
|
||||
String getSharpnessJson = ServiceUtil.createTvSettingsRetrievalJson(SHARPNESS_NODE_ID);
|
||||
logger.debug("Post Tv Picture retrieval sharpness json: {}", getSharpnessJson);
|
||||
return (int) OBJECT_MAPPER.readValue(connectionManager.doHttpsPost(CURRENT_SETTINGS_PATH, getSharpnessJson),
|
||||
TvSettingsUpdateDTO.class).getValues().get(0).getValue().getData().getValue();
|
||||
}
|
||||
|
||||
private void setSharpness(int sharpness) throws IOException {
|
||||
String tvPictureSharpnessJson = ServiceUtil.createTvSettingsUpdateJson(SHARPNESS_NODE_ID, sharpness / 10);
|
||||
logger.debug("Post Tv Picture brightness json: {}", tvPictureSharpnessJson);
|
||||
connectionManager.doHttpsPost(UPDATE_SETTINGS_PATH, tvPictureSharpnessJson);
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager.OBJECT_MAPPER;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.*;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.service.KeyPress.KEY_MUTE;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.ConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVConnectionManager;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.api.PhilipsTVService;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.keypress.KeyPressDTO;
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.volume.VolumeDTO;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VolumeService} is responsible for handling volume commands, which are sent to the
|
||||
* volume channel or mute channel.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VolumeService implements PhilipsTVService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private final PhilipsTVConnectionManager handler;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public VolumeService(PhilipsTVConnectionManager handler, ConnectionManager connectionManager) {
|
||||
this.handler = handler;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(String channel, Command command) {
|
||||
try {
|
||||
if (command instanceof RefreshType) {
|
||||
VolumeDTO volumeDTO = getVolume();
|
||||
handler.postUpdateChannel(CHANNEL_VOLUME, new PercentType(volumeDTO.getCurrentVolume()));
|
||||
handler.postUpdateChannel(CHANNEL_MUTE, volumeDTO.isMuted() ? OnOffType.ON : OnOffType.OFF);
|
||||
} else if (CHANNEL_VOLUME.equals(channel) && command instanceof PercentType) {
|
||||
setVolume((PercentType) command);
|
||||
handler.postUpdateChannel(CHANNEL_VOLUME, (PercentType) command);
|
||||
} else if (CHANNEL_MUTE.equals(channel) && command instanceof OnOffType) {
|
||||
setMute();
|
||||
} else {
|
||||
logger.warn("Unknown command: {} for Channel {}", command, channel);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (isTvOfflineException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.NONE, TV_OFFLINE_MSG);
|
||||
} else if (isTvNotListeningException(e)) {
|
||||
handler.postUpdateThing(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
TV_NOT_LISTENING_MSG);
|
||||
} else {
|
||||
logger.warn("Error during handling the VolumeService command {} for Channel {}: {}", command, channel,
|
||||
e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private VolumeDTO getVolume() throws IOException {
|
||||
String jsonContent = connectionManager.doHttpsGet(VOLUME_PATH);
|
||||
return OBJECT_MAPPER.readValue(jsonContent, VolumeDTO.class);
|
||||
}
|
||||
|
||||
private void setVolume(PercentType volumeToSet) throws IOException {
|
||||
VolumeDTO volumeDTO = new VolumeDTO();
|
||||
volumeDTO.setMuted(false);
|
||||
volumeDTO.setCurrentVolume(volumeToSet.intValue());
|
||||
String volumeJson = OBJECT_MAPPER.writeValueAsString(volumeDTO);
|
||||
logger.debug("Set json volume: {}", volumeJson);
|
||||
connectionManager.doHttpsPost(VOLUME_PATH, volumeJson);
|
||||
}
|
||||
|
||||
private void setMute() throws IOException {
|
||||
// We just sent the KEY_MUTE and dont bother what was actually requested
|
||||
KeyPressDTO keyPressDTO = new KeyPressDTO(KEY_MUTE);
|
||||
String muteJson = OBJECT_MAPPER.writeValueAsString(keyPressDTO);
|
||||
logger.debug("Set json mute state: {}", muteJson);
|
||||
connectionManager.doHttpsPost(KEY_CODE_PATH, muteJson);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.api;
|
||||
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.apache.http.conn.HttpHostConnectException;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* Interface for Philips TV services.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface PhilipsTVService {
|
||||
|
||||
/**
|
||||
* Procedure for sending command.
|
||||
*
|
||||
* @param channel the channel to which the command applies
|
||||
* @param command the command to be handled
|
||||
*/
|
||||
void handleCommand(String channel, Command command);
|
||||
|
||||
default boolean isTvOfflineException(Exception exception) {
|
||||
String message = Optional.ofNullable(exception.getMessage()).orElse("");
|
||||
if (!message.isEmpty()) {
|
||||
if ((exception instanceof NoRouteToHostException) && message.contains("Host unreachable")) {
|
||||
return true;
|
||||
} else {
|
||||
return (exception instanceof ConnectTimeoutException) && message.contains("timed out");
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
default boolean isTvNotListeningException(Exception exception) {
|
||||
String message = Optional.ofNullable(exception.getMessage()).orElse("");
|
||||
if (!message.isEmpty()) {
|
||||
return (exception instanceof HttpHostConnectException) && message.contains("Connection refused");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link TvSettingsUpdateDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class DataDTO {
|
||||
|
||||
@JsonProperty
|
||||
private Object value; // can be int or string
|
||||
|
||||
public DataDTO() {
|
||||
}
|
||||
|
||||
public DataDTO(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Data{" + "value = '" + value + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link TvSettingsCurrentDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class NodesDTO {
|
||||
|
||||
@JsonProperty("nodeid")
|
||||
private int nodeid;
|
||||
|
||||
public void setNodeid(int nodeid) {
|
||||
this.nodeid = nodeid;
|
||||
}
|
||||
|
||||
public int getNodeid() {
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NodesItem{" + "nodeid = '" + nodeid + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link TvSettingsCurrentDTO} class defines the Data Transfer Object
|
||||
* for the POST Request to Philips TV API /menuitems/settings/current endpoint to retrieve current settings of the tv,
|
||||
* e.g. the tv picture brightness.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class TvSettingsCurrentDTO {
|
||||
|
||||
@JsonProperty("nodes")
|
||||
private List<NodesDTO> nodes;
|
||||
|
||||
public TvSettingsCurrentDTO() {
|
||||
}
|
||||
|
||||
public TvSettingsCurrentDTO(List<NodesDTO> nodes) {
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
public void setNodes(List<NodesDTO> nodes) {
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
public List<NodesDTO> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TvSettingsCurrentDTO{" + "nodes = '" + nodes + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link TvSettingsUpdateDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /menuitems/settings/update endpoint to update settings of the tv, e.g. turning on/off
|
||||
* ambilight hue power.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class TvSettingsUpdateDTO {
|
||||
|
||||
@JsonProperty
|
||||
private List<ValuesDTO> values;
|
||||
|
||||
public TvSettingsUpdateDTO() {
|
||||
}
|
||||
|
||||
public TvSettingsUpdateDTO(List<ValuesDTO> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public void setValues(List<ValuesDTO> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public List<ValuesDTO> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TvSettingsDTO{" + "values = '" + values + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link TvSettingsUpdateDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class ValueDTO {
|
||||
|
||||
@JsonProperty("Controllable")
|
||||
private String controllable = "";
|
||||
|
||||
@JsonProperty
|
||||
private DataDTO data;
|
||||
|
||||
@JsonProperty("Nodeid")
|
||||
private int nodeid;
|
||||
|
||||
@JsonProperty("Available")
|
||||
private String available = "";
|
||||
|
||||
public ValueDTO() {
|
||||
}
|
||||
|
||||
public ValueDTO(DataDTO data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void setControllable(String controllable) {
|
||||
this.controllable = controllable;
|
||||
}
|
||||
|
||||
public String getControllable() {
|
||||
return controllable;
|
||||
}
|
||||
|
||||
public void setData(DataDTO data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public DataDTO getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setNodeid(int nodeid) {
|
||||
this.nodeid = nodeid;
|
||||
}
|
||||
|
||||
public int getNodeid() {
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
public void setAvailable(String available) {
|
||||
this.available = available;
|
||||
}
|
||||
|
||||
public String getAvailable() {
|
||||
return available;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Value{" + "controllable = '" + controllable + '\'' + ",data = '" + data + '\'' + ",nodeid = '" + nodeid
|
||||
+ '\'' + ",available = '" + available + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link TvSettingsUpdateDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class ValuesDTO {
|
||||
|
||||
@JsonProperty
|
||||
private ValueDTO value;
|
||||
|
||||
public ValuesDTO() {
|
||||
}
|
||||
|
||||
public ValuesDTO(ValueDTO value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setValue(ValueDTO value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ValueDTO getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ValuesItem{" + "value = '" + value + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link AmbilightColorSettingsDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class AmbilightColorDTO {
|
||||
|
||||
@JsonProperty("saturation")
|
||||
private int saturation;
|
||||
|
||||
@JsonProperty("brightness")
|
||||
private int brightness;
|
||||
|
||||
@JsonProperty("hue")
|
||||
private int hue;
|
||||
|
||||
public AmbilightColorDTO() {
|
||||
}
|
||||
|
||||
public AmbilightColorDTO(HSBType hsb) {
|
||||
hue = hsb.getHue().intValue() * 255 / 360;
|
||||
saturation = hsb.getSaturation().intValue() * 255 / 100;
|
||||
brightness = hsb.getBrightness().intValue() * 255 / 100;
|
||||
}
|
||||
|
||||
public void setSaturation(int saturation) {
|
||||
this.saturation = saturation;
|
||||
}
|
||||
|
||||
public int getSaturation() {
|
||||
return saturation;
|
||||
}
|
||||
|
||||
public void setBrightness(int brightness) {
|
||||
this.brightness = brightness;
|
||||
}
|
||||
|
||||
public int getBrightness() {
|
||||
return brightness;
|
||||
}
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
}
|
||||
|
||||
public int getHue() {
|
||||
return hue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Color{" + "saturation = '" + saturation + '\'' + ",brightness = '" + brightness + '\'' + ",hue = '"
|
||||
+ hue + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link AmbilightColorSettingsDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class AmbilightColorDeltaDTO {
|
||||
|
||||
@JsonProperty("saturation")
|
||||
private int saturation;
|
||||
|
||||
@JsonProperty("brightness")
|
||||
private int brightness;
|
||||
|
||||
@JsonProperty("hue")
|
||||
private int hue;
|
||||
|
||||
public void setSaturation(int saturation) {
|
||||
this.saturation = saturation;
|
||||
}
|
||||
|
||||
public int getSaturation() {
|
||||
return saturation;
|
||||
}
|
||||
|
||||
public void setBrightness(int brightness) {
|
||||
this.brightness = brightness;
|
||||
}
|
||||
|
||||
public int getBrightness() {
|
||||
return brightness;
|
||||
}
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
}
|
||||
|
||||
public int getHue() {
|
||||
return hue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ColorDelta{" + "saturation = '" + saturation + '\'' + ",brightness = '" + brightness + '\'' + ",hue = '"
|
||||
+ hue + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link AmbilightConfigDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class AmbilightColorSettingsDTO {
|
||||
|
||||
@JsonProperty("color")
|
||||
private AmbilightColorDTO color;
|
||||
|
||||
@JsonProperty("colorDelta")
|
||||
private AmbilightColorDeltaDTO colorDelta;
|
||||
|
||||
@JsonProperty("speed")
|
||||
private int speed;
|
||||
|
||||
public AmbilightColorSettingsDTO(AmbilightColorDTO color, AmbilightColorDeltaDTO colorDelta) {
|
||||
this.color = color;
|
||||
this.colorDelta = colorDelta;
|
||||
}
|
||||
|
||||
public void setColor(AmbilightColorDTO color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public AmbilightColorDTO getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColorDelta(AmbilightColorDeltaDTO colorDelta) {
|
||||
this.colorDelta = colorDelta;
|
||||
}
|
||||
|
||||
public AmbilightColorDeltaDTO getColorDelta() {
|
||||
return colorDelta;
|
||||
}
|
||||
|
||||
public void setSpeed(int speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public int getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ColorSettings{" + "color = '" + color + '\'' + ",colorDelta = '" + colorDelta + '\'' + ",speed = '"
|
||||
+ speed + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link AmbilightConfigDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /ambilight/currentconfiguration endpoint to retrieve or set the current ambilight style.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class AmbilightConfigDTO {
|
||||
|
||||
@JsonProperty("isExpert")
|
||||
private boolean isExpert;
|
||||
|
||||
@JsonProperty("menuSetting")
|
||||
private String menuSetting = "";
|
||||
|
||||
@JsonProperty("styleName")
|
||||
private String styleName = "";
|
||||
|
||||
@JsonProperty("colorSettings")
|
||||
private AmbilightColorSettingsDTO colorSettings;
|
||||
|
||||
@JsonProperty("algorithm")
|
||||
private String algorithm = "";
|
||||
|
||||
public AmbilightConfigDTO() {
|
||||
}
|
||||
|
||||
public AmbilightConfigDTO(AmbilightColorSettingsDTO colorSettings) {
|
||||
this.colorSettings = colorSettings;
|
||||
}
|
||||
|
||||
public void setMenuSetting(String menuSetting) {
|
||||
this.menuSetting = menuSetting;
|
||||
}
|
||||
|
||||
public String getMenuSetting() {
|
||||
return menuSetting;
|
||||
}
|
||||
|
||||
public void setStyleName(String styleName) {
|
||||
this.styleName = styleName;
|
||||
}
|
||||
|
||||
public String getStyleName() {
|
||||
return styleName;
|
||||
}
|
||||
|
||||
public boolean isIsExpert() {
|
||||
return isExpert;
|
||||
}
|
||||
|
||||
public void setIsExpert(boolean isExpert) {
|
||||
this.isExpert = isExpert;
|
||||
}
|
||||
|
||||
public AmbilightColorSettingsDTO getColorSettings() {
|
||||
return colorSettings;
|
||||
}
|
||||
|
||||
public void setColorSettings(AmbilightColorSettingsDTO colorSettings) {
|
||||
this.colorSettings = colorSettings;
|
||||
}
|
||||
|
||||
public String getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public void setAlgorithm(String algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AmbilightConfigDTO{" + "isExpert = '" + isExpert + '\'' + ",menuSetting = '" + menuSetting + '\''
|
||||
+ ",styleName = '" + styleName + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link AmbilightLoungeDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /ambilight/lounge endpoint to power on or off the ambilight lounge mode.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class AmbilightLoungeDTO {
|
||||
|
||||
@JsonProperty("color")
|
||||
private AmbilightColorDTO color;
|
||||
|
||||
public AmbilightLoungeDTO(AmbilightColorDTO color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public void setColor(AmbilightColorDTO color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public AmbilightColorDTO getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AmbilightLoungeDTO{" + "color = '" + color + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link AmbilightModeDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /ambilight/mode endpoint to retrieve or set the ambilight mode.
|
||||
* <p>
|
||||
* current (string): One of following values:
|
||||
* <p>
|
||||
* internal: The internal ambilight algorithm is used to calculate the ambilight colours.
|
||||
* <p>
|
||||
* manual: The cached ambilight colours are shown.
|
||||
* <p>
|
||||
* expert: The cached ambilight colours are used as input for the internal ambilight algorithm
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class AmbilightModeDTO {
|
||||
|
||||
@JsonProperty("current")
|
||||
private String current = "";
|
||||
|
||||
public AmbilightModeDTO() {
|
||||
}
|
||||
|
||||
public void setCurrent(String current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public String getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AmbilightModeDTO{" + "current = '" + current + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.POWER_ON;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link AmbilightPowerDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /ambilight/power endpoint to retrieve or set the current power state.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class AmbilightPowerDTO {
|
||||
|
||||
@JsonProperty("power")
|
||||
private String power = "";
|
||||
|
||||
public String getPower() {
|
||||
return power;
|
||||
}
|
||||
|
||||
public void setPower(String power) {
|
||||
this.power = power;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isPoweredOn() {
|
||||
return power.equalsIgnoreCase(POWER_ON);
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.ambilight;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link AmbilightTopologyDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /ambilight/topology endpoint to retrieve the ambilight topology information.
|
||||
* <p>
|
||||
* Endpoint returns:
|
||||
* <p>
|
||||
* layers (integer): The number of layers.
|
||||
* <p>
|
||||
* left (integer): The number of pixels on the left.
|
||||
* <p>
|
||||
* top (integer): The number of pixels on the top.
|
||||
* <p>
|
||||
* right (integer): The number of pixels on the right.
|
||||
* <p>
|
||||
* bottom (integer): The number of pixels on the bottom.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class AmbilightTopologyDTO {
|
||||
|
||||
@JsonProperty("top")
|
||||
private int top;
|
||||
|
||||
@JsonProperty("left")
|
||||
private int left;
|
||||
|
||||
@JsonProperty("bottom")
|
||||
private int bottom;
|
||||
|
||||
@JsonProperty("layers")
|
||||
private int layers;
|
||||
|
||||
@JsonProperty("right")
|
||||
private int right;
|
||||
|
||||
public AmbilightTopologyDTO() {
|
||||
}
|
||||
|
||||
public void setTop(int top) {
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
public int getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setLeft(int left) {
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
public int getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setBottom(int bottom) {
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public int getBottom() {
|
||||
return bottom;
|
||||
}
|
||||
|
||||
public void setLayers(int layers) {
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
public int getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
public void setRight(int right) {
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public int getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public int getPixelSizeForGivenSide(String side) {
|
||||
int value;
|
||||
switch (side) {
|
||||
case "left":
|
||||
value = left;
|
||||
break;
|
||||
case "right":
|
||||
value = right;
|
||||
break;
|
||||
case "top":
|
||||
value = top;
|
||||
break;
|
||||
case "bottom":
|
||||
value = bottom;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected side: " + side);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AmbilightTopologyDTO{" + "top = '" + top + '\'' + ",left = '" + left + '\'' + ",bottom = '" + bottom
|
||||
+ '\'' + ",layers = '" + layers + '\'' + ",right = '" + right + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link AvailableAppsDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class ApplicationsDTO {
|
||||
|
||||
@JsonProperty("label")
|
||||
private String label = "";
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id = "";
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type = "";
|
||||
|
||||
@JsonProperty("intent")
|
||||
private IntentDTO intent;
|
||||
|
||||
@JsonProperty("order")
|
||||
private int order;
|
||||
|
||||
public ApplicationsDTO() {
|
||||
}
|
||||
|
||||
public ApplicationsDTO(IntentDTO intent) {
|
||||
this.intent = intent;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setIntent(IntentDTO intent) {
|
||||
this.intent = intent;
|
||||
}
|
||||
|
||||
public IntentDTO getIntent() {
|
||||
return intent;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApplicationsItem{" + "label = '" + label + '\'' + ",id = '" + id + '\'' + ",type = '" + type + '\''
|
||||
+ ",intent = '" + intent + '\'' + ",order = '" + order + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link AvailableAppsDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /applications endpoint for retrieving all installed apps.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class AvailableAppsDTO {
|
||||
|
||||
@JsonProperty("version")
|
||||
private int version;
|
||||
|
||||
@JsonProperty("applications")
|
||||
private @Nullable List<ApplicationsDTO> applications;
|
||||
|
||||
public AvailableAppsDTO() {
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setApplications(List<ApplicationsDTO> applications) {
|
||||
this.applications = applications;
|
||||
}
|
||||
|
||||
public @Nullable List<ApplicationsDTO> getApplications() {
|
||||
return applications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AvailableAppsDTO{" + "version = '" + version + '\'' + ",applications = '" + applications + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link LaunchAppDTO} and {@link CurrentAppDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class ComponentDTO {
|
||||
|
||||
@JsonProperty("className")
|
||||
private String className = "";
|
||||
|
||||
@JsonProperty("packageName")
|
||||
private String packageName = "";
|
||||
|
||||
public void setClassName(String className) {
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public void setPackageName(String packageName) {
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Component{" + "className = '" + className + '\'' + ",packageName = '" + packageName + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link LaunchAppDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /activities/current endpoint for retrieving the current running TV app.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class CurrentAppDTO {
|
||||
|
||||
@JsonProperty("component")
|
||||
private ComponentDTO component;
|
||||
|
||||
public CurrentAppDTO() {
|
||||
}
|
||||
|
||||
public CurrentAppDTO(ComponentDTO component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public void setComponent(ComponentDTO component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public ComponentDTO getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Intent{" + "component = '" + component + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link IntentDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class ExtrasDTO {
|
||||
|
||||
@JsonProperty("query")
|
||||
private String query = "";
|
||||
|
||||
public void setQuery(String query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Extras{" + "query = '" + query + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link LaunchAppDTO} and {@link LaunchAppDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class IntentDTO {
|
||||
|
||||
@JsonProperty("component")
|
||||
private ComponentDTO component;
|
||||
|
||||
@JsonProperty("action")
|
||||
private String action = "";
|
||||
|
||||
@JsonProperty("extras")
|
||||
private ExtrasDTO extras;
|
||||
|
||||
public IntentDTO() {
|
||||
}
|
||||
|
||||
public IntentDTO(ComponentDTO component, ExtrasDTO extras) {
|
||||
this.component = component;
|
||||
this.extras = extras;
|
||||
}
|
||||
|
||||
public void setComponent(ComponentDTO component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
public ComponentDTO getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setExtras(ExtrasDTO extras) {
|
||||
this.extras = extras;
|
||||
}
|
||||
|
||||
public ExtrasDTO getExtras() {
|
||||
return extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Intent{" + "component = '" + component + '\'' + ",action = '" + action + '\'' + ",extras = '" + extras
|
||||
+ '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.application;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link LaunchAppDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /activities/launch endpoint for launching TV apps and launching search for content.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class LaunchAppDTO {
|
||||
|
||||
@JsonProperty("intent")
|
||||
private IntentDTO intent;
|
||||
|
||||
public LaunchAppDTO() {
|
||||
}
|
||||
|
||||
public LaunchAppDTO(IntentDTO intent) {
|
||||
this.intent = intent;
|
||||
}
|
||||
|
||||
public void setIntent(IntentDTO intent) {
|
||||
this.intent = intent;
|
||||
}
|
||||
|
||||
public IntentDTO getIntent() {
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LaunchAppDTO{" + "intent = '" + intent + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link AvailableTvChannelsDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API channeldb/tv/channelLists/all endpoint for retrieving all tv channels.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class AvailableTvChannelsDTO {
|
||||
|
||||
@JsonProperty("Channel")
|
||||
private @Nullable List<ChannelDTO> channel;
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id = "";
|
||||
|
||||
@JsonProperty("medium")
|
||||
private String medium = "";
|
||||
|
||||
@JsonProperty("version")
|
||||
private int version;
|
||||
|
||||
@JsonProperty("listType")
|
||||
private String listType = "";
|
||||
|
||||
@JsonProperty("operator")
|
||||
private String operator = "";
|
||||
|
||||
@JsonProperty("installCountry")
|
||||
private String installCountry = "";
|
||||
|
||||
public AvailableTvChannelsDTO() {
|
||||
}
|
||||
|
||||
public void setChannel(List<ChannelDTO> channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public @Nullable List<ChannelDTO> getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setMedium(String medium) {
|
||||
this.medium = medium;
|
||||
}
|
||||
|
||||
public String getMedium() {
|
||||
return medium;
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setListType(String listType) {
|
||||
this.listType = listType;
|
||||
}
|
||||
|
||||
public String getListType() {
|
||||
return listType;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public void setInstallCountry(String installCountry) {
|
||||
this.installCountry = installCountry;
|
||||
}
|
||||
|
||||
public String getInstallCountry() {
|
||||
return installCountry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AvailableTvChannelsDTO{" + "channel = '" + channel + '\'' + ",id = '" + id + '\'' + ",medium = '"
|
||||
+ medium + '\'' + ",version = '" + version + '\'' + ",listType = '" + listType + '\'' + ",operator = '"
|
||||
+ operator + '\'' + ",installCountry = '" + installCountry + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link TvChannelDTO} and {@link AvailableTvChannelsDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class ChannelDTO {
|
||||
|
||||
@JsonProperty("serviceType")
|
||||
private String serviceType = "";
|
||||
|
||||
@JsonProperty("logoVersion")
|
||||
private int logoVersion;
|
||||
|
||||
@JsonProperty("ccid")
|
||||
private String ccid = "";
|
||||
|
||||
@JsonProperty("name")
|
||||
private String name = "";
|
||||
|
||||
@JsonProperty("preset")
|
||||
private String preset = "";
|
||||
|
||||
@JsonProperty("tsid")
|
||||
private int tsid;
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type = "";
|
||||
|
||||
@JsonProperty("onid")
|
||||
private int onid;
|
||||
|
||||
@JsonProperty("sid")
|
||||
private int sid;
|
||||
|
||||
public void setServiceType(String serviceType) {
|
||||
this.serviceType = serviceType;
|
||||
}
|
||||
|
||||
public String getServiceType() {
|
||||
return serviceType;
|
||||
}
|
||||
|
||||
public void setLogoVersion(int logoVersion) {
|
||||
this.logoVersion = logoVersion;
|
||||
}
|
||||
|
||||
public int getLogoVersion() {
|
||||
return logoVersion;
|
||||
}
|
||||
|
||||
public void setCcid(@Nullable String ccid) {
|
||||
if (!ccid.isEmpty()) {
|
||||
this.ccid = ccid;
|
||||
}
|
||||
}
|
||||
|
||||
public String getCcid() {
|
||||
return ccid;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setPreset(String preset) {
|
||||
this.preset = preset;
|
||||
}
|
||||
|
||||
public String getPreset() {
|
||||
return preset;
|
||||
}
|
||||
|
||||
public void setTsid(int tsid) {
|
||||
this.tsid = tsid;
|
||||
}
|
||||
|
||||
public int getTsid() {
|
||||
return tsid;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setOnid(int onid) {
|
||||
this.onid = onid;
|
||||
}
|
||||
|
||||
public int getOnid() {
|
||||
return onid;
|
||||
}
|
||||
|
||||
public void setSid(int sid) {
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
public int getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChannelItem{" + "serviceType = '" + serviceType + '\'' + ",logoVersion = '" + logoVersion + '\''
|
||||
+ ",ccid = '" + ccid + '\'' + ",name = '" + name + '\'' + ",preset = '" + preset + '\'' + ",tsid = '"
|
||||
+ tsid + '\'' + ",type = '" + type + '\'' + ",onid = '" + onid + '\'' + ",sid = '" + sid + '\'' + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Part of {@link TvChannelDTO}
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class ChannelListDTO {
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id = "";
|
||||
|
||||
@JsonProperty("version")
|
||||
private String version = "";
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.channel;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link TvChannelDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /activities/tv endpoint to get and switch tv channels.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class TvChannelDTO {
|
||||
|
||||
@JsonProperty("channel")
|
||||
private ChannelDTO channel;
|
||||
|
||||
@JsonProperty("channelList")
|
||||
private ChannelListDTO channelList;
|
||||
|
||||
public TvChannelDTO() {
|
||||
}
|
||||
|
||||
public TvChannelDTO(ChannelDTO channel, ChannelListDTO channelList) {
|
||||
this.channel = channel;
|
||||
this.channelList = channelList;
|
||||
}
|
||||
|
||||
public ChannelDTO getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public ChannelListDTO getChannelList() {
|
||||
return channelList;
|
||||
}
|
||||
|
||||
public void setChannel(ChannelDTO channelDTO) {
|
||||
this.channel = channelDTO;
|
||||
}
|
||||
|
||||
public void setChannelList(ChannelListDTO channelList) {
|
||||
this.channelList = channelList;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.keypress;
|
||||
|
||||
import org.openhab.binding.androidtv.internal.protocol.philipstv.service.KeyPress;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link KeyPressDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /input/key endpoint for remote controller emulation.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
|
||||
public class KeyPressDTO {
|
||||
|
||||
@JsonProperty("key")
|
||||
private KeyPress key;
|
||||
|
||||
public KeyPressDTO() {
|
||||
}
|
||||
|
||||
public KeyPressDTO(KeyPress key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public KeyPress getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(KeyPress key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.power;
|
||||
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.POWER_ON;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.STANDBY;
|
||||
import static org.openhab.binding.androidtv.internal.protocol.philipstv.PhilipsTVBindingConstants.STANDBYKEEP;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link PowerStateDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /powerstate endpoint to retrieve or set the current power state.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class PowerStateDTO {
|
||||
|
||||
@JsonProperty("powerstate")
|
||||
private String powerState = "";
|
||||
|
||||
public PowerStateDTO() {
|
||||
}
|
||||
|
||||
public String getPowerState() {
|
||||
return powerState;
|
||||
}
|
||||
|
||||
public void setPowerState(String powerState) {
|
||||
this.powerState = powerState;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isPoweredOn() {
|
||||
return powerState.equalsIgnoreCase(POWER_ON);
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isStandby() {
|
||||
return (powerState.equalsIgnoreCase(STANDBY) || powerState.equalsIgnoreCase(STANDBYKEEP));
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isStandbyKeep() {
|
||||
return powerState.equalsIgnoreCase(STANDBYKEEP);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.androidtv.internal.protocol.philipstv.service.model.volume;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The {@link VolumeDTO} class defines the Data Transfer Object
|
||||
* for the Philips TV API /audio/volume endpoint.
|
||||
*
|
||||
* @author Benjamin Meyer - Initial contribution
|
||||
* @author Ben Rosenblum - Merged into AndroidTV
|
||||
*/
|
||||
public class VolumeDTO {
|
||||
|
||||
@JsonProperty("current")
|
||||
private int currentVolume;
|
||||
|
||||
@JsonProperty("muted")
|
||||
private boolean muted;
|
||||
|
||||
public VolumeDTO() {
|
||||
}
|
||||
|
||||
public int getCurrentVolume() {
|
||||
return currentVolume;
|
||||
}
|
||||
|
||||
public void setCurrentVolume(int currentVolume) {
|
||||
this.currentVolume = currentVolume;
|
||||
}
|
||||
|
||||
public boolean isMuted() {
|
||||
return muted;
|
||||
}
|
||||
|
||||
public void setMuted(boolean muted) {
|
||||
this.muted = muted;
|
||||
}
|
||||
}
|
@ -7,15 +7,17 @@ addon.androidtv.description = This is the add-on for AndroidTV.
|
||||
|
||||
thing-type.androidtv.googletv.label = GoogleTV
|
||||
thing-type.androidtv.googletv.description = GoogleTV
|
||||
thing-type.androidtv.philipstv.label = Philips TV
|
||||
thing-type.androidtv.philipstv.description = A Philips TV device
|
||||
thing-type.androidtv.shieldtv.label = ShieldTV
|
||||
thing-type.androidtv.shieldtv.description = Nvidia ShieldTV
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.androidtv.googletv.delay.label = Delay
|
||||
thing-type.config.androidtv.googletv.delay.label = Message Delay
|
||||
thing-type.config.androidtv.googletv.delay.description = Delay between messages
|
||||
thing-type.config.androidtv.googletv.gtvEnabled.label = Enable GoogleTV
|
||||
thing-type.config.androidtv.googletv.gtvEnabled.description = Enable the GoogleTV Protocol
|
||||
thing-type.config.androidtv.googletv.googletvPort.label = GoogleTV Port
|
||||
thing-type.config.androidtv.googletv.googletvPort.description = Port to connect to
|
||||
thing-type.config.androidtv.googletv.heartbeat.label = Heartbeat Frequency
|
||||
thing-type.config.androidtv.googletv.heartbeat.description = Frequency of heartbeats
|
||||
thing-type.config.androidtv.googletv.ipAddress.label = Hostname
|
||||
@ -24,12 +26,34 @@ thing-type.config.androidtv.googletv.keystoreFileName.label = Keystore File Name
|
||||
thing-type.config.androidtv.googletv.keystoreFileName.description = Java keystore containing key and certs
|
||||
thing-type.config.androidtv.googletv.keystorePassword.label = Keystore Password
|
||||
thing-type.config.androidtv.googletv.keystorePassword.description = Password for the keystore file
|
||||
thing-type.config.androidtv.googletv.googletvPort.label = GoogleTV Port
|
||||
thing-type.config.androidtv.googletv.googletvPort.description = Port to connect to
|
||||
thing-type.config.androidtv.googletv.reconnect.label = Reconnect Delay
|
||||
thing-type.config.androidtv.googletv.reconnect.description = Delay between reconnection attempts
|
||||
thing-type.config.androidtv.philipstv.delay.label = Delay
|
||||
thing-type.config.androidtv.philipstv.delay.description = Delay between messages
|
||||
thing-type.config.androidtv.philipstv.googletvPort.label = GoogleTV Port
|
||||
thing-type.config.androidtv.philipstv.googletvPort.description = Port to connect to
|
||||
thing-type.config.androidtv.philipstv.gtvEnabled.label = Enable GoogleTV
|
||||
thing-type.config.androidtv.philipstv.gtvEnabled.description = Enable the GoogleTV Protocol
|
||||
thing-type.config.androidtv.philipstv.heartbeat.label = Heartbeat Frequency
|
||||
thing-type.config.androidtv.philipstv.heartbeat.description = Frequency of heartbeats
|
||||
thing-type.config.androidtv.philipstv.ipAddress.label = Hostname
|
||||
thing-type.config.androidtv.philipstv.ipAddress.description = Hostname or IP address of the device
|
||||
thing-type.config.androidtv.philipstv.keystoreFileName.label = Keystore File Name
|
||||
thing-type.config.androidtv.philipstv.keystoreFileName.description = Java keystore containing key and certs
|
||||
thing-type.config.androidtv.philipstv.keystorePassword.label = Keystore Password
|
||||
thing-type.config.androidtv.philipstv.keystorePassword.description = Password for the keystore file
|
||||
thing-type.config.androidtv.philipstv.philipstvPort.label = PhilipsTV Port
|
||||
thing-type.config.androidtv.philipstv.philipstvPort.description = Port to connect to
|
||||
thing-type.config.androidtv.philipstv.reconnect.label = Reconnect Delay
|
||||
thing-type.config.androidtv.philipstv.reconnect.description = Delay between reconnection attempts
|
||||
thing-type.config.androidtv.philipstv.refreshRate.label = Refresh Rate
|
||||
thing-type.config.androidtv.philipstv.refreshRate.description = How often the Philips TV status details get refreshed. Value in seconds. '0' deactives refreshing.
|
||||
thing-type.config.androidtv.philipstv.useUpnpDiscovery.label = Use UPnP Discovery
|
||||
thing-type.config.androidtv.philipstv.useUpnpDiscovery.description = Enables UPnP Discovery. If disabled, constant HTTPS polling will happen.
|
||||
thing-type.config.androidtv.shieldtv.delay.label = Delay
|
||||
thing-type.config.androidtv.shieldtv.delay.description = Delay between messages
|
||||
thing-type.config.androidtv.shieldtv.googletvPort.label = GoogleTV Port
|
||||
thing-type.config.androidtv.shieldtv.googletvPort.description = Port to connect to
|
||||
thing-type.config.androidtv.shieldtv.gtvEnabled.label = Enable GoogleTV
|
||||
thing-type.config.androidtv.shieldtv.gtvEnabled.description = Enable the GoogleTV Protocol
|
||||
thing-type.config.androidtv.shieldtv.heartbeat.label = Heartbeat Frequency
|
||||
@ -40,21 +64,65 @@ thing-type.config.androidtv.shieldtv.keystoreFileName.label = Keystore File Name
|
||||
thing-type.config.androidtv.shieldtv.keystoreFileName.description = Java keystore containing key and certs
|
||||
thing-type.config.androidtv.shieldtv.keystorePassword.label = Keystore Password
|
||||
thing-type.config.androidtv.shieldtv.keystorePassword.description = Password for the keystore file
|
||||
thing-type.config.androidtv.shieldtv.googletvPort.label = GoogleTV Port
|
||||
thing-type.config.androidtv.shieldtv.googletvPort.description = Port to connect to
|
||||
thing-type.config.androidtv.shieldtv.shieldtvPort.label = ShieldTV Port
|
||||
thing-type.config.androidtv.shieldtv.shieldtvPort.description = Port to connect to
|
||||
thing-type.config.androidtv.shieldtv.reconnect.label = Reconnect Delay
|
||||
thing-type.config.androidtv.shieldtv.reconnect.description = Delay between reconnection attempts
|
||||
thing-type.config.androidtv.shieldtv.shieldtvPort.label = ShieldTV Port
|
||||
thing-type.config.androidtv.shieldtv.shieldtvPort.description = Port to connect to
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.androidtv.ambilightBottomColor.label = Bottom Ambilight
|
||||
channel-type.androidtv.ambilightBottomColor.description = Sets the Ambilight color for the bottom.
|
||||
channel-type.androidtv.ambilightColor.label = All Ambilight
|
||||
channel-type.androidtv.ambilightColor.description = Sets the Ambilight color for all sides.
|
||||
channel-type.androidtv.ambilightHuePower.label = Ambilight + Hue Power
|
||||
channel-type.androidtv.ambilightHuePower.description = Ambilight + Hue power. Turns ambilight with connected Philips Hue Lamps on or off.
|
||||
channel-type.androidtv.ambilightLeftColor.label = Left Ambilight
|
||||
channel-type.androidtv.ambilightLeftColor.description = Sets the Ambilight color for the left side.
|
||||
channel-type.androidtv.ambilightLoungePower.label = Ambilight Lounge Power
|
||||
channel-type.androidtv.ambilightLoungePower.description = Ambilight lounge power. Turns ambilight lounge on or off.
|
||||
channel-type.androidtv.ambilightPower.label = Ambilight Power
|
||||
channel-type.androidtv.ambilightPower.description = Ambilight power. Turns ambilight on or off.
|
||||
channel-type.androidtv.ambilightRightColor.label = Right Ambilight
|
||||
channel-type.androidtv.ambilightRightColor.description = Sets the Ambilight color for the right side.
|
||||
channel-type.androidtv.ambilightStyle.label = Ambilight Style
|
||||
channel-type.androidtv.ambilightStyle.description = Current ambilight style. Changing this to a value from the List, switches the ambilight style.
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_VIDEO\ STANDARD = FOLLOW_VIDEO STANDARD
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_VIDEO\ NATURAL = FOLLOW_VIDEO NATURAL
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_VIDEO\ IMMERSIVE = FOLLOW_VIDEO IMMERSIVE
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_VIDEO\ VIVID = FOLLOW_VIDEO VIVID
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_VIDEO\ GAME = FOLLOW_VIDEO GAME
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_VIDEO\ COMFORT = FOLLOW_VIDEO COMFORT
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_VIDEO\ RELAX = FOLLOW_VIDEO RELAX
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ ENERGY_ADAPTIVE_BRIGHTNESS = FOLLOW_AUDIO ENERGY_ADAPTIVE_BRIGHTNESS
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ ENERGY_ADAPTIVE_COLORS = FOLLOW_AUDIO ENERGY_ADAPTIVE_COLORS
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ VU_METER = FOLLOW_AUDIO VU_METER
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ SPECTRUM_ANALYZER = FOLLOW_AUDIO SPECTRUM_ANALYZER
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ KNIGHT_RIDER_CLOCKWISE = FOLLOW_AUDIO KNIGHT_RIDER_CLOCKWISE
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ KNIGHT_RIDER_ALTERNATING = FOLLOW_AUDIO KNIGHT_RIDER_ALTERNATING
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ RANDOM_PIXEL_FLASH = FOLLOW_AUDIO RANDOM_PIXEL_FLASH
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ PARTY = FOLLOW_AUDIO PARTY
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_AUDIO\ MODE_RANDOM = FOLLOW_AUDIO MODE_RANDOM
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_COLOR\ MANUAL_HUE = FOLLOW_COLOR MANUAL_HUE
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_COLOR\ HOT_LAVA = FOLLOW_COLOR HOT_LAVA
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_COLOR\ DEEP_WATER = FOLLOW_COLOR DEEP_WATER
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_COLOR\ FRESH_NATURE = FOLLOW_COLOR FRESH_NATURE
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_COLOR\ ISF = FOLLOW_COLOR ISF
|
||||
channel-type.androidtv.ambilightStyle.state.option.FOLLOW_COLOR\ PTA_LOUNGE = FOLLOW_COLOR PTA_LOUNGE
|
||||
channel-type.androidtv.ambilightTopColor.label = Top Ambilight
|
||||
channel-type.androidtv.ambilightTopColor.description = Sets the Ambilight color for the top.
|
||||
channel-type.androidtv.app.label = App
|
||||
channel-type.androidtv.app.description = App Control
|
||||
channel-type.androidtv.appicon.label = App Icon
|
||||
channel-type.androidtv.appicon.description = App Icon
|
||||
channel-type.androidtv.appname.label = App Name
|
||||
channel-type.androidtv.appname.description = App Name
|
||||
channel-type.androidtv.appurl.label = App URL
|
||||
channel-type.androidtv.appurl.description = App URL
|
||||
channel-type.androidtv.brightness.label = Brightness
|
||||
channel-type.androidtv.brightness.description = Brightness of the TV picture.
|
||||
channel-type.androidtv.contrast.label = Contrast
|
||||
channel-type.androidtv.contrast.description = Contrast of the TV picture.
|
||||
channel-type.androidtv.debug.label = DEBUG Command
|
||||
channel-type.androidtv.debug.description = Binding control (for debugging)
|
||||
channel-type.androidtv.keyboard.label = Keyboard
|
||||
@ -67,6 +135,17 @@ channel-type.androidtv.pincode.label = Pin Code
|
||||
channel-type.androidtv.pincode.description = Send Pin Code
|
||||
channel-type.androidtv.player.label = Player
|
||||
channel-type.androidtv.player.description = Player Control
|
||||
channel-type.androidtv.searchContent.label = Search Content
|
||||
channel-type.androidtv.searchContent.description = Keyword(s) to search for on TV via Google Assistant
|
||||
channel-type.androidtv.sharpness.label = Sharpness
|
||||
channel-type.androidtv.sharpness.description = Sharpness of the TV picture.
|
||||
channel-type.androidtv.tvChannel.label = TV Channel
|
||||
channel-type.androidtv.tvChannel.description = Name of the currently running TV Channel. Changing this to a value from the List, switches the channel.
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.androidtv.googletv.gtvEnabled.label = Enable GoogleTV
|
||||
thing-type.config.androidtv.googletv.gtvEnabled.description = Enable the GoogleTV Protocol
|
||||
|
||||
# custom thing status
|
||||
|
||||
@ -86,5 +165,18 @@ offline.interrupted = Interrupted
|
||||
offline.io-error = I/O Error
|
||||
offline.runtime-exception = Runtime exception
|
||||
offline.user-forced-pin-process = User Forced PIN Process
|
||||
offline.error-occured-while-presenting-pairing-code = Error occurred while trying to present a Pairing Code on TV
|
||||
offline.error-occured-during-retrieval-of-credentials = Error occurred during retrieval of credentials
|
||||
offline.pairing-is-not-configured-yet = Pairing is not configured yet
|
||||
offline.error-occurred-while-trying-to-present-a-pairing-code-on-tv = Error occurred while trying to present a Pairing Code on TV
|
||||
offline.pairing-code-is-available-but-credentials-missing = Pairing Code is available, but credentials missing. Trying to retrieve them
|
||||
offline.error-occurred-during-retrieval-of-credentials = Error occurred during retrieval of credentials
|
||||
offline.pairing-was-unsuccessful = Pairing was unsuccessful
|
||||
offline.error-occurred-during-creation-of-http-client = Error occurred during creation of HTTP client
|
||||
offline.authentication-with-philips-tv-device-was-successful-continuing-initialization-of-the-tv = Authentication with Philips TV device was successful. Continuing initialization of the tv.
|
||||
offline.could-not-successfully-finish-pairing-process-with-the-tv = Could not successfully finish pairing process with the TV
|
||||
offline.tv-is-not-reachable-and-should-therefore-be-off = TV is not reachable and should therefore be off
|
||||
offline.tv-does-not-accept-commands-at-the-moment = TV does not accept commands at the moment
|
||||
offline.unknown = Unknown
|
||||
online.standby = Standby
|
||||
online.online = Online
|
||||
|
@ -157,6 +157,106 @@
|
||||
<default>5</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="delay" type="integer" min="0">
|
||||
<label>Message Delay</label>
|
||||
<description>Delay between messages</description>
|
||||
<default>0</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="philipstv">
|
||||
<label>Philips TV</label>
|
||||
<description>A Philips TV device</description>
|
||||
|
||||
<channels>
|
||||
<channel id="debug" typeId="debug"/>
|
||||
<channel id="keypress" typeId="keypress"/>
|
||||
<channel id="keyboard" typeId="keyboard"/>
|
||||
<channel id="keycode" typeId="keycode"/>
|
||||
<channel id="pincode" typeId="pincode"/>
|
||||
<channel id="volume" typeId="system.volume"/>
|
||||
<channel id="mute" typeId="system.mute"/>
|
||||
<channel id="power" typeId="system.power"/>
|
||||
<channel id="brightness" typeId="brightness"/>
|
||||
<channel id="contrast" typeId="contrast"/>
|
||||
<channel id="sharpness" typeId="sharpness"/>
|
||||
<channel id="app" typeId="app"/>
|
||||
<channel id="appname" typeId="appname"/>
|
||||
<channel id="appicon" typeId="appicon"/>
|
||||
<channel id="tvChannel" typeId="tvChannel"/>
|
||||
<channel id="player" typeId="player"/>
|
||||
<channel id="searchContent" typeId="searchContent"/>
|
||||
<channel id="ambilightPower" typeId="ambilightPower"/>
|
||||
<channel id="ambilightHuePower" typeId="ambilightHuePower"/>
|
||||
<channel id="ambilightLoungePower" typeId="ambilightLoungePower"/>
|
||||
<channel id="ambilightStyle" typeId="ambilightStyle"/>
|
||||
<channel id="ambilightColor" typeId="ambilightColor"/>
|
||||
<channel id="ambilightLeftColor" typeId="ambilightLeftColor"/>
|
||||
<channel id="ambilightRightColor" typeId="ambilightRightColor"/>
|
||||
<channel id="ambilightTopColor" typeId="ambilightTopColor"/>
|
||||
<channel id="ambilightBottomColor" typeId="ambilightBottomColor"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="ipAddress" type="text" required="true">
|
||||
<context>network-address</context>
|
||||
<label>Hostname</label>
|
||||
<description>Hostname or IP address of the device</description>
|
||||
</parameter>
|
||||
<parameter name="googletvPort" type="integer">
|
||||
<label>GoogleTV Port</label>
|
||||
<description>Port to connect to</description>
|
||||
<default>6466</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="philipstvPort" type="integer">
|
||||
<label>PhilipsTV Port</label>
|
||||
<description>Port to connect to</description>
|
||||
<default>1926</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="refreshRate" type="integer">
|
||||
<label>Refresh Rate</label>
|
||||
<description>
|
||||
How often the Philips TV status details get refreshed. Value in seconds. '0' deactives refreshing.
|
||||
</description>
|
||||
<advanced>true</advanced>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
<parameter name="useUpnpDiscovery" type="boolean">
|
||||
<label>Use UPnP Discovery</label>
|
||||
<description>
|
||||
Enables UPnP Discovery. If disabled, constant HTTPS polling will happen.
|
||||
</description>
|
||||
<advanced>true</advanced>
|
||||
<default>true</default>
|
||||
</parameter>
|
||||
<parameter name="keystoreFileName" type="text">
|
||||
<label>Keystore File Name</label>
|
||||
<description>Java keystore containing key and certs</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="keystorePassword" type="text">
|
||||
<context>password</context>
|
||||
<label>Keystore Password</label>
|
||||
<description>Password for the keystore file</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="reconnect" type="integer" min="0">
|
||||
<label>Reconnect Delay</label>
|
||||
<description>Delay between reconnection attempts</description>
|
||||
<default>60</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="heartbeat" type="integer" min="0">
|
||||
<label>Heartbeat Frequency</label>
|
||||
<description>Frequency of heartbeats</description>
|
||||
<default>5</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="delay" type="integer" min="0">
|
||||
<label>Delay</label>
|
||||
<description>Delay between messages</description>
|
||||
@ -197,6 +297,12 @@
|
||||
<description>App URL</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="appicon" advanced="true">
|
||||
<item-type>Image</item-type>
|
||||
<label>App Icon</label>
|
||||
<description>App Icon</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="keypress">
|
||||
<item-type>String</item-type>
|
||||
<label>Key Press</label>
|
||||
@ -227,4 +333,131 @@
|
||||
<description>Player Control</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tvChannel" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>TV Channel</label>
|
||||
<description>Name of the currently running TV Channel. Changing this to a value from the List, switches the
|
||||
channel.
|
||||
</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="searchContent" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Search Content</label>
|
||||
<description>Keyword(s) to search for on TV via Google Assistant</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightPower">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Ambilight Power</label>
|
||||
<description>Ambilight power. Turns ambilight on or off.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightHuePower">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Ambilight + Hue Power</label>
|
||||
<description>Ambilight + Hue power. Turns ambilight with connected Philips Hue Lamps on or off.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightLoungePower">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Ambilight Lounge Power</label>
|
||||
<description>Ambilight lounge power. Turns ambilight lounge on or off.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightStyle" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Ambilight Style</label>
|
||||
<description>Current ambilight style. Changing this to a value from the List, switches the ambilight style.
|
||||
</description>
|
||||
<category>Ambilight</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="FOLLOW_VIDEO STANDARD">FOLLOW_VIDEO STANDARD</option>
|
||||
<option value="FOLLOW_VIDEO NATURAL">FOLLOW_VIDEO NATURAL</option>
|
||||
<option value="FOLLOW_VIDEO IMMERSIVE">FOLLOW_VIDEO IMMERSIVE</option>
|
||||
<option value="FOLLOW_VIDEO VIVID">FOLLOW_VIDEO VIVID</option>
|
||||
<option value="FOLLOW_VIDEO GAME">FOLLOW_VIDEO GAME</option>
|
||||
<option value="FOLLOW_VIDEO COMFORT">FOLLOW_VIDEO COMFORT</option>
|
||||
<option value="FOLLOW_VIDEO RELAX">FOLLOW_VIDEO RELAX</option>
|
||||
|
||||
<option value="FOLLOW_AUDIO ENERGY_ADAPTIVE_BRIGHTNESS">FOLLOW_AUDIO ENERGY_ADAPTIVE_BRIGHTNESS</option>
|
||||
<option value="FOLLOW_AUDIO ENERGY_ADAPTIVE_COLORS">FOLLOW_AUDIO ENERGY_ADAPTIVE_COLORS</option>
|
||||
<option value="FOLLOW_AUDIO VU_METER">FOLLOW_AUDIO VU_METER</option>
|
||||
<option value="FOLLOW_AUDIO SPECTRUM_ANALYZER">FOLLOW_AUDIO SPECTRUM_ANALYZER</option>
|
||||
<option value="FOLLOW_AUDIO KNIGHT_RIDER_CLOCKWISE">FOLLOW_AUDIO KNIGHT_RIDER_CLOCKWISE</option>
|
||||
<option value="FOLLOW_AUDIO KNIGHT_RIDER_ALTERNATING">FOLLOW_AUDIO KNIGHT_RIDER_ALTERNATING</option>
|
||||
<option value="FOLLOW_AUDIO RANDOM_PIXEL_FLASH">FOLLOW_AUDIO RANDOM_PIXEL_FLASH</option>
|
||||
<option value="FOLLOW_AUDIO PARTY">FOLLOW_AUDIO PARTY</option>
|
||||
<option value="FOLLOW_AUDIO MODE_RANDOM">FOLLOW_AUDIO MODE_RANDOM</option>
|
||||
|
||||
<option value="FOLLOW_COLOR MANUAL_HUE">FOLLOW_COLOR MANUAL_HUE</option>
|
||||
<option value="FOLLOW_COLOR HOT_LAVA">FOLLOW_COLOR HOT_LAVA</option>
|
||||
<option value="FOLLOW_COLOR DEEP_WATER">FOLLOW_COLOR DEEP_WATER</option>
|
||||
<option value="FOLLOW_COLOR FRESH_NATURE">FOLLOW_COLOR FRESH_NATURE</option>
|
||||
<option value="FOLLOW_COLOR ISF">FOLLOW_COLOR ISF</option>
|
||||
<option value="FOLLOW_COLOR PTA_LOUNGE">FOLLOW_COLOR PTA_LOUNGE</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightColor" advanced="true">
|
||||
<item-type>Color</item-type>
|
||||
<label>All Ambilight</label>
|
||||
<description>Sets the Ambilight color for all sides.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightLeftColor" advanced="true">
|
||||
<item-type>Color</item-type>
|
||||
<label>Left Ambilight</label>
|
||||
<description>Sets the Ambilight color for the left side.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightRightColor" advanced="true">
|
||||
<item-type>Color</item-type>
|
||||
<label>Right Ambilight</label>
|
||||
<description>Sets the Ambilight color for the right side.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightTopColor" advanced="true">
|
||||
<item-type>Color</item-type>
|
||||
<label>Top Ambilight</label>
|
||||
<description>Sets the Ambilight color for the top.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ambilightBottomColor" advanced="true">
|
||||
<item-type>Color</item-type>
|
||||
<label>Bottom Ambilight</label>
|
||||
<description>Sets the Ambilight color for the bottom.</description>
|
||||
<category>Ambilight</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="brightness" advanced="true">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Brightness</label>
|
||||
<description>Brightness of the TV picture.</description>
|
||||
<category>Tv Picture</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="contrast" advanced="true">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Contrast</label>
|
||||
<description>Contrast of the TV picture.</description>
|
||||
<category>Tv Picture</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sharpness" advanced="true">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Sharpness</label>
|
||||
<description>Sharpness of the TV picture.</description>
|
||||
<category>Tv Picture</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
|
Loading…
Reference in New Issue
Block a user