Example #1
0
 def execute(self, handler, cmd, source):
     """
     Execute an arbitrary command
     :param handler: CLIHandler to use for reply
     :param cmd: Received command
     :param source: Call source
     :return: TRUE: Command found and handled, FALSE: Unknown command, nothing done
     """
     if self.plugin and getattr(self.plugin, 'alive', False):
         if self.logics is None:
             self.logics = Logics.get_instance()
         for command, data in self._commands.items():
             if cmd == command or cmd.startswith(command + " "):
                 self.logger.debug(
                     "try to dispatch command '{}'".format(cmd))
                 try:
                     data['function'](handler, cmd.lstrip(command).strip(),
                                      source)
                 except Exception as e:
                     self.logger.exception(e)
                     handler.push(
                         "Exception \"{0}\" occured when executing command \"{1}\".\n"
                         .format(e, command))
                     handler.push("See smarthomeNG log for details\n")
                 return True
     return False
Example #2
0
    def __init__(self, smarthome, dispatcher, sock, addr, items, visu_logics,
                 proto, querydef):
        lib.connection.Stream.__init__(self, sock, addr)
        self.terminator = b"\r\n\r\n"
        self.logger = logging.getLogger(__name__)
        self._sh = smarthome
        self.shtime = dispatcher.shtime
        self._dp = dispatcher
        self.found_terminator = self.parse_header
        self.addr = addr
        self.header = {}
        self.monitor = {'item': [], 'rrd': [], 'log': []}
        self.monitor_id = {'item': 'item', 'rrd': 'item', 'log': 'name'}
        self._update_series = {}
        self.items = items
        self.rrd = False
        self.log = False
        self.logs = self._sh.return_logs()
        self._series_lock = threading.Lock()
        self.visu_logics = visu_logics
        self.proto = proto
        self.querydef = querydef
        self.logger.info(
            "VISU: Websocket handler uses protocol version {0}".format(
                self.proto))
        self.sw = ''
        self.swversion = ''
        self.hostname = ''
        self.browser = ''
        self.browserversion = ''

        # get access to the logics api
        from lib.logic import Logics
        self.logics = Logics.get_instance()
        return
Example #3
0
    def logics_initialize(self):
        """
        Initialize access to logics API and test if Blockly plugin is loaded
        
        This can't be done during __init__, since not all components are loaded/initialized
        at that time.
        """
        if self.logics is not None:
            return

        self.logics = Logics.get_instance()
        self.yaml_updates = (self.logics.return_config_type() == '.yaml')

        # find out if blockly plugin is loaded
        if self.blockly_plugin_loaded == None:
            self.blockly_plugin_loaded = False
            #            for x in self._sh._plugins:
            #            for x in self._sh.return_plugins():
            for x in self.plugins.return_plugins():
                try:
                    if x.get_shortname() == 'blockly':
                        self.blockly_plugin_loaded = True
                except:
                    pass
        return
Example #4
0
    def run(self):
        """
        This is called when the plugins thread is about to run
        """
        self.alive = True
        self.logics = Logics.get_instance() # Returns the instance of the Logics class, to be used to access the logics-api
        q = self._updater.start_polling(timeout=self._long_polling_timeout)   # (poll_interval=0.0, timeout=10, network_delay=None, clean=False, bootstrap_retries=0, read_latency=2.0, allowed_updates=None)
        if self._pretty_thread_names:
            self.logger.debug("Changing Telegrams thread names to pretty thread names")
            try:
                for t in self._updater._Updater__threads:
                  if 'dispatcher' in t.name: 
                    t.name = 'Telegram Dispatcher'
                    
                  if 'updater' in t.name: 
                    t.name = 'Telegram Updater'
                    
                for t in self._updater.dispatcher._Dispatcher__async_threads:
                  *_, num = t.name.split('_')
                  t.name = 'Telegram Worker {}'.format(num) if num.isnumeric() else num

            except:
                self.logger.warning("Could not assign pretty names to Telegrams threads, maybe object model of python-telegram-bot module has changed? Please inform the author of plugin!")
        self.logger.debug("started polling the updater, Queue is {}".format(q))
        self.msg_broadcast(self._welcome_msg)
        self.logger.debug("sent welcome message {}")
