Module http

This module implements the possibility to write web interfaces for SmartHomeNG plugins.

API des Moduls

class modules.http.CherryPyFilter(name='')[Quellcode]

Bases: Filter

This class builds a filter to be used in logging.yaml to configure logging

Returning True tells logging to suppress this logentry, whereas False will include the record into further processing and eventual output

filter(record)[Quellcode]

Determine if the specified record is to be logged.

Returns True if the record should be logged, or False otherwise. If deemed appropriate, the record may be modified in-place.

class modules.http.Http(*args, **kargs)[Quellcode]

Bases: Module

version = '1.7.2'
webif_mount_prefix = '/plugin'
gtemplates_dir = ''
gstatic_dir = ''
init_template_environment()[Quellcode]

Initialize the Jinja2 template engine environment

Rückgabe:

Jinja2 template engine environment

Rückgabetyp:

object

is_staticfile(path)[Quellcode]

Method tests, if the given pathname points to an existing file in the webif’s static directory or the global static directory gstatic in the http module

This method extends the jinja2 template engine

Parameter:
  • path – path to test

  • type – str

Rückgabe:

True if the file exists

Rückgabetyp:

bool

is_port_in_use(port)[Quellcode]
get_user_dict()[Quellcode]

Returns the user(s) defined in ../etc/module.yaml (section http) as a dict

The information is a dict containing the hashed_password and a list of groups for each user

Rückgabe:

Information of defined users

Rückgabetyp:

dict

validate_password(realm, username, password)[Quellcode]

Validate a given user/password combination

Parameter:
  • realm

  • username

  • password

Rückgabe:

validate_service_password(realm, username, password)[Quellcode]
get_local_ip_address()[Quellcode]

Returns the local ip address under which the webinterface can be reached

Rückgabe:

ip address

Rückgabetyp:

str

get_local_hostname()[Quellcode]

Returns the local hostname under which the webinterface can be reached

Rückgabe:

fully qualified hostname

Rückgabetyp:

str

get_local_port()[Quellcode]

Returns the local port under which the webinterface can be reached

Rückgabe:

port number

Rückgabetyp:

int

get_local_servicesport()[Quellcode]

Returns the local port under which the webservices can be reached

Rückgabe:

port number

Rückgabetyp:

int

get_service_user()[Quellcode]

Returns the user with which the webservices can be reached

Rückgabe:

user

Rückgabetyp:

str

get_service_password()[Quellcode]

Returns the hashed password with which the webservices can be reached

Rückgabe:

hashed password

Rückgabetyp:

str

get_webifs_for_plugin(pluginname)[Quellcode]

Returns infos about the registered webinterfaces for a plugin (specified by shortname)

The information is returned as a list of dicts. One listentry for each registered webinterface. The dict for each registered webinterface has the following structure:

webif_dict = {‚Mount‘: mount,

‚Pluginclass‘: pluginclass, ‚Webifname‘: webifname, ‚Pluginname‘: pluginname, ‚Instance‘: instance, ‚Conf‘: conf, ‚Description‘: description}

Parameter:

pluginname (str) – Shortname of the plugin

Rückgabe:

Tnfos about the registered webinterfaces

Rückgabetyp:

list of dicts

get_services_for_plugin(pluginname)[Quellcode]

Returns infos about the registered webservices for a plugin (specified by shortname)

The information is returned as a list of dicts. One listentry for each registered webservice. The dict for each registered webinterface has the following structure:

service_dict = {‚mount‘: mount,

‚pluginclass‘: pluginclass, ‚servicename‘: servicename, ‚pluginname‘: pluginname, ‚instance‘: instance, ‚conf‘: conf, ‚description‘: description}

Parameter:

pluginname (str) – Shortname of the plugin

Rückgabe:

Tnfos about the registered webservices

Rückgabetyp:

list of dicts

register_webif(app, pluginname, conf, pluginclass='', instance='', description='', webifname='', use_global_basic_auth=True, useprefix=True)[Quellcode]

Register an application for CherryPy

This method is called by a plugin to register a webinterface

It should be called like this:

self.mod_http.register_webif(WebInterface( … ),

self.get_shortname(), config, self.get_classname(), self.get_instance_name(), description, webifname, use_global_basic_auth, useprefix)

