Skip to content

Commit daffd43

Browse files
authored
RSDK-5028 Write analog python SDK (#460)
1 parent a372745 commit daffd43

File tree

5 files changed

+65
-2
lines changed

5 files changed

+65
-2
lines changed

src/viam/components/board/board.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,14 @@ async def set_power_mode(
263263
mode: the desired power mode
264264
"""
265265
...
266+
267+
@abc.abstractmethod
268+
async def write_analog(self, pin: str, value: int, *, timeout: Optional[float] = None, **kwargs):
269+
"""
270+
Write an analog value to a pin on the board.
271+
272+
Args:
273+
pin (str): name of the pin.
274+
value (int): value to write.
275+
"""
276+
...

src/viam/components/board/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
SetPWMRequest,
2626
StatusRequest,
2727
StatusResponse,
28+
WriteAnalogRequest,
2829
)
2930
from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase
3031
from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict
@@ -178,3 +179,7 @@ async def set_power_mode(
178179

179180
async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None) -> List[Geometry]:
180181
return await get_geometries(self.client, self.name, extra, timeout)
182+
183+
async def write_analog(self, pin: str, value: int, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None):
184+
request = WriteAnalogRequest(name=self.name, pin=pin, value=value)
185+
await self.client.WriteAnalog(request, timeout=timeout)

src/viam/components/board/service.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from grpclib.server import Stream
22

3-
from viam.errors import ResourceNotFoundError, MethodNotImplementedError
3+
from viam.errors import ResourceNotFoundError
44
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetGeometriesRequest, GetGeometriesResponse
55
from viam.proto.component.board import (
66
BoardServiceBase,
@@ -178,7 +178,14 @@ async def SetPowerMode(self, stream: Stream[SetPowerModeRequest, SetPowerModeRes
178178
await stream.send_message(response)
179179

180180
async def WriteAnalog(self, stream: Stream[WriteAnalogRequest, WriteAnalogResponse]) -> None:
181-
raise MethodNotImplementedError("WriteAnalog")
181+
request = await stream.recv_message()
182+
assert request is not None
183+
name = request.name
184+
board = self.get_resource(name)
185+
timeout = stream.deadline.time_remaining() if stream.deadline else None
186+
await board.write_analog(pin=request.pin, value=request.value, timeout=timeout, metadata=stream.metadata)
187+
response = WriteAnalogResponse()
188+
await stream.send_message(response)
182189

183190
async def DoCommand(self, stream: Stream[DoCommandRequest, DoCommandResponse]) -> None:
184191
request = await stream.recv_message()

tests/mocks/components.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,11 @@ async def set_power_mode(
388388
self.power_mode = mode
389389
self.power_mode_duration = duration
390390

391+
async def write_analog(self, pin: str, value: int, *, timeout: Optional[float] = None, **kwargs):
392+
self.timeout = timeout
393+
self.analog_write_pin = pin
394+
self.analog_write_value = value
395+
391396

392397
class MockCamera(Camera):
393398
def __init__(self, name: str):

tests/test_board.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
SetPWMRequest,
4040
StatusRequest,
4141
StatusResponse,
42+
WriteAnalogRequest,
43+
WriteAnalogResponse,
4244
)
4345
from viam.resource.manager import ResourceManager
4446
from viam.utils import dict_to_struct, struct_to_dict
@@ -144,6 +146,15 @@ async def test_get_geometries(self, board: MockBoard):
144146
geometries = await board.get_geometries()
145147
assert geometries == GEOMETRIES
146148

149+
@pytest.mark.asyncio
150+
async def test_write_analog(self, board: MockBoard):
151+
value = 10
152+
pin = "pin1"
153+
await board.write_analog(pin=pin, value=value, timeout=1.11)
154+
assert board.timeout == loose_approx(1.11)
155+
assert board.analog_write_value == value
156+
assert board.analog_write_pin == pin
157+
147158

148159
class TestService:
149160
@pytest.mark.asyncio
@@ -320,6 +331,19 @@ async def test_set_power_mode(self, board: MockBoard, service: BoardRPCService):
320331
assert board.power_mode == PowerMode.POWER_MODE_OFFLINE_DEEP
321332
assert board.power_mode_duration == pm_duration.ToTimedelta()
322333

334+
@pytest.mark.asyncio
335+
async def test_write_analog(self, board: MockBoard, service: BoardRPCService):
336+
async with ChannelFor([service]) as channel:
337+
client = BoardServiceStub(channel)
338+
pin = "pin1"
339+
value = 10
340+
request = WriteAnalogRequest(name=board.name, pin=pin, value=value)
341+
response: WriteAnalogResponse = await client.WriteAnalog(request, timeout=6.66)
342+
assert response == WriteAnalogResponse()
343+
assert board.timeout == loose_approx(6.66)
344+
assert board.analog_write_value == value
345+
assert board.analog_write_pin == pin
346+
323347

324348
class TestClient:
325349
@pytest.mark.asyncio
@@ -501,3 +525,14 @@ async def test_get_pwm_freq(self, board: MockBoard, service: BoardRPCService):
501525
mock_pin = cast(MockGPIOPin, board.gpios["pin1"])
502526
assert mock_pin.extra == extra
503527
assert mock_pin.timeout is None
528+
529+
@pytest.mark.asyncio
530+
async def test_write_analog(self, board: MockBoard, service: BoardRPCService):
531+
async with ChannelFor([service]) as channel:
532+
client = BoardClient(name=board.name, channel=channel)
533+
pin = "pin1"
534+
value = 42
535+
extra = {"foo": "bar", "baz": [1, 2, 3]}
536+
await client.write_analog(pin, value, extra=extra)
537+
assert board.analog_write_pin == "pin1"
538+
assert board.analog_write_value == 42

0 commit comments

Comments
 (0)