{"id":39258637,"url":"https://github.com/dobermai/sauna","last_synced_at":"2026-01-20T16:58:05.287Z","repository":{"id":332204248,"uuid":"1132808111","full_name":"dobermai/sauna","owner":"dobermai","description":"Unofficial Rust CLI and API client for controlling Klafs saunas","archived":false,"fork":false,"pushed_at":"2026-01-12T21:14:21.000Z","size":364,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T01:30:21.040Z","etag":null,"topics":["cli","iot","klafs","rust","sauna","smart-home"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dobermai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-12T13:33:18.000Z","updated_at":"2026-01-12T21:26:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dobermai/sauna","commit_stats":null,"previous_names":["dobermai/sauna"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/dobermai/sauna","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dobermai%2Fsauna","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dobermai%2Fsauna/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dobermai%2Fsauna/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dobermai%2Fsauna/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dobermai","download_url":"https://codeload.github.com/dobermai/sauna/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dobermai%2Fsauna/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28556064,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T00:46:33.223Z","status":"ssl_error","status_checked_at":"2026-01-19T00:46:32.754Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["cli","iot","klafs","rust","sauna","smart-home"],"created_at":"2026-01-18T00:24:24.473Z","updated_at":"2026-01-19T01:01:14.745Z","avatar_url":"https://github.com/dobermai.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.png\" alt=\"Sauna CLI Logo\" width=\"200\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eKlafs Sauna Control\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  A Rust library and CLI for controlling Klafs saunas via their cloud API.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://crates.io/crates/klafs-api\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/klafs-api.svg\" alt=\"crates.io\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://crates.io/crates/klafs-api\"\u003e\u003cimg src=\"https://img.shields.io/crates/d/klafs-api.svg\" alt=\"downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://docs.rs/klafs-api\"\u003e\u003cimg src=\"https://docs.rs/klafs-api/badge.svg\" alt=\"docs.rs\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/dobermai/sauna/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/dobermai/sauna/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"#license\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg\" alt=\"License: MIT/Apache-2.0\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.rust-lang.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/rust-1.70%2B-orange.svg\" alt=\"Rust: 1.70+\"\u003e\u003c/a\u003e\n  \u003ca href=\"#\"\u003e\u003cimg src=\"https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey.svg\" alt=\"Platform\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003e⚠️ Unofficial project — not affiliated with KLAFS GmbH \u0026 Co. KG\u003c/strong\u003e\n\u003c/p\u003e\n\n## Overview\n\nThis project provides:\n\n- **klafs-api** - A Rust library for interacting with the Klafs sauna API\n- **sauna** - A command-line tool for controlling your sauna\n\n## Quick Start\n\n```bash\n# Login to your Klafs account (use your USERNAME, not email!)\nsauna login\n\n# Find your sauna ID and set it as default (auto-selects if only one sauna)\nsauna saunas\nsauna config --sauna-id \"your-sauna-uuid\" --pin \"1234\"\n\n# Check status\nsauna status\n\n# Start your sauna\nsauna power-on\n\n# Or schedule it for later\nsauna power-on --at 18:30\n\n# Adjust settings\nsauna set-temp 85\nsauna set-mode sanarium\n\n# Turn off\nsauna power-off\n```\n\n\u003e **Important**: Use your KLAFS **username**, not your email address, when logging in. This is the same username you use on the KLAFS web portal.\n\n## Installation\n\n### Homebrew (macOS)\n\n```bash\nbrew install dobermai/tap/sauna\n```\n\n### Cargo\n\n```bash\ncargo install sauna\n```\n\n### Download Binary\n\nPre-built binaries are available for Linux, macOS, and Windows on the [Releases](https://github.com/dobermai/sauna/releases) page.\n\n### From Source\n\n```bash\ngit clone https://github.com/dobermai/sauna.git\ncd sauna\ncargo install --path sauna\n```\n\n### Platform Support\n\nThis project has been developed and tested on **macOS**. It should work on **Linux** and **Windows** as well, but these platforms have not been tested yet. If you encounter any issues on these platforms, please [open an issue](https://github.com/dobermai/sauna/issues) or submit a pull request.\n\n## CLI Usage\n\n### Global Flags\n\n```bash\n# Enable verbose logging\nsauna --verbose \u003ccommand\u003e\n\n# Enable HTTP debug logging (writes to file)\nsauna --debug \u003ccommand\u003e\n\n# Save debug output to a file (used with --debug)\nsauna --debug-file debug.log \u003ccommand\u003e\n```\n\n### Login\n\nAuthenticate with your Klafs account. Credentials are stored securely in your system keyring.\n\n```bash\nsauna login\n# Username and password will be prompted securely\n\n# Provide credentials via flags\nsauna login --username your_username --password your_password\n```\n\n\u003e **Important**: Use your KLAFS **username**, not your email address. This is the same username you use on the KLAFS web portal.\n\n\u003e **Warning**: Klafs locks accounts after 3 failed login attempts!\n\n### Discover Saunas\n\nList all saunas registered to your account:\n\n```bash\n# Human-readable output\nsauna saunas\n\n# JSON output\nsauna saunas --json\n```\n\nExample output:\n\n```\nRegistered Saunas\n\n* My Home Sauna\n    ID: 364cc9db-86f1-49d1-86cd-f6ef9b20a490\n    (default)\n\n  Guest House Sauna\n    ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890\n\nUse 'sauna config --sauna-id \u003cID\u003e' to set a default.\n```\n\n### Configure Defaults\n\nSet your default sauna ID to avoid specifying it with every command:\n\n```bash\nsauna config --sauna-id \"your-sauna-uuid\"\n\n# Store PIN for power control (stored in system keyring)\nsauna config --pin \"1234\"\n\n# Auto-select is enabled by default and will pick the sauna automatically\n# when exactly one sauna is registered.\n# Disable auto-select behavior\nsauna config --auto-select false\n\n# View current configuration\nsauna config --show\n```\n\n### Get Sauna Status\n\n```bash\n# Human-readable output\nsauna status\n\n# JSON output\nsauna status --json\n\n# Specify a different sauna\nsauna status --sauna-id \"another-sauna-uuid\"\n```\n\nExample output:\n\n```\nSauna Status\n\n  Connection:     Connected\n  Status:         Off\n\n  Mode:           Sanarium\n  Current Temp:   N/A\n  Target Temp:    70°C\n\n  Scheduled:      Not scheduled\n```\n\nWhen the sauna is heating:\n\n```\nSauna Status\n\n  Connection:     Connected\n  Status:         Heating (45°C -\u003e 85°C)\n\n  Mode:           Sauna\n  Current Temp:   45°C\n  Target Temp:    85°C\n\n  Remaining Time: 1h 30m\n  Scheduled:      Not scheduled\n```\n\n### Power Control\n\n```bash\n# Power on immediately (requires PIN; uses stored PIN if not provided)\nsauna power-on\n\n# Schedule power on for a specific time\nsauna power-on --at 18:30\n\n# Provide PIN explicitly\nsauna power-on --pin 1234\n\n# Power off\nsauna power-off\n```\n\n### Temperature and Mode\n\n```bash\n# Set temperature (10-100°C for Sauna, 40-75°C for Sanarium)\nsauna set-temp 85\n\n# Set mode: sauna or sanarium\nsauna set-mode sauna\n```\n\n### Humidity Control\n\n```bash\n# Set humidity level (1-10, Sanarium mode only)\nsauna set-humidity 7\n```\n\n### Scheduling\n\n```bash\n# Set scheduled start time (without starting)\nsauna schedule 18:30\n\n# Clear the schedule\nsauna schedule --clear\n\n# You can also clear by omitting the time\nsauna schedule\n```\n\n### Profiles\n\nSave and reuse sauna configurations locally:\n\n```bash\n# Create a profile\nsauna profile create hot --mode sauna --temp 90\nsauna profile create relaxed --mode sanarium --temp 60 --humidity 7\n\n# List all profiles\nsauna profile list\n\n# Show profile details\nsauna profile show hot\n\n# Apply a profile (sets mode, temperature, humidity)\nsauna profile apply hot\n\n# Apply and start the sauna\nsauna profile apply hot --start\n\n# Delete a profile\nsauna profile delete hot\n```\n\nProfiles are stored locally in `~/.config/klafs/profiles.toml`.\n\n### Configure Multiple Settings\n\nSet multiple parameters in one command:\n\n```bash\n# Set temperature and humidity (current mode)\nsauna configure --temp 85 --humidity 5\n\n# Set temperature and schedule\nsauna configure --temp 85 --time 18:30\n\n# Set all at once\nsauna configure --temp 85 --humidity 5 --time 18:30\n```\n\n### Light Control\n\nControl the cabin lights:\n\n```bash\n# Main light\nsauna light on\nsauna light on --brightness 8\nsauna light off\n\n# Sunset light\nsauna sunset on\nsauna sunset on --brightness 10\nsauna sunset off\n```\n\n## Library Usage\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\nklafs-api = \"0.1\"\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\"] }\n```\n\nExample:\n\n```rust\nuse klafs_api::KlafsClient;\n\n#[tokio::main]\nasync fn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let client = KlafsClient::new()?;\n\n    // Login (use your KLAFS username, not email!)\n    client.login(\"your_username\", \"password\").await?;\n\n    // Get sauna status\n    let status = client.get_status(\"your-sauna-uuid\").await?;\n\n    println!(\"Connected: {}\", status.is_connected);\n    println!(\"Powered On: {}\", status.is_powered_on);\n    println!(\"Current Temperature: {}°C\", status.current_temperature);\n    println!(\"Target Temperature: {}°C\", status.target_temperature());\n\n    if let Some(mode) = status.current_mode() {\n        println!(\"Mode: {}\", mode);\n    }\n\n    Ok(())\n}\n```\n\n## API Reference\n\nBase URL: `https://sauna-app-19.klafs.com`\n\n### Endpoints\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/Account/Login` | POST | Authenticate (form-encoded) |\n| `/SaunaApp/ChangeSettings` | GET | List registered saunas (HTML) |\n| `/SaunaApp/GetData?id={id}` | GET | Get sauna status (JSON) |\n| `/SaunaApp/StartCabin` | POST | Power on sauna (supports scheduling) |\n| `/SaunaApp/StopCabin` | POST | Power off sauna |\n| `/SaunaApp/ChangeTemperature` | POST | Set target temperature |\n| `/SaunaApp/ChangeHumLevel` | POST | Set humidity level |\n| `/SaunaApp/SetMode` | POST | Set operating mode |\n| `/SaunaApp/SetSelectedTime` | POST | Set scheduled start time |\n| `/SaunaApp/LightChange` | POST | Control lights (main, color, sunset) |\n| `/SaunaApp/SetBathingTime` | POST | Set session duration (**broken - see below**) |\n\n### Sauna Modes\n\n| Mode | Value | Temperature Range |\n|------|-------|-------------------|\n| Sauna | 1 | 10-100°C |\n| Sanarium | 2 | 40-75°C |\n\n### Operation Status Codes (opStatus)\n\n| Code | Meaning |\n|------|---------|\n| 0 | Off |\n| 1 | Scheduled (waiting for start time) |\n| 2 | Heating |\n| 3 | Ready |\n\n## Project Structure\n\n```\nsauna/\n├── Cargo.toml              # Workspace manifest\n├── klafs-api/              # API client library\n│   ├── src/\n│   │   ├── lib.rs          # Public API\n│   │   ├── client.rs       # HTTP client\n│   │   ├── debug.rs        # HTTP traffic debugging\n│   │   ├── error.rs        # Error types\n│   │   └── models.rs       # Data models\n│   └── tests/\n│       ├── fixtures/       # Test fixtures (HTML, JSON)\n│       └── integration_tests.rs\n└── sauna/                  # CLI application\n    └── src/\n        ├── main.rs         # CLI commands\n        ├── config.rs       # Configuration \u0026 keyring\n        └── profiles.rs     # Profile storage\n```\n\n## Security Notes\n\n- Credentials are stored in your system's secure keyring (macOS Keychain, Windows Credential Manager, or Linux Secret Service)\n- The PIN for power control is also stored securely in the keyring\n- Session cookies are managed in-memory and not persisted to disk\n- **Klafs locks accounts after 3 failed login attempts** - be careful with automated scripts\n\n## Unsupported Features\n\nThe following Klafs features are **not currently supported**:\n\n- **Bathing duration (session length)** - The `SetBathingTime` API endpoint exists and accepts requests, but the sauna ignores the setting. This appears to be a server-side bug.\n- **Infrared mode** - Cannot be tested/verified without hardware access\n- **Color light** - Cannot be tested/verified without hardware access\n- **Light status** - API does not report accurate light state; control commands work but status is unreliable\n- **Klafs Favorites** - Server-side favorites have no list API; use local profiles instead\n\n## Roadmap\n\n- [x] Core library with login and status\n- [x] CLI with credential storage\n- [x] Sauna discovery (list registered saunas)\n- [x] Power on/off commands\n- [x] Temperature, mode, humidity control\n- [x] Scheduling (immediate and timed start)\n- [x] Profiles feature (save/apply configurations)\n- [x] Combined configure command\n- [x] HTTP traffic debugging\n- [x] Integration tests with mock server\n- [ ] UniFFI bindings for iOS/macOS Swift apps\n- [ ] TUI interface (ratatui-based)\n\n## Contributing\n\nContributions are welcome! If you'd like to help:\n\n- **Report bugs** or **request features** by [opening an issue](https://github.com/dobermai/sauna/issues)\n- **Submit pull requests** for bug fixes or new features\n- **Test on other platforms** (Linux, Windows) and report your findings\n\n## Acknowledgments\n\nInspired by other community projects:\n- [dss-vdc-klafs](https://github.com/axe-world/dss-vdc-klafs)\n- [IPSymconKlafsSaunaControl](https://github.com/Pommespanzer/IPSymconKlafsSaunaControl)\n\n## Disclaimer \u0026 Legal\n\n### Trademark Notice\n\n\"KLAFS\" is a registered trademark of KLAFS GmbH \u0026 Co. KG. This project is not affiliated with, endorsed by, sponsored by, or otherwise connected to KLAFS GmbH \u0026 Co. KG. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation or endorsement.\n\n### No Warranty\n\nTHIS SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n### Use at Your Own Risk\n\n- This software interacts with third-party services and hardware. The authors are not responsible for any damage to your sauna, property, or any other consequences resulting from the use of this software.\n- The API may change at any time without notice, which could break functionality.\n- Improper use of sauna equipment can be dangerous. Always follow the manufacturer's safety guidelines.\n- **Klafs locks accounts after 3 failed login attempts.** Be careful with automated scripts.\n\n### Intended Use\n\nThis software is intended for personal, non-commercial use by owners of Klafs saunas who wish to integrate their sauna with home automation systems or control it via command line. It is provided for educational and interoperability purposes.\n\n## License\n\nLicensed under either of:\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n- MIT License ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdobermai%2Fsauna","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdobermai%2Fsauna","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdobermai%2Fsauna/lists"}