python-openevse-http 1.1.0__tar.gz → 1.3.0__tar.gz
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.
- {python_openevse_http-1.1.0/python_openevse_http.egg-info → python_openevse_http-1.3.0}/PKG-INFO +1 -1
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/const.py +2 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/sensors.py +38 -1
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/utils.py +1 -1
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0/python_openevse_http.egg-info}/PKG-INFO +1 -1
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/requirements_lint.txt +1 -1
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_client.py +4 -1
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_sensors.py +38 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/dependabot.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/release-drafter.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/workflows/autolabeler.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/workflows/links.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/workflows/publish-to-pypi.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/workflows/release-drafter.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/workflows/test.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.gitignore +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.pre-commit-config.yaml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.yamllint +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/EXTERNAL_SESSION.md +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/LICENSE +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/README.md +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/codecov.yml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/example_external_session.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/__init__.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/__main__.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/client.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/commands.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/exceptions.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/managers.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/properties.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/py.typed +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/openevsehttp/websocket.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/pyproject.toml +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/SOURCES.txt +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/dependency_links.txt +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/not-zip-safe +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/requires.txt +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/top_level.txt +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/requirements.txt +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/requirements_test.txt +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/setup.cfg +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/setup.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/__init__.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/common.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/conftest.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/github_v2.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/github_v4.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v2_json/config.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v2_json/status.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-broken-semver.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-broken.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-dev.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-extra-version.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-new.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-unknown-semver.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/schedule.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/status-broken.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/status-new.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/status.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/websocket.json +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_commands.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_external_session.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_main_edge_cases.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_managers.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_mixins.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_properties.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_shaper.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/test_websocket.py +0 -0
- {python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tox.ini +0 -0
|
@@ -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"
|
|
@@ -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
|
|
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."""
|
|
@@ -32,7 +32,7 @@ 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(r"
|
|
35
|
+
if re.search(r"_modified$", version, re.IGNORECASE):
|
|
36
36
|
is_dev = True
|
|
37
37
|
elif re.search(
|
|
38
38
|
r"(?:^|[^a-zA-Z0-9])(master|main)(?:[^a-zA-Z0-9]|$)", version, re.IGNORECASE
|
|
@@ -671,7 +671,7 @@ async def test_version_check_dev_branches():
|
|
|
671
671
|
charger._config = {"version": "feature_1A2B3C"}
|
|
672
672
|
assert charger._version_check("2.0.0") is True
|
|
673
673
|
|
|
674
|
-
#
|
|
674
|
+
# Suffix matching for _modified - treated as dev, returns True
|
|
675
675
|
charger._config = {
|
|
676
676
|
"version": "local_feature/gui-nightshift-default_2bcdf1d0_modified"
|
|
677
677
|
}
|
|
@@ -680,6 +680,9 @@ async def test_version_check_dev_branches():
|
|
|
680
680
|
charger._config = {"version": "custom_branch/my-feature_abc123_modified"}
|
|
681
681
|
assert charger._version_check("2.0.0") is True
|
|
682
682
|
|
|
683
|
+
charger._config = {"version": "main_modified"}
|
|
684
|
+
assert charger._version_check("2.0.0") is True
|
|
685
|
+
|
|
683
686
|
# False positives containing 'main' or 'master' but not at word boundaries,
|
|
684
687
|
# ending in 6-char hashes without dev keywords, or other non-matching modified strings
|
|
685
688
|
# — should fail version check
|
|
@@ -88,6 +88,44 @@ async def test_soc(test_charger, test_charger_v2, mock_aioclient, caplog):
|
|
|
88
88
|
await test_charger_v2.ws_disconnect()
|
|
89
89
|
|
|
90
90
|
|
|
91
|
+
# ── home_battery ─────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
async def test_home_battery(test_charger, test_charger_v2, mock_aioclient, caplog):
|
|
95
|
+
"""Test home_battery function."""
|
|
96
|
+
await test_charger.update()
|
|
97
|
+
mock_aioclient.post(
|
|
98
|
+
TEST_URL_STATUS,
|
|
99
|
+
status=200,
|
|
100
|
+
body='{"home_battery_soc": 82, "home_battery_power": -1500}',
|
|
101
|
+
repeat=True,
|
|
102
|
+
)
|
|
103
|
+
with caplog.at_level(logging.DEBUG):
|
|
104
|
+
await test_charger.home_battery(82, -1500)
|
|
105
|
+
assert (
|
|
106
|
+
"Posting home battery data: {'home_battery_soc': 82, 'home_battery_power': -1500}"
|
|
107
|
+
in caplog.text
|
|
108
|
+
)
|
|
109
|
+
assert (
|
|
110
|
+
"Home battery response: {'home_battery_soc': 82, 'home_battery_power': -1500}"
|
|
111
|
+
in caplog.text
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
await test_charger.home_battery(soc=50)
|
|
115
|
+
assert "Posting home battery data: {'home_battery_soc': 50}" in caplog.text
|
|
116
|
+
|
|
117
|
+
await test_charger.home_battery()
|
|
118
|
+
assert "No home battery data to send to device." in caplog.text
|
|
119
|
+
await test_charger.ws_disconnect()
|
|
120
|
+
|
|
121
|
+
await test_charger_v2.update()
|
|
122
|
+
with pytest.raises(UnsupportedFeature):
|
|
123
|
+
with caplog.at_level(logging.DEBUG):
|
|
124
|
+
await test_charger_v2.home_battery(50, -100)
|
|
125
|
+
assert "Feature not supported for older firmware." in caplog.text
|
|
126
|
+
await test_charger_v2.ws_disconnect()
|
|
127
|
+
|
|
128
|
+
|
|
91
129
|
# ── voltage ──────────────────────────────────────────────────────────
|
|
92
130
|
|
|
93
131
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/workflows/publish-to-pypi.yml
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/.github/workflows/release-drafter.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/python_openevse_http.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v2_json/config.json
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v2_json/status.json
RENAMED
|
File without changes
|
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-broken.json
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-dev.json
RENAMED
|
File without changes
|
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config-new.json
RENAMED
|
File without changes
|
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/config.json
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/schedule.json
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/status-broken.json
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/status-new.json
RENAMED
|
File without changes
|
{python_openevse_http-1.1.0 → python_openevse_http-1.3.0}/tests/fixtures/v4_json/status.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|