Skip to content

Commit b69b05d

Browse files
RSDK-4788: Add Readings to Python SDK (#459)
Co-authored-by: viambot <[email protected]>
1 parent c7f6341 commit b69b05d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+659
-493
lines changed

examples/server/v1/components.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ def __init__(
653653
accuracy: Mapping[str, float],
654654
):
655655
super().__init__(name)
656+
self.num_readings = random.randint(1, 10)
656657
self.coordinates = coordinates
657658
self.altitude = altitude
658659
self.lin_vel = lin_vel
@@ -663,6 +664,9 @@ def __init__(
663664
self.properties = properties
664665
self.accuracy = accuracy
665666

667+
async def get_readings(self, **kwargs) -> Mapping[str, Any]:
668+
return {"abcdefghij"[idx]: random.random() for idx in range(self.num_readings)}
669+
666670
async def get_position(self, **kwargs) -> Tuple[GeoPoint, float]:
667671
return (self.coordinates, self.altitude)
668672

src/viam/components/movement_sensor/client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from grpclib.client import Channel
44

55
from viam.components.movement_sensor.movement_sensor import MovementSensor
6-
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry
6+
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry, GetReadingsRequest, GetReadingsResponse
77
from viam.proto.component.movementsensor import (
88
GetAccuracyRequest,
99
GetAccuracyResponse,
@@ -96,7 +96,9 @@ async def get_accuracy(self, *, extra: Optional[Dict[str, Any]] = None, timeout:
9696
async def get_readings(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None) -> Mapping[str, Any]:
9797
if extra is None:
9898
extra = {}
99-
return await super().get_readings(extra=extra, timeout=timeout)
99+
request = GetReadingsRequest(name=self.name, extra=dict_to_struct(extra))
100+
response: GetReadingsResponse = await self.client.GetReadings(request, timeout=timeout)
101+
return response.readings
100102

101103
async def do_command(self, command: Mapping[str, ValueTypes], *, timeout: Optional[float] = None) -> Mapping[str, ValueTypes]:
102104
request = DoCommandRequest(name=self.name, command=dict_to_struct(command))

src/viam/components/movement_sensor/movement_sensor.py

Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import abc
2-
import asyncio
32
from dataclasses import dataclass
4-
from typing import Any, Dict, Final, List, Mapping, Optional, Tuple
3+
from typing import Any, Dict, Final, Mapping, Optional, Tuple
54

6-
from grpclib import GRPCError
75
from typing_extensions import Self
8-
9-
from viam.errors import MethodNotImplementedError, NotSupportedError
6+
from viam.components.component_base import ComponentBase
107
from viam.proto.component.movementsensor import GetPropertiesResponse
118
from viam.resource.types import RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, Subtype
129

13-
from ..sensor import Sensor
1410
from . import GeoPoint, Orientation, Vector3
1511

1612

17-
class MovementSensor(Sensor):
13+
class MovementSensor(ComponentBase):
1814
"""MovementSensor reports information about the robot's direction, position and speed.
1915
2016
This acts as an abstract base class for any sensors that can provide data regarding the robot's direction, position, and speed.
@@ -137,48 +133,7 @@ async def get_readings(self, *, extra: Optional[Dict[str, Any]] = None, timeout:
137133
If a sensor is not configured to have a measurement or fails to read a piece of data, it will not appear in the readings dictionary.
138134
139135
Returns:
140-
Mapping[str, Any]: The readings for the MovementSensor:
141-
{
142-
position: GeoPoint,
143-
altitude: float,
144-
linear_velocity: Vector3,
145-
angular_velocity: Vector3,
146-
linear_acceleration: Vector3,
147-
compass: float,
148-
orientation: Orientation,
149-
}
136+
Mapping[str, Any]: The readings for the MovementSensor. Can be of any type.
137+
150138
"""
151-
(pos, lv, av, la, comp, orient) = await asyncio.gather(
152-
self.get_position(extra=extra, timeout=timeout),
153-
self.get_linear_velocity(extra=extra, timeout=timeout),
154-
self.get_angular_velocity(extra=extra, timeout=timeout),
155-
self.get_linear_acceleration(extra=extra, timeout=timeout),
156-
self.get_compass_heading(extra=extra, timeout=timeout),
157-
self.get_orientation(extra=extra, timeout=timeout),
158-
return_exceptions=True,
159-
)
160-
161-
readings = {}
162-
163-
# Add returned value to the readings dictionary if value is of expected type; omit if unimplemented.
164-
def add_reading(name: str, reading, returntype: List) -> None:
165-
possible_error_types = (NotImplementedError, MethodNotImplementedError, NotSupportedError)
166-
if type(reading) in returntype:
167-
if name == "position":
168-
readings["position"] = reading[0]
169-
readings["altitude"] = reading[1]
170-
else:
171-
readings[name] = reading
172-
return
173-
elif isinstance(reading, possible_error_types) or (isinstance(reading, GRPCError) and "Unimplemented" in str(reading.message)):
174-
return
175-
raise reading
176-
177-
add_reading("position", pos, [tuple])
178-
add_reading("linear_velocity", lv, [Vector3])
179-
add_reading("angular_velocity", av, [Vector3])
180-
add_reading("linear_acceleration", la, [Vector3])
181-
add_reading("compass", comp, [float, int])
182-
add_reading("orientation", orient, [Orientation])
183-
184-
return readings
139+
...

src/viam/components/movement_sensor/service.py

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

33
from viam.components.movement_sensor.movement_sensor import MovementSensor
4-
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetGeometriesRequest, GetGeometriesResponse
4+
from viam.proto.common import (
5+
DoCommandRequest,
6+
DoCommandResponse,
7+
GetGeometriesRequest,
8+
GetGeometriesResponse,
9+
GetReadingsRequest,
10+
GetReadingsResponse,
11+
)
512
from viam.proto.component.movementsensor import (
613
GetAccuracyRequest,
714
GetAccuracyResponse,
@@ -22,7 +29,7 @@
2229
MovementSensorServiceBase,
2330
)
2431
from viam.resource.rpc_service_base import ResourceRPCServiceBase
25-
from viam.utils import dict_to_struct, struct_to_dict
32+
from viam.utils import dict_to_struct, sensor_readings_native_to_value, struct_to_dict
2633

2734

2835
class MovementSensorRPCService(MovementSensorServiceBase, ResourceRPCServiceBase):
@@ -128,3 +135,13 @@ async def GetGeometries(self, stream: Stream[GetGeometriesRequest, GetGeometries
128135
geometries = await sensor.get_geometries(extra=struct_to_dict(request.extra), timeout=timeout)
129136
response = GetGeometriesResponse(geometries=geometries)
130137
await stream.send_message(response)
138+
139+
async def GetReadings(self, stream: Stream[GetReadingsRequest, GetReadingsResponse]) -> None:
140+
request = await stream.recv_message()
141+
assert request is not None
142+
name = request.name
143+
sensor = self.get_resource(name)
144+
timeout = stream.deadline.time_remaining() if stream.deadline else None
145+
readings = await sensor.get_readings(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata)
146+
response = GetReadingsResponse(readings=sensor_readings_native_to_value(readings))
147+
await stream.send_message(response)

src/viam/components/power_sensor/client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from grpclib.client import Channel
44

55
from viam.components.power_sensor.power_sensor import PowerSensor
6-
from viam.proto.common import DoCommandRequest, DoCommandResponse
6+
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetReadingsRequest, GetReadingsResponse
77
from viam.proto.component.powersensor import (
88
GetCurrentRequest,
99
GetCurrentResponse,
@@ -49,7 +49,9 @@ async def get_power(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Op
4949
async def get_readings(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None) -> Mapping[str, Any]:
5050
if extra is None:
5151
extra = {}
52-
return await super().get_readings(extra=extra, timeout=timeout)
52+
request = GetReadingsRequest(name=self.name, extra=dict_to_struct(extra))
53+
response: GetReadingsResponse = await self.client.GetReadings(request, timeout=timeout)
54+
return response.readings
5355

5456
async def do_command(self, command: Mapping[str, ValueTypes], *, timeout: Optional[float] = None) -> Mapping[str, ValueTypes]:
5557
request = DoCommandRequest(name=self.name, command=dict_to_struct(command))

src/viam/components/power_sensor/power_sensor.py

Lines changed: 3 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
import abc
2-
import asyncio
3-
from typing import Any, Dict, Final, List, Mapping, Optional, Tuple
4-
5-
from grpclib import GRPCError
2+
from typing import Any, Dict, Final, Mapping, Optional, Tuple
63

74
from viam.components.component_base import ComponentBase
8-
from viam.errors import MethodNotImplementedError, NotSupportedError
95
from viam.resource.types import RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, Subtype
106

117

@@ -57,35 +53,6 @@ async def get_readings(self, *, extra: Optional[Dict[str, Any]] = None, timeout:
5753
is_ac: bool
5854
power: float
5955
}
60-
"""
61-
(vol, cur, pow) = await asyncio.gather(
62-
self.get_voltage(extra=extra, timeout=timeout),
63-
self.get_current(extra=extra, timeout=timeout),
64-
self.get_power(extra=extra, timeout=timeout),
65-
return_exceptions=True,
66-
)
67-
68-
readings = {}
69-
70-
# Add returned value to the readings dictionary if value is of expected type; omit if unimplemented.
71-
def add_reading(name: str, reading, returntype: List) -> None:
72-
possible_error_types = (NotImplementedError, MethodNotImplementedError, NotSupportedError)
73-
if type(reading) in returntype:
74-
if name == "voltage":
75-
readings["voltage"] = reading[0]
76-
readings["is_ac"] = reading[1]
77-
elif name == "current":
78-
readings["current"] = reading[0]
79-
readings["is_ac"] = reading[1]
80-
else:
81-
readings[name] = reading
82-
return
83-
elif isinstance(reading, possible_error_types) or (isinstance(reading, GRPCError) and "Unimplemented" in str(reading.message)):
84-
return
85-
raise reading
8656
87-
add_reading("voltage", vol, [tuple])
88-
add_reading("current", cur, [tuple])
89-
add_reading("power", pow, [float])
90-
91-
return readings
57+
"""
58+
...

src/viam/components/power_sensor/service.py

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

33
from viam.components.power_sensor.power_sensor import PowerSensor
4-
from viam.proto.common import DoCommandRequest, DoCommandResponse
4+
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetReadingsRequest, GetReadingsResponse
55
from viam.proto.component.powersensor import (
66
GetCurrentRequest,
77
GetCurrentResponse,
@@ -12,7 +12,7 @@
1212
PowerSensorServiceBase,
1313
)
1414
from viam.resource.rpc_service_base import ResourceRPCServiceBase
15-
from viam.utils import dict_to_struct, struct_to_dict
15+
from viam.utils import dict_to_struct, sensor_readings_native_to_value, struct_to_dict
1616

1717

1818
class PowerSensorRPCService(PowerSensorServiceBase, ResourceRPCServiceBase):
@@ -22,6 +22,16 @@ class PowerSensorRPCService(PowerSensorServiceBase, ResourceRPCServiceBase):
2222

2323
RESOURCE_TYPE = PowerSensor
2424

25+
async def GetReadings(self, stream: Stream[GetReadingsRequest, GetReadingsResponse]) -> None:
26+
request = await stream.recv_message()
27+
assert request is not None
28+
name = request.name
29+
sensor = self.get_resource(name)
30+
timeout = stream.deadline.time_remaining() if stream.deadline else None
31+
readings = await sensor.get_readings(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata)
32+
response = GetReadingsResponse(readings=sensor_readings_native_to_value(readings))
33+
await stream.send_message(response)
34+
2535
async def GetVoltage(self, stream: Stream[GetVoltageRequest, GetVoltageResponse]) -> None:
2636
request = await stream.recv_message()
2737
assert request is not None

src/viam/components/sensor/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from grpclib.client import Channel
44

5-
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry
6-
from viam.proto.component.sensor import GetReadingsRequest, GetReadingsResponse, SensorServiceStub
5+
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry, GetReadingsRequest, GetReadingsResponse
6+
from viam.proto.component.sensor import SensorServiceStub
77
from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase
88
from viam.utils import ValueTypes, dict_to_struct, get_geometries, sensor_readings_value_to_native, struct_to_dict
99

src/viam/components/sensor/service.py

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

3-
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetGeometriesRequest, GetGeometriesResponse
4-
from viam.proto.component.sensor import GetReadingsRequest, GetReadingsResponse, SensorServiceBase
3+
from viam.proto.common import (
4+
DoCommandRequest,
5+
DoCommandResponse,
6+
GetGeometriesRequest,
7+
GetGeometriesResponse,
8+
GetReadingsRequest,
9+
GetReadingsResponse,
10+
)
11+
from viam.proto.component.sensor import SensorServiceBase
512
from viam.resource.rpc_service_base import ResourceRPCServiceBase
613
from viam.utils import dict_to_struct, sensor_readings_native_to_value, struct_to_dict
714

0 commit comments

Comments
 (0)