Example #5
0
    def run(self):
        self.alive = True
        self.logics = Logics.get_instance(
        )  # Returns the instance of the Logics class, to be used to access the logics-api

        self._updater.start_polling(
        )  # (poll_interval=0.0, timeout=10, network_delay=None, clean=False, bootstrap_retries=0, read_latency=2.0, allowed_updates=None)
Example #6
0
    def __init__(self):

        # !! Cannot initialze self.logics here, because at startup logics are initialized after plugins !!
        self.logics = Logics.get_instance()
        self.logger.info("BackendLogics __init__ self.logics = {}".format(self.logics))
        self.plugins = Plugins.get_instance()
        self.logger.info("BackendLogics __init__ self.plugins = {}".format(str(self.plugins)))
        self.scheduler = Scheduler.get_instance()
        self.logger.info("BackendLogics __init__ self.scheduler = {}".format(self.scheduler))
Example #7
0
    def index(self, reload=None):
        """
        Build index.html for cherrypy

        Display a list of all connected visu clients
        Render the template and return the html file to be delivered to the browser

        :return: contents of the template after beeing rendered
        """

        # get API handles that were unavailable during __init__
        if self.items is None:
            self.items = Items.get_instance()
        if self.logics is None:
            self.logics = Logics.get_instance()

        clients = []

        for clientinfo in self.plugin.return_clients():
            c = clientinfo.get('addr', '')
            client = dict()
            client['ip'] = clientinfo.get('ip', '')
            client['port'] = clientinfo.get('port', '')
            try:
                client['name'] = socket.gethostbyaddr(client['ip'])[0]
            except:
                client['name'] = client['ip']

            client['sw'] = clientinfo.get('sw', '')
            client['swversion'] = clientinfo.get('swversion', '')
            client['protocol'] = clientinfo.get('protocol', '')
            client['hostname'] = clientinfo.get('hostname', '')
            client['browser'] = clientinfo.get('browser', '')
            client['browserversion'] = clientinfo.get('browserversion', '')
            clients.append(client)

        clients_sorted = sorted(clients, key=lambda k: k['name'])

        plgitems = []
        for item in self.items.return_items():
            if ('visu_acl' in item.conf):
                plgitems.append(item)

        plglogics = []
        for logic in self.logics.return_logics():
            plglogics.append(self.logics.get_logic_info(logic))

        tmpl = self.tplenv.get_template('index.html')
        return tmpl.render(p=self.plugin,
                           items=sorted(plgitems,
                                        key=lambda k: str.lower(k['_path'])),
                           logics=sorted(plglogics,
                                         key=lambda k: str.lower(k['name'])),
                           clients=clients_sorted,
                           client_count=len(clients_sorted))
