bricklogger 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bricklogger-0.2.2 → bricklogger-0.2.3}/PKG-INFO +34 -20
- {bricklogger-0.2.2 → bricklogger-0.2.3}/README.md +33 -19
- {bricklogger-0.2.2 → bricklogger-0.2.3}/pyproject.toml +1 -1
- {bricklogger-0.2.2 → bricklogger-0.2.3}/pyproject.toml.orig +1 -1
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/__init__.py +1 -1
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/__init__.py +3 -1
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/init.py +30 -7
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/mcp_command.py +18 -17
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/plugins.py +2 -3
- bricklogger-0.2.3/src/bricklogger/cli/services.py +102 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/update.py +2 -2
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/loader.py +6 -7
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/architecture.md +5 -5
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/docker.md +14 -14
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/cli.md +71 -23
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/configuration.md +17 -17
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/mcp.md +7 -6
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/plugins.md +36 -33
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/web.md +3 -6
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/getting-started.md +73 -47
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/environment.py +279 -41
- bricklogger-0.2.3/src/bricklogger/ops/services.py +309 -0
- bricklogger-0.2.3/src/bricklogger/ops/units.py +135 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/updates.py +61 -47
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/units/bricklogger-mcp.service +1 -2
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/units/bricklogger-web.service +1 -2
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/units/bricklogger.service +1 -4
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/texts.py +2 -2
- bricklogger-0.2.2/src/bricklogger/ops/units.py +0 -152
- {bricklogger-0.2.2 → bricklogger-0.2.3}/LICENSE +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/__main__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/client.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/config.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/context.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/daemon_commands.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/guided.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/model.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/notify.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/output.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/query.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/roles.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/cli/serve.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/daemon.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/examples.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/instances.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/issues.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/schema.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/validation.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/config/values.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/api.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/codes.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/core.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/explorer.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/instances.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/jobs.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/logging.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/metadata.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/notify.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/overlay.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/plan.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/plugins.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/rules.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/run.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/sink.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/sparql.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/spool.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/state.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/daemon/updates.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/README.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/api.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/daemon.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/destinations.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/notifications.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/features/sources.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/docs/vision.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/mcp/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/mcp/http.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/mcp/instructions.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/mcp/server.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/Brick.ttl +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/LICENSE-Brick.txt +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/diff.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/inference.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/ontology.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/prefixes.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/shapes.ttl +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/upload.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/versions.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/model/working_graph.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/catalogue.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/client.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/config.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/context.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/docs.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/errors.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/plugin_volume.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/status.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/tools.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/ops/tree.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/bacnet_ip/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/bacnet_ip/config.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/bacnet_ip/declaration.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/bacnet_ip/references.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/bacnet_ip/source.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/bacnet_ip/tools.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/bacnet_ip/values.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/timescaledb/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/timescaledb/config.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/timescaledb/declaration.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/plugins/timescaledb/destination.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/py.typed +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/sdk/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/sdk/bacnet.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/sdk/contract.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/sdk/declaration.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/sdk/registry.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/sdk/testing.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/__init__.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/app.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/client.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/forms.py +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/css/app.css +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/css/explorer.css +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/fonts/ibm-plex-mono-400.woff2 +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/fonts/ibm-plex-mono-500.woff2 +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/fonts/ibm-plex-mono-600.woff2 +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/fonts/ibm-plex-sans-var.woff2 +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/js/explorer.js +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/LICENSES.md +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/codemirror-yaml.min.js +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/codemirror.min.css +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/codemirror.min.js +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/cytoscape.min.js +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/htmx.min.js +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/yasgui.min.css +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/static/vendor/yasgui.min.js +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/base.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/config.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/daemon.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/explorer.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/instances.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/login.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/model.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/notifications.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/overview.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/config_result.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/daemon.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/diff.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/health.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/instances.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/job.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/model_versions.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/notifications.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/notify_test.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/overview.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/plugins.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/points.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/statusline.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/tool_result.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/partials/unreachable.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/plugins.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/points.html +0 -0
- {bricklogger-0.2.2 → bricklogger-0.2.3}/src/bricklogger/web/templates/query.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bricklogger
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Data bridge for building automation: collects data based on a Brick model and writes it to time-series databases
|
|
5
5
|
Keywords: brick,bacnet,building-automation,timescaledb,data-logger
|
|
6
6
|
Author: Michael Rosenlund
|
|
@@ -74,16 +74,18 @@ page is the short version.
|
|
|
74
74
|
|
|
75
75
|
## Install
|
|
76
76
|
|
|
77
|
+
As the login that is to run the logger, not as root:
|
|
78
|
+
|
|
77
79
|
```bash
|
|
78
|
-
curl -
|
|
80
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # uv, if the machine has none
|
|
81
|
+
uv tool install bricklogger
|
|
79
82
|
```
|
|
80
83
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`--` when the script is piped: `… | sudo sh -s -- --version 0.2.2`.
|
|
84
|
+
uv brings a Python that fits, so the machine needs nothing else. Everything
|
|
85
|
+
stays in that login's home directory: the program in uv's tool directory, the
|
|
86
|
+
command in `~/.local/bin`, the configuration in `~/.config/bricklogger` and the
|
|
87
|
+
data in `~/.local/share/bricklogger`. `uv tool install bricklogger==0.2.3`
|
|
88
|
+
installs a given version.
|
|
87
89
|
|
|
88
90
|
**As a container** the same program is `ghcr.io/cx1-aps/bricklogger`, with a
|
|
89
91
|
compose file for the daemon, the web interface and the MCP server; see
|
|
@@ -104,9 +106,9 @@ Bricklogger creates and migrates its own tables at the first start.
|
|
|
104
106
|
## First setup
|
|
105
107
|
|
|
106
108
|
```bash
|
|
107
|
-
bricklogger init # guided: sources, destinations, secrets
|
|
109
|
+
bricklogger init # guided: sources, destinations, secrets, services
|
|
108
110
|
bricklogger validate # after any edit by hand
|
|
109
|
-
bricklogger
|
|
111
|
+
bricklogger services install --web # if init did not: the daemon and the web interface
|
|
110
112
|
bricklogger model upload building.ttl # validate, infer, activate
|
|
111
113
|
bricklogger status
|
|
112
114
|
bricklogger points --outcome active # the last value of every point
|
|
@@ -115,17 +117,17 @@ bricklogger points --outcome active # the last value of every point
|
|
|
115
117
|
`init` asks for the settings of each source and destination and writes four
|
|
116
118
|
files: `sources.yaml`, `destinations.yaml`, `rules.yaml` and `daemon.yaml`.
|
|
117
119
|
Secrets, such as the database password, go into an `env` file beside them and
|
|
118
|
-
are referred to as `${NAME}`.
|
|
120
|
+
are referred to as `${NAME}`. Last, `init` offers to run the daemon — and the
|
|
121
|
+
web interface and the MCP server, if you want them — as `systemd --user`
|
|
122
|
+
services that start at boot. The first rule set accepts every point in the
|
|
119
123
|
model every five minutes; [rules](https://cx1-aps.github.io/bricklogger/features/configuration/)
|
|
120
124
|
narrow that down by class, location, equipment or any SPARQL pattern.
|
|
121
125
|
|
|
122
126
|
## The web interface and an assistant
|
|
123
127
|
|
|
124
|
-
|
|
125
|
-
bricklogger serve
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
Everything the CLI does can be done there, and the model explorer shows the
|
|
128
|
+
The web interface is at `http://127.0.0.1:8421` once its service runs, or
|
|
129
|
+
after `bricklogger serve` in a terminal. Everything the CLI does can be done
|
|
130
|
+
there, and the model explorer shows the
|
|
129
131
|
building as a tree and a graph, with every point's outcome and value.
|
|
130
132
|
|
|
131
133
|
To let an AI assistant that speaks MCP set up sources, destinations and rules,
|
|
@@ -145,7 +147,7 @@ before it writes, and never takes a secret's value. See
|
|
|
145
147
|
bricklogger plugins # what is installed
|
|
146
148
|
bricklogger plugins add bricklogger-ibos # add a plugin from PyPI
|
|
147
149
|
bricklogger plugins remove ibos # remove one by its type
|
|
148
|
-
|
|
150
|
+
systemctl --user restart bricklogger # the daemon reads plugins at start
|
|
149
151
|
```
|
|
150
152
|
|
|
151
153
|
A plugin is a Python package that provides a source or a destination type. A
|
|
@@ -169,14 +171,26 @@ See [notifications](https://cx1-aps.github.io/bricklogger/features/notifications
|
|
|
169
171
|
|
|
170
172
|
```bash
|
|
171
173
|
bricklogger update status # what there is to upgrade
|
|
172
|
-
|
|
174
|
+
bricklogger update all # Bricklogger and the plugins together
|
|
173
175
|
```
|
|
174
176
|
|
|
175
177
|
`update` checks the configuration with the new version before it restarts
|
|
176
178
|
anything, and puts the previous versions back if it does not hold; the
|
|
177
179
|
configuration and the data stay where they are. `update core` upgrades
|
|
178
|
-
Bricklogger alone, `update <type>` one plugin.
|
|
179
|
-
|
|
180
|
+
Bricklogger alone, `update <type>` one plugin. Do not run
|
|
181
|
+
`uv tool install bricklogger` again over an installation with plugins: it
|
|
182
|
+
uninstalls every plugin not named with `--with`. A container pulls the new
|
|
183
|
+
image instead.
|
|
184
|
+
|
|
185
|
+
**Upgrading from 0.2 installed with the install script:** the install script
|
|
186
|
+
is gone, and so is installing as root. Remove the old installation with the
|
|
187
|
+
script it came from — `curl -fsSL
|
|
188
|
+
https://github.com/CX1-ApS/bricklogger/releases/download/v0.2.2/install.sh |
|
|
189
|
+
sudo sh -s -- --uninstall`, without `sudo` for one in a home directory — then
|
|
190
|
+
install as above, add the plugins again with `bricklogger plugins add`, copy
|
|
191
|
+
the configuration, its `env` file and the data over if they lay in
|
|
192
|
+
`/etc/bricklogger` and `/var/lib/bricklogger` — with `data_dir` in
|
|
193
|
+
`daemon.yaml` changed to the new place — and run `bricklogger services install`.
|
|
180
194
|
|
|
181
195
|
**Upgrading from 0.1 with an iBOS source:** iBOS is no longer built in. The
|
|
182
196
|
`ibos` instance shows as failed until the plugin is added with
|
|
@@ -29,16 +29,18 @@ page is the short version.
|
|
|
29
29
|
|
|
30
30
|
## Install
|
|
31
31
|
|
|
32
|
+
As the login that is to run the logger, not as root:
|
|
33
|
+
|
|
32
34
|
```bash
|
|
33
|
-
curl -
|
|
35
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # uv, if the machine has none
|
|
36
|
+
uv tool install bricklogger
|
|
34
37
|
```
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
`--` when the script is piped: `… | sudo sh -s -- --version 0.2.2`.
|
|
39
|
+
uv brings a Python that fits, so the machine needs nothing else. Everything
|
|
40
|
+
stays in that login's home directory: the program in uv's tool directory, the
|
|
41
|
+
command in `~/.local/bin`, the configuration in `~/.config/bricklogger` and the
|
|
42
|
+
data in `~/.local/share/bricklogger`. `uv tool install bricklogger==0.2.3`
|
|
43
|
+
installs a given version.
|
|
42
44
|
|
|
43
45
|
**As a container** the same program is `ghcr.io/cx1-aps/bricklogger`, with a
|
|
44
46
|
compose file for the daemon, the web interface and the MCP server; see
|
|
@@ -59,9 +61,9 @@ Bricklogger creates and migrates its own tables at the first start.
|
|
|
59
61
|
## First setup
|
|
60
62
|
|
|
61
63
|
```bash
|
|
62
|
-
bricklogger init # guided: sources, destinations, secrets
|
|
64
|
+
bricklogger init # guided: sources, destinations, secrets, services
|
|
63
65
|
bricklogger validate # after any edit by hand
|
|
64
|
-
bricklogger
|
|
66
|
+
bricklogger services install --web # if init did not: the daemon and the web interface
|
|
65
67
|
bricklogger model upload building.ttl # validate, infer, activate
|
|
66
68
|
bricklogger status
|
|
67
69
|
bricklogger points --outcome active # the last value of every point
|
|
@@ -70,17 +72,17 @@ bricklogger points --outcome active # the last value of every point
|
|
|
70
72
|
`init` asks for the settings of each source and destination and writes four
|
|
71
73
|
files: `sources.yaml`, `destinations.yaml`, `rules.yaml` and `daemon.yaml`.
|
|
72
74
|
Secrets, such as the database password, go into an `env` file beside them and
|
|
73
|
-
are referred to as `${NAME}`.
|
|
75
|
+
are referred to as `${NAME}`. Last, `init` offers to run the daemon — and the
|
|
76
|
+
web interface and the MCP server, if you want them — as `systemd --user`
|
|
77
|
+
services that start at boot. The first rule set accepts every point in the
|
|
74
78
|
model every five minutes; [rules](https://cx1-aps.github.io/bricklogger/features/configuration/)
|
|
75
79
|
narrow that down by class, location, equipment or any SPARQL pattern.
|
|
76
80
|
|
|
77
81
|
## The web interface and an assistant
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
bricklogger serve
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
Everything the CLI does can be done there, and the model explorer shows the
|
|
83
|
+
The web interface is at `http://127.0.0.1:8421` once its service runs, or
|
|
84
|
+
after `bricklogger serve` in a terminal. Everything the CLI does can be done
|
|
85
|
+
there, and the model explorer shows the
|
|
84
86
|
building as a tree and a graph, with every point's outcome and value.
|
|
85
87
|
|
|
86
88
|
To let an AI assistant that speaks MCP set up sources, destinations and rules,
|
|
@@ -100,7 +102,7 @@ before it writes, and never takes a secret's value. See
|
|
|
100
102
|
bricklogger plugins # what is installed
|
|
101
103
|
bricklogger plugins add bricklogger-ibos # add a plugin from PyPI
|
|
102
104
|
bricklogger plugins remove ibos # remove one by its type
|
|
103
|
-
|
|
105
|
+
systemctl --user restart bricklogger # the daemon reads plugins at start
|
|
104
106
|
```
|
|
105
107
|
|
|
106
108
|
A plugin is a Python package that provides a source or a destination type. A
|
|
@@ -124,14 +126,26 @@ See [notifications](https://cx1-aps.github.io/bricklogger/features/notifications
|
|
|
124
126
|
|
|
125
127
|
```bash
|
|
126
128
|
bricklogger update status # what there is to upgrade
|
|
127
|
-
|
|
129
|
+
bricklogger update all # Bricklogger and the plugins together
|
|
128
130
|
```
|
|
129
131
|
|
|
130
132
|
`update` checks the configuration with the new version before it restarts
|
|
131
133
|
anything, and puts the previous versions back if it does not hold; the
|
|
132
134
|
configuration and the data stay where they are. `update core` upgrades
|
|
133
|
-
Bricklogger alone, `update <type>` one plugin.
|
|
134
|
-
|
|
135
|
+
Bricklogger alone, `update <type>` one plugin. Do not run
|
|
136
|
+
`uv tool install bricklogger` again over an installation with plugins: it
|
|
137
|
+
uninstalls every plugin not named with `--with`. A container pulls the new
|
|
138
|
+
image instead.
|
|
139
|
+
|
|
140
|
+
**Upgrading from 0.2 installed with the install script:** the install script
|
|
141
|
+
is gone, and so is installing as root. Remove the old installation with the
|
|
142
|
+
script it came from — `curl -fsSL
|
|
143
|
+
https://github.com/CX1-ApS/bricklogger/releases/download/v0.2.2/install.sh |
|
|
144
|
+
sudo sh -s -- --uninstall`, without `sudo` for one in a home directory — then
|
|
145
|
+
install as above, add the plugins again with `bricklogger plugins add`, copy
|
|
146
|
+
the configuration, its `env` file and the data over if they lay in
|
|
147
|
+
`/etc/bricklogger` and `/var/lib/bricklogger` — with `data_dir` in
|
|
148
|
+
`daemon.yaml` changed to the new place — and run `bricklogger services install`.
|
|
135
149
|
|
|
136
150
|
**Upgrading from 0.1 with an iBOS source:** iBOS is no longer built in. The
|
|
137
151
|
`ibos` instance shows as failed until the plugin is added with
|
|
@@ -24,6 +24,7 @@ from bricklogger.cli.plugins import plugins_app
|
|
|
24
24
|
from bricklogger.cli.query import query_command
|
|
25
25
|
from bricklogger.cli.roles import destinations_app, sources_app
|
|
26
26
|
from bricklogger.cli.serve import serve_command
|
|
27
|
+
from bricklogger.cli.services import services_app
|
|
27
28
|
from bricklogger.cli.update import update_app
|
|
28
29
|
from bricklogger.config import resolve_config_dir
|
|
29
30
|
|
|
@@ -49,7 +50,7 @@ def _root(
|
|
|
49
50
|
typer.Option(
|
|
50
51
|
"--config-dir",
|
|
51
52
|
help="The config directory; default $BRICKLOGGER_CONFIG_DIR, "
|
|
52
|
-
"then
|
|
53
|
+
"then ~/.config/bricklogger.",
|
|
53
54
|
show_default=False,
|
|
54
55
|
),
|
|
55
56
|
] = None,
|
|
@@ -92,6 +93,7 @@ app.command("validate")(validate_command)
|
|
|
92
93
|
app.command("status")(status_command)
|
|
93
94
|
app.command("points")(points_command)
|
|
94
95
|
app.add_typer(daemon_app, name="daemon")
|
|
96
|
+
app.add_typer(services_app, name="services")
|
|
95
97
|
app.add_typer(sources_app, name="sources")
|
|
96
98
|
app.add_typer(destinations_app, name="destinations")
|
|
97
99
|
app.add_typer(rules_app, name="rules")
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
In a terminal it is a guided setup — which sources and destinations, a name
|
|
4
4
|
and the settings of each from the plugin's own schema, secrets straight into
|
|
5
|
-
the ``env`` file
|
|
6
|
-
|
|
7
|
-
exists, so it can never destroy
|
|
5
|
+
the ``env`` file, and last the offer to set up the services — and
|
|
6
|
+
``--non-interactive`` writes the four files with commented examples instead.
|
|
7
|
+
Either way it refuses to overwrite a file that exists, so it can never destroy
|
|
8
|
+
a configuration.
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
from __future__ import annotations
|
|
@@ -19,6 +20,7 @@ from bricklogger.cli.config import registry, report_validation
|
|
|
19
20
|
from bricklogger.cli.context import CliContext, cli_context
|
|
20
21
|
from bricklogger.cli.guided import ask_settings, write_env
|
|
21
22
|
from bricklogger.cli.output import fail
|
|
23
|
+
from bricklogger.cli.services import install as install_services
|
|
22
24
|
from bricklogger.config import (
|
|
23
25
|
CONFIG_FILES,
|
|
24
26
|
RESERVED_INSTANCE_NAMES,
|
|
@@ -31,6 +33,7 @@ from bricklogger.config import (
|
|
|
31
33
|
write_examples,
|
|
32
34
|
write_text,
|
|
33
35
|
)
|
|
36
|
+
from bricklogger.ops import services
|
|
34
37
|
from bricklogger.sdk.declaration import DestinationDeclaration, SourceDeclaration
|
|
35
38
|
|
|
36
39
|
NonInteractiveFlag = Annotated[
|
|
@@ -102,8 +105,7 @@ def _guided(context: CliContext) -> None:
|
|
|
102
105
|
write_text(config_dir, "destinations", destinations),
|
|
103
106
|
write_text(config_dir, "rules", examples["rules"]),
|
|
104
107
|
]
|
|
105
|
-
|
|
106
|
-
written.append(write_env(config_dir, secrets))
|
|
108
|
+
written.append(write_env(config_dir, secrets))
|
|
107
109
|
except OSError as exc:
|
|
108
110
|
raise fail(f"could not write to {config_dir}: {exc}") from exc
|
|
109
111
|
typer.echo("")
|
|
@@ -119,12 +121,33 @@ def _guided(context: CliContext) -> None:
|
|
|
119
121
|
where=str(config_dir),
|
|
120
122
|
)
|
|
121
123
|
typer.echo("")
|
|
122
|
-
|
|
123
|
-
typer.echo("
|
|
124
|
+
started = _offer_services(context)
|
|
125
|
+
typer.echo("")
|
|
126
|
+
if started:
|
|
127
|
+
typer.echo("Next: upload the model.")
|
|
128
|
+
else:
|
|
129
|
+
typer.echo("Next: start the daemon and upload the model.")
|
|
130
|
+
typer.echo(" bricklogger daemon start")
|
|
124
131
|
typer.echo(" bricklogger model upload <model.ttl>")
|
|
125
132
|
typer.echo(" bricklogger status")
|
|
126
133
|
|
|
127
134
|
|
|
135
|
+
def _offer_services(context: CliContext) -> bool:
|
|
136
|
+
"""Ask whether to set up the services, and do it on a yes; whether the
|
|
137
|
+
daemon now runs as one. Nothing is asked where they cannot be set up."""
|
|
138
|
+
if services.refusal(services.this_host(), context.config_dir) is not None:
|
|
139
|
+
return False
|
|
140
|
+
if not typer.confirm(
|
|
141
|
+
"Set up the services now? The daemon then starts at boot", default=True
|
|
142
|
+
):
|
|
143
|
+
typer.echo("The same later: bricklogger services install [--web] [--mcp]")
|
|
144
|
+
return False
|
|
145
|
+
web = typer.confirm(" Also the web interface?", default=True)
|
|
146
|
+
mcp = typer.confirm(" Also the MCP server over HTTP?", default=False)
|
|
147
|
+
install_services(context.config_dir, web=web, mcp=mcp)
|
|
148
|
+
return True
|
|
149
|
+
|
|
150
|
+
|
|
128
151
|
def _collect(
|
|
129
152
|
role: str,
|
|
130
153
|
file: str,
|
|
@@ -208,27 +208,28 @@ def _restart_line(before: dict[str, object], restart: bool) -> str:
|
|
|
208
208
|
)
|
|
209
209
|
if _restart_unit(command, str(before["url"]).removesuffix("/mcp")):
|
|
210
210
|
return f"restarted {UNIT}; the new token is in effect"
|
|
211
|
-
return
|
|
211
|
+
return (
|
|
212
|
+
f"{UNIT} was restarted but does not answer yet; check it with "
|
|
213
|
+
f"systemctl --user status {UNIT}"
|
|
214
|
+
)
|
|
212
215
|
|
|
213
216
|
|
|
214
217
|
def _systemctl() -> list[str] | None:
|
|
215
|
-
"""The systemctl
|
|
218
|
+
"""The login's systemctl when it has the MCP unit active; else ``None``."""
|
|
216
219
|
if shutil.which("systemctl") is None:
|
|
217
220
|
return None
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return command
|
|
231
|
-
return None
|
|
221
|
+
command = ["systemctl", "--user"]
|
|
222
|
+
try:
|
|
223
|
+
answer = subprocess.run(
|
|
224
|
+
[*command, "is-active", UNIT],
|
|
225
|
+
capture_output=True,
|
|
226
|
+
text=True,
|
|
227
|
+
timeout=5,
|
|
228
|
+
check=False,
|
|
229
|
+
)
|
|
230
|
+
except (OSError, subprocess.SubprocessError):
|
|
231
|
+
return None
|
|
232
|
+
return command if answer.stdout.strip() == "active" else None
|
|
232
233
|
|
|
233
234
|
|
|
234
235
|
def _restart_unit(command: list[str], url: str, timeout: float = 15.0) -> bool:
|
|
@@ -282,7 +283,7 @@ def _server_line(settings: DaemonSettings, token: str | None) -> str:
|
|
|
282
283
|
return f"server: running at {url} — accepts this token"
|
|
283
284
|
return (
|
|
284
285
|
f"server: running at {url} — rejects this token; restart it, "
|
|
285
|
-
f"e.g. systemctl restart {UNIT}"
|
|
286
|
+
f"e.g. systemctl --user restart {UNIT}"
|
|
286
287
|
)
|
|
287
288
|
|
|
288
289
|
|
|
@@ -155,9 +155,8 @@ def _restart_note() -> None:
|
|
|
155
155
|
if plugin_directory() is not None:
|
|
156
156
|
typer.echo(" docker compose restart daemon (in a container)")
|
|
157
157
|
else:
|
|
158
|
-
typer.echo(
|
|
159
|
-
|
|
160
|
-
)
|
|
158
|
+
typer.echo(" systemctl --user restart bricklogger (a service)")
|
|
159
|
+
typer.echo(" bricklogger daemon restart (started by hand)")
|
|
161
160
|
typer.echo(
|
|
162
161
|
"The MCP server over HTTP reads them the same way; the web interface "
|
|
163
162
|
"needs nothing."
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""``bricklogger services``: the daemon, the web interface and the MCP server as
|
|
2
|
+
``systemd --user`` units of the login. See ``docs/features/cli.md``,
|
|
3
|
+
"services"."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
|
|
13
|
+
from bricklogger.cli.context import cli_context
|
|
14
|
+
from bricklogger.cli.output import fail, print_json, stdout
|
|
15
|
+
from bricklogger.ops import services
|
|
16
|
+
from bricklogger.ops.errors import OperationError
|
|
17
|
+
|
|
18
|
+
services_app = typer.Typer(
|
|
19
|
+
no_args_is_help=True,
|
|
20
|
+
help="Run the daemon, the web interface and the MCP server as systemd --user "
|
|
21
|
+
"services of this login, started at boot.",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
WebFlag = Annotated[bool, typer.Option("--web", help="The web interface.")]
|
|
25
|
+
McpFlag = Annotated[bool, typer.Option("--mcp", help="The MCP server over HTTP.")]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@services_app.command("install")
|
|
29
|
+
def install_command(
|
|
30
|
+
ctx: typer.Context, web: WebFlag = False, mcp: McpFlag = False
|
|
31
|
+
) -> None:
|
|
32
|
+
"""Set up the daemon as a service, and the web interface and the MCP server
|
|
33
|
+
when their flag is given; enable lingering, and start what was written.
|
|
34
|
+
|
|
35
|
+
Can be run again: a flag adds its unit and leaves the others as they are.
|
|
36
|
+
"""
|
|
37
|
+
install(cli_context(ctx).config_dir, web=web, mcp=mcp)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def install(config_dir: Path, *, web: bool, mcp: bool) -> None:
|
|
41
|
+
"""``services install``, and what ``init`` runs when it is told yes."""
|
|
42
|
+
try:
|
|
43
|
+
result = services.install(config_dir=config_dir, web=web, mcp=mcp)
|
|
44
|
+
except OperationError as exc:
|
|
45
|
+
raise fail(exc.message) from exc
|
|
46
|
+
if result.written:
|
|
47
|
+
typer.echo(f"wrote {', '.join(result.written)} in {result.unit_dir}")
|
|
48
|
+
if result.started:
|
|
49
|
+
typer.echo(f"started {', '.join(result.started)}")
|
|
50
|
+
if result.restarted:
|
|
51
|
+
typer.echo(f"restarted {', '.join(result.restarted)} with the new unit")
|
|
52
|
+
if not (result.written or result.started or result.restarted):
|
|
53
|
+
typer.echo(f"{', '.join(result.units)} already set up and running")
|
|
54
|
+
if result.linger_command is not None:
|
|
55
|
+
typer.echo(
|
|
56
|
+
"lingering could not be enabled, so the services stop at logout and do "
|
|
57
|
+
"not start at boot; enable it once with:"
|
|
58
|
+
)
|
|
59
|
+
typer.echo(f" {result.linger_command}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@services_app.command("uninstall")
|
|
63
|
+
def uninstall_command(web: WebFlag = False, mcp: McpFlag = False) -> None:
|
|
64
|
+
"""Stop, disable and remove the services: all of them without a flag, the
|
|
65
|
+
ones named with one. The configuration and the data stay."""
|
|
66
|
+
try:
|
|
67
|
+
result = services.uninstall(web=web, mcp=mcp)
|
|
68
|
+
except OperationError as exc:
|
|
69
|
+
raise fail(exc.message) from exc
|
|
70
|
+
if result.removed:
|
|
71
|
+
typer.echo(f"removed {', '.join(result.removed)}")
|
|
72
|
+
else:
|
|
73
|
+
typer.echo("no service was set up")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@services_app.command("status")
|
|
77
|
+
def status_command(
|
|
78
|
+
json_output: Annotated[
|
|
79
|
+
bool, typer.Option("--json", help="Emit JSON instead of a table.")
|
|
80
|
+
] = False,
|
|
81
|
+
) -> None:
|
|
82
|
+
"""For each unit: written, enabled and active; and whether lingering is on."""
|
|
83
|
+
state = services.status()
|
|
84
|
+
if json_output:
|
|
85
|
+
print_json(state.as_dict())
|
|
86
|
+
return
|
|
87
|
+
table = Table(box=None)
|
|
88
|
+
for column in ("Unit", "Written", "Enabled", "Active"):
|
|
89
|
+
table.add_column(column)
|
|
90
|
+
for unit in state.units:
|
|
91
|
+
table.add_row(
|
|
92
|
+
unit.name, _word(unit.written), _word(unit.enabled), _word(unit.active)
|
|
93
|
+
)
|
|
94
|
+
stdout.print(table)
|
|
95
|
+
if not state.systemd:
|
|
96
|
+
typer.echo("systemctl --user does not answer on this machine")
|
|
97
|
+
else:
|
|
98
|
+
typer.echo(f"lingering: {_word(state.linger)}")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _word(value: bool | None) -> str:
|
|
102
|
+
return "?" if value is None else "yes" if value else "no"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""``bricklogger update``: what there is to upgrade, and the upgrade itself.
|
|
2
2
|
|
|
3
3
|
``update status`` installs nothing. ``update core``, ``update all`` and
|
|
4
|
-
``update TYPE`` upgrade from PyPI with
|
|
4
|
+
``update TYPE`` upgrade from PyPI with ``uv tool install``, validate with
|
|
5
5
|
the new version, put the previous versions back when that fails, write the
|
|
6
6
|
units again and restart what runs as a unit. ``update`` alone shows this help,
|
|
7
7
|
as every group does. See ``docs/features/cli.md``, "update".
|
|
@@ -168,7 +168,7 @@ def _report(result: Updated, target: str, no_restart: bool) -> None:
|
|
|
168
168
|
for unit in result.not_answering:
|
|
169
169
|
typer.echo(
|
|
170
170
|
f"{unit} was restarted but does not answer yet; check its log with "
|
|
171
|
-
f"journalctl -u {unit}"
|
|
171
|
+
f"journalctl --user -u {unit}"
|
|
172
172
|
)
|
|
173
173
|
for note in result.notes:
|
|
174
174
|
typer.echo(note)
|
|
@@ -30,7 +30,7 @@ CONFIG_FILES: tuple[str, ...] = ("daemon", "sources", "destinations", "rules")
|
|
|
30
30
|
"""The four files, by name without extension, in the order they are reported."""
|
|
31
31
|
|
|
32
32
|
SYSTEM_CONFIG_DIR = Path("/etc/bricklogger")
|
|
33
|
-
"""The config directory
|
|
33
|
+
"""The config directory in the container, which names it with the variable."""
|
|
34
34
|
|
|
35
35
|
SYSTEM_DATA_DIR = Path("/var/lib/bricklogger")
|
|
36
36
|
"""The data directory that belongs to it."""
|
|
@@ -58,22 +58,21 @@ def resolve_config_dir(
|
|
|
58
58
|
env: Mapping[str, str] | None = None,
|
|
59
59
|
home: Path | None = None,
|
|
60
60
|
) -> Path:
|
|
61
|
-
"""The flag, then the environment variable, then the
|
|
62
|
-
|
|
61
|
+
"""The flag, then the environment variable, then the one in the home
|
|
62
|
+
directory."""
|
|
63
63
|
if cli_value is not None:
|
|
64
64
|
return cli_value
|
|
65
65
|
environment = os.environ if env is None else env
|
|
66
66
|
from_env = environment.get(CONFIG_DIR_ENV)
|
|
67
67
|
if from_env:
|
|
68
68
|
return Path(from_env)
|
|
69
|
-
if SYSTEM_CONFIG_DIR.is_dir():
|
|
70
|
-
return SYSTEM_CONFIG_DIR
|
|
71
69
|
return user_config_dir(home)
|
|
72
70
|
|
|
73
71
|
|
|
74
72
|
def default_data_dir(config_dir: Path, home: Path | None = None) -> Path:
|
|
75
|
-
"""Where the data goes when ``daemon.yaml`` does not say: beside
|
|
76
|
-
configuration in ``/var/lib``, otherwise in the home
|
|
73
|
+
"""Where the data goes when ``daemon.yaml`` does not say: beside the
|
|
74
|
+
container's configuration in ``/var/lib``, otherwise in the home
|
|
75
|
+
directory."""
|
|
77
76
|
return SYSTEM_DATA_DIR if config_dir == SYSTEM_CONFIG_DIR else user_data_dir(home)
|
|
78
77
|
|
|
79
78
|
|
|
@@ -805,8 +805,8 @@ the runtime state, and **the spools** of the destinations.
|
|
|
805
805
|
|
|
806
806
|
## Platform
|
|
807
807
|
|
|
808
|
-
Bricklogger runs in production on **Linux**.
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
that.
|
|
808
|
+
Bricklogger runs in production on **Linux**. The filesystem defaults —
|
|
809
|
+
`~/.config/bricklogger` and `~/.local/share/bricklogger` for the login that
|
|
810
|
+
runs it, `/etc/bricklogger` and `/var/lib/bricklogger` in the container — the
|
|
811
|
+
installation with `uv tool install` and `systemd --user` services, and the
|
|
812
|
+
choice of OWL-RL reasoner follow from that.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Docker
|
|
2
2
|
|
|
3
|
-
Bricklogger also runs as a container. The image holds the same program
|
|
4
|
-
[install
|
|
5
|
-
same four configuration files
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
Bricklogger also runs as a container. The image holds the same program
|
|
4
|
+
[`uv tool install`](getting-started.md#install) installs — the same commands
|
|
5
|
+
and the same four configuration files — so a host where everything else is a
|
|
6
|
+
container needs nothing else installed. The installation with uv remains the
|
|
7
|
+
primary one; the image is the second way, and neither changes how
|
|
8
|
+
Bricklogger works.
|
|
9
9
|
|
|
10
10
|
## The image
|
|
11
11
|
|
|
@@ -14,16 +14,16 @@ published by GitHub Actions.
|
|
|
14
14
|
|
|
15
15
|
| Tag | What it is |
|
|
16
16
|
|-----|------------|
|
|
17
|
-
| `0.2.
|
|
17
|
+
| `0.2.3` | One released version — what a building's logger should name |
|
|
18
18
|
| `0.2` | The newest patch of that minor version |
|
|
19
19
|
| `latest` | The newest release |
|
|
20
20
|
|
|
21
21
|
Every version is built for `linux/amd64` and `linux/arm64`, and only after the
|
|
22
22
|
test suite has passed.
|
|
23
23
|
|
|
24
|
-
Inside, the
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
Inside, the Python environment is under `/opt/bricklogger`, the
|
|
25
|
+
`bricklogger` command on the path, the configuration in `/etc/bricklogger` —
|
|
26
|
+
named by `BRICKLOGGER_CONFIG_DIR` — and the data in `/var/lib/bricklogger`. All
|
|
27
27
|
of it belongs to an unprivileged user, and the container runs as that user and
|
|
28
28
|
never as root.
|
|
29
29
|
|
|
@@ -55,7 +55,7 @@ name: bricklogger
|
|
|
55
55
|
|
|
56
56
|
services:
|
|
57
57
|
daemon:
|
|
58
|
-
image: ghcr.io/cx1-aps/bricklogger:0.2.
|
|
58
|
+
image: ghcr.io/cx1-aps/bricklogger:0.2.3
|
|
59
59
|
network_mode: host
|
|
60
60
|
restart: unless-stopped
|
|
61
61
|
stop_grace_period: 30s
|
|
@@ -65,7 +65,7 @@ services:
|
|
|
65
65
|
- plugins:/var/lib/bricklogger/plugins
|
|
66
66
|
|
|
67
67
|
web:
|
|
68
|
-
image: ghcr.io/cx1-aps/bricklogger:0.2.
|
|
68
|
+
image: ghcr.io/cx1-aps/bricklogger:0.2.3
|
|
69
69
|
command: ["bricklogger", "serve"]
|
|
70
70
|
profiles: ["web"]
|
|
71
71
|
depends_on: ["daemon"]
|
|
@@ -77,7 +77,7 @@ services:
|
|
|
77
77
|
- plugins:/var/lib/bricklogger/plugins
|
|
78
78
|
|
|
79
79
|
mcp:
|
|
80
|
-
image: ghcr.io/cx1-aps/bricklogger:0.2.
|
|
80
|
+
image: ghcr.io/cx1-aps/bricklogger:0.2.3
|
|
81
81
|
command: ["bricklogger", "mcp", "serve", "--http"]
|
|
82
82
|
profiles: ["mcp"]
|
|
83
83
|
depends_on: ["daemon"]
|
|
@@ -357,7 +357,7 @@ docker run -d --name bricklogger \
|
|
|
357
357
|
-v bricklogger-config:/etc/bricklogger \
|
|
358
358
|
-v bricklogger-data:/var/lib/bricklogger \
|
|
359
359
|
-v bricklogger-plugins:/var/lib/bricklogger/plugins \
|
|
360
|
-
ghcr.io/cx1-aps/bricklogger:0.2.
|
|
360
|
+
ghcr.io/cx1-aps/bricklogger:0.2.3
|
|
361
361
|
```
|
|
362
362
|
|
|
363
363
|
The web interface and the MCP server are two more `docker run` lines with the
|