bricklogger 0.2.0__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.
Files changed (158) hide show
  1. bricklogger-0.2.0/LICENSE +21 -0
  2. bricklogger-0.2.0/PKG-INFO +208 -0
  3. bricklogger-0.2.0/README.md +163 -0
  4. bricklogger-0.2.0/pyproject.toml +126 -0
  5. bricklogger-0.2.0/pyproject.toml.orig +103 -0
  6. bricklogger-0.2.0/src/bricklogger/__init__.py +17 -0
  7. bricklogger-0.2.0/src/bricklogger/__main__.py +6 -0
  8. bricklogger-0.2.0/src/bricklogger/cli/__init__.py +107 -0
  9. bricklogger-0.2.0/src/bricklogger/cli/client.py +62 -0
  10. bricklogger-0.2.0/src/bricklogger/cli/config.py +199 -0
  11. bricklogger-0.2.0/src/bricklogger/cli/context.py +32 -0
  12. bricklogger-0.2.0/src/bricklogger/cli/daemon_commands.py +386 -0
  13. bricklogger-0.2.0/src/bricklogger/cli/guided.py +141 -0
  14. bricklogger-0.2.0/src/bricklogger/cli/init.py +184 -0
  15. bricklogger-0.2.0/src/bricklogger/cli/mcp_command.py +330 -0
  16. bricklogger-0.2.0/src/bricklogger/cli/model.py +422 -0
  17. bricklogger-0.2.0/src/bricklogger/cli/notify.py +93 -0
  18. bricklogger-0.2.0/src/bricklogger/cli/output.py +41 -0
  19. bricklogger-0.2.0/src/bricklogger/cli/plugins.py +410 -0
  20. bricklogger-0.2.0/src/bricklogger/cli/query.py +102 -0
  21. bricklogger-0.2.0/src/bricklogger/cli/roles.py +685 -0
  22. bricklogger-0.2.0/src/bricklogger/cli/serve.py +66 -0
  23. bricklogger-0.2.0/src/bricklogger/config/__init__.py +95 -0
  24. bricklogger-0.2.0/src/bricklogger/config/daemon.py +76 -0
  25. bricklogger-0.2.0/src/bricklogger/config/examples.py +110 -0
  26. bricklogger-0.2.0/src/bricklogger/config/instances.py +91 -0
  27. bricklogger-0.2.0/src/bricklogger/config/issues.py +72 -0
  28. bricklogger-0.2.0/src/bricklogger/config/loader.py +325 -0
  29. bricklogger-0.2.0/src/bricklogger/config/schema.py +425 -0
  30. bricklogger-0.2.0/src/bricklogger/config/validation.py +283 -0
  31. bricklogger-0.2.0/src/bricklogger/config/values.py +125 -0
  32. bricklogger-0.2.0/src/bricklogger/daemon/__init__.py +1 -0
  33. bricklogger-0.2.0/src/bricklogger/daemon/api.py +505 -0
  34. bricklogger-0.2.0/src/bricklogger/daemon/codes.py +53 -0
  35. bricklogger-0.2.0/src/bricklogger/daemon/core.py +1199 -0
  36. bricklogger-0.2.0/src/bricklogger/daemon/explorer.py +818 -0
  37. bricklogger-0.2.0/src/bricklogger/daemon/instances.py +432 -0
  38. bricklogger-0.2.0/src/bricklogger/daemon/jobs.py +133 -0
  39. bricklogger-0.2.0/src/bricklogger/daemon/logging.py +93 -0
  40. bricklogger-0.2.0/src/bricklogger/daemon/metadata.py +79 -0
  41. bricklogger-0.2.0/src/bricklogger/daemon/notify.py +790 -0
  42. bricklogger-0.2.0/src/bricklogger/daemon/overlay.py +171 -0
  43. bricklogger-0.2.0/src/bricklogger/daemon/plan.py +184 -0
  44. bricklogger-0.2.0/src/bricklogger/daemon/plugins.py +212 -0
  45. bricklogger-0.2.0/src/bricklogger/daemon/rules.py +306 -0
  46. bricklogger-0.2.0/src/bricklogger/daemon/run.py +62 -0
  47. bricklogger-0.2.0/src/bricklogger/daemon/sink.py +115 -0
  48. bricklogger-0.2.0/src/bricklogger/daemon/sparql.py +92 -0
  49. bricklogger-0.2.0/src/bricklogger/daemon/spool.py +164 -0
  50. bricklogger-0.2.0/src/bricklogger/daemon/state.py +650 -0
  51. bricklogger-0.2.0/src/bricklogger/docs/README.md +24 -0
  52. bricklogger-0.2.0/src/bricklogger/docs/architecture.md +808 -0
  53. bricklogger-0.2.0/src/bricklogger/docs/docker.md +376 -0
  54. bricklogger-0.2.0/src/bricklogger/docs/features/api.md +316 -0
  55. bricklogger-0.2.0/src/bricklogger/docs/features/cli.md +409 -0
  56. bricklogger-0.2.0/src/bricklogger/docs/features/configuration.md +285 -0
  57. bricklogger-0.2.0/src/bricklogger/docs/features/daemon.md +287 -0
  58. bricklogger-0.2.0/src/bricklogger/docs/features/destinations.md +101 -0
  59. bricklogger-0.2.0/src/bricklogger/docs/features/mcp.md +233 -0
  60. bricklogger-0.2.0/src/bricklogger/docs/features/notifications.md +191 -0
  61. bricklogger-0.2.0/src/bricklogger/docs/features/plugins.md +594 -0
  62. bricklogger-0.2.0/src/bricklogger/docs/features/sources.md +404 -0
  63. bricklogger-0.2.0/src/bricklogger/docs/features/web.md +248 -0
  64. bricklogger-0.2.0/src/bricklogger/docs/getting-started.md +254 -0
  65. bricklogger-0.2.0/src/bricklogger/docs/vision.md +82 -0
  66. bricklogger-0.2.0/src/bricklogger/mcp/__init__.py +7 -0
  67. bricklogger-0.2.0/src/bricklogger/mcp/http.py +95 -0
  68. bricklogger-0.2.0/src/bricklogger/mcp/instructions.py +47 -0
  69. bricklogger-0.2.0/src/bricklogger/mcp/server.py +609 -0
  70. bricklogger-0.2.0/src/bricklogger/model/Brick.ttl +57114 -0
  71. bricklogger-0.2.0/src/bricklogger/model/LICENSE-Brick.txt +32 -0
  72. bricklogger-0.2.0/src/bricklogger/model/__init__.py +109 -0
  73. bricklogger-0.2.0/src/bricklogger/model/diff.py +77 -0
  74. bricklogger-0.2.0/src/bricklogger/model/inference.py +257 -0
  75. bricklogger-0.2.0/src/bricklogger/model/ontology.py +22 -0
  76. bricklogger-0.2.0/src/bricklogger/model/prefixes.py +91 -0
  77. bricklogger-0.2.0/src/bricklogger/model/shapes.ttl +31 -0
  78. bricklogger-0.2.0/src/bricklogger/model/upload.py +121 -0
  79. bricklogger-0.2.0/src/bricklogger/model/versions.py +145 -0
  80. bricklogger-0.2.0/src/bricklogger/model/working_graph.py +93 -0
  81. bricklogger-0.2.0/src/bricklogger/ops/__init__.py +28 -0
  82. bricklogger-0.2.0/src/bricklogger/ops/catalogue.py +135 -0
  83. bricklogger-0.2.0/src/bricklogger/ops/client.py +216 -0
  84. bricklogger-0.2.0/src/bricklogger/ops/config.py +239 -0
  85. bricklogger-0.2.0/src/bricklogger/ops/context.py +61 -0
  86. bricklogger-0.2.0/src/bricklogger/ops/docs.py +57 -0
  87. bricklogger-0.2.0/src/bricklogger/ops/environment.py +588 -0
  88. bricklogger-0.2.0/src/bricklogger/ops/errors.py +53 -0
  89. bricklogger-0.2.0/src/bricklogger/ops/plugin_volume.py +257 -0
  90. bricklogger-0.2.0/src/bricklogger/ops/status.py +104 -0
  91. bricklogger-0.2.0/src/bricklogger/ops/tools.py +46 -0
  92. bricklogger-0.2.0/src/bricklogger/ops/tree.py +84 -0
  93. bricklogger-0.2.0/src/bricklogger/plugins/__init__.py +1 -0
  94. bricklogger-0.2.0/src/bricklogger/plugins/bacnet_ip/__init__.py +1 -0
  95. bricklogger-0.2.0/src/bricklogger/plugins/bacnet_ip/config.py +215 -0
  96. bricklogger-0.2.0/src/bricklogger/plugins/bacnet_ip/declaration.py +80 -0
  97. bricklogger-0.2.0/src/bricklogger/plugins/bacnet_ip/references.py +313 -0
  98. bricklogger-0.2.0/src/bricklogger/plugins/bacnet_ip/source.py +705 -0
  99. bricklogger-0.2.0/src/bricklogger/plugins/bacnet_ip/tools.py +594 -0
  100. bricklogger-0.2.0/src/bricklogger/plugins/bacnet_ip/values.py +126 -0
  101. bricklogger-0.2.0/src/bricklogger/plugins/timescaledb/__init__.py +1 -0
  102. bricklogger-0.2.0/src/bricklogger/plugins/timescaledb/config.py +26 -0
  103. bricklogger-0.2.0/src/bricklogger/plugins/timescaledb/declaration.py +17 -0
  104. bricklogger-0.2.0/src/bricklogger/plugins/timescaledb/destination.py +316 -0
  105. bricklogger-0.2.0/src/bricklogger/py.typed +0 -0
  106. bricklogger-0.2.0/src/bricklogger/sdk/__init__.py +73 -0
  107. bricklogger-0.2.0/src/bricklogger/sdk/bacnet.py +112 -0
  108. bricklogger-0.2.0/src/bricklogger/sdk/contract.py +299 -0
  109. bricklogger-0.2.0/src/bricklogger/sdk/declaration.py +169 -0
  110. bricklogger-0.2.0/src/bricklogger/sdk/registry.py +198 -0
  111. bricklogger-0.2.0/src/bricklogger/sdk/testing.py +269 -0
  112. bricklogger-0.2.0/src/bricklogger/web/__init__.py +1 -0
  113. bricklogger-0.2.0/src/bricklogger/web/app.py +967 -0
  114. bricklogger-0.2.0/src/bricklogger/web/client.py +131 -0
  115. bricklogger-0.2.0/src/bricklogger/web/forms.py +158 -0
  116. bricklogger-0.2.0/src/bricklogger/web/static/css/app.css +155 -0
  117. bricklogger-0.2.0/src/bricklogger/web/static/css/explorer.css +149 -0
  118. bricklogger-0.2.0/src/bricklogger/web/static/fonts/ibm-plex-mono-400.woff2 +0 -0
  119. bricklogger-0.2.0/src/bricklogger/web/static/fonts/ibm-plex-mono-500.woff2 +0 -0
  120. bricklogger-0.2.0/src/bricklogger/web/static/fonts/ibm-plex-mono-600.woff2 +0 -0
  121. bricklogger-0.2.0/src/bricklogger/web/static/fonts/ibm-plex-sans-var.woff2 +0 -0
  122. bricklogger-0.2.0/src/bricklogger/web/static/js/explorer.js +1185 -0
  123. bricklogger-0.2.0/src/bricklogger/web/static/vendor/LICENSES.md +12 -0
  124. bricklogger-0.2.0/src/bricklogger/web/static/vendor/codemirror-yaml.min.js +8 -0
  125. bricklogger-0.2.0/src/bricklogger/web/static/vendor/codemirror.min.css +8 -0
  126. bricklogger-0.2.0/src/bricklogger/web/static/vendor/codemirror.min.js +8 -0
  127. bricklogger-0.2.0/src/bricklogger/web/static/vendor/cytoscape.min.js +31 -0
  128. bricklogger-0.2.0/src/bricklogger/web/static/vendor/htmx.min.js +1 -0
  129. bricklogger-0.2.0/src/bricklogger/web/static/vendor/yasgui.min.css +1 -0
  130. bricklogger-0.2.0/src/bricklogger/web/static/vendor/yasgui.min.js +3 -0
  131. bricklogger-0.2.0/src/bricklogger/web/templates/base.html +62 -0
  132. bricklogger-0.2.0/src/bricklogger/web/templates/config.html +77 -0
  133. bricklogger-0.2.0/src/bricklogger/web/templates/daemon.html +6 -0
  134. bricklogger-0.2.0/src/bricklogger/web/templates/explorer.html +124 -0
  135. bricklogger-0.2.0/src/bricklogger/web/templates/instances.html +44 -0
  136. bricklogger-0.2.0/src/bricklogger/web/templates/login.html +24 -0
  137. bricklogger-0.2.0/src/bricklogger/web/templates/model.html +30 -0
  138. bricklogger-0.2.0/src/bricklogger/web/templates/notifications.html +7 -0
  139. bricklogger-0.2.0/src/bricklogger/web/templates/overview.html +7 -0
  140. bricklogger-0.2.0/src/bricklogger/web/templates/partials/config_result.html +13 -0
  141. bricklogger-0.2.0/src/bricklogger/web/templates/partials/daemon.html +20 -0
  142. bricklogger-0.2.0/src/bricklogger/web/templates/partials/diff.html +14 -0
  143. bricklogger-0.2.0/src/bricklogger/web/templates/partials/health.html +1 -0
  144. bricklogger-0.2.0/src/bricklogger/web/templates/partials/instances.html +69 -0
  145. bricklogger-0.2.0/src/bricklogger/web/templates/partials/job.html +31 -0
  146. bricklogger-0.2.0/src/bricklogger/web/templates/partials/model_versions.html +37 -0
  147. bricklogger-0.2.0/src/bricklogger/web/templates/partials/notifications.html +20 -0
  148. bricklogger-0.2.0/src/bricklogger/web/templates/partials/notify_test.html +9 -0
  149. bricklogger-0.2.0/src/bricklogger/web/templates/partials/overview.html +47 -0
  150. bricklogger-0.2.0/src/bricklogger/web/templates/partials/plugins.html +53 -0
  151. bricklogger-0.2.0/src/bricklogger/web/templates/partials/points.html +36 -0
  152. bricklogger-0.2.0/src/bricklogger/web/templates/partials/statusline.html +13 -0
  153. bricklogger-0.2.0/src/bricklogger/web/templates/partials/tool_result.html +26 -0
  154. bricklogger-0.2.0/src/bricklogger/web/templates/partials/unreachable.html +4 -0
  155. bricklogger-0.2.0/src/bricklogger/web/templates/plugins.html +6 -0
  156. bricklogger-0.2.0/src/bricklogger/web/templates/points.html +37 -0
  157. bricklogger-0.2.0/src/bricklogger/web/templates/query.html +24 -0
  158. bricklogger-0.2.0/src/bricklogger/web/texts.py +363 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CX1 ApS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: bricklogger