Example #8
0
    def index_html(self, cmd='', filename='', logicname='', v=0):

        self.logger.info(
            "index_html: cmd = '{}', filename = '{}', logicname = '{}'".format(
                cmd, filename, logicname))
        if self.edit_redirect != '':
            self.edit_html(cmd='edit', logicname=self.edit_redirect)

        if self.logics is None:
            self.logics = Logics.get_instance()

        cherrypy.lib.caching.expires(0)

        if cmd == '' and filename == '' and logicname == '':
            cmd = self.cmd
            if cmd == '':
                cmd = 'new'

        self.cmd = cmd.lower()
        self.logger.info(
            "index_html: cmd = {}, filename = {}, logicname = {}".format(
                cmd, filename, logicname))
        if self.cmd == '':
            #            self.logic_filename = ''
            self.logicname = ''
        elif self.cmd == 'new':
            self.logic_filename = 'new'
            self.logicname = ''
        elif self.cmd == 'edit' and filename != '':
            self.logic_filename = filename
            self.logicname = logicname
        self.logger.info(
            "index_html: self.logicname = '{}', self.logic_filename = '{}'".
            format(self.logicname, self.logic_filename))

        language = self._sh.get_defaultlanguage()
        if language != get_translation_lang():
            self.logger.debug(
                "index_html: Language = '{}' get_translation_lang() = '{}'".
                format(language, get_translation_lang()))
            if not load_translation(language):
                self.logger.warning(
                    "index_html: Language '{}' not found, using standard language instead"
                    .format(language))

        tmpl = self.tplenv.get_template('blockly.html')
        return tmpl.render(smarthome=self._sh,
                           dyn_sh_toolbox=self._DynToolbox(self._sh),
                           cmd=self.cmd,
                           logicname=logicname,
                           timestamp=str(time.time()),
                           lang=translation_lang)
Example #9
0
 async def get_shng_class_instances(self):
     """
     Ensure that the instance vars for items and logics are initialized
     """
     while self.items is None:
         self.items = Items.get_instance()
         if self.items is None:
             await asyncio.sleep(1)
     while self.logics is None:
         self.logics = Logics.get_instance()
         if self.logics is None:
             await asyncio.sleep(1)
     return
Example #10
0
    def __init__(self, module):
        self._sh = module._sh
        self.module = module
        self.base_dir = self._sh.get_basedir()
        self.logger = logging.getLogger(__name__)

        self.etc_dir = self._sh._etc_dir

        self.logics_dir = os.path.join(self.base_dir, 'logics')
        self.logics = Logics.get_instance()
        self.logger.info("__init__ self.logics = {}".format(self.logics))
        self.plugins = Plugins.get_instance()
        self.logger.info("__init__ self.plugins = {}".format(str(
            self.plugins)))
        self.scheduler = Scheduler.get_instance()
        self.logger.info("__init__ self.scheduler = {}".format(self.scheduler))

        self.blockly_plugin_loaded = None
        self.logics_data = {}

        self.logics = Logics.get_instance()
        return
Example #11
0
 def run(self):
     """
     This is called when the plugins thread is about to run
     """
     self.alive = True
     self.logics = Logics.get_instance(
     )  # Returns the instance of the Logics class, to be used to access the logics-api
     q = self._updater.start_polling(
         timeout=self._long_polling_timeout
     )  # (poll_interval=0.0, timeout=10, network_delay=None, clean=False, bootstrap_retries=0, read_latency=2.0, allowed_updates=None)
     self.logger.debug("started polling the updater, Queue is {}".format(q))
     self._msg_broadcast(self._welcome_msg)
     self.logger.debug("sent welcome message {}")
Example #12
0
    def _add_scene_entry(self,
                         item,
                         state,
                         ditemname,
                         value,
                         learn=False,
                         name=''):
        """
        Adds a single assignement entry to the loaded scenes
        
        :param item: item defing the scene (type: scene)
        :param row: list of: state number, item to assign to, value to assign to item
        :param name: name of the scene state
        :type item: item object
        :type row: list (with 3 entries)
        :type name: str
        """
        logger.debug(
            "_add_scene_entry: item = {}, state = {}, ditem = {}, value = {}, learn = {}, name = {}"
            .format(item.id(), state, ditemname, value, learn, name))
        value = item.get_stringwithabsolutepathes(value, 'sh.', '(', 'scene')
        #        ditem = self._sh.return_item(item.get_absolutepath(ditemname, attribute='scene'))
        ditem = self.items.return_item(
            item.get_absolutepath(ditemname, attribute='scene'))

        if learn:
            rvalue = self._eval(value)
            if str(rvalue) != value:
                logger.warning(
                    "_add_scene_entry - Learn set to 'False', because '{}' != '{}'"
                    .format(rvalue, value))
                learn = False

        if ditem is None:
            ditem = Logics.return_logic(ditemname)
            if ditem is None:
                logger.warning(
                    "Could not find item or logic '{}' specified in {}".format(
                        ditemname, scene_file))
                return

        if item.id() in self._scenes:
            if state in self._scenes[item.id()]:
                self._scenes[item.id()][state].append(
                    [ditem, value, name, learn])
            else:
                self._scenes[item.id()][state] = [[ditem, value, name, learn]]
        else:
            self._scenes[item.id()] = {state: [[ditem, value, name, learn]]}
        return
