python-openevse-http 0.1.55__tar.gz → 0.1.57__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-0.1.55 → python-openevse-http-0.1.57}/PKG-INFO +1 -1
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/openevsehttp/__main__.py +124 -6
- python-openevse-http-0.1.57/openevsehttp/const.py +15 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/openevsehttp/exceptions.py +4 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/python_openevse_http.egg-info/PKG-INFO +1 -1
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/setup.py +1 -1
- python-openevse-http-0.1.55/openevsehttp/const.py +0 -4
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/README.md +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/openevsehttp/__init__.py +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/openevsehttp/websocket.py +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/python_openevse_http.egg-info/SOURCES.txt +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/python_openevse_http.egg-info/dependency_links.txt +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/python_openevse_http.egg-info/not-zip-safe +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/python_openevse_http.egg-info/requires.txt +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/python_openevse_http.egg-info/top_level.txt +0 -0
- {python-openevse-http-0.1.55 → python-openevse-http-0.1.57}/setup.cfg +0 -0
|
@@ -5,6 +5,7 @@ import asyncio
|
|
|
5
5
|
import datetime
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
|
+
import re
|
|
8
9
|
from typing import Any, Callable, Dict, Union
|
|
9
10
|
|
|
10
11
|
import aiohttp # type: ignore
|
|
@@ -12,10 +13,23 @@ from aiohttp.client_exceptions import ContentTypeError, ServerTimeoutError
|
|
|
12
13
|
from awesomeversion import AwesomeVersion
|
|
13
14
|
from awesomeversion.exceptions import AwesomeVersionCompareException
|
|
14
15
|
|
|
15
|
-
from .const import
|
|
16
|
+
from .const import (
|
|
17
|
+
BAT_LVL,
|
|
18
|
+
BAT_RANGE,
|
|
19
|
+
GRID,
|
|
20
|
+
MAX_AMPS,
|
|
21
|
+
MIN_AMPS,
|
|
22
|
+
RELEASE,
|
|
23
|
+
SOLAR,
|
|
24
|
+
TTF,
|
|
25
|
+
TYPE,
|
|
26
|
+
VALUE,
|
|
27
|
+
VOLTAGE,
|
|
28
|
+
)
|
|
16
29
|
from .exceptions import (
|
|
17
30
|
AlreadyListening,
|
|
18
31
|
AuthenticationError,
|
|
32
|
+
InvalidType,
|
|
19
33
|
MissingMethod,
|
|
20
34
|
MissingSerial,
|
|
21
35
|
ParseJSONError,
|
|
@@ -120,13 +134,17 @@ class OpenEVSE:
|
|
|
120
134
|
_LOGGER.warning("Non JSON response: %s", message)
|
|
121
135
|
|
|
122
136
|
if resp.status == 400:
|
|
123
|
-
|
|
137
|
+
if "msg" in message.keys():
|
|
138
|
+
index = "msg"
|
|
139
|
+
elif "error" in message.keys():
|
|
140
|
+
index = "error"
|
|
141
|
+
_LOGGER.error("Error 400: %s", message[index])
|
|
124
142
|
raise ParseJSONError
|
|
125
143
|
if resp.status == 401:
|
|
126
144
|
_LOGGER.error("Authentication error: %s", message)
|
|
127
145
|
raise AuthenticationError
|
|
128
146
|
if resp.status in [404, 405, 500]:
|
|
129
|
-
_LOGGER.
|
|
147
|
+
_LOGGER.warning("%s", message)
|
|
130
148
|
|
|
131
149
|
if method == "post" and "config_version" in message:
|
|
132
150
|
await self.update()
|
|
@@ -552,7 +570,16 @@ class OpenEVSE:
|
|
|
552
570
|
if max_version != "":
|
|
553
571
|
limit = AwesomeVersion(max_version)
|
|
554
572
|
|
|
573
|
+
firmware_filtered = None
|
|
574
|
+
|
|
575
|
+
try:
|
|
576
|
+
firmware_search = re.search("\\d\\.\\d\\.\\d", self._config["version"])
|
|
577
|
+
if firmware_search is not None:
|
|
578
|
+
firmware_filtered = firmware_search[0]
|
|
579
|
+
except Exception: # pylint: disable=broad-exception-caught
|
|
580
|
+
_LOGGER.warning("Non-standard versioning string.")
|
|
555
581
|
_LOGGER.debug("Detected firmware: %s", self._config["version"])
|
|
582
|
+
_LOGGER.debug("Filtered firmware: %s", firmware_filtered)
|
|
556
583
|
|
|
557
584
|
if "dev" in self._config["version"]:
|
|
558
585
|
value = self._config["version"]
|
|
@@ -562,7 +589,7 @@ class OpenEVSE:
|
|
|
562
589
|
elif "master" in self._config["version"]:
|
|
563
590
|
value = "dev"
|
|
564
591
|
else:
|
|
565
|
-
value =
|
|
592
|
+
value = firmware_filtered
|
|
566
593
|
|
|
567
594
|
current = AwesomeVersion(value)
|
|
568
595
|
|
|
@@ -600,9 +627,9 @@ class OpenEVSE:
|
|
|
600
627
|
|
|
601
628
|
# Prefer grid sensor data
|
|
602
629
|
if grid is not None:
|
|
603
|
-
data =
|
|
630
|
+
data[GRID] = grid
|
|
604
631
|
elif solar is not None:
|
|
605
|
-
data =
|
|
632
|
+
data[SOLAR] = solar
|
|
606
633
|
|
|
607
634
|
if not data:
|
|
608
635
|
_LOGGER.info("No sensor data to send to device.")
|
|
@@ -611,6 +638,97 @@ class OpenEVSE:
|
|
|
611
638
|
response = await self.process_request(url=url, method="post", data=data)
|
|
612
639
|
_LOGGER.debug("Self-production response: %s", response)
|
|
613
640
|
|
|
641
|
+
# State of charge HTTP posting
|
|
642
|
+
async def soc(
|
|
643
|
+
self,
|
|
644
|
+
battery_level: int | None = None,
|
|
645
|
+
battery_range: int | None = None,
|
|
646
|
+
time_to_full: int | None = None,
|
|
647
|
+
voltage: int | None = None,
|
|
648
|
+
) -> None:
|
|
649
|
+
"""Send pushed sensor data to self-prodcution."""
|
|
650
|
+
if not self._version_check("4.1.0"):
|
|
651
|
+
_LOGGER.debug("Feature not supported for older firmware.")
|
|
652
|
+
raise UnsupportedFeature
|
|
653
|
+
|
|
654
|
+
url = f"{self.url}status"
|
|
655
|
+
data = {}
|
|
656
|
+
|
|
657
|
+
# Build post data
|
|
658
|
+
if battery_level is not None:
|
|
659
|
+
data[BAT_LVL] = battery_level
|
|
660
|
+
if battery_range is not None:
|
|
661
|
+
data[BAT_RANGE] = battery_range
|
|
662
|
+
if time_to_full is not None:
|
|
663
|
+
data[TTF] = time_to_full
|
|
664
|
+
if voltage is not None:
|
|
665
|
+
data[VOLTAGE] = voltage
|
|
666
|
+
|
|
667
|
+
if not data:
|
|
668
|
+
_LOGGER.info("No SOC data to send to device.")
|
|
669
|
+
else:
|
|
670
|
+
_LOGGER.debug("Posting SOC data: %s", data)
|
|
671
|
+
response = await self.process_request(url=url, method="post", data=data)
|
|
672
|
+
_LOGGER.debug("SOC response: %s", response)
|
|
673
|
+
|
|
674
|
+
# Limit endpoint
|
|
675
|
+
async def set_limit(
|
|
676
|
+
self, limit_type: str, value: int, release: bool | None = None
|
|
677
|
+
) -> Any:
|
|
678
|
+
"""Set charge limit."""
|
|
679
|
+
if not self._version_check("5.0.0"):
|
|
680
|
+
_LOGGER.debug("Feature not supported for older firmware.")
|
|
681
|
+
raise UnsupportedFeature
|
|
682
|
+
|
|
683
|
+
url = f"{self.url}limit"
|
|
684
|
+
data: Dict[str, Any] = {}
|
|
685
|
+
valid_types = ["time", "energy", "soc", "range"]
|
|
686
|
+
|
|
687
|
+
if limit_type not in valid_types:
|
|
688
|
+
raise InvalidType
|
|
689
|
+
|
|
690
|
+
data[TYPE] = limit_type
|
|
691
|
+
data[VALUE] = value
|
|
692
|
+
if release is not None:
|
|
693
|
+
data[RELEASE] = release
|
|
694
|
+
|
|
695
|
+
_LOGGER.debug("Limit data: %s", data)
|
|
696
|
+
_LOGGER.debug("Setting limit config on %s", url)
|
|
697
|
+
response = await self.process_request(
|
|
698
|
+
url=url, method="post", data=data
|
|
699
|
+
) # noqa: E501
|
|
700
|
+
return response
|
|
701
|
+
|
|
702
|
+
async def clear_limit(self) -> Any:
|
|
703
|
+
"""Clear charge limit."""
|
|
704
|
+
if not self._version_check("5.0.0"):
|
|
705
|
+
_LOGGER.debug("Feature not supported for older firmware.")
|
|
706
|
+
raise UnsupportedFeature
|
|
707
|
+
|
|
708
|
+
url = f"{self.url}limit"
|
|
709
|
+
data: Dict[str, Any] = {}
|
|
710
|
+
|
|
711
|
+
_LOGGER.debug("Clearing limit config on %s", url)
|
|
712
|
+
response = await self.process_request(
|
|
713
|
+
url=url, method="delete", data=data
|
|
714
|
+
) # noqa: E501
|
|
715
|
+
return response
|
|
716
|
+
|
|
717
|
+
async def get_limit(self) -> Any:
|
|
718
|
+
"""Get charge limit."""
|
|
719
|
+
if not self._version_check("5.0.0"):
|
|
720
|
+
_LOGGER.debug("Feature not supported for older firmware.")
|
|
721
|
+
raise UnsupportedFeature
|
|
722
|
+
|
|
723
|
+
url = f"{self.url}limit"
|
|
724
|
+
data: Dict[str, Any] = {}
|
|
725
|
+
|
|
726
|
+
_LOGGER.debug("Getting limit config on %s", url)
|
|
727
|
+
response = await self.process_request(
|
|
728
|
+
url=url, method="get", data=data
|
|
729
|
+
) # noqa: E501
|
|
730
|
+
return response
|
|
731
|
+
|
|
614
732
|
@property
|
|
615
733
|
def hostname(self) -> str:
|
|
616
734
|
"""Return charger hostname."""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Constants for the OpenEVSE HTTP python library."""
|
|
2
|
+
USER_AGENT = "python-openevse-http"
|
|
3
|
+
MIN_AMPS = 6
|
|
4
|
+
MAX_AMPS = 48
|
|
5
|
+
|
|
6
|
+
SOLAR = "solar"
|
|
7
|
+
GRID = "grid_ie"
|
|
8
|
+
BAT_LVL = "battery_level"
|
|
9
|
+
BAT_RANGE = "battery_range"
|
|
10
|
+
TTF = "time_to_full_charge"
|
|
11
|
+
VOLTAGE = "voltage"
|
|
12
|
+
SHAPER_LIVE = "shaper_live_pwr"
|
|
13
|
+
TYPE = "type"
|
|
14
|
+
VALUE = "value"
|
|
15
|
+
RELEASE = "release"
|
|
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
|