mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[folderwatcher] Initial contribution (#10045)
Signed-off-by: Alexandr Salamatov <wpgnetworks@gmail.com>
This commit is contained in:
parent
95259b1095
commit
5a0a325344
@ -77,6 +77,7 @@
|
|||||||
/bundles/org.openhab.binding.feed/ @svilenvul
|
/bundles/org.openhab.binding.feed/ @svilenvul
|
||||||
/bundles/org.openhab.binding.feican/ @Hilbrand
|
/bundles/org.openhab.binding.feican/ @Hilbrand
|
||||||
/bundles/org.openhab.binding.fmiweather/ @ssalonen
|
/bundles/org.openhab.binding.fmiweather/ @ssalonen
|
||||||
|
/bundles/org.openhab.binding.folderwatcher/ @goopilot
|
||||||
/bundles/org.openhab.binding.folding/ @fa2k
|
/bundles/org.openhab.binding.folding/ @fa2k
|
||||||
/bundles/org.openhab.binding.foobot/ @airboxlab @Hilbrand
|
/bundles/org.openhab.binding.foobot/ @airboxlab @Hilbrand
|
||||||
/bundles/org.openhab.binding.freebox/ @lolodomo
|
/bundles/org.openhab.binding.freebox/ @lolodomo
|
||||||
|
@ -371,6 +371,11 @@
|
|||||||
<artifactId>org.openhab.binding.fmiweather</artifactId>
|
<artifactId>org.openhab.binding.fmiweather</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
|
<artifactId>org.openhab.binding.folderwatcher</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openhab.addons.bundles</groupId>
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
<artifactId>org.openhab.binding.folding</artifactId>
|
<artifactId>org.openhab.binding.folding</artifactId>
|
||||||
|
13
bundles/org.openhab.binding.folderwatcher/NOTICE
Normal file
13
bundles/org.openhab.binding.folderwatcher/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
|
82
bundles/org.openhab.binding.folderwatcher/README.md
Executable file
82
bundles/org.openhab.binding.folderwatcher/README.md
Executable file
@ -0,0 +1,82 @@
|
|||||||
|
# FolderWatcher Binding
|
||||||
|
|
||||||
|
This binding is intended to monitor FTP and local folder and its subfolders and notify of new files
|
||||||
|
|
||||||
|
## Supported Things
|
||||||
|
|
||||||
|
Currently the binding support two types of things: `ftpfolder` and `localfolder`.
|
||||||
|
|
||||||
|
|
||||||
|
## Thing Configuration
|
||||||
|
|
||||||
|
The `ftpfolder` thing has the following configuration options:
|
||||||
|
|
||||||
|
| Parameter | Name | Description | Required | Default value |
|
||||||
|
|-------------|--------------|------------------------------------------------------------------------------------------------------------------------|----------|---------------|
|
||||||
|
| ftpAddress | FTP server | IP address of FTP server | yes | n/a |
|
||||||
|
| ftpPort | FTP port | Port of FTP server | yes | 21 |
|
||||||
|
| secureMode | FTP Security | FTP Security | yes | None |
|
||||||
|
| ftpUsername | Username | FTP user name | yes | n/a |
|
||||||
|
| ftpPassword | Password | FTP password | yes | n/a |
|
||||||
|
| ftpDir | RootDir | Root directory to be watched | yes | n/a |
|
||||||
|
| listRecursiveFtp | List Sub Folders | Allow listing of sub folders | yes | No |
|
||||||
|
| listHidden | List Hidden | Allow listing of hidden files | yes | false |
|
||||||
|
| connectionTimeout | Connection timeout, s | Connection timeout for FTP request | yes | 30 |
|
||||||
|
| pollInterval | Polling interval, s | Interval for polling folder changes | yes | 60 |
|
||||||
|
| diffHours | Time stamp difference, h | How many hours back to analyze | yes | 24 |
|
||||||
|
|
||||||
|
The `localfolder` thing has the following configuration options:
|
||||||
|
|
||||||
|
| Parameter | Name | Description | Required | Default value |
|
||||||
|
|-------------|--------------|------------------------------------------------------------------------------------------------------------------------|----------|---------------|
|
||||||
|
| localDir | Local Directory | Local directory to be watched | yes | n/a |
|
||||||
|
| listHiddenLocal | List Hidden | Allow listing of hidden files | yes | No |
|
||||||
|
| pollIntervalLocal | Polling interval, s | Interval for polling folder changes | yes | 60 |
|
||||||
|
| listRecursiveLocal | List Sub Folders | Allow listing of sub folders | yes | No |
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
This binding currently supports the following events:
|
||||||
|
|
||||||
|
| Channel Type ID | Item Type | Description |
|
||||||
|
|-----------------|--------------|----------------------------------------------------------------------------------------|
|
||||||
|
| newftpfile | String | A new file name discovered on FTP |
|
||||||
|
| newlocalfile | String | A new file name discovered on in local folder |
|
||||||
|
|
||||||
|
|
||||||
|
## Full Example
|
||||||
|
|
||||||
|
Thing configuration:
|
||||||
|
|
||||||
|
```java
|
||||||
|
folderwatcher:localfolder:myLocalFolder [ localDir="/tmp/dumps", pollIntervalLocal=60, listHiddenLocal="false", listRecursiveLocal="false" ]
|
||||||
|
folderwatcher:ftpfolder:myLocalFolder [ ftpAddress="192.168.0.222", ftpPort=21, secureMode="EXPLICIT", ftpUsername="ftpuser", ftpPassword="ftppass",ftpDir="/suvcams/192.168.0.209",listHidden="true",listRecursiveFtp="true",connectionTimeout=33,pollInterval=66,diffHours=25]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using in a rule:
|
||||||
|
|
||||||
|
FTP example:
|
||||||
|
|
||||||
|
```java
|
||||||
|
rule "New FTP file"
|
||||||
|
when
|
||||||
|
Channel 'folderwatcher:ftpfolder:XXXXX:newfile' triggered
|
||||||
|
then
|
||||||
|
|
||||||
|
logInfo('NewFTPFile', receivedEvent.toString())
|
||||||
|
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Local folder example:
|
||||||
|
|
||||||
|
```java
|
||||||
|
rule "New Local file"
|
||||||
|
when
|
||||||
|
Channel 'folderwatcher:localfolder:XXXXX:newfile' triggered
|
||||||
|
then
|
||||||
|
|
||||||
|
logInfo('NewLocalFile', receivedEvent.toString())
|
||||||
|
|
||||||
|
end
|
||||||
|
```
|
25
bundles/org.openhab.binding.folderwatcher/pom.xml
Normal file
25
bundles/org.openhab.binding.folderwatcher/pom.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
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.1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>org.openhab.binding.folderwatcher</artifactId>
|
||||||
|
|
||||||
|
<name>openHAB Add-ons :: Bundles :: FolderWatcher Binding</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-net</groupId>
|
||||||
|
<artifactId>commons-net</artifactId>
|
||||||
|
<version>3.7.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<features name="org.openhab.binding.folderwatcher-${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-folderwatcher" description="FolderWatcher Binding" version="${project.version}">
|
||||||
|
<feature>openhab-runtime-base</feature>
|
||||||
|
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.folderwatcher/${project.version}</bundle>
|
||||||
|
</feature>
|
||||||
|
</features>
|
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link FolderWatcherBindingConstants} class defines common constants, which are
|
||||||
|
* used across the whole binding.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class FolderWatcherBindingConstants {
|
||||||
|
private static final String BINDING_ID = "folderwatcher";
|
||||||
|
public static final ThingTypeUID THING_TYPE_FTPFOLDER = new ThingTypeUID(BINDING_ID, "ftpfolder");
|
||||||
|
public static final ThingTypeUID THING_TYPE_LOCALFOLDER = new ThingTypeUID(BINDING_ID, "localfolder");
|
||||||
|
public static final String CHANNEL_NEWFILE = "newfile";
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal;
|
||||||
|
|
||||||
|
import static org.openhab.binding.folderwatcher.internal.FolderWatcherBindingConstants.*;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.folderwatcher.internal.handler.FtpFolderWatcherHandler;
|
||||||
|
import org.openhab.binding.folderwatcher.internal.handler.LocalFolderWatcherHandler;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link FolderWatcherHandlerFactory} is responsible for creating things and thing
|
||||||
|
* handlers.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
@Component(configurationPid = "binding.folderwatcher", service = ThingHandlerFactory.class)
|
||||||
|
public class FolderWatcherHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_FTPFOLDER,
|
||||||
|
THING_TYPE_LOCALFOLDER);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
|
||||||
|
if (THING_TYPE_FTPFOLDER.equals(thingTypeUID)) {
|
||||||
|
return new FtpFolderWatcherHandler(thing);
|
||||||
|
} else if (THING_TYPE_LOCALFOLDER.equals(thingTypeUID)) {
|
||||||
|
return new LocalFolderWatcherHandler(thing);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link FolderWatcherBindingConstants} class defines common constants, which are
|
||||||
|
* used across the whole binding.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public enum SecureMode {
|
||||||
|
NONE,
|
||||||
|
IMPLICIT,
|
||||||
|
EXPLICIT
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal.common;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link WatcherCommon} class contains commonly used methods.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class WatcherCommon {
|
||||||
|
|
||||||
|
private static void initFile(File file, String watchDir) throws IOException {
|
||||||
|
try (BufferedWriter fileWriter = new BufferedWriter(new FileWriter(file))) {
|
||||||
|
fileWriter.write(watchDir);
|
||||||
|
fileWriter.newLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> initStorage(File file, String watchDir) throws IOException {
|
||||||
|
List<String> returnList = List.of();
|
||||||
|
List<String> currentFileListing = List.of();
|
||||||
|
if (!file.exists()) {
|
||||||
|
Files.createDirectories(file.toPath().getParent());
|
||||||
|
initFile(file, watchDir);
|
||||||
|
} else {
|
||||||
|
currentFileListing = Files.readAllLines(file.toPath().toAbsolutePath());
|
||||||
|
if (currentFileListing.get(0).equals(watchDir)) {
|
||||||
|
returnList = currentFileListing;
|
||||||
|
} else {
|
||||||
|
initFile(file, watchDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void saveNewListing(List<String> newList, File listingFile) throws IOException {
|
||||||
|
try (BufferedWriter fileWriter = new BufferedWriter(new FileWriter(listingFile, true))) {
|
||||||
|
for (String newFile : newList) {
|
||||||
|
fileWriter.write(newFile);
|
||||||
|
fileWriter.newLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.folderwatcher.internal.SecureMode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link FtpFolderWatcherConfiguration} class contains fields mapping thing configuration parameters.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class FtpFolderWatcherConfiguration {
|
||||||
|
public String ftpAddress = "";
|
||||||
|
public int ftpPort;
|
||||||
|
public String ftpUsername = "";
|
||||||
|
public String ftpPassword = "";
|
||||||
|
public String ftpDir = "";
|
||||||
|
public int pollInterval;
|
||||||
|
public int connectionTimeout;
|
||||||
|
public boolean listHidden;
|
||||||
|
public int diffHours;
|
||||||
|
public boolean listRecursiveFtp;
|
||||||
|
public SecureMode secureMode = SecureMode.NONE;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link LocalFolderWatcherConfiguration} class contains fields mapping thing configuration parameters.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class LocalFolderWatcherConfiguration {
|
||||||
|
public String localDir = "";
|
||||||
|
public boolean listHiddenLocal;
|
||||||
|
public int pollIntervalLocal;
|
||||||
|
public boolean listRecursiveLocal;
|
||||||
|
}
|
@ -0,0 +1,247 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.binding.folderwatcher.internal.FolderWatcherBindingConstants.CHANNEL_NEWFILE;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.apache.commons.net.ftp.FTPClient;
|
||||||
|
import org.apache.commons.net.ftp.FTPFile;
|
||||||
|
import org.apache.commons.net.ftp.FTPReply;
|
||||||
|
import org.apache.commons.net.ftp.FTPSClient;
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.folderwatcher.internal.common.WatcherCommon;
|
||||||
|
import org.openhab.binding.folderwatcher.internal.config.FtpFolderWatcherConfiguration;
|
||||||
|
import org.openhab.core.OpenHAB;
|
||||||
|
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 FtpFolderWatcherHandler} is responsible for handling commands, which are
|
||||||
|
* sent to one of the channels.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class FtpFolderWatcherHandler extends BaseThingHandler {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(FtpFolderWatcherHandler.class);
|
||||||
|
private FtpFolderWatcherConfiguration config = new FtpFolderWatcherConfiguration();
|
||||||
|
private @Nullable File currentFtpListingFile;
|
||||||
|
private @Nullable ScheduledFuture<?> executionJob, initJob;
|
||||||
|
private FTPClient ftp = new FTPClient();
|
||||||
|
private List<String> previousFtpListing = new ArrayList<>();
|
||||||
|
|
||||||
|
public FtpFolderWatcherHandler(Thing thing) {
|
||||||
|
super(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
logger.debug("Channel {} triggered with command {}", channelUID.getId(), command);
|
||||||
|
if (command instanceof RefreshType) {
|
||||||
|
refreshFTPFolderInformation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
File currentFtpListingFile;
|
||||||
|
config = getConfigAs(FtpFolderWatcherConfiguration.class);
|
||||||
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
if (config.connectionTimeout <= 0) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
|
"Connection timeout can't be negative");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (config.ftpPort < 0) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "FTP port can't be negative");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (config.pollInterval <= 0) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
|
"Polling interval can't be null or negative");
|
||||||
|
}
|
||||||
|
|
||||||
|
currentFtpListingFile = new File(OpenHAB.getUserDataFolder() + File.separator + "FolderWatcher" + File.separator
|
||||||
|
+ thing.getUID().getAsString().replace(':', '_') + ".data");
|
||||||
|
try {
|
||||||
|
this.currentFtpListingFile = currentFtpListingFile;
|
||||||
|
previousFtpListing = WatcherCommon.initStorage(currentFtpListingFile, config.ftpAddress + config.ftpDir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||||
|
logger.debug("Can't write file {}, error message {}", currentFtpListingFile, e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.initJob = scheduler.scheduleWithFixedDelay(this::connectionKeepAlive, 0, config.pollInterval,
|
||||||
|
TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
ScheduledFuture<?> executionJob = this.executionJob;
|
||||||
|
ScheduledFuture<?> initJob = this.initJob;
|
||||||
|
if (executionJob != null) {
|
||||||
|
executionJob.cancel(true);
|
||||||
|
}
|
||||||
|
if (initJob != null) {
|
||||||
|
initJob.cancel(true);
|
||||||
|
}
|
||||||
|
if (ftp.isConnected()) {
|
||||||
|
try {
|
||||||
|
ftp.logout();
|
||||||
|
ftp.disconnect();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Error terminating FTP connection: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void listDirectory(FTPClient ftpClient, String dirPath, boolean recursive, List<String> dirFiles)
|
||||||
|
throws IOException {
|
||||||
|
Instant dateNow = Instant.now();
|
||||||
|
for (FTPFile file : ftpClient.listFiles(dirPath)) {
|
||||||
|
String currentFileName = file.getName();
|
||||||
|
if (currentFileName.equals(".") || currentFileName.equals("..")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String filePath = dirPath + "/" + currentFileName;
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
if (recursive) {
|
||||||
|
try {
|
||||||
|
listDirectory(ftpClient, filePath, recursive, dirFiles);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Can't read FTP directory: {}", filePath, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
long diff = ChronoUnit.HOURS.between(file.getTimestamp().toInstant(), dateNow);
|
||||||
|
if (diff < config.diffHours) {
|
||||||
|
dirFiles.add("ftp:/" + ftpClient.getRemoteAddress() + filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectionKeepAlive() {
|
||||||
|
if (!ftp.isConnected()) {
|
||||||
|
switch (config.secureMode) {
|
||||||
|
case NONE:
|
||||||
|
ftp = new FTPClient();
|
||||||
|
break;
|
||||||
|
case IMPLICIT:
|
||||||
|
ftp = new FTPSClient(true);
|
||||||
|
break;
|
||||||
|
case EXPLICIT:
|
||||||
|
ftp = new FTPSClient(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reply = 0;
|
||||||
|
ftp.setListHiddenFiles(config.listHidden);
|
||||||
|
ftp.setConnectTimeout(config.connectionTimeout * 1000);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ftp.connect(config.ftpAddress, config.ftpPort);
|
||||||
|
reply = ftp.getReplyCode();
|
||||||
|
|
||||||
|
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||||
|
ftp.disconnect();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
|
"FTP server refused connection.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (ftp.isConnected()) {
|
||||||
|
try {
|
||||||
|
ftp.disconnect();
|
||||||
|
} catch (IOException e2) {
|
||||||
|
logger.debug("Error disconneting, lost connection? : {}", e2.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!ftp.login(config.ftpUsername, config.ftpPassword)) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ftp.getReplyString());
|
||||||
|
ftp.logout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
ScheduledFuture<?> executionJob = this.executionJob;
|
||||||
|
if (executionJob != null) {
|
||||||
|
executionJob.cancel(true);
|
||||||
|
}
|
||||||
|
this.executionJob = scheduler.scheduleWithFixedDelay(this::refreshFTPFolderInformation, 0,
|
||||||
|
config.pollInterval, TimeUnit.SECONDS);
|
||||||
|
} catch (IOException e) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshFTPFolderInformation() {
|
||||||
|
String ftpRootDir = config.ftpDir;
|
||||||
|
final File currentFtpListingFile = this.currentFtpListingFile;
|
||||||
|
if (ftp.isConnected()) {
|
||||||
|
ftp.enterLocalPassiveMode();
|
||||||
|
try {
|
||||||
|
if (ftpRootDir.endsWith("/")) {
|
||||||
|
ftpRootDir = ftpRootDir.substring(0, ftpRootDir.length() - 1);
|
||||||
|
}
|
||||||
|
if (!ftpRootDir.startsWith("/")) {
|
||||||
|
ftpRootDir = "/" + ftpRootDir;
|
||||||
|
}
|
||||||
|
List<String> currentFtpListing = new ArrayList<>();
|
||||||
|
listDirectory(ftp, ftpRootDir, config.listRecursiveFtp, currentFtpListing);
|
||||||
|
List<String> diffFtpListing = new ArrayList<>(currentFtpListing);
|
||||||
|
diffFtpListing.removeAll(previousFtpListing);
|
||||||
|
diffFtpListing.forEach(file -> triggerChannel(CHANNEL_NEWFILE, file));
|
||||||
|
if (!diffFtpListing.isEmpty() && currentFtpListingFile != null) {
|
||||||
|
try {
|
||||||
|
WatcherCommon.saveNewListing(diffFtpListing, currentFtpListingFile);
|
||||||
|
} catch (IOException e2) {
|
||||||
|
logger.debug("Can't save new listing into file: {}", e2.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previousFtpListing = new ArrayList<>(currentFtpListing);
|
||||||
|
} catch (IOException e) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
|
"FTP connection lost. " + e.getMessage());
|
||||||
|
try {
|
||||||
|
ftp.disconnect();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
logger.debug("Error disconneting, lost connection? {}", e1.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.debug("FTP connection lost.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2021 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.folderwatcher.internal.handler;
|
||||||
|
|
||||||
|
import static org.openhab.binding.folderwatcher.internal.FolderWatcherBindingConstants.CHANNEL_NEWFILE;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.FileVisitor;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.folderwatcher.internal.common.WatcherCommon;
|
||||||
|
import org.openhab.binding.folderwatcher.internal.config.LocalFolderWatcherConfiguration;
|
||||||
|
import org.openhab.core.OpenHAB;
|
||||||
|
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 LocalFolderWatcherHandler} is responsible for handling commands, which are
|
||||||
|
* sent to one of the channels.
|
||||||
|
*
|
||||||
|
* @author Alexandr Salamatov - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class LocalFolderWatcherHandler extends BaseThingHandler {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(LocalFolderWatcherHandler.class);
|
||||||
|
private LocalFolderWatcherConfiguration config = new LocalFolderWatcherConfiguration();
|
||||||
|
private File currentLocalListingFile = new File(OpenHAB.getUserDataFolder() + File.separator + "FolderWatcher"
|
||||||
|
+ File.separator + thing.getUID().getAsString().replace(':', '_') + ".data");
|
||||||
|
private @Nullable ScheduledFuture<?> executionJob;
|
||||||
|
private List<String> previousLocalListing = new ArrayList<>();
|
||||||
|
|
||||||
|
public LocalFolderWatcherHandler(Thing thing) {
|
||||||
|
super(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
logger.debug("Channel {} triggered with command {}", channelUID.getId(), command);
|
||||||
|
if (command instanceof RefreshType) {
|
||||||
|
refreshFolderInformation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
config = getConfigAs(LocalFolderWatcherConfiguration.class);
|
||||||
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
|
||||||
|
if (!Files.isDirectory(Paths.get(config.localDir))) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Local directory is not valid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
previousLocalListing = WatcherCommon.initStorage(currentLocalListingFile, config.localDir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||||
|
logger.debug("Can't write file {}: {}", currentLocalListingFile, e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.pollIntervalLocal > 0) {
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
executionJob = scheduler.scheduleWithFixedDelay(this::refreshFolderInformation, config.pollIntervalLocal,
|
||||||
|
config.pollIntervalLocal, TimeUnit.SECONDS);
|
||||||
|
} else {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
|
"Polling interval can't be null or negative");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
ScheduledFuture<?> executionJob = this.executionJob;
|
||||||
|
if (executionJob != null) {
|
||||||
|
executionJob.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshFolderInformation() {
|
||||||
|
final String rootDir = config.localDir;
|
||||||
|
try {
|
||||||
|
List<String> currentLocalListing = new ArrayList<>();
|
||||||
|
|
||||||
|
Files.walkFileTree(Paths.get(rootDir), new FileVisitor<@Nullable Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult preVisitDirectory(@Nullable Path dir, @Nullable BasicFileAttributes attrs)
|
||||||
|
throws IOException {
|
||||||
|
if (dir != null) {
|
||||||
|
if (!dir.equals(Paths.get(rootDir)) && !config.listRecursiveLocal) {
|
||||||
|
return FileVisitResult.SKIP_SUBTREE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(@Nullable Path file, @Nullable BasicFileAttributes attrs)
|
||||||
|
throws IOException {
|
||||||
|
if (file != null) {
|
||||||
|
if (Files.isHidden(file) && !config.listHiddenLocal) {
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
currentLocalListing.add(file.toAbsolutePath().toString());
|
||||||
|
}
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFileFailed(@Nullable Path file, @Nullable IOException exc)
|
||||||
|
throws IOException {
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult postVisitDirectory(@Nullable Path dir, @Nullable IOException exc)
|
||||||
|
throws IOException {
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<String> diffLocalListing = new ArrayList<>(currentLocalListing);
|
||||||
|
diffLocalListing.removeAll(previousLocalListing);
|
||||||
|
diffLocalListing.forEach(file -> triggerChannel(CHANNEL_NEWFILE, file));
|
||||||
|
|
||||||
|
if (!diffLocalListing.isEmpty()) {
|
||||||
|
WatcherCommon.saveNewListing(diffLocalListing, currentLocalListingFile);
|
||||||
|
}
|
||||||
|
previousLocalListing = new ArrayList<>(currentLocalListing);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("File manipulation error: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<binding:binding id="folderwatcher" 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>FolderWatcher Binding</name>
|
||||||
|
<description>This binding will monitor specified location for new files and trigger event channel with new file names.</description>
|
||||||
|
|
||||||
|
</binding:binding>
|
@ -0,0 +1,126 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<thing:thing-descriptions bindingId="folderwatcher"
|
||||||
|
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">
|
||||||
|
|
||||||
|
<thing-type id="ftpfolder">
|
||||||
|
<label>FTP Folder</label>
|
||||||
|
<description>FTP folder to be watched</description>
|
||||||
|
|
||||||
|
<channels>
|
||||||
|
<channel id="newfile" typeId="newfile-channel"/>
|
||||||
|
</channels>
|
||||||
|
|
||||||
|
<config-description>
|
||||||
|
<parameter name="ftpAddress" type="text" required="true">
|
||||||
|
<label>FTP Server</label>
|
||||||
|
<description>Address of FTP server</description>
|
||||||
|
<context>network-address</context>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="ftpPort" type="integer" min="1" max="65535">
|
||||||
|
<label>FTP Port</label>
|
||||||
|
<default>21</default>
|
||||||
|
<description>FTP server's port</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="secureMode" type="text">
|
||||||
|
<label>FTP Security</label>
|
||||||
|
<limitToOptions>true</limitToOptions>
|
||||||
|
<options>
|
||||||
|
<option value="NONE">None</option>
|
||||||
|
<option value="IMPLICIT">TLS/SSL Implicit</option>
|
||||||
|
<option value="EXPLICIT">TLS/SSL Explicit</option>
|
||||||
|
</options>
|
||||||
|
<default>NONE</default>
|
||||||
|
<description>FTP Security settings</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="ftpUsername" type="text" required="true">
|
||||||
|
<label>Username</label>
|
||||||
|
<description>User name</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="ftpPassword" type="text" required="true">
|
||||||
|
<label>Password</label>
|
||||||
|
<description>FTP server password</description>
|
||||||
|
<context>password</context>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="ftpDir" type="text" required="true">
|
||||||
|
<label>Root Directory</label>
|
||||||
|
<description>Root directory to be watched</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="listHidden" type="boolean">
|
||||||
|
<label>List Hidden</label>
|
||||||
|
<default>false</default>
|
||||||
|
<description>Allow listing of hidden files</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="listRecursiveFtp" type="boolean">
|
||||||
|
<label>List Sub Folders</label>
|
||||||
|
<default>false</default>
|
||||||
|
<description>Allow listing of sub folders</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="connectionTimeout" type="integer" min="1" unit="s">
|
||||||
|
<label>Connection Timeout</label>
|
||||||
|
<description>Connection timeout for FTP request, sec</description>
|
||||||
|
<default>30</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="pollInterval" type="integer" min="1" unit="s">
|
||||||
|
<label>Polling Interval</label>
|
||||||
|
<description>Interval for polling folder changes, sec</description>
|
||||||
|
<default>60</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="diffHours" type="integer" min="1" unit="h">
|
||||||
|
<label>Timestamp Difference</label>
|
||||||
|
<description>How many hours back to analyze</description>
|
||||||
|
<default>24</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
|
||||||
|
</thing-type>
|
||||||
|
|
||||||
|
<channel-type id="newfile-channel">
|
||||||
|
<kind>trigger</kind>
|
||||||
|
<label>New File Name(s)</label>
|
||||||
|
<description>A new file name</description>
|
||||||
|
<category>String</category>
|
||||||
|
<event/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<thing-type id="localfolder">
|
||||||
|
<label>Local Folder</label>
|
||||||
|
<description>Local folder to be watched</description>
|
||||||
|
|
||||||
|
<channels>
|
||||||
|
<channel id="newfile" typeId="newfile-channel"/>
|
||||||
|
</channels>
|
||||||
|
|
||||||
|
<config-description>
|
||||||
|
<parameter name="localDir" type="text" required="true">
|
||||||
|
<label>Local Directory</label>
|
||||||
|
<description>Local directory to be watched</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="pollIntervalLocal" type="integer" min="1" unit="s">
|
||||||
|
<label>Polling Interval</label>
|
||||||
|
<description>Interval for polling folder changes, sec</description>
|
||||||
|
<default>60</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="listHiddenLocal" type="boolean">
|
||||||
|
<label>List Hidden</label>
|
||||||
|
<default>false</default>
|
||||||
|
<description>Allow listing of hidden files</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="listRecursiveLocal" type="boolean">
|
||||||
|
<label>List Sub Folders</label>
|
||||||
|
<default>false</default>
|
||||||
|
<description>Allow listing of sub folders</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</thing-type>
|
||||||
|
</thing:thing-descriptions>
|
@ -108,6 +108,7 @@
|
|||||||
<module>org.openhab.binding.feed</module>
|
<module>org.openhab.binding.feed</module>
|
||||||
<module>org.openhab.binding.feican</module>
|
<module>org.openhab.binding.feican</module>
|
||||||
<module>org.openhab.binding.fmiweather</module>
|
<module>org.openhab.binding.fmiweather</module>
|
||||||
|
<module>org.openhab.binding.folderwatcher</module>
|
||||||
<module>org.openhab.binding.folding</module>
|
<module>org.openhab.binding.folding</module>
|
||||||
<module>org.openhab.binding.foobot</module>
|
<module>org.openhab.binding.foobot</module>
|
||||||
<module>org.openhab.binding.freebox</module>
|
<module>org.openhab.binding.freebox</module>
|
||||||
|
Loading…
Reference in New Issue
Block a user