2 Copyright (C) 2012 Intel Corporation
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "bluemonkey.h"
21 #include "abstractroutingengine.h"
22 #include "ambplugin.h"
25 #include <QJsonDocument>
35 #define foreach Q_FOREACH
37 typedef std::map<std::string, QObject*> create_bluemonkey_module_t(std::map<std::string, std::string> config, QObject* parent);
39 extern "C" AbstractSource * create(AbstractRoutingEngine* routingengine, map<string, string> config)
41 auto plugin = new AmbPlugin<BluemonkeySink>(routingengine, config);
47 QVariant gvariantToQVariant(GVariant *value)
49 GVariantClass c = g_variant_classify(value);
50 if(c == G_VARIANT_CLASS_BOOLEAN)
51 return QVariant((bool) g_variant_get_boolean(value));
53 else if(c == G_VARIANT_CLASS_BYTE)
54 return QVariant((char) g_variant_get_byte(value));
56 else if(c == G_VARIANT_CLASS_INT16)
57 return QVariant((int) g_variant_get_int16(value));
59 else if(c == G_VARIANT_CLASS_UINT16)
60 return QVariant((unsigned int) g_variant_get_uint16(value));
62 else if(c == G_VARIANT_CLASS_INT32)
63 return QVariant((int) g_variant_get_int32(value));
65 else if(c == G_VARIANT_CLASS_UINT32)
66 return QVariant((unsigned int) g_variant_get_uint32(value));
68 else if(c == G_VARIANT_CLASS_INT64)
69 return QVariant((long long) g_variant_get_int64(value));
71 else if(c == G_VARIANT_CLASS_UINT64)
72 return QVariant((unsigned long long) g_variant_get_uint64(value));
74 else if(c == G_VARIANT_CLASS_DOUBLE)
75 return QVariant(g_variant_get_double(value));
77 else if(c == G_VARIANT_CLASS_STRING)
78 return QVariant(g_variant_get_string(value, NULL));
80 else if(c == G_VARIANT_CLASS_ARRAY)
82 gsize dictsize = g_variant_n_children(value);
84 for (int i=0; i<dictsize; i++)
86 GVariant *childvariant = g_variant_get_child_value(value, i);
87 GVariant *innervariant = g_variant_get_variant(childvariant);
88 list.append(gvariantToQVariant(innervariant));
94 return QVariant::Invalid;
98 AbstractPropertyType* qVariantToAbstractPropertyType(QString name, QVariant var)
103 if(var.type() == QVariant::UInt)
104 return new BasicPropertyType<uint>(name.toStdString(), var.toUInt());
105 else if(var.type() == QVariant::Double)
106 return new BasicPropertyType<double>(name.toStdString(), var.toDouble());
107 else if(var.type() == QVariant::Bool)
108 return new BasicPropertyType<bool>(name.toStdString(), var.toBool());
109 else if(var.type() == QVariant::Int)
110 return new BasicPropertyType<int>(name.toStdString(), var.toInt());
111 else if(var.type() == QVariant::String)
112 return new StringPropertyType(name.toStdString(), var.toString().toStdString());
113 else if(var.type() == QVariant::List && var.toList().count())
115 QVariant subVariant = var.toList().at(0);
116 if(subVariant.type() == QVariant::UInt)
117 return new ListPropertyType<BasicPropertyType<uint>>(name.toStdString(), subVariant.toUInt());
118 else if(subVariant.type() == QVariant::Double)
119 return new ListPropertyType<BasicPropertyType<double>>(name.toStdString(), subVariant.toDouble());
120 else if(subVariant.type() == QVariant::Bool)
121 return new ListPropertyType<BasicPropertyType<bool>>(name.toStdString(), subVariant.toBool());
122 else if(subVariant.type() == QVariant::Int)
123 return new ListPropertyType<BasicPropertyType<int>>(name.toStdString(), subVariant.toInt());
124 else if(subVariant.type() == QVariant::String)
125 return new ListPropertyType<StringPropertyType>(name.toStdString(), subVariant.toString().toStdString());
130 QVariant toQVariant(AbstractPropertyType* val)
134 value["name"] = val->name.c_str();
135 value["zone"] = val->zone;
136 value["source"] = val->sourceUuid.c_str();
137 value["timestamp"] = val->timestamp;
138 value["sequence"] = val->sequence;
139 value["value"] = gvariantToQVariant(val->toVariant());
144 BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource &parent)
145 : QObject(0), AmbPluginImpl(e, config, parent), engine(nullptr), mSilentMode(false)
147 QTimer::singleShot(1,this,SLOT(reloadEngine()));
149 auth = new Authenticate(config, this);
152 BluemonkeySink::~BluemonkeySink()
154 Q_FOREACH(void* module, modules)
161 PropertyList BluemonkeySink::subscriptions()
166 void BluemonkeySink::supportedChanged(const PropertyList & supportedProperties)
168 DebugOut()<<"supported changed"<<endl;
171 void BluemonkeySink::propertyChanged(AbstractPropertyType * value)
176 const string BluemonkeySink::uuid() const
181 int BluemonkeySink::supportedOperations()
183 return AbstractSource::Get | AbstractSource::Set;
186 QObject *BluemonkeySink::subscribeTo(QString str)
188 return new Property(str.toStdString(), "", routingEngine, Zone::None, this);
191 QObject *BluemonkeySink::subscribeTo(QString str, int zone, QString srcFilter)
193 return new Property(str.toStdString(), srcFilter, routingEngine, zone, this);
196 QObject* BluemonkeySink::subscribeTo(QString str, int zone)
198 return new Property(str.toStdString(), "", routingEngine, zone, this);
202 QStringList BluemonkeySink::sourcesForProperty(QString property)
204 std::vector<std::string> list = routingEngine->sourcesForProperty(property.toStdString());
208 strList<<itr.c_str();
214 QStringList BluemonkeySink::supportedProperties()
216 PropertyList props = routingEngine->supported();
227 bool BluemonkeySink::authenticate(QString pass)
232 void BluemonkeySink::loadConfig(QString str)
235 if(!file.open(QIODevice::ReadOnly))
237 DebugOut(DebugOut::Error)<<"failed to open config file: "<<str.toStdString()<<endl;
241 QString script = file.readAll();
245 DebugOut()<<"evaluating script: "<<script.toStdString()<<endl;
247 QJSValue val = engine->evaluate(script);
249 DebugOut()<<val.toString().toStdString()<<endl;
253 DebugOut(DebugOut::Error) << val.property("name").toString().toStdString() << endl;
254 DebugOut(DebugOut::Error) << val.property("message").toString().toStdString() << endl;
255 DebugOut(DebugOut::Error) << str.toStdString() << ":" <<val.property("lineNumber").toString().toStdString() << endl;
259 bool BluemonkeySink::loadModule(QString path)
261 void* handle = dlopen(path.toUtf8().data(), RTLD_LAZY);
265 DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << dlerror() << endl;
269 if(modules.contains(handle))
272 modules.push_back(handle);
274 void* c = dlsym(handle, "create");
278 DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << path.toStdString() << " " << dlerror() << endl;
282 create_bluemonkey_module_t* create = (create_bluemonkey_module_t*)(c);
284 std::map<std::string, QObject*> exports = create(configuration, this);
286 for(auto i : exports)
288 std::string obj = i.first;
289 if(!engine->globalObject().hasProperty(obj.c_str()))
291 QJSValue val = engine->newQObject(i.second);
292 engine->globalObject().setProperty(obj.c_str(), val);
299 void BluemonkeySink::reloadEngine()
302 engine->deleteLater();
304 engine = new QJSEngine(this);
306 QJSValue value = engine->newQObject(this);
307 engine->globalObject().setProperty("bluemonkey", value);
309 loadConfig(configuration["config"].c_str());
312 void BluemonkeySink::writeProgram(QString program)
316 QJSValue result = temp.evaluate(program);
319 DebugOut(DebugOut::Error)<<"Syntax error in program: "<<result.toString().toStdString()<<endl;
323 QFile file(configuration["customPrograms"].c_str());
325 if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
327 DebugOut(DebugOut::Error)<<"failed to open file: "<<file.fileName().toStdString()<<endl;
331 file.write(program.toUtf8());
337 void BluemonkeySink::log(QString str)
339 DebugOut()<<str.toStdString()<<endl;
342 QObject *BluemonkeySink::createTimer()
344 return new QTimer(this);
347 QObject *BluemonkeySink::createQObject()
349 return new QObject(this);
352 void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTime end, QJSValue cbFunction)
354 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
355 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
356 AsyncRangePropertyRequest request;
357 request.timeBegin = b;
360 PropertyList reqlist;
362 foreach(QString prop, properties)
364 reqlist.push_back(prop.toStdString());
367 request.properties = reqlist;
368 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
372 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
376 if(cbFunction.isCallable())
380 for(auto val : reply->values)
382 list.append(toQVariant(val));
385 QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
387 cbFunction.call(QJSValueList()<<val);
394 routingEngine->getRangePropertyAsync(request);
397 void BluemonkeySink::createCustomProperty(QString name, QJSValue defaultValue, int zone)
399 QVariant var = defaultValue.toVariant();
401 DebugOut() << "Variant value for: " << name.toStdString() << " is " << defaultValue.toString().toStdString() << endl;
403 auto create = [name, var]() -> AbstractPropertyType*
405 return qVariantToAbstractPropertyType(name, var);
408 addPropertySupport(zone, create);
410 AsyncSetPropertyRequest request;
411 request.property = name.toStdString();
412 request.zoneFilter = zone;
413 request.value = VehicleProperty::getPropertyTypeForPropertyNameValue(name.toStdString(), defaultValue.toString().toStdString());
415 routingEngine->updateSupported(supported(), PropertyList(), &source);
416 routingEngine->setProperty(request);
420 QVariant Property::value()
422 return mValue ? gvariantToQVariant(mValue->toVariant()) : QVariant::Invalid;
425 void Property::setValue(QVariant v)
427 if(v.type() == QVariant::List || v.type() == QVariant::Map)
430 QJsonDocument doc = QJsonDocument::fromVariant(v);
432 QString json = doc.toJson();
434 mValue->fromString(json.toStdString());
438 QString tempVal = v.toString();
439 mValue->fromString(tempVal.toStdString());
442 AsyncSetPropertyRequest request;
443 request.property = mValue->name;
444 request.value = mValue->copy();
445 request.completed = [&](AsyncPropertyReply* reply)
449 propertyChanged(reply->value);
453 DebugOut(DebugOut::Warning) << "Error, trying to set value: " << reply->error << endl;
457 routingEngine->setProperty(request);
460 void Property::getHistory(QDateTime begin, QDateTime end, QJSValue cbFunction)
462 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
463 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
464 AsyncRangePropertyRequest request;
465 request.timeBegin = b;
468 PropertyList reqlist;
469 reqlist.push_back(mValue->name);
471 request.properties = reqlist;
472 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
476 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
480 if(cbFunction.isCallable())
484 for(auto val : reply->values)
486 list.append(toQVariant(val));
489 QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
490 cbFunction.call(QJSValueList()<<val);
497 routingEngine->getRangePropertyAsync(request);
500 Property::Property(VehicleProperty::Property prop, QString srcFilter, AbstractRoutingEngine* re, Zone::Type zone, QObject *parent)
501 :QObject(parent), AbstractSink(re, std::map<std::string,std::string>()),mValue(nullptr), mUuid(amb::createUuid()), mZone(zone)
503 setType(prop.c_str());
506 QString Property::name()
508 return mValue->name.c_str();
511 void Property::setType(QString t)
513 if(mValue && name() != "")
514 routingEngine->unsubscribeToProperty(name().toStdString(), this);
516 routingEngine->subscribeToProperty(t.toStdString(), this);
518 mValue = VehicleProperty::getPropertyTypeForPropertyNameValue(t.toStdString());
523 AsyncPropertyRequest request;
524 request.property = mValue->name;
525 request.completed = [this](AsyncPropertyReply* reply)
528 propertyChanged(reply->value);
533 routingEngine->getPropertyAsync(request);
536 void Property::propertyChanged(AbstractPropertyType *value)
538 if(value->zone != mZone)
545 mValue = value->copy();
547 changed(gvariantToQVariant(mValue->toVariant()));
551 QVariant BluemonkeySink::zonesForProperty(QString prop, QString src)
553 PropertyInfo info = routingEngine->getPropertyInfo(prop.toStdString(), src.toStdString());
557 for(auto i : info.zones())