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.
- enviroplussensorstomqtt-0.1.0/LICENSE +21 -0
- enviroplussensorstomqtt-0.1.0/PKG-INFO +208 -0
- enviroplussensorstomqtt-0.1.0/README.md +173 -0
- enviroplussensorstomqtt-0.1.0/pyproject.toml +70 -0
- enviroplussensorstomqtt-0.1.0/setup.cfg +4 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/__init__.py +5 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/args.py +160 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/config.py +218 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/hardware.py +173 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/log_setup.py +36 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/main.py +141 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/mqtt.py +238 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/sd_notify.py +51 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt/sensor.py +265 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/PKG-INFO +208 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/SOURCES.txt +22 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/dependency_links.txt +1 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/entry_points.txt +2 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/requires.txt +14 -0
- enviroplussensorstomqtt-0.1.0/src/enviroplussensorstomqtt.egg-info/top_level.txt +1 -0
- enviroplussensorstomqtt-0.1.0/src/tests/test_args.py +104 -0
- enviroplussensorstomqtt-0.1.0/src/tests/test_basic.py +10 -0
- enviroplussensorstomqtt-0.1.0/src/tests/test_config.py +93 -0
- 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
|
+
[](https://www.python.org/downloads/)
|
|
39
|
+
[](https://opensource.org/licenses/MIT)
|
|
40
|
+
[](https://github.com/astral-sh/uv)
|
|
41
|
+
[](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
|
+
[](https://www.python.org/downloads/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://github.com/astral-sh/uv)
|
|
6
|
+
[](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,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
|