Skip to content

Conversation

@Smanar
Copy link
Collaborator

@Smanar Smanar commented Jan 11, 2023

Ok so long story, with the @Idaho947 help, see #6618

This device can work with button map, but not possible for all buttons, thoses one just cycle some vlaues.
@kasteleman that know a lot this device have found a solution.

Need to use the GUI, to update the attribute 0x0004 in the cluster 0xfd01 with the value 63

Attribute is uint8 you should set the first 6 so that would be 00111111
00111111 is 63 in dec and 0x3F in hex

After that the device use the special cluster to send special command. So the DDF can work without the buttonmap file.

The manufacture number of the device is 0x1166 but need to use 0x1169 in the request .....

@Smanar Smanar marked this pull request as draft January 11, 2023 17:49
@Smanar Smanar mentioned this pull request Jan 11, 2023
@Smanar Smanar marked this pull request as ready for review January 12, 2023 16:20
@manup
Copy link
Member

manup commented Jan 16, 2023

Need to use the GUI, to update the attribute 0x0004 in the cluster 0xfd01 with the value 63

Note you can use a hack in DDF to make this automatic. By adding a bogus item (any numeric item that isn't already used) and add zcl read/write functions and interval to it to set the value, the write function just returns 63. Then set the item to public: false.

It's not pretty but works, I've used that for another device ;)

@manup manup added this to the v2.21.0-beta milestone Jan 16, 2023
@Smanar
Copy link
Collaborator Author

Smanar commented Jan 17, 2023

Ha ? you have the device link ?
Because I don't see how to use DDF to write an attribute without using user request.

And it's "deconz rules" compliant ?

@manup
Copy link
Member

manup commented Jan 18, 2023

This happens in DEV_InitDeviceFromDescription() during load:

if (!ddfItem.defaultValue.isNull() && !ddfItem.writeParameters.isNull())
{
QString writeFunction;
const auto writeParam = ddfItem.writeParameters.toMap();
if (writeParam.contains(QLatin1String("fn")))
{
writeFunction = writeParam.value(QLatin1String("fn")).toString();
}
if (writeFunction.isEmpty() || writeFunction == QLatin1String("zcl"))
{
bool ok;
StateChange stateChange(StateChange::StateWaitSync, SC_WriteZclAttribute, sub.uniqueId.at(1).toUInt());
stateChange.addTargetValue(item->descriptor().suffix, item->toVariant());
stateChange.setChangeTimeoutMs(1000 * 60 * 60);
if (writeParam.contains(QLatin1String("state.timeout")))
{
int stateTimeout = writeParam.value(QLatin1String("state.timeout")).toInt(&ok);
if (ok && stateTimeout > 0)
{
stateChange.setStateTimeoutMs(1000 * stateTimeout);
}
}
rsub->addStateChange(stateChange);
}
}

If I remember correctly it's at least used by the Philips Hue Dimmer to write initial attributes of the manufacturer specific cluster.
Note this is done/verified on each deCONZ restart and initial pairing.

Initially with the default value from the DDF and if the item is changed later on via API, on successive deCONZ starts the new value is taken as it's loaded from the database. Quite handy...

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 18, 2023

I don't found the sample, but If I have understand need to use something like :

        {
          "name": "config/usertest",
          "public": false,
          "refresh.interval": 84000,
          "write": {"fn": "zcl", "ep": 1, "cl": "0xfd01", "at": "0x0004", "dt": "0x20", "eval": "63"},
        },

But I don't understand why it don't make that for all "write" field ? (I don't see what is the specific thing we need to use in the DDF compared with classic "write" command that don't need to be used at start)

@manup
Copy link
Member

manup commented Jan 21, 2023

This is only a special case which doesn't need any extra C++ code. It's a bit difficult to describe, but basically if a item has a default value and has a write function this code will trigger on startup.

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 21, 2023

if a item has a default value and has a write function this code will trigger on startup

A right, have forget that, so the "magic" code need to be

        {
          "name": "config/hostflags",
          "public": false,
          "refresh.interval": 84000,
          "write": {"fn": "zcl", "ep": 1, "cl": "0xfd01", "at": "0x0004", "dt": "0x20", "eval": "Item.val = Attr.val"},
          "default": 63
        },

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 22, 2023

