[bluemonkey] - new libbm, ble module
authorKevron Rees <kevron.m.rees@intel.com>
Thu, 19 Feb 2015 00:01:27 +0000 (16:01 -0800)
committerKevron Rees <kevron.m.rees@intel.com>
Thu, 19 Feb 2015 00:01:27 +0000 (16:01 -0800)
16 files changed:
CMakeLists.txt
README.md
lib/debugout.h
plugins/bluemonkey/CMakeLists.txt
plugins/bluemonkey/amb.cpp [new file with mode: 0644]
plugins/bluemonkey/amb.h [new file with mode: 0644]
plugins/bluemonkey/ble.cpp [new file with mode: 0644]
plugins/bluemonkey/ble.h [new file with mode: 0644]
plugins/bluemonkey/bluemonkey.cpp
plugins/bluemonkey/bluemonkey.h
plugins/bluemonkey/bluemonkeynode.cpp [new file with mode: 0644]
plugins/bluemonkey/bmconfig.js [new file with mode: 0644]
plugins/bluemonkey/bmdbus.cpp
plugins/bluemonkey/bmdbus.h
plugins/bluemonkey/config.js
plugins/bluemonkey/db.cpp

index 5d88c1b..e46c364 100644 (file)
@@ -10,7 +10,7 @@ set(PROJECT_NAME "automotive-message-broker")
 set(PROJECT_PRETTY_NAME "Automotive Message Broker")
 set(PROJECT_SERIES "0.15")
 set(PROJECT_MAJOR_VERSION "0.14")
-set(PROJECT_MINOR_VERSION "800")
+set(PROJECT_MINOR_VERSION "801")
 set(PROJECT_VERSION "${PROJECT_MAJOR_VERSION}.${PROJECT_MINOR_VERSION}")
 set(PROJECT_CODENAME "")
 set(PROJECT_QUALITY "alpha")
index 9c4afa8..f3373a6 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Automotive Message Broker Daemon {#ambd}
 
-Version 0.14.800
+Version 0.14.801
 
 ## Introduction
 
index 1f6116e..46e49b3 100644 (file)
@@ -144,7 +144,7 @@ public:
                {
                        ostream out(buf);
                        out.precision(15);
-                       out<<val<<" ";
+                       out<<val;
                }
                return *this;
        }
index 8427b3b..fc06e64 100644 (file)
@@ -42,7 +42,7 @@ if(Qt5Sql_FOUND)
        message(STATUS "enabling database bluemonkey module")
        add_library(bluemonkeyDbModule MODULE db.cpp)
        set_target_properties(bluemonkeyDbModule PROPERTIES PREFIX "")
-       target_link_libraries(bluemonkeyDbModule ${link_libraries} amb -L${CMAKE_CURRENT_BINARY_DIR}/lib ${QT_LIBRARIES} ${Qt5Sql_LIBRARIES})
+       target_link_libraries(bluemonkeyDbModule ${link_libraries} ${QT_LIBRARIES} ${Qt5Sql_LIBRARIES})
        install(TARGETS bluemonkeyDbModule LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH})
 endif()
 
@@ -50,35 +50,56 @@ find_package(Qt5DBus)
 
 if(Qt5DBus_FOUND)
        message(STATUS "enabling dbus bluemonkey module")
-       set(QT_INCLUDE_DIRS ${QT_INCLUDE_DIRS} ${QMAKE_INSTALL_PATH}/include/QtCore/${Qt5Core_VERSION}/QtCore)
        add_executable(bluemonkeyDBusModule bmdbus.cpp)
        set_target_properties(bluemonkeyDBusModule PROPERTIES PREFIX "")
        set_target_properties(bluemonkeyDBusModule PROPERTIES SUFFIX ".so")
-       target_link_libraries(bluemonkeyDBusModule ${link_libraries} amb -L${CMAKE_CURRENT_BINARY_DIR}/lib ${QT_LIBRARIES} ${Qt5DBus_LIBRARIES})
+       target_link_libraries(bluemonkeyDBusModule ${link_libraries} ${QT_LIBRARIES} ${Qt5DBus_LIBRARIES})
        set(QT_INCLUDE_DIRS ${QT_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS})
        install(TARGETS bluemonkeyDBusModule RUNTIME DESTINATION ${PLUGIN_INSTALL_PATH})
 endif()
 
+find_package(Qt5Bluetooth)
+
+if(Qt5Bluetooth_FOUND)
+       message(STATUS "enabling bluetooth LE bluemonkey module")
+       add_executable(bluemonkeyBleModule ble.cpp)
+       set_target_properties(bluemonkeyBleModule PROPERTIES PREFIX "")
+       set_target_properties(bluemonkeyBleModule PROPERTIES SUFFIX ".so")
+       target_link_libraries(bluemonkeyBleModule ${QT_LIBRARIES} ${Qt5Bluetooth_LIBRARIES})
+       set(QT_INCLUDE_DIRS ${QT_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS})
+       install(TARGETS bluemonkeyBleModule RUNTIME DESTINATION ${PLUGIN_INSTALL_PATH})
+endif()
+
 include_directories(${CMAKE_SOURCE_DIR}/lib ${include_dirs} ${communi_INCLUDE_DIRS} ${QT_INCLUDE_DIRS} ${QT_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}/plugins/common)
 
-set(bluemonkeyplugin_headers bluemonkey.h authenticate.h)
-set(bluemonkeyplugin_sources bluemonkey.cpp authenticate.cpp)
+add_executable(bluemonkey bluemonkeynode.cpp)
+target_link_libraries(bluemonkey ${link_libraries} ${QT_LIBRARIES} bm)
+install(TARGETS bluemonkey RUNTIME DESTINATION bin)
+
+add_library(bm SHARED bluemonkey.cpp)
+target_link_libraries(bm dl ${QT_LIBRARIES})
+install(TARGETS bm LIBRARY DESTINATION ${LIB_INSTALL_DIR})
+install (FILES bluemonkey.h DESTINATION ${INCLUDE_INSTALL_DIR}/amb COMPONENT Devel)
+
+set(bluemonkeyplugin_headers amb.h authenticate.h)
+set(bluemonkeyplugin_sources amb.cpp authenticate.cpp)
 
 add_library(bluemonkeyplugin MODULE ${bluemonkeyplugin_sources})
 set_target_properties(bluemonkeyplugin PROPERTIES PREFIX "")
-target_link_libraries(bluemonkeyplugin dl amb -L${CMAKE_CURRENT_BINARY_DIR}/lib ${link_libraries} ${QT_LIBRARIES} ${communi_LIBRARIES} amb-plugins-common -L${CMAKE_CURRENT_BINARY_DIR}/plugins/common)
+target_link_libraries(bluemonkeyplugin dl amb bm -L${CMAKE_CURRENT_BINARY_DIR}/lib ${link_libraries} ${QT_LIBRARIES} ${communi_LIBRARIES} amb-plugins-common -L${CMAKE_CURRENT_BINARY_DIR}/plugins/common)
 
 set(config_files ${CMAKE_CURRENT_BINARY_DIR}/config.js)
 configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.js ${CMAKE_CURRENT_BINARY_DIR}/config.js @ONLY)
+configure_file (${CMAKE_CURRENT_SOURCE_DIR}/bmconfig.js ${CMAKE_CURRENT_BINARY_DIR}/bmconfig.js @ONLY)
 
 install(TARGETS bluemonkeyplugin LIBRARY DESTINATION ${PLUGIN_INSTALL_PATH})
 install (FILES ${config_files} DESTINATION /etc/ambd/bluemonkey)
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/README ${CMAKE_CURRENT_BINARY_DIR}/bluemonkey.README.md @ONLY)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bluemonkey.in.idl ${CMAKE_CURRENT_BINARY_DIR}/docs/bluemonkey.idl @ONLY)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bluemonkey.in.json ${CMAKE_CURRENT_BINARY_DIR}/bluemonkey @ONLY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/bluemonkey.in.json ${CMAKE_CURRENT_BINARY_DIR}/segment/bluemonkey @ONLY)
 
-install (FILES ${CMAKE_CURRENT_BINARY_DIR}/bluemonkey DESTINATION ${PLUGIN_SEGMENT_INSTALL_PATH})
+install (FILES ${CMAKE_CURRENT_BINARY_DIR}/segment/bluemonkey DESTINATION ${PLUGIN_SEGMENT_INSTALL_PATH})
 
 set(bluemonkey_doc_files ${CMAKE_CURRENT_BINARY_DIR}/bluemonkey.README.md)
 
diff --git a/plugins/bluemonkey/amb.cpp b/plugins/bluemonkey/amb.cpp
new file mode 100644 (file)
index 0000000..beaa98e
--- /dev/null
@@ -0,0 +1,442 @@
+#include "amb.h"
+#include <abstractroutingengine.h>
+#include <ambplugin.h>
+#include <debugout.h>
+
+#include <dbusplugin.h>
+#include <dbusexport.h>
+
+#include <QJSEngine>
+#include <QString>
+#include <QVariant>
+
+extern "C" void create(AbstractRoutingEngine* routingengine, map<string, string> config)
+{
+       auto plugin = new AmbPlugin<BluemonkeySink>(routingengine, config);
+       plugin->init();
+}
+
+QVariant gvariantToQVariant(GVariant *value)
+{
+       GVariantClass c = g_variant_classify(value);
+       if(c == G_VARIANT_CLASS_BOOLEAN)
+               return QVariant((bool) g_variant_get_boolean(value));
+
+       else if(c == G_VARIANT_CLASS_BYTE)
+               return QVariant((char) g_variant_get_byte(value));
+
+       else if(c == G_VARIANT_CLASS_INT16)
+               return QVariant((int) g_variant_get_int16(value));
+
+       else if(c == G_VARIANT_CLASS_UINT16)
+               return QVariant((unsigned int) g_variant_get_uint16(value));
+
+       else if(c == G_VARIANT_CLASS_INT32)
+               return QVariant((int) g_variant_get_int32(value));
+
+       else if(c ==  G_VARIANT_CLASS_UINT32)
+               return QVariant((unsigned int) g_variant_get_uint32(value));
+
+       else if(c == G_VARIANT_CLASS_INT64)
+               return QVariant((long long) g_variant_get_int64(value));
+
+       else if(c == G_VARIANT_CLASS_UINT64)
+               return QVariant((unsigned long long) g_variant_get_uint64(value));
+
+       else if(c == G_VARIANT_CLASS_DOUBLE)
+               return QVariant(g_variant_get_double(value));
+
+       else if(c == G_VARIANT_CLASS_STRING)
+               return QVariant(g_variant_get_string(value, NULL));
+
+       else if(c == G_VARIANT_CLASS_ARRAY)
+       {
+               gsize dictsize = g_variant_n_children(value);
+               QVariantList list;
+               for (int i=0; i<dictsize; i++)
+               {
+                       GVariant *childvariant = g_variant_get_child_value(value, i);
+                       GVariant *innervariant = g_variant_get_variant(childvariant);
+                       list.append(gvariantToQVariant(innervariant));
+               }
+               return list;
+       }
+
+       else
+               return QVariant::Invalid;
+
+}
+
+AbstractPropertyType* qVariantToAbstractPropertyType(QString name, QVariant var)
+{
+       if(!var.isValid())
+               return nullptr;
+
+       if(var.type() == QVariant::UInt)
+               return new BasicPropertyType<uint>(name.toStdString(), var.toUInt());
+       else if(var.type() == QVariant::Double)
+               return new BasicPropertyType<double>(name.toStdString(), var.toDouble());
+       else if(var.type() == QVariant::Bool)
+               return new BasicPropertyType<bool>(name.toStdString(), var.toBool());
+       else if(var.type() == QVariant::Int)
+               return new BasicPropertyType<int>(name.toStdString(), var.toInt());
+       else if(var.type() == QVariant::String)
+               return new StringPropertyType(name.toStdString(), var.toString().toStdString());
+       else if(var.type() == QVariant::List && var.toList().count())
+       {
+               QVariant subVariant = var.toList().at(0);
+               if(subVariant.type() == QVariant::UInt)
+                       return new ListPropertyType<uint>(name.toStdString(), subVariant.toUInt());
+               else if(subVariant.type() == QVariant::Double)
+                       return new ListPropertyType<double>(name.toStdString(), subVariant.toDouble());
+               else if(subVariant.type() == QVariant::Bool)
+                       return new ListPropertyType<bool>(name.toStdString(), subVariant.toBool());
+               else if(subVariant.type() == QVariant::Int)
+                       return new ListPropertyType<int>(name.toStdString(), subVariant.toInt());
+               else if(subVariant.type() == QVariant::String)
+                       return new ListPropertyType<std::string>(name.toStdString(), subVariant.toString().toStdString());
+       }
+       return nullptr;
+}
+
+QVariant toQVariant(AbstractPropertyType* val)
+{
+       QVariantMap value;
+
+       value["name"] = val->name.c_str();
+       value["zone"] = val->zone;
+       value["source"] = val->sourceUuid.c_str();
+       value["timestamp"] = val->timestamp;
+       value["sequence"] = val->sequence;
+       value["value"] = gvariantToQVariant(val->toVariant());
+
+       return value;
+}
+
+class BluemonkeyDBusInterface: public DBusSink
+{
+public:
+       BluemonkeyDBusInterface(std::string ifaceName, AbstractRoutingEngine* re, GDBusConnection* connection)
+               :DBusSink(ifaceName, re, connection)
+       {
+
+       }
+};
+
+BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource &parent)
+       : QObject(0), AmbPluginImpl(e, config, parent), mSilentMode(false)
+{
+       bluemonkey = new Bluemonkey(config, this);
+       auth = new Authenticate(config, this);
+}
+
+BluemonkeySink::~BluemonkeySink()
+{
+}
+
+void BluemonkeySink::init()
+{
+       connect(bluemonkey, &Bluemonkey::ready,[this](){bluemonkey->loadModule("amb", this);});
+}
+
+
+PropertyList BluemonkeySink::subscriptions()
+{
+
+}
+
+void BluemonkeySink::supportedChanged(const PropertyList & supportedProperties)
+{
+       DebugOut()<<"supported changed"<<endl;
+}
+
+void BluemonkeySink::propertyChanged(AbstractPropertyType * value)
+{
+
+}
+
+const string BluemonkeySink::uuid() const
+{
+       return "bluemonkey";
+}
+
+int BluemonkeySink::supportedOperations()
+{
+       return AbstractSource::Get | AbstractSource::Set;
+}
+
+QObject *BluemonkeySink::subscribeTo(QString str)
+{
+       return new Property(str.toStdString(), "", routingEngine, Zone::None, this);
+}
+
+QObject *BluemonkeySink::subscribeTo(QString str, int zone, QString srcFilter)
+{
+       return new Property(str.toStdString(), srcFilter, routingEngine, zone, this);
+}
+
+QObject* BluemonkeySink::subscribeTo(QString str, int zone)
+{
+       return new Property(str.toStdString(), "", routingEngine, zone, this);
+}
+
+
+QStringList BluemonkeySink::sourcesForProperty(QString property)
+{
+       std::vector<std::string> list = routingEngine->sourcesForProperty(property.toStdString());
+       QStringList strList;
+       for(auto itr : list)
+       {
+               strList<<itr.c_str();
+       }
+
+       return strList;
+}
+
+QStringList BluemonkeySink::supportedProperties()
+{
+       PropertyList props = routingEngine->supported();
+       QStringList strList;
+       for(auto p : props)
+       {
+               strList<<p.c_str();
+       }
+
+       return strList;
+}
+
+bool BluemonkeySink::authenticate(QString pass)
+{
+
+}
+
+void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTime end, QJSValue cbFunction)
+{
+       double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
+       double e = (double)end.toMSecsSinceEpoch() / 1000.0;
+       AsyncRangePropertyRequest request;
+       request.timeBegin = b;
+       request.timeEnd = e;
+
+       PropertyList reqlist;
+
+       Q_FOREACH(QString prop, properties)
+       {
+               reqlist.push_back(prop.toStdString());
+       }
+
+       request.properties = reqlist;
+       request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
+       {
+               if(!reply->success)
+               {
+                       DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
+                       return;
+               }
+
+               if(cbFunction.isCallable())
+               {
+                       QVariantList list;
+
+                       for(auto val : reply->values)
+                       {
+                               list.append(toQVariant(val));
+                       }
+
+                       QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
+
+                       cbFunction.call(QJSValueList()<<val);
+
+               }
+
+               delete reply;
+       };
+
+       routingEngine->getRangePropertyAsync(request);
+}
+
+void BluemonkeySink::createCustomProperty(QString name, QJSValue defaultValue, int zone)
+{
+       QVariant var = defaultValue.toVariant();
+
+       DebugOut() << "Variant value for: " << name.toStdString() << " is " << defaultValue.toString().toStdString() << endl;
+
+       auto create = [name, var]() -> AbstractPropertyType*
+       {
+               return qVariantToAbstractPropertyType(name, var);
+       };
+
+       addPropertySupport(zone, create);
+
+       AsyncSetPropertyRequest request;
+       request.property = name.toStdString();
+       request.zoneFilter = zone;
+       request.value = VehicleProperty::getPropertyTypeForPropertyNameValue(name.toStdString(), QJsonDocument::fromVariant(var).toJson().data());
+
+       routingEngine->updateSupported(supported(), PropertyList(), &source);
+       routingEngine->setProperty(request);
+}
+
+void BluemonkeySink::exportInterface(QString name, QJSValue properties)
+{
+       std::unordered_map<std::string, std::string> propertiesMap;
+
+       QVariantList tempProps = properties.toVariant().toList();
+
+       DebugOut() << "num keys: " << tempProps.size() << endl;
+
+       Q_FOREACH(QVariant i, tempProps)
+       {
+               QVariantMap obj = i.toMap();
+               propertiesMap[obj.firstKey().toStdString()] = obj.first().toString().toStdString();
+       }
+
+       DebugOut() << "exporting new dbus interface: " << name.toStdString() << endl;
+       auto exporter = amb::Exporter::instance();
+       exporter->exportProperty<DBusSink>(name.toStdString(), propertiesMap, routingEngine);
+}
+
+QVariant Property::value()
+{
+       return mValue ? gvariantToQVariant(mValue->toVariant()) : QVariant::Invalid;
+}
+
+void Property::setValue(QVariant v)
+{
+       if(v.type() == QVariant::List || v.type() == QVariant::Map)
+       {
+
+               QJsonDocument doc = QJsonDocument::fromVariant(v);
+
+               QString json = doc.toJson();
+
+               mValue->fromString(json.toStdString());
+       }
+       else
+       {
+               QString tempVal = v.toString();
+               mValue->fromString(tempVal.toStdString());
+       }
+
+       AsyncSetPropertyRequest request;
+       request.property = mValue->name;
+       request.value = mValue->copy();
+       request.completed = [&](AsyncPropertyReply* reply)
+       {
+               if(reply->success)
+               {
+                       propertyChanged(reply->value);
+               }
+               else
+               {
+                       DebugOut(DebugOut::Warning) << "Error, trying to set value: " << reply->error << endl;
+               }
+               delete reply;
+       };
+       routingEngine->setProperty(request);
+}
+
+void Property::getHistory(QDateTime begin, QDateTime end, QJSValue cbFunction)
+{
+       double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
+       double e = (double)end.toMSecsSinceEpoch() / 1000.0;
+       AsyncRangePropertyRequest request;
+       request.timeBegin = b;
+       request.timeEnd = e;
+
+       PropertyList reqlist;
+       reqlist.push_back(mValue->name);
+
+       request.properties = reqlist;
+       request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
+       {
+               if(!reply->success)
+               {
+                       DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
+                       return;
+               }
+
+               if(cbFunction.isCallable())
+               {
+                       QVariantList list;
+
+                       for(auto val : reply->values)
+                       {
+                               list.append(toQVariant(val));
+                       }
+
+                       QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
+                       cbFunction.call(QJSValueList()<<val);
+
+               }
+
+               delete reply;
+       };
+
+       routingEngine->getRangePropertyAsync(request);
+}
+
+Property::Property(VehicleProperty::Property prop, QString srcFilter, AbstractRoutingEngine* re, Zone::Type zone, QObject *parent)
+       :QObject(parent), AbstractSink(re, std::map<std::string,std::string>()),mValue(nullptr), mUuid(amb::createUuid()), mZone(zone)
+{
+       setType(prop.c_str());
+}
+
+QString Property::name()
+{
+       return mValue->name.c_str();
+}
+
+void Property::setType(QString t)
+{
+       if(mValue && name() != "")
+               routingEngine->unsubscribeToProperty(name().toStdString(), this);
+
+       routingEngine->subscribeToProperty(t.toStdString(), this);
+
+       mValue = VehicleProperty::getPropertyTypeForPropertyNameValue(t.toStdString());
+
+       if(!mValue)
+               return;
+
+       AsyncPropertyRequest request;
+       request.property = mValue->name;
+       request.completed = [this](AsyncPropertyReply* reply)
+       {
+               if(reply->success)
+                       propertyChanged(reply->value);
+
+               delete reply;
+       };
+
+       routingEngine->getPropertyAsync(request);
+}
+
+void Property::propertyChanged(AbstractPropertyType *value)
+{
+       if(value->zone != mZone)
+               return;
+
+       if(mValue)
+       {
+               delete mValue;
+       }
+       mValue = value->copy();
+
+       changed(gvariantToQVariant(mValue->toVariant()));
+}
+
+
+QVariant BluemonkeySink::zonesForProperty(QString prop, QString src)
+{
+       PropertyInfo info = routingEngine->getPropertyInfo(prop.toStdString(), src.toStdString());
+
+       QVariantList list;
+
+       for(auto i : info.zones())
+       {
+               list << i;
+       }
+
+       return list;
+}
diff --git a/plugins/bluemonkey/amb.h b/plugins/bluemonkey/amb.h
new file mode 100644 (file)
index 0000000..b39d84c
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef _AMB_BLUEMONKEY_PLUGIN_H_
+#define _AMB_BLUEMONKEY_PLUGIN_H_
+
+#include "bluemonkey.h"
+
+#include <abstractsource.h>
+#include <ambpluginimpl.h>
+#include <uuidhelper.h>
+
+#include <map>
+
+
+class Property: public QObject, public AbstractSink
+{
+       Q_OBJECT
+       Q_PROPERTY(QString name READ name)
+       Q_PROPERTY(QString source READ source)
+       Q_PROPERTY(double timestamp READ timestamp)
+       Q_PROPERTY(QVariant value READ value WRITE setValue)
+       Q_PROPERTY(int zone READ zone)
+
+public:
+       Property(VehicleProperty::Property, QString srcFilter, AbstractRoutingEngine * re, Zone::Type zone = Zone::None, QObject * parent = 0);
+
+       QString name();
+       void setType(QString t);
+
+       QString source()
+       {
+               return mValue->sourceUuid.c_str();
+       }
+
+       double timestamp()
+       {
+               return mValue->timestamp;
+       }
+
+       virtual PropertyList subscriptions() { return PropertyList(); }
+       virtual void supportedChanged(const PropertyList &)
+       {
+               DebugOut()<<"Bluemonkey Property Supported Changed"<<endl;
+       }
+
+       virtual void propertyChanged(AbstractPropertyType* value);
+
+       virtual const std::string uuid() { return mUuid; }
+
+       QVariant value();
+       void setValue(QVariant v);
+
+       void getHistory(QDateTime begin, QDateTime end, QJSValue cbFunction);
+
+       Zone::Type zone() { return mZone; }
+
+Q_SIGNALS:
+
+       void changed(QVariant val);
+
+private:
+       AbstractPropertyType* mValue;
+       const std::string mUuid;
+       Zone::Type mZone;
+
+};
+
+
+class BluemonkeySink : public QObject, public AmbPluginImpl
+{
+Q_OBJECT
+
+public:
+       using AmbPluginImpl::setProperty;
+       using QObject::setProperty;
+
+       BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config,  AbstractSource& parent);
+       ~BluemonkeySink();
+       void init();
+       virtual PropertyList subscriptions();
+       virtual void supportedChanged(const PropertyList & supportedProperties);
+       virtual void propertyChanged(AbstractPropertyType* value);
+       virtual const std::string uuid() const;
+
+       virtual int supportedOperations();
+
+private: //source privates
+
+       PropertyList mSupported;
+       std::list<AbstractPropertyType*> propertyValueCache;
+
+
+public Q_SLOTS:
+
+       QObject* subscribeTo(QString str);
+       QObject* subscribeTo(QString str, int zone);
+       QObject* subscribeTo(QString str, int zone, QString srcFilter);
+
+       QStringList sourcesForProperty(QString property);
+       QVariant zonesForProperty(QString property, QString src);
+
+       QStringList supportedProperties();
+
+       bool authenticate(QString pass);
+
+       void getHistory(QStringList properties, QDateTime begin, QDateTime end, QJSValue cbFunction);
+
+       void setSilentMode(bool m)
+       {
+               mSilentMode = m;
+       }
+
+       void createCustomProperty(QString name, QJSValue defaultValue)
+       {
+               createCustomProperty(name, defaultValue, Zone::None);
+       }
+
+       void createCustomProperty(QString name, QJSValue defaultValue, int zone);
+
+       void exportInterface(QString name, QJSValue properties);
+
+private:
+       Bluemonkey* bluemonkey;
+       Authenticate* auth;
+       bool mSilentMode;
+};
+
+#endif
diff --git a/plugins/bluemonkey/ble.cpp b/plugins/bluemonkey/ble.cpp
new file mode 100644 (file)
index 0000000..afd5fc6
--- /dev/null
@@ -0,0 +1,190 @@
+#include "ble.h"
+
+#include <QBluetoothDeviceDiscoveryAgent>
+#include <QBluetoothDeviceInfo>
+#include <QLowEnergyController>
+#include <QLowEnergyService>
+#include <QLowEnergyCharacteristic>
+#include <QtDebug>
+#include <QCoreApplication>
+
+extern "C" void create(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &js, QObject* parent)
+{
+       exports["ble"] = new Ble(parent);
+}
+
+Ble::Ble(QObject *parent)
+       :QObject(parent)
+{
+       mDeviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
+
+       connect(mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, this, &Ble::deviceDiscovered);
+       connect(mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished, this, &Ble::scanningChanged);
+       connect(mDeviceDiscoveryAgent, &QBluetoothDeviceDiscoveryAgent::canceled, this, &Ble::scanningChanged);
+}
+
+QList<QObject *> Ble::devices()
+{
+       return devices(QString());
+}
+
+QList<QObject *> Ble::devices(const QString &serviceUuid)
+{
+       QList<QObject*> d;
+
+       Q_FOREACH(auto s, services)
+       {
+               if(s->isValid && (serviceUuid.isEmpty() || serviceUuid == s->serviceUuid))
+               {
+                       d.append(s);
+               }
+       }
+
+       return d;
+}
+
+QObject *Ble::device(const QString &address)
+{
+       Q_FOREACH(auto s, services)
+       {
+               if(s->deviceAddress == address)
+               {
+                       return s;
+               }
+       }
+
+       return nullptr;
+}
+
+void Ble::addService(const QString &serviceUuid, const QString &rxUuid, const QString &txUuid)
+{
+       auto service = new ServiceIdentifier(serviceUuid, rxUuid, txUuid, this);
+
+       connect(service, &ServiceIdentifier::destroyed, [this, &service]()
+       {
+               services.removeAll(service);
+       });
+
+       services.append(service);
+}
+
+void Ble::startScan(bool scan)
+{
+       qDebug() << "Scanning: " << (scan ? "true":"false");
+       scan ? mDeviceDiscoveryAgent->start() : mDeviceDiscoveryAgent->stop();
+}
+
+bool Ble::scanning()
+{
+       return mDeviceDiscoveryAgent->isActive();
+}
+
+void Ble::deviceDiscovered(const QBluetoothDeviceInfo &device)
+{
+       if(device.coreConfigurations() & QBluetoothDeviceInfo::LowEnergyCoreConfiguration)
+       {
+               qDebug() << "BLE device found: " << device.address().toString();
+
+               ///We have a device.  Let's scan to see if it supports the service Uuid's we want
+               auto control = new QLowEnergyController(device.address(), this);
+
+               connect(control, &QLowEnergyController::stateChanged, [control, this](QLowEnergyController::ControllerState state)
+               {
+                       qDebug() << "Controller state changed for device: " << control->remoteAddress().toString() << state;
+                       if(state == QLowEnergyController::DiscoveredState)
+                       {
+                               devicesChanged();
+                       }
+               });
+               connect(control, &QLowEnergyController::disconnected, control, &QLowEnergyController::deleteLater); // if we disconnect, clean up.
+               connect(control, &QLowEnergyController::connected, [&control]()
+               {
+                       qDebug() << "Device connected. Discovering services...";
+                       control->discoverServices();
+               });
+               connect(control, &QLowEnergyController::serviceDiscovered, [&control, this, device](const QBluetoothUuid & uuid)
+               {
+                       Q_FOREACH(ServiceIdentifier * service, services)
+                       {
+                               qDebug() << "checking if service uuid (" << uuid.toString() << ") matches the one we want (" << service->serviceUuid << ")";
+                               if(service->serviceUuid == uuid.toString())
+                               {
+                                       service->service = control->createServiceObject(uuid, service);
+                                       service->deviceName = device.name();
+                                       service->deviceAddress = device.address().toString();
+
+                                       if(!service->service)
+                                       {
+                                               qDebug() << "Could not get service object on device with address: " << control->remoteAddress().toString();
+                                               return;
+                                       }
+
+                                       connect(service->service, &QLowEnergyService::stateChanged,[&service](QLowEnergyService::ServiceState s)
+                                       {
+                                               if(s == QLowEnergyService::ServiceDiscovered)
+                                               {
+                                                       QLowEnergyCharacteristic rx = service->service->characteristic(QBluetoothUuid(service->rxUuid));
+
+                                                       if(!rx.isValid())
+                                                       {
+                                                               qDebug() << "rx characteristic not found in service.";
+                                                               qDebug() << "Characteristic: " << service->rxUuid;
+                                                               qDebug() << "Service: " << service->serviceUuid;
+                                                               service->isValid = false;
+                                                               return;
+                                                       }
+
+                                                       QLowEnergyCharacteristic tx = service->service->characteristic(QBluetoothUuid(service->txUuid));
+
+                                                       if(!tx.isValid())
+                                                       {
+                                                               qDebug() << "rx characteristic not found in service.";
+                                                               qDebug() << "Characteristic: " << service->rxUuid;
+                                                               qDebug() << "Service: " << service->serviceUuid;
+                                                               service->isValid = false;
+                                                               return;
+                                                       }
+
+                                                       service->isValid = true;
+                                               }
+                                       });
+                               }
+                       }
+               });
+               qDebug() << "attempting to connect to device: " << device.address().toString();
+               control->connectToDevice();
+       }
+}
+
+
+void ServiceIdentifier::write(const QByteArray &data)
+{
+       {
+               if(!service || !isValid)
+                       return;
+
+               service->writeCharacteristic(service->characteristic(QBluetoothUuid(txUuid)), data, QLowEnergyService::WriteWithoutResponse);
+       }
+}
+
+void ServiceIdentifier::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue)
+{
+       if(characteristic.uuid().toString() != rxUuid)
+               return;
+
+       onMessage(newValue);
+}
+
+int main(int argc, char** argv)
+{
+       qDebug() << "Bluemonkey BLE Module"  << "Version: " << PROJECT_VERSION;
+
+       QCoreApplication app(argc, argv);
+
+       Ble ble;
+
+       ble.startScan(true);
+
+       return app.exec();
+}
+
diff --git a/plugins/bluemonkey/ble.h b/plugins/bluemonkey/ble.h
new file mode 100644 (file)
index 0000000..70bcaa8
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _BLE_H_
+#define _BLE_H_
+
+#include <QObject>
+#include <QList>
+#include <QString>
+#include <QByteArray>
+#include <QJSValue>
+
+#include <QBluetoothDeviceInfo>
+
+class QBluetoothDeviceDiscoveryAgent;
+class QLowEnergyService;
+class QLowEnergyCharacteristic;
+
+class ServiceIdentifier : public QObject
+{
+       Q_OBJECT
+public:
+       ServiceIdentifier(const QString & s, const QString & r, const QString & t, QObject *parent = nullptr)
+               :QObject(parent), serviceUuid(s), rxUuid(r), txUuid(t), service(nullptr), isValid(false) {}
+       QString serviceUuid;
+       QString rxUuid;
+       QString txUuid;
+       QString deviceName;
+       QString deviceAddress;
+
+       QLowEnergyService * service;
+
+       bool isValid;
+
+public Q_SLOTS:
+       void write(const QByteArray & data);
+
+Q_SIGNALS:
+       void onMessage(const QByteArray & data);
+
+private Q_SLOTS:
+       void characteristicChanged(const QLowEnergyCharacteristic & characteristic, const QByteArray & newValue);
+};
+
+class Ble : public QObject
+{
+       Q_OBJECT
+       Q_PROPERTY(bool scan READ scanning WRITE startScan NOTIFY scanningChanged)
+       Q_PROPERTY(QList<QObject*> devices READ devices NOTIFY devicesChanged)
+public:
+
+       Ble(QObject* parent = nullptr);
+
+       QList<QObject*> devices();
+       QList<QObject*> devices(const QString & serviceUuid);
+       QObject* device(const QString & address);
+
+public Q_SLOTS:
+
+       void addService(const QString & serviceUuid, const QString & rxUuid, const QString & txUuid);
+
+       void startScan(bool scan);
+
+       bool scanning();
+
+Q_SIGNALS:
+       void scanningChanged();
+       void devicesChanged();
+
+private Q_SLOTS:
+
+       void deviceDiscovered(const QBluetoothDeviceInfo & device);
+
+private:
+       QList<ServiceIdentifier*> services;
+       QBluetoothDeviceDiscoveryAgent* mDeviceDiscoveryAgent;
+};
+
+
+#endif
index 4a21a1b..b19afc6 100644 (file)
 
 
 #include "bluemonkey.h"
