diff --git a/SDK/CPP/public/include/voltu/defines.hpp b/SDK/CPP/public/include/voltu/defines.hpp
index 19f2416f2812cc41b69b6c2f73a7a7f3bd4f7588..513190c63f792199e063c857f48def876794660a 100644
--- a/SDK/CPP/public/include/voltu/defines.hpp
+++ b/SDK/CPP/public/include/voltu/defines.hpp
@@ -1,5 +1,5 @@
 /**
- * @file system.hpp
+ * @file defines.hpp
  * @copyright Copyright (c) 2020 Sebastian Hahta, MIT License
  * @author Sebastian Hahta
  */
@@ -20,3 +20,15 @@
 /// Lifetime of the return value is tied to the lifetime of a parent object
 #define PY_RV_LIFETIME_PARENT
 #endif
+
+#ifndef PY_SINGLETON
+/// Singleton instance, members exported to module. Requires creating the
+/// instance in PyModule constructor.
+#define PY_SINGLETON
+#endif
+
+#ifndef PY_SINGLETON_OBJECT
+/// Export as singleton instance instead of exporting members to module
+#define PY_SINGLETON_OBJECT
+#endif
+
diff --git a/SDK/CPP/public/include/voltu/initialise.hpp b/SDK/CPP/public/include/voltu/initialise.hpp
index 4a6e5b3ffc2c2326b5934d2577d0458605ddc51c..5d34a1e691797b8c4922aa274775d7f84ef401ac 100644
--- a/SDK/CPP/public/include/voltu/initialise.hpp
+++ b/SDK/CPP/public/include/voltu/initialise.hpp
@@ -13,34 +13,34 @@ namespace voltu
 {
 	/**
 	 * @brief Get core VolTu instance.
-	 * 
+	 *
 	 * This method returns a smart pointer to a singleton VolTu runtime
 	 * instance and must be the first VolTu call. On any given machine it is
 	 * only sensible and possible to have one runtime instance of VolTu due to
 	 * its use of hardware devices. Multiple real instances are not possible.
-	 * 
+	 *
 	 * @code
 	 * int main(int argc, char** argv) {
 	 *     auto vtu = voltu::instance();
-	 * 
+	 *
 	 *     vtu->open("device:camera");
 	 *     ...
 	 * }
 	 * @endcode
-	 * 
+	 *
 	 * @note
 	 * This method must only be called once.
-	 * 
+	 *
 	 * @throw voltu::exceptions::LibraryLoadFailed
 	 * If runtime not found or is invalid.
 	 *
 	 * @throw voltu::exceptions::RuntimeVersionMismatch
 	 * If major or minor version does not match the SDK headers.
-	 * 
+	 *
 	 * @throw voltu::exceptions::RuntimeAlreadyInUse
 	 * If a runtime instance is in use by another application.
-	 * 
+	 *
 	 * @return Singleton VolTu runtime instance.
 	 */
-	PY_API std::shared_ptr<voltu::System> instance();
+	std::shared_ptr<voltu::System> instance();
 }
diff --git a/SDK/CPP/public/include/voltu/system.hpp b/SDK/CPP/public/include/voltu/system.hpp
index 6a7e4cd96387a6e50b4933dad6892eb52104755d..0ac85870c0579ac953d40430d60507026f3bf94b 100644
--- a/SDK/CPP/public/include/voltu/system.hpp
+++ b/SDK/CPP/public/include/voltu/system.hpp
@@ -29,50 +29,51 @@ struct Version
 
 /**
  * @brief Singleton Voltu system instance.
- * 
+ *
  * Provides access to the key components such as opening streams or files and
  * creating virtual cameras. Use `voltu::instance()` to obtain the object. All
- * object instances in VolTu are managed by shared smart pointers.
+ * object instances in VolTu are managed by shared smart pointers. Python API
+ * automatically creates instance available as voltu.System.
  */
