updates2mqtt 1.3.5__tar.gz → 1.3.6__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 (55) hide show
  1. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.pre-commit-config.yaml +2 -2
  2. updates2mqtt-1.3.6/CHANGELOG.md +8 -0
  3. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/PKG-INFO +10 -137
  4. updates2mqtt-1.3.6/README.md +79 -0
  5. updates2mqtt-1.3.6/docs/configuration.md +98 -0
  6. updates2mqtt-1.3.6/docs/examples/config_maximal.md +7 -0
  7. updates2mqtt-1.3.6/docs/examples/config_minimal.md +7 -0
  8. updates2mqtt-1.3.6/docs/examples/docker_compose.md +7 -0
  9. updates2mqtt-1.3.6/docs/installation.md +29 -0
  10. updates2mqtt-1.3.6/docs/local_builds.md +22 -0
  11. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/examples/config.yaml.maximal +3 -3
  12. updates2mqtt-1.3.6/examples/config.yaml.minimal +9 -0
  13. updates2mqtt-1.3.6/no_config.yaml +33 -0
  14. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/pyproject.toml +1 -1
  15. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/app.py +13 -5
  16. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/config.py +20 -13
  17. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/mqtt.py +16 -4
  18. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/tests/test_config.py +19 -2
  19. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/uv.lock +90 -90
  20. updates2mqtt-1.3.5/README.md +0 -206
  21. updates2mqtt-1.3.5/examples/config.yaml.minimal +0 -22
  22. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.dockerignore +0 -0
  23. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.github/dependabot.yml +0 -0
  24. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.github/workflows/docker-publish.yml +0 -0
  25. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.github/workflows/pypi-publish.yml +0 -0
  26. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.github/workflows/python-package.yml +0 -0
  27. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.gitignore +0 -0
  28. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.hintrc +0 -0
  29. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.python-version +0 -0
  30. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/.safety-project.ini +0 -0
  31. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/Dockerfile +0 -0
  32. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/LICENSE +0 -0
  33. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/SECURITY.md +0 -0
  34. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/common_packages.yaml +0 -0
  35. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/conftest.py +0 -0
  36. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/docs/images/ha_mqtt_discovery.png +0 -0
  37. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/docs/images/ha_update_detail.png +0 -0
  38. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/docs/images/ha_update_page.png +0 -0
  39. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/docs/index.md +0 -0
  40. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/examples/docker-compose.yaml +0 -0
  41. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/mkdocs.yml +0 -0
  42. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/refresh-deps.sh +0 -0
  43. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/scripts/healthcheck.sh +0 -0
  44. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/__init__.py +0 -0
  45. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/__main__.py +0 -0
  46. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/hass_formatter.py +0 -0
  47. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/integrations/__init__.py +0 -0
  48. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/integrations/docker.py +0 -0
  49. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/integrations/git_utils.py +0 -0
  50. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/model.py +0 -0
  51. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/src/updates2mqtt/py.typed +0 -0
  52. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/tests/__init__.py +0 -0
  53. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/tests/test_docker.py +0 -0
  54. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/tests/test_git_utils.py +0 -0
  55. {updates2mqtt-1.3.5 → updates2mqtt-1.3.6}/tests/test_mqtt.py +0 -0
@@ -1,6 +1,6 @@
1
1
  repos:
2
2
  - repo: https://github.com/asottile/pyupgrade
3
- rev: v3.21.0
3
+ rev: v3.21.1
4
4
  hooks:
5
5
  - id: pyupgrade
6
6
  args: [--py313-plus]
@@ -17,7 +17,7 @@ repos:
17
17
  - id: check-shebang-scripts-are-executable
18
18
  name: Check shell scripts are executable
19
19
  - repo: https://github.com/astral-sh/uv-pre-commit
20
- rev: 0.9.7
20
+ rev: 0.9.9
21
21
  hooks:
22
22
  - id: uv-lock
23
23
  - repo: https://github.com/astral-sh/ruff-pre-commit
@@ -0,0 +1,8 @@
1
+ # CHANGELOG
2
+
3
+ ## 1.3.6
4
+ - Changed exit code on graceful shutdown to 143
5
+ - App now exits if the MQTT username / password is not authorized
6
+ - Improved handling of env vars, default config now assumes MQTT_HOST etc unless overridden
7
+ - Will now run without a config if correct `MQTT_HOST`,`MQTT_USER`,`MQTT_PASS`,`MQTT_PORT` env vars set or match the defaults (`127.0.0.1:1883`)
8
+ - Deps update
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: updates2mqtt
3
- Version: 1.3.5
3
+ Version: 1.3.6
4
4
  Summary: System update and docker image notification and execution over MQTT