-#include "abstractroutingengine.h"
-#include "ambplugin.h"
-#include "debugout.h"
-
-#include "dbusplugin.h"
-#include "dbusexport.h"
 
 #include <QJsonDocument>
 #include <QJSEngine>
 
 typedef void create_bluemonkey_module_t(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &javascript, QObject* parent);
 
-extern "C" void create(AbstractRoutingEngine* routingengine, map<string, string> config)
-{
-       auto plugin = new AmbPlugin<BluemonkeySink>(routingengine, config);
-       plugin->init();
-}
-
-QVariant gvariantToQVariant(GVariant *value)
-{
-       GVariantClass c = g_variant_classify(value);
-       if(c == G_VARIANT_CLASS_BOOLEAN)
-               return QVariant((bool) g_variant_get_boolean(value));
-
-       else if(c == G_VARIANT_CLASS_BYTE)
-               return QVariant((char) g_variant_get_byte(value));
-
-       else if(c == G_VARIANT_CLASS_INT16)
-               return QVariant((int) g_variant_get_int16(value));
-
-       else if(c == G_VARIANT_CLASS_UINT16)
-               return QVariant((unsigned int) g_variant_get_uint16(value));
-
-       else if(c == G_VARIANT_CLASS_INT32)
-               return QVariant((int) g_variant_get_int32(value));
-
-       else if(c ==  G_VARIANT_CLASS_UINT32)
-               return QVariant((unsigned int) g_variant_get_uint32(value));
-
-       else if(c == G_VARIANT_CLASS_INT64)
-               return QVariant((long long) g_variant_get_int64(value));
-
-       else if(c == G_VARIANT_CLASS_UINT64)
-               return QVariant((unsigned long long) g_variant_get_uint64(value));
-
-       else if(c == G_VARIANT_CLASS_DOUBLE)
-               return QVariant(g_variant_get_double(value));
-
-       else if(c == G_VARIANT_CLASS_STRING)
-               return QVariant(g_variant_get_string(value, NULL));
-
-       else if(c == G_VARIANT_CLASS_ARRAY)
-       {
-               gsize dictsize = g_variant_n_children(value);
-               QVariantList list;
-               for (int i=0; i<dictsize; i++)
-               {
-                       GVariant *childvariant = g_variant_get_child_value(value, i);
-                       GVariant *innervariant = g_variant_get_variant(childvariant);
-                       list.append(gvariantToQVariant(innervariant));
-               }
-               return list;
-       }
-
-       else
-               return QVariant::Invalid;
-
-}
-
-AbstractPropertyType* qVariantToAbstractPropertyType(QString name, QVariant var)
-{
-       if(!var.isValid())
-               return nullptr;
-
-       if(var.type() == QVariant::UInt)
-               return new BasicPropertyType<uint>(name.toStdString(), var.toUInt());
-       else if(var.type() == QVariant::Double)
-               return new BasicPropertyType<double>(name.toStdString(), var.toDouble());
-       else if(var.type() == QVariant::Bool)
-               return new BasicPropertyType<bool>(name.toStdString(), var.toBool());
-       else if(var.type() == QVariant::Int)
-               return new BasicPropertyType<int>(name.toStdString(), var.toInt());
-       else if(var.type() == QVariant::String)
-               return new StringPropertyType(name.toStdString(), var.toString().toStdString());
-       else if(var.type() == QVariant::List && var.toList().count())
-       {
-               QVariant subVariant = var.toList().at(0);
-               if(subVariant.type() == QVariant::UInt)
-                       return new ListPropertyType<uint>(name.toStdString(), subVariant.toUInt());
-               else if(subVariant.type() == QVariant::Double)
-                       return new ListPropertyType<double>(name.toStdString(), subVariant.toDouble());
-               else if(subVariant.type() == QVariant::Bool)
-                       return new ListPropertyType<bool>(name.toStdString(), subVariant.toBool());
-               else if(subVariant.type() == QVariant::Int)
-                       return new ListPropertyType<int>(name.toStdString(), subVariant.toInt());
-               else if(subVariant.type() == QVariant::String)
-                       return new ListPropertyType<std::string>(name.toStdString(), subVariant.toString().toStdString());
-       }
-       return nullptr;
-}
-
-QVariant toQVariant(AbstractPropertyType* val)
-{
-       QVariantMap value;
-
-       value["name"] = val->name.c_str();
-       value["zone"] = val->zone;
-       value["source"] = val->sourceUuid.c_str();
-       value["timestamp"] = val->timestamp;
-       value["sequence"] = val->sequence;
-       value["value"] = gvariantToQVariant(val->toVariant());
-
-       return value;
-}
-
-class BluemonkeyDBusInterface: public DBusSink
-{
-public:
-       BluemonkeyDBusInterface(std::string ifaceName, AbstractRoutingEngine* re, GDBusConnection* connection)
-               :DBusSink(ifaceName, re, connection)
-       {
-
-       }
-};
-
-BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource &parent)
-       : QObject(0), AmbPluginImpl(e, config, parent), mSilentMode(false)
-{
-       bluemonkey = new Bluemonkey(config, this);
-       auth = new Authenticate(config, this);
-}
-
-BluemonkeySink::~BluemonkeySink()
-{
-}
-
-void BluemonkeySink::init()
-{
-       connect(bluemonkey, &Bluemonkey::ready,[this](){bluemonkey->loadModule("amb", this);});
-}
-
-
-PropertyList BluemonkeySink::subscriptions()
-{
-
-}
-
-void BluemonkeySink::supportedChanged(const PropertyList & supportedProperties)
-{
-       DebugOut()<<"supported changed"<<endl;
-}
-
-void BluemonkeySink::propertyChanged(AbstractPropertyType * value)
-{
-
-}
-
-const string BluemonkeySink::uuid() const
-{
-       return "bluemonkey";
-}
-
-int BluemonkeySink::supportedOperations()
-{
-       return AbstractSource::Get | AbstractSource::Set;
-}
-
-QObject *BluemonkeySink::subscribeTo(QString str)
-{
-       return new Property(str.toStdString(), "", routingEngine, Zone::None, this);
-}
-
-QObject *BluemonkeySink::subscribeTo(QString str, int zone, QString srcFilter)
-{
-       return new Property(str.toStdString(), srcFilter, routingEngine, zone, this);
-}
-
-QObject* BluemonkeySink::subscribeTo(QString str, int zone)
-{
-       return new Property(str.toStdString(), "", routingEngine, zone, this);
-}
-
-
-QStringList BluemonkeySink::sourcesForProperty(QString property)
+Bluemonkey::Bluemonkey(std::map<std::string, std::string> config, QObject *parent)
+       :QObject(parent), engine(nullptr), configuration(config)
 {
-       std::vector<std::string> list = routingEngine->sourcesForProperty(property.toStdString());
-       QStringList strList;
-       for(auto itr : list)
-       {
-               strList<<itr.c_str();
-       }
-
-       return strList;
+       QTimer::singleShot(1,this,SLOT(reloadEngine()));
 }
 
