[Twitter] 3.0 Twitter Binding (#10241)

* [twitter][WIP] Initial contribution

using the 1.x binding as a template, I created a new Twitter Binding.

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com> (github: computergeek1507)
Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* trying to fix twitter4j dependency stuff

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* add to bundle POM

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* trying to fix build

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* Fixed dependency issues, Got Actions working

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* updating readme

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* fix class name

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* Fixes based on review

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* Cleanup based on review and mvn checks

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* grammar fix

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* remove Apache dependencies

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* added Null Checks based on review

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>

* change null check around

Signed-off-by: Scott Hanson <scooter_seh@yahoo.com>
This commit is contained in:
Scott H 2021-09-05 03:33:00 -04:00 committed by GitHub
parent 0087c8c828
commit b37022c5d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 769 additions and 0 deletions

View File

@ -299,6 +299,7 @@
/bundles/org.openhab.binding.tplinksmarthome/ @Hilbrand
/bundles/org.openhab.binding.tr064/ @openhab/add-ons-maintainers
/bundles/org.openhab.binding.tradfri/ @cweitkamp @kaikreuzer
/bundles/org.openhab.binding.twitter/ @computergeek1507
/bundles/org.openhab.binding.unifi/ @mgbowman
/bundles/org.openhab.binding.unifiedremote/ @GiviMAD
/bundles/org.openhab.binding.upb/ @marcusb

View File

@ -0,0 +1,22 @@
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
== Third-party Content
twitter4j
* License: Apache License 2.0
* Project: https://twitter4j.org/
* Source: https://github.com/Twitter4J/Twitter4J

View File

@ -0,0 +1,66 @@
# Twitter Binding
The Twitter binding allows your home to Tweet 280 characters at a time. It also supports direct messages and tweeting with media.
## Supported Things
```
account - Twitter Account.
```
## Thing Configuration
The Twitter Account Thing requires you to create a Twitter App in the Twitter Developer Page.
| Property | Default | Required | Description |
|-------------------|---------|:--------:|-----------------------------------|
| consumerKey | | Yes | Consumer API Key |
| consumerSecret | | Yes | Consumer API Secret |
| accessToken | | Yes | Access Token |
| accessTokenSecret | | Yes | Access Token Secret |
| refresh | 30 | No | Tweet refresh interval in minutes |
## Channels
| channel | type | description |
|------------|--------|------------------------------------------------|
| lasttweet | String | This channel provides the Latest Tweet message |
## Full Example
twitter.things:
```
Thing twitter:account:sampleaccount [ consumerKey="11111", consumerSecret="22222", accessToken="33333", accessTokenSecret="444444" ]
```
twitter.items:
```
String sample_tweet "Latest Tweet: [%s]" { channel="twitter:account:sampleaccount:lasttweet" }
```
## Rule Action
This binding includes rule actions for sending tweets and direct messages.
* `boolean success = sendTweet(String text)`
* `boolean success = sendTweetWithAttachment(String text, String URL)`
* `boolean success = sendDirectMessage(String recipientID, String text)`
Examples:
```
val tweetActions = getActions("twitter","twitter:account:sampleaccount")
val success = tweetActions.sendTweet("This is A Tweet")
val success2 = tweetActions.sendTweetWithAttachment("This is A Tweet with a Pic", file:///tmp/201601011031.jpg)
val success3 = tweetActions.sendTweetWithAttachment("Windows Picture", "D:\\Test.png" )
val success4 = tweetActions.sendTweetWithAttachment("HTTP Picture", "http://www.mywebsite.com/Test.png" )
val success5 = tweetActions.sendDirectMessage("1234567", "Wake Up" )
```

View File

@ -0,0 +1,29 @@
<?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.2.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.twitter</artifactId>
<name>openHAB Add-ons :: Bundles :: Twitter Binding</name>
<properties>
<bnd.importpackage>!android.*,!com.android.org.*,!dalvik.*,!javax.annotation.meta.*,!org.apache.harmony.*,!org.conscrypt.*,!sun.*,!com.google.appengine.api.*</bnd.importpackage>
</properties>
<dependencies>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>4.0.7</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.twitter-${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-twitter" description="Twitter Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.twitter/${project.version}</bundle>
</feature>
</features>

View File

@ -0,0 +1,34 @@
/**
* 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.twitter.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link TwitterBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Scott Hanson - Initial contribution
*/
@NonNullByDefault
public class TwitterBindingConstants {
private static final String BINDING_ID = "twitter";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_ACCOUNT = new ThingTypeUID(BINDING_ID, "account");
// List of all Channel ids
public static final String CHANNEL_LASTTWEET = "lasttweet";
}

View File

@ -0,0 +1,333 @@
/**
* 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.twitter.internal;
import static org.openhab.binding.twitter.internal.TwitterBindingConstants.CHANNEL_LASTTWEET;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
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.twitter.internal.action.TwitterActions;
import org.openhab.binding.twitter.internal.config.TwitterConfig;
import org.openhab.core.io.net.http.HttpUtil;
import org.openhab.core.library.types.RawType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import twitter4j.DirectMessage;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.StatusUpdate;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
/**
* The {@link TwitterHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Scott Hanson - Initial contribution
*/
@NonNullByDefault
public class TwitterHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(TwitterHandler.class);
private TwitterConfig config = new TwitterConfig();
private @Nullable ScheduledFuture<?> refreshTask;
private static final int CHARACTER_LIMIT = 280;
private static @Nullable Twitter client = null;
boolean isProperlyConfigured = false;
public TwitterHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
// creates list of available Actions
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singletonList(TwitterActions.class);
}
@Override
public void initialize() {
config = getConfigAs(TwitterConfig.class);
// create a New Twitter Client
Twitter localClient = createClient();
client = localClient;
refresh();// Get latest status
isProperlyConfigured = true;
refreshTask = scheduler.scheduleWithFixedDelay(this::refresh, 0, config.refresh, TimeUnit.MINUTES);
updateStatus(ThingStatus.ONLINE);
}
@Override
public void dispose() {
ScheduledFuture<?> localRefreshTask = refreshTask;
if (localRefreshTask != null) {
localRefreshTask.cancel(true);
}
}
/**
* Internal method for Getting Twitter Status
*
*/
private void refresh() {
try {
if (!checkPrerequisites()) {
return;
}
Twitter localClient = client;
if (localClient != null) {
ResponseList<Status> statuses = localClient.getUserTimeline();
if (statuses.size() > 0) {
updateState(CHANNEL_LASTTWEET, StringType.valueOf(statuses.get(0).getText()));
} else {
logger.debug("No Statuses Found");
}
}
} catch (TwitterException e) {
logger.debug("Error when trying to refresh Twitter Account: {}", e.getMessage());
}
}
/**
* Internal method for sending a tweet, with or without image
*
* @param tweetTxt
* text string to be sent as a Tweet
* @param fileToAttach
* the file to attach. May be null if no attached file.
*
* @return <code>true</code>, if sending the tweet has been successful and
* <code>false</code> in all other cases.
*/
private boolean sendTweet(final String tweetTxt, final @Nullable File fileToAttach) {
if (!checkPrerequisites()) {
return false;
}
// abbreviate the Tweet to meet the 280 character limit ...
String abbreviatedTweetTxt = abbreviateString(tweetTxt, CHARACTER_LIMIT);
try {
Twitter localClient = client;
if (localClient != null) {
// send the Tweet
StatusUpdate status = new StatusUpdate(abbreviatedTweetTxt);
if (fileToAttach != null && fileToAttach.isFile()) {
status.setMedia(fileToAttach);
}
Status updatedStatus = localClient.updateStatus(status);
logger.debug("Successfully sent Tweet '{}'", updatedStatus.getText());
updateState(CHANNEL_LASTTWEET, StringType.valueOf(updatedStatus.getText()));
return true;
}
} catch (TwitterException e) {
logger.warn("Failed to send Tweet '{}' because of : {}", abbreviatedTweetTxt, e.getLocalizedMessage());
}
return false;
}
/**
* Sends a standard Tweet.
*
* @param tweetTxt
* text string to be sent as a Tweet
*
* @return <code>true</code>, if sending the tweet has been successful and
* <code>false</code> in all other cases.
*/
public boolean sendTweet(String tweetTxt) {
if (!checkPrerequisites()) {
return false;
}
return sendTweet(tweetTxt, (File) null);
}
/**
* Sends a Tweet with an image
*
* @param tweetTxt
* text string to be sent as a Tweet
* @param tweetPicture
* the path of the picture that needs to be attached (either an url,
* either a path pointing to a local file)
*
* @return <code>true</code>, if sending the tweet has been successful and
* <code>false</code> in all other cases.
*/
public boolean sendTweet(String tweetTxt, String tweetPicture) {
if (!checkPrerequisites()) {
return false;
}
// prepare the image attachment
File fileToAttach = null;
boolean deleteTemporaryFile = false;
if (tweetPicture.startsWith("http://") || tweetPicture.startsWith("https://")) {
try {
// we have a remote url and need to download the remote file to a temporary location
Path tDir = Files.createTempDirectory("TempDirectory");
String path = tDir + File.separator + "openhab-twitter-remote_attached_file" + "."
+ getExtension(tweetPicture);
// URL url = new URL(tweetPicture);
fileToAttach = new File(path);
deleteTemporaryFile = true;
RawType rawPicture = HttpUtil.downloadImage(tweetPicture);
if (rawPicture != null) {
try (FileOutputStream fos = new FileOutputStream(path)) {
fos.write(rawPicture.getBytes(), 0, rawPicture.getBytes().length);
} catch (FileNotFoundException ex) {
logger.debug("Could not create {} in temp dir. {}", path, ex.getMessage());
} catch (IOException ex) {
logger.debug("Could not write {} to temp dir. {}", path, ex.getMessage());
}
} else {
logger.debug("Could not download tweet file from {}", tweetPicture);
}
} catch (IOException ex) {
logger.debug("Could not write {} to temp dir. {}", tweetPicture, ex.getMessage());
}
} else {
// we have a local file and can just use it directly
fileToAttach = new File(tweetPicture);
}
if (fileToAttach != null && fileToAttach.isFile()) {
logger.debug("Image '{}' correctly found, will be included in tweet", tweetPicture);
} else {
logger.warn("Image '{}' not found, will only tweet text", tweetPicture);
}
// send the Tweet
boolean result = sendTweet(tweetTxt, fileToAttach);
// delete temp file (if needed)
if (deleteTemporaryFile) {
if (fileToAttach != null) {
try {
fileToAttach.delete();
} catch (final Exception ignored) {
return false;
}
}
}
return result;
}
/**
* Sends a DirectMessage
*
* @param recipientId
* recipient ID of the twitter user
* @param messageTxt
* text string to be sent as a Direct Message
*
* @return <code>true</code>, if sending the direct message has been successful and
* <code>false</code> in all other cases.
*/
public boolean sendDirectMessage(String recipientId, String messageTxt) {
if (!checkPrerequisites()) {
return false;
}
try {
Twitter localClient = client;
if (localClient != null) {
// abbreviate the Tweet to meet the allowed character limit ...
String abbreviatedMessageTxt = abbreviateString(messageTxt, CHARACTER_LIMIT);
// send the direct message
DirectMessage message = localClient.sendDirectMessage(recipientId, abbreviatedMessageTxt);
logger.debug("Successfully sent direct message '{}' to @'{}'", message.getText(),
message.getRecipientId());
return true;
}
} catch (TwitterException e) {
logger.warn("Failed to send Direct Message '{}' because of :'{}'", messageTxt, e.getLocalizedMessage());
}
return false;
}
/**
* check if twitter account was created with prerequisites
*
* @return <code>true</code>, if twitter account was initialized
* <code>false</code> in all other cases.
*/
private boolean checkPrerequisites() {
if (client == null) {
logger.debug("Twitter client is not yet configured > execution aborted!");
return false;
}
if (!isProperlyConfigured) {
logger.debug("Twitter client is not yet configured > execution aborted!");
return false;
}
return true;
}
/**
* Creates and returns a Twitter4J Twitter client.
*
* @return a new instance of a Twitter4J Twitter client.
*/
private twitter4j.Twitter createClient() {
twitter4j.Twitter client = TwitterFactory.getSingleton();
client.setOAuthConsumer(config.consumerKey, config.consumerSecret);
client.setOAuthAccessToken(new AccessToken(config.accessToken, config.accessTokenSecret));
return client;
}
public static String abbreviateString(String input, int maxLength) {
if (input.length() <= maxLength) {
return input;
} else {
return input.substring(0, maxLength);
}
}
public static String getExtension(String filename) {
if (filename.contains(".")) {
return filename.substring(filename.lastIndexOf(".") + 1);
}
return new String();
}
}

