diff --git a/platypush/backend/http/templates/nav.html b/platypush/backend/http/templates/nav.html
index 83968be3..b340f52e 100644
--- a/platypush/backend/http/templates/nav.html
+++ b/platypush/backend/http/templates/nav.html
@@ -1,9 +1,27 @@
+{%
+    with pluginIcons = {
+        'light.hue': 'fa fa-lightbulb',
+        'media.mplayer': 'fa fa-film',
+        'media.mpv': 'fa fa-film',
+        'media.omxplayer': 'fa fa-film',
+        'media.vlc': 'fa fa-film',
+        'music.mpd': 'fa fa-music',
+        'music.snapcast': 'fa fa-volume-up',
+        'tts': 'fa fa-comment',
+        'tts.google': 'fa fa-comment',
+    }
+%}
+
 <nav>
     <ul>
         {% for plugin in plugins|sort %}
-            <li :class="{selected: '{{ plugin }}' == selectedPlugin}">
+            <li :class="{selected: '{{ plugin }}' == selectedPlugin}" title="{{ plugin }}">
                 <a href="#{{ plugin }}" @click="selectedPlugin = '{{ plugin }}'">
-                    {{ plugin }}
+                    {% if plugin in pluginIcons %}
+                        <i class="{{ pluginIcons[plugin] }}"></i>
+                    {% else %}
+                        {% raw %}{{ plugin }}{{% endraw %}
+                    {% endif %}
                 </a>
             </li>
         {% endfor %}
@@ -14,3 +32,5 @@
     </ul>
 </nav>
 
+{% endwith %}
+
diff --git a/platypush/plugins/__init__.py b/platypush/plugins/__init__.py
index 43677735..2ac59461 100644
--- a/platypush/plugins/__init__.py
+++ b/platypush/plugins/__init__.py
@@ -48,7 +48,6 @@ class Plugin(EventGenerator):
             .get('action', [])
         )
 
