feat: add the foundation files with a working script
This commit is contained in:
11
.dockerignore
Normal file
11
.dockerignore
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
.env
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
Dockerfile
|
||||||
|
README.md
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
sensor_data.json
|
||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Use an official Python runtime as a parent image
|
||||||
|
FROM python:3.9-slim
|
||||||
|
|
||||||
|
# Set the working directory in the container
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the dependencies file to the working directory
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# Install any needed packages specified in requirements.txt
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copy the rest of the application
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Run main.py when the container launches
|
||||||
|
CMD ["python", "main.py"]
|
||||||
43
README.md
Normal file
43
README.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Home Assistant Logger
|
||||||
|
|
||||||
|
This script connects to a Home Assistant instance, fetches temperature and humidity data, stores it, and generates an HTML report.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Docker
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
### 1. Build the Docker Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t ha-logger .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Run the Docker Container
|
||||||
|
|
||||||
|
You need to provide your Home Assistant URL and a Long-Lived Access Token as environment variables.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -v $(pwd):/app
|
||||||
|
-e HA_URL="http://your-home-assistant-ip:8123"
|
||||||
|
-e HA_TOKEN="your-long-lived-access-token"
|
||||||
|
ha-logger
|
||||||
|
```
|
||||||
|
|
||||||
|
- Replace `"http://your-home-assistant-ip:8123"` with the URL of your Home Assistant instance.
|
||||||
|
- Replace `"your-long-lived-access-token"` with your token.
|
||||||
|
|
||||||
|
The `-v $(pwd):/app` command mounts the current directory into the container, so the output files (`index.html` and `sensor_data.json`) are created and updated in your project folder.
|
||||||
|
|
||||||
|
### How it Works
|
||||||
|
|
||||||
|
- The script connects to your Home Assistant instance using the provided URL and token.
|
||||||
|
- It fetches all devices and filters for sensors that have a unit of `°C` (Celsius) or `%` (for humidity).
|
||||||
|
- The new readings are appended to the `sensor_data.json` file.
|
||||||
|
- An `index.html` file is generated, displaying the latest readings and a searchable, sortable history of all readings.
|
||||||
|
|
||||||
|
### Generated Files
|
||||||
|
|
||||||
|
- **`sensor_data.json`**: Stores the historical data for all sensor readings.
|
||||||
|
- **`index.html`**: The generated HTML report. Open this file in your browser to see the sensor data.
|
||||||
576
index.html
Normal file
576
index.html
Normal file
@ -0,0 +1,576 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Home Assistant Sensor Readings</title>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body { font-family: sans-serif; }
|
||||||
|
table { border-collapse: collapse; width: 100%; }
|
||||||
|
th, td { border: 1px solid #ddd; padding: 8px; }
|
||||||
|
th { background-color: #f2f2f2; }
|
||||||
|
.sort:hover { cursor: pointer; background-color: #e6e6e6; }
|
||||||
|
input { padding: 8px; margin-bottom: 10px; width: 100%; box-sizing: border-box; }
|
||||||
|
.temp-row { background-color: #ffe0b2; } /* Light orange for temperature */
|
||||||
|
.humidity-row { background-color: #b3e5fc; } /* Light blue for humidity */
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Last updated: 2026-01-25 09:40:05</p>
|
||||||
|
|
||||||
|
<h1>Recent Sensor Readings</h1>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Entity ID</th>
|
||||||
|
<th>Friendly Name</th>
|
||||||
|
<th>State</th>
|
||||||
|
<th>Unit</th>
|
||||||
|
<th>Last Updated</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td>sensor.kuchnia_czujnik_klimatu_temperatura</td>
|
||||||
|
<td>Kuchnia Czujnik Klimatu Temperatura</td>
|
||||||
|
<td>21.8</td>
|
||||||
|
<td>°C</td>
|
||||||
|
<td>2026-01-25T08:35:10.975179+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td>sensor.kuchnia_czujnik_klimatu_wilgotnosc</td>
|
||||||
|
<td>Kuchnia Czujnik Klimatu Wilgotność</td>
|
||||||
|
<td>31.6</td>
|
||||||
|
<td>%</td>
|
||||||
|
<td>2026-01-25T08:38:41.244256+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td>sensor.czujnik_klimatu_salon_temperatura</td>
|
||||||
|
<td>Czujnik Klimatu Salon Temperatura</td>
|
||||||
|
<td>22.2</td>
|
||||||
|
<td>°C</td>
|
||||||
|
<td>2026-01-25T07:55:35.936876+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td>sensor.czujnik_klimatu_salon_wilgotnosc</td>
|
||||||
|
<td>Czujnik Klimatu Salon Wilgotność</td>
|
||||||
|
<td>26.8</td>
|
||||||
|
<td>%</td>
|
||||||
|
<td>2026-01-25T08:23:14.904455+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td>sensor.czujnik_klimatu_gora_front_temperatura</td>
|
||||||
|
<td>Czujnik Klimatu Góra Front Temperatura</td>
|
||||||
|
<td>20.4</td>
|
||||||
|
<td>°C</td>
|
||||||
|
<td>2026-01-25T08:07:11.830919+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td>sensor.czujnik_klimatu_gora_front_wilgotnosc</td>
|
||||||
|
<td>Czujnik Klimatu Góra Front Wilgotność</td>
|
||||||
|
<td>25.8</td>
|
||||||
|
<td>%</td>
|
||||||
|
<td>2026-01-25T08:28:17.305597+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td>sensor.czujnik_klimatu_gora_tyl_temperatura</td>
|
||||||
|
<td>Czujnik Klimatu Góra Tył Temperatura</td>
|
||||||
|
<td>19.4</td>
|
||||||
|
<td>°C</td>
|
||||||
|
<td>2026-01-25T08:06:49.620048+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td>sensor.czujnik_klimatu_gora_tyl_wilgotnosc</td>
|
||||||
|
<td>Czujnik Klimatu Góra Tył Wilgotność</td>
|
||||||
|
<td>27.4</td>
|
||||||
|
<td>%</td>
|
||||||
|
<td>2026-01-25T08:02:24.184686+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td>sensor.czujnik_klimatu_kotlownia_temperatura</td>
|
||||||
|
<td>Czujnik Klimatu Kotłownia Temperatura</td>
|
||||||
|
<td>20.3</td>
|
||||||
|
<td>°C</td>
|
||||||
|
<td>2026-01-25T08:30:37.760046+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td>sensor.czujnik_klimatu_kotlownia_wilgotnosc</td>
|
||||||
|
<td>Czujnik Klimatu Kotłownia Wilgotność</td>
|
||||||
|
<td>24.2</td>
|
||||||
|
<td>%</td>
|
||||||
|
<td>2026-01-25T08:18:35.511162+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td>sensor.czujnik_klimatu_na_zewnatrz_temperatura</td>
|
||||||
|
<td>Czujnik Klimatu Na Zewnątrz Temperatura</td>
|
||||||
|
<td>0.6</td>
|
||||||
|
<td>°C</td>
|
||||||
|
<td>2026-01-25T08:38:14.361984+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td>sensor.czujnik_klimatu_na_zewnatrz_wilgotnosc</td>
|
||||||
|
<td>Czujnik Klimatu Na Zewnątrz Wilgotność</td>
|
||||||
|
<td>82.1</td>
|
||||||
|
<td>%</td>
|
||||||
|
<td>2026-01-25T08:27:38.801311+00:00</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h1>Historical Sensor Readings</h1>
|
||||||
|
<div id="historical-data">
|
||||||
|
<input class="search" placeholder="Search" />
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sort" data-sort="entity_id">Entity ID</th>
|
||||||
|
<th class="sort" data-sort="friendly_name">Friendly Name</th>
|
||||||
|
<th class="sort" data-sort="state">State</th>
|
||||||
|
<th class="sort" data-sort="unit">Unit</th>
|
||||||
|
<th class="sort" data-sort="timestamp">Timestamp</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list">
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_bateria</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_temperatura</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Temperatura</td>
|
||||||
|
<td class="state">21.7</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Wilgotność</td>
|
||||||
|
<td class="state">29.4</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Temperatura</td>
|
||||||
|
<td class="state">22.2</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Wilgotność</td>
|
||||||
|
<td class="state">26.8</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Temperatura</td>
|
||||||
|
<td class="state">20.4</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Wilgotność</td>
|
||||||
|
<td class="state">25.8</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Temperatura</td>
|
||||||
|
<td class="state">19.4</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Wilgotność</td>
|
||||||
|
<td class="state">27.4</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Temperatura</td>
|
||||||
|
<td class="state">20.3</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Wilgotność</td>
|
||||||
|
<td class="state">24.2</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Temperatura</td>
|
||||||
|
<td class="state">0.3</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Wilgotność</td>
|
||||||
|
<td class="state">82.1</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_ruchu_taras_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Ruchu Taras Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.ewelink_snzb_03p_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Ruchu Garaże Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:33:39.202329</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_bateria</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_temperatura</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Temperatura</td>
|
||||||
|
<td class="state">21.8</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Wilgotność</td>
|
||||||
|
<td class="state">32.6</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Temperatura</td>
|
||||||
|
<td class="state">22.2</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Wilgotność</td>
|
||||||
|
<td class="state">26.8</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Temperatura</td>
|
||||||
|
<td class="state">20.4</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Wilgotność</td>
|
||||||
|
<td class="state">25.8</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Temperatura</td>
|
||||||
|
<td class="state">19.4</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Wilgotność</td>
|
||||||
|
<td class="state">27.4</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Temperatura</td>
|
||||||
|
<td class="state">20.3</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Wilgotność</td>
|
||||||
|
<td class="state">24.2</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Temperatura</td>
|
||||||
|
<td class="state">0.3</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Wilgotność</td>
|
||||||
|
<td class="state">82.1</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_ruchu_taras_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Ruchu Taras Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.ewelink_snzb_03p_bateria</td>
|
||||||
|
<td class="friendly_name">Czujnik Ruchu Garaże Bateria</td>
|
||||||
|
<td class="state">100.0</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:37:31.559000</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_temperatura</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Temperatura</td>
|
||||||
|
<td class="state">21.8</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.kuchnia_czujnik_klimatu_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Kuchnia Czujnik Klimatu Wilgotność</td>
|
||||||
|
<td class="state">31.6</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Temperatura</td>
|
||||||
|
<td class="state">22.2</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_salon_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Salon Wilgotność</td>
|
||||||
|
<td class="state">26.8</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Temperatura</td>
|
||||||
|
<td class="state">20.4</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_front_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Front Wilgotność</td>
|
||||||
|
<td class="state">25.8</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Temperatura</td>
|
||||||
|
<td class="state">19.4</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_gora_tyl_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Góra Tył Wilgotność</td>
|
||||||
|
<td class="state">27.4</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Temperatura</td>
|
||||||
|
<td class="state">20.3</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_kotlownia_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Kotłownia Wilgotność</td>
|
||||||
|
<td class="state">24.2</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="temp-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_temperatura</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Temperatura</td>
|
||||||
|
<td class="state">0.6</td>
|
||||||
|
<td class="unit">°C</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="humidity-row">
|
||||||
|
<td class="entity_id">sensor.czujnik_klimatu_na_zewnatrz_wilgotnosc</td>
|
||||||
|
<td class="friendly_name">Czujnik Klimatu Na Zewnątrz Wilgotność</td>
|
||||||
|
<td class="state">82.1</td>
|
||||||
|
<td class="unit">%</td>
|
||||||
|
<td class="timestamp">2026-01-25T09:40:05.881503</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var options = {
|
||||||
|
valueNames: [ 'entity_id', 'friendly_name', 'state', 'unit', 'timestamp' ]
|
||||||
|
};
|
||||||
|
var historicalList = new List('historical-data', options);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
103
main.py
Normal file
103
main.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# --- Configuration ---
|
||||||
|
HA_URL = os.environ.get("HA_URL")
|
||||||
|
HA_TOKEN = os.environ.get("HA_TOKEN")
|
||||||
|
DATA_FILE = "sensor_data.json"
|
||||||
|
HTML_FILE = "index.html"
|
||||||
|
TEMPLATE_DIR = "templates"
|
||||||
|
|
||||||
|
# --- Error Handling ---
|
||||||
|
if not HA_URL or not HA_TOKEN:
|
||||||
|
raise ValueError("HA_URL and HA_TOKEN environment variables must be set.")
|
||||||
|
|
||||||
|
# --- Functions ---
|
||||||
|
|
||||||
|
def get_ha_data():
|
||||||
|
"""Fetches all states from Home Assistant and filters for temp/humidity sensors."""
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {HA_TOKEN}",
|
||||||
|
"content-type": "application/json",
|
||||||
|
}
|
||||||
|
url = f"{HA_URL}/api/states"
|
||||||
|
try:
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
response.raise_for_status() # Raise an exception for bad status codes
|
||||||
|
states = response.json()
|
||||||
|
|
||||||
|
sensors = [
|
||||||
|
s for s in states
|
||||||
|
if "unit_of_measurement" in s["attributes"] and (
|
||||||
|
s["attributes"]["unit_of_measurement"] == "°C" or
|
||||||
|
(s["attributes"]["unit_of_measurement"] == "%" and
|
||||||
|
s["attributes"].get("device_class") != "battery")
|
||||||
|
)
|
||||||
|
]
|
||||||
|
return sensors
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"Error connecting to Home Assistant: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def read_historical_data():
|
||||||
|
"""Reads historical sensor data from the JSON file."""
|
||||||
|
if not os.path.exists(DATA_FILE):
|
||||||
|
return []
|
||||||
|
with open(DATA_FILE, "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
def write_historical_data(new_data):
|
||||||
|
"""Appends new sensor data to the historical record."""
|
||||||
|
historical_data = read_historical_data()
|
||||||
|
timestamp = datetime.now().isoformat()
|
||||||
|
|
||||||
|
for sensor in new_data:
|
||||||
|
historical_data.append({
|
||||||
|
"entity_id": sensor["entity_id"],
|
||||||
|
"friendly_name": sensor["attributes"].get("friendly_name", sensor["entity_id"]),
|
||||||
|
"state": sensor["state"],
|
||||||
|
"unit": sensor["attributes"].get("unit_of_measurement"),
|
||||||
|
"timestamp": timestamp,
|
||||||
|
})
|
||||||
|
|
||||||
|
with open(DATA_FILE, "w") as f:
|
||||||
|
json.dump(historical_data, f, indent=4)
|
||||||
|
|
||||||
|
def generate_html_report(recent_data, historical_data, last_updated_time):
|
||||||
|
"""Generates an HTML report from the sensor data."""
|
||||||
|
env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))
|
||||||
|
template = env.get_template("index.html.j2")
|
||||||
|
|
||||||
|
html_content = template.render(
|
||||||
|
recent_data=recent_data,
|
||||||
|
historical_data=historical_data,
|
||||||
|
last_updated_time=last_updated_time
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(HTML_FILE, "w") as f:
|
||||||
|
f.write(html_content)
|
||||||
|
print(f"Successfully generated HTML report: {HTML_FILE}")
|
||||||
|
|
||||||
|
# --- Main Execution ---
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function to run the script."""
|
||||||
|
print("Fetching data from Home Assistant...")
|
||||||
|
recent_sensor_data = get_ha_data()
|
||||||
|
|
||||||
|
if recent_sensor_data:
|
||||||
|
print(f"Found {len(recent_sensor_data)} temperature/humidity sensors.")
|
||||||
|
write_historical_data(recent_sensor_data)
|
||||||
|
historical_data = read_historical_data()
|
||||||
|
last_updated_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
generate_html_report(recent_sensor_data, historical_data, last_updated_time)
|
||||||
|
else:
|
||||||
|
print("Could not fetch new data. Report generation skipped.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
requests
|
||||||
|
Jinja2
|
||||||
80
templates/index.html.j2
Normal file
80
templates/index.html.j2
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Home Assistant Sensor Readings</title>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body { font-family: sans-serif; }
|
||||||
|
table { border-collapse: collapse; width: 100%; }
|
||||||
|
th, td { border: 1px solid #ddd; padding: 8px; }
|
||||||
|
th { background-color: #f2f2f2; }
|
||||||
|
.sort:hover { cursor: pointer; background-color: #e6e6e6; }
|
||||||
|
input { padding: 8px; margin-bottom: 10px; width: 100%; box-sizing: border-box; }
|
||||||
|
.temp-row { background-color: #ffe0b2; } /* Light orange for temperature */
|
||||||
|
.humidity-row { background-color: #b3e5fc; } /* Light blue for humidity */
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Last updated: {{ last_updated_time }}</p>
|
||||||
|
|
||||||
|
<h1>Recent Sensor Readings</h1>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Entity ID</th>
|
||||||
|
<th>Friendly Name</th>
|
||||||
|
<th>State</th>
|
||||||
|
<th>Unit</th>
|
||||||
|
<th>Last Updated</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for sensor in recent_data %}
|
||||||
|
<tr class="{% if sensor.attributes.unit_of_measurement == '°C' %}temp-row{% elif sensor.attributes.unit_of_measurement == '%' %}humidity-row{% endif %}">
|
||||||
|
<td>{{ sensor.entity_id }}</td>
|
||||||
|
<td>{{ sensor.attributes.friendly_name }}</td>
|
||||||
|
<td>{{ sensor.state }}</td>
|
||||||
|
<td>{{ sensor.attributes.unit_of_measurement }}</td>
|
||||||
|
<td>{{ sensor.last_updated }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h1>Historical Sensor Readings</h1>
|
||||||
|
<div id="historical-data">
|
||||||
|
<input class="search" placeholder="Search" />
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="sort" data-sort="entity_id">Entity ID</th>
|
||||||
|
<th class="sort" data-sort="friendly_name">Friendly Name</th>
|
||||||
|
<th class="sort" data-sort="state">State</th>
|
||||||
|
<th class="sort" data-sort="unit">Unit</th>
|
||||||
|
<th class="sort" data-sort="timestamp">Timestamp</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list">
|
||||||
|
{% for reading in historical_data %}
|
||||||
|
<tr class="{% if reading.unit == '°C' %}temp-row{% elif reading.unit == '%' %}humidity-row{% endif %}">
|
||||||
|
<td class="entity_id">{{ reading.entity_id }}</td>
|
||||||
|
<td class="friendly_name">{{ reading.friendly_name }}</td>
|
||||||
|
<td class="state">{{ reading.state }}</td>
|
||||||
|
<td class="unit">{{ reading.unit }}</td>
|
||||||
|
<td class="timestamp">{{ reading.timestamp }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var options = {
|
||||||
|
valueNames: [ 'entity_id', 'friendly_name', 'state', 'unit', 'timestamp' ]
|
||||||
|
};
|
||||||
|
var historicalList = new List('historical-data', options);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user