Skip to content

Commit

Permalink
Functional version of remote gateway control and group cascades in sa…
Browse files Browse the repository at this point in the history
…me IP network
  • Loading branch information
manup committed Sep 18, 2016
1 parent 8f9f3cd commit 3c1e631
Show file tree
Hide file tree
Showing 7 changed files with 690 additions and 50 deletions.
187 changes: 187 additions & 0 deletions database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"
#include "deconz/dbg_trace.h"
#include "gateway.h"
#include "json.h"

/******************************************************************************
Expand All @@ -32,6 +33,7 @@ static int sqliteLoadAllRulesCallback(void *user, int ncols, char **colval , cha
static int sqliteLoadAllSensorsCallback(void *user, int ncols, char **colval , char **colname);
static int sqliteGetAllLightIdsCallback(void *user, int ncols, char **colval , char **colname);
static int sqliteGetAllSensorIdsCallback(void *user, int ncols, char **colval , char **colname);
static int sqliteLoadAllGatewaysCallback(void *user, int ncols, char **colval , char **colname);

/******************************************************************************
Implementation
Expand Down Expand Up @@ -72,6 +74,7 @@ void DeRestPluginPrivate::initDb()
"CREATE TABLE IF NOT EXISTS sensors (sid TEXT PRIMARY KEY, name TEXT, type TEXT, modelid TEXT, manufacturername TEXT, uniqueid TEXT, swversion TEXT, state TEXT, config TEXT, fingerprint TEXT, deletedState TEXT, mode TEXT)",
"CREATE TABLE IF NOT EXISTS scenes (gsid TEXT PRIMARY KEY, gid TEXT, sid TEXT, name TEXT, transitiontime TEXT, lights TEXT)",
"CREATE TABLE IF NOT EXISTS schedules (id TEXT PRIMARY KEY, json TEXT)",
"CREATE TABLE IF NOT EXISTS gateways (uuid TEXT PRIMARY KEY, name TEXT, ip TEXT, port TEXT, pairing TEXT, apikey TEXT, cgroups TEXT)",
"ALTER TABLE sensors add column fingerprint TEXT",
"ALTER TABLE sensors add column deletedState TEXT",
"ALTER TABLE sensors add column mode TEXT",
Expand Down Expand Up @@ -189,6 +192,7 @@ void DeRestPluginPrivate::readDb()
loadAllRulesFromDb();
loadAllSchedulesFromDb();
loadAllSensorsFromDb();
loadAllGatewaysFromDb();
}

/*! Sqlite callback to load authentification data.
Expand Down Expand Up @@ -1684,6 +1688,35 @@ void DeRestPluginPrivate::loadAllSensorsFromDb()
}
}

/*! Loads all gateways from database
*/
void DeRestPluginPrivate::loadAllGatewaysFromDb()
{
int rc;
char *errmsg = 0;

DBG_Assert(db != 0);

if (!db)
{
return;
}

QString sql(QLatin1String("SELECT * FROM gateways"));

DBG_Printf(DBG_INFO_L2, "sql exec %s\n", qPrintable(sql));
rc = sqlite3_exec(db, qPrintable(sql), sqliteLoadAllGatewaysCallback, this, &errmsg);

if (rc != SQLITE_OK)
{
if (errmsg)
{
DBG_Printf(DBG_ERROR_L2, "sqlite3_exec %s, error: %s\n", qPrintable(sql), errmsg);
sqlite3_free(errmsg);
}
}
}

/*! Sqlite callback to load all light ids into temporary array.
*/
static int sqliteGetAllLightIdsCallback(void *user, int ncols, char **colval , char **colname)
Expand Down Expand Up @@ -1806,6 +1839,82 @@ static int sqliteGetAllSensorIdsCallback(void *user, int ncols, char **colval ,
return 0;
}