5
5
  Project-URL: Repository, https://github.com/rhizomatics/updates2mqtt
6
6
  Project-URL: Documentation, https://updates2mqtt.rhizomatics.org.uk
@@ -52,152 +52,25 @@ Use Home Assistant to notify you of updates to Docker images for your containers
52
52
 
53
53
  ## Description
54
54
 
55
- updates2mqtt perioidically checks for new versions of components being available, and publishes new version info to MQTT.
56
- HomeAssistant auto discovery is supported, so all updates can be seen in the same place as Home Assistant's
57
- own components and add-ins.
55
+ 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.
58
56
 
59
- Currently only Docker containers are supported, either via an image registry check, or a git repo for source. The design is modular, so other update sources can be added, at least for notification. The next anticipated is **apt** for Debian based systems.
57
+ 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.
60
58
 
61
- Components can also be updated, either automatically or triggered via MQTT, for example by hitting the *Install*
62
- button in the HomeAssistant update dialog. Icons and release notes can be specified for a better HA experience.
59
+ Components can also be updated, either automatically or triggered via MQTT, for example by hitting the *Install* button in the HomeAssistant update dialog. Icons and release notes can be specified for a better HA experience.
63
60
 
64
- ## Install
61
+ To get started, read the [Installation](installation.md) and [Configuration](configuration.md) pages.
65
62
 
66
- updates2mqtt prefers to be run inside a Docker container.
67
-
68
- ### Manual - Run without installing using uv
69
- ```
70
- uv run --with updates2mqtt updates2mqtt
71
- ```
72
-
73
- ### Manual - Install and run with pip
74
- ```
75
- pip install updates2mqtt
76
- python3 -m updates2mqtt
77
- ```
78
- ### Docker
79
-
80
- See `examples` directory for a working `docker-compose.yaml`.
81
-
82
- If you want to update and restart containers, then the file system paths to the location of the
83
- directory where the docker compose file lives must be available in the updates2mqtt container.
84
-
85
- The example `docker-compose.yaml` mounts `/home/containers` for this purpose, so if your containers are in
86
- `/home/containers/app1`, `/home/containers/app2` etc, then updates2mqtt will be able to find them. Map as
87
- many root paths as needed.
88
-
89
- ## Configuration
90
-
91
- Create file `config.yaml` in `conf` directory. If the file is not present, a default file will be generated.
92
-
93
- ### Example configuration file
94
-
95
- This is a maximal config file, the minimum is no config file at all, which will generate a default config file. The only mandatory values are the MQTT user name and password, everything else can be omitted.
63
+ For a quick spin, try this:
96
64
 
97
65
  ```yaml
98
-
99
- node:
100
- name: docker-host-1 # Unique name for this instance, used to name MQTT entities. Defaults to O/S hostname
101
- git_repo_path: /usr/bin/git # Path to git inside container, needed only if non-default and using local docker builds
102
- healthcheck:
103
- enabled: true
104
- interval: 300 # publish a heartbeat every 5 minutes
105
- topic_template: healthcheck/{node_name}/updates2mqtt
106
- mqtt:
107
- host: ${oc.env:MQTT_HOST}
108
- user: ${oc.env:MQTT_USER}
109
- password: ${oc.env:MQTT_PASS}$ # Use an environment variable for secrets
110
- port: ${oc.env:MQTT_PORT}
111
- topic_root: updates2mqtt
112
- homeassistant:
113
- discovery:
114
- prefix: homeassistant # Matches the default MQTT discovery prefix in Home Assistant
115
- enabled: true
116
- state_topic_suffix: state
117
- docker:
118
- enabled: true
119
- allow_pull: true # if true, will do a `docker pull` if an update is available
120
- allow_restart: true # if true, will do a `docker-compose up` if an update is installed
121
- allow_build: true # if true, will do a `docker-compose build` if a git repo is configured
122
- compose_version: v2 # Controls whether to use `docker-compose` (v1) or `docker compose` (v2) command
123
- default_entity_picture_url: https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png # Picture for update dialog
124
- device_icon: mdi:docker # Material Design Icon to use when browsing entities in Home Assistant
125
- # device_icon: mdi:train-car-container # Alternative icon if you don't like Docker branding
126
- discover_metadata:
127
- linuxserver.io:
128
- enabled: true
129
- cache_ttl: 604800 # cache metadata for 1 week
130
- scan_interval: 10800 # sleep interval between scan runs, in seconds
131
- log:
132
- level: INFO
133
- ```
134
-
135
- ### Moving Secrets Out of Config
136
-
137
- Example use of environment variables, e.g. for secrets:
138
-
139
- ```
140
- mqtt:
141
- password: ${oc.env:MQTT_PASS}
66
+ docker run -e MQTT_USER=user1 -e MQTT_PASS=pass1 -e MQTT_HOST=192.168.1.5 ghcr.io/rhizomatics/updates2mqtt:release
142
67
  ```
