├── .github
└── workflows
│ └── python-publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── bin
├── arduplot
└── arduplot.cmd
├── pyproject.toml
├── setup.cfg
└── src
└── arduplot
├── __init__.py
├── filter_plotter.py
└── plotserialdata.py
/.github/workflows/python-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will upload a Python Package using Twine when a release is created
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3 |
4 | # This workflow uses actions that are not certified by GitHub.
5 | # They are provided by a third-party and are governed by
6 | # separate terms of service, privacy policy, and support
7 | # documentation.
8 |
9 | name: Upload Python Package
10 |
11 | on:
12 | release:
13 | types: [published]
14 |
15 | permissions:
16 | contents: read
17 |
18 | jobs:
19 | deploy:
20 |
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - uses: actions/checkout@v3
25 | - name: Set up Python
26 | uses: actions/setup-python@v3
27 | with:
28 | python-version: '3.x'
29 | - name: Install dependencies
30 | run: |
31 | python -m pip install --upgrade pip
32 | pip install build
33 | - name: Build package
34 | run: python -m build
35 | - name: Publish package
36 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
37 | with:
38 | user: __token__
39 | password: ${{ secrets.PYPI_API_TOKEN }}
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .venv
2 | dist
3 | src/arduplot.egg-info
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Yoonseok Hur
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # arduplot
2 |
3 | ### No Serial Plotter for PlatformIO/VSCode ???
4 |
5 |
The following picture shows the Arduino IDE's serial plotter which plots the data coming through the serial port.
6 |
7 | 
8 |
9 |
10 | But there is no built-in equivalent tool for the PlatformIO and/or VSCode. Hence arduplot(Arduino Plot) is made to support the equivalent funcitionality.
11 | This tool can be run stand alone with the usage below. This needs to be started in the PIO Terminal Panel, specifically in the PIO bundled python venv.
12 |
13 | Usage: arduplot [OPTIONS] [LABELS]...
14 |
15 | Options:
16 | -w, --width INTEGER Plotter Width
17 | -i, --width INTEGER Plotter Y Axis Min
18 | -x, --width INTEGER Plotter Y Axis Max
19 | -e, --period INTEGER Plotter sample period (ms), default=1000"
20 | -t, --title TEXT Plotter Title
21 | -s, --socket INTEGER TCP Socket Port number
22 | -n, --stdin Standard input pipe
23 | -p, --port TEXT Serial Port, a number or a device name
24 | -b, --baud INTEGER Set baudrate, default=115200
25 | --help Show this message and exit.
26 |
27 | As an example, you can build and run https://github.com/iotlab101/pio_filter_dht22 on an esp8266 and run the following command.
28 |
29 |
30 | arduplot -p COM5 -t Thermometer -w 100 Temperature Humidity
31 |
32 | Here -t Thermometer is the title of the plot chart, -w 100 is the width of the plot, and Temperature and the Humidity are the labels of the plotting data.
33 | And you'll see see the plot like this
34 |
35 | 
36 |
37 | (And you can plot the data from a TCP connection as well instead of the serial port if you use the **-s** option. Use the **-s** option to open and wait on a socket, then feed the data to the socket. The data format should be the same as the Serial port case)
38 |
39 | ### Optional Plot Configuration
40 | There is an optional configuration file where you can set the setting for the plotting for the project. If you create a json file named **'plotcfg.json'** under the the PIO project directory, you don't have to pass the parameters every time you invoke the tool.
41 |
42 | {
43 | "label": [
44 | "temperature",
45 | "humidity"
46 | ],
47 | "title": "Thermmeter",
48 | "width": 100
49 | }
50 |
51 | This configuration would be helpful, if you want to run this tool over the TCP port via some other tool where it's not easy to pass-through the setting information.
52 | ## Installation and Prerequisite
53 | * This plotter uses the following dependancies, and they will be installed when you install this tool..
54 |
55 | matplotlib
56 | click
57 | pyserial
58 |
59 | You can install this tool with the pip as follows
60 |
61 | pip install arduplot
62 |
63 |
64 | ## Running it as part of PlatformIO monitor filter ##
65 | **1**. Install the arduplot firstpip install arduplot
66 | **2**. Configure the tool. There are three ways to configure.
67 |
68 | - configure every time you create a pio project
69 | - configure your platform wise like esp8266 or esp32
70 | - or you just configure globally by setting an environment variable.
71 |
72 |
73 | For i), you create a folder 'monitor' under your pio project folder, and copy ~/.platformio/penv/lib/python3.9/site-packages/arduplot/filter_plotter.py script to that folder.
74 | <Project>/monitor
75 |
76 | For ii), you create the ~/.platformio/platform/espressif8266/monitor folder and copy ~/.platformio/penv/lib/python3.9/site-packages/arduplot/filter_plotter.py to that folder. If you're using other platform like esp32, then create the ~/.platformio/platform/espressif32/monitor folder and copy to that folder.
77 |
78 | ~/.platformio/platform/espressif8266/monitor (or ~/.platformio/platform/espressif32/monitor for esp32)
79 |
80 |
81 | And for iii), you can just set the environment variable as below and run this without copying. For Windows, you set the environment variable as such in the Windows way.
82 | export PLATFORMIO_MONITOR_DIR=${HOME}/.platformio/penv/lib/python3.9/site-packages/arduplot/
83 |
84 |
85 | **3**. With the above steps done, run pio device monitor -f plotter
And you will get this plot.
86 |
87 | ### Windows usage with Version Core 6.1.5·Home 3.4.3
88 | In GUI go to PlatformIO sidebar
89 | -> Select New Terminal in quick access at the bottom
90 | In the Terminal window run the following
91 | -> `pip install arduplot`
92 | Close the terminal or type exit
93 |
94 | Edit the platform.ini file (with VS or your preference)
95 | add or ammend (add ,plotter if the entry line already exists) plotter to the monitor filter flag
96 | -> `monitor_filters = plotter`
97 |
98 | Happy hunting guide addition compliments of @cybertza
99 | (please note the process will stay not responding in windows until data has been recieved from the serial)
100 |
101 |
102 |
103 | ### New Features for arduplot 0.2.8 ###
104 | Thanks to Antonio(@ancebfer), arduplot has two new features. That is `-e` and `-n` option.
105 |
106 | `-e` is for the rendering time interval in milli seconds unit
107 |
108 | and
109 |
110 | The original arduplot takes the input from either a serial port or some tcp port(this is used in `pio device monitor -f plotter` command). Now
111 |
112 | `-n` introduce another input, that is the standard input. What we can do with it is to pipe some data into the arduplot.
113 |
114 | For example, here is an example python code named 'wave.py' that generates the data.
115 | ```python
116 | #!/usr/bin/env python3
117 | import math
118 | import time
119 |
120 | freq = 1 # Hz
121 | period = 0.01 # s
122 |
123 | t = 0
124 | while True:
125 | x = 2 * math.pi * freq * t
126 | y1 = math.sin(x)
127 | y2 = math.cos(x)
128 | print(y1, y2)
129 | t += period
130 | time.sleep(period)
131 | ```
132 |
133 | And we can use the arduplot to plot the graph with the fed data by
134 | ```
135 | python waves.py | arduplot -n -w 500 -e 10
136 | ```
137 | This sample is also taken from Antoino's work in the pull request.
138 | And thank you @thijstriemstra and @cybertza for your contribution as well.
139 |
--------------------------------------------------------------------------------
/bin/arduplot:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright (c)
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy
5 | # of this software and associated documentation files (the "Software"), to deal
6 | # in the Software without restriction, including without limitation the rights
7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | # copies of the Software, and to permit persons to whom the Software is
9 | # furnished to do so, subject to the following conditions:
10 | #
11 | # The above copyright notice and this permission notice shall be included in all
12 | # copies or substantial portions of the Software.
13 | #
14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | # SOFTWARE.
21 |
22 | import re
23 | import sys
24 | from arduplot.plotserialdata import main
25 | if __name__ == '__main__':
26 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
27 | sys.exit(main())
--------------------------------------------------------------------------------
/bin/arduplot.cmd:
--------------------------------------------------------------------------------
1 | @setlocal
2 | @echo off
3 | REM Copyright (c)
4 | REM
5 | REM Permission is hereby granted, free of charge, to any person obtaining a copy
6 | REM of this software and associated documentation files (the "Software"), to deal
7 | REM in the Software without restriction, including without limitation the rights
8 | REM to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | REM copies of the Software, and to permit persons to whom the Software is
10 | REM furnished to do so, subject to the following conditions:
11 | REM
12 | REM The above copyright notice and this permission notice shall be included in all
13 | REM copies or substantial portions of the Software.
14 | REM
15 | REM THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | REM IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | REM FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | REM AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | REM LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | REM OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | REM SOFTWARE.
22 | python "%~dp0\arduplot" %*
23 | @echo on
24 | @endlocal
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = [
3 | "setuptools>=42",
4 | "wheel"
5 | ]
6 | build-backend = "setuptools.build_meta"
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = arduplot
3 | version = 0.3.3
4 | author = Yoonseok Hur
5 | author_email = yoonseok@gmail.com
6 | description = This tool listens to the serial port and draws the data to matplotlib.
7 | long_description = file: README.md
8 | long_description_content_type = text/markdown
9 | url = https://github.com/yhur/arduplot
10 | project_urls =
11 | Bug Tracker = https://github.com/yhur/arduplot/issues
12 | classifiers =
13 | Programming Language :: Python :: 3
14 | License :: OSI Approved :: MIT License
15 | Operating System :: POSIX :: Linux
16 | Operating System :: Microsoft :: Windows
17 | Operating System :: MacOS
18 |
19 | [options]
20 | package_dir =
21 | = src
22 | packages = find:
23 | python_requires = >=3.6
24 | install_requires =
25 | matplotlib
26 | pyserial
27 | click
28 | scripts =
29 | bin/arduplot
30 | bin/arduplot.cmd
31 |
32 | [options.packages.find]
33 | where = src
34 |
--------------------------------------------------------------------------------
/src/arduplot/__init__.py:
--------------------------------------------------------------------------------
1 | #from serialplotter import main
2 | # Copyright (c)
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy
5 | # of this software and associated documentation files (the "Software"), to deal
6 | # in the Software without restriction, including without limitation the rights
7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | # copies of the Software, and to permit persons to whom the Software is
9 | # furnished to do so, subject to the following conditions:
10 | #
11 | # The above copyright notice and this permission notice shall be included in all
12 | # copies or substantial portions of the Software.
13 | #
14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | # SOFTWARE.
21 | from arduplot.plotserialdata import main
--------------------------------------------------------------------------------
/src/arduplot/filter_plotter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | '''
3 | Copyright (c)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | '''
23 |
24 | import subprocess
25 | import socket
26 | import os
27 | import signal
28 | import sys
29 | from platformio.commands.device import DeviceMonitorFilter
30 | from platformio.project.config import ProjectConfig
31 |
32 | PORT = 19200
33 |
34 | class SerialPlotter(DeviceMonitorFilter):
35 | NAME = "plotter"
36 |
37 | def __init__(self, *args, **kwargs):
38 | super(SerialPlotter, self).__init__(*args, **kwargs)
39 | self.buffer = ''
40 | self.arduplot = 'arduplot'
41 | self.plot = None
42 | self.plot_sock = ''
43 | self.plot = ''
44 |
45 | def __call__(self):
46 | pio_root = ProjectConfig.get_instance().get_optional_dir("core")
47 | if sys.platform == 'win32':
48 | self.arduplot = os.path.join(pio_root, 'penv', 'Scripts' , self.arduplot + '.cmd')
49 | else:
50 | self.arduplot = os.path.join(pio_root, 'penv', 'bin' , self.arduplot)
51 | print('--- serial_plotter is starting')
52 | self.plot = subprocess.Popen([self.arduplot, '-s', str(PORT)])
53 | try:
54 | self.plot_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
55 | self.plot_sock.connect(('localhost', PORT))
56 | except socket.error:
57 | pass
58 | return self
59 |
60 | def __del__(self):
61 | if self.plot:
62 | if sys.platform == 'win32':
63 | self.plot.send_signal(signal.CTRL_C_EVENT)
64 | self.plot.kill()
65 |
66 | def rx(self, text):
67 | if self.plot.poll() is None: # None means the child is running
68 | self.buffer += text
69 | if '\n' in self.buffer:
70 | try:
71 | self.plot_sock.send(bytes(self.buffer, 'utf-8'))
72 | except BrokenPipeError:
73 | try:
74 | self.plot_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
75 | self.plot_sock.connect(('localhost', PORT))
76 | except socket.error:
77 | pass
78 | self.buffer = ''
79 | else:
80 | os.kill(os.getpid(), signal.SIGINT)
81 | return text
--------------------------------------------------------------------------------
/src/arduplot/plotserialdata.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | '''
3 | Copyright (c)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | '''
23 |
24 | import os
25 | import sys
26 | import signal
27 | import json
28 | import socket
29 | import matplotlib.pyplot as plt
30 | from matplotlib import animation
31 | import serial
32 | import click
33 | from serial.serialutil import SerialException
34 | try:
35 | from platformio.project.config import ProjectConfig
36 | PIO_MODE = True
37 | except ImportError:
38 | PIO_MODE = False
39 |
40 | def sighandler(signum, frame):
41 | '''signal handler for Ctrl-C'''
42 | sys.exit(9)
43 | signal.signal(signal.SIGINT, sighandler)
44 |
45 | def value_by_key(j, key, value):
46 | '''utility function to get the plotter configuration setting'''
47 | if key in j:
48 | return j[key]
49 | return value
50 |
51 | # BEGIN MAIN FUNCTION
52 | @click.command(context_settings=dict(help_option_names=["-h", "--help"]),
53 | help="arduplot(ver:0.2.9) plots serial data from the serial port, TCP socket or standard input")
54 | @click.option("--width", "-w", type=int, help="Plotter Width")
55 | @click.option("--ymin", "-i", type=int, help="Plotter Y axis Min")
56 | @click.option("--ymax", "-x", type=int, help="Plotter Y axis Max")
57 | @click.option("--period", "-e", type=int, help="Plotter sample period (ms), default=1000")
58 | @click.option("--title", "-t", help="Plotter Title")
59 | @click.option("--stdin", "-n", is_flag=True, help="Standard input pipe")
60 | @click.option("--socket", "-s", type=int, help="TCP Socket Port number")
61 | @click.option("--port", "-p", help="Serial Port, a number or a device name")
62 | @click.option("--baud", "-b", type=int, help="Set baudrate, default=115200")
63 | @click.argument("labels", nargs=-1)
64 | def main(**kwargs):
65 | '''main function'''
66 | # Reading data function from the Serial Port
67 | def uart_in():
68 | return ser.readline().decode('utf-8')
69 |
70 | # Reading data function from the TCP socket
71 | def tcp_in():
72 | return client_socket.recv(1024).decode('utf-8')
73 |
74 | # Reading data function from the Standard Input
75 | def pipe_in():
76 | return sys.stdin.readline()
77 |
78 | # Callback function for plotting the data by animation.FuncAnimation
79 | def animate(self):
80 | ax.clear()
81 | buffer = get_input().split('\n')
82 | line = buffer[-2 if len(buffer[-1]) == 0 else -1].split()
83 | # data labelling
84 | if len(line) > len(data_label):
85 | for i in range(len(line) - len(data_label)):
86 | data_label.append(f'data{len(data_label) + 1}')
87 |
88 | # Prepare the data for plotting
89 | for idx, l in enumerate(line):
90 | try:
91 | l = float(l)
92 | except ValueError:
93 | print(f"Can't convert {l} to float. Zeroed out.")
94 | l = 0.0
95 | if len(data) <= idx:
96 | data.append([])
97 | data[idx].append(l)
98 | data[idx] = data[idx][-width:] # Truncate to graph width
99 | ax.plot(data[idx], label=data_label[idx])
100 |
101 | # plotting
102 | plt.title(title)
103 | plt.xticks(rotation=90, ha='right')
104 | plt.legend()
105 | plt.axis([0, width, ymin, ymax])
106 | plt.grid(color='gray', linestyle='dotted', linewidth=1)
107 | fig.tight_layout(pad=2.5)
108 |
109 | # main control
110 | # main variabls
111 | data = []
112 | width = 50
113 | ymin = None
114 | ymax = None
115 | period = 1000
116 | title = 'Serial Data Plot'
117 | data_label = []
118 | stdin_pipe = kwargs['stdin'] or None
119 | tcp_socket = kwargs['socket'] or None
120 |
121 | # check and get the plotter config if the config file exists
122 | try:
123 | with open('plotcfg.json', 'r', encoding='utf-8') as jfile:
124 | plot_cfg = json.load(jfile)
125 | title = value_by_key(plot_cfg, 'title', title)
126 | width = value_by_key(plot_cfg, 'width', width)
127 | ymin = value_by_key(plot_cfg, 'ymin', ymin)
128 | ymax = value_by_key(plot_cfg, 'ymax', ymax)
129 | period = value_by_key(plot_cfg, 'period', period)
130 | data_label = value_by_key(plot_cfg, 'label', data_label)
131 | except FileNotFoundError:
132 | pass
133 | title = kwargs['title'] or title
134 | width = kwargs['width'] or width
135 | ymin = kwargs['ymin'] or ymin
136 | ymax = kwargs['ymax'] or ymax
137 | period = kwargs['period'] or period
138 | data_label = list(kwargs['labels']) or data_label
139 |
140 | if stdin_pipe:
141 | get_input = pipe_in
142 | elif tcp_socket:
143 | get_input = tcp_in
144 | server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
145 | server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
146 | server_socket.bind(('localhost', tcp_socket))
147 | server_socket.listen()
148 | client_socket, addr = server_socket.accept()
149 | else:
150 | get_input = uart_in
151 | ser = serial.Serial()
152 | ser.timeout = 10
153 | ser.port = None
154 | ser.baudrate = 115200
155 | if PIO_MODE:
156 | if os.path.isfile(ProjectConfig.get_default_path()):
157 | config = ProjectConfig.get_instance() # PIO project config
158 | for s in config.sections():
159 | ser.port = config.get(s, 'monitor_port') or ser.port
160 | ser.baudrate = config.get(s, 'monitor_speed') or ser.baudrate
161 | ser.port = kwargs['port'] or ser.port
162 | ser.baudrate = kwargs['baud'] or ser.baudrate
163 | if ser.port is None:
164 | print("Please check the platformio.ini for the 'monitor_port or the -p option")
165 | sys.exit(2)
166 | else:
167 | ser.baudrate = kwargs['baud'] or ser.baudrate
168 | ser.port = kwargs['port']
169 | if not ser.port:
170 | print('\nPlease provide the serial port information\n')
171 | print('\t arduplot -p /dev/cu.usbserail-ABCDEEF or arduplot -p COM3\n')
172 | sys.exit(3)
173 | try:
174 | ser.open()
175 | if ser.is_open is True:
176 | print('\nSerial port listening:')
177 | print(f'\tport: {ser.port}, baud: {ser.baudrate}\n')
178 | except SerialException:
179 | print(f'Serial Device {ser.port} is not found')
180 | sys.exit(4)
181 |
182 | fig = plt.figure()
183 | if stdin_pipe:
184 | fig.canvas.manager.set_window_title('Standard input')
185 | elif tcp_socket:
186 | fig.canvas.manager.set_window_title('tcp://localhost:'+str(tcp_socket))
187 | else:
188 | fig.canvas.manager.set_window_title(ser.port)
189 |
190 | ax = fig.subplots()
191 | ani = animation.FuncAnimation(fig, animate, interval=period, cache_frame_data=False)
192 | plt.show()
193 | # END MAIN FUNCTION
194 |
195 | if __name__ == '__main__':
196 | main()
197 |
--------------------------------------------------------------------------------