From 83694b1cd23aa603bf8c5b11f095f85d95ad65f7 Mon Sep 17 00:00:00 2001 From: trizmark Date: Wed, 1 May 2024 17:31:35 +0100 Subject: [PATCH 1/6] Add new status codes --- pymyenergi/libbi.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pymyenergi/libbi.py b/pymyenergi/libbi.py index 4976535..322d91e 100644 --- a/pymyenergi/libbi.py +++ b/pymyenergi/libbi.py @@ -1,12 +1,8 @@ -import logging - from pymyenergi.connection import Connection from . import LIBBI from .base_device import BaseDevice -_LOGGER = logging.getLogger(__name__) - STATES = { 0: "Off", 1: "On", @@ -27,9 +23,11 @@ 151: "FW Upgrade (ARM)", 156: "FW Upgrade (DSP)", 172: "BMS Charge Temperature Low", + 176: "BMS Updating", 234: "Calibration Charge", 251: "FW Upgrade (DSP)", 252: "FW Upgrade (ARM)", + 253: "BMS Upgrading" } LIBBI_MODES = ["Stopped", "Normal", "Export"] From fefd3ba6290c828fbdba5a7544d4a50ef9aafecc Mon Sep 17 00:00:00 2001 From: trizmark Date: Wed, 1 May 2024 17:35:22 +0100 Subject: [PATCH 2/6] Fix inconsistent check --- pymyenergi/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymyenergi/connection.py b/pymyenergi/connection.py index 9bac9d7..3eb3619 100644 --- a/pymyenergi/connection.py +++ b/pymyenergi/connection.py @@ -36,7 +36,7 @@ def __init__( self.app_email = app_email self.auth = httpx.DigestAuth(self.username, self.password) self.headers = {"User-Agent": "Wget/1.14 (linux-gnu)"} - if self.app_email and app_password: + if self.app_email and self.app_password: self.oauth = Cognito(_USER_POOL_ID, _CLIENT_ID, username=self.app_email) self.oauth.authenticate(password=self.app_password) self.oauth_headers = {"Authorization": f"Bearer {self.oauth.access_token}"} From 5a30da40d18fc1f303775bbc8c66a34b6b09eb19 Mon Sep 17 00:00:00 2001 From: trizmark Date: Wed, 1 May 2024 20:12:09 +0100 Subject: [PATCH 3/6] Double-check app credentials --- pymyenergi/connection.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pymyenergi/connection.py b/pymyenergi/connection.py index 3eb3619..e17583f 100644 --- a/pymyenergi/connection.py +++ b/pymyenergi/connection.py @@ -57,10 +57,11 @@ def _checkMyenergiServerURL(self, responseHeader): raise WrongCredentials() async def discoverLocations(self): - locs = await self.get("/api/Location", oauth=True) - # check if guest location - use the first location by default - if locs["content"][0]["isGuestLocation"] == True: - self.invitation_id = locs["content"][0]["invitationData"]["invitationId"] + if self.app_email and self.app_password: + locs = await self.get("/api/Location", oauth=True) + # check if guest location - use the first location by default + if locs["content"][0]["isGuestLocation"] == True: + self.invitation_id = locs["content"][0]["invitationData"]["invitationId"] def checkAndUpdateToken(self): # check if we have oauth credentials From 3446fba4bbec2d919efcf6b22f5c1969a4e7bb39 Mon Sep 17 00:00:00 2001 From: trizmark Date: Wed, 1 May 2024 20:27:52 +0100 Subject: [PATCH 4/6] Fix linting errors --- pymyenergi/cli.py | 4 ++-- pymyenergi/client.py | 2 +- pymyenergi/connection.py | 2 +- pymyenergi/libbi.py | 4 ---- pymyenergi/zappi.py | 1 + tests/fixtures/libbi.json | 2 +- tests/test_client.py | 2 +- 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pymyenergi/cli.py b/pymyenergi/cli.py index deec9e0..898dba2 100644 --- a/pymyenergi/cli.py +++ b/pymyenergi/cli.py @@ -13,13 +13,13 @@ from pymyenergi.eddi import BOOST_TARGETS from pymyenergi.eddi import EDDI_MODES from pymyenergi.exceptions import WrongCredentials -from pymyenergi.zappi import CHARGE_MODES from pymyenergi.libbi import LIBBI_MODES +from pymyenergi.zappi import CHARGE_MODES from . import EDDI from . import HARVI -from . import ZAPPI from . import LIBBI +from . import ZAPPI logging.basicConfig() logging.root.setLevel(logging.WARNING) diff --git a/pymyenergi/client.py b/pymyenergi/client.py index 0211b3f..031c495 100644 --- a/pymyenergi/client.py +++ b/pymyenergi/client.py @@ -12,8 +12,8 @@ from . import EDDI from . import FREQUENCY_GRID from . import HARVI -from . import LIBBI from . import HOUR +from . import LIBBI from . import VOLTAGE_GRID from . import ZAPPI from .eddi import Eddi diff --git a/pymyenergi/connection.py b/pymyenergi/connection.py index e17583f..8253e34 100644 --- a/pymyenergi/connection.py +++ b/pymyenergi/connection.py @@ -8,7 +8,6 @@ from typing import Text import httpx - from pycognito import Cognito from .exceptions import MyenergiException @@ -19,6 +18,7 @@ _USER_POOL_ID = 'eu-west-2_E57cCJB20' _CLIENT_ID = '2fup0dhufn5vurmprjkj599041' + class Connection: """Connection to myenergi API.""" diff --git a/pymyenergi/libbi.py b/pymyenergi/libbi.py index 322d91e..afa17bc 100644 --- a/pymyenergi/libbi.py +++ b/pymyenergi/libbi.py @@ -81,10 +81,6 @@ def local_mode(self): """Get current known status""" return self._data.get("lmo", 1) - @property - def prefix(self): - return "E" - @property def ct_keys(self): """Return CT key names that are not none""" diff --git a/pymyenergi/zappi.py b/pymyenergi/zappi.py index 69acadb..c8ced08 100644 --- a/pymyenergi/zappi.py +++ b/pymyenergi/zappi.py @@ -16,6 +16,7 @@ } SINGLE_PHASE = "SINGLE_PHASE" + class Zappi(BaseDevice): """Zappi Client for myenergi API.""" diff --git a/tests/fixtures/libbi.json b/tests/fixtures/libbi.json index 6b7d9a5..05eca1e 100644 --- a/tests/fixtures/libbi.json +++ b/tests/fixtures/libbi.json @@ -38,4 +38,4 @@ "fwv": "3702S5.041", "newAppAvailable": "False", "newBootloaderAvailable": "False" -} \ No newline at end of file +} diff --git a/tests/test_client.py b/tests/test_client.py index f70adb7..329e694 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -2,8 +2,8 @@ from pymyenergi.client import MyenergiClient from pymyenergi.eddi import Eddi from pymyenergi.harvi import Harvi -from pymyenergi.zappi import Zappi from pymyenergi.libbi import Libbi +from pymyenergi.zappi import Zappi # All test coroutines will be treated as marked. pytestmark = pytest.mark.asyncio From d591124478455a92e1870c541387dd0c49362b4d Mon Sep 17 00:00:00 2001 From: trizmark Date: Tue, 14 May 2024 14:26:42 +0100 Subject: [PATCH 5/6] Added graceful OAuth handling to libbi --- pymyenergi/libbi.py | 57 ++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/pymyenergi/libbi.py b/pymyenergi/libbi.py index afa17bc..d6c2838 100644 --- a/pymyenergi/libbi.py +++ b/pymyenergi/libbi.py @@ -27,7 +27,7 @@ 234: "Calibration Charge", 251: "FW Upgrade (DSP)", 252: "FW Upgrade (ARM)", - 253: "BMS Upgrading" + 253: "BMS Upgrading", } LIBBI_MODES = ["Stopped", "Normal", "Export"] @@ -195,12 +195,18 @@ def generated(self): @property def charge_from_grid(self): """Is charging from the grid enabled?""" - return self._extra_data.get("charge_from_grid") + if self._connection.app_email and self._connection.app_password: + return self._extra_data.get("charge_from_grid") + else: + return None @property def charge_target(self): """Libbi charge target""" - return self._extra_data.get("charge_target", 0) / 1000 + if self._connection.app_email and self._connection.app_password: + return self._extra_data.get("charge_target", 0) / 1000 + else: + return None @property def prefix(self): @@ -225,12 +231,15 @@ async def set_operating_mode(self, mode: str): async def set_charge_from_grid(self, charge_from_grid: bool): """Set charge from grid""" - await self._connection.put( - f"/api/AccountAccess/LibbiMode?chargeFromGrid={charge_from_grid}&serialNo={self._serialno}", - oauth=True, - ) - self._extra_data["charge_from_grid"] = charge_from_grid - return True + if self._connection.app_email and self._connection.app_password: + await self._connection.put( + f"/api/AccountAccess/LibbiMode?chargeFromGrid={charge_from_grid}&serialNo={self._serialno}", + oauth=True, + ) + self._extra_data["charge_from_grid"] = charge_from_grid + return True + else: + return False async def set_priority(self, priority): """Set device priority""" @@ -242,12 +251,15 @@ async def set_priority(self, priority): async def set_charge_target(self, charge_target: float): """Set charge target""" - await self._connection.put( - f"/api/AccountAccess/{self._serialno}/TargetEnergy?targetEnergy={charge_target}", - oauth=True, - ) - self._extra_data["charge_target"] = charge_target - return True + if self._connection.app_email and self._connection.app_password: + await self._connection.put( + f"/api/AccountAccess/{self._serialno}/TargetEnergy?targetEnergy={charge_target}", + oauth=True, + ) + self._extra_data["charge_target"] = charge_target + return True + else: + return False def show(self, short_format=False): """Returns a string with all data in human readable format""" @@ -269,11 +281,18 @@ def show(self, short_format=False): ret = ret + f"Status: {self.status}\n" ret = ret + "Local Mode: " + self.get_mode_description(self.local_mode) + "\n" ret = ret + "Charge from Grid: " - if self.charge_from_grid: - ret = ret + "Enabled\n" + if self.charge_from_grid is not None: + if self.charge_from_grid: + ret = ret + "Enabled\n" + else: + ret = ret + "Disabled\n" + else: + ret = ret + f"\n" + ret = ret + f"Charge target: " + if self.charge_target is not None: + ret = ret + f"{self.charge_target}kWh\n" else: - ret = ret + "Disabled\n" - ret = ret + f"Charge target: {self.charge_target}kWh\n" + ret = ret + f"\n" ret = ret + f"CT 1 {self.ct1.name} {self.ct1.power}W phase {self.ct1.phase}\n" ret = ret + f"CT 2 {self.ct2.name} {self.ct2.power}W phase {self.ct2.phase}\n" ret = ret + f"CT 3 {self.ct3.name} {self.ct3.power}W phase {self.ct3.phase}\n" From 5528e7df20f7cde6258034ba7bea54ad490e9a4e Mon Sep 17 00:00:00 2001 From: trizmark Date: Tue, 14 May 2024 15:28:49 +0100 Subject: [PATCH 6/6] added --skip-oauth flag to cli --- README.md | 2 +- pymyenergi/cli.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f4ca8d2..0e84f7c 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ app_password=yourapppassword ### CLI usage ``` -usage: myenergi [-h] [-u USERNAME] [-p PASSWORD] [-e APP_EMAIL] [-a APP_PASSWORD] [-d] [-j] +usage: myenergi [-h] [-u USERNAME] [-p PASSWORD] [-e APP_EMAIL] [-a APP_PASSWORD] [-d] [-j] [--skip-oauth] {list,overview,zappi,eddi,harvi,libbi} ... myenergi CLI. diff --git a/pymyenergi/cli.py b/pymyenergi/cli.py index 898dba2..4381908 100644 --- a/pymyenergi/cli.py +++ b/pymyenergi/cli.py @@ -28,11 +28,15 @@ async def main(args): username = args.username or input("Please enter your hub serial number: ") password = args.password or getpass(prompt="Password (apikey): ") - app_email = args.app_email or input("App email (enter to skip; only needed for libbi): ") - if app_email: - app_password = args.app_password or getpass(prompt="App password: ") + if not args.skip_oauth: + app_email = args.app_email or input("App email (enter to skip; only needed for libbi): ") + if app_email: + app_password = args.app_password or getpass(prompt="App password: ") + else: + app_password = "" else: - app_password = '' + app_email = "" + app_password = "" conn = Connection(username, password, app_password, app_email) if app_email and app_password: await conn.discoverLocations() @@ -195,6 +199,7 @@ def cli(): dest="app_email", default=config.get("hub", "app_email").strip('"'), ) + parser.add_argument("--skip-oauth", dest="skip_oauth", action="store_true", default=False) parser.add_argument("-d", "--debug", dest="debug", action="store_true") parser.add_argument("-j", "--json", dest="json", action="store_true", default=False) parser.add_argument("--version", dest="version", action="store_true", default=False)