Parameter:
  • app (object) – Instance of the application object

  • pluginname (str) – Mount point for the application

  • conf (dict) – Cherrypy application configuration dictionary

  • pluginclass (str) – Name of the plugin’s class

  • instance – Instance of the plugin (if multi-instance)

  • description (str) – Description of the functionallity of the webif. If left empty, a generic description will be generated

  • webifname (str) – Name of the webinterface. If left empty, the pluginname is used

  • use_global_basic_auth (bool) – if True, global basic_auth settings from the http module are used. If False, registering plugin provides its own basic_auth

  • useprefix (bool) – if False, no webif_mount_prefix is added to the turl

register_service(app, pluginname, conf, pluginclass='', instance='', description='', servicename='', use_global_basic_auth=True)[Quellcode]

Register a service for CherryPy

This method is called by a plugin to register a webservice.

It should be called like this:

self.mod_http.register_service(Webservice( … ),

self.get_shortname(), config, self.get_classname(), self.get_instance_name(), description, servicename, use_global_basic_auth)

Parameter:
  • app (object) – Instance of the service object

  • pluginname (str) – Mount point for the service

  • conf (dict) – Cherrypy application configuration dictionary

  • pluginclass (str) – Name of the plugin’s class

  • instance – Instance of the plugin (if multi-instance)

  • description (str) – Description of the functionallity of the webif. If left empty, a generic description will be generated

  • servicename (str) – Name of the service. I if left empty, the pluginname is used

  • use_global_basic_auth – if True, global basic_auth settings from the http module are used. If False, registering plugin provides its own basic_auth

Type:

use_global_basic_auth: bool

register_visu(pluginname, conf, visu_port=None, use_global_basic_auth=True)[Quellcode]

Register a service for CherryPy

This method is called by a plugin to register a webservice.

It should be called like this:

self.mod_http.register_visu(self.get_shortname(), config, use_global_basic_auth)

Parameter:
  • pluginname (str) – Mount point for the service

  • conf (dict) – Cherrypy application configuration dictionary

  • use_global_basic_auth – if True, global basic_auth settings from the http module are used. If False, registering plugin provides its own basic_auth

Type:

use_global_basic_auth: bool

start()[Quellcode]

If the module needs to startup threads or uses python modules that create threads, put thread creation code or the module startup code here.

Otherwise don’t enter code here

stop()[Quellcode]

If the module has started threads or uses python modules that created threads, put cleanup code here.

Otherwise don’t enter code here

log_server_info(server_nr)[Quellcode]

Log the information of a cherrypy server object

Rückgabe:

class modules.http.ModuleApp(mod, starturl)[Quellcode]

Bases: object

The module http implements it’s own webinterface. This WebApp implements the entrypoint for the webinterface of the module ‚http‘.

Depenting on the configuration of the ‚http‘ module, it redirects to the webinterface of a specified plugin or it redirects to a chooser which allows the start of the differnt webinterfaces of the plugins.

This webinterface is mounted to CherryPy as ‚/‘

index()[Quellcode]

This method is exposed to CherryPy. It implements the page ‚index.html‘

A formatted version of the http README.md can be found here:

A raw version of the README.md for copy and paste can be found below the metadata file.

The meta data file:

module.yaml
# Metadata for the plugin
module:
    # Global module attributes
    classname: Http
    version: 1.7.2
    sh_minversion: 1.5b
#   sh_maxversion:              # maximum shNG version to use this plugin (leave empty if latest)
    description:
        de: 'Modul zur Implementierung von Backend-Webinterfaces für Plugins'
        en: 'Module for implementing a backend-webinterface for plugins'
        fr: "Module pour l'implémentation d'interfaces web des extensions"

