python-openevse-http 1.0.2__py3-none-any.whl → 1.4.0__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.
openevsehttp/client.py CHANGED
@@ -53,11 +53,16 @@ class OpenEVSE(CommandsMixin, ManagersMixin, SensorsMixin, PropertiesMixin):
53
53
  user: str | None = None,
54
54
  pwd: str | None = None,
55
55
  session: aiohttp.ClientSession | None = None,
56
+ ssl: bool = False,
57
+ ssl_verify: bool = True,
56
58
  ) -> None:
57
59
  """Connect to an OpenEVSE charger equipped with wifi or ethernet."""
58
60
  self._user = user or ""
59
61
  self._pwd = pwd or ""
60
- self.url = f"http://{host}/"
62
+ self.ssl = ssl
63
+ self.ssl_verify = ssl_verify
64
+ scheme = "https" if ssl else "http"
65
+ self.url = f"{scheme}://{host}/"
61
66
  self._status: dict[str, Any] = {}
62
67
  self._config: dict[str, Any] = {}
63
68
  self._override: Any = None
@@ -134,6 +139,8 @@ class OpenEVSE(CommandsMixin, ManagersMixin, SensorsMixin, PropertiesMixin):
134
139
  kwargs = {"data": rapi, "auth": auth}
135
140
  if data is not None:
136
141
  kwargs["json"] = data
142
+ if url.startswith("https://") and not self.ssl_verify:
143
+ kwargs["ssl"] = False
137
144
  async with http_method(url, **kwargs) as resp:
138
145
  try:
139
146
  raw = await resp.text()
@@ -285,6 +292,7 @@ class OpenEVSE(CommandsMixin, ManagersMixin, SensorsMixin, PropertiesMixin):
285
292
  self._user,
286
293
  self._pwd,
287
294
  self._session,
295
+ ssl_verify=self.ssl_verify,
288
296
  )
289
297
 
290
298
  def _validate_session_loop(self, loop: asyncio.AbstractEventLoop) -> None:
openevsehttp/commands.py CHANGED
@@ -23,6 +23,8 @@ class CommandsMixin:
23
23
  """Mixin providing command methods for OpenEVSE."""
24
24
 
25
25
  url: str
26
+ ssl: bool
27
+ ssl_verify: bool
26
28
  _status: dict[str, Any]
27
29
  _config: dict[str, Any]
28
30
  _session: aiohttp.ClientSession | None
openevsehttp/const.py CHANGED
@@ -23,6 +23,8 @@ BAT_RANGE = "battery_range"
23
23
  TTF = "time_to_full_charge"
24
24
  VOLTAGE = "voltage"
25
25
  SHAPER_LIVE = "shaper_live_pwr"
26
+ HOME_BATTERY_SOC = "home_battery_soc"
27
+ HOME_BATTERY_POWER = "home_battery_power"
26
28
  TYPE = "type"
27
29
  VALUE = "value"
28
30
  RELEASE = "release"
openevsehttp/sensors.py CHANGED
@@ -6,7 +6,16 @@ import logging
6
6
  from collections.abc import Mapping
7
7
  from typing import Any
8
8
 
9
- from .const import BAT_LVL, BAT_RANGE, GRID, SOLAR, TTF, VOLTAGE
9
+ from .const import (
10
+ BAT_LVL,
11
+ BAT_RANGE,
12
+ GRID,
13
+ HOME_BATTERY_POWER,
14
+ HOME_BATTERY_SOC,
15
+ SOLAR,
16
+ TTF,
17
+ VOLTAGE,
18
+ )
10
19
  from .exceptions import UnsupportedFeature
11
20
 
12
21
  _LOGGER = logging.getLogger(__name__)
@@ -122,6 +131,34 @@ class SensorsMixin:
122
131
  response = await self.process_request(url=url, method="post", data=data)
123
132
  _LOGGER.debug("SOC response: %s", self._normalize_response(response))
124
133
 
134
+ # Home/powerwall battery HTTP Posting
135
+ async def home_battery(
136
+ self,
137
+ soc: int | None = None,
138
+ power: int | None = None,
139
+ ) -> None:
140
+ """Send pushed home/powerwall battery data to the charger."""
141
+ if not self._version_check("4.1.0"):
142
+ _LOGGER.debug("Feature not supported for older firmware.")
143
+ raise UnsupportedFeature
144
+
145
+ url = f"{self.url}status"
146
+ data = {}
147
+
148
+ if soc is not None:
149
+ data[HOME_BATTERY_SOC] = soc
150
+ if power is not None:
151
+ data[HOME_BATTERY_POWER] = power
152
+
153
+ if not data:
154
+ _LOGGER.info("No home battery data to send to device.")
155
+ else:
156
+ _LOGGER.debug("Posting home battery data: %s", data)
157
+ response = await self.process_request(url=url, method="post", data=data)
158
+ _LOGGER.debug(
159
+ "Home battery response: %s", self._normalize_response(response)
160
+ )
161
+
125
162
  # Shaper HTTP Posting