static int sqliteLoadAllGatewaysCallback(void *user, int ncols, char **colval , char **colname)
{
DBG_Assert(user != 0);

if (!user || (ncols <= 0))
{
return 0;
}

DeRestPluginPrivate *d = static_cast<DeRestPluginPrivate*>(user);

int idxUuid = -1;
int idxName = -1;
int idxIp = -1;
int idxPort = -1;
int idxApikey = -1;
int idxPairing = -1;
int idxCgroups = -1;

for (int i = 0; i < ncols; i++)
{
if (colval[i] && (colval[i][0] != '\0'))
{
if (strcmp(colname[i], "uuid") == 0) { idxUuid = i; }
else if (strcmp(colname[i], "name") == 0) { idxName = i; }
else if (strcmp(colname[i], "ip") == 0) { idxIp = i; }
else if (strcmp(colname[i], "port") == 0) { idxPort = i; }
else if (strcmp(colname[i], "apikey") == 0) { idxApikey = i; }
else if (strcmp(colname[i], "pairing") == 0) { idxPairing = i; }
else if (strcmp(colname[i], "cgroups") == 0) { idxCgroups = i; }
}
}

if (idxUuid == -1)
{
return 0; // required
}

Gateway *gw = new Gateway(d);

gw->setUuid(colval[idxUuid]);
if (idxName != -1) { gw->setName(colval[idxName]); }
if (idxIp != -1) { gw->setAddress(QHostAddress(colval[idxIp])); }
if (idxPort != -1) { gw->setPort(QString(colval[idxPort]).toUShort()); }
if (idxApikey != -1) { gw->setApiKey(colval[idxApikey]); }
if (idxPairing != -1) { gw->setPairingEnabled(colval[idxPairing][0] == '1'); }
if (idxCgroups != -1 && colval[idxCgroups][0] == '[') // must be json array
{
bool ok;
QVariant var = Json::parse(colval[idxCgroups], ok);

if (ok && var.type() == QVariant::List)
{
QVariantList ls = var.toList();
for (int i = 0; i < ls.size(); i++)
{
QVariantMap e = ls[i].toMap();
if (e.contains(QLatin1String("lg")) && e.contains(QLatin1String("rg")))
{
double lg = e[QLatin1String("lg")].toDouble();
double rg = e[QLatin1String("rg")].toDouble();

if (lg > 0 && lg <= 0xfffful && rg > 0 && rg <= 0xfffful)
{
gw->addCascadeGroup(lg, rg);
}
}
}
}
}
gw->setNeedSaveDatabase(false);
d->gateways.push_back(gw);

return 0;
}

/*! Determines a unused id for a sensor.
*/
int DeRestPluginPrivate::getFreeSensorId()
Expand Down Expand Up @@ -2062,6 +2171,84 @@ void DeRestPluginPrivate::saveDb()
saveDatabaseItems &= ~DB_USERPARAM;
}

// save gateways
if (saveDatabaseItems & DB_GATEWAYS)
{
std::vector<Gateway*>::iterator i = gateways.begin();
std::vector<Gateway*>::iterator end = gateways.end();

for (; i != end; ++i)
{
Gateway *gw = *i;
if (!gw->needSaveDatabase())
{
continue;
}

gw->setNeedSaveDatabase(false);

if (!gw->pairingEnabled())
{
// delete gateways from db (if exist)
QString sql = QString(QLatin1String("DELETE FROM gateways WHERE uuid='%1'")).arg(gw->uuid());

DBG_Printf(DBG_INFO_L2, "sql exec %s\n", qPrintable(sql));
errmsg = NULL;
rc = sqlite3_exec(db, sql.toUtf8().constData(), NULL, NULL, &errmsg);

if (rc != SQLITE_OK)
{
if (errmsg)
{
DBG_Printf(DBG_ERROR, "sqlite3_exec failed: %s, error: %s\n", qPrintable(sql), errmsg);
sqlite3_free(errmsg);
}
}
}
else
{
QByteArray cgroups("[]");
if (!gw->cascadeGroups().empty())
{
QVariantList ls;
for (size_t i = 0; i < gw->cascadeGroups().size(); i++)
{
const Gateway::CascadeGroup &cg = gw->cascadeGroups()[i];
QVariantMap e;
e[QLatin1String("lg")] = (double)cg.local;
e[QLatin1String("rg")] = (double)cg.remote;
ls.push_back(e);
}
cgroups = Json::serialize(ls);
}

QString sql = QString(QLatin1String("REPLACE INTO gateways (uuid, name, ip, port, pairing, apikey, cgroups) VALUES ('%1', '%2', '%3', '%4', '%5', '%6', '%7')"))
.arg(gw->uuid())
.arg(gw->name())
.arg(gw->address().toString())
.arg(gw->port())
.arg((gw->pairingEnabled() ? '1' : '0'))
.arg(gw->apiKey())
.arg(qPrintable(cgroups));

DBG_Printf(DBG_INFO_L2, "sql exec %s\n", qPrintable(sql));
errmsg = NULL;
rc = sqlite3_exec(db, sql.toUtf8().constData(), NULL, NULL, &errmsg);

if (rc != SQLITE_OK)
{
if (errmsg)
{
DBG_Printf(DBG_ERROR, "sqlite3_exec failed: %s, error: %s\n", qPrintable(sql), errmsg);
sqlite3_free(errmsg);
}
}
}
}

saveDatabaseItems &= ~DB_GATEWAYS;
}

