sensehatsensorstomqtt 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 (43) hide show
  1. sensehatsensorstomqtt-0.1.0/LICENSE +21 -0
  2. sensehatsensorstomqtt-0.1.0/PKG-INFO +353 -0
  3. sensehatsensorstomqtt-0.1.0/README.md +317 -0
  4. sensehatsensorstomqtt-0.1.0/pyproject.toml +83 -0
  5. sensehatsensorstomqtt-0.1.0/setup.cfg +4 -0
  6. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/__init__.py +4 -0
  7. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/args.py +185 -0
  8. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/colors.py +23 -0
  9. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/config.py +416 -0
  10. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/consts.py +6 -0
  11. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/display.py +159 -0
  12. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/hardware.py +17 -0
  13. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/log_setup.py +41 -0
  14. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/main.py +134 -0
  15. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/sd_notify.py +51 -0
  16. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/sensor.py +471 -0
  17. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt/utils.py +36 -0
  18. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt.egg-info/PKG-INFO +353 -0
  19. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt.egg-info/SOURCES.txt +41 -0
  20. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt.egg-info/dependency_links.txt +1 -0
  21. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt.egg-info/entry_points.txt +2 -0
  22. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt.egg-info/requires.txt +14 -0
  23. sensehatsensorstomqtt-0.1.0/src/sensehatsensorstomqtt.egg-info/top_level.txt +1 -0
  24. sensehatsensorstomqtt-0.1.0/tests/test_accuracy.py +138 -0
  25. sensehatsensorstomqtt-0.1.0/tests/test_additional_sensors.py +75 -0
  26. sensehatsensorstomqtt-0.1.0/tests/test_args.py +134 -0
  27. sensehatsensorstomqtt-0.1.0/tests/test_colors.py +29 -0
  28. sensehatsensorstomqtt-0.1.0/tests/test_config.py +81 -0
  29. sensehatsensorstomqtt-0.1.0/tests/test_display.py +249 -0
  30. sensehatsensorstomqtt-0.1.0/tests/test_log_setup.py +35 -0
  31. sensehatsensorstomqtt-0.1.0/tests/test_mqtt_features.py +104 -0
  32. sensehatsensorstomqtt-0.1.0/tests/test_mqtt_publish.py +149 -0
  33. sensehatsensorstomqtt-0.1.0/tests/test_paho_version.py +47 -0
  34. sensehatsensorstomqtt-0.1.0/tests/test_readme.py +44 -0
  35. sensehatsensorstomqtt-0.1.0/tests/test_resilience.py +62 -0
  36. sensehatsensorstomqtt-0.1.0/tests/test_resources.py +97 -0
  37. sensehatsensorstomqtt-0.1.0/tests/test_sd_notify.py +58 -0
  38. sensehatsensorstomqtt-0.1.0/tests/test_secret_leak.py +83 -0
  39. sensehatsensorstomqtt-0.1.0/tests/test_sensor.py +180 -0
  40. sensehatsensorstomqtt-0.1.0/tests/test_shutdown_and_cadence.py +273 -0
  41. sensehatsensorstomqtt-0.1.0/tests/test_systemd.py +77 -0
  42. sensehatsensorstomqtt-0.1.0/tests/test_utils.py +36 -0
  43. sensehatsensorstomqtt-0.1.0/tests/test_validation.py +180 -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,353 @@
