Skip to content

Commit 6f891d1

Browse files
authored
[RSDK-7154] update analog reader interface to include range/accuracy (#619)
Surprisingly, the compiled protobufs in this repo already have the new data, and all I needed to do was start using it! When reading an analog pin on a board, you now get the raw value, the minimum/maximum possible value the reader can output, and the minimum change the reader can notice.
1 parent 1a5aa41 commit 6f891d1

File tree

6 files changed

+29
-16
lines changed

6 files changed

+29
-16
lines changed

src/viam/components/board/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ async def create_status(component: Board) -> Status:
1818
for x in analog_names:
1919
analog = await component.analog_by_name(x)
2020
read = await analog.read()
21-
analogs[x] = read
21+
analogs[x] = read.value
2222

2323
for y in digital_interrupt_names:
2424
digital_interrupt = await component.digital_interrupt_by_name(y)

src/viam/components/board/board.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import abc
22
from datetime import timedelta
3+
import sys
34
from typing import Any, Dict, Final, List, Optional
45

5-
from viam.proto.component.board import PowerMode, StreamTicksResponse
6+
from viam.proto.component.board import PowerMode, StreamTicksResponse, ReadAnalogReaderResponse
67
from viam.resource.types import RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, Subtype
78
from viam.streams import Stream
89

910
from ..component_base import ComponentBase
1011

12+
if sys.version_info >= (3, 10):
13+
from typing import TypeAlias
14+
else:
15+
from typing_extensions import TypeAlias
16+
1117
Tick = StreamTicksResponse
1218
TickStream = Stream[Tick]
1319

@@ -38,11 +44,18 @@ class Analog:
3844
name: str
3945
"""The name of the analog pin"""
4046

47+
Value: "TypeAlias" = ReadAnalogReaderResponse
48+
"""
49+
Value contains the result of reading an analog reader. It contains the raw data read,
50+
the reader's minimum and maximum possible values, and its step size (the minimum possible
51+
change between values it can read).
52+
"""
53+
4154
def __init__(self, name: str):
4255
self.name = name
4356

4457
@abc.abstractmethod
45-
async def read(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> int:
58+
async def read(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> Value:
4659
"""
4760
Read the current value from the reader.
4861
@@ -59,7 +72,7 @@ async def read(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optiona
5972
reading = await reader.read()
6073
6174
Returns:
62-
int: The current value.
75+
Value: The current value, including the min, max, and step_size of the reader.
6376
"""
6477
...
6578

src/viam/components/board/client.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
PWMRequest,
2020
PWMResponse,
2121
ReadAnalogReaderRequest,
22-
ReadAnalogReaderResponse,
2322
SetGPIORequest,
2423
SetPowerModeRequest,
2524
SetPWMFrequencyRequest,
@@ -48,12 +47,11 @@ async def read(
4847
extra: Optional[Dict[str, Any]] = None,
4948
timeout: Optional[float] = None,
5049
**__,
51-
) -> int:
50+
) -> Board.Analog.Value:
5251
if extra is None:
5352
extra = {}
5453
request = ReadAnalogReaderRequest(board_name=self.board.name, analog_reader_name=self.name, extra=dict_to_struct(extra))
55-
response: ReadAnalogReaderResponse = await self.board.client.ReadAnalogReader(request, timeout=timeout)
56-
return response.value
54+
return await self.board.client.ReadAnalogReader(request, timeout=timeout)
5755

5856
async def write(
5957
self,

src/viam/components/board/service.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,7 @@ async def ReadAnalogReader(self, stream: Stream[ReadAnalogReaderRequest, ReadAna
138138
except ResourceNotFoundError as e:
139139
raise e.grpc_error
140140
timeout = stream.deadline.time_remaining() if stream.deadline else None
141-
value = await analog_reader.read(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata)
142-
response = ReadAnalogReaderResponse(value=value)
141+
response = await analog_reader.read(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata)
143142
await stream.send_message(response)
144143

145144
async def GetDigitalInterruptValue(self, stream: Stream[GetDigitalInterruptValueRequest, GetDigitalInterruptValueResponse]) -> None:

tests/mocks/components.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,12 @@ async def do_command(self, command: Mapping[str, ValueTypes], *, timeout: Option
230230

231231

232232
class MockAnalog(Board.Analog):
233-
def __init__(self, name: str, value: int):
234-
self.value = value
233+
def __init__(self, name: str, value: int, min_range: float, max_range: float, step_size: float):
234+
self.value = self.Value(value=value, min_range=min_range, max_range=max_range, step_size=step_size)
235235
self.timeout: Optional[float] = None
236236
super().__init__(name)
237237

238-
async def read(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> int:
238+
async def read(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> Board.Analog.Value:
239239
self.extra = extra
240240
self.timeout = timeout
241241
return self.value

tests/test_board.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ def board() -> MockBoard:
4545
return MockBoard(
4646
name="board",
4747
analogs={
48-
"reader1": MockAnalog("reader1", 3),
49-
"writer1": MockAnalog("writer1", 5),
48+
"reader1": MockAnalog("reader1", 3, 0.0, 1.0, 0.1),
49+
"writer1": MockAnalog("writer1", 5, 0.0, 1.0, 0.1),
5050
},
5151
digital_interrupts={
5252
"interrupt1": MockDigitalInterrupt("interrupt1"),
@@ -119,7 +119,7 @@ async def test_status(self, board: MockBoard):
119119
assert status.name == MockBoard.get_resource_name(board.name)
120120
assert status.status == message_to_struct(
121121
BoardStatus(
122-
analogs={"reader1": int(read1), "writer1": int(read2)},
122+
analogs={"reader1": int(read1.value), "writer1": int(read2.value)},
123123
digital_interrupts={"interrupt1": val},
124124
)
125125
)
@@ -171,6 +171,9 @@ async def test_read_analog(self, board: MockBoard, service: BoardRPCService):
171171
request = ReadAnalogReaderRequest(board_name=board.name, analog_reader_name="reader1", extra=dict_to_struct(extra))
172172
response: ReadAnalogReaderResponse = await client.ReadAnalogReader(request, timeout=4.4)
173173
assert response.value == 3
174+
assert response.min_range == 0.0
175+
assert response.max_range == 1.0
176+
assert response.step_size == pytest.approx(0.1)
174177

175178
reader = cast(MockAnalog, board.analogs["reader1"])
176179
assert reader.extra == extra

0 commit comments

Comments
 (0)