python-openevse-http 1.4.0__tar.gz → 1.5.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.
Files changed (76) hide show
  1. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/workflows/autolabeler.yml +1 -1
  2. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/workflows/links.yml +1 -1
  3. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/workflows/publish-to-pypi.yml +1 -1
  4. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/workflows/release-drafter.yml +1 -1
  5. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/workflows/test.yml +3 -3
  6. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/PKG-INFO +1 -1
  7. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/commands.py +20 -0
  8. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/properties.py +23 -0
  9. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/pyproject.toml +1 -1
  10. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/python_openevse_http.egg-info/PKG-INFO +1 -1
  11. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/python_openevse_http.egg-info/SOURCES.txt +2 -0
  12. python_openevse_http-1.5.0/python_openevse_http.egg-info/scm_file_list.json +70 -0
  13. python_openevse_http-1.5.0/python_openevse_http.egg-info/scm_version.json +8 -0
  14. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/requirements_lint.txt +1 -1
  15. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/requirements_test.txt +1 -1
  16. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_commands.py +33 -0
  17. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_properties.py +27 -1
  18. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  19. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  21. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/dependabot.yml +0 -0
  22. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/pull_request_template.md +0 -0
  23. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.github/release-drafter.yml +0 -0
  24. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.gitignore +0 -0
  25. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.pre-commit-config.yaml +0 -0
  26. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/.yamllint +0 -0
  27. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/EXTERNAL_SESSION.md +0 -0
  28. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/LICENSE +0 -0
  29. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/README.md +0 -0
  30. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/codecov.yml +0 -0
  31. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/example_external_session.py +0 -0
  32. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/__init__.py +0 -0
  33. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/__main__.py +0 -0
  34. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/client.py +0 -0
  35. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/const.py +0 -0
  36. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/exceptions.py +0 -0
  37. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/managers.py +0 -0
  38. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/py.typed +0 -0
  39. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/sensors.py +0 -0
  40. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/utils.py +0 -0
  41. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/openevsehttp/websocket.py +0 -0
  42. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/python_openevse_http.egg-info/dependency_links.txt +0 -0
  43. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/python_openevse_http.egg-info/not-zip-safe +0 -0
  44. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/python_openevse_http.egg-info/requires.txt +0 -0
  45. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/python_openevse_http.egg-info/top_level.txt +0 -0
  46. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/requirements.txt +0 -0
  47. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/setup.cfg +0 -0
  48. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/setup.py +0 -0
  49. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/__init__.py +0 -0
  50. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/common.py +0 -0
  51. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/conftest.py +0 -0
  52. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/github_v2.json +0 -0
  53. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/github_v4.json +0 -0
  54. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v2_json/config.json +0 -0
  55. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v2_json/status.json +0 -0
  56. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/config-broken-semver.json +0 -0
  57. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/config-broken.json +0 -0
  58. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/config-dev.json +0 -0
  59. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/config-extra-version.json +0 -0
  60. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/config-new.json +0 -0
  61. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/config-unknown-semver.json +0 -0
  62. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/config.json +0 -0
  63. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/schedule.json +0 -0
  64. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/status-broken.json +0 -0
  65. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/status-new.json +0 -0
  66. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/v4_json/status.json +0 -0
  67. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/fixtures/websocket.json +0 -0
  68. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_client.py +0 -0
  69. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_external_session.py +0 -0
  70. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_main_edge_cases.py +0 -0
  71. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_managers.py +0 -0
  72. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_mixins.py +0 -0
  73. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_sensors.py +0 -0
  74. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_shaper.py +0 -0
  75. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tests/test_websocket.py +0 -0
  76. {python_openevse_http-1.4.0 → python_openevse_http-1.5.0}/tox.ini +0 -0
@@ -38,6 +38,6 @@ jobs:
38
38
  with:
39
39
  egress-policy: audit
40
40
 
41
- - uses: release-drafter/release-drafter/autolabeler@693d20e7c1ce1a81d3a41962f85914253b518449 # v7
41
+ - uses: release-drafter/release-drafter/autolabeler@ed4bc48ec97379be2258e7b7ac2624a3e26ab809 # v7
42
42
  env:
43
43
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -19,7 +19,7 @@ jobs:
19
19
  with:
20
20
  egress-policy: audit
21
21
 
22
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
22
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
23
23
 
24
24
  - name: Link Checker
25
25
  uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2
@@ -25,7 +25,7 @@ jobs:
25
25
  with:
26
26
  egress-policy: audit