-
     def run(self, method, *args, **kwargs):
         if method not in self.registered_actions:
             raise RuntimeError('{} is not a registered action on {}'.format(
diff --git a/platypush/plugins/adafruit/io.py b/platypush/plugins/adafruit/io.py
index 27e8b2a0..23a7009b 100644
--- a/platypush/plugins/adafruit/io.py
+++ b/platypush/plugins/adafruit/io.py
@@ -8,10 +8,10 @@ from Adafruit_IO import Client
 from Adafruit_IO.errors import ThrottlingError
 
 from platypush.context import get_backend
-from platypush.message import Message
 from platypush.plugins import Plugin, action
 
-data_throttler_lock = Lock()
+data_throttler_lock = None
+
 
 class AdafruitIoPlugin(Plugin):
     """
@@ -49,7 +49,7 @@ class AdafruitIoPlugin(Plugin):
 
     _DATA_THROTTLER_QUEUE = 'platypush/adafruit.io'
 
-    def __init__(self, username, key, throttle_seconds=None, *args, **kwargs):
+    def __init__(self, username, key, throttle_seconds=None, **kwargs):
         """
         :param username: Your Adafruit username
         :type username: str
@@ -57,33 +57,39 @@ class AdafruitIoPlugin(Plugin):
         :param key: Your Adafruit IO key
         :type key: str
 
-        :param throttle_seconds: If set, then instead of sending the values directly over ``send`` the plugin will first collect all the samples within the specified period and then dispatch them to Adafruit IO. You may want to set it if you have data sources providing a lot of data points and you don't want to hit the throttling limitations of Adafruit.
+        :param throttle_seconds: If set, then instead of sending the values directly over ``send`` the plugin will
+            first collect all the samples within the specified period and then dispatch them to Adafruit IO.
+            You may want to set it if you have data sources providing a lot of data points and you don't want to hit
+            the throttling limitations of Adafruit.
         :type throttle_seconds: float
         """
 
-        super().__init__(*args, **kwargs)
+        global data_throttler_lock
+        super().__init__(**kwargs)
 
         self._username = username
         self._key = key
         self.aio = Client(username=username, key=key)
         self.throttle_seconds = throttle_seconds
 
+        if not data_throttler_lock:
+            data_throttler_lock = Lock()
+
         if self.throttle_seconds and not data_throttler_lock.locked():
-            redis = self._get_redis()
+            self._get_redis()
             self.logger.info('Starting Adafruit IO throttler thread')
             data_throttler_lock.acquire(False)
             self.data_throttler = Thread(target=self._data_throttler())
             self.data_throttler.start()
 
-
-    def _get_redis(self):
+    @staticmethod
+    def _get_redis():
         from redis import Redis
 
         redis_args = get_backend('redis').redis_args
         redis_args['socket_timeout'] = 1
         return Redis(**redis_args)
 
-
     def _data_throttler(self):
         from redis.exceptions import TimeoutError as QueueTimeoutError
 
@@ -104,7 +110,7 @@ class AdafruitIoPlugin(Plugin):
                         pass
 
                     if data and (last_processed_batch_timestamp is None or
-                                time.time() - last_processed_batch_timestamp >= self.throttle_seconds):
+                                 time.time() - last_processed_batch_timestamp >= self.throttle_seconds):
                         last_processed_batch_timestamp = time.time()
                         self.logger.info('Processing feeds batch for Adafruit IO')
 
@@ -115,7 +121,8 @@ class AdafruitIoPlugin(Plugin):
                                 try:
                                     self.send(feed, value, enqueue=False)
                                 except ThrottlingError:
-                                    self.logger.warning('Adafruit IO throttling threshold hit, taking a nap before retrying')
+                                    self.logger.warning('Adafruit IO throttling threshold hit, taking a nap ' +
+                                                        'before retrying')
                                     time.sleep(self.throttle_seconds)
 
                         data = {}
@@ -135,7 +142,9 @@ class AdafruitIoPlugin(Plugin):
         :param value: Value to send
         :type value: Numeric or string
 
-        :param enqueue: If throttle_seconds is set, this method by default will append values to the throttling queue to be periodically flushed instead of sending the message directly. In such case, pass enqueue=False to override the behaviour and send the message directly instead.
+        :param enqueue: If throttle_seconds is set, this method by default will append values to the throttling queue
+            to be periodically flushed instead of sending the message directly. In such case, pass enqueue=False to
+            override the behaviour and send the message directly instead.
         :type enqueue: bool
         """
 
@@ -145,8 +154,7 @@ class AdafruitIoPlugin(Plugin):
         else:
             # Otherwise send it to the Redis queue to be picked up by the throttler thread
             redis = self._get_redis()
-            redis.rpush(self._DATA_THROTTLER_QUEUE, json.dumps({feed:value}))
-
+            redis.rpush(self._DATA_THROTTLER_QUEUE, json.dumps({feed: value}))
 
     @action
     def send_location_data(self, feed, lat, lon, ele, value):
@@ -169,12 +177,19 @@ class AdafruitIoPlugin(Plugin):
         :type value: Numeric or string
         """
 
-        self.aio.send_location_data(feed=feed, value=value, lat=lat, lon=lon, ele=ele)
+        self.aio.send_data(feed=feed, value=value, metadata={
+            'lat': lat,
+            'lon': lon,
+            'ele': ele,
+        })
 
     @classmethod
     def _cast_value(cls, value):
-        try: value = float(value)
-        except: pass
+        try:
+            value = float(value)
+        except ValueError:
+            pass
+
         return value
 
     def _convert_data_to_dict(self, *data):
@@ -188,7 +203,6 @@ class AdafruitIoPlugin(Plugin):
             } for i in data
         ]
 
-
     @action
     def receive(self, feed, limit=1):
         """
@@ -243,7 +257,7 @@ class AdafruitIoPlugin(Plugin):
         :type feed: str
 
         :param data_id: Data point ID to remove
-        :type data_id: int
+        :type data_id: str
         """
 
         self.aio.delete(feed, data_id)
diff --git a/platypush/plugins/music/mpd/__init__.py b/platypush/plugins/music/mpd/__init__.py
index f8574931..c3601c9e 100644
--- a/platypush/plugins/music/mpd/__init__.py
+++ b/platypush/plugins/music/mpd/__init__.py
@@ -6,6 +6,7 @@ import time
 from platypush.plugins import action
 from platypush.plugins.music import MusicPlugin
 
+
 class MusicMpdPlugin(MusicPlugin):
     """
     This plugin allows you to interact with an MPD/Mopidy music server.  MPD
diff --git a/platypush/plugins/music/snapcast.py b/platypush/plugins/music/snapcast.py
index 9c227f4a..cb12b95f 100644
--- a/platypush/plugins/music/snapcast.py
+++ b/platypush/plugins/music/snapcast.py
@@ -29,7 +29,7 @@ class MusicSnapcastPlugin(Plugin):
         :type port: int
         """
 
-        super().__init__(*args, **kwargs)
+        super().__init__(**kwargs)
 
         self.host = host
         self.port = port
diff --git a/platypush/plugins/tts/__init__.py b/platypush/plugins/tts/__init__.py
index ddd32495..7a61c626 100644
--- a/platypush/plugins/tts/__init__.py
+++ b/platypush/plugins/tts/__init__.py
@@ -3,6 +3,7 @@ import urllib.parse
 
 from platypush.plugins import Plugin, action
 
+
 class TtsPlugin(Plugin):
     """
     Default Text-to-Speech plugin. It leverages Google Translate.
@@ -28,15 +29,13 @@ class TtsPlugin(Plugin):
         :type language: str
         """
         if language is None: language=self.lang
-        output = None
-        errors = []
         cmd = ['mplayer -ao alsa -really-quiet -noconsolecontrols ' +
                '"http://translate.google.com/translate_tts?{}"'
                .format(urllib.parse.urlencode({
-                   'ie'     : 'UTF-8',
-                   'client' : 'tw-ob',
-                   'tl'     : language,
-                   'q'      : text,
+                   'ie': 'UTF-8',
+                   'client': 'tw-ob',
+                   'tl': language,
+                   'q': text,
                 }))]
 
         try:
diff --git a/platypush/plugins/tts/google.py b/platypush/plugins/tts/google.py
index d67e1e45..db3b7ce0 100644
--- a/platypush/plugins/tts/google.py
+++ b/platypush/plugins/tts/google.py
@@ -6,6 +6,7 @@ from google.cloud import texttospeech
 
 from platypush.plugins import Plugin, action
 
+
 class TtsGooglePlugin(Plugin):
     """
     Advanced text-to-speech engine that leverages the Google Cloud TTS API.
diff --git a/platypush/utils/__init__.py b/platypush/utils/__init__.py
index 292ac15e..dad6a6fb 100644
--- a/platypush/utils/__init__.py
+++ b/platypush/utils/__init__.py
@@ -12,6 +12,7 @@ import urllib.request
 
 logger = logging.getLogger(__name__)
 
+
 def get_module_and_method_from_action(action):
     """ Input  : action=music.mpd.play
         Output : ('music.mpd', 'play') """
@@ -19,7 +20,7 @@ def get_module_and_method_from_action(action):
     tokens = action.split('.')
     module_name = str.join('.', tokens[:-1])
     method_name = tokens[-1:][0]
-    return (module_name, method_name)
+    return module_name, method_name
 
 
 def get_message_class_by_type(msgtype):
@@ -49,6 +50,32 @@ def get_event_class_by_type(type):
     return getattr(event_module, type.split('.')[-1])
 
 
+def get_plugin_module_by_name(plugin_name):
+    """ Gets the module of a plugin by name (e.g. "music.mpd" or "media.vlc") """
+
+    module_name = 'platypush.plugins.' + plugin_name
+    try:
+        return importlib.import_module('platypush.plugins.' + plugin_name)
+    except ImportError as e:
+        logger.error('Cannot import {}: {}'.format(module_name, str(e)))
+        return None
+
+
+def get_plugin_class_by_name(plugin_name):
+    """ Gets the class of a plugin by name (e.g. "music.mpd" or "media.vlc") """
+
+    module = get_plugin_module_by_name(plugin_name)
+    if not module:
+        return
+
+    class_name = getattr(module, ''.join([_.capitalize() for _ in plugin_name.split('.')]) + 'Plugin')
+    try:
+        return getattr(module, ''.join([_.capitalize() for _ in plugin_name.split('.')]) + 'Plugin')
+    except Exception as e:
+        logger.error('Cannot import class {}: {}'.format(class_name, str(e)))
+        return None
+
+
 def set_timeout(seconds, on_timeout):
     """
     Set a function to be called if timeout expires without being cleared.