-class System
+PY_SINGLETON_OBJECT class System
 {
 public:
 	virtual ~System() = default;
-	
+
 	/**
 	 * @brief Get the runtime version information.
-	 * 
+	 *
 	 * This method gets the VolTu version of the runtime shared library, which
 	 * may not be the same as the version of the SDK here.
-	 * 
+	 *
 	 * @see voltu.hpp
-	 * 
+	 *
 	 * @return Always returns semantic versioning structure.
 	 */
 	virtual voltu::Version getVersion() const = 0;
 
 	/**
 	 * @brief Make a virtual room or composite room.
-	 * 
+	 *
 	 * @return A new virtual room instance.
 	 */
 	PY_API virtual voltu::RoomPtr createRoom() = 0;
 
 	/**
 	 * @brief Create a virtual observer.
-	 * 
+	 *
 	 * An observer renderers virtual camera views, audio and other data from
 	 * submitted framesets. It is possible and recommended that a single
 	 * observer instance be used to renderer multiple different views, rather
 	 * than creating lots of observers. This saves memory resources.
-	 * 
+	 *
 	 * @return A new observer instance.
 	 */
 	PY_API virtual voltu::ObserverPtr createObserver() = 0;
 
 	/**
 	 * @brief Open a file, device or network stream using a URI.
-	 * 
+	 *
 	 * All data sources in VolTu are represented by Universal Resource
 	 * Identifiers (URIs), with some non-standard additions. A few examples
 	 * are:
@@ -83,11 +84,11 @@ public:
 	 * * `./file.ftl`
 	 * * `device:camera`
 	 * * `device:screen`
-	 * 
+	 *
 	 * Note that returning from this call does not guarantee that the source
 	 * is fully open and operational, this depends on network handshakes or
 	 * file processing that occurs asynchronously.
-	 * 
+	 *
 	 * @throw voltu::exceptions::BadSourceURI If an unrecognised URI is given.
 	 * @return A feed management object for the data source.
 	 */
@@ -95,14 +96,14 @@ public:
 
 	/**
 	 * @brief Get a list of all available rooms.
-	 * 
+	 *
 	 * A room is a 3D captured physical space, or a combination of such spaces,
 	 * and is represented by a unique identifier within the local system. This
 	 * method obtains a list of all available rooms from all sources. To obtain
 	 * rooms, either use `open` or `createRoom`.
-	 * 
+	 *
 	 * @return A list of room ids, which can be empty.
-	 * 
+	 *
 	 * @see getRoom
 	 * @see open
 	 */
@@ -110,13 +111,13 @@ public:
 
 	/**
 	 * @brief Get a room instance from identifier.
-	 * 
+	 *
 	 * A room instance enables access to all data frames associated with that
 	 * room, including image data. Calling `getRoom` with the same ID
 	 * multiple times will return different smart pointers to room instances
 	 * but provides access to the same data regardless and is valid. An invalid
 	 * room ID will throw an exception.
-	 * 
+	 *
 	 * @throw voltu::exceptions::InvalidRoomId If the ID does not exist.
 	 * @return Room instance or accessing room data.
 	 */
@@ -127,14 +128,14 @@ public:
 
 	/**
 	 * @brief Make an empty operator pipeline for frame processing.
-	 * 
+	 *
 	 * A pipeline allows a sequence of processing operations to be applied to
 	 * a data frame. These operations include stereo correspondence, fusion,
 	 * data evaluation and various image processing operations. Only some
 	 * of these operators are exposed in the SDK. Once a pipeline instance
 	 * is obtained, you can add specific operators to it, configure them and
 	 * then submit frames from processing.
-	 * 
+	 *
 	 * @return A unique pipeline instance.
 	 */
 	PY_API virtual voltu::PipelinePtr createPipeline() = 0;
diff --git a/SDK/CPP/public/python/CMakeLists.txt b/SDK/CPP/public/python/CMakeLists.txt
index 473b0626c2190b4602b485b855fa3447ca3839bc..27a2a8bdf953f51e343883412aebbbdbf6a14c0b 100644
--- a/SDK/CPP/public/python/CMakeLists.txt
+++ b/SDK/CPP/public/python/CMakeLists.txt
@@ -18,7 +18,7 @@ add_custom_command(
             ${CMAKE_CURRENT_SOURCE_DIR}/../include
             ${SDK_AUTO_HEADERS}
 
-    DEPENDS voltu_sdk
+    DEPENDS voltu_sdk gen.py
 )
 
 pybind11_add_module(voltu_sdk_py MODULE
diff --git a/SDK/CPP/public/python/README.md b/SDK/CPP/public/python/README.md
index a5cd30d6d96bab1733841acf5bca73947d6655f0..52773c98c80059795aed630660c4c882de90c671 100644
--- a/SDK/CPP/public/python/README.md
+++ b/SDK/CPP/public/python/README.md
@@ -1,7 +1,8 @@
 # Python API generator
 
 Dependencies
- * python3-ply (build only)
+ * python3-dev
+ * python3-ply
 
 Build system uses Pybind11 to generate a python module. Most of the bindings are
 automatically generated by gen.py script which is automatically called by CMake
@@ -14,11 +15,14 @@ build. Several (empty) macros are used in headers to annoate Python API details.
 
  * PY_API function/method is to be included in Python API
  * PY_NO_SHARED_PTR shared_ptr<> is not used with instances of this class.
-   https://pybind11.readthedocs.io/en/latest/advanced/smart_ptrs.html?#std-shared-ptr
+   See [pybind11 documentation](https://pybind11.readthedocs.io/en/latest/advanced/smart_ptrs.html?#std-shared-ptr)
+   for techncal details.
  * PY_RV_LIFETIME_PARENT lifetime of method's return valued is tied to
-   lifetime of parent objects (this). (return_value_policy::reference_internal
+   lifetime of parent objects (this). (
+   [return_value_policy::reference_internal](https://pybind11.readthedocs.io/en/latest/advanced/functions.html#return-value-policies)
    is set for this method)
-   https://pybind11.readthedocs.io/en/latest/advanced/functions.html#return-value-policies
+ * PY_SINGLETON Singleton class, methods are exported to to module scope.
+ * PY_SINGLETON_OBJECT Singleton instance is accessible as module attribute.
 
 ## Notes:
  * Binding to default constructor is generated for structs. Class constructors
@@ -28,6 +32,10 @@ build. Several (empty) macros are used in headers to annoate Python API details.
  * Default arguments are supported (extracted from header).
  * Public class properties are available in python, read-only if const,
    otherwise read write.
+ * Singletons have to be created in PyModule constructor and be available
+   as class members.
+ * Exceptions have to be included manually in module.cpp
+ * C++ preprocessor is not used
 
 ## Not supported (yet) in automatic binding generation:
  * Nested classes
@@ -35,3 +43,4 @@ build. Several (empty) macros are used in headers to annoate Python API details.
  * Constructors
  * Automatic documentation (Doxygen)
  * Generator does not verify that shared_ptr<> is used consistently/correctly
+ * Member variables of singleton classes
diff --git a/SDK/CPP/public/python/automatic_bindings.cpp.in b/SDK/CPP/public/python/automatic_bindings.cpp.in
deleted file mode 100644
index 291de8913a266dd029a6e7ccbc4e7f3796ed82d3..0000000000000000000000000000000000000000
--- a/SDK/CPP/public/python/automatic_bindings.cpp.in
+++ /dev/null
@@ -1,15 +0,0 @@
-{includes}
-
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-#include <pybind11/eigen.h>
-
-#include "types/image.hpp"
-
-namespace py = pybind11;
-
-using namespace voltu;
-
-void py_automatic_bindings(py::module& m) {{
-    {code}
-}}
diff --git a/SDK/CPP/public/python/examples/example1.py b/SDK/CPP/public/python/examples/example1.py
index 1cc1a26681470b9212662da2959224daf35bf89c..e124328892a0164790e029c0f447f8df58d0ba60 100644
--- a/SDK/CPP/public/python/examples/example1.py
+++ b/SDK/CPP/public/python/examples/example1.py
@@ -3,7 +3,6 @@
 
 import cv2
 import voltu
-import time
 import sys
 import os
 
@@ -11,23 +10,15 @@ if len(sys.argv) != 2:
 	print("%s filename" % os.path.basename(__file__))
 	exit(1)
 
-#if not os.path.exists(sys.argv[1]):
-#	print("can't find %s" % sys.argv[1])
-#	exit(1)
-
-api = voltu.instance()
+api = voltu.System
 api.open(sys.argv[1])
 room = api.getRoom(0)
 
 while True:
-	try:
-		room.waitNextFrame(1000)
+	if room.waitNextFrame(1000):
 		frames = room.getFrame().getImageSet(voltu.Channel.kColour)
 		im = frames[0].getHost()
 		cv2.imshow("im", im)
 
-		if cv2.waitKey(10) == 27:
-			break
-
-	except Exception as e:
-		print(e)
+	if cv2.waitKey(10) == 27:
+		break
diff --git a/SDK/CPP/public/python/examples/example2.py b/SDK/CPP/public/python/examples/example2.py
index 629fec948de0f93c9d94184e8a79033afb211896..8b8bfcf777d558ef8e267ce4a6685af564d15b22 100644
--- a/SDK/CPP/public/python/examples/example2.py
+++ b/SDK/CPP/public/python/examples/example2.py
@@ -3,7 +3,6 @@
 
 import cv2
 import voltu
-import time
 import sys
 import os
 
@@ -11,25 +10,17 @@ if len(sys.argv) != 2:
 	print("%s filename" % os.path.basename(__file__))
 	exit(1)
 
-#if not os.path.exists(sys.argv[1]):
-#	print("can't find %s" % sys.argv[1])
-#	exit(1)
-
-api = voltu.instance()
+api = voltu.System
 api.open(sys.argv[1])
 room = api.getRoom(0)
 cam = api.createCamera()
 
 while True:
-	try:
-		room.waitNextFrame(1000)
+	if room.waitNextFrame(1000):
 		cam.submit(room.getFrame())
 		frames = cam.getFrame().getImageSet(voltu.Channel.kColour)
 		im = frames[0].getHost()
 		cv2.imshow("im", im)
 
-		if cv2.waitKey(10) == 27:
-			break
-
-	except Exception as e:
-		print(e)
+	if cv2.waitKey(10) == 27:
+		break
diff --git a/SDK/CPP/public/python/gen.py b/SDK/CPP/public/python/gen.py
index 00e8252c7efea6975acc331c5076453aa5c3695b..649b45b6f69f731ff38c9c0a833b7c0fd8b27474 100755
--- a/SDK/CPP/public/python/gen.py
+++ b/SDK/CPP/public/python/gen.py
@@ -1,5 +1,30 @@
 #!/usr/bin/env python3
 
+"""
+Python binding generator. Creates pybind11 bindings for given headers.
+See README.md for details.
+"""
+
+template = """ /* This file was automatically generated by gen.py. */
+
+{includes}
+
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include <pybind11/eigen.h>
+
+#include "types/image.hpp"
+#include "module.hpp"
+
+namespace py = pybind11;
+
+using namespace voltu;
+
+void PyModule::py_automatic_bindings(py::module& m) {{
+    {code}
+}}
+"""
+
 import sys
 import os
 
@@ -19,12 +44,12 @@ def get_loc_msg(data):
 def print_warn(msg, loc=None):
     if loc is not None:
         msg += " " + get_loc_msg(loc)
-    print("WARNING: %s" % msg, file=sys.stderr)
+    print("gen.py warning: %s" % msg, file=sys.stderr)
 
 def print_err(msg, loc=None):
     if loc is not None:
         msg += " " + get_loc_msg(loc)
-    print("ERROR: %s" % msg, file=sys.stderr)
+    print("gen.py error: %s" % msg, file=sys.stderr)
 
 def include_in_api(data):
     return "PY_API" in data["debug"]
@@ -49,23 +74,14 @@ def create_enum_bindigs(enum, parent=[], pybind_handle="", export_values=False):
 
     return "\n\t".join(cpp)
 
-def create_function_bindings(func, parent=[], pybind_handle=None):
-    func_name = func["name"]
-    full_name = parent + [func_name]
-    full_name_cpp = "::".join(full_name)
-
-    if "PY_API" not in func["debug"]:
-        print_err("%s not included in Python API" % full_name_cpp, func)
-        raise ValueError("No PY_API")
-
-    args = ["\"{0}\"".format(func_name), "&{0}".format(full_name_cpp)]
+def process_func_args(func):
+    args = []
 
     for param in func["parameters"]:
         param_name = param["name"]
 
-        if  param_name == "&":
-            print_warn("Argument name missing for %s" % full_name_cpp, func)
-
+        if  param_name in ["&", "", "*"]:
+            print_warn("Argument name missing for %s" % func["name"])
             continue
 
         if "default" in param:
@@ -74,9 +90,50 @@ def create_function_bindings(func, parent=[], pybind_handle=None):
         else:
             args.append("py::arg(\"{0}\")".format(param_name))
 
+    return args
+
+def wrap_lambda(func, instance_ptr, capture=True):
+    """ Wrap func to instance (singleton) with C++ lambda """
+    args_lambda = []
+    args_lambda_sig = []
+    for i, param in enumerate(func["parameters"]):
+        argname = "p" + str(i)
+        args_lambda_sig.append("%s %s" % (param["type"], argname))
+        args_lambda.append(argname)
+
+    return "[%s](%s){ return %s->%s(%s); }" % (
+        ("&" if capture else ""),
+        ", ".join(args_lambda_sig),
+        instance_ptr,
+        func["name"],
+        ", ".join(args_lambda))
+
+def create_function_bindings(func, parent=[], pybind_handle=None, bind_to_singleton=None):
+    """ Create function bindings, if bind_to_singleton is set, C++ lamda is
+    generated to wrap the call to instance (named by bind_by_singleton).
+    """
+
+    func_name = func["name"]
+    full_name = parent + [func_name]
+    full_name_cpp = "::".join(full_name)
+
+    if not include_in_api(func):
+        print_err("%s not included in Python API" % full_name_cpp, func)
+        raise ValueError("No PY_API")
+
+    args = ["\"{0}\"".format(func_name)]
+
+    if bind_to_singleton is None:
+        args.append("&{0}".format(full_name_cpp))
+
+    else:
+        args.append(wrap_lambda(func, bind_to_singleton))
+
+    args += process_func_args(func)
+
     if "PY_RV_LIFETIME_PARENT" in func["debug"]:
-        if func["parent"] is None:
-            print_err("PY_RV_LIFETIME_PARENT used for function", func)
+        if func["parent"] is None or bind_to_singleton is not None:
+            print_err("PY_RV_LIFETIME_PARENT used for function or singleton", func)
             raise ValueError()
 
         args.append("py::return_value_policy::reference_internal")
@@ -88,6 +145,8 @@ def create_function_bindings(func, parent=[], pybind_handle=None):
     return cpp
 
 def create_class_bindings(cls, parent=[], pybind_handle=""):
+    """ Create bindings for a class """
+
     cls_name = cls["name"]
     full_name = parent + [cls_name]
     cpp = []
@@ -116,8 +175,30 @@ def create_class_bindings(cls, parent=[], pybind_handle=""):
 
     return "\n\t\t".join(cpp)
 
-if __name__ == "__main__":
+def create_singleton_bindings(instance_ptr, cls, parent=[], pybind_handle="", export=False):
+    """ Singleton class bindings, either creates a singleton instance or
+    exports functions directly to module. Singleton pointer available with
+    instance_ptr, which should be class member of PyModule.
+    """
+    if not export:
+        # use usual bindings and export as attribute to pybind handle
+        return "\n\t".join([
+            create_class_bindings(cls, parent, pybind_handle) + ";",
+            "{0}.attr(\"{1}\") = {2};".format(pybind_handle, cls["name"], instance_ptr)
+        ])
+
+    else:
+        # use C++ lambdas to wrap all methods
+        cpp = []
+        for func in cls["methods"]["public"]:
+            if not include_in_api(func):
+                continue
+
+            cpp.append(create_function_bindings(func, parent, pybind_handle, instance_ptr) + ";")
+
+        return "\n\t".join(cpp)
 
+if __name__ == "__main__":
     from pprint import pprint
 
     if (len(sys.argv) < 4):
@@ -131,6 +212,7 @@ if __name__ == "__main__":
 
     out = []
     includes = []
+
     for fname in fsin:
         includes.append(fname)
 
@@ -145,7 +227,13 @@ if __name__ == "__main__":
             ns = data["namespace"]
             # workaround: parser does not save debug in same way as for funcs
             data["debug"] = read_line(data["filename"], data["line_number"])
-            out.append(create_class_bindings(data, [ns], handle) + ";")
+
+            if "PY_SINGLETON_OBJECT" in data["debug"]:
+                out.append(create_singleton_bindings("instance_" + data["name"], data, [ns], handle, False))
+            elif "PY_SINGLETON" in data["debug"]:
+                out.append(create_singleton_bindings("instance_" + data["name"], data, [ns], handle, True))
+            else:
+                out.append(create_class_bindings(data, [ns], handle) + ";")
 
         for data in hdr.functions:
             ns = data["namespace"].strip("::") # bug? in parser
@@ -153,9 +241,7 @@ if __name__ == "__main__":
                 out.append(create_function_bindings(data, [ns], handle) + ";")
 
     includes = "\n".join("#include <{0}>".format(i) for i in includes)
-    template_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "automatic_bindings.cpp.in")
-    with open(template_file, "r") as f:
-        template = f.read()
+
     out = template.format(includes=includes, code="\n\t".join(out))
     with open(fout, "w",) as f:
         f.write(out)
diff --git a/SDK/CPP/public/python/module.cpp b/SDK/CPP/public/python/module.cpp
index 8564a388ef67f2b2adbdc929ae3c2e5e579700c9..636e7b809fcb6757776ef711dd837eb330130c9f 100644
--- a/SDK/CPP/public/python/module.cpp
+++ b/SDK/CPP/public/python/module.cpp
@@ -1,13 +1,16 @@
 
 #include "module.hpp"
 
-#include <voltu/voltu.hpp>
 #include <voltu/initialise.hpp>
 #include <voltu/types/errors.hpp>
 
 namespace py = pybind11;
 
-void py_exceptions(pybind11::module& m) {
+PyModule::PyModule() {
+    instance_System = voltu::instance();
+}
+
+void PyModule::py_exceptions(pybind11::module& m) {
 	py::register_exception<voltu::exceptions::Exception>(m, "Error");
 	py::register_exception<voltu::exceptions::BadImageChannel>(m, "ErrorBadImageChannel");
 	py::register_exception<voltu::exceptions::NoFrame>(m, "ErrorNoFrame");
@@ -15,8 +18,11 @@ void py_exceptions(pybind11::module& m) {
 	py::register_exception<voltu::exceptions::BadSourceURI>(m, "ErrorBadSourceURI");
 }
 
+static auto module = PyModule();
+
 PYBIND11_MODULE(voltu, m) {
 	m.attr("version") = py::make_tuple(VOLTU_VERSION_MAJOR, VOLTU_VERSION_MINOR, VOLTU_VERSION_PATCH);
-	py_exceptions(m);
-	py_automatic_bindings(m);
+
+	module.py_exceptions(m);
+	module.py_automatic_bindings(m);
 }
diff --git a/SDK/CPP/public/python/module.hpp b/SDK/CPP/public/python/module.hpp
index b605cf7f6b7030701858cf8d4cf2ffbba95636bf..f59e4d6280356357b56d4d2db928653aadd4a973 100644
--- a/SDK/CPP/public/python/module.hpp
+++ b/SDK/CPP/public/python/module.hpp
@@ -1,5 +1,15 @@
 #pragma once
 
 #include <pybind11/pybind11.h>
+#include <voltu/voltu.hpp>
+#include <voltu/system.hpp>
 
-void py_automatic_bindings(pybind11::module& m);
+class PyModule {
+public:
+    PyModule();
+    void py_automatic_bindings(pybind11::module& m);
+    void py_exceptions(pybind11::module& m);
+
+private:
+    std::shared_ptr<voltu::System> instance_System;
+};
diff --git a/SDK/CPP/public/python/tests/test_load.py b/SDK/CPP/public/python/tests/test_load.py
index da800f67563627d12ee3809cef2f641dd01ee9a7..5118876f9a66210f24abc674cb782a9cb01a8a48 100644
--- a/SDK/CPP/public/python/tests/test_load.py
+++ b/SDK/CPP/public/python/tests/test_load.py
@@ -1,16 +1,19 @@
 import unittest
 import os
-import voltu
 
 class LoadLibrary(unittest.TestCase):
 
-    def test_get_instance(self):
-        self.assertIsNotNone(voltu.instance())
-        # second call to instance() returns None; should
-        # return same instance instead?
-        # self.assertIsNotNone(voltu.instance())
+    def test_import(self):
+        import voltu
+
+    def test_import_twice(self):
+        # verify that System instance is created just once
+        import voltu
+        import voltu
+        self.assertIsNotNone(voltu.System)
 
     def test_version(self):
+        import voltu
         major, minor, patch = voltu.version
 
 if __name__ == '__main__':