enviroplussensorstomqtt 0.1.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 (24) hide show
  1. enviroplussensorstomqtt-0.1.0/LICENSE +21 -0
  2. enviroplussensorstomqtt-0.1.0/PKG-INFO +208 -0
  3. enviroplussensorstomqtt-0.1.0/README.md +173 -0
  4. enviroplussensorstomqtt-0.1.0/pyproject.toml +70 -0
  5. enviroplussensorstomqtt-0.1.0/setup.cfg +4 -0
  6. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/__init__.py +5 -0
  7. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/args.py +160 -0
  8. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/config.py +218 -0
  9. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/hardware.py +173 -0
  10. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/log_setup.py +36 -0
  11. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/main.py +141 -0
  12. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/mqtt.py +238 -0
  13. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/sd_notify.py +51 -0
  14. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/sensor.py +265 -0
  15. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/PKG-INFO +208 -0
  16. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/SOURCES.txt +22 -0
  17. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/dependency_links.txt +1 -0
  18. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/entry_points.txt +2 -0
  19. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/requires.txt +14 -0
  20. enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/top_level.txt +1 -0
  21. enviroplussensorstomqtt-0.1.0/src/tests/test_args.py +104 -0
  22. enviroplussensorstomqtt-0.1.0/src/tests/test_basic.py +10 -0
  23. enviroplussensorstomqtt-0.1.0/src/tests/test_config.py +93 -0
  24. enviroplussensorstomqtt-0.1.0/src/tests/test_log_setup.py +41 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Olof Hellqvist
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: enviroplussensorstomqtt
3
+ Version: 0.1.0
4
+ Summary: Publish Pimoroni Enviro+ environmental sensor data to MQTT
5
+ Author-email: Olof Hellqvist <olof.hellqvist@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/hellqvio86/enviroplus-sensors-to-mqtt
8
+ Project-URL: Repository, https://github.com/hellqvio86/enviroplus-sensors-to-mqtt
9
+ Project-URL: Issues, https://github.com/hellqvio86/enviroplus-sensors-to-mqtt/issues
10
+ Keywords: enviroplus,temperature,humidity,pressure,mqtt,raspberry-pi
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Home Automation
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: enviroplus
23
+ Requires-Dist: pimoroni-bme280
24
+ Requires-Dist: pms5003
25
+ Requires-Dist: smbus2
26
+ Requires-Dist: paho-mqtt<3.0.0,>=2.0.0
27
+ Requires-Dist: pyyaml
28
+ Requires-Dist: setproctitle
29
+ Provides-Extra: tests
30
+ Requires-Dist: pytest; extra == "tests"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest; extra == "dev"
33
+ Requires-Dist: ruff; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # Enviroplus Sensors to MQTT
37
+
38
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
40
+ [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
41
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
42
+
43
+ A robust Python service that reads environmental sensor data from a Pimoroni Enviro+ HAT on a Raspberry Pi and publishes structured JSON payloads to an MQTT broker.
44
+
45
+ ---
46
+
47
+ ## Features
48
+
49
+ - **Sensors supported**: BME280 (temperature, humidity, pressure), MICS6814 (reducing, oxidising, NH3 gas resistance), MEMS microphone (noise low/mid/high/amp), and PMS5003 particulate matter sensor (PM1, PM2.5, PM10).
50
+ - **Fault-isolated sampling**: Transient I2C/serial/sensor errors are handled cleanly per sensor group rather than crashing the service.
51
+ - **Self-heating compensation**: Configurable temperature offset (`--temperature_offset` / `temperature_offset`).
52
+ - **Resilient MQTT loop**: Long-lived connection with automatic reconnect, error-checked publishing, and Last Will and Testament (LWT) offline messaging.
53
+ - **systemd-first architecture**: Direct console logging formatted for `journald` with graceful shutdown on `SIGTERM` / `SIGINT`.
54
+ - **Environment variable secrets**: Secure credential loading via `MQTT_HOST`, `MQTT_USERNAME`, and `MQTT_PASSWORD`.
55
+
56
+ ---
57
+
58
+ ## Hardware & System Prerequisites (Raspberry Pi)
59
+
60
+ Ensure the required Raspberry Pi hardware interfaces are enabled via `raspi-config`:
61
+ - **I2C**: Enabled (`Interface Options -> I2C`)
62
+ - **SPI**: Enabled (`Interface Options -> SPI`)
63
+ - **Serial Port**: Hardware serial enabled, serial console disabled (`Interface Options -> Serial Port`)
64
+ - **Microphone**: If using the MEMS noise sensor, ensure the microphone audio overlay is enabled in `/boot/config.txt`.
65
+
66
+ Install system libraries required by the sensor hardware stacks:
67
+ ```bash
68
+ sudo apt-get update
69
+ sudo apt-get install -y python3-dev gcc i2c-tools cmake libffi-dev libopenblas0
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Installation & Setup
75
+
76
+ We recommend using [uv](https://github.com/astral-sh/uv) for fast, deterministic installs:
77
+
78
+ ```bash
79
+ # Clone the repository
80
+ git clone https://github.com/hellqvio86/enviroplus-sensors-to-mqtt.git
81
+ cd enviroplus-sensors-to-mqtt
82
+
83
+ # Install dependencies into local virtualenv
84
+ make install
85
+ ```
86
+
87
+ ### Running Tests & Linting
88
+
89
+ ```bash
90
+ make test
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Configuration
96
+
97
+ Configuration is loaded and merged with the following precedence (highest to lowest):
98
+ 1. Command-line flags
99
+ 2. Environment variables (`MQTT_HOST`, `MQTT_USERNAME`, `MQTT_PASSWORD`)
100
+ 3. YAML config file (`--config_file <path>`, `/etc/enviroplussensorstomqtt.yaml`, or `./config.yaml`)
101
+ 4. Built-in defaults
102
+
103
+ ### Configuration Reference
104
+
105
+ | Option | CLI Flag | Environment Variable | Default | Description |
106
+ |---|---|---|---|---|
107
+ | `host` | `--host` | `MQTT_HOST` | *(required)* | MQTT broker hostname or IP |
108
+ | `port` | `--port` | - | `1883` | MQTT broker port (1-65535) |
109
+ | `topics` | `--topics` | - | *(required)* | Comma-separated list of MQTT topics |
110
+ | `username` | `--username` | `MQTT_USERNAME` | `None` | MQTT broker username (optional) |
111
+ | `password` | `--password` | `MQTT_PASSWORD` | `None` | MQTT broker password (optional) |
112
+ | `interval` | `--interval` | - | `60.0` | Seconds between measurement cycles |
113
+ | `measurements` | `--measurements` | - | `3` | Number of samples to median per cycle |
114
+ | `temperature_offset` | `--temperature_offset` | - | `0.0` | °C offset to subtract for board self-heating |
115
+ | `enable_ltr559` | `--disable-ltr559` | - | `true` | Enable/disable LTR559 light and proximity sensor |
116
+ | `client_id` | `--client_id` | - | `None` | Optional MQTT client ID |
117
+ | `tls` | `--tls` / `--no-tls` | - | `false` | Enable TLS encryption for MQTT broker connection |
118
+ | `tls_ca_certs` | `--tls_ca_certs` | - | `None` | Path to CA certificates file for TLS verification |
119
+ | `tls_certfile` | `--tls_certfile` | - | `None` | Path to client certificate file for mutual TLS |
120
+ | `tls_keyfile` | `--tls_keyfile` | - | `None` | Path to client private key file for mutual TLS |
121
+ | `tls_insecure` | `--tls_insecure` / `--no-tls_insecure` | - | `false` | Disable server certificate hostname verification |
122
+ | `per_metric_topics` | `--per_metric_topics` / `--no-per_metric_topics` | - | `false` | Also publish individual values to `{topic}/{metric}` subtopics |
123
+ | `ha_discovery` | `--ha_discovery` / `--no-ha_discovery` | - | `false` | Enable Home Assistant MQTT Discovery registration |
124
+ | `ha_discovery_prefix` | `--ha_discovery_prefix` | - | `homeassistant` | MQTT topic prefix for Home Assistant discovery |
125
+ | `device_id` | `--device_id` | - | `enviroplus` | Unique device identifier for Home Assistant discovery |
126
+ | `qos` | - | - | `1` | MQTT QoS level (0, 1, or 2) |
127
+ | `retain` | - | - | `true` | Retain published MQTT messages |
128
+ | `debug` | `-D`, `--debug` | - | `false` | Enable verbose debug logging |
129
+ | `log_file` | `--log_file` | - | `None` | Optional file path for file logging |
130
+
131
+ ### YAML Configuration Example
132
+
133
+ Save as `/etc/enviroplussensorstomqtt.yaml` or `config.yaml` with permissions `chmod 600 config.yaml`:
134
+
135
+ ```yaml
136
+ host: "192.168.1.50"
137
+ port: 1883
138
+ username: "mqtt_user"
139
+ password: "secure_password"
140
+ topics:
141
+ - "home/sensors/livingroom/enviroplus"
142
+ interval: 60.0
143
+ measurements: 3
144
+ temperature_offset: 2.5
145
+ enable_ltr559: true
146
+ qos: 1
147
+ retain: true
148
+ debug: false
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Example MQTT Payload
154
+
155
+ Readings are published as a retained JSON object:
156
+
157
+ ```json
158
+ {
159
+ "temperature": 21.45,
160
+ "unit_of_temperature": "C",
161
+ "humidity": 45.20,
162
+ "unit_of_humidity": "%",
163
+ "pressure": 1013.2,
164
+ "unit_of_pressure": "mbar",
165
+ "noise_low": 0.12,
166
+ "noise_mid": 0.08,
167
+ "noise_high": 0.05,
168
+ "noise_amp": 0.02,
169
+ "gas_oxidising": 182500,
170
+ "unit_of_gas_oxidising": "Ohms",
171
+ "gas_reducing": 245000,
172
+ "unit_of_gas_reducing": "Ohms",
173
+ "gas_nh3": 312000,
174
+ "unit_of_gas_nh3": "Ohms",
175
+ "pm1": 2,
176
+ "pm25": 6,
177
+ "pm10": 9,
178
+ "lux": 150.25,
179
+ "unit_of_lux": "Lux",
180
+ "proximity": 38,
181
+ "time_utc": "2026-10-09T08:30:00.000000"
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Systemd Service Installation
188
+
189
+ To install as a background service:
190
+
191
+ ```bash
192
+ make install-service
193
+ sudo systemctl enable enviroplussensorstomqtt
194
+ sudo systemctl start enviroplussensorstomqtt
195
+ ```
196
+
197
+ Check status and follow logs:
198
+
199
+ ```bash
200
+ sudo systemctl status enviroplussensorstomqtt
201
+ journalctl -u enviroplussensorstomqtt -f
202
+ ```
203
+
204
+ <p align="right">
205
+ <a href="https://www.buymeacoffee.com/olofhellqvc">
206
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me a Coffee" height="48">
207
+ </a>
208
+ </p>
@@ -0,0 +1,173 @@
1
+ # Enviroplus Sensors to MQTT
2
+
3
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
6
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
7
+
8
+ A robust Python service that reads environmental sensor data from a Pimoroni Enviro+ HAT on a Raspberry Pi and publishes structured JSON payloads to an MQTT broker.
9
+
10
+ ---
11
+
12
+ ## Features
13
+
14
+ - **Sensors supported**: BME280 (temperature, humidity, pressure), MICS6814 (reducing, oxidising, NH3 gas resistance), MEMS microphone (noise low/mid/high/amp), and PMS5003 particulate matter sensor (PM1, PM2.5, PM10).
15
+ - **Fault-isolated sampling**: Transient I2C/serial/sensor errors are handled cleanly per sensor group rather than crashing the service.
16
+ - **Self-heating compensation**: Configurable temperature offset (`--temperature_offset` / `temperature_offset`).
17
+ - **Resilient MQTT loop**: Long-lived connection with automatic reconnect, error-checked publishing, and Last Will and Testament (LWT) offline messaging.
18
+ - **systemd-first architecture**: Direct console logging formatted for `journald` with graceful shutdown on `SIGTERM` / `SIGINT`.
19
+ - **Environment variable secrets**: Secure credential loading via `MQTT_HOST`, `MQTT_USERNAME`, and `MQTT_PASSWORD`.
20
+
21
+ ---
22
+
23
+ ## Hardware & System Prerequisites (Raspberry Pi)
24
+
25
+ Ensure the required Raspberry Pi hardware interfaces are enabled via `raspi-config`:
26
+ - **I2C**: Enabled (`Interface Options -> I2C`)
27
+ - **SPI**: Enabled (`Interface Options -> SPI`)
28
+ - **Serial Port**: Hardware serial enabled, serial console disabled (`Interface Options -> Serial Port`)
29
+ - **Microphone**: If using the MEMS noise sensor, ensure the microphone audio overlay is enabled in `/boot/config.txt`.
30
+
31
+ Install system libraries required by the sensor hardware stacks:
32
+ ```bash
33
+ sudo apt-get update
34
+ sudo apt-get install -y python3-dev gcc i2c-tools cmake libffi-dev libopenblas0
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Installation & Setup
40
+
41
+ We recommend using [uv](https://github.com/astral-sh/uv) for fast, deterministic installs:
42
+
43
+ ```bash
44
+ # Clone the repository
45
+ git clone https://github.com/hellqvio86/enviroplus-sensors-to-mqtt.git
46
+ cd enviroplus-sensors-to-mqtt
47
+
48
+ # Install dependencies into local virtualenv
49
+ make install
50
+ ```
51
+
52
+ ### Running Tests & Linting
53
+
54
+ ```bash
55
+ make test
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Configuration
61
+
62
+ Configuration is loaded and merged with the following precedence (highest to lowest):
63
+ 1. Command-line flags
64
+ 2. Environment variables (`MQTT_HOST`, `MQTT_USERNAME`, `MQTT_PASSWORD`)
65
+ 3. YAML config file (`--config_file <path>`, `/etc/enviroplussensorstomqtt.yaml`, or `./config.yaml`)
66
+ 4. Built-in defaults
67
+
68
+ ### Configuration Reference
69
+
70
+ | Option | CLI Flag | Environment Variable | Default | Description |
71
+ |---|---|---|---|---|
72
+ | `host` | `--host` | `MQTT_HOST` | *(required)* | MQTT broker hostname or IP |
73
+ | `port` | `--port` | - | `1883` | MQTT broker port (1-65535) |
74
+ | `topics` | `--topics` | - | *(required)* | Comma-separated list of MQTT topics |
75
+ | `username` | `--username` | `MQTT_USERNAME` | `None` | MQTT broker username (optional) |
76
+ | `password` | `--password` | `MQTT_PASSWORD` | `None` | MQTT broker password (optional) |
77
+ | `interval` | `--interval` | - | `60.0` | Seconds between measurement cycles |
78
+ | `measurements` | `--measurements` | - | `3` | Number of samples to median per cycle |
79
+ | `temperature_offset` | `--temperature_offset` | - | `0.0` | °C offset to subtract for board self-heating |
80
+ | `enable_ltr559` | `--disable-ltr559` | - | `true` | Enable/disable LTR559 light and proximity sensor |
81
+ | `client_id` | `--client_id` | - | `None` | Optional MQTT client ID |
82
+ | `tls` | `--tls` / `--no-tls` | - | `false` | Enable TLS encryption for MQTT broker connection |
83
+ | `tls_ca_certs` | `--tls_ca_certs` | - | `None` | Path to CA certificates file for TLS verification |
84
+ | `tls_certfile` | `--tls_certfile` | - | `None` | Path to client certificate file for mutual TLS |
85
+ | `tls_keyfile` | `--tls_keyfile` | - | `None` | Path to client private key file for mutual TLS |
86
+ | `tls_insecure` | `--tls_insecure` / `--no-tls_insecure` | - | `false` | Disable server certificate hostname verification |
87
+ | `per_metric_topics` | `--per_metric_topics` / `--no-per_metric_topics` | - | `false` | Also publish individual values to `{topic}/{metric}` subtopics |
88
+ | `ha_discovery` | `--ha_discovery` / `--no-ha_discovery` | - | `false` | Enable Home Assistant MQTT Discovery registration |
89
+ | `ha_discovery_prefix` | `--ha_discovery_prefix` | - | `homeassistant` | MQTT topic prefix for Home Assistant discovery |
90
+ | `device_id` | `--device_id` | - | `enviroplus` | Unique device identifier for Home Assistant discovery |
91
+ | `qos` | - | - | `1` | MQTT QoS level (0, 1, or 2) |
92
+ | `retain` | - | - | `true` | Retain published MQTT messages |
93
+ | `debug` | `-D`, `--debug` | - | `false` | Enable verbose debug logging |
94
+ | `log_file` | `--log_file` | - | `None` | Optional file path for file logging |
95
+
96
+ ### YAML Configuration Example
97
+
98
+ Save as `/etc/enviroplussensorstomqtt.yaml` or `config.yaml` with permissions `chmod 600 config.yaml`:
99
+
100
+ ```yaml
101
+ host: "192.168.1.50"
102
+ port: 1883
103
+ username: "mqtt_user"
104
+ password: "secure_password"
105
+ topics:
106
+ - "home/sensors/livingroom/enviroplus"
107
+ interval: 60.0
108
+ measurements: 3
109
+ temperature_offset: 2.5
110
+ enable_ltr559: true
111
+ qos: 1
112
+ retain: true
113
+ debug: false
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Example MQTT Payload
119
+
120
+ Readings are published as a retained JSON object:
121
+
122
+ ```json
123
+ {
124
+ "temperature": 21.45,
125
+ "unit_of_temperature": "C",
126
+ "humidity": 45.20,
127
+ "unit_of_humidity": "%",
128
+ "pressure": 1013.2,
129
+ "unit_of_pressure": "mbar",
130
+ "noise_low": 0.12,
131
+ "noise_mid": 0.08,
132
+ "noise_high": 0.05,
133
+ "noise_amp": 0.02,
134
+ "gas_oxidising": 182500,
135
+ "unit_of_gas_oxidising": "Ohms",
136
+ "gas_reducing": 245000,
137
+ "unit_of_gas_reducing": "Ohms",
138
+ "gas_nh3": 312000,
139
+ "unit_of_gas_nh3": "Ohms",
140
+ "pm1": 2,
141
+ "pm25": 6,
142
+ "pm10": 9,
143
+ "lux": 150.25,
144
+ "unit_of_lux": "Lux",
145
+ "proximity": 38,
146
+ "time_utc": "2026-10-09T08:30:00.000000"
147
+ }
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Systemd Service Installation
153
+
154
+ To install as a background service:
155
+
156
+ ```bash
157
+ make install-service
158
+ sudo systemctl enable enviroplussensorstomqtt
159
+ sudo systemctl start enviroplussensorstomqtt
160
+ ```
161
+
162
+ Check status and follow logs:
163
+
164
+ ```bash
165
+ sudo systemctl status enviroplussensorstomqtt
166
+ journalctl -u enviroplussensorstomqtt -f
167
+ ```
168
+
169
+ <p align="right">
170
+ <a href="https://www.buymeacoffee.com/olofhellqvc">
171
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me a Coffee" height="48">
172
+ </a>
173
+ </p>
@@ -0,0 +1,70 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "enviroplussensorstomqtt"
7
+ version = "0.1.0"
8
+ description = "Publish Pimoroni Enviro+ environmental sensor data to MQTT"
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "Olof Hellqvist", email = "olof.hellqvist@gmail.com" }
12
+ ]
13
+ license = "MIT"
14
+ requires-python = ">=3.11"
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Developers",
18
+ "Topic :: Home Automation",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+ ]
25
+ keywords = ["enviroplus", "temperature", "humidity", "pressure", "mqtt", "raspberry-pi"]
26
+ dependencies = [
27
+ "enviroplus",
28
+ "pimoroni-bme280",
29
+ "pms5003",
30
+ "smbus2",
31
+ "paho-mqtt>=2.0.0,<3.0.0",
32
+ "pyyaml",
33
+ "setproctitle",
34
+ ]
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/hellqvio86/enviroplus-sensors-to-mqtt"
38
+ Repository = "https://github.com/hellqvio86/enviroplus-sensors-to-mqtt"
39
+ Issues = "https://github.com/hellqvio86/enviroplus-sensors-to-mqtt/issues"
40
+
41
+ [project.optional-dependencies]
42
+ tests = [
43
+ "pytest",
44
+ ]
45
+ dev = [
46
+ "pytest",
47
+ "ruff",
48
+ ]
49
+
50
+ [project.scripts]
51
+ enviroplussensorstomqtt = "enviroplussensorstomqtt.main:main"
52
+
53
+ [tool.setuptools]
54
+ package-dir = {"" = "src"}
55
+
56
+ [tool.setuptools.packages.find]
57
+ where = ["src"]
58
+ include = ["enviroplussensorstomqtt*"]
59
+
60
+ [tool.ruff]
61
+ line-length = 120
62
+ target-version = "py311"
63
+ src = ["src"]
64
+
65
+ [tool.ruff.lint]
66
+ select = ["E", "F", "W", "I", "B", "UP", "RUF"]
67
+ ignore = []
68
+
69
+ [tool.ruff.lint.per-file-ignores]
70
+ "src/tests/*" = ["S101"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ """Enviroplus sensors to MQTT."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ __all__ = ["__version__"]
@@ -0,0 +1,160 @@
1
+ """Args handler module."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import os
7
+ from typing import Any
8
+
9
+ from .config import parse_config, validate_config
10
+
11
+
12
+ def args_handler(
13
+ argv: list[str] | None = None,
14
+ *,
15
+ config_file: str | None = None,
16
+ validate: bool = False,
17
+ ) -> dict[str, Any]:
18
+ """
19
+ Function for reading arguments and config file.
20
+
21
+ Args:
22
+ argv (list[str], optional): Arguments list to parse. Defaults to sys.argv[1:].
23
+ config_file (str, optional): Default config file to use if not overridden by CLI.
24
+ validate (bool, optional): Whether to validate config immediately against AppConfig schema.
25
+
26
+ Returns:
27
+ dict: Parsed and merged configuration dictionary.
28
+ """
29
+ parser = argparse.ArgumentParser(description="Publish Enviro+ sensor data to MQTT")
30
+ parser.add_argument("--username", type=str, required=False, help="MQTT username")
31
+ parser.add_argument("--password", type=str, required=False, help="MQTT password")
32
+ parser.add_argument("--host", type=str, required=False, help="MQTT broker host")
33
+ parser.add_argument("--port", type=int, required=False, help="MQTT broker port")
34
+ parser.add_argument("--topics", type=str, required=False, help="Comma-separated MQTT topics")
35
+ parser.add_argument("--config_file", type=str, required=False, help="Path to YAML configuration file")
36
+ parser.add_argument("--log_file", type=str, required=False, help="Path to log file")
37
+ parser.add_argument("--interval", type=float, required=False, help="Interval in seconds between cycles")
38
+ parser.add_argument("--measurements", type=int, required=False, help="Number of samples to average per cycle")
39
+ parser.add_argument(
40
+ "--temperature_offset",
41
+ type=float,
42
+ required=False,
43
+ help="Temperature offset in °C to subtract/compensate for self-heating",
44
+ )
45
+ parser.add_argument("--client_id", type=str, required=False, help="MQTT client ID")
46
+ parser.add_argument("--tls", action=argparse.BooleanOptionalAction, default=None, help="Enable TLS")
47
+ parser.add_argument("--tls_ca_certs", type=str, required=False, help="Path to CA certificate")
48
+ parser.add_argument("--tls_certfile", type=str, required=False, help="Path to client certificate")
49
+ parser.add_argument("--tls_keyfile", type=str, required=False, help="Path to client key")
50
+ parser.add_argument("--tls_insecure", action=argparse.BooleanOptionalAction, default=None, help="Skip TLS verify")
51
+ parser.add_argument(
52
+ "--per_metric_topics", action=argparse.BooleanOptionalAction, default=None, help="Publish per-metric"
53
+ )
54
+ parser.add_argument(
55
+ "--ha_discovery", action=argparse.BooleanOptionalAction, default=None, help="Enable HA discovery"
56
+ )
57
+ parser.add_argument("--ha_discovery_prefix", type=str, required=False, help="HA discovery prefix")
58
+ parser.add_argument("--device_id", type=str, required=False, help="Device ID for HA discovery")
59
+ parser.add_argument(
60
+ "--disable-ltr559",
61
+ action="store_true",
62
+ help="Disable LTR559 light and proximity sensor",
63
+ )
64
+ parser.add_argument("-D", "--debug", action="store_true", help="Enable debug logging")
65
+ args = parser.parse_args(argv)
66
+
67
+ if args.config_file:
68
+ config = parse_config(config_file=args.config_file)
69
+ elif config_file:
70
+ config = parse_config(config_file=config_file)
71
+ elif os.path.isfile("/etc/enviroplussensorstomqtt.yaml"):
72
+ config = parse_config(config_file="/etc/enviroplussensorstomqtt.yaml")
73
+ elif os.path.isfile("config.yaml"):
74
+ config = parse_config(config_file="config.yaml")
75
+ else:
76
+ config = parse_config()
77
+
78
+ if args.username is not None:
79
+ config["username"] = args.username
80
+
81
+ if args.password is not None:
82
+ config["password"] = args.password
83
+
84
+ if args.host is not None:
85
+ config["host"] = args.host
86
+
87
+ if args.port is not None:
88
+ config["port"] = args.port
89
+
90
+ if args.debug:
91
+ config["debug"] = True
92
+
93
+ if args.disable_ltr559:
94
+ config["enable_ltr559"] = False
95
+
96
+ if args.log_file is not None:
97
+ config["log_file"] = args.log_file
98
+
99
+ if args.interval is not None:
100
+ config["interval"] = args.interval
101
+
102
+ if args.measurements is not None:
103
+ config["measurements"] = args.measurements
104
+
105
+ if args.temperature_offset is not None:
106
+ config["temperature_offset"] = args.temperature_offset
107
+
108
+ if args.topics is not None:
109
+ config["topics"] = [item.strip() for item in args.topics.split(",") if item.strip()]
110
+
111
+ if args.client_id is not None:
112
+ config["client_id"] = args.client_id
113
+
114
+ if args.tls is not None:
115
+ config["tls"] = args.tls
116
+
117
+ if args.tls_ca_certs is not None:
118
+ config["tls_ca_certs"] = args.tls_ca_certs
119
+
120
+ if args.tls_certfile is not None:
121
+ config["tls_certfile"] = args.tls_certfile
122
+
123
+ if args.tls_keyfile is not None:
124
+ config["tls_keyfile"] = args.tls_keyfile
125
+
126
+ if args.tls_insecure is not None:
127
+ config["tls_insecure"] = args.tls_insecure
128
+
129
+ if args.per_metric_topics is not None:
130
+ config["per_metric_topics"] = args.per_metric_topics
131
+
132
+ if args.ha_discovery is not None:
133
+ config["ha_discovery"] = args.ha_discovery
134
+
135
+ if args.ha_discovery_prefix is not None:
136
+ config["ha_discovery_prefix"] = args.ha_discovery_prefix
137
+
138
+ if args.device_id is not None:
139
+ config["device_id"] = args.device_id
140
+
141
+ # Environment variable fallbacks for secrets and broker config
142
+ if not config.get("password") and "MQTT_PASSWORD" in os.environ:
143
+ config["password"] = os.environ["MQTT_PASSWORD"]
144
+
145
+ if not config.get("username") and "MQTT_USERNAME" in os.environ:
146
+ config["username"] = os.environ["MQTT_USERNAME"]
147
+
148
+ if not config.get("host") and "MQTT_HOST" in os.environ:
149
+ config["host"] = os.environ["MQTT_HOST"]
150
+
151
+ # Validate configuration if requested
152
+ if validate:
153
+ app_config = validate_config(config)
154
+ config = app_config.to_dict()
155
+
156
+ if config.get("debug"):
157
+ debug_config = {k: ("***" if k == "password" and v else v) for k, v in config.items()}
158
+ print(f"config: {debug_config}")
159
+
160
+ return config