126
163
  async def set_shaper_live_pwr(self, power: int) -> None:
127
164
  """Send pushed sensor data to shaper."""
openevsehttp/utils.py CHANGED
@@ -32,7 +32,9 @@ def get_awesome_version(version: str) -> AwesomeVersion:
32
32
  # We use custom word boundary checks to avoid false positives like 'domain' matching 'main'
33
33
  # or 'webmaster' matching 'master'.
34
34
  is_dev = False
35
- if re.search(
35
+ if re.search(r"_modified$", version, re.IGNORECASE):
36
+ is_dev = True
37
+ elif re.search(
36
38
  r"(?:^|[^a-zA-Z0-9])(master|main)(?:[^a-zA-Z0-9]|$)", version, re.IGNORECASE
37
39
  ):
38
40
  is_dev = True
openevsehttp/websocket.py CHANGED
@@ -42,9 +42,11 @@ class OpenEVSEWebsocket:
42
42
  user: str | None = None,
43
43
  password: str | None = None,
44
44
  session: aiohttp.ClientSession | None = None,
45
+ ssl_verify: bool = True,
45
46
  ) -> None:
46
47
  """Initialize a OpenEVSEWebsocket instance."""
47
48
  self.session = session
49
+ self.ssl_verify = ssl_verify
48
50
  self.uri = self._get_uri(server)
49
51
  self._user = user
50
52
  self._password = password
@@ -133,10 +135,16 @@ class OpenEVSEWebsocket:
133
135
  try:
134
136
  # Narrow type for mypy since _ensure_session sets self.session
135
137
  assert self.session is not None
138
+ ws_kwargs: dict[str, Any] = {
139
+ "heartbeat": 15,
140
+ "auth": auth,
141
+ }
142
+ if self.uri.startswith("wss://") and not self.ssl_verify:
143
+ ws_kwargs["ssl"] = False
144
+
136
145
  async with self.session.ws_connect(
137
146
  self.uri,
138
- heartbeat=15,
139
- auth=auth,
147
+ **ws_kwargs,
140
148
  ) as ws_client:
141
149
  self._client = ws_client
142
150
  await self._set_state(STATE_CONNECTED)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python_openevse_http
3
- Version: 1.0.2
3
+ Version: 1.4.0
4
4
  Summary: Python wrapper for OpenEVSE HTTP API
5
5
  Home-page: https://github.com/firstof9/python-openevse-http
6
6
  Download-URL: https://github.com/firstof9/python-openevse-http
@@ -84,6 +84,35 @@ async def main():
84
84
  if __name__ == "__main__":
85
85
  asyncio.run(main())
