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

Feature request: Custom Device Monitor Filters for projects not platforms #3924

Closed
damiendr opened this issue Apr 9, 2021 · 4 comments
Closed

Comments

@damiendr
Copy link

damiendr commented Apr 9, 2021

I find myself wanting to write a custom device monitor filter that colors the output according to the syntax of the serial protocol I use for a particular project.

Unfortunately it seems one can only write custom filters as part of a platform.

It would be nice to be able to add a "monitor" folder in a project, or directly pass the path to a Python file to the --filter option.

@ivankravets ivankravets added this to the Backlog milestone Apr 10, 2021
@ivankravets ivankravets removed this from the Backlog milestone Apr 10, 2021
@Esjayar
Copy link

Esjayar commented Jun 30, 2021

+1 for this. I wrote a filter for debugging some communications from a device I was interfacing with and alas and alack putting it in the monitor folder of my project did nothing.

So I went ahead and tweaked the device monitor loading code a bit to also load filters from projects. Probably would only take someone who knows what they are doing a few minutes, but took me 30 or so....

Here is what I changed in case anyone else wants to have this for their projects while we wait for this to (hopefully) be added.
In commands/device/command.py:
Replace this:

    if "platform" in project_options:
        with fs.cd(kwargs["project_dir"]):
            platform = PlatformFactory.new(project_options["platform"])
            device_helpers.register_platform_filters(platform, options=kwargs)

With this:

    if "platform" in project_options:
        with fs.cd(kwargs["project_dir"]):
            platform = PlatformFactory.new(project_options["platform"])
            monitor_dir = os.path.join(platform.get_dir(), "monitor")
            device_helpers.register_filters(monitor_dir, options=kwargs)

    with fs.cd(kwargs["project_dir"]):
        monitor_dir = os.path.join(kwargs["project_dir"], "monitor")
        device_helpers.register_filters(monitor_dir, options=kwargs)

In commands/device/helpers.py:
Replace this:

def register_platform_filters(platform, options=None):
    monitor_dir = os.path.join(platform.get_dir(), "monitor")
    if not os.path.isdir(monitor_dir):
        return

    for name in os.listdir(monitor_dir):
        if not name.startswith("filter_") or not name.endswith(".py"):
            continue
        path = os.path.join(monitor_dir, name)
        if not os.path.isfile(path):
            continue
        load_monitor_filter(path, options)

With this:

def register_filters(monitor_dir, options=None):
    if not os.path.isdir(monitor_dir):
        return

    for name in os.listdir(monitor_dir):
        if not name.startswith("filter_") or not name.endswith(".py"):
            continue
        path = os.path.join(monitor_dir, name)
        if not os.path.isfile(path):
            continue
        load_monitor_filter(path, options)

@ivankravets ivankravets added this to the 5.2.3 milestone Oct 25, 2021
@ivankravets
Copy link
Member

Thanks for the feature request! Please re-test with pio upgrade --dev. There is also updated docs https://docs.platformio.org/en/latest/core/userguide/device/cmd_monitor.html#filters

@WebDust21
Copy link

So this is a great feature I'm trying to leverage--but here almost 2 years after this issue was closed, I can't seem to figure out how to get it to work. Been digging all over the place for answers, only finding one (unanswered) PIO forum post in the same vein (https://community.platformio.org/t/possible-to-write-serial-monitor-custom-filters-to-process-raw-binary-data/35190)

I'm trying to write a custom project-specific monitor filter. Starting as simple as possible, I've started with https://docs.platformio.org/en/latest/core/userguide/device/cmd_monitor.html#cmd-device-monitor-custom-filters .
Copied the example code verbatim into a "demo.py" script, and put it in a folder in the immediate project directory, named "monitor". Oh, but the docs indicate that "Each filter is a Python-based file and its name should have the filter_ prefix." So the verbatim-copied Python script is located in "/monitor/filter_demo.py".

Added the following to the platformio.ini "project environment" section:

monitor_speed = 19200
monitor_encoding = filter_demo

That didn't work. I've tried "demo", "filter_demo", and "filter_demo.py" for "monitor_encoding" all with no luck. I've also tried renaming the "demo" and "Demo" names inside "filter_demo.py" with "filter_demo" but to no avail.

So maybe it wasn't looking in the right place. Based on https://docs.platformio.org/en/latest/projectconf/sections/platformio/options/directory/monitor_dir.html#projectconf-pio-monitor-dir I added what is indicated as the "default filter search path" to the head of the "platformio.ini" file:

[platformio]
monitor_dir = <Project>/monitor

Doesn't work.

Guessing based on the above page, I then tried this:

[platformio]
monitor_dir = monitor

This time it added a "_pycache_" folder inside the "monitor" directory. But the "Serial Monitor" still failed.

All I ever get from the Serial Monitor is a long error trace, ending with, "LookupError: unknown encoding: [whatever is on the 'monitor_encoding' line]"

What am I missing here?

@WebDust21
Copy link

WebDust21 commented Aug 30, 2023

Think I might have figured it out...

monitor_encoding = hexlify

works just fine--and I know that's a Python filter. Which is what threw me off.

Apparently I missed the memo about using "monitor_filters" (https://docs.platformio.org/en/latest/projectconf/sections/env/options/monitor/monitor_filters.html)

monitor_filters = filter_demo

surprisingly works. Almost anticlimactic after all the errors...

That's with the following inside of "filter_demo.py", which is located in "/monitor/filter_demo.py"

from platformio.public import DeviceMonitorFilterBase


class Demo(DeviceMonitorFilterBase):
    NAME = "filter_demo"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        print("Demo filter is loaded")

    def rx(self, text):
        return f"Received: {text}\n"

    def tx(self, text):
        print(f"Sent: {text}\n")
        return text

And I don't even need the "[platformio] monitor_dir" stuff.

Whew. I can get back to actual work now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants