Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSDK-7307: Update Status for Board in Python SDK #586

Merged
merged 9 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ _buf: clean

buf:
poetry run $(MAKE) _buf
$(MAKE) better_imports

_better_imports:
python3 -m etc.generate_proto_import -v
Expand Down
16 changes: 8 additions & 8 deletions etc/generate_proto_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper

from viam import logging
import logging

PACKAGE_PATH = Path(__file__).parent.parent

Expand All @@ -25,7 +25,7 @@


LOGGER = logging.getLogger(__name__)
logging.setLevel(logging.INFO)
LOGGER.setLevel(logging.INFO)


def clean():
Expand All @@ -51,7 +51,7 @@ def get_packages(root: str) -> Dict[str, List[str]]:

packages: Dict[str, List[str]] = {}

for (dirpath, _, filenames) in os.walk(root):
for dirpath, _, filenames in os.walk(root):
rel_path = Path(dirpath).relative_to(root).__str__()
if "__" in rel_path:
continue
Expand Down Expand Up @@ -140,18 +140,18 @@ def check_class(obj) -> bool:
f.write("@generated by Viam.\n")
f.write("Do not edit manually!\n")
f.write("'''\n")
for (imp, cls) in classes.items():
for imp, cls in classes.items():
f.write(f'from {"."*(len(package.split("."))+IMPORT_LEVEL)}{PROTO_GEN_PACKAGE}.{package}.{imp} import (\n')
f.write(" %s\n" % (",\n ".join(cls)))
f.write(")\n")
f.write("\n__all__ = [\n")
for (imp, cls) in classes.items():
for imp, cls in classes.items():
f.write(" %s,\n" % (",\n ".join([f"'{c}'" for c in cls])))
f.write("]\n")