27
27
 
28
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
28
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
29
29
  with:
30
30
  ref: ${{ inputs.tag || github.ref }}
31
31
  fetch-depth: 0
@@ -18,6 +18,6 @@ jobs:
18
18
  egress-policy: audit
19
19
 
20
20
  # Drafts your next Release notes as Pull Requests are merged into "main"
21
- - uses: release-drafter/release-drafter@693d20e7c1ce1a81d3a41962f85914253b518449 # v7
21
+ - uses: release-drafter/release-drafter@ed4bc48ec97379be2258e7b7ac2624a3e26ab809 # v7
22
22
  env:
23
23
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -22,7 +22,7 @@ jobs:
22
22
  with:
23
23
  egress-policy: audit
24
24
 
25
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
25
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
26
26
  - name: Set up Python
27
27
  uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
28
28
  with:
@@ -45,7 +45,7 @@ jobs:
45
45
  with:
46
46
  egress-policy: audit
47
47
 
48
- - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
48
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
49
49
  with:
50
50
  fetch-depth: 2
51
51
  - name: Set up Python ${{ matrix.python-version }}
@@ -74,7 +74,7 @@ jobs:
74
74
  egress-policy: audit
75
75
 
76
76
  - name: Check out the repository
77
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
77
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
78
78
  with:
79
79
  fetch-depth: 2
80
80
  - name: Download coverage data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python_openevse_http
3
- Version: 1.4.0
3
+ Version: 1.5.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
@@ -667,3 +667,23 @@ class CommandsMixin:
667
667
 
668
668
  new_state = not bool(shaper_active)
669
669
  await self.set_shaper(new_state)
670
+
671
+ async def set_mqtt_vehicle_range_miles(self, enable: bool = True) -> None:
672
+ """Set mqtt_vehicle_range_miles configuration setting.
673
+
674
+ Dynamically changing this setting will affect future evaluations of
675
+ the vehicle_range_with_unit property.
676
+ """
677
+ if not isinstance(enable, bool):
678
+ raise TypeError("Value must be a boolean.")
679
+
680
+ url = f"{self.url}config"
681
+ data = {"mqtt_vehicle_range_miles": enable}
682
+
683
+ _LOGGER.debug("Setting mqtt_vehicle_range_miles to %s", enable)
684
+ response = await self.process_request(url=url, method="post", data=data)
685
+ response = self._normalize_response(response)
686
+ msg = response.get("msg") if isinstance(response, Mapping) else None
687
+ if msg not in SUCCESS_ANSWERS:
688
+ _LOGGER.error("Problem issuing command: %s", response)
689
+ raise UnknownError
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import logging
6
+ import warnings
6
7
  from collections.abc import Mapping
7
8
  from datetime import datetime, timedelta, timezone
8
9
  from typing import Any, cast
@@ -458,11 +459,33 @@ class PropertiesMixin:
458
459
  @property
459
460
  def vehicle_range(self) -> int | None:
460
461
  """Return battery range."""
462
+ warnings.warn(
463
+ "vehicle_range is deprecated, use vehicle_range_with_unit instead",
464
+ DeprecationWarning,
465
+ stacklevel=2,
466
+ )
461
467
  return cast(
462
468
  "int | None",
463
469
  self._status.get("vehicle_range", self._status.get("battery_range", None)),
464
470
  )
465
471
 
472
+ @property
473
+ def vehicle_range_with_unit(self) -> tuple[int, str] | None:
474
+ """Return battery range and its unit."""
475
+ value = cast(
476
+ "int | None",
477
+ self._status.get("vehicle_range", self._status.get("battery_range", None)),
478
+ )
479
+ if value is None:
480
+ return None
481
+ unit = "miles" if self.mqtt_vehicle_range_miles else "km"
482
+ return (value, unit)
483
+
484
+ @property
485
+ def mqtt_vehicle_range_miles(self) -> bool:
486
+ """Return True if mqtt vehicle range is in miles, False if km."""
487
+ return bool(self._config.get("mqtt_vehicle_range_miles", False))
488
+
466
489
  @property
467
490
  def vehicle_eta(self) -> datetime | None:
468
491
  """Return time to full charge."""