parameters:
    # Definition of parameters to be configured in etc/module.yaml
    connectionretries:
        type: int
        valid_min: 0
        valid_max: 100
        default: 5
        description:
            de: Maximale Anzahl an Verbindungsversuchen zum Start von smarthomeNG, um die lokale IP zu eruieren.
            en: Maximum number of connection retries to retrieve local IP address
            fr: Nombre maximum de tentatives de connexion pour récupérer l'adresse IP locale
    user:
        type: str
        default: 'admin'
        description:
            de: Benutzername für den Web Zugriff (Basic Auth), falls ein Passwort definiert ist
            en: username for the web access (basic auth), if a password is defined
            fr: Nom d'utilisateur pour l'accès web (Auth basique) si un mot de passe est défini
    password:
        type: str
        description:
            de: Passwort (im Klartext) für den Web Zugriff
            en: password (unencrypted) for the web access
            fr: Mot de passe (texte clair) pour l'accès web
    hashed_password:
        type: password
        description:
            de: hashed Version des Passworts für den Web Zugriff, ersetzt den Parameter 'password'
            en: hashed version of the password for the web access, supersedes the parameter 'password'
            fr: version haché du mot de passe pour l'interface web, remplace le paramètre 'password'

    service_user:
        type: str
        default: 'serviceuser'
        description:
            de: Benutzername für den Zugriff auf Webservices (Basic Auth), falls ein Passwort definiert ist
            en: username for the access to webervices (basic auth), if a password is defined
            fr: Nom d'utilisateur pour l'accès au service web (Auth basique) si un mot de passe est défini
    service_password:
        type: str
        description:
            de: Passwort (im Klartext) für den Zugriff auf Webservices
            en: password (unencrypted) for the access to webervices
            fr: Mot de passe (texte clair) pour l'accès aux services web
    service_hashed_password:
        type: password
        description:
            de: hashed Version des Passworts für den Zugriff auf Webservices, ersetzt den Parameter 'password'
            en: hashed version of the password for the access to webervices, supersedes the parameter 'password'
            fr: version haché du mot de passe pour l'accès au service web (Auth basique) si un mot de passe est défini
    ip:
        type: ipv4
        description:
            de: IP Adresse auf der das http Modul aktiv sein soll - muss normalerweise nicht angegeben werden
            en: IP adress on which the http module should operate - not needed, has only to be specified for special configurations
            fr: Adresse IP sur laquelle le module http devrait fonctionner - il n'est généralement pas nécessaire de la spécifier
    port:
        type: int
        valid_min: 0
        valid_max: 65535
        default: 8383
        description:
            de: Portnummer für die Webinterfaces bei Nutzung von http
            en: Port number for the access to web interfaces
            fr: Numéro de port pour l'accès à l'interface web
    tls_port:
        type: int
        valid_min: 0
        valid_max: 65535
        default: 8385
        description:
            de: Portnummer für die Webinterfaces bei Nutzung von https
            en: Port number for the access to webervices when using https
            fr: Numéro de port pour l'accès à l'interface web si utilisation de https
    use_tls:
        type: bool
        gui_type: yes_no
        default: False
        description:
            de: Auf True setzen, um Zugriffe über https:// zu ermöglichen (Zertifikat muss installiert sein)
            en: Set to true to allow access over https:// (certificate has to be installed)
            fr: Mettre sur 'true' pour activer les accès par https (certificats doivent être installés)
    tls_cert:
        type: str
        default: shng.cer
        description:
            de: Name der Zertifikatsdatei mit der Endung '.cer' oder '.pem'. Die Datei muss im Verzeichnis ../etc liegen
            en: Name of the certificate file. The file musst be stored in ../etc
            fr: Nom du fichier contanent les certificats. Le fichier doit se trouver dans ../etc
    tls_key:
        type: str
        default: shng.key
        description:
            de: Name der Datei mit dem privaten Schlüssel und der Endung '.key'. Die Datei muss im Verzeichnis ../etc liegen
            en: Name of the private key file. The file musst be stored in ../etc
            fr: Nom du fichier contanent les clés privés. Le fichier doit se trouver dans ../etc

    servicesport:
        type: int
        valid_min: 0
        valid_max: 65535
        default: 8384
        description:
            de: Portnummer für die Webservices
            en: Port number for the access to webervices
            fr: Numéro de port pour les services web

    showpluginlist:
        type: bool
        gui_type: yes_no
        default: True
        description:
            de: Anzeige einer Liste der Plugins mit Webinterfaces unter der url /plugins
            en: Show a list of plugins with web interfaces under the url /plugins
            fr: Afficher une listes des extensions avec interface web sous l'url /plugins

    showservicelist:
        type: bool
        gui_type: yes_no
        default: False
        description:
            de: Anzeige einer Liste der Plugins mit Webservices unter der url /services
            en: Show a list of plugins with webservices under the url /services
            fr: Afficher une listes des extensions avec des services web sous l'url /services

    starturl:
        type: str
        default: admin
        description:
            de: Weiterleitungs-Url, wenn SmartHomeNG im Browser nur mit <DNS-Name>:<Portnummer> aufgerufen wird.
            en: Redirection-url, if SmartHomeNG is called in the browser only by <dns-name>:<portnumber>
            fr: Url de redirection si SmartHomeNG est chargé par le navigateur en utilisant seulement <nom-dns>:<numéro de port>.

    threads:
        type: int
        default: 4
        description:
            de: Anzahl Threads, die für jede CherryPy App eingerichtet wird
            en: number of threads setup per CherryPy app
            fr: numéro de tâches prévus par application CherryPy
        valid_list:
          - 2
          - 3
          - 4
          - 5
          - 6
          - 7
          - 8

    showtraceback:
        type: bool
        gui_type: yes_no
        default: False
        description:
            de: Traceback bei Python Exceptions in der Fehlermeldung im Browser anzeigen. (Sollte in Produktionsinstallationen False sein)
            en: Show traceback of Python exceptions on the error page displayed in the browser. (Should be False in production environment)
            fr: Montrer les traces des exepctions Python sur la page d'erreurs affiché dans le navigateur. (Normallement 'False' dans en environnement de production)

    webif_pagelength:
        type: int
        default: 0
        valid_list:
          - -1
          - 0
          - 25
          - 50
          - 100
        description:
            de: 'Anzahl an Tabellen-Zeilen, die standardmäßig in einer Web Interface Tabelle pro Seite angezeigt werden.
                 0 = automatisch (so viele in das Browser-Fenster passen) , -1 = alle
                 (Wirkt sich nur auf Web Interfaces mit sortierbaren Tabellen aus)'
            en: 'Amount of table lines being listed in a web interface table per page by default.
                 0 = automatic (as many as can be fitted into the browser window), -1 = all
                 (Only affects web interfaces with sortable tables)'
        description_long:
            de: 'Anzahl an Tabellen-Zeilen, die standardmäßig in einer Web Interface Tabelle pro Seite angezeigt werden.\n
                 Bei 0 wird die Tabelle automatisch an die Höhe des Browserfensters angepasst.\n
                 Bei -1 werden alle Tabelleneinträge auf einer Seite angezeigt.'
            en: 'Amount of table lines being listed in a web interface table per page by default.\n
                 0 adjusts the table height automatically based on the height of the browser windows.\n

                 -1 shows all table entries on one page.'
