goucrt

module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 14, 2026 License: MPL-2.0

README

A Unfolded Circle Remote Two Integration Library in Go

GitHub Workflow Status (with event) GitHub GitHub (Pre-)Release Date

⚠️ DISCLAIMER This is Work in Progress and might not yet be functional.

This Unfolded Circle Remote Two integration driver written in Go implements is written as generic as possible to be used with any kind of device to control.

Currently this repository implements a driver for the following devices:

Intergrations implemented using this library:

Device / Clients

Generic Client

The generic client is not functional. You need to implement your own Client for the device you want to control

Deconz

Run with ucrt deconz

This client currently implements Light entities for discovered DeCONZ Lights and Groups and Sensor entitites for selected DeCONZ sensors.

Shelly

Run with ucrt shelly

This client currently implements Switch entities for discovered Shelly Devices. It uses MQTT to discover and control Shelly devices.

Tasmota

Run with ucrt tasmota

This client currently implements Switch entities and Light entities It uses MQTT to discover and control Tasmota devices.

Currently on the following Sonoff device types are supported

  • 0 Sonoff Basic results in a Switch entity
  • 4 RGBW results in a Light entity

Note The light entity does not really suport RGBW. So currently, as a somehow working workaround, when setting the brithness is set to 0, the entity changes between RGB & W Settings.

How to use

Unfolder Circle Remote Two integration

Usage:
  ucrt-amd64 [command]

Available Commands:
  completion  Generate the autocompletion script for the specified shell
  deconz      Start Deconz Ingegration
  help        Help about any command
  shelly      Start Shelly Ingegration
  tasmota     Start Tasmota Ingegration

Flags:
      --debug                         Enable debug log level
      --disableMDNS                   Disable integration advertisement via mDNS
  -h, --help                          help for ucrt-amd64
  -l, --listenPort int                the port this integration is listening for websocket connection from the remote (default 8080)
      --registration                  Enable driver registration on the Remote Two instead of mDNS advertisement
      --registrationPin string        Pin of the RemoteTwo for driver registration
      --registrationUsername string   Username of the RemoteTwo for driver registration (default "web-configurator")
      --remoteTwoIP string            IP Address of your Remote Two instance (disables Remote Two discovery)
      --remoteTwoPort int             Port of your Remote Two instance (disables Remote Two discovery) (default 80)
      --ucconfighome string           Configuration directory to save the user configuration from the driver setup (default "./ucconfig/")
      --websocketPath string          path where this integration is available for websocket connections (default "/ws")

Use "ucrt-amd64 [command] --help" for more information about a command.

As a Container

You can start the Integration as a container by using the released container images:

Example to start the DenonAVR Integration:

docker run ghcr.io/splattner/goucrt:v0.1.7 denonavr

To keep the setup data persistet mount a volume to /app/ucconfig:

docker run -v ./localdir:/app/ucconfig ghcr.io/splattner/goucrt:v0.1.7 denonavr

For the mDNS adventisement to work correctly I suggest starting the integration in the host network. And you can set your websocket listening port with the environment variable UC_INTEGRATION_HTTP_PORT:

docker run --net=host -e UC_INTEGRATION_HTTP_PORT=10000 -v ./localdir:/app/ucconfig ghcr.io/splattner/goucrt:v0.1.7 denonavr
As a custom-installed driver on the Remote

Since firmware v1.9.0, the remote can install an integration driver directly as a .tar.gz archive - no separate host needed. goucrt's deCONZ, Shelly and Tasmota clients each build as their own installable archive; see the Core-API's custom driver installation docs for the full format and the remote's sandbox environment.

Build all three archives:

make custom-driver-archives

This produces custom-driver-dist/{deconz,shelly,tasmota}-custom-driver.tar.gz, each a statically linked linux/arm64 binary at bin/driver plus a generated driver.json and the client's icon at the archive root. Released versions are attached to each GitHub release alongside the container images.

Install one in the remote's web-configurator: integrations, Add new, Install custom, and upload the archive. Or via the REST API:

curl --location 'http://$REMOTE_IP/api/intg/install' \
  --user 'web-configurator:$PIN' \
  --form 'file=@"deconz-custom-driver.tar.gz"'

Setup data persists across restarts in the remote-managed $UC_CONFIG_HOME/$UC_DATA_HOME directories - nothing to mount, unlike the container image. mDNS advertisement and self-registration are disabled automatically in this mode (see Environment Variables below): the remote already knows how to reach the driver from the installation itself.

Configuration
Environment Variables

The following environment variables exist in addition to the configuration file:

Variable Values Description
UC_CONFIG_HOME directory path Configuration directory to save the user configuration from the driver setup.
Default: ./ucconfig/
UC_DATA_HOME directory path Directory for a driver's own application data, separate from user setup data.
Default: same as UC_CONFIG_HOME. goucrt itself doesn't write anything here yet; it's exposed for driver code to use.
UC_DISABLE_MDNS_PUBLISH true / false Disables mDNS service advertisement.
Default: false
UC_INTEGRATION_HTTP_PORT int The port this integration is listening for websocket connections from the remote. Set automatically by the remote when running as a custom-installed driver; always takes precedence over UC_INTEGRATION_LISTEN_PORT/--listenPort when set.
Default: 8080
UC_INTEGRATION_LISTEN_PORT int Same as UC_INTEGRATION_HTTP_PORT above, kept for backwards compatibility. Use UC_INTEGRATION_HTTP_PORT if you can - it's the name the remote itself uses.
UC_INTEGRATION_INTERFACE host/IP Host/IP address to listen on. Set automatically by the remote when running as a custom-installed driver.
Default: all interfaces (0.0.0.0)
UC_INTEGRATION_WEBSOCKET_PATH string Path where this integration is available for websocket connections.
Default: /ws
UC_RT_HOST string IP Address of your Remote Two instance (disables Remote Two discovery via mDNS for registration)
UC_RT_PORT int Port of your Remote Two instance (disables Remote Two discovery via mDNS for registration)
UC_ENABLE_REGISTRATION string Enable driver registration on the Remote Two instead of mDNS advertisement.
Default: false
UC_REGISTRATION_USERNAME string Username of the RemoteTwo for driver registration.
Default: web-configurator
UC_REGISTRATION_PIN string Pin of the RemoteTwo for driver registration