@@ -32,7 +32,7 @@ ignore = [
32
32
  max-complexity = 18
33
33
 
34
34
  [build-system]
35
- requires = ["setuptools>=82.0.1", "setuptools-scm>=10.0.5"]
35
+ requires = ["setuptools>=82.0.1", "setuptools-scm>=10.1.1"]
36
36
  build-backend = "setuptools.build_meta"
37
37
 
38
38
  [tool.setuptools_scm]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python_openevse_http
3
- Version: 1.4.0
3
+ Version: 1.5.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
@@ -40,6 +40,8 @@ python_openevse_http.egg-info/SOURCES.txt
40
40
  python_openevse_http.egg-info/dependency_links.txt
41
41
  python_openevse_http.egg-info/not-zip-safe
42
42
  python_openevse_http.egg-info/requires.txt
43
+ python_openevse_http.egg-info/scm_file_list.json
44
+ python_openevse_http.egg-info/scm_version.json
43
45
  python_openevse_http.egg-info/top_level.txt
44
46
  tests/__init__.py
45
47
  tests/common.py
@@ -0,0 +1,70 @@
1
+ {
2
+ "files": [
3
+ ".pre-commit-config.yaml",
4
+ ".yamllint",
5
+ "README.md",
6
+ "EXTERNAL_SESSION.md",
7
+ "tox.ini",
8
+ "requirements_lint.txt",
9
+ "requirements_test.txt",
10
+ "LICENSE",
11
+ "setup.py",
12
+ "pyproject.toml",
13
+ "requirements.txt",
14
+ "codecov.yml",
15
+ ".gitignore",
16
+ "example_external_session.py",
17
+ "openevsehttp/py.typed",
18
+ "openevsehttp/__init__.py",
19
+ "openevsehttp/const.py",
20
+ "openevsehttp/exceptions.py",
21
+ "openevsehttp/utils.py",
22
+ "openevsehttp/client.py",
23
+ "openevsehttp/websocket.py",
24
+ "openevsehttp/managers.py",
25
+ "openevsehttp/properties.py",
26
+ "openevsehttp/sensors.py",
27
+ "openevsehttp/commands.py",
28
+ "openevsehttp/__main__.py",
29
+ "tests/__init__.py",
30
+ "tests/test_managers.py",
31
+ "tests/test_client.py",
32
+ "tests/test_main_edge_cases.py",
33
+ "tests/test_shaper.py",
34
+ "tests/test_commands.py",
35
+ "tests/conftest.py",
36
+ "tests/test_external_session.py",
37
+ "tests/test_mixins.py",
38
+ "tests/test_websocket.py",
39
+ "tests/test_properties.py",
40
+ "tests/test_sensors.py",
41
+ "tests/common.py",
42
+ "tests/fixtures/github_v4.json",
43
+ "tests/fixtures/github_v2.json",
44
+ "tests/fixtures/websocket.json",
45
+ "tests/fixtures/v2_json/config.json",
46
+ "tests/fixtures/v2_json/status.json",
47
+ "tests/fixtures/v4_json/config-broken-semver.json",
48
+ "tests/fixtures/v4_json/status-new.json",
49
+ "tests/fixtures/v4_json/status-broken.json",
50
+ "tests/fixtures/v4_json/config-broken.json",
51
+ "tests/fixtures/v4_json/config-dev.json",
52
+ "tests/fixtures/v4_json/schedule.json",
53
+ "tests/fixtures/v4_json/config.json",
54
+ "tests/fixtures/v4_json/config-unknown-semver.json",
55
+ "tests/fixtures/v4_json/config-new.json",
56
+ "tests/fixtures/v4_json/config-extra-version.json",
57
+ "tests/fixtures/v4_json/status.json",
58
+ ".github/release-drafter.yml",
59
+ ".github/pull_request_template.md",
60
+ ".github/dependabot.yml",
61
+ ".github/ISSUE_TEMPLATE/bug_report.yml",
62
+ ".github/ISSUE_TEMPLATE/config.yml",
63
+ ".github/ISSUE_TEMPLATE/feature_request.yml",
64
+ ".github/workflows/test.yml",
65
+ ".github/workflows/autolabeler.yml",
66
+ ".github/workflows/release-drafter.yml",
67
+ ".github/workflows/links.yml",
68
+ ".github/workflows/publish-to-pypi.yml"
69
+ ]
70
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.5.0",
3
+ "distance": 0,
4
+ "node": "g1f850ad2b147d75315538154ce50b42e8ad81319",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-06-23"
8
+ }
@@ -1,4 +1,4 @@
1
1
  -r requirements.txt
2
2
  prek==0.4.5
3
- ruff==0.15.17
3
+ ruff==0.15.18
4
4
  mypy==2.1.0
@@ -1,6 +1,6 @@
1
1
  -r requirements.txt
2
2
  prek==0.4.5
3
- pytest==9.1.0
3
+ pytest==9.1.1
4
4
  pytest-cov==7.1.0
5
5
  pytest-timeout==2.4.0
6
6
  pytest-asyncio
@@ -1334,3 +1334,36 @@ async def test_update_firmware_bytes_empty(test_charger, caplog):
1334
1334
  with pytest.raises(ValueError):
1335
1335
  await test_charger.update_firmware(firmware_bytes=b"")
1336
1336
  assert "Empty firmware bytes provided" in caplog.text
1337
+
1338
+
1339
+ async def test_set_mqtt_vehicle_range_miles(test_charger_new, mock_aioclient, caplog):
1340
+ """Test set_mqtt_vehicle_range_miles command."""
1341
+ await test_charger_new.update()
1342
+ mock_aioclient.post(
1343
+ TEST_URL_CONFIG,
1344
+ status=200,
1345
+ body='{"msg": "OK"}',
1346
+ )
1347
+ with caplog.at_level(logging.DEBUG):
1348
+ await test_charger_new.set_mqtt_vehicle_range_miles(True)
1349
+ assert "Setting mqtt_vehicle_range_miles to True" in caplog.text
1350
+
1351
+ mock_aioclient.post(
1352
+ TEST_URL_CONFIG,
1353
+ status=200,
1354
+ body='{"msg": "OK"}',
1355
+ )
1356
+ with caplog.at_level(logging.DEBUG):
1357
+ await test_charger_new.set_mqtt_vehicle_range_miles(False)
1358
+ assert "Setting mqtt_vehicle_range_miles to False" in caplog.text
1359
+
1360
+ with pytest.raises(TypeError, match=r"Value must be a boolean\."):
1361
+ await test_charger_new.set_mqtt_vehicle_range_miles("invalid")
1362
+
1363
+ mock_aioclient.post(
1364
+ TEST_URL_CONFIG,
1365
+ status=200,
1366
+ body='{"msg": "error"}',
1367
+ )
1368
+ with pytest.raises(UnknownError):
1369
+ await test_charger_new.set_mqtt_vehicle_range_miles(True)
@@ -159,6 +159,8 @@ SERVER_URL = "openevse.test.tld"
159
159
  ("test_charger_v2", "vehicle_soc", None),
160
160
  ("test_charger", "vehicle_range", 468),
161
161
  ("test_charger_v2", "vehicle_range", None),
162
+ ("test_charger", "vehicle_range_with_unit", (468, "km")),
163
+ ("test_charger_v2", "vehicle_range_with_unit", None),
162
164
  # shaper
163
165
  ("test_charger", "shaper_active", True),
164
166
  ("test_charger_v2", "shaper_active", None),
@@ -207,7 +209,11 @@ async def test_simple_properties(fixture, prop, expected, request):
207
209
  with pytest.raises(expected):
208
210
  _ = getattr(charger, prop)
209
211
  else:
210
- assert getattr(charger, prop) == expected
212
+ if prop == "vehicle_range":
213
+ with pytest.deprecated_call():
214
+ assert getattr(charger, prop) == expected
215
+ else:
216
+ assert getattr(charger, prop) == expected
211
217
  await charger.ws_disconnect()
212
218
 
213
219
 
@@ -490,3 +496,23 @@ async def test_wifi_firmware_none():
490
496
  charger = OpenEVSE(SERVER_URL)
491
497
  charger._config = {}
492
498
  assert charger.wifi_firmware is None
499
+
500
+
501
+ async def test_mqtt_vehicle_range_miles():
502
+ """Test mqtt_vehicle_range_miles property and vehicle_range_with_unit unit selection."""
503
+ charger = OpenEVSE(SERVER_URL)
504
+ # Default is False
505
+ assert charger.mqtt_vehicle_range_miles is False
506
+
507
+ charger._config = {"mqtt_vehicle_range_miles": True}
508
+ assert charger.mqtt_vehicle_range_miles is True
509
+
510
+ charger._status = {"vehicle_range": 150}
511
+ with pytest.deprecated_call():
512
+ assert charger.vehicle_range == 150
513
+ assert charger.vehicle_range_with_unit == (150, "miles")
514
+
515
+ charger._config = {"mqtt_vehicle_range_miles": False}
516
+ with pytest.deprecated_call():
517
+ assert charger.vehicle_range == 150
518
+ assert charger.vehicle_range_with_unit == (150, "km")