{"id":15021078,"url":"https://github.com/christophecvb/touchportalpluginsdk","last_synced_at":"2025-08-29T21:35:14.036Z","repository":{"id":39997700,"uuid":"267048594","full_name":"ChristopheCVB/TouchPortalPluginSDK","owner":"ChristopheCVB","description":"This Project is an SDK to create a Touch Portal Plugin using Java or Kotlin and Gradle","archived":false,"fork":false,"pushed_at":"2024-11-18T17:29:49.000Z","size":867,"stargazers_count":42,"open_issues_count":12,"forks_count":8,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-07-13T01:21:40.001Z","etag":null,"topics":["annotations","annotations-processor","gradle","java","kotlin","plugin-sdk","sdk","sdk-java","touch-portal","touch-portal-plugin"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChristopheCVB.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=K5NSGWHK3RDP6\u0026item_name=Touch+Portal+Plugin+SDK\u0026currency_code=EUR\u0026source=url"]}},"created_at":"2020-05-26T13:21:32.000Z","updated_at":"2025-01-03T01:38:47.000Z","dependencies_parsed_at":"2023-01-30T01:15:59.993Z","dependency_job_id":"c1522a94-20bd-4943-b7e2-bb90f8855bc4","html_url":"https://github.com/ChristopheCVB/TouchPortalPluginSDK","commit_stats":{"total_commits":287,"total_committers":8,"mean_commits":35.875,"dds":0.3240418118466899,"last_synced_commit":"97f71be7df95664c15c078a1d7641d38b5964200"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/ChristopheCVB/TouchPortalPluginSDK","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopheCVB%2FTouchPortalPluginSDK","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopheCVB%2FTouchPortalPluginSDK/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopheCVB%2FTouchPortalPluginSDK/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopheCVB%2FTouchPortalPluginSDK/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChristopheCVB","download_url":"https://codeload.github.com/ChristopheCVB/TouchPortalPluginSDK/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChristopheCVB%2FTouchPortalPluginSDK/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272766775,"owners_count":24989407,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-29T02:00:10.610Z","response_time":87,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["annotations","annotations-processor","gradle","java","kotlin","plugin-sdk","sdk","sdk-java","touch-portal","touch-portal-plugin"],"created_at":"2024-09-24T19:56:06.558Z","updated_at":"2025-08-29T21:35:13.996Z","avatar_url":"https://github.com/ChristopheCVB.png","language":"Java","funding_links":["https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=K5NSGWHK3RDP6\u0026item_name=Touch+Portal+Plugin+SDK\u0026currency_code=EUR\u0026source=url"],"categories":[],"sub_categories":[],"readme":"# [Touch Portal](https://www.touch-portal.com/) Plugin SDK\n\n[![Touch Portal Plugin SDK](https://raw.githubusercontent.com/ChristopheCVB/TouchPortalPluginSDK/master/resources/TP%20Plugin%20SDK%20Logo.png)](#touch-portal-plugin-sdk)\n\n[![Build, Coverage and Publish Release](https://github.com/ChristopheCVB/TouchPortalPluginSDK/workflows/Build,%20Coverage%20and%20Publish%20Release/badge.svg)](#touch-portal-plugin-sdk)\n[![Build and Publish Snapshot](https://github.com/ChristopheCVB/TouchPortalPluginSDK/workflows/Build%20and%20Publish%20Snapshot/badge.svg)](#touch-portal-plugin-sdk)\n[![Code Coverage](https://codecov.io/gh/ChristopheCVB/TouchPortalPluginSDK/branch/master/graph/badge.svg)](https://codecov.io/gh/ChristopheCVB/TouchPortalPluginSDK)\n[![Language gradle: Java](https://img.shields.io/lgtm/grade/java/g/ChristopheCVB/TouchPortalPluginSDK.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/ChristopheCVB/TouchPortalPluginSDK/context:java)\n\nThis Project is an SDK to create a Touch Portal Plugin using Java or Kotlin and Gradle.\nThis SDK is a complete solution which will not only help you connect to communicate with TouchPortal through Actions, Events, States, Settings and Connectors, but it will also help you with the hassle of packaging it  \n\nFor further reference, the Touch Portal Plugin documentation can be found [here](https://www.touch-portal.com/api)\n\n## Documentation\n\nOnce you have cloned this project, you can run the `gradlew javaDoc` and browse the document in the `build/docs/javadoc` of each module\n\n## Releases\n\nGo to [releases](https://github.com/ChristopheCVB/TouchPortalPluginSDK/releases) to check which is the latest\n\n### Maven Central\n\nVersions before `7.0.0` were not published to Maven Central\n\n#### Gradle\n\n```groovy\nplugins {\n  id 'com.christophecvb.touchportal.plugin-packager' version 'X.Y.Z'\n}\n\ntpPlugin.mainClassSimpleName = 'MyTouchPortalPlugin'\n\ndependencies {\n  implementation 'com.christophecvb.touchportal:plugin-sdk:X.Y.Z'\n  annotationProcessor 'com.christophecvb.touchportal:plugin-sdk-annotations-processor:X.Y.Z'\n}\n```\n\n## Get Started\n\n- Create a new Gradle Java Project\n- Copy the `build.gradle` from the `SampleJava` or `SampleKotlin` module to your new module\n    - Edit the properties `mainClassPackage` and `mainClassSimpleName`\n    - Replace `versionName` by your plugin version (`'1.0.0'` for example)\n    - Replace the dependencies to get the latest Maven Central ones\n- Create a class (`mainClassSimpleName`'s value), in the package you chose (`mainClassPackage`'s value), extending `TouchPortalPlugin` and implementing `TouchPortalPlugin.TouchPortalPluginListener` (i.e. `MyTouchPortalPlugin extends TouchPortalPlugin implements TouchPortalPlugin.TouchPortalPluginListener`) like the example below:\n\n```java\npublic class MyTouchPortalPlugin extends TouchPortalPlugin implements TouchPortalPlugin.TouchPortalPluginListener {\n    /**\n     * Logger\n     */\n    private final static Logger LOGGER = Logger.getLogger(TouchPortalPlugin.class.getName());\n    \n    /**\n     * Constructor calling super\n     */\n    public MyTouchPortalPlugin() {\n        super(true);// true is for paralleling Actions executions\n    }\n\n    public static void main(String... args) {\n        if (args != null \u0026\u0026 args.length == 1) {\n            if (PluginHelper.COMMAND_START.equals(args[0])) {\n                // Initialize your Plugin\n                MyTouchPortalPlugin myTouchPortalPlugin = new MyTouchPortalPlugin();\n                // Initiate the connection with the Touch Portal Plugin System (will trigger an onInfo message with a confirmation from TouchPortal and the initial settings)\n                boolean connectedPairedAndListening = myTouchPortalPlugin.connectThenPairAndListen(myTouchPortalPlugin);\n            }\n        }\n    }\n\n    /**\n     * Called when the Socket connection is lost or the plugin has received the close Message\n     */\n    public void onDisconnected(Exception exception) {  }\n\n    /**\n     * Called when receiving a message from the Touch Portal Plugin System\n     */\n    public void onReceived(JsonObject jsonMessage) { }\n\n    /**\n     * Called when the Info Message is received when Touch Portal confirms our initial connection is successful\n     */\n    public void onInfo(TPInfoMessage tpInfoMessage) { }\n\n    /**\n     * Called when a List Change Message is received\n     */\n    public void onListChanged(TPListChangeMessage tpListChangedMessage) { }\n\n    /**\n     * Called when a Broadcast Message is received\n     */\n    public void onBroadcast(TPBroadcastMessage tpBroadcastMessage) { }\n\n    /**\n     * Called when a Settings Message is received\n     */\n    public void onSettings(TPSettingsMessage tpSettingsMessage) { }\n\n    /**\n     * Called when a Notification Option Clicked Message is received\n     */\n    public void onNotificationOptionClicked(TPNotificationOptionClickedMessage tpNotificationOptionClickedMessage) { }\n}\n```\n\n## Development and Interaction\nThe SDK will automatically invoke your action methods if they contain only `@Data` annotated parameters\n\n```java\npublic class MyTouchPortalPlugin extends TouchPortalPlugin implements TouchPortalPlugin.TouchPortalPluginListener {\n    // ...\n\n    /**\n     * Action example with a Data Text parameter\n     *\n     * @param text String\n     */\n    @Action(description = \"Long Description of Dummy Action with Data Text\", format = \"Set text to {$text$}\", categoryId = \"BaseCategory\")\n    private void actionWithText(@Data String text) {\n      MyTouchPortalPlugin.LOGGER.log(Level.INFO, \"Action actionWithText received: \" + text);\n    }\n    \n    // ...\n}\n```\n\nOtherwise, call your actions manually in the `onReceived(JsonObject jsonMessage)` method\n\n```java\npublic class MyTouchPortalPlugin extends TouchPortalPlugin implements TouchPortalPlugin.TouchPortalPluginListener {\n    // ...\n  \n    public void onReceived(JsonObject jsonMessage) {\n        // Check if ReceiveMessage is an Action\n        if (ReceivedMessageHelper.isTypeAction(jsonMessage)) {\n            // Get the Action ID\n            String receivedActionId = ReceivedMessageHelper.getActionId(jsonMessage);\n            if (receivedActionId != null) {\n                // Manually call the action methods which not all parameters are annotated with @Data\n                switch (receivedActionId) {\n                    // case ...:\n                    // break;\n                }\n            }\n        }\n    }\n    \n    //...\n}\n```\n\nDon't forget to initialize all your services once you receive the onInfo event. The TPInfoMessage will also contain the initial values of your settings.\n\n```java\npublic class MyTouchPortalPlugin extends TouchPortalPlugin implements TouchPortalPlugin.TouchPortalPluginListener {\n    // ...\n  \n    public void onInfo(TPInfoMessage tpInfoMessage) {\n        // TPInfoMessage will contain the initial settings stored by TP\n        // -\u003e Note that your annotated Settings fields will be up-to-date at this point\n      \n        // continue plugin initialization\n    }\n    \n    // ...\n}\n```\n\nFinally, send messages back to TouchPortal when you want to update your states\n\n```java\npublic class MyTouchPortalPlugin extends TouchPortalPlugin implements TouchPortalPlugin.TouchPortalPluginListener {\n    // ...\n  \n    @State(defaultValue = \"Default Value\", categoryId = \"SecondCategory\")\n    private String customStateText;\n  \n    @Action(description = \"Long Description of Dummy Action with Data Text\", format = \"Set text to {$text$}\", categoryId = \"BaseCategory\")\n    private void actionWithText(@Data String text) {\n      // ... do something then update state\n      this.customStateText = \"new state value\";\n      this.sendStateUpdate(MyTouchPortalPluginConstants.BaseCategory.States.CustomStateText.ID, this.customStateText, true);\n    }\n    \n    // ...\n}\n```\n\n## Use Annotations to describe your plugin\n\nThe provided Annotations help you in the automatic generation of the `entry.tp` file (necessary for packaging and deployment of your plugin)\n\nCurrent supported annotations include: Plugin, Category, Action, Data, State, Event and Setting \n\nMore examples can be found in the sample modules\n\n```java\n// ...\n\n@Plugin(\n        name = \"My Touch Portal Plugin\",\n        version = BuildConfig.VERSION_CODE,\n        colorDark = \"#203060\",\n        colorLight = \"#4070F0\",\n        parentCategory = ParentCategory.MISC\n)\npublic class MyTouchPortalPlugin extends TouchPortalPlugin {\n    //...\n\n    /**\n     * Action example that contains a dynamic data text\n     *\n     * @param text String\n     */\n    @Action(\n            description = \"Long Description of Dummy Action with Data\",\n            format = \"Set text to {$text$}\",\n            categoryId = \"BaseCategory\"\n    )\n    private void dummyWithData(@Data String text) {\n        LOGGER.log(Level.Info, \"Action dummyWithData received: \" + text);\n    }\n\n    /**\n     * State and Event definition example\n     */\n    @State(defaultValue = \"1\", categoryId = \"BaseCategory\")\n    @Event(valueChoices = {\"1\", \"2\"}, format = \"When customStateWithEvent becomes $val\")\n    private String customStateWithEvent;\n\n    private enum Categories {\n        /**\n         * Category definition example\n         */\n        @Category(name = \"My Touch Portal Plugin\", imagePath = \"images/icon-24.png\")\n        BaseCategory\n    }\n\n    //...\n}\n```\n\n## Prepackaging\n\nAdd the Plugin icon and extra resources into the `src/main/resources/` directory of your module\n\n## Clean, Build and Package\n\n- Clean Project\n  - `gradlew clean`\n- Build Project\n  - `gradlew build` \n- Package Project\n  - `gradlew packagePlugin` task to pack your plugin into a `.tpp` file. Output files will be in your module's `build/plugin` directory.\n\n## Debugging tips\n\n- A clean Touch Portal installation won't accept plugin connections by default. You need to install your plugin first on TouchPortal to 'jumpstart' the Plugin listening service and then restart Touch Portal.\n- Using IntelliJ, you can also create a Configuration to start and debug the plugin right from the IDE\n  - Run \u003e Edit Configurations\n  - Add New Configuration (`+`)\n  - Select Application\n    - Name: `TPP Start`\n    - Module: `Java 8 (1.8)`\n    - ClassPath Module (`-cp`): `YourModule.main`\n    - Main Class: `your.package.YourTouchPortalPlugin`\n    - Arguments: `start`\n    - Working Directory: `YourModule/build/plugin/YourTouchPortalPlugin`\n![Touch Portal Plugin SDK Gradle Application Configuration](https://raw.githubusercontent.com/ChristopheCVB/TouchPortalPluginSDK/master/resources/TP%20Plugin%20SDK%20Gradle%20Application%20Configuration.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophecvb%2Ftouchportalpluginsdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristophecvb%2Ftouchportalpluginsdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophecvb%2Ftouchportalpluginsdk/lists"}