From dad7b08a982dd799435b72b3407e9d830eb433f0 Mon Sep 17 00:00:00 2001 From: Dirk Alders Date: Sat, 30 Jan 2021 23:21:01 +0100 Subject: [PATCH] Application Structure reworked --- report | 2 +- smarthome.py | 573 ++++++++++++++++++++++++------------------------ socket_protocol | 2 +- 3 files changed, 291 insertions(+), 286 deletions(-) diff --git a/report b/report index 25889f2..139f0bd 160000 --- a/report +++ b/report @@ -1 +1 @@ -Subproject commit 25889f225b3593d515e37bebffef21458c961f64 +Subproject commit 139f0bd0c29b8b44e235622f7fd8db7dc0037ec0 diff --git a/smarthome.py b/smarthome.py index 387424d..e1bfad7 100644 --- a/smarthome.py +++ b/smarthome.py @@ -9,7 +9,6 @@ import helpers import garage_protocol import gui import logging -import numbers import os import report import socket_protocol @@ -19,301 +18,180 @@ import time import wetation_protocol import wx +############################################################################################################################ +# # +# Application Structure # +# # +# +-----------------------------+ +------------------------------+ +---------------------------+ # +# | Data Request Task (1s) | | Data Receive Callback | | GUI Update WX-IDLE-TASK | # +# | Counter 0-9 | | | | | # +# | | | Append data to ValueStorage | | - Update all GUI Elements | # +# | *: Request door_pos | +------------------------------+ | - Check Data Status to | # +# | 0: Request env-data-in bmp | | mark all fragile con- | # +# | 1: Request env-data-in dht | | tent | # +# | 5: Request env-data-out bmp | +---------------------------+ # +# | 6: Request env-data-out dht | # +# | 9: Reconnect if needed | # +# +-----------------------------+ # +# # +############################################################################################################################ + + try: from config import APP_NAME as ROOT_LOGGER_NAME except ImportError: ROOT_LOGGER_NAME = 'root' +logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__) -class WetationFrameProt(gui.Wetation): - PROT_ID_GARAGE = 0 - PROT_ID_IN = 1 - PROT_ID_OUT = 2 - ALL_PROT_IDS = [PROT_ID_GARAGE, PROT_ID_IN, PROT_ID_OUT, ] - PROT_NAMES = { - PROT_ID_GARAGE: u'garage', - PROT_ID_IN: u'wet-in', - PROT_ID_OUT: u'wet-out', +class ValueStorage(dict): + MAX_AGE = 60 # Seconds + + DATA_KEY_GATE_POSITION = 'gate_position' + DATA_KEY_HUMIDITY_IN = 'humidity_in' + DATA_KEY_HUMIDITY_OUT = 'humidity_out' + DATA_KEY_PRESSURE_IN = 'pressure_in' + DATA_KEY_PRESSURE_OUT = 'pressure_out' + DATA_KEY_TEMPERATURE_IN = 'temp_in' + DATA_KEY_TEMPERATURE_OUT = 'temp_out' + DATA_KEY_2ND_TEMPERATURE_IN = '2nd_temp_in' + DATA_KEY_2ND_TEMPERATURE_OUT = '2nd_temp_out' + + FORMATTER_TEMP = ('%.1f °C', '-.- °C') + FORMATTER_HUMI = ('%.1f %%', '-.- %') + FORMATTER_PRES = ('%4d hPa', '- hPa') + + DATA_KEYS_CONT_STAT = [DATA_KEY_HUMIDITY_IN, DATA_KEY_HUMIDITY_OUT, DATA_KEY_PRESSURE_IN, DATA_KEY_PRESSURE_OUT, DATA_KEY_TEMPERATURE_IN, DATA_KEY_TEMPERATURE_OUT, DATA_KEY_2ND_TEMPERATURE_IN, DATA_KEY_2ND_TEMPERATURE_OUT] + + def append(self, drk, value): + tm = time.time() + logger.info('Value stored (%s): %s', drk, repr(value)) + if drk in self.DATA_KEYS_CONT_STAT: + self[drk] = (value.mean, tm) + if drk + '.min' not in self or value.min < self[drk + '.min'][0]: + self[drk + '.min'] = (value.min, tm) + if drk + '.max' not in self or value.max < self[drk + '.max'][0]: + self[drk + '.max'] = (value.max, tm) + else: + self[drk] = (value, tm) + + def reset_min_max(self, data_key): + del self[data_key + '.min'] + del self[data_key + '.max'] + + def __get_formatter__(self, key): + return { + self.DATA_KEY_2ND_TEMPERATURE_IN: self.FORMATTER_TEMP, + self.DATA_KEY_2ND_TEMPERATURE_OUT: self.FORMATTER_TEMP, + self.DATA_KEY_HUMIDITY_IN: self.FORMATTER_HUMI, + self.DATA_KEY_HUMIDITY_OUT: self.FORMATTER_HUMI, + self.DATA_KEY_PRESSURE_IN: self.FORMATTER_PRES, + self.DATA_KEY_PRESSURE_OUT: self.FORMATTER_PRES, + self.DATA_KEY_TEMPERATURE_IN: self.FORMATTER_TEMP, + self.DATA_KEY_TEMPERATURE_OUT: self.FORMATTER_TEMP, + }.get(key) + + def get_validated(self, key, value_type=None, default=None): + tm = time.time() + fallback = { + self.DATA_KEY_TEMPERATURE_IN: self.DATA_KEY_2ND_TEMPERATURE_IN, + self.DATA_KEY_TEMPERATURE_OUT: self.DATA_KEY_2ND_TEMPERATURE_OUT, + }.get(key) + if value_type in ['min', 'max']: + key = key + '.' + value_type + value = dict.get(self, key) + if value is None and fallback is not None: + value = dict.get(self, fallback) + if value is None: + return default + if tm - value[1] <= self.MAX_AGE: + if key == self.DATA_KEY_GATE_POSITION: + return int(value[0] * 50) + else: + return value[0] + else: + return default + + def get(self, key, value_type=None, formatted=True, default=None): + formatter = self.__get_formatter__(key) + value = self.get_validated(key, value_type, default=default) + if not formatted: + return value + else: + if formatter is None: + return default + else: + try: + return formatter[0] % value + except Exception: + return formatter[1] + + +class Wetation(gui.Wetation): + SRC_ID_GARAGE = 0 + SRC_ID_IN = 1 + SRC_ID_OUT = 2 + ALL_SRC_IDS = [SRC_ID_GARAGE, SRC_ID_IN, SRC_ID_OUT, ] + + SRC_NAMES = { + SRC_ID_GARAGE: u'garage', + SRC_ID_IN: u'wet-in', + SRC_ID_OUT: u'wet-out', } - PROT_IPS = { - PROT_ID_GARAGE: config.server_garage_ip, - PROT_ID_IN: config.server_in_ip, - PROT_ID_OUT: config.server_out_ip, + SRC_IPS = { + SRC_ID_GARAGE: config.server_garage_ip, + SRC_ID_IN: config.server_in_ip, + SRC_ID_OUT: config.server_out_ip, } - PROT_PORTS = { - PROT_ID_GARAGE: config.server_garage_port, - PROT_ID_IN: config.server_in_port, - PROT_ID_OUT: config.server_out_port, + SRC_PORTS = { + SRC_ID_GARAGE: config.server_garage_port, + SRC_ID_IN: config.server_in_port, + SRC_ID_OUT: config.server_out_port, } - PROT_SECRETS = { - PROT_ID_GARAGE: config.server_garage_secret, - PROT_ID_IN: config.server_in_secret, - PROT_ID_OUT: config.server_out_secret, - } - - PROT_CLASSES = { - PROT_ID_GARAGE: garage_protocol.my_base_protocol_tcp, - PROT_ID_IN: wetation_protocol.my_base_protocol_tcp, - PROT_ID_OUT: wetation_protocol.my_base_protocol_tcp, + SRC_SECRETS = { + SRC_ID_GARAGE: config.server_garage_secret, + SRC_ID_IN: config.server_in_secret, + SRC_ID_OUT: config.server_out_secret, } - REQUEST_MSGS_SLOW = { - PROT_ID_IN: [ - { - 'service_id': socket_protocol.SID_READ_REQUEST, - 'data_id': wetation_protocol.ENVDATA_STATISTIC_DHT, - }, - { - 'service_id': socket_protocol.SID_READ_REQUEST, - 'data_id': wetation_protocol.ENVDATA_STATISTIC_BMP, - }, - ], - PROT_ID_OUT: [ - { - 'service_id': socket_protocol.SID_READ_REQUEST, - 'data_id': wetation_protocol.ENVDATA_STATISTIC_DHT, - }, - { - 'service_id': socket_protocol.SID_READ_REQUEST, - 'data_id': wetation_protocol.ENVDATA_STATISTIC_BMP, - }, - ], + SRC_CLASSES = { + SRC_ID_GARAGE: garage_protocol.my_base_protocol_tcp, + SRC_ID_IN: wetation_protocol.my_base_protocol_tcp, + SRC_ID_OUT: wetation_protocol.my_base_protocol_tcp, } - REQUEST_MSGS_FAST = { - PROT_ID_GARAGE: [ - { - 'service_id': socket_protocol.SID_READ_REQUEST, - 'data_id': garage_protocol.GATE_POSITION, - }, - ], - } - - def __init__(self, *args, **kwds): - self.__min_temp_in__ = None - self.__min_temp_out__ = None - self.__max_temp_in__ = None - self.__max_temp_out__ = None - self.__prot__ = {} + gui.Wetation.__init__(self, *args, **kwds) + self.Bind(wx.EVT_IDLE, self.gui_update) self.in_temperature_min.Bind(wx.EVT_LEFT_DOWN, self.reset_in_temp_minmax_evt) self.in_temperature_max.Bind(wx.EVT_LEFT_DOWN, self.reset_in_temp_minmax_evt) self.out_temperature_min.Bind(wx.EVT_LEFT_DOWN, self.reset_out_temp_minmax_evt) self.out_temperature_max.Bind(wx.EVT_LEFT_DOWN, self.reset_out_temp_minmax_evt) self.ShowFullScreen(config.FULL_SCREEN) - + # + self.__src__ = {} + self.__value_storage__ = ValueStorage() self.__init_communication__() - time.sleep(3.5) # Wait for established connections before starting the tasks - - self.__task_1s__ = task.periodic(1, self.__task_1s_callback__) - self.__task_10s__ = task.periodic(10, self.__task_10s_callback__) - self.__task_60s__ = task.periodic(60, self.__task_60s_callback__) + # + self.__drt_cnt__ = -1 + self.__task_1s__ = task.periodic(1, self.data_request_task) def __init_communication__(self): # # Start TCP-Clients - for prot_id in self.ALL_PROT_IDS: - cn = self.PROT_NAMES[prot_id] - logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__ + '.' + cn) - logger.info('Initiating communication channel') - c_tcp = tcp_socket.tcp_client_stp(self.PROT_IPS[prot_id], self.PROT_PORTS[prot_id]) - self.__prot__[prot_id] = self.PROT_CLASSES[prot_id](c_tcp, secret=self.PROT_SECRETS[prot_id], auto_auth=True, channel_name=cn) + for src_id in self.ALL_SRC_IDS: + cn = self.SRC_NAMES[src_id] + c_tcp = tcp_socket.tcp_client_stp(self.SRC_IPS[src_id], self.SRC_PORTS[src_id], channel_name=cn) + self.__src__[src_id] = self.SRC_CLASSES[src_id](c_tcp, secret=self.SRC_SECRETS[src_id], auto_auth=True, channel_name=cn) # - self.__prot__[prot_id].register_callback(None, None, self.__prot_resp_callbacks__, prot_id) - - def __initiate_data_request__(self, rt, request_msgs): - for prot_id in request_msgs: - cn = self.PROT_NAMES[prot_id] - logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__ + '.' + cn) - for request_msg in request_msgs.get(prot_id, []): - service_id = request_msg['service_id'] - data_id = request_msg['data_id'] - if self.__prot__[prot_id].connection_established(): - logger.debug('Sending data request for service_id %d and data_id %d', service_id, data_id) - self.__prot__[prot_id].send(service_id, data_id, None) - else: - wx.CallAfter(self.__no_data__, prot_id, service_id + 1, data_id) - - def __task_1s_callback__(self, rt): - # request data from fast prot ids - self.__initiate_data_request__(rt, self.REQUEST_MSGS_FAST) - # set date and time - wx.CallAfter(self.update_time) - - def __task_10s_callback__(self, rt): - # request data from slow prot ids - self.__initiate_data_request__(rt, self.REQUEST_MSGS_SLOW) - - def __task_60s_callback__(self, rt): - # reconnect prots if needed - for prot_id in self.ALL_PROT_IDS: - cn = self.PROT_NAMES[prot_id] - logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__ + '.' + cn) - if not self.__prot__[prot_id].connected(): - logger.warning("Trying to reconnect prot_id %d", prot_id) - self.__prot__[prot_id].reconnect() - - def __validate_response_data__(self, prot_id, service_id, data_id, data): - rv = False - cn = self.PROT_NAMES[prot_id] - logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__ + '.' + cn) - if prot_id == self.PROT_ID_GARAGE: - if service_id == socket_protocol.SID_READ_RESPONSE and data_id == garage_protocol.GATE_POSITION: - rv = isinstance(data, numbers.Number) - elif service_id == socket_protocol.SID_EXECUTE_RESPONSE and data_id == garage_protocol.OPEN_CLOSE_GATE: - if data is True: - rv = True - elif prot_id in [self.PROT_ID_IN, self.PROT_ID_OUT]: - if service_id == socket_protocol.SID_READ_RESPONSE and data_id == wetation_protocol.ENVDATA_STATISTIC_BMP: - rv = True - for main_key in [bmp_180.KEY_PRESSURE, bmp_180.KEY_TEMPERATURE, bmp_180.KEY_TIME]: - if main_key not in data: - rv = False - break - else: - for sub_key in ['mean', 'min_val', 'max_val', 'quantifier']: - if not isinstance(data[main_key].get(sub_key), numbers.Number): - rv = False - break - elif service_id == socket_protocol.SID_READ_RESPONSE and data_id == wetation_protocol.ENVDATA_STATISTIC_DHT: - rv = True - for main_key in [dht_22.KEY_HUMIDITY, dht_22.KEY_TEMPERATURE, dht_22.KEY_TIME]: - if main_key not in data: - rv = False - break - else: - for sub_key in ['mean', 'min_val', 'max_val', 'quantifier']: - if not isinstance(data[main_key].get(sub_key), numbers.Number): - rv = False - break - if rv is False: - logger.warning("Validation failed for message: prot_id=%s, service_id=%s, data_id=%s, data=%s", repr(prot_id), repr(service_id), repr(data_id), repr(data)) - return rv - - def __prot_resp_callbacks__(self, msg, prot_id): - service_id = msg.get_service_id() - data_id = msg.get_data_id() - data = msg.get_data() - if self.__validate_response_data__(prot_id, service_id, data_id, data): - wx.CallAfter(self.__data__, prot_id, service_id, data_id, data) - return socket_protocol.STATUS_OKAY, None - else: - wx.CallAfter(self.__no_data__, prot_id, service_id, data_id) - return socket_protocol.STATUS_SERVICE_OR_DATA_UNKNOWN, None - - def __no_data__(self, prot_id, service_id, data_id): - cn = self.PROT_NAMES[prot_id] - logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__ + '.' + cn) - if prot_id == self.PROT_ID_GARAGE: - if service_id == socket_protocol.SID_READ_RESPONSE and data_id == garage_protocol.GATE_POSITION: - logger.warning('Resetting GUI elements for %s', cn) - self.heading_garage.Show(False) - self.gate_oc.Show(False) - self.gate_open.Show(False) - self.gate_position.Show(False) - self.gate_close.Show(False) - self.Layout() - return - elif service_id == socket_protocol.SID_EXECUTE_RESPONSE and data_id == garage_protocol.OPEN_CLOSE_GATE: - return - elif prot_id in [self.PROT_ID_IN, self.PROT_ID_OUT]: - if service_id == socket_protocol.SID_READ_RESPONSE and data_id == wetation_protocol.ENVDATA_STATISTIC_BMP: - logger.warning('Resetting GUI elements for %s', cn) - txt_pressure = '- hPa' - if prot_id == self.PROT_ID_IN: - self.in_pressure.SetLabel(txt_pressure) - else: - self.out_pressure.SetLabel(txt_pressure) - self.Layout() - return - elif service_id == socket_protocol.SID_READ_RESPONSE and data_id == wetation_protocol.ENVDATA_STATISTIC_DHT: - logger.warning('Resetting GUI elements for %s', cn) - txt_temperature = '-.- °C' - txt_humidity = '-.- %' - if prot_id == self.PROT_ID_IN: - self.in_temperature.SetLabel(txt_temperature) - self.in_humidity.SetLabel(txt_humidity) - else: - self.out_temperature.SetLabel(txt_temperature) - self.out_humidity.SetLabel(txt_humidity) - self.Layout() - return - logger.warning("Unknown response with no valid data for prot_id %d, service_id=%d, data_id=%d", prot_id, service_id, data_id) - - def __data__(self, prot_id, service_id, data_id, data): - cn = self.PROT_NAMES[prot_id] - logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__ + '.' + cn) - if prot_id == self.PROT_ID_GARAGE: - if service_id == socket_protocol.SID_READ_RESPONSE and data_id == garage_protocol.GATE_POSITION: - logger.debug('Setting %s position to %3d', cn, int(data * 100)) - self.heading_garage.Show(True) - self.gate_oc.Show(True) - self.gate_open.Show(True) - self.gate_position.Show(True) - self.gate_close.Show(True) - self.gate_position.SetValue(int(data * 100)) - self.Layout() - return - elif service_id == socket_protocol.SID_EXECUTE_RESPONSE and data_id == garage_protocol.OPEN_CLOSE_GATE: - return - elif prot_id in [self.PROT_ID_IN, self.PROT_ID_OUT]: - if service_id == socket_protocol.SID_READ_RESPONSE and data_id == wetation_protocol.ENVDATA_STATISTIC_BMP: - data = helpers.continues_statistic_multivalue(**data) - logger.debug('Setting %s pressure to %4d hPa', cn, data[bmp_180.KEY_PRESSURE].mean) - # - # Current environmental data - if prot_id == self.PROT_ID_IN: - wx.CallAfter(self.update_current_bmp_env_data, data, self.in_pressure) - else: - wx.CallAfter(self.update_current_bmp_env_data, data, self.out_pressure) - return - elif service_id == socket_protocol.SID_READ_RESPONSE and data_id == wetation_protocol.ENVDATA_STATISTIC_DHT: - data = helpers.continues_statistic_multivalue(**data) - # - # Current environmental data - temp = data[dht_22.KEY_TEMPERATURE].mean - logger.debug('Setting %s temperature to %4.1f °C', cn, temp) - logger.debug('Setting %s humidity to %3.1f %%', cn, data[dht_22.KEY_HUMIDITY].mean) - if prot_id == self.PROT_ID_IN: - if self.__max_temp_in__ is None or temp > self.__max_temp_in__: - self.__max_temp_in__ = temp - if self.__min_temp_in__ is None or temp < self.__min_temp_in__: - self.__min_temp_in__ = temp - wx.CallAfter(self.update_current_dht_env_data, data, self.in_temperature, self.in_humidity, self.in_temperature_min, self.in_temperature_max, self.__min_temp_in__, self.__max_temp_in__) - else: - if self.__max_temp_out__ is None or temp > self.__max_temp_out__: - self.__max_temp_out__ = temp - if self.__min_temp_out__ is None or temp < self.__min_temp_out__: - self.__min_temp_out__ = temp - wx.CallAfter(self.update_current_dht_env_data, data, self.out_temperature, self.out_humidity, self.out_temperature_min, self.out_temperature_max, self.__min_temp_out__, self.__max_temp_out__) - return - logger.warning("Unknown response with valid data for prot_id %d, service_id=%d, data_id=%d", prot_id, service_id, data_id) - - def update_current_bmp_env_data(self, env_data, pressure): - pressure.SetLabel('%.0f hPa' % env_data[bmp_180.KEY_PRESSURE].mean) - self.Layout() - - def update_current_dht_env_data(self, env_data, temperature, humidity, temperature_min, temperature_max, value_min, value_max): - if isinstance(value_min, numbers.Number) and isinstance(value_max, numbers.Number): - temperature_min.SetLabel('%.1f' % value_min) - temperature_max.SetLabel('%.1f' % value_max) - temperature.SetLabel('%.1f °C' % env_data[dht_22.KEY_TEMPERATURE].mean) - humidity.SetLabel('%.1f %%' % env_data[dht_22.KEY_HUMIDITY].mean) - self.Layout() - - def update_time(self): - self.time.SetLabel(time.strftime("%H:%M")) - self.date.SetLabel(time.strftime("%d.%m.%Y")) - self.Layout() + self.__src__[src_id].register_callback(None, None, self.data_receive_callback, src_id) def gate_oc_evt(self, event): - cn = self.PROT_NAMES[self.PROT_ID_GARAGE] - logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__ + '.' + cn) r = wx.MessageDialog( self, "Soll das Garagentor betätigt werden?", @@ -321,38 +199,167 @@ class WetationFrameProt(gui.Wetation): wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING ).ShowModal() if r == wx.ID_YES: - logger.debug("Gate open/close request") - self.__prot__[self.PROT_ID_GARAGE].send(socket_protocol.SID_EXECUTE_REQUEST, garage_protocol.OPEN_CLOSE_GATE, None) + logger.info("Gate open/close request") + self.__src__[self.SRC_ID_GARAGE].send(socket_protocol.SID_EXECUTE_REQUEST, garage_protocol.OPEN_CLOSE_GATE, None) event.Skip() def reset_in_temp_minmax_evt(self, event): - self.__min_temp_in__ = None - self.__max_temp_in__ = None - self.in_temperature_min.SetLabel("-.- °C") - self.in_temperature_max.SetLabel("-.- °C") - self.Layout() + self.__value_storage__.reset_min_max(ValueStorage.DATA_KEY_TEMPERATURE_IN) + self.__value_storage__.reset_min_max(ValueStorage.DATA_KEY_2ND_TEMPERATURE_IN) event.Skip() def reset_out_temp_minmax_evt(self, event): - self.__min_temp_out__ = None - self.__max_temp_out__ = None - self.out_temperature_min.SetLabel("-.- °C") - self.out_temperature_max.SetLabel("-.- °C") + self.__value_storage__.reset_min_max(ValueStorage.DATA_KEY_TEMPERATURE_OUT) + self.__value_storage__.reset_min_max(ValueStorage.DATA_KEY_2ND_TEMPERATURE_OUT) + event.Skip() + + def data_request_task(self, rt): + (rt) + if self.__drt_cnt__ < 9: + self.__drt_cnt__ += 1 + else: + self.__drt_cnt__ = 0 + logger.debug('data_request_task stated with cnt = %d', self.__drt_cnt__) + # + # Request GATE_POSITION + # + self.__src__[self.SRC_ID_GARAGE].send(service_id=socket_protocol.SID_READ_REQUEST, data_id=garage_protocol.GATE_POSITION, data=None) + # + # Request WET-OUT-DATA + # + if self.__drt_cnt__ == 0: + self.__src__[self.SRC_ID_OUT].send(service_id=socket_protocol.SID_READ_REQUEST, data_id=wetation_protocol.ENVDATA_STATISTIC_BMP, data=None) + elif self.__drt_cnt__ == 1: + self.__src__[self.SRC_ID_OUT].send(service_id=socket_protocol.SID_READ_REQUEST, data_id=wetation_protocol.ENVDATA_STATISTIC_DHT, data=None) + # + # Request WET-IN-DATA + # + elif self.__drt_cnt__ == 5: + self.__src__[self.SRC_ID_IN].send(service_id=socket_protocol.SID_READ_REQUEST, data_id=wetation_protocol.ENVDATA_STATISTIC_BMP, data=None) + elif self.__drt_cnt__ == 6: + self.__src__[self.SRC_ID_IN].send(service_id=socket_protocol.SID_READ_REQUEST, data_id=wetation_protocol.ENVDATA_STATISTIC_DHT, data=None) + elif self.__drt_cnt__ == 9: + self.__reconnect__() + # + + def __reconnect__(self): + for src_id in self.ALL_SRC_IDS: + if not self.__src__[src_id].is_connected(): + logger.warning("Trying to reconnect prot_id %s", self.SRC_NAMES.get(src_id, 'Unknown')) + self.__src__[src_id].reconnect() + + def __data_receive_key__(self, src_id, data_id, key=None, default_value=None): + return { + self.SRC_ID_GARAGE: { + garage_protocol.GATE_POSITION: { + None: ValueStorage.DATA_KEY_GATE_POSITION, + } + }, + self.SRC_ID_IN: { + wetation_protocol.ENVDATA_STATISTIC_BMP: { + bmp_180.KEY_PRESSURE: ValueStorage.DATA_KEY_PRESSURE_IN, + bmp_180.KEY_TEMPERATURE: ValueStorage.DATA_KEY_2ND_TEMPERATURE_IN + }, + wetation_protocol.ENVDATA_STATISTIC_DHT: { + dht_22.KEY_HUMIDITY: ValueStorage.DATA_KEY_HUMIDITY_IN, + dht_22.KEY_TEMPERATURE: ValueStorage.DATA_KEY_TEMPERATURE_IN + }, + }, + self.SRC_ID_OUT: { + wetation_protocol.ENVDATA_STATISTIC_BMP: { + bmp_180.KEY_PRESSURE: ValueStorage.DATA_KEY_PRESSURE_OUT, + bmp_180.KEY_TEMPERATURE: ValueStorage.DATA_KEY_2ND_TEMPERATURE_OUT + }, + wetation_protocol.ENVDATA_STATISTIC_DHT: { + dht_22.KEY_HUMIDITY: ValueStorage.DATA_KEY_HUMIDITY_OUT, + dht_22.KEY_TEMPERATURE: ValueStorage.DATA_KEY_TEMPERATURE_OUT + }, + } + }.get(src_id, {}).get(data_id, {}).get(key, default_value) + + def data_receive_callback(self, data, src_id): + if src_id in [self.SRC_ID_IN, self.SRC_ID_OUT] and data.get_data_id() in [wetation_protocol.ENVDATA_STATISTIC_DHT, wetation_protocol.ENVDATA_STATISTIC_BMP]: + try: + for key in data.get_data(): + if key != bmp_180.KEY_TIME: + drk = self.__data_receive_key__(src_id, data.get_data_id(), key) + if drk is not None: + self.__process_rx_data__( + drk, + helpers.continues_statistic(**data.get_data()[key]) + ) + else: + self.__warning_rx_data__('Unknown RX-Data', data, src_id) + except TypeError as e: + self.__warning_rx_data__('Wront DataType in RX-Data (%s)' % e, data, src_id) + else: + drk = self.__data_receive_key__(src_id, data.get_data_id()) + if drk is not None: + self.__process_rx_data__( + drk, + data.get_data() + ) + else: + self.__warning_rx_data__('Unknown RX-Data', data, src_id) + + def __process_rx_data__(self, drk, data): + self.__value_storage__.append(drk, data) + + def __warning_rx_data__(self, desc, data, src_id): + logger.warning('%s from %s: %s', desc, self.SRC_NAMES.get(src_id, 'Unknown'), repr(data)) + + def __check_data_status__(self): + if dict.get(self.__value_storage__, ValueStorage.DATA_KEY_TEMPERATURE_IN) is None and dict.get(self.__value_storage__, ValueStorage.DATA_KEY_2ND_TEMPERATURE_IN) is not None: + self.in_temperature.SetBackgroundColour((255, 255, 200, 255)) + else: + self.in_temperature.SetBackgroundColour((250, 249, 255, 255)) + if dict.get(self.__value_storage__, ValueStorage.DATA_KEY_TEMPERATURE_OUT) is None and dict.get(self.__value_storage__, ValueStorage.DATA_KEY_2ND_TEMPERATURE_OUT) is not None: + self.out_temperature.SetBackgroundColour((255, 255, 200, 255)) + else: + self.out_temperature.SetBackgroundColour((250, 249, 255, 255)) + if dict.get(self.__value_storage__, ValueStorage.DATA_KEY_GATE_POSITION) is None: + self.heading_garage.SetBackgroundColour((142, 35, 35, 255)) + else: + self.heading_garage.SetBackgroundColour((35, 35, 142, 255)) + + def gui_update(self, event): + # + # TIME and DATE + # + self.time.SetLabel(time.strftime("%H:%M")) + self.date.SetLabel(time.strftime("%d.%m.%Y")) + # + update_list = [ + # WET-OUT + (self.out_humidity.SetLabel, [ValueStorage.DATA_KEY_HUMIDITY_OUT, 'mean', True]), + (self.out_pressure.SetLabel, [ValueStorage.DATA_KEY_PRESSURE_OUT, 'mean', True]), + (self.out_temperature.SetLabel, [ValueStorage.DATA_KEY_TEMPERATURE_OUT, 'mean', True]), + (self.out_temperature_max.SetLabel, [ValueStorage.DATA_KEY_TEMPERATURE_OUT, 'max', True]), + (self.out_temperature_min.SetLabel, [ValueStorage.DATA_KEY_TEMPERATURE_OUT, 'min', True]), + # WET-IN + (self.in_humidity.SetLabel, [ValueStorage.DATA_KEY_HUMIDITY_IN, 'mean', True]), + (self.in_pressure.SetLabel, [ValueStorage.DATA_KEY_PRESSURE_IN, 'mean', True]), + (self.in_temperature.SetLabel, [ValueStorage.DATA_KEY_TEMPERATURE_IN, 'mean', True]), + (self.in_temperature_max.SetLabel, [ValueStorage.DATA_KEY_TEMPERATURE_IN, 'max', True]), + (self.in_temperature_min.SetLabel, [ValueStorage.DATA_KEY_TEMPERATURE_IN, 'min', True]), + # GATE + (self.gate_position.SetValue, [ValueStorage.DATA_KEY_GATE_POSITION, None, False, 50]) + ] + # + for func, args in update_list: + func(self.__value_storage__.get(*args)) + self.__check_data_status__() + # + # self.Layout() event.Skip() def run(self): self.__task_1s__.run() - self.__task_10s__.run() - self.__task_60s__.run() def close(self): self.__task_1s__.stop() self.__task_1s__.join() - self.__task_10s__.stop() - self.__task_10s__.join() - self.__task_60s__.stop() - self.__task_60s__.join() def __del__(self): self.close() @@ -360,14 +367,12 @@ class WetationFrameProt(gui.Wetation): class MyApp(wx.App): def OnInit(self): - self.frame = WetationFrameProt(None, wx.ID_ANY, "") + self.frame = Wetation(None, wx.ID_ANY, "") self.SetTopWindow(self.frame) self.frame.Show() return True - - if __name__ == "__main__": report.appLoggingConfigure(os.path.dirname(__file__), config.LOGTARGET, ((config.APP_NAME, config.LOGLVL), ), fmt=config.formatter, host=config.LOGHOST, port=config.LOGPORT) # diff --git a/socket_protocol b/socket_protocol index b5ee202..a8aa159 160000 --- a/socket_protocol +++ b/socket_protocol @@ -1 +1 @@ -Subproject commit b5ee20216e9215dd6555d5bae702a48e7512ecce +Subproject commit a8aa15974b309b3f916fe4312538e166ae2f3691