README.md
# Module http (README)

This module allows plugins to implement a web interface. The API is described below. The first plugin to utilize this API is the backend plugin.

> Note: To write a plugin that utilizes this module, you have to be familiar with CherryPy.


## Requirements

This module is running under SmartHomeNG versions beyond v1.3. It requires Python >= 3.4 as well as the lib **cherrypy**. You can install the libraries (python modules) with:

```
(sudo apt-get install python-cherrypy)
sudo pip3 install cherrypy
```

And please pay attention that the lib(s) are installed for Python3 and not an older Python 2.7 that is probably installed on your system. Be careful to use `pip3` and not `pip`.

> Note: This module needs the module handling in SmartHomeNG to be activated. Make sure, that `use_modules`in `etc/smarthome.yaml` is **not** set to False!


## Configuration

### etc/module.yaml


```yaml
# etc/module.yaml
http:
    module_name: http
#    port: 8383
#    servicesport: 8384
#    showpluginlist: False
    showservicelist: True
#    starturl: backend
#    threads: 8
#    showtraceback: True
#    webif_pagelength: 0
```

#### user (optional)

username for the web access. By default username `admin` is used.

#### password (optional)

password for the web access. By default empty. Without a password access is available for everyone.

#### hashed_password (optional)

hashed password for the web access. By default empty. Without a hashed password the parameter password is used.

#### service_user (optional

username for the access to webervices. By default username `serviceuser` is used.

#### service_password (optional)

password for the access to the web services. By default empty. Without a password access is available for everyone.

#### service_hashed_password (optional)

hashed password for access to the web services. By default empty. Without a hashed password the parameter Service_password is used.

#### port (optional)
The port on which the html interface listens. By default port **`8383`** is used.

#### servicesport (optional)
The port on which the html interface listens. By default port **`8384`** is used.

#### showpluginlist
If set to `False` no list of pluins with web interface is shown under `smarthomeNG.local:8383/plugins`. By default, **showpluginlist** is **True**.

#### showservicelist
If set to `True` a list of webservices is shown under `smarthomeNG.local:8384/services`. By default, ** showservicelist** is **False**.

