Changes between Version 60 and Version 61 of Proposal


Ignore:
Timestamp:
Aug 22, 2013, 1:27:15 PM (11 years ago)
Author:
Frédéric
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Proposal

    v60 v61  
    1313'''pKNyX''' will provide powerfull tools so you will only focus on '''your''' problem, and not on language subtilities, like it can be the case with other languages, like C, C++...
    1414
    15 Ok, let me show you what I have in mind.
     15== Virtual devices ==
    1616
    17 == Vocabulary ==
     17See the [[Tutorial]].
    1818
    19 First, some definitions of terms and concepts I will use in '''pKNyX'''. They are the summary of my undersanding of the KNX specifications.
     19== Caching and persistence ==
    2020
    21 ''TODO''
     21'''pKNyX''' will have to implement a cache mode to avoid too much load on the bus.
    2222
    23 == Functional Blocks ==
     23By persistence, I mean the ability to store usefull informations (like Datapoint-s changes) to a database.
    2424
    25 This will be the central feature of '''pKNyX''', allowing user to create virtual devices which mimics real KNX devices. The Device itself will be implemented as the process level.
    26 
    27 Here is a very simple example of what I have in mind: creating a virtual minimalistic weather station, which uses informations from a non-KNX real weather-station, or from a web site. This station only implements temperature/humidity.
    28 
    29 {{{
    30 #!python
    31 from pknyx.api import FunctionalBlock, Stack, ETS, Scheduler
    32 
    33 
    34 stack = Stack(individualAddress="1.2.3")
    35 ets = ETS(stack)
    36 schedule = Scheduler()
    37 
    38 
    39 class WeatherTemperatureBlock(FunctionalBlock):
    40 
    41     DP_01 = dict(name="temperature", access="output", dptId="9.001", default=19.)
    42     DP_02 = dict(name="humidity", access="output", dptId="9.007", default=50.)
    43 
    44     GO_01 = dict(dp="temperature", flags="CRT", priority="low")
    45     GO_02 = dict(dp="humidity", flags="CRT", priority="low")
    46 
    47     @schedule.every(minute=5)
    48     def updateTemperatureHumidity(self, event):
    49 
    50         # temperature = xxx
    51         # humidity = xxx
    52         self.dp["temperature"] = temperature
    53         self.dp["humidity"] = humidity
    54 
    55 
    56 ets.register(WeatherTemperatureBlock, name="weather_temperature", desc="A simple weather temperature/humidity example")
    57 
    58 ets.weave(fb="weatherTempBlock", dp="temperature", gad="1/1/1")
    59 ets.weave(fb="weatherTempBlock", dp="humidity", gad="1/1/2")
    60 
    61 stack.mainLoop()
    62 }}}
    63 
    64 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.
    65 
    66 Lets have a closer look to this example. First, we import some python objects:
    67 
    68 {{{
    69 #!python
    70 from pknyx.api import FunctionalBlock, Stack, ETS, Scheduler
    71 }}}
    72 
    73 These objects are classes.
    74 
    75 We then instanciante some high level objects and helpers:
    76 
    77 {{{
    78 #!python
    79 stack = Stack(individualAddress="1.2.3")
    80 ets = ETS(stack)
    81 schedule = Scheduler()
    82 }}}
    83 
    84 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.
    85 
    86 The {{{ETS}}} object is a tool which works more or less like the real ETS application (see below).
    87 
    88 The {{{Scheduler}}} is a helper implementating a powerfull scheduler (see below).
    89 
    90 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:
    91 
    92 {{{
    93 #!python
    94 class WeatherTemperatureBlock(FunctionalBlock):
    95 
    96     DP_01 = dict(name="temperature", access="output", dptId="9.001", default=19.)
    97     DP_02 = dict(name="humidity", access="output", dptId="9.007", default=50.)
    98 
    99     GO_01 = dict(dp="temperature", flags="CRT", priority="low")
    100     GO_02 = dict(dp="humidity", flags="CRT", priority="low")
    101 }}}
    102 
    103 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.
    104 
    105 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.
    106 
    107 In our class, we also defined a method which role is to update the temperature and humidity Datapoints values:
    108 
    109 {{{
    110 #!python
    111     @schedule.every(minute=5)
    112     def updateTemperatureHumidity(self, event):
    113 
    114         # temperature = xxx
    115         # humidity = xxx
    116         self.dp["temperature"].value = temperature
    117         self.dp["humidity"].value = humidity
    118 }}}
    119 
    120 Note how this method is periodically called, using the {{{schedule.every()}}} method as python decorator. This decorator will automatically register our method and call it every 5 minutes.
    121 
    122 In this method, we get the temperature and humidity values (not explained here), and give these values to the respective Datapoints.
    123 
    124 Then, we register our new Funtional Block (this will automatically instanciate it - and do other things):
    125 
    126 {{{
    127 #!python
    128 ets.register(WeatherTemperatureBlock, name="weather_temperature", desc="A simple weather block example")
    129 }}}
    130 
    131 and use the {{{ETS}}} object to weave (bind, link...) our Datapoints (their matching Group Objects, in fact) to Group Addresses:
    132 
    133 {{{
    134 #!python
    135 ets.weave(fb="weatherTempBlock", dp="temperature", gad="1/1/1")
    136 ets.weave(fb="weatherTempBlock", dp="humidity", gad="1/1/2")
    137 }}}
    138 
    139 And finally, we launch the framework main loop:
    140 
    141 {{{
    142 #!python
    143 stack.mainLoop()
    144 }}}
    145 
    146 (this call is blocking).
    147 
    148 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?
    149 
    150 That's it for now. This is only a draft version; final implementation may change, according to feedback/suggestions I will get. But the core is all there. Again, the goal of the framework is to provide very high level tools to build complete and powerfull applications and KNX extensions.
    151 == Simple rule ==
    152 
    153 My first idea was to provide a special API to create rules, but in fact, they can be implemented as Functional Block. This way, we use the same paradigm, wich is always better ;o)
    154 
    155 Let's have a look at another example; this is something I currently implemented as a rule in '''linknx'''. Here, I juste create a Functional Block:
    156 
    157 {{{
    158 #!python
    159 from pknyx.api import FunctionalBlock, Stack, ETS, Scheduler
    160 
    161 
    162 stack = Stack(individualAddress="1.2.3")
    163 ets = ETS(stack)
    164 schedule = Scheduler()
    165 
    166 
    167 class HeatingManagerBlock(FunctionalBlock):
    168 
    169     DP_01 = dict(name="temperature", access="input", dptId="9.001", default=19.)
    170     DP_02 = dict(name="setup", access="input", dptId="9.001", default=19.)
    171     DP_03 = dict(name="heater", access="output", dptId="1.001", default="Off")
    172 
    173     GO_01 = dict(dp="temperature", flags="CWU", priority="low")
    174     GO_02 = dict(dp="setup", flags="CWU", priority="low")
    175     GO_03 = dict(dp="heater", flags="CRT", priority="low")
    176 
    177     @schedule.every(minute=5)
    178     def manageHeater(self):
    179 
    180         # Read inputs
    181         temperature = self.dp["bathroom"].value
    182         setup = self.dp["setup"].value
    183 
    184         # Manage heater
    185         if temperature < setup - 0.25:
    186             heater = "On"
    187         elif temperature > setup + 0.25:
    188             heater = "Off"
    189 
    190         # Set outputs
    191         self.dp["bathroom_heater"].value = heater
    192 
    193 
    194 ets.register(HeatingManagerBlock, name="heating_manager", desc="A simple heating manager block example")
    195 
    196 ets.weave(fb="heatingManagerBlock", dp="temperature", gad="1/1/1")
    197 ets.weave(fb="heatingManagerBlock", dp="setup", gad="1/1/2")
    198 ets.weave(fb="heatingManagerBlock", dp="heater", gad="1/1/3")
    199 
    200 stack.mainLoop()
    201 }}}
    202 
    203 All you have to do is to use the Group Addresses you use in your real installation, through ETS application. The first one will update the temperature the Functional Block needs; the second one is used to give the setpoint, and the last one is used to switch on/off a real heater, through a KNX actuator.
    204 
    205 Note that it is possible to instanciate several heating managers, and weave them to different heaters.
    206 
    207 A more complex heating manager could compute a PID and output the power to use to heat.
    20825== '''linknx''' compatibility mode ==
    20926
     
    21532
    21633The purpose of this will be to provide the model part of an automatic web page generation mechanism. I don't know yet how it will exactly work, but the idea is to provide a simple list of usefull informations/settings which can be used from smartphones (simples buttons and displays).
     34
    21735== Unsorted ideas ==
    21836