diff --git a/README.md b/README.md index 4f91bf0..182bcb3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,104 @@ # gazpar2haws -Gazpar2HAWS is a gateway that reads data history from the GrDF (French gas provider) meter and send it to Home Assistant using WebSocket interface +Gazpar2HAWS is a gateway that reads data history from the GrDF (French gas provider) meter and send it to Home Assistant using WebSocket interface. + +It is compatible with Home Assistant Energy Dashboard and permits to upload the history and keep it updated with the latest readings. + +## Installation + +Gazpar2HAWS can be installed on any host as a standalone program. + +### 1. Using source files + +The project requires [Poetry](https://python-poetry.org/) tool for dependency and package management. + +```sh +$ cd /path/to/my_install_folder/ + +$ git clone https://github.com/ssenart/gazpar2haws.git + +$ cd gazpar2haws + +$ poetry install + +$ poetry shell + +``` + +### 2. Using PIP package + +```sh +$ cd /path/to/my_install_folder/ + +$ mkdir gazpar2haws + +$ cd gazpar2haws + +$ python -m venv .venv + +$ source .venv/bin/activate + +$ pip install gazpar2haws + +``` + +## Usage + +### Command line + +```sh +$ python -m gazpar2haws --config /path/to/configuration.yaml --secrets /path/to/secrets.yaml +``` + +### Configuration file + +The default configuration file is below. + +```yaml +logging: + file: log/gazpar2haws.log + console: true + level: debug + format: '%(asctime)s %(levelname)s [%(name)s] %(message)s' + +grdf: + scan_interval: 0 # Number of minutes between each data retrieval (0 means no scan: a single data retrieval at startup, then stops). + devices: + - name: gazpar2haws + username: "!secret grdf.username" + password: "!secret grdf.password" + pce_identifier: "!secret grdf.pce_identifier" + timezone: Europe/Paris + last_days: 365 # Number of days of data to retrieve + reset: false # If true, the data will be reset before the first data retrieval + +homeassistant: + host: "!secret homeassistant.host" + port: "!secret homeassistant.port" + token: "!secret homeassistant.token" +``` + +The default secret file: + +```yaml +grdf.username: ${GRDF_USERNAME} +grdf.password: ${GRDF_PASSWORD} +grdf.pce_identifier: ${GRDF_PCE_IDENTIFIER} + +homeassistant.host: ${HA_HOST} +homeassistant.port: ${HA_PORT} +homeassistant.token: ${HA_TOKEN} +``` + +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. + +## License +[MIT](https://choosealicense.com/licenses/mit/) + +## Project status +Gazpar2HAWS has been initiated for integration with [Home Assistant](https://www.home-assistant.io/) energy dashboard. + + + diff --git a/config/configuration.yaml b/config/configuration.yaml index 99eff49..b3d0003 100644 --- a/config/configuration.yaml +++ b/config/configuration.yaml @@ -1,22 +1,21 @@ logging: file: log/gazpar2haws.log console: true - level: debug + level: info format: '%(asctime)s %(levelname)s [%(name)s] %(message)s' grdf: - scan_interval: 0 # Number of minutes between each data retrieval (0 means no scan: a single data retrieval at startup, then stops). + scan_interval: 1440 # Number of minutes between each data retrieval (0 means no scan: a single data retrieval at startup, then stops). devices: - - name: gazpar2haws + - name: gazpar2haws # Name of the device in home assistant. It will be used as the entity_id: sensor.${name}. username: "!secret grdf.username" password: "!secret grdf.password" pce_identifier: "!secret grdf.pce_identifier" timezone: Europe/Paris - last_days: 365 # Number of days of data to retrieve - reset: true # If true, the data will be reset before the first data retrieval + last_days: 365 # Number of days of data to retrieve. + reset: false # If true, the data will be reset before the first data retrieval. If false, the data will be kept and new data will be added. homeassistant: host: "!secret homeassistant.host" port: "!secret homeassistant.port" token: "!secret homeassistant.token" - diff --git a/gazpar2haws/__init__.py b/gazpar2haws/__init__.py index e69de29..ed94b7e 100644 --- a/gazpar2haws/__init__.py +++ b/gazpar2haws/__init__.py @@ -0,0 +1 @@ +from gazpar2haws.version import __version__ # noqa: F401 \ No newline at end of file diff --git a/gazpar2haws/__main__.py b/gazpar2haws/__main__.py index d8675a5..39681fd 100644 --- a/gazpar2haws/__main__.py +++ b/gazpar2haws/__main__.py @@ -1,16 +1,16 @@ -import sys +import asyncio import argparse import logging import traceback -from gazpar2haws import __version__ from gazpar2haws import config_utils +from gazpar2haws import __version__ from gazpar2haws.bridge import Bridge Logger = logging.getLogger(__name__) # ---------------------------------- -def main(): +async def main(): """Main function""" parser = argparse.ArgumentParser(prog="gazpar2haws", description="Gateway that reads data history from the GrDF (French gas provider) meter and send it to Home Assistant using WebSocket interface.") parser.add_argument("-v", "--version", @@ -73,7 +73,7 @@ def main(): # Start the bridge bridge = Bridge(config) - bridge.run() + await bridge.run() Logger.info("Gazpar2HAWS stopped.") @@ -88,4 +88,4 @@ def main(): # ---------------------------------- if __name__ == '__main__': - sys.exit(main()) + asyncio.run(main()) diff --git a/gazpar2haws/bridge.py b/gazpar2haws/bridge.py index 6609152..dc6c411 100644 --- a/gazpar2haws/bridge.py +++ b/gazpar2haws/bridge.py @@ -47,14 +47,15 @@ def handle_signal(self, signum, frame): # ---------------------------------- async def run(self): - # Connect to Home Assistant - await self._homeassistant.connect() - # Set running flag self._running = True try: while self._running: + + # Connect to Home Assistant + await self._homeassistant.connect() + # Publish Gazpar data to Home Assistant WS Logger.info("Publishing Gazpar data to Home Assistant WS...") @@ -65,6 +66,9 @@ async def run(self): Logger.info("Gazpar data published to Home Assistant WS.") + # Disconnect from Home Assistant + await self._homeassistant.disconnect() + # Wait before next scan Logger.info(f"Waiting {self._grdf_scan_interval} minutes before next scan...") @@ -76,13 +80,6 @@ async def run(self): except KeyboardInterrupt: print("Keyboard interrupt detected. Shutting down gracefully...") Logger.info("Keyboard interrupt detected. Shutting down gracefully...") - finally: - await self.dispose() - - # ---------------------------------- - async def dispose(self): - # Stop the network loop - await self._homeassistant.disconnect() # ---------------------------------- async def _await_with_interrupt(self, total_sleep_time: int, check_interval: int): diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 0000000..2554cf1 --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,13 @@ +import pytest +from gazpar2haws import __main__ +import sys + + +# ---------------------------------- +@pytest.mark.asyncio +async def test_main(): + + # Simulate command line arguments + sys.argv = ["gazpar2haws", "-c", "config/configuration.yaml", "-s", "config/secrets.yaml"] + + await __main__.main()