86
86
  ```
87
+ ### HTTPS and SSL Verification Options
88
+
89
+ If your OpenEVSE WiFi/ethernet module uses HTTPS, you can configure the client to connect securely using the `ssl=True` parameter:
90
+
91
+ ```python
92
+ # Connect securely using HTTPS (validating SSL/TLS certificates)
93
+ charger = OpenEVSE(
94
+ "192.168.1.30",
95
+ session=session,
96
+ ssl=True,
97
+ )
98
+ ```
99
+
100
+ #### Bypassing SSL Verification (Self-Signed Certificates)
101
+
102
+ > [!WARNING]
103
+ > Disabling SSL certificate validation (`ssl_verify=False`) disables TLS verification and exposes the connection to Man-in-the-Middle (MITM) attacks. Only use this configuration when connecting to an OpenEVSE module with a self-signed certificate over a trusted local network.
104
+
105
+ To bypass certificate verification:
106
+
107
+ ```python
108
+ # Connect using HTTPS, and disable certificate verification
109
+ charger = OpenEVSE(
110
+ "192.168.1.30",
111
+ session=session,
112
+ ssl=True,
113
+ ssl_verify=False,
114
+ )
115
+ ```
87
116
 
88
117
  ## API Support Matrix
89
118
 
@@ -0,0 +1,17 @@
1
+ openevsehttp/__init__.py,sha256=I6a1mjOZHYiWb_qfCuDuFLOOncrkkB_7uwybtOIujfY,1165
2
+ openevsehttp/__main__.py,sha256=EHmSdT7GjAVvHQxvLBTjZXsj_V5SB6B2_kpgUAT7mPM,146
3
+ openevsehttp/client.py,sha256=bySzhJ9SKU0IN7-QQfW7_ZrKNw-EoPV4RvnRBXtmCQ8,19326
4
+ openevsehttp/commands.py,sha256=OFPreBlsXUViwvjbVsD_0bmLv9ZSWqHnwdo2lBqdrSs,27278
5
+ openevsehttp/const.py,sha256=-frkFduu8hxEBab9FnwA3D65XHrsyH0W7P9miYsWh90,1726
6
+ openevsehttp/exceptions.py,sha256=bqz-tHTW1AYJMKcm0s5M6z5tA6XZgjnCiBLW1XrZ_70,672
7
+ openevsehttp/managers.py,sha256=EtQMQziwhoZeqKe2zWY-0yS7zedhuYjYtL5j9xBBCZ0,5380
8
+ openevsehttp/properties.py,sha256=xbQfx256FZwNPPn9ryWWOMKliyCChq4ZaTH9NDQVR_8,17968
9
+ openevsehttp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ openevsehttp/sensors.py,sha256=zhQSToY_Zp2rOhPnUXT40xS5ZnUavqNGLm4zAFiUUrY,5717
11
+ openevsehttp/utils.py,sha256=fPUWL64gFTRw4TtV4WITDAFMJ75VjNhPBaU6diwVlv0,2019
12
+ openevsehttp/websocket.py,sha256=yMuLNsB2qYZLtfYRW7-D7NH7rv-qaSTp7F79OajKm_0,10790
13
+ python_openevse_http-1.4.0.dist-info/licenses/LICENSE,sha256=hSB6TOQ7rmwSGb6XzqRjDGMvmUj5_GlacqQin3tegtA,11341
14
+ python_openevse_http-1.4.0.dist-info/METADATA,sha256=uQBdZBdNAnWvyuwoWpgJYjBDlxUAoDxot4LANe6TZTY,5411
15
+ python_openevse_http-1.4.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
16
+ python_openevse_http-1.4.0.dist-info/top_level.txt,sha256=u8RUkoEIE33Cjn6gmqiEoVpZ0VZ59WJ3FXBwwOg0CPE,13
17
+ python_openevse_http-1.4.0.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- openevsehttp/__init__.py,sha256=I6a1mjOZHYiWb_qfCuDuFLOOncrkkB_7uwybtOIujfY,1165
2
- openevsehttp/__main__.py,sha256=EHmSdT7GjAVvHQxvLBTjZXsj_V5SB6B2_kpgUAT7mPM,146
3
- openevsehttp/client.py,sha256=dSvlotG7xxgnDxkI_o2KtIddVw58y6ZgIdJa9gu-WnU,19013
4
- openevsehttp/commands.py,sha256=JGxjmGvE2-eUJ1gD76y_701Qk3Kzab-6XtGeaXXDSb0,27243
5
- openevsehttp/const.py,sha256=9jVzW4CZz7uP7VKbGQT4v0jNeP5PPC55tR-jnG11ODA,1646
6
- openevsehttp/exceptions.py,sha256=bqz-tHTW1AYJMKcm0s5M6z5tA6XZgjnCiBLW1XrZ_70,672
7
- openevsehttp/managers.py,sha256=EtQMQziwhoZeqKe2zWY-0yS7zedhuYjYtL5j9xBBCZ0,5380
8
- openevsehttp/properties.py,sha256=xbQfx256FZwNPPn9ryWWOMKliyCChq4ZaTH9NDQVR_8,17968
9
- openevsehttp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- openevsehttp/sensors.py,sha256=yO4Q1sgJkvmfOi5dpoTwEoldsrpqgGz0k9fC7mFWass,4680
11
- openevsehttp/utils.py,sha256=Q4I_rmh8UdD-DVAZxfb95VBdUl5jtSEE1DHqRxkktUE,1938
12
- openevsehttp/websocket.py,sha256=dOSemvm7CM5pFb9RaoJSTIM6Tf5xtWMLEBEccKlBUKI,10517
13
- python_openevse_http-1.0.2.dist-info/licenses/LICENSE,sha256=hSB6TOQ7rmwSGb6XzqRjDGMvmUj5_GlacqQin3tegtA,11341
14
- python_openevse_http-1.0.2.dist-info/METADATA,sha256=aTPqaY0mhzUFNc0Z_uBCSnxlX4azB0YFEAupqd8KbFw,4417
15
- python_openevse_http-1.0.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
16
- python_openevse_http-1.0.2.dist-info/top_level.txt,sha256=u8RUkoEIE33Cjn6gmqiEoVpZ0VZ59WJ3FXBwwOg0CPE,13
17
- python_openevse_http-1.0.2.dist-info/RECORD,,