From 28046de4b9de81c94bcc602b5966c4bb3ba7ee01 Mon Sep 17 00:00:00 2001 From: Klaas Schoute Date: Tue, 31 Aug 2021 23:59:05 +0200 Subject: [PATCH 1/3] Update data in models --- omnikinverter/models.py | 20 +++++++++++++------- test_output.py | 4 +++- tests/fixtures/status.json | 3 +-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/omnikinverter/models.py b/omnikinverter/models.py index 9811233d..fd379b49 100644 --- a/omnikinverter/models.py +++ b/omnikinverter/models.py @@ -13,7 +13,9 @@ class Inverter: serial_number: str | None model: str | None - firmware: str | None + firmware_main: str | None + firmware_slave: str | None + solar_rated_power: int | None solar_current_power: int | None solar_energy_today: float | None solar_energy_total: float | None @@ -31,10 +33,12 @@ def from_json(data: dict[str, Any]) -> Inverter: data = json.loads(data) return Inverter( - serial_number=data["g_sn"], + serial_number=data["i_sn"], model=data["i_modle"], - firmware=data["i_ver_m"], - solar_current_power=data["i_pow_n"], + firmware_main=data["i_ver_m"], + firmware_slave=data["i_ver_s"], + solar_rated_power=int(data["i_pow"]), + solar_current_power=int(data["i_pow_n"]), solar_energy_today=float(data["i_eday"]), solar_energy_total=float(data["i_eall"]), ) @@ -57,8 +61,8 @@ def get_values(position): matches = re.search(r'(?<=myDeviceArray\[0\]=").*?(?=";)', data) data_list = matches.group(0).split(",") - if position in [5, 6, 7]: - if position == 5: + if position in [4, 5, 6, 7]: + if position in [4, 5]: return int(data_list[position]) return float(data_list[position]) / 100 return data_list[position] @@ -66,7 +70,9 @@ def get_values(position): return Inverter( serial_number=get_values(0), model=get_values(3), - firmware=get_values(2), + firmware_main=get_values(1), + firmware_slave=get_values(2), + solar_rated_power=get_values(4), solar_current_power=get_values(5), solar_energy_today=get_values(6), solar_energy_total=get_values(7), diff --git a/test_output.py b/test_output.py index 48c7212a..484e3772 100644 --- a/test_output.py +++ b/test_output.py @@ -17,7 +17,9 @@ async def main(): print() print(f"Serial Number: {inverter.serial_number}") print(f"Model: {inverter.model}") - print(f"Firmware: {inverter.firmware}") + print(f"Firmware Main: {inverter.firmware_main}") + print(f"Firmware Slave: {inverter.firmware_slave}") + print(f"Rated Power: {inverter.solar_rated_power}") print(f"Current Power: {inverter.solar_current_power}") print(f"Energy Production Today: {inverter.solar_energy_today}") print(f"Energy Production Total: {inverter.solar_energy_total}") diff --git a/tests/fixtures/status.json b/tests/fixtures/status.json index 5d4f9ed4..f7d1b124 100644 --- a/tests/fixtures/status.json +++ b/tests/fixtures/status.json @@ -1,6 +1,5 @@ { - "g_sn":"12345678910", - "g_ver":"VER:ME-111001-V1.0.6(2015-10-16)", + "i_sn":"12345678910", "i_ver_m":"V1.25Build23261", "i_ver_s":"V1.40Build52927", "i_modle":"omnik2000tl2", From 4513a0b1e4a7c682e2a2d2ecb7d1e10d816f0b9d Mon Sep 17 00:00:00 2001 From: Klaas Schoute Date: Wed, 1 Sep 2021 00:00:46 +0200 Subject: [PATCH 2/3] Add exception for wrong data source --- omnikinverter/__init__.py | 3 ++- omnikinverter/exceptions.py | 4 ++++ omnikinverter/models.py | 15 +++++++++++---- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/omnikinverter/__init__.py b/omnikinverter/__init__.py index 53782af0..8ed1b722 100644 --- a/omnikinverter/__init__.py +++ b/omnikinverter/__init__.py @@ -1,6 +1,6 @@ """Asynchronous Python client for the Omnik Inverter.""" -from .models import Inverter +from .models import Inverter, OmnikInverterWrongSourceError from .omnikinverter import ( OmnikInverter, OmnikInverterConnectionError, @@ -12,4 +12,5 @@ "OmnikInverter", "OmnikInverterError", "OmnikInverterConnectionError", + "OmnikInverterWrongSourceError", ] diff --git a/omnikinverter/exceptions.py b/omnikinverter/exceptions.py index 0d507c54..0caf9cea 100644 --- a/omnikinverter/exceptions.py +++ b/omnikinverter/exceptions.py @@ -7,3 +7,7 @@ class OmnikInverterError(Exception): class OmnikInverterConnectionError(OmnikInverterError): """Omnik Inverter connection exception.""" + + +class OmnikInverterWrongSourceError(OmnikInverterError): + """Omnik Inverter wrong data source url exception.""" diff --git a/omnikinverter/models.py b/omnikinverter/models.py index fd379b49..f3fc2135 100644 --- a/omnikinverter/models.py +++ b/omnikinverter/models.py @@ -6,6 +6,8 @@ from dataclasses import dataclass from typing import Any +from .exceptions import OmnikInverterWrongSourceError + @dataclass class Inverter: @@ -60,12 +62,17 @@ def get_values(position): else: matches = re.search(r'(?<=myDeviceArray\[0\]=").*?(?=";)', data) - data_list = matches.group(0).split(",") + try: + data_list = matches.group(0).split(",") if position in [4, 5, 6, 7]: if position in [4, 5]: - return int(data_list[position]) - return float(data_list[position]) / 100 - return data_list[position] + return int(data_list[position]) + return float(data_list[position]) / 100 + return data_list[position] + except AttributeError as exception: + raise OmnikInverterWrongSourceError( + "Your inverter has no data source from a javascript file." + ) from exception return Inverter( serial_number=get_values(0), From 0d4a5f7dd26aa993ce84235039d156f138aa954b Mon Sep 17 00:00:00 2001 From: Klaas Schoute Date: Wed, 1 Sep 2021 00:02:44 +0200 Subject: [PATCH 3/3] Add extra tests for pytest --- tests/fixtures/wrong_status.js | 1 + tests/{test_input.py => test_omnik.py} | 54 +++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 tests/fixtures/wrong_status.js rename tests/{test_input.py => test_omnik.py} (52%) diff --git a/tests/fixtures/wrong_status.js b/tests/fixtures/wrong_status.js new file mode 100644 index 00000000..2ff82b5c --- /dev/null +++ b/tests/fixtures/wrong_status.js @@ -0,0 +1 @@ +var txt;var opt;function initPage(){txt=window.parent.reList().page.status;opt=window.parent.reList().page.option;for(var A=1;A<13;A++){inner("t"+A,txt["t"+A]);inner("p1_"+A,txt.pg1[A]);inner("p2_"+A,txt.pg2[A]);inner("p3_"+A,txt.pg3[A]);inner("p4_"+A,txt.pg4[A])}inner("p3_1_1",txt.pg1[6]);inner("p3_2_1",txt.pg1[6]);inner("p3_1_2",txt.pg3[6]);inner("p3_2_2",txt.pg3[6]);inner("p3_1_3",txt.pg3[4]);inner("p3_2_3",txt.pg3[4]);inner("p3_2_4",txt.pg3[5]);inner("p3_2_5",txt.pg3[7]);changeFont();child_getH()}function initData(){child_getH();ajax("status.json?CMD=inv_query&rand="+Math.random())}function ajaxReturn(B){if(B.time!=null){inner("gtype",txt.pg1["s3"]);inner("gsn",B.g_sn);inner("ver",B.g_ver);inner("time",new Date(B.time*1000).toString());inner("worktime",B.g_time+" "+txt.pg1["s4"]);inner("error",B.g_err);inner("mac",B.mac);inner("auto_ip",enb_txt(B.auto_ip));inner("ip",B.ip);inner("sub",B.sub);inner("gate",B.gate);inner("auto_dns",enb_txt(B.auto_dns));inner("dns",B.dns);inner("dns_bak",B.dns_bak);inner("type",reInvBrand(B.i_type));if(B.i_num==null||B.i_num==0){}else{show("inv_data",true);inner("list",B.i_sn);var A=[B.i_sn,B.i_ver_m,B.i_ver_s,B.i_modle,B.i_pow,B.i_pow_n,B.i_eday,B.i_eall,B.i_alarm,B.i_last_t];inv_data_show(A)}inner("ip_a",B.l_a_ip);inner("port_a",B.l_a_port);inner("agreement_a",agr_txt(9,B.l_a_agr));if(B.ip_b!=null){show("server_b",true);inner("ip_b",B.ip_b);inner("port_b",B.port_b);inner("domain_b",B.ipdm_b);inner("agreement_b",agr_txt(9,B.agr_b))}if(B.i_status!=null){if(B.i_status==0){show("inv_data",false)}else{show("inv_data",true)}}}if(B.conn_a!=null){initStatus("status_0",B.conn_a)}if(B.conn_b!=null){initStatus("status_1",B.conn_b)}}var sels=1;function upfold(A){var B=getCon("pg"+A);if(B.style.display=="none"){B.style.display="";getCon("p"+A).src="image/up.png"}else{B.style.display="none";getCon("p"+A).src="image/down.png"}child_getH();if(A==3&&B.style.display!="none"){ajax("s_ping.json?CMD=inv_query&server=110&rand="+Math.random())}}function inv_data_show(A){var D=new Array("list","mver","sver","inv_tp","rate_p","now_p","day_e","all_e","alarm","uptime");if(A!=null){for(var B=1;B<10;B++){if(A[B]==""){if(isNaN(parseInt(A[B]))){inner(D[B],"---");continue}}var C=A[B];switch(B){case 4:C+=" W";break;case 5:if(C*1==4294967295){C="---"}else{C+=" W"}break;case 6:if(C*1==4294967295){C="---"}else{C+=" kWh"}break;case 7:if(C*1==4294967295){C="---"}else{C+=" kWh"}break;case 9:if(getCon("list").innerHTML=="---"){C="---"}else{C+=txt.pg2["s2"]}break}inner(D[B],C)}}}function initStatus(C,B){var A=txt.pg3["s1"];var D=txt.pg3["s2"];if(B==1){getCon(C).innerHTML=A}else{getCon(C).innerHTML=D}}function enb_txt(A){var B=txt.pg2["s4"];if(A==1){B=txt.pg2["s3"]}return B}function agr_txt(C,A){var B="";if(C==1){B=opt[1];if(A==1){B=opt[2]}}if(C==3){B=opt[3];if(A==1){B=opt[4]}}if(C==5){B=opt[5];if(A==1){B=opt[6]}}if(C==7){B=opt[7];if(A==1){B=opt[8]}}if(C==9){if(A==2){B=opt[11]}else{if(A==1){B=opt[10]}else{if(A==3){B=opt[12]}else{B=opt[9]}}}}return B}; diff --git a/tests/test_input.py b/tests/test_omnik.py similarity index 52% rename from tests/test_input.py rename to tests/test_omnik.py index 6ff1811a..665f14f6 100644 --- a/tests/test_input.py +++ b/tests/test_omnik.py @@ -1,8 +1,15 @@ """Test for retrieving information from the Omnik Inverter device.""" +import asyncio + import aiohttp import pytest -from omnikinverter import Inverter, OmnikInverter +from omnikinverter import ( + Inverter, + OmnikInverter, + OmnikInverterConnectionError, + OmnikInverterWrongSourceError, +) from . import load_fixtures @@ -24,9 +31,10 @@ async def test_js_input(aresponses): omnik = OmnikInverter(host="example.com", use_json=False, session=session) inverter: Inverter = await omnik.inverter() assert inverter - assert inverter.firmware == "V5.3-00157" - assert inverter.model == "omnik2000tl2" assert inverter.serial_number == "12345678910" + assert inverter.firmware_main == "NL2-V9.8-5931" + assert inverter.firmware_slave == "V5.3-00157" + assert inverter.model == "omnik2000tl2" assert inverter.solar_current_power == 1010 assert inverter.solar_energy_today == 4.88 assert inverter.solar_energy_total == 1053.19 @@ -49,9 +57,45 @@ async def test_json_input(aresponses): omnik = OmnikInverter(host="example.com", use_json=True, session=session) inverter: Inverter = await omnik.inverter() assert inverter - assert inverter.firmware == "V1.25Build23261" - assert inverter.model == "omnik2000tl2" assert inverter.serial_number == "12345678910" + assert inverter.firmware_slave == "V1.40Build52927" + assert inverter.firmware_main == "V1.25Build23261" + assert inverter.model == "omnik2000tl2" assert inverter.solar_current_power == 1225 assert inverter.solar_energy_today == 10.90 assert inverter.solar_energy_total == 8674.0 + + +@pytest.mark.asyncio +async def test_wrong_source(aresponses): + """Test on wrong data source error raise.""" + aresponses.add( + "example.com", + "/js/status.js", + "GET", + aresponses.Response( + status=200, + headers={"Content-Type": "application/x-javascript"}, + text=load_fixtures("wrong_status.js"), + ), + ) + async with aiohttp.ClientSession() as session: + omnik = OmnikInverter(host="example.com", use_json=False, session=session) + with pytest.raises(OmnikInverterWrongSourceError): + assert await omnik.inverter() + + +@pytest.mark.asyncio +async def test_timeout(aresponses): + """Test request timeout from Omnik Inverter.""" + # Faking a timeout by sleeping + async def response_handler(_): + await asyncio.sleep(0.2) + return aresponses.Response(body="Goodmorning!", text=load_fixtures("status.js")) + + aresponses.add("example.com", "/js/status.js", "GET", response_handler) + + async with aiohttp.ClientSession() as session: + omnik = OmnikInverter(host="example.com", use_json=False, session=session) + with pytest.raises(OmnikInverterConnectionError): + assert await omnik.inverter()