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" void create(AbstractRoutingEngine* routingengine, map<string, string> config)
41 auto plugin = new AmbPlugin<BluemonkeySink>(routingengine, config);
45 QVariant gvariantToQVariant(GVariant *value)
47 GVariantClass c = g_variant_classify(value);
48 if(c == G_VARIANT_CLASS_BOOLEAN)
49 return QVariant((bool) g_variant_get_boolean(value));
51 else if(c == G_VARIANT_CLASS_BYTE)
52 return QVariant((char) g_variant_get_byte(value));
54 else if(c == G_VARIANT_CLASS_INT16)
55 return QVariant((int) g_variant_get_int16(value));
57 else if(c == G_VARIANT_CLASS_UINT16)
58 return QVariant((unsigned int) g_variant_get_uint16(value));
60 else if(c == G_VARIANT_CLASS_INT32)
61 return QVariant((int) g_variant_get_int32(value));
63 else if(c == G_VARIANT_CLASS_UINT32)
64 return QVariant((unsigned int) g_variant_get_uint32(value));
66 else if(c == G_VARIANT_CLASS_INT64)
67 return QVariant((long long) g_variant_get_int64(value));
69 else if(c == G_VARIANT_CLASS_UINT64)
70 return QVariant((unsigned long long) g_variant_get_uint64(value));
72 else if(c == G_VARIANT_CLASS_DOUBLE)
73 return QVariant(g_variant_get_double(value));
75 else if(c == G_VARIANT_CLASS_STRING)
76 return QVariant(g_variant_get_string(value, NULL));
78 else if(c == G_VARIANT_CLASS_ARRAY)
80 gsize dictsize = g_variant_n_children(value);
82 for (int i=0; i<dictsize; i++)
84 GVariant *childvariant = g_variant_get_child_value(value, i);
85 GVariant *innervariant = g_variant_get_variant(childvariant);
86 list.append(gvariantToQVariant(innervariant));
92 return QVariant::Invalid;
96 AbstractPropertyType* qVariantToAbstractPropertyType(QString name, QVariant var)
101 if(var.type() == QVariant::UInt)
102 return new BasicPropertyType<uint>(name.toStdString(), var.toUInt());
103 else if(var.type() == QVariant::Double)
104 return new BasicPropertyType<double>(name.toStdString(), var.toDouble());
105 else if(var.type() == QVariant::Bool)
106 return new BasicPropertyType<bool>(name.toStdString(), var.toBool());
107 else if(var.type() == QVariant::Int)
108 return new BasicPropertyType<int>(name.toStdString(), var.toInt());
109 else if(var.type() == QVariant::String)
110 return new StringPropertyType(name.toStdString(), var.toString().toStdString());
111 else if(var.type() == QVariant::List && var.toList().count())
113 QVariant subVariant = var.toList().at(0);
114 if(subVariant.type() == QVariant::UInt)
115 return new ListPropertyType<BasicPropertyType<uint>>(name.toStdString(), subVariant.toUInt());
116 else if(subVariant.type() == QVariant::Double)
117 return new ListPropertyType<BasicPropertyType<double>>(name.toStdString(), subVariant.toDouble());
118 else if(subVariant.type() == QVariant::Bool)
119 return new ListPropertyType<BasicPropertyType<bool>>(name.toStdString(), subVariant.toBool());
120 else if(subVariant.type() == QVariant::Int)
121 return new ListPropertyType<BasicPropertyType<int>>(name.toStdString(), subVariant.toInt());
122 else if(subVariant.type() == QVariant::String)
123 return new ListPropertyType<StringPropertyType>(name.toStdString(), subVariant.toString().toStdString());
128 QVariant toQVariant(AbstractPropertyType* val)
132 value["name"] = val->name.c_str();
133 value["zone"] = val->zone;
134 value["source"] = val->sourceUuid.c_str();
135 value["timestamp"] = val->timestamp;
136 value["sequence"] = val->sequence;
137 value["value"] = gvariantToQVariant(val->toVariant());
142 BluemonkeySink::BluemonkeySink(AbstractRoutingEngine* e, map<string, string> config, AbstractSource &parent)
143 : QObject(0), AmbPluginImpl(e, config, parent), engine(nullptr), mSilentMode(false)
145 QTimer::singleShot(1,this,SLOT(reloadEngine()));
147 auth = new Authenticate(config, this);
150 BluemonkeySink::~BluemonkeySink()
152 Q_FOREACH(void* module, modules)
159 PropertyList BluemonkeySink::subscriptions()
164 void BluemonkeySink::supportedChanged(const PropertyList & supportedProperties)
166 DebugOut()<<"supported changed"<<endl;
169 void BluemonkeySink::propertyChanged(AbstractPropertyType * value)
174 const string BluemonkeySink::uuid() const
179 int BluemonkeySink::supportedOperations()
181 return AbstractSource::Get | AbstractSource::Set;
184 QObject *BluemonkeySink::subscribeTo(QString str)
186 return new Property(str.toStdString(), "", routingEngine, Zone::None, this);
189 QObject *BluemonkeySink::subscribeTo(QString str, int zone, QString srcFilter)
191 return new Property(str.toStdString(), srcFilter, routingEngine, zone, this);
194 QObject* BluemonkeySink::subscribeTo(QString str, int zone)
196 return new Property(str.toStdString(), "", routingEngine, zone, this);
200 QStringList BluemonkeySink::sourcesForProperty(QString property)
202 std::vector<std::string> list = routingEngine->sourcesForProperty(property.toStdString());
206 strList<<itr.c_str();
212 QStringList BluemonkeySink::supportedProperties()
214 PropertyList props = routingEngine->supported();
225 bool BluemonkeySink::authenticate(QString pass)
230 void BluemonkeySink::loadConfig(QString str)
233 if(!file.open(QIODevice::ReadOnly))
235 DebugOut(DebugOut::Error)<<"failed to open config file: "<<str.toStdString()<<endl;
239 QString script = file.readAll();
243 DebugOut()<<"evaluating script: "<<script.toStdString()<<endl;
245 QJSValue val = engine->evaluate(script);
247 DebugOut()<<val.toString().toStdString()<<endl;
251 DebugOut(DebugOut::Error) << val.property("name").toString().toStdString() << endl;
252 DebugOut(DebugOut::Error) << val.property("message").toString().toStdString() << endl;
253 DebugOut(DebugOut::Error) << str.toStdString() << ":" <<val.property("lineNumber").toString().toStdString() << endl;
257 bool BluemonkeySink::loadModule(QString path)
259 void* handle = dlopen(path.toUtf8().data(), RTLD_LAZY);
263 DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << dlerror() << endl;
267 if(modules.contains(handle))
270 modules.push_back(handle);
272 void* c = dlsym(handle, "create");
276 DebugOut(DebugOut::Warning) << "bluemonkey load module failed: " << path.toStdString() << " " << dlerror() << endl;
280 create_bluemonkey_module_t* create = (create_bluemonkey_module_t*)(c);
282 std::map<std::string, QObject*> exports = create(configuration, this);
284 for(auto i : exports)
286 std::string obj = i.first;
287 if(!engine->globalObject().hasProperty(obj.c_str()))
289 QJSValue val = engine->newQObject(i.second);
290 engine->globalObject().setProperty(obj.c_str(), val);
297 void BluemonkeySink::reloadEngine()
300 engine->deleteLater();
302 engine = new QJSEngine(this);
304 QJSValue value = engine->newQObject(this);
305 engine->globalObject().setProperty("bluemonkey", value);
307 loadConfig(configuration["config"].c_str());
310 void BluemonkeySink::writeProgram(QString program)
314 QJSValue result = temp.evaluate(program);
317 DebugOut(DebugOut::Error)<<"Syntax error in program: "<<result.toString().toStdString()<<endl;
321 QFile file(configuration["customPrograms"].c_str());
323 if(!file.open(QIODevice::ReadWrite | QIODevice::Append))
325 DebugOut(DebugOut::Error)<<"failed to open file: "<<file.fileName().toStdString()<<endl;
329 file.write(program.toUtf8());
335 void BluemonkeySink::log(QString str)
337 DebugOut()<<str.toStdString()<<endl;
340 QObject *BluemonkeySink::createTimer()
342 return new QTimer(this);
345 QObject *BluemonkeySink::createQObject()
347 return new QObject(this);
350 void BluemonkeySink::getHistory(QStringList properties, QDateTime begin, QDateTime end, QJSValue cbFunction)
352 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
353 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
354 AsyncRangePropertyRequest request;
355 request.timeBegin = b;
358 PropertyList reqlist;
360 foreach(QString prop, properties)
362 reqlist.push_back(prop.toStdString());
365 request.properties = reqlist;
366 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
370 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
374 if(cbFunction.isCallable())
378 for(auto val : reply->values)
380 list.append(toQVariant(val));
383 QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
385 cbFunction.call(QJSValueList()<<val);
392 routingEngine->getRangePropertyAsync(request);
395 void BluemonkeySink::createCustomProperty(QString name, QJSValue defaultValue, int zone)
397 QVariant var = defaultValue.toVariant();
399 DebugOut() << "Variant value for: " << name.toStdString() << " is " << defaultValue.toString().toStdString() << endl;
401 auto create = [name, var]() -> AbstractPropertyType*
403 return qVariantToAbstractPropertyType(name, var);
406 addPropertySupport(zone, create);
408 AsyncSetPropertyRequest request;
409 request.property = name.toStdString();
410 request.zoneFilter = zone;
411 request.value = VehicleProperty::getPropertyTypeForPropertyNameValue(name.toStdString(), defaultValue.toString().toStdString());
413 routingEngine->updateSupported(supported(), PropertyList(), &source);
414 routingEngine->setProperty(request);
418 QVariant Property::value()
420 return mValue ? gvariantToQVariant(mValue->toVariant()) : QVariant::Invalid;
423 void Property::setValue(QVariant v)
425 if(v.type() == QVariant::List || v.type() == QVariant::Map)
428 QJsonDocument doc = QJsonDocument::fromVariant(v);
430 QString json = doc.toJson();
432 mValue->fromString(json.toStdString());
436 QString tempVal = v.toString();
437 mValue->fromString(tempVal.toStdString());
440 AsyncSetPropertyRequest request;
441 request.property = mValue->name;
442 request.value = mValue->copy();
443 request.completed = [&](AsyncPropertyReply* reply)
447 propertyChanged(reply->value);
451 DebugOut(DebugOut::Warning) << "Error, trying to set value: " << reply->error << endl;
455 routingEngine->setProperty(request);
458 void Property::getHistory(QDateTime begin, QDateTime end, QJSValue cbFunction)
460 double b = (double)begin.toMSecsSinceEpoch() / 1000.0;
461 double e = (double)end.toMSecsSinceEpoch() / 1000.0;
462 AsyncRangePropertyRequest request;
463 request.timeBegin = b;
466 PropertyList reqlist;
467 reqlist.push_back(mValue->name);
469 request.properties = reqlist;
470 request.completed = [&cbFunction](AsyncRangePropertyReply* reply)
474 DebugOut(DebugOut::Error)<<"bluemoney get history call failed"<<endl;
478 if(cbFunction.isCallable())
482 for(auto val : reply->values)
484 list.append(toQVariant(val));
487 QJSValue val = cbFunction.engine()->toScriptValue<QVariantList>(list);
488 cbFunction.call(QJSValueList()<<val);
495 routingEngine->getRangePropertyAsync(request);
498 Property::Property(VehicleProperty::Property prop, QString srcFilter, AbstractRoutingEngine* re, Zone::Type zone, QObject *parent)
499 :QObject(parent), AbstractSink(re, std::map<std::string,std::string>()),mValue(nullptr), mUuid(amb::createUuid()), mZone(zone)
501 setType(prop.c_str());
504 QString Property::name()
506 return mValue->name.c_str();
509 void Property::setType(QString t)
511 if(mValue && name() != "")
512 routingEngine->unsubscribeToProperty(name().toStdString(), this);
514 routingEngine->subscribeToProperty(t.toStdString(), this);
516 mValue = VehicleProperty::getPropertyTypeForPropertyNameValue(t.toStdString());
521 AsyncPropertyRequest request;
522 request.property = mValue->name;
523 request.completed = [this](AsyncPropertyReply* reply)
526 propertyChanged(reply->value);
531 routingEngine->getPropertyAsync(request);
534 void Property::propertyChanged(AbstractPropertyType *value)
536 if(value->zone != mZone)
543 mValue = value->copy();
545 changed(gvariantToQVariant(mValue->toVariant()));
549 QVariant BluemonkeySink::zonesForProperty(QString prop, QString src)
551 PropertyInfo info = routingEngine->getPropertyInfo(prop.toStdString(), src.toStdString());
555 for(auto i : info.zones())