Skip to content

Commit f079614

Browse files
Merge da9945f into c45d6cc
2 parents c45d6cc + da9945f commit f079614

32 files changed

+3374
-626
lines changed

.flake8

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ignore = D107, D400, E501, W504, D204
2020
# Specify a list of mappings of files and the codes that should be ignored for the entirety of the file.
2121
per-file-ignores =
2222
tests/*:D101,D102,D104
23+
umodbus/const.py:F821
2324

2425
# Provide a comma-separated list of glob patterns to exclude from checks.
2526
exclude =
@@ -42,6 +43,7 @@ exclude =
4243
# example testing folder before going live
4344
thinking
4445
.idea
46+
.bak
4547
# custom scripts, not being part of the distribution
4648
libs_external
4749
modules

.github/workflows/test.yml

+9
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ jobs:
3333
run: |
3434
python -m pip install --upgrade pip
3535
if [ -f requirements-deploy.txt ]; then pip install -r requirements-deploy.txt; fi
36+
- name: Execute tests
37+
run: |
38+
docker build --tag micropython-test --file Dockerfile.tests .
39+
- name: Run Client/Host TCP example
40+
run: |
41+
docker compose up --build --exit-code-from micropython-host
42+
- name: Run Client/Host TCP test
43+
run: |
44+
docker compose -f docker-compose-tcp-test.yaml up --build --exit-code-from micropython-host
3645
- name: Build package
3746
run: |
3847
changelog2version \

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
.DS_Store
33
.DS_Store?
44
pymakr.conf
5-
tests/
65
config/config*.py
76
thinking/
87
*.bin

Dockerfile.client

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Build image
2+
# $ docker build -t micropython-client -f Dockerfile.client .
3+
#
4+
# Run image
5+
# $ docker run -it --rm --name micropython-client micropython-client
6+
7+
FROM micropython/unix:v1.18
8+
9+
# use "volumes" in docker-compose file to remove need of rebuilding
10+
# COPY ./ /home
11+
# COPY umodbus /root/.micropython/lib/umodbus
12+
13+
RUN micropython-dev -m upip install micropython-ulogging
14+
RUN micropython-dev -m upip install micropython-urequests
15+
16+
CMD [ "micropython-dev", "-m", "examples/tcp_client_example.py" ]

Dockerfile.host

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Build image
2+
# $ docker build -t micropython-host -f Dockerfile.host .
3+
#
4+
# Run image
5+
# $ docker run -it --rm --name micropython-host micropython-host
6+
7+
FROM micropython/unix:v1.18
8+
9+
# use "volumes" in docker-compose file to remove need of rebuilding
10+
# COPY ./ /home
11+
# COPY umodbus /root/.micropython/lib/umodbus
12+
13+
RUN micropython-dev -m upip install micropython-ulogging
14+
RUN micropython-dev -m upip install micropython-urequests
15+
16+
CMD [ "micropython-dev", "-m", "examples/tcp_host_example.py" ]

Dockerfile.test_tcp_example

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Build image
2+
# $ docker build -t micropython-tcp-example -f Dockerfile.test_tcp_example .
3+
# if a command fails, it will exit with non-zero code
4+
#
5+
# Run image, only possible if all tests passed
6+
# $ docker run -it --rm --name micropython-tcp-example micropython-tcp-example
7+
8+
FROM micropython/unix:v1.18
9+
10+
# use "volumes" in docker-compose file to remove need of rebuilding
11+
# COPY ./ /home
12+
# COPY umodbus /root/.micropython/lib/umodbus
13+
# COPY unittest.py /root/.micropython/lib/unittest.py
14+
15+
RUN micropython-dev -m upip install micropython-ulogging
16+
RUN micropython-dev -m upip install micropython-urequests

Dockerfile.tests

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Build image
2+
# $ docker build -t micropython-test -f Dockerfile.tests .
3+
# if a unittest fails, it will exit with non-zero code
4+
#
5+
# Run image, only possible if all tests passed
6+
# $ docker run -it --rm --name micropython-test micropython-test
7+
8+
FROM micropython/unix:v1.18
9+
10+
COPY ./ /home
11+
# keep examples and tests registers JSON file easily in sync
12+
COPY registers/example.json /home/tests/test-registers.json
13+
COPY umodbus /root/.micropython/lib/umodbus
14+
COPY unittest.py /root/.micropython/lib/unittest.py
15+
16+
RUN micropython-dev -m upip install micropython-ulogging
17+
RUN micropython-dev -m upip install micropython-urequests
18+
RUN micropython-dev -c "import unittest; unittest.main('tests')"
19+
20+
ENTRYPOINT ["/bin/bash"]

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ Act as client, provide Modbus data via RTU or TCP to a host device.
189189
See [Modbus TCP Client example](examples/tcp_client_example.py) and
190190
[Modbus RTU Client example](examples/rtu_client_example.py)
191191

192-
Both examples are using [example register definitions](examples/example.json)
192+
Both examples are using [example register definitions](registers/example.json)
193193

194194
Use the provided example scripts [read RTU](examples/read_registers_rtu.sh) or
195195
[read TCP](examples/read_registers_tcp.sh) to read the data from the devices.
@@ -228,6 +228,7 @@ of this library.
228228

229229
* **sfera-labs** - *Initial work* - [giampiero7][ref-sferalabs-exo-sense]
230230
* **pycom** - *Initial Modbus work* - [pycom-modbus][ref-pycom-modbus]
231+
* **pfalcon** - *Initial MicroPython unittest module* - [micropython-unittest][ref-pfalcon-unittest]:
231232

232233
<!-- Links -->
233234
[ref-sferalabs-exo-sense]: https://github.com/sfera-labs/exo-sense-py-modbus
@@ -238,3 +239,4 @@ of this library.
238239
[ref-myevse-be]: https://brainelectronics.de/
239240
[ref-myevse-tindie]: https://www.tindie.com/stores/brainelectronics/
240241
[ref-giampiero7]: https://github.com/giampiero7
242+
[ref-pfalcon-unittest]: https://github.com/pfalcon/pycopy-lib/blob/56ebf2110f3caa63a3785d439ce49b11e13c75c0/unittest/unittest.py

USAGE.md

+106-6
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,19 @@ Using and testing this `micropython-modbus` library
66

77
<!-- MarkdownTOC -->
88

9-
- [Development environment](#development-environment)
9+
- [Classic development environment](#classic-development-environment)
1010
- [TCP](#tcp)
1111
- [Read data](#read-data)
1212
- [Write data](#write-data)
13+
- [Docker development environment](#docker-development-environment)
14+
- [Pull container](#pull-container)
15+
- [Spin up container](#spin-up-container)
16+
- [Simple container](#simple-container)
17+
- [Enter MicroPython REPL](#enter-micropython-repl)
18+
- [Manually run unittests](#manually-run-unittests)
19+
- [Custom container for unittests](#custom-container-for-unittests)
20+
- [Docker compose](#docker-compose)
21+
- [Test for TCP example](#test-for-tcp-example)
1322
- [MicroPython](#micropython)
1423
- [TCP](#tcp-1)
1524
- [Client](#client)
@@ -21,7 +30,7 @@ Using and testing this `micropython-modbus` library
2130
The onwards described steps assume a successful setup as described in
2231
[SETUP.md](SETUP.md)
2332

24-
## Development environment
33+
## Classic development environment
2534

2635
This section describes the necessary steps on the computer to get ready to
2736
test and run the examples.
@@ -50,7 +59,7 @@ the [modules submodule](modules)
5059

5160
```bash
5261
python modules/read_device_info_registers.py \
53-
--file=examples/example.json \
62+
--file=registers/example.json \
5463
--connection=tcp \
5564
--address=192.168.178.69 \
5665
--port=502 \
@@ -64,14 +73,14 @@ Or use the even more convenient wrapper script for the wrapper.
6473

6574
```bash
6675
cd examples
67-
sh read_registers_tcp.sh 192.168.178.69 example.json 502
76+
sh read_registers_tcp.sh 192.168.178.69 ../registers/example.json 502
6877
```
6978

7079
#### Write data
7180

7281
```bash
7382
python modules/write_device_info_registers.py \
74-
--file=examples/set-example.json \
83+
--file=registers/set-example.json \
7584
--connection=tcp \
7685
--address=192.168.178.69 \
7786
--port=502 \
@@ -85,7 +94,98 @@ Or use the even more convenient wrapper script for the wrapper.
8594

8695
```bash
8796
cd examples
88-
sh write_registers_tcp.sh 192.168.178.69 set-example.json 502
97+
sh write_registers_tcp.sh 192.168.178.69 ../registers/set-example.json 502
98+
```
99+
100+
## Docker development environment
101+
102+
### Pull container
103+
104+
Checkout the available
105+
[MicroPython containers](https://hub.docker.com/r/micropython/unix/tags)
106+
107+
```bash
108+
docker pull micropython/unix:v1.18
109+
```
110+
111+
### Spin up container
112+
113+
#### Simple container
114+
115+
Use this command for your first tests or to run some MicroPython commands in
116+
a simple REPL
117+
118+
```bash
119+
docker run -it \
120+
--name micropython-1.18 \
121+
--network=host \
122+
--entrypoint bash \
123+
micropython/unix:v1.18
124+
```
125+
126+
#### Enter MicroPython REPL
127+
128+
Inside the container enter the REPL by running `micropython-dev`. The console
129+
should now look similar to this
130+
131+
```
132+
root@debian:/home#
133+
MicroPython v1.18 on 2022-01-17; linux version
134+
Use Ctrl-D to exit, Ctrl-E for paste mode
135+
>>>
136+
```
137+
138+
#### Manually run unittests
139+
140+
In order to manually execute only a specific set of tests use the following
141+
command inside the container
142+
143+
```bash
144+
# run all unittests defined in "tests" directory and exit with status result
145+
micropython-dev -c "import unittest; unittest.main('tests')"
146+
147+
# run all tests of "TestAbsoluteTruth" defined in tests/test_absolute_truth.py
148+
# and exit with status result
149+
micropython-dev -c "import unittest; unittest.main(name='tests.test_absolute_truth', fromlist=['TestAbsoluteTruth'])"
150+
```
151+
152+
#### Custom container for unittests
153+
154+
```bash
155+
docker build \
156+
--tag micropython-test \
157+
--file Dockerfile.tests .
158+
```
159+
160+
The unittests are executed during the building process. It will exit with a
161+
non-zero status in case of a unittest failure.
162+
163+
The return value can be collected by `echo $?` (on Linux based systems), which
164+
will be either `0` in case all tests passed, or `1` if one or multiple tests
165+
failed.
166+
167+
#### Docker compose
168+
169+
The following command uses the setup defined in the `docker-compose.yaml` file
170+
to act as two MicroPython devices communicating via TCP. The container
171+
`micropython-host` defined by `Dockerfile.host` acts as host and sets/gets
172+
data at/from the client as defined by `tcp_host_example.py`. On the other hand
173+
the container `micropython-client` defined by `Dockerfile.client` acts as
174+
client and provides data for the host as defined by `tcp_client_example.py`.
175+
The port defined in `tcp_host_example.py` and `tcp_client_example.py` has to
176+
be open and optionally exposed in the `docker-compose.yaml` file.
177+
178+
```bash
179+
docker compose up --build --exit-code-from micropython-host
180+
```
181+
182+
The option `--build` can be skipped on the second run, to avoid rebuilds of
183+
the containers. All "dynamic" data is shared via `volumes`
184+
185+
##### Test for TCP example
186+
187+
```bash
188+
docker compose -f docker-compose-tcp-test.yaml up --build --exit-code-from micropython-host
89189
```
90190

91191
## MicroPython

changelog.md

+35-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
<!-- ## [Unreleased] -->
1616

1717
## Released
18+
## [2.0.0] - 2022-12-03
19+
### Added
20+
- Perform MicroPython based unittests on every `Test` workflow run
21+
- Add usage description of docker based MicroPython unittest framework in [USAGE](USAGE.md)
22+
- Add [docker compose file](docker-compose.yaml) based in MicroPython 1.18 image
23+
- Add [TCP client Dockerfile](Dockerfile.client), [TCP host Dockerfile](Dockerfile.host), [unittest Dockerfile](Dockerfile.tests) and [TCP unittest specific Dockerfile](Dockerfile.test_tcp_example). All based on MicroPython 1.18 image
24+
- Add initial test, testing the unittest itself
25+
- Add [unittest](unittest.py) implementation based on pfalcon's [micropython-unittest](https://github.com/pfalcon/pycopy-lib/blob/56ebf2110f3caa63a3785d439ce49b11e13c75c0/unittest/unittest.py)
26+
- Docstrings available for all functions of [functions.py](umodbus/functions.py), see #27
27+
- Typing hints available for all functions of [functions.py](umodbus/functions.py), [serial.py](umodbus/serial.py) and [tcp.py](umodbus/tcp.py), see #27
28+
- Unittest for [functions.py](umodbus/functions.py), see #16
29+
- Unittest for [const.py](umodbus/const.py), see #16
30+
31+
### Changed
32+
- Use default values for all registers defined in the [example JSON](registers/example.json)
33+
- [TCP host example](examples/tcp_host_example.py) and [TCP client example](examples/tcp_client_example.py) define a static IP address and skip further WiFi setup steps in case a Docker usage is detected by a failing import of the `network` module, contributes to #16
34+
- Define all Modbus function codes as `const()` to avoid external modifications, contributes to #18
35+
- Remove dependency to `Serial` and `requests` from `umodbus.modbus`, see #18
36+
- `ModbusRTU` class is part of [serial.py](umodbus/serial.py), see #18
37+
- `ModbusTCP` class is part of [tcp.py](umodbus/tcp.py), see #18
38+
- `ModbusRTU` and `ModbusTCP` classes and related functions removed from [modbus.py](umodbus/modbus.py), see #18
39+
- Imports changed from:
40+
- `from umodbus.modbus import ModbusRTU` to `from umodbus.serial import ModbusRTU`
41+
- `from umodbus.modbus import ModbusTCP` to `from umodbus.tcp import ModbusTCP`
42+
- `read_coils` and `read_discrete_inputs` return a list with the same length as the requested quantity instead of always 8, see #12 and #25
43+
- Common functions `bytes_to_bool` and `to_short` moved to [functions.py](umodbus/functions.py)
44+
45+
### Fixed
46+
- `write_multiple_coils` function works as specified. Constructed outputs value was incorrect, see #22
47+
- `read_coils` returns list with amount of requested coils, see #12
48+
- `read_holding_registers` returns list with amount of requested registers, see #25
49+
1850
## [1.2.0] - 2022-11-13
1951
### Added
2052
- [TCP host example script](examples/tcp_host_example.py)
@@ -28,7 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2860

2961
### Changed
3062
- Add more info to [TCP client example script](examples/tcp_client_example.py)
31-
- Update [modules submodule](modules) to `1.3.0`
63+
- Update [modules submodule](https://github.com/brainelectronics/python-modules/tree/43bad716b7db27db07c94c2d279cee57d0c8c753) to `1.3.0`
3264
- Line breaks are no longer used in this changelog for enumerations
3365
- Issues are referenced as `#123` instead of `[#123][ref-issue-123]` to avoid explicit references at the bottom or some other location in the file
3466
- Scope of contents permissions in release and test release workflow is now `write` to use auto release creation
@@ -115,8 +147,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
115147
- PEP8 style issues on all files of [`lib/uModbus`](lib/uModbus)
116148

117149
<!-- Links -->
118-
[Unreleased]: https://github.com/brainelectronics/micropython-modbus/compare/1.2.0...develop
150+
[Unreleased]: https://github.com/brainelectronics/micropython-modbus/compare/2.0.0...develop
119151

152+
[2.0.0]: https://github.com/brainelectronics/micropython-modbus/tree/2.0.0
120153
[1.2.0]: https://github.com/brainelectronics/micropython-modbus/tree/1.2.0
121154
[1.1.1]: https://github.com/brainelectronics/micropython-modbus/tree/1.1.1
122155
[1.1.0]: https://github.com/brainelectronics/micropython-modbus/tree/1.1.0

0 commit comments

Comments
 (0)