-QStringList BluemonkeySink::supportedProperties()
+Bluemonkey::~Bluemonkey()
 {
-       PropertyList props = routingEngine->supported();
-       QStringList strList;
-       for(auto p : props)
+       Q_FOREACH(void* module, modules)
        {
-               strList<<p.c_str();
+               dlclose(module);
        }
 
-       return strList;
-}
-
-
-bool BluemonkeySink::authenticate(QString pass)
-{
-
+       engine->deleteLater();
 }
 
 void Bluemonkey::loadConfig(QString str)
@@ -245,7 +54,7 @@ void Bluemonkey::loadConfig(QString str)
        QFile file(str);
        if(!file.open(QIODevice::ReadOnly))
        {
-               DebugOut(DebugOut::Error)<<"failed to open config file: "<<str.toStdString()<<endl;
+               qDebug()<< "failed to open config file: "<< str;
                return;
        }
 
@@ -253,17 +62,17 @@ void Bluemonkey::loadConfig(QString str)
 
        file.close();
 
-       DebugOut(7)<<"evaluating script: "<<script.toStdString()<<endl;
+       qDebug() << "evaluating script: "<< script;
 
        QJSValue val = engine->evaluate(script);
 
-       DebugOut()<<val.toString().toStdString()<<endl;
+       qDebug()<< val.toString();
 
        if(val.isError())
        {
-               DebugOut(DebugOut::Error) << val.property("name").toString().toStdString() << endl;
-               DebugOut(DebugOut::Error) << val.property("message").toString().toStdString() << endl;
-               DebugOut(DebugOut::Error) << str.toStdString() << ":" <<val.property("lineNumber").toString().toStdString() << endl;
+               qDebug() <<  val.property("name").toString() <<  endl;
+               qDebug() <<  val.property("message").toString() <<  endl;
+               qDebug() <<  str <<  ":" << val.property("lineNumber").toString() <<  endl;
        }
 }
 