#### starturl (optional)
The name of the plugin that is started when calling url `smarthomeNG.local:8383` without further detailing that url. If you want to startup the **backend** plugin for example: You set `starturl: backend`. That results in a redirect which redirects `smarthomeNG.local:8383` to `smarthomeNG.local:8383/backend`.

if `starturl` is not specified or point to an url that does not exist, a redirect to `smarthomeNG.local:8383/plugins` will take place (if ** showpluginlist** is **True**). It points to a page that lists all plugins that have registered a html interface and allows you to start those interfaces.

> Note: If you have redirected to a specific plugin, you can always get to the page with the list of all plugins that have registered a html interface, by entering the url `smarthomeNG.local:8383/plugins`.

####  threads (optional)
Number of worker threads to start by cherrypy (default 8, which may be too much for slow CPUs)

#### showtraceback
If set to **True, error-pages (except for error 404) will show the Python traceback for that error.

#### webif_pagelength
Amount of items being listed in a web interface table per page by default.
0 adjusts the table height automatically based on the height of the browser windows.
-1 shows all table entries on one page.

## API of module http

### Test if module http is loaded

`http` is a loadlable module. Therefore there is no guarantiee that it is present in every system. Before you can use this module, you have to make sure ist is loaded. You can do it by calling a method of the main smarthome object. Do it like this:

```
self.classname = self.__class__.__name__

try:
    self.mod_http = self._sh.get_module('http')
except:
    self.mod_http = None

if self.mod_http == None:
    # Do what is necessary if you can't start a web interface
    # for your plugin. For example:
    self.logger.error('{}: Module ''http'' not loaded - Abort loading of plugin {0}'.format(self.classname))
    return
```

### Registering a web application/interface

For registering a web interface (or a web application in CherryPy terminology) you first have to define an application configuration for cherrypy.

> Note: Be careful not to include a CherryPy ``global`` configuration.

An application configuration for CherryPy can look like this;

```
app_config = {
    '/': {
        'tools.staticdir.root': current_dir,
        'tools.auth_basic.on': self._basic_auth,
        'tools.auth_basic.realm': 'earth',
        'tools.auth_basic.checkpassword': self.validate_password,
    },
    '/static': {
        'tools.staticdir.on': True,
        'tools.staticdir.dir': os.path.join(current_dir, 'static')
    }
}
```

> Note: The `tools.auth_basic`entries in this example are for implementing a basic logon security. If you don`t want/need login security, delete those enties.

For registering a web application/interface you have to call the `register_app` of module `http`:

```
register_app(app_object,
             appname,
             app_config,
             pluginclass, instance,
             description)
```

For example:

```
appname = 'backend'    # Name of the plugin
pluginclass = self.__class__.__name__
instance = self.get_instance_name()

self.mod_http.register_app(Backend(self, self.updates_allowed, language, self.developer_mode, self.pypi_timeout),
                          appname,
                          app_config,
                          pluginclass, instance,
                          description='Administration interface for SmartHomeNG')
```

## Implementing a web interface for you plugin

For details about implementing a web interface (CherryPy application) for your plugin, refer to the CherryPy documentation.

The documentation will tell you how to expose parts of your python code to be availabe through CheryPy`s http-server.

### Methods for implementing a web interface

#### get_local_ip_address()
Returns the ip address under which the web interface is listening.

#### get_local_hostname()
Returns the hostname (with domain) under which the web interface is listening.

#### get_local_port()
Returns the port under which the implemented web interfaces can be reached.

#### get_local_servicesport( ... )
Returns the port under which the implemented webservices can be reached.

#### register_app()

##### Parameters
- **app**	- Instance of the CherryPy App
- **pluginname**  - Standard would be: Shortname of the plugin (name of the plugin's directory)
- **conf**  - dict with CherryPy App-Config
- **pluginclass**  - Class of the plugin
- **instance**   - Optional: Instance of the plugin (if multi-instance)
- **description**  - Optional: Description to be shown on page with plugin-list

#### register_service( ... )

##### Parameters
- **service**	- Instance of the CherryPy App
- **servicename**  - Standard would be: Shortname of the plugin (name of the plugin's directory)
- **conf**  - dict with CherryPy App-Config
- **pluginclass**  - Class of the plugin
- **instance**   - Optional: Instance of the plugin (if multi-instance)
- **description**  - Optional: Description to be shown on page with services-list