1
+ Metadata-Version: 2.4
2
+ Name: sensehatsensorstomqtt
3
+ Version: 0.1.0
4
+ Summary: sense-hat sensors data to mqtt
5
+ Author-email: Olof Hellqvist <olof.hellqvist@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/hellqvio86/sense-hat-sensors-to-mqtt
8
+ Project-URL: Repository, https://github.com/hellqvio86/sense-hat-sensors-to-mqtt
9
+ Project-URL: Issues, https://github.com/hellqvio86/sense-hat-sensors-to-mqtt/issues
10
+ Keywords: sense-hat,temperature,mqtt
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Home Automation
14
+ Classifier: Topic :: System :: Hardware
15
+ Classifier: Topic :: System :: Monitoring
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: paho-mqtt<3.0.0,>=2.0.0
24
+ Requires-Dist: pyyaml>=6.0
25
+ Requires-Dist: sense-hat<3.0.0,>=2.2.0
26
+ Provides-Extra: tests
27
+ Requires-Dist: pytest; extra == "tests"
28
+ Requires-Dist: pytest-cov; extra == "tests"
29
+ Provides-Extra: dev
30
+ Requires-Dist: mypy; extra == "dev"
31
+ Requires-Dist: pytest; extra == "dev"
32
+ Requires-Dist: pytest-cov; extra == "dev"
33
+ Requires-Dist: ruff; extra == "dev"
34
+ Requires-Dist: types-PyYAML; extra == "dev"
35
+ Dynamic: license-file
36
+
37
+ # Sense Hat Sensors to MQTT
38
+
39
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
+ [![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)
42
+ [![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)
43
+
44
+ A robust Python service for Raspberry Pi with a **Sense HAT**. Once per configurable cycle (default 60s), it samples temperature, humidity, and pressure using median filtering, publishes a structured JSON payload to one or more MQTT topics with retain and QoS, and optionally scrolls the measurements on the 8x8 LED matrix (unless in night mode).
45
+
46
+ ---
47
+
48
+ ## Prerequisites & Hardware Setup
49
+
50
+ ### 1. Enable I2C Interface
51
+ The Sense HAT sensors communicate over the Raspberry Pi I2C bus. You must ensure I2C is enabled:
52
+
53
+ ```bash
54
+ sudo raspi-config nonint do_i2c 0
55
+ ```
56
+ *(Alternatively, run `sudo raspi-config` and navigate to **Interface Options** -> **I2C** -> **Yes**).*
57
+
58
+ Verify `/dev/i2c-1` exists:
59
+ ```bash
60
+ ls -l /dev/i2c*
61
+ ```
62
+
63
+ ### 2. System Packages & Python Environment
64
+ The Sense HAT software stack depends on `RTIMULib` C bindings provided by the Raspberry Pi OS package `python3-sense-hat`.
65
+
66
+ Install the required apt packages:
67
+ ```bash
68
+ sudo apt-get update
69
+ sudo apt-get install -y python3-dev gcc cmake python3-sense-hat libjpeg-dev zlib1g-dev libfreetype6-dev
70
+ ```
71
+
72
+ > [!IMPORTANT]
73
+ > Because `sense-hat` relies on native `RTIMULib` in system site-packages, any Python virtual environment **must** be created with `--system-site-packages`. The included `Makefile` handles this automatically.
74
+
75
+ ### 3. Install `uv`
76
+ This project uses [`uv`](https://docs.astral.sh/uv/) for fast, deterministic dependency management:
77
+ ```bash
78
+ curl -LsSf https://astral.sh/uv/install.sh | sh
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Installation & Setup
84
+
85
+ Clone the repository and install into a local virtual environment:
86
+
87
+ ```bash
88
+ git clone https://github.com/hellqvio86/sense-hat-sensors-to-mqtt.git
89
+ cd sense-hat-sensors-to-mqtt
90
+ make install
91
+ ```
92
+
93
+ This creates `.venv` with `--system-site-packages` and syncs all dependencies from `uv.lock`.
94
+
95
+ ### Running Locally
96
+ Run the application with a YAML configuration file:
97
+ ```bash
98
+ uv run sensehatsensorstomqtt --config_file ./config.yaml
99
+ ```
100
+ Or run directly with CLI arguments:
101
+ ```bash
102
+ uv run sensehatsensorstomqtt --host 192.168.1.100 --topics home/sensors/sensehat -D
103
+ ```
104
+
105
+ ### Running Tests & Linting
106
+ Run the test suite, Ruff linter, formatting checks, and Mypy type-checker:
107
+ ```bash
108
+ make test
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Configuration
114
+
115
+ Configuration values are resolved with the following precedence (highest to lowest):
116
+ 1. Command-line arguments (`--host`, `--port`, etc.)
117
+ 2. Environment variables (`MQTT_PASSWORD`)
118
+ 3. Configuration file in the following search order:
119
+ - File specified via `--config_file <path>`
120
+ - `/etc/sensehatsensorstomqtt.yaml`
121
+ - `./config.yaml` (in current working directory)
122
+ 4. Built-in defaults
123
+
124
+ ### Example `config.yaml`
125
+
126
+ ```yaml
127
+ host: "192.168.1.100"
128
+ port: 1883
129
+ username: "mqtt_user"
130
+ password: "mqtt_password"
131
+ # Or read password securely from file:
132
+ # password_file: "/etc/sensehat_mqtt.password"
133
+ topics:
134
+ - "home/sensors/sensehat"
135
+ qos: 1
136
+ retain: true
137
+ publish_timeout: 5.0
138
+
139
+ # MQTT Client & Security
140
+ client_id: "sensehat-pi"
141
+ tls: false
142
+ tls_ca_certs: "/etc/ssl/certs/ca-certificates.crt"
143
+ tls_certfile: null
144
+ tls_keyfile: null
145
+ tls_insecure: false
146
+
147
+ # Topics & Home Assistant Discovery
148
+ per_metric_topics: false
149
+ ha_discovery: false
150
+ ha_discovery_prefix: "homeassistant"
151
+ device_id: "sensehat"
152
+
153
+ # Availability / Last Will and Testament (LWT)
154
+ status_topic: "home/sensors/sensehat/status"
155
+
156
+ # Cadence & Sampling
157
+ interval: 60.0
158
+ measurements: 3
159
+ sample_spacing: 1.0
160
+
161
+ # Sensor Calibration & CPU Compensation
162
+ temperature_offset: 0.0
163
+ compensate_cpu_temp: true
164
+ cpu_temp_factor: 5.466
165
+
166
+ # LED Matrix Display
167
+ display: true
168
+ display_pause: 5.0
169
+ night_start: 19
170
+ night_end: 7
171
+
172
+ # Logging
173
+ log_file: "/var/log/sensehatsensorstomqtt.log"
174
+ debug: false
175
+ ```
176
+
177
+ ### Configuration Reference Table
178
+
179
+ | Key | CLI Argument | Env Var | Type | Default | Description |
180
+ | :--- | :--- | :--- | :--- | :--- | :--- |
181
+ | `host` | `--host` | | `string` | *(Required)* | MQTT broker hostname or IP address. |
182
+ | `port` | `--port` | | `integer` | `1883` | MQTT broker port (1–65535). |
183
+ | `username` | `--username` | | `string` | `None` | Username for authenticated MQTT brokers. |
184
+ | `password` | `--password` | `MQTT_PASSWORD` | `string` | `None` | Password for authenticated MQTT brokers. |
185
+ | `password_file` | `--password_file` | | `string` | `None` | Path to a file containing the MQTT password. |
186
+ | `topics` | `--topics` | | `list` / `csv` | *(Required)* | MQTT topics to publish sensor telemetry to. |
187
+ | `qos` | `--qos` | | `integer` | `1` | MQTT Quality of Service level (`0`, `1`, or `2`). |
188
+ | `retain` | `--retain` / `--no-retain` | | `boolean` | `true` | Whether MQTT messages are published with the retain flag. |
189
+ | `publish_timeout`| | | `float` | `5.0` | Timeout in seconds waiting for MQTT broker publish acknowledgment. |
190
+ | `client_id` | `--client_id` | | `string` | `None` | Explicit MQTT client ID. |
191
+ | `tls` | `--tls` / `--no-tls` | | `boolean` | `false` | Enable TLS encryption for MQTT connection. |
192
+ | `tls_ca_certs` | `--tls_ca_certs` | | `string` | `None` | Path to CA certificates file for TLS verification. |
193
+ | `tls_certfile` | `--tls_certfile` | | `string` | `None` | Path to client certificate file for mutual TLS. |
194
+ | `tls_keyfile` | `--tls_keyfile` | | `string` | `None` | Path to client private key file for mutual TLS. |
195
+ | `tls_insecure` | `--tls_insecure` / `--no-tls_insecure` | | `boolean` | `false` | Disable server certificate hostname verification. |
196
+ | `per_metric_topics` | `--per_metric_topics` / `--no-per_metric_topics` | | `boolean` | `false` | Also publish individual values to `{topic}/{metric}` subtopics. |
197
+ | `ha_discovery` | `--ha_discovery` / `--no-ha_discovery` | | `boolean` | `false` | Enable Home Assistant MQTT Discovery entity registration. |
198
+ | `ha_discovery_prefix` | `--ha_discovery_prefix` | | `string` | `homeassistant` | MQTT topic prefix for Home Assistant discovery. |
199
+ | `device_id` | `--device_id` | | `string` | `sensehat` | Unique device identifier used in Home Assistant discovery. |
200
+ | `include_imu` | `--include_imu` / `--no-include_imu` | | `boolean` | `false` | Include IMU sensors (orientation, accelerometer, gyroscope, compass) in payload. |
201
+ | `include_pressure_temp` | `--include_pressure_temp` / `--no-include_pressure_temp` | | `boolean` | `false` | Include temperature read from the pressure sensor in payload. |
202
+ | `status_topic` | `--status_topic` | | `string` | `None` | LWT and availability topic (`online` / `offline`). |
203
+ | `interval` | `--interval` | | `float` | `60.0` | Cadence interval in seconds between publication cycles. |
204
+ | `measurements` | `--measurements` | | `integer` | `3` | Number of samples taken per cycle for median filtering ($\ge 1$). |
205
+ | `sample_spacing` | `--sample_spacing`| | `float` | `1.0` | Delay in seconds between individual sensor sample reads. |
206
+ | `temperature_offset` | `--temperature_offset` | | `float` | `0.0` | Manual temperature offset in °C subtracted from readings. |
207
+ | `compensate_cpu_temp` | `--compensate_cpu_temp` / `--no-compensate_cpu_temp` | | `boolean` | `false` | Compensate for Raspberry Pi CPU heat radiation. |
208
+ | `cpu_temp_factor` | `--cpu_temp_factor` | | `float` | `5.466` | Scaling factor for CPU temperature compensation. |
209
+ | `display` | `--display` / `--no-display` | | `boolean` | `true` | Enable or disable the 8x8 LED matrix display. |
210
+ | `display_pause` | `--display_pause` | | `float` | `5.0` | Pause in seconds between messages scrolling on the LED matrix. |
211
+ | `night_start` | `--night_start` | | `integer` | `19` | Local hour (0–23) when night mode starts (turns LED matrix off). |
212
+ | `night_end` | `--night_end` | | `integer` | `7` | Local hour (0–23) when night mode ends (turns LED matrix on). |
213
+ | `log_file` | `--log_file` | | `string` | `None` | Path to rotating log file. Defaults to stderr. |
214
+ | `debug` | `-D`, `--debug` | | `boolean` | `false` | Enable verbose debug logging (passwords are redacted). |
215
+
216
+ ---
217
+
218
+ ## MQTT Payload Schema
219
+
220
+ Each cycle publishes a single JSON object to the configured topic(s):
221
+
222
+ ```json
223
+ {
224
+ "temperature": 21.45,
225
+ "humidity": 45.20,
226
+ "pressure": 1013.2,
227
+ "unit_of_temperature": "C",
228
+ "unit_of_humidity": "%",
229
+ "unit_of_pressure": "mbar",
230
+ "time_utc": "2026-10-09T10:15:30+00:00"
231
+ }
232
+ ```
233
+
234
+ ### Fields & Units
235
+ - `temperature` (`float`): Ambient temperature in degrees Celsius (°C), rounded to 2 decimal places (`0.01`). Calibrated by `temperature_offset` and/or `compensate_cpu_temp`.
236
+ - `humidity` (`float`): Relative humidity in percent (`%`), rounded to 2 decimal places (`0.01`).
237
+ - `pressure` (`float`): Atmospheric pressure in millibars (hPa), rounded to 1 decimal place (`0.1`). Note: $1\text{ mbar} = 1\text{ hPa} = 100\text{ Pa}$.
238
+ - `unit_of_temperature` (`string`): Temperature unit (`"C"`).
239
+ - `unit_of_humidity` (`string`): Humidity unit (`"%"`).
240
+ - `unit_of_pressure` (`string`): Pressure unit (`"mbar"`).
241
+ - `time_utc` (`string`): Timezone-aware ISO-8601 UTC timestamp with second precision (`YYYY-MM-DDTHH:MM:SS+00:00`).
242
+ - `pressure_temperature` (`float`, optional): Temperature in °C from the pressure sensor when `include_pressure_temp` is enabled.
243
+ - `orientation` (`object`, optional): IMU pitch, roll, and yaw angles in degrees when `include_imu` is enabled.
244
+ - `accelerometer` (`object`, optional): Raw acceleration vector (`x`, `y`, `z`) in Gs when `include_imu` is enabled.
245
+ - `gyroscope` (`object`, optional): Raw rotational velocity vector (`x`, `y`, `z`) in rad/s when `include_imu` is enabled.
246
+ - `compass` (`object`, optional): Raw magnetic field vector (`x`, `y`, `z`) in microteslas ($\mu\text{T}$) when `include_imu` is enabled.
247
+
248
+ ---
249
+
250
+ ## Sensor Calibration & Accuracy
251
+
252
+ The Raspberry Pi Sense HAT sits directly above the Pi CPU and SoC. As a result, heat generated by the board causes raw Sense HAT temperature readings to run significantly higher than ambient room temperature, which also distorts relative humidity calculations.
253
+
254
+ To improve temperature accuracy, two calibration mechanisms are supported:
255
+
256
+ 1. **Manual Offset (`temperature_offset`)**: Subtracts a fixed degree Celsius offset (e.g. `3.5`) from the measured temperature:
257
+ ```yaml
258
+ temperature_offset: 3.5
259
+ ```
260
+ 2. **CPU Temperature Compensation (`compensate_cpu_temp`)**: Reads Pi CPU temperature from `/sys/class/thermal/thermal_zone0/temp` each cycle and calculates ambient temperature using:
261
+ $$\text{temp} = \text{temp}_{\text{raw}} - \frac{\text{temp}_{\text{cpu}} - \text{temp}_{\text{raw}}}{\text{factor}} - \text{offset}$$
262
+ The scaling factor can be tuned via `cpu_temp_factor` (default `5.466`, typical range `1.2`–`5.5` depending on enclosure and airflow).
263
+
264
+ On startup, initial sensor readings are primed and discarded to prevent publishing uncalibrated or stale initial values.
265
+
266
+ ---
267
+
268
+ ## LED Matrix Display & Night Mode
269
+
270
+ When `display: true` (the default), the service scrolls current readings on the Sense HAT 8x8 LED matrix after each publish cycle.
271
+
272
+ - **Night Window**: Between `night_start` (default `19` / 7 PM) and `night_end` (default `7` / 7 AM), the LED matrix is kept completely dark to avoid disturbance.
273
+ - **Headless Mode**: For server closets or always-dark installations, set `display: false` or pass `--no-display` to completely disable the LED matrix and save power.
274
+ - **Non-blocking Loop**: If the LED display encounters an error or hardware disconnect, display failures are logged safely without interrupting sensor publishing.
275
+
276
+ ---
277
+
278
+ ## Security Best Practices
279
+
280
+ 1. **Do not put plaintext passwords in command-line arguments**: Flags like `--password` are visible in `ps` and `/proc/*/cmdline`. Use `MQTT_PASSWORD` environment variable or `password_file` instead.
281
+ 2. **Secure file permissions**: Ensure your config and password files are restricted:
282
+ ```bash
283
+ chmod 600 config.yaml /etc/sensehat_mqtt.password
284
+ ```
285
+ 3. **Automatic Log Redaction**: Passwords are automatically redacted (`***`) in debug output and logs.
286
+
287
+ ---
288
+
289
+ ## Systemd Service Installation
290
+
291
+ To install this application as a hardened system service managed by `systemd`:
292
+
293
+ ```bash
294
+ make install-service
295
+ ```
296
+
297
+ This command will:
298
+ 1. Ensure the system user `sensehat` exists with memberships in `i2c`, `video`, and `input` groups.
299
+ 2. Install the wrapper executable directly to `/usr/local/bin/sensehatsensorstomqtt`.
300
+ 3. Install the hardened systemd unit file from `systemd/sensehatsensorstomqtt.service` into `/etc/systemd/system/`.
301
+ 4. Reload `systemd`.
302
+
303
+ Enable and start the service:
304
+ ```bash
305
+ sudo systemctl enable sensehatsensorstomqtt
306
+ sudo systemctl start sensehatsensorstomqtt
307
+ ```
308
+
309
+ Check status and follow live logs:
310
+ ```bash
311
+ sudo systemctl status sensehatsensorstomqtt
312
+ journalctl -u sensehatsensorstomqtt -f
313
+ ```
314
+
315
+ ---
316
+
317
+ ## Troubleshooting
318
+
319
+ ### `ModuleNotFoundError: No module named 'RTIMU'`
320
+ - **Cause**: The native `RTIMULib` C library from Raspberry Pi OS is missing, or the virtual environment was created without access to system site-packages.
321
+ - **Fix**: Install the apt package and recreate the virtual environment:
322
+ ```bash
323
+ sudo apt-get install -y python3-sense-hat
324
+ make clean && make install
325
+ ```
326
+
327
+ ### `PermissionError: [Errno 13] Permission denied: '/dev/i2c-1'`
328
+ - **Cause**: The current user or service account lacks permissions to access the I2C device bus.
329
+ - **Fix**: Add your user to the necessary hardware groups:
330
+ ```bash
331
+ sudo usermod -aG i2c,video,input $USER
332
+ ```
333
+ *(Log out and back in for group changes to take effect).*
334
+
335
+ ### `ConnectionRefusedError` or MQTT Publish Timeout
336
+ - **Cause**: The broker is unreachable, offline, or rejecting credentials.
337
+ - **Fix**: Verify your broker address and port with `ping` or `mosquitto_sub`:
338
+ ```bash
339
+ mosquitto_sub -h <broker-ip> -p 1883 -u <user> -P <pass> -t "test"
340
+ ```
341
+
342
+ ### LED Matrix is Dark During the Day
343
+ - **Cause**: Check if `night_start` and `night_end` match your system timezone. Ensure system time is correct:
344
+ ```bash
345
+ timedatectl
346
+ ```
347
+ Or check if `--no-display` or `display: false` was set in your configuration.
348
+
349
+ <p align="right">
350
+ <a href="https://www.buymeacoffee.com/olofhellqvc">
351
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me a Coffee" height="48">
352
+ </a>
353
+ </p>