View File

@ -0,0 +1,55 @@
/**
* 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.twitter.internal;
import static org.openhab.binding.twitter.internal.TwitterBindingConstants.THING_TYPE_ACCOUNT;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
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 TwitterHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Scott Hanson - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.twitter", service = ThingHandlerFactory.class)
public class TwitterHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_ACCOUNT);
@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_ACCOUNT.equals(thingTypeUID)) {
return new TwitterHandler(thing);
}
return null;
}
}

View File

@ -0,0 +1,124 @@
/**
* 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.twitter.internal.action;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.twitter.internal.TwitterHandler;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.ActionOutput;
import org.openhab.core.automation.annotation.RuleAction;
import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.binding.ThingActionsScope;
import org.openhab.core.thing.binding.ThingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link TweetActions} class defines rule actions for sending tweet
*
* @author Scott Hanson - Initial contribution
*/
@ThingActionsScope(name = "twitter")
@NonNullByDefault
public class TwitterActions implements ThingActions {
private final Logger logger = LoggerFactory.getLogger(TwitterActions.class);
private @Nullable TwitterHandler handler;
@RuleAction(label = "@text/sendTweetActionLabel", description = "@text/sendTweetActionDescription")
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean sendTweet(
@ActionInput(name = "text") @Nullable String text) {
if (text == null) {
logger.warn("Cannot send Tweet as text is missing.");
return false;
}
final TwitterHandler handler = this.handler;
if (handler == null) {
logger.debug("Handler is null, cannot tweet.");
return false;
} else {
return handler.sendTweet(text);
}
}
@RuleAction(label = "@text/sendAttachmentTweetActionLabel", description = "@text/sendAttachmentTweetActionDescription")
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean sendTweetWithAttachment(
@ActionInput(name = "text") @Nullable String text, @ActionInput(name = "url") @Nullable String urlString) {
if (text == null) {
logger.warn("Cannot send Tweet as text is missing.");
return false;
}
if (urlString == null) {
logger.warn("Cannot send Tweet as urlString is missing.");
return false;
}
final TwitterHandler handler = this.handler;
if (handler == null) {
logger.debug("Handler is null, cannot tweet.");
return false;
} else {
return handler.sendTweet(text, urlString);
}
}
@RuleAction(label = "@text/sendDirectMessageActionLabel", description = "@text/sendDirectMessageActionDescription")
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean sendDirectMessage(
@ActionInput(name = "recipient") @Nullable String recipient,
@ActionInput(name = "text") @Nullable String text) {
if (recipient == null) {
logger.warn("Cannot send Direct Message as recipient is missing.");
return false;
}
if (text == null) {
logger.warn("Cannot send Direct Message as text is missing.");
return false;
}
final TwitterHandler handler = this.handler;
if (handler == null) {
logger.debug("Handler is null, cannot tweet.");
return false;
} else {
return handler.sendDirectMessage(recipient, text);
}
}
public static boolean sendTweet(ThingActions actions, @Nullable String text) {
return ((TwitterActions) actions).sendTweet(text);
}
public static boolean sendTweetWithAttachment(ThingActions actions, @Nullable String text,
@Nullable String urlString) {
return ((TwitterActions) actions).sendTweetWithAttachment(text, urlString);
}
public static boolean sendDirectMessage(ThingActions actions, @Nullable String recipient, @Nullable String text) {
return ((TwitterActions) actions).sendDirectMessage(recipient, text);
}
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
if (handler instanceof TwitterHandler) {
this.handler = (TwitterHandler) handler;
}
}
@Override
public @Nullable ThingHandler getThingHandler() {
return handler;
}
}

