[panasonicbdp] Initial contribution (#16122)

Signed-off-by: Michael Lobstein <michael.lobstein@gmail.com>
This commit is contained in:
mlobstein 2024-01-01 13:54:35 -06:00 committed by GitHub
parent f4596f581e
commit db64df1687
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1480 additions and 0 deletions

View File

@ -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

View File

@ -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>

View 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

View 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 |
| &#42; (Cancel) | CLEAR |
| &#35; ([_]) | 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 |
| &#42; (Cancel) | CLEAR |
| &#35; ([_]) | 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 |

View 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>

View File

@ -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>

View File

@ -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");
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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.

View File

@ -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>

View File

@ -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>

View File

@ -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>