added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.sonyaudio/.classpath
Normal file
32
bundles/org.openhab.binding.sonyaudio/.classpath
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
bundles/org.openhab.binding.sonyaudio/.project
Normal file
23
bundles/org.openhab.binding.sonyaudio/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.sonyaudio</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
bundles/org.openhab.binding.sonyaudio/NOTICE
Normal file
13
bundles/org.openhab.binding.sonyaudio/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
|
||||
99
bundles/org.openhab.binding.sonyaudio/README.md
Normal file
99
bundles/org.openhab.binding.sonyaudio/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# SonyAudio Binding
|
||||
|
||||
This binding integrates the [Sony Audio Control API](https://developer.sony.com/develop/audio-control-api/).
|
||||
|
||||
## Supported Things
|
||||
|
||||
For the moment the devices that are supported by this binding are
|
||||
* STR-DN1080
|
||||
* HT-CT800
|
||||
* SRS-ZR5
|
||||
* HT-ST5000
|
||||
* HT-Z9F
|
||||
* HT-ZF9
|
||||
* HT-MT500
|
||||
|
||||
When being defined in a \*.things file, the specific thing types
|
||||
STR-DN1080, HT-ST5000, HT-ZF9, HT-Z9F, HT-CT800, HT-MT500 and SRS-ZR5 should be used.
|
||||
|
||||
Please note that these thing types are case sensitive (you need to define them in upper case).
|
||||
|
||||
## Discovery
|
||||
|
||||
The SonyAudio devices are discovered through UPnP in the local network and all devices are put in the Inbox.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The SonyAudio Thing requires the network address, port and path as a configuration value in order for the binding to know how to access the device.
|
||||
Additionally, a refresh interval, used to poll the Sony Audio device, can be specified (in seconds).
|
||||
|
||||
```
|
||||
Thing sonyaudio:HT-ST5000:1 [ipAddress="192.168.123.123", port=10000, path="/sony", refresh=60]
|
||||
```
|
||||
|
||||
## Channels
|
||||
|
||||
The devices support the following channels:
|
||||
|
||||
| Channel Type ID | Item Type | Access Mode | Description | Thing types |
|
||||
|----------------------------|-----------|-------------|---------------------------------------------------------------------------------------|--------------------------------------------------------|
|
||||
| power | Switch | RW | Main power on/off | HT-CT800, SRS-ZR5, HT-ST5000, HT-ZF9, HT-Z9F, HT-MT500 |
|
||||
| input | String | RW | Set or get the input source | HT-CT800, SRS-ZR5, HT-ST5000, HT-ZF9, HT-Z9F, HT-MT500 |
|
||||
| volume | Dimmer | RW | Set or get the master volume | HT-CT800, SRS-ZR5, HT-ST5000, HT-ZF9, HT-Z9F, HT-MT500 |
|
||||
| mute | Switch | RW | Set or get the mute state of the master volume | HT-CT800, SRS-ZR5, HT-ST5000, HT-ZF9, HT-Z9F, HT-MT500 |
|
||||
| soundField | String | RW | Sound field | HT-CT800, SRS-ZR5, HT-ST5000, HT-ZF9, HT-Z9F, HT-MT500 |
|
||||
| master#power | Switch | RW | Main power on/off | STR-1080 |
|
||||
| master#soundField | String | RW | Sound field | STR-1080 |
|
||||
| zone1#power | Switch | RW | Power for zone1 for devices supporting multizone | STR-1080 |
|
||||
| zone1#input | String | RW | Set or get the input source for zone1 for devices supporting multizone | STR-1080 |
|
||||
| zone1#volume | Dimmer | RW | Set or get the zone1 volume for devices supporting multizone | STR-1080 |
|
||||
| zone1#mute | Switch | RW | Set or get the mute state for zone1 volume | STR-1080 |
|
||||
| zone2#power | Switch | RW | Power for zone2 for devices supporting multizone | STR-1080 |
|
||||
| zone2#input | String | RW | Set or get the input source for zone2 for devices supporting multizone | STR-1080 |
|
||||
| zone2#volume | Dimmer | RW | Set or get the zone2 volume for devices supporting multizone | STR-1080 |
|
||||
| zone2#mute | Switch | RW | Set or get the mute state for zone2 volume | STR-1080 |
|
||||
| zone3#power | Switch | RW | Power for zone3 for devices supporting multizone | none |
|
||||
| zone3#input | String | RW | Set or get the input source for zone3 for devices supporting multizone | none |
|
||||
| zone3#volume | Dimmer | RW | Set or get the zone3 volume for devices supporting multizone | none |
|
||||
| zone3#mute | Switch | RW | Set or get the mute state for zone3 volume | none |
|
||||
| zone4#power | Switch | RW | Power for zone4 for devices supporting multizone | STR-1080 |
|
||||
| zone4#input | String | RW | Set or get the input source for zone4 for devices supporting multizone | STR-1080 |
|
||||
| zone4#volume | Dimmer | RW | Set or get the zone4 volume for devices supporting multizone | STR-1080 |
|
||||
| zone4#mute | Switch | RW | Set or get the mute state for zone4 volume | STR-1080 |
|
||||
| radio#broadcastFreq | Number | R | Current radio frequency | STR-1080 |
|
||||
| radio#broadcastStation | Number | RW | Set or get current preset radio station | STR-1080 |
|
||||
| radio#broadcastSeekStation | String | W | Seek for new broadcast station, forward search "fwdSeeking" and backward "bwdSeeking" | STR-1080 |
|
||||
| nightMode | Switch | RW | Set or get the Night Mode state | HT-ZF9 |
|
||||
|
||||
|
||||
## Full Example
|
||||
|
||||
demo.things:
|
||||
|
||||
```
|
||||
Thing sonyaudio:HT-ST5000:living [ipAddress="192.168.123.123"]
|
||||
```
|
||||
|
||||
demo.items:
|
||||
|
||||
```
|
||||
Group SonyAudio <sonyaudio>
|
||||
|
||||
Dimmer Sony_Volume "Volume [%.0f %%]" <soundvolume> (SonyAudio) {channel="sonyaudio:HT-ST5000:living:volume"}
|
||||
Switch Sony_Mute "Mute" <soundvolume_mute> (SonyAudio) {channel="sonyaudio:HT-ST5000:living:mute"}
|
||||
String Sony_Sound_Field "Sound Field: [%s]" <text> (SonyAudio) {channel="sonyaudio:HT-ST5000:living:master#soundField"}
|
||||
```
|
||||
|
||||
demo.sitemap:
|
||||
|
||||
```
|
||||
sitemap demo label="Main Menu" {
|
||||
Frame label="Sony" {
|
||||
Text label="Volume" icon="soundvolume" {
|
||||
Slider item=Sony_Volume
|
||||
Switch item=Sony_Mute
|
||||
}
|
||||
Text item=Sony_Sound_Field
|
||||
}
|
||||
}
|
||||
```
|
||||
17
bundles/org.openhab.binding.sonyaudio/pom.xml
Normal file
17
bundles/org.openhab.binding.sonyaudio/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>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.sonyaudio</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: SonyAudio Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.sonyaudio-${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-sonyaudio" description="Sony Audio Binding" version="${project.version}">
|
||||
<feature>openhab-transport-upnp</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.sonyaudio/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author David - Initial contribution
|
||||
*/
|
||||
public class SonyAudioBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "sonyaudio";
|
||||
|
||||
public static final String SONY_TYPE_STRDN1080 = "STR-DN1080";
|
||||
public static final String SONY_TYPE_HTCT800 = "HT-CT800";
|
||||
public static final String SONY_TYPE_HTST5000 = "HT-ST5000";
|
||||
public static final String SONY_TYPE_HTZ9F = "HT-Z9F";
|
||||
public static final String SONY_TYPE_HTZF9 = "HT-ZF9";
|
||||
public static final String SONY_TYPE_HTMT500 = "HT-MT500";
|
||||
public static final String SONY_TYPE_SRSZR5 = "SRS-ZR5";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_STRDN1080 = new ThingTypeUID(BINDING_ID, SONY_TYPE_STRDN1080);
|
||||
public static final ThingTypeUID THING_TYPE_HTCT800 = new ThingTypeUID(BINDING_ID, SONY_TYPE_HTCT800);
|
||||
public static final ThingTypeUID THING_TYPE_HTST5000 = new ThingTypeUID(BINDING_ID, SONY_TYPE_HTST5000);
|
||||
public static final ThingTypeUID THING_TYPE_HTZ9F = new ThingTypeUID(BINDING_ID, SONY_TYPE_HTZ9F);
|
||||
public static final ThingTypeUID THING_TYPE_HTZF9 = new ThingTypeUID(BINDING_ID, SONY_TYPE_HTZF9);
|
||||
public static final ThingTypeUID THING_TYPE_HTMT500 = new ThingTypeUID(BINDING_ID, SONY_TYPE_HTMT500);
|
||||
public static final ThingTypeUID THING_TYPE_SRSZR5 = new ThingTypeUID(BINDING_ID, SONY_TYPE_SRSZR5);
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
|
||||
.of(THING_TYPE_STRDN1080, THING_TYPE_HTCT800, THING_TYPE_HTST5000, THING_TYPE_HTZ9F, THING_TYPE_HTZF9,
|
||||
THING_TYPE_HTMT500, THING_TYPE_SRSZR5)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// List of thing parameters names
|
||||
public static final String HOST_PARAMETER = "ipAddress";
|
||||
public static final String SCALAR_PORT_PARAMETER = "port";
|
||||
public static final String SCALAR_PATH_PARAMETER = "path";
|
||||
public static final String REFRESHINTERVAL = "refreshInterval";
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_POWER = "power";
|
||||
public static final String CHANNEL_INPUT = "input";
|
||||
public static final String CHANNEL_VOLUME = "volume";
|
||||
public static final String CHANNEL_MUTE = "mute";
|
||||
public static final String CHANNEL_SOUND_FIELD = "soundField";
|
||||
|
||||
public static final String CHANNEL_MASTER_POWER = "master#power";
|
||||
public static final String CHANNEL_MASTER_SOUND_FIELD = "master#soundField";
|
||||
|
||||
public static final String CHANNEL_ZONE1_POWER = "zone1#power";
|
||||
public static final String CHANNEL_ZONE1_INPUT = "zone1#input";
|
||||
public static final String CHANNEL_ZONE1_VOLUME = "zone1#volume";
|
||||
public static final String CHANNEL_ZONE1_MUTE = "zone1#mute";
|
||||
|
||||
public static final String CHANNEL_ZONE2_POWER = "zone2#power";
|
||||
public static final String CHANNEL_ZONE2_INPUT = "zone2#input";
|
||||
public static final String CHANNEL_ZONE2_VOLUME = "zone2#volume";
|
||||
public static final String CHANNEL_ZONE2_MUTE = "zone2#mute";
|
||||
|
||||
public static final String CHANNEL_ZONE3_POWER = "zone3#power";
|
||||
public static final String CHANNEL_ZONE3_INPUT = "zone3#input";
|
||||
public static final String CHANNEL_ZONE3_VOLUME = "zone3#volume";
|
||||
public static final String CHANNEL_ZONE3_MUTE = "zone3#mute";
|
||||
|
||||
public static final String CHANNEL_ZONE4_POWER = "zone4#power";
|
||||
public static final String CHANNEL_ZONE4_INPUT = "zone4#input";
|
||||
public static final String CHANNEL_ZONE4_VOLUME = "zone4#volume";
|
||||
public static final String CHANNEL_ZONE4_MUTE = "zone4#mute";
|
||||
|
||||
public static final String CHANNEL_RADIO_FREQ = "radio#broadcastFreq";
|
||||
public static final String CHANNEL_RADIO_STATION = "radio#broadcastStation";
|
||||
public static final String CHANNEL_RADIO_SEEK_STATION = "radio#broadcastSeekStation";
|
||||
|
||||
public static final String CHANNEL_NIGHTMODE = "nightMode";
|
||||
|
||||
// Used for Discovery service
|
||||
public static final String MANUFACTURER = "SONY";
|
||||
public static final String UPNP_DEVICE_TYPE = "MediaRenderer";
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal;
|
||||
|
||||
import java.util.EventListener;
|
||||
|
||||
import org.openhab.binding.sonyaudio.internal.protocol.SonyAudioConnection;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioEventListener} event listener interface
|
||||
* handlers.
|
||||
*
|
||||
* @author David - Initial contribution
|
||||
*/
|
||||
public interface SonyAudioEventListener extends EventListener {
|
||||
void updateConnectionState(boolean connected);
|
||||
|
||||
void updateInput(int zone, SonyAudioConnection.SonyAudioInput input);
|
||||
|
||||
void updateSeekStation(String seek);
|
||||
|
||||
void updateCurrentRadioStation(int radioStation);
|
||||
|
||||
void updateVolume(int zone, SonyAudioConnection.SonyAudioVolume volume);
|
||||
|
||||
void updatePowerStatus(int zone, boolean power);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.binding.sonyaudio.internal.handler.HtCt800Handler;
|
||||
import org.openhab.binding.sonyaudio.internal.handler.HtMt500Handler;
|
||||
import org.openhab.binding.sonyaudio.internal.handler.HtSt5000Handler;
|
||||
import org.openhab.binding.sonyaudio.internal.handler.HtZ9fHandler;
|
||||
import org.openhab.binding.sonyaudio.internal.handler.HtZf9Handler;
|
||||
import org.openhab.binding.sonyaudio.internal.handler.SrsZr5Handler;
|
||||
import org.openhab.binding.sonyaudio.internal.handler.StrDn1080Handler;
|
||||
import org.openhab.core.io.net.http.WebSocketFactory;
|
||||
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.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author David - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.sonyaudio")
|
||||
public class SonyAudioHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private WebSocketClient webSocketClient;
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SonyAudioBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
switch (thingTypeUID.getId()) {
|
||||
case SonyAudioBindingConstants.SONY_TYPE_STRDN1080:
|
||||
return new StrDn1080Handler(thing, webSocketClient);
|
||||
case SonyAudioBindingConstants.SONY_TYPE_HTCT800:
|
||||
return new HtCt800Handler(thing, webSocketClient);
|
||||
case SonyAudioBindingConstants.SONY_TYPE_HTST5000:
|
||||
return new HtSt5000Handler(thing, webSocketClient);
|
||||
case SonyAudioBindingConstants.SONY_TYPE_HTZ9F:
|
||||
return new HtZ9fHandler(thing, webSocketClient);
|
||||
case SonyAudioBindingConstants.SONY_TYPE_HTZF9:
|
||||
return new HtZf9Handler(thing, webSocketClient);
|
||||
case SonyAudioBindingConstants.SONY_TYPE_HTMT500:
|
||||
return new HtMt500Handler(thing, webSocketClient);
|
||||
case SonyAudioBindingConstants.SONY_TYPE_SRSZR5:
|
||||
return new SrsZr5Handler(thing, webSocketClient);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Reference
|
||||
protected void setWebSocketFactory(WebSocketFactory webSocketFactory) {
|
||||
this.webSocketClient = webSocketFactory.getCommonWebSocketClient();
|
||||
}
|
||||
|
||||
protected void unsetWebSocketFactory(WebSocketFactory webSocketFactory) {
|
||||
this.webSocketClient = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.discovery;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.jupnp.model.meta.RemoteDevice;
|
||||
import org.openhab.binding.sonyaudio.internal.SonyAudioBindingConstants;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This class identifies SONY products by their Upnp service information.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
@Component(immediate = true)
|
||||
public class SonyAudioDiscoveryParticipant implements UpnpDiscoveryParticipant {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SonyAudioDiscoveryParticipant.class);
|
||||
|
||||
private Set<ThingTypeUID> supportedThingTypes;
|
||||
|
||||
public SonyAudioDiscoveryParticipant() {
|
||||
this.supportedThingTypes = SonyAudioBindingConstants.SUPPORTED_THING_TYPES_UIDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return supportedThingTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscoveryResult createResult(RemoteDevice device) {
|
||||
DiscoveryResult result = null;
|
||||
|
||||
ThingUID thingUid = getThingUID(device);
|
||||
if (thingUid != null) {
|
||||
String label = StringUtils.isEmpty(device.getDetails().getFriendlyName()) ? device.getDisplayString()
|
||||
: device.getDetails().getFriendlyName();
|
||||
String host = device.getIdentity().getDescriptorURL().getHost();
|
||||
int port = device.getIdentity().getDescriptorURL().getPort();
|
||||
String path = device.getIdentity().getDescriptorURL().getPath();
|
||||
try {
|
||||
Map<String, Object> properties = getDescription(host, port, path);
|
||||
properties.put(SonyAudioBindingConstants.HOST_PARAMETER,
|
||||
device.getIdentity().getDescriptorURL().getHost());
|
||||
result = DiscoveryResultBuilder.create(thingUid).withLabel(label).withProperties(properties).build();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThingUID getThingUID(RemoteDevice device) {
|
||||
ThingUID result = null;
|
||||
|
||||
if (!StringUtils.containsIgnoreCase(device.getDetails().getManufacturerDetails().getManufacturer(),
|
||||
SonyAudioBindingConstants.MANUFACTURER)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
logger.debug("Manufacturer matched: search: {}, device value: {}.", SonyAudioBindingConstants.MANUFACTURER,
|
||||
device.getDetails().getManufacturerDetails().getManufacturer());
|
||||
if (!StringUtils.containsIgnoreCase(device.getType().getType(), SonyAudioBindingConstants.UPNP_DEVICE_TYPE)) {
|
||||
return result;
|
||||
}
|
||||
logger.debug("Device type matched: search: {}, device value: {}.", SonyAudioBindingConstants.UPNP_DEVICE_TYPE,
|
||||
device.getType().getType());
|
||||
logger.debug("Device services: {}", device.getServices().toString());
|
||||
String deviceModel = device.getDetails().getModelDetails() != null
|
||||
? device.getDetails().getModelDetails().getModelName()
|
||||
: null;
|
||||
logger.debug("Device model: {}.", deviceModel);
|
||||
ThingTypeUID thingTypeUID = findThingType(deviceModel);
|
||||
if (thingTypeUID != null) {
|
||||
result = new ThingUID(thingTypeUID, device.getIdentity().getUdn().getIdentifierString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private ThingTypeUID findThingType(String deviceModel) {
|
||||
ThingTypeUID thingTypeUID = null;
|
||||
for (ThingTypeUID thingType : SonyAudioBindingConstants.SUPPORTED_THING_TYPES_UIDS) {
|
||||
if (thingType.getId().equalsIgnoreCase(deviceModel)) {
|
||||
return thingType;
|
||||
}
|
||||
}
|
||||
|
||||
return thingTypeUID;
|
||||
}
|
||||
|
||||
private Map<String, Object> getDescription(String host, int port, String path) throws IOException {
|
||||
Map<String, Object> properties = new HashMap<>(2, 1);
|
||||
URL url = new URL("http", host, port, path);
|
||||
logger.debug("URL: {}", url.toString());
|
||||
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
||||
String s;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
while ((s = bufferedReader.readLine()) != null) {
|
||||
builder.append(s);
|
||||
}
|
||||
Pattern ScalarWebAPImatch = Pattern.compile("<av:X_ScalarWebAPI_BaseURL>(.*)</av:X_ScalarWebAPI_BaseURL>");
|
||||
Pattern baseURLmatch = Pattern.compile("http://(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d+)([^<]*)");
|
||||
|
||||
Matcher tagmatch = ScalarWebAPImatch.matcher(builder.toString());
|
||||
if (tagmatch.find()) {
|
||||
Matcher matcher = baseURLmatch.matcher(tagmatch.group());
|
||||
matcher.find();
|
||||
// String scalar_host = matcher.group(0);
|
||||
int scalar_port = Integer.parseInt(matcher.group(2));
|
||||
String scalar_path = matcher.group(3);
|
||||
|
||||
properties.put(SonyAudioBindingConstants.SCALAR_PORT_PARAMETER, scalar_port);
|
||||
properties.put(SonyAudioBindingConstants.SCALAR_PATH_PARAMETER, scalar_path);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link HtCt800Handler} is responsible for handling commands for HT-CT800, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class HtCt800Handler extends SonyAudioHandler {
|
||||
|
||||
public HtCt800Handler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing, webSocketClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setInputCommand(Command command) {
|
||||
switch (command.toString().toLowerCase()) {
|
||||
case "btaudio":
|
||||
return "extInput:btAudio";
|
||||
case "tv":
|
||||
return "extInput:tv";
|
||||
case "hdmi1":
|
||||
return "extInput:hdmi?port=1";
|
||||
case "hdmi2":
|
||||
return "extInput:hdmi?port=2";
|
||||
case "hdmi3":
|
||||
return "extInput:hdmi?port=3";
|
||||
case "analog":
|
||||
return "extInput:line";
|
||||
case "usb":
|
||||
return "storage:usb1";
|
||||
case "network":
|
||||
return "dlna:music";
|
||||
case "cast":
|
||||
return "cast:audio";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringType inputSource(String input) {
|
||||
String in = input.toLowerCase();
|
||||
if (in.contains("extinput:btaudio".toLowerCase())) {
|
||||
return new StringType("btaudio");
|
||||
}
|
||||
if (in.contains("extinput:tv".toLowerCase())) {
|
||||
return new StringType("tv");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=1".toLowerCase())) {
|
||||
return new StringType("hdmi1");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=2".toLowerCase())) {
|
||||
return new StringType("hdmi2");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=3".toLowerCase())) {
|
||||
return new StringType("hdmi3");
|
||||
}
|
||||
if (in.contains("extinput:line".toLowerCase())) {
|
||||
return new StringType("analog");
|
||||
}
|
||||
if (in.contains("storage:usb1".toLowerCase())) {
|
||||
return new StringType("usb");
|
||||
}
|
||||
if (in.contains("dlna:music".toLowerCase())) {
|
||||
return new StringType("network");
|
||||
}
|
||||
if (in.contains("cast:audio".toLowerCase())) {
|
||||
return new StringType("cast");
|
||||
}
|
||||
return new StringType(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link HtMt500Handler} is responsible for handling commands for HT-ST500, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class HtMt500Handler extends SonyAudioHandler {
|
||||
|
||||
public HtMt500Handler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing, webSocketClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setInputCommand(Command command) {
|
||||
switch (command.toString().toLowerCase()) {
|
||||
case "btaudio":
|
||||
return "extInput:btAudio";
|
||||
case "tv":
|
||||
return "extInput:tv";
|
||||
case "analog":
|
||||
return "extInput:line";
|
||||
case "usb":
|
||||
return "storage:usb1";
|
||||
case "network":
|
||||
return "dlna:music";
|
||||
case "cast":
|
||||
return "cast:audio";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringType inputSource(String input) {
|
||||
String in = input.toLowerCase();
|
||||
if (in.contains("extinput:btaudio".toLowerCase())) {
|
||||
return new StringType("btaudio");
|
||||
}
|
||||
if (in.contains("extinput:tv".toLowerCase())) {
|
||||
return new StringType("tv");
|
||||
}
|
||||
if (in.contains("extinput:line".toLowerCase())) {
|
||||
return new StringType("analog");
|
||||
}
|
||||
if (in.contains("storage:usb1".toLowerCase())) {
|
||||
return new StringType("usb");
|
||||
}
|
||||
if (in.contains("dlna:music".toLowerCase())) {
|
||||
return new StringType("network");
|
||||
}
|
||||
if (in.contains("cast:audio".toLowerCase())) {
|
||||
return new StringType("cast");
|
||||
}
|
||||
return new StringType(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link HtSt5000Handler} is responsible for handling commands for HT-ST5000, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class HtSt5000Handler extends SonyAudioHandler {
|
||||
|
||||
public HtSt5000Handler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing, webSocketClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setInputCommand(Command command) {
|
||||
switch (command.toString().toLowerCase()) {
|
||||
case "btaudio":
|
||||
return "extInput:btAudio";
|
||||
case "tv":
|
||||
return "extInput:tv";
|
||||
case "hdmi1":
|
||||
return "extInput:hdmi?port=1";
|
||||
case "hdmi2":
|
||||
return "extInput:hdmi?port=2";
|
||||
case "hdmi3":
|
||||
return "extInput:hdmi?port=3";
|
||||
case "analog":
|
||||
return "extInput:line";
|
||||
case "usb":
|
||||
return "storage:usb1";
|
||||
case "network":
|
||||
return "dlna:music";
|
||||
case "cast":
|
||||
return "cast:audio";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringType inputSource(String input) {
|
||||
String in = input.toLowerCase();
|
||||
if (in.contains("extinput:btaudio".toLowerCase())) {
|
||||
return new StringType("btaudio");
|
||||
}
|
||||
if (in.contains("extinput:tv".toLowerCase())) {
|
||||
return new StringType("tv");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=1".toLowerCase())) {
|
||||
return new StringType("hdmi1");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=2".toLowerCase())) {
|
||||
return new StringType("hdmi2");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=3".toLowerCase())) {
|
||||
return new StringType("hdmi3");
|
||||
}
|
||||
if (in.contains("extinput:line".toLowerCase())) {
|
||||
return new StringType("analog");
|
||||
}
|
||||
if (in.contains("storage:usb1".toLowerCase())) {
|
||||
return new StringType("usb");
|
||||
}
|
||||
if (in.contains("dlna:music".toLowerCase())) {
|
||||
return new StringType("network");
|
||||
}
|
||||
if (in.contains("cast:audio".toLowerCase())) {
|
||||
return new StringType("cast");
|
||||
}
|
||||
return new StringType(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link HtZ9fHandler} is responsible for handling commands for HT-Z9F, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class HtZ9fHandler extends SonyAudioHandler {
|
||||
|
||||
public HtZ9fHandler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing, webSocketClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setInputCommand(Command command) {
|
||||
switch (command.toString().toLowerCase()) {
|
||||
case "btaudio":
|
||||
return "extInput:btAudio";
|
||||
case "tv":
|
||||
return "extInput:tv";
|
||||
case "hdmi1":
|
||||
return "extInput:hdmi?port=1";
|
||||
case "hdmi2":
|
||||
return "extInput:hdmi?port=2";
|
||||
case "analog":
|
||||
return "extInput:line";
|
||||
case "usb":
|
||||
return "storage:usb1";
|
||||
case "network":
|
||||
return "dlna:music";
|
||||
case "cast":
|
||||
return "cast:audio";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringType inputSource(String input) {
|
||||
String in = input.toLowerCase();
|
||||
if (in.contains("extinput:btaudio".toLowerCase())) {
|
||||
return new StringType("btaudio");
|
||||
}
|
||||
if (in.contains("extinput:tv".toLowerCase())) {
|
||||
return new StringType("tv");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=1".toLowerCase())) {
|
||||
return new StringType("hdmi1");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=2".toLowerCase())) {
|
||||
return new StringType("hdmi2");
|
||||
}
|
||||
if (in.contains("extinput:line".toLowerCase())) {
|
||||
return new StringType("analog");
|
||||
}
|
||||
if (in.contains("storage:usb1".toLowerCase())) {
|
||||
return new StringType("usb");
|
||||
}
|
||||
if (in.contains("dlna:music".toLowerCase())) {
|
||||
return new StringType("network");
|
||||
}
|
||||
if (in.contains("cast:audio".toLowerCase())) {
|
||||
return new StringType("cast");
|
||||
}
|
||||
return new StringType(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link HtZf9Handler} is responsible for handling commands for HT-ZF9, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class HtZf9Handler extends SonyAudioHandler {
|
||||
|
||||
public HtZf9Handler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing, webSocketClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setInputCommand(Command command) {
|
||||
switch (command.toString().toLowerCase()) {
|
||||
case "btaudio":
|
||||
return "extInput:btAudio";
|
||||
case "tv":
|
||||
return "extInput:tv";
|
||||
case "hdmi1":
|
||||
return "extInput:hdmi?port=1";
|
||||
case "hdmi2":
|
||||
return "extInput:hdmi?port=2";
|
||||
case "analog":
|
||||
return "extInput:line";
|
||||
case "usb":
|
||||
return "storage:usb1";
|
||||
case "network":
|
||||
return "dlna:music";
|
||||
case "cast":
|
||||
return "cast:audio";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringType inputSource(String input) {
|
||||
String in = input.toLowerCase();
|
||||
if (in.contains("extinput:btaudio".toLowerCase())) {
|
||||
return new StringType("btaudio");
|
||||
}
|
||||
if (in.contains("extinput:tv".toLowerCase())) {
|
||||
return new StringType("tv");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=1".toLowerCase())) {
|
||||
return new StringType("hdmi1");
|
||||
}
|
||||
if (in.contains("extinput:hdmi?port=2".toLowerCase())) {
|
||||
return new StringType("hdmi2");
|
||||
}
|
||||
if (in.contains("extinput:line".toLowerCase())) {
|
||||
return new StringType("analog");
|
||||
}
|
||||
if (in.contains("storage:usb1".toLowerCase())) {
|
||||
return new StringType("usb");
|
||||
}
|
||||
if (in.contains("dlna:music".toLowerCase())) {
|
||||
return new StringType("network");
|
||||
}
|
||||
if (in.contains("cast:audio".toLowerCase())) {
|
||||
return new StringType("cast");
|
||||
}
|
||||
return new StringType(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,596 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import static org.openhab.binding.sonyaudio.internal.SonyAudioBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.binding.sonyaudio.internal.SonyAudioBindingConstants;
|
||||
import org.openhab.binding.sonyaudio.internal.SonyAudioEventListener;
|
||||
import org.openhab.binding.sonyaudio.internal.protocol.SonyAudioConnection;
|
||||
import org.openhab.core.cache.ExpiringCache;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.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.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
abstract class SonyAudioHandler extends BaseThingHandler implements SonyAudioEventListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SonyAudioHandler.class);
|
||||
|
||||
private WebSocketClient webSocketClient;
|
||||
|
||||
protected SonyAudioConnection connection;
|
||||
private ScheduledFuture<?> connectionCheckerFuture;
|
||||
private ScheduledFuture<?> refreshJob;
|
||||
|
||||
private int currentRadioStation = 0;
|
||||
private final Map<Integer, String> input_zone = new HashMap<>();
|
||||
|
||||
private static final long CACHE_EXPIRY = TimeUnit.SECONDS.toMillis(5);
|
||||
|
||||
protected ExpiringCache<Boolean>[] powerCache;
|
||||
protected ExpiringCache<SonyAudioConnection.SonyAudioInput>[] inputCache;
|
||||
protected ExpiringCache<SonyAudioConnection.SonyAudioVolume>[] volumeCache;
|
||||
protected ExpiringCache<Map<String, String>> soundSettingsCache;
|
||||
|
||||
protected Supplier<Boolean>[] powerSupplier;
|
||||
protected Supplier<SonyAudioConnection.SonyAudioInput>[] inputSupplier;
|
||||
protected Supplier<SonyAudioConnection.SonyAudioVolume>[] volumeSupplier;
|
||||
protected Supplier<Map<String, String>> soundSettingsSupplier;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public SonyAudioHandler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing);
|
||||
|
||||
this.webSocketClient = webSocketClient;
|
||||
|
||||
powerCache = new ExpiringCache[5];
|
||||
powerSupplier = new Supplier[5];
|
||||
inputCache = new ExpiringCache[5];
|
||||
inputSupplier = new Supplier[5];
|
||||
volumeCache = new ExpiringCache[5];
|
||||
volumeSupplier = new Supplier[5];
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final int index = i;
|
||||
|
||||
inputSupplier[i] = () -> {
|
||||
try {
|
||||
return connection.getInput(index);
|
||||
} catch (IOException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
};
|
||||
|
||||
powerSupplier[i] = () -> {
|
||||
try {
|
||||
return connection.getPower(index);
|
||||
} catch (IOException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
};
|
||||
|
||||
volumeSupplier[i] = () -> {
|
||||
try {
|
||||
return connection.getVolume(index);
|
||||
} catch (IOException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
};
|
||||
|
||||
powerCache[i] = new ExpiringCache<>(CACHE_EXPIRY, powerSupplier[i]);
|
||||
inputCache[i] = new ExpiringCache<>(CACHE_EXPIRY, inputSupplier[i]);
|
||||
volumeCache[i] = new ExpiringCache<>(CACHE_EXPIRY, volumeSupplier[i]);
|
||||
}
|
||||
|
||||
soundSettingsSupplier = () -> {
|
||||
try {
|
||||
return connection.getSoundSettings();
|
||||
} catch (IOException ex) {
|
||||
throw new CompletionException(ex);
|
||||
}
|
||||
};
|
||||
|
||||
soundSettingsCache = new ExpiringCache<>(CACHE_EXPIRY, soundSettingsSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (connection == null || !connection.checkConnection()) {
|
||||
logger.debug("Thing not yet initialized!");
|
||||
return;
|
||||
}
|
||||
|
||||
String id = channelUID.getId();
|
||||
|
||||
logger.debug("Handle command {} {}", channelUID, command);
|
||||
|
||||
if (getThing().getStatusInfo().getStatus() != ThingStatus.ONLINE) {
|
||||
switch (id) {
|
||||
case CHANNEL_POWER:
|
||||
case CHANNEL_MASTER_POWER:
|
||||
logger.debug("Device powered off sending {} {}", channelUID, command);
|
||||
break;
|
||||
default:
|
||||
logger.debug("Device powered off ignore command {} {}", channelUID, command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
switch (id) {
|
||||
case CHANNEL_POWER:
|
||||
case CHANNEL_MASTER_POWER:
|
||||
handlePowerCommand(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_ZONE1_POWER:
|
||||
handlePowerCommand(command, channelUID, 1);
|
||||
break;
|
||||
case CHANNEL_ZONE2_POWER:
|
||||
handlePowerCommand(command, channelUID, 2);
|
||||
break;
|
||||
case CHANNEL_ZONE3_POWER:
|
||||
handlePowerCommand(command, channelUID, 3);
|
||||
break;
|
||||
case CHANNEL_ZONE4_POWER:
|
||||
handlePowerCommand(command, channelUID, 4);
|
||||
break;
|
||||
case CHANNEL_INPUT:
|
||||
handleInputCommand(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_ZONE1_INPUT:
|
||||
handleInputCommand(command, channelUID, 1);
|
||||
break;
|
||||
case CHANNEL_ZONE2_INPUT:
|
||||
handleInputCommand(command, channelUID, 2);
|
||||
break;
|
||||
case CHANNEL_ZONE3_INPUT:
|
||||
handleInputCommand(command, channelUID, 3);
|
||||
break;
|
||||
case CHANNEL_ZONE4_INPUT:
|
||||
handleInputCommand(command, channelUID, 4);
|
||||
break;
|
||||
case CHANNEL_VOLUME:
|
||||
handleVolumeCommand(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_ZONE1_VOLUME:
|
||||
handleVolumeCommand(command, channelUID, 1);
|
||||
break;
|
||||
case CHANNEL_ZONE2_VOLUME:
|
||||
handleVolumeCommand(command, channelUID, 2);
|
||||
break;
|
||||
case CHANNEL_ZONE3_VOLUME:
|
||||
handleVolumeCommand(command, channelUID, 3);
|
||||
break;
|
||||
case CHANNEL_ZONE4_VOLUME:
|
||||
handleVolumeCommand(command, channelUID, 4);
|
||||
break;
|
||||
case CHANNEL_MUTE:
|
||||
handleMuteCommand(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_ZONE1_MUTE:
|
||||
handleMuteCommand(command, channelUID, 1);
|
||||
break;
|
||||
case CHANNEL_ZONE2_MUTE:
|
||||
handleMuteCommand(command, channelUID, 2);
|
||||
break;
|
||||
case CHANNEL_ZONE3_MUTE:
|
||||
handleMuteCommand(command, channelUID, 3);
|
||||
break;
|
||||
case CHANNEL_ZONE4_MUTE:
|
||||
handleMuteCommand(command, channelUID, 4);
|
||||
break;
|
||||
case CHANNEL_MASTER_SOUND_FIELD:
|
||||
case CHANNEL_SOUND_FIELD:
|
||||
handleSoundSettings(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_RADIO_FREQ:
|
||||
handleRadioCommand(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_RADIO_STATION:
|
||||
handleRadioStationCommand(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_RADIO_SEEK_STATION:
|
||||
handleRadioSeekStationCommand(command, channelUID);
|
||||
break;
|
||||
case CHANNEL_NIGHTMODE:
|
||||
handleNightMode(command, channelUID);
|
||||
break;
|
||||
default:
|
||||
logger.error("Command {}, {} not supported by {}!", id, command, channelUID);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void handleSoundSettings(Command command, ChannelUID channelUID) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
logger.debug("handleSoundSettings RefreshType");
|
||||
Map<String, String> result = soundSettingsCache.getValue();
|
||||
if (result != null) {
|
||||
updateState(channelUID, new StringType(result.get("soundField")));
|
||||
}
|
||||
}
|
||||
if (command instanceof StringType) {
|
||||
logger.debug("handleSoundSettings set {}", command);
|
||||
connection.setSoundSettings("soundField", ((StringType) command).toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void handleNightMode(Command command, ChannelUID channelUID) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
logger.debug("handleNightMode RefreshType");
|
||||
Map<String, String> result = soundSettingsCache.getValue();
|
||||
if (result != null) {
|
||||
updateState(channelUID, new StringType(result.get("nightMode")));
|
||||
}
|
||||
}
|
||||
if (command instanceof OnOffType) {
|
||||
logger.debug("handleNightMode set {}", command);
|
||||
connection.setSoundSettings("nightMode", ((OnOffType) command) == OnOffType.ON ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePowerCommand(Command command, ChannelUID channelUID) throws IOException {
|
||||
handlePowerCommand(command, channelUID, 0);
|
||||
}
|
||||
|
||||
public void handlePowerCommand(Command command, ChannelUID channelUID, int zone) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
try {
|
||||
logger.debug("handlePowerCommand RefreshType {}", zone);
|
||||
Boolean result = powerCache[zone].getValue();
|
||||
updateState(channelUID, result ? OnOffType.ON : OnOffType.OFF);
|
||||
} catch (CompletionException ex) {
|
||||
throw new IOException(ex.getCause());
|
||||
}
|
||||
}
|
||||
if (command instanceof OnOffType) {
|
||||
logger.debug("handlePowerCommand set {} {}", zone, command);
|
||||
connection.setPower(((OnOffType) command) == OnOffType.ON, zone);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleInputCommand(Command command, ChannelUID channelUID) throws IOException {
|
||||
handleInputCommand(command, channelUID, 0);
|
||||
}
|
||||
|
||||
public void handleInputCommand(Command command, ChannelUID channelUID, int zone) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
logger.debug("handleInputCommand RefreshType {}", zone);
|
||||
try {
|
||||
SonyAudioConnection.SonyAudioInput result = inputCache[zone].getValue();
|
||||
if (result != null) {
|
||||
if (zone > 0) {
|
||||
input_zone.put(zone, result.input);
|
||||
}
|
||||
updateState(channelUID, inputSource(result.input));
|
||||
|
||||
if (result.radio_freq.isPresent()) {
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_RADIO_FREQ,
|
||||
new DecimalType(result.radio_freq.get() / 1000000.0));
|
||||
}
|
||||
}
|
||||
} catch (CompletionException ex) {
|
||||
throw new IOException(ex.getCause());
|
||||
}
|
||||
}
|
||||
if (command instanceof StringType) {
|
||||
logger.debug("handleInputCommand set {} {}", zone, command);
|
||||
connection.setInput(setInputCommand(command), zone);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleVolumeCommand(Command command, ChannelUID channelUID) throws IOException {
|
||||
handleVolumeCommand(command, channelUID, 0);
|
||||
}
|
||||
|
||||
public void handleVolumeCommand(Command command, ChannelUID channelUID, int zone) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
try {
|
||||
logger.debug("handleVolumeCommand RefreshType {}", zone);
|
||||
SonyAudioConnection.SonyAudioVolume result = volumeCache[zone].getValue();
|
||||
if (result != null) {
|
||||
updateState(channelUID, new PercentType(result.volume));
|
||||
}
|
||||
} catch (CompletionException ex) {
|
||||
throw new IOException(ex.getCause());
|
||||
}
|
||||
}
|
||||
if (command instanceof PercentType) {
|
||||
logger.debug("handleVolumeCommand PercentType set {} {}", zone, command);
|
||||
connection.setVolume(((PercentType) command).intValue(), zone);
|
||||
}
|
||||
if (command instanceof IncreaseDecreaseType) {
|
||||
logger.debug("handleVolumeCommand IncreaseDecreaseType set {} {}", zone, command);
|
||||
String change = command == IncreaseDecreaseType.INCREASE ? "+1" : "-1";
|
||||
connection.setVolume(change, zone);
|
||||
}
|
||||
if (command instanceof OnOffType) {
|
||||
logger.debug("handleVolumeCommand OnOffType set {} {}", zone, command);
|
||||
connection.setMute(((OnOffType) command) == OnOffType.ON, zone);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleMuteCommand(Command command, ChannelUID channelUID) throws IOException {
|
||||
handleMuteCommand(command, channelUID, 0);
|
||||
}
|
||||
|
||||
public void handleMuteCommand(Command command, ChannelUID channelUID, int zone) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
try {
|
||||
logger.debug("handleMuteCommand RefreshType {}", zone);
|
||||
SonyAudioConnection.SonyAudioVolume result = volumeCache[zone].getValue();
|
||||
if (result != null) {
|
||||
updateState(channelUID, result.mute ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
} catch (CompletionException ex) {
|
||||
throw new IOException(ex.getCause());
|
||||
}
|
||||
}
|
||||
if (command instanceof OnOffType) {
|
||||
logger.debug("handleMuteCommand set {} {}", zone, command);
|
||||
connection.setMute(((OnOffType) command) == OnOffType.ON, zone);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRadioCommand(Command command, ChannelUID channelUID) throws IOException {
|
||||
}
|
||||
|
||||
public void handleRadioStationCommand(Command command, ChannelUID channelUID) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
updateState(channelUID, new DecimalType(currentRadioStation));
|
||||
}
|
||||
if (command instanceof DecimalType) {
|
||||
currentRadioStation = ((DecimalType) command).intValue();
|
||||
String radioCommand = "radio:fm?contentId=" + currentRadioStation;
|
||||
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
String input = input_zone.get(i);
|
||||
if (input != null && input.startsWith("radio:fm")) {
|
||||
connection.setInput(radioCommand, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRadioSeekStationCommand(Command command, ChannelUID channelUID) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
updateState(channelUID, new StringType(""));
|
||||
}
|
||||
if (command instanceof StringType) {
|
||||
switch (((StringType) command).toString()) {
|
||||
case "fwdSeeking":
|
||||
connection.radioSeekFwd();
|
||||
break;
|
||||
case "bwdSeeking":
|
||||
connection.radioSeekBwd();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract String setInputCommand(Command command);
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
Configuration config = getThing().getConfiguration();
|
||||
String ipAddress = (String) config.get(SonyAudioBindingConstants.HOST_PARAMETER);
|
||||
String path = (String) config.get(SonyAudioBindingConstants.SCALAR_PATH_PARAMETER);
|
||||
Object port_o = config.get(SonyAudioBindingConstants.SCALAR_PORT_PARAMETER);
|
||||
int port = 10000;
|
||||
if (port_o instanceof BigDecimal) {
|
||||
port = ((BigDecimal) port_o).intValue();
|
||||
} else if (port_o instanceof Integer) {
|
||||
port = (int) port_o;
|
||||
}
|
||||
|
||||
Object refresh_o = config.get(SonyAudioBindingConstants.REFRESHINTERVAL);
|
||||
int refresh = 0;
|
||||
if (refresh_o instanceof BigDecimal) {
|
||||
refresh = ((BigDecimal) refresh_o).intValue();
|
||||
} else if (refresh_o instanceof Integer) {
|
||||
refresh = (int) refresh_o;
|
||||
}
|
||||
|
||||
try {
|
||||
connection = new SonyAudioConnection(ipAddress, port, path, this, scheduler, webSocketClient);
|
||||
|
||||
Runnable connectionChecker = () -> {
|
||||
try {
|
||||
if (!connection.checkConnection()) {
|
||||
if (getThing().getStatus() != ThingStatus.OFFLINE) {
|
||||
logger.debug("Lost connection");
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Exception in check connection to @{}. Cause: {}", connection.getConnectionName(),
|
||||
ex.getMessage(), ex);
|
||||
}
|
||||
};
|
||||
|
||||
connectionCheckerFuture = scheduler.scheduleWithFixedDelay(connectionChecker, 1, 10, TimeUnit.SECONDS);
|
||||
|
||||
// Start the status updater
|
||||
startAutomaticRefresh(refresh);
|
||||
} catch (URISyntaxException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing SonyAudioHandler");
|
||||
super.dispose();
|
||||
if (connectionCheckerFuture != null) {
|
||||
connectionCheckerFuture.cancel(true);
|
||||
connectionCheckerFuture = null;
|
||||
}
|
||||
if (refreshJob != null) {
|
||||
refreshJob.cancel(true);
|
||||
refreshJob = null;
|
||||
}
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateConnectionState(boolean connected) {
|
||||
logger.debug("Changing connection status to {}", connected);
|
||||
if (connected) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateInput(int zone, SonyAudioConnection.SonyAudioInput input) {
|
||||
inputCache[zone].putValue(input);
|
||||
switch (zone) {
|
||||
case 0:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_INPUT, inputSource(input.input));
|
||||
break;
|
||||
case 1:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE1_INPUT, inputSource(input.input));
|
||||
break;
|
||||
case 2:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE2_INPUT, inputSource(input.input));
|
||||
break;
|
||||
case 3:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE3_INPUT, inputSource(input.input));
|
||||
break;
|
||||
case 4:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE4_INPUT, inputSource(input.input));
|
||||
break;
|
||||
}
|
||||
|
||||
if (input.radio_freq.isPresent()) {
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_RADIO_FREQ,
|
||||
new DecimalType(input.radio_freq.get() / 1000000.0));
|
||||
}
|
||||
}
|
||||
|
||||
public abstract StringType inputSource(String input);
|
||||
|
||||
@Override
|
||||
public void updateCurrentRadioStation(int radioStation) {
|
||||
currentRadioStation = radioStation;
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_RADIO_STATION, new DecimalType(currentRadioStation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSeekStation(String seek) {
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_RADIO_SEEK_STATION, new StringType(seek));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateVolume(int zone, SonyAudioConnection.SonyAudioVolume volume) {
|
||||
volumeCache[zone].putValue(volume);
|
||||
switch (zone) {
|
||||
case 0:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_VOLUME, new PercentType(volume.volume));
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_MUTE, volume.mute ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 1:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE1_VOLUME, new PercentType(volume.volume));
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE1_MUTE, volume.mute ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 2:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE2_VOLUME, new PercentType(volume.volume));
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE2_MUTE, volume.mute ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 3:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE3_VOLUME, new PercentType(volume.volume));
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE3_MUTE, volume.mute ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 4:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE4_VOLUME, new PercentType(volume.volume));
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE4_MUTE, volume.mute ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePowerStatus(int zone, boolean power) {
|
||||
powerCache[zone].invalidateValue();
|
||||
switch (zone) {
|
||||
case 0:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_POWER, power ? OnOffType.ON : OnOffType.OFF);
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_MASTER_POWER, power ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 1:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE1_POWER, power ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 2:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE2_POWER, power ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 3:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE3_POWER, power ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
case 4:
|
||||
updateState(SonyAudioBindingConstants.CHANNEL_ZONE4_POWER, power ? OnOffType.ON : OnOffType.OFF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void startAutomaticRefresh(int refresh) {
|
||||
if (refresh <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
List<Channel> channels = getThing().getChannels();
|
||||
for (Channel channel : channels) {
|
||||
if (!isLinked(channel.getUID())) {
|
||||
continue;
|
||||
}
|
||||
handleCommand(channel.getUID(), RefreshType.REFRESH);
|
||||
}
|
||||
}, 5, refresh, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link SrsZr5Handler} is responsible for handling commands for SRS-ZR5, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class SrsZr5Handler extends SonyAudioHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SrsZr5Handler.class);
|
||||
|
||||
public SrsZr5Handler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing, webSocketClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setInputCommand(Command command) {
|
||||
switch (command.toString().toLowerCase()) {
|
||||
case "btaudio":
|
||||
return "extInput:btAudio";
|
||||
case "usb":
|
||||
return "storage:usb1";
|
||||
case "analog":
|
||||
return "extInput:line?port=1";
|
||||
case "hdmi":
|
||||
return "extInput:hdmi";
|
||||
case "network":
|
||||
return "dlna:music";
|
||||
case "cast":
|
||||
return "cast:audio";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringType inputSource(String input) {
|
||||
String in = input.toLowerCase();
|
||||
if (in.contains("extinput:btaudio".toLowerCase())) {
|
||||
return new StringType("btaudio");
|
||||
}
|
||||
if (in.contains("storage:usb1".toLowerCase())) {
|
||||
return new StringType("usb");
|
||||
}
|
||||
if (in.contains("extinput:line?port=1".toLowerCase())) {
|
||||
return new StringType("analog");
|
||||
}
|
||||
if (in.contains("extinput:hdmi".toLowerCase())) {
|
||||
return new StringType("hdmi1");
|
||||
}
|
||||
if (in.contains("dlna:music".toLowerCase())) {
|
||||
return new StringType("network");
|
||||
}
|
||||
if (in.contains("cast:audio".toLowerCase())) {
|
||||
return new StringType("cast");
|
||||
}
|
||||
return new StringType(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSoundSettings(Command command, ChannelUID channelUID) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
try {
|
||||
logger.debug("SrsZr5Handler handleSoundSettings RefreshType");
|
||||
Map<String, String> result = soundSettingsCache.getValue();
|
||||
if (result != null) {
|
||||
logger.debug("SrsZr5Handler Updating sound field to {} {}", result.get("clearAudio"),
|
||||
result.get("soundField"));
|
||||
if (result.get("clearAudio").equalsIgnoreCase("on")) {
|
||||
updateState(channelUID, new StringType("clearAudio"));
|
||||
} else {
|
||||
updateState(channelUID, new StringType(result.get("soundField")));
|
||||
}
|
||||
}
|
||||
} catch (CompletionException ex) {
|
||||
throw new IOException(ex.getCause());
|
||||
}
|
||||
}
|
||||
if (command instanceof StringType) {
|
||||
if (((StringType) command).toString().equalsIgnoreCase("clearAudio")) {
|
||||
connection.setSoundSettings("clearAudio", "on");
|
||||
} else {
|
||||
connection.setSoundSettings("soundField", ((StringType) command).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link StrDn1080Handler} is responsible for handling commands for STR-DN1080, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class StrDn1080Handler extends SonyAudioHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(StrDn1080Handler.class);
|
||||
|
||||
public StrDn1080Handler(Thing thing, WebSocketClient webSocketClient) {
|
||||
super(thing, webSocketClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setInputCommand(Command command) {
|
||||
switch (command.toString().toLowerCase()) {
|
||||
case "btaudio":
|
||||
return "extInput:btAudio";
|
||||
case "fm":
|
||||
return "radio:fm";
|
||||
case "usb":
|
||||
return "storage:usb1";
|
||||
case "bd/dvd":
|
||||
return "extInput:bd-dvd";
|
||||
case "game":
|
||||
return "extInput:game";
|
||||
case "sat/catv":
|
||||
return "extInput:sat-catv";
|
||||
case "video1":
|
||||
return "extInput:video?port=1";
|
||||
case "video2":
|
||||
return "extInput:video?port=2";
|
||||
case "tv":
|
||||
return "extInput:tv";
|
||||
case "sa-cd/cd":
|
||||
return "extInput:sacd-cd";
|
||||
case "network":
|
||||
return "dlna:music";
|
||||
case "source":
|
||||
return "extInput:source";
|
||||
case "cast":
|
||||
return "cast:audio";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringType inputSource(String input) {
|
||||
String in = input.toLowerCase();
|
||||
if (in.contains("extinput:btaudio".toLowerCase())) {
|
||||
return new StringType("btaudio");
|
||||
}
|
||||
if (in.contains("radio:fm".toLowerCase())) {
|
||||
return new StringType("fm");
|
||||
}
|
||||
if (in.contains("storage:usb1".toLowerCase())) {
|
||||
return new StringType("usb");
|
||||
}
|
||||
if (in.contains("extInput:bd-dvd".toLowerCase())) {
|
||||
return new StringType("bd/dvd");
|
||||
}
|
||||
if (in.contains("extInput:game".toLowerCase())) {
|
||||
return new StringType("game");
|
||||
}
|
||||
if (in.contains("extInput:sat-catv".toLowerCase())) {
|
||||
return new StringType("sat/catv");
|
||||
}
|
||||
if (in.contains("extInput:video?port=1".toLowerCase())) {
|
||||
return new StringType("video1");
|
||||
}
|
||||
if (in.contains("extInput:video?port=2".toLowerCase())) {
|
||||
return new StringType("video2");
|
||||
}
|
||||
if (in.contains("extinput:tv".toLowerCase())) {
|
||||
return new StringType("tv");
|
||||
}
|
||||
if (in.contains("extInput:sacd-cd".toLowerCase())) {
|
||||
return new StringType("sa-cd/cd");
|
||||
}
|
||||
if (in.contains("dlna:music".toLowerCase())) {
|
||||
return new StringType("network");
|
||||
}
|
||||
if (in.contains("extInput:source".toLowerCase())) {
|
||||
return new StringType("source");
|
||||
}
|
||||
if (in.contains("cast:audio".toLowerCase())) {
|
||||
return new StringType("cast");
|
||||
}
|
||||
return new StringType(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSoundSettings(Command command, ChannelUID channelUID) throws IOException {
|
||||
if (command instanceof RefreshType) {
|
||||
try {
|
||||
logger.debug("StrDn1080Handler handleSoundSettings RefreshType");
|
||||
Map<String, String> result = soundSettingsCache.getValue();
|
||||
|
||||
if (result != null) {
|
||||
logger.debug("StrDn1080Handler Updateing sound field to {} {}", result.get("pureDirect"),
|
||||
result.get("soundField"));
|
||||
if (result.get("pureDirect").equalsIgnoreCase("on")) {
|
||||
updateState(channelUID, new StringType("pureDirect"));
|
||||
} else {
|
||||
updateState(channelUID, new StringType(result.get("soundField")));
|
||||
}
|
||||
}
|
||||
} catch (CompletionException ex) {
|
||||
throw new IOException(ex.getCause());
|
||||
}
|
||||
}
|
||||
if (command instanceof StringType) {
|
||||
if (((StringType) command).toString().equalsIgnoreCase("pureDirect")) {
|
||||
connection.setSoundSettings("pureDirect", "on");
|
||||
} else {
|
||||
connection.setSoundSettings("soundField", ((StringType) command).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioConnection} is responsible for communicating with SONY audio products
|
||||
* handlers.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class SonyAudioClientSocket {
|
||||
private final Logger logger = LoggerFactory.getLogger(SonyAudioClientSocket.class);
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private static final int REQUEST_TIMEOUT_MS = 60000;
|
||||
|
||||
private CountDownLatch commandLatch = null;
|
||||
private JsonObject commandResponse = null;
|
||||
private int nextMessageId = 1;
|
||||
|
||||
private boolean connected = false;
|
||||
|
||||
private final URI uri;
|
||||
private Session session;
|
||||
|
||||
private final JsonParser parser = new JsonParser();
|
||||
private final Gson mapper;
|
||||
|
||||
private static int ping = 0;
|
||||
|
||||
private final SonyAudioClientSocketEventListener eventHandler;
|
||||
|
||||
public SonyAudioClientSocket(SonyAudioClientSocketEventListener eventHandler, URI uri,
|
||||
ScheduledExecutorService scheduler) {
|
||||
mapper = new GsonBuilder().disableHtmlEscaping().create();
|
||||
this.eventHandler = eventHandler;
|
||||
this.uri = uri;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public synchronized void open(WebSocketClient webSocketClient) {
|
||||
try {
|
||||
if (isConnected()) {
|
||||
logger.warn("connect: connection is already open");
|
||||
}
|
||||
|
||||
SonyAudioWebSocketListener socket = new SonyAudioWebSocketListener();
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
|
||||
try {
|
||||
webSocketClient.connect(socket, uri, request).get(1, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
logger.debug("Could not establish websocket within a second.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.debug("Exception then trying to start the websocket {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
logger.debug("Closing socket {}", uri);
|
||||
// if there is an old web socket then clean up and destroy
|
||||
if (session != null) {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
logger.debug("Exception during closing the websocket session {}", e.getMessage(), e);
|
||||
}
|
||||
session = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
if (session == null || !session.isOpen()) {
|
||||
connected = false;
|
||||
return connected;
|
||||
}
|
||||
|
||||
RemoteEndpoint remote = session.getRemote();
|
||||
|
||||
ByteBuffer payload = ByteBuffer.allocate(4).putInt(ping++);
|
||||
try {
|
||||
remote.sendPing(payload);
|
||||
} catch (IOException e) {
|
||||
logger.warn("Connection to {} lost: {}", uri, e.getMessage());
|
||||
connected = false;
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public class SonyAudioWebSocketListener {
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session wssession) {
|
||||
logger.debug("Connected to server");
|
||||
session = wssession;
|
||||
connected = true;
|
||||
if (eventHandler != null) {
|
||||
scheduler.submit(() -> {
|
||||
try {
|
||||
eventHandler.onConnectionOpened(uri);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling onConnectionOpened() {}", e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String message) {
|
||||
logger.debug("Message received from server: {}", message);
|
||||
try {
|
||||
final JsonObject json = parser.parse(message).getAsJsonObject();
|
||||
if (json.has("id")) {
|
||||
logger.debug("Response received from server: {}", json);
|
||||
int messageId = json.get("id").getAsInt();
|
||||
if (messageId == nextMessageId - 1) {
|
||||
commandResponse = json;
|
||||
commandLatch.countDown();
|
||||
}
|
||||
} else {
|
||||
logger.debug("Event received from server: {}", json);
|
||||
try {
|
||||
if (eventHandler != null) {
|
||||
scheduler.submit(() -> {
|
||||
try {
|
||||
eventHandler.handleEvent(json);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling event {} player state change message: {}", json,
|
||||
e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling player state change message", e);
|
||||
}
|
||||
}
|
||||
} catch (JsonParseException e) {
|
||||
logger.debug("Not valid JSON message: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason) {
|
||||
session = null;
|
||||
connected = false;
|
||||
logger.debug("Closing a WebSocket due to {}", reason);
|
||||
scheduler.submit(() -> {
|
||||
try {
|
||||
eventHandler.onConnectionClosed();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling onConnectionClosed()", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable error) {
|
||||
onClose(0, error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMessage(String str) throws IOException {
|
||||
if (isConnected()) {
|
||||
logger.debug("send message fo {}: {}", uri.toString(), str);
|
||||
session.getRemote().sendString(str);
|
||||
} else {
|
||||
String stack = "";
|
||||
stack += "Printing stack trace:\n";
|
||||
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
|
||||
for (int i = 1; i < elements.length; i++) {
|
||||
StackTraceElement s = elements[i];
|
||||
stack += "\tat " + s.getClassName() + "." + s.getMethodName() + "(" + s.getFileName() + ":"
|
||||
+ s.getLineNumber() + ")\n";
|
||||
}
|
||||
logger.error("Socket not initialized, trying to send {} {}", str, stack);
|
||||
throw new IOException("Socket not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized JsonElement callMethod(SonyAudioMethod method) throws IOException {
|
||||
try {
|
||||
method.id = nextMessageId;
|
||||
String message = mapper.toJson(method);
|
||||
logger.debug("callMethod send {}", message);
|
||||
|
||||
commandLatch = new CountDownLatch(1);
|
||||
commandResponse = null;
|
||||
nextMessageId++;
|
||||
|
||||
sendMessage(message);
|
||||
if (commandLatch.await(REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
|
||||
logger.debug("callMethod {} returns {}", uri.toString(), commandResponse.toString());
|
||||
return commandResponse.get("result");
|
||||
} else {
|
||||
logger.debug("Timeout during callMethod({}, {})", method.method, message);
|
||||
throw new IOException("Timeout during callMethod");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException("Timeout in callMethod");
|
||||
}
|
||||
}
|
||||
|
||||
public URI getURI() {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.protocol;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioClientSocketEventListener} socket event listener
|
||||
* handlers.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public interface SonyAudioClientSocketEventListener {
|
||||
void handleEvent(JsonObject json);
|
||||
|
||||
void onConnectionClosed();
|
||||
|
||||
void onConnectionOpened(URI resource);
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.protocol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.openhab.binding.sonyaudio.internal.SonyAudioEventListener;
|
||||
import org.openhab.binding.sonyaudio.internal.protocol.SwitchNotifications.Notification;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioConnection} is responsible for communicating with SONY audio products
|
||||
* handlers.
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public class SonyAudioConnection implements SonyAudioClientSocketEventListener {
|
||||
private final Logger logger = LoggerFactory.getLogger(SonyAudioConnection.class);
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
private final String path;
|
||||
private final URI base_uri;
|
||||
|
||||
private final WebSocketClient webSocketClient;
|
||||
|
||||
private SonyAudioClientSocket avContentSocket;
|
||||
private SonyAudioClientSocket audioSocket;
|
||||
private SonyAudioClientSocket systemSocket;
|
||||
|
||||
private final SonyAudioEventListener listener;
|
||||
|
||||
private int min_volume = 0;
|
||||
private int max_volume = 50;
|
||||
|
||||
private final Gson gson;
|
||||
|
||||
public SonyAudioConnection(String host, int port, String path, SonyAudioEventListener listener,
|
||||
ScheduledExecutorService scheduler, WebSocketClient webSocketClient) throws URISyntaxException {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.path = path;
|
||||
this.listener = listener;
|
||||
this.gson = new Gson();
|
||||
this.webSocketClient = webSocketClient;
|
||||
|
||||
base_uri = new URI(String.format("ws://%s:%d/%s", host, port, path)).normalize();
|
||||
|
||||
URI wsAvContentUri = base_uri.resolve(base_uri.getPath() + "/avContent").normalize();
|
||||
avContentSocket = new SonyAudioClientSocket(this, wsAvContentUri, scheduler);
|
||||
URI wsAudioUri = base_uri.resolve(base_uri.getPath() + "/audio").normalize();
|
||||
audioSocket = new SonyAudioClientSocket(this, wsAudioUri, scheduler);
|
||||
|
||||
URI wsSystemUri = base_uri.resolve(base_uri.getPath() + "/system").normalize();
|
||||
systemSocket = new SonyAudioClientSocket(this, wsSystemUri, scheduler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(JsonObject json) {
|
||||
int zone = 0;
|
||||
JsonObject param;
|
||||
|
||||
try {
|
||||
param = json.getAsJsonArray("params").get(0).getAsJsonObject();
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("Invalid json in handleEvent");
|
||||
return;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
logger.debug("Invalid json in handleEvent");
|
||||
return;
|
||||
}
|
||||
|
||||
if (param == null) {
|
||||
logger.debug("Unable to get params form json in handleEvent");
|
||||
return;
|
||||
}
|
||||
|
||||
if (param.has("output")) {
|
||||
String outputStr = param.get("output").getAsString();
|
||||
Pattern pattern = Pattern.compile(".*zone=(\\d+)");
|
||||
Matcher m = pattern.matcher(outputStr);
|
||||
if (m.matches()) {
|
||||
try {
|
||||
zone = Integer.parseInt(m.group(1));
|
||||
} catch (NumberFormatException e) {
|
||||
logger.error("This should never happen, pattern should only match integers");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.get("method").getAsString().equalsIgnoreCase("notifyPlayingContentInfo")) {
|
||||
SonyAudioInput input = new SonyAudioInput();
|
||||
input.input = param.get("uri").getAsString();
|
||||
if (param.has("broadcastFreq")) {
|
||||
int freq = param.get("broadcastFreq").getAsInt();
|
||||
input.radio_freq = Optional.of(freq);
|
||||
checkRadioPreset(input.input);
|
||||
}
|
||||
listener.updateInput(zone, input);
|
||||
listener.updateSeekStation("");
|
||||
}
|
||||
|
||||
if (json.get("method").getAsString().equalsIgnoreCase("notifyVolumeInformation")) {
|
||||
SonyAudioVolume volume = new SonyAudioVolume();
|
||||
|
||||
int rawVolume = param.get("volume").getAsInt();
|
||||
volume.volume = Math.round(100 * (rawVolume - min_volume) / (max_volume - min_volume));
|
||||
|
||||
volume.mute = param.get("mute").getAsString().equalsIgnoreCase("on");
|
||||
listener.updateVolume(zone, volume);
|
||||
}
|
||||
|
||||
if (json.get("method").getAsString().equalsIgnoreCase("notifyPowerStatus")) {
|
||||
String power = param.get("status").getAsString();
|
||||
listener.updatePowerStatus(zone, power.equalsIgnoreCase("active"));
|
||||
}
|
||||
|
||||
listener.updateConnectionState(true);
|
||||
}
|
||||
|
||||
private void checkRadioPreset(String input) {
|
||||
Pattern pattern = Pattern.compile(".*contentId=(\\d+)");
|
||||
Matcher m = pattern.matcher(input);
|
||||
if (m.matches()) {
|
||||
listener.updateCurrentRadioStation(Integer.parseInt(m.group(1)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onConnectionClosed() {
|
||||
listener.updateConnectionState(false);
|
||||
}
|
||||
|
||||
private class Notifications {
|
||||
public List<Notification> enabled;
|
||||
public List<Notification> disabled;
|
||||
}
|
||||
|
||||
private Notifications getSwitches(SonyAudioClientSocket socket, Notifications notifications) throws IOException {
|
||||
SwitchNotifications switchNotifications = new SwitchNotifications(notifications.enabled,
|
||||
notifications.disabled);
|
||||
JsonElement switches = socket.callMethod(switchNotifications);
|
||||
|
||||
Type notificationListType = new TypeToken<List<Notification>>() {
|
||||
}.getType();
|
||||
notifications.enabled = gson.fromJson(switches.getAsJsonArray().get(0).getAsJsonObject().get("enabled"),
|
||||
notificationListType);
|
||||
notifications.disabled = gson.fromJson(switches.getAsJsonArray().get(0).getAsJsonObject().get("disabled"),
|
||||
notificationListType);
|
||||
|
||||
return notifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onConnectionOpened(URI resource) {
|
||||
try {
|
||||
Notifications notifications = new Notifications();
|
||||
notifications.enabled = Arrays.asList(new Notification[] {});
|
||||
notifications.disabled = Arrays.asList(new Notification[] {});
|
||||
|
||||
if (avContentSocket.getURI().equals(resource)) {
|
||||
notifications = getSwitches(avContentSocket, notifications);
|
||||
|
||||
for (Iterator<Notification> iter = notifications.disabled.listIterator(); iter.hasNext();) {
|
||||
Notification a = iter.next();
|
||||
if (a.name.equalsIgnoreCase("notifyPlayingContentInfo")) {
|
||||
notifications.enabled.add(a);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
SwitchNotifications switchNotifications = new SwitchNotifications(notifications.enabled,
|
||||
notifications.disabled);
|
||||
avContentSocket.callMethod(switchNotifications);
|
||||
}
|
||||
|
||||
if (audioSocket.getURI().equals(resource)) {
|
||||
notifications = getSwitches(audioSocket, notifications);
|
||||
|
||||
for (Iterator<Notification> iter = notifications.disabled.listIterator(); iter.hasNext();) {
|
||||
Notification a = iter.next();
|
||||
if (a.name.equalsIgnoreCase("notifyVolumeInformation")) {
|
||||
notifications.enabled.add(a);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
SwitchNotifications switchNotifications = new SwitchNotifications(notifications.enabled,
|
||||
notifications.disabled);
|
||||
audioSocket.callMethod(switchNotifications);
|
||||
}
|
||||
|
||||
if (systemSocket.getURI().equals(resource)) {
|
||||
notifications = getSwitches(systemSocket, notifications);
|
||||
|
||||
for (Iterator<Notification> iter = notifications.disabled.listIterator(); iter.hasNext();) {
|
||||
Notification a = iter.next();
|
||||
if (a.name.equalsIgnoreCase("notifyPowerStatus")) {
|
||||
notifications.enabled.add(a);
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
SwitchNotifications switchNotifications = new SwitchNotifications(notifications.enabled,
|
||||
notifications.disabled);
|
||||
systemSocket.callMethod(switchNotifications);
|
||||
}
|
||||
listener.updateConnectionState(true);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to setup connection");
|
||||
listener.updateConnectionState(false);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
logger.debug("SonyAudio closing connections");
|
||||
if (avContentSocket != null) {
|
||||
avContentSocket.close();
|
||||
}
|
||||
avContentSocket = null;
|
||||
|
||||
if (audioSocket != null) {
|
||||
audioSocket.close();
|
||||
}
|
||||
audioSocket = null;
|
||||
|
||||
if (systemSocket != null) {
|
||||
systemSocket.close();
|
||||
}
|
||||
systemSocket = null;
|
||||
}
|
||||
|
||||
private boolean checkConnection(SonyAudioClientSocket socket) {
|
||||
if (!socket.isConnected()) {
|
||||
logger.debug("checkConnection: try to connect to {}", socket.getURI().toString());
|
||||
socket.open(webSocketClient);
|
||||
return socket.isConnected();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkConnection() {
|
||||
return checkConnection(avContentSocket) && checkConnection(audioSocket) && checkConnection(systemSocket);
|
||||
}
|
||||
|
||||
public String getConnectionName() {
|
||||
if (base_uri != null) {
|
||||
return base_uri.toString();
|
||||
}
|
||||
return String.format("ws://%s:%d/%s", host, port, path);
|
||||
}
|
||||
|
||||
public Boolean getPower(int zone) throws IOException {
|
||||
if (zone > 0) {
|
||||
if (avContentSocket == null) {
|
||||
throw new IOException("AvContent Socket not connected");
|
||||
}
|
||||
GetCurrentExternalTerminalsStatus getCurrentExternalTerminalsStatus = new GetCurrentExternalTerminalsStatus();
|
||||
JsonElement element = avContentSocket.callMethod(getCurrentExternalTerminalsStatus);
|
||||
|
||||
if (element != null && element.isJsonArray()) {
|
||||
Iterator<JsonElement> terminals = element.getAsJsonArray().get(0).getAsJsonArray().iterator();
|
||||
while (terminals.hasNext()) {
|
||||
JsonObject terminal = terminals.next().getAsJsonObject();
|
||||
String uri = terminal.get("uri").getAsString();
|
||||
if (uri.equalsIgnoreCase("extOutput:zone?zone=" + Integer.toString(zone))) {
|
||||
return terminal.get("active").getAsString().equalsIgnoreCase("active") ? true : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IOException(
|
||||
"Unexpected responses: Unable to parse GetCurrentExternalTerminalsStatus response message");
|
||||
} else {
|
||||
if (systemSocket == null) {
|
||||
throw new IOException("System Socket not connected");
|
||||
}
|
||||
|
||||
GetPowerStatus getPowerStatus = new GetPowerStatus();
|
||||
JsonElement element = systemSocket.callMethod(getPowerStatus);
|
||||
|
||||
if (element != null && element.isJsonArray()) {
|
||||
String powerStatus = element.getAsJsonArray().get(0).getAsJsonObject().get("status").getAsString();
|
||||
return powerStatus.equalsIgnoreCase("active") ? true : false;
|
||||
}
|
||||
throw new IOException("Unexpected responses: Unable to parse GetPowerStatus response message");
|
||||
}
|
||||
}
|
||||
|
||||
public void setPower(boolean power) throws IOException {
|
||||
setPower(power, 0);
|
||||
}
|
||||
|
||||
public void setPower(boolean power, int zone) throws IOException {
|
||||
if (zone > 0) {
|
||||
if (avContentSocket == null) {
|
||||
throw new IOException("AvContent Socket not connected");
|
||||
}
|
||||
SetActiveTerminal setActiveTerminal = new SetActiveTerminal(power, zone);
|
||||
avContentSocket.callMethod(setActiveTerminal);
|
||||
} else {
|
||||
if (systemSocket == null) {
|
||||
throw new IOException("System Socket not connected");
|
||||
}
|
||||
SetPowerStatus setPowerStatus = new SetPowerStatus(power);
|
||||
systemSocket.callMethod(setPowerStatus);
|
||||
}
|
||||
}
|
||||
|
||||
public class SonyAudioInput {
|
||||
public String input = "";
|
||||
public Optional<Integer> radio_freq = Optional.empty();
|
||||
}
|
||||
|
||||
public SonyAudioInput getInput() throws IOException {
|
||||
GetPlayingContentInfo getPlayingContentInfo = new GetPlayingContentInfo();
|
||||
return getInput(getPlayingContentInfo);
|
||||
}
|
||||
|
||||
public SonyAudioInput getInput(int zone) throws IOException {
|
||||
GetPlayingContentInfo getPlayingContentInfo = new GetPlayingContentInfo(zone);
|
||||
return getInput(getPlayingContentInfo);
|
||||
}
|
||||
|
||||
private SonyAudioInput getInput(GetPlayingContentInfo getPlayingContentInfo) throws IOException {
|
||||
if (avContentSocket == null) {
|
||||
throw new IOException("AvContent Socket not connected");
|
||||
}
|
||||
JsonElement element = avContentSocket.callMethod(getPlayingContentInfo);
|
||||
|
||||
if (element != null && element.isJsonArray()) {
|
||||
SonyAudioInput ret = new SonyAudioInput();
|
||||
|
||||
JsonObject result = element.getAsJsonArray().get(0).getAsJsonArray().get(0).getAsJsonObject();
|
||||
String uri = result.get("uri").getAsString();
|
||||
checkRadioPreset(uri);
|
||||
ret.input = uri;
|
||||
|
||||
if (result.has("broadcastFreq")) {
|
||||
int freq = result.get("broadcastFreq").getAsInt();
|
||||
ret.radio_freq = Optional.of(freq);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
throw new IOException("Unexpected responses: Unable to parse GetPlayingContentInfo response message");
|
||||
}
|
||||
|
||||
public void setInput(String input) throws IOException {
|
||||
if (avContentSocket == null) {
|
||||
throw new IOException("AvContent Socket not connected");
|
||||
}
|
||||
SetPlayContent setPlayContent = new SetPlayContent(input);
|
||||
avContentSocket.callMethod(setPlayContent);
|
||||
}
|
||||
|
||||
public void setInput(String input, int zone) throws IOException {
|
||||
if (avContentSocket == null) {
|
||||
throw new IOException("AvContent Socket not connected");
|
||||
}
|
||||
SetPlayContent setPlayContent = new SetPlayContent(input, zone);
|
||||
avContentSocket.callMethod(setPlayContent);
|
||||
}
|
||||
|
||||
public void radioSeekFwd() throws IOException {
|
||||
if (avContentSocket == null) {
|
||||
throw new IOException("AvContent Socket not connected");
|
||||
}
|
||||
SeekBroadcastStation seekBroadcastStation = new SeekBroadcastStation(true);
|
||||
avContentSocket.callMethod(seekBroadcastStation);
|
||||
}
|
||||
|
||||
public void radioSeekBwd() throws IOException {
|
||||
if (avContentSocket == null) {
|
||||
throw new IOException("AvContent Socket not connected");
|
||||
}
|
||||
SeekBroadcastStation seekBroadcastStation = new SeekBroadcastStation(false);
|
||||
avContentSocket.callMethod(seekBroadcastStation);
|
||||
}
|
||||
|
||||
public class SonyAudioVolume {
|
||||
public Integer volume = 0;
|
||||
public Boolean mute = false;
|
||||
}
|
||||
|
||||
public SonyAudioVolume getVolume(int zone) throws IOException {
|
||||
GetVolumeInformation getVolumeInformation = new GetVolumeInformation(zone);
|
||||
|
||||
if (audioSocket == null || !audioSocket.isConnected()) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
JsonElement element = audioSocket.callMethod(getVolumeInformation);
|
||||
|
||||
if (element != null && element.isJsonArray()) {
|
||||
JsonObject result = element.getAsJsonArray().get(0).getAsJsonArray().get(0).getAsJsonObject();
|
||||
|
||||
SonyAudioVolume ret = new SonyAudioVolume();
|
||||
|
||||
int volume = result.get("volume").getAsInt();
|
||||
min_volume = result.get("minVolume").getAsInt();
|
||||
max_volume = result.get("maxVolume").getAsInt();
|
||||
int vol = Math.round(100 * (volume - min_volume) / (max_volume - min_volume));
|
||||
if (vol < 0) {
|
||||
vol = 0;
|
||||
}
|
||||
ret.volume = vol;
|
||||
|
||||
String mute = result.get("mute").getAsString();
|
||||
ret.mute = mute.equalsIgnoreCase("on") ? true : false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
throw new IOException("Unexpected responses: Unable to parse GetVolumeInformation response message");
|
||||
}
|
||||
|
||||
public void setVolume(int volume) throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
SetAudioVolume setAudioVolume = new SetAudioVolume(volume, min_volume, max_volume);
|
||||
audioSocket.callMethod(setAudioVolume);
|
||||
}
|
||||
|
||||
public void setVolume(String volumeChange) throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
SetAudioVolume setAudioVolume = new SetAudioVolume(volumeChange);
|
||||
audioSocket.callMethod(setAudioVolume);
|
||||
}
|
||||
|
||||
public void setVolume(int volume, int zone) throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
SetAudioVolume setAudioVolume = new SetAudioVolume(zone, volume, min_volume, max_volume);
|
||||
audioSocket.callMethod(setAudioVolume);
|
||||
}
|
||||
|
||||
public void setVolume(String volumeChange, int zone) throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
SetAudioVolume setAudioVolume = new SetAudioVolume(zone, volumeChange);
|
||||
audioSocket.callMethod(setAudioVolume);
|
||||
}
|
||||
|
||||
public void setMute(boolean mute) throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
SetAudioMute setAudioMute = new SetAudioMute(mute);
|
||||
audioSocket.callMethod(setAudioMute);
|
||||
}
|
||||
|
||||
public void setMute(boolean mute, int zone) throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
SetAudioMute setAudioMute = new SetAudioMute(mute, zone);
|
||||
audioSocket.callMethod(setAudioMute);
|
||||
}
|
||||
|
||||
public Map<String, String> getSoundSettings() throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
Map<String, String> m = new HashMap<>();
|
||||
|
||||
GetSoundSettings getSoundSettings = new GetSoundSettings();
|
||||
JsonElement element = audioSocket.callMethod(getSoundSettings);
|
||||
|
||||
if (element == null || !element.isJsonArray()) {
|
||||
throw new IOException("Unexpected responses: Unable to parse GetSoundSettings response message");
|
||||
}
|
||||
Iterator<JsonElement> iterator = element.getAsJsonArray().get(0).getAsJsonArray().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
JsonObject item = iterator.next().getAsJsonObject();
|
||||
|
||||
m.put(item.get("target").getAsString(), item.get("currentValue").getAsString());
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public void setSoundSettings(String target, String value) throws IOException {
|
||||
if (audioSocket == null) {
|
||||
throw new IOException("Audio Socket not connected");
|
||||
}
|
||||
SetSoundSettings setSoundSettings = new SetSoundSettings(target, value);
|
||||
audioSocket.callMethod(setSoundSettings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.sonyaudio.internal.protocol;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The {@link SonyAudioMethod} base class for SONY API methods
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
public abstract class SonyAudioMethod {
|
||||
protected int id = 1;
|
||||
protected String method;
|
||||
protected String version;
|
||||
|
||||
public SonyAudioMethod(String method, String version) {
|
||||
this.method = method;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link GetPowerStatus} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class GetPowerStatus extends SonyAudioMethod {
|
||||
public String[] params = new String[] {};
|
||||
|
||||
public GetPowerStatus() {
|
||||
super("getPowerStatus", "1.1");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link GetCurrentExternalTerminalsStatus} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class GetCurrentExternalTerminalsStatus extends SonyAudioMethod {
|
||||
public String[] params = new String[] {};
|
||||
|
||||
public GetCurrentExternalTerminalsStatus() {
|
||||
super("getCurrentExternalTerminalsStatus", "1.0");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetPowerStatus} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetPowerStatus extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
public String status;
|
||||
|
||||
Param(boolean power) {
|
||||
status = power ? "active" : "off";
|
||||
}
|
||||
}
|
||||
|
||||
SetPowerStatus(boolean power) {
|
||||
super("setPowerStatus", "1.1");
|
||||
Param param = new Param(power);
|
||||
params = new Param[] { param };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetActiveTerminal} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetActiveTerminal extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
public String active;
|
||||
public String uri;
|
||||
|
||||
Param(boolean power, int zone) {
|
||||
active = power ? "active" : "inactive";
|
||||
if (zone > 0) {
|
||||
uri = "extOutput:zone?zone=" + Integer.toString(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetActiveTerminal(boolean power, int zone) {
|
||||
super("setActiveTerminal", "1.0");
|
||||
Param param = new Param(power, zone);
|
||||
params = new Param[] { param };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link GetPlayingContentInfo} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class GetPlayingContentInfo extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
String output = "";
|
||||
|
||||
Param() {
|
||||
}
|
||||
|
||||
Param(int zone) {
|
||||
if (zone > 0) {
|
||||
output = "extOutput:zone?zone=" + Integer.toString(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GetPlayingContentInfo() {
|
||||
super("getPlayingContentInfo", "1.2");
|
||||
Param param = new Param();
|
||||
params = new Param[] { param };
|
||||
}
|
||||
|
||||
GetPlayingContentInfo(int zone) {
|
||||
super("getPlayingContentInfo", "1.2");
|
||||
Param param = new Param(zone);
|
||||
params = new Param[] { param };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetPlayContent} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetPlayContent extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
String output = "";
|
||||
String uri;
|
||||
|
||||
Param(String input) {
|
||||
uri = input;
|
||||
}
|
||||
|
||||
Param(String input, int zone) {
|
||||
uri = input;
|
||||
if (zone > 0) {
|
||||
output = "extOutput:zone?zone=" + Integer.toString(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetPlayContent(String input) {
|
||||
super("setPlayContent", "1.2");
|
||||
params = new Param[] { new Param(input) };
|
||||
}
|
||||
|
||||
SetPlayContent(String input, int zone) {
|
||||
super("setPlayContent", "1.2");
|
||||
params = new Param[] { new Param(input, zone) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link GetVolumeInformation} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class GetVolumeInformation extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
String output = "";
|
||||
|
||||
Param() {
|
||||
}
|
||||
|
||||
Param(int zone) {
|
||||
if (zone > 0) {
|
||||
output = "extOutput:zone?zone=" + Integer.toString(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GetVolumeInformation() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
GetVolumeInformation(int zone) {
|
||||
super("getVolumeInformation", "1.1");
|
||||
params = new Param[] { new Param(zone) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetAudioVolume} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetAudioVolume extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
String output = "";
|
||||
String volume;
|
||||
|
||||
Param(long new_volume) {
|
||||
volume = Long.toString(new_volume);
|
||||
}
|
||||
|
||||
Param(String volume_change) {
|
||||
volume = volume_change;
|
||||
}
|
||||
|
||||
Param(long new_volume, int zone) {
|
||||
volume = Long.toString(new_volume);
|
||||
if (zone > 0) {
|
||||
output = "extOutput:zone?zone=" + Integer.toString(zone);
|
||||
}
|
||||
}
|
||||
|
||||
Param(String volume_change, int zone) {
|
||||
volume = volume_change;
|
||||
if (zone > 0) {
|
||||
output = "extOutput:zone?zone=" + Integer.toString(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetAudioVolume(int volume, int min, int max) {
|
||||
super("setAudioVolume", "1.1");
|
||||
long scaled_volume = scaleVolume(volume, min, max);
|
||||
params = new Param[] { new Param(scaled_volume) };
|
||||
}
|
||||
|
||||
SetAudioVolume(int zone, int volume, int min, int max) {
|
||||
super("setAudioVolume", "1.1");
|
||||
long scaled_volume = scaleVolume(volume, min, max);
|
||||
params = new Param[] { new Param(scaled_volume, zone) };
|
||||
}
|
||||
|
||||
SetAudioVolume(String volume_change) {
|
||||
super("setAudioVolume", "1.1");
|
||||
params = new Param[] { new Param(volume_change) };
|
||||
}
|
||||
|
||||
SetAudioVolume(int zone, String volume_change) {
|
||||
super("setAudioVolume", "1.1");
|
||||
params = new Param[] { new Param(volume_change, zone) };
|
||||
}
|
||||
|
||||
long scaleVolume(int volume, int min, int max) {
|
||||
return Math.round(((max - min) * volume / 100.0) + min);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetAudioMute} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetAudioMute extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
String output = "";
|
||||
String mute;
|
||||
|
||||
Param(boolean mute) {
|
||||
this.mute = mute ? "on" : "off";
|
||||
}
|
||||
|
||||
Param(boolean mute, int zone) {
|
||||
this.mute = mute ? "on" : "off";
|
||||
if (zone > 0) {
|
||||
output = "extOutput:zone?zone=" + Integer.toString(zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetAudioMute(boolean mute) {
|
||||
super("setAudioMute", "1.1");
|
||||
params = new Param[] { new Param(mute) };
|
||||
}
|
||||
|
||||
SetAudioMute(boolean mute, int zone) {
|
||||
super("setAudioMute", "1.1");
|
||||
params = new Param[] { new Param(mute, zone) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class GetSoundSettings extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
String target;
|
||||
|
||||
Param(String target) {
|
||||
this.target = target;
|
||||
}
|
||||
}
|
||||
|
||||
GetSoundSettings() {
|
||||
super("getSoundSettings", "1.1");
|
||||
params = new Param[] { new Param("") };
|
||||
}
|
||||
|
||||
GetSoundSettings(String target) {
|
||||
super("getSoundSettings", "1.1");
|
||||
params = new Param[] { new Param(target) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetSoundSettings extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Settings {
|
||||
String value;
|
||||
String target;
|
||||
|
||||
Settings(String target, String value) {
|
||||
this.target = target;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
class Param {
|
||||
|
||||
Settings[] settings;
|
||||
|
||||
Param(Settings[] settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
}
|
||||
|
||||
SetSoundSettings() {
|
||||
super("setSoundSettings", "1.1");
|
||||
}
|
||||
|
||||
SetSoundSettings(String target, String value) {
|
||||
super("setSoundSettings", "1.1");
|
||||
Settings[] settings = { new Settings(target, value) };
|
||||
params = new Param[] { new Param(settings) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetSoundField} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetSoundField extends SetSoundSettings {
|
||||
SetSoundField(String soundField) {
|
||||
super("soundField", soundField);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetPureDirect} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetPureDirect extends SetSoundSettings {
|
||||
SetPureDirect(boolean pureDirect) {
|
||||
super("pureDirect", pureDirect ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SetClearAudio} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SetClearAudio extends SetSoundSettings {
|
||||
SetClearAudio(boolean clearAudio) {
|
||||
super("clearAudio", clearAudio ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SwitchNotifications} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SwitchNotifications extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Notification {
|
||||
String name;
|
||||
String version;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Notification{name='" + name + "' version='" + version + "'}";
|
||||
}
|
||||
}
|
||||
|
||||
class Param {
|
||||
List<Notification> enabled;
|
||||
List<Notification> disabled;
|
||||
|
||||
Param(List<Notification> enabled, List<Notification> disabled) {
|
||||
this.enabled = enabled;
|
||||
this.disabled = disabled;
|
||||
}
|
||||
}
|
||||
|
||||
SwitchNotifications(List<Notification> enabled, List<Notification> disabled) {
|
||||
super("switchNotifications", "1.0");
|
||||
params = new Param[] { new Param(!enabled.isEmpty() ? enabled : null, !disabled.isEmpty() ? disabled : null) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link SeekBroadcastStation} SONY Audio control API method
|
||||
*
|
||||
* @author David Åberg - Initial contribution
|
||||
*/
|
||||
class SeekBroadcastStation extends SonyAudioMethod {
|
||||
public Param[] params;
|
||||
|
||||
class Param {
|
||||
String tuning = "auto";
|
||||
String direction;
|
||||
|
||||
Param(boolean forward) {
|
||||
this.direction = forward ? "fwd" : "bwd";
|
||||
}
|
||||
}
|
||||
|
||||
SeekBroadcastStation(boolean forward) {
|
||||
super("seekBroadcastStation", "1.0");
|
||||
params = new Param[] { new Param(forward) };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="sonyaudio" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>SonyAudio Binding</name>
|
||||
<description>This is the binding for SonyAudio products (Receivers and wireless speakers).</description>
|
||||
<author>David Åberg</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="thing-type:sonyaudio:config">
|
||||
<parameter name="ipAddress" type="text">
|
||||
<label>Network Address</label>
|
||||
<description>The IP or host name of the SONY audio device</description>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" min="1" max="65535">
|
||||
<label>Port</label>
|
||||
<description>Port for the SONY audio device to control.
|
||||
Home Audio products usually use port 10000 and Personal Audio
|
||||
products usually use port 54480.</description>
|
||||
<default>10000</default>
|
||||
</parameter>
|
||||
<parameter name="path" type="text">
|
||||
<label>Base Path</label>
|
||||
<description>The base path, "/sony" in most cases</description>
|
||||
<default>/sony</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="refreshInterval" type="integer" min="0">
|
||||
<label>Refresh Interval</label>
|
||||
<description>The refresh interval in seconds for polling the receiver (0=disable). Binding receive automatically
|
||||
updates from
|
||||
</description>
|
||||
<default>300</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sonyaudio"
|
||||
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">
|
||||
|
||||
<!-- Commands -->
|
||||
<channel-type id="input-ct800">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="btaudio">Bluetooth Audio</option>
|
||||
<option value="tv">TV</option>
|
||||
<option value="hdmi1">HDMI1</option>
|
||||
<option value="hdmi2">HDMI2</option>
|
||||
<option value="hdmi3">HDMI3</option>
|
||||
<option value="analog">Analog</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="network">Home Network</option>
|
||||
<option value="cast">Chromecast</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sound-field-ct800">
|
||||
<item-type>String</item-type>
|
||||
<label>Sound Field</label>
|
||||
<description>Select the Sound Field for the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="clearAudio">ClearAudio+</option>
|
||||
<option value="movie">Movie</option>
|
||||
<option value="music">Music</option>
|
||||
<option value="sports">Sports</option>
|
||||
<option value="game">Game Studio</option>
|
||||
<option value="standard">Standard</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<!-- HT-CT800 Thing Type -->
|
||||
<thing-type id="HT-CT800">
|
||||
<label>SONY Soundbar HT-CT800</label>
|
||||
<description>SONY Soundbar HT-CT800</description>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-ct800"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="soundField" typeId="sound-field-ct800"/>
|
||||
</channels>
|
||||
<config-description-ref uri="thing-type:sonyaudio:config"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sonyaudio"
|
||||
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">
|
||||
|
||||
<!-- Commands -->
|
||||
<channel-type id="input-mt500">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="btaudio">Bluetooth Audio</option>
|
||||
<option value="tv">TV</option>
|
||||
<option value="analog">Analog</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="network">Home Network</option>
|
||||
<option value="cast">Chromecast</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sound-field-mt500">
|
||||
<item-type>String</item-type>
|
||||
<label>Sound Field</label>
|
||||
<description>Select the Sound Field for the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="clearAudio">ClearAudio+</option>
|
||||
<option value="movie">Movie</option>
|
||||
<option value="music">Music</option>
|
||||
<option value="sports">Sports</option>
|
||||
<option value="game">Game Studio</option>
|
||||
<option value="standard">Standard</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<!-- HT-MT500 Thing Type -->
|
||||
<thing-type id="HT-MT500">
|
||||
<label>SONY Soundbar HT-MT500</label>
|
||||
<description>SONY Soundbar HT-MT500</description>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-mt500"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="soundField" typeId="sound-field-mt500"/>
|
||||
</channels>
|
||||
<config-description-ref uri="thing-type:sonyaudio:config"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sonyaudio"
|
||||
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">
|
||||
|
||||
<!-- Commands -->
|
||||
<channel-type id="input-st5000">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="btaudio">Bluetooth Audio</option>
|
||||
<option value="tv">TV</option>
|
||||
<option value="hdmi1">HDMI1</option>
|
||||
<option value="hdmi2">HDMI2</option>
|
||||
<option value="hdmi3">HDMI3</option>
|
||||
<option value="analog">Analog</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="network">Home Network</option>
|
||||
<option value="cast">Chromecast</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sound-field-st5000">
|
||||
<item-type>String</item-type>
|
||||
<label>Sound Field</label>
|
||||
<description>Select the Sound Field for the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="clearAudio">ClearAudio+</option>
|
||||
<option value="3dsurround">3D Surround</option>
|
||||
<option value="movie">Movie</option>
|
||||
<option value="music">Music</option>
|
||||
<option value="sports">Sports</option>
|
||||
<option value="game">Game Studio</option>
|
||||
<option value="standard">Standard</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<!-- HT-ST5000 Thing Type -->
|
||||
<thing-type id="HT-ST5000">
|
||||
<label>SONY Soundbar HT-ST5000</label>
|
||||
<description>SONY Soundbar HT-ST5000</description>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-st5000"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="soundField" typeId="sound-field-st5000"/>
|
||||
</channels>
|
||||
<config-description-ref uri="thing-type:sonyaudio:config"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sonyaudio"
|
||||
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">
|
||||
|
||||
<!-- Commands -->
|
||||
<channel-type id="input-z9f-zf9">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="btaudio">Bluetooth Audio</option>
|
||||
<option value="tv">TV</option>
|
||||
<option value="hdmi1">HDMI1</option>
|
||||
<option value="hdmi2">HDMI2</option>
|
||||
<option value="analog">Analog</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="network">Home Network</option>
|
||||
<option value="cast">Chromecast</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sound-field-z9f-zf9">
|
||||
<item-type>String</item-type>
|
||||
<label>Sound Field</label>
|
||||
<description>Select the Sound Field for the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="auto">Auto Sound</option>
|
||||
<option value="news">News</option>
|
||||
<option value="cinemaStudio">Cinema</option>
|
||||
<option value="music">Music</option>
|
||||
<option value="sports">Sports</option>
|
||||
<option value="game">Game Studio</option>
|
||||
<option value="standard">Standard</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="nightMode">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Night Mode</label>
|
||||
<description>Enable/Disable Night Mode</description>
|
||||
</channel-type>
|
||||
|
||||
<!-- HT-z9f Thing Type -->
|
||||
<thing-type id="HT-Z9F">
|
||||
<label>SONY Soundbar HT-Z9F</label>
|
||||
<description>SONY Soundbar HT-Z9F</description>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-z9f-zf9"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="soundField" typeId="sound-field-z9f-zf9"/>
|
||||
</channels>
|
||||
<config-description-ref uri="thing-type:sonyaudio:config"/>
|
||||
</thing-type>
|
||||
|
||||
<!-- HT-zf9 Thing Type -->
|
||||
<thing-type id="HT-ZF9">
|
||||
<label>SONY Soundbar HT-ZF9</label>
|
||||
<description>SONY Soundbar HT-ZF9</description>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-z9f-zf9"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="soundField" typeId="sound-field-z9f-zf9"/>
|
||||
<channel id="nightMode" typeId="nightMode"/>
|
||||
</channels>
|
||||
<config-description-ref uri="thing-type:sonyaudio:config"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sonyaudio"
|
||||
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">
|
||||
|
||||
<!-- Commands -->
|
||||
<channel-type id="input-zr5">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the speaker</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="btaudio">Bluetooth Audio</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="analog">Analog</option>
|
||||
<option value="hdmi1">HDMI</option>
|
||||
<option value="network">Home Network</option>
|
||||
<option value="cast">Chromecast</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sound-field-zr5">
|
||||
<item-type>String</item-type>
|
||||
<label>Sound Field</label>
|
||||
<description>Select the Sound Field for the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="clearAudio">ClearAudio+</option>
|
||||
<option value="hiphop">R&B / HIP HOP</option>
|
||||
<option value="standard">FLAT</option>
|
||||
<option value="rock">ROCK</option>
|
||||
<option value="pop">POP</option>
|
||||
<option value="latin">LATIN</option>
|
||||
<option value="jazz">JAZZ</option>
|
||||
<option value="classic">CLASSIC</option>
|
||||
<option value="custom">CUSTOM</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<!-- SRS-ZR5 Thing Type -->
|
||||
<thing-type id="SRS-ZR5">
|
||||
<label>SONY Wireless Speaker SRS-ZR5</label>
|
||||
<description>SONY wireless Speaker SRS-ZR5</description>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-zr5"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
<channel id="soundField" typeId="sound-field-zr5"/>
|
||||
</channels>
|
||||
<config-description-ref uri="thing-type:sonyaudio:config"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,167 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sonyaudio"
|
||||
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">
|
||||
|
||||
<channel-group-type id="masterControls">
|
||||
<label>Master</label>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="soundField" typeId="sound-field-dn1080"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="zone1Controls">
|
||||
<label>Main Zone</label>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-dn1080-zone1"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="zone2Controls">
|
||||
<label>Zone 2</label>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-dn1080-zone2"/>
|
||||
<channel id="volume" typeId="volume"/>
|
||||
<channel id="mute" typeId="mute"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="zone4Controls">
|
||||
<label>HDMI Zone</label>
|
||||
<channels>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="input" typeId="input-dn1080-zone4"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<channel-group-type id="radioControls">
|
||||
<label>Radio</label>
|
||||
<channels>
|
||||
<channel id="broadcastFreq" typeId="radioBroadcastFreq"/>
|
||||
<channel id="broadcastStation" typeId="radioBroadcastStation"/>
|
||||
<channel id="broadcastSeekStation" typeId="radioSeekBroadcastStation"/>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
|
||||
<!-- Commands -->
|
||||
<channel-type id="radioBroadcastFreq">
|
||||
<item-type>Number</item-type>
|
||||
<label>Broadcast Frequency</label>
|
||||
<description>The broadcast frequency</description>
|
||||
<state pattern="%.2f MHz" readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radioBroadcastStation">
|
||||
<item-type>Number</item-type>
|
||||
<label>Broadcast Station</label>
|
||||
<description>Select preset broadcast station</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radioSeekBroadcastStation">
|
||||
<item-type>String</item-type>
|
||||
<label>Change Broadcast Station</label>
|
||||
<description>Change broadcast station</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="fwdSeeking">Seek Forward</option>
|
||||
<option value="bwdSeeking">Seek Backward</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="input-dn1080-zone1">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="btaudio">Bluetooth Audio</option>
|
||||
<option value="fm">FM</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="bd/dvd">BD/DVD</option>
|
||||
<option value="game">GAME</option>
|
||||
<option value="sat/catv">SAT/CATV</option>
|
||||
<option value="video1">VIDEO 1</option>
|
||||
<option value="video2">VIDEO 2</option>
|
||||
<option value="tv">TV</option>
|
||||
<option value="sa-cd/cd">SA-CD/CD</option>
|
||||
<option value="network">Home Network</option>
|
||||
<option value="cast">Chromecast</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="input-dn1080-zone2">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="btaudio">Bluetooth Audio</option>
|
||||
<option value="fm">FM</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="source">SOURCE</option>
|
||||
<option value="sat/catv">SAT/CATV</option>
|
||||
<option value="video1">VIDEO 1</option>
|
||||
<option value="sa-cd/cd">SA-CD/CD</option>
|
||||
<option value="network">Home Network</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="input-dn1080-zone4">
|
||||
<item-type>String</item-type>
|
||||
<label>Input Source</label>
|
||||
<description>Select the input source of the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="bd/dvd">BD/DVD</option>
|
||||
<option value="game">GAME</option>
|
||||
<option value="sat/catv">SAT/CATV</option>
|
||||
<option value="video2">VIDEO 2</option>
|
||||
<option value="sa-cd/cd">SA-CD/CD</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sound-field-dn1080">
|
||||
<item-type>String</item-type>
|
||||
<label>Sound Field</label>
|
||||
<description>Select the Sound Field for the receiver</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="pureDirect">Pure Direct</option>
|
||||
<option value="2chStereo">2ch Stereo</option>
|
||||
<option value="multiChStereo">Multi Ch Stereo</option>
|
||||
<option value="direct">Direct</option>
|
||||
<option value="audioFormatDecoding">A.F.D.</option>
|
||||
<option value="dolbySurround">Dolby Surround</option>
|
||||
<option value="neuralX">Neural:X</option>
|
||||
<option value="frontSurround">Front Surround</option>
|
||||
<option value="audioEnhancer">Audio Enhancer</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<!-- STR-DN1080 Thing Type -->
|
||||
<thing-type id="STR-DN1080">
|
||||
<label>SONY Receiver STR-DN1080</label>
|
||||
<description>SONY receiver STR-DN1080</description>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group typeId="masterControls" id="master"/>
|
||||
<channel-group typeId="zone1Controls" id="zone1"/>
|
||||
<channel-group typeId="zone2Controls" id="zone2"/>
|
||||
<channel-group typeId="zone4Controls" id="zone4"/>
|
||||
<channel-group typeId="radioControls" id="radio"/>
|
||||
</channel-groups>
|
||||
|
||||
<config-description-ref uri="thing-type:sonyaudio:config"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="sonyaudio"
|
||||
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">
|
||||
|
||||
<channel-type id="power">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Power</label>
|
||||
<description>Power on/off your device</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="volume">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Volume</label>
|
||||
<description>Set the volume level</description>
|
||||
<category>SoundVolume</category>
|
||||
<state min="0" max="100" step="1" pattern="%d %%"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="mute">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Mute</label>
|
||||
<description>Enable/Disable Mute on the AVR</description>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user