View File

@ -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.twitter.internal.config;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link TwitterConfig} class contains fields mapping thing configuration parameters.
*
* @author Scott Hanson - Initial contribution
*/
@NonNullByDefault
public class TwitterConfig {
public String consumerKey = "";
public String consumerSecret = "";
public String accessToken = "";
public String accessTokenSecret = "";
public int refresh = 30;
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="twitter" 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>Twitter Binding</name>
<description>Supports adding Thing for getting the Last Tweet. Send Tweets and Pictures with Actions.</description>
</binding:binding>

View File

@ -0,0 +1,9 @@
# actions
sendTweetActionLabel = send a Tweet
sendTweetActionDescription = Sends a Tweet.
sendAttachmentTweetActionLabel = send a Tweet with attachment
sendAttachmentTweetActionDescription = Sends a Tweet with an attachment.
sendDirectMessageActionLabel = send a DirectMessage
sendDirectMessageActionDescription = Sends a DirectMessage.

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="twitter"
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="account">
<label>Twitter Account</label>
<description>Account uses for sending Tweets</description>
<channels>
<channel id="lasttweet" typeId="lasttweet"/>
</channels>
<config-description>
<parameter name="consumerKey" type="text" required="true">
<label>Consumer API Key</label>
<context>password</context>
</parameter>
<parameter name="consumerSecret" type="text" required="true">
<label>Consumer API Secret</label>
<context>password</context>
</parameter>
<parameter name="accessToken" type="text" required="true">
<label>Access Token</label>
<context>password</context>
</parameter>
<parameter name="accessTokenSecret" type="text" required="true">
<label>Access Token Secret</label>
<context>password</context>
</parameter>
<parameter name="refresh" type="integer" required="false" unit="min" min="1">
<label>Refresh Time</label>
<description>Refresh Time for This Account in Mins</description>
<default>30</default>
</parameter>
</config-description>
</thing-type>
<channel-type id="lasttweet">
<item-type>String</item-type>
<label>Last Tweet</label>
<description>Users Last Tweet</description>
<state readOnly="true"/>
</channel-type>
</thing:thing-descriptions>

View File

@ -331,6 +331,7 @@
<module>org.openhab.binding.tplinksmarthome</module>
<module>org.openhab.binding.tr064</module>
<module>org.openhab.binding.tradfri</module>
<module>org.openhab.binding.twitter</module>
<module>org.openhab.binding.unifi</module>
<module>org.openhab.binding.unifiedremote</module>
<module>org.openhab.binding.upnpcontrol</module>