143
- ### Customizing images and release notes
144
-
145
- Individual docker containers can have customized entity pictures or release notes, using env variables, for example in the `docker-compose.yaml` or in a separate `.env` file:
146
-
147
- ```
148
- environment:
149
- - UPD2MQTT_PICTURE=https://frigate.video/images/logo.svg
150
- - UPD2MQTT_RELNOTES=https://github.com/blakeblackshear/frigate/releases
151
- ```
152
-
153
- The images will show up in the *Update* section of *Settings* menu in HomeAssistant,
154
- as will the release notes link. SVG icons should be used.
155
-
156
- Some popular services have the icon and release note links pre-configured, in `common_packages.yaml`,
157
- and packages from `linuxserver.io` can have metadata automatically discovered.
158
-
159
- #### Icon Sources
160
-
161
- - [Homarr Dashboard Icons](https://github.com/homarr-labs/dashboard-icons)
162
- - [Self Hosted Icons](https://github.com/selfhst/icons)
163
- - [Simple Icons](https://github.com/simple-icons/simple-icons)
164
- - [Tabler Icons](https://tabler.io/icons)
165
- - [Papirus Icons](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme)
166
- - [Homelab SVG Assets](https://github.com/loganmarchione/homelab-svg-assets)
167
-
168
- ### Automated updates
169
-
170
- If Docker containers should be immediately updated, without any confirmation
171
- or trigger, *e.g.* from the HomeAssistant update dialog, then set an environment variable `UPD2MQTT_UPDATE`
172
- in the target container to `Auto` ( it defaults to `Passive`)
173
-
174
- ### Custom docker builds
175
-
176
- If the image is locally built from a checked out git repo, package update can be driven
177
- by the availability of git repo changes to pull rather than a new image on a Docker registry.
178
-
179
- Declare the git path using the env var in ``UPD2MQTT_GIT_REPO_PATH`` in the docker container ( directly or via an ``.env`` file).
180
- The git repo at this path will be used as the source of timestamps, and an update command will carry out a
181
- ``git pull`` and ``docker-compose build`` rather than pulling an image.
182
-
183
- Note that the updates2mqtt docker container needs access to this path declared in its volumes, and that has to
184
- be read/write if automated install required.
185
-
186
- ### Environment Variables
187
-
188
- The following environment variables can be used to configure updates2mqtt:
189
-
190
- | Env Var | Description | Default |
191
- |---------| ------------|----------|
192
- | `UPD2MQTT_UPDATE` | Update mode, either `Passive` or `Auto`. If `Auto`, updates will be installed automatically. | `Passive` |
193
- | `UPD2MQTT_PICTURE` | URL to an icon to use in Home Assistant. | Docker logo URL |
194
- | `UPD2MQTT_RELNOTES` | URL to release notes for the package. | |
195
- | `UPD2MQTT_GIT_REPO_PATH` | Relative path to a local git repo if the image is built locally. | |
196
- | `UPD2MQTT_IGNORE` | If set to `True`, the container will be ignored by updates2mqtt. | False |
197
-
198
68
 
199
69
  ## Release Support
200
70
 
71
+ Presently only Docker containers are supported, although others are planned,
72
+ probably with priority for `apt`.
73
+
201
74
  | Ecosystem | Support | Comments |
202
75
  |-----------|-------------|----------------------------------------------------------------------------------------------------|
203
76
  | Docker | Scan. Fetch | Fetch is ``docker pull`` only. Restart support only for ``docker-compose`` image based containers. |
@@ -0,0 +1,79 @@
1
+ [![Rhizomatics Open Source](https://avatars.githubusercontent.com/u/162821163?s=96&v=4)](https://github.com/rhizomatics)
2
+
3
+ # updates2mqtt
4
+
5
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/rhizomatics/supernotify)
6
+ [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/rhizomatics/updates2mqtt/main.svg)](https://results.pre-commit.ci/latest/github/rhizomatics/updates2mqtt/main)
7
+ [![Publish Python 🐍 distribution 📦 to PyPI and TestPyPI](https://github.com/rhizomatics/updates2mqtt/actions/workflows/pypi-publish.yml/badge.svg)](https://github.com/rhizomatics/updates2mqtt/actions/workflows/pypi-publish.yml)
8
+ [![Github Deploy](https://github.com/rhizomatics/updates2mqtt/actions/workflows/python-package.yml/badge.svg?branch=main)](https://github.com/rhizomatics/updates2mqtt/actions/workflows/python-package.yml)
9
+ [![CodeQL](https://github.com/rhizomatics/updates2mqtt/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/rhizomatics/updates2mqtt/actions/workflows/github-code-scanning/codeql)
10
+ [![Dependabot Updates](https://github.com/rhizomatics/updates2mqtt/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/rhizomatics/updates2mqtt/actions/workflows/dependabot/dependabot-updates)
11
+
12
+ ## Summary
13
+
14
+ Use Home Assistant to notify you of updates to Docker images for your containers and optionally perform the *pull* (or optionally *build*) and *update*.
15
+
16
+ ![Example Home Assistant update dialog](images/ha_update_detail.png "Home Assistant Updates")
17
+
18
+ ## Description
19
+
20
+ 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.
21
+
22
+ 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.
23
+
24
+ Components can also be updated, either automatically or triggered via MQTT, for example by hitting the *Install* button in the HomeAssistant update dialog. Icons and release notes can be specified for a better HA experience.
25
+
26
+ To get started, read the [Installation](installation.md) and [Configuration](configuration.md) pages.
27
+
28
+ For a quick spin, try this:
29
+
30
+ ```yaml
31
+ docker run -e MQTT_USER=user1 -e MQTT_PASS=pass1 -e MQTT_HOST=192.168.1.5 ghcr.io/rhizomatics/updates2mqtt:release
32
+ ```
33
+
34
+ ## Release Support
35
+
36
+ Presently only Docker containers are supported, although others are planned,
37
+ probably with priority for `apt`.
38
+
39
+ | Ecosystem | Support | Comments |
40
+ |-----------|-------------|----------------------------------------------------------------------------------------------------|
41
+ | Docker | Scan. Fetch | Fetch is ``docker pull`` only. Restart support only for ``docker-compose`` image based containers. |
42
+
43
+ ## Healthcheck
44
+
45
+ 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.
46
+
47
+ A `healthcheck.sh` script is included in the Docker image, and can be used as a Docker healthcheck, if the container environment variables are set for `MQTT_HOST`, `MQTT_PORT`, `MQTT_USER` and `MQTT_PASS`.
48
+
49
+ TIP: Check healthcheck is working using `docker inspect --format "{{json .State.Health }}" updates2mqtt | jq`
50
+
51
+ ## HomeAssistant integration
52
+
53
+ Any updates that have support for automated install will automatically show in the
54
+ Home Assistant settings page if the [MQTT Integration](https://www.home-assistant.io/integrations/mqtt/) is installed and automatic discovery is not disabled.
55
+
56
+ ![Home Assistant MQTT Integraion configuration](images/ha_mqtt_discovery.png "Home Assistant MQTT Discovery")
57
+
58
+ The `homeassistant` default topic prefix matches the default updates2mqtt config, if its changed in HomeAssistant, then the updates2mqtt config must be changed to match.
59
+
60
+ ![Home Assistant updates in Settings](images/ha_update_page.png "Home Assistant Updates")
61
+
62
+ For Home Assistant integration, updates2mqtt represents each component being managed as a [MQTT Update](https://www.home-assistant.io/integrations/update.mqtt/) entity, and uses [MQTT discovery(https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery)] so that HomeAssistant automatically picks up components discovered by updates2mqtt with zero configuration on HomeAssistant itself.
63
+
64
+ There are 3 separate types of MQTT topic used for HomeAssisstant integration:
65
+
66
+ - *Config* to support auto discovery. A topic is created per component, with a name like `homeassistant/update/dockernuc_docker_jellyfin/update/config`. This can be disabled in the config file, and the `homeassistant` topic prefix can also be configured.
67
+ - *State* to report the current version and the latest version available, again one topic per component, like `updates2mqtt/dockernuc/docker/jellyfin`.
68
+ - *Command* to support triggering an update. These will be created on the fly by HomeAssistant when an update is requested, and updates2mqtt subscribes to pick up the changes, so you won't typically see these if browsing MQTT topics. Only one is needed per updates2mqtt agent, with a name like `updates2mqtt/dockernuc/docker`
69
+
70
+ If the package supports automated update, then *Skip* and *Install* buttons will appear on the Home Assistant
71
+ interface, and the package can be remotely fetched and the component restarted.
72
+
73
+ ## Related Projects
74
+
75
+ - [psmqtt](https://github.com/eschava/psmqtt) - Report system health and metrics via MQTT
76
+ -
77
+ ## Development
78
+
79
+ Access to Docker APIs uses the Python [docker-py](https://docker-py.readthedocs.io/en/stable/) SDK for Python. [Eclipse Paho](https://eclipse.dev/paho/files/paho.mqtt.python/html/client.html) is used for MQTT access, and [OmegaConf](https://omegaconf.readthedocs.io) for configuration.
@@ -0,0 +1,98 @@
1
+ # Configuration
2
+
3
+ Create file `config.yaml` in `conf` directory. If the file is not present, a default file will be generated.
4
+
5
+ ### Example configuration file
6
+
7
+ This is a maximal config file, the minimum is no config file at all, which will generate a default config file. The only mandatory values are the MQTT user name and password, everything else can be omitted.
8
+
9
+ ```yaml
10
+
11
+ node:
12
+ name: docker-host-1 # Unique name for this instance, used to name MQTT entities. Defaults to O/S hostname
13
+ git_repo_path: /usr/bin/git # Path to git inside container, needed only if non-default and using local docker builds
14
+ healthcheck:
15
+ enabled: true
16
+ interval: 300 # publish a heartbeat every 5 minutes
17
+ topic_template: healthcheck/{node_name}/updates2mqtt
18
+ mqtt:
19
+ host: ${oc.env:MQTT_HOST}
20
+ user: ${oc.env:MQTT_USER}
21
+ password: ${oc.env:MQTT_PASS}$ # Use an environment variable for secrets
22
+ port: ${oc.env:MQTT_PORT}
23
+ topic_root: updates2mqtt
24
+ homeassistant:
25
+ discovery:
26
+ prefix: homeassistant # Matches the default MQTT discovery prefix in Home Assistant
27
+ enabled: true
28
+ state_topic_suffix: state
29
+ docker:
30
+ enabled: true
31
+ allow_pull: true # if true, will do a `docker pull` if an update is available
32
+ allow_restart: true # if true, will do a `docker-compose up` if an update is installed
33
+ allow_build: true # if true, will do a `docker-compose build` if a git repo is configured
34
+ compose_version: v2 # Controls whether to use `docker-compose` (v1) or `docker compose` (v2) command
35
+ default_entity_picture_url: https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png # Picture for update dialog
36
+ device_icon: mdi:docker # Material Design Icon to use when browsing entities in Home Assistant
37
+ # device_icon: mdi:train-car-container # Alternative icon if you don't like Docker branding
38
+ discover_metadata:
39
+ linuxserver.io:
40
+ enabled: true
41
+ cache_ttl: 604800 # cache metadata for 1 week
42
+ scan_interval: 10800 # sleep interval between scan runs, in seconds
43
+ log:
44
+ level: INFO
45
+ ```
46
+
47
+ ### Moving Secrets Out of Config
48
+
49
+ Example use of environment variables, e.g. for secrets:
50
+
51
+ ```
52
+ mqtt:
53
+ password: ${oc.env:MQTT_PASS}
54
+ ```
55
+ ### Customizing images and release notes
56
+
57
+ Individual docker containers can have customized entity pictures or release notes, using env variables, for example in the `docker-compose.yaml` or in a separate `.env` file:
58
+
59
+ ```
60
+ environment:
61
+ - UPD2MQTT_PICTURE=https://frigate.video/images/logo.svg
62
+ - UPD2MQTT_RELNOTES=https://github.com/blakeblackshear/frigate/releases
63
+ ```
64
+
65
+ The images will show up in the *Update* section of *Settings* menu in HomeAssistant,
66
+ as will the release notes link. SVG icons should be used.
67
+
68
+ #### Icon Sources
69
+
70
+ Updates look nicer in Home Assistant with a suitable icon. Updates2mqtt comes
71
+ pre-packaged with some common ones, in `common_packages.yaml`, and can automatically fetch them (and release links) for the popular [linuxserver.io](https://www.linuxserver.io) packages.
72
+
73
+ If you have something not covered, here are some good places to look for self-hosted app icons:
74
+
75
+ - [Homarr Dashboard Icons](https://github.com/homarr-labs/dashboard-icons)
76
+ - [Self Hosted Icons](https://github.com/selfhst/icons)
77
+ - [Simple Icons](https://github.com/simple-icons/simple-icons)
78
+ - [Tabler Icons](https://tabler.io/icons)
79
+ - [Papirus Icons](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme)
80
+ - [Homelab SVG Assets](https://github.com/loganmarchione/homelab-svg-assets)
81
+
82
+ ### Automated updates
83
+
84
+ If Docker containers should be immediately updated, without any confirmation
85
+ or trigger, *e.g.* from the HomeAssistant update dialog, then set an environment variable `UPD2MQTT_UPDATE` in the target container to `Auto` ( it defaults to `Passive`)
86
+
87
+
88
+ ### Environment Variables
89
+
90
+ The following environment variables can be used to configure updates2mqtt:
91
+
92
+ | Env Var | Description | Default |
93
+ |---------| ------------|----------|
94
+ | `UPD2MQTT_UPDATE` | Update mode, either `Passive` or `Auto`. If `Auto`, updates will be installed automatically. | `Passive` |
95
+ | `UPD2MQTT_PICTURE` | URL to an icon to use in Home Assistant. | Docker logo URL |
96
+ | `UPD2MQTT_RELNOTES` | URL to release notes for the package. | |
97
+ | `UPD2MQTT_GIT_REPO_PATH` | Relative path to a local git repo if the image is built locally. | |
98
+ | `UPD2MQTT_IGNORE` | If set to `True`, the container will be ignored by updates2mqtt. | False |
@@ -0,0 +1,7 @@
1
+ # Maximal Configuration
2
+
3
+ More extensive example configuration, using all the features
4
+
5
+ ``` yaml
6
+ --8<-- "examples/config.yaml.minimal"
7
+ ```
@@ -0,0 +1,7 @@
1
+ # Minimal Configuration
2
+
3
+ Smallest working configuration
4
+
5
+ ``` yaml
6
+ --8<-- "examples/config.yaml.maximal"
7
+ ```
@@ -0,0 +1,7 @@
1
+ # Docker Compose
2
+
3
+ Example Docker Compose configuration to run *updates2mqtt* as a container.
4
+
5
+ ``` yaml
6
+ --8<-- "examples/docker-compose.yaml"
7
+ ```
@@ -0,0 +1,29 @@
1
+ # Installation
2
+
3
+ ## Install
4
+
5
+ updates2mqtt prefers to be run inside a Docker container, though can run standalone, for example scripted via cron or systemd.
6
+
7
+ ### Docker
8
+
9
+ See `examples` directory for a working `docker-compose.yaml`.
10
+
11
+ If you want to update and restart containers, then the file system paths to the location of the directory where the docker compose file lives must be available in the updates2mqtt container.
12
+
13
+ The example `docker-compose.yaml` mounts `/home/containers` for this purpose, so if your containers are in
14
+ `/home/containers/app1`, `/home/containers/app2` etc, then updates2mqtt will be able to find them. Map as many root paths as needed.
15
+
16
+ ### Without Docker
17
+
18
+ #### Run without installing using uv
19
+
20
+ ```
21
+ uv run --with updates2mqtt updates2mqtt
22
+ ```
23
+
24
+ #### Install and run with pip
25
+
26
+ ```
27
+ pip install updates2mqtt
28
+ python3 -m updates2mqtt
29
+ ```
@@ -0,0 +1,22 @@
1
+ # Local Builds
2
+
3
+ ## Custom docker builds
4
+
5
+ If the image is locally built from a checked out git repo, package update can be driven by the availability of git repo changes to pull rather than a new image on a Docker registry.
6
+
7
+ (People sometimes do this as a quick way of forking and changing a repo that doesn't quite work for them, or if the app is a development work in progress).
8
+
9
+ ```yaml title="Example docker-compose.yaml snippet"
10
+ services:
11
+ mymailserver:
12
+ build: ./build/mymailserver
13
+ environment:
14
+ - UPD2MQTT_GIT_REPO_PATH=build/mymailserver
15
+ volumes:
16
+ - /home/containers/mymailserver/build:/home/containers/mymailserver/build
17
+ ```
18
+
19
+ Declare the git path using the env var in ``UPD2MQTT_GIT_REPO_PATH`` in the docker container ( directly or via an ``.env`` file). The git repo at this path will be used as the source of timestamps, and an update command will carry out a
20
+ ``git pull`` and ``docker-compose build`` rather than pulling an image.
21
+
22
+ Note that the updates2mqtt docker container needs access to this path declared in its volumes, and that has to be read/write if automated install required.
@@ -9,9 +9,9 @@ node:
9
9
  topic_template: healthcheck/{node_name}/updates2mqtt
10
10
  mqtt:
11
11
  host: localhost
12
- port: ${oc.env:MQTT_PORT}
13
- user: ${oc.env:MQTT_USER}
14
- password: ${oc.env:MQTT_PASS}
12
+ port: 1883
13
+ user: mymqttuser
14
+ password: mysecret
15
15
  topic_root: updates2mqtt
16
16
  homeassistant:
17
17
  discovery:
@@ -0,0 +1,9 @@
1
+ mqtt:
2
+ host: ${oc.env:MQTT_HOST,"127.0.0.1"}
3
+ port: ${oc.env:MQTT_PORT,1883}
4
+ user: ${oc.env:MQTT_USER}
5
+ password: ${oc.env:MQTT_PASS}
6
+
7
+ node:
8
+ name: dockernuc
9
+
@@ -0,0 +1,33 @@
1
+ log:
2
+ level: INFO
3
+ node:
4
+ name: Jeys-MacBook-Pro
5
+ git_path: /usr/bin/git
6
+ healthcheck:
7
+ enabled: true
8
+ interval: 300
9
+ topic_template: healthcheck/{node_name}/updates2mqtt
10
+ mqtt:
11
+ host: ${oc.env:MQTT_HOST,localhost}
12
+ user: ${oc.env:MQTT_USER,null}
13
+ password: ${oc.env:MQTT_PASS,null}
14
+ port: ${oc.decode:${oc.env:MQTT_PORT,1883}}
15
+ topic_root: updates2mqtt
16
+ homeassistant:
17
+ discovery:
18
+ prefix: homeassistant
19
+ enabled: true
20
+ state_topic_suffix: state
21
+ docker:
22
+ enabled: true
23
+ allow_pull: true
24
+ allow_restart: true
25
+ allow_build: true
26
+ compose_version: v2
27
+ default_entity_picture_url: https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png
28
+ device_icon: mdi:docker
29
+ discover_metadata:
30
+ linuxserver.io:
31
+ enabled: true
32
+ cache_ttl: 604800
33
+ scan_interval: 10800
@@ -7,7 +7,7 @@ authors = [
7
7
  ]
8
8
 
9
9
  requires-python = ">=3.13"
10
- version = "1.3.5"
10
+ version = "1.3.6"
11
11
  license="Apache-2.0"
12
12
  keywords=["mqtt", "docker", "updates", "automation","home-assistant","homeassistant","selfhosting"]
13
13
 
@@ -99,12 +99,17 @@ class App:
99
99
  for scanner in self.scanners:
100
100
  self.publisher.subscribe_hass_command(scanner)
101
101
 
102
- while not self.stopped.is_set():
102
+ while not self.stopped.is_set() and self.publisher.is_available():
103
103
  await self.scan()
104
- if not self.stopped.is_set():
104
+ if not self.stopped.is_set() and self.publisher.is_available():
105
105
  await asyncio.sleep(self.cfg.scan_interval)
106
106
  else:
107
107
  log.info("Stop requested, exiting run loop and skipping sleep")
108
+
109
+ if not self.publisher.is_available():
110
+ log.error("MQTT fatal connection error - check host,port,user,password in config")
111
+ self.shutdown(exit_code=1)
112
+
108
113
  log.debug("Exiting run loop")
109
114
 
110
115
  async def on_discovery(self, discovery: Discovery) -> None:
@@ -144,8 +149,8 @@ class App:
144
149
  await asyncio.gather(*running_tasks, return_exceptions=True)
145
150
  log.debug("Cancellation task completed")
146
151
 
147
- def shutdown(self, *args) -> None: # noqa: ANN002
148
- log.info("Shutting down on SIGTERM: %s", args)
152
+ def shutdown(self, *args, exit_code: int = 143) -> None: # noqa: ANN002, ARG002
153
+ log.info("Shutting down, exit_code: %s", exit_code)
149
154
  self.stopped.set()
150
155
  for scanner in self.scanners:
151
156
  scanner.stop()
@@ -155,8 +160,11 @@ class App:
155
160
  self.publisher.stop()
156
161
  log.debug("Interrupt: %s", interrupt_task.done())
157
162
  log.info("Shutdown handling complete")
163
+ sys.exit(exit_code) # SIGTERM Graceful Exit = 143
158
164
 
159
165
  async def healthcheck(self) -> None:
166
+ if not self.publisher.is_available():
167
+ return
160
168
  self.publisher.publish(
161
169
  topic=self.healthcheck_topic,
162
170
  payload={
@@ -178,7 +186,7 @@ async def repeated_call(func: Callable, interval: int = 60, *args: Any, **kwargs
178
186
  await func(*args, **kwargs)
179
187
  await asyncio.sleep(interval)
180
188
  except asyncio.CancelledError:
181
- log.exception("Periodic task cancelled")
189
+ log.debug("Periodic task cancelled")
182
190
  except Exception:
183
191
  log.exception("Periodic task failed")
184
192
 
@@ -4,17 +4,17 @@ from dataclasses import dataclass, field
4
4
  from pathlib import Path
5
5
 
6
6
  import structlog
7
- from omegaconf import MISSING, MissingMandatoryValue, OmegaConf, ValidationError
7
+ from omegaconf import MISSING, DictConfig, MissingMandatoryValue, OmegaConf, ValidationError
8
8
 
9
9
  log = structlog.get_logger()
10
10
 
11
11
 
12
12
  @dataclass
13
13
  class MqttConfig:
14
- host: str = "localhost"
15
- user: str = MISSING
16
- password: str = MISSING
17
- port: int = 1883
14
+ host: str = "${oc.env:MQTT_HOST,localhost}"
15
+ user: str = f"${{oc.env:MQTT_USER,{MISSING}}}"
16
+ password: str = f"${{oc.env:MQTT_PASS,{MISSING}}}"
17
+ port: int = "${oc.decode:${oc.env:MQTT_PORT,1883}}" # type: ignore[assignment]
18
18
  topic_root: str = "updates2mqtt"
19
19
 
20
20
 
@@ -111,10 +111,11 @@ def load_package_info(pkginfo_file_path: Path) -> UpdateInfoConfig:
111
111
  return typing.cast("UpdateInfoConfig", cfg)
112
112
 
113
113
 
114
- def load_app_config(conf_file_path: Path, return_new: bool = False) -> Config | None:
115
- base_cfg = OmegaConf.structured(Config)
114
+ def load_app_config(conf_file_path: Path, return_invalid: bool = False) -> Config | None:
115
+ base_cfg: DictConfig = OmegaConf.structured(Config)
116
+ is_new: bool = False
116
117
  if conf_file_path.exists():
117
- cfg = OmegaConf.merge(base_cfg, OmegaConf.load(conf_file_path))
118
+ cfg: DictConfig = typing.cast("DictConfig", OmegaConf.merge(base_cfg, OmegaConf.load(conf_file_path)))
118
119
  else:
119
120
  if not conf_file_path.parent.exists():
120
121
  try:
@@ -126,9 +127,7 @@ def load_app_config(conf_file_path: Path, return_new: bool = False) -> Config |
126
127
  conf_file_path.write_text(OmegaConf.to_yaml(base_cfg))
127
128
  log.info(f"Auto-generated a new config file at {conf_file_path}")
128
129
  log.info("The config has place holders for MQTT user and password")
129
- if return_new:
130
- return base_cfg
131
- return None
130
+ is_new = True
132
131
  except Exception:
133
132
  log.exception("Unable to write config file", path=conf_file_path)
134
133
  cfg = base_cfg
@@ -137,7 +136,15 @@ def load_app_config(conf_file_path: Path, return_new: bool = False) -> Config |
137
136
  # Validate that all required fields are present, throw exception now rather than when config first used
138
137
  OmegaConf.to_container(cfg, throw_on_missing=True)
139
138
  OmegaConf.set_readonly(cfg, True)
140
- return typing.cast("Config", cfg)
139
+ config: Config = typing.cast("Config", cfg)
140
+ if config.mqtt.user == MISSING or config.mqtt.password == MISSING:
141
+ if not is_new:
142
+ log.warning("MQTT connection configuration has place holders")
143
+ if not is_new and not return_invalid:
144
+ return None
145
+ return config
141
146
  except (MissingMandatoryValue, ValidationError) as e:
142
147
  log.error("Configuration error %s", e, path=conf_file_path.as_posix())
143
- return None
148
+ if return_invalid and cfg is not None:
149
+ return typing.cast("Config", cfg)
150
+ raise