diff --git a/platypush/entities/sensors.py b/platypush/entities/sensors.py
index f3489ac90..1bd94a148 100644
--- a/platypush/entities/sensors.py
+++ b/platypush/entities/sensors.py
@@ -18,21 +18,39 @@ logger = logging.getLogger(__name__)
 
 
 class Sensor(Device):
+    """
+    Abstract class for sensor entities. A sensor entity is, by definition, an
+    entity with the ``is_read_only`` property set to ``True``.
+    """
+
     __abstract__ = True
 
-    def __init__(self, *args, is_read_only=True, **kwargs):
-        super().__init__(*args, is_read_only=is_read_only, **kwargs)
+    def __init__(self, *args, **kwargs):
+        kwargs['is_read_only'] = True
+        super().__init__(*args, **kwargs)
 
 
 if 'raw_sensor' not in Base.metadata:
 
     class RawSensor(Sensor):
+        """
+        Models a raw sensor, whose value can contain either a string, a
+        hex-encoded binary string, or a JSON-encoded object.
+        """
+
         __tablename__ = 'raw_sensor'
 
         id = Column(
             Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True
         )
         value = Column(String)
+        is_binary = Column(Boolean, default=False)
+        """ If ``is_binary`` is ``True``, then ``value`` is a hex string. """
+        is_json = Column(Boolean, default=False)
+        """
+        If ``is_json`` is ``True``, then ``value`` is a JSON-encoded string
+        object or array.
+        """
 
         __mapper_args__ = {
             'polymorphic_identity': __tablename__,
@@ -42,6 +60,11 @@ if 'raw_sensor' not in Base.metadata:
 if 'numeric_sensor' not in Base.metadata:
 
     class NumericSensor(Sensor):
+        """
+        Models a numeric sensor, with a numeric value and an optional min/max
+        range.
+        """
+
         __tablename__ = 'numeric_sensor'
 
         id = Column(
@@ -60,18 +83,22 @@ if 'numeric_sensor' not in Base.metadata:
 if 'binary_sensor' not in Base.metadata:
 
     class BinarySensor(Sensor):
+        """
+        Models a binary sensor, with a binary boolean value.
+        """
+
         __tablename__ = 'binary_sensor'
 
         def __init__(self, *args, value=None, **kwargs):
             if isinstance(value, str):
                 value = value.lower()
 
-            if value in {True, 1, '1', 't', 'true', 'on', 'ON'}:
+            if str(value).lower() in {'1', 't', 'true', 'on'}:
                 value = True
-            elif value in {False, 0, '0', 'f', 'false', 'off', 'OFF'}:
+            elif str(value).lower() in {'0', 'f', 'false', 'off'}:
                 value = False
             elif value is not None:
-                logger.warning(f'Unsupported value for BinarySensor type: {value}')
+                logger.warning('Unsupported value for BinarySensor type: %s', value)
                 value = None
 
             super().__init__(*args, value=value, **kwargs)
@@ -89,6 +116,10 @@ if 'binary_sensor' not in Base.metadata:
 if 'enum_sensor' not in Base.metadata:
 
     class EnumSensor(Sensor):
+        """
+        Models an enum sensor, whose value belongs to a set of pre-defined values.
+        """
+
         __tablename__ = 'enum_sensor'
 
         id = Column(
@@ -96,16 +127,22 @@ if 'enum_sensor' not in Base.metadata:
         )
         value = Column(String)
         values = Column(JSON)
+        """ Possible values for the sensor, as a JSON array. """
 
         __mapper_args__ = {
             'polymorphic_identity': __tablename__,
         }
 
 
-if 'multi_value_sensor' not in Base.metadata:
+if 'composite_sensor' not in Base.metadata:
 
-    class MultiValueSensor(Sensor):
-        __tablename__ = 'multi_value_sensor'
+    class CompositeSensor(Sensor):
+        """
+        A composite sensor is a sensor whose value can be mapped to a JSON
+        object (either a dictionary or an array)
+        """
+
+        __tablename__ = 'composite_sensor'
 
         id = Column(
             Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True