{"id":15515836,"url":"https://github.com/markusressel/openhasp-config-manager","last_synced_at":"2026-02-12T02:16:54.086Z","repository":{"id":46416172,"uuid":"513288199","full_name":"markusressel/openhasp-config-manager","owner":"markusressel","description":"A tool to manage all of your openHASP device configs in a centralized place.","archived":false,"fork":false,"pushed_at":"2026-02-03T00:41:25.000Z","size":1208,"stargazers_count":16,"open_issues_count":3,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-02-03T13:48:43.989Z","etag":null,"topics":["cli","configuration-management","deployment","deployment-automation","docker","esp32","helper","jsonl","mqtt","openhasp","python","validation"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markusressel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","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},"funding":{"github":["markusressel"]}},"created_at":"2022-07-12T20:46:40.000Z","updated_at":"2026-02-03T00:41:29.000Z","dependencies_parsed_at":"2026-01-03T11:01:21.394Z","dependency_job_id":null,"html_url":"https://github.com/markusressel/openhasp-config-manager","commit_stats":{"total_commits":281,"total_committers":2,"mean_commits":140.5,"dds":"0.042704626334519546","last_synced_commit":"9bc6b7950728f8e4a27e10b8eb78c4e44a4c1cbd"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/markusressel/openhasp-config-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Fopenhasp-config-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Fopenhasp-config-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Fopenhasp-config-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Fopenhasp-config-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markusressel","download_url":"https://codeload.github.com/markusressel/openhasp-config-manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusressel%2Fopenhasp-config-manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29255419,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-09T03:05:00.817Z","status":"ssl_error","status_checked_at":"2026-02-09T03:04:53.275Z","response_time":56,"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","configuration-management","deployment","deployment-automation","docker","esp32","helper","jsonl","mqtt","openhasp","python","validation"],"created_at":"2024-10-02T10:04:32.586Z","updated_at":"2026-02-09T03:05:54.155Z","avatar_url":"https://github.com/markusressel.png","language":"Python","funding_links":["https://github.com/sponsors/markusressel"],"categories":[],"sub_categories":[],"readme":"# openhasp-config-manager\n\nThe missing management layer for your openHASP setup. A powerful suite of tools to simplify hardware UI design, combining\na logic-aware config engine with a robust API client and deployment automation.\n\n# Features\n\n🏗️ Advanced Configuration Engine\n\n* 🏠 Centralized Management: Manage an unlimited fleet of devices from one folder structure with shared configuration support.\n* 🛠️ Smart JSONL Preprocessing:\n  * **Multiline Support:** Write clean, readable blocks instead of giant single-line strings.\n  * **Jinja2 Templating:** Power your UI with logic, math, and cross-object variables (e.g., `{{ p1b1.y + 10 }}`).\n  * **Comments:** Use `//` to document your layout logic directly inside your `.jsonl` files.\n  * **YAML Variables:** Define global and local variables to reuse values across your entire setup.\n* 🎨 **Global Theme Engine:** Define styles (colors, fonts, radii) once and apply them to all objects instantly.\n\n🚢 Smart Deployment \u0026 Validation\n\n* 🛡️ **Early Error Detection:** Automatically catch syntax mistakes in .jsonl and .cmd files before they hit your hardware.\n* 🔄 **Delta Deployments:** Save time and flash wear—only upload what changed.\n* 🔍 **Visual Diffs:** Review exactly what will change with a git-style +/- line-by-line output.\n* 📺 **GUI Preview (WIP):** Inspect and prototype your screens in a digital previewer before deploying.\n\n🔌 API \u0026 Interaction\n\n* 📡 **Unified API Client:** Interact with your plates via a single Python interface over Web or MQTT.\n* ⚡ **Command Execution:** Send openHASP commands programmatically.\n* 🔔 **Real-time Events:** Subscribe to button presses, state updates, and touch events as they happen.\n* 🪄 **AppDaemon Integration Utilities:** Seamlessly integrate with AppDaemon for advanced automations and logic.\n\n# CLI\n\n```shell\n\u003e openhasp-config-manager -h\nUsage: openhasp-config-manager [OPTIONS] COMMAND [ARGS]...\n\nOptions:\n  --version   Show the version and exit.\n  -h, --help  Show this message and exit.\n\nCommands:\n  cmd         Sends a command request to a device.\n  deploy      Combines the generation and upload of a configuration.\n  generate    Generates the output files for all devices in the given...\n  help        Show this message and exit.\n  listen      Sends a state update request to a device.\n  logs        Prints the logs of a device.\n  screenshot  Requests a screenshot from the given device and stores it...\n  shell       Connects to the telnet server of a device.\n  state       Sends a state update request to a device.\n  upload      Uploads the previously generated configuration to their...\n  vars        Prints the variables accessible in a given path.\n```\n\n# 🛠️ Project Status\n\nI use `openhasp-config-manager` **exclusively** to manage my own openHASP devices. While it is my \"daily driver\", please keep in mind:\n\n* **In Development:** I’m actively adding tests and refining features to make it more robust.\n* **Rough Edges:** Error logging is still a bit basic. If something goes wrong, the logs might require some \"detective work\" to figure out the exact cause.\n* **Experimental:** It’s stable for my needs, but since every openHASP setup is unique, you might run into edge cases I haven't hit yet.\n\nIf you like the project and want to help polish those error logs or add features, I’m always happy to review an issue or a PR!\n\n# Setup\n\n## Docker\n\n```\ndocker run -it --rm \\\n  --name openhasp-config-manager \\\n  --user 1000:1000 \\\n  -v \"./openhasp-configs:/app/openhasp-configs\" \\\n  -v \"./output:/app/output\" \\\n  ghcr.io/markusressel/openhasp-config-manager\n```\n\n## Installation\n\nSince openhasp-config-manager needs some dependencies (see [here](/pyproject.toml)) it is\n**recommended to install it inside a virtualenv**.\n\n### venv-install\n\n[venv-install](https://github.com/markusressel/venv-install) is a little helper tool to ease the\ninstallation, management and usage of python cli tools in venvs.\n\n```bash\nvenv-install openhasp-config-manager openhasp-config-manager\nopenhasp-config-manager -h\n```\n\n### Manual\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eManual Installation \u0026 Uninstallation\u003c/b\u003e\u003c/summary\u003e\n\n```bash\nmkdir -p ~/venvs/openhasp-config-manager\npython3 -m venv ~/venvs/openhasp-config-manager\nsource ~/venvs/openhasp-config-manager/bin/activate\npip3 install openhasp-config-manager\n```\n\nAnd to use it:\n\n```shell\nsource ~/venvs/openhasp-config-manager/bin/activate\nopenhasp-config-manager -h\nopenhasp-config-manager analyze -c \"./openhasp-configs\"\n...\n```\n\n### Uninstall\n\n```bash\ndeactivate\nrm -rf ~/venvs/openhasp-config-manager\n```\n\n\u003c/details\u003e\n\n\n## Getting Started\n\nopenhasp-config-manager is first and foremost a configuration\nmanagement system. Simply follow the basic folder structure and\nconfig deployment will become trivial. **Please read all of this,\nas it is very important to understand the basic structure on\nwhich everything relies.**\n\n### 📁 Folder Structure\n\nThe following folders should reside inside a single parent\nfolder, f.ex. named `openhasp-configs`. This folder can be\nlocated anywhere you like, but must be accessible to\nopenhasp-config-manager when executing.\n\n* `common`: The `common` subdirectory can be used for files\n  that should be included on _all_ device. This folder is optional.\n* `devices`: The `devices` folder is required. It must contain one\n  subfolder for each openHASP device you want to configure using\n  openhasp-config-manager. It is recommended to name subfolders according\n  to the physical devices associated with them.\n  * `touch_down_1` (example device folder)\n    * A device folder contains `*.jsonl`, `*.cmd` and other files which should\n      only be uploaded to that particular device.\n    * You can create arbitrary nested folder structures for organizing the files.\n      There is a limit to the file name length though,\n      see [FAQ](#output-file-name-length-must-not-exceed-30-characters)\n    * You must provide a `config.json` file, see [config.json](#config.json)\n      for more info.\n\nA more advanced configuration layout could look something like this:\n\n```text\nopenhasp-configs\n├── common\n│   ├── content\n│   │   └── card.jsonl\n│   ├── dialog\n│   │   ├── connected.jsonl\n│   │   └── offline.jsonl\n│   ├── navigation_bar.jsonl\n│   └── page_header.jsonl\n└── devices\n    └── touch_down_1\n        ├── 0_home\n        │   ├── 0_header.jsonl\n        │   ├── 1_content.jsonl\n        │   └── page.cmd\n        ├── 5_about\n        │   ├── 0_header.jsonl\n        │   ├── 1_content.jsonl\n        │   └── page.cmd\n        ├── boot.cmd\n        ├── config.json\n        ├── offline.cmd\n        └── online.cmd\n```\n\n### ⚙️ Plate Setup (`config.json`)\n\nopenhasp-config-manager makes use of the `config.json` on your plate by extracting information\nlike the screen orientation. It even allows you to deploy changes within the `config.json` file.\n\n\u003e Note: Since [the official API does not support\nuploading the full file](https://github.com/HASwitchPlate/openHASP/issues/363), only settings\nwhich can also be set through the web ui on the plate itself are currently supported.\n \n**However**, the official `config.json` file doesn't provide enough info for openhasp-config-manager\nto enable all of its features. To fix that we need to add a custom section to the file.\n\n1. Download your config.json via the openHASP web browser, see [official docs](https://www.openhasp.com/latest/faq/?h=web#is-there-a-file-browser-built-in).\n2. Append the `openhasp_config_manager` block, adjusting the values as needed.\n\n```json\n{\n  \"openhasp_config_manager\": {\n    \"device\": {\n      \"ip\": \"192.168.5.134\",\n      \"screen\": {\n        \"width\": 320,\n        \"height\": 480\n      }\n    }\n  },\n  \"wifi\": {\n    \"ssid\": \"Turris IoT\",\n    ...\n  }\n  ... rest of config ...\n```\n\n### 🧠 Config File Preprocessing\n\nopenhasp-config-manager runs all configuration files through various preprocessors, which allow us to use\nfeatures the original file formats do not support by themselves, like f.ex. templating.\n\n#### 📝 Multiline JSONL files\n\nWhile the JSONL file format requires each object to be on a single line, openhasp-config-manager\nallows you to add as many line breaks as you wish. This makes it much easier to edit, since a config\nlike this:\n\n```json\n{\n  \"page\": 0,\n  \"id\": 31,\n  \"obj\": \"msgbox\",\n  \"text\": \"%ip%\",\n  \"auto_close\": 5000\n}\n```\n\nwill be deployed like this:\n\n```json lines\n{\"page\": 0, \"id\": 31, \"obj\": \"msgbox\", \"text\": \"%ip%\", \"auto_close\": 5000}\n```\n\n#### Comments\n\nNeither JSON nor JSONL allows comments, but openhasp-config-manager does!\nYou can mark comments by prefixing them with a double forward-slash:\n\n```json5\n// File description\n{\n  // Object Description\n  \"page\": 0,\n  \"id\": 31,\n  // Property Description\n  \"obj\": \"msgbox\",\n  \"text\": \"%ip%\",\n  \"auto_close\": 5000\n}\n```\n\n#### 🪄 Templating\n\nYou can use Jinja2 templates inside all jsonl object values. To access the value of another object in a\ntemplate, you can use the `pXbY` syntax established by openHASP, where `X` is the `page` of an object and\n`Y` is its `id`. openhasp-config-manager even tries to resolve templates that lead to other templates.\nBe careful not to create loops in this way though.\n\nYou can use the full functionality of Jinja2 like f.ex. math operations, function calls or type conversions.\n\n```yaml\n{\n  \"page\": 1,\n  \"id\": 1,\n  \"x\": 0,\n  \"y\": 0,\n  ...\n}\n\n  {\n    \"page\": 1,\n    \"id\": 2,\n    \"x\": \"{{ p1b1.x }}\",\n    \"y\": \"{{ p1b1.y + 10 }}\",\n    ...\n  }\n```\n\n#### 📦 Variables \u0026 Scoping\n\nBesides accessing other objects, you can also define custom variables yourself, which can then\nbe referenced inside of templates. Variables are defined using `*.yaml` files. If you\ndecided to use a subfolder structure to organize your configuration files you can use these folders\nto also set the scope of variables. More specific variable definitions (longer path) will override\nless specific ones.\n\n##### Global\n\nGlobal variables can be specified by creating `*.yaml` files inside the root config folder (f.ex. `openhasp-configs`).\n\nExample:\n\n`openhasp-configs/global.vars.yaml`\n\n```yaml\nabout:\n  page_title: \"About\"\n```\n\nTo access this variable, use a Jinja2 template:\n\n`openhasp-configs/common/about_page.jsonl`\n\n```json lines\n{\n  \"page\": 9,\n  \"id\": 1,\n  ...\n  \"title\": \"{{ about.page_title }}\",\n  ...\n}\n```\n\n##### Device specific\n\nDevice specific variables can be specified by creating `*.yaml` files inside any of the sub-folders\nof a `device` folder.\n\n\u003e **Note**\n\u003e\n\u003e Device specific variables will override global variables, given the same name.\n\nExample:\n\n`openhasp-configs/device/my_device/device.vars.yaml`\n\n```yaml\npage_title: \"My Device\"\n```\n\n`openhasp-configs/device/my_device/some_folder/some_page.jsonl`\n\n```json lines\n{\n  \"page\": 1,\n  \"id\": 1,\n  ...\n  \"title\": \"{{ page_title }}\",\n  ...\n}\n```\n\n`openhasp-configs/device/my_device/some_other_folder/some_page.jsonl`\n\n```json lines\n{\n  \"page\": 2,\n  \"id\": 1,\n  ...\n  \"title\": \"{{ page_title }}\",\n  ...\n}\n```\n\n#### Printing variables\n\nIf you are not sure what variables are accessible in a given path, you can use the `vars`\ncommand, which will give you a copy\u0026paste ready output of all variables for a\ngiven directory:\n\n```shell\n\u003e openhasp-config-manager vars -c openhasp-configs -p devices/touch_down_1/home\ncommon.navbar.first_page: 1\ncommon.navbar.last_page: 4\n...\nheader.title: Home\n```\n\n#### 🎨 Theming\n\nTo specify default property values for an object type, simply define them as a variable\nunder `theme.obj.\u003cobj-type\u003e`, where `\u003cobj-type\u003e` is the value of the `obj` property of the object.\n\nThe keys used must conform to the naming of the object properties as specified in OpenHasp, see:\nhttps://www.openhasp.com/latest/design/objects/\n\nFor example, to make the background color of all buttons red by default, define:\n\n`theme.yaml`\n```yaml\ntheme:\n  obj:\n    btn:\n      bg_color: \"#FF0000\"\n```\n\nin a global variable file named `theme.yaml` located at the root of your configurations directory\n`openhasp-configs/theme.yaml`.\n\n## Deployment\n\nTo deploy your configurations to the already connected openHASP devices, simply use the\n`generate`, `upload` or `deploy` commands of `openhasp-config-manager`.\n\n\u003e **Note**\n\u003e openhasp-config-manager needs direct IP access as well as an enabled webservice on the plate\n\u003e to be able to deploy files to the device. To enable the webservice\n\u003e try: `openhasp-config-manager cmd -d plate35 -C service -p \"start http\"`\n\n## Run commands\n\nWhile openhasp-config-manager is first and foremost a config management system,\nit also allows you to run commands on a device by issuing MQTT messages without the need to install a separate\nMQTT client first. Note that the MQTT _server_ still needs to be running and also has to\nbe reachable from your local machine for this to work.\n\nFor a list of possible commands to send to a device, take a look at the official\ndocumentation: https://openhasp.haswitchplate.com/latest/commands/\n\n```shell\n\u003e openhasp-config-manager cmd -c ./openhasp-configs -d plate35 -C backlight -p \"{\\\"state\\\":\\\"on\\\",\\\"brightness\\\":128}\"\n```\n\n## AppDaemon Integration Utilities\n\nIf you want to integrate your openHASP devices with [AppDaemon](https://github.com/AppDaemon/appdaemon), openhasp-config-manager contains\nsome utilities to make this process easier.\n\n### Plate Controller\n\nThe `OpenHaspController` class provides a high-level interface to manage the state of your plate, send commands and listen to events.\nSee: [openhasp_config_manager/ad/README.md](openhasp_config_manager/ad/README.md) for more details and examples.\n\n## API Client\n\nIf you don't want to use all of the file-tree related features of openhasp-config-manager,\nbut still want to interact with your openHASP devices using python and the official API,\nyou can use the `OpenHaspClient` class to do so. It provides a simple interface\nto interact with a plate, send commands, listen to events and state updates.\n\nSee\n\n- [example.py](example.py)\n- [example_image.py](example_image.py)\n- [example_jsonl.py](example_jsonl.py)\n\nto see how to use it.\n\n# FAQ\n\n## How do I see device logs?\n\nTry the `logs` command (this does require network access to the device):\n\n```shell\n\u003e openhasp-config-manager logs -d plate35\n```\n\nIf that doesn't work, open a terminal and run the following command with the device connected via USB cable:\n\n```shell\nbash -c \"screen -q -L -Logfile device.log /dev/ttyUSB0 115200 \u0026\u003e /dev/null; tail -F device.log; killall screen\"\n```\n\n## Output file name length must not exceed 30 characters\n\nopenHASP doesn't support subfolders. To keep your local project organized, the manager flattens your structure \nduring upload (e.g., `folder/page.jsonl` becomes `folder_page.jsonl`). So f.ex. the file in the following structure:\n\n```text\nopenhasp-configs\n└── devices\n    └── touch_down_1\n        └── 0_home\n            └── 0_header.jsonl\n```\n\nwould be uploaded to the `touch_down_1` device with the name `0_home_0_header.jsonl`.\n\nTo avoid the \"Output file name length must not exceed 30 characters\" error, make sure that the\nflattened file name (including the device folder prefix) does not exceed 30 characters.\n\n# Contributing\n\nGitHub is for social coding: if you want to write code, I encourage contributions\nthrough pull requests from forks of this repository. Create GitHub tickets for\nbugs and new features and comment on the ones that you are interested in.\n\n# License\n\n```text\nopenhasp-config-manager is free software: you can redistribute it and/or modify\nit under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusressel%2Fopenhasp-config-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkusressel%2Fopenhasp-config-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusressel%2Fopenhasp-config-manager/lists"}