Changes between Version 9 and Version 10 of Tutorial
- Timestamp:
- Aug 22, 2013, 11:34:46 AM (11 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Tutorial
v9 v10 29 29 Functional Block-s can be deployed as one or several Device-s. In '''pKNyX''', each Device runs as a process. All Device-s can run on the same machine, or spread over a set of machines. Like in real KNX world. 30 30 31 == Create the device ==32 33 As said, '''pKNyX''' main entry is a Device, which will run as a process. As any good framework, '''pKNyX''' helps in starting writing code by auto-generating some usefull files, in a specific hierarchy, to implement thisDevice in a correct way.34 35 The tool to do that is '''{{{pknyx-admin.py}}}'''. This a global tool to manage devices (create/check/ start). Let's see how to use it to create a fresh device:31 == Create device structure == 32 33 As any good framework, '''pKNyX''' helps in starting writing code by auto-generating some usefull files, in a specific hierarchy, to implement a Device in a correct way. 34 35 The tool to do that is '''{{{pknyx-admin.py}}}'''. This a global tool to manage devices (create/check/run). Let's see how to use it to create a fresh device: 36 36 37 37 {{{ 38 38 $ pknyx-admin.py createdevice timer 39 create 'timer' from template... 40 done 39 enerate 'timer' structure from template... 40 'timer' dir created 41 'timer/admin.py' file generated 42 'timer/timer' dir created 43 'timer/timer/__init__.py' file generated 44 'timer/timer/config.py' file generated 45 'timer/timer/device.py' file generated 46 'timer/timer/fb' dir created 47 'timer/timer/fb/__init__.py' file generated 48 'timer/timer/fb/timerFB.py' file generated 49 'timer/timer/plugins' dir created 50 'timer/timer/plugins/__init__.py' file generated 51 'timer' structure done 41 52 }}} 42 53 … … 45 56 {{{ 46 57 $ tree timer 47 timer 58 timer/ 48 59 ├── admin.py 49 60 └── timer 50 61 ├── config.py 51 62 ├── device.py 52 └── __init__.py 53 54 1 directory, 4 files 55 }}} 56 57 The top-level dir {{{timer}}} can be renamed as you want. It contains a script called '''{{{admin.py}}}'''; this script is in fact the {{{pknyx-admin.py}}} one, with a pre-defined env var pointing on our timer structure, in order to manage it. It is possible to use the global {{{pknyx-admin.py}}} script, but it would need to define $PKNX_DEVICE_PATH var and make it point to the second {{{timer}}} dir, so that the python interpreter can correctly import our files. So, for now, let's use the {{{admin.py}}} script. 58 59 The '''{{{config.py}}}''' file contains a few pre-defined constants: 63 ├── fb 64 │ ├── __init__.py 65 │ └── timerFB.py 66 ├── __init__.py 67 └── plugins 68 └── __init__.py 69 70 3 directories, 7 files 71 }}} 72 73 The top-level dir {{{timer}}} can be renamed as you want. All further references are from this dir. 74 75 This dir contains a script called '''{{{admin.py}}}'''; this script is in fact the {{{pknyx-admin.py}}} one, with a pre-defined env var pointing on our timer structure, in order to manage it. It is possible to use the global {{{pknyx-admin.py}}} script, but it would need to define $PKNX_DEVICE_PATH var and make it point to the second {{{timer}}} dir, so that the python interpreter can correctly import our files. So, for now, let's use the {{{admin.py}}} script. 76 77 The '''{{{timer/config.py}}}''' file contains a few pre-defined constants: 60 78 61 79 {{{ … … 74 92 This is where we will add new configs values for our Device, if needed. 75 93 76 The last file is '''{{{device.py}}}'''; this is the most important one, where we will implement our Device code: 77 78 {{{ 79 """# -*- coding: utf-8 -*- 80 81 from pknyx.api import Device, FunctionalBlock 94 The next file, '''{{{timer/device.py}}}''', contains a Device example: 95 96 {{{ 97 #!python 98 # -*- coding: utf-8 -*- 99 100 from pknyx.api import Device 101 102 from fb.timerFB import TimerFB 103 104 105 class Timer(Device): 106 FB_01 = dict(cls=TimerFB, name="timer_fb", desc="timer fb") 107 108 LNK_01 = dict(fb="timer_fb", dp="dp_01", gad="1/1/1") 109 110 DESC = "Timer" 111 112 113 DEVICE = Timer 114 }}} 115 116 Last generated file is '''{{{timer/fb/timerFB.py}}}'''; it contains a Functional Block example: 117 118 {{{ 119 #!python 120 # -*- coding: utf-8 -*- 121 122 from pknyx.api import FunctionalBlock 82 123 from pknyx.api import logger, schedule, notify 83 124 84 125 85 class FB(FunctionalBlock):126 class TimerFB(FunctionalBlock): 86 127 DP_01 = dict(name="dp_01", access="output", dptId="1.001", default="Off") 87 128 88 129 GO_01 = dict(dp="dp_01", flags="CWT", priority="low") 89 130 90 DESC = "FB" 91 92 93 class Timer(Device): 94 FB_01 = dict(cls=FB, name="fb_01", desc="fb 01") 95 96 LNK_01 = dict(fb="fb_01", dp="dp_01", gad="1/1/1") 97 98 DESC = "Timer" 99 100 101 DEVICE = Timer 102 }}} 103 104 As you see, it already contains a dummy Functional Block, and a dummy Device, in order to show how things work. 105 106 == The Timer example == 131 DESC = "Timer FB" 132 }}} 133 134 == Timer implementation == 107 135 108 136 Ok, lets's start to implement our simple timer example. This timer monitors the state of a light, and switches it off automatically after a delay. 109 137 110 Let's modify the {{{device.py}}} according to this: 111 112 {{{ 113 #!python 114 from pknyx.api import Device, FunctionalBlock 138 First, modify the {{{timerFB.py}}} file according to this: 139 140 {{{ 141 #!python 142 # -*- coding: utf-8 -*- 143 144 from pknyx.api import FunctionalBlock 115 145 from pknyx.api import logger, schedule, notify 116 146 … … 154 184 logger.info("%s: delay changed; restart timer" % self._name) 155 185 self._timer = delay 186 }}} 187 188 Then, modify {{{device.py}}} like this: 189 190 {{{ 191 #!python 192 # -*- coding: utf-8 -*- 193 194 from pknyx.api import Device 195 196 from fb.timerFB import TimerFB 156 197 157 198 158 199 class Timer(Device): 159 FB_01 = dict(cls=TimerFB, name="timer fb", desc="timer fb")200 FB_01 = dict(cls=TimerFB, name="timer_fb", desc="timer fb") 160 201 161 202 LNK_01 = dict(fb="timerfb", dp="cmd", gad="1/1/1") … … 163 204 LNK_03 = dict(fb="timerfb", dp="delay", gad="1/3/1") 164 205 165 DESC = "Timer device"206 DESC = "Timer" 166 207 167 208 … … 175 216 {{{ 176 217 $ ./admin.py checkdevice 177 MainThread::AdminUtility._checkRunDevice(): logger level is 'info'178 MainThread::AdminUtility._checkRunDevice(): config path is './timer'179 MainThread::AdminUtility._checkRunDevice(): device name is 'timer'180 MainThread::AdminUtility._checkRunDevice(): device individual address is '1.1.1'181 no error found218 Logger level is 'info' 219 Config path is './timer' 220 Device name is 'timer' 221 Device Individual Address is '1.1.1' 222 No error found 182 223 $ 183 224 }}} … … 187 228 {{{ 188 229 $ ./admin.py rundevice 189 MainThread::AdminUtility._checkRunDevice(): logger level is 'info'190 MainThread::AdminUtility._checkRunDevice(): config path is './timer'191 MainThread::AdminUtility._checkRunDevice(): device name is 'timer'192 MainThread::AdminUtility._checkRunDevice(): device individual address is '1.1.1'193 MainThread::AdminUtility._runDevice(): detachis 'False'194 MainThread::Scheduler started195 MainThread::Stack running230 Logger level is 'info' 231 Config path is './timer' 232 Device name is 'timer' 233 Device Individual Address is '1.1.1' 234 Detaching is 'False' 235 Scheduler started 236 Stack running 196 237 }}} 197 238 … … 199 240 200 241 {{{ 201 LinkLayer::timerfb: start timer for 10s202 203 Thread-15::timerfb: timer expired; switch off242 timerfb: start timer for 10s 243 244 timerfb: timer expired; switch off 204 245 }}} 205 246 … … 210 251 '''Important note: to avoid internal loops, a device drops all telegrams sent by itself. So, if you want 2 virtual devices to communicate, you must ensure that they don't use the same source address, like in a real installation. Keep this in mind ; if you don't see telegrams you are expecting, the problem may be there.''' 211 252 212 So, lets deep inside this example to explain how things work. First, we import some python objects: 213 214 {{{ 215 #!python 216 from pknyx.api import Device, FunctionalBlock 253 So, lets deep inside this example to explain how things work, starting with the {{{timer/timer/gb/timerFB.py}}} module. 254 255 First, we import some python objects: 256 257 {{{ 258 #!python 259 from pknyx.api import FunctionalBlock 217 260 from pknyx.api import logger, schedule, notify 218 261 }}} 219 262 220 '''{{{ Device}}}''' and '''{{{FunctionalBlock}}}''' are classes; '''{{{logger}}}''', '''{{{schedule}}}''', '''{{{notify}}}''' are instances.263 '''{{{FunctionalBlock}}}''' is a class; '''{{{logger}}}''', '''{{{schedule}}}''', '''{{{notify}}}''' are instances. 221 264 222 265 The {{{logger}}} object is a global logger service, which allows you to output all informations you want, at different levels. '''pKNyX''' makes a big usage of that logger. By default, the template set the logger level to '''{{{info}}}''', but you can set it to other levels. See the documentation. … … 307 350 I think you got the point ;o) 308 351 309 Now we need to implement our Device: 352 Now we need to implement our Device, in {{{timer/timer/device.py}}}: 353 354 {{{ 355 #!python 356 # -*- coding: utf-8 -*- 357 358 from pknyx.api import Device 359 360 from fb.timerFB import TimerFB 361 }}} 362 363 A few imports; most important one is, of course, our custom Functional Block. 364 365 Then, we implement our Device: 310 366 311 367 {{{ 312 368 #!python 313 369 class Timer(Device): 314 FB_01 = dict(cls=TimerFB, name="timer fb", desc="timer fb")315 316 LNK_01 = dict(fb="timer fb", dp="cmd", gad="1/1/1")317 LNK_02 = dict(fb="timer fb", dp="state", gad="1/2/1")318 LNK_03 = dict(fb="timer fb", dp="delay", gad="1/3/1")319 320 DESC = "Timer device"321 }}} 322 323 As you see, it mustinherits the {{{Device}}} class. Like for the Function Block, things are defined through class attributes; '''pKNyX''', like python, tries to limit the number of paradigms.370 FB_01 = dict(cls=TimerFB, name="timer_fb", desc="timer fb") 371 372 LNK_01 = dict(fb="timer_fb", dp="cmd", gad="1/1/1") 373 LNK_02 = dict(fb="timer_fb", dp="state", gad="1/2/1") 374 LNK_03 = dict(fb="timer_fb", dp="delay", gad="1/3/1") 375 376 DESC = "Timer" 377 }}} 378 379 As you see, it inherits the {{{Device}}} class. Like for the Function Block, things are defined through class attributes; '''pKNyX''', like python, tries to limit the number of paradigms. 324 380 325 381 We first need to tell which Function Block(-s) our device will use. This is done by creating a dict, which name must start with '''{{{FB_}}}'''. Here, we only have one Functional Block.