Ok so not working, IDK what is missing ?

@SwoopX
Copy link
Collaborator

SwoopX commented Jan 22, 2023

Use the Force, Luke ^^

...and add zcl read/write functions...

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 23, 2023

@SwoopX You think it's because of the missing "read" one ? from the code it look only for the write ?
if (!ddfItem.defaultValue.isNull() && !ddfItem.writeParameters.isNull())

Perhaps with a "state.timeout" ?

@SwoopX
Copy link
Collaborator

SwoopX commented Jan 23, 2023

@Smanar Even better, I know it. The state machine just acts upon known states and since you never read, you have an undefined state and nothing will ever happen.

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 25, 2023

Ok so we give up with the automatic attribute write. Don't want to work.


        {
          "name": "config/interfacemode",
          "public": false,
          "refresh.interval": 84000,
          "write": {"fn": "zcl", "ep": 1, "cl": "0xfd01", "at": "0x0004", "dt": "0x20", "eval": "Item.val = Attr.val"},
          "read": {"fn": "zcl", "ep": 1, "cl": "0xfd01", "at": "0x0004"},
          "default": 63
        },

@SwoopX
Copy link
Collaborator

SwoopX commented Jan 25, 2023

@Smanar I'm afraid you overlook the obvious and I haven't paid any attention to what attribute/cluster you're working with I have to say.

Write functions do the obvious (quelle surprise 🙂).
Read functions are responsible to poll a device with an intervall specified by the refresh intervall (simplified). When a read function is defined, the attribute is always polled once after deconz restart and then subsequently with the set intervall.
Parse functions are mandatory to interpret what a device sends via an attribute read or report.

For the internal state machine to work, the bare minimum is a parse and write function (that case assumes the device sends reports)!
To set a certain configuration upon device pairing, all 3 functions are required as well as a defined default value. This ensures an attribute is directly read and compared against the desired value (the default). Upon mismatch, the state machine triggers the write and than a new read to verify success. On failure, the cycle starts again...

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 26, 2023

So to resume you mean we need to use parse/read/ and write, to use this feature ?

        {
          "name": "config/interfacemode",
          "public": false,
          "refresh.interval": 84000,
          "write": {"fn": "zcl", "ep": 1, "cl": "0xfd01", "at": "0x0004", "dt": "0x20", "eval": "Item.val = Attr.val"},
          "read": {"fn": "zcl", "ep": 1, "cl": "0xfd01", "at": "0x0004"},
          "parse": {"fn": "zcl", "ep": 1, "cl": "0xfd01", "at": "0x0004", "eval": "Item.val = Attr.val"}
          "default": 63
        },

But I don't need pool or interpret report, and from the code it check only for write, but can make a test.

@SwoopX
Copy link
Collaborator

SwoopX commented Jan 26, 2023

So to resume you mean we need to use parse/read/ and write, to use this feature ?

Yes, indeed.

But I don't need pool or interpret report...

You absolutely need it, as explained above. All posts in this PR are about automatically setting a certain value, right?

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 27, 2023

You absolutely need it, as explained above. All posts in this PR are about automatically setting a certain value, right?

Yeah, but only at inclusion.

@SwoopX
Copy link
Collaborator

SwoopX commented Jan 27, 2023

Right. And it also fires upon deconz restart... As we do not have anything like "do stuff just once", a refresh interval of 86400 is kind of a compromise to "just do it once a day".

As I recall, I also had a use case for completely prohibiting any polling with something like refresh.interval: never, but I do not remember the details 🤷‍♂️

@Smanar
Copy link
Collaborator Author

Smanar commented Jan 28, 2023

As I recall, I also had a use case for completely prohibiting any polling with something like refresh.interval: never, but I do not remember the details

This device is a router, not a problem, and with a refresh interval of 86400 ....

Need to test it now

@manup
Copy link
Member

manup commented Feb 6, 2023

Is the PR ready to merge yet?

@Smanar
Copy link
Collaborator Author

Smanar commented Feb 6, 2023

Yep, users still need to use the GUI to enable it, but the DDF is working.

@manup manup merged commit f76c944 into dresden-elektronik:master Feb 6, 2023
@Smanar Smanar deleted the innr_250 branch December 22, 2023 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants