{"id":21694577,"url":"https://github.com/hjohn/nexus","last_synced_at":"2026-05-11T02:39:40.161Z","repository":{"id":261878817,"uuid":"885608747","full_name":"hjohn/Nexus","owner":"hjohn","description":null,"archived":false,"fork":false,"pushed_at":"2024-11-09T00:04:13.000Z","size":34,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-25T13:42:56.788Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hjohn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"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}},"created_at":"2024-11-08T23:42:04.000Z","updated_at":"2024-11-09T00:04:17.000Z","dependencies_parsed_at":"2024-11-09T01:17:09.730Z","dependency_job_id":"dcc72579-7b56-4857-a866-8d7489536bb6","html_url":"https://github.com/hjohn/Nexus","commit_stats":null,"previous_names":["hjohn/nexus"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FNexus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FNexus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FNexus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjohn%2FNexus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hjohn","download_url":"https://codeload.github.com/hjohn/Nexus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244629094,"owners_count":20484122,"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","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":[],"created_at":"2024-11-25T18:30:48.334Z","updated_at":"2026-05-11T02:39:40.122Z","avatar_url":"https://github.com/hjohn.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.int4.db/parent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.int4.nexus/parent)\r\n[![Build Status](https://github.com/hjohn/Nexus/actions/workflows/maven.yml/badge.svg?branch=master)](https://github.com/hjohn/Nexus/actions)\r\n[![Coverage](https://codecov.io/gh/hjohn/Nexus/branch/master/graph/badge.svg?token=QCNNRFYF98)](https://codecov.io/gh/hjohn/Nexus)\r\n[![License](https://img.shields.io/badge/License-BSD_2--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)\r\n[![javadoc](https://javadoc.io/badge2/org.int4.nexus/parent/javadoc.svg)](https://javadoc.io/doc/org.int4.nexus/parent)\r\n\r\n# Nexus\r\n\r\nAn activity based controller for your Home Cinema needs. The activities and devices are configured with a YAML (JSON) configuration file. It allows for various input devices, like `/dev/input/event` devices, `hcidump`, mappings of input values to commands, simple templates and various forms of output (HTTP, MQTT). The system tracks what devices are active, and when switching activities will activate and de-activate only what is needed.\r\n\r\n## Configuration\r\n\r\n### Actions and Schemes\r\n\r\nThe configuration file is in essence a large mapping definition, where one action leads to another. Actions are URI's distinguished with a scheme. Actions can be associated with a device, a template, an activity or a supported output type.\r\n\r\nAs actions are URI's, the always start with `\u003cscheme\u003e:`. The `scheme` can be well known schemes like `http` or `mqtt`, built-in schemes like `activty`, `cmd`, `device`, and `delay` or schemes from templates defined in the configuration file.\r\n\r\n#### The `activity` scheme\r\n\r\nThe activity scheme has the following basic format:\r\n\r\n    activity:off or activity:switch:\u003cactivity-name\u003e\r\n\r\nWith `activity:off` all current active devices will be turned off and there will no longer be an activity selected until such time as a new activity is activated.\r\n\r\nWith `activity:switch:\u003cactivity-name\u003e` a specific activity can be activated. Activities can be given descriptive names like `listen-music`, `watch-tv`, etc.\r\n\r\n#### The `cmd` (command) scheme\r\n\r\nThis scheme has the following format:\r\n\r\n    cmd:\u003ccommand-name\u003e\r\n\r\nThis scheme executes actions only in the context of the currently active activity. It will look for a mapping in the currently active activity that matches the given command name, and if found will execute the given follow up action there. For example, if `up` in the current activity is mapped to `http://192.168.3.9/doStuff` then `cmd:up` will find this mapping and execute the HTTP call that was associated with it. If the current activity has no mapping with the given name, or there is no active activity, then the command will do nothing.\r\n\r\n#### The `device` scheme\r\n\r\nThe device scheme can be used to trigger an action for a specific device. A device defined with the id `Yamaha` which has a mapping for `VOL_UP` can be targetted like this:\r\n\r\n    device:Yamaha:VOL_UP\r\n\r\nThe above action will look for a device with the id `Yamaha`, find the mapping named `VOL_UP` and execute the action defined for it. If there is no such mapping, the action will be ignored.\r\n\r\n#### The `delay` scheme\r\n\r\nSometimes it is useful to delay an action while a device activates or becomes ready to receive more actions. The delay action allows you to introduce arbitrary delays which block all processing until the delay completes. Its format is:\r\n\r\n    delay:\u003camount\u003e:\u003cunit\u003e\r\n\r\nThe supported units are minutes (`m`), seconds (`s`), milliseconds (`ms`) and nanoseconds (`ns`). The amount must be a whole number and cannot be negative.\r\n\r\nExamples:\r\n\r\n    delay:5:s -- delay for five seconds\r\n    delay:1:m -- delay for one minute\r\n    delay:250:ms -- delay for 250 milliseconds\r\n    delay:100000:ns -- delay for 1000000 nanoseconds\r\n\r\n#### Action Propagation Example\r\n\r\nWhen an action is triggered by some input device, the configuration file is checked to see how a given input action maps to a mapping in an activity, which in turn can map to a device or template, which in turn may map to an external action like a HTTP call or MQTT message. Below is an example of how an input received from an input device may get mapped into an action for a specific device:\r\n\r\n    input-device:rc1:KEY:VOLUMEUP:pressed -\u003e cmd:volume-up\r\n    cmd:volume-up -\u003e device:Yamaha:VOL_UP (based on the current active activity)\r\n    device:Yamaha:VOL_UP -\u003e irsend:NEC:32:5EA158A7:0 (a specific IR command for the Yamaha device using the irsend template)\r\n    irsend:NEC:32:5EA158A7:0 -\u003e http://192.168.3.18/cm?cmnd=IRSend(...) (a HTTP request to a Tasmota IR Blaster)\r\n\r\n### Templates\r\n\r\nTemplates are used to reduce the amount of boilerplate that needs to be specified when defining an action URI. For example, for a HTTP call, you may need to specify its name, port, path and part of its payload every time. Putting the common parts in a template not only makes the actions shorter and easier to understand, but it also makes it easier to change all commands using the template in one place.\r\n\r\nTemplates look like this:\r\n\r\n```yaml\r\ntemplates:\r\n\r\n  irsend:\r\n    template: \u003cprotocol\u003e:\u003cbits\u003e:\u003cdata\u003e:\u003crepeat\u003e\r\n    method: GET\r\n    action: http://192.168.3.18/cm\r\n    query:\r\n      cmnd: IRSend {\"Protocol\":\"\u003cprotocol\u003e\",\"Bits\":\u003cbits\u003e,\"Data\":\"0x\u003cdata\u003e\",\"Repeat\":\u003crepeat\u003e}\r\n\r\n  mediasystem:\r\n    template: \u003ckey\u003e\r\n    method: POST\r\n    action: http://192.168.3.17:8040/executeCommand\r\n    payload: '\u003ckey\u003e'\r\n```\r\nEach template has an id which defines the scheme the template will apply to. In the above example, we define the schemes `irsend` and `mediasystem`. Any mappings that start with these identifiers will have the template applied. Every template has a `template` section where angle bracket syntax can be used to identify parts that can be configured for the template. For the `irsend` template, creating a mapping that reads `irsend:NEC:32:12345678:0` means that the template values for `protocol`, `bits`, `data` and `repeat` will be `NEC`, `32`, `12345678` and `0` respectively. The final resulting action for the `irsend` template will be a new action of the form (excluding URL encoding for clarity):\r\n\r\n    http://192.168.3.18/cm?cmnd=IRSend {\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":\"0x12345678\",\"Repeat\":0}\r\n\r\nTemplates can map to any other action, including to another template.\r\n\r\n### Defining a device\r\n\r\nDevices are defined in the `devices` section. Each device has an arbitrary `id` with which the device can be referred to use one of its mappings. A device also has an activation and deactivation sequence. Here's an example for a Yamaha Receiver:\r\n\r\n```yaml\r\ndevices:\r\n  - id: Yamaha\r\n    activation:\r\n      - irsend:NEC:32:7E8154AB:1\r\n    deactivation:\r\n      - irsend:NEC:32:7E8154AB:1\r\n    mappings:\r\n      SET_OUTPUT_HDMI_1: irsend:NEC_LIKE:32:5EA1E21C:1\r\n      SET_OUTPUT_HDMI_2: irsend:NEC_LIKE:32:5EA152AC:1\r\n      SET_OUTPUT_HDMI_3: irsend:NEC_LIKE:32:5EA1B24C:1\r\n      SET_OUTPUT_HDMI_4: irsend:NEC_LIKE:32:5EA10AF4:1\r\n      SET_OUTPUT_HDMI_5: irsend:NEC_LIKE:32:5EA10EF0:1\r\n      VOL_UP: irsend:NEC:32:5EA158A7:0\r\n      VOL_DOWN: irsend:NEC:32:5EA1D827:0\r\n      MUTE: irsend:NEC:32:5EA138C7:1\r\n```\r\n\r\nTo map an action to a mapping for this device, you'd use `device:Yamaha:VOL_UP`.\r\n\r\n### Defining an activity\r\n\r\nAn activity defines which devices participate in it, any initial set-up and how commands (`cmd`) should be mapped to other actions (usually devices). An example is given below:\r\n\r\n```yaml\r\nactivities:\r\n  - id: watch-tv\r\n    description: Watch TV\r\n    participants:\r\n      - Yamaha\r\n      - Arris\r\n      - Epson-Projector\r\n    setup:\r\n      - device:Yamaha:SET_OUTPUT_HDMI_2\r\n    mappings:\r\n      volume-up: device:Yamaha:VOL_UP\r\n      volume-down: device:Yamaha:VOL_DOWN\r\n      mute: device:Yamaha:MUTE\r\n      channel-up: device:Arris:channel-up\r\n      channel-down: device:Arris:channel-down\r\n```\r\nThe above activity has three participants (a HDMI receiver, a TV box and a Projector). Any devices which were not active when this activity is activated will have its activitation sequence triggered. Once all devices are active, the setup actions are triggered one by one. Once the activity is fully setup, it becomes active, and any command actions will use the mappings in this activity to map commands to activity specific actions.\r\n\r\n### Defining Connectors\r\n\r\nConnectors provide sources of input. Currently only Linux input devices are supported using either `/dev/input/event` style devices or even more low-level, the `hcidump` tool (for reading bluetooth devices that refuse to create a normal input device). An example is given below for a Conceptronic Remote and for any currently paired bluetooth device:\r\n\r\n```yaml\r\nconnectors:\r\n  org.int4.nexus.core.connector.InputDeviceConnector:\r\n    - id: rc1\r\n      device: /dev/input/by-id/usb-TopSeed_Technology_Corp._USB_RF_Combo_Device-event-kbd\r\n    - id: rc2\r\n      device: /dev/input/by-id/usb-TopSeed_Technology_Corp._USB_RF_Combo_Device-if01-event-mouse\r\n  org.int4.nexus.core.connector.HciDumpConnector:\r\n    - id: hci\r\n```\r\nThe id's will be used to distinguish the generated action URI's for these inputs. The `InputDeviceConnector` creates actions of the form `input-device:\u003cid\u003e:` while the `HciDumpConnector` will create actions of the form `hci:`.\r\n\r\nMost connectors will contain some kind of key code (text or hexadecimal) to which a key state is appended. The states supported are `pressed`, `released`, `held`, `short-pressed` and `long-pressed`. These can be mapped arbitrarily to follow-up actions. Some example input URI's:\r\n\r\n    input-device:rc1:KEY:LEFT:pressed -- the input device with id \"rc1\" notified us that \"KEY:LEFT\" is in the pressed state\r\n    input-device:rc1:KEY:LEFT:held -- the input device with id \"rc1\" notified us that \"KEY:LEFT\" is being held down (this repeats)\r\n    input-device:rc1:KEY:LEFT:long-pressed -- the input device with id \"rc1\" notified us that \"KEY:LEFT\" has reached the long press threshold\r\n    input-device:rc1:KEY:LEFT:released -- the input device with id \"rc1\" notified us that \"KEY:LEFT\" was released\r\n\r\nThe `HciDumpConnector` has less readable actions (and you may have to monitor its output to find the required codes). For example:\r\n\r\n    hci:001f:44000000:pressed -- could signal that the \"left\" key was pressed\r\n\r\nRead on in the next section how to make these input actions more readable.\r\n\r\n### Input Mappings\r\n\r\nThe inputs generated by connectors can sometimes be hard to read or need to be mapped to something non-obvious. Although it is possible for a connector to generate an action that could immediately map to some device mapping, most input connectors will not. This means that any input must be mapped to another action, be it a command for the active activity, a direct action like a HTTP call or always to a specific device (without the activity indirection).\r\n\r\nFor example, to map the `LEFT` key from the `rc1` input device to a `left` command when it is pressed and repeated each time when it is held, define the following input mappings:\r\n\r\n```yaml\r\ninput-mappings:\r\n    input-device:rc1:KEY:LEFT:pressed: cmd:left\r\n    input-device:rc1:KEY:LEFT:held: cmd:left\r\n```\r\n\r\nTo control activities with long press actions, you can for example do this:\r\n\r\n```yaml\r\ninput-mappings:\r\n  input-device:rc1:KEY:SLEEP:long-pressed: activity:off\r\n  input-device:rc1:KEY:RADIO:long-pressed: activity:switch:watch-chromecast\r\n  input-device:rc1:KEY:MP3:long-pressed: activity:switch:watch-tv\r\n```\r\n\r\nInputs that have meaningless codes can be mapped a bit more clearly like this:\r\n\r\n```yaml\r\ninput-mappings:\r\n  hci:001f:61000000:pressed: cmd:subtitles  # Text key\r\n  hci:001f:bd010000:pressed: cmd:info  # Info key\r\n```\r\n\r\nTo more directly have a specific input action control a device or trigger an external action, just use a different scheme for the mapping. For example:\r\n\r\n```yaml\r\ninput-mappings:\r\n    input-device:rc1:KEY:VOLUMEUP:pressed: device:Yamaha:VOL_UP\r\n```\r\n\r\nThe above command will always trigger the VOL_UP mapping on the Yamaha device, regardless of selected activity or whether any activity is active at all. Note that if the device is off, it won't be turned on in this case. Only activities can turn devices on and off (although it  is possible still to directly map to an on/off action for a device if so desired).\r\n\r\n### Handlers\r\n\r\nHandlers offer ways to trigger an external action. They are defined in the configuration file in the `handlers` section, and may offer additional configuration parameters. A handler has its own scheme that can be chosen with its `id`. It is allowed to define the same handler multiple times with different id's to allow for different configurations. To use a specific handler in an action, make sure its scheme matches the id of the intended handler.\r\n\r\nCurrently there are three supported handlers: `MqttProtocolHandler`, `WakeOnLanHandler` and `HttpProtocolHandler`.\r\n\r\n## Full Sample Configuration\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjohn%2Fnexus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhjohn%2Fnexus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjohn%2Fnexus/lists"}