Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into updateForDDFsirens
Browse files Browse the repository at this point in the history
  • Loading branch information
SwoopX committed Aug 7, 2024
2 parents ad3ed2a + e2dc40a commit 20ede2f
Show file tree
Hide file tree
Showing 375 changed files with 2,900 additions and 478 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.13)

project(de_rest_plugin VERSION 2.27.04 LANGUAGES C;CXX)
project(de_rest_plugin VERSION 2.27.06 LANGUAGES C;CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

Expand Down
17 changes: 12 additions & 5 deletions de_web_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3690,7 +3690,10 @@ LightNode *DeRestPluginPrivate::updateLightNode(const deCONZ::NodeEvent &event)
{
if (RStateEffectValuesMueller.indexOf(lightNode->toString(RStateEffect), 0) <= 1)
{
lightNode->setValue(RStateEffect, RStateEffectValues[ia->numericValue().u8]);
if ((int)ia->numericValue().u8 < RStateEffectValues.size())
{
lightNode->setValue(RStateEffect, RStateEffectValues[ia->numericValue().u8]);
}
}
}
else if (ia->id() == 0x4004) // color loop time
Expand Down Expand Up @@ -16749,19 +16752,23 @@ void DEV_AllocateGroup(const Device *device, Resource *rsub, ResourceItem *item)
*/
void DEV_ReloadDeviceIdendifier(unsigned atomIndexMfname, unsigned atomIndexModelid)
{
(void)atomIndexMfname;

for (auto &dev : plugin->m_devices)
{
{
const ResourceItem *mfname = dev->item(RAttrManufacturerName);
if (!mfname || mfname->atomIndex() != atomIndexMfname)
const ResourceItem *modelid = dev->item(RAttrModelId);
if (!modelid || modelid->atomIndex() != atomIndexModelid)
continue;
}

#if 0 // ignore for now since manufacturer name might have case sensitive variations
{
const ResourceItem *modelid = dev->item(RAttrModelId);
if (!modelid || modelid->atomIndex() != atomIndexModelid)
const ResourceItem *mfname = dev->item(RAttrManufacturerName);
if (!mfname || mfname->atomIndex() != atomIndexMfname)
continue;
}
#endif

enqueueEvent(Event(RDevices, REventDDFReload, 0, dev->key()));
}
Expand Down
111 changes: 102 additions & 9 deletions device_descriptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct DDF_LoadRecord
{
AT_AtomIndex modelid;
AT_AtomIndex mfname;
uint32_t mfnameLowerCaseHash;
DDF_LoadState loadState;
};

Expand Down Expand Up @@ -166,6 +167,66 @@ static void DDF_UpdateItemHandles(std::vector<DeviceDescription> &descriptions,
static void DDF_TryCompileAndFixJavascript(QString *expr, const QString &path);
DeviceDescription DDF_LoadScripts(const DeviceDescription &ddf);

/*
* https://maskray.me/blog/2023-04-12-elf-hash-function
*
* PJW hash adapted from musl libc.
*
* TODO(mpi): make this a own module U_StringHash()
*/
static uint32_t DDF_StringHash(const void *s0, unsigned size)
{
uint32_t h;
const unsigned char *s;

h = 0;
s = (const unsigned char*)s0;

while (size--)
{
h = 16 * h + *s++;
h ^= h >> 24 & 0xF0;
}
return h & 0xfffffff;
}

/*! Helper to create a 32-bit string hash from an atom string.
This is mainly used to get a unique number to compare case insensitive manufacturer names.
For example for "HEIMAN", "heiman" and "Heiman" atoms this function returns the same hash.
*/
static uint32_t DDF_AtomLowerCaseStringHash(AT_AtomIndex ati)
{
unsigned len;
AT_Atom atom;
char str[192];

str[0] = '\0';
atom = AT_GetAtomByIndex(ati);

if (atom.len == 0)
return 0;

if (sizeof(str) <= atom.len) // should not happen
return DDF_StringHash(atom.data, atom.len);

for (len = 0; len < atom.len; len++)
{
uint8_t ch = atom.data[len];

if (ch & 0x80) // non ASCII UTF-8 string, don't bother
return DDF_StringHash(atom.data, atom.len);

if (ch >= 'A' && ch <= 'Z')
ch += (unsigned char)('a' - 'A');

str[len] = (char)ch;
}

str[len] = '\0';
return DDF_StringHash(str, len);
}

/*! Constructor. */
DeviceDescriptions::DeviceDescriptions(QObject *parent) :
QObject(parent),
Expand Down Expand Up @@ -861,6 +922,7 @@ void DeviceDescriptions::prepare()
{
DDF_LoadRecord rec;
rec.mfname.index = res[i].mfnameAtomIndex;
rec.mfnameLowerCaseHash = DDF_AtomLowerCaseStringHash(rec.mfname);
rec.modelid.index = res[i].modelIdAtomIndex;
rec.loadState = DDF_LoadStateScheduled;
records.push_back(rec);
Expand Down Expand Up @@ -1089,6 +1151,8 @@ const DeviceDescription &DeviceDescriptions::get(const Resource *resource, DDF_M
U_ASSERT(modelidAtomIndex != 0);
U_ASSERT(mfnameAtomIndex != 0);

uint32_t mfnameLowerCaseHash = DDF_AtomLowerCaseStringHash(AT_AtomIndex{mfnameAtomIndex});

/*
* Filter matching DDFs, there can be multiple entries for the same modelid and manufacturer name.
* Further sorting for the 'best' match according to attr/ddf_policy is done afterwards.
Expand All @@ -1098,7 +1162,7 @@ const DeviceDescription &DeviceDescriptions::get(const Resource *resource, DDF_M

for (;matchedCount < matchedIndices.size();)
{
i = std::find_if(i, d->descriptions.end(), [modelidAtomIndex, mfnameAtomIndex](const DeviceDescription &ddf)
i = std::find_if(i, d->descriptions.end(), [modelidAtomIndex, mfnameAtomIndex, mfnameLowerCaseHash](const DeviceDescription &ddf)
{
if (ddf.mfnameAtomIndices.size() != ddf.modelidAtomIndices.size())
{
Expand All @@ -1107,8 +1171,16 @@ const DeviceDescription &DeviceDescriptions::get(const Resource *resource, DDF_M

for (size_t j = 0; j < ddf.modelidAtomIndices.size(); j++)
{
if (ddf.modelidAtomIndices[j] == modelidAtomIndex && ddf.mfnameAtomIndices[j] == mfnameAtomIndex)
return true;
if (ddf.modelidAtomIndices[j] == modelidAtomIndex)
{
if (ddf.mfnameAtomIndices[j] == mfnameAtomIndex) // exact manufacturer name match
return true;

// tolower() manufacturer name match
uint32_t mfnameLowerCaseHash2 = DDF_AtomLowerCaseStringHash(AT_AtomIndex{ddf.mfnameAtomIndices[j]});
if (mfnameLowerCaseHash == mfnameLowerCaseHash2)
return true;
}
}

return false;
Expand Down Expand Up @@ -1180,6 +1252,11 @@ const DeviceDescription &DeviceDescriptions::get(const Resource *resource, DDF_M
{
rawJsonIndex = matchedIndices[i];
}
else if (ddf1.storageLocation == deCONZ::DdfUserLocation && d->descriptions[rawJsonIndex].storageLocation == deCONZ::DdfLocation)
{
// already had a match but user location has more precedence than system location
rawJsonIndex = matchedIndices[i];
}
continue;
}

Expand Down Expand Up @@ -1373,12 +1450,19 @@ bool DeviceDescriptions::loadDDFAndBundlesFromDisc(const Resource *resource)
return false;
}

uint32_t mfnameLowerCaseHash = DDF_AtomLowerCaseStringHash(AT_AtomIndex{mfnameAtomIndex});

for (const DDF_LoadRecord &loadRecord : d->ddfLoadRecords)
{
if (loadRecord.mfname.index == mfnameAtomIndex && loadRecord.modelid.index == modelidAtomIndex)
if (loadRecord.mfnameLowerCaseHash == mfnameLowerCaseHash && loadRecord.modelid.index == modelidAtomIndex)
{
return false; // been here before
}

if (loadRecord.mfname.index == mfnameAtomIndex && loadRecord.modelid.index == modelidAtomIndex)
{
return false; // been here before, note this check can likely be removed due the lower case check already been hit
}
}

DBG_Printf(DBG_DDF, "try load DDF from disc for %s -- %s\n", mfnameItem->toCString(), modelidItem->toCString());
Expand All @@ -1387,6 +1471,7 @@ bool DeviceDescriptions::loadDDFAndBundlesFromDisc(const Resource *resource)
DDF_LoadRecord loadRecord;
loadRecord.modelid.index = modelidAtomIndex;
loadRecord.mfname.index = mfnameAtomIndex;
loadRecord.mfnameLowerCaseHash = mfnameLowerCaseHash;
loadRecord.loadState = DDF_LoadStateScheduled;
d->ddfLoadRecords.push_back(loadRecord);

Expand Down Expand Up @@ -2161,6 +2246,7 @@ void DeviceDescriptions::readAllRawJson()
{
AT_AtomIndex mfnameIndex;
AT_AtomIndex modelidIndex;
uint32_t mfnameLowerCaseHash = 0;

mfnameIndex.index = 0;
modelidIndex.index = 0;
Expand All @@ -2185,6 +2271,10 @@ void DeviceDescriptions::readAllRawJson()
continue;
}
}
else
{
mfnameLowerCaseHash = DDF_AtomLowerCaseStringHash(mfnameIndex);
}
}

{
Expand All @@ -2199,12 +2289,12 @@ void DeviceDescriptions::readAllRawJson()
{
if (modelidIndex.index == d->ddfLoadRecords[k].modelid.index)
{
if (mfnameIndex.index == 0)
if (mfnameLowerCaseHash == 0)
{
// ignore for now, in worst case we load a DDF to memory which isn't used
U_ASSERT(0);
}
else if (mfnameIndex.index != d->ddfLoadRecords[k].mfname.index)
else if (mfnameLowerCaseHash != d->ddfLoadRecords[k].mfnameLowerCaseHash)
{
continue;
}
Expand Down Expand Up @@ -2516,14 +2606,16 @@ static int DDF_IsBundleScheduled(DDF_ParseContext *pctx, const char *desc, unsig
if (!foundAtoms)
continue;

uint32_t mfnameLowerCaseHash = DDF_AtomLowerCaseStringHash(mfname_ati);

for (size_t j = 0; j < ddfLoadRecords.size(); j++)
{
const DDF_LoadRecord &rec = ddfLoadRecords[j];

if (rec.mfname.index != mfname_ati.index)
if (rec.modelid.index != modelid_ati.index)
continue;

if (rec.modelid.index != modelid_ati.index)
if (rec.mfnameLowerCaseHash != mfnameLowerCaseHash)
continue;

return 1;
Expand Down Expand Up @@ -2564,12 +2656,13 @@ void DeviceDescriptions::reloadAllRawJsonAndBundles(const Resource *resource)
const ResourceItem *modelidItem = resource->item(RAttrModelId);
unsigned mfnameAtomIndex = mfnameItem->atomIndex();
unsigned modelidAtomIndex = modelidItem->atomIndex();
uint32_t mfnameLowerCaseHash = DDF_AtomLowerCaseStringHash(AT_AtomIndex{mfnameAtomIndex});

for (size_t j = 0; j < d_ptr2->ddfLoadRecords.size(); j++)
{
DDF_LoadRecord &rec = d_ptr2->ddfLoadRecords[j];

if (rec.mfname.index != mfnameAtomIndex)
if (rec.mfnameLowerCaseHash != mfnameLowerCaseHash)
continue;

if (rec.modelid.index != modelidAtomIndex)
Expand Down
3 changes: 2 additions & 1 deletion devices/3A-Nue/Lxn59-2s7lX1.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"uuid":"417af879-4d80-4816-ba08-b1b74aeead77",
"manufacturername":"3A Smart Home DE",
"modelid":"LXN59-2S7LX1.0",
"product":"2 gang switch",
"vendor": "Zemismart",
"product":"2 gang inline switch (ZW-EU-02)",
"sleeper":false,
"status":"Gold",
"subdevices":[
Expand Down
3 changes: 2 additions & 1 deletion devices/3A-Nue/lxn59-1s7lx1.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"uuid": "724fdfb6-6e4b-4247-9d91-d3a92bf41622",
"manufacturername": "3A Smart Home DE",
"modelid": "LXN59-1S7LX1.0",
"product": "Another Smart socket plug",
"vendor": "Zemismart",
"product": "1 gang inline switch (ZW-EU-01)",
"sleeper": false,
"status": "Gold",
"subdevices": [
Expand Down
4 changes: 2 additions & 2 deletions devices/3A-Nue/lxt56-ls27lx1.7.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"uuid": "73cc635e-9c11-4623-af5a-e6a7a8fb68f8",
"manufacturername": "3A Smart Home DE",
"modelid": "LXT56-LS27LX1.7",
"vendor": "Zemismart",
"product": "3A12S-15",
"vendor": "3A Nue",
"product": "RGBW LED strip controller (3A12S-15)",
"sleeper": false,
"status": "Gold",
"subdevices": [
Expand Down
4 changes: 2 additions & 2 deletions devices/Jasco-GE/GE45856_wall_switch.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"uuid": "548bbc95-bc25-40b6-86a8-161a2edba487",
"manufacturername": "Jasco Products",
"modelid": "45856",
"vendor": "GE",
"product": "45856",
"vendor": "Jasco",
"product": "GE ZigBee in-wall smart switch (45856GE)",
"sleeper": false,
"status": "Gold",
"subdevices": [
Expand Down
Loading

0 comments on commit 20ede2f

Please sign in to comment.