Skip to content

Commit

Permalink
vicare: Initial commit for new Viessmann plugin, communicating via Vi…
Browse files Browse the repository at this point in the history
…essmann API with backend.
  • Loading branch information
aschwith committed Dec 11, 2023
1 parent 7c6ffab commit d66346a
Show file tree
Hide file tree
Showing 8 changed files with 1,290 additions and 0 deletions.
757 changes: 757 additions & 0 deletions vicare/__init__.py

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions vicare/locale.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# translations for the web interface
plugin_translations:
# Translations for the plugin specially for the web interface
'Informationen': {'de': '=', 'en': 'Informations'}
'Einstellungen': {'de': '=', 'en': 'Settings'}

# Alternative format for translations of longer texts:
'Viessmann Explanation':
de: 'Schritt für Schritt Anleitung zur Verbindung des Plugins mit dem Vissmann Backend.'
en: 'Step by step manual for connecting the plugin with the Viessmann backend.'








120 changes: 120 additions & 0 deletions vicare/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Metadata for the plugin
plugin:
# Global plugin attributes
type: gateway # plugin type (gateway, interface, protocol, system, web)
description:
de: 'Plugin zur Anbindung an das Viessmann Backend an SmartHomeNG'
en: 'Plugin to connect the Viessmann backend with SmartHomeNG'
maintainer: aschwith
tester: 'n/a'
state: develop
keywords: Viessmann, ViCare, Vitocontrol
#documentation:
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1916122-support-thread-f%C3%BCr-das-viessmann-plugin

version: 1.9.0 # Plugin version
sh_minversion: 1.9.0 # minimum shNG version to use this plugin
# sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest)
multi_instance: False # plugin supports multi instance
restartable: True
classname: Vicare # class containing the plugin

parameters:

clientID:
type: str
mandatory: True
description:
de: "Client ID (via Viessmann Developper API Portal generiert)"
en: "Client id (generated via Viessmann developper api portal)"

redirectUrl:
type: str
mandatory: True
description:
de: "Redirect Url (via Viessmann Developper API Portal angelegt)"
en: "Redirect uri (defined via Viessmann Developper API Portal)"

accessToken:
type: str
gui_type: readonly
description:
de: "Token (beim Oauth2 Verfahren generiert)"
en: "Token (generated during the Oauth2 procedure)"

refreshToken:
type: str
gui_type: readonly
description:
de: "Refresh token (beim Oauth2 Verfahren generiert)"
en: "Refresh token (generated during the Oauth2 procedure)"



item_attributes:
# Definition of item attributes defined by this plugin (enter 'item_attributes: NONE', if section should be empty)
vicare_tx_key:
type: str
description:
de: 'Key für das Senden von Kommandos an das Viessmann Backend'
en: 'Key for sending commands to the Viessmann backend'
valid_list:
- 'heating.circuits.1.operating.programs.normal'
- 'heating.circuits.1.operating.programs.reduced'
- 'heating.dhw.temperature.main'
- 'heating.dhw.operating.modes.active'
- 'heating.circuits.1.operating.modes.active'

vicare_tx_path:
type: list
description:
de: 'Array mit Einträgen zum Pfad des Sendekommandos im Feature command'
en: 'Array of entries to find command in json response'

vicare_rx_key:
type: str
description:
de: 'Key für den Empfang von Statusinformationen aus dem Viessmann Backend'
en: 'Key for receiving status informations from the Viessmann backend'
valid_list:
- 'boilerSerial'
- 'heating.circuits.1.sensors.temperature.supply'
- 'heating.circuits.1.operating.programs.active'
- 'heating.circuits.1.operating.modes.heating'
- 'heating.circuits.1.operating.modes.active'
- 'heating.gas.consumption.total'
- 'heating.circuits.1.operating.programs.comfort'
- 'heating.circuits.1.operating.programs.normal'
- 'heating.circuits.1.operating.programs.reduced'
- 'heating.circuits.1.circulation.pump'
- 'heating.operating.programs.holiday'
- 'heating.dhw'
- 'heating.dhw.temperature.main'
- 'heating.dhw.oneTimeCharge'
- 'heating.dhw.operating.modes.active'
- 'heating.dhw.sensors.temperature.dhwCylinder'
- 'heating.dhw.sensors.temperature.hotWaterStorage'
- 'heating.boiler.sensors.temperature.commonSupply'
- 'heating.boiler.temperature'
- 'heating.sensors.temperature.outside'
- 'heating.power.consumption.summary.heating'
- 'heating.power.consumption.total'
- 'device.messages.errors.raw'