@@ -273,7 +82,7 @@ bool Bluemonkey::loadModule(QString path)
 
        if(!handle)
        {
-               DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << dlerror() << endl;
+               qDebug() <<  "bluemonkey load module failed: " <<  dlerror() <<  endl;
                return false;
        }
 
@@ -286,20 +95,25 @@ bool Bluemonkey::loadModule(QString path)
 
        if(!c)
        {
-               DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << path.toStdString() << " " << dlerror() << endl;
+               qDebug() <<  "bluemonkey load module failed: " <<  path <<  " " <<  dlerror() <<  endl;
                return false;
        }
 
-       create_bluemonkey_module_t* create = (create_bluemonkey_module_t*)(c);
+       create_bluemonkey_module_t* create = reinterpret_cast<create_bluemonkey_module_t*>(c);
+
+       if(!create)
+       {
+               qCritical() << "Failed to call create() on module "<< path << ". Check signature.";
+       }
 
        std::map<std::string, QObject*> exports;
        QString js;
-       create(configuration, exports, js, this);
+       create(configuration, exports, js, nullptr);
 
        for(auto i : exports)
        {
                QObject* obj = i.second;
-               loadModule(i.first, obj);
+               loadModule(i.first.c_str(), obj);
        }
 
        engine->evaluate(js);
@@ -317,10 +131,6 @@ void Bluemonkey::reloadEngine()
        QJSValue value = engine->newQObject(this);
        engine->globalObject().setProperty("bluemonkey", value);
 
-       //engine->moveToThread(thread);
-
-       thread->start();
-
        ready();
 
        loadConfig(configuration["config"].c_str());
@@ -334,7 +144,7 @@ void Bluemonkey::writeProgram(QString program)
        QJSValue result = temp.evaluate(program);
        if(result.isError())
        {
-               DebugOut(DebugOut::Error)<<"Syntax error in program: "<<result.toString().toStdString()<<endl;
+               qDebug()<< "Syntax error in program: "<< result.toString();
                return;
        }
 
