def __init__(self, hass, config): from aionefit import NefitCore """Initialize the thermostat.""" name = config.get(CONF_NAME) serial = config.get(CONF_SERIAL) accesskey = config.get(CONF_ACCESSKEY) password = config.get(CONF_PASSWORD) self.config = config self.hass = hass self._name = name self.error_state = "initializing" self._online = False self._unit_of_measurement = TEMP_CELSIUS self._uistatus = None self._attributes = {} self._stateattr = {} self._data = {} self._hvac_modes = [HVAC_MODE_HEAT] self._url_events = { '/ecus/rrc/uiStatus': asyncio.Event(), '/heatingCircuits/hc1/actualSupplyTemperature': asyncio.Event(), '/system/sensors/temperatures/outdoor_t1': asyncio.Event(), '/system/appliance/systemPressure': asyncio.Event(), '/ecus/rrc/recordings/yearTotal': asyncio.Event() } self._client = NefitCore(serial_number=serial, access_key=accesskey, password=password, message_callback=self.parse_message) self._client.failed_auth_handler = self.failed_auth_handler self._client.no_content_callback = self.no_content_callback
def __init__(self, hass, credentials): from aionefit import NefitCore _LOGGER.debug("Initialize Nefit class") self.data = {} self.ids = {} self.hass = hass self.error_state = "initializing" self.events = {'/ecus/rrc/uiStatus': asyncio.Event()} self.nefit = NefitCore(serial_number=credentials.get(CONF_SERIAL), access_key=credentials.get(CONF_ACCESSKEY), password=credentials.get(CONF_PASSWORD), message_callback=self.parse_message) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback
def __init__(self, hass, credentials): from aionefit import NefitCore _LOGGER.debug("Initialize Nefit class") self.data = {} #stores device states and values self.keys = {} #unique name for entity self.events = {} self.uiStatusVars = {} #variables to monitor for sensors self.hass = hass self.connected_state = STATE_INIT self.nefit = NefitCore(serial_number=credentials.get(CONF_SERIAL), access_key=credentials.get(CONF_ACCESSKEY), password=credentials.get(CONF_PASSWORD), message_callback=self.parse_message) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback
async def main(loop): def parse_recursive(msg): if 'type' in msg and msg['type'] == 'refEnum': for reference in msg['references']: client.get(reference['id']) else: pprint(msg) async def parse_message(msg): pprint(msg) client = NefitCore(serial_number=SERIAL_NUMBER, access_key=ACCESS_KEY, password=PASSWORD, message_callback=parse_message) await client.connect() loop.nefitclient = client await client.xmppclient.connected_event.wait() client.get('/ecus/rrc/uiStatus')
async def nefit_connect(self): if self.first_run: self._nefit_client = NefitCore( self._serial_number, self._attr_access_key, self._attr_password, message_callback=self.received_message, ) self._nefit_client.failed_auth_handler = self.failed_auth_handler self._nefit_client.no_content_callback = self.no_content_callback self._nefit_client.session_end_callback = self.session_end_callback await self._nefit_client.connect() await self._nefit_client.xmppclient.connected_event.wait() await fhem.readingsSingleUpdateIfChanged(self.hash, "state", "connected", 1) if self.first_run: self.create_async_task(self.update_loop()) self.first_run = False
def __init__(self, hass, config): """Initialize nefit easy component.""" _LOGGER.debug("Initialize Nefit class") self._data = {} # stores device states and values self._event = asyncio.Event() self._lock = asyncio.Lock() self.hass = hass self.connected_state = STATE_INIT self.expected_end = False self.is_connecting = False self.serial = config[CONF_SERIAL] self._config = config self._request = None self.nefit = NefitCore( serial_number=config[CONF_SERIAL], access_key=config[CONF_ACCESSKEY], password=config[CONF_PASSWORD], message_callback=self.parse_message, ) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback self.nefit.session_end_callback = self.session_end_callback self._urls = {} self._status_keys = {} update_interval = timedelta(seconds=60) super().__init__( hass, _LOGGER, name=DOMAIN, update_interval=update_interval, )
def __init__(self, hass, credentials): """Initialize nefit easy component.""" _LOGGER.debug("Initialize Nefit class") self.data = {} # stores device states and values self.keys = {} # unique name for entity self.events = {} self.ui_status_vars = {} # variables to monitor for sensors self.hass = hass self.connected_state = STATE_INIT self.expected_end = False self.is_connecting = False self.serial = credentials.get(CONF_SERIAL) self.nefit = NefitCore( serial_number=credentials.get(CONF_SERIAL), access_key=credentials.get(CONF_ACCESSKEY), password=credentials.get(CONF_PASSWORD), message_callback=self.parse_message, ) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback self.nefit.session_end_callback = self.session_end_callback
class NefitEasy: def __init__(self, hass, credentials): from aionefit import NefitCore _LOGGER.debug("Initialize Nefit class") self.data = {} self.ids = {} self.hass = hass self.error_state = "initializing" self.events = {'/ecus/rrc/uiStatus': asyncio.Event()} self.nefit = NefitCore(serial_number=credentials.get(CONF_SERIAL), access_key=credentials.get(CONF_ACCESSKEY), password=credentials.get(CONF_PASSWORD), message_callback=self.parse_message) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback async def connect(self): self.nefit.connect() _LOGGER.debug("Waiting for connected event") try: # await self.nefit.xmppclient.connected_event.wait() await asyncio.wait_for( self.nefit.xmppclient.connected_event.wait(), timeout=15.0) _LOGGER.debug("adding stop listener") self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.shutdown) except concurrent.futures._base.TimeoutError: _LOGGER.debug("TimeoutError on waiting for connected event") self.hass.components.persistent_notification.create( 'Timeout while connecting to Bosch cloud. Retrying in the background', title='Nefit error', notification_id='nefit_logon_error') raise PlatformNotReady if self.error_state == "authentication_failed": self.hass.components.persistent_notification.create( 'Invalid credentials while connecting to Bosch cloud.', title='Nefit error', notification_id='nefit_logon_error') raise PlatformNotReady def shutdown(self, event): _LOGGER.debug("Shutdown connection to Bosch cloud") self.nefit.disconnect() def no_content_callback(self, data): _LOGGER.debug("no_content_callback: %s", data) def failed_auth_handler(self, event): self.error_state = "authentication_failed" self.nefit.xmppclient.connected_event.set() def parse_message(self, data): """Message received callback function for the XMPP client. """ _LOGGER.debug("parse_message callback called with data %s", data) if not 'id' in data: _LOGGER.error("Unknown response received: %s", data) return if data['id'] == '/ecus/rrc/uiStatus': self.data['uistatus'] = data['value'] self.data['temp_setpoint'] = float( data['value']['TSP']) #for climate self.data['inhouse_temperature'] = float( data['value']['IHT']) #for climate self.data['user_mode'] = data['value']['UMD'] #for climate self.data['boiler_indicator'] = data['value']['BAI'] #for climate self.data['last_update'] = data['value']['CTD'] elif data['id'] == '/dhwCircuits/dhwA/dhwOperationClockMode' or data[ 'id'] == '/dhwCircuits/dhwA/dhwOperationManualMode': self.data['hot_water'] = data['value'] self.events['hot_water'].set() if data['id'] in self.events: if data['id'] in self.ids: self.data[self.ids[data['id']]] = data['value'] # Mark event as finished self.events[data['id']].set()
class nefit(generic.FhemModule): URL_RRC_UISTATUS = "/ecus/rrc/uiStatus" URL_REC_GASUSAGEPOINTER = "/ecus/rrc/recordings/gasusagePointer" URL_REC_GASUSAGE = "/ecus/rrc/recordings/gasusage" URL_REC_YEARTOTAL = "/ecus/rrc/recordings/yearTotal" URL_OUTDOOR_TEMP = "/system/sensors/temperatures/outdoor_t1" URL_DAY_STARTSWITH = "/ecus/rrc/dayassunday/day" URL_DAY_ACTIVE = "/ecus/rrc/dayassunday/day%DAY%/active" URL_DAY_MODE = "/ecus/rrc/dayassunday/day%DAY%/mode" URL_DAY_DATE = "/ecus/rrc/dayassunday/day%DAY%/date" URL_SYSTEM_PRESSURE = "/system/appliance/systemPressure" def __init__(self, logger): super().__init__(logger) self.first_run = True self.module_shutdown = False attr_config = { "interval": { "default": 900, "format": "int", "help": "Change interval, default is 900.", }, "password": { "default": "" }, "access_key": { "default": "" }, } self.set_attr_config(attr_config) set_config = { "mode": { "args": ["mode"], "argsh": ["mode"], "params": { "mode": { "default": "clock", "optional": False } }, "options": "clock,manual", }, "desiredTemp": { "args": ["temperature"], "params": { "temperature": { "format": "float" } }, "options": "slider,10,0.5,30,1", }, "dayAsSunday_00_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "0", }, "dayAsSunday_01_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "1", }, "dayAsSunday_02_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "2", }, "dayAsSunday_03_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "3", }, "dayAsSunday_04_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "4", }, "dayAsSunday_05_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "5", }, "dayAsSunday_06_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "6", }, "dayAsSunday_12_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "12", }, "dayAsSunday_07_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "7", }, "dayAsSunday_08_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "8", }, "dayAsSunday_09_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "9", }, "dayAsSunday_10_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "10", }, "dayAsSunday_11_active": { "args": ["onoff"], "options": "on,off", "function": "set_dayassunday_activate", "function_param": "11", }, "dayAsSunday_07_date": { "args": ["dateval"], "function": "set_dayassunday_date", "function_param": "7", }, "dayAsSunday_08_date": { "args": ["dateval"], "function": "set_dayassunday_date", "function_param": "8", }, "dayAsSunday_09_date": { "args": ["dateval"], "function": "set_dayassunday_date", "function_param": "9", }, "dayAsSunday_10_date": { "args": ["dateval"], "function": "set_dayassunday_date", "function_param": "10", }, "dayAsSunday_11_date": { "args": ["dateval"], "function": "set_dayassunday_date", "function_param": "11", }, "todayAsSunday": { "args": ["onoff"], "options": "on,off" }, "tomorrowAsSunday": { "args": ["onoff"], "options": "on,off" }, } self.set_set_config(set_config) # FHEM FUNCTION async def Define(self, hash, args, argsh): await super().Define(hash, args, argsh) if len(args) != 4: return "Usage: define netfit_thermostat fhempy nefit <SERIAL_NUMBER>" self._serial_number = args[3] hash["SERIAL_NUMBER"] = self._serial_number if self._attr_access_key == "" or self._attr_password == "": await fhem.readingsBeginUpdate(hash) await fhem.readingsBulkUpdateIfChanged( hash, "state", "set access_key and password attribute") await fhem.readingsEndUpdate(hash, 1) else: await fhem.readingsSingleUpdateIfChanged(hash, "state", "connecting", 1) self.create_async_task(self.nefit_connect()) async def set_attr_password(self, hash): if self._attr_password != "" and self._attr_access_key != "": self.create_async_task(self.nefit_connect()) async def set_attr_access_key(self, hash): if self._attr_password != "" and self._attr_access_key != "": self.create_async_task(self.nefit_connect()) async def set_dayassunday_activate(self, hash, params): day = params["function_param"] onoff = params["onoff"] self._nefit_client.put_value( nefit.URL_DAY_ACTIVE.replace("%DAY%", day), onoff) await self.update_dayassunday(day) async def set_dayassunday_date(self, hash, params): day = params["function_param"] dateval = params["dateval"] self._nefit_client.put_value(nefit.URL_DAY_DATE.replace("%DAY%", day), dateval) await self.update_dayassunday(day) async def set_desiredTemp(self, hash, params): self._nefit_client.set_temperature(params["temperature"]) self._nefit_client.get(nefit.URL_RRC_UISTATUS) async def set_mode(self, hash, params): self._nefit_client.set_usermode(params["mode"]) self._nefit_client.get(nefit.URL_RRC_UISTATUS) async def set_todayAsSunday(self, hash, params): # call set_dayassunday_activate await self.set_dayassunday_activate(hash, { "onoff": params["onoff"], "function_param": "11" }) if params["onoff"] == "on": # call set_dayssunday_date today = datetime.date.today() await self.set_dayassunday_date( hash, { "dateval": f"{today.month:02d}-{today.day:02d}", "function_param": "11", }, ) async def set_tomorrowAsSunday(self, hash, params): # call set_dayassunday_activate await self.set_dayassunday_activate(hash, { "onoff": params["onoff"], "function_param": "10" }) if params["onoff"] == "on": # call set_dayssunday_date tomorrow = datetime.date.today() + datetime.timedelta(days=1) await self.set_dayassunday_date( hash, { "dateval": f"{tomorrow.month:02d}-{tomorrow.day:02d}", "function_param": "10", }, ) async def received_message(self, msg): try: if msg["id"] == nefit.URL_RRC_UISTATUS: await self.handle_uistatus(msg) elif msg["id"] == nefit.URL_REC_GASUSAGEPOINTER: await self.handle_gasusagepointer(msg) elif msg["id"] == nefit.URL_REC_GASUSAGE: await self.handle_gasusage(msg) elif msg["id"] == nefit.URL_REC_YEARTOTAL: await self.handle_yeartotal(msg) elif msg["id"] == nefit.URL_OUTDOOR_TEMP: await self.handle_outdoortemp(msg) elif msg["id"] == nefit.URL_SYSTEM_PRESSURE: await self.handle_systempressure(msg) elif msg["id"].startswith(nefit.URL_DAY_STARTSWITH): await self.handle_dayassunday(msg) except Exception: self.logger.exception(f"Failed to handle msg: {msg}") async def handle_systempressure(self, msg): if msg["value"] <= msg["maxValue"] and msg["value"] >= msg["minValue"]: await fhem.readingsSingleUpdateIfChanged(self.hash, "system_pressure", float(msg["value"]) / 10, 1) async def handle_dayassunday(self, msg): day = int(re.findall(r"\d+", msg["id"])[0]) val_type = re.findall(r"/(\w+)$", msg["id"])[0] await fhem.readingsSingleUpdateIfChanged( self.hash, f"dayassunday_{day:02d}_{val_type}", msg["value"], 1) async def handle_outdoortemp(self, msg): await fhem.readingsSingleUpdateIfChanged(self.hash, "outdoor_temperature", msg["value"], 1) async def handle_yeartotal(self, msg): await fhem.readingsSingleUpdateIfChanged(self.hash, "year_total_kwh", msg["value"], 1) async def handle_gasusage(self, msg): entry = msg["value"][self._gasusage_page_entry] yesterday = datetime.date.today() - datetime.timedelta(days=1) if entry[ "d"] == f"{yesterday.day:02d}-{yesterday.month:02d}-{yesterday.year}": await fhem.readingsSingleUpdateIfChanged( self.hash, "yesterday_consumption_ch", entry["ch"], 1) await fhem.readingsSingleUpdateIfChanged( self.hash, "yesterday_consumption_hw", entry["hw"], 1) await fhem.readingsSingleUpdateIfChanged(self.hash, "yesterday_temperature", entry["T"] / 10, 1) async def handle_gasusagepointer(self, msg): if msg["value"] < 2: # no entry in history yet return self._gasusage_page = math.ceil((msg["value"] - 2) / 32) self._gasusage_page_entry = (msg["value"] - 2) % 32 self._nefit_client.get(nefit.URL_REC_GASUSAGE + "?page=" + str(self._gasusage_page)) async def handle_uistatus(self, msg): await fhem.readingsBeginUpdate(self.hash) try: await fhem.readingsBulkUpdateIfChanged(self.hash, "ars", msg["value"]["ARS"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "boiler_heating", msg["value"]["BAI"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "boiler_block", msg["value"]["BBE"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "boiler_lock", msg["value"]["BLE"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "boiler_maintainance", msg["value"]["BMR"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "clock_program", msg["value"]["CPM"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "current_switchpoint", msg["value"]["CSP"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "current_time_date", msg["value"]["CTD"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "control", msg["value"]["CTR"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "todayAsSunday", msg["value"]["DAS"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "hot_water", msg["value"]["DHW"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "dot", msg["value"]["DOT"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "esi", msg["value"]["ESI"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "temp_in_fahrenheit", msg["value"]["FAH"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "fireplace_mode", msg["value"]["FPA"]) await fhem.readingsBulkUpdateIfChanged( self.hash, "presence_detection_status_device", msg["value"]["HED_DB"]) await fhem.readingsBulkUpdateIfChanged( self.hash, "presence_detection_device", msg["value"]["HED_DEV"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "presence_detection", msg["value"]["HED_EN"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "holiday_mode", msg["value"]["HMD"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "inhouse_status", msg["value"]["IHS"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "temperature", msg["value"]["IHT"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "manual_mode_temperature", msg["value"]["MMT"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "pmr", msg["value"]["PMR"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "rs", msg["value"]["RS"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "tomorrowAsSunday", msg["value"]["TAS"]) await fhem.readingsBulkUpdateIfChanged( self.hash, "temperature_override_duration", msg["value"]["TOD"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "temperature_override", msg["value"]["TOR"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "temperature_override", msg["value"]["TOT"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "desiredTemp", msg["value"]["TSP"]) await fhem.readingsBulkUpdateIfChanged(self.hash, "mode", msg["value"]["UMD"]) except Exception: self.logger.exception("Failed to handle uiStatus") await fhem.readingsEndUpdate(self.hash, 1) async def nefit_connect(self): if self.first_run: self._nefit_client = NefitCore( self._serial_number, self._attr_access_key, self._attr_password, message_callback=self.received_message, ) self._nefit_client.failed_auth_handler = self.failed_auth_handler self._nefit_client.no_content_callback = self.no_content_callback self._nefit_client.session_end_callback = self.session_end_callback await self._nefit_client.connect() await self._nefit_client.xmppclient.connected_event.wait() await fhem.readingsSingleUpdateIfChanged(self.hash, "state", "connected", 1) if self.first_run: self.create_async_task(self.update_loop()) self.first_run = False async def failed_auth_handler(self, event): pass async def no_content_callback(self, data): pass async def session_end_callback(self): await fhem.readingsSingleUpdateIfChanged(self.hash, "state", "disconnected", 1) if not self.module_shutdown: await asyncio.sleep(10) await self.nefit_connect() async def update_loop(self): while True: try: self._nefit_client.get(nefit.URL_RRC_UISTATUS) self._nefit_client.get(nefit.URL_REC_YEARTOTAL) self._nefit_client.get(nefit.URL_OUTDOOR_TEMP) self._nefit_client.get(nefit.URL_SYSTEM_PRESSURE) await self.update_dayassunday() await self.update_gasusage() except Exception: self.logger.exception("Failed to update readings") await asyncio.sleep(self._attr_interval) async def update_dayassunday(self, day=None): if day is None: for day in range(13): self._nefit_client.get( nefit.URL_DAY_ACTIVE.replace("%DAY%", str(day))) self._nefit_client.get( nefit.URL_DAY_DATE.replace("%DAY%", str(day))) self._nefit_client.get( nefit.URL_DAY_MODE.replace("%DAY%", str(day))) else: self._nefit_client.get( nefit.URL_DAY_ACTIVE.replace("%DAY%", str(day))) self._nefit_client.get( nefit.URL_DAY_DATE.replace("%DAY%", str(day))) self._nefit_client.get( nefit.URL_DAY_MODE.replace("%DAY%", str(day))) async def update_gasusage(self): self._nefit_client.get(nefit.URL_REC_GASUSAGEPOINTER) async def Undefine(self, hash): await super().Undefine(hash) self.module_shutdown = True
class NefitThermostat(ClimateDevice): """Representation of a NefitThermostat device.""" def __init__(self, hass, config): from aionefit import NefitCore """Initialize the thermostat.""" name = config.get(CONF_NAME) serial = config.get(CONF_SERIAL) accesskey = config.get(CONF_ACCESSKEY) password = config.get(CONF_PASSWORD) self.config = config self.hass = hass self._name = name self.error_state = "initializing" self._online = False self._unit_of_measurement = TEMP_CELSIUS self._uistatus = None self._attributes = {} self._stateattr = {} self._data = {} self._hvac_modes = [HVAC_MODE_HEAT] self._url_events = { '/ecus/rrc/uiStatus': asyncio.Event(), '/heatingCircuits/hc1/actualSupplyTemperature': asyncio.Event(), '/system/sensors/temperatures/outdoor_t1': asyncio.Event(), '/system/appliance/systemPressure': asyncio.Event(), '/ecus/rrc/recordings/yearTotal': asyncio.Event() } self._client = NefitCore(serial_number=serial, access_key=accesskey, password=password, message_callback=self.parse_message) self._client.failed_auth_handler = self.failed_auth_handler self._client.no_content_callback = self.no_content_callback async def connect(self): self._client.connect() _LOGGER.debug("Waiting for connected event") try: # await self._client.xmppclient.connected_event.wait() await asyncio.wait_for(self._client.xmppclient.connected_event.wait(), timeout=10.0) _LOGGER.debug("adding stop listener") self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self._shutdown) except concurrent.futures._base.TimeoutError: _LOGGER.debug("TimeoutError on waiting for connected event") self.hass.components.persistent_notification.create( 'Timeout while connecting to Bosch cloud. Retrying in the background', title='Nefit error', notification_id='nefit_logon_error') raise PlatformNotReady if self.error_state == "authentication_failed": self.hass.components.persistent_notification.create( 'Invalid credentials while connecting to Bosch cloud.', title='Nefit error', notification_id='nefit_logon_error') raise PlatformNotReady def no_content_callback(self, data): _LOGGER.debug("no_content_callback: %s", data) def failed_auth_handler(self, event): self.error_state = "authentication_failed" self._client.xmppclient.connected_event.set() @property def supported_features(self): """Return the list of supported features. """ return SUPPORT_FLAGS @property def target_temperature_step(self): return 0.5 def parse_message(self, data): """Message received callback function for the XMPP client. """ _LOGGER.debug("parse_message callback called with data %s", data) if not 'id' in data: _LOGGER.error("Unknown response received: %s", data) return if data['id'] == '/ecus/rrc/uiStatus': self._uistatus = data['value'] self._data['temp_setpoint'] = float(data['value']['TSP']) self._data['inhouse_temperature'] = float(data['value']['IHT']) self._data['user_mode'] = data['value']['UMD'] self._stateattr['boiler_indicator'] = data['value']['BAI'] self._stateattr['current_time'] = data['value']['CTD'] elif data['id'] == '/heatingCircuits/hc1/actualSupplyTemperature': self._stateattr['supply_temperature'] = data['value'] elif data['id'] == '/system/sensors/temperatures/outdoor_t1': self._stateattr['outdoor_temperature'] = data['value'] elif data['id'] == '/system/appliance/systemPressure': self._stateattr['system_pressure'] = data['value'] elif data['id'] == '/ecus/rrc/recordings/yearTotal': self._stateattr['year_total'] = data['value'] if data['id'] in self._url_events: self._url_events[data['id']].set() async def async_update(self): """Get latest data """ _LOGGER.debug("async_update called") tasks = [] for url in self._url_events: event = self._url_events[url] event.clear() self._client.get(url) tasks.append(asyncio.wait_for(event.wait(), timeout=10)) await asyncio.gather(*tasks) _LOGGER.debug("async_update finished") @property def name(self): """Return the name of the ClimateDevice. """ return self._name @property def temperature_unit(self): """Return the unit of measurement. """ return self._unit_of_measurement @property def current_temperature(self): """Return the current temperature. """ return self._data.get('inhouse_temperature') @property def target_temperature(self): return self._data.get('temp_setpoint') @property def hvac_modes (self): """List of available modes.""" return self._hvac_modes @property def hvac_mode(self): return HVAC_MODE_HEAT @property def hvac_action(self): """Return the current running hvac operation if supported.""" if self._stateattr.get('boiler_indicator') == 'CH': #HW (hot water) is not for climate return CURRENT_HVAC_HEAT return CURRENT_HVAC_IDLE @property def preset_modes(self): """Return available preset modes.""" return [ OPERATION_CLOCK ] @property def preset_mode(self): """Return the current preset mode.""" if self._data.get('user_mode') == 'manual': return None elif self._data.get('user_mode') == 'clock': return OPERATION_CLOCK else: return None @property def device_state_attributes(self): """Return the device specific state attributes.""" return self._stateattr @property def min_temp(self): """Return the minimum temperature.""" return self.config.get(CONF_MIN_TEMP) @property def max_temp(self): """Return the maximum temperature.""" return self.config.get(CONF_MAX_TEMP) async def async_set_preset_mode(self, preset_mode): """Set new target operation mode.""" _LOGGER.debug("set_preset_mode called mode={}.".format(preset_mode)) if preset_mode == OPERATION_CLOCK: new_mode = "clock" else: new_mode = "manual" self._client.set_usermode(new_mode) await asyncio.wait_for(self._client.xmppclient.message_event.wait(), timeout=10.0) self._client.xmppclient.message_event.clear() self._data['user_mode'] = new_mode async def async_set_temperature(self, **kwargs): """Set new target temperature.""" temperature = kwargs.get(ATTR_TEMPERATURE) self._data['target_temperature'] = temperature _LOGGER.debug("set_temperature called (temperature={}).".format(temperature)) self._client.set_temperature(temperature) await asyncio.wait_for(self._client.xmppclient.message_event.wait(), timeout=10.0) self._client.xmppclient.message_event.clear() self._data['target_temperature'] = temperature def _shutdown(self, event): _LOGGER.debug("shutdown") self._client.disconnect()
class NefitEasy: def __init__(self, hass, credentials): from aionefit import NefitCore _LOGGER.debug("Initialize Nefit class") self.data = {} #stores device states and values self.keys = {} #unique name for entity self.events = {} self.uiStatusVars = {} #variables to monitor for sensors self.hass = hass self.connected_state = STATE_INIT self.expected_end = False self.is_connecting = False self.serial = credentials.get(CONF_SERIAL) self.nefit = NefitCore(serial_number=credentials.get(CONF_SERIAL), access_key=credentials.get(CONF_ACCESSKEY), password=credentials.get(CONF_PASSWORD), message_callback=self.parse_message) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback self.nefit.session_end_callback = self.session_end_callback #self.hass.services.register(DOMAIN, "test_disconnect", self.nefit.disconnect) async def connect(self): _LOGGER.debug("Starting connecting..") if not self.is_connecting: self.is_connecting = True retries_connection = 0 while self.connected_state != STATE_CONNECTED and retries_connection < 3: await self.nefit.connect() _LOGGER.debug("Waiting for connected event") try: await asyncio.wait_for( self.nefit.xmppclient.connected_event.wait(), timeout=29.0) self.connected_state = STATE_CONNECTED _LOGGER.debug("adding stop listener") self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.shutdown) except concurrent.futures._base.TimeoutError: _LOGGER.debug( "TimeoutError on waiting for connected event (connection retries=%d)", retries_connection) retries_connection = retries_connection + 1 except: _LOGGER.debug("Unknown error") #test password for decrypting messages if connected if self.connected_state == STATE_CONNECTED: _LOGGER.info("Testing connection (connect retries=%d)", retries_connection) retries_validation = 0 while self.connected_state != STATE_CONNECTION_VERIFIED and retries_validation < 3: try: self.nefit.get('/gateway/brandID') await asyncio.wait_for( self.nefit.xmppclient.message_event.wait(), timeout=29.0) self.nefit.xmppclient.message_event.clear() if self.connected_state == STATE_ERROR_AUTH: self.is_connecting = False return self.connected_state = STATE_CONNECTION_VERIFIED _LOGGER.info( "Connected %s with %d retries and %d test retries.", self.serial, retries_connection, retries_validation) except concurrent.futures._base.TimeoutError: _LOGGER.error( "Did not get a response in time for testing connection (validation retries=%d).", retries_validation) retries_validation = retries_validation + 1 except: _LOGGER.error( "No connection while testing connection.") break if self.connected_state != STATE_CONNECTION_VERIFIED: self.hass.components.persistent_notification.create( 'Did not succeed in connecting {} to Bosch cloud after retrying 3 times. Retry in 30 seconds.' .format(self.serial), title='Nefit connect error', notification_id='nefit_connect_error') self.is_connecting = False #wait 30 seconds to retry await asyncio.sleep(30) await self.connect() self.is_connecting = False else: _LOGGER.debug("Connection procedure was already running..") async def shutdown(self, event): _LOGGER.debug("Shutdown connection to Bosch cloud") self.expected_end = True await self.nefit.disconnect() async def no_content_callback(self, data): _LOGGER.debug("no_content_callback: %s", data) async def failed_auth_handler(self, event): self.connected_state = STATE_ERROR_AUTH self.nefit.xmppclient.connected_event.set() #disconnect, since nothing will work from now. await self.shutdown('auth_failed') if event == 'auth_error_password': self.hass.components.persistent_notification.create( 'Invalid password for connecting {} to Bosch cloud.'.format( self.serial), title='Nefit password error', notification_id='nefit_password_error') else: self.hass.components.persistent_notification.create( 'Invalid credentials (serial or accesskey) for connecting {} to Bosch cloud.' .format(self.serial), title='Nefit authentication error', notification_id='nefit_logon_error') async def session_end_callback(self): """If connection is closed unexpectedly, try to reconnect""" if not self.expected_end: self.hass.components.persistent_notification.create( 'Unexpected disconnect of {} with Bosch server. Try to reconnect..' .format(self.serial), title='Nefit disconnect', notification_id='nefit_disconnect') _LOGGER.info("Starting reconnect procedure.") # Reset values self.connected_state = STATE_INIT self.expected_end = False # Retry connection await self.connect() async def parse_message(self, data): """Message received callback function for the XMPP client.""" _LOGGER.debug("parse_message data %s", data) if not 'id' in data: _LOGGER.error("Unknown response received: %s", data) return if data['id'] in self.keys: key = self.keys[data['id']] _LOGGER.debug("Got update for %s.", key) if data['id'] == '/ecus/rrc/uiStatus' and self.connected_state == STATE_CONNECTION_VERIFIED: self.data['temp_setpoint'] = float( data['value']['TSP']) #for climate self.data['inhouse_temperature'] = float( data['value']['IHT']) #for climate self.data['user_mode'] = data['value']['UMD'] #for climate self.data['boiler_indicator'] = data['value'][ 'BAI'] #for climate self.data['last_update'] = data['value']['CTD'] # Update all sensors/switches when there is new data form uiStatus for uikey in self.uiStatusVars: self.updateDeviceValue( uikey, data['value'].get(self.uiStatusVars[uikey])) self.updateDeviceValue(key, data['value']) # Mark event as finished if it was part of an update action if key in self.events: self.events[key].set() def updateDeviceValue(self, key, value): """Store new device value and send to dispatcher to be picked up by device""" self.data[key] = value #send update signal to dispatcher to pick up new state signal = DISPATCHER_ON_DEVICE_UPDATE.format(key=key) async_dispatcher_send(self.hass, signal) async def get_value(self, key, url): isNewKey = not url in self.keys if isNewKey: self.events[key] = asyncio.Event() self.keys[url] = key event = self.events[key] event.clear() #clear old event self.nefit.get(url) await asyncio.wait_for(event.wait(), timeout=9) if isNewKey: del self.events[key] del self.keys[url] return self.data[key]
class NefitEasy: """Supporting class for nefit easy.""" def __init__(self, hass, credentials): """Initialize nefit easy component.""" _LOGGER.debug("Initialize Nefit class") self.data = {} # stores device states and values self.keys = {} # unique name for entity self.events = {} self.ui_status_vars = {} # variables to monitor for sensors self.hass = hass self.connected_state = STATE_INIT self.expected_end = False self.is_connecting = False self.serial = credentials.get(CONF_SERIAL) self.nefit = NefitCore( serial_number=credentials.get(CONF_SERIAL), access_key=credentials.get(CONF_ACCESSKEY), password=credentials.get(CONF_PASSWORD), message_callback=self.parse_message, ) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback self.nefit.session_end_callback = self.session_end_callback async def connect(self): """Connect to nefit easy.""" _LOGGER.debug("Starting connecting..") if not self.is_connecting: self.is_connecting = True retries_connection = 0 while self.connected_state != STATE_CONNECTED and retries_connection < 3: await self.nefit.connect() _LOGGER.debug("Waiting for connected event") try: await asyncio.wait_for( self.nefit.xmppclient.connected_event.wait(), timeout=29.0) self.connected_state = STATE_CONNECTED _LOGGER.debug("adding stop listener") self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.shutdown) except asyncio.TimeoutError: _LOGGER.debug( "TimeoutError on waiting for connected event (connection retries=%d)", retries_connection, ) retries_connection = retries_connection + 1 except: # noqa: E722 pylint: disable=bare-except _LOGGER.debug("Unknown error") # test password for decrypting messages if connected if self.connected_state == STATE_CONNECTED: _LOGGER.info("Testing connection (connect retries=%d)", retries_connection) retries_validation = 0 while (self.connected_state != STATE_CONNECTION_VERIFIED and retries_validation < 3): try: self.nefit.get("/gateway/brandID") await asyncio.wait_for( self.nefit.xmppclient.message_event.wait(), timeout=29.0) self.nefit.xmppclient.message_event.clear() if self.connected_state == STATE_ERROR_AUTH: self.is_connecting = False return self.connected_state = STATE_CONNECTION_VERIFIED _LOGGER.info( "Connected %s with %d retries and %d test retries.", self.serial, retries_connection, retries_validation, ) except asyncio.TimeoutError: _LOGGER.error( "Did not get a response in time for testing connection (validation retries=%d).", retries_validation, ) retries_validation = retries_validation + 1 except: # noqa: E722 pylint: disable=bare-except _LOGGER.error( "No connection while testing connection.") break if self.connected_state != STATE_CONNECTION_VERIFIED: self.hass.components.persistent_notification.create( f"Did not succeed in connecting {self.serial} to Bosch cloud after retrying 3 times. Retry in 30 seconds.", title="Nefit connect error", notification_id="nefit_connect_error", ) self.is_connecting = False # wait 30 seconds to retry await asyncio.sleep(30) await self.connect() self.is_connecting = False else: _LOGGER.debug("Connection procedure was already running..") async def shutdown(self, event): """Shutdown.""" _LOGGER.debug("Shutdown connection to Bosch cloud") self.expected_end = True await self.nefit.disconnect() async def no_content_callback(self, data): """Log no content.""" _LOGGER.debug("no_content_callback: %s", data) async def failed_auth_handler(self, event): """Handle failed auth.""" self.connected_state = STATE_ERROR_AUTH self.nefit.xmppclient.connected_event.set() # disconnect, since nothing will work from now. await self.shutdown("auth_failed") if event == "auth_error_password": self.hass.components.persistent_notification.create( f"Invalid password for connecting {self.serial} to Bosch cloud.", title="Nefit password error", notification_id="nefit_password_error", ) else: self.hass.components.persistent_notification.create( f"Invalid credentials (serial or accesskey) for connecting {self.serial} to Bosch cloud.", title="Nefit authentication error", notification_id="nefit_logon_error", ) async def session_end_callback(self): """If connection is closed unexpectedly, try to reconnect.""" if not self.expected_end: self.hass.components.persistent_notification.create( f"Unexpected disconnect of {self.serial} with Bosch server. Try to reconnect..", title="Nefit disconnect", notification_id="nefit_disconnect", ) _LOGGER.info("Starting reconnect procedure.") # Reset values self.connected_state = STATE_INIT self.expected_end = False # Retry connection await self.connect() async def parse_message(self, data): """Message received callback function for the XMPP client.""" _LOGGER.debug("parse_message data %s", data) if "id" not in data: _LOGGER.error("Unknown response received: %s", data) return if data["id"] in self.keys: key = self.keys[data["id"]] _LOGGER.debug("Got update for %s.", key) if (data["id"] == "/ecus/rrc/uiStatus" and self.connected_state == STATE_CONNECTION_VERIFIED): self.data["temp_setpoint"] = float( data["value"]["TSP"]) # for climate self.data["inhouse_temperature"] = float( data["value"]["IHT"]) # for climate self.data["user_mode"] = data["value"]["UMD"] # for climate self.data["boiler_indicator"] = data["value"][ "BAI"] # for climate self.data["last_update"] = data["value"]["CTD"] # Update all sensors/switches when there is new data form uiStatus for uikey in self.ui_status_vars: self.update_device_value( uikey, data["value"].get(self.ui_status_vars[uikey])) self.update_device_value(key, data["value"]) # Mark event as finished if it was part of an update action if key in self.events: self.events[key].set() def update_device_value(self, key, value): """Store new device value and send to dispatcher to be picked up by device.""" self.data[key] = value # send update signal to dispatcher to pick up new state signal = DISPATCHER_ON_DEVICE_UPDATE.format(key=key) async_dispatcher_send(self.hass, signal) async def get_value(self, key, url): """Get value.""" is_new_key = url not in self.keys if is_new_key: self.events[key] = asyncio.Event() self.keys[url] = key event = self.events[key] event.clear() # clear old event self.nefit.get(url) await asyncio.wait_for(event.wait(), timeout=9) if is_new_key: del self.events[key] del self.keys[url] return self.data[key]
class NefitEasy(DataUpdateCoordinator): """Supporting class for nefit easy.""" def __init__(self, hass, config): """Initialize nefit easy component.""" _LOGGER.debug("Initialize Nefit class") self._data = {} # stores device states and values self._event = asyncio.Event() self._lock = asyncio.Lock() self.hass = hass self.connected_state = STATE_INIT self.expected_end = False self.is_connecting = False self.serial = config[CONF_SERIAL] self._config = config self._request = None self.nefit = NefitCore( serial_number=config[CONF_SERIAL], access_key=config[CONF_ACCESSKEY], password=config[CONF_PASSWORD], message_callback=self.parse_message, ) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback self.nefit.session_end_callback = self.session_end_callback self._urls = {} self._status_keys = {} update_interval = timedelta(seconds=60) super().__init__( hass, _LOGGER, name=DOMAIN, update_interval=update_interval, ) async def add_key(self, key, typeconf): """Add key to list of endpoints.""" async with self._lock: if url in typeconf: self._urls[typeconf[url]] = { "key": key, short: typeconf.get(short) } elif short in typeconf: self._status_keys[typeconf[short]] = key async def connect(self): """Connect to nefit easy.""" _LOGGER.debug("Starting connecting..") if not self.is_connecting: self.is_connecting = True retries_connection = 0 while self.connected_state != STATE_CONNECTED and retries_connection < 3: await self.nefit.connect() _LOGGER.debug("Waiting for connected event") try: await asyncio.wait_for( self.nefit.xmppclient.connected_event.wait(), timeout=29.0) self.connected_state = STATE_CONNECTED _LOGGER.debug("adding stop listener") self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.shutdown) except asyncio.TimeoutError: _LOGGER.debug( "TimeoutError on waiting for connected event (connection retries=%d)", retries_connection, ) retries_connection = retries_connection + 1 except: # noqa: E722 pylint: disable=bare-except _LOGGER.debug("Unknown error") # test password for decrypting messages if connected if self.connected_state == STATE_CONNECTED: _LOGGER.info("Testing connection (connect retries=%d)", retries_connection) retries_validation = 0 while (self.connected_state != STATE_CONNECTION_VERIFIED and retries_validation < 3): try: self.nefit.get("/gateway/brandID") await asyncio.wait_for( self.nefit.xmppclient.message_event.wait(), timeout=29.0) self.nefit.xmppclient.message_event.clear() if self.connected_state == STATE_ERROR_AUTH: self.is_connecting = False return self.connected_state = STATE_CONNECTION_VERIFIED _LOGGER.info( "Connected %s with %d retries and %d test retries.", self.serial, retries_connection, retries_validation, ) except asyncio.TimeoutError: _LOGGER.error( "Did not get a response in time for testing connection (validation retries=%d).", retries_validation, ) retries_validation = retries_validation + 1 except: # noqa: E722 pylint: disable=bare-except _LOGGER.error( "No connection while testing connection.") break if self.connected_state != STATE_CONNECTION_VERIFIED: self.hass.components.persistent_notification.create( f"Did not succeed in connecting {self.serial} to Bosch cloud after retrying 3 times. Retry in 30 seconds.", title="Nefit connect error", notification_id="nefit_connect_error", ) self.is_connecting = False # wait 30 seconds to retry await asyncio.sleep(30) await self.connect() self.is_connecting = False else: _LOGGER.debug("Connection procedure was already running..") async def shutdown(self, event): """Shutdown.""" _LOGGER.debug("Shutdown connection to Bosch cloud") self.expected_end = True await self.nefit.disconnect() async def no_content_callback(self, data): """Log no content.""" _LOGGER.debug("no_content_callback: %s", data) async def failed_auth_handler(self, event): """Handle failed auth.""" self.connected_state = STATE_ERROR_AUTH self.nefit.xmppclient.connected_event.set() # disconnect, since nothing will work from now. await self.shutdown("auth_failed") if event == "auth_error_password": self.hass.components.persistent_notification.create( f"Invalid password for connecting {self.serial} to Bosch cloud.", title="Nefit password error", notification_id="nefit_password_error", ) else: self.hass.components.persistent_notification.create( f"Invalid credentials (serial or accesskey) for connecting {self.serial} to Bosch cloud.", title="Nefit authentication error", notification_id="nefit_logon_error", ) async def session_end_callback(self): """If connection is closed unexpectedly, try to reconnect.""" if not self.expected_end: self.hass.components.persistent_notification.create( f"Unexpected disconnect of {self.serial} with Bosch server. Try to reconnect..", title="Nefit disconnect", notification_id="nefit_disconnect", ) _LOGGER.info("Starting reconnect procedure.") # Reset values self.connected_state = STATE_INIT self.expected_end = False # Retry connection await self.connect() async def parse_message(self, data): """Message received callback function for the XMPP client.""" if (data["id"] == "/ecus/rrc/uiStatus" and self.connected_state == STATE_CONNECTION_VERIFIED): self._data["temp_setpoint"] = float( data["value"]["TSP"]) # for climate self._data["inhouse_temperature"] = float( data["value"]["IHT"]) # for climate self._data["user_mode"] = data["value"]["UMD"] # for climate self._data["boiler_indicator"] = data["value"][ "BAI"] # for climate self._data["last_update"] = data["value"]["CTD"] for val, key in self._status_keys.items(): self._data[key] = data["value"].get(val) elif (data["id"].startswith( "/ecus/rrc/homeentrancedetection/userprofile") and self.connected_state == STATE_CONNECTION_VERIFIED): m = re.search(r"(?<=userprofile)\w+", data["id"]) id = m.group(0) val = data["id"].rsplit("/", 1)[-1] self._data[f"presence{id}_{val}"] = data["value"] elif (data["id"] in self._urls and self.connected_state == STATE_CONNECTION_VERIFIED): self._data[self._urls[data["id"]]["key"]] = data["value"] else: return if self._request == data["id"]: self._event.set() else: self.async_set_updated_data(self._data) async def _async_update_data(self): """Update data via library.""" if self.connected_state != STATE_CONNECTION_VERIFIED: raise UpdateFailed("Nefit easy not connected!") async with self._lock: url = "/ecus/rrc/uiStatus" await self._async_get_url(url) for url in self._urls: await self._async_get_url(url) return self._data async def async_init_presence(self, endpoint, index): """Init presence detection.""" async with self._lock: url = f"{endpoint}/userprofile{index}/active" await self._async_get_url(url) if self._data[f"presence{index}_active"] == "on": url = f"{endpoint}/userprofile{index}/name" await self._async_get_url(url) return self._data.get(f"presence{index}_name") return None async def update_ui_status_later(self, delay): """Force update of uiStatus after delay.""" self.hass.loop.call_later(delay, self.nefit.get, "/ecus/rrc/uiStatus") async def _async_get_url(self, url): self._event.clear() self._request = url self.nefit.get(url) await asyncio.wait_for(self._event.wait(), timeout=9) self._request = None
class NefitEasy: def __init__(self, hass, credentials): from aionefit import NefitCore _LOGGER.debug("Initialize Nefit class") self.data = {} #stores device states and values self.keys = {} #unique name for entity self.events = {} self.uiStatusVars = {} #variables to monitor for sensors self.hass = hass self.connected_state = STATE_INIT self.nefit = NefitCore(serial_number=credentials.get(CONF_SERIAL), access_key=credentials.get(CONF_ACCESSKEY), password=credentials.get(CONF_PASSWORD), message_callback=self.parse_message) self.nefit.failed_auth_handler = self.failed_auth_handler self.nefit.no_content_callback = self.no_content_callback async def connect(self): self.nefit.connect() _LOGGER.debug("Waiting for connected event") try: # await self.nefit.xmppclient.connected_event.wait() await asyncio.wait_for(self.nefit.xmppclient.connected_event.wait(), timeout=60.0) self.connected_state = STATE_CONNECTED _LOGGER.debug("adding stop listener") self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.shutdown) except concurrent.futures._base.TimeoutError: _LOGGER.debug("TimeoutError on waiting for connected event") self.hass.components.persistent_notification.create( 'Timeout while connecting to Bosch cloud.', title='Nefit error', notification_id='nefit_logon_error') raise PlatformNotReady if self.connected_state == STATE_ERROR_AUTH: self.hass.components.persistent_notification.create( 'Invalid credentials while connecting to Bosch cloud.', title='Nefit error', notification_id='nefit_logon_error') raise PlatformNotReady def shutdown(self, event): _LOGGER.debug("Shutdown connection to Bosch cloud") self.nefit.disconnect() def no_content_callback(self, data): _LOGGER.debug("no_content_callback: %s", data) def failed_auth_handler(self, event): self.connected_state = STATE_ERROR_AUTH self.nefit.xmppclient.connected_event.set() def parse_message(self, data): """Message received callback function for the XMPP client. """ _LOGGER.debug("parse_message data %s", data) if not 'id' in data: _LOGGER.error("Unknown response received: %s", data) return if data['id'] in self.keys: key = self.keys[data['id']] _LOGGER.debug("Got update for %s.", key) if data['id'] == '/ecus/rrc/uiStatus': self.data['temp_setpoint'] = float(data['value']['TSP']) #for climate self.data['inhouse_temperature'] = float(data['value']['IHT']) #for climate self.data['user_mode'] = data['value']['UMD'] #for climate self.data['boiler_indicator'] = data['value']['BAI'] #for climate self.data['last_update'] = data['value']['CTD'] for uikey in self.uiStatusVars: self.updateDeviceValue(uikey, data['value'].get(self.uiStatusVars[uikey])) self.updateDeviceValue(key, data['value']) # Mark event as finished if it was part of an update action if key in self.events: self.events[key].set() def updateDeviceValue(self, key, value): """Store new device value and send to dispatcher to be picked up by device""" self.data[key] = value #send update signal to dispatcher to pick up new state signal = DISPATCHER_ON_DEVICE_UPDATE.format(key=key) async_dispatcher_send(self.hass, signal)