| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| # Metadata for the Smart-Plugin | ||
| plugin: | ||
| type: system # plugin type (gateway, interface, protocol, system, web) | ||
| description: # Alternative: description in multiple languages | ||
| de: 'Raum Temperatur Regler' | ||
| en: 'Room Temperatur controller' | ||
| maintainer: Thomas Creutz / bmxp | ||
| tester: bmxp | ||
| state: ready | ||
| support: https://knx-user-forum.de/forum/supportforen/smarthome-py/31450-rtr-heizungs-plugin | ||
| documentation: https://www.smarthomeng.de/dev/user/plugins/rtr/README.html | ||
| version: 1.2.4 # Plugin version | ||
| sh_minversion: 1.2 # minimum shNG version to use this plugin | ||
| restartable: True | ||
| multi_instance: False # plugin supports multi instance | ||
| classname: RTR # class containing the plugin | ||
|
|
||
| parameters: | ||
| default_Kp: | ||
| type: int | ||
| default: 10 | ||
| description: | ||
| de: 'Standard Verstärkungsfaktor für erstellte Items' | ||
| en: 'default proportional gain for created items' | ||
|
|
||
| default_Ki: | ||
| type: int | ||
| default: 15 | ||
| description: | ||
| de: 'Standard Integralfaktor für erstellte Items' | ||
| en: 'default integral gain for created items' | ||
|
|
||
| cycle_time: | ||
| type: int | ||
| default: 60 | ||
| description: | ||
| de: "Abständen in Sekunden, in denen die Regelung arbeitet. Dieser Wert sollte nur geändert werden, wenn man weiss was man tut!" | ||
| en: "Cycle timer in secounds. Don't change when you don't know what you do!" | ||
|
|
||
| defaultBoostTime: | ||
| type: int | ||
| default: 240 | ||
| description: | ||
| de: "Legt die Standard Zeit in Minuten fest, nachdem die Boost-Temperatur automatisch zurück auf Standard gesetzt wird" | ||
| en: "Defines the default time in minutes, when the boost-temperature gets autmatically set back to Default" | ||
|
|
||
| defaultOnExpiredTimer: | ||
| type: bool | ||
| default: true | ||
| description: | ||
| de: "Wenn nicht aktiviert, werden beim wiederherstellen von abgelaufenen Timern die Temperaturen nicht zurück auf Default gesetzt" | ||
| en: "when not True, a expired timer will not set back to Default-Temperature on a timer restore (when SH will be restarted)" | ||
|
|
||
| defaultValveProtect: | ||
| type: bool | ||
| default: true | ||
| description: | ||
| de: "Wenn Wahr wird für alle Regler Ventilschutz voreingestellt" | ||
| en: "If True, all controller will preset to protect valves" | ||
|
|
||
| item_attributes: | ||
| rtr_current: | ||
| type: int | ||
| mandatory: True | ||
| description: | ||
| de: 'Ordnet das Item dem Regler/Controller mit gegebener ID als Ist-Wert zu' | ||
| en: 'Defines the Item as current value for the given controller ID' | ||
|
|
||
| rtr_Kp: | ||
| type: int | ||
| description: | ||
| de: 'Ordnet dem Item einen vom Standard abweichenden Verstärkungsfaktor zu. Muss auf dem selben Item wie rtr_current gesetzt werden' | ||
| en: 'Defines a different proportional gain for the controller. Only valid in the same Item where rtr_current is defined' | ||
|
|
||
| rtr_Ki: | ||
| type: int | ||
| description: | ||
| de: 'Ordnet dem Item einen vom Standard abweichenden Integralfaktor zu. Muss auf dem selben Item wie rtr_current gesetzt werden' | ||
| en: 'Defines a different integral gain for the controller. Only valid in the same Item where rtr_current is defined' | ||
|
|
||
| rtr_setpoint: | ||
| type: int | ||
| mandatory: True | ||
| description: | ||
| de: 'Ordnet das Item dem Regler/Controller mit gegebener ID als Soll-Wert zu' | ||
| en: 'Defines the Item as setpoint value for the given controller ID' | ||
|
|
||
| rtr_temp_default: | ||
| type: float | ||
| description: | ||
| de: 'Ordnet dem Regler/Controller eine Standard Temperatur zu, auf die rtr_setpoint zurück gesetzt wird. Muss auf dem selben Item wie rtr_setpoint gesetzt werden' | ||
| en: 'Defines a default temperature for rtr_setpoint. Only valid in the same Item where rtr_setpoint is defined' | ||
|
|
||
| rtr_temp_drop: | ||
| type: float | ||
| description: | ||
| de: 'Ordnet dem Regler/Controller eine Absenk-Temperatur zu, auf die rtr_setpoint beim aufruf der Funktion drop gesetzt wird. Muss auf dem selben Item wie rtr_setpoint gesetzt werden' | ||
| en: 'Defines a drop temperature for rtr_setpoint, which is set by calling the drop function. Only valid in the same Item where rtr_setpoint is defined' | ||
|
|
||
| rtr_temp_boost: | ||
| type: float | ||
| description: | ||
| de: 'Ordnet dem Regler eine Boost-Temperatur zu, auf die rtr_setpoint beim aufruf der Funktion boost gesetzt wird. Muss auf dem selben Item wie rtr_setpoint gesetzt werden' | ||
| en: 'Defines a boost temperature for rtr_setpoint, which is set by calling the boost function. Only valid in the same Item where rtr_setpoint is defined' | ||
|
|
||
| rtr_temp_boost_time: | ||
| type: int | ||
| description: | ||
| de: 'Ordnet dem Regler eine Standard Zeit für den Boost in Minten zu und überschreibt somit den globalen Standard defaultBoostTime. Muss auf dem selben Item wie rtr_setpoint gesetzt werden' | ||
| en: 'Defines a default boost time in minutes for this controller and so overrides the global defaultBoostTime. Only valid in the same Item where rtr_setpoint is defined' | ||
|
|
||
| rtr_actuator: | ||
| type: int | ||
| mandatory: True | ||
| description: | ||
| de: 'Ordnet das Item dem Controller mit gegebener ID als Stellgröße zu' | ||
| en: 'Defines the Item as actuator value for the given controller ID' | ||
|
|
||
| rtr_valve_protect: | ||
| type: bool | ||
| description: | ||
| de: 'Aktiviert den Ventilschutz für diesen Controller' | ||
| en: 'Activates the valve protection for this controller ID' | ||
|
|
||
| rtr_hvac_mode: | ||
| type: int | ||
| description: | ||
| de: 'Setzt den Modus' | ||
| en: 'Sets the mode' | ||
|
|
||
| rtr_stops: | ||
| type: list(int) | ||
| description: | ||
| de: 'Ordnet das Item dem einen oder mehreren Controllern per ID als Stop-Objekt zu. Kann nur auf einem Item vom Typ Bool gesetzt werden. Ist der Item Wert True, Pausiert die Regelung' | ||
| en: 'Defines the Item as stop item for the given controller IDs. Only valid on Item-Type Bool. If Item is True, the controller gets paused' | ||
|
|
||
| item_structs: NONE | ||
| # Definition of item-structure templates for this plugin (enter 'item_structs: NONE', if section should be empty) | ||
|
|
||
| logic_parameters: NONE | ||
| # Definition of logic parameters defined by this plugin | ||
|
|
||
| plugin_functions: NONE | ||
| # Definition of function interface of the plugin | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # translations for the web interface | ||
| plugin_translations: | ||
| # Translations for the plugin specially for the web interface | ||
| 'Wert 2': {'de': '=', 'en': 'Value 2'} | ||
| 'Wert 4': {'de': '=', 'en': 'Value 4'} | ||
|
|
||
| # Alternative format for translations of longer texts: | ||
| 'Hier kommt der Inhalt des Webinterfaces hin.': | ||
| de: '=' | ||
| en: 'Here goes the content of the web interface.' | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| #!/usr/bin/env python3 | ||
| # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab | ||
| ######################################################################### | ||
| # Copyright 2020- <AUTHOR> <EMAIL> | ||
| ######################################################################### | ||
| # This file is part of SmartHomeNG. | ||
| # https://www.smarthomeNG.de | ||
| # https://knx-user-forum.de/forum/supportforen/smarthome-py | ||
| # | ||
| # Sample plugin for new plugins to run with SmartHomeNG version 1.5 and | ||
| # upwards. | ||
| # | ||
| # SmartHomeNG is free software: you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation, either version 3 of the License, or | ||
| # (at your option) any later version. | ||
| # | ||
| # SmartHomeNG is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with SmartHomeNG. If not, see <http://www.gnu.org/licenses/>. | ||
| # | ||
| ######################################################################### | ||
|
|
||
| import datetime | ||
| import time | ||
| import os | ||
|
|
||
| from lib.item import Items | ||
| from lib.model.smartplugin import SmartPluginWebIf | ||
|
|
||
|
|
||
| # ------------------------------------------ | ||
| # Webinterface of the plugin | ||
| # ------------------------------------------ | ||
|
|
||
| import cherrypy | ||
| import csv | ||
| from jinja2 import Environment, FileSystemLoader | ||
|
|
||
|
|
||
| class WebInterface(SmartPluginWebIf): | ||
|
|
||
| def __init__(self, webif_dir, plugin): | ||
| """ | ||
| Initialization of instance of class WebInterface | ||
| :param webif_dir: directory where the webinterface of the plugin resides | ||
| :param plugin: instance of the plugin | ||
| :type webif_dir: str | ||
| :type plugin: object | ||
| """ | ||
| self.logger = plugin.logger | ||
| self.webif_dir = webif_dir | ||
| self.plugin = plugin | ||
| self.items = Items.get_instance() | ||
|
|
||
| self.tplenv = self.init_template_environment() | ||
|
|
||
|
|
||
| @cherrypy.expose | ||
| def index(self, reload=None): | ||
| """ | ||
| Build index.html for cherrypy | ||
| Render the template and return the html file to be delivered to the browser | ||
| :return: contents of the template after beeing rendered | ||
| """ | ||
| tmpl = self.tplenv.get_template('index.html') | ||
| # add values to be passed to the Jinja2 template eg: tmpl.render(p=self.plugin, interface=interface, ...) | ||
| return tmpl.render(p=self.plugin, items=sorted(self.items.return_items(), key=lambda k: str.lower(k['_path']))) | ||
|
|
||
|
|
||
| @cherrypy.expose | ||
| def get_data_html(self, dataSet=None): | ||
| """ | ||
| Return data to update the webpage | ||
| For the standard update mechanism of the web interface, the dataSet to return the data for is None | ||
| :param dataSet: Dataset for which the data should be returned (standard: None) | ||
| :return: dict with the data needed to update the web page. | ||
| """ | ||
| if dataSet is None: | ||
| # get the new data | ||
| data = {} | ||
|
|
||
| # data['item'] = {} | ||
| # for i in self.plugin.items: | ||
| # data['item'][i]['value'] = self.plugin.getitemvalue(i) | ||
| # | ||
| # return it as json the the web page | ||
| # try: | ||
| # return json.dumps(data) | ||
| # except Exception as e: | ||
| # self.logger.error("get_data_html exception: {}".format(e)) | ||
| return {} | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| This directory is for storing images that are used by the web interface. | ||
|
|
||
| If you want to have your own logo on the top of the web interface, store it here and name it plugin_logo.<extension>. | ||
|
|
||
| Extension can be png, svg or jpg | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| {% extends "base_plugin.html" %} | ||
|
|
||
| {% set logo_frame = false %} | ||
|
|
||
| <!-- set update_interval to a value > 0 (in milliseconds) to enable periodic data updates --> | ||
| {% set update_interval = 0 %} | ||
|
|
||
| <!-- | ||
| Additional script tag for plugin specific javascript code go into this block | ||
| --> | ||
| {% block pluginscripts %} | ||
| <script> | ||
| function handleUpdatedData(response, dataSet=null) { | ||
| if (dataSet === 'devices_info' || dataSet === null) { | ||
| var objResponse = JSON.parse(response); | ||
| myProto = document.getElementById(dataSet); | ||
| for (var device in objResponse) { | ||
| <!-- | ||
| shngInsertText (device+'_source', objResponse[device]['source']); | ||
| shngInsertText (device+'_powerState', objResponse[device]['powerState']); | ||
| --> | ||
| } | ||
| } | ||
| } | ||
| </script> | ||
| {% endblock pluginscripts %} | ||
|
|
||
|
|
||
| {% block headtable %} | ||
| <table class="table table-striped table-hover"> | ||
| <tbody> | ||
| <tr> | ||
| <td class="py-1"><strong>default_Kp</strong></td> | ||
| <td class="py-1">{{ p._defaults['Kp'] }}</td> | ||
| <td class="py-1" width="50px"></td> | ||
| <td class="py-1"><strong>defaultBoostTime</strong></td> | ||
| <td class="py-1">{{ p._defaults['tempBoostTime'] }}</td> | ||
| <td class="py-1" width="50px"></td> | ||
| </tr> | ||
| <tr> | ||
| <td class="py-1"><strong>default_Ki</strong></td> | ||
| <td class="py-1">{{ p._defaults['Ki'] }}</td> | ||
| <td></td> | ||
| <td class="py-1"><strong>defaultOnExpiredTimer</strong></td> | ||
| <td class="py-1">{{ p._defaultOnExpiredTimer }}</td> | ||
| <td></td> | ||
| </tr> | ||
| <tr> | ||
| <td class="py-1"><strong>cycle_time</strong></td> | ||
| <td class="py-1">{{ p._cycle_time }}</td> | ||
| <td></td> | ||
| <td class="py-1"><strong>default ValveProtect</strong></td> | ||
| <td class="py-1">{{ p._defaults['valveProtect'] }}</td> | ||
| <td></td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
| {% endblock headtable %} | ||
|
|
||
|
|
||
| <!-- | ||
| Additional buttons for the web interface (if any are needed) - displayed below the headtable-section | ||
| --> | ||
| {% block buttons %} | ||
| {% if 1==2 %} | ||
| <div> | ||
| <button id="btn1" class="btn btn-shng btn-sm" name="scan" onclick="shngPost('', {learn: 'on'})"><i class="fas fa-question"></i> {{ _('nach Devices suchen') }} </button> | ||
| </div> | ||
| {% endif %} | ||
| {% endblock %} | ||
|
|
||
| <!-- | ||
| Define the number of tabs for the body of the web interface (1 - 3) | ||
| --> | ||
| {% set tabcount = 1 %} | ||
|
|
||
|
|
||
| <!-- | ||
| Set the tab that will be visible on start, if another tab that 1 is wanted (1 - 3) | ||
| --> | ||
| {% if item_count==0 %} | ||
| {% set start_tab = 2 %} | ||
| {% endif %} | ||
|
|
||
|
|
||
| <!-- | ||
| Content block for the first tab of the Webinterface | ||
| --> | ||
| {% set tab1title = "<strong>" ~ p.get_shortname() ~ " Controller</strong>" %} | ||
| {% block bodytab1 %} | ||
| <div class="container-fluid m-2"> | ||
| {% for c in p._controller %} | ||
| <h2>{{ c }}</h2> | ||
| <table> | ||
| {% set pairs = p._controller[c] %} | ||
| {% for key in pairs %} | ||
| <tr> | ||
| <td>{{ key }}</td><td>{{ pairs[key] }}</td> | ||
| </tr> | ||
| {% endfor %} | ||
| </table> | ||
| </li> | ||
| {% endfor %} | ||
| </div> | ||
| {% endblock bodytab1 %} | ||
|
|
||
|
|
||
| <!-- | ||
| Content block for the second tab of the Webinterface | ||
| --> | ||
| {% set tab2title = "<strong>" ~ p.get_shortname() ~ " Geräte</strong> (" ~ device_count ~ ")" %} | ||
| {% block bodytab2 %} | ||
| {% endblock bodytab2 %} | ||
|
|
||
|
|
||
| <!-- | ||
| Content block for the third tab of the Webinterface | ||
| If wanted, a title for the tab can be defined as: | ||
| {% set tab3title = "<strong>" ~ p.get_shortname() ~ " Geräte</strong>" %} | ||
| It has to be defined before (and outside) the block bodytab3 | ||
| --> | ||
| {% block bodytab3 %} | ||
| {% endblock bodytab3 %} | ||
|
|
||
|
|
||
| <!-- | ||
| Content block for the fourth tab of the Webinterface | ||
| If wanted, a title for the tab can be defined as: | ||
| {% set tab4title = "<strong>" ~ p.get_shortname() ~ " Geräte</strong>" %} | ||
| It has to be defined before (and outside) the block bodytab4 | ||
| --> | ||
| {% block bodytab4 %} | ||
| {% endblock bodytab4 %} |