@@ -342,7 +152,7 @@ void Bluemonkey::writeProgram(QString program)
 
        if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
        {
-               DebugOut(DebugOut::Error) << "failed to open file: " << file.fileName().toStdString() << endl;
+               qDebug() <<  "failed to open file: " <<  file.fileName() <<  endl;
                return;
        }
 
@@ -354,7 +164,7 @@ void Bluemonkey::writeProgram(QString program)
 
 void Bluemonkey::log(QString str)
 {
-       DebugOut()<<str.toStdString()<<endl;
+       qDebug()<< str;
 }
 
 QObject *Bluemonkey::createTimer()
@@ -367,262 +177,13 @@ QObject *Bluemonkey::createQObject()
        return new QObject(this);
 }
 
-void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTime end, QJSValue cbFunction)
-{
-       double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
-       double e = (double)end.toMSecsSinceEpoch() / 1000.0;
-       AsyncRangePropertyRequest request;
-       request.timeBegin = b;
-       request.timeEnd = e;
-
-       PropertyList reqlist;
-
-       foreach(QString prop, properties)
-       {
-               reqlist.push_back(prop.toStdString());
-       }
-
-       request.properties = reqlist;
-       request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
-       {
-               if(!reply->success)
-               {
-                       DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
-                       return;
-               }
-
-               if(cbFunction.isCallable())
-               {
-                       QVariantList list;
-
-                       for(auto val : reply->values)
-                       {
-                               list.append(toQVariant(val));
-                       }
-
-                       QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
-
-                       cbFunction.call(QJSValueList()<<val);
-
-               }
-
-               delete reply;
-       };
-
-       routingEngine->getRangePropertyAsync(request);
-}
-
-void BluemonkeySink::createCustomProperty(QString name, QJSValue defaultValue, int zone)
-{
-       QVariant var = defaultValue.toVariant();
-
-       DebugOut() << "Variant value for: " << name.toStdString() << " is " << defaultValue.toString().toStdString() << endl;
-
-       auto create = [name, var]() -> AbstractPropertyType*
-       {
-               return qVariantToAbstractPropertyType(name, var);
-       };
-
-       addPropertySupport(zone, create);
-
-       AsyncSetPropertyRequest request;
-       request.property = name.toStdString();
-       request.zoneFilter = zone;
-       request.value = VehicleProperty::getPropertyTypeForPropertyNameValue(name.toStdString(), QJsonDocument::fromVariant(var).toJson().data());
-
-       routingEngine->updateSupported(supported(), PropertyList(), &source);
-       routingEngine->setProperty(request);
-}
-
-void BluemonkeySink::exportInterface(QString name, QJSValue properties)
-{
-       std::unordered_map<std::string, std::string> propertiesMap;
-
-       QVariantList tempProps = properties.toVariant().toList();
-
-       DebugOut() << "num keys: " << tempProps.size() << endl;
-
-       Q_FOREACH(QVariant i, tempProps)
-       {
-               QVariantMap obj = i.toMap();
-               propertiesMap[obj.firstKey().toStdString()] = obj.first().toString().toStdString();
-       }
-
-       DebugOut() << "exporting new dbus interface: " << name.toStdString() << endl;
-       auto exporter = amb::Exporter::instance();
-       exporter->exportProperty<DBusSink>(name.toStdString(), propertiesMap, routingEngine);
-}
-
-QVariant Property::value()
-{
-       return mValue ? gvariantToQVariant(mValue->toVariant()) : QVariant::Invalid;
-}
-
-void Property::setValue(QVariant v)
-{
-       if(v.type() == QVariant::List || v.type() == QVariant::Map)
-       {
-
-               QJsonDocument doc = QJsonDocument::fromVariant(v);
-
-               QString json = doc.toJson();
-
-               mValue->fromString(json.toStdString());
-       }
-       else
-       {
-               QString tempVal = v.toString();
-               mValue->fromString(tempVal.toStdString());
-       }
-
-       AsyncSetPropertyRequest request;
-       request.property = mValue->name;
-       request.value = mValue->copy();
-       request.completed = [&](AsyncPropertyReply* reply)
-       {
-               if(reply->success)
-               {
-                       propertyChanged(reply->value);
-               }
-               else
-               {
-                       DebugOut(DebugOut::Warning) << "Error, trying to set value: " << reply->error << endl;
-               }
-               delete reply;
-       };
-       routingEngine->setProperty(request);
-}
-
-void Property::getHistory(QDateTime begin, QDateTime end, QJSValue cbFunction)
-{
-       double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
-       double e = (double)end.toMSecsSinceEpoch() / 1000.0;
-       AsyncRangePropertyRequest request;
-       request.timeBegin = b;
-       request.timeEnd = e;
-
-       PropertyList reqlist;
-       reqlist.push_back(mValue->name);
-
-       request.properties = reqlist;
-       request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
-       {
-               if(!reply->success)
-               {
-                       DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
-                       return;
-               }
-
-               if(cbFunction.isCallable())
-               {
-                       QVariantList list;
-
-                       for(auto val : reply->values)
-                       {
-                               list.append(toQVariant(val));
-                       }
-
-                       QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
-                       cbFunction.call(QJSValueList()<<val);
-
-               }
-
-               delete reply;
-       };
-
-       routingEngine->getRangePropertyAsync(request);
-}
-
-Property::Property(VehicleProperty::Property prop, QString srcFilter, AbstractRoutingEngine* re, Zone::Type zone, QObject *parent)
-       :QObject(parent), AbstractSink(re, std::map<std::string,std::string>()),mValue(nullptr), mUuid(amb::createUuid()), mZone(zone)
-{
-       setType(prop.c_str());
-}
-
-QString Property::name()
-{
-       return mValue->name.c_str();
-}
-
-void Property::setType(QString t)
-{
-       if(mValue && name() != "")
-               routingEngine->unsubscribeToProperty(name().toStdString(), this);
-
-       routingEngine->subscribeToProperty(t.toStdString(), this);
-
-       mValue = VehicleProperty::getPropertyTypeForPropertyNameValue(t.toStdString());
-
-       if(!mValue)
-               return;
-
-       AsyncPropertyRequest request;
-       request.property = mValue->name;
-       request.completed = [this](AsyncPropertyReply* reply)
-       {
-               if(reply->success)
-                       propertyChanged(reply->value);
-
-               delete reply;
-       };
-
-       routingEngine->getPropertyAsync(request);
-}
-
-void Property::propertyChanged(AbstractPropertyType *value)
-{
-       if(value->zone != mZone)
-               return;
-
-       if(mValue)
-       {
-               delete mValue;
-       }
-       mValue = value->copy();
-
-       changed(gvariantToQVariant(mValue->toVariant()));
-}
-
-
-QVariant BluemonkeySink::zonesForProperty(QString prop, QString src)
-{
-       PropertyInfo info = routingEngine->getPropertyInfo(prop.toStdString(), src.toStdString());
-
-       QVariantList list;
-
-       for(auto i : info.zones())
-       {
-               list << i;
-       }
-
-       return list;
-}
-
-
-Bluemonkey::Bluemonkey(std::map<string, string> config, QObject *parent)
-       :QObject(parent), engine(nullptr), configuration(config)
-{
-       thread = new QThread(this);
-       QTimer::singleShot(1,this,SLOT(reloadEngine()));
-}
-
-Bluemonkey::~Bluemonkey()
-{
-       Q_FOREACH(void* module, modules)
-       {
-               dlclose(module);
-       }
-
-       engine->deleteLater();
-}
 
-bool Bluemonkey::loadModule(const std::string & name, QObject *module)
+bool Bluemonkey::loadModule(const QString &name, QObject *module)
 {
-       std::string obj = name;
-       if(!engine->globalObject().hasProperty(obj.c_str()))
+       if(!engine->globalObject().hasProperty(name))
        {
                QJSValue val = engine->newQObject(module);
-               engine->globalObject().setProperty(obj.c_str(), val);
+               engine->globalObject().setProperty(name, val);
        }
 }
 
index c8a82cd..6aed204 100644 (file)
 */
 
 
-#ifndef BluemonkeySink_H
-#define BluemonkeySink_H
-
-#include <abstractsource.h>
-#include <ambpluginimpl.h>
-#include <uuidhelper.h>
+#ifndef Bluemonkey_H
+#define Bluemonkey_H
 
 #include <map>
 
 #include <QJsonDocument>
 #include <QDateTime>
 #include <QJSValue>
-#include <QThread>
 
 #include "authenticate.h"
 
 class QJSEngine;
 