3
+ Version: 0.2.0
4
+ Summary: Data bridge for building automation: collects data based on a Brick model and writes it to time-series databases
5
+ Keywords: brick,bacnet,building-automation,timescaledb,data-logger
6
+ Author: Michael Rosenlund
7
+ Author-email: Michael Rosenlund <michael.rosenlund@cx1.dk>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 2 - Pre-Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Environment :: Web Environment
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Home Automation
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Requires-Dist: pydantic>=2.7
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: typer>=0.12
25
+ Requires-Dist: httpx>=0.27
26
+ Requires-Dist: fastapi>=0.110
27
+ Requires-Dist: uvicorn>=0.29
28
+ Requires-Dist: jinja2>=3.1
29
+ Requires-Dist: python-multipart>=0.0.9
30
+ Requires-Dist: itsdangerous>=2.1
31
+ Requires-Dist: rdflib>=7.0
32
+ Requires-Dist: pyshacl>=0.30
33
+ Requires-Dist: reasonable>=0.4
34
+ Requires-Dist: pyoxigraph>=0.4
35
+ Requires-Dist: bacpypes3>=0.0.90
36
+ Requires-Dist: psycopg[binary]>=3.1
37
+ Requires-Dist: mcp>=2.2.0
38
+ Requires-Dist: packaging>=24
39
+ Requires-Python: >=3.11
40
+ Project-URL: Homepage, https://github.com/CX1-ApS/bricklogger
41
+ Project-URL: Documentation, https://cx1-aps.github.io/bricklogger/
42
+ Project-URL: Source, https://github.com/CX1-ApS/bricklogger
43
+ Project-URL: Issues, https://github.com/CX1-ApS/bricklogger/issues
44
+ Description-Content-Type: text/markdown
45
+
46
+ # Bricklogger
47
+
48
+ Bricklogger is a data bridge for building automation. It reads a
49
+ [Brick](https://brickschema.org/) model of a building, collects the values of
50
+ the points the model describes from the building's automation systems, and
51
+ writes them to a time-series database. The model decides what is collected:
52
+ upload a new model, and the logger follows it.
53
+
54
+ - **Sources:** BACnet/IP on the local network is built in; other systems are
55
+ added as plugins, such as the [iBOS source](https://github.com/CX1-ApS/bricklogger-ibos)
56
+ for the iBOS Data API in the cloud.
57
+ - **Destination:** TimescaleDB, with every observation timestamped by its
58
+ source and a spool that holds them while the database is away.
59
+ - **Interfaces:** a command-line interface first, a web interface with the same
60
+ abilities beside it — including a model explorer — an HTTP API, and an MCP
61
+ server so an AI assistant can configure the logger for you.
62
+ - **Read only:** Bricklogger never writes to a building automation system.
63
+
64
+ The full documentation is at **<https://cx1-aps.github.io/bricklogger/>**. This
65
+ page is the short version.
66
+
67
+ ## What you need
68
+
69
+ - A Linux machine, amd64 or arm64, that can reach the building's network —
70
+ for BACnet/IP, on the same subnet as the devices or with a route to them.
71
+ - A Brick model of the building as Turtle (`.ttl`), with the points' external
72
+ references (BACnet device and object, for instance).
73
+ - A TimescaleDB database Bricklogger may create tables in.
74
+
75
+ ## Install
76
+
77
+ ```bash
78
+ curl -fsSL https://github.com/CX1-ApS/bricklogger/releases/latest/download/install.sh | sudo sh
79
+ ```
80
+
81
+ The script brings its own Python, so the machine needs only `curl`. With
82
+ `sudo` it installs a service: the program under `/opt/bricklogger`, the
83
+ configuration in `/etc/bricklogger`, the data in `/var/lib/bricklogger` and
84
+ three systemd units, left stopped. Without `sudo` everything stays in your home
85
+ directory. `--version 0.2.0` installs a given version; options come after
86
+ `--` when the script is piped: `… | sudo sh -s -- --version 0.2.0`.
87
+
88
+ **As a container** the same program is `ghcr.io/cx1-aps/bricklogger`, with a
89
+ compose file for the daemon, the web interface and the MCP server; see
90
+ [Docker](https://cx1-aps.github.io/bricklogger/docker/).
91
+
92
+ ## Prepare the database
93
+
94
+ ```sql
95
+ CREATE DATABASE brick;
96
+ \c brick
97
+ CREATE EXTENSION IF NOT EXISTS timescaledb;
98
+ CREATE ROLE bricklogger LOGIN PASSWORD '...';
99
+ GRANT ALL ON SCHEMA public TO bricklogger;
100
+ ```
101
+
102
+ Bricklogger creates and migrates its own tables at the first start.
103
+
104
+ ## First setup
105
+
106
+ ```bash
107
+ bricklogger init # guided: sources, destinations, secrets
108
+ bricklogger validate # after any edit by hand
109
+ bricklogger daemon start # or: sudo systemctl enable --now bricklogger
110
+ bricklogger model upload building.ttl # validate, infer, activate
111
+ bricklogger status
112
+ bricklogger points --outcome active # the last value of every point
113
+ ```
114
+
115
+ `init` asks for the settings of each source and destination and writes four
116
+ files: `sources.yaml`, `destinations.yaml`, `rules.yaml` and `daemon.yaml`.
117
+ Secrets, such as the database password, go into an `env` file beside them and
118
+ are referred to as `${NAME}`. The first rule set accepts every point in the
119
+ model every five minutes; [rules](https://cx1-aps.github.io/bricklogger/features/configuration/)
120
+ narrow that down by class, location, equipment or any SPARQL pattern.
121
+
122
+ ## The web interface and an assistant
123
+
124
+ ```bash
125
+ bricklogger serve # http://127.0.0.1:8421
126
+ ```
127
+
128
+ Everything the CLI does can be done there, and the model explorer shows the
129
+ building as a tree and a graph, with every point's outcome and value.
130
+
131
+ To let an AI assistant that speaks MCP set up sources, destinations and rules,
132
+ register the MCP server with it — for Claude Code on the same machine:
133
+
134
+ ```bash
135
+ claude mcp add --transport stdio bricklogger -- bricklogger mcp serve
136
+ ```
137
+
138
+ The assistant reads the plugins' schemas and this documentation, validates
139
+ before it writes, and never takes a secret's value. See
140
+ [MCP](https://cx1-aps.github.io/bricklogger/features/mcp/) for remote use.
141
+
142
+ ## Plugins
143
+
144
+ ```bash
145
+ bricklogger plugins # what is installed
146
+ bricklogger plugins add bricklogger-ibos # add a plugin from PyPI
147
+ bricklogger plugins remove ibos # remove one by its type
148
+ sudo systemctl restart bricklogger # the daemon reads plugins at start
149
+ ```
150
+
151
+ A plugin is a Python package that provides a source or a destination type. A
152
+ plugin that cannot load stops nothing: its instances show as failed and the
153
+ rest keep running. Writing one is described under
154
+ [plugins](https://cx1-aps.github.io/bricklogger/features/plugins/).
155
+
156
+ ## Mail notifications
157
+
158
+ Bricklogger can mail an administrator when something goes wrong, when it is
159
+ put right, and once a day as proof that it is alive. Put the mail server and
160
+ recipients under `notifications` in `daemon.yaml`, then:
161
+
162
+ ```bash
163
+ bricklogger notify test
164
+ ```
165
+
166
+ See [notifications](https://cx1-aps.github.io/bricklogger/features/notifications/).
167
+
168
+ ## Upgrade
169
+
170
+ Run the install script again; it leaves the plugins, the configuration and the
171
+ data where they are. Then restart the daemon. A container pulls the new image
172
+ instead:
173
+
174
+ ```bash
175
+ curl -fsSL https://github.com/CX1-ApS/bricklogger/releases/latest/download/install.sh | sudo sh
176
+ sudo systemctl restart bricklogger
177
+ ```
178
+
179
+ After an upgrade to a new minor version, `bricklogger plugins` shows whether
180
+ every plugin still loads.
181
+
182
+ **Upgrading from 0.1 with an iBOS source:** iBOS is no longer built in. The
183
+ `ibos` instance shows as failed until the plugin is added with
184
+ `bricklogger plugins add bricklogger-ibos` and the daemon is restarted; the
185
+ configuration and the collected history stay as they were.
186
+
187
+ ## If nothing arrives
188
+
189
+ - `bricklogger status warnings` lists what stands in the way, one line per
190
+ cause — points no source claims, points without a reference, read errors.
191
+ - `bricklogger sources bacnet_main discover` shows the BACnet devices that
192
+ answer. If none does, the address in `sources.yaml` or the network is the
193
+ problem, not the model.
194
+ - `bricklogger sources bacnet_main resolve <point>` shows how one point's
195
+ reference resolves, and reads it.
196
+ - `bricklogger destinations status` shows whether the database takes writes.
197
+ While it does not, observations wait in the spool.
198
+
199
+ ## Reporting a problem
200
+
201
+ Bugs and questions go in the
202
+ [issues](https://github.com/CX1-ApS/bricklogger/issues). A security
203
+ vulnerability is reported privately, as [SECURITY.md](https://github.com/CX1-ApS/bricklogger/blob/main/SECURITY.md) describes.
204
+
205
+ ## License
206
+
207
+ [MIT](https://github.com/CX1-ApS/bricklogger/blob/main/LICENSE). Bricklogger bundles Brick's ontology and a few web libraries
208
+ and fonts under their own licenses, listed with them in the package.
@@ -0,0 +1,163 @@
1
+ # Bricklogger
2
+
3
+ Bricklogger is a data bridge for building automation. It reads a
4
+ [Brick](https://brickschema.org/) model of a building, collects the values of
5
+ the points the model describes from the building's automation systems, and
6
+ writes them to a time-series database. The model decides what is collected:
7
+ upload a new model, and the logger follows it.
8
+
9
+ - **Sources:** BACnet/IP on the local network is built in; other systems are
10
+ added as plugins, such as the [iBOS source](https://github.com/CX1-ApS/bricklogger-ibos)
11
+ for the iBOS Data API in the cloud.
12
+ - **Destination:** TimescaleDB, with every observation timestamped by its
13
+ source and a spool that holds them while the database is away.
14
+ - **Interfaces:** a command-line interface first, a web interface with the same
15
+ abilities beside it — including a model explorer — an HTTP API, and an MCP
16
+ server so an AI assistant can configure the logger for you.
17
+ - **Read only:** Bricklogger never writes to a building automation system.
18
+
19
+ The full documentation is at **<https://cx1-aps.github.io/bricklogger/>**. This
20
+ page is the short version.
21
+
22
+ ## What you need
23
+
24
+ - A Linux machine, amd64 or arm64, that can reach the building's network —
25
+ for BACnet/IP, on the same subnet as the devices or with a route to them.
26
+ - A Brick model of the building as Turtle (`.ttl`), with the points' external
27
+ references (BACnet device and object, for instance).
28
+ - A TimescaleDB database Bricklogger may create tables in.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ curl -fsSL https://github.com/CX1-ApS/bricklogger/releases/latest/download/install.sh | sudo sh
34
+ ```
35
+
36
+ The script brings its own Python, so the machine needs only `curl`. With
37
+ `sudo` it installs a service: the program under `/opt/bricklogger`, the
38
+ configuration in `/etc/bricklogger`, the data in `/var/lib/bricklogger` and
39
+ three systemd units, left stopped. Without `sudo` everything stays in your home
40
+ directory. `--version 0.2.0` installs a given version; options come after
41
+ `--` when the script is piped: `… | sudo sh -s -- --version 0.2.0`.
42
+
43
+ **As a container** the same program is `ghcr.io/cx1-aps/bricklogger`, with a
44
+ compose file for the daemon, the web interface and the MCP server; see
45
+ [Docker](https://cx1-aps.github.io/bricklogger/docker/).
46
+
47
+ ## Prepare the database
48
+
49
+ ```sql
50
+ CREATE DATABASE brick;
51
+ \c brick
52
+ CREATE EXTENSION IF NOT EXISTS timescaledb;
53
+ CREATE ROLE bricklogger LOGIN PASSWORD '...';
54
+ GRANT ALL ON SCHEMA public TO bricklogger;
55
+ ```
56
+
57
+ Bricklogger creates and migrates its own tables at the first start.
58
+
59
+ ## First setup
60
+
61
+ ```bash
62
+ bricklogger init # guided: sources, destinations, secrets
63
+ bricklogger validate # after any edit by hand
64
+ bricklogger daemon start # or: sudo systemctl enable --now bricklogger
65
+ bricklogger model upload building.ttl # validate, infer, activate
66
+ bricklogger status
67
+ bricklogger points --outcome active # the last value of every point
68
+ ```
69
+
70
+ `init` asks for the settings of each source and destination and writes four
71
+ files: `sources.yaml`, `destinations.yaml`, `rules.yaml` and `daemon.yaml`.
72
+ Secrets, such as the database password, go into an `env` file beside them and
73
+ are referred to as `${NAME}`. The first rule set accepts every point in the
74
+ model every five minutes; [rules](https://cx1-aps.github.io/bricklogger/features/configuration/)
75
+ narrow that down by class, location, equipment or any SPARQL pattern.
76
+
77
+ ## The web interface and an assistant
78
+
79
+ ```bash
80
+ bricklogger serve # http://127.0.0.1:8421
81
+ ```
82
+
83
+ Everything the CLI does can be done there, and the model explorer shows the
84
+ building as a tree and a graph, with every point's outcome and value.
85
+
86
+ To let an AI assistant that speaks MCP set up sources, destinations and rules,
87
+ register the MCP server with it — for Claude Code on the same machine:
88
+
89
+ ```bash
90
+ claude mcp add --transport stdio bricklogger -- bricklogger mcp serve
91
+ ```
92
+
93
+ The assistant reads the plugins' schemas and this documentation, validates
94
+ before it writes, and never takes a secret's value. See
95
+ [MCP](https://cx1-aps.github.io/bricklogger/features/mcp/) for remote use.
96
+
97
+ ## Plugins
98
+
99
+ ```bash
100
+ bricklogger plugins # what is installed
101
+ bricklogger plugins add bricklogger-ibos # add a plugin from PyPI
102
+ bricklogger plugins remove ibos # remove one by its type
103
+ sudo systemctl restart bricklogger # the daemon reads plugins at start
104
+ ```
105
+
106
+ A plugin is a Python package that provides a source or a destination type. A
107
+ plugin that cannot load stops nothing: its instances show as failed and the
108
+ rest keep running. Writing one is described under
109
+ [plugins](https://cx1-aps.github.io/bricklogger/features/plugins/).
110
+
111
+ ## Mail notifications
112
+
113
+ Bricklogger can mail an administrator when something goes wrong, when it is
114
+ put right, and once a day as proof that it is alive. Put the mail server and
115
+ recipients under `notifications` in `daemon.yaml`, then:
116
+
117
+ ```bash
118
+ bricklogger notify test
119
+ ```
120
+
121
+ See [notifications](https://cx1-aps.github.io/bricklogger/features/notifications/).
122
+
123
+ ## Upgrade
124
+
125
+ Run the install script again; it leaves the plugins, the configuration and the
126
+ data where they are. Then restart the daemon. A container pulls the new image
127
+ instead:
128
+
129
+ ```bash
130
+ curl -fsSL https://github.com/CX1-ApS/bricklogger/releases/latest/download/install.sh | sudo sh
131
+ sudo systemctl restart bricklogger
132
+ ```
133
+
134
+ After an upgrade to a new minor version, `bricklogger plugins` shows whether
135
+ every plugin still loads.
136
+
137
+ **Upgrading from 0.1 with an iBOS source:** iBOS is no longer built in. The
138
+ `ibos` instance shows as failed until the plugin is added with
139
+ `bricklogger plugins add bricklogger-ibos` and the daemon is restarted; the
140
+ configuration and the collected history stay as they were.
141
+
142
+ ## If nothing arrives
143
+
144
+ - `bricklogger status warnings` lists what stands in the way, one line per
145
+ cause — points no source claims, points without a reference, read errors.
146
+ - `bricklogger sources bacnet_main discover` shows the BACnet devices that
147
+ answer. If none does, the address in `sources.yaml` or the network is the
148
+ problem, not the model.
149
+ - `bricklogger sources bacnet_main resolve <point>` shows how one point's
150
+ reference resolves, and reads it.
151
+ - `bricklogger destinations status` shows whether the database takes writes.
152
+ While it does not, observations wait in the spool.
153
+
154
+ ## Reporting a problem
155
+
156
+ Bugs and questions go in the
157
+ [issues](https://github.com/CX1-ApS/bricklogger/issues). A security
158
+ vulnerability is reported privately, as [SECURITY.md](https://github.com/CX1-ApS/bricklogger/blob/main/SECURITY.md) describes.
159
+
160
+ ## License
161
+
162
+ [MIT](https://github.com/CX1-ApS/bricklogger/blob/main/LICENSE). Bricklogger bundles Brick's ontology and a few web libraries
163
+ and fonts under their own licenses, listed with them in the package.
@@ -0,0 +1,126 @@
1
+ [project]
2
+ name = "bricklogger"
3
+ version = "0.2.0"
4
+ description = "Data bridge for building automation: collects data based on a Brick model and writes it to time-series databases"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.11"
9
+ keywords = [
10
+ "brick",
11
+ "bacnet",
12
+ "building-automation",
13
+ "timescaledb",
14
+ "data-logger",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 2 - Pre-Alpha",
18
+ "Environment :: Console",
19
+ "Environment :: Web Environment",
20
+ "Intended Audience :: Developers",
21
+ "Intended Audience :: System Administrators",
22
+ "Operating System :: POSIX :: Linux",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Home Automation",
28
+ "Topic :: Scientific/Engineering",
29
+ ]
30
+ dependencies = [
31
+ "pydantic>=2.7",
32
+ "pyyaml>=6.0",
33
+ "typer>=0.12",
34
+ "httpx>=0.27",
35
+ "fastapi>=0.110",
36
+ "uvicorn>=0.29",
37
+ "jinja2>=3.1",
38
+ "python-multipart>=0.0.9",
39
+ "itsdangerous>=2.1",
40
+ "rdflib>=7.0",
41
+ "pyshacl>=0.30",
42
+ "reasonable>=0.4",
43
+ "pyoxigraph>=0.4",
44
+ "bacpypes3>=0.0.90",
45
+ "psycopg[binary]>=3.1",
46
+ "mcp>=2.2.0",
47
+ "packaging>=24",
48
+ ]
49
+
50
+ [[project.authors]]
51
+ name = "Michael Rosenlund"
52
+ email = "michael.rosenlund@cx1.dk"
53
+
54
+ [project.urls]
55
+ Homepage = "https://github.com/CX1-ApS/bricklogger"
56
+ Documentation = "https://cx1-aps.github.io/bricklogger/"
57
+ Source = "https://github.com/CX1-ApS/bricklogger"
58
+ Issues = "https://github.com/CX1-ApS/bricklogger/issues"
59
+
60
+ [project.scripts]
61
+ bricklogger = "bricklogger.cli:main"
62
+
63
+ [project.entry-points."bricklogger.sources"]
64
+ bacnet-ip = "bricklogger.plugins.bacnet_ip.declaration:SOURCE"
65
+
66
+ [project.entry-points."bricklogger.destinations"]
67
+ timescaledb = "bricklogger.plugins.timescaledb.declaration:DESTINATION"
68
+
69
+ [dependency-groups]
70
+ dev = [
71
+ "pytest>=8.0",
72
+ "ruff>=0.5",
73
+ "mypy>=1.10",
74
+ "types-PyYAML>=6.0",
75
+ "mkdocs-material>=9.7.6",
76
+ ]
77
+
78
+ [build-system]
79
+ requires = ["uv_build>=0.8,<0.13"]
80
+ build-backend = "uv_build"
81
+
82
+ [tool.uv.build-backend]
83
+ module-name = "bricklogger"
84
+ module-root = "src"
85
+
86
+ [tool.ruff]
87
+ line-length = 88
88
+ target-version = "py311"
89
+ src = [
90
+ "src",
91
+ "tests",
92
+ ]
93
+
94
+ [tool.ruff.lint]
95
+ select = [
96
+ "E",
97
+ "F",
98
+ "W",
99
+ "I",
100
+ "UP",
101
+ "B",
102
+ "SIM",
103
+ "RUF",
104
+ ]
105
+
106
+ [tool.mypy]
107
+ python_version = "3.11"
108
+ strict = true
109
+ plugins = ["pydantic.mypy"]
110
+ files = [
111
+ "src",
112
+ "tests",
113
+ ]
114
+
115
+ [[tool.mypy.overrides]]
116
+ module = [
117
+ "bacpypes3.*",
118
+ "rdflib.*",
119
+ "pyshacl.*",
120
+ "reasonable.*",
121
+ ]
122
+ ignore_missing_imports = true
123
+
124
+ [tool.pytest.ini_options]
125
+ testpaths = ["tests"]
126
+ addopts = "-q"
@@ -0,0 +1,103 @@
1
+ [project]
2
+ name = "bricklogger"
3
+ version = "0.2.0"
4
+ description = "Data bridge for building automation: collects data based on a Brick model and writes it to time-series databases"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Michael Rosenlund", email = "michael.rosenlund@cx1.dk" }]
9
+ requires-python = ">=3.11"
10
+ keywords = ["brick", "bacnet", "building-automation", "timescaledb", "data-logger"]
11
+ classifiers = [
12
+ "Development Status :: 2 - Pre-Alpha",
13
+ "Environment :: Console",
14
+ "Environment :: Web Environment",
15
+ "Intended Audience :: Developers",
16
+ "Intended Audience :: System Administrators",
17
+ "Operating System :: POSIX :: Linux",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Home Automation",
23
+ "Topic :: Scientific/Engineering",
24
+ ]
25
+ dependencies = [
26
+ # core
27
+ "pydantic>=2.7",
28
+ "pyyaml>=6.0",
29
+ # CLI
30
+ "typer>=0.12",
31
+ "httpx>=0.27",
32
+ # API and web interface
33
+ "fastapi>=0.110",
34
+ "uvicorn>=0.29",
35
+ "jinja2>=3.1",
36
+ "python-multipart>=0.0.9",
37
+ "itsdangerous>=2.1",
38
+ # Brick model and working graph
39
+ "rdflib>=7.0",
40
+ "pyshacl>=0.30",
41
+ "reasonable>=0.4",
42
+ "pyoxigraph>=0.4",
43
+ # plugins
44
+ "bacpypes3>=0.0.90",
45
+ "psycopg[binary]>=3.1",
46
+ "mcp>=2.2.0",
47
+ # plugin management: the requirements and markers read at `plugins remove`
48
+ "packaging>=24",
49
+ ]
50
+
51
+ [project.urls]
52
+ Homepage = "https://github.com/CX1-ApS/bricklogger"
53
+ Documentation = "https://cx1-aps.github.io/bricklogger/"
54
+ Source = "https://github.com/CX1-ApS/bricklogger"
55
+ Issues = "https://github.com/CX1-ApS/bricklogger/issues"
56
+
57
+ [project.scripts]
58
+ bricklogger = "bricklogger.cli:main"
59
+
60
+ [project.entry-points."bricklogger.sources"]
61
+ bacnet-ip = "bricklogger.plugins.bacnet_ip.declaration:SOURCE"
62
+
63
+ [project.entry-points."bricklogger.destinations"]
64
+ timescaledb = "bricklogger.plugins.timescaledb.declaration:DESTINATION"
65
+
66
+ [dependency-groups]
67
+ dev = [
68
+ "pytest>=8.0",
69
+ "ruff>=0.5",
70
+ "mypy>=1.10",
71
+ "types-PyYAML>=6.0",
72
+ "mkdocs-material>=9.7.6",
73
+ ]
74
+
75
+ [build-system]
76
+ requires = ["uv_build>=0.8,<0.13"]
77
+ build-backend = "uv_build"
78
+
79
+ [tool.uv.build-backend]
80
+ module-name = "bricklogger"
81
+ module-root = "src"
82
+
83
+ [tool.ruff]
84
+ line-length = 88
85
+ target-version = "py311"
86
+ src = ["src", "tests"]
87
+
88
+ [tool.ruff.lint]
89
+ select = ["E", "F", "W", "I", "UP", "B", "SIM", "RUF"]
90
+
91
+ [tool.mypy]
92
+ python_version = "3.11"
93
+ strict = true
94
+ plugins = ["pydantic.mypy"]
95
+ files = ["src", "tests"]
96
+
97
+ [[tool.mypy.overrides]]
98
+ module = ["bacpypes3.*", "rdflib.*", "pyshacl.*", "reasonable.*"]
99
+ ignore_missing_imports = true
100
+
101
+ [tool.pytest.ini_options]
102
+ testpaths = ["tests"]
103
+ addopts = "-q"
@@ -0,0 +1,17 @@
1
+ """Bricklogger: a data bridge for building automation, driven by a Brick model.
2
+
3
+ The package is laid out after the architecture in ``docs/architecture.md``:
4
+
5
+ - ``bricklogger.daemon`` — the long-running core that collects and writes,
6
+ - ``bricklogger.cli`` — the ``bricklogger`` command, the control plane,
7
+ - ``bricklogger.web`` — the web interface served by ``bricklogger serve``,
8
+ - ``bricklogger.mcp`` — the MCP server served by ``bricklogger mcp serve``, for
9
+ an AI assistant,
10
+ - ``bricklogger.ops`` — the operations the CLI and the MCP server share,
11
+ - ``bricklogger.sdk`` — the contract and the helpers plugins are built on,
12
+ - ``bricklogger.plugins`` — the built-in source (BACnet/IP) and
13
+ destination (TimescaleDB), registered through the same entry points as
14
+ external plugins.
15
+ """
16
+
17
+ __version__ = "0.2.0"
@@ -0,0 +1,6 @@
1
+ """``python -m bricklogger``: the same as the ``bricklogger`` command."""
2
+
3
+ from bricklogger.cli import main
4
+
5
+ if __name__ == "__main__":
6
+ main()