wirely 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wirely-0.1.0/LICENSE +21 -0
- wirely-0.1.0/MANIFEST.in +11 -0
- wirely-0.1.0/PKG-INFO +94 -0
- wirely-0.1.0/README.md +62 -0
- wirely-0.1.0/doc/README.md +8 -0
- wirely-0.1.0/doc/language.md +166 -0
- wirely-0.1.0/doc/libraries.md +177 -0
- wirely-0.1.0/doc/python-style.md +12 -0
- wirely-0.1.0/examples/delay.wrl +7 -0
- wirely-0.1.0/examples/flipflop.wrl +10 -0
- wirely-0.1.0/examples/gpio.wrl +4 -0
- wirely-0.1.0/examples/knx.wrl +23 -0
- wirely-0.1.0/examples/test.wrl +86 -0
- wirely-0.1.0/pyproject.toml +40 -0
- wirely-0.1.0/setup.cfg +4 -0
- wirely-0.1.0/test/abb.py +37 -0
- wirely-0.1.0/test/abb.wrl +8 -0
- wirely-0.1.0/test/and.py +29 -0
- wirely-0.1.0/test/and.wrl +14 -0
- wirely-0.1.0/test/compiler.wrl +8 -0
- wirely-0.1.0/test/csv.py +270 -0
- wirely-0.1.0/test/csv.wrl +9 -0
- wirely-0.1.0/test/delay.py +75 -0
- wirely-0.1.0/test/delay.wrl +13 -0
- wirely-0.1.0/test/ext_prog.py +70 -0
- wirely-0.1.0/test/ext_prog.wrl +3 -0
- wirely-0.1.0/test/flipflop.py +90 -0
- wirely-0.1.0/test/flipflop.wrl +9 -0
- wirely-0.1.0/test/gpio.py +143 -0
- wirely-0.1.0/test/gpio.wrl +9 -0
- wirely-0.1.0/test/knx.py +450 -0
- wirely-0.1.0/test/knx.wrl +81 -0
- wirely-0.1.0/test/knx_time.py +74 -0
- wirely-0.1.0/test/knx_time.wrl +7 -0
- wirely-0.1.0/test/mqtt.py +345 -0
- wirely-0.1.0/test/mqtt.wrl +73 -0
- wirely-0.1.0/test/negative/duplicate_block_type_in_reopened_library.wrl +9 -0
- wirely-0.1.0/test/negative/library_inside_node_type.wrl +4 -0
- wirely-0.1.0/test/negative/singleton_input.wrl +3 -0
- wirely-0.1.0/test/negative/singleton_parameter.wrl +3 -0
- wirely-0.1.0/test/negative/unknown_abb_jra.wrl +2 -0
- wirely-0.1.0/test/negative/unknown_node_type.wrl +1 -0
- wirely-0.1.0/test/negative/unknown_parameter.wrl +1 -0
- wirely-0.1.0/test/nested_library.wrl +42 -0
- wirely-0.1.0/test/option.py +26 -0
- wirely-0.1.0/test/option.wrl +25 -0
- wirely-0.1.0/test/parser.wrl +4 -0
- wirely-0.1.0/test/simple.wrl +3 -0
- wirely-0.1.0/test/std.py +49 -0
- wirely-0.1.0/test/std.wrl +10 -0
- wirely-0.1.0/test/time.py +291 -0
- wirely-0.1.0/test/time.wrl +15 -0
- wirely-0.1.0/test/two_n.py +349 -0
- wirely-0.1.0/test/two_n.wrl +42 -0
- wirely-0.1.0/test/types.py +169 -0
- wirely-0.1.0/test/types.wrl +0 -0
- wirely-0.1.0/test/username_password.txt +2 -0
- wirely-0.1.0/tools/build-pex +36 -0
- wirely-0.1.0/tools/git_write_wd_tree.py +80 -0
- wirely-0.1.0/tools/run-tests +67 -0
- wirely-0.1.0/tools/setup-venv +31 -0
- wirely-0.1.0/tools/test-gitlab-ci +395 -0
- wirely-0.1.0/tools/wirely +27 -0
- wirely-0.1.0/wirely/__init__.py +406 -0
- wirely-0.1.0/wirely/__main__.py +45 -0
- wirely-0.1.0/wirely/ast.py +1135 -0
- wirely-0.1.0/wirely/block.py +542 -0
- wirely-0.1.0/wirely/block_type.py +342 -0
- wirely-0.1.0/wirely/blocks.lark +126 -0
- wirely-0.1.0/wirely/compiler.py +125 -0
- wirely-0.1.0/wirely/engine.py +418 -0
- wirely-0.1.0/wirely/enum.py +15 -0
- wirely-0.1.0/wirely/example.py +36 -0
- wirely-0.1.0/wirely/graphviz.py +107 -0
- wirely-0.1.0/wirely/knx/__init__.py +0 -0
- wirely-0.1.0/wirely/knx/connection_adapter.py +90 -0
- wirely-0.1.0/wirely/knx/connection_config.py +152 -0
- wirely-0.1.0/wirely/lib/abb_jra.wrl +64 -0
- wirely-0.1.0/wirely/lib/csv.wrl +32 -0
- wirely-0.1.0/wirely/lib/ext_prog.wrl +12 -0
- wirely-0.1.0/wirely/lib/gpio.wrl +23 -0
- wirely-0.1.0/wirely/lib/knx.wrl +80 -0
- wirely-0.1.0/wirely/lib/memory.wrl +45 -0
- wirely-0.1.0/wirely/lib/mqtt.wrl +66 -0
- wirely-0.1.0/wirely/lib/std.wrl +134 -0
- wirely-0.1.0/wirely/lib/time.wrl +93 -0
- wirely-0.1.0/wirely/lib/two_n.wrl +111 -0
- wirely-0.1.0/wirely/misc/__init__.py +0 -0
- wirely-0.1.0/wirely/misc/service.py +48 -0
- wirely-0.1.0/wirely/native/__init__.py +74 -0
- wirely-0.1.0/wirely/native/abb_jra.py +66 -0
- wirely-0.1.0/wirely/native/csv.py +194 -0
- wirely-0.1.0/wirely/native/ext_prog.py +77 -0
- wirely-0.1.0/wirely/native/gpio.py +125 -0
- wirely-0.1.0/wirely/native/knx.py +455 -0
- wirely-0.1.0/wirely/native/memory.py +113 -0
- wirely-0.1.0/wirely/native/mqtt.py +605 -0
- wirely-0.1.0/wirely/native/std.py +334 -0
- wirely-0.1.0/wirely/native/test_library.py +14 -0
- wirely-0.1.0/wirely/native/time.py +359 -0
- wirely-0.1.0/wirely/native/two_n.py +632 -0
- wirely-0.1.0/wirely/node.py +125 -0
- wirely-0.1.0/wirely/parser.py +175 -0
- wirely-0.1.0/wirely/program.py +155 -0
- wirely-0.1.0/wirely/run.py +143 -0
- wirely-0.1.0/wirely/service.py +65 -0
- wirely-0.1.0/wirely/test.py +569 -0
- wirely-0.1.0/wirely/time.py +172 -0
- wirely-0.1.0/wirely/two_n/__init__.py +0 -0
- wirely-0.1.0/wirely/two_n/cert.py +126 -0
- wirely-0.1.0/wirely/two_n/client.py +402 -0
- wirely-0.1.0/wirely/two_n/fake_server.py +415 -0
- wirely-0.1.0/wirely/two_n/grab_images.py +146 -0
- wirely-0.1.0/wirely/types.py +522 -0
- wirely-0.1.0/wirely/util.py +111 -0
- wirely-0.1.0/wirely/value.py +163 -0
- wirely-0.1.0/wirely.egg-info/PKG-INFO +94 -0
- wirely-0.1.0/wirely.egg-info/SOURCES.txt +120 -0
- wirely-0.1.0/wirely.egg-info/dependency_links.txt +1 -0
- wirely-0.1.0/wirely.egg-info/entry_points.txt +2 -0
- wirely-0.1.0/wirely.egg-info/requires.txt +30 -0
- wirely-0.1.0/wirely.egg-info/top_level.txt +1 -0
wirely-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steffen Kieß
|
|
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.
|
wirely-0.1.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
recursive-include doc *.md
|
|
2
|
+
recursive-include examples *.wrl
|
|
3
|
+
recursive-include test *.py *.wrl
|
|
4
|
+
include test/username_password.txt
|
|
5
|
+
include tools/build-pex
|
|
6
|
+
include tools/git_write_wd_tree.py
|
|
7
|
+
include tools/run-tests
|
|
8
|
+
include tools/setup-venv
|
|
9
|
+
include tools/test-gitlab-ci
|
|
10
|
+
include tools/wirely
|
|
11
|
+
global-exclude *~ *.py[cod]
|
wirely-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wirely
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Node-based language and runtime for low-level home automation
|
|
5
|
+
Author: Steffen Kieß
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Dist: lark
|
|
11
|
+
Requires-Dist: sdnotify
|
|
12
|
+
Provides-Extra: knx
|
|
13
|
+
Requires-Dist: xknx<4,>=3.0; extra == "knx"
|
|
14
|
+
Provides-Extra: mqtt
|
|
15
|
+
Requires-Dist: aiomqtt<3,>=2.3; extra == "mqtt"
|
|
16
|
+
Provides-Extra: two-n
|
|
17
|
+
Requires-Dist: aiohttp<4,>=3.12; extra == "two-n"
|
|
18
|
+
Requires-Dist: cryptography; extra == "two-n"
|
|
19
|
+
Provides-Extra: graphviz
|
|
20
|
+
Requires-Dist: graphviz; extra == "graphviz"
|
|
21
|
+
Provides-Extra: gpio
|
|
22
|
+
Requires-Dist: gpiod<3,>=2.1; extra == "gpio"
|
|
23
|
+
Provides-Extra: all
|
|
24
|
+
Requires-Dist: wirely[gpio,graphviz,knx,mqtt,two-n]; extra == "all"
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: pyOpenSSL; extra == "test"
|
|
27
|
+
Provides-Extra: pex
|
|
28
|
+
Requires-Dist: pex; extra == "pex"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: wirely[pex,test]; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
Wirely
|
|
34
|
+
======
|
|
35
|
+
|
|
36
|
+
Wirely is a node-based language and runtime for low-level home automation.
|
|
37
|
+
It connects signals from KNX group addresses, MQTT topics, and other device
|
|
38
|
+
interfaces through nodes that process values and apply logic. For example,
|
|
39
|
+
it can listen for boolean values on two KNX group addresses and publish
|
|
40
|
+
`first_value AND NOT second_value` to a third. Wirely works directly with
|
|
41
|
+
these signals; it does not model higher-level concepts such as rooms,
|
|
42
|
+
as Home Assistant does.
|
|
43
|
+
|
|
44
|
+
See the [language documentation](doc/language.md) for how to write Wirely
|
|
45
|
+
programs.
|
|
46
|
+
|
|
47
|
+
Installation
|
|
48
|
+
------------
|
|
49
|
+
|
|
50
|
+
Wirely requires Python 3.11 or newer. Install the core package with:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
python3 -m pip install wirely
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The core install includes the compiler and command-line interface. The
|
|
57
|
+
installed `wirely` command and `python3 -m wirely` provide the same
|
|
58
|
+
subcommands. For example:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
wirely compile program.wrl
|
|
62
|
+
python3 -m wirely compile program.wrl
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Install optional integrations as needed:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
python3 -m pip install 'wirely[knx]' # KNX
|
|
69
|
+
python3 -m pip install 'wirely[mqtt]' # MQTT
|
|
70
|
+
python3 -m pip install 'wirely[two-n]' # 2N devices
|
|
71
|
+
python3 -m pip install 'wirely[graphviz]' # show-graph
|
|
72
|
+
python3 -m pip install 'wirely[gpio]' # GPIO
|
|
73
|
+
python3 -m pip install 'wirely[all]' # all optional integrations
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The `test` extra adds dependencies used only by the test suite. Install
|
|
77
|
+
`wirely[all,test]` to include both integrations and test dependencies.
|
|
78
|
+
|
|
79
|
+
Development checkout
|
|
80
|
+
--------------------
|
|
81
|
+
|
|
82
|
+
Create a virtual environment with all dependencies, then use the
|
|
83
|
+
checkout launchers:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
tools/setup-venv
|
|
87
|
+
tools/wirely compile test/simple.wrl
|
|
88
|
+
tools/run-tests
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The launchers use `venv/bin/python` when available. Otherwise, they warn and
|
|
92
|
+
use the current Python interpreter. `tools/wirely` accepts the same arguments
|
|
93
|
+
as `wirely` and runs the source in this checkout from any working directory.
|
|
94
|
+
The test suite also requires `knxd` and `mosquitto`.
|
wirely-0.1.0/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Wirely
|
|
2
|
+
======
|
|
3
|
+
|
|
4
|
+
Wirely is a node-based language and runtime for low-level home automation.
|
|
5
|
+
It connects signals from KNX group addresses, MQTT topics, and other device
|
|
6
|
+
interfaces through nodes that process values and apply logic. For example,
|
|
7
|
+
it can listen for boolean values on two KNX group addresses and publish
|
|
8
|
+
`first_value AND NOT second_value` to a third. Wirely works directly with
|
|
9
|
+
these signals; it does not model higher-level concepts such as rooms,
|
|
10
|
+
as Home Assistant does.
|
|
11
|
+
|
|
12
|
+
See the [language documentation](doc/language.md) for how to write Wirely
|
|
13
|
+
programs.
|
|
14
|
+
|
|
15
|
+
Installation
|
|
16
|
+
------------
|
|
17
|
+
|
|
18
|
+
Wirely requires Python 3.11 or newer. Install the core package with:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
python3 -m pip install wirely
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The core install includes the compiler and command-line interface. The
|
|
25
|
+
installed `wirely` command and `python3 -m wirely` provide the same
|
|
26
|
+
subcommands. For example:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
wirely compile program.wrl
|
|
30
|
+
python3 -m wirely compile program.wrl
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Install optional integrations as needed:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
python3 -m pip install 'wirely[knx]' # KNX
|
|
37
|
+
python3 -m pip install 'wirely[mqtt]' # MQTT
|
|
38
|
+
python3 -m pip install 'wirely[two-n]' # 2N devices
|
|
39
|
+
python3 -m pip install 'wirely[graphviz]' # show-graph
|
|
40
|
+
python3 -m pip install 'wirely[gpio]' # GPIO
|
|
41
|
+
python3 -m pip install 'wirely[all]' # all optional integrations
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The `test` extra adds dependencies used only by the test suite. Install
|
|
45
|
+
`wirely[all,test]` to include both integrations and test dependencies.
|
|
46
|
+
|
|
47
|
+
Development checkout
|
|
48
|
+
--------------------
|
|
49
|
+
|
|
50
|
+
Create a virtual environment with all dependencies, then use the
|
|
51
|
+
checkout launchers:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
tools/setup-venv
|
|
55
|
+
tools/wirely compile test/simple.wrl
|
|
56
|
+
tools/run-tests
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The launchers use `venv/bin/python` when available. Otherwise, they warn and
|
|
60
|
+
use the current Python interpreter. `tools/wirely` accepts the same arguments
|
|
61
|
+
as `wirely` and runs the source in this checkout from any working directory.
|
|
62
|
+
The test suite also requires `knxd` and `mosquitto`.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Wirely documentation
|
|
2
|
+
|
|
3
|
+
Wirely programs are graphs of typed nodes written in `.wrl` files. Start with
|
|
4
|
+
the [language guide](language.md) to learn how to declare nodes and connect
|
|
5
|
+
them. Then use the [library reference](libraries.md) to find the nodes supplied
|
|
6
|
+
with Wirely.
|
|
7
|
+
|
|
8
|
+
For Python contributions, follow the [Python style guide](python-style.md).
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# The Wirely language
|
|
2
|
+
|
|
3
|
+
Wirely is a declarative language for connecting typed nodes. A `.wrl` file
|
|
4
|
+
instantiates node types and connects their outputs to inputs. A node can
|
|
5
|
+
compute a value, emit an event, keep state, or interact with an external
|
|
6
|
+
service. Several `.wrl` files passed to the compiler form one program.
|
|
7
|
+
|
|
8
|
+
## A first program
|
|
9
|
+
|
|
10
|
+
```wrl
|
|
11
|
+
node source : Std.Constant(Type = boolean, Value = true);
|
|
12
|
+
node printer : Std.DebugPrinter(type = boolean);
|
|
13
|
+
connect source -> printer;
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`source` has an implicit `value boolean` output, and `printer` has an implicit
|
|
17
|
+
`value boolean` input. The connection feeds the output to the input. Save this
|
|
18
|
+
as `hello.wrl` and check it from the repository root with:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
python3 -m wirely compile hello.wrl
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`compile` builds the graph and checks its connections. To start the service,
|
|
25
|
+
use `python3 -m wirely run-service hello.wrl`. Runtime service dependencies
|
|
26
|
+
are described in [the library reference](libraries.md).
|
|
27
|
+
|
|
28
|
+
## Declarations and names
|
|
29
|
+
|
|
30
|
+
Declarations may appear at the top level or inside a node type. Node
|
|
31
|
+
instantiation uses `node name : Type;` or named parameters in parentheses:
|
|
32
|
+
|
|
33
|
+
```wrl
|
|
34
|
+
node source : Std.Constant(Type = boolean, Value = true);
|
|
35
|
+
node sink : Std.DebugPrinter(type = boolean);
|
|
36
|
+
connect source -> sink;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The type name may be a local name or a namespace-qualified name such as
|
|
40
|
+
`Std.Constant`. A program may also declare its own types:
|
|
41
|
+
|
|
42
|
+
```wrl
|
|
43
|
+
node type Forward {
|
|
44
|
+
implicit input : value boolean;
|
|
45
|
+
implicit output : value boolean;
|
|
46
|
+
native procedure run depends on implicit input produces implicit output;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This illustrates a type declaration, but its `native procedure` needs a
|
|
51
|
+
matching Python implementation before the type can be instantiated. To make
|
|
52
|
+
a composite type entirely in `.wrl`, connect its external input to child
|
|
53
|
+
nodes:
|
|
54
|
+
|
|
55
|
+
```wrl
|
|
56
|
+
node type PrintBoolean {
|
|
57
|
+
implicit input : value boolean;
|
|
58
|
+
node printer : Std.DebugPrinter(type = boolean);
|
|
59
|
+
connect implicit input -> printer;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
node source : Std.Constant(Type = boolean, Value = true);
|
|
63
|
+
node sink : PrintBoolean;
|
|
64
|
+
connect source -> sink;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
A `namespace Name { ... }` groups node types under `Name.Type`. Namespaces can
|
|
68
|
+
contain other namespaces, and a dotted declaration names the same path:
|
|
69
|
+
|
|
70
|
+
```wrl
|
|
71
|
+
namespace ABB.JRA { node type Status { } }
|
|
72
|
+
// Equivalent to: namespace ABB { namespace JRA { node type Status { } } }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Both forms define `ABB.JRA.Status`. Repeated declarations of the same namespace
|
|
76
|
+
path add their contents to one namespace; node type names within it must remain
|
|
77
|
+
unique. Namespaces contain node types or other namespaces, not instances.
|
|
78
|
+
A `singleton node type` shares one instance across its uses and cannot declare
|
|
79
|
+
parameters. `native node type` indicates that the implementation also owns
|
|
80
|
+
Python state or resources. Both forms require native support when instantiated.
|
|
81
|
+
|
|
82
|
+
Identifiers are case-sensitive. A keyword can be used as an identifier with
|
|
83
|
+
the `r#` prefix, for example `node r#node : Std.And;`. Declarations end with
|
|
84
|
+
`;`, except type and namespace bodies, which use braces. `//` starts a line
|
|
85
|
+
comment, and `/* ... */` block comments may be nested.
|
|
86
|
+
|
|
87
|
+
## Parameters, types, and literals
|
|
88
|
+
|
|
89
|
+
A node type declares parameters with `parameter Name : Type;`. A parameter
|
|
90
|
+
may have a default (`= value`) or be marked `optional`. Instantiation passes
|
|
91
|
+
named arguments, for example `Time.TriggerAt(Time = "08:00")`. Type parameters
|
|
92
|
+
use `ValueType`; a later parameter or connector can refer to one:
|
|
93
|
+
|
|
94
|
+
```wrl
|
|
95
|
+
node type Example {
|
|
96
|
+
parameter Type : ValueType;
|
|
97
|
+
parameter Initial : Type;
|
|
98
|
+
implicit output : value Type;
|
|
99
|
+
node constant : Std.Constant(Type = Type, Value = Initial);
|
|
100
|
+
connect constant -> implicit output;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Built-in types are `unit`, `boolean`, signed `int8`/`int16`/`int32`/`int64`,
|
|
105
|
+
unsigned `uint8`/`uint16`/`uint32`/`uint64`, `String`, `Duration`,
|
|
106
|
+
`TimeOfDay`, `MonotonicTime`, and `ThermostatSystemMode`. `ValueType` is used
|
|
107
|
+
for type parameters. `Option[T]` and `List[T]` construct types from `T`.
|
|
108
|
+
|
|
109
|
+
Use `true` and `false` for booleans, non-negative decimal or `0x`/`0o`
|
|
110
|
+
integers for integer parameters, quoted strings for `String`, and `[a, b]`
|
|
111
|
+
for list values. Raw strings (`r"..."` and `r#"..."#`) are also accepted.
|
|
112
|
+
Durations and times of day are passed as strings, for example `"PT1S"` and
|
|
113
|
+
`"08:00"`. `None` is the available `Option[T]` literal; use library nodes
|
|
114
|
+
such as `Std.OptionSome` to create an optional value at runtime.
|
|
115
|
+
`MonotonicTime.Invalid` is the available monotonic-time constant. The
|
|
116
|
+
compile-time function `TimeOfDay_AddWrap(time, offset)` adds an `"HH:MM"`
|
|
117
|
+
offset and wraps at midnight.
|
|
118
|
+
|
|
119
|
+
Expressions have limited support: literals, parameter references, lists,
|
|
120
|
+
generic types, and the named time function above. In particular, unary
|
|
121
|
+
minus and general arithmetic expressions are not currently implemented.
|
|
122
|
+
|
|
123
|
+
## Connectors and connections
|
|
124
|
+
|
|
125
|
+
An `input` or `output` declares a named connector. `implicit input` and
|
|
126
|
+
`implicit output` declare the connectors used when a connection names just
|
|
127
|
+
the node. For example:
|
|
128
|
+
|
|
129
|
+
```wrl
|
|
130
|
+
node bus : KNX.Connection(UnixPath = "/run/knxnet");
|
|
131
|
+
node receiver : KNX.ValueReceiver(Type = boolean,
|
|
132
|
+
GroupAddress = "0/4/5");
|
|
133
|
+
connect bus -> receiver.Bus;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The first connection uses `bus`'s implicit output and the named `Bus` input.
|
|
137
|
+
For a named output, write `node_name.OutputName`. Inside a type body,
|
|
138
|
+
`implicit input` and `implicit output` may also be connection endpoints.
|
|
139
|
+
|
|
140
|
+
Data connectors have a kind and a type: `value boolean` carries the current
|
|
141
|
+
value, while `event boolean` carries an occurrence with a boolean payload.
|
|
142
|
+
An event may be absent in a step. Source and target must have the same kind
|
|
143
|
+
and type; Wirely does not automatically convert them. Ordinary inputs accept
|
|
144
|
+
one source. A `list value T` or `list event T` input accepts several sources;
|
|
145
|
+
`connect a, b -> target;` connects both. `Std.And` is an example of a list
|
|
146
|
+
input. Libraries also define resource connectors `knx_bus`, `mqtt_server`,
|
|
147
|
+
and `two_n_device`, which connect a service node to its clients.
|
|
148
|
+
|
|
149
|
+
## State and execution
|
|
150
|
+
|
|
151
|
+
Inside a node type, `state name : Type = value;` declares a persistent value
|
|
152
|
+
with an initial value. `temporary name : Type;` holds a value calculated
|
|
153
|
+
within a step. Native procedures declare which inputs or temporaries they
|
|
154
|
+
`depend on` and which connectors or variables they `produce`. The engine
|
|
155
|
+
orders procedures from these dependencies and rejects dependency cycles.
|
|
156
|
+
|
|
157
|
+
Procedures run in three stages: `stage input` reads external sources, the
|
|
158
|
+
default stage calculates values and updates state, and `stage output` sends
|
|
159
|
+
results to external systems. State updates become visible on the next step.
|
|
160
|
+
`Std.Delay` demonstrates this: it outputs the previous value and stores the
|
|
161
|
+
current input for the following step.
|
|
162
|
+
|
|
163
|
+
The `.wrl` declaration specifies a native procedure's interface; its code
|
|
164
|
+
lives in Python under `wirely/native/`. Node types can combine child nodes
|
|
165
|
+
and connections in `.wrl`, as `KNX.ValueProvider` does. See the
|
|
166
|
+
[library reference](libraries.md) for available nodes and their connectors.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Library reference
|
|
2
|
+
|
|
3
|
+
The compiler loads all ten libraries below by default. Instantiate a node
|
|
4
|
+
as `node name : Library.Type(Parameter = value);`. Names and parameter
|
|
5
|
+
capitalization matter. In the signatures below, `in` and `out` mean implicit
|
|
6
|
+
connectors; named connectors are written explicitly. `value T` carries a
|
|
7
|
+
current value, and `event T` carries an occurrence with a payload. A dash
|
|
8
|
+
means no connector of that kind.
|
|
9
|
+
|
|
10
|
+
See the [language guide](language.md) for syntax and connection rules. The
|
|
11
|
+
declarations in [`wirely/lib/`](../wirely/lib/) are the source for exact
|
|
12
|
+
signatures; behavior comes from [`wirely/native/`](../wirely/native/).
|
|
13
|
+
|
|
14
|
+
## Std
|
|
15
|
+
|
|
16
|
+
General data flow, optional values, edge detection, and debug nodes.
|
|
17
|
+
|
|
18
|
+
| Node type | Parameters | Connectors and behavior |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| `Constant` | `Type: ValueType`, `Value: Type` | Out: `value Type`. Produces the supplied value. |
|
|
21
|
+
| `And` | None | In: `list value boolean`; out: `value boolean`. True when every connected input is true, including an empty list. |
|
|
22
|
+
| `Delay` | `type: ValueType`, `initialValue: type` | In/out: `value type`. Outputs the previous step's input, initially `initialValue`. |
|
|
23
|
+
| `TwoStageValueForward` | `type: ValueType` | In/out: `value type`. Forwards through two native procedures. |
|
|
24
|
+
| `DebugPrinter` | `type: ValueType` | In: `value type`. Prints changes in the output stage. |
|
|
25
|
+
| `DebugEventPrinter` | `type: ValueType` | In: `event type`. Prints events in the output stage. |
|
|
26
|
+
| `DebugInput` | `type: ValueType` | Out: `value type`. Debug-controlled value source. |
|
|
27
|
+
| `DebugEventSource` | `type: ValueType` | Out: `event type`. Debug-controlled event source. |
|
|
28
|
+
| `OptionNone` | `InnerType: ValueType` | Out: `value Option[InnerType]`. Produces `None`. |
|
|
29
|
+
| `OptionSome` | `InnerType: ValueType` | In: `value InnerType`; out: `value Option[InnerType]`. Wraps the input. |
|
|
30
|
+
| `OptionUnwrapOrDefault` | `InnerType: ValueType`, `Default: InnerType` | In: `value Option[InnerType]`; out: `value InnerType`. Uses `Default` for `None`. |
|
|
31
|
+
| `OptionIsSome` | `InnerType: ValueType` | In: `value Option[InnerType]`; out: `value boolean`. True when a value is present. |
|
|
32
|
+
| `OptionCreate` | `InnerType: ValueType` | Named in: `HasValue: value boolean`, `Value: value InnerType`; out: `value Option[InnerType]`. Wraps `Value` when `HasValue` is true; otherwise produces `None`. |
|
|
33
|
+
| `DetectEdge` | `EdgeType: String` | In: `value boolean`; out: `event boolean`. Only `"Falling"` works; `"Rising"` and `"Both"` raise an error when run. |
|
|
34
|
+
|
|
35
|
+
The debug sources are intended for testing and interactive control. Their
|
|
36
|
+
input is supplied through the engine's debug interface, not a `.wrl`
|
|
37
|
+
connection. `TwoStageValueForward` is primarily a demonstration of procedure
|
|
38
|
+
dependencies.
|
|
39
|
+
|
|
40
|
+
## Time
|
|
41
|
+
|
|
42
|
+
Time-based values and triggers. `TimeOfDay` parameters use strings such as
|
|
43
|
+
`"08:00"`; `Duration` parameters use strings such as `"PT1S"`.
|
|
44
|
+
|
|
45
|
+
| Node type | Parameters | Connectors and behavior |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| `MonotonicTimeReached` | None | In: `value MonotonicTime`; out: `value Option[boolean]`. True once the time is reached, false before it, or `None` if the times cannot be compared. |
|
|
48
|
+
| `DelayChange` | `Type: ValueType`, `Time: Duration` | In/out: `value Type`. Changes the output only after the input has remained stable for `Time`. |
|
|
49
|
+
| `TimeOfDayMinute` | None | Out: `value TimeOfDay`. Shared singleton that updates at minute boundaries; normally used through other Time nodes. |
|
|
50
|
+
| `IsBetween` | `start: TimeOfDay`, `end: TimeOfDay` | Out: `value boolean`. Tests the interval from `start` (inclusive) to `end` (exclusive), including intervals that cross midnight. |
|
|
51
|
+
| `TriggerAt` | `Time: TimeOfDay`, `Type: ValueType = unit`, optional `Value: Type` | Out: `event Type`. Emits around the requested time, with logic to avoid duplicate daily events during clock changes. Supply `Value` when `Type` is not `unit`. |
|
|
52
|
+
|
|
53
|
+
## KNX
|
|
54
|
+
|
|
55
|
+
KNX nodes use a `KNX.Connection` node and a named `Bus: knx_bus` input.
|
|
56
|
+
`GroupAddress` is a KNX group address string such as `"0/4/5"`.
|
|
57
|
+
|
|
58
|
+
| Node type | Parameters | Connectors and behavior |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| `Connection` | Optional `Host: String`, `Protocol: String`, `Port: uint16`, `UnixPath: String`, `SSHTarget: String`, `IndividualAddress: String` | Out: `knx_bus`. Opens a KNX connection. |
|
|
61
|
+
| `ValueReceiver` | `Type: ValueType`, `GroupAddress: String` | Named in: `Bus`; out: `value Option[Type]`. Reads the latest value, with `None` before one is available. |
|
|
62
|
+
| `ValueOptionProvider` | `Type: ValueType`, `GroupAddress: String` | Named in: `Bus`; in: `value Option[Type]`. Exposes an optional value on the bus. |
|
|
63
|
+
| `ValueProvider` | `Type: ValueType`, `GroupAddress: String` | Named in: `Bus`; in: `value Type`. Wraps the value with `Std.OptionSome` and uses `ValueOptionProvider`. |
|
|
64
|
+
| `EventReceiver` | `Type: ValueType`, `GroupAddress: String` | Named in: `Bus`; out: `event Type`. Emits received KNX events. |
|
|
65
|
+
| `EventEmitter` | `Type: ValueType`, `GroupAddress: String` | Named in: `Bus`; in: `event Type`. Sends KNX events. |
|
|
66
|
+
|
|
67
|
+
The current native value receiver and provider support `boolean` and
|
|
68
|
+
`uint16`. Other declared `Type` values may fail when those nodes are
|
|
69
|
+
instantiated. Event support depends on the KNX value type handled by the
|
|
70
|
+
native implementation. KNX use requires the `xknx` package and a reachable
|
|
71
|
+
KNX service.
|
|
72
|
+
|
|
73
|
+
Choose one connection mode:
|
|
74
|
+
|
|
75
|
+
- `Host` with `Protocol = "TCP"` or `"UDP"` opens a direct tunnel. `Port`
|
|
76
|
+
defaults to `3671`.
|
|
77
|
+
- `Protocol = "Unix"` opens a local Unix socket. `UnixPath` defaults to
|
|
78
|
+
`/run/knxnet`; supplying `UnixPath` implies `Protocol = "Unix"`.
|
|
79
|
+
- `SSHTarget` opens a Unix socket on a remote host over SSH. It requires
|
|
80
|
+
`Protocol = "Unix"` unless `UnixPath` is also supplied.
|
|
81
|
+
- `Protocol = "Auto"` uses automatic discovery.
|
|
82
|
+
|
|
83
|
+
`IndividualAddress` is supported for TCP and Unix socket connections. An
|
|
84
|
+
empty connection, an SSH target without a protocol or Unix path, and
|
|
85
|
+
parameters from conflicting modes are errors. For example,
|
|
86
|
+
`KNX.Connection(UnixPath = "/run/knxnet")` uses a local socket.
|
|
87
|
+
|
|
88
|
+
## ABB.JRA
|
|
89
|
+
|
|
90
|
+
These nodes decode a 16-bit ABB JRA status word into named boolean outputs.
|
|
91
|
+
`InterpretStatusInformation` takes `value uint16` and produces `value
|
|
92
|
+
boolean` outputs. `InterpretStatusInformationOption` takes `value
|
|
93
|
+
Option[uint16]` and produces `value Option[boolean]` outputs; a missing input
|
|
94
|
+
remains missing in every output. Neither node has parameters.
|
|
95
|
+
|
|
96
|
+
Both expose the same named outputs: `ManualOperation`, `BlockActive`,
|
|
97
|
+
`ForcedOperation`, `FrostAlarm`, `RainAlarm`, `WindAlarm`,
|
|
98
|
+
`AutomaticSunProtection`, `AutomaticHeatingCooling`, `DriveError`,
|
|
99
|
+
`DriveInMotion`, `DriveDown`, `DriveUp`, and `SendReceiveDelayActive`.
|
|
100
|
+
|
|
101
|
+
## MQTT
|
|
102
|
+
|
|
103
|
+
MQTT nodes use a `MQTT.Server` and a named `Server: mqtt_server` input.
|
|
104
|
+
`Topic` is a topic string. `Format` and `Template`, where offered, are
|
|
105
|
+
optional strings used by the native JSON encoder. A template embeds the
|
|
106
|
+
encoded value at one `%s` placeholder; `%%` represents a literal percent
|
|
107
|
+
sign. The `URI` accepts `mqtt://host`, `mqtts://host`, or `mqtt+unix:///path`.
|
|
108
|
+
|
|
109
|
+
| Node type | Parameters | Connectors and behavior |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `Server` | `URI: String` | Out: `mqtt_server`. Connects to a broker. |
|
|
112
|
+
| `ValueOptionProvider` | `Type: ValueType`, `Topic: String`, optional `Format: String`, `Template: String` | Named in: `Server`; in: `value Option[Type]`. Publishes JSON; `None` publishes an empty payload. |
|
|
113
|
+
| `ValueProvider` | Same as `ValueOptionProvider` | Named in: `Server`; in: `value Type`. Wraps the value and uses `ValueOptionProvider`. |
|
|
114
|
+
| `EventEmitter` | `Type: ValueType`, `Topic: String`, optional `Format: String`, `Template: String` | Named in: `Server`; in: `event Type`. Publishes each event as JSON. |
|
|
115
|
+
| `EventReceiver` | `Type: ValueType`, `Topic: String`, optional `Format: String` | Named in: `Server`; out: `event Type`. Emits decoded messages received on the topic. |
|
|
116
|
+
|
|
117
|
+
Only types supported by the native JSON encoder/decoder can be used. MQTT
|
|
118
|
+
requires the `aiomqtt` package and a reachable broker.
|
|
119
|
+
|
|
120
|
+
## CSV
|
|
121
|
+
|
|
122
|
+
`CSV.ValueWriter` takes `Type: ValueType` and `Filename: String`. It appends
|
|
123
|
+
rows from an implicit `value Type` input, recording the timestamp, old value,
|
|
124
|
+
and new value. An empty field marks an unavailable value at startup or
|
|
125
|
+
shutdown. It writes on changes and repeats a current value hourly. `Type`
|
|
126
|
+
must support CSV conversion, such as `boolean`, an integer type, or an
|
|
127
|
+
`Option` of one. The file is opened for append when the service starts.
|
|
128
|
+
|
|
129
|
+
## TwoN
|
|
130
|
+
|
|
131
|
+
TwoN nodes communicate with a 2N device. Create `TwoN.Device`, then connect
|
|
132
|
+
its implicit `two_n_device` output to each client's named `Device` input.
|
|
133
|
+
|
|
134
|
+
| Node type | Parameters | Connectors and behavior |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| `Device` | `Hostname: String`, `Port: uint16 = 443`, `TLSA: List[String]`, `UsernamePasswordFile: String` | Out: `two_n_device`. Connects to the device. The credential file contains a username and password on separate lines; a relative path is resolved beside the `.wrl` file. |
|
|
137
|
+
| `KeyEvent` | `Key: String` | Named in: `Device`; out: `event boolean`. True on press, false on release. |
|
|
138
|
+
| `KeyState` | `Key: String`, `Timeout: Duration = "30s"` | Named in: `Device`; out: `value boolean`. Tracks a key, assuming release after the timeout. Startup state can be wrong if the key was already pressed. |
|
|
139
|
+
| `IOState` | `Port: String` | Named in: `Device`; out: `value boolean`. Tracks an input or output port. |
|
|
140
|
+
| `SwitchState` | `SwitchNumber: int32` | Named in: `Device`; out: `value boolean`. Tracks whether a switch is active. |
|
|
141
|
+
| `CodeEnteredEvent` | `Code: String` | Named in: `Device`; out: `event unit`. Emits when the specified code is entered. |
|
|
142
|
+
| `OutputControl` | `Port: String` | Named in: `Device`; in: `event boolean`. Sets an output on or off. |
|
|
143
|
+
|
|
144
|
+
`TLSA` provides certificate association records. TwoN use needs the bundled
|
|
145
|
+
TwoN dependencies, device credentials, and network access to the device.
|
|
146
|
+
|
|
147
|
+
## GPIO
|
|
148
|
+
|
|
149
|
+
`GPIO.Output` sets a GPIO line from an implicit `value boolean` input.
|
|
150
|
+
Parameters are `ChipDeviceFile: String`, `Name: String`,
|
|
151
|
+
`ActiveState: String = "High"`, `Drive: String = "PushPull"`, and
|
|
152
|
+
`Bias: String = "AsIs"`. `ActiveState` accepts `"High"` or `"Low"`;
|
|
153
|
+
`Drive` accepts `"PushPull"`, `"OpenDrain"`, or `"OpenSource"`; and
|
|
154
|
+
`Bias` accepts `"PullDown"`, `"PullUp"`, `"Disable"`, or `"AsIs"`.
|
|
155
|
+
GPIO use requires the `gpio` extra (or the official `gpiod` 2.x Python
|
|
156
|
+
bindings) and access to the chip device.
|
|
157
|
+
|
|
158
|
+
## Memory
|
|
159
|
+
|
|
160
|
+
`Memory.ToggleFlipFlopTrigger` can switch an external impulse relay
|
|
161
|
+
(latching relay) on or off. Each pulse toggles the relay, so the node compares
|
|
162
|
+
the requested state with feedback and emits a pulse only when the state needs
|
|
163
|
+
to change. It takes an implicit `event boolean` command input (`true` for on,
|
|
164
|
+
`false` for off) and a named `Feedback: value Option[boolean]` input. Its
|
|
165
|
+
implicit `event OutputType` output provides the trigger pulse. If feedback is
|
|
166
|
+
`None`, commands are ignored. Its parameters are `OutputType: ValueType = unit`,
|
|
167
|
+
optional `OutputValue: OutputType`, and `MinimumDelay: Duration = "PT1S"`.
|
|
168
|
+
Set `OutputValue` when `OutputType` is not `unit`. The minimum delay limits
|
|
169
|
+
successive output events.
|
|
170
|
+
|
|
171
|
+
## ExtProg
|
|
172
|
+
|
|
173
|
+
`ExtProg.LaunchOnEvent` launches a shell command when an input event arrives.
|
|
174
|
+
Events received while a launch is pending may be combined into one launch.
|
|
175
|
+
It takes `ShellCommand: String` and `Type: ValueType = unit`, with an implicit
|
|
176
|
+
`event Type` input. The event payload is ignored. The command is passed to
|
|
177
|
+
`sh -c` in the output stage and runs with the service process's permissions.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Python style guide
|
|
2
|
+
|
|
3
|
+
## Text format
|
|
4
|
+
|
|
5
|
+
- Save Python files as UTF-8 with LF line endings and a final newline.
|
|
6
|
+
- Use spaces, not tabs. Indent code with four spaces per level.
|
|
7
|
+
|
|
8
|
+
## Code style
|
|
9
|
+
|
|
10
|
+
- Generally, follow PEP 8.
|
|
11
|
+
- Longer lines are acceptable when they improve readability.
|
|
12
|
+
- Use `snake_case` for functions and variables and `PascalCase` for classes.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
node in : Std.DebugEventSource(type = boolean);
|
|
2
|
+
|
|
3
|
+
node fb : Std.DebugInput(type = Option[boolean]);
|
|
4
|
+
|
|
5
|
+
node trigger : Memory.ToggleFlipFlopTrigger(OutputType = boolean, OutputValue = true, MinimumDelay = "PT1S");
|
|
6
|
+
connect in -> trigger;
|
|
7
|
+
connect fb -> trigger.Feedback;
|
|
8
|
+
|
|
9
|
+
node prnt : Std.DebugEventPrinter(type = boolean);
|
|
10
|
+
connect trigger -> prnt;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Meeting-room lighting example: turn the lights on only when the room is
|
|
2
|
+
// occupied and lighting is enabled.
|
|
3
|
+
node Bus : KNX.Connection(UnixPath = "/run/knxnet");
|
|
4
|
+
|
|
5
|
+
node Occupancy : KNX.ValueReceiver(GroupAddress = "0/0/1", Type = boolean);
|
|
6
|
+
connect Bus -> Occupancy.Bus;
|
|
7
|
+
|
|
8
|
+
node LightingEnabled : KNX.ValueReceiver(GroupAddress = "0/0/2", Type = boolean);
|
|
9
|
+
connect Bus -> LightingEnabled.Bus;
|
|
10
|
+
|
|
11
|
+
// Keep the lights off until both input values have been received.
|
|
12
|
+
node OccupiedValue : Std.OptionUnwrapOrDefault(InnerType = boolean, Default = false);
|
|
13
|
+
connect Occupancy -> OccupiedValue;
|
|
14
|
+
|
|
15
|
+
node EnabledValue : Std.OptionUnwrapOrDefault(InnerType = boolean, Default = false);
|
|
16
|
+
connect LightingEnabled -> EnabledValue;
|
|
17
|
+
|
|
18
|
+
node LightsOn : Std.And;
|
|
19
|
+
connect OccupiedValue, EnabledValue -> LightsOn;
|
|
20
|
+
|
|
21
|
+
node Lights : KNX.ValueProvider(GroupAddress = "0/0/3", Type = boolean);
|
|
22
|
+
connect Bus -> Lights.Bus;
|
|
23
|
+
connect LightsOn -> Lights;
|