Example #13
0
    def __init__(self, smarthome):
        self._sh = smarthome

        global _scenes_instance
        if _scenes_instance is not None:
            import inspect
            curframe = inspect.currentframe()
            calframe = inspect.getouterframes(curframe, 2)
            logger.critical(translate("A second 'scenes' object has been created. There should only be ONE instance of class 'Scenes'!!! Called from: {frame1} ({frame2})", {'frame1': calframe[1][1], 'frame2': calframe[1][3]}))

        _scenes_instance = self

        self.items = Items.get_instance()
        self.logics = Logics.get_instance()

        self._load_scenes()
        return
Example #14
0
    def run(self):
        """
        This is called when the plugins thread is about to run
        """
        self.alive = True
        self.logics = Logics.get_instance(
        )  # Returns the instance of the Logics class, to be used to access the logics-api
        q = self._updater.start_polling(
            timeout=self._long_polling_timeout
        )  # (poll_interval=0.0, timeout=10, network_delay=None, clean=False, bootstrap_retries=0, read_latency=2.0, allowed_updates=None)
        if self._pretty_thread_names:
            if self.logger.isEnabledFor(logging.DEBUG):
                self.logger.debug(
                    "Changing Telegrams thread names to pretty thread names")
            try:
                for t in self._updater._Updater__threads:
                    if 'dispatcher' in t.name:
                        t.name = 'Telegram Dispatcher'
                    if 'updater' in t.name:
                        t.name = 'Telegram Updater'

                for t in self._updater.dispatcher._Dispatcher__async_threads:
                    *_, num = t.name.split('_')
                    t.name = f'Telegram Worker {num}' if num.isnumeric(
                    ) else num

                # from telegram.jobqueue.py @ line 301 thread is named
                # name=f"Bot:{self._dispatcher.bot.id}:job_queue"
                if hasattr(self._updater.job_queue, '_JobQueue__thread'):
                    t = self._updater.job_queue._JobQueue__thread
                    if t.name.startswith('Bot'):
                        _, id, _ = t.name.split(':')
                        self._updater.job_queue._JobQueue__thread.name = f"Telegram JobQueue for id {id}"
                else:
                    # model in telegram.ext.jobqueue.py might be changed now
                    pass
            except Exception as e:
                self.logger.warning(
                    f"Error '{e}' occurred. Could not assign pretty names to Telegrams threads, maybe object model of python-telegram-bot module has changed? Please inform the author of plugin!"
                )
        if self.logger.isEnabledFor(logging.DEBUG):
            self.logger.debug(f"started polling the updater, Queue is {q}")
        if self._welcome_msg:
            self.msg_broadcast(self._welcome_msg)
            if self.logger.isEnabledFor(logging.DEBUG):
                self.logger.debug(f"sent welcome message {self._welcome_msg}")
Example #15
0
    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 = logging.getLogger(__name__)
        self.webif_dir = webif_dir
        self.plugin = plugin

        self.tplenv = self.init_template_environment()

        # try to get API handles
        self.items = Items.get_instance()
        self.logics = Logics.get_instance()
