diff --git a/README.md b/README.md
index ca76c2f68f97a23452397af837bc044b5f445433..efe36bfbf01b0c4675c0eebb7365a44de2f281ae 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,13 @@ Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation)
 
 ## Recent changes
 
+**9.2.0** - 2024-02-08
+  - functions can be used to publish results via MQTT instead returning the results as response to the POST request
+    - if a function is implemented as generator this behaviour is triggered automatically
+  - bug fixes
+    - the semantic definition of the range of measurements and parameters are properly returned now
+    - profiles of base components of a component are properly returned now
+
 **9.1.2** - 2024-01-19
   - added "all" query parameter for semantics, to request complete semantic data model
   - fixed bug when requesting enum or time measurements and parameters
diff --git a/src/http/server.py b/src/http/server.py
index b8fb03079cce21802a696b02d3629b9a534d5696..35780cb623e682fe7263111fae73d91806fe97b8 100644
--- a/src/http/server.py
+++ b/src/http/server.py
@@ -226,15 +226,14 @@ class HTTPServer(object):
         if isinstance(item, Function):
             try:
                 if item.publishes:
-                    # generator = item.invoke_generator(data["arguments"])
                     try:
-                        async for item in item.invoke_generator(data["arguments"]):
+                        async for item in item.invoke_generator(data["arguments"], legacy_mode=self._legacy_mode):
                             self._publisher.publish('/'.join(uuids), json.dumps(item))
                         response = {}
                     except StopAsyncIteration:
                         pass
                 else:
-                    response = await item.invoke(data["arguments"])
+                    response = await item.invoke(data["arguments"], legacy_mode=self._legacy_mode)
                 status = 200
                 logger.info('Response: {}'.format(response))
             except (DeviceException, ServerException, UserException) as e:
diff --git a/src/soil/component.py b/src/soil/component.py
index 8d2e26f6f7f5280ed2fe72d9233d6eca847ec88d..0ae5d4d023967b00bb6da72ca747d1e3bb51a18b 100644
--- a/src/soil/component.py
+++ b/src/soil/component.py
@@ -83,6 +83,7 @@ class Component(Element):
         self._components = components
         self._parameters = parameters
         self._implementation = implementation
+        self._profile_path: str = None
 
     @property
     def children(self) -> List[Element]:
@@ -379,6 +380,7 @@ class Component(Element):
 
     def load_semantics(self, profiles_path: str, metadata_path: str, parent_name: str) -> None:
         super().load_semantics(profiles_path, metadata_path, parent_name)
+        self._profile_path = profiles_path
 
         for child in self.children:
             child.load_semantics(profiles_path, metadata_path, f"{parent_name}{self.uuid[4:].capitalize()}")
@@ -392,7 +394,14 @@ class Component(Element):
         elif kind == 'metadata':
             result = self._metadata
         else:
-            raise DeviceException('The provided kind of semantic information cannot be returned.')
+            try:
+                shape_filename = os.path.join(self._profile_path, f'{kind.replace("Shape", "")}.shacl.ttl')
+                result = rdflib.Graph()
+                result.parse(shape_filename)
+                result.add((rdflib.URIRef(Semantics.namespace[kind]), Namespaces.dcterms.license,
+                            Semantics.profile_license))
+            except Exception:
+                raise DeviceException('The provided kind of semantic information cannot be returned.')
 
         if recursive:
             for child in self._components + self._measurements + self._parameters:
@@ -400,7 +409,26 @@ class Component(Element):
 
         return result
 
+    def _is_semantic_path_of_base_profile(self, profile: rdflib.Graph, suffix: str) -> bool:
+        imported_profiles = list(profile.objects(predicate=Namespaces.owl.imports))
+        for imported_profile in imported_profiles:
+            if Semantics.namespace not in imported_profile:
+                continue
+            imported_profile_name = imported_profile.toPython().replace(Semantics.namespace, '')
+            if imported_profile_name == suffix:
+                return True
+            else:
+                base_shape_filename = os.path.join(self._profile_path, f'{imported_profile_name.replace("Shape", "")}.shacl.ttl')
+                base_graph = rdflib.Graph().parse(base_shape_filename)
+                if self._is_semantic_path_of_base_profile(base_graph, suffix):
+                    return True
+        return False
+
     def resolve_semantic_path(self, suffix: str) -> (Element, str):
