gazpar2haws 0.1.7__py3-none-any.whl → 0.1.8.dev10__py3-none-any.whl

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.
gazpar2haws/__init__.py CHANGED
@@ -1 +1 @@
1
- from gazpar2haws.version import __version__ # noqa: F401
1
+ from gazpar2haws.version import __version__ # noqa: F401
gazpar2haws/__main__.py CHANGED
@@ -1,91 +1,91 @@
1
- import asyncio
2
- import argparse
3
- import logging
4
- import traceback
5
- from gazpar2haws import config_utils
6
- from gazpar2haws import __version__
7
- from gazpar2haws.bridge import Bridge
8
-
9
- Logger = logging.getLogger(__name__)
10
-
11
-
12
- # ----------------------------------
13
- async def main():
14
- """Main function"""
15
- 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.")
16
- parser.add_argument("-v", "--version",
17
- action="version",
18
- version="Gazpar2HAWS version")
19
- parser.add_argument("-c", "--config",
20
- required=False,
21
- default="config/configuration.yaml",
22
- help="Path to the configuration file")
23
- parser.add_argument("-s", "--secrets",
24
- required=False,
25
- default="config/secrets.yaml",
26
- help="Path to the secret file")
27
-
28
- args = parser.parse_args()
29
-
30
- try:
31
- # Load configuration files
32
- config = config_utils.ConfigLoader(args.config, args.secrets)
33
- config.load_secrets()
34
- config.load_config()
35
-
36
- print(f"Gazpar2HAWS version: {__version__}")
37
-
38
- # Set up logging
39
- logging_file = config.get("logging.file")
40
- logging_console = bool(config.get("logging.console"))
41
- logging_level = config.get("logging.level")
42
- logging_format = config.get("logging.format")
43
-
44
- # Convert logging level to integer
45
- if logging_level.upper() == "DEBUG":
46
- level = logging.DEBUG
47
- elif logging_level.upper() == "INFO":
48
- level = logging.INFO
49
- elif logging_level.upper() == "WARNING":
50
- level = logging.WARNING
51
- elif logging_level.upper() == "ERROR":
52
- level = logging.ERROR
53
- elif logging_level.upper() == "CRITICAL":
54
- level = logging.CRITICAL
55
- else:
56
- level = logging.INFO
57
-
58
- logging.basicConfig(filename=logging_file, level=level, format=logging_format)
59
-
60
- if logging_console:
61
- # Add a console handler manually
62
- console_handler = logging.StreamHandler()
63
- console_handler.setLevel(level) # Set logging level for the console
64
- console_handler.setFormatter(logging.Formatter(logging_format)) # Customize console format
65
-
66
- # Get the root logger and add the console handler
67
- logging.getLogger().addHandler(console_handler)
68
-
69
- Logger.info(f"Starting Gazpar2HAWS version {__version__}")
70
-
71
- # Log configuration
72
- Logger.info(f"Configuration:\n{config.dumps()}")
73
-
74
- # Start the bridge
75
- bridge = Bridge(config)
76
- await bridge.run()
77
-
78
- Logger.info("Gazpar2HAWS stopped.")
79
-
80
- return 0
81
-
82
- except BaseException:
83
- errorMessage = f"An error occured while running Gazpar2HAWS: {traceback.format_exc()}"
84
- Logger.error(errorMessage)
85
- print(errorMessage)
86
- return 1
87
-
88
-
89
- # ----------------------------------
90
- if __name__ == '__main__':
91
- asyncio.run(main())
1
+ import asyncio
2
+ import argparse
3
+ import logging
4
+ import traceback
5
+ from gazpar2haws import config_utils
6
+ from gazpar2haws import __version__
7
+ from gazpar2haws.bridge import Bridge
8
+
9
+ Logger = logging.getLogger(__name__)
10
+
11
+
12
+ # ----------------------------------
13
+ async def main():
14
+ """Main function"""
15
+ 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.")
16
+ parser.add_argument("-v", "--version",
17
+ action="version",
18
+ version="Gazpar2HAWS version")
19
+ parser.add_argument("-c", "--config",
20
+ required=False,
21
+ default="config/configuration.yaml",
22
+ help="Path to the configuration file")
23
+ parser.add_argument("-s", "--secrets",
24
+ required=False,
25
+ default="config/secrets.yaml",
26
+ help="Path to the secret file")
27
+
28
+ args = parser.parse_args()
29
+
30
+ try:
31
+ # Load configuration files
32
+ config = config_utils.ConfigLoader(args.config, args.secrets)
33
+ config.load_secrets()
34
+ config.load_config()
35
+
36
+ print(f"Gazpar2HAWS version: {__version__}")
37
+
38
+ # Set up logging
39
+ logging_file = config.get("logging.file")
40
+ logging_console = bool(config.get("logging.console"))
41
+ logging_level = config.get("logging.level")
42
+ logging_format = config.get("logging.format")
43
+
44
+ # Convert logging level to integer
45
+ if logging_level.upper() == "DEBUG":
46
+ level = logging.DEBUG
47
+ elif logging_level.upper() == "INFO":
48
+ level = logging.INFO
49
+ elif logging_level.upper() == "WARNING":
50
+ level = logging.WARNING
51
+ elif logging_level.upper() == "ERROR":
52
+ level = logging.ERROR
53
+ elif logging_level.upper() == "CRITICAL":
54
+ level = logging.CRITICAL
55
+ else:
56
+ level = logging.INFO
57
+
58
+ logging.basicConfig(filename=logging_file, level=level, format=logging_format)
59
+
60
+ if logging_console:
61
+ # Add a console handler manually
62
+ console_handler = logging.StreamHandler()
63
+ console_handler.setLevel(level) # Set logging level for the console
64
+ console_handler.setFormatter(logging.Formatter(logging_format)) # Customize console format
65
+
66
+ # Get the root logger and add the console handler
67
+ logging.getLogger().addHandler(console_handler)
68
+
69
+ Logger.info(f"Starting Gazpar2HAWS version {__version__}")
70
+
71
+ # Log configuration
72
+ Logger.info(f"Configuration:\n{config.dumps()}")
73
+
74
+ # Start the bridge
75
+ bridge = Bridge(config)
76
+ await bridge.run()
77
+
78
+ Logger.info("Gazpar2HAWS stopped.")
79
+
80
+ return 0
81
+
82
+ except BaseException:
83
+ errorMessage = f"An error occured while running Gazpar2HAWS: {traceback.format_exc()}"
84
+ Logger.error(errorMessage)
85
+ print(errorMessage)
86
+ return 1
87
+
88
+
89
+ # ----------------------------------
90
+ if __name__ == '__main__':
91
+ asyncio.run(main())
@@ -1,56 +1,56 @@
1
- import yaml
2
- import os
3
-
4
-
5
- class ConfigLoader:
6
- def __init__(self, config_file="config.yaml", secrets_file="secrets.yaml"):
7
- self.config_file = config_file
8
- self.secrets_file = secrets_file
9
- self.config = {}
10
- self.secrets = {}
11
-
12
- def load_secrets(self):
13
- """Load the secrets file."""
14
- if os.path.exists(self.secrets_file):
15
- with open(self.secrets_file, 'r') as file:
16
- self.secrets = yaml.safe_load(file)
17
- else:
18
- raise FileNotFoundError(f"Secrets file '{self.secrets_file}' not found.")
19
-
20
- def load_config(self):
21
- """Load the main configuration file and resolve secrets."""
22
- if os.path.exists(self.config_file):
23
- with open(self.config_file, 'r', encoding='utf-8') as file:
24
- self.raw_config = yaml.safe_load(file)
25
- self.config = self._resolve_secrets(self.raw_config)
26
- else:
27
- raise FileNotFoundError(f"Configuration file '{self.config_file}' not found.")
28
-
29
- def _resolve_secrets(self, data):
30
- """Recursively resolve `!secret` keys in the configuration."""
31
- if isinstance(data, dict):
32
- return {key: self._resolve_secrets(value) for key, value in data.items()}
33
- elif isinstance(data, list):
34
- return [self._resolve_secrets(item) for item in data]
35
- elif isinstance(data, str) and data.startswith("!secret"):
36
- secret_key = data.split(" ", 1)[1]
37
- if secret_key in self.secrets:
38
- return self.secrets[secret_key]
39
- else:
40
- raise KeyError(f"Secret key '{secret_key}' not found in secrets file.")
41
- else:
42
- return data
43
-
44
- def get(self, key, default=None):
45
- """Get a configuration value."""
46
- keys = key.split(".")
47
- value = self.config
48
- try:
49
- for k in keys:
50
- value = value[k]
51
- return value
52
- except (KeyError, TypeError):
53
- return default
54
-
55
- def dumps(self) -> str:
56
- return yaml.dump(self.raw_config)
1
+ import yaml
2
+ import os
3
+
4
+
5
+ class ConfigLoader:
6
+ def __init__(self, config_file="config.yaml", secrets_file="secrets.yaml"):
7
+ self.config_file = config_file
8
+ self.secrets_file = secrets_file
9
+ self.config = {}
10
+ self.secrets = {}
11
+
12
+ def load_secrets(self):
13
+ """Load the secrets file."""
14
+ if os.path.exists(self.secrets_file):
15
+ with open(self.secrets_file, 'r') as file:
16
+ self.secrets = yaml.safe_load(file)
17
+ else:
18
+ raise FileNotFoundError(f"Secrets file '{self.secrets_file}' not found.")
19
+
20
+ def load_config(self):
21
+ """Load the main configuration file and resolve secrets."""
22
+ if os.path.exists(self.config_file):
23
+ with open(self.config_file, 'r', encoding='utf-8') as file:
24
+ self.raw_config = yaml.safe_load(file)
25
+ self.config = self._resolve_secrets(self.raw_config)
26
+ else:
27
+ raise FileNotFoundError(f"Configuration file '{self.config_file}' not found.")
28
+
29
+ def _resolve_secrets(self, data):
30
+ """Recursively resolve `!secret` keys in the configuration."""
31
+ if isinstance(data, dict):
32
+ return {key: self._resolve_secrets(value) for key, value in data.items()}
33
+ elif isinstance(data, list):
34
+ return [self._resolve_secrets(item) for item in data]
35
+ elif isinstance(data, str) and data.startswith("!secret"):
36
+ secret_key = data.split(" ", 1)[1]
37
+ if secret_key in self.secrets:
38
+ return self.secrets[secret_key]
39
+ else:
40
+ raise KeyError(f"Secret key '{secret_key}' not found in secrets file.")
41
+ else:
42
+ return data
43
+
44
+ def get(self, key, default=None):
45
+ """Get a configuration value."""
46
+ keys = key.split(".")
47
+ value = self.config
48
+ try:
49
+ for k in keys:
50
+ value = value[k]
51
+ return value
52
+ except (KeyError, TypeError):
53
+ return default
54
+
55
+ def dumps(self) -> str:
56
+ return yaml.dump(self.raw_config)
gazpar2haws/gazpar.py CHANGED
@@ -1,139 +1,139 @@
1
- import pygazpar
2
- import traceback
3
- import logging
4
- import pytz
5
- from typing import Any
6
- from datetime import datetime, timedelta
7
- from gazpar2haws.haws import HomeAssistantWS
8
-
9
- Logger = logging.getLogger(__name__)
10
-
11
-
12
- # ----------------------------------
13
- class Gazpar:
14
-
15
- # ----------------------------------
16
- def __init__(self, config: dict[str, Any], homeassistant: HomeAssistantWS):
17
-
18
- self._homeassistant = homeassistant
19
-
20
- # GrDF configuration
21
- self._name = config.get("name")
22
- self._username = config.get("username")
23
- self._password = config.get("password")
24
- self._pce_identifier = str(config.get("pce_identifier"))
25
- self._last_days = int(config.get("last_days"))
26
- self._timezone = config.get("timezone")
27
- self._reset = bool(config.get("reset"))
28
-
29
- # ----------------------------------
30
- def name(self):
31
- return self._name
32
-
33
- # ----------------------------------
34
- # Publish Gaspar data to Home Assistant WS
35
- async def publish(self):
36
-
37
- # Volume and energy sensor names.
38
- volume_sensor_name = f"sensor.{self._name}_volume"
39
- energy_sensor_name = f"sensor.{self._name}_energy"
40
-
41
- # Eventually reset the sensor in Home Assistant
42
- if self._reset:
43
- try:
44
- await self._homeassistant.clear_statistics([volume_sensor_name, energy_sensor_name])
45
- except Exception:
46
- errorMessage = f"Error while resetting the sensor in Home Assistant: {traceback.format_exc()}"
47
- Logger.warning(errorMessage)
48
- raise Exception(errorMessage)
49
-
50
- # Publish volume sensor
51
- await self._publish_entity(volume_sensor_name, pygazpar.PropertyName.VOLUME.value, "m³")
52
- await self._publish_entity(energy_sensor_name, pygazpar.PropertyName.ENERGY.value, "kWh")
53
-
54
- # ----------------------------------
55
- # Publish a sensor to Home Assistant
56
- async def _publish_entity(self, entity_id: str, property_name: str, unit_of_measurement: str):
57
-
58
- # Check the existence of the sensor in Home Assistant
59
- try:
60
- exists_statistic_id = await self._homeassistant.exists_statistic_id(entity_id, "sum")
61
- except Exception:
62
- errorMessage = f"Error while checking the existence of the sensor in Home Assistant: {traceback.format_exc()}"
63
- Logger.warning(errorMessage)
64
- raise Exception(errorMessage)
65
-
66
- if exists_statistic_id:
67
- # Get the last statistic from Home Assistant
68
- try:
69
- last_statistic = await self._homeassistant.get_last_statistic(entity_id)
70
- except Exception:
71
- errorMessage = f"Error while fetching last statistics from Home Assistant: {traceback.format_exc()}"
72
- Logger.warning(errorMessage)
73
- raise Exception(errorMessage)
74
-
75
- # Extract the end date of the last statistics from the unix timestamp
76
- last_date = datetime.fromtimestamp(last_statistic.get("start") / 1000, tz=pytz.timezone(self._timezone))
77
-
78
- # Compute the number of days since the last statistics
79
- last_days = (datetime.now(tz=pytz.timezone(self._timezone)) - last_date).days
80
-
81
- # Get the last meter value
82
- last_value = last_statistic.get("sum")
83
- else:
84
- # If the sensor does not exist in Home Assistant, fetch the last days defined in the configuration
85
- last_days = self._last_days
86
-
87
- # Compute the corresponding last_date
88
- last_date = datetime.now(tz=pytz.timezone(self._timezone)) - timedelta(days=last_days)
89
-
90
- # If no statistic, the last value is initialized to zero
91
- last_value = 0
92
-
93
- Logger.debug(f"Last date: {last_date}, last days: {last_days}, last value: {last_value}")
94
-
95
- # Initialize PyGazpar client
96
- client = pygazpar.Client(pygazpar.JsonWebDataSource(username=self._username, password=self._password))
97
-
98
- try:
99
- data = client.loadSince(pceIdentifier=self._pce_identifier, lastNDays=last_days, frequencies=[pygazpar.Frequency.DAILY])
100
- except Exception:
101
- errorMessage = f"Error while fetching data from GrDF: {traceback.format_exc()}"
102
- Logger.warning(errorMessage)
103
- data = {}
104
-
105
- # Timezone
106
- timezone = pytz.timezone(self._timezone)
107
-
108
- # Compute and fill statistics.
109
- daily = data.get(pygazpar.Frequency.DAILY.value)
110
- statistics = []
111
- total = last_value
112
- for reading in daily:
113
- # Parse date format DD/MM/YYYY into datetime.
114
- date = datetime.strptime(reading[pygazpar.PropertyName.TIME_PERIOD.value], "%d/%m/%Y")
115
-
116
- # Set the timezone
117
- date = timezone.localize(date)
118
-
119
- # Skip all readings before the last statistic date.
120
- if date <= last_date:
121
- Logger.debug(f"Skip date: {date} <= {last_date}")
122
- continue
123
-
124
- # Compute the total volume and energy
125
- total += reading[property_name]
126
-
127
- statistics.append({
128
- "start": date.isoformat(),
129
- "state": total,
130
- "sum": total
131
- })
132
-
133
- # Publish statistics to Home Assistant
134
- try:
135
- await self._homeassistant.import_statistics(entity_id, "recorder", "gazpar2haws", unit_of_measurement, statistics)
136
- except Exception:
137
- errorMessage = f"Error while importing statistics to Home Assistant: {traceback.format_exc()}"
138
- Logger.warning(errorMessage)
139
- raise Exception(errorMessage)
1
+ import pygazpar
2
+ import traceback
3
+ import logging
4
+ import pytz
5
+ from typing import Any
6
+ from datetime import datetime, timedelta
7
+ from gazpar2haws.haws import HomeAssistantWS
8
+
9
+ Logger = logging.getLogger(__name__)
10
+
11
+
12
+ # ----------------------------------
13
+ class Gazpar:
14
+
15
+ # ----------------------------------
16
+ def __init__(self, config: dict[str, Any], homeassistant: HomeAssistantWS):
17
+
18
+ self._homeassistant = homeassistant
19
+
20
+ # GrDF configuration
21
+ self._name = config.get("name")
22
+ self._username = config.get("username")
23
+ self._password = config.get("password")
24
+ self._pce_identifier = str(config.get("pce_identifier"))
25
+ self._last_days = int(config.get("last_days"))
26
+ self._timezone = config.get("timezone")
27
+ self._reset = bool(config.get("reset"))
28
+
29
+ # ----------------------------------
30
+ def name(self):
31
+ return self._name
32
+
33
+ # ----------------------------------
34
+ # Publish Gaspar data to Home Assistant WS
35
+ async def publish(self):
36
+
37
+ # Volume and energy sensor names.
38
+ volume_sensor_name = f"sensor.{self._name}_volume"
39
+ energy_sensor_name = f"sensor.{self._name}_energy"
40
+
41
+ # Eventually reset the sensor in Home Assistant
42
+ if self._reset:
43
+ try:
44
+ await self._homeassistant.clear_statistics([volume_sensor_name, energy_sensor_name])
45
+ except Exception:
46
+ errorMessage = f"Error while resetting the sensor in Home Assistant: {traceback.format_exc()}"
47
+ Logger.warning(errorMessage)
48
+ raise Exception(errorMessage)
49
+
50
+ # Publish volume sensor
51
+ await self._publish_entity(volume_sensor_name, pygazpar.PropertyName.VOLUME.value, "m³")
52
+ await self._publish_entity(energy_sensor_name, pygazpar.PropertyName.ENERGY.value, "kWh")
53
+
54
+ # ----------------------------------
55
+ # Publish a sensor to Home Assistant
56
+ async def _publish_entity(self, entity_id: str, property_name: str, unit_of_measurement: str):
57
+
58
+ # Check the existence of the sensor in Home Assistant
59
+ try:
60
+ exists_statistic_id = await self._homeassistant.exists_statistic_id(entity_id, "sum")
61
+ except Exception:
62
+ errorMessage = f"Error while checking the existence of the sensor in Home Assistant: {traceback.format_exc()}"
63
+ Logger.warning(errorMessage)
64
+ raise Exception(errorMessage)
65
+
66
+ if exists_statistic_id:
67
+ # Get the last statistic from Home Assistant
68
+ try:
69
+ last_statistic = await self._homeassistant.get_last_statistic(entity_id)
70
+ except Exception:
71
+ errorMessage = f"Error while fetching last statistics from Home Assistant: {traceback.format_exc()}"
72
+ Logger.warning(errorMessage)
73
+ raise Exception(errorMessage)
74
+
75
+ # Extract the end date of the last statistics from the unix timestamp
76
+ last_date = datetime.fromtimestamp(last_statistic.get("start") / 1000, tz=pytz.timezone(self._timezone))
77
+
78
+ # Compute the number of days since the last statistics
79
+ last_days = (datetime.now(tz=pytz.timezone(self._timezone)) - last_date).days
80
+
81
+ # Get the last meter value
82
+ last_value = last_statistic.get("sum")
83
+ else:
84
+ # If the sensor does not exist in Home Assistant, fetch the last days defined in the configuration
85
+ last_days = self._last_days
86
+
87
+ # Compute the corresponding last_date
88
+ last_date = datetime.now(tz=pytz.timezone(self._timezone)) - timedelta(days=last_days)
89
+
90
+ # If no statistic, the last value is initialized to zero
91
+ last_value = 0
92
+
93
+ Logger.debug(f"Last date: {last_date}, last days: {last_days}, last value: {last_value}")
94
+
95
+ # Initialize PyGazpar client
96
+ client = pygazpar.Client(pygazpar.JsonWebDataSource(username=self._username, password=self._password))
97
+
98
+ try:
99
+ data = client.loadSince(pceIdentifier=self._pce_identifier, lastNDays=last_days, frequencies=[pygazpar.Frequency.DAILY])
100
+ except Exception:
101
+ errorMessage = f"Error while fetching data from GrDF: {traceback.format_exc()}"
102
+ Logger.warning(errorMessage)
103
+ data = {}
104
+
105
+ # Timezone
106
+ timezone = pytz.timezone(self._timezone)
107
+
108
+ # Compute and fill statistics.
109
+ daily = data.get(pygazpar.Frequency.DAILY.value)
110
+ statistics = []
111
+ total = last_value
112
+ for reading in daily:
113
+ # Parse date format DD/MM/YYYY into datetime.
114
+ date = datetime.strptime(reading[pygazpar.PropertyName.TIME_PERIOD.value], "%d/%m/%Y")
115
+
116
+ # Set the timezone
117
+ date = timezone.localize(date)
118
+
119
+ # Skip all readings before the last statistic date.
120
+ if date <= last_date:
121
+ Logger.debug(f"Skip date: {date} <= {last_date}")
122
+ continue
123
+
124
+ # Compute the total volume and energy
125
+ total += reading[property_name]
126
+
127
+ statistics.append({
128
+ "start": date.isoformat(),
129
+ "state": total,
130
+ "sum": total
131
+ })
132
+
133
+ # Publish statistics to Home Assistant
134
+ try:
135
+ await self._homeassistant.import_statistics(entity_id, "recorder", "gazpar2haws", unit_of_measurement, statistics)
136
+ except Exception:
137
+ errorMessage = f"Error while importing statistics to Home Assistant: {traceback.format_exc()}"
138
+ Logger.warning(errorMessage)
139
+ raise Exception(errorMessage)
gazpar2haws/version.py CHANGED
@@ -1,3 +1,3 @@
1
- import importlib.metadata
2
-
3
- __version__ = importlib.metadata.version('gazpar2haws')
1
+ import importlib.metadata
2
+
3
+ __version__ = importlib.metadata.version('gazpar2haws')
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Stéphane Senart
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Stéphane Senart
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.
@@ -1,18 +1,37 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: gazpar2haws
3
- Version: 0.1.7
3
+ Version: 0.1.8.dev10
4
4
  Summary: Gazpar2HAWS is a gateway that reads data history from the GrDF (French gas provider) meter and send it to Home Assistant using WebSocket interface
