Skip to content

Commit

Permalink
[samsungtv] added KEY_MULTI_VIEW
Browse files Browse the repository at this point in the history
Signed-off-by: Nick Waterton <[email protected]>
  • Loading branch information
NickWaterton committed Oct 30, 2023
1 parent 597f01e commit 30c6368
Show file tree
Hide file tree
Showing 43 changed files with 5,423 additions and 1,839 deletions.
Empty file modified bundles/org.openhab.binding.samsungtv/NOTICE
100644 → 100755
Empty file.
645 changes: 604 additions & 41 deletions bundles/org.openhab.binding.samsungtv/README.md
100644 → 100755

Large diffs are not rendered by default.

Empty file modified bundles/org.openhab.binding.samsungtv/pom.xml
100644 → 100755
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* Copyright (c) 2010-2023 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.samsungtv.internal;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.samsungtv.internal.protocol.RemoteControllerWebSocket;
import org.openhab.core.OpenHAB;
import org.openhab.core.service.WatchService;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The {@link SamsungTvAppWatchService} provides a list of apps for >2020 Samsung TV's
* File should be in json format
*
* @author Nick Waterton - Initial contribution
* @author Nick Waterton - Refactored to new WatchService
*/
@Component(service = SamsungTvAppWatchService.class)
@NonNullByDefault
public class SamsungTvAppWatchService implements WatchService.WatchEventListener {
private static final String APPS_PATH = OpenHAB.getConfigFolder() + File.separator + "services";
private static final String APPS_FILE = "samsungtv.cfg";

private final Logger logger = LoggerFactory.getLogger(SamsungTvAppWatchService.class);
private final RemoteControllerWebSocket remoteControllerWebSocket;
private String host = "";
private boolean started = false;
int count = 0;

public SamsungTvAppWatchService(String host, RemoteControllerWebSocket remoteControllerWebSocket) {
this.host = host;
this.remoteControllerWebSocket = remoteControllerWebSocket;
}

public void start() {
File file = new File(APPS_PATH, APPS_FILE);
if (file.exists() && !getStarted()) {
logger.info("{}: Starting Apps File monitoring service", host);
started = true;
readFileApps();
} else if (count++ == 0) {
logger.warn("{}: cannot start Apps File monitoring service, file {} does not exist", host, file.toString());
remoteControllerWebSocket.addKnownAppIds();
}
}

public boolean getStarted() {
return started;
}

/**
* Check file path for existance
*
*/
public boolean checkFileDir() {
File file = new File(APPS_PATH, APPS_FILE);
return file.exists();
}

public void readFileApps() {
processWatchEvent(WatchService.Kind.MODIFY, Paths.get(APPS_PATH, APPS_FILE));
}

public boolean watchSubDirectories() {
return false;
}

@Override
public void processWatchEvent(WatchService.Kind kind, Path path) {
if (path.endsWith(APPS_FILE) && kind != WatchService.Kind.DELETE) {
logger.debug("{}: Updating Apps list from FILE {}", host, path);
try {
@SuppressWarnings("null")
List<String> allLines = Files.lines(path).filter(line -> !line.trim().startsWith("#"))
.collect(Collectors.toList());
logger.debug("{}: Updated Apps list, {} apps in list", host, allLines.size());
remoteControllerWebSocket.updateAppList(allLines);
} catch (IOException e) {
logger.debug("{}: Cannot read apps file: {}", host, e.getMessage());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
import org.openhab.core.thing.ThingTypeUID;

/**
* The {@link SamsungTvBindingConstants} class defines common constants, which are used
* The {@link SamsungTvBinding} class defines common constants, which are used
* across the whole binding.
*
* @author Pauli Anttila - Initial contribution
* @author Arjan Mels - Added constants for websocket based remote controller
* @author Nick Waterton - Added artMode channels
*/
@NonNullByDefault
public class SamsungTvBindingConstants {
Expand All @@ -33,6 +34,7 @@ public class SamsungTvBindingConstants {
public static final String KEY_CODE = "keyCode";
public static final String POWER = "power";
public static final String ART_MODE = "artMode";
public static final String SET_ART_MODE = "setArtMode";
public static final String SOURCE_APP = "sourceApp";

// List of all media renderer thing channel id's
Expand All @@ -51,4 +53,11 @@ public class SamsungTvBindingConstants {
public static final String CHANNEL_NAME = "channelName";
public static final String BROWSER_URL = "url";
public static final String STOP_BROWSER = "stopBrowser";

// List of all artMode channels (Frame TV's only)
public static final String ART_IMAGE = "artImage";
public static final String ART_LABEL = "artLabel";
public static final String ART_JSON = "artJson";
public static final String ART_BRIGHTNESS = "artBrightness";
public static final String ART_COLOR_TEMPERATURE = "artColorTemperature";
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import static org.openhab.binding.samsungtv.internal.SamsungTvBindingConstants.SAMSUNG_TV_THING_TYPE;

import java.util.Collections;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand Down Expand Up @@ -41,7 +42,7 @@
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.samsungtv")
public class SamsungTvHandlerFactory extends BaseThingHandlerFactory {

private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(SAMSUNG_TV_THING_TYPE);
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(SAMSUNG_TV_THING_TYPE);

private @NonNullByDefault({}) UpnpIOService upnpIOService;
private @NonNullByDefault({}) UpnpService upnpService;
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Copyright (c) 2010-2023 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.samsungtv.internal;

import java.io.IOException;
import java.io.StringReader;
import java.util.Base64;
import java.util.Optional;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.jupnp.model.meta.RemoteDevice;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* The {@link Utils} is a collection of static utilities
*
* @author Nick Waterton - Initial contribution
*/
@NonNullByDefault
public class Utils {
private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
public static DocumentBuilderFactory factory = getDocumentBuilder();

private static DocumentBuilderFactory getDocumentBuilder() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
// see https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
} catch (ParserConfigurationException e) {
LOGGER.debug("XMLParser Configuration Error: {}", e.getMessage());
}
return Optional.ofNullable(factory).orElse(DocumentBuilderFactory.newInstance());
}

/**
* Build {@link Document} from {@link String} which contains XML content.
*
* @param xml
* {@link String} which contains XML content.
* @return {@link Optional Document} or empty if convert has failed.
*/
public static Optional<Document> loadXMLFromString(String xml, String host) {
try {
return Optional.ofNullable(factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml))));
} catch (ParserConfigurationException | SAXException | IOException e) {
LOGGER.debug("{}: Error loading XML: {}", host, e.getMessage());
}
return Optional.empty();
}

public static boolean isSoundChannel(String name) {
return (name.contains("Volume") || name.contains("Mute"));
}

public static String b64encode(String str) {
return Base64.getUrlEncoder().encodeToString(str.getBytes());
}

public static String truncCmd(Command command) {
String cmd = command.toString();
return (cmd.length() <= 80) ? cmd : cmd.substring(0, 80) + "...";
}

public static String getModelName(@Nullable RemoteDevice device) {
return Optional.ofNullable(device).map(a -> a.getDetails()).map(a -> a.getModelDetails())
.map(a -> a.getModelName()).orElse("");
}

public static String getManufacturer(@Nullable RemoteDevice device) {
return Optional.ofNullable(device).map(a -> a.getDetails()).map(a -> a.getManufacturerDetails())
.map(a -> a.getManufacturer()).orElse("");
}

public static String getFriendlyName(@Nullable RemoteDevice device) {
return Optional.ofNullable(device).map(a -> a.getDetails()).map(a -> a.getFriendlyName()).orElse("");
}

public static String getUdn(@Nullable RemoteDevice device) {
return Optional.ofNullable(device).map(a -> a.getIdentity()).map(a -> a.getUdn())
.map(a -> a.getIdentifierString()).orElse("");
}

public static String getHost(@Nullable RemoteDevice device) {
return Optional.ofNullable(device).map(a -> a.getIdentity()).map(a -> a.getDescriptorURL())
.map(a -> a.getHost()).orElse("");
}

public static String getType(@Nullable RemoteDevice device) {
return Optional.ofNullable(device).map(a -> a.getType()).map(a -> a.getType()).orElse("");
}
}
Loading

0 comments on commit 30c6368

Please sign in to comment.