// save nodes
if (saveDatabaseItems & DB_LIGHTS)
{
Expand Down
8 changes: 8 additions & 0 deletions de_web_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,16 +326,24 @@ void DeRestPluginPrivate::apsdeDataIndication(const deCONZ::ApsDataIndication &i

case SCENE_CLUSTER_ID:
handleSceneClusterIndication(task, ind, zclFrame);
handleClusterIndicationGateways(ind, zclFrame);
break;

case OTAU_CLUSTER_ID:
otauDataIndication(ind, zclFrame);
break;

case COMMISSIONING_CLUSTER_ID:
handleCommissioningClusterIndication(task, ind, zclFrame);
break;

case LEVEL_CLUSTER_ID:
handleClusterIndicationGateways(ind, zclFrame);
break;

case ONOFF_CLUSTER_ID:
handleOnOffClusterIndication(task, ind, zclFrame);
handleClusterIndicationGateways(ind, zclFrame);
break;

default:
Expand Down
5 changes: 5 additions & 0 deletions de_web_plugin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
#define DB_RULES 0x00000040
#define DB_SENSORS 0x00000080
#define DB_USERPARAM 0x00000100
#define DB_GATEWAYS 0x00000200

#define DB_LONG_SAVE_DELAY (15 * 60 * 1000) // 15 minutes
#define DB_SHORT_SAVE_DELAY (5 * 1 * 1000) // 5 seconds
Expand Down Expand Up @@ -504,6 +505,8 @@ class DeRestPluginPrivate : public QObject
int getAllGateways(const ApiRequest &req, ApiResponse &rsp);
int getGatewayState(const ApiRequest &req, ApiResponse &rsp);
int setGatewayState(const ApiRequest &req, ApiResponse &rsp);
int addCascadeGroup(const ApiRequest &req, ApiResponse &rsp);
int deleteCascadeGroup(const ApiRequest &req, ApiResponse &rsp);
void gatewayToMap(const ApiRequest &req, const Gateway *gw, QVariantMap &map);

// REST API configuration
Expand Down Expand Up @@ -832,6 +835,7 @@ public Q_SLOTS:
void handleGroupClusterIndication(TaskItem &task, const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame);
void handleSceneClusterIndication(TaskItem &task, const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame);
void handleOnOffClusterIndication(TaskItem &task, const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame);
void handleClusterIndicationGateways(const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame);
void handleCommissioningClusterIndication(TaskItem &task, const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame);
bool handleMgmtBindRspConfirm(const deCONZ::ApsDataConfirm &conf);
void handleDeviceAnnceIndication(const deCONZ::ApsDataIndication &ind);
Expand Down Expand Up @@ -868,6 +872,7 @@ public Q_SLOTS:
void loadSceneFromDb(Scene *scene);
void loadAllRulesFromDb();
void loadAllSensorsFromDb();
void loadAllGatewaysFromDb();
int getFreeLightId();
int getFreeSensorId();
void saveDb();
Expand Down
Loading

0 comments on commit 3c1e631

Please sign in to comment.