Example #16
0
    def _add_scene_entry(self, item, state, ditemname, value, learn=False, name=''):
        """
        Adds a single assignement entry to the loaded scenes
        
        :param item: item defing the scene (type: scene)
        :param row: list of: state number, item to assign to, value to assign to item
        :param name: name of the scene state
        :type item: item object
        :type row: list (with 3 entries)
        :type name: str
        """
        logger.debug("_add_scene_entry: item = {}, state = {}, ditem = {}, value = {}, learn = {}, name = {}".format(item.id(), state, ditemname, value, learn, name))
        value = item.get_stringwithabsolutepathes(value, 'sh.', '(', 'scene')
#        ditem = self._sh.return_item(item.get_absolutepath(ditemname, attribute='scene'))
        ditem = self.items.return_item(item.get_absolutepath(ditemname, attribute='scene'))

        if learn:
            rvalue = self._eval(value)
            if str(rvalue) != value:
                logger.warning("_add_scene_entry - Learn set to 'False', because '{}' != '{}'".format(rvalue, value))
                learn = False
        
        if ditem is None:
            ditem = Logics.return_logic(ditemname)
            if ditem is None:
                logger.warning("Could not find item or logic '{}' specified in {}".format(ditemname, scene_file))
                return

        if item.id() in self._scenes:
            if state in self._scenes[item.id()]:
                self._scenes[item.id()][state].append([ditem, value, name, learn])
            else:
                self._scenes[item.id()][state] = [[ditem, value, name, learn]]
        else:
            self._scenes[item.id()] = {state: [[ditem, value, name, learn]]}
        return
Example #17
0
    def __init__(self, sh, testparam=''):
        """
        Initialization Routine for the module
        """
        # TO DO: Shortname anders setzen (oder warten bis der Plugin Loader es beim Laden setzt
        self._shortname = self.__class__.__name__
        self._shortname = self._shortname.lower()

        self.logger = logging.getLogger(__name__)
        self._sh = sh
        self.etc_dir = sh._etc_dir
        self.shtime = Shtime.get_instance()

        self.logger.debug("Module '{}': Initializing".format(self._shortname))

        # get the parameters for the module (as defined in metadata module.yaml):
        self.logger.debug("Module '{}': Parameters = '{}'".format(self._shortname, dict(self._parameters)))
        self.ip = self.get_parameter_value('ip')
        #if self.ip == '0.0.0.0':
        #    self.ip = Utils.get_local_ipv4_address()
        self.port = self.get_parameter_value('port')
        self.tls_port = self.get_parameter_value('tls_port')
        self.use_tls = self.get_parameter_value('use_tls')
        self.tls_cert = self.get_parameter_value('tls_cert')
        self.tls_key = self.get_parameter_value('tls_key')

        # parameters for smartVISU handling are initialized by the smartvisu plugin
        #self.sv_enabled = self.get_parameter_value('sv_enabled')
        #self.sv_acl = self.get_parameter_value('default_acl')
        #self.sv_querydef = self.get_parameter_value('sv_querydef')
        #self.sv_ser_upd_cycle = self.get_parameter_value('sv_ser_upd_cycle')
        self.sv_enabled = False
        self.sv_acl = 'deny'
        self.sv_querydef = False
        self.sv_ser_upd_cycle = 0

        self.ssl_context = None
        if self.use_tls:
            self.ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
            pem_file = os.path.join(self.etc_dir, self.tls_cert)
            key_file = os.path.join(self.etc_dir, self.tls_key)
            try:
                self.ssl_context.load_cert_chain(pem_file, key_file)
            except Exception as e:
                self.logger.error("Secure websocket port not opened because the following error ocured while initilizing tls: {}".format(e))
                self.ssl_context = None
                self.use_tls = False

        if self.use_tls and self.port == self.tls_port:
            self.logger.error("Secure websocket port not opened because it cannnot be the same port as the ws:// port:")
            self.ssl_context = None
            self.use_tls = False

        self.logger.info("ip         : {}".format(self.ip))
        self.logger.info("port       : {}".format(self.port))
        self.logger.info("tls_port   : {}".format(self.tls_port))
        self.logger.info("use_tls    : {}".format(self.use_tls))
        self.logger.info("tls_cert   : {}".format(self.tls_cert))
        self.logger.info("tls_key    : {}".format(self.tls_key))

        # try to get API handles
        self.items = Items.get_instance()
        self.logics = Logics.get_instance()

        self.loop = None    # Var to hold the event loop for asyncio

        # For Release 1.8 only: Enable smartVISU protocol support even if smartvisu plugin is not loaded
        self.set_smartvisu_support(protocol_enabled=True)