-class Property: public QObject, public AbstractSink
-{
-       Q_OBJECT
-       Q_PROPERTY(QString name READ name)
-       Q_PROPERTY(QString source READ source)
-       Q_PROPERTY(double timestamp READ timestamp)
-       Q_PROPERTY(QVariant value READ value WRITE setValue)
-       Q_PROPERTY(int zone READ zone)
-
-public:
-       Property(VehicleProperty::Property, QString srcFilter, AbstractRoutingEngine * re, Zone::Type zone = Zone::None, QObject * parent = 0);
-
-       QString name();
-       void setType(QString t);
-
-       QString source()
-       {
-               return mValue->sourceUuid.c_str();
-       }
-
-       double timestamp()
-       {
-               return mValue->timestamp;
-       }
-
-       virtual PropertyList subscriptions() { return PropertyList(); }
-       virtual void supportedChanged(const PropertyList &)
-       {
-               DebugOut()<<"Bluemonkey Property Supported Changed"<<endl;
-       }
-
-       virtual void propertyChanged(AbstractPropertyType* value);
-
-       virtual const std::string uuid() { return mUuid; }
-
-       QVariant value();
-       void setValue(QVariant v);
-
-       void getHistory(QDateTime begin, QDateTime end, QJSValue cbFunction);
-
-       Zone::Type zone() { return mZone; }
-
-Q_SIGNALS:
-
-       void changed(QVariant val);
-
-private:
-       AbstractPropertyType* mValue;
-       const std::string mUuid;
-       Zone::Type mZone;
-
-};
-
 class Bluemonkey : public QObject
 {
        Q_OBJECT
 public:
-       Bluemonkey(std::map<std::string, std::string> config, QObject* parent = nullptr);
+       Bluemonkey(std::map<std::string, std::string> config = std::map<std::string, std::string>(), QObject* parent = nullptr);
        ~Bluemonkey();
 
-       bool loadModule(const string &name, QObject* module);
+       bool loadModule(const QString &name, QObject* module);
 
 public Q_SLOTS:
        void assertIsTrue(bool isTrue, const QString &msg="");
@@ -120,71 +62,10 @@ Q_SIGNALS:
        void ready();
 
 private:
-       QThread* thread;
        QList<void*> modules;
        QJSEngine* engine;
        QStringList configsToLoad;
        std::map<std::string, std::string> configuration;
 };
 
-class BluemonkeySink : public QObject, public AmbPluginImpl
-{
-Q_OBJECT
-
-public:
-       using AmbPluginImpl::setProperty;
-       using QObject::setProperty;
-
-       BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config,  AbstractSource& parent);
-       ~BluemonkeySink();
-       void init();
-       virtual PropertyList subscriptions();
-       virtual void supportedChanged(const PropertyList & supportedProperties);
-       virtual void propertyChanged(AbstractPropertyType* value);
-       virtual const std::string uuid() const;
-
-       virtual int supportedOperations();
-
-private: //source privates
-
-       PropertyList mSupported;
-       std::list<AbstractPropertyType*> propertyValueCache;
-
-
-public Q_SLOTS:
-
-       QObject* subscribeTo(QString str);
-       QObject* subscribeTo(QString str, int zone);
-       QObject* subscribeTo(QString str, int zone, QString srcFilter);
-
-       QStringList sourcesForProperty(QString property);
-       QVariant zonesForProperty(QString property, QString src);
-
-       QStringList supportedProperties();
-
-       bool authenticate(QString pass);
-
-       void getHistory(QStringList properties, QDateTime begin, QDateTime end, QJSValue cbFunction);
-
-       void setSilentMode(bool m)
-       {
-               mSilentMode = m;
-       }
-
-       void createCustomProperty(QString name, QJSValue defaultValue)
-       {
-               createCustomProperty(name, defaultValue, Zone::None);
-       }
-
-       void createCustomProperty(QString name, QJSValue defaultValue, int zone);
-
-       void exportInterface(QString name, QJSValue properties);
-
-private:
-       Bluemonkey* bluemonkey;
-       Authenticate* auth;
-       bool mSilentMode;
-};
-
-
-#endif // BluemonkeySink_H
+#endif // Bluemonkey_H
diff --git a/plugins/bluemonkey/bluemonkeynode.cpp b/plugins/bluemonkey/bluemonkeynode.cpp
new file mode 100644 (file)
index 0000000..e4df302
--- /dev/null
@@ -0,0 +1,26 @@
+#include "bluemonkey.h"
+
+#include <QCoreApplication>
+#include <QtDebug>
+
+int main(int argc, char ** argv)
+{
+       QCoreApplication app(argc, argv);
+
+       if(app.arguments().count() < 2)
+       {
+               qDebug() << "Error: must run with path to file.js";
+               qDebug() << "ie: " << app.applicationName() << " /path/to/file.js";
+               return -1;
+       }
+
+       std::string path = app.arguments().at(1).toStdString();
+
+       std::map<std::string, std::string> config;
+
+       config["config"] = path;
+
+       Bluemonkey bluemonkey(config);
+
+       app.exec();
+}
diff --git a/plugins/bluemonkey/bmconfig.js b/plugins/bluemonkey/bmconfig.js
new file mode 100644 (file)
index 0000000..3d88905
--- /dev/null
@@ -0,0 +1,59 @@
+bluemonkey.log("hello world!");
+
+bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDbModule.so");
+bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDBusModule.so");
+bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyBleModule.so");
+
+exportObj = {};
+exportObj.foo = function() { return "bar"; }
+exportObj.bar = true;
+
+if(dbus !== undefined)
+{
+       try
+       {
+               var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
+
+               var reply = dbusIface.GetId();
+
+               bluemonkey.log("org.freedesktop.DBus.GetId() response: " + reply);
+
+               var registered = dbus.registerService("org.bluemonkey", dbus.Session)
+
+               bluemonkey.assertIsTrue(registered, "could not register service: " + dbus.errorMessage(dbus.Session));
+
+               /* TODO: Uncomment this when dbus export works
+               var exported = dbus.exportObject("/one", "org.awesome.interface", dbus.Session, exportObj);
+               bluemonkey.log("exported: " + exported)
+
+               bluemonkey.assertIsTrue(exported, "Failed to export custom dbus object: " + dbus.errorMessage(dbus.Session));
+
+               var exported2 = dbus.exportObject("/two", "org.awesome.interface2", dbus.Session, testExport)
+               bluemonkey.log("exported2: " + exported2)
+
+               bluemonkey.assertIsTrue(exported2, "failed to export testExport: " + dbus.errorMessage());*/
+       }
+       catch(error)
+       {
+               bluemonkey.log("nasty dbus errors");
+       }
+}
+
+if(ble !== undefined)
+{
+       serviceUuid = "5faaf494-d4c6-483e-b592-d1a6ffd436c9";
+       device = ble.addService(serviceUuid, "5faaf495-d4c6-483e-b592-d1a6ffd436c9", "5faaf496-d4c6-483e-b592-d1a6ffd436c9");
+       ble.scanningChanged.connect(function ()
+       {
+               if(!ble.scan)
+               {
+                       bluemonkey.log("scan finished");
+               }
+       });
+
+       ble.scan = true;
+       ble.devicesChanged.connect(function ()
+       {
+               bluemonkey.log("devices that match the service uuid: " + ble.devices(serviceUuid))
+       });
+}
index f8ca281..9fd93b2 100644 (file)
 
 #include "bmdbus.h"
 
-#include <debugout.h>
-
 #include <QDBusInterface>
 #include <QDBusConnection>
 #include <QDBusReply>
 #include <QCoreApplication>
-#include <QMetaMethod>
-
-#include "bmdbus_p.h"
-
-extern "C" std::map<std::string, QObject*> create(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &js, QObject* parent)
+#include <QtDebug>
+extern "C" void create(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &js, QObject* parent)
 {
+       exports["dbus"] = new BMDBus(nullptr);
+       exports["testExport"] = new TestQObject(nullptr);
 
-       exports["dbus"] = new BMDBus(parent);
-       exports["testExport"] = new TestQObject(parent);
-
-       js += "dbus.defineMethodSignature = function(obj, methodName, retType, args)"
+       js.append("dbus.defineMethodSignature = function(obj, methodName, retType, args)"
                  "{"
                  "  metadata = obj['_metadata'];"
                  "  if(!metadata)"
                  "    metadata = new Object;"
                  "  metadata[methodName] = {'retType' : retType, 'signature' : args};"
                  "  obj['_metadata'] = metadata;"
-                 "}";
+                 "}");
 
 }
 
@@ -81,7 +75,7 @@ bool BMDBus::exportObject(const QString &path, const QString &interface, BMDBus:
 #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 1))
        return con.registerObject(path, interface, object, QDBusConnection::ExportAllContents);
 #else
-       DebugOut(DebugOut::Warning) << "BMDBus::exportObject() interface is ignored in qt 5.4 and lower" << endl;
+       qDebug() << "BMDBus::exportObject() interface is ignored in qt 5.4 and lower" ;
        return con.registerObject(path, object, QDBusConnection::ExportAllContents);
 #endif
 */
@@ -103,154 +97,9 @@ QDBusConnection BMDBus::getConnection(const BMDBus::Connection bus)
        return con;
 }
 
