diff --git a/.github/workflows/build-hub-server.yml b/.github/workflows/build-hub-server.yml index 678be37..3e2487a 100644 --- a/.github/workflows/build-hub-server.yml +++ b/.github/workflows/build-hub-server.yml @@ -39,7 +39,20 @@ jobs: echo "CONTEXT=./hub-server" >> $GITHUB_ENV echo "IMAGE_NAME=ghcr.io/devoldschool/powermeter_hub_server/hub-server" >> $GITHUB_ENV - # Step 5: Determine tags + # Step 5: Generate version + - name: Generate version + id: version + run: | + if [ "${{ github.event_name }}" = "release" ]; then + VERSION="${{ github.event.release.tag_name }}" + else + VERSION="dev-${GITHUB_SHA::8}" + fi + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "Writing version $VERSION to __version__.py" + echo "__version__ = \"$VERSION\"" > hub-server/__version__.py + + # Step 6: Determine tags - name: Determine tags run: | TAGS="${{ env.IMAGE_NAME }}:latest,${{ env.IMAGE_NAME }}:${GITHUB_SHA}" @@ -48,7 +61,7 @@ jobs: fi echo "TAGS=$TAGS" >> $GITHUB_ENV - # Step 6: Build and push Docker image + # Step 7: Build and push Docker image - name: Build & Push uses: docker/build-push-action@v5 with: @@ -57,4 +70,5 @@ jobs: push: true tags: ${{ env.TAGS }} labels: | - org.opencontainers.image.description=PowerMeter Hub Server. \ No newline at end of file + org.opencontainers.image.description=PowerMeter Hub Server. + org.opencontainers.image.version=${{ env.VERSION }} diff --git a/README.md b/README.md index b0a61e3..2f2027e 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,17 @@ server: local-data: "aa.bb.cc.dddddd.keys.sensornet.info 86400 IN A 10.0.0.213" ``` +## Data Formats and Units + +**MQTT payloads:** +- **Power**: Raw sensor values (h1/h2: milliamps; h3: deciwatts). + - See below for conversion to Watts. +- **Energy**: Kilowatt-hours (kWh) + +**For Home Assistant users**: When MQTT discovery is *enabled*, Home Assistant automatically converts Power readings to watts using the `value_template` included in discovery messages. + +**For other MQTT consumers**: You must apply the conversion yourself. Formulas are in `config.py`. + ## Home Assistant Integration ### Home Assistant Operating System hosted @@ -137,16 +148,19 @@ HA_DISCOVERY=true With `HA_DISCOVERY=true`, the hub-server will automatically publish Home Assistant MQTT discovery payloads. This creates two sensors per Efergy device: -| Sensor | Topic | Unit | Device Class | State Class | -|------------------------------------------|-------------------------------------|------|--------------|------------------| -| `sensor.efergy_hub_live_power_usage_SID` | `home/efergy//power` | kW | power | measurement | -| `sensor.efergy_hub__energy_consumption` | `home/efergy//energy` | kWh | energy | total_increasing | +| Sensor | Topic | Unit | Device Class | State Class | +|----------------------------------------|-----------------------------------------|------|--------------|------------------| +| `sensor.efergy_hub_power_` | `home/efergy/efergy_h_/power` | W | power | measurement | +| `sensor.efergy_hub_energy_consumption` | `home/efergy/energy_consumption/energy` | kWh | energy | total_increasing | +> **Note**: +> MQTT payloads for power are raw values, but Home Assistant applies the necessary conversion to Watts automatically. See the [Data Formats and Units](#data-formats-and-units) section for details. Home Assistant will pick up these sensors automatically, making them available for dashboards, automations, and the Energy Dashboard. 3. Add Sensors to Energy Dashboard -Once discovered, the `sensor.efergy_energy_consumption` sensor can be added to Home Assistant’s Energy Dashboard under Grid Consumption, allowing you to track daily, weekly, and monthly usage. + +Once discovered, the `sensor.efergy_hub_energy_consumption` sensor can be added to Home Assistant’s Energy Dashboard under Grid Consumption, allowing you to track daily, weekly, and monthly usage. ### Container hosted @@ -181,7 +195,7 @@ sql: !include sensors.yaml 5. **Restart Home Assistant**. You will now have two sensors: -* `sensor.efergy_hub_live_power_usage_SID`: The instantaneous power reading in kW. +* `sensor.efergy_hub_power_`: The instantaneous power reading in W. * `sensor.efergy_hub_energy_consumption`: A running total of energy consumed in kWh, which can be added directly to your Home Assistant Energy Dashboard. @@ -192,4 +206,6 @@ You will now have two sensors: ## Efergy Data Format -Documentation about the known data formats is within the [Wiki](https://github.com/DevOldSchool/powermeter_hub_server/wiki/Hub-v2-v3-Data-Format). +Documentation about the known hub payload formats and data structures: +- [Hub v1 Data Format](https://github.com/DevOldSchool/powermeter_hub_server/wiki/Hub-V1-Data-Format) +- [Hub v2/v3 Data Format](https://github.com/DevOldSchool/powermeter_hub_server/wiki/Hub-v2-v3-Data-Format) diff --git a/hub-server/Dockerfile b/hub-server/Dockerfile index 55ee866..40d94ce 100644 --- a/hub-server/Dockerfile +++ b/hub-server/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-slim +FROM python:3.14-slim LABEL org.opencontainers.image.description="PowerMeter Hub Server." diff --git a/hub-server/__version__.py b/hub-server/__version__.py new file mode 100644 index 0000000..0fbe14e --- /dev/null +++ b/hub-server/__version__.py @@ -0,0 +1,5 @@ +# Auto-generated during build by GitHub Actions +# Do not edit manually - this file is overwritten during CI/CD build +__version__ = "dev-local" + + diff --git a/hub-server/hub_server.py b/hub-server/hub_server.py index 6545652..788c1ce 100755 --- a/hub-server/hub_server.py +++ b/hub-server/hub_server.py @@ -6,6 +6,7 @@ """ import logging import socket +import sys from http.server import HTTPServer, SimpleHTTPRequestHandler from typing import Type from urllib.parse import urlparse, parse_qs @@ -14,8 +15,9 @@ from mqtt_manager import MQTTManager from aggregator import Aggregator from payload_parser import parse_sensor_payload +from __version__ import __version__ from config import ( - SERVER_PORT, LOG_LEVEL + SERVER_PORT, LOG_LEVEL, MQTT_ENABLED, HA_DISCOVERY ) class EfergyHTTPServer(HTTPServer): @@ -243,6 +245,17 @@ def run_server(database: Database, host: str = '0.0.0.0', port: int = 5000): format="%(asctime)s [%(levelname)s] %(filename)s:%(lineno)d - %(message)s", ) + # Startup banner + logging.info("=" * 60) + logging.info(" Efergy Hub Server") + logging.info(f" Version: {__version__}") + logging.info("=" * 60) + logging.info(f" Python: {sys.version.split()[0]}") + logging.info(f" Port: {SERVER_PORT}") + logging.info(f" MQTT: {'enabled' if MQTT_ENABLED else 'disabled'}") + logging.info(f" HA Discovery: {'enabled' if HA_DISCOVERY else 'disabled'}") + logging.info("=" * 60) + # Adjust this path as needed for your project structure DB_FILE_PATH = Path(__file__).resolve().parent / "data/readings.db" diff --git a/hub-server/mqtt_manager.py b/hub-server/mqtt_manager.py index ecf0caa..6a7029d 100644 --- a/hub-server/mqtt_manager.py +++ b/hub-server/mqtt_manager.py @@ -129,7 +129,7 @@ def publish_power_discovery(self, label: str, sid: str, topic: str, hub_version: unit_of_measurement = POWER_UNIT_OF_MEASUREMENT_H3 value_template = POWER_VALUE_TEMPLATE_H3 else: - unit_of_measurement = "kW" + unit_of_measurement = "W" value_template = "{{ (value_json.value | float) }}" payload = {