diff --git a/.github/workflows/tests/fixtures/rmAlarmsNames.json b/.github/workflows/tests/fixtures/rmAlarmsNames.json new file mode 100644 index 0000000..35d5b8e --- /dev/null +++ b/.github/workflows/tests/fixtures/rmAlarmsNames.json @@ -0,0 +1,14 @@ +{ + "remoteMenuAlarmsNamesVer": "37750", + "data": { + "0": "Power outage", + "1": "Boiler temperature sensor damage.", + "2": "Maximum boiler temperature exceeded.", + "3": "Feeder temperature sensor damage.", + "4": "Maximum feeder temperature exceeded.", + "5": "Emission temp. sensor damage.", + "7": "Unsuccessful boiler firing-up attempt.\nEmpty the ashtray.", + "11": "Fan failure!", + "255": "Alarm continues!" + } +} \ No newline at end of file diff --git a/.github/workflows/tests/fixtures/rmCurrentDataParams_v2.json b/.github/workflows/tests/fixtures/rmCurrentDataParams_v2.json new file mode 100644 index 0000000..b46e1c1 --- /dev/null +++ b/.github/workflows/tests/fixtures/rmCurrentDataParams_v2.json @@ -0,0 +1,355 @@ +{ + "remoteMenuCurrDataParamsVer": "17127", + "data": { + "1": { + "special": 1, + "name": "Lighter", + "unit": 31 + }, + "3": { + "special": 1, + "name": "Poker", + "unit": 31 + }, + "26": { + "special": 1, + "name": "Feeder temperature", + "unit": 1 + }, + "28": { + "special": 1, + "name": "Weather temperature", + "unit": 1 + }, + "113": { + "special": 1, + "name": "Unseal", + "unit": 31 + }, + "114": { + "special": 1, + "name": "Fuel level", + "unit": 31 + }, + "117": { + "special": 1, + "name": "Boiler thermostat", + "unit": 31 + }, + "118": { + "special": 1, + "name": "Room thermostat mixer 1", + "unit": 31 + }, + "119": { + "special": 1, + "name": "Room thermostat mixer 2", + "unit": 31 + }, + "120": { + "special": 1, + "name": "Room thermostat mixer 3", + "unit": 31 + }, + "121": { + "special": 1, + "name": "Room thermostat mixer 4", + "unit": 31 + }, + "139": { + "special": 0, + "name": "Valve mixer 1", + "unit": 5 + }, + "140": { + "special": 0, + "name": "Valve mixer 2", + "unit": 5 + }, + "141": { + "special": 0, + "name": "Valve mixer 3", + "unit": 5 + }, + "142": { + "special": 0, + "name": "Valve mixer 4", + "unit": 5 + }, + "143": { + "special": 4, + "name": "Servo mixer 1", + "unit": 31 + }, + "144": { + "special": 4, + "name": "Servo mixer 2", + "unit": 31 + }, + "145": { + "special": 4, + "name": "Servo mixer 3", + "unit": 31 + }, + "146": { + "special": 4, + "name": "Servo mixer 4", + "unit": 31 + }, + "147": { + "special": 3, + "name": "Valve mixer 1", + "unit": 31 + }, + "148": { + "special": 3, + "name": "Valve mixer 2", + "unit": 31 + }, + "149": { + "special": 3, + "name": "Valve mixer 3", + "unit": 31 + }, + "150": { + "special": 3, + "name": "Valve mixer 4", + "unit": 31 + }, + "151": { + "special": 2, + "name": "Oxygen", + "unit": 31 + }, + "154": { + "special": 1, + "name": "Oxygen", + "unit": 5 + }, + "155": { + "special": 0, + "name": "Work at 100%", + "unit": 4 + }, + "156": { + "special": 0, + "name": "Work at 50%", + "unit": 4 + }, + "157": { + "special": 0, + "name": "Work at 30%", + "unit": 4 + }, + "158": { + "special": 0, + "name": "Feeder work", + "unit": 4 + }, + "159": { + "special": 0, + "name": "Firing-up count", + "unit": 0 + }, + "160": { + "special": 0, + "name": "Number of resets", + "unit": 4 + }, + "161": { + "special": 0, + "name": "IP:", + "unit": 0 + }, + "162": { + "special": 0, + "name": "Mask:", + "unit": 0 + }, + "163": { + "special": 0, + "name": "Gateway:", + "unit": 0 + }, + "164": { + "special": 5, + "name": "Server:", + "unit": 31 + }, + "165": { + "special": 0, + "name": "IP:", + "unit": 0 + }, + "166": { + "special": 0, + "name": "Mask:", + "unit": 0 + }, + "167": { + "special": 0, + "name": "Gateway:", + "unit": 0 + }, + "168": { + "special": 5, + "name": "Server:", + "unit": 31 + }, + "169": { + "special": 6, + "name": "Encryption:", + "unit": 31 + }, + "170": { + "special": 0, + "name": "Signal strenght:", + "unit": 5 + }, + "171": { + "special": 5, + "name": "Wifi status:", + "unit": 31 + }, + "173": { + "special": 0, + "name": "SSID:", + "unit": 0 + }, + "1024": { + "special": 1, + "name": "Boiler temperature", + "unit": 1 + }, + "1025": { + "special": 1, + "name": "HUW temperature", + "unit": 1 + }, + "1028": { + "special": 1, + "name": "Upper buffer temperature", + "unit": 1 + }, + "1029": { + "special": 1, + "name": "Lower buffer temperature", + "unit": 1 + }, + "1030": { + "special": 1, + "name": "Emission temperature", + "unit": 1 + }, + "1031": { + "special": 1, + "name": "Temp. mixer 1", + "unit": 1 + }, + "1032": { + "special": 1, + "name": "Temp. mixer 2", + "unit": 1 + }, + "1033": { + "special": 1, + "name": "Temp. mixer 3", + "unit": 1 + }, + "1034": { + "special": 1, + "name": "Temp. mixer 4", + "unit": 1 + }, + "1280": { + "special": 0, + "name": "Preset boiler temperature", + "unit": 1 + }, + "1281": { + "special": 0, + "name": "HUW preset temperature", + "unit": 1 + }, + "1287": { + "special": 0, + "name": "Preset temp. mixer 1", + "unit": 1 + }, + "1288": { + "special": 0, + "name": "Preset temp. mixer 2", + "unit": 1 + }, + "1289": { + "special": 0, + "name": "Preset temp. mixer 3", + "unit": 1 + }, + "1290": { + "special": 0, + "name": "Preset temp. mixer 4", + "unit": 1 + }, + "1536": { + "special": 1, + "name": "Fan", + "unit": 31 + }, + "1538": { + "special": 1, + "name": "Feeder", + "unit": 31 + }, + "1540": { + "special": 1, + "name": "Additional feeder", + "unit": 31 + }, + "1541": { + "special": 1, + "name": "Boiler pump", + "unit": 31 + }, + "1542": { + "special": 1, + "name": "HUW pump", + "unit": 31 + }, + "1543": { + "special": 1, + "name": "Circulating pump", + "unit": 31 + }, + "1544": { + "special": 1, + "name": "Pump mixer 1", + "unit": 31 + }, + "1547": { + "special": 1, + "name": "Pump mixer 2", + "unit": 31 + }, + "1550": { + "special": 1, + "name": "Pump mixer 3", + "unit": 31 + }, + "1553": { + "special": 1, + "name": "Pump mixer 4", + "unit": 31 + }, + "1792": { + "special": 7, + "name": "", + "unit": 31 + }, + "1794": { + "special": 0, + "name": "Burner output", + "unit": 5 + } + } +} \ No newline at end of file diff --git a/.github/workflows/tests/fixtures/rmStructure.json b/.github/workflows/tests/fixtures/rmStructure.json new file mode 100644 index 0000000..762bb4a --- /dev/null +++ b/.github/workflows/tests/fixtures/rmStructure.json @@ -0,0 +1,1346 @@ +{ + "remoteMenuStructureVer": 18631, + "data": [ + { + "pass_index": 0, + "index": 1, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 0, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 8, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 1, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 2, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 3, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 4, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 5, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 9, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 11, + "type": 5, + "lock": false + }, + { + "pass_index": 0, + "index": 8, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 12, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 13, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 14, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 15, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 16, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 20, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 21, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 23, + "type": 2, + "lock": false + }, + { + "pass_index": 0, + "index": 7, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 46, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 111, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 112, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 121, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 24, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 25, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 132, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 5, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 49, + "type": 1, + "lock_index": 3, + "lock": true + }, + { + "pass_index": 0, + "index": 52, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 53, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 54, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 3, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 55, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 56, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 57, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 6, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 63, + "type": 1, + "lock_index": 2, + "lock": true + }, + { + "pass_index": 0, + "index": 75, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 79, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 83, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 122, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 2, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 161, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 162, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 4, + "type": 7, + "lock": false + }, + { + "pass_index": 1, + "index": 26, + "type": 0, + "lock": false + }, + { + "pass_index": 2, + "index": 27, + "type": 0, + "lock": false + }, + { + "pass_index": 3, + "index": 28, + "type": 0, + "lock": false + }, + { + "pass_index": 4, + "index": 29, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 10, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 0, + "type": 3, + "lock": false, + "data_id": "1024" + }, + { + "pass_index": 0, + "index": 26, + "type": 3, + "lock": false, + "data_id": "26" + }, + { + "pass_index": 0, + "index": 28, + "type": 3, + "lock": false, + "data_id": "28" + }, + { + "pass_index": 0, + "index": 6, + "type": 3, + "lock": false, + "data_id": "1030" + }, + { + "pass_index": 0, + "index": 1, + "type": 3, + "lock": false, + "data_id": "1025" + }, + { + "pass_index": 0, + "index": 12, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 4, + "type": 3, + "lock": false, + "data_id": "1028" + }, + { + "pass_index": 0, + "index": 5, + "type": 3, + "lock": false, + "data_id": "1029" + }, + { + "pass_index": 0, + "index": 113, + "type": 3, + "lock": false, + "data_id": "113" + }, + { + "pass_index": 0, + "index": 114, + "type": 3, + "lock": false, + "data_id": "114" + }, + { + "pass_index": 0, + "index": 117, + "type": 3, + "lock": false, + "data_id": "117" + }, + { + "pass_index": 0, + "index": 151, + "type": 3, + "lock": false, + "data_id": "151" + }, + { + "pass_index": 0, + "index": 12, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 5, + "type": 3, + "lock": false, + "data_id": "1541" + }, + { + "pass_index": 0, + "index": 0, + "type": 3, + "lock": false, + "data_id": "1536" + }, + { + "pass_index": 0, + "index": 2, + "type": 3, + "lock": false, + "data_id": "1538" + }, + { + "pass_index": 0, + "index": 1, + "type": 3, + "lock": false, + "data_id": "1" + }, + { + "pass_index": 0, + "index": 3, + "type": 3, + "lock": false, + "data_id": "3" + }, + { + "pass_index": 0, + "index": 6, + "type": 3, + "lock": false, + "data_id": "1542" + }, + { + "pass_index": 0, + "index": 4, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 4, + "type": 3, + "lock": false, + "data_id": "1540" + }, + { + "pass_index": 0, + "index": 2, + "type": 3, + "lock": false, + "data_id": "1794" + }, + { + "pass_index": 0, + "index": 12, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 7, + "type": 3, + "lock": false, + "data_id": "1031" + }, + { + "pass_index": 0, + "index": 7, + "type": 3, + "lock": false, + "data_id": "1287" + }, + { + "pass_index": 0, + "index": 118, + "type": 3, + "lock": false, + "data_id": "118" + }, + { + "pass_index": 0, + "index": 8, + "type": 3, + "lock": false, + "data_id": "1544" + }, + { + "pass_index": 0, + "index": 139, + "type": 3, + "lock": false, + "data_id": "139" + }, + { + "pass_index": 0, + "index": 143, + "type": 3, + "lock": false, + "data_id": "143" + }, + { + "pass_index": 0, + "index": 8, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 171, + "type": 3, + "lock": false, + "data_id": "171" + }, + { + "pass_index": 0, + "index": 173, + "type": 3, + "lock": false, + "data_id": "173" + }, + { + "pass_index": 0, + "index": 169, + "type": 3, + "lock": false, + "data_id": "169" + }, + { + "pass_index": 0, + "index": 170, + "type": 3, + "lock": false, + "data_id": "170" + }, + { + "pass_index": 0, + "index": 8, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 165, + "type": 3, + "lock": false, + "data_id": "165" + }, + { + "pass_index": 0, + "index": 166, + "type": 3, + "lock": false, + "data_id": "166" + }, + { + "pass_index": 0, + "index": 167, + "type": 3, + "lock": false, + "data_id": "167" + }, + { + "pass_index": 0, + "index": 168, + "type": 3, + "lock": false, + "data_id": "168" + }, + { + "pass_index": 0, + "index": 10, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 155, + "type": 3, + "lock": false, + "data_id": "155" + }, + { + "pass_index": 0, + "index": 156, + "type": 3, + "lock": false, + "data_id": "156" + }, + { + "pass_index": 0, + "index": 157, + "type": 3, + "lock": false, + "data_id": "157" + }, + { + "pass_index": 0, + "index": 159, + "type": 3, + "lock": false, + "data_id": "159" + }, + { + "pass_index": 0, + "index": 158, + "type": 3, + "lock": false, + "data_id": "158" + }, + { + "pass_index": 0, + "index": 19, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 19, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 20, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 9, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 21, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 22, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 10, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 23, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 24, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 11, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 18, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 12, + "type": 1, + "lock_index": 4, + "lock": true + }, + { + "pass_index": 0, + "index": 45, + "type": 1, + "lock_index": 4, + "lock": true + }, + { + "pass_index": 0, + "index": 13, + "type": 1, + "lock_index": 4, + "lock": true + }, + { + "pass_index": 0, + "index": 14, + "type": 1, + "lock_index": 4, + "lock": true + }, + { + "pass_index": 0, + "index": 133, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 1, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 139, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 5, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 30, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 31, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 33, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 37, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 163, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 0, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 5, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 149, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 152, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 148, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 157, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 158, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 1, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 38, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 19, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 39, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 40, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 41, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 42, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 43, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 47, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 48, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 37, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 140, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 147, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 146, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 131, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 142, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 143, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 113, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 15, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 16, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 17, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 150, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 8, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 58, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 59, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 50, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 51, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 60, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 61, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 62, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 151, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 8, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 87, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 67, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 71, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 91, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 95, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 103, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 99, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 107, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 4, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 159, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 160, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 144, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 164, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 1, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 44, + "type": 0, + "lock": false + }, + { + "pass_index": 0, + "index": 9, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 25, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 26, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 27, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 28, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 29, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 30, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 31, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 32, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 33, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 12, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 0, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 1, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 2, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 41, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 3, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 4, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 5, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 42, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 6, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 7, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 8, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 43, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 2, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 134, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 135, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 4, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 34, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 35, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 36, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 145, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 8, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 153, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 38, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 39, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 40, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 44, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 154, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 155, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 156, + "type": 1, + "lock": false + }, + { + "pass_index": 0, + "index": 2, + "type": 7, + "lock": false + }, + { + "pass_index": 0, + "index": 160, + "type": 3, + "lock": false, + "data_id": "160" + } + ] +} \ No newline at end of file diff --git a/.github/workflows/tests/fixtures/sysParams.json b/.github/workflows/tests/fixtures/sysParams.json new file mode 100644 index 0000000..3ce6f2f --- /dev/null +++ b/.github/workflows/tests/fixtures/sysParams.json @@ -0,0 +1,953 @@ +{ + regRefresh: 5, + lan: false, + uid: "7VCPMB4ZJ8DHH208002Z0", + ecosrvSoftVer: "3.2.3819", + regAllowed: true, + schedules: { + ecomaxSchedules: { + mixer1TZ: [ + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 0, + 0, + 0, + 20 + ] + ], + cwuTZ: [ + [ + 192, + 15, + 255, + 0, + 1, + 255 + ], + [ + 192, + 127, + 224, + 3, + 255, + 255 + ], + [ + 192, + 127, + 224, + 3, + 255, + 255 + ], + [ + 192, + 31, + 224, + 3, + 255, + 255 + ], + [ + 192, + 31, + 224, + 3, + 255, + 255 + ], + [ + 192, + 15, + 128, + 3, + 255, + 255 + ], + [ + 192, + 15, + 255, + 255, + 255, + 255 + ], + [ + 0, + 10, + 0, + 20 + ] + ], + boilerTZ: [ + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 255, + 255, + 255, + 255, + 255, + 255 + ], + [ + 0, + 0, + 0, + 20 + ] + ], + boilerWorkTZ: [ + [ + 255, + 252, + 0, + 0, + 7, + 255 + ], + [ + 255, + 252, + 0, + 0, + 7, + 255 + ], + [ + 255, + 252, + 0, + 0, + 7, + 255 + ], + [ + 255, + 252, + 0, + 0, + 7, + 255 + ], + [ + 255, + 252, + 0, + 0, + 7, + 255 + ], + [ + 255, + 252, + 0, + 0, + 7, + 255 + ], + [ + 255, + 252, + 0, + 0, + 7, + 255 + ], + [ + 0, + 0, + 0, + 20 + ] + ] + } + }, + panelsNames: [], + tiles: [ + { + minValue_: 0, + idx: 0, + seqNo_: 1, + bit_: null, + type_: "tile_text", + name_: null, + maxValue_: 100, + memberName_: "mode", + extra_: "CAN_TURN_OFF_BOILER" + }, + { + minValue_: 0, + idx: 1, + seqNo_: 3, + bit_: null, + type_: "tile_power", + name_: null, + maxValue_: 100, + memberName_: "boilerPower" + }, + { + minValue_: 0, + idx: 2, + seqNo_: 4, + bit_: null, + type_: "tile_level", + name_: null, + maxValue_: 100, + memberName_: "fuelLevel" + }, + { + minValue_: 0, + idx: 3, + seqNo_: 6, + bit_: null, + type_: "tile_fan", + name_: null, + maxValue_: 100, + memberName_: "fanPower" + }, + { + minValue_: 0, + idx: 4, + seqNo_: 8, + bit_: null, + type_: "tile_temp_ro", + name_: null, + maxValue_: 450, + memberName_: "tempFlueGas" + }, + { + minValue_: 0, + idx: 5, + seqNo_: 9, + bit_: null, + type_: "tile_text_icon", + name_: null, + maxValue_: 100, + memberName_: "lambdaLevel" + }, + { + minValue_: 0, + idx: 6, + seqNo_: 10, + bit_: null, + type_: "tile_temp", + name_: null, + setMemberName_: "tempCOSet", + maxValue_: 100, + memberName_: "tempCO" + }, + { + minValue_: 0, + idx: 7, + seqNo_: 12, + bit_: null, + type_: "tile_temp", + name_: null, + setMemberName_: "tempCWUSet", + maxValue_: 100, + memberName_: "tempCWU", + extra_: null + }, + { + minValue_: -35, + idx: 8, + seqNo_: 13, + bit_: null, + type_: "tile_temp_ro", + name_: null, + maxValue_: 40, + memberName_: "tempExternalSensor" + }, + { + minValue_: 0, + idx: 9, + seqNo_: 16, + bit_: null, + type_: "tile_temp", + name_: null, + setMemberName_: "mixerSetTemp1", + maxValue_: 100, + memberName_: "mixerTemp1", + extra_: null + }, + { + minValue_: 0, + idx: 10, + seqNo_: 100000, + bit_: null, + type_: "tile_temp_ro", + name_: null, + maxValue_: 100, + memberName_: "tempFeeder" + } + ], + modulesVers: [ + [ + "lbModuleAVerCurr", + "8.30.176", + 9 + ], + [ + "lbPanelModuleVerCurr", + "8.11.42", + 79 + ], + [ + "lbModuleBVerCurr", + "1.30.7", + 19 + ], + [ + "lbLambdaModuleVerCurr", + "0.1.7", + 31 + ] + ], + etNewConfTrans: false, + etConfDesc: null, + schema: {}, + key: "secret_key", + mainSrv: true, + servicePassword: "b61265c6a561e90476ef78be3d2cea768306afa55a2edasdasd5a4d6a46d4a684d68a46da46sd4a6s4d65as4d654as6d54as3dd172f", + password: "********************************************", + quality: 74, + eth0: "0.0.0.0", + ecosrvPort: "443", + tilesET: null, + etPasswords: {}, + ssid: "secret_wifi_ssid_name", + logFl: 0, + encryption: "psk2", + signal: "-54", + wifi: true, + fuelConsumptionCalc: false, + econetConfVer: null, + wlan0: "10.10.1.77", + alarms: [ + { + code: "0", + fromDate: "2024-03-14 23:01:18", + toDate: "2024-03-14 23:05:10" + }, + { + code: "0", + fromDate: "2024-03-14 22:58:47", + toDate: "2024-03-14 23:00:17" + }, + { + code: "0", + fromDate: "2024-03-14 22:06:26", + toDate: "2024-03-14 22:15:02" + }, + { + code: "0", + fromDate: "2024-03-03 10:32:14", + toDate: "2024-03-08 23:58:21" + }, + { + code: "0", + fromDate: "2024-02-28 10:13:26", + toDate: "2024-02-28 10:35:02" + }, + { + code: "0", + fromDate: "2024-02-27 14:12:08", + toDate: "2024-02-27 14:38:52" + }, + { + code: "7", + fromDate: "2024-02-04 11:57:42", + toDate: "2024-02-04 13:38:39" + }, + { + code: "7", + fromDate: "2024-02-04 00:07:41", + toDate: "2024-02-04 10:35:51" + }, + { + code: "7", + fromDate: "2024-02-03 09:02:34", + toDate: "2024-02-03 09:21:06" + }, + { + code: "7", + fromDate: "2024-01-30 15:31:02", + toDate: "2024-01-30 19:28:44" + }, + { + code: "7", + fromDate: "2024-01-03 21:19:05", + toDate: "2024-01-04 07:02:46" + }, + { + code: "7", + fromDate: "2024-01-03 08:38:11", + toDate: "2024-01-03 20:18:48" + }, + { + code: "7", + fromDate: "2024-01-02 22:00:35", + toDate: "2024-01-03 06:38:18" + }, + { + code: "7", + fromDate: "2023-12-07 17:56:42", + toDate: "2023-12-07 18:20:14" + }, + { + code: "0", + fromDate: "2023-11-12 21:14:53", + toDate: "2023-11-12 21:18:00" + }, + { + code: "0", + fromDate: "2023-11-12 21:05:56", + toDate: "2023-11-12 21:09:27" + }, + { + code: "0", + fromDate: "2023-11-12 20:53:29", + toDate: "2023-11-12 20:54:16" + }, + { + code: "0", + fromDate: "2023-11-12 19:29:30", + toDate: "2023-11-12 19:30:06" + }, + { + code: "0", + fromDate: "2023-11-05 16:28:41", + toDate: "2023-11-05 16:33:25" + }, + { + code: "0", + fromDate: "2023-11-02 19:00:21", + toDate: "2023-11-02 19:00:36" + }, + { + code: "7", + fromDate: "2023-10-23 20:53:19", + toDate: "2023-10-23 21:16:31" + }, + { + code: "7", + fromDate: "2023-10-23 18:34:59", + toDate: "2023-10-23 19:48:58" + }, + { + code: "7", + fromDate: "2023-10-23 13:04:38", + toDate: "2023-10-23 14:16:26" + }, + { + code: "0", + fromDate: "2023-10-21 02:07:10", + toDate: "2023-10-21 02:13:58" + }, + { + code: "0", + fromDate: "2023-10-21 01:39:17", + toDate: "2023-10-21 01:40:34" + }, + { + code: "0", + fromDate: "2023-10-19 12:22:09", + toDate: "2023-10-19 12:27:18" + }, + { + code: "0", + fromDate: "2023-09-27 13:02:08", + toDate: "2023-09-27 13:32:57" + }, + { + code: "0", + fromDate: "2023-07-31 19:08:20", + toDate: "2023-07-31 19:25:56" + }, + { + code: "7", + fromDate: "2023-07-31 12:55:52", + toDate: "2023-07-31 19:00:46" + }, + { + code: "7", + fromDate: "2023-07-31 00:58:45", + toDate: "2023-07-31 06:22:36" + }, + { + code: "0", + fromDate: "2023-07-30 17:05:45", + toDate: "2023-07-30 18:47:27" + }, + { + code: "7", + fromDate: "2023-07-30 09:54:08", + toDate: "2023-07-30 09:55:50" + }, + { + code: "7", + fromDate: "2023-07-30 07:59:46", + toDate: "2023-07-30 08:51:33" + }, + { + code: "7", + fromDate: "2023-07-30 04:14:02", + toDate: "2023-07-30 07:03:56" + }, + { + code: "7", + fromDate: "2023-07-30 01:23:47", + toDate: "2023-07-30 01:26:15" + }, + { + code: "7", + fromDate: "2023-07-29 19:45:06", + toDate: "2023-07-29 19:55:32" + }, + { + code: "7", + fromDate: "2023-07-29 02:47:35", + toDate: "2023-07-29 07:43:00" + }, + { + code: "7", + fromDate: "2023-07-28 10:28:45", + toDate: "2023-07-28 10:30:25" + }, + { + code: "7", + fromDate: "2023-07-28 02:57:55", + toDate: "2023-07-28 08:25:48" + }, + { + code: "7", + fromDate: "2023-07-28 00:46:15", + toDate: "2023-07-28 01:40:15" + }, + { + code: "7", + fromDate: "2023-07-27 21:12:27", + toDate: "2023-07-27 21:45:53" + }, + { + code: "7", + fromDate: "2023-07-27 19:51:34", + toDate: "2023-07-27 20:12:50" + }, + { + code: "7", + fromDate: "2023-07-27 15:46:12", + toDate: "2023-07-27 18:40:06" + }, + { + code: "7", + fromDate: "2023-07-27 09:00:49", + toDate: "2023-07-27 09:19:39" + }, + { + code: "7", + fromDate: "2023-07-21 08:29:53", + toDate: "2023-07-21 09:09:07" + }, + { + code: "7", + fromDate: "2023-07-20 21:12:53", + toDate: "2023-07-20 21:57:05" + }, + { + code: "7", + fromDate: "2023-07-20 09:33:18", + toDate: "2023-07-20 18:39:03" + }, + { + code: "7", + fromDate: "2023-07-19 00:22:21", + toDate: "2023-07-19 06:39:37" + }, + { + code: "0", + fromDate: "2023-07-18 19:49:01", + toDate: "2023-07-18 20:07:31" + }, + { + code: "0", + fromDate: "2023-07-18 18:43:24", + toDate: "2023-07-18 19:47:06" + }, + { + code: "7", + fromDate: "2023-07-18 10:26:47", + toDate: "2023-07-18 17:28:02" + }, + { + code: "7", + fromDate: "2023-07-18 09:22:47", + toDate: "2023-07-18 09:26:56" + }, + { + code: "0", + fromDate: "2023-07-18 08:17:12", + toDate: "2023-07-18 08:18:01" + }, + { + code: "7", + fromDate: "2023-07-18 07:56:42", + toDate: "2023-07-18 07:59:08" + }, + { + code: "7", + fromDate: "2023-07-18 05:45:02", + toDate: "2023-07-18 06:50:23" + }, + { + code: "0", + fromDate: "2023-06-16 09:50:07", + toDate: "2023-06-22 00:47:12" + }, + { + code: "7", + fromDate: "2023-05-07 04:45:49", + toDate: "2023-05-07 06:03:46" + }, + { + code: "7", + fromDate: "2023-05-04 20:29:40", + toDate: "2023-05-05 06:37:10" + }, + { + code: "7", + fromDate: "2023-04-30 15:05:32", + toDate: "2023-04-30 15:07:11" + }, + { + code: "7", + fromDate: "2023-04-29 14:49:29", + toDate: "2023-04-29 15:28:23" + }, + { + code: "7", + fromDate: "2023-04-28 08:45:06", + toDate: "2023-04-29 13:53:23" + }, + { + code: "0", + fromDate: "2023-04-02 08:33:29", + toDate: "2023-04-02 08:38:46" + }, + { + code: "0", + fromDate: "2023-03-30 17:56:31", + toDate: "2023-03-30 17:58:59" + }, + { + code: "0", + fromDate: "2023-03-23 12:15:45", + toDate: "2023-03-23 12:17:20" + }, + { + code: "0", + fromDate: "2023-03-15 21:41:30", + toDate: "2023-03-15 21:42:13" + }, + { + code: "2", + fromDate: "2023-03-14 20:29:19", + toDate: "2023-03-14 20:53:30" + }, + { + code: "0", + fromDate: "2023-02-28 12:38:03", + toDate: "2023-02-28 12:39:33" + }, + { + code: "0", + fromDate: "2023-02-28 12:25:44", + toDate: "2023-02-28 12:32:29" + }, + { + code: "0", + fromDate: "2023-02-28 12:06:37", + toDate: "2023-02-28 12:08:23" + }, + { + code: "7", + fromDate: "2023-02-27 07:00:53", + toDate: "2023-02-28 09:59:02" + }, + { + code: "7", + fromDate: "2023-02-25 16:11:42", + toDate: "2023-02-26 17:42:59" + }, + { + code: "7", + fromDate: "2023-02-24 01:11:00", + toDate: "2023-02-24 09:18:31" + }, + { + code: "7", + fromDate: "2023-02-21 20:02:05", + toDate: "2023-02-21 22:23:43" + }, + { + code: "7", + fromDate: "2023-02-19 05:48:38", + toDate: "2023-02-19 06:02:29" + }, + { + code: "7", + fromDate: "2023-02-17 17:53:59", + toDate: "2023-02-17 21:43:28" + }, + { + code: "7", + fromDate: "2023-02-16 23:15:26", + toDate: "2023-02-17 00:16:18" + }, + { + code: "7", + fromDate: "2023-02-14 00:43:19", + toDate: "2023-02-14 10:04:33" + }, + { + code: "7", + fromDate: "2023-02-12 16:27:40", + toDate: "2023-02-12 17:44:12" + }, + { + code: "7", + fromDate: "2023-02-06 23:27:31", + toDate: "2023-02-07 06:55:51" + }, + { + code: "7", + fromDate: "2023-01-26 22:13:50", + toDate: "2023-01-27 09:48:32" + }, + { + code: "7", + fromDate: "2023-01-18 13:53:34", + toDate: "2023-01-18 18:58:03" + }, + { + code: "0", + fromDate: "2023-01-14 07:42:13", + toDate: "2023-01-14 08:55:26" + }, + { + code: "0", + fromDate: "2022-12-28 18:15:46", + toDate: "2022-12-28 18:16:16" + }, + { + code: "7", + fromDate: "2022-12-04 16:52:37", + toDate: "2022-12-28 18:16:32" + }, + { + code: "7", + fromDate: "2022-12-04 15:37:53", + toDate: "2022-12-04 15:55:58" + }, + { + code: "0", + fromDate: "2022-11-23 22:02:01", + toDate: "2022-11-23 22:07:44" + }, + { + code: "0", + fromDate: "2022-02-13 20:30:57", + toDate: "2022-02-19 05:13:09" + }, + { + code: "7", + fromDate: "2022-02-02 07:20:55", + toDate: "2022-02-02 09:43:04" + }, + { + code: "7", + fromDate: "2022-02-01 21:12:51", + toDate: "2022-02-02 06:19:48" + }, + { + code: "7", + fromDate: "2022-01-30 21:10:19", + toDate: "2022-01-30 21:12:56" + }, + { + code: "0", + fromDate: "2022-01-26 04:06:07", + toDate: "2022-01-26 04:10:24" + }, + { + code: "7", + fromDate: "2022-01-22 14:21:59", + toDate: "2022-01-22 16:50:10" + }, + { + code: "7", + fromDate: "2022-01-22 09:07:05", + toDate: "2022-01-22 13:25:54" + }, + { + code: "7", + fromDate: "2022-01-19 21:21:49", + toDate: "2022-01-19 22:15:17" + }, + { + code: "7", + fromDate: "2022-01-09 15:23:27", + toDate: "2022-01-09 16:10:01" + }, + { + code: "7", + fromDate: "2022-01-09 12:33:41", + toDate: "2022-01-09 14:27:22" + }, + { + code: "7", + fromDate: "2022-01-08 23:47:44", + toDate: "2022-01-09 11:37:34" + }, + { + code: "7", + fromDate: "2021-12-03 12:22:54", + toDate: "2021-12-03 20:06:01" + }, + { + code: "7", + fromDate: "2021-12-02 05:15:46", + toDate: "2021-12-02 08:16:38" + }, + { + code: "0", + fromDate: "2021-11-27 03:02:39", + toDate: "2021-11-27 03:02:53" + } + ], + remoteMenu: true, + login: "login_name", + ecosrvAddr: "econet24.com", + etConfVer: null, + ecosrvHttps: true, + history: [], + settingsVer: 30827, + softVer: "3.2.3819", + routerType: "mr3020-v3", + protocolType: "em", + controllerID: "ecoMAX810P-L TOUCH", + prodLogo: 2, + regImgID: 2, + regType: 0, + regProd: 2, + moduleASoftVer: "8.30.176.R1", + moduleBSoftVer: "1.30.7", + moduleCSoftVer: null, + moduleLambdaSoftVer: "3.2.7", + moduleEcoSTERSoftVer: null, + modulePanelSoftVer: "8.11.42", + schemaID: 24, + panelVer: null +} \ No newline at end of file diff --git a/custom_components/econet300/__init__.py b/custom_components/econet300/__init__.py index 03268a6..9fafe6a 100644 --- a/custom_components/econet300/__init__.py +++ b/custom_components/econet300/__init__.py @@ -1,4 +1,5 @@ """The Example Integration integration.""" + from __future__ import annotations from homeassistant.config_entries import ConfigEntry @@ -22,7 +23,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: cache = MemCache() try: - api = await make_api(hass, cache, entry.data) + data: dict[str, str] = dict(entry.data) + api = await make_api(hass, cache, data) coordinator = EconetDataCoordinator(hass, api) await coordinator.async_config_entry_first_refresh() @@ -31,14 +33,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: SERVICE_API: api, SERVICE_COORDINATOR: coordinator, } - - await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - return True - except AuthError as auth_error: raise ConfigEntryAuthFailed("Client not authenticated") from auth_error except TimeoutError as timeout_error: raise ConfigEntryNotReady("Target not found") from timeout_error + else: + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + return True async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/custom_components/econet300/api.py b/custom_components/econet300/api.py index 1adc953..6a5f0b7 100644 --- a/custom_components/econet300/api.py +++ b/custom_components/econet300/api.py @@ -1,4 +1,5 @@ """Econet300 API class class describint methods of getting and setting data.""" + import asyncio from http import HTTPStatus import logging @@ -111,8 +112,7 @@ async def _get(self, url): except TimeoutError: _LOGGER.warning("Timeout error, retry(%i/%i)", attempt, max_attempts) await asyncio.sleep(1) - finally: - attempt += 1 + attempt += 1 class Econet300Api: @@ -232,10 +232,9 @@ async def get_param_limits(self, param: str): async def fetch_data(self) -> dict[str, Any]: """Fetch data from regParamsData.""" - reg_params = await self._fetch_reg_key( + return await self._fetch_reg_key( API_REG_PARAMS_DATA_URI, API_REG_PARAMS_DATA_PARAM_DATA ) - return reg_params async def _fetch_reg_key(self, reg, data_key: str | None = None): """Fetch a key from the json-encoded data returned by the API for a given registry If key is None, then return whole data.""" diff --git a/custom_components/econet300/binary_sensor.py b/custom_components/econet300/binary_sensor.py index 12f83df..c3cf58b 100644 --- a/custom_components/econet300/binary_sensor.py +++ b/custom_components/econet300/binary_sensor.py @@ -1,4 +1,5 @@ """Econet binary sensor.""" + from dataclasses import dataclass import logging @@ -26,7 +27,7 @@ _LOGGER = logging.getLogger(__name__) -@dataclass +@dataclass(frozen=True) class EconetBinarySensorEntityDescription(BinarySensorEntityDescription): """Describes Econet binary sensor entity.""" @@ -118,4 +119,5 @@ async def async_setup_entry( entities: list[EconetBinarySensor] = [] entities.extend(create_binary_sensors(coordinator, api)) - return async_add_entities(entities) + async_add_entities(entities) + return True diff --git a/custom_components/econet300/common_functions.py b/custom_components/econet300/common_functions.py index fc1db06..2e15026 100644 --- a/custom_components/econet300/common_functions.py +++ b/custom_components/econet300/common_functions.py @@ -9,7 +9,7 @@ def camel_to_snake(key: str) -> str: return re.sub("([a-z0-9])([A-Z])", r"\1_\2", key).lower() -def get_key_by_value(search_dict: dict, search_value: str) -> str: +def get_key_by_value(search_dict: dict, search_value: str) -> str | None: """Get a key from a dict by passing its value.""" for key, value in search_dict.items(): if value == search_value: diff --git a/custom_components/econet300/config_flow.py b/custom_components/econet300/config_flow.py index 86c0f3e..562a6f3 100644 --- a/custom_components/econet300/config_flow.py +++ b/custom_components/econet300/config_flow.py @@ -1,4 +1,5 @@ """Config flow for Example Integration integration.""" + from __future__ import annotations import logging diff --git a/custom_components/econet300/const.py b/custom_components/econet300/const.py index dc3ad13..38b2d2f 100644 --- a/custom_components/econet300/const.py +++ b/custom_components/econet300/const.py @@ -1,4 +1,5 @@ """Constants from the Home Assistant.""" + from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.number import NumberDeviceClass from homeassistant.components.sensor import SensorDeviceClass, SensorStateClass @@ -131,6 +132,7 @@ } BINARY_SENSOR_MAP = { + "1": "lighter", "111": "weatherControl", "113": "unseal", "117": "thermostat", @@ -228,6 +230,7 @@ ############################# ###### BINARY SENSORS ####### ############################# + "lighter": BinarySensorDeviceClass.RUNNING, "weatherControl": BinarySensorDeviceClass.RUNNING, "unseal": BinarySensorDeviceClass.RUNNING, "thermostat": BinarySensorDeviceClass.RUNNING, @@ -296,14 +299,18 @@ ENTITY_VALUE_PROCESSOR = { "mode": lambda x: OPERATION_MODE_NAMES.get(x, "unknown"), "thermostat": ( - lambda x: "ON" - if str(x).strip() == "true" - else ("OFF" if str(x).strip() == "false" else None) + lambda x: ( + "ON" + if str(x).strip() == "true" + else ("OFF" if str(x).strip() == "false" else None) + ) ), "lambdaStatus": ( - lambda x: "stop" - if x == 0 - else ("start" if x == 1 else ("working" if x == 2 else "unknown")) + lambda x: ( + "stop" + if x == 0 + else ("start" if x == 1 else ("working" if x == 2 else "unknown")) + ) ), "status_wifi": lambda x: "Connected" if x == 1 else "Disconnected", "main_server": lambda x: "Server available" if x == 1 else "Server not available", diff --git a/custom_components/econet300/number.py b/custom_components/econet300/number.py index 78f7c19..bb95006 100644 --- a/custom_components/econet300/number.py +++ b/custom_components/econet300/number.py @@ -29,7 +29,7 @@ _LOGGER = logging.getLogger(__name__) -@dataclass +@dataclass(frozen=True) class EconetNumberEntityDescription(NumberEntityDescription): """Describes Econet number entity.""" @@ -66,7 +66,7 @@ def _sync_state(self, value): self.hass.async_create_task(self.async_set_limits_values()) async def async_set_limits_values(self): - """async Sync number limits.""" + """Async Sync number limits.""" limits = await self.api.get_param_limits(self.entity_description.key) _LOGGER.debug("Number limits retrieved: %s", limits) if limits is None: diff --git a/custom_components/econet300/sensor.py b/custom_components/econet300/sensor.py index fddc528..feffd47 100644 --- a/custom_components/econet300/sensor.py +++ b/custom_components/econet300/sensor.py @@ -32,7 +32,7 @@ _LOGGER = logging.getLogger(__name__) -@dataclass +@dataclass(frozen=True) class EconetSensorEntityDescription(SensorEntityDescription): """Describes Econet sensor entity.""" @@ -84,6 +84,7 @@ def __init__( def create_entity_description(key: str) -> EconetSensorEntityDescription: """Create Econect300 sensor entity based on supplied key.""" + # Retrieve map_key from SENSOR_MAP, falling back to the key itself map_key = SENSOR_MAP.get(key, key) _LOGGER.debug("SENSOR_MAP: %s", SENSOR_MAP) _LOGGER.debug("Creating entity description for key: %s, map_key: %s", key, map_key) diff --git a/custom_components/econet300/strings.json b/custom_components/econet300/strings.json index aca8d82..b2ab56c 100644 --- a/custom_components/econet300/strings.json +++ b/custom_components/econet300/strings.json @@ -20,22 +20,53 @@ }, "entity": { "binary_sensor": { - "weather_control": {"name": "Weather control the boiler"}, - "unseal": { "name": "Unseal" }, - "thermostat": { "name": "Boiler thermostat" }, - "pump_co_works": { "name": "Pump CO" }, - "fan_works": { "name": "Fan" }, - "aditional_feeder": { "name": "Aditional feeder" }, - "pump_fireplace_works": { "name": "Boiler Pump" }, - "pump_cwu_works": { "name": "Pump CWU" }, - "mixer_pump1": { "name": "Mixer 1 pump" }, - "boiler_pump": { "name": "Boiler pump" } + "lighter": { + "name": "Lighter" + }, + "weather_control": { + "name": "Weather control the boiler" + }, + "unseal": { + "name": "Unseal" + }, + "thermostat": { + "name": "Boiler thermostat" + }, + "pump_co_works": { + "name": "Pump CO" + }, + "fan_works": { + "name": "Fan" + }, + "aditional_feeder": { + "name": "Aditional feeder" + }, + "pump_fireplace_works": { + "name": "Boiler Pump" + }, + "pump_cwu_works": { + "name": "Pump CWU" + }, + "mixer_pump1": { + "name": "Mixer 1 pump" + }, + "boiler_pump": { + "name": "Boiler pump" + } }, "sensor": { - "boiler_power": { "name": "Boiler output" }, - "fuel_level": { "name": "Fuel level" }, - "fan_power": { "name": "Fan power" }, - "fan_works": { "name": "Fan" }, + "boiler_power": { + "name": "Boiler output" + }, + "fuel_level": { + "name": "Fuel level" + }, + "fan_power": { + "name": "Fan power" + }, + "fan_works": { + "name": "Fan" + }, "lambda_status": { "name": "Lambda status", "state": { @@ -45,9 +76,15 @@ "unknown": "Unknown" } }, - "lambda_set": { "name": "Lambda set" }, - "lambda_level": { "name": "Lambda level" }, - "main_server": { "name": "Main server" }, + "lambda_set": { + "name": "Lambda set" + }, + "lambda_level": { + "name": "Lambda level" + }, + "main_server": { + "name": "Main server" + }, "mode": { "name": "Boiler mode", "state": { @@ -67,25 +104,63 @@ "unknown": "Unknown" } }, - "mixer_temp1": { "name": "Mixer 1 temperature" }, - "mixer_set_temp1": { "name": "Mixer target temperature" }, - "pump_cwu_works": { "name": "HUW pump" }, - "pump_fireplace_works": { "name": "Boiler pump" }, - "signal": { "name": "Signal quality" }, - "servo_mixer1": { "name": "Mixer 1 servo position" }, - "status_wifi": { "name": "Wireless network connected" }, - "temp_co": { "name": "Heating temperature" }, - "temp_cwu": { "name": "Water heater temperature" }, - "temp_upper_buffer": { "name": "Upper buffer temperature" }, - "temp_lower_buffer": { "name": "Lower buffer temperature" }, - "temp_flue_gas": { "name": "Flue gas temperature" }, - "temp_external_sensor": { "name": "Outside temperature" }, - "temp_feeder": {"name": "Feeder temperature"}, - "temp_co_set": { "name": "Heating target temperature" }, - "thermostat": { "name": "Thermostat" }, - "unseal": { "name": "Unseal" }, - "valve_mixer1": { "name": "Mixer 1 valve % open" }, - "weather_control": {"name": "Weather control the boiler"} + "mixer_temp1": { + "name": "Mixer 1 temperature" + }, + "mixer_set_temp1": { + "name": "Mixer target temperature" + }, + "pump_cwu_works": { + "name": "HUW pump" + }, + "pump_fireplace_works": { + "name": "Boiler pump" + }, + "signal": { + "name": "Signal quality" + }, + "servo_mixer1": { + "name": "Mixer 1 servo position" + }, + "status_wifi": { + "name": "Wireless network connected" + }, + "temp_co": { + "name": "Heating temperature" + }, + "temp_cwu": { + "name": "Water heater temperature" + }, + "temp_upper_buffer": { + "name": "Upper buffer temperature" + }, + "temp_lower_buffer": { + "name": "Lower buffer temperature" + }, + "temp_flue_gas": { + "name": "Flue gas temperature" + }, + "temp_external_sensor": { + "name": "Outside temperature" + }, + "temp_feeder": { + "name": "Feeder temperature" + }, + "temp_co_set": { + "name": "Heating target temperature" + }, + "thermostat": { + "name": "Thermostat" + }, + "unseal": { + "name": "Unseal" + }, + "valve_mixer1": { + "name": "Mixer 1 valve % open" + }, + "weather_control": { + "name": "Weather control the boiler" + } } } -} +} \ No newline at end of file diff --git a/custom_components/econet300/translations/en.json b/custom_components/econet300/translations/en.json index 630f343..a2ffffc 100644 --- a/custom_components/econet300/translations/en.json +++ b/custom_components/econet300/translations/en.json @@ -10,9 +10,9 @@ } }, "error": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Invalid authentication", - "unknown": "Unexpected error" + "cannot_connect": "Failed to connect", + "invalid_auth": "Invalid authentication", + "unknown": "Unexpected error" }, "abort": { "already_configured": "Device is already configured" @@ -20,22 +20,53 @@ }, "entity": { "binary_sensor": { - "weather_control": {"name": "Weather control the boiler"}, - "unseal": { "name": "Unseal" }, - "thermostat": { "name": "Boiler thermostat" }, - "pump_co_works": { "name": "Pump CO" }, - "fan_works": { "name": "Fan" }, - "aditional_feeder": { "name": "Aditional feeder" }, - "pump_fireplace_works": { "name": "Boiler Pump" }, - "pump_cwu_works": { "name": "Pump CWU" }, - "mixer_pump1": { "name": "Mixer 1 pump" }, - "boiler_pump": { "name": "Boiler pump" } + "lighter": { + "name": "Lighter" + }, + "weather_control": { + "name": "Weather control the boiler" + }, + "unseal": { + "name": "Unseal" + }, + "thermostat": { + "name": "Boiler thermostat" + }, + "pump_co_works": { + "name": "Pump CO" + }, + "fan_works": { + "name": "Fan" + }, + "aditional_feeder": { + "name": "Aditional feeder" + }, + "pump_fireplace_works": { + "name": "Boiler Pump" + }, + "pump_cwu_works": { + "name": "Pump CWU" + }, + "mixer_pump1": { + "name": "Mixer 1 pump" + }, + "boiler_pump": { + "name": "Boiler pump" + } }, "sensor": { - "boiler_power": { "name": "Boiler output" }, - "fuel_level": { "name": "Fuel level" }, - "fan_power": { "name": "Fan power" }, - "fan_works": { "name": "Fan" }, + "boiler_power": { + "name": "Boiler output" + }, + "fuel_level": { + "name": "Fuel level" + }, + "fan_power": { + "name": "Fan power" + }, + "fan_works": { + "name": "Fan" + }, "lambda_status": { "name": "Lambda status", "state": { @@ -45,9 +76,15 @@ "unknown": "Unknown" } }, - "lambda_set": { "name": "Lambda set" }, - "lambda_level": { "name": "Lambda level" }, - "main_server": { "name": "Main server" }, + "lambda_set": { + "name": "Lambda set" + }, + "lambda_level": { + "name": "Lambda level" + }, + "main_server": { + "name": "Main server" + }, "mode": { "name": "Boiler mode", "state": { @@ -67,25 +104,63 @@ "unknown": "Unknown" } }, - "mixer_temp1": { "name": "Mixer 1 temperature" }, - "mixer_set_temp1": { "name": "Mixer target temperature" }, - "pump_cwu_works": { "name": "HUW pump" }, - "pump_fireplace_works": { "name": "Boiler pump" }, - "signal": { "name": "Signal quality" }, - "servo_mixer1": { "name": "Mixer 1 servo position" }, - "status_wifi": { "name": "Wireless network connected" }, - "temp_co": { "name": "Heating temperature" }, - "temp_cwu": { "name": "Water heater temperature" }, - "temp_upper_buffer": { "name": "Upper buffer temperature" }, - "temp_lower_buffer": { "name": "Lower buffer temperature" }, - "temp_flue_gas": { "name": "Flue gas temperature" }, - "temp_external_sensor": { "name": "Outside temperature" }, - "temp_feeder": {"name": "Feeder temperature"}, - "temp_co_set": { "name": "Heating target temperature" }, - "thermostat": { "name": "Thermostat" }, - "unseal": { "name": "Unseal" }, - "valve_mixer1": { "name": "Mixer 1 valve % open" }, - "weather_control": {"name": "Weather control the boiler"} + "mixer_temp1": { + "name": "Mixer 1 temperature" + }, + "mixer_set_temp1": { + "name": "Mixer target temperature" + }, + "pump_cwu_works": { + "name": "HUW pump" + }, + "pump_fireplace_works": { + "name": "Boiler pump" + }, + "signal": { + "name": "Signal quality" + }, + "servo_mixer1": { + "name": "Mixer 1 servo position" + }, + "status_wifi": { + "name": "Wireless network connected" + }, + "temp_co": { + "name": "Heating temperature" + }, + "temp_cwu": { + "name": "Water heater temperature" + }, + "temp_upper_buffer": { + "name": "Upper buffer temperature" + }, + "temp_lower_buffer": { + "name": "Lower buffer temperature" + }, + "temp_flue_gas": { + "name": "Flue gas temperature" + }, + "temp_external_sensor": { + "name": "Outside temperature" + }, + "temp_feeder": { + "name": "Feeder temperature" + }, + "temp_co_set": { + "name": "Heating target temperature" + }, + "thermostat": { + "name": "Thermostat" + }, + "unseal": { + "name": "Unseal" + }, + "valve_mixer1": { + "name": "Mixer 1 valve % open" + }, + "weather_control": { + "name": "Weather control the boiler" + } } } -} +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 6107abe..b083173 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,28 @@ +# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html + +[tool.poetry] +name = "ecoNET-300-Home-Assistant-Integration" +version = "v1.0.0-beta" +description = "ecoNET300 Home Assistant integration" +authors = ["Jon "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "~3.12.0" +pymammotion = "0.2.66" +homeassistant = "^2024.9.0" +autotyping = "^24.3.0" + [tool.mypy] python_version = "3.12" +show_error_codes = true +follow_imports = "normal" +disable_error_code = [ + "annotation-unchecked", + "import-not-found", + "import-untyped" +] +extra_checks = false [tool.black] line-length = 88 @@ -16,12 +39,268 @@ load-plugins = [ [tool.pylint."MESSAGES CONTROL"] # Reasons disabled: # format - handled by ruff +# locally-disabled - it spams too much +# duplicate-code - unavoidable +# cyclic-import - doesn't test if both import on load +# abstract-class-little-used - prevents from setting right foundation +# unused-argument - generic callbacks and setup methods create a lot of warnings +# too-many-* - are not enforced for the sake of readability +# too-few-* - same as too-many-* +# abstract-method - with intro of async there are always methods missing +# inconsistent-return-statements - doesn't handle raise +# too-many-ancestors - it's too strict. +# wrong-import-order - isort guards this +# consider-using-f-string - str.format sometimes more readable +# --- +# Pylint CodeStyle plugin +# consider-using-namedtuple-or-dataclass - too opinionated +# consider-using-assignment-expr - decision to use := better left to devs disable = [ "format", - ] + "abstract-method", + "cyclic-import", + "duplicate-code", + "inconsistent-return-statements", + "locally-disabled", + "not-context-manager", + "too-few-public-methods", + "too-many-ancestors", + "too-many-arguments", + "too-many-instance-attributes", + "too-many-lines", + "too-many-locals", + "too-many-public-methods", + "too-many-boolean-expressions", + "wrong-import-order", + "consider-using-f-string", + "consider-using-namedtuple-or-dataclass", + "consider-using-assignment-expr", + + # Handled by ruff + # Ref: + "await-outside-async", # PLE1142 + "bad-str-strip-call", # PLE1310 + "bad-string-format-type", # PLE1307 + "bidirectional-unicode", # PLE2502 + "continue-in-finally", # PLE0116 + "duplicate-bases", # PLE0241 + "format-needs-mapping", # F502 + "function-redefined", # F811 + # Needed because ruff does not understand type of __all__ generated by a function + # "invalid-all-format", # PLE0605 + "invalid-all-object", # PLE0604 + "invalid-character-backspace", # PLE2510 + "invalid-character-esc", # PLE2513 + "invalid-character-nul", # PLE2514 + "invalid-character-sub", # PLE2512 + "invalid-character-zero-width-space", # PLE2515 + "logging-too-few-args", # PLE1206 + "logging-too-many-args", # PLE1205 + "missing-format-string-key", # F524 + "mixed-format-string", # F506 + "no-method-argument", # N805 + "no-self-argument", # N805 + "nonexistent-operator", # B002 + "nonlocal-without-binding", # PLE0117 + "not-in-loop", # F701, F702 + "notimplemented-raised", # F901 + "return-in-init", # PLE0101 + "return-outside-function", # F706 + "syntax-error", # E999 + "too-few-format-args", # F524 + "too-many-format-args", # F522 + "too-many-star-expressions", # F622 + "truncated-format-string", # F501 + "undefined-all-variable", # F822 + "undefined-variable", # F821 + "used-prior-global-declaration", # PLE0118 + "yield-inside-async-function", # PLE1700 + "yield-outside-function", # F704 + "anomalous-backslash-in-string", # W605 + "assert-on-string-literal", # PLW0129 + "assert-on-tuple", # F631 + "bad-format-string", # W1302, F + "bad-format-string-key", # W1300, F + "bare-except", # E722 + "binary-op-exception", # PLW0711 + "cell-var-from-loop", # B023 + # "dangerous-default-value", # B006, ruff catches new occurrences, needs more work + "duplicate-except", # B014 + "duplicate-key", # F601 + "duplicate-string-formatting-argument", # F + "duplicate-value", # F + "eval-used", # S307 + "exec-used", # S102 + "expression-not-assigned", # B018 + "f-string-without-interpolation", # F541 + "forgotten-debug-statement", # T100 + "format-string-without-interpolation", # F + # "global-statement", # PLW0603, ruff catches new occurrences, needs more work + "global-variable-not-assigned", # PLW0602 + "implicit-str-concat", # ISC001 + "import-self", # PLW0406 + "inconsistent-quotes", # Q000 + "invalid-envvar-default", # PLW1508 + "keyword-arg-before-vararg", # B026 + "logging-format-interpolation", # G + "logging-fstring-interpolation", # G + "logging-not-lazy", # G + "misplaced-future", # F404 + "named-expr-without-context", # PLW0131 + "nested-min-max", # PLW3301 + "pointless-statement", # B018 + "raise-missing-from", # B904 + "redefined-builtin", # A001 + "try-except-raise", # TRY302 + "unused-argument", # ARG001, we don't use it + "unused-format-string-argument", #F507 + "unused-format-string-key", # F504 + "unused-import", # F401 + "unused-variable", # F841 + "useless-else-on-loop", # PLW0120 + "wildcard-import", # F403 + "bad-classmethod-argument", # N804 + "consider-iterating-dictionary", # SIM118 + "empty-docstring", # D419 + "invalid-name", # N815 + "line-too-long", # E501, disabled globally + "missing-class-docstring", # D101 + "missing-final-newline", # W292 + "missing-function-docstring", # D103 + "missing-module-docstring", # D100 + "multiple-imports", #E401 + "singleton-comparison", # E711, E712 + "subprocess-run-check", # PLW1510 + "superfluous-parens", # UP034 + "ungrouped-imports", # I001 + "unidiomatic-typecheck", # E721 + "unnecessary-direct-lambda-call", # PLC3002 + "unnecessary-lambda-assignment", # PLC3001 + "unnecessary-pass", # PIE790 + "unneeded-not", # SIM208 + "useless-import-alias", # PLC0414 + "wrong-import-order", # I001 + "wrong-import-position", # E402 + "comparison-of-constants", # PLR0133 + "comparison-with-itself", # PLR0124 + "consider-alternative-union-syntax", # UP007 + "consider-merging-isinstance", # PLR1701 + "consider-using-alias", # UP006 + "consider-using-dict-comprehension", # C402 + "consider-using-generator", # C417 + "consider-using-get", # SIM401 + "consider-using-set-comprehension", # C401 + "consider-using-sys-exit", # PLR1722 + "consider-using-ternary", # SIM108 + "literal-comparison", # F632 + "property-with-parameters", # PLR0206 + "super-with-arguments", # UP008 + "too-many-branches", # PLR0912 + "too-many-return-statements", # PLR0911 + "too-many-statements", # PLR0915 + "trailing-comma-tuple", # COM818 + "unnecessary-comprehension", # C416 + "use-a-generator", # C417 + "use-dict-literal", # C406 + "use-list-literal", # C405 + "useless-object-inheritance", # UP004 + "useless-return", # PLR1711 + "no-else-break", # RET508 + "no-else-continue", # RET507 + "no-else-raise", # RET506 + "no-else-return", # RET505 + "broad-except", # BLE001 + "protected-access", # SLF001 + # "no-self-use", # PLR6301 # Optional plugin, not enabled + + # Handled by mypy + # Ref: + "abstract-class-instantiated", + "arguments-differ", + "assigning-non-slot", + "assignment-from-no-return", + "assignment-from-none", + "bad-exception-cause", + "bad-format-character", + "bad-reversed-sequence", + "bad-super-call", + "bad-thread-instantiation", + "catching-non-exception", + "comparison-with-callable", + "deprecated-class", + "dict-iter-missing-items", + "format-combined-specification", + "global-variable-undefined", + "import-error", + "inconsistent-mro", + "inherit-non-class", + "init-is-generator", + "invalid-class-object", + "invalid-enum-extension", + "invalid-envvar-value", + "invalid-format-returned", + "invalid-hash-returned", + "invalid-metaclass", + "invalid-overridden-method", + "invalid-repr-returned", + "invalid-sequence-index", + "invalid-slice-index", + "invalid-slots-object", + "invalid-slots", + "invalid-star-assignment-target", + "invalid-str-returned", + "invalid-unary-operand-type", + "invalid-unicode-codec", + "isinstance-second-argument-not-valid-type", + "method-hidden", + "misplaced-format-function", + "missing-format-argument-key", + "missing-format-attribute", + "missing-kwoa", + "no-member", + "no-value-for-parameter", + "non-iterator-returned", + "non-str-assignment-to-dunder-name", + "nonlocal-and-global", + "not-a-mapping", + "not-an-iterable", + "not-async-context-manager", + "not-callable", + "not-context-manager", + "overridden-final-method", + "raising-bad-type", + "raising-non-exception", + "redundant-keyword-arg", + "relative-beyond-top-level", + "self-cls-assignment", + "signature-differs", + "star-needs-assignment-target", + "subclassed-final-class", + "super-without-brackets", + "too-many-function-args", + "typevar-double-variance", + "typevar-name-mismatch", + "unbalanced-dict-unpacking", + "unbalanced-tuple-unpacking", + "unexpected-keyword-arg", + "unhashable-member", + "unpacking-non-sequence", + "unsubscriptable-object", + "unsupported-assignment-operation", + "unsupported-binary-operation", + "unsupported-delete-operation", + "unsupported-membership-test", + "used-before-assignment", + "using-final-decorator-in-unsupported-version", + "wrong-exception-operation", +] +enable = [ + #"useless-suppression", # temporarily every now and then to clean them up + "use-symbolic-message-instead", +] -[tool.pylint.BASIC] -class-const-naming-style = "any" +[tool.pylint.REPORTS] +score = false [tool.pylint.TYPECHECK] ignored-classes = [ @@ -46,7 +325,7 @@ runtime-typing = false max-line-length-suggestions = 72 [tool.ruff] -required-version = ">=0.4.1" +required-version = ">=0.4.3" [tool.ruff.lint] select = [