-
-
-BluemonkeyQObjectPrivate::BluemonkeyQObjectPrivate(BluemonkeyQObject *iface)
-{
-
-}
-
-QVariant BluemonkeyQObjectPrivate::property(const QByteArray &property)
-{
-
-}
-
-bool BluemonkeyQObjectPrivate::setProperty(const QByteArray &property, const QVariant &value)
-{
-
-}
-
-void BluemonkeyQObjectPrivate::createFrom(const QJSValue &value)
-{
-       if(!value.isObject() || !value.hasProperty("_metadata"))
-       {
-               DebugOut(DebugOut::Warning) << "No metadata or not object" << endl;
-               return;
-       }
-
-       QVariantMap metaData = value.property("_metadata").toVariant().toMap();
-
-       Q_FOREACH(QString key, metaData.keys())
-       {
-               QString methodName = key;
-               QVariantMap metaMethod = metaData[key].toMap();
-
-               QStringList args = metaMethod["args"].toStringList();
-               QString returnType = metaMethod["retType"].toString();
-               metaObject->addMethod();
-       }
-
-}
-
-
-BluemonkeyMetaObject::BluemonkeyMetaObject(BluemonkeyQObject *qq, BluemonkeyQObjectPrivate *dd, const QMetaObject *mo)
-       :q(qq), d(dd)
-{
-       m_builder.setSuperClass(mo);
-       m_builder.setClassName(mo->className());
-       m_builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
-
-       m_metaObject = m_builder.toMetaObject();
-
-       QObjectPrivate* op = QObjectPrivate::get(q);
-       m_parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
-       *static_cast<QMetaObject*>(this) = *m_metaObject;
-       op->metaObject = this;
-}
-
-BluemonkeyMetaObject::~BluemonkeyMetaObject()
-{
-       delete m_metaObject;
-}
-
-void BluemonkeyMetaObject::updateProperties(const QVariantMap &data)
-{
-       Q_FOREACH(QString key, data.keys())
-       {
-               int i = m_propertyIdLookup.value(key.toUtf8());
-               activate(q, i + m_metaObject->methodOffset(), 0);
-       }
-}
-
-void BluemonkeyMetaObject::addProperty(const QByteArray& name, const QJSValue& property)
-{
-       int id = m_builder.propertyCount();
-       m_builder.addSignal("__"+QByteArray::number(id)+"()");
-       m_propertyIdLookup.insert(name, id);
-       QMetaType::Type propertyType = jsType(property);
-       m_propertyTypeLookup.insert(name, propertyType);
-}
-
-void BluemonkeyMetaObject::addMethod(const QByteArray& name, const QString & returnType, const QStringList &args)
-{
-       if(!method.isCallable()) return;
-
-       if(returnType.isEmpty())
-               returnType = "void";
-
-
-}
-
-QMetaType::Type BluemonkeyMetaObject::jsType(const QJSValue &value)
-{
-       int type = 0;
-       if(value.isArray())
-       {
-               type = qMetaTypeId<QVariantList>();
-       }
-       else if(value.isBool())
-       {
-               type = qMetaTypeId<bool>();
-       }
-       else if(value.isDate())
-       {
-               type = qMetaTypeId<QDateTime>();
-       }
-       else if(value.isNumber())
-       {
-               type = qMetaTypeId<double>();
-       }
-       else if(value.isObject())
-       {
-               type = qMetaTypeId<BluemonkeyQObject*>();
-       }
-       else if(value.isQObject())
-       {
-               type = qMetaTypeId<QObject*>();
-       }
-       else if(value.isString())
-       {
-               type = qMetaTypeId<QString>();
-       }
-       else if(value.isVariant())
-       {
-               type = qMetaTypeId<QVariant>();
-       }
-}
-
-int BluemonkeyMetaObject::metaCall(QMetaObject::Call _c, int _id, void **_a)
-{
-
-}
-
-int BluemonkeyMetaObject::createProperty(const char *, const char *)
-{
-
-}
-
-
-BluemonkeyQObject::BluemonkeyQObject(QObject *parent)
-       :QObject(*new BluemonkeyQObjectPrivate(this), parent)
-{
-       Q_D(BluemonkeyQObject);
-       d->metaObject = new BluemonkeyMetaObject(this, d, metaObject());
-}
-
 int main(int argc, char** argv)
 {
-       DebugOut::setDebugThreshhold(7);
-
-       DebugOut() << "Started BMDBus test " PROJECT_VERSION << endl;
+       qDebug() << "Started BMDBus test " PROJECT_VERSION ;
 
        QCoreApplication app(argc, argv);
 
@@ -264,7 +113,7 @@ int main(int argc, char** argv)
 
        QDBusReply<QString> reply = iface->call("awesomeMethod");
 
-       DebugOut() << "Reply value: " << reply.value().toStdString() << endl;
+       qDebug() << "Reply value: " << reply.value().toStdString() ;
 */
        app.exec();
 }
index 47256c4..284e9d5 100644 (file)
@@ -53,8 +53,6 @@ public Q_SLOTS:
 
        bool exportObject(const QString & path, const QString & interface, Connection bus, const QJSValue &obj);
 
-       QJSValue defineMethodSignature(const QJSValue & obj, const QString & methodName, const QString & returnType, const QStringList & arguments);
-
        QString errorMessage(const Connection bus = Session);
 
 private: ///methods:
@@ -62,20 +60,6 @@ private: ///methods:
        QDBusConnection getConnection(const Connection bus);
 };
 
-class BluemonkeyQObjectPrivate;
-class BluemonkeyQObject : public QObject
-{
-       Q_OBJECT
-public:
-       BluemonkeyQObject(QObject* parent = nullptr);
-
-private:
-       Q_DECLARE_PRIVATE(BluemonkeyQObject)
-       Q_DISABLE_COPY(BluemonkeyQObject)
-};
-
-Q_DECLARE_METATYPE(BluemonkeyQObject*)
-
 class BareQObject : public QObject
 {
        Q_OBJECT
index 7cc0b20..18a1c57 100644 (file)
@@ -27,61 +27,6 @@ dbusConnected.changed.connect(function () {
                                                           {'AnswerToTheUniverse' : 'AnswerToTheUniverse'}]);
 });
 
-bluemonkey.loadModule("@PLUGIN_INSTALL_PATH@/bluemonkeyDBusModule.so");
-
-exportObj = bluemonkey.createQObject();
-exportObj.foo = function() { return "bar"; }
-exportObj.bar = true;
-
-testExport.jsFunc = function() { return "js rules!"; }
-
-if(dbus)
-{
-       try
-       {
-               var dbusIface = dbus.createInterface("org.freedesktop.DBus", "/", "org.freedesktop.DBus", dbus.Session);
-
-               var reply = dbusIface.GetId();
-
-               bluemonkey.log("org.freedesktop.DBus.GetId() response: " + reply);
-
-               var registered = dbus.registerService("org.bluemonkey", dbus.Session)
-
-               bluemonkey.assertIsTrue(registered, "could not register service: " + dbus.errorMessage(dbus.Session));
-
-               for(prop in exportObj)
-               {
-                       bluemonkey.log(prop +"="+ exportObj[prop]);
-               }
-               for(prop in testExport)
-               {
-                       bluemonkey.log(prop +"="+ testExport[prop]);
-               }
-
-               var exported = dbus.exportObject("/one", "org.awesome.interface", dbus.Session, exportObj);
-               bluemonkey.log("exported: " + exported)
-
-               bluemonkey.assertIsTrue(exported, "Failed to export custom dbus object: " + dbus.errorMessage(dbus.Session));
-
-               var exported2 = dbus.exportObject("/two", "org.awesome.interface2", dbus.Session, testExport)
-               bluemonkey.log("exported2: " + exported2)
-
-               bluemonkey.assertIsTrue(exported2, "failed to export testExport: " + dbus.errorMessage());
-
-               //var exportedIface = dbus.createInterface("org.bluemonkey", "/", "org.awesome.interface", dbus.Session);
-
-               //bluemonkey.assertIsTrue(exportedIface.foo, "member 'foo' is missing " + dbus.errorMessage());
-
-               //var reply = exportedIface.foo();
-
-               //bluemonkey.assertIsTrue(reply === "bar" && exportedIface.bar === true);
-       }
-       catch(error)
-       {
-               bluemonkey.log("nasty dbus errors");
-       }
-}
-
 amb.createCustomProperty("VehicleSpeed", 10);
 amb.createCustomProperty("EngineSpeed", 5000);
 amb.createCustomProperty("PowertrainTorque", 324);
index 609e731..3949c6e 100644 (file)
 
 #include "db.h"
 
-#include <debugout.h>
-
 #include <QObject>
 #include <QSqlError>
 #include <QSqlRecord>
 #include <QtQml>
 
-extern "C" std::map<std::string, QObject*> create(std::map<std::string, std::string> config, QObject* parent)
+extern "C" void create(std::map<std::string, std::string> config, std::map<std::string, QObject*> &exports, QString &js, QObject* parent)
 {
-       std::map<std::string, QObject*> moduleInstances;
-       moduleInstances["database"] = new BluemonkeyDatabaseModule(parent);
-       return moduleInstances;
+       exports["database"] = new BluemonkeyDatabaseModule(parent);
 }
 
 bool Database::open(QString connectionName, QString filename)