+        # we need to check FIRST if the requested semantic path refers to the profile of a base component of this component
+        if self._is_semantic_path_of_base_profile(self._metadata_profile, suffix):
+            return self, suffix
+
         try:
             return super().resolve_semantic_path(suffix)
         except ChildNotFoundException:
@@ -411,15 +439,6 @@ class Component(Element):
                 except ChildNotFoundException:
                     continue
 
-            # check if the profile of this component imports a shape which matches the path
-            imported_profiles = list(self._metadata_profile.objects(predicate=Namespaces.owl.imports))
-            for imported_profile in imported_profiles:
-                if imported_profile.toPython().replace(Semantics.namespace, '') == suffix:
-                    # TODO implement loading and returning of the base components profile
-                    #  (is not present as element, so might require adaption of the method signature,
-                    #  might also be called recursively, if the base component has own bases which are queried)
-                    raise ChildNotFoundException('Profiles of base components can currently not be returned.')
-
             raise ChildNotFoundException('Could not resolve the semantic path.')
 
     @property
diff --git a/src/soil/figure.py b/src/soil/figure.py
index 1b28f0788f105e779aca7288941be9b980b9897b..f833f03631f09ac7011a868b2bdb52f00ed95156 100644
--- a/src/soil/figure.py
+++ b/src/soil/figure.py
@@ -15,7 +15,7 @@ from .semantics import Namespaces
 nest_asyncio.apply()
 
 from .element import Element
-from .error import DimensionException, RangeException, TypeException, NotImplementedException
+from .error import DimensionException, RangeException, TypeException, NotImplementedException, ChildNotFoundException
 from ..utils import root_logger
 from ..utils.constants import HTTP_GET, HTTP_OPTIONS
 from ..utils.error import DeviceException
@@ -99,6 +99,7 @@ class Figure(Element, ABC):
                         predecessor=e)
 
                 Figure.check_all(self._datatype, self._dimension, self._range, value)
+                self._value = value
                 return value
             else:
                 return self._value
@@ -319,3 +320,13 @@ class Figure(Element, ABC):
             return self._getter
         else:
             raise NotImplementedException(self._uuid, self._name)
+
+    def resolve_semantic_path(self, suffix: str) -> (Element, str):
+        try:
+            return super().resolve_semantic_path(suffix)
+        except ChildNotFoundException:
+            # check if the path fits the range
+            if suffix == f'{self.semantic_name.split("/")[-1]}Range':
+                return self, 'range'
+
+            raise ChildNotFoundException('Could not resolve the semantic path.')
diff --git a/src/soil/function.py b/src/soil/function.py
index 504a5b381455a54869e5df55be2e83403633f357..1676f523f447e125acdfc23f72cb099982685bfe 100644
--- a/src/soil/function.py
+++ b/src/soil/function.py
@@ -1,3 +1,4 @@
+import datetime
 import inspect
 import json
 from typing import Any, Dict, List, Union, Callable
@@ -6,7 +7,7 @@ import rdflib
 
 from .element import Element
 from .error import InvokationException, NotImplementedException, ChildNotFoundException
-from .figure import Figure
+from .figure import Figure, serialize_time
 from .parameter import Parameter
 from ..utils import root_logger
 from ..utils.constants import HTTP_GET, HTTP_OPTIONS
@@ -87,7 +88,7 @@ class Function(Element):
         else:
             super().__setitem__(key, value)
 
-    def _prepare_invocation_result(self, result: Any) -> Dict[str, List[Dict[str, Any]]]:
+    def _prepare_invocation_result(self, result: Any, legacy_mode: bool = False) -> Dict[str, List[Dict[str, Any]]]:
         returns = {"returns": []}
         if result is not None:
             # if only one element is returned encapsulate result with tuple to make for-loop working
@@ -107,10 +108,13 @@ class Function(Element):
                 else:
                     var = var[0]
                     Figure.check_all(var.datatype, var.dimension, var.range, value)
-                    returns['returns'] += [{'uuid': uuid, 'value': value}]
+                    ret = self.__getitem__([uuid]).serialize([], legacy_mode, HTTP_OPTIONS)
+                    ret['value'] = value
+                    ret['timestamp'] = serialize_time(datetime.datetime.now())
+                    returns['returns'] += [ret]
         return returns
 