When running as a custom-installed driver, mDNS advertisement and self-registration are disabled automatically (there's no way for the sandboxed process to receive CLI flags, so UC_DISABLE_MDNS_PUBLISH/UC_ENABLE_REGISTRATION can't be set either) - neither serves a purpose there, since the remote already knows about the driver from the installation archive.

Development

The generic client is in pgk/client/client.go. In order to implement your own client, you have to implement the following functions:

// Client specific functions
// Initialize the client
// Here you can add entities if they are already known
initFunc func()
// Called by RemoteTwo when the integration is added and setup started
setupFunc      func()
// Handles connect/disconnect calls from RemoteTwo
clientLoopFunc func()

See Denon Client Example in in pkg/client/denonavrclient.go

Todo's

  • Implement all available entities
  • Handle command calls
  • Allow for attribute changes
  • Allow for driver regisration
    • Make it more robust
  • Allow for driver authentication with token/header
  • Documentation, how to use, how to implement your own device
  • probably way more

How to Build and Run

# in cmd/ucrt
go get -u
go build .
Docker
docker build -f build/Dockerfile -t  ghcr.io/splattner/goucrt:latest

Verifying

Checksum
Checksums
wget https://github.com/splattner/goucrt/releases/download/v0.1.3/goucrt_0.1.3_checksums.txt
cosign verify-blob \
  --certificate-identity 'https://github.com/splattner/goucrt/.github/workflows/release.yaml@refs/tags/v0.1.3' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  --cert https://github.com/splattner/goucrt/releases/download/v0.1.3/goucrt_0.1.3_checksums.txt.pem \
  --signature https://github.com/splattner/goucrt/releases/download/v0.1.3/goucrt_0.1.3_checksums.txt.sig \
  ./goucrt_0.1.3_checksums.txt

You can then download any file you want from the release, and verify it with, for example:

wget https://github.com/splattner/goucrt/releases/download/v0.1.3/goucrt_0.1.3_linux_amd64.tar.gz.sbom
wget https://github.com/splattner/goucrt/releases/download/v0.1.3/goucrt_0.1.3_linux_amd64.tar.gz
sha256sum --ignore-missing -c checksums.txt

And both should say "OK".

You can then inspect the .sbom file to see the entire dependency tree of the binary.

Docker image
cosign verify ghcr.io/splattner/goucrt:v0.1.3 --certificate-identity 'https://github.com/splattner/goucrt/.github/workflows/release.yaml@refs/tags/v0.1.3' --certificate-oidc-issuer 'https://token.actions.githubusercontent.com'

License

This project is licensed under the Mozilla Public License 2.0. See the LICENSE file for details.

Directories

Path Synopsis
cmd
deconz-driver command
Command deconz-driver is the deCONZ client built as its own single-purpose binary, for packaging as a custom-installed driver on the remote (see doc/integration-driver/driver-installation.md).
Command deconz-driver is the deCONZ client built as its own single-purpose binary, for packaging as a custom-installed driver on the remote (see doc/integration-driver/driver-installation.md).
shelly-driver command
Command shelly-driver is the Shelly client built as its own single-purpose binary, for packaging as a custom-installed driver on the remote.
Command shelly-driver is the Shelly client built as its own single-purpose binary, for packaging as a custom-installed driver on the remote.
tasmota-driver command
Command tasmota-driver is the Tasmota client built as its own single-purpose binary, for packaging as a custom-installed driver on the remote.
Command tasmota-driver is the Tasmota client built as its own single-purpose binary, for packaging as a custom-installed driver on the remote.
ucrt command
internal
spec
Package spec parses the vendored Core-API AsyncAPI definition (see spec/core-api) so goucrt's own tests can check its hand-maintained protocol constants against the spec instead of relying on someone noticing drift by eye.
Package spec parses the vendored Core-API AsyncAPI definition (see spec/core-api) so goucrt's own tests can check its hand-maintained protocol constants against the spec instead of relying on someone noticing drift by eye.
spec/spectest
Package spectest provides small testing helpers for checking goucrt's hand-maintained protocol constants and golden fixtures against the vendored Core-API spec (see internal/spec).
Package spectest provides small testing helpers for checking goucrt's hand-maintained protocol constants and golden fixtures against the vendored Core-API spec (see internal/spec).
pkg
cmd
tools
extractgoldens command
Command extractgoldens extracts the worked JSON request/event examples from the vendored Core-API entity docs (spec/core-api/doc/entities/*.md) into individual golden fixture files under pkg/entities/testdata, for the entity types goucrt currently implements.
Command extractgoldens extracts the worked JSON request/event examples from the vendored Core-API entity docs (spec/core-api/doc/entities/*.md) into individual golden fixture files under pkg/entities/testdata, for the entity types goucrt currently implements.
gendriverjson command
Command gendriverjson writes the driver.json metadata file a custom-installed driver archive needs at its root, using integration.GenerateDriverJSON - see that function's doc comment for how and why.
Command gendriverjson writes the driver.json metadata file a custom-installed driver archive needs at its root, using integration.GenerateDriverJSON - see that function's doc comment for how and why.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL