updates2mqtt 1.5.0__tar.gz → 1.6.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.
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/PKG-INFO +71 -32
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/README.md +52 -13
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/pyproject.toml +8 -6
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/app.py +15 -6
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/config.py +14 -6
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/hass_formatter.py +8 -17
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/integrations/docker.py +210 -46
- updates2mqtt-1.6.0/src/updates2mqtt/integrations/git_utils.py +123 -0
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/model.py +27 -1
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/mqtt.py +2 -4
- updates2mqtt-1.5.0/.dockerignore +0 -13
- updates2mqtt-1.5.0/.github/dependabot.yml +0 -30
- updates2mqtt-1.5.0/.github/workflows/auto_assign_issue.yml +0 -18
- updates2mqtt-1.5.0/.github/workflows/auto_assign_pr.yml +0 -18
- updates2mqtt-1.5.0/.github/workflows/docker-publish.yml +0 -78
- updates2mqtt-1.5.0/.github/workflows/main.yml +0 -18
- updates2mqtt-1.5.0/.github/workflows/pypi-publish.yml +0 -78
- updates2mqtt-1.5.0/.github/workflows/python-package.yml +0 -67
- updates2mqtt-1.5.0/.gitignore +0 -171
- updates2mqtt-1.5.0/.hintrc +0 -8
- updates2mqtt-1.5.0/.pre-commit-config.yaml +0 -71
- updates2mqtt-1.5.0/.python-version +0 -1
- updates2mqtt-1.5.0/.safety-project.ini +0 -5
- updates2mqtt-1.5.0/CHANGELOG.md +0 -36
- updates2mqtt-1.5.0/Dockerfile +0 -39
- updates2mqtt-1.5.0/LICENSE +0 -201
- updates2mqtt-1.5.0/SECURITY.md +0 -29
- updates2mqtt-1.5.0/common_packages.yaml +0 -119
- updates2mqtt-1.5.0/conftest.py +0 -147
- updates2mqtt-1.5.0/docs/configuration.md +0 -129
- updates2mqtt-1.5.0/docs/examples/config_maximal.md +0 -7
- updates2mqtt-1.5.0/docs/examples/config_minimal.md +0 -7
- updates2mqtt-1.5.0/docs/examples/docker_compose.md +0 -9
- updates2mqtt-1.5.0/docs/examples/env.md +0 -7
- updates2mqtt-1.5.0/docs/examples/index.md +0 -5
- updates2mqtt-1.5.0/docs/home_assistant.md +0 -51
- updates2mqtt-1.5.0/docs/images/ha_entities.png +0 -0
- updates2mqtt-1.5.0/docs/images/ha_mqtt_discovery.png +0 -0
- updates2mqtt-1.5.0/docs/images/ha_update_detail.png +0 -0
- updates2mqtt-1.5.0/docs/images/ha_update_dialog.png +0 -0
- updates2mqtt-1.5.0/docs/images/ha_update_page.png +0 -0
- updates2mqtt-1.5.0/docs/images/logo-blank-256x256.png +0 -0
- updates2mqtt-1.5.0/docs/images/updates2mqtt-dark-256x256.png +0 -0
- updates2mqtt-1.5.0/docs/index.md +0 -1
- updates2mqtt-1.5.0/docs/installation.md +0 -58
- updates2mqtt-1.5.0/docs/local_builds.md +0 -22
- updates2mqtt-1.5.0/docs/robots.txt +0 -4
- updates2mqtt-1.5.0/docs/troubleshooting.md +0 -171
- updates2mqtt-1.5.0/examples/config.yaml.maximal +0 -37
- updates2mqtt-1.5.0/examples/config.yaml.minimal +0 -9
- updates2mqtt-1.5.0/examples/docker-compose.yaml +0 -18
- updates2mqtt-1.5.0/mkdocs.yml +0 -81
- updates2mqtt-1.5.0/no_config.yaml +0 -33
- updates2mqtt-1.5.0/refresh-deps.sh +0 -7
- updates2mqtt-1.5.0/scripts/healthcheck.sh +0 -91
- updates2mqtt-1.5.0/src/updates2mqtt/integrations/git_utils.py +0 -66
- updates2mqtt-1.5.0/tests/__init__.py +0 -0
- updates2mqtt-1.5.0/tests/test_app.py +0 -130
- updates2mqtt-1.5.0/tests/test_config.py +0 -69
- updates2mqtt-1.5.0/tests/test_docker.py +0 -87
- updates2mqtt-1.5.0/tests/test_git_utils.py +0 -49
- updates2mqtt-1.5.0/tests/test_hass_formatter.py +0 -85
- updates2mqtt-1.5.0/tests/test_mqtt.py +0 -139
- updates2mqtt-1.5.0/uv.lock +0 -1454
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/__init__.py +0 -0
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/__main__.py +0 -0
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/integrations/__init__.py +0 -0
- {updates2mqtt-1.5.0 → updates2mqtt-1.6.0}/src/updates2mqtt/py.typed +0 -0
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: updates2mqtt
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.0
|
|
4
4
|
Summary: System update and docker image notification and execution over MQTT
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Project-URL: Documentation, https://updates2mqtt.rhizomatics.org.uk
|
|
8
|
-
Project-URL: Issues, https://github.com/rhizomatics/updates2mqtt/issues
|
|
9
|
-
Project-URL: Changelog, https://github.com/rhizomatics/updates2mqtt/blob/main/CHANGELOG.md
|
|
5
|
+
Keywords: mqtt,docker,updates,automation,home-assistant,homeassistant,selfhosting
|
|
6
|
+
Author: jey burrows
|
|
10
7
|
Author-email: jey burrows <jrb@rhizomatics.org.uk>
|
|
11
8
|
License-Expression: Apache-2.0
|
|
12
|
-
License-File: LICENSE
|
|
13
|
-
Keywords: automation,docker,home-assistant,homeassistant,mqtt,selfhosting,updates
|
|
14
9
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
-
Classifier: Environment :: Console
|
|
16
|
-
Classifier: Intended Audience :: System Administrators
|
|
17
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
18
10
|
Classifier: License :: Other/Proprietary License
|
|
19
11
|
Classifier: Natural Language :: English
|
|
20
12
|
Classifier: Operating System :: OS Independent
|
|
21
|
-
Classifier:
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Environment :: Console
|
|
23
14
|
Classifier: Topic :: Home Automation
|
|
24
|
-
Classifier: Topic :: System :: Monitoring
|
|
25
15
|
Classifier: Topic :: System :: Systems Administration
|
|
16
|
+
Classifier: Topic :: System :: Monitoring
|
|
17
|
+
Classifier: Intended Audience :: System Administrators
|
|
18
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
26
19
|
Classifier: Typing :: Typed
|
|
27
|
-
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
28
22
|
Requires-Dist: docker>=7.1.0
|
|
29
|
-
Requires-Dist: hishel[httpx]>=0.1.4
|
|
30
|
-
Requires-Dist: httpx>=0.28.1
|
|
31
|
-
Requires-Dist: omegaconf>=2.3.0
|
|
32
23
|
Requires-Dist: paho-mqtt>=2.1.0
|
|
33
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: omegaconf>=2.3.0
|
|
34
25
|
Requires-Dist: structlog>=25.4.0
|
|
26
|
+
Requires-Dist: rich>=14.0.0
|
|
27
|
+
Requires-Dist: httpx>=0.28.1
|
|
28
|
+
Requires-Dist: hishel[httpx]>=0.1.4
|
|
35
29
|
Requires-Dist: usingversion>=0.1.2
|
|
30
|
+
Requires-Python: >=3.13
|
|
31
|
+
Project-URL: Changelog, https://github.com/rhizomatics/updates2mqtt/blob/main/CHANGELOG.md
|
|
32
|
+
Project-URL: Documentation, https://updates2mqtt.rhizomatics.org.uk
|
|
33
|
+
Project-URL: Homepage, https://updates2mqtt.rhizomatics.org.uk
|
|
34
|
+
Project-URL: Issues, https://github.com/rhizomatics/updates2mqtt/issues
|
|
35
|
+
Project-URL: Repository, https://github.com/rhizomatics/updates2mqtt
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
|
|
38
38
|
{ align=left }
|
|
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
|
|
|
42
42
|
[](https://github.com/rhizomatics)
|
|
43
43
|
|
|
44
44
|
[](https://pypi.org/project/updates2mqtt/)
|
|
45
|
-
[](https://github.com/rhizomatics/
|
|
45
|
+
[](https://github.com/rhizomatics/updates2mqtt)
|
|
46
46
|
[](https://updates2mqtt.rhizomatics.org.uk/developer/coverage/)
|
|
47
47
|

|
|
48
48
|
[](https://results.pre-commit.ci/latest/github/rhizomatics/updates2mqtt/main)
|
|
@@ -69,7 +69,7 @@ Read the release notes, and optionally click *Update* to trigger a Docker *pull*
|
|
|
69
69
|
|
|
70
70
|
## Description
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
Updates2MQTT perioidically checks for new versions of components being available, and publishes new version info to MQTT. HomeAssistant auto discovery is supported, so all updates can be seen in the same place as Home Assistant's own components and add-ins.
|
|
73
73
|
|
|
74
74
|
Currently only Docker containers are supported, either via an image registry check, or a git repo for source (see [Local Builds](local_builds.md)). The design is modular, so other update sources can be added, at least for notification. The next anticipated is **apt** for Debian based systems.
|
|
75
75
|
|
|
@@ -79,8 +79,14 @@ To get started, read the [Installation](installation.md) and [Configuration](con
|
|
|
79
79
|
|
|
80
80
|
For a quick spin, try this:
|
|
81
81
|
|
|
82
|
-
```
|
|
83
|
-
docker run -e MQTT_USER=user1 -e MQTT_PASS=
|
|
82
|
+
```bash
|
|
83
|
+
docker run -v /var/run/docker.sock:/var/run/docker.sock -e MQTT_USER=user1 -e MQTT_PASS=user1 -e MQTT_HOST=192.168.1.5 ghcr.io/rhizomatics/updates2mqtt:release
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
or without Docker, using [uv](https://docs.astral.sh/uv/)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
export MQTT_HOST=192.168.1.1;export MQTT_USER=user1;export MQTT_PASS=user1;uv run --with updates2mqtt python -m updates2mqtt
|
|
84
90
|
```
|
|
85
91
|
|
|
86
92
|
## Release Support
|
|
@@ -93,7 +99,7 @@ Presently only Docker containers are supported, although others are planned, pro
|
|
|
93
99
|
|
|
94
100
|
## Heartbeat
|
|
95
101
|
|
|
96
|
-
A heartbeat JSON payload is optionally published periodically to a configurable MQTT topic, defaulting to `healthcheck/{node_name}/updates2mqtt`. It contains the current version of
|
|
102
|
+
A heartbeat JSON payload is optionally published periodically to a configurable MQTT topic, defaulting to `healthcheck/{node_name}/updates2mqtt`. It contains the current version of Updates2MQTT, the node name, a timestamp, and some basic stats.
|
|
97
103
|
|
|
98
104
|
## Healthcheck
|
|
99
105
|
|
|
@@ -136,17 +142,48 @@ restarter:
|
|
|
136
142
|
- UPD2MQTT_UPDATE=AUTO
|
|
137
143
|
```
|
|
138
144
|
|
|
145
|
+
This can be used in conjunction with the `UPD2MQTT_VERSION_INCLUDE` and `UPD2MQTT_VERSION_EXCLUDE` to
|
|
146
|
+
limit which updates get automatically applied, for example excluding nightly builds.
|
|
147
|
+
|
|
148
|
+
Automated updates can also apply to local builds, where a `git_repo_path` has been defined - if there are remote
|
|
149
|
+
commits available to pull, then a `git pull`, `docker compose build` and `docker compose up` will be executed.
|
|
150
|
+
|
|
139
151
|
### Environment Variables
|
|
140
152
|
|
|
141
153
|
The following environment variables can be used to configure containers for `updates2mqtt`:
|
|
142
154
|
|
|
143
|
-
| Env Var
|
|
144
|
-
|
|
145
|
-
| `UPD2MQTT_UPDATE`
|
|
146
|
-
| `UPD2MQTT_PICTURE`
|
|
147
|
-
| `UPD2MQTT_RELNOTES`
|
|
148
|
-
| `UPD2MQTT_GIT_REPO_PATH`
|
|
149
|
-
| `UPD2MQTT_IGNORE`
|
|
155
|
+
| Env Var | Description | Default |
|
|
156
|
+
|----------------------------|----------------------------------------------------------------------------------------------|-----------------|
|
|
157
|
+
| `UPD2MQTT_UPDATE` | Update mode, either `Passive` or `Auto`. If `Auto`, updates will be installed automatically. | `Passive` |
|
|
158
|
+
| `UPD2MQTT_PICTURE` | URL to an icon to use in Home Assistant. | Docker logo URL |
|
|
159
|
+
| `UPD2MQTT_RELNOTES` | URL to release notes for the package. | |
|
|
160
|
+
| `UPD2MQTT_GIT_REPO_PATH` | Relative path to a local git repo if the image is built locally. | |
|
|
161
|
+
| `UPD2MQTT_IGNORE` | If set to `True`, the container will be ignored by Updates2MQTT. | False |
|
|
162
|
+
| `UPD2MQTT_VERSION_INCLUDE` | Only recognize versions matching this string or regular expression | |
|
|
163
|
+
| `UPD2MQTT_VERSION_EXCLUDE` | Skip update if version matches this string or regular expression | |
|
|
164
|
+
|
|
165
|
+
### Docker Labels
|
|
166
|
+
|
|
167
|
+
Alternatively, use Docker labels
|
|
168
|
+
|
|
169
|
+
| Label | Env Var |
|
|
170
|
+
|--------------------------------|----------------------------|
|
|
171
|
+
| `updates2mqtt.update` | `UPD2MQTT_UPDATE` |
|
|
172
|
+
| `updates2mqtt.picture` | `UPD2MQTT_PCITURE` |
|
|
173
|
+
| `updates2mqtt.relnotes` | `UPD2MQTT_RELNOTES` |
|
|
174
|
+
| `updates2mqtt.git_repo_path` | `UPD2MQTT_GIT_REPO_PATH` |
|
|
175
|
+
| `updates2mqtt.ignore` | `UPD2MQTT_IGNORE` |
|
|
176
|
+
| `updates2mqtt.version_include` | `UPD2MQTT_VERSION_INCLUDE` |
|
|
177
|
+
| `updates2mqtt.version_exclude` | `UPD2MQTT_VERSION_EXCLUDE` |
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
```yaml title="Example Compose Snippet"
|
|
181
|
+
restarter:
|
|
182
|
+
image: docker:cli
|
|
183
|
+
command: ["/bin/sh", "-c", "while true; do sleep 86400; docker restart mailserver; done"]
|
|
184
|
+
labels:
|
|
185
|
+
updates2mqtt.relnotes: https://component.my.com/release_notes
|
|
186
|
+
```
|
|
150
187
|
|
|
151
188
|
|
|
152
189
|
## Related Projects
|
|
@@ -157,6 +194,8 @@ Other apps useful for self-hosting with the help of MQTT:
|
|
|
157
194
|
|
|
158
195
|
Find more at [awesome-mqtt](https://github.com/rhizomatics/awesome-mqtt)
|
|
159
196
|
|
|
197
|
+
For a more powerful Docker update manager, try [What's Up Docker](https://getwud.github.io/wud/)
|
|
198
|
+
|
|
160
199
|
## Development
|
|
161
200
|
|
|
162
201
|
This component relies on several open source packages:
|
|
@@ -169,4 +208,4 @@ This component relies on several open source packages:
|
|
|
169
208
|
- [httpx](https://www.python-httpx.org) for retrieving metadata
|
|
170
209
|
- The Astral [uv](https://docs.astral.sh/uv/) and [ruff](https://docs.astral.sh/ruff/) tools for development and build
|
|
171
210
|
- [pytest](https://docs.pytest.org/en/stable/) and supporting add-ins for automated testing
|
|
172
|
-
- [usingversion](https://pypi.org/project/usingversion/) to log current version info
|
|
211
|
+
- [usingversion](https://pypi.org/project/usingversion/) to log current version info
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://github.com/rhizomatics)
|
|
6
6
|
|
|
7
7
|
[](https://pypi.org/project/updates2mqtt/)
|
|
8
|
-
[](https://github.com/rhizomatics/
|
|
8
|
+
[](https://github.com/rhizomatics/updates2mqtt)
|
|
9
9
|
[](https://updates2mqtt.rhizomatics.org.uk/developer/coverage/)
|
|
10
10
|

|
|
11
11
|
[](https://results.pre-commit.ci/latest/github/rhizomatics/updates2mqtt/main)
|
|
@@ -32,7 +32,7 @@ Read the release notes, and optionally click *Update* to trigger a Docker *pull*
|
|
|
32
32
|
|
|
33
33
|
## Description
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Updates2MQTT perioidically checks for new versions of components being available, and publishes new version info to MQTT. HomeAssistant auto discovery is supported, so all updates can be seen in the same place as Home Assistant's own components and add-ins.
|
|
36
36
|
|
|
37
37
|
Currently only Docker containers are supported, either via an image registry check, or a git repo for source (see [Local Builds](local_builds.md)). The design is modular, so other update sources can be added, at least for notification. The next anticipated is **apt** for Debian based systems.
|
|
38
38
|
|
|
@@ -42,8 +42,14 @@ To get started, read the [Installation](installation.md) and [Configuration](con
|
|
|
42
42
|
|
|
43
43
|
For a quick spin, try this:
|
|
44
44
|
|
|
45
|
-
```
|
|
46
|
-
docker run -e MQTT_USER=user1 -e MQTT_PASS=
|
|
45
|
+
```bash
|
|
46
|
+
docker run -v /var/run/docker.sock:/var/run/docker.sock -e MQTT_USER=user1 -e MQTT_PASS=user1 -e MQTT_HOST=192.168.1.5 ghcr.io/rhizomatics/updates2mqtt:release
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
or without Docker, using [uv](https://docs.astral.sh/uv/)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
export MQTT_HOST=192.168.1.1;export MQTT_USER=user1;export MQTT_PASS=user1;uv run --with updates2mqtt python -m updates2mqtt
|
|
47
53
|
```
|
|
48
54
|
|
|
49
55
|
## Release Support
|
|
@@ -56,7 +62,7 @@ Presently only Docker containers are supported, although others are planned, pro
|
|
|
56
62
|
|
|
57
63
|
## Heartbeat
|
|
58
64
|
|
|
59
|
-
A heartbeat JSON payload is optionally published periodically to a configurable MQTT topic, defaulting to `healthcheck/{node_name}/updates2mqtt`. It contains the current version of
|
|
65
|
+
A heartbeat JSON payload is optionally published periodically to a configurable MQTT topic, defaulting to `healthcheck/{node_name}/updates2mqtt`. It contains the current version of Updates2MQTT, the node name, a timestamp, and some basic stats.
|
|
60
66
|
|
|
61
67
|
## Healthcheck
|
|
62
68
|
|
|
@@ -99,17 +105,48 @@ restarter:
|
|
|
99
105
|
- UPD2MQTT_UPDATE=AUTO
|
|
100
106
|
```
|
|
101
107
|
|
|
108
|
+
This can be used in conjunction with the `UPD2MQTT_VERSION_INCLUDE` and `UPD2MQTT_VERSION_EXCLUDE` to
|
|
109
|
+
limit which updates get automatically applied, for example excluding nightly builds.
|
|
110
|
+
|
|
111
|
+
Automated updates can also apply to local builds, where a `git_repo_path` has been defined - if there are remote
|
|
112
|
+
commits available to pull, then a `git pull`, `docker compose build` and `docker compose up` will be executed.
|
|
113
|
+
|
|
102
114
|
### Environment Variables
|
|
103
115
|
|
|
104
116
|
The following environment variables can be used to configure containers for `updates2mqtt`:
|
|
105
117
|
|
|
106
|
-
| Env Var
|
|
107
|
-
|
|
108
|
-
| `UPD2MQTT_UPDATE`
|
|
109
|
-
| `UPD2MQTT_PICTURE`
|
|
110
|
-
| `UPD2MQTT_RELNOTES`
|
|
111
|
-
| `UPD2MQTT_GIT_REPO_PATH`
|
|
112
|
-
| `UPD2MQTT_IGNORE`
|
|
118
|
+
| Env Var | Description | Default |
|
|
119
|
+
|----------------------------|----------------------------------------------------------------------------------------------|-----------------|
|
|
120
|
+
| `UPD2MQTT_UPDATE` | Update mode, either `Passive` or `Auto`. If `Auto`, updates will be installed automatically. | `Passive` |
|
|
121
|
+
| `UPD2MQTT_PICTURE` | URL to an icon to use in Home Assistant. | Docker logo URL |
|
|
122
|
+
| `UPD2MQTT_RELNOTES` | URL to release notes for the package. | |
|
|
123
|
+
| `UPD2MQTT_GIT_REPO_PATH` | Relative path to a local git repo if the image is built locally. | |
|
|
124
|
+
| `UPD2MQTT_IGNORE` | If set to `True`, the container will be ignored by Updates2MQTT. | False |
|
|
125
|
+
| `UPD2MQTT_VERSION_INCLUDE` | Only recognize versions matching this string or regular expression | |
|
|
126
|
+
| `UPD2MQTT_VERSION_EXCLUDE` | Skip update if version matches this string or regular expression | |
|
|
127
|
+
|
|
128
|
+
### Docker Labels
|
|
129
|
+
|
|
130
|
+
Alternatively, use Docker labels
|
|
131
|
+
|
|
132
|
+
| Label | Env Var |
|
|
133
|
+
|--------------------------------|----------------------------|
|
|
134
|
+
| `updates2mqtt.update` | `UPD2MQTT_UPDATE` |
|
|
135
|
+
| `updates2mqtt.picture` | `UPD2MQTT_PCITURE` |
|
|
136
|
+
| `updates2mqtt.relnotes` | `UPD2MQTT_RELNOTES` |
|
|
137
|
+
| `updates2mqtt.git_repo_path` | `UPD2MQTT_GIT_REPO_PATH` |
|
|
138
|
+
| `updates2mqtt.ignore` | `UPD2MQTT_IGNORE` |
|
|
139
|
+
| `updates2mqtt.version_include` | `UPD2MQTT_VERSION_INCLUDE` |
|
|
140
|
+
| `updates2mqtt.version_exclude` | `UPD2MQTT_VERSION_EXCLUDE` |
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
```yaml title="Example Compose Snippet"
|
|
144
|
+
restarter:
|
|
145
|
+
image: docker:cli
|
|
146
|
+
command: ["/bin/sh", "-c", "while true; do sleep 86400; docker restart mailserver; done"]
|
|
147
|
+
labels:
|
|
148
|
+
updates2mqtt.relnotes: https://component.my.com/release_notes
|
|
149
|
+
```
|
|
113
150
|
|
|
114
151
|
|
|
115
152
|
## Related Projects
|
|
@@ -120,6 +157,8 @@ Other apps useful for self-hosting with the help of MQTT:
|
|
|
120
157
|
|
|
121
158
|
Find more at [awesome-mqtt](https://github.com/rhizomatics/awesome-mqtt)
|
|
122
159
|
|
|
160
|
+
For a more powerful Docker update manager, try [What's Up Docker](https://getwud.github.io/wud/)
|
|
161
|
+
|
|
123
162
|
## Development
|
|
124
163
|
|
|
125
164
|
This component relies on several open source packages:
|
|
@@ -132,4 +171,4 @@ This component relies on several open source packages:
|
|
|
132
171
|
- [httpx](https://www.python-httpx.org) for retrieving metadata
|
|
133
172
|
- The Astral [uv](https://docs.astral.sh/uv/) and [ruff](https://docs.astral.sh/ruff/) tools for development and build
|
|
134
173
|
- [pytest](https://docs.pytest.org/en/stable/) and supporting add-ins for automated testing
|
|
135
|
-
- [usingversion](https://pypi.org/project/usingversion/) to log current version info
|
|
174
|
+
- [usingversion](https://pypi.org/project/usingversion/) to log current version info
|
|
@@ -7,7 +7,7 @@ authors = [
|
|
|
7
7
|
]
|
|
8
8
|
|
|
9
9
|
requires-python = ">=3.13"
|
|
10
|
-
version = "1.
|
|
10
|
+
version = "1.6.0"
|
|
11
11
|
license="Apache-2.0"
|
|
12
12
|
keywords=["mqtt", "docker", "updates", "automation","home-assistant","homeassistant","selfhosting"]
|
|
13
13
|
|
|
@@ -59,7 +59,7 @@ dev = [
|
|
|
59
59
|
"icdiff",
|
|
60
60
|
"genbadge[all]"
|
|
61
61
|
]
|
|
62
|
-
|
|
62
|
+
docs=[
|
|
63
63
|
"mkdocs",
|
|
64
64
|
"mkdocs-material",
|
|
65
65
|
"mkdocs-minify-plugin",
|
|
@@ -74,10 +74,12 @@ mkdocs=[
|
|
|
74
74
|
]
|
|
75
75
|
|
|
76
76
|
[build-system]
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
77
|
+
requires = ["uv_build>=0.9.18,<0.10.0"]
|
|
78
|
+
build-backend = "uv_build"
|
|
79
|
+
|
|
80
|
+
[tool.uv.build-backend]
|
|
81
|
+
module-root = "src"
|
|
82
|
+
module-name = "updates2mqtt"
|
|
81
83
|
|
|
82
84
|
[tool.bandit]
|
|
83
85
|
exclude_dirs = ["tests"]
|
|
@@ -39,10 +39,13 @@ class App:
|
|
|
39
39
|
self.last_scan_timestamp: str | None = None
|
|
40
40
|
app_config: Config | None = load_app_config(CONF_FILE)
|
|
41
41
|
if app_config is None:
|
|
42
|
-
log.error(f"Invalid configuration at {CONF_FILE}
|
|
42
|
+
log.error(f"Invalid configuration at {CONF_FILE}")
|
|
43
|
+
log.error("Edit config to fix missing or invalid values and restart")
|
|
44
|
+
log.error("Alternately supply correct MQTT_HOST,MQTT_USER,MQTT_PASSWORD environment variables")
|
|
43
45
|
log.error("Exiting app")
|
|
44
46
|
sys.exit(1)
|
|
45
47
|
self.cfg: Config = app_config
|
|
48
|
+
self.self_bounce: Event = Event()
|
|
46
49
|
|
|
47
50
|
structlog.configure(wrapper_class=structlog.make_filtering_bound_logger(getattr(logging, str(self.cfg.log.level))))
|
|
48
51
|
log.debug("Logging initialized", level=self.cfg.log.level)
|
|
@@ -54,7 +57,7 @@ class App:
|
|
|
54
57
|
self.scan_count: int = 0
|
|
55
58
|
self.last_scan: str | None = None
|
|
56
59
|
if self.cfg.docker.enabled:
|
|
57
|
-
self.scanners.append(DockerProvider(self.cfg.docker, self.common_pkg, self.cfg.node))
|
|
60
|
+
self.scanners.append(DockerProvider(self.cfg.docker, self.common_pkg, self.cfg.node, self.self_bounce))
|
|
58
61
|
self.stopped = Event()
|
|
59
62
|
self.healthcheck_topic = self.cfg.node.healthcheck.topic_template.format(node_name=self.cfg.node.name)
|
|
60
63
|
|
|
@@ -123,7 +126,11 @@ class App:
|
|
|
123
126
|
self.publisher.publish_hass_config(discovery)
|
|
124
127
|
|
|
125
128
|
self.publisher.publish_hass_state(discovery)
|
|
126
|
-
if
|
|
129
|
+
if (
|
|
130
|
+
discovery.update_policy == "Auto"
|
|
131
|
+
and discovery.can_update
|
|
132
|
+
and discovery.latest_version != discovery.current_version
|
|
133
|
+
):
|
|
127
134
|
# TODO: review auto update, trigger by version, use update interval as throttle
|
|
128
135
|
elapsed: float = (
|
|
129
136
|
time.time() - discovery.update_last_attempt if discovery.update_last_attempt is not None else -1
|
|
@@ -155,7 +162,11 @@ class App:
|
|
|
155
162
|
log.debug("Cancellation task completed")
|
|
156
163
|
|
|
157
164
|
def shutdown(self, *args, exit_code: int = 143) -> None: # noqa: ANN002, ARG002
|
|
158
|
-
|
|
165
|
+
if self.self_bounce.is_set():
|
|
166
|
+
exit_code = 1
|
|
167
|
+
log.info("Self bouncing, overriding exit_code: %s", exit_code)
|
|
168
|
+
else:
|
|
169
|
+
log.info("Shutting down, exit_code: %s", exit_code)
|
|
159
170
|
self.stopped.set()
|
|
160
171
|
for scanner in self.scanners:
|
|
161
172
|
scanner.stop()
|
|
@@ -206,8 +217,6 @@ def run() -> None:
|
|
|
206
217
|
import asyncio
|
|
207
218
|
import signal
|
|
208
219
|
|
|
209
|
-
from .app import App
|
|
210
|
-
|
|
211
220
|
# pyright: ignore[reportAttributeAccessIssue]
|
|
212
221
|
log.debug(f"Starting updates2mqtt v{updates2mqtt.version}") # pyright: ignore[reportAttributeAccessIssue]
|
|
213
222
|
app = App()
|
|
@@ -25,7 +25,7 @@ class MqttConfig:
|
|
|
25
25
|
password: str = f"${{oc.env:MQTT_PASS,{MISSING}}}"
|
|
26
26
|
port: int = "${oc.decode:${oc.env:MQTT_PORT,1883}}" # type: ignore[assignment]
|
|
27
27
|
topic_root: str = "updates2mqtt"
|
|
28
|
-
protocol: str = "3.11"
|
|
28
|
+
protocol: str = "${oc.env:MQTT_VERSION,3.11}"
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
@dataclass
|
|
@@ -47,6 +47,7 @@ class DockerConfig:
|
|
|
47
47
|
discover_metadata: dict[str, MetadataSourceConfig] = field(
|
|
48
48
|
default_factory=lambda: {"linuxserver.io": MetadataSourceConfig(enabled=True)}
|
|
49
49
|
)
|
|
50
|
+
api_throttle_wait: int = 60 * 15
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
@dataclass
|
|
@@ -80,12 +81,12 @@ class NodeConfig:
|
|
|
80
81
|
|
|
81
82
|
@dataclass
|
|
82
83
|
class LogConfig:
|
|
83
|
-
level: LogLevel =
|
|
84
|
+
level: LogLevel = "${oc.decode:${oc.env:U2M_LOG_LEVEL,INFO}}" # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
|
|
84
85
|
|
|
85
86
|
|
|
86
87
|
@dataclass
|
|
87
88
|
class Config:
|
|
88
|
-
log: LogConfig = field(default_factory=LogConfig)
|
|
89
|
+
log: LogConfig = field(default_factory=LogConfig) # pyright: ignore[reportArgumentType, reportCallIssue]
|
|
89
90
|
node: NodeConfig = field(default_factory=NodeConfig)
|
|
90
91
|
mqtt: MqttConfig = field(default_factory=MqttConfig) # pyright: ignore[reportArgumentType, reportCallIssue]
|
|
91
92
|
homeassistant: HomeAssistantConfig = field(default_factory=HomeAssistantConfig)
|
|
@@ -132,22 +133,29 @@ def load_package_info(pkginfo_file_path: Path) -> dict[str, PackageUpdateInfo]:
|
|
|
132
133
|
raise
|
|
133
134
|
|
|
134
135
|
|
|
136
|
+
def is_autogen_config() -> bool:
|
|
137
|
+
env_var: str | None = os.environ.get("U2M_AUTOGEN_CONFIG")
|
|
138
|
+
return not (env_var and env_var.lower() in ("no", "0", "false"))
|
|
139
|
+
|
|
140
|
+
|
|
135
141
|
def load_app_config(conf_file_path: Path, return_invalid: bool = False) -> Config | None:
|
|
136
142
|
base_cfg: DictConfig = OmegaConf.structured(Config)
|
|
137
143
|
if conf_file_path.exists():
|
|
138
144
|
cfg: DictConfig = typing.cast("DictConfig", OmegaConf.merge(base_cfg, OmegaConf.load(conf_file_path)))
|
|
139
|
-
|
|
145
|
+
elif is_autogen_config():
|
|
140
146
|
if not conf_file_path.parent.exists():
|
|
141
147
|
try:
|
|
142
148
|
log.debug(f"Creating config directory {conf_file_path.parent} if not already present")
|
|
143
149
|
conf_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
144
150
|
except Exception:
|
|
145
|
-
log.
|
|
151
|
+
log.warning("Unable to create config directory", path=conf_file_path.parent)
|
|
146
152
|
try:
|
|
147
153
|
conf_file_path.write_text(OmegaConf.to_yaml(base_cfg))
|
|
148
154
|
log.info(f"Auto-generated a new config file at {conf_file_path}")
|
|
149
155
|
except Exception:
|
|
150
|
-
log.
|
|
156
|
+
log.warning("Unable to write config file", path=conf_file_path)
|
|
157
|
+
cfg = base_cfg
|
|
158
|
+
else:
|
|
151
159
|
cfg = base_cfg
|
|
152
160
|
|
|
153
161
|
try:
|
|
@@ -21,7 +21,6 @@ HASS_UPDATE_SCHEMA = [
|
|
|
21
21
|
def hass_format_config(
|
|
22
22
|
discovery: Discovery,
|
|
23
23
|
object_id: str,
|
|
24
|
-
node_name: str,
|
|
25
24
|
state_topic: str,
|
|
26
25
|
command_topic: str | None,
|
|
27
26
|
force_command_topic: bool | None,
|
|
@@ -29,13 +28,8 @@ def hass_format_config(
|
|
|
29
28
|
area: str | None = None,
|
|
30
29
|
session: str | None = None,
|
|
31
30
|
) -> dict[str, Any]:
|
|
32
|
-
if device_creation:
|
|
33
|
-
# avoid duplication, since Home Assistant will concatenate device and entity name on update
|
|
34
|
-
name: str = f"{discovery.name} {discovery.source_type}"
|
|
35
|
-
else:
|
|
36
|
-
name = f"{discovery.name} {discovery.source_type} on {node_name}"
|
|
37
31
|
config: dict[str, Any] = {
|
|
38
|
-
"name":
|
|
32
|
+
"name": discovery.title,
|
|
39
33
|
"device_class": None, # not firmware, so defaults to null
|
|
40
34
|
"unique_id": object_id,
|
|
41
35
|
"state_topic": state_topic,
|
|
@@ -46,7 +40,7 @@ def hass_format_config(
|
|
|
46
40
|
"can_restart": discovery.can_restart,
|
|
47
41
|
"update_policy": discovery.update_policy,
|
|
48
42
|
"origin": {
|
|
49
|
-
"name": f"{
|
|
43
|
+
"name": f"{discovery.node} updates2mqtt",
|
|
50
44
|
"sw_version": updates2mqtt.version, # pyright: ignore[reportAttributeAccessIssue]
|
|
51
45
|
"support_url": "https://github.com/rhizomatics/updates2mqtt/issues",
|
|
52
46
|
},
|
|
@@ -57,10 +51,10 @@ def hass_format_config(
|
|
|
57
51
|
config["icon"] = discovery.device_icon
|
|
58
52
|
if device_creation:
|
|
59
53
|
config["device"] = {
|
|
60
|
-
"name": f"{
|
|
54
|
+
"name": f"{discovery.node} updates2mqtt",
|
|
61
55
|
"sw_version": updates2mqtt.version, # pyright: ignore[reportAttributeAccessIssue]
|
|
62
56
|
"manufacturer": "rhizomatics",
|
|
63
|
-
"identifiers": [f"{
|
|
57
|
+
"identifiers": [f"{discovery.node}.updates2mqtt"],
|
|
64
58
|
}
|
|
65
59
|
if area:
|
|
66
60
|
config["device"]["suggested_area"] = area
|
|
@@ -68,20 +62,17 @@ def hass_format_config(
|
|
|
68
62
|
config["command_topic"] = command_topic
|
|
69
63
|
if discovery.can_update:
|
|
70
64
|
config["payload_install"] = f"{discovery.source_type}|{discovery.name}|install"
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
config["custom"] = {}
|
|
66
|
+
config["custom"][discovery.source_type] = discovery.custom
|
|
73
67
|
config.update(discovery.provider.hass_config_format(discovery))
|
|
74
68
|
return config
|
|
75
69
|
|
|
76
70
|
|
|
77
|
-
def hass_format_state(discovery: Discovery,
|
|
78
|
-
title: str = (
|
|
79
|
-
discovery.title_template.format(name=discovery.name, node=node_name) if discovery.title_template else discovery.name
|
|
80
|
-
)
|
|
71
|
+
def hass_format_state(discovery: Discovery, session: str, in_progress: bool = False) -> dict[str, Any]: # noqa: ARG001
|
|
81
72
|
state = {
|
|
82
73
|
"installed_version": discovery.current_version,
|
|
83
74
|
"latest_version": discovery.latest_version,
|
|
84
|
-
"title": title,
|
|
75
|
+
"title": discovery.title,
|
|
85
76
|
"in_progress": in_progress,
|
|
86
77
|
}
|
|
87
78
|
if discovery.release_summary:
|