Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ omit =
homeassistant/components/vesync/const.py
homeassistant/components/vesync/switch.py
homeassistant/components/viaggiatreno/sensor.py
homeassistant/components/vicare/climate.py
Comment thread
oischinger marked this conversation as resolved.
Outdated
homeassistant/components/vizio/media_player.py
homeassistant/components/vlc/media_player.py
homeassistant/components/vlc_telnet/media_player.py
Expand Down
1 change: 1 addition & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ homeassistant/components/velbus/* @cereal2nd
homeassistant/components/velux/* @Julius2342
homeassistant/components/version/* @fabaff
homeassistant/components/vesync/* @markperdue @webdjoe
homeassistant/components/vicare/* @oischinger
homeassistant/components/vizio/* @raman325
homeassistant/components/vlc_telnet/* @rodripf
homeassistant/components/waqi/* @andrey-git
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/vicare/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""The ViCare integration."""
235 changes: 235 additions & 0 deletions homeassistant/components/vicare/climate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
"""Viessmann ViCare climate device."""
import logging

import voluptuous as vol
Comment thread
oischinger marked this conversation as resolved.
Outdated
from PyViCare.PyViCareDevice import Device


from homeassistant.components.climate import ClimateDevice
from homeassistant.components.climate.const import (
SUPPORT_PRESET_MODE,
SUPPORT_TARGET_TEMPERATURE,
PRESET_ECO,
PRESET_COMFORT,
HVAC_MODE_OFF,
HVAC_MODE_HEAT,
HVAC_MODE_AUTO,
)
from homeassistant.const import (
TEMP_CELSIUS,
ATTR_TEMPERATURE,
CONF_USERNAME,
CONF_PASSWORD,
CONF_NAME,
PRECISION_WHOLE,
)
import homeassistant.helpers.config_validation as cv
from homeassistant.components.sensor import PLATFORM_SCHEMA

_LOGGER = logging.getLogger(__name__)

REQUIREMENTS = ["PyViCare==0.1.0"]
Comment thread
oischinger marked this conversation as resolved.
Outdated

CONF_CIRCUIT = "circuit"

VICARE_MODE_DHW = "dhw"
VICARE_MODE_DHWANDHEATING = "dhwAndHeating"
VICARE_MODE_FORCEDREDUCED = "forcedReduced"
VICARE_MODE_FORCEDNORMAL = "forcedNormal"
VICARE_MODE_OFF = "standby"

VICARE_PROGRAM_ACTIVE = "active"
VICARE_PROGRAM_COMFORT = "comfort"
VICARE_PROGRAM_ECO = "eco"
VICARE_PROGRAM_EXTERNAL = "external"
VICARE_PROGRAM_HOLIDAY = "holiday"
VICARE_PROGRAM_NORMAL = "normal"
VICARE_PROGRAM_REDUCED = "reduced"
VICARE_PROGRAM_STANDBY = "standby"

VICARE_HOLD_MODE_AWAY = "away"
VICARE_HOLD_MODE_HOME = "home"
VICARE_HOLD_MODE_OFF = "off"

VICARE_TEMP_HEATING_MIN = 3
VICARE_TEMP_HEATING_MAX = 37

SUPPORT_FLAGS_HEATING = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE

VICARE_TO_HA_HVAC_HEATING = {
VICARE_MODE_DHW: HVAC_MODE_OFF,
VICARE_MODE_DHWANDHEATING: HVAC_MODE_AUTO,
VICARE_MODE_FORCEDREDUCED: HVAC_MODE_OFF,
VICARE_MODE_FORCEDNORMAL: HVAC_MODE_HEAT,
VICARE_MODE_OFF: HVAC_MODE_OFF,
}

HA_TO_VICARE_HVAC_HEATING = {
HVAC_MODE_HEAT: VICARE_MODE_FORCEDNORMAL,
HVAC_MODE_OFF: VICARE_MODE_FORCEDREDUCED,
HVAC_MODE_AUTO: VICARE_MODE_DHWANDHEATING,
}

VICARE_TO_HA_PRESET_HEATING = {
VICARE_PROGRAM_COMFORT: PRESET_COMFORT,
VICARE_PROGRAM_ECO: PRESET_ECO,
}

HA_TO_VICARE_PRESET_HEATING = {
PRESET_COMFORT: VICARE_PROGRAM_COMFORT,
PRESET_ECO: VICARE_PROGRAM_ECO,
}

VALUE_UNKNOWN = "unknown"

PYVICARE_ERROR = "error"


PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_USERNAME): cv.string,
vol.Required(CONF_PASSWORD): cv.string,
vol.Optional(CONF_CIRCUIT): int,
vol.Optional(CONF_NAME, default="ViCare"): cv.string,
}
)


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Create the ViCare climate devices."""
if config.get(CONF_CIRCUIT) is None:
Comment thread
oischinger marked this conversation as resolved.
Outdated
vicare_api = Device(
config[CONF_USERNAME], config[CONF_PASSWORD], "/tmp/vicare_token.save"
)
else:
vicare_api = Device(
config[CONF_USERNAME],
config[CONF_PASSWORD],
"/tmp/vicare_token.save",
config[CONF_CIRCUIT],
)
add_entities([ViCareClimate(f"{config[CONF_NAME]} Heating", vicare_api)])


class ViCareClimate(ClimateDevice):
"""Representation of the ViCare heating climate device."""

def __init__(self, name, api):
"""Initialize the climate device."""
self._name = name
self._state = None
self._api = api
self._target_temperature = None
self._current_mode = VALUE_UNKNOWN
Comment thread
oischinger marked this conversation as resolved.
Outdated
self._current_temperature = None
self._current_program = VALUE_UNKNOWN
Comment thread
oischinger marked this conversation as resolved.
Outdated

def update(self):
"""Let HA know there has been an update from the ViCare API."""
_room_temperature = self._api.getRoomTemperature()
if _room_temperature is not None and _room_temperature != "error":
self._current_temperature = _room_temperature
else:
self._current_temperature = self._api.getSupplyTemperature()
self._current_program = self._api.getActiveProgram()

# The getCurrentDesiredTemperature call can yield 'error' (str) when the system is in standby
desired_temperature = self._api.getCurrentDesiredTemperature()
if desired_temperature == PYVICARE_ERROR:
desired_temperature = None

self._target_temperature = desired_temperature

self._current_mode = self._api.getActiveMode()

@property
def supported_features(self):
"""Return the list of supported features."""
return SUPPORT_FLAGS_HEATING

@property
def name(self):
"""Return the name of the climate device."""
return self._name

@property
def temperature_unit(self):
"""Return the unit of measurement."""
return TEMP_CELSIUS

@property
def current_temperature(self):
"""Return the current temperature."""
return self._current_temperature

@property
def target_temperature(self):
"""Return the temperature we try to reach."""
return self._target_temperature

@property
def hvac_mode(self):
"""Return current hvac mode."""
return VICARE_TO_HA_HVAC_HEATING.get(self._current_mode)

def set_hvac_mode(self, hvac_mode):
"""Set a new hvac mode on the ViCare API."""
vicare_mode = HA_TO_VICARE_HVAC_HEATING.get(hvac_mode)
if vicare_mode is None:
_LOGGER.error(
f"cannot set invalid vicare mode: {hvac_mode} / {vicare_mode}"
)
else:
Comment thread
oischinger marked this conversation as resolved.
Outdated
_LOGGER.debug(f"setting hvac mode to {hvac_mode} / {vicare_mode}")
self._api.setMode(vicare_mode)

@property
def hvac_modes(self):
"""Return the list of available hvac modes."""
return list(HA_TO_VICARE_HVAC_HEATING)

@property
def min_temp(self):
"""Return the minimum temperature."""
return VICARE_TEMP_HEATING_MIN

@property
def max_temp(self):
"""Return the maximum temperature."""
return VICARE_TEMP_HEATING_MAX

@property
def precision(self):
"""Return the precision of the system."""
return PRECISION_WHOLE

def set_temperature(self, **kwargs):
"""Set new target temperatures."""
temp = kwargs.get(ATTR_TEMPERATURE)
if temp is not None:
self._target_temperature = temp
self._api.setProgramTemperature(
self._current_program, self._target_temperature
)

@property
def preset_mode(self):
"""Return the current preset mode, e.g., home, away, temp."""
return VICARE_TO_HA_PRESET_HEATING.get(self._current_program)

@property
def preset_modes(self):
"""Return the available preset mode."""
return list(VICARE_TO_HA_PRESET_HEATING)

def set_preset_mode(self, preset_mode):
"""Set new preset mode and deactivate any existing programs."""
vicare_program = HA_TO_VICARE_PRESET_HEATING.get(preset_mode)
if vicare_program is None:
_LOGGER.error(
f"cannot set invalid vicare program: {preset_mode} / {vicare_program}"
Comment thread
oischinger marked this conversation as resolved.
Outdated
)
else:
Comment thread
oischinger marked this conversation as resolved.
Outdated
_LOGGER.debug(f"setting preset to {preset_mode} / {vicare_program}")
Comment thread
oischinger marked this conversation as resolved.
Outdated
self._api.deactivateProgram(self._current_program)
self._api.activateProgram(vicare_program)
9 changes: 9 additions & 0 deletions homeassistant/components/vicare/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"domain": "vicare",
"name": "Viessmann ViCare",
"documentation": "https://www.home-assistant.io/components/vicare",
"dependencies": [],
"codeowners": ["@oischinger"],
"requirements": ["PyViCare==0.1.0"]
}

Loading