def add_init_files(root: str):
for (dirpath, _, filenames) in os.walk(root):
for dirpath, _, filenames in os.walk(root):
if "__init__.py" not in filenames:
LOGGER.debug(f"Adding __init__.py at {dirpath}")
path = Path(dirpath) / "__init__.py"
Expand All @@ -163,7 +163,7 @@ def run(add_inits: bool = True):
LOGGER.info("Generating better proto imports")
clean()
packages = get_packages(GENERATED_PATH.__str__())
for (package, modules) in packages.items():
for package, modules in packages.items():
build_dirs(NEW_IMPORT_PATH.__str__(), package, modules)
if add_inits:
add_init_files(NEW_IMPORT_PATH.__str__())
Expand All @@ -179,7 +179,7 @@ def run(add_inits: bool = True):
if "q" in arg:
LOGGER.disabled = True
if "v" in arg:
logging.setLevel(logging.DEBUG)
LOGGER.setLevel(logging.DEBUG)
if "i" in arg:
add_inits = False
except getopt.error:
Expand Down
13 changes: 1 addition & 12 deletions examples/server/v1/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@
from viam.media.video import NamedImage
from viam.operations import run_with_operation
from viam.proto.common import (
AnalogStatus,
BoardStatus,
Capsule,
DigitalInterruptStatus,
Geometry,
GeoPoint,
KinematicsFileFormat,
Expand Down Expand Up @@ -311,21 +308,13 @@ async def analog_reader_names(self) -> List[str]:
async def digital_interrupt_names(self) -> List[str]:
return [key for key in self.digital_interrupts.keys()]

async def status(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> BoardStatus:
return BoardStatus(
analogs={name: AnalogStatus(value=await analog.read()) for (name, analog) in self.analog_readers.items()},
digital_interrupts={name: DigitalInterruptStatus(value=await di.value()) for (name, di) in self.digital_interrupts.items()},
)

async def set_power_mode(self, **kwargs):
raise NotImplementedError()

async def write_analog(self, pin: str, value: int, *, timeout: Optional[float] = None, **kwargs):
raise NotImplementedError()

async def stream_ticks(
self, interrupts: List[Board.DigitalInterrupt], *, timeout: Optional[float] = None, **kwargs
) -> TickStream:
async def stream_ticks(self, interrupts: List[Board.DigitalInterrupt], *, timeout: Optional[float] = None, **kwargs) -> TickStream:
raise NotImplementedError()

async def get_geometries(self, extra: Optional[Dict[str, Any]] = None, **kwargs) -> List[Geometry]:
Expand Down
2 changes: 1 addition & 1 deletion src/viam/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from importlib.metadata import PackageNotFoundError, version
from uuid import uuid4

from viam.proto.common import ResourceName as _ResourceName
from viam.gen.common.v1.common_pb2 import ResourceName as _ResourceName

from .logging import getLogger as _getLogger

Expand Down
2 changes: 1 addition & 1 deletion src/viam/components/audio_input/audio_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
from google.protobuf.duration_pb2 import Duration
from typing_extensions import Self

from viam.streams import StreamSource
from viam.media.audio import Audio, AudioStream
from viam.proto.component.audioinput import PropertiesResponse
from viam.resource.types import RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, Subtype
from viam.streams import StreamSource

from ..component_base import ComponentBase

Expand Down
2 changes: 1 addition & 1 deletion src/viam/components/audio_input/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from grpclib.client import Channel

from viam.streams import Stream, StreamWithIterator
from viam.media.audio import Audio
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry
from viam.proto.component.audioinput import (
Expand All @@ -14,6 +13,7 @@
SampleFormat,
)
from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase
from viam.streams import Stream, StreamWithIterator
from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict

from .audio_input import AudioInput
Expand Down
23 changes: 19 additions & 4 deletions src/viam/components/board/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import asyncio

from viam.proto.common import AnalogStatus, DigitalInterruptStatus
from viam.proto.component.board import Status as BoardStatus
from viam.proto.robot import Status
from viam.resource.registry import Registry, ResourceRegistration
from viam.utils import message_to_struct
Expand All @@ -6,13 +10,24 @@
from .client import BoardClient
from .service import BoardRPCService

__all__ = [
"Board"
]
__all__ = ["Board"]


async def create_status(component: Board) -> Status:
return Status(name=Board.get_resource_name(component.name), status=message_to_struct(await component.status()))
(analog_names, digital_interrupt_names) = await asyncio.gather(component.analog_reader_names(), component.digital_interrupt_names())
analogs, digital_interrupts = {}, {}
for x in analog_names:
analog = await component.analog_reader_by_name(x)
read = await analog.read()
analogs[x] = AnalogStatus(value=read)

for y in digital_interrupt_names:
digital_interrupt = await component.digital_interrupt_by_name(y)
val = await digital_interrupt.value()
digital_interrupts[y] = DigitalInterruptStatus(value=val)

s = BoardStatus(analogs=analogs, digital_interrupts=digital_interrupts)
return Status(name=Board.get_resource_name(component.name), status=message_to_struct(s))


Registry.register_subtype(ResourceRegistration(Board, BoardRPCService, lambda name, channel: BoardClient(name, channel), create_status))
22 changes: 1 addition & 21 deletions src/viam/components/board/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from datetime import timedelta
from typing import Any, Dict, Final, List, Optional

from viam.proto.common import BoardStatus
from viam.proto.component.board import PowerMode, StreamTicksResponse
from viam.resource.types import RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, Subtype
from viam.streams import Stream
Expand Down Expand Up @@ -341,23 +340,6 @@ async def digital_interrupt_names(self) -> List[str]:
"""
...

@abc.abstractmethod
async def status(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> BoardStatus:
"""
Return the current status of the board.

::

my_board = Board.from_robot(robot=robot, name="my_board")

# Get the current status of the board.
status = await my_board.status()

Returns:
viam.proto.common.BoardStatus: The status.
"""
...

@abc.abstractmethod
async def set_power_mode(
self, mode: PowerMode.ValueType, duration: Optional[timedelta] = None, *, timeout: Optional[float] = None, **kwargs
Expand Down Expand Up @@ -396,9 +378,7 @@ async def write_analog(self, pin: str, value: int, *, timeout: Optional[float] =
...

@abc.abstractmethod
async def stream_ticks(
self, interrupts: List[DigitalInterrupt], *, timeout: Optional[float] = None, **kwargs
) -> TickStream:
async def stream_ticks(self, interrupts: List[DigitalInterrupt], *, timeout: Optional[float] = None, **kwargs) -> TickStream:
"""
Stream digital interrupt ticks.

Expand Down
39 changes: 13 additions & 26 deletions src/viam/components/board/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
from typing import Any, Dict, List, Mapping, Optional

from google.protobuf.duration_pb2 import Duration
from grpclib.client import Channel, Stream as ClientStream
from grpclib.client import Channel
from grpclib.client import Stream as ClientStream

from viam.logging import getLogger
from viam.proto.common import BoardStatus, DoCommandRequest, DoCommandResponse, Geometry
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry
from viam.proto.component.board import (
BoardServiceStub,
GetDigitalInterruptValueRequest,
Expand All @@ -23,14 +24,12 @@
SetPowerModeRequest,
SetPWMFrequencyRequest,
SetPWMRequest,
StatusRequest,
StatusResponse,
StreamTicksRequest,
StreamTicksResponse,
WriteAnalogRequest,
)
from viam.streams import StreamWithIterator
from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase
from viam.streams import StreamWithIterator
from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict

from .board import Board, TickStream
Expand Down Expand Up @@ -165,49 +164,37 @@ class BoardClient(Board, ReconfigurableResourceRPCClientBase):
gRPC client for the Board component.
"""

_analog_reader_names: List[str]
_digital_interrupt_names: List[str]

def __init__(self, name: str, channel: Channel):
self.channel = channel
self.client = BoardServiceStub(channel)
self._analog_reader_names: Optional[List[str]] = None
self._digital_interrupt_names: Optional[List[str]] = None
self._analog_reader_names = []
self._digital_interrupt_names = []
super().__init__(name)

async def analog_reader_by_name(self, name: str) -> Board.AnalogReader:
self._analog_reader_names.append(name)
return AnalogReaderClient(name, self)

async def digital_interrupt_by_name(self, name: str) -> Board.DigitalInterrupt:
self._digital_interrupt_names.append(name)
return DigitalInterruptClient(name, self)

async def gpio_pin_by_name(self, name: str) -> Board.GPIOPin:
return GPIOPinClient(name, self)

async def analog_reader_names(self) -> List[str]:
if self._analog_reader_names is None:
status = await self.status()
names = [name for name in status.analogs.keys()]
self._analog_reader_names = names
return []
return self._analog_reader_names

async def digital_interrupt_names(self) -> List[str]:
if self._digital_interrupt_names is None:
status = await self.status()
names = [name for name in status.digital_interrupts.keys()]
self._digital_interrupt_names = names
return []
return self._digital_interrupt_names

async def status(
self,
*,
extra: Optional[Dict[str, Any]] = None,
timeout: Optional[float] = None,
**__,
) -> BoardStatus:
if extra is None:
extra = {}
request = StatusRequest(name=self.name, extra=dict_to_struct(extra))
response: StatusResponse = await self.client.Status(request, timeout=timeout)
return response.status

async def do_command(
self,
command: Mapping[str, ValueTypes],
Expand Down
12 changes: 0 additions & 12 deletions src/viam/components/board/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
SetPWMFrequencyResponse,
SetPWMRequest,
SetPWMResponse,
StatusRequest,
StatusResponse,
StreamTicksRequest,
StreamTicksResponse,
WriteAnalogRequest,
Expand All @@ -46,16 +44,6 @@ class BoardRPCService(BoardServiceBase, ResourceRPCServiceBase[Board]):

RESOURCE_TYPE = Board

async def Status(self, stream: Stream[StatusRequest, StatusResponse]) -> None:
request = await stream.recv_message()
assert request is not None
name = request.name
board = self.get_resource(name)
timeout = stream.deadline.time_remaining() if stream.deadline else None
status = await board.status(extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata)
response = StatusResponse(status=status)
await stream.send_message(response)

async def SetGPIO(self, stream: Stream[SetGPIORequest, SetGPIOResponse]) -> None:
request = await stream.recv_message()
assert request is not None
Expand Down
7 changes: 6 additions & 1 deletion src/viam/gen/app/mltraining/v1/ml_training_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ class MLTrainingServiceBase(abc.ABC):
async def SubmitTrainingJob(self, stream: 'grpclib.server.Stream[app.mltraining.v1.ml_training_pb2.SubmitTrainingJobRequest, app.mltraining.v1.ml_training_pb2.SubmitTrainingJobResponse]') -> None:
pass

@abc.abstractmethod
async def SubmitCustomTrainingJob(self, stream: 'grpclib.server.Stream[app.mltraining.v1.ml_training_pb2.SubmitCustomTrainingJobRequest, app.mltraining.v1.ml_training_pb2.SubmitCustomTrainingJobResponse]') -> None:
pass

@abc.abstractmethod
async def GetTrainingJob(self, stream: 'grpclib.server.Stream[app.mltraining.v1.ml_training_pb2.GetTrainingJobRequest, app.mltraining.v1.ml_training_pb2.GetTrainingJobResponse]') -> None:
pass
Expand All @@ -32,12 +36,13 @@ async def DeleteCompletedTrainingJob(self, stream: 'grpclib.server.Stream[app.ml
pass

def __mapping__(self) -> typing.Dict[str, grpclib.const.Handler]:
return {'/viam.app.mltraining.v1.MLTrainingService/SubmitTrainingJob': grpclib.const.Handler(self.SubmitTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.SubmitTrainingJobRequest, app.mltraining.v1.ml_training_pb2.SubmitTrainingJobResponse), '/viam.app.mltraining.v1.MLTrainingService/GetTrainingJob': grpclib.const.Handler(self.GetTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.GetTrainingJobRequest, app.mltraining.v1.ml_training_pb2.GetTrainingJobResponse), '/viam.app.mltraining.v1.MLTrainingService/ListTrainingJobs': grpclib.const.Handler(self.ListTrainingJobs, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.ListTrainingJobsRequest, app.mltraining.v1.ml_training_pb2.ListTrainingJobsResponse), '/viam.app.mltraining.v1.MLTrainingService/CancelTrainingJob': grpclib.const.Handler(self.CancelTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.CancelTrainingJobRequest, app.mltraining.v1.ml_training_pb2.CancelTrainingJobResponse), '/viam.app.mltraining.v1.MLTrainingService/DeleteCompletedTrainingJob': grpclib.const.Handler(self.DeleteCompletedTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.DeleteCompletedTrainingJobRequest, app.mltraining.v1.ml_training_pb2.DeleteCompletedTrainingJobResponse)}
return {'/viam.app.mltraining.v1.MLTrainingService/SubmitTrainingJob': grpclib.const.Handler(self.SubmitTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.SubmitTrainingJobRequest, app.mltraining.v1.ml_training_pb2.SubmitTrainingJobResponse), '/viam.app.mltraining.v1.MLTrainingService/SubmitCustomTrainingJob': grpclib.const.Handler(self.SubmitCustomTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.SubmitCustomTrainingJobRequest, app.mltraining.v1.ml_training_pb2.SubmitCustomTrainingJobResponse), '/viam.app.mltraining.v1.MLTrainingService/GetTrainingJob': grpclib.const.Handler(self.GetTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.GetTrainingJobRequest, app.mltraining.v1.ml_training_pb2.GetTrainingJobResponse), '/viam.app.mltraining.v1.MLTrainingService/ListTrainingJobs': grpclib.const.Handler(self.ListTrainingJobs, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.ListTrainingJobsRequest, app.mltraining.v1.ml_training_pb2.ListTrainingJobsResponse), '/viam.app.mltraining.v1.MLTrainingService/CancelTrainingJob': grpclib.const.Handler(self.CancelTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.CancelTrainingJobRequest, app.mltraining.v1.ml_training_pb2.CancelTrainingJobResponse), '/viam.app.mltraining.v1.MLTrainingService/DeleteCompletedTrainingJob': grpclib.const.Handler(self.DeleteCompletedTrainingJob, grpclib.const.Cardinality.UNARY_UNARY, app.mltraining.v1.ml_training_pb2.DeleteCompletedTrainingJobRequest, app.mltraining.v1.ml_training_pb2.DeleteCompletedTrainingJobResponse)}

class MLTrainingServiceStub:

def __init__(self, channel: grpclib.client.Channel) -> None:
self.SubmitTrainingJob = grpclib.client.UnaryUnaryMethod(channel, '/viam.app.mltraining.v1.MLTrainingService/SubmitTrainingJob', app.mltraining.v1.ml_training_pb2.SubmitTrainingJobRequest, app.mltraining.v1.ml_training_pb2.SubmitTrainingJobResponse)
self.SubmitCustomTrainingJob = grpclib.client.UnaryUnaryMethod(channel, '/viam.app.mltraining.v1.MLTrainingService/SubmitCustomTrainingJob', app.mltraining.v1.ml_training_pb2.SubmitCustomTrainingJobRequest, app.mltraining.v1.ml_training_pb2.SubmitCustomTrainingJobResponse)
self.GetTrainingJob = grpclib.client.UnaryUnaryMethod(channel, '/viam.app.mltraining.v1.MLTrainingService/GetTrainingJob', app.mltraining.v1.ml_training_pb2.GetTrainingJobRequest, app.mltraining.v1.ml_training_pb2.GetTrainingJobResponse)
self.ListTrainingJobs = grpclib.client.UnaryUnaryMethod(channel, '/viam.app.mltraining.v1.MLTrainingService/ListTrainingJobs', app.mltraining.v1.ml_training_pb2.ListTrainingJobsRequest, app.mltraining.v1.ml_training_pb2.ListTrainingJobsResponse)
self.CancelTrainingJob = grpclib.client.UnaryUnaryMethod(channel, '/viam.app.mltraining.v1.MLTrainingService/CancelTrainingJob', app.mltraining.v1.ml_training_pb2.CancelTrainingJobRequest, app.mltraining.v1.ml_training_pb2.CancelTrainingJobResponse)
Expand Down
Loading
Loading