Support multiple nymea hosts
This commit is contained in:
parent
e9c345cc8b
commit
c8a91ba9b1
@ -26,27 +26,29 @@ DeviceControlApplication::DeviceControlApplication(int argc, char *argv[]) : QAp
|
|||||||
setApplicationName("nymea-app");
|
setApplicationName("nymea-app");
|
||||||
setOrganizationName("nymea");
|
setOrganizationName("nymea");
|
||||||
|
|
||||||
qDebug() << "Creating QML view";
|
QString nymeaId = QtAndroid::androidActivity().callObjectMethod<jstring>("nymeaId").toString();
|
||||||
QQmlApplicationEngine *qmlEngine = new QQmlApplicationEngine(this);
|
QString thingId = QtAndroid::androidActivity().callObjectMethod<jstring>("thingId").toString();
|
||||||
|
|
||||||
Engine *m_engine = new Engine(this);
|
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup("tabSettings0");
|
|
||||||
QUuid lastConnected = settings.value("lastConnectedHost").toUuid();
|
|
||||||
settings.endGroup();
|
|
||||||
|
|
||||||
NymeaDiscovery *discovery = new NymeaDiscovery(this);
|
NymeaDiscovery *discovery = new NymeaDiscovery(this);
|
||||||
AWSClient::instance()->setConfig(settings.value("cloudEnvironment").toString());
|
AWSClient::instance()->setConfig(settings.value("cloudEnvironment").toString());
|
||||||
discovery->setAwsClient(AWSClient::instance());
|
discovery->setAwsClient(AWSClient::instance());
|
||||||
|
NymeaHost *host = discovery->nymeaHosts()->find(nymeaId);
|
||||||
|
|
||||||
NymeaHost *host = discovery->nymeaHosts()->find(lastConnected);
|
if (!host) {
|
||||||
qDebug() << "**** Tab settings" << lastConnected << host;
|
qWarning() << "No such nymea host:" << nymeaId;
|
||||||
if (host) {
|
// TODO: We could wait here until the discovery finds it... But it really should be cached already...
|
||||||
m_engine->jsonRpcClient()->connectToHost(host);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString thingId = QtAndroid::androidActivity().callObjectMethod<jstring>("thingId").toString();
|
Engine *m_engine = new Engine(this);
|
||||||
|
|
||||||
|
qDebug() << "Connecting to:" << host;
|
||||||
|
m_engine->jsonRpcClient()->connectToHost(host);
|
||||||
|
|
||||||
|
qDebug() << "Creating QML view";
|
||||||
|
QQmlApplicationEngine *qmlEngine = new QQmlApplicationEngine(this);
|
||||||
|
|
||||||
registerQmlTypes();
|
registerQmlTypes();
|
||||||
|
|
||||||
|
|||||||
@ -8,32 +8,53 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QtAndroid>
|
#include <QtAndroid>
|
||||||
|
|
||||||
AndroidBinder::AndroidBinder(Engine * engine):
|
AndroidBinder::AndroidBinder(NymeaAppService *service):
|
||||||
m_engine(engine)
|
m_service(service)
|
||||||
{
|
{
|
||||||
QAndroidParcel parcel;
|
|
||||||
parcel.writeData("foobar");
|
|
||||||
transact(10, parcel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidBinder::onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags)
|
bool AndroidBinder::onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags)
|
||||||
{
|
{
|
||||||
qDebug() << "onTransact: code " << code << ", flags " << int(flags);
|
qDebug() << "onTransact: code " << code << ", flags " << int(flags);
|
||||||
|
|
||||||
switch (code) {
|
// QString payload = data.readData();
|
||||||
case 0: { // Status request
|
QString payload = data.handle().callObjectMethod<jstring>("readString").toString();
|
||||||
qDebug() << "Engine is:" << m_engine->jsonRpcClient()->connected();
|
|
||||||
bool isReady = m_engine->jsonRpcClient()->connected() && !m_engine->thingManager()->fetchingData();
|
QJsonParseError error;
|
||||||
isReady = false;
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(payload.toUtf8(), &error);
|
||||||
reply.handle().callMethod<void>("writeBoolean", "(Z)V", isReady);
|
if (error.error != QJsonParseError::NoError) {
|
||||||
if (isReady) {
|
qWarning() << "Error parsing JSON from parcel:" << error.errorString();
|
||||||
reply.handle().callMethod<void>("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(m_engine->jsonRpcClient()->currentHost()->name()).object<jstring>());
|
qWarning() << payload;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QVariantMap request = jsonDoc.toVariant().toMap();
|
||||||
|
|
||||||
|
if (request.value("method").toString() == "GetInstances") {
|
||||||
|
QVariantMap params;
|
||||||
|
QVariantList instances;
|
||||||
|
foreach (const QUuid &nymeaId, m_service->engines().keys()) {
|
||||||
|
Engine *engine = m_service->engines().value(nymeaId);
|
||||||
|
QVariantMap instance;
|
||||||
|
instance.insert("id", nymeaId);
|
||||||
|
instance.insert("isReady", engine->jsonRpcClient()->connected() && !engine->thingManager()->fetchingData());
|
||||||
|
instance.insert("name", engine->jsonRpcClient()->currentHost()->name());
|
||||||
|
instances.append(instance);
|
||||||
|
}
|
||||||
|
params.insert("instances", instances);
|
||||||
|
sendReply(reply, params);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.value("method").toString() == "GetThings") {
|
||||||
|
QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
|
||||||
|
Engine *engine = m_service->engines().value(nymeaId);
|
||||||
|
if (!engine) {
|
||||||
|
qWarning() << "Android client requested things for an invalid nymea instance:" << nymeaId;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} break;
|
|
||||||
case 1: {// Things request
|
|
||||||
QVariantList thingsList;
|
QVariantList thingsList;
|
||||||
for (int i = 0; i < m_engine->thingManager()->things()->rowCount(); i++) {
|
for (int i = 0; i < engine->thingManager()->things()->rowCount(); i++) {
|
||||||
Device *thing = m_engine->thingManager()->things()->get(i);
|
Device *thing = engine->thingManager()->things()->get(i);
|
||||||
QVariantMap thingMap;
|
QVariantMap thingMap;
|
||||||
thingMap.insert("id", thing->id());
|
thingMap.insert("id", thing->id());
|
||||||
thingMap.insert("name", thing->name());
|
thingMap.insert("name", thing->name());
|
||||||
@ -62,41 +83,110 @@ bool AndroidBinder::onTransact(int code, const QAndroidParcel &data, const QAndr
|
|||||||
thingMap.insert("actions", actions);
|
thingMap.insert("actions", actions);
|
||||||
thingsList.append(thingMap);
|
thingsList.append(thingMap);
|
||||||
}
|
}
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(thingsList);
|
QVariantMap params;
|
||||||
reply.handle().callMethod<void>("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(jsonDoc.toJson()).object<jstring>());
|
params.insert("things", thingsList);
|
||||||
} break;
|
sendReply(reply, params);
|
||||||
case 2: {// ExecuteAction
|
return true;
|
||||||
// QString thingId = data.handle().callMethod<QAndroidJniObject>("readString", "").toString();
|
|
||||||
// jstring atId = data.handle().callMethod<jstring>("readString", "");
|
|
||||||
// QString actionTypeId = QAndroidJniObject::fromLocalRef(atId).toString();
|
|
||||||
// jstring p = data.handle().callMethod<jstring>("readString", "");
|
|
||||||
// QString param = QAndroidJniObject::fromLocalRef(p).toString();
|
|
||||||
qDebug() << "ExecuteAction";
|
|
||||||
QString thingId = data.readData();
|
|
||||||
QString actionTypeId = data.readData();
|
|
||||||
QString param = data.readData();
|
|
||||||
qDebug() << "**** executeAction:" << thingId << actionTypeId << param;
|
|
||||||
|
|
||||||
// FIXME: Only works with state generated actions!
|
|
||||||
QVariantMap paramMap;
|
|
||||||
paramMap.insert("paramTypeId", actionTypeId);
|
|
||||||
paramMap.insert("value", param);
|
|
||||||
m_engine->thingManager()->executeAction(thingId, actionTypeId, {paramMap});
|
|
||||||
|
|
||||||
} break;
|
|
||||||
// default:
|
|
||||||
// QAndroidBinder binder = data.readBinder();
|
|
||||||
|
|
||||||
// qDebug() << TAG << ": onTransact() received non-name data" << data.readVariant();
|
|
||||||
// reply.writeVariant(QVariant("Cannot process this!"));
|
|
||||||
|
|
||||||
// // send back message
|
|
||||||
// QAndroidParcel sendData, replyData;
|
|
||||||
// sendData.writeVariant(QVariant("Send me only names!"));
|
|
||||||
// binder.transact(0, sendData, &replyData);
|
|
||||||
// qDebug() << TAG << ": onTransact() received " << replyData.readData();
|
|
||||||
|
|
||||||
// break;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
if (request.value("method").toString() == "ExecuteAction") {
|
||||||
|
qDebug() << "ExecuteAction";
|
||||||
|
QUuid nymeaId = request.value("params").toMap().value("nymeaId").toUuid();
|
||||||
|
Engine *engine = m_service->engines().value(nymeaId);
|
||||||
|
if (!engine) {
|
||||||
|
qWarning() << "Android client requested executeAction for an invalid nymea instance:" << nymeaId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QUuid thingId = request.value("params").toMap().value("thingId").toUuid();
|
||||||
|
QUuid actionTypeId = request.value("params").toMap().value("actionTypeId").toUuid();
|
||||||
|
QVariantList params = request.value("params").toMap().value("params").toList();
|
||||||
|
|
||||||
|
qDebug() << "**** executeAction:" << thingId << actionTypeId << params;
|
||||||
|
engine->thingManager()->executeAction(thingId, actionTypeId, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch (code) {
|
||||||
|
// case 0: { // Status request
|
||||||
|
// bool isReady = m_engine->jsonRpcClient()->connected() && !m_engine->thingManager()->fetchingData();
|
||||||
|
// isReady = false;
|
||||||
|
// reply.handle().callMethod<void>("writeBoolean", "(Z)V", isReady);
|
||||||
|
// if (isReady) {
|
||||||
|
// reply.handle().callMethod<void>("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(m_engine->jsonRpcClient()->currentHost()->name()).object<jstring>());
|
||||||
|
// }
|
||||||
|
// } break;
|
||||||
|
// case 1: {// Things request
|
||||||
|
// QVariantList thingsList;
|
||||||
|
// for (int i = 0; i < m_engine->thingManager()->things()->rowCount(); i++) {
|
||||||
|
// Device *thing = m_engine->thingManager()->things()->get(i);
|
||||||
|
// QVariantMap thingMap;
|
||||||
|
// thingMap.insert("id", thing->id());
|
||||||
|
// thingMap.insert("name", thing->name());
|
||||||
|
// thingMap.insert("className", thing->thingClass()->displayName());
|
||||||
|
// thingMap.insert("interfaces", thing->thingClass()->interfaces());
|
||||||
|
// QVariantList states;
|
||||||
|
// for (int j = 0; j < thing->states()->rowCount(); j++) {
|
||||||
|
// State *state = thing->states()->get(j);
|
||||||
|
// QVariantMap stateMap;
|
||||||
|
// stateMap.insert("stateTypeId", state->stateTypeId());
|
||||||
|
// stateMap.insert("name", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->name());
|
||||||
|
// stateMap.insert("displayName", thing->thingClass()->stateTypes()->getStateType(state->stateTypeId())->displayName());
|
||||||
|
// stateMap.insert("value", state->value());
|
||||||
|
// states.append(stateMap);
|
||||||
|
// }
|
||||||
|
// thingMap.insert("states", states);
|
||||||
|
// QVariantList actions;
|
||||||
|
// for (int j = 0; j < thing->thingClass()->actionTypes()->rowCount(); j++) {
|
||||||
|
// ActionType *actionType = thing->thingClass()->actionTypes()->get(j);
|
||||||
|
// QVariantMap actionMap;
|
||||||
|
// actionMap.insert("actionTypeId", actionType->id());
|
||||||
|
// actionMap.insert("name", actionType->name());
|
||||||
|
// actionMap.insert("displayName", actionType->displayName());
|
||||||
|
// actions.append(actionMap);
|
||||||
|
// }
|
||||||
|
// thingMap.insert("actions", actions);
|
||||||
|
// thingsList.append(thingMap);
|
||||||
|
// }
|
||||||
|
// QJsonDocument jsonDoc = QJsonDocument::fromVariant(thingsList);
|
||||||
|
// reply.handle().callMethod<void>("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(jsonDoc.toJson()).object<jstring>());
|
||||||
|
// } break;
|
||||||
|
// case 2: {// ExecuteAction
|
||||||
|
//// QString thingId = data.handle().callMethod<QAndroidJniObject>("readString", "").toString();
|
||||||
|
//// jstring atId = data.handle().callMethod<jstring>("readString", "");
|
||||||
|
//// QString actionTypeId = QAndroidJniObject::fromLocalRef(atId).toString();
|
||||||
|
//// jstring p = data.handle().callMethod<jstring>("readString", "");
|
||||||
|
//// QString param = QAndroidJniObject::fromLocalRef(p).toString();
|
||||||
|
// qDebug() << "ExecuteAction";
|
||||||
|
// QString thingId = data.readData();
|
||||||
|
// QString actionTypeId = data.readData();
|
||||||
|
// QString param = data.readData();
|
||||||
|
// qDebug() << "**** executeAction:" << thingId << actionTypeId << param;
|
||||||
|
|
||||||
|
// // FIXME: Only works with state generated actions!
|
||||||
|
// QVariantMap paramMap;
|
||||||
|
// paramMap.insert("paramTypeId", actionTypeId);
|
||||||
|
// paramMap.insert("value", param);
|
||||||
|
// m_engine->thingManager()->executeAction(thingId, actionTypeId, {paramMap});
|
||||||
|
|
||||||
|
// } break;
|
||||||
|
//// default:
|
||||||
|
//// QAndroidBinder binder = data.readBinder();
|
||||||
|
|
||||||
|
//// qDebug() << TAG << ": onTransact() received non-name data" << data.readVariant();
|
||||||
|
//// reply.writeVariant(QVariant("Cannot process this!"));
|
||||||
|
|
||||||
|
//// // send back message
|
||||||
|
//// QAndroidParcel sendData, replyData;
|
||||||
|
//// sendData.writeVariant(QVariant("Send me only names!"));
|
||||||
|
//// binder.transact(0, sendData, &replyData);
|
||||||
|
//// qDebug() << TAG << ": onTransact() received " << replyData.readData();
|
||||||
|
|
||||||
|
//// break;
|
||||||
|
// }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidBinder::sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms)
|
||||||
|
{
|
||||||
|
QString payload = QJsonDocument::fromVariant(params).toJson();
|
||||||
|
reply.handle().callMethod<void>("writeString", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(payload).object<jstring>());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,17 +3,21 @@
|
|||||||
|
|
||||||
#include <QAndroidBinder>
|
#include <QAndroidBinder>
|
||||||
|
|
||||||
|
#include "nymeaappservice.h"
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
|
||||||
class AndroidBinder : public QAndroidBinder
|
class AndroidBinder : public QAndroidBinder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AndroidBinder(Engine *engine);
|
explicit AndroidBinder(NymeaAppService *service);
|
||||||
|
|
||||||
bool onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags) override;
|
bool onTransact(int code, const QAndroidParcel &data, const QAndroidParcel &reply, QAndroidBinder::CallType flags) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Engine *m_engine = nullptr;
|
void sendReply(const QAndroidParcel &reply, const QVariantMap ¶ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NymeaAppService *m_service = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ANDROIDBINDER_H
|
#endif // ANDROIDBINDER_H
|
||||||
|
|||||||
@ -11,44 +11,63 @@
|
|||||||
|
|
||||||
NymeaAppService::NymeaAppService(int argc, char **argv):
|
NymeaAppService::NymeaAppService(int argc, char **argv):
|
||||||
QAndroidService(argc, argv, [=](const QAndroidIntent &) {
|
QAndroidService(argc, argv, [=](const QAndroidIntent &) {
|
||||||
return new AndroidBinder{m_engine};
|
return new AndroidBinder{this};
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
setApplicationName("nymea-app");
|
setApplicationName("nymea-app");
|
||||||
setOrganizationName("nymea");
|
setOrganizationName("nymea");
|
||||||
|
|
||||||
m_engine = new Engine(this);
|
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup("tabSettings0");
|
|
||||||
QUuid lastConnected = settings.value("lastConnectedHost").toUuid();
|
|
||||||
settings.endGroup();
|
|
||||||
|
|
||||||
NymeaDiscovery *discovery = new NymeaDiscovery(this);
|
NymeaDiscovery *discovery = new NymeaDiscovery(this);
|
||||||
AWSClient::instance()->setConfig(settings.value("cloudEnvironment").toString());
|
AWSClient::instance()->setConfig(settings.value("cloudEnvironment").toString());
|
||||||
discovery->setAwsClient(AWSClient::instance());
|
discovery->setAwsClient(AWSClient::instance());
|
||||||
|
|
||||||
NymeaHost *host = discovery->nymeaHosts()->find(lastConnected);
|
|
||||||
if (host) {
|
for (int i = 0; i < 5; i++) {
|
||||||
m_engine->jsonRpcClient()->connectToHost(host);
|
settings.beginGroup(QString("tabSettings%1").arg(i));
|
||||||
|
QUuid lastConnected = settings.value("lastConnectedHost").toUuid();
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
if (lastConnected.isNull()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NymeaHost *host = discovery->nymeaHosts()->find(lastConnected);
|
||||||
|
if (!host) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Engine *engine = new Engine(this);
|
||||||
|
engine->jsonRpcClient()->connectToHost(host);
|
||||||
|
m_engines.insert(host->uuid(), engine);
|
||||||
|
|
||||||
|
|
||||||
|
QObject::connect(engine->thingManager(), &DeviceManager::thingStateChanged, [=](const QUuid &thingId, const QUuid &stateTypeId, const QVariant &value){
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
|
||||||
|
params.insert("thingId", thingId);
|
||||||
|
params.insert("stateTypeId", stateTypeId);
|
||||||
|
params.insert("value", value);
|
||||||
|
sendNotification("ThingStateChanged", params);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(engine->thingManager(), &DeviceManager::fetchingDataChanged, [=]() {
|
||||||
|
qDebug() << "Fetching data changed";
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("nymeaId", engine->jsonRpcClient()->currentHost()->uuid());
|
||||||
|
params.insert("isReady", !engine->thingManager()->fetchingData());
|
||||||
|
qDebug() << "Nymea host is ready" << engine->jsonRpcClient()->currentHost()->uuid();
|
||||||
|
sendNotification("ReadyStateChanged", params);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject::connect(m_engine->thingManager(), &DeviceManager::thingStateChanged, [=](const QUuid &thingId, const QUuid &stateTypeId, const QVariant &value){
|
qDebug() << "NymeaAppService started.";
|
||||||
QVariantMap params;
|
|
||||||
params.insert("thingId", thingId);
|
|
||||||
params.insert("stateTypeId", stateTypeId);
|
|
||||||
params.insert("value", value);
|
|
||||||
sendNotification("ThingStateChanged", params);
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(m_engine->thingManager(), &DeviceManager::fetchingDataChanged, [=]() {
|
}
|
||||||
QVariantMap params;
|
|
||||||
params.insert("isReady", !m_engine->thingManager()->fetchingData());
|
QHash<QUuid, Engine *> NymeaAppService::engines() const
|
||||||
if (m_engine->jsonRpcClient()->connected()) {
|
{
|
||||||
params.insert("systemName", m_engine->jsonRpcClient()->currentHost()->name());
|
return m_engines;
|
||||||
}
|
|
||||||
sendNotification("ReadyStateChanged", params);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NymeaAppService::sendNotification(const QString ¬ification, const QVariantMap ¶ms)
|
void NymeaAppService::sendNotification(const QString ¬ification, const QVariantMap ¶ms)
|
||||||
|
|||||||
@ -11,12 +11,14 @@ class NymeaAppService : public QAndroidService
|
|||||||
public:
|
public:
|
||||||
explicit NymeaAppService(int argc, char** argv);
|
explicit NymeaAppService(int argc, char** argv);
|
||||||
|
|
||||||
|
QHash<QUuid, Engine*> engines() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sendNotification(const QString ¬ification, const QVariantMap ¶ms);
|
void sendNotification(const QString ¬ification, const QVariantMap ¶ms);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Engine *m_engine = nullptr;
|
QHash<QUuid, Engine*> m_engines;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -11,3 +11,6 @@ APP_REVISION=$$member(VERSION_INFO, 1)
|
|||||||
|
|
||||||
DEFINES+=APP_VERSION=\\\"$${APP_VERSION}\\\"
|
DEFINES+=APP_VERSION=\\\"$${APP_VERSION}\\\"
|
||||||
android:QMAKE_POST_LINK += cp $$top_srcdir/version.txt $$top_builddir/
|
android:QMAKE_POST_LINK += cp $$top_srcdir/version.txt $$top_builddir/
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
$$PWD/packaging/android/src/io/guh/nymeaapp/NymeaHost.java
|
||||||
|
|||||||
@ -36,7 +36,10 @@ public class NymeaAppControlService extends ControlsProviderService {
|
|||||||
private String TAG = "nymea-app: NymeaAppControlService";
|
private String TAG = "nymea-app: NymeaAppControlService";
|
||||||
private NymeaAppServiceConnection m_serviceConnection;
|
private NymeaAppServiceConnection m_serviceConnection;
|
||||||
|
|
||||||
|
// For publishing all available
|
||||||
private ReplayProcessor m_publisherForAll;
|
private ReplayProcessor m_publisherForAll;
|
||||||
|
private ArrayList<UUID> m_pendingForAll = new ArrayList<UUID>(); // pending nymea ids to query
|
||||||
|
|
||||||
private ReplayProcessor m_updatePublisher;
|
private ReplayProcessor m_updatePublisher;
|
||||||
private List m_activeControlIds;
|
private List m_activeControlIds;
|
||||||
|
|
||||||
@ -44,52 +47,84 @@ public class NymeaAppControlService extends ControlsProviderService {
|
|||||||
private void ensureServiceConnection() {
|
private void ensureServiceConnection() {
|
||||||
if (m_serviceConnection == null) {
|
if (m_serviceConnection == null) {
|
||||||
m_serviceConnection = new NymeaAppServiceConnection(getBaseContext()) {
|
m_serviceConnection = new NymeaAppServiceConnection(getBaseContext()) {
|
||||||
@Override public void onReady() {
|
@Override public void onConnectedChanged(boolean connected) {
|
||||||
process();
|
Log.d(TAG, "Connected to NymeaAppService. Known hosts: " + m_serviceConnection.getHosts().size());
|
||||||
|
if (connected && m_publisherForAll != null) {
|
||||||
|
Log.d(TAG, "Processing all");
|
||||||
|
processAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Override public void onUpdate(UUID thingId) {
|
@Override public void onReadyChanged(UUID nymeaId, boolean ready) {
|
||||||
|
Log.d(TAG, "Nymea instance " + nymeaId.toString() + " ready state changed: " + Boolean.toString(ready));
|
||||||
|
if (ready) {
|
||||||
|
process(nymeaId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override public void onUpdate(UUID nymeaId, UUID thingId) {
|
||||||
Log.d(TAG, "onUpdate()");
|
Log.d(TAG, "onUpdate()");
|
||||||
if (m_updatePublisher != null && m_activeControlIds.contains(thingId.toString())) {
|
if (m_updatePublisher != null && m_activeControlIds.contains(thingId.toString())) {
|
||||||
Thing thing = m_serviceConnection.getThing(thingId);
|
Log.d(TAG, "Updating publisher for thing: " + thingId);
|
||||||
Log.d(TAG, "Updating publisher for thing: " + thing.name + " id: " + thing.id);
|
m_updatePublisher.onNext(thingToControl(nymeaId, thingId));
|
||||||
m_updatePublisher.onNext(thingToControl(thing));
|
|
||||||
// m_updatePublisher.onComplete();
|
// m_updatePublisher.onComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!m_serviceConnection.isConnected()) {
|
Intent serviceIntent = new Intent(this, NymeaAppService.class);
|
||||||
Intent serviceIntent = new Intent(this, NymeaAppService.class);
|
bindService(serviceIntent, m_serviceConnection, Context.BIND_AUTO_CREATE);
|
||||||
bindService(serviceIntent, m_serviceConnection, Context.BIND_AUTO_CREATE);
|
}
|
||||||
|
|
||||||
|
private void processAll() {
|
||||||
|
ensureServiceConnection();
|
||||||
|
if (m_serviceConnection.connected()) {
|
||||||
|
// Need to add all the pending before processing
|
||||||
|
if (m_publisherForAll != null) {
|
||||||
|
for (UUID nymeaId: m_serviceConnection.getHosts().keySet()) {
|
||||||
|
m_pendingForAll.add(nymeaId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (UUID nymeaId: m_serviceConnection.getHosts().keySet()) {
|
||||||
|
process(nymeaId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Not connected to NymeaAppService yet...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void process() {
|
private void process(UUID nymeaId) {
|
||||||
Log.d(TAG, "Processing...");
|
Log.d(TAG, "Processing...");
|
||||||
ensureServiceConnection();
|
ensureServiceConnection();
|
||||||
if (!m_serviceConnection.isReady()) {
|
if (!m_serviceConnection.connected()) {
|
||||||
|
Log.d(TAG, "NymeaAppService not connected to nymea instance " + nymeaId + " yet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!m_serviceConnection.getHosts().keySet().contains(nymeaId)) {
|
||||||
Log.d(TAG, "Service connection is not ready yet...");
|
Log.d(TAG, "Service connection is not ready yet...");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Thing thing : m_serviceConnection.getThings()) {
|
for (Thing thing : m_serviceConnection.getHosts().get(nymeaId).things.values()) {
|
||||||
Log.d(TAG, "Processing thing: " + thing.name);
|
Log.d(TAG, "Processing thing: " + thing.name);
|
||||||
|
|
||||||
if (m_publisherForAll != null) {
|
if (m_publisherForAll != null) {
|
||||||
Log.d(TAG, "Adding stateless");
|
Log.d(TAG, "Adding stateless");
|
||||||
m_publisherForAll.onNext(thingToControl(thing));
|
m_publisherForAll.onNext(thingToControl(nymeaId, thing.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_updatePublisher != null) {
|
if (m_updatePublisher != null) {
|
||||||
if (m_activeControlIds.contains(thing.id.toString())) {
|
if (m_activeControlIds.contains(thing.id.toString())) {
|
||||||
Log.d(TAG, "Adding stateful");
|
Log.d(TAG, "Adding stateful");
|
||||||
m_updatePublisher.onNext(thingToControl(thing));
|
m_updatePublisher.onNext(thingToControl(nymeaId, thing.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_pendingForAll.contains(nymeaId)) {
|
||||||
|
m_pendingForAll.remove(nymeaId);
|
||||||
|
}
|
||||||
|
|
||||||
// The publisher for all needs to be completed when done
|
// The publisher for all needs to be completed when done
|
||||||
if (m_publisherForAll != null) {
|
if (m_publisherForAll != null && m_pendingForAll.isEmpty()) {
|
||||||
Log.d(TAG, "Completing all publisher");
|
Log.d(TAG, "Completing all publisher");
|
||||||
m_publisherForAll.onComplete();
|
m_publisherForAll.onComplete();
|
||||||
}
|
}
|
||||||
@ -103,7 +138,7 @@ public class NymeaAppControlService extends ControlsProviderService {
|
|||||||
public Publisher createPublisherForAllAvailable() {
|
public Publisher createPublisherForAllAvailable() {
|
||||||
Log.d(TAG, "Creating publishers for all");
|
Log.d(TAG, "Creating publishers for all");
|
||||||
m_publisherForAll = ReplayProcessor.create();
|
m_publisherForAll = ReplayProcessor.create();
|
||||||
process();
|
processAll();
|
||||||
return FlowAdapters.toFlowPublisher(m_publisherForAll);
|
return FlowAdapters.toFlowPublisher(m_publisherForAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,19 +147,20 @@ public class NymeaAppControlService extends ControlsProviderService {
|
|||||||
Log.d(TAG, "Creating publishers for " + Integer.toString(controlIds.size()));
|
Log.d(TAG, "Creating publishers for " + Integer.toString(controlIds.size()));
|
||||||
m_updatePublisher = ReplayProcessor.create();
|
m_updatePublisher = ReplayProcessor.create();
|
||||||
m_activeControlIds = controlIds;
|
m_activeControlIds = controlIds;
|
||||||
process();
|
processAll();
|
||||||
return FlowAdapters.toFlowPublisher(m_updatePublisher);
|
return FlowAdapters.toFlowPublisher(m_updatePublisher);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performControlAction(String controlId, ControlAction action, Consumer consumer) {
|
public void performControlAction(String controlId, ControlAction action, Consumer consumer) {
|
||||||
Log.d(TAG, "Performing control action: " + controlId);
|
Log.d(TAG, "Performing control action: " + controlId);
|
||||||
//// PendingAction pendingAction = new PendingAction();
|
|
||||||
//// pendingAction.thingId = controlId;
|
|
||||||
//// pendingAction.actionTypeId = "";
|
|
||||||
//// pendingAction.consumer = consumer;
|
|
||||||
//// m_pendingActions.put(
|
|
||||||
|
|
||||||
|
UUID nymeaId = m_serviceConnection.hostForThing(UUID.fromString(controlId));
|
||||||
|
if (nymeaId == null) {
|
||||||
|
Log.d(TAG, "Nymea host not found for thing id: " + controlId);
|
||||||
|
consumer.accept(ControlAction.RESPONSE_FAIL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Thing thing = m_serviceConnection.getThing(UUID.fromString(controlId));
|
Thing thing = m_serviceConnection.getThing(UUID.fromString(controlId));
|
||||||
if (thing == null) {
|
if (thing == null) {
|
||||||
Log.d(TAG, "Thing not found for id: " + controlId);
|
Log.d(TAG, "Thing not found for id: " + controlId);
|
||||||
@ -162,17 +198,21 @@ public class NymeaAppControlService extends ControlsProviderService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_serviceConnection.executeAction(thing.id, actionTypeId, param);
|
m_serviceConnection.executeAction(nymeaId, thing.id, actionTypeId, param);
|
||||||
consumer.accept(ControlAction.RESPONSE_OK);
|
consumer.accept(ControlAction.RESPONSE_OK);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<UUID, Integer> m_intents = new HashMap<UUID, Integer>();
|
private HashMap<UUID, Integer> m_intents = new HashMap<UUID, Integer>();
|
||||||
|
|
||||||
private Control thingToControl(Thing thing) {
|
private Control thingToControl(UUID nymeaId, UUID thingId) {
|
||||||
// Log.d(TAG, "Creating control for thing: " + thing.name + " id: " + thing.id);
|
// Log.d(TAG, "Creating control for thing: " + thing.name + " id: " + thing.id);
|
||||||
|
|
||||||
// NOTE: intentId 1 doesn't work for some reason I don't understand yet... so let's make sure we never add "1" to it by always added 100
|
NymeaHost nymeaHost = m_serviceConnection.getHosts().get(nymeaId);
|
||||||
|
Thing thing = nymeaHost.things.get(thingId);
|
||||||
|
|
||||||
|
// NOTE: intentId 1 doesn't work for some reason I don't understand yet...
|
||||||
|
// so let's make sure we never add "1" to it by always added 100
|
||||||
int intentId = m_intents.size() + 100;
|
int intentId = m_intents.size() + 100;
|
||||||
PendingIntent pi;
|
PendingIntent pi;
|
||||||
if (m_intents.containsKey(thing.id)) {
|
if (m_intents.containsKey(thing.id)) {
|
||||||
@ -184,6 +224,7 @@ public class NymeaAppControlService extends ControlsProviderService {
|
|||||||
Context context = getBaseContext();
|
Context context = getBaseContext();
|
||||||
Intent intent = new Intent(context, NymeaAppControlsActivity.class);
|
Intent intent = new Intent(context, NymeaAppControlsActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||||
|
intent.putExtra("nymeaId", nymeaId.toString());
|
||||||
intent.putExtra("thingId", thing.id.toString());
|
intent.putExtra("thingId", thing.id.toString());
|
||||||
pi = PendingIntent.getActivity(context, intentId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
pi = PendingIntent.getActivity(context, intentId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
Log.d(TAG, "Created pendingintent for " + thing.name + " with id " + intentId + " and extra " + thing.id);
|
Log.d(TAG, "Created pendingintent for " + thing.name + " with id " + intentId + " and extra " + thing.id);
|
||||||
@ -191,7 +232,7 @@ public class NymeaAppControlService extends ControlsProviderService {
|
|||||||
Control.StatefulBuilder builder = new Control.StatefulBuilder(thing.id.toString(), pi)
|
Control.StatefulBuilder builder = new Control.StatefulBuilder(thing.id.toString(), pi)
|
||||||
.setTitle(thing.name)
|
.setTitle(thing.name)
|
||||||
.setSubtitle(thing.className)
|
.setSubtitle(thing.className)
|
||||||
.setStructure(m_serviceConnection.nymeaName());
|
.setStructure(nymeaHost.name);
|
||||||
|
|
||||||
if (thing.interfaces.contains("impulsebasedgaragedoor")) {
|
if (thing.interfaces.contains("impulsebasedgaragedoor")) {
|
||||||
builder.setDeviceType(DeviceTypes.TYPE_GARAGE);
|
builder.setDeviceType(DeviceTypes.TYPE_GARAGE);
|
||||||
|
|||||||
@ -32,10 +32,13 @@ public class NymeaAppControlsActivity extends org.qtproject.qt5.android.bindings
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String nymeaId()
|
||||||
|
{
|
||||||
|
return getIntent().getStringExtra("nymeaId");
|
||||||
|
}
|
||||||
|
|
||||||
public String thingId()
|
public String thingId()
|
||||||
{
|
{
|
||||||
Log.d(TAG, "ThingId called!");
|
|
||||||
Log.d(TAG, getIntent().getStringExtra("thingId"));
|
|
||||||
return getIntent().getStringExtra("thingId");
|
return getIntent().getStringExtra("thingId");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,13 @@ package io.guh.nymeaapp;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
@ -29,59 +31,63 @@ import org.json.*;
|
|||||||
public class NymeaAppServiceConnection implements ServiceConnection {
|
public class NymeaAppServiceConnection implements ServiceConnection {
|
||||||
private static final String TAG = "nymea-app: NymeaAppServiceConnection";
|
private static final String TAG = "nymea-app: NymeaAppServiceConnection";
|
||||||
private IBinder m_service;
|
private IBinder m_service;
|
||||||
private boolean m_isConnectedToNymea = false;
|
|
||||||
private boolean m_isReady = false;
|
|
||||||
private Context m_context;
|
private Context m_context;
|
||||||
|
|
||||||
private String m_nymeaName = "nymea";
|
private boolean m_connected = false;
|
||||||
private ArrayList<Thing> m_things = new ArrayList<>();
|
private HashMap<UUID, NymeaHost> m_nymeaHosts = new HashMap<UUID, NymeaHost>();
|
||||||
|
|
||||||
public NymeaAppServiceConnection(Context context) {
|
public NymeaAppServiceConnection(Context context) {
|
||||||
super();
|
super();
|
||||||
m_context = context;
|
m_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
final public boolean isConnected() {
|
final public boolean connected() {
|
||||||
return m_service != null;
|
return m_connected;
|
||||||
|
}
|
||||||
|
public void onConnectedChanged(boolean connected) {};
|
||||||
|
|
||||||
|
public final HashMap<UUID, NymeaHost> getHosts() {
|
||||||
|
return m_nymeaHosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
final public boolean isConnectedToNymea() {
|
|
||||||
return m_isConnectedToNymea;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public String nymeaName() {
|
|
||||||
return m_nymeaName;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public boolean isReady() {
|
|
||||||
return m_isReady;
|
|
||||||
}
|
|
||||||
|
|
||||||
final public ArrayList<Thing> getThings() {
|
|
||||||
return m_things;
|
|
||||||
}
|
|
||||||
final public Thing getThing(UUID thingId) {
|
final public Thing getThing(UUID thingId) {
|
||||||
for (int i = 0; i < m_things.size(); i++) {
|
for (HashMap.Entry<UUID, NymeaHost> entry : m_nymeaHosts.entrySet()) {
|
||||||
if (m_things.get(i).id.equals(thingId)) {
|
Thing thing = entry.getValue().things.get(thingId);
|
||||||
return m_things.get(i);
|
if (thing != null) {
|
||||||
|
return thing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final public UUID hostForThing(UUID thingId) {
|
||||||
|
for (HashMap.Entry<UUID, NymeaHost> entry : m_nymeaHosts.entrySet()) {
|
||||||
|
Thing thing = entry.getValue().things.get(thingId);
|
||||||
|
if (thing != null) {
|
||||||
|
return entry.getKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onReady() {}
|
public void onReadyChanged(UUID nymeaId, boolean ready) {}
|
||||||
public void onError() {}
|
public void onError() {}
|
||||||
public void onUpdate(UUID thingId) {}
|
public void onUpdate(UUID nymeaId, UUID thingId) {}
|
||||||
|
|
||||||
final public void executeAction(UUID thingId, UUID actionTypeId, String param) {
|
final public void executeAction(UUID nymeaId, UUID thingId, UUID actionTypeId, String paramValue) {
|
||||||
try {
|
try {
|
||||||
Parcel parcel = Parcel.obtain();
|
JSONObject params = new JSONObject();
|
||||||
parcel.writeByteArray(thingId.toString().getBytes());
|
params.put("nymeaId", nymeaId.toString());
|
||||||
parcel.writeByteArray(actionTypeId.toString().getBytes());
|
params.put("thingId", thingId.toString());
|
||||||
parcel.writeByteArray(param.getBytes());
|
params.put("actionTypeId", actionTypeId.toString());
|
||||||
|
JSONArray actionParams = new JSONArray();
|
||||||
|
JSONObject param = new JSONObject();
|
||||||
|
param.put("paramTypeId", actionTypeId.toString());
|
||||||
|
param.put("value", paramValue);
|
||||||
|
actionParams.put(param);
|
||||||
|
params.put("params", actionParams);
|
||||||
|
Parcel parcel = createRequest("ExecuteAction", params);
|
||||||
Parcel retParcel = Parcel.obtain();
|
Parcel retParcel = Parcel.obtain();
|
||||||
m_service.transact(2, parcel, retParcel, 0);
|
m_service.transact(1, parcel, retParcel, 0);
|
||||||
// thingsList = retParcel.readString();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(TAG, "Error calling executeAction on NymeaAppService");
|
Log.d(TAG, "Error calling executeAction on NymeaAppService");
|
||||||
}
|
}
|
||||||
@ -94,30 +100,44 @@ public class NymeaAppServiceConnection implements ServiceConnection {
|
|||||||
registerServiceBroadcastReceiver();
|
registerServiceBroadcastReceiver();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Parcel parcel = Parcel.obtain();
|
Parcel parcel = createRequest("GetInstances");
|
||||||
Parcel retParcel = Parcel.obtain();
|
Parcel retParcel = Parcel.obtain();
|
||||||
m_service.transact(0, parcel, retParcel, 0);
|
|
||||||
m_isReady = retParcel.readBoolean();
|
m_service.transact(1, parcel, retParcel, 0);
|
||||||
if (!m_isReady) {
|
|
||||||
m_nymeaName = retParcel.readString();
|
JSONObject reply = new JSONObject(retParcel.readString());
|
||||||
m_isConnectedToNymea = true;
|
Log.d(TAG, "Instaces received: " + reply.toString());
|
||||||
Log.d(TAG, "Service is ready!");
|
JSONArray instances = reply.getJSONArray("instances");
|
||||||
fetchThings();
|
for (int i = 0; i < instances.length(); i++) {
|
||||||
} else {
|
JSONObject instanceMap = instances.getJSONObject(i);
|
||||||
Log.d(TAG, "Service is not ready yet!");
|
NymeaHost nymeaHost = new NymeaHost();
|
||||||
|
nymeaHost.id = UUID.fromString(instanceMap.getString("id"));
|
||||||
|
nymeaHost.name = instanceMap.getString("name");
|
||||||
|
nymeaHost.isReady = instanceMap.getBoolean("isReady");
|
||||||
|
m_nymeaHosts.put(nymeaHost.id, nymeaHost);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (JSONException e) {
|
||||||
Log.d(TAG, "Error while waiting for service to be connected to nymea");
|
Log.d(TAG, "Error while processing JSON in communication with NymeaAppService: " + e.toString());
|
||||||
m_service = null;
|
onError();
|
||||||
|
return;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.d(TAG, "Error communicating with NymeaAppService: " + e.toString());
|
||||||
onError();
|
onError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_connected = true;
|
||||||
|
onConnectedChanged(m_connected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onServiceDisconnected(ComponentName arg0) {
|
@Override public void onServiceDisconnected(ComponentName arg0) {
|
||||||
m_service = null;
|
m_service = null;
|
||||||
m_isConnectedToNymea = false;
|
for (int i = 0; i < m_nymeaHosts.size(); i++) {
|
||||||
m_isReady = false;
|
m_nymeaHosts.get(i).isReady = false;
|
||||||
|
}
|
||||||
|
m_connected = false;
|
||||||
|
onConnectedChanged(m_connected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerServiceBroadcastReceiver() {
|
public void registerServiceBroadcastReceiver() {
|
||||||
@ -130,7 +150,7 @@ public class NymeaAppServiceConnection implements ServiceConnection {
|
|||||||
private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
|
private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
// Log.d(TAG, "In OnReceive broadcast receiver");
|
Log.d(TAG, "In OnReceive broadcast receiver");
|
||||||
if (NymeaAppService.NYMEA_APP_BROADCAST.equals(intent.getAction())) {
|
if (NymeaAppService.NYMEA_APP_BROADCAST.equals(intent.getAction())) {
|
||||||
String payload = intent.getStringExtra("data");
|
String payload = intent.getStringExtra("data");
|
||||||
try {
|
try {
|
||||||
@ -147,52 +167,57 @@ public class NymeaAppServiceConnection implements ServiceConnection {
|
|||||||
JSONObject data = new JSONObject(payload);
|
JSONObject data = new JSONObject(payload);
|
||||||
JSONObject params = data.getJSONObject("params");
|
JSONObject params = data.getJSONObject("params");
|
||||||
Log.d(TAG, "Broadcast received from NymeaAppService: " + data.getString("notification"));
|
Log.d(TAG, "Broadcast received from NymeaAppService: " + data.getString("notification"));
|
||||||
|
Log.d(TAG, params.toString());
|
||||||
|
|
||||||
if (data.getString("notification").equals("ThingStateChanged")) {
|
if (data.getString("notification").equals("ThingStateChanged")) {
|
||||||
|
UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
|
||||||
UUID thingId = UUID.fromString(params.getString("thingId"));
|
UUID thingId = UUID.fromString(params.getString("thingId"));
|
||||||
UUID stateTypeId = UUID.fromString(params.getString("stateTypeId"));
|
UUID stateTypeId = UUID.fromString(params.getString("stateTypeId"));
|
||||||
String value = params.getString("value");
|
String value = params.getString("value");
|
||||||
Log.d(TAG, "Thing state changed: " + thingId + " stateTypeId: " + stateTypeId + " value: " + value);
|
Log.d(TAG, "Thing state changed: " + thingId + " stateTypeId: " + stateTypeId + " value: " + value);
|
||||||
|
|
||||||
for (int i = 0; i < m_things.size(); i++) {
|
Thing thing = getThing(thingId);
|
||||||
if (m_things.get(i).id.equals(thingId)) {
|
if (thing != null) {
|
||||||
m_things.get(i).stateById(stateTypeId).value = value;
|
thing.stateById(stateTypeId).value = value;
|
||||||
onUpdate(thingId);
|
onUpdate(nymeaId, thingId);
|
||||||
}
|
} else {
|
||||||
|
Log.d(TAG, "Got a state change notification for a thing we don't know!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.getString("notification").equals("ReadyStateChanged")) {
|
if (data.getString("notification").equals("ReadyStateChanged")) {
|
||||||
m_isReady = params.getBoolean("isReady");
|
UUID nymeaId = UUID.fromString(params.getString("nymeaId"));
|
||||||
if (m_isReady) {
|
NymeaHost host = m_nymeaHosts.get(nymeaId);
|
||||||
m_nymeaName = params.getString("systemName");
|
host.isReady = params.getBoolean("isReady");
|
||||||
fetchThings();
|
if (host.isReady) {
|
||||||
|
Log.d(TAG, "Host is ready. Fetching things...");
|
||||||
|
fetchThings(nymeaId);
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Host is not ready yet...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchThings() {
|
private void fetchThings(UUID nymeaId) {
|
||||||
|
Log.d(TAG, "Fetching things");
|
||||||
String thingsList;
|
String thingsList;
|
||||||
try {
|
try {
|
||||||
Log.d(TAG, "Fetching things");
|
JSONObject params = new JSONObject();
|
||||||
Parcel parcel = Parcel.obtain();
|
params.put("nymeaId", nymeaId.toString());
|
||||||
|
Parcel parcel = createRequest("GetThings", params);
|
||||||
Parcel retParcel = Parcel.obtain();
|
Parcel retParcel = Parcel.obtain();
|
||||||
m_service.transact(1, parcel, retParcel, 0);
|
m_service.transact(1, parcel, retParcel, 0);
|
||||||
thingsList = retParcel.readString();
|
thingsList = retParcel.readString();
|
||||||
Log.d(TAG, "Things fetched");
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(TAG, "Error fetching things from NymeaAppService");
|
Log.d(TAG, "Error fetching things from NymeaAppService");
|
||||||
m_service = null;
|
|
||||||
m_isConnectedToNymea = false;
|
|
||||||
onError();
|
onError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Log.d(TAG, "Parsing JSON");
|
JSONObject result = new JSONObject(thingsList);
|
||||||
JSONArray arr = new JSONArray(thingsList);
|
for (int i = 0; i < result.getJSONArray("things").length(); i++) {
|
||||||
for (int i = 0; i < arr.length(); i++) {
|
JSONObject entry = result.getJSONArray("things").getJSONObject(i);
|
||||||
JSONObject entry = arr.getJSONObject(i);
|
|
||||||
Thing thing = new Thing();
|
Thing thing = new Thing();
|
||||||
thing.id = UUID.fromString(entry.getString("id"));
|
thing.id = UUID.fromString(entry.getString("id"));
|
||||||
thing.name = entry.getString("name");
|
thing.name = entry.getString("name");
|
||||||
@ -220,19 +245,34 @@ public class NymeaAppServiceConnection implements ServiceConnection {
|
|||||||
a.displayName = actionMap.getString("displayName");
|
a.displayName = actionMap.getString("displayName");
|
||||||
thing.actions.add(a);
|
thing.actions.add(a);
|
||||||
}
|
}
|
||||||
m_things.add(thing);
|
m_nymeaHosts.get(nymeaId).things.put(thing.id, thing);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(TAG, "Error parsing JSON from NymeaAppService: " + e.toString());
|
Log.d(TAG, "Error parsing JSON from NymeaAppService: " + e.toString());
|
||||||
|
Log.d(TAG, thingsList);
|
||||||
m_service = null;
|
m_service = null;
|
||||||
m_isConnectedToNymea = false;
|
|
||||||
onError();
|
onError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "Fetched things");
|
Log.d(TAG, "Things fetched: " + m_nymeaHosts.get(nymeaId).things.size());
|
||||||
m_isReady = true;
|
m_nymeaHosts.get(nymeaId).isReady = true;
|
||||||
onReady();
|
onReadyChanged(nymeaId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Parcel createRequest(String method) throws JSONException {
|
||||||
|
return createRequest(method, null);
|
||||||
|
}
|
||||||
|
private Parcel createRequest(String method, JSONObject params) throws JSONException {
|
||||||
|
Parcel ret = Parcel.obtain();
|
||||||
|
JSONObject payload = new JSONObject();
|
||||||
|
payload.put("method", method);
|
||||||
|
if (params != null) {
|
||||||
|
payload.put("params", params);
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Parcel payload: " + payload.toString());
|
||||||
|
ret.writeString(payload.toString());
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
packaging/android/src/io/guh/nymeaapp/NymeaHost.java
Normal file
13
packaging/android/src/io/guh/nymeaapp/NymeaHost.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package io.guh.nymeaapp;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class NymeaHost {
|
||||||
|
|
||||||
|
UUID id;
|
||||||
|
boolean isReady = false;
|
||||||
|
String name = "";
|
||||||
|
HashMap<UUID, Thing> things = new HashMap<UUID, Thing>();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user