vicare_path:
type: list
description:
de: 'Array mit Pfad zur Eigenschaft in Feature property'
en: 'Array of entries to find property in json response'


plugin_functions: NONE

logic_parameters: NONE

item_structs: NONE





1 change: 1 addition & 0 deletions vicare/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
authlib
54 changes: 54 additions & 0 deletions vicare/user_doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.. index:: Plugins; vicare
.. index:: vicare

==========
vicare
==========

.. image:: webif/static/img/plugin_logo.png
:alt: plugin logo
:width: 300px
:height: 300px
:scale: 50 %
:align: left

Allgemein
=========

SmarthomeNG plugin mit Unterstützung für Viessmann Heizungen via vicare backend mit OAuth2 Identifizierung.

Konfiguration
=============

Die Informationen zur Konfiguration des Plugins sind unter :doc:`/plugins_doc/config/vicare` beschrieben.
Die Kopplung zwischen Plugin und Viessmann Backend erfolgt über das OAuth2 Verfahren. Das Webinterface führt Schritt für Schritt durch den Anmeldeprozess. Die Authentifizierung muss einmal via
Webinterface durchgeführt werden. Nach Abschluss erhält man einen access Token und einen refresh Token. Beide werden persistent in der plugin.yaml gespeichert. Mit Hilfe des refresh Tokens generiert
das Plugin bei jedem Neustart einen neuen accessToken. Der refresh Token ist 180 Tage gültig, d.g. die manuelle Authentifizierung muss alle 180 Tage einmal durchgeführt werden. Dies ist eine Vorgabe der Viessmann API.

Requirements
=============
- authlib

Supported Hardware
==================
z.B. Vitodens 200-W


Web Interface
=============


Aufruf des Webinterfaces
------------------------

Das Plugin kann aus dem Admin Interface aufgerufen werden. Dazu auf der Seite Plugins in der entsprechenden
Zeile das Icon in der Spalte **Web Interface** anklicken.

Außerdem kann das Webinterface direkt über ``http://smarthome.local:8383/vicare`` aufgerufen werden.


Beispiele
---------

Folgende Informationen können im Webinterface angezeigt werden:

136 changes: 136 additions & 0 deletions vicare/webif/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/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
import json

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, action=None, email=None, hashInput=None, code=None, tokenInput=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
"""

generateURLSuccessfull = None
tokenRequestCompleted = None

if action is not None:
if action == "generateURL":
self.logger.info("generate URL triggered via webinterface")
self.plugin.generate_code_verifier()
self.plugin.calculate_code_challenge(self.plugin.codeVerifier)
generateURLSuccessfull = self.plugin.generate_request_url()
elif action == "requestToken":
self.logger.info("Request token triggered via webinterface")
if (code is not None) and (not code == ''):
tokenRequestCompleted = self.plugin.retrieve_accessToken(code)
elif (code is None) or (code == ''):
self.logger.error("Token request not possible: Code missing in field above.")
tokenRequestCompleted = False
else:
self.logger.error("Token request not possible: Missing argument.")
tokenRequestCompleted = False
else:
self.logger.error("Unknown command received via webinterface")

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,
generateURLSuccessfull=generateURLSuccessfull,
tokenRequestCompleted=tokenRequestCompleted )


@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 dataSets are used, define them here
if dataSet == 'overview':
# get the new data from the plugin variable called _webdata
data = self.plugin._webdata
try:
data = json.dumps(data)
return data
except Exception as e:
self.logger.error(f"get_data_html exception: {e}")
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 {}
Binary file added vicare/webif/static/img/plugin_logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit d66346a

Please sign in to comment.