5
- License: MIT
5
+ License: MIT License
6
+
7
+ Copyright (c) 2024 Stéphane Senart
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
6
26
  Author: Stéphane Senart
7
- Requires-Python: >=3.12,<4.0
8
- Classifier: License :: OSI Approved :: MIT License
9
- Classifier: Programming Language :: Python :: 3
27
+ Requires-Python: >=3.9
28
+ Classifier: Programming Language :: Python :: 3.9
29
+ Classifier: Programming Language :: Python :: 3.10
30
+ Classifier: Programming Language :: Python :: 3.11
10
31
  Classifier: Programming Language :: Python :: 3.12
11
- Classifier: Programming Language :: Python :: 3.13
12
- Requires-Dist: pygazpar (>=1.2.6,<2.0.0)
13
- Requires-Dist: pytest-asyncio (>=0.25.0,<0.26.0)
14
- Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
15
- Requires-Dist: websockets (>=14.1,<15.0)
32
+ Requires-Dist: pygazpar (>=1.2.7)
33
+ Requires-Dist: pyyaml (>=6.0.2)
34
+ Requires-Dist: websockets (>=14.1)
16
35
  Description-Content-Type: text/markdown
17
36
 
18
37
  # gazpar2haws
@@ -0,0 +1,11 @@
1
+ gazpar2haws/__init__.py,sha256=3MCDQdGGmT3FQMKaAB3mBJq7L75T_bJSdpDRjE-pado,58
2
+ gazpar2haws/__main__.py,sha256=EMWGYVVfKEJySSvn8fmNfzFZWVjsPefUFyt4gTC506w,3162
3
+ gazpar2haws/bridge.py,sha256=plcXR8y6lH84OSHuUOogNcbM7uua24inoF9SSERKGHo,3539
4
+ gazpar2haws/config_utils.py,sha256=Q_-07kAIqvjjHG27tHLLnyaTAZcFVdt1iRzksz2wy1k,2067
5
+ gazpar2haws/gazpar.py,sha256=jXpOtqWW6fv6BQmVLoA0G7B93HjztY7MemvGnszBXPU,5615
6
+ gazpar2haws/haws.py,sha256=H0Qa01Qtsn3QdnGqIGkXE-Ympf7MSXkbFwAbzaMAodM,6895
7
+ gazpar2haws/version.py,sha256=tJINl5RAPtGkwDz8nWdcM1emyqLY2N2XfgsBHuofz5U,83
8
+ gazpar2haws-0.1.8.dev10.dist-info/LICENSE,sha256=ajApZPyhVx8AU9wN7DXeRGhoWFqY2ylBZUa5GRhTmok,1073
9
+ gazpar2haws-0.1.8.dev10.dist-info/METADATA,sha256=2soXtuY3I0r2aqJIn1tO1yMUFj188wtY2jd7lQ0STiY,9456
10
+ gazpar2haws-0.1.8.dev10.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
11
+ gazpar2haws-0.1.8.dev10.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 2.0.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
CHANGELOG.md DELETED
@@ -1,60 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [0.1.7] - 2025-01-05
9
-
10
- ### Fixed
11
-
12
- [#18](https://github.com/ssenart/gazpar2haws/issues/18): Regression on DockerHub deployment.
13
-
14
- ## [0.1.6] - 2025-01-05
15
-
16
- ### Added
17
-
18
- [#4](https://github.com/ssenart/gazpar2haws/issues/4): Deploy gazpar2haws as an HA add-on.
19
-
20
- ## [0.1.5] - 2025-01-04
21
-
22
- ### Added
23
-
24
- [#15](https://github.com/ssenart/gazpar2haws/issues/15): Using HassIO, websocket endpoint is /core/websocket.
25
-
26
- ## [0.1.4] - 2025-01-04
27
-
28
- ### Fixed
29
-
30
- [#13](https://github.com/ssenart/gazpar2haws/issues/13): Using HassIO, connection to the supervisor requires Authorization header.
31
-
32
- ## [0.1.3] - 2025-01-03
33
-
34
- ### Changed
35
-
36
- [#11](https://github.com/ssenart/gazpar2haws/issues/11): Upgrade PyGazpar version to 1.2.6.
37
-
38
- ## [0.1.2] - 2024-12-30
39
-
40
- ### Added
41
-
42
- [#2](https://github.com/ssenart/gazpar2haws/issues/2): DockerHub deployment.
43
-
44
- ### Fixed
45
-
46
- [#9](https://github.com/ssenart/gazpar2haws/issues/9): Incorrect timezone info creates duplicate import.
47
-
48
- [#6](https://github.com/ssenart/gazpar2haws/issues/6): The last meter value may be imported multiple times and cause the today value being wrong.
49
-
50
- [#3](https://github.com/ssenart/gazpar2haws/issues/3): reset=false makes the meter import to restart from zero.
51
-
52
- ## [0.1.1] - 2024-12-22
53
-
54
- ### Added
55
-
56
- [#1](https://github.com/ssenart/gazpar2haws/issues/1): Publish energy indicator in kWh.
57
-
58
- ## [0.1.0] - 2024-12-21
59
-
60
- First version of the project.
@@ -1,12 +0,0 @@
1
- CHANGELOG.md,sha256=VTHCw5lk7xiOq9TwQUWkePNYJq9d37n9NM0H9TAXwdI,1688
2
- gazpar2haws/__init__.py,sha256=yzol8uZSBI7pIRGUmYJ6-vRBwkM4MI3IGf5cQpNsaFw,57
3
- gazpar2haws/__main__.py,sha256=g8xk0x_kprBHKHLzgf9y9EY2_gKC9V3k4z0n-EDTd-I,3253
4
- gazpar2haws/bridge.py,sha256=plcXR8y6lH84OSHuUOogNcbM7uua24inoF9SSERKGHo,3539
5
- gazpar2haws/config_utils.py,sha256=D0lu-3KY-vLEyD2vDN05UABkMnpMJjqw1RuDJVrkGFs,2123
6
- gazpar2haws/gazpar.py,sha256=8yrMzs9HfMSgq3HPeJs64SHWb5RWm7ZL3tgfzhlwHFQ,5754
7
- gazpar2haws/haws.py,sha256=H0Qa01Qtsn3QdnGqIGkXE-Ympf7MSXkbFwAbzaMAodM,6895
8
- gazpar2haws/version.py,sha256=ebdTNl4h0hNKmN3Gbs592VJsYbMmrkB47WyZMJevaQo,86
9
- gazpar2haws-0.1.7.dist-info/LICENSE,sha256=G6JttcnlwcRHYzIcDflSGOVrHTtaP3BEegM2lH00xHw,1094
10
- gazpar2haws-0.1.7.dist-info/METADATA,sha256=DCB5_09TfIhQMsEGI91e8aBmNzpujnB01sloo6ZEkqo,8274
11
- gazpar2haws-0.1.7.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
12
- gazpar2haws-0.1.7.dist-info/RECORD,,