Skip to content

Commit

Permalink
Updated Matter Python REPL (#11563)
Browse files Browse the repository at this point in the history
* Updated CHIP REPL!

This resurrects the chip-repl to be more usable and user-friendly,
especially around how pretty printing, help text/documentation are
generated.

Notably, it leverages the 'rich' module to:
    - Provide capabilities to inspect the methods/values in any given
      class/module.
    - Pretty printing of cluster objects.

* Missed a file

* Restyled
  • Loading branch information
mrjerryjohns authored and pull[bot] committed Dec 18, 2021
1 parent b775f8d commit 1727587
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 70 deletions.
4 changes: 2 additions & 2 deletions scripts/build_python.sh
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ gn --root="$CHIP_ROOT" gen "$OUTPUT_ROOT" --args="chip_detail_logging=$chip_deta
# Compiles python files
# Check pybindings was requested
if [ "$enable_pybindings" == true ]; then
ninja -v -C "$OUTPUT_ROOT" pycontroller
ninja -C "$OUTPUT_ROOT" pycontroller
else
ninja -v -C "$OUTPUT_ROOT" python
ninja -C "$OUTPUT_ROOT" python
fi

# Create a virtual environment that has access to the built python tools
Expand Down
1 change: 1 addition & 0 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ pw_python_action("python") {
{
src_dir = "."
sources = [
"ChipReplStartup.py",
"chip-device-ctrl.py",
"chip-repl.py",
"chip/ChipBleBase.py",
Expand Down
51 changes: 51 additions & 0 deletions src/controller/python/ChipReplStartup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from rich import print
from rich.pretty import pprint
from rich import pretty
from rich import inspect
from rich.console import Console
import logging
from chip import ChipDeviceCtrl
import chip.clusters as Clusters
import coloredlogs
import chip.logging
import argparse
import builtins


def ReplInit():
#
# Install the pretty printer that rich provides to replace the existing
# printer.
#
pretty.install(indent_guides=True, expand_all=True)

console = Console()

console.rule('Matter REPL')
console.print('''
[bold blue]
Welcome to the Matter Python REPL!
For help, please type [/][bold green]matterhelp()[/][bold blue]
To get more information on a particular object/class, you can pass
that into [bold green]matterhelp()[/][bold blue] as well.
''')
console.rule()

coloredlogs.install(level='DEBUG')
chip.logging.RedirectToPythonLogging()
logging.getLogger().setLevel(logging.ERROR)


def matterhelp(classOrObj=None):
if (classOrObj == None):
inspect(builtins.devCtrl, methods=True, help=True, private=False)
else:
inspect(classOrObj, methods=True, help=True, private=False)


def mattersetlog(level):
logging.getLogger().setLevel(level)
2 changes: 2 additions & 0 deletions src/controller/python/build-chip-wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ def finalize_options(self):
'ipython',
'dacite',
'rich',
'stringcase',
'pyyaml',
]

if platform.system() == 'Darwin':
Expand Down
110 changes: 42 additions & 68 deletions src/controller/python/chip-repl.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -17,81 +17,55 @@
# limitations under the License.
#

from IPython import embed
import IPython
import chip
import chip.logging
import coloredlogs
import logging
from traitlets.config import Config
from rich import print
from rich import pretty
from rich import inspect
import builtins
import argparse
import sys


def main():
# The chip imports at the top level will be visible in the ipython REPL.

coloredlogs.install(level='DEBUG')
chip.logging.RedirectToPythonLogging()

# trace/debug logging is not friendly to an interactive console. Only keep errors.
logging.getLogger().setLevel(logging.ERROR)

embed(header='''
Welcome to the CHIP python REPL utilty.
Usage examples:
######## Enable detailed logging if needed #########
import logging
logging.getLogger().setLevel(logging.DEBUG)
######## List available BLE adapters #########
import chip.ble
print(chip.ble.GetAdapters())
######## Discover chip devices #########
import chip.ble
chip.ble.DiscoverAsync(2000, lambda *x: print('Discovered: %r' % (x,)), lambda: print('Done'))
for device in chip.ble.DiscoverSync(2000):
print(device)
####### Commision a BLE device #########
import chip.ble.commissioning
device = chip.ble.commissioning.Connect(discriminator=3840, pin=20202021)
if device.needsNetworkCredentials:
device.ConnectToWifi("ssid", "password")
######## Thread provisioning ########
import chip.ble.commissioning
device = chip.ble.commissioning.Connect(discriminator=3840, pin=20202021)
# Thread data is an opaque blob, but it can be build with internal constructs
# starting from a memset(0) equivalent
from chip.internal.thread import ThreadNetworkInfo
data = ThreadNetworkInfo.parse(b'\\x00'*ThreadNetworkInfo.sizeof())
data.NetworkName = "OpenThread"
data.ExtendedPANId = b"\\xde\\xad\\x00\\xbe\\xef\\x00\\xca\\xfe"
data.MasterKey = b"\\x00\\x11\\x22\\x33\\x44\\x55\\x66\\x77\\x88\\x99\\xAA\\xBB\\xCC\\xDD\\xEE\\xFF"
data.PANId = 0xabcd
data.Channel = 15
if device.needsNetworkCredentials:
device.ConnectToThread(ThreadNetworkInfo.build(data))
######## Node discovery ########
import chip.discovery
chip.discovery.FindAddressAsync(123, 456, lambda x: print("%r", x))
print(chip.discovery.FindAddress(123, 456)
'''.strip())
parser = argparse.ArgumentParser()
parser.add_argument(
"-n", "--noautoinit", help="Disable the default auto-initialization of the controller", action="store_true")
args = parser.parse_args()

c = Config()
c.InteractiveShellApp.exec_lines = [
"from rich import print",
"from rich.pretty import pprint",
"from rich import pretty",
"from rich import inspect",
"from rich.console import Console",
"import logging",
"from chip import ChipDeviceCtrl",
"import chip.clusters as Clusters",
"import coloredlogs",
"import chip.logging",
"import argparse",
"from chip.ChipReplStartup import *",
"ReplInit()",
]

if (not(args.noautoinit)):
c.InteractiveShellApp.exec_lines.extend([
"import builtins",
"devCtrl = ChipDeviceCtrl.ChipDeviceController(controllerNodeId=12344321)",
"builtins.devCtrl = devCtrl",
"console = Console()",
"console.print('\\n\\n[blue]CHIP Device Controller has been initialized, and is available as [bold red]devCtrl')"
])

sys.argv = [sys.argv[0]]

IPython.start_ipython(config=c)


if __name__ == "__main__":
Expand Down

0 comments on commit 1727587

Please sign in to comment.