Skip to content

Commit bec7167

Browse files
committed
bugfixes and more tests
1 parent c756ab6 commit bec7167

7 files changed

+136
-31
lines changed

lmcloud/client_bluetooth.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ async def set_temp(self, boiler: BoilerType, temperature: float) -> None:
115115
data = {
116116
"name": "SettingBoilerTarget",
117117
"parameter": {
118-
"identifier": boiler,
118+
"identifier": boiler.value,
119119
"value": temperature,
120120
},
121121
}

lmcloud/client_cloud.py

+13-12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
TOKEN_URL,
2222
BoilerType,
2323
FirmwareType,
24+
PhysicalKey,
2425
PrebrewMode,
2526
)
2627
from .exceptions import AuthFail, RequestNotSuccessful
@@ -142,7 +143,7 @@ async def set_steam(
142143
"""Turn Steamboiler on or off"""
143144

144145
data = {
145-
"identifier": BoilerType.STEAM,
146+
"identifier": BoilerType.STEAM.value,
146147
"state": enabled,
147148
}
148149
url = f"{GW_MACHINE_BASE_URL}/{serial_number}/enable-boiler"
@@ -159,7 +160,7 @@ async def set_temp(
159160
) -> bool:
160161
"""Set boiler temperature (in Celsius)."""
161162

162-
data = {"identifier": boiler, "value": temperature}
163+
data = {"identifier": boiler.value, "value": temperature}
163164
url = f"{GW_MACHINE_BASE_URL}/{serial_number}/target-boiler"
164165
response = await self._rest_api_call(url=url, method=HTTPMethod.POST, data=data)
165166
if await self._check_cloud_command_status(serial_number, response):
@@ -175,7 +176,7 @@ async def set_prebrew_mode(
175176
"""Enable/Disable Pre-Brew or Pre-Infusion (mutually exclusive)."""
176177

177178
url = f"{GW_MACHINE_BASE_URL}/{serial_number}/enable-preinfusion"
178-
data = {"mode": mode}
179+
data = {"mode": mode.value}
179180
response = await self._rest_api_call(url=url, method=HTTPMethod.POST, data=data)
180181
if await self._check_cloud_command_status(serial_number, response):
181182
return True
@@ -186,20 +187,20 @@ async def configure_pre_brew_infusion_time(
186187
serial_number: str,
187188
on_time: float,
188189
off_time: float,
189-
key: int = 1,
190+
key: PhysicalKey,
190191
) -> bool:
191192
"""Set Pre-Brew details. Also used for preinfusion (prebrewOnTime=0, prebrewOnTime=ms)."""
192193

193-
on_time = round(on_time, 1) * 100
194-
off_time = round(off_time, 1) * 100
195-
button = f"Dose{chr(key + 64)}"
194+
on_time = round(on_time, 1) * 1000
195+
off_time = round(off_time, 1) * 1000
196+
button = f"Dose{key.name}"
196197

197198
url = f"{GW_MACHINE_BASE_URL}/{serial_number}/setting-preinfusion"
198199
data = {
199200
"button": button,
200201
"group": "Group1",
201-
"holdTimeMs": off_time,
202-
"wetTimeMs": on_time,
202+
"holdTimeMs": int(off_time),
203+
"wetTimeMs": int(on_time),
203204
}
204205
response = await self._rest_api_call(url=url, method=HTTPMethod.POST, data=data)
205206
if await self._check_cloud_command_status(serial_number, response):
@@ -223,12 +224,12 @@ async def enable_plumbin(
223224
async def set_dose(
224225
self,
225226
serial_number: str,
226-
key: int,
227+
key: PhysicalKey,
227228
value: int,
228229
) -> bool:
229230
"""Set the value for a dose"""
230231

231-
dose_index = f"Dose{chr(key + 64)}"
232+
dose_index = f"Dose{key.name}"
232233

233234
url = f"{GW_MACHINE_BASE_URL}/{serial_number}/dose"
234235
data = {
@@ -343,7 +344,7 @@ async def update_firmware(
343344
"""Update Firmware."""
344345

345346
_LOGGER.debug("Updating firmware for component %s", component)
346-
url = f"{GW_MACHINE_BASE_URL}/{serial_number}/firmware/{component}/update"
347+
url = f"{GW_MACHINE_BASE_URL}/{serial_number}/firmware/{component.value}/update"
347348
await self._rest_api_call(url=url, method=HTTPMethod.POST, data={})
348349
retry_counter = 0
349350
while retry_counter <= 20:

lmcloud/lm_machine.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ async def set_prebrew_time(
239239
self,
240240
prebrew_on_time: float | None = None,
241241
prebrew_off_time: float | None = None,
242-
key: PhysicalKey = PhysicalKey(1),
242+
key: PhysicalKey = PhysicalKey.A,
243243
) -> bool:
244244
"""Set prebrew time"""
245245

@@ -260,7 +260,7 @@ async def set_prebrew_time(
260260
async def set_preinfusion_time(
261261
self,
262262
preinfusion_time: float,
263-
key: PhysicalKey = PhysicalKey(1),
263+
key: PhysicalKey = PhysicalKey.A,
264264
) -> bool:
265265
"""Set preinfusion time"""
266266

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
setuptools.setup(
99
name="lmcloud",
10-
version="1.0.0b14",
10+
version="1.0.0b15",
1111
description="A Python implementation of the new La Marzocco API",
1212
long_description=readme,
1313
long_description_content_type="text/markdown",

tests/__init__.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
"""Test utilities"""
22

33
from lmcloud import LaMarzoccoCloudClient, LaMarzoccoMachine, LaMarzoccoGrinder
4+
from lmcloud.client_bluetooth import LaMarzoccoBluetoothClient
5+
from lmcloud.client_local import LaMarzoccoLocalClient
46
from lmcloud.const import MachineModel, GrinderModel
57

68
MACHINE_SERIAL = "GS01234"
79
GRINDER_SERIAL = "G00000000000"
810

911

1012
async def init_machine(
11-
cloud_client: LaMarzoccoCloudClient,
13+
cloud_client: LaMarzoccoCloudClient | None = None,
14+
bluetooth_client: LaMarzoccoBluetoothClient | None = None,
15+
local_client: LaMarzoccoLocalClient | None = None,
1216
) -> LaMarzoccoMachine:
1317
"""Get an initialized machine"""
1418

@@ -17,6 +21,8 @@ async def init_machine(
1721
serial_number=MACHINE_SERIAL,
1822
name="MyMachine",
1923
cloud_client=cloud_client,
24+
local_client=local_client,
25+
bluetooth_client=bluetooth_client,
2026
)
2127
return machine
2228

tests/conftest.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
"""Fixtures for the tests."""
22

3+
# pylint: disable=W0212
4+
35
import json
46
from collections.abc import Generator
57
from http import HTTPMethod
68
from pathlib import Path
79
from unittest.mock import AsyncMock
810

911
import pytest
12+
from bleak import BLEDevice, BleakError
1013
from httpx import Response
1114

15+
from lmcloud.client_bluetooth import LaMarzoccoBluetoothClient
1216
from lmcloud.client_cloud import LaMarzoccoCloudClient
1317
from lmcloud.client_local import LaMarzoccoLocalClient
1418

@@ -69,7 +73,7 @@ def cloud_client() -> Generator[LaMarzoccoCloudClient, None, None]:
6973
oauth_client = AsyncMock()
7074
oauth_client.request.side_effect = get_mock_response
7175

72-
client._oauth_client = oauth_client # pylint: disable=protected-access
76+
client._oauth_client = oauth_client
7377
yield client
7478

7579

@@ -80,3 +84,20 @@ def local_machine_client() -> Generator[LaMarzoccoLocalClient, None, None]:
8084
httpx_client.get.side_effect = get_local_machine_mock_response
8185
client = LaMarzoccoLocalClient("192.168.1.42", "secret", client=httpx_client)
8286
yield client
87+
88+
89+
@pytest.fixture
90+
def bluetooth_client() -> Generator[LaMarzoccoBluetoothClient, None, None]:
91+
"""Fixture for a bluetooth client."""
92+
ble_device = BLEDevice(
93+
address="00:11:22:33:44:55",
94+
name="MyMachine",
95+
details={"path": "path/to/device"},
96+
rssi=50,
97+
)
98+
99+
bt_client = LaMarzoccoBluetoothClient("username", "serial", "token", ble_device)
100+
bt_client._client = AsyncMock()
101+
bt_client._client.is_connected = True
102+
bt_client._client.write_gatt_char.side_effect = BleakError("Failed to write")
103+
yield bt_client

tests/test_machine.py

+90-13
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
"""Test the LaMarzoccoMachine class."""
22

3+
# pylint: disable=W0212
4+
35
from unittest.mock import AsyncMock, patch
46

57
import pytest
68
from syrupy import SnapshotAssertion
9+
from http import HTTPMethod
710

11+
from lmcloud.client_bluetooth import LaMarzoccoBluetoothClient
812
from lmcloud.client_cloud import LaMarzoccoCloudClient
913
from lmcloud.client_local import LaMarzoccoLocalClient
1014
from lmcloud.const import BoilerType, MachineModel, PhysicalKey, WeekDay
@@ -31,12 +35,7 @@ async def test_local_client(
3135
) -> None:
3236
"""Ensure that the local client delivers same result"""
3337

34-
machine = await LaMarzoccoMachine.create(
35-
model=MachineModel.GS3_AV,
36-
serial_number=MACHINE_SERIAL,
37-
name="MyMachine",
38-
local_client=local_machine_client,
39-
)
38+
machine = await init_machine(local_client=local_machine_client)
4039

4140
machine2 = await init_machine(cloud_client)
4241

@@ -103,13 +102,7 @@ async def test_websocket_message(
103102
snapshot: SnapshotAssertion,
104103
):
105104
"""Test parsing of websocket messages."""
106-
machine = await LaMarzoccoMachine.create(
107-
model=MachineModel.GS3_AV,
108-
serial_number=MACHINE_SERIAL,
109-
name="MyMachine",
110-
cloud_client=cloud_client,
111-
local_client=local_machine_client,
112-
)
105+
machine = await init_machine(cloud_client, local_client=local_machine_client)
113106

114107
message = r'[{"Boilers":"[{\"id\":\"SteamBoiler\",\"isEnabled\":true,\"target\":131,\"current\":113},{\"id\":\"CoffeeBoiler1\",\"isEnabled\":true,\"target\":94,\"current\":81}]"}]'
115108
machine.on_websocket_message_received(message)
@@ -118,3 +111,87 @@ async def test_websocket_message(
118111
message = r'[{"BoilersTargetTemperature":"{\"SteamBoiler\":131,\"CoffeeBoiler1\":94}"},{"Boilers":"[{\"id\":\"SteamBoiler\",\"isEnabled\":true,\"target\":131,\"current\":50},{\"id\":\"CoffeeBoiler1\",\"isEnabled\":true,\"target\":94,\"current\":36}]"}]'
119112
machine.on_websocket_message_received(message)
120113
assert machine.config == snapshot
114+
115+
116+
async def test_set_power(
117+
cloud_client: LaMarzoccoCloudClient, bluetooth_client: LaMarzoccoBluetoothClient
118+
):
119+
"""Test setting the power."""
120+
machine = await init_machine(cloud_client, bluetooth_client=bluetooth_client)
121+
122+
assert await machine.set_power(True)
123+
124+
bluetooth_client._client.write_gatt_char.assert_called_once_with( # type: ignore[attr-defined]
125+
"050b7847-e12b-09a8-b04b-8e0922a9abab",
126+
b'{"name":"MachineChangeMode","parameter":{"mode":"BrewingMode"}}\x00',
127+
)
128+
cloud_client._oauth_client.request.assert_any_call( # type: ignore[union-attr]
129+
HTTPMethod.POST,
130+
"https://gw-lmz.lamarzocco.io/v1/home/machines/GS01234/status",
131+
json={"status": "BrewingMode"},
132+
)
133+
134+
135+
async def test_set_steam(
136+
cloud_client: LaMarzoccoCloudClient, bluetooth_client: LaMarzoccoBluetoothClient
137+
):
138+
"""Test setting the steam."""
139+
machine = await init_machine(cloud_client, bluetooth_client=bluetooth_client)
140+
141+
assert await machine.set_steam(True)
142+
143+
bluetooth_client._client.write_gatt_char.assert_called_once_with( # type: ignore[attr-defined]
144+
"050b7847-e12b-09a8-b04b-8e0922a9abab",
145+
b'{"name":"SettingBoilerEnable","parameter":{"identifier":"SteamBoiler","state":true}}\x00',
146+
)
147+
cloud_client._oauth_client.request.assert_any_call( # type: ignore[union-attr]
148+
HTTPMethod.POST,
149+
"https://gw-lmz.lamarzocco.io/v1/home/machines/GS01234/enable-boiler",
150+
json={"identifier": "SteamBoiler", "state": True},
151+
)
152+
153+
154+
async def test_set_temperature(
155+
cloud_client: LaMarzoccoCloudClient, bluetooth_client: LaMarzoccoBluetoothClient
156+
):
157+
"""Test setting temperature."""
158+
machine = await init_machine(cloud_client, bluetooth_client=bluetooth_client)
159+
160+
assert await machine.set_temp(BoilerType.STEAM, 131)
161+
162+
bluetooth_client._client.write_gatt_char.assert_called_once_with( # type: ignore[attr-defined]
163+
"050b7847-e12b-09a8-b04b-8e0922a9abab",
164+
b'{"name":"SettingBoilerTarget","parameter":{"identifier":"SteamBoiler","value":131}}\x00',
165+
)
166+
cloud_client._oauth_client.request.assert_any_call( # type: ignore[union-attr]
167+
HTTPMethod.POST,
168+
"https://gw-lmz.lamarzocco.io/v1/home/machines/GS01234/target-boiler",
169+
json={"identifier": "SteamBoiler", "value": 131},
170+
)
171+
172+
173+
async def test_set_prebrew_time(cloud_client: LaMarzoccoCloudClient):
174+
"""Test setting prebrew time."""
175+
machine = await init_machine(
176+
cloud_client,
177+
)
178+
179+
assert await machine.set_prebrew_time(1.0, 3.5)
180+
181+
cloud_client._oauth_client.request.assert_any_call( # type: ignore[union-attr]
182+
HTTPMethod.POST,
183+
"https://gw-lmz.lamarzocco.io/v1/home/machines/GS01234/setting-preinfusion",
184+
json={
185+
"button": "DoseA",
186+
"group": "Group1",
187+
"holdTimeMs": 3500,
188+
"wetTimeMs": 1000,
189+
},
190+
)
191+
192+
assert await machine.set_preinfusion_time(4.5)
193+
cloud_client._oauth_client.request.assert_any_call( # type: ignore[union-attr]
194+
HTTPMethod.POST,
195+
"https://gw-lmz.lamarzocco.io/v1/home/machines/GS01234/setting-preinfusion",
196+
json={"button": "DoseA", "group": "Group1", "holdTimeMs": 4500, "wetTimeMs": 0},
197+
)

0 commit comments

Comments
 (0)