-    async def invoke_generator(self, arguments: List[Figure]) -> Dict[str, List[Dict[str, Any]]]:
+    async def invoke_generator(self, arguments: List[Figure], legacy_mode: bool = False) -> Dict[str, List[Dict[str, Any]]]:
         returns = {"returns": []}
         args = {}
         if self._implementation is None:
@@ -127,7 +131,7 @@ class Function(Element):
                 while True:
                     try:
                         result = await anext(generator)
-                        yield self._prepare_invocation_result(result)
+                        yield self._prepare_invocation_result(result, legacy_mode)
                     except StopAsyncIteration as e:
                         raise e
             else:
@@ -136,13 +140,16 @@ class Function(Element):
                 while True:
                     try:
                         result = next(generator)
-                        yield self._prepare_invocation_result(result)
+                        yield self._prepare_invocation_result(result, legacy_mode)
                     except StopIteration as e:
                         raise e
+        except StopIteration or StopAsyncIteration as e:
+            raise e
         except Exception as e:
             raise DeviceException(str(e), predecessor=e)
 
-    async def invoke(self, arguments: List[Figure]) -> Dict[str, List[Dict[str, Any]]]:
+
+    async def invoke(self, arguments: List[Figure], legacy_mode: bool = False) -> Dict[str, List[Dict[str, Any]]]:
         args = {}
         if self._implementation is None:
             raise NotImplementedException(self._uuid, self._name)
@@ -161,7 +168,7 @@ class Function(Element):
         except Exception as e:
             raise DeviceException(str(e), predecessor=e)
 
-        return self._prepare_invocation_result(result)
+        return self._prepare_invocation_result(result, legacy_mode)
 
     def serialize(self, keys: List[str], legacy_mode: bool, method: int = HTTP_GET) -> Dict[str, Any]:
         if not keys or 'all' in keys:
diff --git a/src/soil/measurement.py b/src/soil/measurement.py
index 35adbd3aa3fd7667f992d910956f4348c35f9739..6f30a7554ebbc9664ca8d7d55a4782570290fd2b 100644
--- a/src/soil/measurement.py
+++ b/src/soil/measurement.py
@@ -1,3 +1,4 @@
+import copy
 import datetime
 import warnings
 from typing import Dict, Callable, List
@@ -177,6 +178,13 @@ class Measurement(Figure):
             result = self._metadata_profile
         elif kind == 'metadata':
             result = self._metadata
+        elif kind == 'range':
+            range_graph = copy.deepcopy(self._metadata)
+            subjects = range_graph.subjects()
+            for subject in subjects:
+                if subject != Semantics.namespace[f'{self._semantic_name}Range']:
+                    range_graph.remove((subject, None, None))
+            return range_graph
         elif kind == 'data':
             data_graph = rdflib.Graph()
             data_graph.bind('sosa', Namespaces.sosa)
diff --git a/src/soil/parameter.py b/src/soil/parameter.py
index 466d78882600c5c7370f1749976fc548f0bebc05..b70da8cad7c6b5e1633f7eaa81a9f63015a3e797 100644
--- a/src/soil/parameter.py
+++ b/src/soil/parameter.py
@@ -63,7 +63,7 @@ class Parameter(Figure):
         :return: the value of the attribute indicated by 'item'.
         """
         if item == "constant":
-            return self._setter is None
+            return self._setter is None and self.uuid[:3] == 'PAR'
         return super().__getitem__(item, method)
 
     def serialize(self, keys: [str], legacy_mode: bool, method=HTTP_GET):
@@ -139,6 +139,13 @@ class Parameter(Figure):
     def serialize_semantics(self, kind: str, recursive=False) -> rdflib.Graph:
         if kind == 'profile':
             result = self._metadata_profile
+        elif kind == 'range':
+            range_graph = copy.deepcopy(self._metadata)
+            subjects = range_graph.subjects()
+            for subject in subjects:
+                if subject != Semantics.namespace[f'{self._semantic_name}Range']:
+                    range_graph.remove((subject, None, None))
+            return range_graph
         elif kind == 'metadata':
             result = copy.deepcopy(self._metadata)