47 | | |
48 | | weatherTempBlock = WeatherTemperatureBlock(name="weather_tempertature", desc="A simple weather block example") |
49 | | |
50 | | stack = Stack(individualAddress="1.2.3") |
51 | | ets = ETS(stack) |
52 | | |
53 | | ets.weave(fb=weatherTempBlock, dp="temperature", gad="1/1/1") |
54 | | ets.weave(fb=weatherTempBlock, dp="humidity", gad="1/1/2") |
55 | | |
56 | | stack.run() |
57 | | }}} |
58 | | |
59 | | That's it! As you can see, concepts used here are simple... This Functional Block can be then used from any other real device of your installation, through Groups Addresses {{{1/1/1}}} and {{{1/1/2}}}. All you have to do, is to weave (link, bind...) the Group Objects of your real devices to these Groups Addresses, using the real '''ETS''' application. |
60 | | |
61 | | Lets have a closer look to this example. First, we import some python objects: |
62 | | |
63 | | {{{ |
64 | | #!python |
65 | | from pknyx.api import FunctionalBlock, Stack, ETS |
66 | | }}} |
67 | | |
68 | | These objects are classes. |
69 | | |
70 | | Then, we create a custom Functional Block; this is done by subclassing the '''!FunctionBlock''' base class, and adding a few attributes: |
71 | | |
72 | | {{{ |
73 | | #!python |
74 | | class WeatherTemperatureBlock(FunctionalBlock): |
75 | | |
76 | | DP_01 = dict(name="temperature", access="output", dptId="9.001", default=19.) |
77 | | DP_02 = dict(name="humidity", access="output", dptId="9.007", default=50.) |
78 | | |
79 | | GO_01 = dict(dp="temperature", flags="CRT", priority="low") |
80 | | GO_02 = dict(dp="humidity", flags="CRT", priority="low") |
81 | | }}} |
82 | | |
83 | | The {{{DP_xx}}} class attributes are the Datapoints of our Functional Block. The {{{GO_xx}}} class attributes are the Group Objects mapping the Datapoints to the bus. They are both defined as python dictionnary; they will be automatically instanciated for you by the framework. The named used here does not matter, as long as they start with {{{DP_}}} for Datapoints, and {{{GO_}}} for Group Objects. |
84 | | |
85 | | Then, we just instanciate our new Funtional Block: |
86 | | |
87 | | {{{ |
88 | | #!python |
89 | | weatherTempBlock = WeatherTemperatureBlock(name="weather_tempertature", desc="A simple weather block example") |
90 | | }}} |
91 | | |
92 | | We also need to instanciante some global high level objects: |
93 | | |
94 | | {{{ |
95 | | #!python |
96 | | stack = Stack(individualAddress="1.2.3") |
97 | | ets = ETS(stack) |
98 | | }}} |
99 | | |
100 | | The {{{Stack}}} object is used to communicate over the bus (real bus, of course, but also on virtual bus). We can give it an Individual Address, to mimic real devices behaviour. |
101 | | |
102 | | The {{{ETS}}} object is a tool which works like the reall ETS application, and used to weave (bind, link...) our Group Objects to Group Addresses: |
103 | | |
104 | | {{{ |
105 | | #!python |
106 | | ets.weave(fb=weatherTempBlock, dp="temperature", gad="1/1/1") |
107 | | ets.weave(fb=weatherTempBlock, dp="humidity", gad="1/1/2") |
108 | | }}} |
109 | | |
110 | | And finally: |
111 | | |
112 | | {{{ |
113 | | #!python |
114 | | stack.serve() |
115 | | }}} |
116 | | |
117 | | This call is blocking, and launch the framework main loop. |
118 | | |
119 | | We now have a process (Device) running, listening to the bus. The Datapoints, through their respective Group Objects, will react to requests on the Group Addresses their are weaved to ("1/1/1" and "1/1/2"). According to the flags, they will transmit their internal value on a Read request, or if this value changes. |
120 | | |
121 | | Ok, but our Functional Block is not really usefull yet, as it does not refresh its Datapoints! Let's see how it can be done: |
122 | | |
123 | | {{{ |
124 | | #!python |
125 | | from pknyx.api import FunctionalBlock, Stack, ETS |
126 | | from pknyx.api import Scheduler |
127 | | |
128 | | |
129 | | schedule = Scheduler() |
130 | | |
131 | | |
132 | | class WeatherTemperatureBlock(FunctionalBlock): |
133 | | |
134 | | DP_01 = dict(name="temperature", access="output", dptId="9.001", default=19.) |
135 | | DP_02 = dict(name="humidity", access="output", dptId="9.007", default=50.) |
136 | | |
137 | | GO_01 = dict(dp="temperature", flags="CRT", priority="low") |
138 | | GO_02 = dict(dp="humidity", flags="CRT", priority="low") |
139 | | |
| 62 | ets.weave(fb=weatherTempBlock, dp="temperature", gad="1/1/1") |
| 63 | ets.weave(fb=weatherTempBlock, dp="humidity", gad="1/1/2") |
| 64 | |
| 65 | stack.run() |
| 66 | }}} |
| 67 | |
| 68 | That's it! As you can see, concepts used here are simple... This Functional Block can be then used from any other real device of your installation, through Groups Addresses {{{1/1/1}}} and {{{1/1/2}}}. All you have to do, is to weave (link, bind...) the Group Objects of your real devices to these Groups Addresses, using the real '''ETS''' application. |
| 69 | |
| 70 | Lets have a closer look to this example. First, we import some python objects: |
| 71 | |
| 72 | {{{ |
| 73 | #!python |
| 74 | from pknyx.api import FunctionalBlock, Stack, ETS, Scheduler |
| 75 | }}} |
| 76 | |
| 77 | These objects are classes. |
| 78 | |
| 79 | We then instanciante some high level objects and helpers: |
| 80 | |
| 81 | {{{ |
| 82 | #!python |
171 | | We have also defined a method which role is to update the temperature and humidity Datapoints values: |
| 88 | The {{{Stack}}} object is used to communicate over the bus (real bus, of course, but also virtual bus). We can give it an Individual Address, to mimic real devices behaviour. This address will be used as Source Address when communicating over the bus. |
| 89 | |
| 90 | The {{{ETS}}} object is a tool which works more or less like the real ETS application (see below). |
| 91 | |
| 92 | The {{{Scheduler}}} is a helper implementating a powerfull scheduler (see below). |
| 93 | |
| 94 | The main part is to create our custom Functional Block; this is done by subclassing the '''!FunctionBlock''' base class, and adding a few attributes/methods: |
| 95 | |
| 96 | {{{ |
| 97 | #!python |
| 98 | class WeatherTemperatureBlock(FunctionalBlock): |
| 99 | |
| 100 | DP_01 = dict(name="temperature", access="output", dptId="9.001", default=19.) |
| 101 | DP_02 = dict(name="humidity", access="output", dptId="9.007", default=50.) |
| 102 | |
| 103 | GO_01 = dict(dp="temperature", flags="CRT", priority="low") |
| 104 | GO_02 = dict(dp="humidity", flags="CRT", priority="low") |
| 105 | }}} |
| 106 | |
| 107 | The {{{DP_xx}}} class attributes are the Datapoints of our Functional Block. The {{{GO_xx}}} class attributes are the Group Objects mapping the Datapoints to the bus. They are both defined as python dictionnary; they will be automatically instanciated for us by the framework. The named used here do not matter, as long as they start with {{{DP_}}} for Datapoints, and {{{GO_}}} for Group Objects. |
| 108 | |
| 109 | There are a few parameters in the dicts; some are obvious, some will need more explanations. But this is out of the scope of this proposal. |
| 110 | |
| 111 | In our class, we also defined a method which role is to update the temperature and humidity Datapoints values: |
187 | | In our method, we retreive the temperature and humidity values (not explained here), and give the value to the respective Datapoints. If the value has changed from the previous call, the Datapoint will automagically transmit it to the bus (according to the flags, of course). |
| 125 | In this method, we get the temperature and humidity values (not explained here), and give the value to the respective Datapoints. |
| 126 | |
| 127 | Then, we instanciate our new Funtional Block: |
| 128 | |
| 129 | {{{ |
| 130 | #!python |
| 131 | weatherTempBlock = WeatherTemperatureBlock(name="weather_tempertature", desc="A simple weather block example") |
| 132 | }}} |
| 133 | |
| 134 | and use the {{{ETS}}} object to weave (bind, link...) our Datapoints (their matching Group Objects, in fact) to Group Addresses: |
| 135 | |
| 136 | {{{ |
| 137 | #!python |
| 138 | ets.weave(fb=weatherTempBlock, dp="temperature", gad="1/1/1") |
| 139 | ets.weave(fb=weatherTempBlock, dp="humidity", gad="1/1/2") |
| 140 | }}} |
| 141 | |
| 142 | And finally, we launch the framework main loop: |
| 143 | |
| 144 | {{{ |
| 145 | #!python |
| 146 | stack.serve() |
| 147 | }}} |
| 148 | |
| 149 | (this call is blocking). |
| 150 | |
| 151 | We now have a process (Device) running, listening to the bus. The Datapoints, through their respective Group Objects, will react to requests on the Group Addresses they are weaved to ("1/1/1" and "1/1/2"). According to the flags, they will transmit their internal value on Read requests or if their value internally change (updated). Yes, you don't have to manage this: '''pKNyX''' does it for you! This is the all point of a framework, isn't it? |