mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[panasonicbdp] Initial contribution (#16122)
Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
This commit is contained in:
parent
f4596f581e
commit
db64df1687
@ -264,6 +264,7 @@
|
||||
/bundles/org.openhab.binding.oppo/ @mlobstein
|
||||
/bundles/org.openhab.binding.orbitbhyve/ @octa22
|
||||
/bundles/org.openhab.binding.orvibo/ @tavalin
|
||||
/bundles/org.openhab.binding.panasonicbdp/ @mlobstein
|
||||
/bundles/org.openhab.binding.paradoxalarm/ @theater
|
||||
/bundles/org.openhab.binding.pentair/ @jsjames
|
||||
/bundles/org.openhab.binding.phc/ @gnlpfjh
|
||||
|
@ -1306,6 +1306,11 @@
|
||||
<artifactId>org.openhab.binding.orvibo</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.panasonicbdp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.paradoxalarm</artifactId>
|
||||
|
13
bundles/org.openhab.binding.panasonicbdp/NOTICE
Normal file
13
bundles/org.openhab.binding.panasonicbdp/NOTICE
Normal file
@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
242
bundles/org.openhab.binding.panasonicbdp/README.md
Normal file
242
bundles/org.openhab.binding.panasonicbdp/README.md
Normal file
@ -0,0 +1,242 @@
|
||||
# Panasonic Blu-ray Player Binding
|
||||
|
||||
This binding connects Panasonic Blu-ray players from 2011/2012 and UHD Blu-ray players from 2018 to openHAB.
|
||||
**Supported Blu-ray models:** DMP-BDT110, DMP-BDT210, DMP-BDT310, DMP-BDT120, DMP-BDT220, DMP-BDT320, DMP-BBT01 & DMP-BDT500.
|
||||
**Supported UHD models:** DP-UB420/424, DP-UB820/824 & DP-UB9000/9004.
|
||||
|
||||
**Please note:** The player must be on the same IP subnet as the openHAB server for this binding to function.
|
||||
If the connection to the player originates from a different subnet, 404 response errors are sent in response to all requests.
|
||||
|
||||
To enable network remote control of the Blu-ray model players, configure the following settings:
|
||||
**Player Settings/Network/Network Settings/Remote Device Settings**
|
||||
Then make sure you have the following values set:
|
||||
**Remote Device Operation: On**
|
||||
**Registration Type: Automatic**
|
||||
|
||||
For the UHD models, Voice Control must be enabled for the player's http interface to be active:
|
||||
**Player Settings/Network/Voice Control: On**
|
||||
|
||||
To enable the binding to control the player while off (network active while off), Quick Start mode must be On as follows:
|
||||
**Player Settings/System/Quick Start: On**
|
||||
|
||||
**UHD Model Command Authentication:**
|
||||
The UHD models require authentication to use the control API.
|
||||
A player key must be specified in the thing configuration in order for the `power`, `button` and `control` channels to work.
|
||||
UHD model players that are patched do not require a player key.
|
||||
See the [AVForums discussions](https://www.avforums.com/forums/blu-ray-dvd-player-multiregion-hacks.126/) of the DP-UB420/820/9000 players for more information.
|
||||
|
||||
## Supported Things
|
||||
|
||||
There are two supported thing types, which represent either a BD player or a UHD player.
|
||||
A supported Blu-ray player uses the `bd-player` id and a supported UHD Blu-ray player uses the `uhd-player` id.
|
||||
Multiple Things can be added if more than one player is to be controlled.
|
||||
|
||||
## Discovery
|
||||
|
||||
Auto-discovery is supported if the player can be located on the local network using UPnP.
|
||||
Otherwise the thing must be manually added.
|
||||
|
||||
## Binding Configuration
|
||||
|
||||
The binding has no configuration options, all configuration is done at Thing level.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The Thing has a few configuration parameters:
|
||||
|
||||
| Name | Type | Description | Default | Required |
|
||||
|-----------|---------|-------------------------------------------------------------------------------------------------------|---------|----------|
|
||||
| hostName | text | The host name or IP address of the player. | N/A | yes |
|
||||
| refresh | integer | Overrides the refresh interval of the player status. Minimum interval is 5 seconds. | 5 | no |
|
||||
| playerKey | text | For UHD models, to enable authentication of control commands, a key for the player must be specified. | N/A | no |
|
||||
|
||||
Some notes:
|
||||
|
||||
* The control protocol of these players is undocumented and may not work consistently in all situations
|
||||
* The UHD models only support playback elapsed time (not title total time or chapter information) reporting
|
||||
* The time and chapter information is only available when playing a Blu-ray disc (not DVD or CD)
|
||||
* There are reports in forum postings that not all commands work on all of the older models (i.e.: Power does not work on DMP-BDT110)
|
||||
* Not all status information is available from all BD models (i.e.: playback elapsed time not reported by some models)
|
||||
|
||||
## Channels
|
||||
|
||||
The following channels are available:
|
||||
|
||||
| Channel ID | Item Type | Read/Write | Description |
|
||||
|-----------------|-------------|------------|---------------------------------------------------------------------------------------|
|
||||
| power | Switch | RW | Turn the power for the player ON or OFF. |
|
||||
| button | String | W | Sends a command to the player. See lists of available commands in Appendix A below. |
|
||||
| control | Player | RW | Control Playback e.g. Play/Pause/Next/Previous/FForward/Rewind. |
|
||||
| player-status | String | R | The player status i.e.: Power Off, Tray Open, Stopped, Playback, Pause Playback, etc. |
|
||||
| time-elapsed | Number:Time | R | The total number of seconds of playback time elapsed. |
|
||||
| time-total | Number:Time | R | The total length of the current playing title in seconds. Not on UHD models. |
|
||||
| chapter-current | Number | R | The current chapter number. Not on UHD models. |
|
||||
| chapter-total | Number | R | The total number of chapters in the current title. Not on UHD models. |
|
||||
|
||||
## Full Example
|
||||
|
||||
panasonicbdp.things:
|
||||
|
||||
```java
|
||||
panasonicbdp:bd-player:mybdplayer "My Blu-ray player" [ hostName="192.168.10.1", refresh=5 ]
|
||||
panasonicbdp:uhd-player:myuhdplayer "My UHD Blu-ray player" [ hostName="192.168.10.1", refresh=5, playerKey="ABCDEF1234567890abcdef0123456789" ]
|
||||
```
|
||||
|
||||
panasonicbdp.items:
|
||||
|
||||
```java
|
||||
// BD Player
|
||||
Switch Player_Power "Power" { channel="panasonicbdp:bd-player:mybdplayer:power" }
|
||||
String Player_Button "Send Command" { channel="panasonicbdp:bd-player:mybdplayer:button", autoupdate="false" }
|
||||
Player Player_Control "Control" { channel="panasonicbdp:bd-player:mybdplayer:control" }
|
||||
String Player_PlayerStatus "Status: [%s]" { channel="panasonicbdp:bd-player:mybdplayer:player-status" }
|
||||
Number:Time Player_TimeElapsed "Elapsed Time: [%d %unit%]" { channel="panasonicbdp:bd-player:mybdplayer:time-elapsed" }
|
||||
Number:Time Player_TimeTotal "Total Time: [%d %unit%]" { channel="panasonicbdp:bd-player:mybdplayer:time-total" }
|
||||
Number Player_ChapterCurrent "Current Chapter: [%d]" { channel="panasonicbdp:bd-player:mybdplayer:chapter-current" }
|
||||
Number Player_ChapterTotal "Total Chapters: [%d]" { channel="panasonicbdp:bd-player:mybdplayer:chapter-total" }
|
||||
|
||||
// UHD Player
|
||||
Switch Player_Power "Power" { channel="panasonicbdp:uhd-player:myuhdplayer:power" }
|
||||
String Player_Button "Send Command" { channel="panasonicbdp:uhd-player:myuhdplayer:button", autoupdate="false" }
|
||||
Player Player_Control "Control" { channel="panasonicbdp:uhd-player:myuhdplayer:control" }
|
||||
String Player_PlayerStatus "Status: [%s]" { channel="panasonicbdp:uhd-player:myuhdplayer:player-status" }
|
||||
Number:Time Player_TimeElapsed "Elapsed Time: [%d %unit%]" { channel="panasonicbdp:uhd-player:myuhdplayer:time-elapsed" }
|
||||
```
|
||||
|
||||
panasonicbdp.sitemap:
|
||||
|
||||
```perl
|
||||
sitemap panasonicbdp label="Panasonic Blu-ray" {
|
||||
Frame label="Blu-ray Player" {
|
||||
Switch item=Player_Power
|
||||
Selection item=Player_Button icon="player"
|
||||
Default item=Player_Control
|
||||
Text item=Player_PlayerStatus
|
||||
Text item=Player_TimeElapsed icon="time"
|
||||
// The following three channels are not available on UHD models
|
||||
Text item=Player_TimeTotal icon="time"
|
||||
Text item=Player_ChapterCurrent icon="time"
|
||||
Text item=Player_ChapterTotal icon="time"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Appendix A - 'button' channel command codes:
|
||||
|
||||
**List of available button commands for BD players:**
|
||||
|
||||
| Function | Command |
|
||||
|--------------------------|----------|
|
||||
| Power On | POWERON |
|
||||
| Power Off | POWEROFF |
|
||||
| Power Toggle | POWER |
|
||||
| Play | PLAYBACK |
|
||||
| Pause | PAUSE |
|
||||
| Stop | STOP |
|
||||
| Fast Forward | CUE |
|
||||
| Reverse | REV |
|
||||
| Skip Forward | SKIPFWD |
|
||||
| Skip Back | SKIPREV |
|
||||
| Open/Close | OP_CL |
|
||||
| Status | DSPSEL |
|
||||
| Top Menu | TITLE |
|
||||
| Pop-Up Menu | PUPMENU |
|
||||
| Up | UP |
|
||||
| Down | DOWN |
|
||||
| Left | LEFT |
|
||||
| Right | RIGHT |
|
||||
| OK | SELECT |
|
||||
| Submenu | MENU |
|
||||
| Return | RETURN |
|
||||
| 1 (@.) | D1 |
|
||||
| 2 (ABC) | D2 |
|
||||
| 3 (DEF) | D3 |
|
||||
| 4 (GHI) | D4 |
|
||||
| 5 (JKL) | D5 |
|
||||
| 6 (MNO) | D6 |
|
||||
| 7 (PQRS) | D7 |
|
||||
| 8 (TUV) | D8 |
|
||||
| 9 (WXYZ) | D9 |
|
||||
| 0 (-,) | D0 |
|
||||
| 12 | D12 |
|
||||
| * (Cancel) | CLEAR |
|
||||
| # ([_]) | SHARP |
|
||||
| Red | RED |
|
||||
| Green | GREEN |
|
||||
| Blue | BLUE |
|
||||
| Yellow | YELLOW |
|
||||
| Home | MLTNAVI |
|
||||
| Netflix (broken/too old) | NETFLIX |
|
||||
| VIERA Cast | V_CAST |
|
||||
| Network | NETWORK |
|
||||
| Setup | SETUP |
|
||||
| Exit | EXIT |
|
||||
| Audio | AUDIOSEL |
|
||||
| 3D | 3D |
|
||||
| Playback View (buttons not in other views)||
|
||||
| PIP | P_IN_P |
|
||||
| OSD (DISPLAY) | OSDONOFF |
|
||||
| Shuttle(BD) View (buttons not in other views)||
|
||||
| Swipe in CW circle | SHFWD2 |
|
||||
| Swipe in CCW circle | SHREV2 |
|
||||
|
||||
**List of available button commands for UHD players:**
|
||||
|
||||
| Function | Command |
|
||||
|------------------|------------------|
|
||||
| Power On | POWERON |
|
||||
| Power Off | POWEROFF |
|
||||
| Power Toggle | POWER |
|
||||
| Play | PLAYBACK |
|
||||
| Pause | PAUSE |
|
||||
| Stop | STOP |
|
||||
| Fast Forward | CUE |
|
||||
| Reverse | REV |
|
||||
| Skip Forward | SKIPFWD |
|
||||
| Skip Back | SKIPREV |
|
||||
| Manual Skip +60s | MNSKIP |
|
||||
| Manual Skip -10s | MNBACK |
|
||||
| Open/Close | OP_CL |
|
||||
| Status | DSPSEL |
|
||||
| Top Menu | TITLE |
|
||||
| Pop-up Menu | PUPMENU |
|
||||
| Up | UP |
|
||||
| Down | DOWN |
|
||||
| Left | LEFT |
|
||||
| Right | RIGHT |
|
||||
| OK | SELECT |
|
||||
| Submenu | MENU |
|
||||
| Return | RETURN |
|
||||
| 1 (@.) | D1 |
|
||||
| 2 (ABC) | D2 |
|
||||
| 3 (DEF) | D3 |
|
||||
| 4 (GHI) | D4 |
|
||||
| 5 (JKL) | D5 |
|
||||
| 6 (MNO) | D6 |
|
||||
| 7 (PQRS) | D7 |
|
||||
| 8 (TUV) | D8 |
|
||||
| 9 (WXYZ) | D9 |
|
||||
| 0 (-,) | D0 |
|
||||
| 12 | D12 |
|
||||
| * (Cancel) | CLEAR |
|
||||
| # ([_]) | SHARP |
|
||||
| Red | RED |
|
||||
| Green | GREEN |
|
||||
| Blue | BLUE |
|
||||
| Yellow | YELLOW |
|
||||
| Home | MLTNAVI |
|
||||
| Netflix | NETFLIX |
|
||||
| VIERA Cast | V_CAST |
|
||||
| Network | NETWORK |
|
||||
| Setup | SETUP |
|
||||
| Exit | EXIT |
|
||||
| Audio | AUDIOSEL |
|
||||
| Subtitle | TITLEONOFF |
|
||||
| Closed Caption | CLOSED_CAPTION |
|
||||
| Playback Info | PLAYBACKINFO |
|
||||
| HDR Picture Mode | HDR_PICTUREMODE |
|
||||
| Mirroring | MIRACAST |
|
||||
| Picture Setting | PICTURESETTINGS |
|
||||
| Sound Effect | SOUNDEFFECT |
|
||||
| High Clarity | HIGHCLARITY |
|
||||
| Skip The Trailer | SKIP_THE_TRAILER |
|
17
bundles/org.openhab.binding.panasonicbdp/pom.xml
Normal file
17
bundles/org.openhab.binding.panasonicbdp/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.panasonicbdp</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Panasonic Blu-ray Player Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.panasonicbdp-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-panasonicbdp" description="Panasonic Blu-ray Player 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.panasonicbdp/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -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.panasonicbdp.internal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.measure.Unit;
|
||||
import javax.measure.quantity.Time;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link PanaBlurayBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Michael Lobstein - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PanaBlurayBindingConstants {
|
||||
public static final String BINDING_ID = "panasonicbdp";
|
||||
public static final String PROPERTY_UUID = "uuid";
|
||||
public static final String PROPERTY_HOST_NAME = "hostName";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BD_PLAYER = new ThingTypeUID(BINDING_ID, "bd-player");
|
||||
public static final ThingTypeUID THING_TYPE_UHD_PLAYER = new ThingTypeUID(BINDING_ID, "uhd-player");
|
||||
|
||||
// List of all Channel id's
|
||||
public static final String POWER = "power";
|
||||
public static final String BUTTON = "button";
|
||||
public static final String CONTROL = "control";
|
||||
public static final String PLAYER_STATUS = "player-status";
|
||||
public static final String TIME_ELAPSED = "time-elapsed";
|
||||
public static final String TIME_TOTAL = "time-total";
|
||||
public static final String CHAPTER_CURRENT = "chapter-current";
|
||||
public static final String CHAPTER_TOTAL = "chapter-total";
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_BD_PLAYER,
|
||||
THING_TYPE_UHD_PLAYER);
|
||||
|
||||
// Units of measurement of the data delivered by the API
|
||||
public static final Unit<Time> API_SECONDS_UNIT = Units.SECOND;
|
||||
|
||||
public static final int DEFAULT_REFRESH_PERIOD_SEC = 5;
|
||||
public static final String USER_AGENT = "MEI-LAN-REMOTE-CALL";
|
||||
public static final String SHA_256_ALGORITHM = "SHA-256";
|
||||
public static final String CRLF = "\r\n";
|
||||
public static final String COMMA = ",";
|
||||
public static final String STOP_STATUS = "00";
|
||||
public static final String OPEN_STATUS = "01";
|
||||
public static final String OFF_STATUS = "07";
|
||||
public static final String PLAY_STATUS = "08";
|
||||
public static final String PAUSE_STATUS = "09";
|
||||
public static final String EMPTY = "";
|
||||
public static final String PLAYER_CMD_ERR = "52,\"";
|
||||
|
||||
public static final String CMD_POWER = "POWER";
|
||||
public static final String CMD_PLAYBACK = "PLAYBACK";
|
||||
public static final String CMD_PAUSE = "PAUSE";
|
||||
public static final String CMD_SKIPFWD = "SKIPFWD";
|
||||
public static final String CMD_SKIPREV = "SKIPREV";
|
||||
public static final String CMD_CUE = "CUE";
|
||||
public static final String CMD_REV = "REV";
|
||||
|
||||
// Map the player status numbers to the corresponding i18n translation file keys
|
||||
public static final Map<String, String> STATUS_MAP = Map.of(STOP_STATUS, "stop", OPEN_STATUS, "open", "02",
|
||||
"reverse", "05", "forward", "06", "slowfwd", OFF_STATUS, "off", PLAY_STATUS, "play", PAUSE_STATUS, "pause",
|
||||
"86", "slowrev");
|
||||
|
||||
// pre-define the POST body for status update calls
|
||||
public static final Fields REVIEW_POST_CMD = new Fields();
|
||||
static {
|
||||
REVIEW_POST_CMD.add("cCMD_REVIEW.x", "100");
|
||||
REVIEW_POST_CMD.add("cCMD_REVIEW.y", "100");
|
||||
}
|
||||
|
||||
public static final Fields PST_POST_CMD = new Fields();
|
||||
static {
|
||||
PST_POST_CMD.add("cCMD_PST.x", "100");
|
||||
PST_POST_CMD.add("cCMD_PST.y", "100");
|
||||
}
|
||||
|
||||
public static final Fields GET_STATUS_POST_CMD = new Fields();
|
||||
static {
|
||||
GET_STATUS_POST_CMD.add("cCMD_GET_STATUS.x", "100");
|
||||
GET_STATUS_POST_CMD.add("cCMD_GET_STATUS.y", "100");
|
||||
}
|
||||
|
||||
public static final Fields GET_NONCE_CMD = new Fields();
|
||||
static {
|
||||
GET_NONCE_CMD.add("SID", "1234ABCD");
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* 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.panasonicbdp.internal;
|
||||
|
||||
import static org.openhab.binding.panasonicbdp.internal.PanaBlurayBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link PanaBlurayConfiguration} is the class used to match the
|
||||
* thing configuration.
|
||||
*
|
||||
* @author Michael Lobstein - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PanaBlurayConfiguration {
|
||||
public String hostName = EMPTY;
|
||||
public int refresh = DEFAULT_REFRESH_PERIOD_SEC;
|
||||
public String playerKey = EMPTY;
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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.panasonicbdp.internal;
|
||||
|
||||
import static org.openhab.binding.panasonicbdp.internal.PanaBlurayBindingConstants.SUPPORTED_THING_TYPES_UIDS;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.panasonicbdp.internal.handler.PanaBlurayHandler;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link PanaBlurayHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Michael Lobstein - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.panasonicbdp")
|
||||
public class PanaBlurayHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final TranslationProvider translationProvider;
|
||||
private final LocaleProvider localeProvider;
|
||||
|
||||
@Activate
|
||||
public PanaBlurayHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
||||
@Reference TranslationProvider translationProvider, @Reference LocaleProvider localeProvider) {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
this.translationProvider = translationProvider;
|
||||
this.localeProvider = localeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
if (SUPPORTED_THING_TYPES_UIDS.contains(thing.getThingTypeUID())) {
|
||||
return new PanaBlurayHandler(thing, httpClient, translationProvider, localeProvider);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 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.panasonicbdp.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.panasonicbdp.internal.PanaBlurayBindingConstants.*;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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.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;
|
||||
|
||||
/**
|
||||
*
|
||||
* Discovery Service for Panasonic Blu-ray Players.
|
||||
*
|
||||
* @author Michael Lobstein - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(immediate = true)
|
||||
public class PanaBlurayDiscoveryParticipant implements UpnpDiscoveryParticipant {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PanaBlurayDiscoveryParticipant.class);
|
||||
|
||||
private static final String MANUFACTURER = "Panasonic";
|
||||
private static final String UB_PREFIX = "UB";
|
||||
private static final String UPNP_RESULT_MEDIA_RENDERER = "MediaRenderer";
|
||||
|
||||
private static final List<String> MODELS = List.of("BDT110", "BDT210", "BDT310", "BDT120", "BDT220", "BDT320",
|
||||
"BBT01", "BDT500", "UB420", "UB424", "UB820", "UB824", "UB9000", "UB9004");
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return SUPPORTED_THING_TYPES_UIDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
|
||||
final ThingUID uid = getThingUID(device);
|
||||
if (uid != null) {
|
||||
final Map<String, Object> properties = new HashMap<>(2);
|
||||
|
||||
final URL url = device.getIdentity().getDescriptorURL();
|
||||
final String label = device.getDetails().getFriendlyName();
|
||||
|
||||
properties.put(PROPERTY_UUID, uid.getId());
|
||||
properties.put(PROPERTY_HOST_NAME, url.getHost());
|
||||
|
||||
final DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withRepresentationProperty(PROPERTY_UUID).withLabel(label).build();
|
||||
|
||||
logger.debug("Created a DiscoveryResult for device '{}' with UID '{}'", label, uid.getId());
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
||||
if (device.getDetails().getManufacturerDetails().getManufacturer() != null
|
||||
&& device.getDetails().getModelDetails().getModelNumber() != null) {
|
||||
if (device.getDetails().getManufacturerDetails().getManufacturer().startsWith(MANUFACTURER)) {
|
||||
logger.debug("Panasonic UPNP device found at {}", device.getIdentity().getDescriptorURL().getHost());
|
||||
String id = device.getIdentity().getUdn().getIdentifierString().replaceAll(":", EMPTY);
|
||||
|
||||
// Shorten to just the mac address, ie: 4D454930-0600-1000-8000-80C755A1D630 -> 80C755A1D630
|
||||
if (id.length() > 12) {
|
||||
id = id.substring(id.length() - 12);
|
||||
}
|
||||
|
||||
final String modelNumber = device.getDetails().getModelDetails().getModelNumber();
|
||||
|
||||
if (MODELS.stream().anyMatch(supportedModel -> (modelNumber.contains(supportedModel)))) {
|
||||
if (modelNumber.contains(UB_PREFIX)) {
|
||||
// UHD (UB-nnnn) players return multiple UPNP results, ignore all but the 'MediaRenderer' result
|
||||
if (UPNP_RESULT_MEDIA_RENDERER.equals(device.getType().getType())) {
|
||||
return new ThingUID(THING_TYPE_UHD_PLAYER, id);
|
||||
}
|
||||
} else {
|
||||
return new ThingUID(THING_TYPE_BD_PLAYER, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,391 @@
|
||||
/**
|
||||
* 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.panasonicbdp.internal.handler;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpStatus.OK_200;
|
||||
import static org.openhab.binding.panasonicbdp.internal.PanaBlurayBindingConstants.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.util.FormContentProvider;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
import org.openhab.binding.panasonicbdp.internal.PanaBlurayConfiguration;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.NextPreviousType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PlayPauseType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.RewindFastforwardType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
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.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link PanaBlurayHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Michael Lobstein - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PanaBlurayHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(PanaBlurayHandler.class);
|
||||
private final HttpClient httpClient;
|
||||
private static final int REQUEST_TIMEOUT = 5000;
|
||||
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
|
||||
private String urlStr = "http://%host%/WAN/dvdr/dvdr_ctrl.cgi";
|
||||
private String nonceUrlStr = "http://%host%/cgi-bin/get_nonce.cgi";
|
||||
private int refreshInterval = DEFAULT_REFRESH_PERIOD_SEC;
|
||||
private String playerMode = EMPTY;
|
||||
private String playerKey = EMPTY;
|
||||
private boolean debounce = true;
|
||||
private boolean authEnabled = false;
|
||||
private Object sequenceLock = new Object();
|
||||
private ThingTypeUID thingTypeUID = THING_TYPE_BD_PLAYER;
|
||||
|
||||
private final TranslationProvider translationProvider;
|
||||
private final LocaleProvider localeProvider;
|
||||
private final @Nullable Bundle bundle;
|
||||
|
||||
public PanaBlurayHandler(Thing thing, HttpClient httpClient, @Reference TranslationProvider translationProvider,
|
||||
@Reference LocaleProvider localeProvider) {
|
||||
super(thing);
|
||||
this.httpClient = httpClient;
|
||||
this.translationProvider = translationProvider;
|
||||
this.localeProvider = localeProvider;
|
||||
this.bundle = FrameworkUtil.getBundle(PanaBlurayHandler.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing Panasonic Blu-ray Player handler.");
|
||||
PanaBlurayConfiguration config = getConfigAs(PanaBlurayConfiguration.class);
|
||||
|
||||
this.thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
final String host = config.hostName;
|
||||
final String playerKey = config.playerKey;
|
||||
|
||||
if (!host.isBlank()) {
|
||||
urlStr = urlStr.replace("%host%", host);
|
||||
nonceUrlStr = nonceUrlStr.replace("%host%", host);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/error.hostname");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!playerKey.isBlank()) {
|
||||
if (playerKey.length() != 32) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/error.keyerror");
|
||||
return;
|
||||
}
|
||||
this.playerKey = playerKey;
|
||||
authEnabled = true;
|
||||
}
|
||||
refreshInterval = config.refresh;
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
startAutomaticRefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the job to periodically get a status update from the player
|
||||
*/
|
||||
private void startAutomaticRefresh() {
|
||||
ScheduledFuture<?> refreshJob = this.refreshJob;
|
||||
if (refreshJob == null || refreshJob.isCancelled()) {
|
||||
this.refreshJob = scheduler.scheduleWithFixedDelay(this::refreshPlayerStatus, 0, refreshInterval,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends commands to the player to get status information and updates the channels
|
||||
*/
|
||||
private void refreshPlayerStatus() {
|
||||
final String[] playerStatusRespArr = sendCommand(REVIEW_POST_CMD, urlStr).split(CRLF);
|
||||
|
||||
if (playerStatusRespArr.length == 1 && playerStatusRespArr[0].isBlank()) {
|
||||
return;
|
||||
} else if (playerStatusRespArr.length >= 2) {
|
||||
// CMD_REVIEW response second line, 4th group is the status:
|
||||
// F,,,07,00,,8,,,,1,000:00,,05:10,F,FF:FF,0000,0000,0000,0000
|
||||
final String playerStatusArr[] = playerStatusRespArr[1].split(COMMA);
|
||||
|
||||
if (playerStatusArr.length >= 4) {
|
||||
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
// update playerMode if different
|
||||
if (!playerMode.equals(playerStatusArr[3])) {
|
||||
playerMode = playerStatusArr[3];
|
||||
final String i18nKey = STATUS_MAP.get(playerMode) != null ? STATUS_MAP.get(playerMode) : "unknown";
|
||||
updateState(PLAYER_STATUS, new StringType(translationProvider.getText(bundle, "status." + i18nKey,
|
||||
i18nKey, localeProvider.getLocale())));
|
||||
updateState(CONTROL, PLAY_STATUS.equals(playerMode) ? PlayPauseType.PLAY : PlayPauseType.PAUSE);
|
||||
|
||||
// playback stopped, tray open, or power switched off, zero out time and chapters
|
||||
if (!isPlayingMode()) {
|
||||
updateState(TIME_ELAPSED, UnDefType.UNDEF);
|
||||
updateState(TIME_TOTAL, UnDefType.UNDEF);
|
||||
updateState(CHAPTER_CURRENT, UnDefType.UNDEF);
|
||||
updateState(CHAPTER_TOTAL, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
|
||||
if (debounce) {
|
||||
updateState(POWER, OnOffType.from(!OFF_STATUS.equals(playerMode)));
|
||||
}
|
||||
debounce = true;
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "@text/error.polling");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "@text/error.polling");
|
||||
return;
|
||||
}
|
||||
|
||||
// if time/chapter channels are not linked or player is stopped or paused there is no need to make extra calls
|
||||
if (isAnyStatusChannelsLinked() && isPlayingMode() && !PAUSE_STATUS.equals(playerMode)) {
|
||||
final String[] pstRespArr = sendCommand(PST_POST_CMD, urlStr).split(CRLF);
|
||||
|
||||
if (pstRespArr.length >= 2) {
|
||||
// CMD_PST response second line: 1,1543,0,00000000 (play mode, current time, ?, ?)
|
||||
final String pstArr[] = pstRespArr[1].split(COMMA);
|
||||
|
||||
if (pstArr.length >= 2) {
|
||||
try {
|
||||
updateState(TIME_ELAPSED, new QuantityType<>(Integer.parseInt(pstArr[1]), API_SECONDS_UNIT));
|
||||
} catch (NumberFormatException nfe) {
|
||||
logger.debug("Error parsing time elapsed integer in CMD_PST message: {}", pstRespArr[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only BD players support the CMD_GET_STATUS command, it returns a 404 error on UHD models
|
||||
if (THING_TYPE_BD_PLAYER.equals(thingTypeUID)
|
||||
&& (isLinked(TIME_TOTAL) || isLinked(CHAPTER_CURRENT) || isLinked(CHAPTER_TOTAL))) {
|
||||
final String[] getStatusRespArr = sendCommand(GET_STATUS_POST_CMD, urlStr).split(CRLF);
|
||||
|
||||
if (getStatusRespArr.length >= 2) {
|
||||
// CMD_GET_STATUS response second line: 1,0,0,1,5999,61440,500,1,16,00000000
|
||||
// (?, ?, ?, cur time, total time, title#?, ?, chapter #, total chapter, ?)
|
||||
final String getStatusArr[] = getStatusRespArr[1].split(COMMA);
|
||||
|
||||
if (getStatusArr.length >= 10) {
|
||||
try {
|
||||
updateState(TIME_TOTAL,
|
||||
new QuantityType<>(Integer.parseInt(getStatusArr[4]), API_SECONDS_UNIT));
|
||||
updateState(CHAPTER_CURRENT, new DecimalType(Integer.parseInt(getStatusArr[7])));
|
||||
updateState(CHAPTER_TOTAL, new DecimalType(Integer.parseInt(getStatusArr[8])));
|
||||
} catch (NumberFormatException nfe) {
|
||||
logger.debug("Error parsing integer in CMD_GET_STATUS message: {}", getStatusRespArr[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
ScheduledFuture<?> refreshJob = this.refreshJob;
|
||||
if (refreshJob != null) {
|
||||
refreshJob.cancel(true);
|
||||
this.refreshJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
synchronized (sequenceLock) {
|
||||
if (command instanceof RefreshType) {
|
||||
logger.debug("Unsupported refresh command: {}", command);
|
||||
} else if (BUTTON.equals(channelUID.getId()) || POWER.equals(channelUID.getId())
|
||||
|| CONTROL.equals(channelUID.getId())) {
|
||||
final String commandStr;
|
||||
if (command instanceof OnOffType) {
|
||||
commandStr = CMD_POWER + command; // e.g. POWERON or POWEROFF
|
||||
// if the power is switched on while the polling is running, the switch could bounce back to off,
|
||||
// set this flag to stop the first polling event from changing the state of the switch to give the
|
||||
// player time to start up and report the correct power status on the next poll
|
||||
debounce = false;
|
||||
} else if (command instanceof PlayPauseType || command instanceof NextPreviousType
|
||||
|| command instanceof RewindFastforwardType) {
|
||||
if (command == PlayPauseType.PLAY) {
|
||||
commandStr = CMD_PLAYBACK;
|
||||
} else if (command == PlayPauseType.PAUSE) {
|
||||
commandStr = CMD_PAUSE;
|
||||
} else if (command == NextPreviousType.NEXT) {
|
||||
commandStr = CMD_SKIPFWD;
|
||||
} else if (command == NextPreviousType.PREVIOUS) {
|
||||
commandStr = CMD_SKIPREV;
|
||||
} else if (command == RewindFastforwardType.FASTFORWARD) {
|
||||
commandStr = CMD_CUE;
|
||||
} else if (command == RewindFastforwardType.REWIND) {
|
||||
commandStr = CMD_REV;
|
||||
} else {
|
||||
logger.debug("Invalid control command: {}", command);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
commandStr = command.toString();
|
||||
}
|
||||
|
||||
// build the fields to POST the RC_ command string
|
||||
Fields fields = new Fields();
|
||||
fields.add("cCMD_RC_" + commandStr + ".x", "100");
|
||||
fields.add("cCMD_RC_" + commandStr + ".y", "100");
|
||||
|
||||
// if command authentication enabled, get nonce to create authKey and add it to the POST fields
|
||||
if (authEnabled) {
|
||||
final String nonce = sendCommand(GET_NONCE_CMD, nonceUrlStr).trim();
|
||||
if (nonce.isBlank()) {
|
||||
return;
|
||||
} else if (nonce.length() != 32) {
|
||||
logger.debug("Error retrieving nonce, message was: {}", nonce);
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "@text/error.nonce");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
fields.add("cAUTH_FORM", playerKey.substring(0, playerKey.contains("2") ? 2 : 3));
|
||||
fields.add("cAUTH_VALUE", getAuthKey(playerKey + nonce));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.debug("Error creating auth key: {}", e.getMessage());
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "@text/error.authkey");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// send the command to the player
|
||||
sendCommand(fields, urlStr);
|
||||
} else {
|
||||
logger.debug("Unsupported command: {}", command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to the player using a pre-built post body
|
||||
*
|
||||
* @param fields a pre-built post body to send to the player
|
||||
* @param url the url to receive the command
|
||||
* @return the response string from the player
|
||||
*/
|
||||
private String sendCommand(Fields fields, String url) {
|
||||
try {
|
||||
logger.trace("POST url: {}, data: {}", url, fields);
|
||||
ContentResponse response = httpClient.POST(url).agent(USER_AGENT).method(HttpMethod.POST)
|
||||
.content(new FormContentProvider(fields)).timeout(REQUEST_TIMEOUT, TimeUnit.MILLISECONDS).send();
|
||||
|
||||
final String output = response.getContentAsString();
|
||||
logger.trace("Response status: {}, response: {}", response.getStatus(), output);
|
||||
|
||||
if (response.getStatus() != OK_200) {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "@text/error.polling");
|
||||
return EMPTY;
|
||||
} else if (output.startsWith(PLAYER_CMD_ERR)) {
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, "@text/error.invalid");
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
return output;
|
||||
} catch (TimeoutException | ExecutionException e) {
|
||||
logger.debug("Error executing command: {}, {}", fields.getNames().iterator().next(), e.getMessage());
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "@text/error.exception");
|
||||
} catch (InterruptedException e) {
|
||||
logger.debug("InterruptedException executing command: {}, {}", fields.getNames().iterator().next(),
|
||||
e.getMessage());
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the player is currently in a playing mode.
|
||||
*/
|
||||
private boolean isPlayingMode() {
|
||||
return !(STOP_STATUS.equals(playerMode) || OPEN_STATUS.equals(playerMode) || OFF_STATUS.equals(playerMode));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if any of the time or chapter channels are linked depending on which thing type is used.
|
||||
*/
|
||||
private boolean isAnyStatusChannelsLinked() {
|
||||
if (THING_TYPE_BD_PLAYER.equals(thingTypeUID)) {
|
||||
return isLinked(TIME_ELAPSED) || isLinked(TIME_TOTAL) || isLinked(CHAPTER_CURRENT)
|
||||
|| isLinked(CHAPTER_TOTAL);
|
||||
}
|
||||
return isLinked(TIME_ELAPSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLinked(String channelName) {
|
||||
final Channel channel = this.thing.getChannel(channelName);
|
||||
return channel != null ? isLinked(channel.getUID()) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SHA-256 hash of the input string
|
||||
*
|
||||
* @param input the input string to generate the hash from
|
||||
* @return the 256 bit hash string
|
||||
*/
|
||||
private String getAuthKey(String input) throws NoSuchAlgorithmException {
|
||||
final MessageDigest md = MessageDigest.getInstance(SHA_256_ALGORITHM);
|
||||
final byte[] hash = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
// convert byte array into signum representation
|
||||
final BigInteger number = new BigInteger(1, hash);
|
||||
|
||||
// convert message digest into hex value
|
||||
final StringBuilder hexString = new StringBuilder(number.toString(16));
|
||||
|
||||
// pad with leading zeros
|
||||
while (hexString.length() < 32) {
|
||||
hexString.insert(0, "0");
|
||||
}
|
||||
|
||||
return hexString.toString().toUpperCase();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="panasonicbdp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>Panasonic Blu-ray Player Binding</name>
|
||||
<description>Controls Panasonic 2011/2012 Blu-ray and 2018 UHD Blu-ray Players</description>
|
||||
<connection>local</connection>
|
||||
|
||||
<discovery-methods>
|
||||
<discovery-method>
|
||||
<service-type>upnp</service-type>
|
||||
<match-properties>
|
||||
<match-property>
|
||||
<name>manufacturer</name>
|
||||
<regex>(?i)Panasonic</regex>
|
||||
</match-property>
|
||||
<match-property>
|
||||
<name>modelName</name>
|
||||
<regex>(?i)BDT[1-3][1-2]0|BBT01|BDT500|UB[4|8]2[0|4]|UB900[0|4]</regex>
|
||||
</match-property>
|
||||
</match-properties>
|
||||
</discovery-method>
|
||||
</discovery-methods>
|
||||
|
||||
</addon:addon>
|
@ -0,0 +1,175 @@
|
||||
# add-on
|
||||
|
||||
addon.panasonicbdp.name = Panasonic Blu-ray Player Binding
|
||||
addon.panasonicbdp.description = Controls Panasonic 2011/2012 Blu-ray and 2018 UHD Blu-ray Players
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.panasonicbdp.bd-player.label = Panasonic Blu-ray Player
|
||||
thing-type.panasonicbdp.bd-player.description = Panasonic Blu-ray Player model DMP-BDT[1-3]10, DMP-BDT[1-3]20, DMP-BBT01 or DMP-BDT500
|
||||
thing-type.panasonicbdp.bd-player.channel.power.label = Power
|
||||
thing-type.panasonicbdp.bd-player.channel.power.description = Turn the power for the player on or off
|
||||
thing-type.panasonicbdp.uhd-player.label = Panasonic UHD Blu-ray Player
|
||||
thing-type.panasonicbdp.uhd-player.description = Panasonic UHD Blu-ray model DP-UB420/424, DP-UB820/824 or DP-UB9000/9004
|
||||
thing-type.panasonicbdp.uhd-player.channel.power.label = Power
|
||||
thing-type.panasonicbdp.uhd-player.channel.power.description = Turn the power for the player on or off
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.panasonicbdp.bd-player.hostName.label = Player Host Name/IP Address
|
||||
thing-type.config.panasonicbdp.bd-player.hostName.description = Host Name or IP Address of the player
|
||||
thing-type.config.panasonicbdp.bd-player.refresh.label = Refresh Interval
|
||||
thing-type.config.panasonicbdp.bd-player.refresh.description = Specifies the refresh interval in seconds
|
||||
thing-type.config.panasonicbdp.uhd-player.hostName.label = Player Host Name/IP Address
|
||||
thing-type.config.panasonicbdp.uhd-player.hostName.description = Host Name or IP Address of the player
|
||||
thing-type.config.panasonicbdp.uhd-player.playerKey.label = Player Key
|
||||
thing-type.config.panasonicbdp.uhd-player.playerKey.description = To enable authentication of control commands, a key for the player must be specified
|
||||
thing-type.config.panasonicbdp.uhd-player.refresh.label = Refresh Interval
|
||||
thing-type.config.panasonicbdp.uhd-player.refresh.description = Specifies the refresh interval in seconds
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.panasonicbdp.button.label = Remote Button
|
||||
channel-type.panasonicbdp.button.description = A remote button press to send to the player
|
||||
channel-type.panasonicbdp.button.state.option.POWERON = Power On
|
||||
channel-type.panasonicbdp.button.state.option.POWEROFF = Power Off
|
||||
channel-type.panasonicbdp.button.state.option.POWER = Power Toggle
|
||||
channel-type.panasonicbdp.button.state.option.PLAYBACK = Play
|
||||
channel-type.panasonicbdp.button.state.option.PAUSE = Pause
|
||||
channel-type.panasonicbdp.button.state.option.STOP = Stop
|
||||
channel-type.panasonicbdp.button.state.option.CUE = Fast Forward
|
||||
channel-type.panasonicbdp.button.state.option.REV = Reverse
|
||||
channel-type.panasonicbdp.button.state.option.SKIPFWD = Skip Forward
|
||||
channel-type.panasonicbdp.button.state.option.SKIPREV = Skip Back
|
||||
channel-type.panasonicbdp.button.state.option.OP_CL = Open/Close
|
||||
channel-type.panasonicbdp.button.state.option.DSPSEL = Status
|
||||
channel-type.panasonicbdp.button.state.option.TITLE = Top Menu
|
||||
channel-type.panasonicbdp.button.state.option.PUPMENU = Pop-up Menu
|
||||
channel-type.panasonicbdp.button.state.option.UP = Up
|
||||
channel-type.panasonicbdp.button.state.option.DOWN = Down
|
||||
channel-type.panasonicbdp.button.state.option.LEFT = Left
|
||||
channel-type.panasonicbdp.button.state.option.RIGHT = Right
|
||||
channel-type.panasonicbdp.button.state.option.SELECT = OK
|
||||
channel-type.panasonicbdp.button.state.option.MENU = Submenu
|
||||
channel-type.panasonicbdp.button.state.option.RETURN = Return
|
||||
channel-type.panasonicbdp.button.state.option.D1 = 1
|
||||
channel-type.panasonicbdp.button.state.option.D2 = 2
|
||||
channel-type.panasonicbdp.button.state.option.D3 = 3
|
||||
channel-type.panasonicbdp.button.state.option.D4 = 4
|
||||
channel-type.panasonicbdp.button.state.option.D5 = 5
|
||||
channel-type.panasonicbdp.button.state.option.D6 = 6
|
||||
channel-type.panasonicbdp.button.state.option.D7 = 7
|
||||
channel-type.panasonicbdp.button.state.option.D8 = 8
|
||||
channel-type.panasonicbdp.button.state.option.D9 = 9
|
||||
channel-type.panasonicbdp.button.state.option.D0 = 0
|
||||
channel-type.panasonicbdp.button.state.option.D12 = 12
|
||||
channel-type.panasonicbdp.button.state.option.CLEAR = Cancel
|
||||
channel-type.panasonicbdp.button.state.option.SHARP = #
|
||||
channel-type.panasonicbdp.button.state.option.RED = Red
|
||||
channel-type.panasonicbdp.button.state.option.GREEN = Green
|
||||
channel-type.panasonicbdp.button.state.option.BLUE = Blue
|
||||
channel-type.panasonicbdp.button.state.option.YELLOW = Yellow
|
||||
channel-type.panasonicbdp.button.state.option.MLTNAVI = Home
|
||||
channel-type.panasonicbdp.button.state.option.V_CAST = Viera Cast
|
||||
channel-type.panasonicbdp.button.state.option.NETWORK = Network
|
||||
channel-type.panasonicbdp.button.state.option.SETUP = Setup
|
||||
channel-type.panasonicbdp.button.state.option.EXIT = Exit
|
||||
channel-type.panasonicbdp.button.state.option.AUDIOSEL = Audio
|
||||
channel-type.panasonicbdp.button.state.option.3D = 3D
|
||||
channel-type.panasonicbdp.button.state.option.P_IN_P = PIP
|
||||
channel-type.panasonicbdp.button.state.option.OSDONOFF = OSD
|
||||
channel-type.panasonicbdp.button.state.option.SHFWD2 = (swipe in CW circle)
|
||||
channel-type.panasonicbdp.button.state.option.SHREV2 = (swipe in CCW circle)
|
||||
channel-type.panasonicbdp.chapter-current.label = Current Chapter
|
||||
channel-type.panasonicbdp.chapter-current.description = The current chapter number
|
||||
channel-type.panasonicbdp.chapter-total.label = Total Chapters
|
||||
channel-type.panasonicbdp.chapter-total.description = The total number of chapters in the current title
|
||||
channel-type.panasonicbdp.control.label = Control
|
||||
channel-type.panasonicbdp.control.description = Transport Controls e.g. Play/Pause/Next/Previous/FForward/Rewind
|
||||
channel-type.panasonicbdp.player-status.label = Player Status
|
||||
channel-type.panasonicbdp.player-status.description = The current player status
|
||||
channel-type.panasonicbdp.time-elapsed.label = Playback Time
|
||||
channel-type.panasonicbdp.time-elapsed.description = The current playback time elapsed
|
||||
channel-type.panasonicbdp.time-total.label = Total Time
|
||||
channel-type.panasonicbdp.time-total.description = The total length of the current title
|
||||
channel-type.panasonicbdp.uhd-button.label = Remote Button
|
||||
channel-type.panasonicbdp.uhd-button.description = A remote button press to send to the player
|
||||
channel-type.panasonicbdp.uhd-button.state.option.POWERON = Power On
|
||||
channel-type.panasonicbdp.uhd-button.state.option.POWEROFF = Power Off
|
||||
channel-type.panasonicbdp.uhd-button.state.option.POWER = Power Toggle
|
||||
channel-type.panasonicbdp.uhd-button.state.option.PLAYBACK = Play
|
||||
channel-type.panasonicbdp.uhd-button.state.option.PAUSE = Pause
|
||||
channel-type.panasonicbdp.uhd-button.state.option.STOP = Stop
|
||||
channel-type.panasonicbdp.uhd-button.state.option.CUE = Fast Forward
|
||||
channel-type.panasonicbdp.uhd-button.state.option.REV = Reverse
|
||||
channel-type.panasonicbdp.uhd-button.state.option.SKIPFWD = Skip Forward
|
||||
channel-type.panasonicbdp.uhd-button.state.option.SKIPREV = Skip Back
|
||||
channel-type.panasonicbdp.uhd-button.state.option.MNSKIP = Manual Skip +60s
|
||||
channel-type.panasonicbdp.uhd-button.state.option.MNBACK = Manual Skip -10s
|
||||
channel-type.panasonicbdp.uhd-button.state.option.OP_CL = Open/Close
|
||||
channel-type.panasonicbdp.uhd-button.state.option.DSPSEL = Status
|
||||
channel-type.panasonicbdp.uhd-button.state.option.TITLE = Top Menu
|
||||
channel-type.panasonicbdp.uhd-button.state.option.PUPMENU = Pop-up Menu
|
||||
channel-type.panasonicbdp.uhd-button.state.option.UP = Up
|
||||
channel-type.panasonicbdp.uhd-button.state.option.DOWN = Down
|
||||
channel-type.panasonicbdp.uhd-button.state.option.LEFT = Left
|
||||
channel-type.panasonicbdp.uhd-button.state.option.RIGHT = Right
|
||||
channel-type.panasonicbdp.uhd-button.state.option.SELECT = OK
|
||||
channel-type.panasonicbdp.uhd-button.state.option.MENU = Submenu
|
||||
channel-type.panasonicbdp.uhd-button.state.option.RETURN = Return
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D1 = 1
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D2 = 2
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D3 = 3
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D4 = 4
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D5 = 5
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D6 = 6
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D7 = 7
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D8 = 8
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D9 = 9
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D0 = 0
|
||||
channel-type.panasonicbdp.uhd-button.state.option.D12 = 12
|
||||
channel-type.panasonicbdp.uhd-button.state.option.CLEAR = Clear
|
||||
channel-type.panasonicbdp.uhd-button.state.option.SHARP = #
|
||||
channel-type.panasonicbdp.uhd-button.state.option.RED = Red
|
||||
channel-type.panasonicbdp.uhd-button.state.option.GREEN = Green
|
||||
channel-type.panasonicbdp.uhd-button.state.option.BLUE = Blue
|
||||
channel-type.panasonicbdp.uhd-button.state.option.YELLOW = Yellow
|
||||
channel-type.panasonicbdp.uhd-button.state.option.MLTNAVI = Home
|
||||
channel-type.panasonicbdp.uhd-button.state.option.NETFLIX = Netflix
|
||||
channel-type.panasonicbdp.uhd-button.state.option.V_CAST = Viera Cast
|
||||
channel-type.panasonicbdp.uhd-button.state.option.NETWORK = Network
|
||||
channel-type.panasonicbdp.uhd-button.state.option.SETUP = Setup
|
||||
channel-type.panasonicbdp.uhd-button.state.option.EXIT = Exit
|
||||
channel-type.panasonicbdp.uhd-button.state.option.AUDIOSEL = Audio
|
||||
channel-type.panasonicbdp.uhd-button.state.option.TITLEONOFF = Subtitle
|
||||
channel-type.panasonicbdp.uhd-button.state.option.CLOSED_CAPTION = Closed Caption
|
||||
channel-type.panasonicbdp.uhd-button.state.option.PLAYBACKINFO = Playback Info
|
||||
channel-type.panasonicbdp.uhd-button.state.option.HDR_PICTUREMODE = HDR Picture Mode
|
||||
channel-type.panasonicbdp.uhd-button.state.option.MIRACAST = Mirroring
|
||||
channel-type.panasonicbdp.uhd-button.state.option.PICTURESETTINGS = Picture Setting
|
||||
channel-type.panasonicbdp.uhd-button.state.option.SOUNDEFFECT = Sound Effect
|
||||
channel-type.panasonicbdp.uhd-button.state.option.HIGHCLARITY = High Clarity
|
||||
channel-type.panasonicbdp.uhd-button.state.option.SKIP_THE_TRAILER = Skip The Trailer
|
||||
|
||||
# player status descriptions
|
||||
|
||||
status.off = Power Off
|
||||
status.open = Tray Open
|
||||
status.stop = Stopped
|
||||
status.play = Playback
|
||||
status.pause = Pause Playback
|
||||
status.reverse = Rev Playback
|
||||
status.forward = Cue Playback
|
||||
status.slowfwd = Slow Forward Playback
|
||||
status.slowrev = Slow Backward Playback
|
||||
status.unknown = Unknown
|
||||
|
||||
# error status descriptions
|
||||
|
||||
error.hostname = Host Name must be specified.
|
||||
error.exception = Error communicating with the player.
|
||||
error.polling = Invalid status response received from player.
|
||||
error.keyerror = Error sending command to the player. Invalid playerKey length, should be 32 characters.
|
||||
error.nonce = Error sending command to the player. Nonce retrieval failure.
|
||||
error.authkey = Error sending command to the player. Error creating auth key.
|
||||
error.invalid = Error sending command to the player. See README for player configuration instructions.
|
@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="panasonicbdp"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Panasonic Blu-ray Player Thing -->
|
||||
<thing-type id="bd-player">
|
||||
<label>Panasonic Blu-ray Player</label>
|
||||
<description>
|
||||
Panasonic Blu-ray Player model DMP-BDT[1-3]10, DMP-BDT[1-3]20, DMP-BBT01 or DMP-BDT500
|
||||
</description>
|
||||
|
||||
<channels>
|
||||
<channel id="power" typeId="system.power">
|
||||
<label>Power</label>
|
||||
<description>Turn the power for the player on or off</description>
|
||||
</channel>
|
||||
<channel id="button" typeId="button"/>
|
||||
<channel id="control" typeId="control"/>
|
||||
<channel id="player-status" typeId="player-status"/>
|
||||
<channel id="time-elapsed" typeId="time-elapsed"/>
|
||||
<channel id="time-total" typeId="time-total"/>
|
||||
<channel id="chapter-current" typeId="chapter-current"/>
|
||||
<channel id="chapter-total" typeId="chapter-total"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uuid</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="hostName" type="text" required="true">
|
||||
<context>network-address</context>
|
||||
<label>Player Host Name/IP Address</label>
|
||||
<description>Host Name or IP Address of the player</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="5" required="false" unit="s">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval in seconds</description>
|
||||
<default>5</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="button">
|
||||
<item-type>String</item-type>
|
||||
<label>Remote Button</label>
|
||||
<description>A remote button press to send to the player</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="POWERON">Power On</option>
|
||||
<option value="POWEROFF">Power Off</option>
|
||||
<option value="POWER">Power Toggle</option>
|
||||
<option value="PLAYBACK">Play</option>
|
||||
<option value="PAUSE">Pause</option>
|
||||
<option value="STOP">Stop</option>
|
||||
<option value="CUE">Fast Forward</option>
|
||||
<option value="REV">Reverse</option>
|
||||
<option value="SKIPFWD">Skip Forward</option>
|
||||
<option value="SKIPREV">Skip Back</option>
|
||||
<option value="OP_CL">Open/Close</option>
|
||||
<option value="DSPSEL">Status</option>
|
||||
<option value="TITLE">Top Menu</option>
|
||||
<option value="PUPMENU">Pop-up Menu</option>
|
||||
<option value="UP">Up</option>
|
||||
<option value="DOWN">Down</option>
|
||||
<option value="LEFT">Left</option>
|
||||
<option value="RIGHT">Right</option>
|
||||
<option value="SELECT">OK</option>
|
||||
<option value="MENU">Submenu</option>
|
||||
<option value="RETURN">Return</option>
|
||||
<option value="D1">1</option>
|
||||
<option value="D2">2</option>
|
||||
<option value="D3">3</option>
|
||||
<option value="D4">4</option>
|
||||
<option value="D5">5</option>
|
||||
<option value="D6">6</option>
|
||||
<option value="D7">7</option>
|
||||
<option value="D8">8</option>
|
||||
<option value="D9">9</option>
|
||||
<option value="D0">0</option>
|
||||
<option value="D12">12</option>
|
||||
<option value="CLEAR">Cancel</option>
|
||||
<option value="SHARP">#</option>
|
||||
<option value="RED">Red</option>
|
||||
<option value="GREEN">Green</option>
|
||||
<option value="BLUE">Blue</option>
|
||||
<option value="YELLOW">Yellow</option>
|
||||
<option value="MLTNAVI">Home</option>
|
||||
<option value="V_CAST">Viera Cast</option>
|
||||
<option value="NETWORK">Network</option>
|
||||
<option value="SETUP">Setup</option>
|
||||
<option value="EXIT">Exit</option>
|
||||
<option value="AUDIOSEL">Audio</option>
|
||||
<option value="3D">3D</option>
|
||||
<option value="P_IN_P">PIP</option>
|
||||
<option value="OSDONOFF">OSD</option>
|
||||
<option value="SHFWD2">(swipe in CW circle)</option>
|
||||
<option value="SHREV2">(swipe in CCW circle)</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="control">
|
||||
<item-type>Player</item-type>
|
||||
<label>Control</label>
|
||||
<description>Transport Controls e.g. Play/Pause/Next/Previous/FForward/Rewind</description>
|
||||
<category>Player</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="player-status">
|
||||
<item-type>String</item-type>
|
||||
<label>Player Status</label>
|
||||
<description>The current player status</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="time-elapsed">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Playback Time</label>
|
||||
<description>The current playback time elapsed</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="time-total">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Total Time</label>
|
||||
<description>The total length of the current title</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chapter-current">
|
||||
<item-type>Number</item-type>
|
||||
<label>Current Chapter</label>
|
||||
<description>The current chapter number</description>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="chapter-total">
|
||||
<item-type>Number</item-type>
|
||||
<label>Total Chapters</label>
|
||||
<description>The total number of chapters in the current title</description>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="panasonicbdp"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Panasonic UHD Blu-ray Player Thing -->
|
||||
<thing-type id="uhd-player">
|
||||
<label>Panasonic UHD Blu-ray Player</label>
|
||||
<description>
|
||||
Panasonic UHD Blu-ray model DP-UB420/424, DP-UB820/824 or DP-UB9000/9004
|
||||
</description>
|
||||
|
||||
<channels>
|
||||
<channel id="power" typeId="system.power">
|
||||
<label>Power</label>
|
||||
<description>Turn the power for the player on or off</description>
|
||||
</channel>
|
||||
<channel id="button" typeId="uhd-button"/>
|
||||
<channel id="control" typeId="control"/>
|
||||
<channel id="player-status" typeId="player-status"/>
|
||||
<channel id="time-elapsed" typeId="time-elapsed"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uuid</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="hostName" type="text" required="true">
|
||||
<context>network-address</context>
|
||||
<label>Player Host Name/IP Address</label>
|
||||
<description>Host Name or IP Address of the player</description>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="5" required="false" unit="s">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval in seconds</description>
|
||||
<default>5</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
</parameter>
|
||||
<parameter name="playerKey" type="text" required="false">
|
||||
<label>Player Key</label>
|
||||
<description>To enable authentication of control commands, a key for the player must be specified</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="uhd-button">
|
||||
<item-type>String</item-type>
|
||||
<label>Remote Button</label>
|
||||
<description>A remote button press to send to the player</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="POWERON">Power On</option>
|
||||
<option value="POWEROFF">Power Off</option>
|
||||
<option value="POWER">Power Toggle</option>
|
||||
<option value="PLAYBACK">Play</option>
|
||||
<option value="PAUSE">Pause</option>
|
||||
<option value="STOP">Stop</option>
|
||||
<option value="CUE">Fast Forward</option>
|
||||
<option value="REV">Reverse</option>
|
||||
<option value="SKIPFWD">Skip Forward</option>
|
||||
<option value="SKIPREV">Skip Back</option>
|
||||
<option value="MNSKIP">Manual Skip +60s</option>
|
||||
<option value="MNBACK">Manual Skip -10s</option>
|
||||
<option value="OP_CL">Open/Close</option>
|
||||
<option value="DSPSEL">Status</option>
|
||||
<option value="TITLE">Top Menu</option>
|
||||
<option value="PUPMENU">Pop-up Menu</option>
|
||||
<option value="UP">Up</option>
|
||||
<option value="DOWN">Down</option>
|
||||
<option value="LEFT">Left</option>
|
||||
<option value="RIGHT">Right</option>
|
||||
<option value="SELECT">OK</option>
|
||||
<option value="MENU">Submenu</option>
|
||||
<option value="RETURN">Return</option>
|
||||
<option value="D1">1</option>
|
||||
<option value="D2">2</option>
|
||||
<option value="D3">3</option>
|
||||
<option value="D4">4</option>
|
||||
<option value="D5">5</option>
|
||||
<option value="D6">6</option>
|
||||
<option value="D7">7</option>
|
||||
<option value="D8">8</option>
|
||||
<option value="D9">9</option>
|
||||
<option value="D0">0</option>
|
||||
<option value="D12">12</option>
|
||||
<option value="CLEAR">Clear</option>
|
||||
<option value="SHARP">#</option>
|
||||
<option value="RED">Red</option>
|
||||
<option value="GREEN">Green</option>
|
||||
<option value="BLUE">Blue</option>
|
||||
<option value="YELLOW">Yellow</option>
|
||||
<option value="MLTNAVI">Home</option>
|
||||
<option value="NETFLIX">Netflix</option>
|
||||
<option value="V_CAST">Viera Cast</option>
|
||||
<option value="NETWORK">Network</option>
|
||||
<option value="SETUP">Setup</option>
|
||||
<option value="EXIT">Exit</option>
|
||||
<option value="AUDIOSEL">Audio</option>
|
||||
<option value="TITLEONOFF">Subtitle</option>
|
||||
<option value="CLOSED_CAPTION">Closed Caption</option>
|
||||
<option value="PLAYBACKINFO">Playback Info</option>
|
||||
<option value="HDR_PICTUREMODE">HDR Picture Mode</option>
|
||||
<option value="MIRACAST">Mirroring</option>
|
||||
<option value="PICTURESETTINGS">Picture Setting</option>
|
||||
<option value="SOUNDEFFECT">Sound Effect</option>
|
||||
<option value="HIGHCLARITY">High Clarity</option>
|
||||
<option value="SKIP_THE_TRAILER">Skip The Trailer</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="control">
|
||||
<item-type>Player</item-type>
|
||||
<label>Control</label>
|
||||
<description>Transport Controls e.g. Play/Pause/Next/Previous/FForward/Rewind</description>
|
||||
<category>Player</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="player-status">
|
||||
<item-type>String</item-type>
|
||||
<label>Player Status</label>
|
||||
<description>The current player status</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="time-elapsed">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>Playback Time</label>
|
||||
<description>The current playback time elapsed</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -296,6 +296,7 @@
|
||||
<module>org.openhab.binding.oppo</module>
|
||||
<module>org.openhab.binding.orbitbhyve</module>
|
||||
<module>org.openhab.binding.orvibo</module>
|
||||
<module>org.openhab.binding.panasonicbdp</module>
|
||||
<module>org.openhab.binding.paradoxalarm</module>
|
||||
<module>org.openhab.binding.pentair</module>
|
||||
<module>org.openhab.binding.phc</module>
|
||||
|
Loading…
Reference in New Issue
Block a user