Skip to content

Commit

Permalink
Release GDM 1.75.0
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 455022444
  • Loading branch information
GDM Authors authored and artorl committed Jun 15, 2022
1 parent ad04f6c commit af6cd9e
Show file tree
Hide file tree
Showing 40 changed files with 1,749 additions and 788 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ GDM runs on the test host and communicates with the physical devices via one or
more device transports (such as SSH, ADB, HTTPS, UART). GDM does not require any
additional support from the device firmware.

GDM is used for on-device testing at Google Nest.
GDM is used for on-device testing at Google Gazoo.

## Table of contents

Expand Down Expand Up @@ -122,7 +122,7 @@ Installation steps:
To enable flashing ESP32 dev boards through GDM, install `esptool`:

```shell
~/gazoo/gdm/virtual_env/bin/pip install esptool>=3.2
~/gazoo/gdm/virtual_env/bin/pip install esptool==4.1
```

GDM installation creates a virtual environment for the CLI at
Expand Down
4 changes: 2 additions & 2 deletions docs/Matter_endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ the device will raise a `DeviceError`:

```
>>> nrf.door_lock
nrfmatter-4585 starting MatterEndpointsAccessor.get_endpoint_instance_by_class(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
nrfmatter-4585 starting MatterEndpointsAccessor.get_endpoint_id(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
nrfmatter-4585 starting MatterEndpointsAccessorPwRpc.get_endpoint_instance_by_class(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
nrfmatter-4585 starting MatterEndpointsAccessorPwRpc.get_endpoint_id(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
Traceback (most recent call last):
....
raise errors.DeviceError(
Expand Down
4 changes: 2 additions & 2 deletions docs/device_setup/ESP32_Matter_sample_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,8 @@ Assume `esp` does not have a `DoorLock` endpoint.

```
>>> esp.door_lock
esp32matter-4585 starting MatterEndpointsAccessor.get_endpoint_instance_by_class(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
esp32matter-4585 starting MatterEndpointsAccessor.get_endpoint_id(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
esp32matter-4585 starting MatterEndpointsAccessorPwRpc.get_endpoint_instance_by_class(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
esp32matter-4585 starting MatterEndpointsAccessorPwRpc.get_endpoint_id(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
Traceback (most recent call last):
....
raise errors.DeviceError(
Expand Down
4 changes: 2 additions & 2 deletions docs/device_setup/NRF_Matter_sample_app.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,8 @@ Assume `nrf` does not have a `DoorLock` endpoint.

```
>>> nrf.door_lock
nrfmatter-4585 starting MatterEndpointsAccessor.get_endpoint_instance_by_class(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
nrfmatter-4585 starting MatterEndpointsAccessor.get_endpoint_id(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
nrfmatter-4585 starting MatterEndpointsAccessorPwRpc.get_endpoint_instance_by_class(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
nrfmatter-4585 starting MatterEndpointsAccessorPwRpc.get_endpoint_id(endpoint_class=<class 'gazoo_device.capabilities.matter_endpoints.door_lock.DoorLockEndpoint'>)
Traceback (most recent call last):
....
raise errors.DeviceError(
Expand Down
110 changes: 110 additions & 0 deletions docs/device_setup/Raspberry_Pi_as_matter_controller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# GDM device setup: Raspberry Pi (as a Matter controller)

Supported models: Raspberry Pi 4 with at least 4GB of memory.

Supported kernel images: Ubuntu 21.04 or later.

## Setup

1. Follow the instructions from
[Installing prerequisites on Raspberry Pi 4](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/BUILDING.md#installing-prerequisites-on-raspberry-pi-4)
section of
[project-chip/connectedhomeip](https://github.com/project-chip/connectedhomeip)'s
Building Matter guide to set up the Raspberry Pi.
2. On the raspberry pi, build `chip-tool` and install it to
`/usr/local/bin/chip-tool`. Follow the instructions on
https://github.com/project-chip/connectedhomeip/tree/master/examples/chip-tool#building-the-example-application.

3. On the raspberry pi, save the commit SHA the `chip-tool` was built at by
running

```shell
echo $COMMIT_SHA > ~/.matter_sdk_version
```

4. Ensure that user `pi` can write to `/usr/local/bin` directory. This is
required for `matter_controller.upgrade` functionality to work properly. Run
the command below on the raspberry pi:

```shell
sudo chown -R `whoami`:pi /usr/local/bin
```

5. Follow the instructions from
[GDM device setup: Raspberry Pi (as a support device)](./Raspberry_Pi_as_supporting_device.md)
starting from the `Configure GDM SSH keys` step to ensure that gdm can
detect the raspberry pi as a `rpi_matter_controller`. The output of `gdm
devices` command should look like:

```shell
$ gdm devices
Device Alias Type Model Connected
------------------------------ --------------- ------------------------ -------------------- ----------

Other Devices Alias Type Model Available
------------------------------ --------------- ------------------------ -------------------- ----------
rpi_matter_controller-1234 <undefined> rpi_matter_controller 4 Model B Rev 1.4 available
```

### Optional: Thread Border Router Setup

Requirement:
[NRF52840-DONGLE](https://www.nordicsemi.com/Products/Development-hardware/nrf52840-dongle)

1. On the host machine, follow the instructions from
[project-chip/connectedhomeip](https://github.com/project-chip/connectedhomeip)'s
[Configuring OpenThread Radio Co-processor on nRF52840 Dongle](https://github.com/project-chip/connectedhomeip/blob/master/docs/guides/openthread_rcp_nrf_dongle.md)
page to build and install the NRF52840-DONGLE RCP firmware.

2. Plug the NRF52840-DONGLE to the raspberry pi.

3. On the raspberry pi, install the OpenThread Border Router following Step 2
and 3 from this
[instructions](https://openthread.io/codelabs/openthread-border-router#0).

In Step 2 “Setup OTBR”, use eth0 as the infrastructure network as the
Raspberry Pi should be connected to the WiFi router via the ethernet (eth0)
interface:

```shell
INFRA_IF_NAME=eth0 ./script/setup
```

In
[Step 2 “Setup OTBR”](https://openthread.io/codelabs/openthread-border-router#1),
skip the part about flashing the RCP firmware if this was done successfully
in step 1 above.

After
[Step 3 “Form a Thread Network”](https://openthread.io/codelabs/openthread-border-router#1),
you can stop - you have created a Thread network and are ready to commission
CHIP devices onto it. Note the thread dataset as it will be needed to
commission CHIP devices onto the network:

```shell
sudo ot-ctl dataset active -x

0e080000000000010000000300001835060004001fffe00208161de905837b6ba10708fdd61eb482e203ad0510fe8c68576cef838b184b41df13c9e694030f4f70656e5468726561642d323832610102282a0410615a57bd3d170a24ac2a461d37c8e97c0c0402a0fff8
```

## Usage

```shell
# Commission a device on network with 20202021 setup code and assign it node id 100.
gdm issue rpi_matter_controller-1234 - matter_controller commission 100 20202021

# Commission a device over thread using dataset generated from `Optional: Thread Border Router Setup` step
gdm issue rpi_matter_controller-1234 - matter_controller commission 100 20202021 --operational_dataset 0e080000000000010000000300001835060004001fffe00208161de905837b6ba10708fdd61eb482e203ad0510fe8c68576cef838b184b41df13c9e694030f4f70656e5468726561642d323832610102282a0410615a57bd3d170a24ac2a461d37c8e97c0c0402a0fff8

# Send a toggle command to the device's onoff cluster at endpoint 1.
gdm issue rpi_matter_controller-1234 - matter_controller send 100 1 onoff toggle []

# Upgrade chip-tool version using a binary from the host machine.
gdm issue rpi_matter_controller-1234 - matter_controller upgrade --build_file=/path/to/chip-tool --build_id=$COMMIT_SHA

# Print commit SHA the chip-tool was built at.
gdm issue rpi_matter_controller-1234 - matter_controller version

# To see all supported functionality
gdm man rpi_matter_controller
```
22 changes: 22 additions & 0 deletions docs/device_setup/Raspberry_Pi_as_supporting_device.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,25 @@ echo "Example file" > /tmp/foo.txt
gdm issue raspberrypi-1234 - file_transfer - send_file_to_device --src=/tmp/foo.txt --dest=/tmp
gdm man raspberrypi # To see all supported functionality
```

## Troubleshooting

If `gdm detect` detection fails (couldn't recognize your Raspberry Pi), check
if your device is still pingable first:

```
ping <IP_ADDRESS>
```

If it's alive, try the following commands on your host:

```
ssh -T -oPasswordAuthentication=no -oStrictHostKeyChecking=no -oBatchMode=yes -oConnectTimeout=3 -i /gazoo/gdm/keys/gazoo_device_controllers/raspberrypi3_ssh_key pi@<IP_ADDRESS>
```

If it shows permission denied failure, you'll need to manually add the new host
key to RPi's authorized keys.

```
ssh-copy-id -i ~/gazoo/gdm/keys/gazoo_device_controllers/raspberrypi3_ssh_key.pub pi@<IP_ADDRESS>
```
2 changes: 1 addition & 1 deletion gazoo_device/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
# limitations under the License.

"""Gazoo Device Manager version."""
version = "1.72.0"
version = "1.75.0"
48 changes: 47 additions & 1 deletion gazoo_device/auxiliary_devices/raspberry_pi_matter_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@

"""Raspberry Pi Matter Controller device class."""

from typing import Optional

from gazoo_device import decorators
from gazoo_device import detect_criteria
from gazoo_device import errors
from gazoo_device import gdm_logger
from gazoo_device.auxiliary_devices import raspberry_pi
from gazoo_device.capabilities import matter_controller_chip_tool
from gazoo_device.capabilities import matter_endpoints_accessor_chip_tool
from gazoo_device.capabilities.matter_endpoints import on_off_light

logger = gdm_logger.get_logger()

Expand All @@ -42,4 +47,45 @@ def matter_controller(
device_name=self.name,
regex_shell_fn=self.shell_with_regex,
shell_fn=self.shell,
send_file_to_device=self.file_transfer.send_file_to_device)
send_file_to_device=self.file_transfer.send_file_to_device,
get_property_fn=self.get_property,
set_property_fn=self.get_manager().set_prop)

@decorators.OptionalProperty
def matter_node_id(self) -> Optional[int]:
"""Matter Node ID assigned to the currently commissioned end device."""
return self.props["optional"].get("matter_node_id")

@decorators.CapabilityDecorator(
matter_endpoints_accessor_chip_tool.MatterEndpointsAccessorChipTool)
def matter_endpoints(
self
) -> matter_endpoints_accessor_chip_tool.MatterEndpointsAccessorChipTool:
"""Matter capability to access commissioned device's endpoint instances."""
if self.matter_node_id is None:
raise errors.DeviceError(
"matter_endpoints requires a commissioned end device.")

return self.lazy_init(
matter_endpoints_accessor_chip_tool.MatterEndpointsAccessorChipTool,
device_name=self.name,
node_id_getter=lambda: self.matter_node_id,
shell_fn=self.shell,
shell_with_regex=self.shell_with_regex,
matter_controller=self.matter_controller)

# ******************** Matter endpoint aliases ******************** #

@decorators.CapabilityDecorator(on_off_light.OnOffLightEndpoint)
def on_off_light(self) -> on_off_light.OnOffLightEndpoint:
"""Matter OnOff Light endpoint instance.
Returns:
OnOff Light endpoint instance.
Raises:
DeviceError when OnOff Light endpoint is not supported on the
device.
"""
return self.matter_endpoints.get_endpoint_instance_by_class(
on_off_light.OnOffLightEndpoint)
8 changes: 4 additions & 4 deletions gazoo_device/base_classes/matter_device_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from gazoo_device import gdm_logger
from gazoo_device.base_classes import gazoo_device_base
from gazoo_device.capabilities import device_power_default
from gazoo_device.capabilities import matter_endpoints_accessor
from gazoo_device.capabilities import matter_endpoints_accessor_pw_rpc
from gazoo_device.capabilities import pwrpc_button_default
from gazoo_device.capabilities import pwrpc_common_default
from gazoo_device.capabilities.matter_endpoints import color_temperature_light
Expand Down Expand Up @@ -255,12 +255,12 @@ def pw_rpc_common(self) -> pwrpc_common_default.PwRPCCommonDefault:
rpc_timeout_s=_RPC_TIMEOUT)

@decorators.CapabilityDecorator(
matter_endpoints_accessor.MatterEndpointsAccessor)
matter_endpoints_accessor_pw_rpc.MatterEndpointsAccessorPwRpc)
def matter_endpoints(
self) -> matter_endpoints_accessor.MatterEndpointsAccessor:
self) -> matter_endpoints_accessor_pw_rpc.MatterEndpointsAccessorPwRpc:
"""Generic Matter endpoint instance."""
return self.lazy_init(
matter_endpoints_accessor.MatterEndpointsAccessor,
matter_endpoints_accessor_pw_rpc.MatterEndpointsAccessorPwRpc,
device_name=self.name,
switchboard_call=self.switchboard.call,
rpc_timeout_s=_RPC_TIMEOUT
Expand Down
12 changes: 3 additions & 9 deletions gazoo_device/capabilities/flash_build_esptool.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,12 @@

logger = gdm_logger.get_logger()

# Import path differs for esptool internally and externally.
try:
# pylint: disable=g-import-not-at-top
from esptool import esptool
import esptool
_ESPTOOL_AVAILABLE = True
except ImportError:
try:
# pylint: disable=g-import-not-at-top
import esptool
_ESPTOOL_AVAILABLE = True
except ImportError:
_ESPTOOL_AVAILABLE = False
_ESPTOOL_AVAILABLE = False

_DEFAULT_BOOT_UP_TIMEOUT_SECONDS = 30
_SWITCHBOARD_CAPABILITY = 'switchboard'
Expand Down Expand Up @@ -116,7 +110,7 @@ def __init__(
'licensing restrictions. To enable flashing for this device type, '
'install "esptool": "pip install esptool>=3.2".')

if chip_type not in esptool.SUPPORTED_CHIPS: # pytype: disable=module-attr
if chip_type not in esptool.CHIP_LIST: # pytype: disable=module-attr
raise ValueError(f'Chip {chip_type} not supported by esptool.')

super().__init__(device_name=device_name)
Expand Down
18 changes: 5 additions & 13 deletions gazoo_device/capabilities/interfaces/matter_controller_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,14 @@ def commission(self, node_id: int, setup_code: str,
"""

@abc.abstractmethod
def decommission(self, node_id: int) -> None:
"""Forgets a commissioned device with the given node id.
Args:
node_id: Assigned node id to decommission.
"""
def decommission(self) -> None:
"""Forgets a commissioned device with the given node id."""

@abc.abstractmethod
def read(self, node_id: int, endpoint_id: int, cluster: str,
attribute: str) -> Any:
def read(self, endpoint_id: int, cluster: str, attribute: str) -> Any:
"""Reads a cluster's attribute for the given node id and endpoint.
Args:
node_id: Node ID assigned to the commissioned end device.
endpoint_id: Endpoint ID within the node to read attribute from.
cluster: Name of the cluster to read the attribute value from.
attribute: Name of the cluster attribute to read.
Expand All @@ -79,25 +73,23 @@ def read(self, node_id: int, endpoint_id: int, cluster: str,
"""

@abc.abstractmethod
def write(self, node_id: int, endpoint_id: int, cluster: str, attribute: str,
def write(self, endpoint_id: int, cluster: str, attribute: str,
value: Any) -> None:
"""Writes a cluster's attribute for the given node id and endpoint.
Args:
node_id: Node ID assigned to the commissioned end device.
endpoint_id: Endpoint ID within the node to write attribute to.
cluster: Name of the cluster to write the attribute value to (e.g. onoff).
attribute: Name of the cluster attribute to write (e.g. on-time).
value: New attribute value to update the cluster with.
"""

@abc.abstractmethod
def send(self, node_id: int, endpoint_id: int, cluster: str, command: str,
def send(self, endpoint_id: int, cluster: str, command: str,
arguments: Sequence[Any]) -> None:
"""Sends a command to a device with the given node id and endpoint.
Args:
node_id: Node ID assigned to the commissioned end device.
endpoint_id: Endpoint ID within the node to read attribute from.
cluster: Name of the cluster to send the command to (e.g. onoff).
command: Name of the command to send (e.g. toggle).
Expand Down
Loading

0 comments on commit af6cd9e

Please sign in to comment.