Example #18
0
    def __init__(self):

        self.logics = Logics.get_instance()
        self.logger.warning("BackendLogics __init__ self.logics = {}".format(
            str(self.logics)))
Example #19
0
    def __init__(self, smarthome):
        self._sh = smarthome

        global _scenes_instance
        if _scenes_instance is not None:
            import inspect
            curframe = inspect.currentframe()
            calframe = inspect.getouterframes(curframe, 2)
            logger.critical(
                "A second 'scenes' object has been created. There should only be ONE instance of class 'Scenes'!!! Called from: {} ({})"
                .format(calframe[1][1], calframe[1][3]))

        _scenes_instance = self

        self.items = Items.get_instance()
        self.logics = Logics.get_instance()

        self._scenes = {}
        self._learned_values = {}
        self._scenes_dir = smarthome._scenes_dir
        if not os.path.isdir(self._scenes_dir):
            logger.warning(
                "Directory scenes not found. Ignoring scenes.".format(
                    self._scenes_dir))
            return

        self._learned_values = {}
        #   for item in smarthome.return_items():
        for item in self.items.return_items():
            if item.type() == 'scene':
                self.scene_file = os.path.join(self._scenes_dir, item.id())

                scene_file_yaml = yaml.yaml_load(self.scene_file + '.yaml',
                                                 ordered=False,
                                                 ignore_notfound=True)
                if scene_file_yaml is not None:
                    # Reading yaml file with scene definition
                    for state in scene_file_yaml:
                        actions = scene_file_yaml[state].get('actions', None)
                        if actions is not None:
                            if isinstance(actions, dict):
                                actions = [actions]
                            if isinstance(actions, list):
                                for action in actions:
                                    if isinstance(action, dict):
                                        self._add_scene_entry(
                                            item, str(state),
                                            action.get('item', ''),
                                            str(action.get('value', '')),
                                            action.get('learn', ''),
                                            scene_file_yaml[state].get(
                                                'name', ''))
                                    else:
                                        logger.warning(
                                            "Scene {}, state {}: action '{}' is not a dict"
                                            .format(item, state, action))
                            else:
                                logger.warning(
                                    "Scene {}, state {}: actions are not a list"
                                    .format(item, state))
                    self._load_learned_values(str(item.id()))
                else:
                    # Trying to read conf file with scene definition
                    scene_conf_file = self.scene_file + '.conf'
                    try:
                        with open(scene_conf_file, 'r', encoding='UTF-8') as f:
                            reader = csv.reader(f, delimiter=' ')
                            for row in reader:
                                if row == []:  # ignore empty lines
                                    continue
                                if row[0][0] == '#':  # ignore comments
                                    continue
                                self._add_scene_entry(item, row[0], row[1],
                                                      row[2])
                    except Exception as e:
                        logger.warning(
                            "Problem reading scene file {0}: No .yaml or .conf file found with this name"
                            .format(self.scene_file))
                        continue
                item.add_method_trigger(self._trigger)
Example #20
0
 def run(self):
     self.alive = True
     self.logics = Logics.get_instance(
     )  # Returns the instance of the Logics class, to be used to access the logics-api
Example #21
0
 def setUp(self):
     logger.warning('')
     self.sh = MockSmartHome()
     self._logics = Logics(self.sh, self.sh._logic_conf_basename, self.sh._env_logic_conf_basename)
     self.logics = Logics.get_instance()