Control a Grenton smart home from Swift, over the local network.
Developer toolsSwift · PythonGitHub @osieckiAdamOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Swift implementation of the Grenton Core spec — the Grenton smart-home mobile-interface protocol
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Control a Grenton smart home from Swift on macOS and iOS: lights, shutters, thermostats, scenes and sensors, over the local network, the way the myGrenton app does.
Documentation: https://osieckiadam.github.io/grenton-core-swift/ — installation, a Getting Started walkthrough and the API reference.
| Local, no cloud | Talks to the CLU controllers directly on your network, with their own encryption. |
| Every device | Switches, dimmers, RGB lights, shutters, thermostats, scenes, sensors, cameras, schedules and TV remotes. |
| Always current | CLUs push every change, so state stays up to date without polling. |
| Conformance-tested | Implements the Grenton Core specification and passes its conformance suite. |
This repository is the Swift implementation of Grenton Core, a portable library for the Grenton smart-home "mobile interface" protocol. The specification is language-agnostic and lives in grenton-core-spec, together with the conformance suite every port must pass. It covers provisioning (an Object Manager client), the encrypted UDP runtime for CLU controllers and a canonical device model, extracted from the homeassistant-grenton integration.
main.vendor/grenton-core-spec as a git submodule.docs/grenton-core-swift-port.md — the Swift port plan: maintainers' notes, in Polish| Target | Status | Spec section |
|---|---|---|
GrentonModel | done | §3 |
GrentonRuntime | done (session, transports, state store) | §5 |
GrentonProvisioning | done (Object Manager download, project-file import) | §4 |
GrentonDevices | done (descriptors, entities, physical objects, GrentonSystem facade) | §6 |
GrentonKit | the umbrella: one import for apps, GrentonSystem(interfaceArchive:), InterfaceStore (the archive, kept safely) | §2 |
GrentonSimulation | the same entities without a CLU, for app tests | §2 |
GrentonSwiftUI | Observed: an entity a SwiftUI view follows (iOS 17 / macOS 14) | §2 |
Examples/ | small programs using the library | — |
| Documentation | DocC reference and guides | — |
You need a Mac with Swift 6.2.3+ (Xcode 26.2+ or the Command Line Tools), and a computer running Grenton Object Manager on the same LAN as the Mac and the CLUs.
git clone https://github.com/osieckiAdam/grenton-core-swift.git
cd grenton-core-swift
1. Download the interface from Object Manager. You need its IP address and the PIN; see Where to get the PIN and IP address below.
swift run fetch-interface 192.168.1.50 dist/interface.zip 149 853
There is no separate swift build step. swift run fetches the one
dependency (ZIPFoundation), compiles the package and starts the example. The
first run takes about 20 seconds, and later runs start almost immediately.
The saved file lets every next step run without a PIN. It contains the CLU
encryption key, so it is written readable by you only and dist/ is
git-ignored.
No PIN at hand? The project file you save in Object Manager (.omp) holds
the same interface and key; swift run import-project house.omp reads it
and lists the devices. The other examples take the downloaded archive.
2. List your devices. This works offline, from the saved file alone.
swift run list-devices dist/interface.zip
switch "Living room ceiling" — page SALON
k3Xq9TzA_0: Living room ceiling
k3Xq9TzA_0 is the entity id the next steps take. At the end you also see
the CLU objects shown by several widgets, such as a thermostat that appears
on two pages under two names.
3. Watch the live state. This is read-only.
swift run watch-state dist/interface.zip 30
It connects to the CLUs, prints every entity's current state, and then prints each change for 30 seconds. Switch a light in the house to see one arrive.
On the first connection macOS asks whether the terminal may access devices on the local network. Allow it, or nothing can reach the CLUs.
4. Turn a light on and off. This changes your house.
swift run switch-light dist/interface.zip k3Xq9TzA_0 on
swift run switch-light dist/interface.zip k3Xq9TzA_0 off
It works for switches, dimmers and RGB lights, and waits for the CLU to confirm the new state.
Object Manager shows both in one dialog, the one it opens when you send the interface to a mobile device:
fetch-interface.9998.The screenshot hides the IP address and port; your dialog shows them in the same place, above the token.
149 853 and 149853 both work.
The PIN is the last argument, so the space needs no quotes.9998, append it to the IP address:
swift run fetch-interface 192.168.1.50:9999 dist/interface.zip 149 853.fetch-interface prints saved to ….
Object Manager serves the interface only while this window is open (the
dialog itself says so).Examples/ holds small programs that use the library the way
an app would. Each one is a single main.swift meant to be read.
| Example | What it shows | Changes your house? |
|---|---|---|
fetch-interface | Download the interface from Object Manager with the PIN and save it | no |
import-project | Read the interface from an Object Manager project file (.omp) instead of downloading it, and list the devices | no (offline) |
list-devices | Devices and entities per page, skipped widgets, objects shown by several widgets | no (offline) |
read-values | Read any CLU value once — a feature no widget shows — without subscribing | no |
watch-state | Every entity's normalized state after connecting, then changes as they happen | no |
switch-light | Turn a switch, dimmer or RGB light on/off and wait for the CLU to confirm | yes |
run-scene | Run a scene by its name or entity id | yes |
swift run set-thermostat dist/interface.zip THE1001 21
set-thermostat reads the current target first, writes nothing if it
cannot, and prints the command that restores the previous value. Object
names such as THE1001 (yours will differ) are in the output of list-devices.
The documentation site is published at https://osieckiadam.github.io/grenton-core-swift/ on every release. It has three parts:
To build and open it locally:
scripts/docs.sh
Then open http://localhost:8000/. The first run fetches the DocC plugin and
takes a minute or two. scripts/docs.sh build only generates the site into
.build/site. The hand-written pages are in site/; the reference comes
from the doc comments and the .docc catalogs.
Swift 6.2.3+ (Xcode 26.2+) to build; apps run on iOS 16+ / macOS 13+. Apple platforms only: the runtime uses Network.framework and CommonCrypto, so there is no Linux build.
Releases are tagged with the version of the specification they implement
(0.9.1 implements spec 0.9.1 and passes suite 0.9.1). Until 1.0 the
package promises conformance with the spec, not a frozen API:
GrentonKit (which re-exports GrentonDevices and GrentonProvisioning),
GrentonSimulation and GrentonSwiftUI are what an app is meant to use
and change deliberately; GrentonModel and GrentonRuntime are plumbing between
them and may still change shape. The catalogue enums — BoundEntity,
EntityDescriptor, DeviceKind, WidgetDTO, the error enums and the
others that grow with Grenton's products — are @nonexhaustive
(SE-0487): a new case is a minor release, and a switch over them in an
app needs @unknown default. That is why the package needs Swift 6.2.3
to build. Every change is listed in
CHANGELOG.md.
MIT. The specification and its conformance suite (grenton-core-spec) are MIT as well.
The conformance tests read the suite from the vendor/grenton-core-spec
submodule, so fetch it first:
git submodule update --init # or clone with --recurse-submodules
swift test
GrentonConformanceTests runs every case of the
conformance suite. It fails if the
submodule is missing, if the manifest is inconsistent, or if a case fails.
Tests/GrentonConformanceTests/port.json
declares the suite version, the profiles this port claims (currently
stateless, mapping and session) and any skipped cases (none today).
The session scenarios drive a real CluSession through a scripted
transport and a virtual clock, so they need no network and no CLU.
To move to a newer suite, update the submodule and bump suiteVersion in
port.json:
git -C vendor/grenton-core-spec pull origin main
set-thermostat| Find a thermostat by its CLU object, read its state, set the target temperature and confirm the CLU applied it |
| yes |
probe-register | Research probe behind spec §5.3.2 and §5.4.4: registers a watched object and up to 29 other keys of one CLU in several clientRegister forms, measures where the pushes go, how long a registration lives, the largest registration a CLU answers, fetchValues, and (phase K) which value forms an action accepts | only phase K, which writes a dimmer you name and restores it |