dresden-elektronik / deconz-rest-plugin

deCONZ REST-API plugin to control ZigBee devices
BSD 3-Clause "New" or "Revised" License
1.9k stars 499 forks source link

Add support for Danalock v3 #520

Closed hazcod closed 4 years ago

hazcod commented 6 years ago

Smart locks are the future, so let's support the Zigbee version of the Danalock v3.

https://danalock.com/danalock-v3.html

tomac01 commented 6 years ago

I agree!

pascal1337 commented 6 years ago

Hey,

i tried to integrate my Danalock V3-Zigbee.

But the problem is, that the cluster for changing the lock state is shown as "unknown cluster". Attached you can see the information I can see.

Also I have attached to official zigbee documentation for the danalock.

Additional info: Danalock uses new ZHA V3 and is currently supported only by amazon echo plus (with zigbee)

May someone help?

Best regards TD003 Zigbee manual.pdf

danalock_1 danalock_2

ebaauw commented 6 years ago

You’ll need to add the 0x0101 cluster (attributes and commands) to general.xml for it to show in the deCONZ GUI. Typically this involves manually translating the text from the ZCL or ZHA specification into XML.

Next step would be figuring out how the lock responds to the various commands, how its state is reflected in the attributes, and whether it supports attribute reporting.

Then, we need to figure out what /lights and/or /sensors resources to create for the lock. This will be ugly: we cannot PUT a /sensors state, so controlling the lock will likely be through a /lights resource (cf. what we did for the siren, window covering, and vent). Additionally, there’s no config.battery for a /lights resource, so we’d need an additional /sensors resource to expose the battery level.

pascal1337 commented 6 years ago

I'm very new to zigbee "coding". May someone is willing to help me :) I guess it would also help others AND! i think when the raspbee supports smartlocks in general it will be a great advantage for the product.

pascal1337 commented 6 years ago

So I now added the following cluster:

<cluster id="0x0101" name="Door Lock">
    <description>Provides a mechanism for the controlling a Smart Lock.</description>
    <client>
    </client>
    <server>
        <attribute id="0x00" name="Lock state" type="u32" access="rw" required="o"></attribute>
        <attribute id="0x01" name="Lock type" type="u32" default="0x00" access="rw" required="o"></attribute>
        <attribute id="0x02" name="Actuator enabled" type="u32" default="0x00" access="rw" required="o"></attribute>
        <attribute id="0x10" name="Num lock records supported" type="u32" default="17918" access="rw" required="o"></attribute>
        <attribute id="0x11" name="Num total users Supported" type="u32" default="0" access="rw" required="o"></attribute>
        <attribute id="0x12" name="Num PIN users supported" type="u32" default="0" access="rw" required="o"></attribute>
        <attribute id="0x13" name="Num FRID users supported" type="u32" default="0" access="rw" required="o"></attribute>
        <attribute id="0x14" name="Num weekday schedules supported" type="u32" default="0" access="rw" required="o"></attribute>
        <attribute id="0x15" name="Num yearday schedules supported" type="u32" default="0" access="rw" required="o"></attribute>
        <attribute id="0x16" name="Num holiday schedules supported" type="u32" default="0" access="rw" required="o"></attribute>
        <attribute id="0x20" name="Enable logging" type="u32" default="1" access="rw" required="o"></attribute>
        <attribute id="0x34" name="Zigbee security level" type="u32" default="0" access="rw" required="o"></attribute>
        <attribute id="0x40" name="Alarm mask" type="u32" default="0xFFFF" access="rw" required="o"></attribute>
        <attribute id="0x42" name="RF operation event mask" type="u32" default="0xFFFF" access="rw" required="o"></attribute>
        <attribute id="0x43" name="Manual operation event mask" type="u32" default="0xFFFF" access="rw" required="o"></attribute>
        <attribute id="0xFFFD" name="Cluster revision" type="u32" default="0x01" access="rw" required="o"></attribute>
        <command id="0x00" dir="send" name="LockDoorResponse" required="o">
            <description></description>
            <payload></payload>
        </command>
        <command id="0x01" dir="send" name="UnlockDoorResponse" required="o">
            <description></description>
            <payload></payload>
        </command>
        <command id="0x00" dir="recv" name="LockDoor" required="o">
            <description></description>
            <payload></payload>
        </command>
        <command id="0x00" dir="recv" name="UnlockDoor" required="o">
            <description></description>
            <payload></payload>
        </command>
        <command id="0x01" dir="recv" name="GetLogRecord" required="o">
            <description></description>
            <payload></payload>
        </command>
        <command id="0x04" dir="send" name="GetLogRecordResponse" required="o">
            <description></description>
            <payload></payload>
        </command>
        <command id="0x20" dir="send" name="Operationg Event Notification" required="o">
            <description></description>
            <payload></payload>
        </command>
    </server>
</cluster>

Its adopted from danalocks zigbee documentation (mentioned above).

But with this code, every cluster in deconz is now showing as "unknown". I cannot see any syntax errors.

May someone has more know how then me? :)

Best regards

ebaauw commented 6 years ago

If all the clusters show unknown, there’s something wrong with the general.xml. Typically a syntax error, but maybe also a logical error. The command IDs seem to have duplicates. Did you put this in the Closures domain, just before the Windows covering cluster? If you could attach the zipped general.xml, I’ll have a look.

EDIT The Danalock Zigbee manual is very brief. Looking at the ZCL spec, the attributes aren’t all uint32 nor read/write. Also, the response commands have a mandatory payload, and the set commands take the PIN as optional payload. Not sure if the Danalock supports a PIN though.

pascal1337 commented 6 years ago

More information is not submitted by danalock ...

Attached you can find the requested zip file containing general.xml

deconz.zip

Best regards

pascal1337 commented 6 years ago

Anyone already reviewed my case?

Thank you very much 😘

pascal1337 commented 6 years ago

Okay. I just had some tries... As I see, even if I remove my smart lock cluster from general.xml the unknown of every cluster remains.

I compared my general.xml with the "original" one, here from github.

The problem still appears. Every cluster is now unknown. Thefuck is wrong?

ebaauw commented 6 years ago

Looks like you placed the new entries in the wrong domain.

Did you put this in the Closures domain, just before the Windows covering cluster?

pascal1337 commented 6 years ago

Hi

Yes i did. but as i mentioned, i additionaly removed the cluster and compared it with the original. And still everything is unknown. I also let deconz reread the config

ebaauw commented 6 years ago

I also let deconz reread the config

I never got that to work. Best quit and restart deCONZ to reload general.xml.

Could you try the general.xml from my commit mentioned above?

pascal1337 commented 6 years ago

Dang! This works out of the box!

Now let's just make looks "apiable".

Why we don't disguise it as a switch? Like 1 is locked and 0 is unlocked.

ebaauw commented 6 years ago

Could you please post a screenshot of the Door Lock cluster (after reading all the attributes)?

Could you check if you can setup attribute reporting for the Lock State attribute? I would hope/expect that this attribute will reflect the current lock state automatically when you issue a Lock Door or Unlock Door command, and when you control the lock manually.

pascal1337 commented 6 years ago

bildschirmfoto von 2018-08-10 20-09-05 bildschirmfoto von 2018-08-10 20-09-12 Attached the screenshots.

I dont have to setup anything. The state updates out of the box, after updating.

I currently try to modify the rest api plugin source, by just "copying" the window-covering parts.

EDIT: Hmm, lock won't appear. :/

ebaauw commented 6 years ago

I currently try to modify the rest api plugin source, by just "copying" the window-covering parts.

Indeed, best expose it as a light, with state.on mapped to the lock state. However, there's a little more to it. Change addLightNode() in de_web_plugin.cpp:

In light_node.cpp:

That should be enough for the resource to be created (I hope). Best search for DEV_ID_HA_WINDOW_COVERING_DEVICE and WINDOW_COVERING_CLUSTER_ID to make sure they're not whitelisted elsewhere.

Note to self: the device id 0x000a for Door Lock is still missing from general.xml.

Next, you need to map state.on to the Lock State attribute (so that changes to the lock state get reflected in state.on). In nodeEvent() in de_web_plugin.cpp, whitelist DOOR_LOCK_CLUSTER_ID to call updateLightNode(). In updateLightNode(), whitelist the same cluster and add a handler for ic->id() == DOOR_LOCK_CLUSTER_ID, similar to _ONOFF_CLUSTERID, but obviously checking for attribute 0x0101/0x0000.

To control the lock from the REST API, you need to create a new routine addTaskDoorLock() in zcl_tasks.cpp, cf. the addTaskWarning() I created to control the Siren. Based on a lock state parameter, add a task with a Lock Door or Unlock Door command. In rest_lights.cpp, you need to call this routine from setLightState() under if (hasOn). You need to check for taskRef.lightNode->type() == QLatin1String("Door lock"), similar to what I've done under hasAlert for the Siren.

tomac01 commented 6 years ago

I currently try to modify the rest api plugin source, by just "copying" the window-covering parts.

How does it work? Where can I do this?

ebaauw commented 6 years ago

Follow the steps in the README to get a local copy of the source of the REST API plugin and compile and install it. Then edit your local source and recompile the plugin.

tomac01 commented 6 years ago

Then edit your local source

I am a beginner in these things. Is it possible that you upload the changed files? Your instructions above are certainly good, but unfortunately I can not do it without help.

Thanks in advance!!!

pascal1337 commented 6 years ago

So guys. I published my plugin changes here: https://github.com/pascal1337/deconz-rest-plugin/

I did many modifications according window_covering and Warnings.

I am now at a point, where I'm not able to get further. Compilation still shows a "undeclared"-error and the API won't bring up my lock.

Maybe someone can have a closer lo(o/c)k :P

ebaauw commented 6 years ago

VENDOR_DANALOCK should be the Manufacturer code from the Node info panel.

What is the compile error?

tomac01 commented 6 years ago

The following error appears:

g++ -c -pipe -Wno-attributes -Wall -Wno-attributes -O2 -std=gnu++11 -Wall -W -D_REENTRANT -fPIC -DDECONZ_DLLSPEC=Q_DECL_IMPORT -DARCH_ARM -DARCH_ARMV7 -DUSE_WEBSOCKETS -DHAS_SQLITE3 -DGW_SW_VERSION=\"2.05.34\" -DGW_API_VERSION=\"1.0.9\" -DGIT_COMMMIT=\"0e7156dc2109aabd38d10146d6e0d3393b48574a\" -DGW_AUTO_UPDATE_FW_VERSION=0x260b0500 -DGW_MIN_RPI_FW_VERSION=0x261f0500 -DGW_MIN_DERFUSB23E0X_FW_VERSION=0x22030300 -DGW_DEFAULT_NAME=\"Phoscon-GW\" -DQT_NO_DEBUG -DQT_PLUGIN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_SERIALPORT_LIB -DQT_WEBSOCKETS_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -I../.. -I../../common -isystem /usr/include/arm-linux-gnueabihf/qt5 -isystem /usr/include/arm-linux-gnueabihf/qt5/QtWidgets -isystem /usr/include/arm-linux-gnueabihf/qt5/QtGui -isystem /usr/include/arm-linux-gnueabihf/qt5/QtSerialPort -isystem /usr/include/arm-linux-gnueabihf/qt5/QtWebSockets -isystem /usr/include/arm-linux-gnueabihf/qt5/QtNetwork -isystem /usr/include/arm-linux-gnueabihf/qt5/QtCore -Irelease -I. -I/usr/lib/arm-linux-gnueabihf/qt5/mkspecs/linux-g++ -o release/websocket_server.o websocket_server.cpp zcl_tasks.cpp: In member function ‘bool DeRestPluginPrivate::addTaskDoorLock(TaskItem&)’: zcl_tasks.cpp:922:21: error: ‘TaskDoorLock’ was not declared in this scope task.taskType = TaskDoorLock; ^~~~~~~~~~~~ zcl_tasks.cpp: In member function ‘bool DeRestPluginPrivate::addTaskDoorUnlock(TaskItem&)’: zcl_tasks.cpp:957:21: error: ‘TaskDoorUnlock’ was not declared in this scope task.taskType = TaskDoorUnlock; ^~~~~~~~~~~~~~ Makefile.Release:1037: recipe for target 'release/zcl_tasks.o' failed make[1]: *** [release/zcl_tasks.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make[1]: Leaving directory '/home/pi/deconz/test/deconz-rest-plugin' Makefile:38: recipe for target 'release' failed make: *** [release] Error 2

pascal1337 commented 6 years ago

Yes. This is the point where I currently stand.

ebaauw commented 6 years ago

Did you declare the lock and unlock functions in de_web_plugin_private.h?

pascal1337 commented 6 years ago

Yes I did. Row 1072, 1073

ebaauw commented 6 years ago

You also need to declare the new tasks in https://github.com/dresden-elektronik/deconz-rest-plugin/blob/db74fcb21e13cf9f0d6c353f625a82a6d6324555/de_web_plugin_private.h#L458

pascal1337 commented 6 years ago

So I did some changes and compiled the plugin, copied it to /usr/share/deCONZ/plugins, rebooted and: img_2049

When I am at home, I will test the functionality.

pascal1337 commented 6 years ago

Sooo guys. When I make an API request

It shows the light correctly with all its details:

{
 "etag": "010881e2e4974327caa7b3eb871a1e34",
 "hascolor": false,
 "manufacturername": "Danalock",
 "modelid": "V3-BTZB",
 "name": "Danalock",
  "state": {
   "alert": "none",
   "on": true,
   "reachable": true
  },
"swversion": "0000000E",
"type": "Door Lock",
"uniqueid": "00:0b:57:ff:fe:59:e0:4b-01"
}

When I try to change steht state

PUT http://192.168.178.100/api/CD5466EA30/lights/7/state {"on":true}

The response is

{
"error":{
 "address":"/lights/7",
 "description":"resource, /lights/7, not available",
 "type":3
 }
}
tomac01 commented 6 years ago

@pascal1337 : Please, coud you update your repository? I warnt to test your changes. Thx!

EDIT: Vielleicht geht es auch auf Deutsch ;-) Ich hab das Verzeichnis von Dir neu runter geladen und nun Compiler (ohne Fehler). Danach hab ich das neue plugin „rüber kopiert“ und einen reboot gemacht. Danach eine Suche in Phoscon gestartet. Leider taucht das Danalock dort nicht auf. Mache ich was falsch?

Danke im Voraus!

Grüße

pascal1337 commented 6 years ago

@tomac01 Hallo :) Das Repo ist jetzt aktuell. Ich bin mir nicht sicher, ob die Suche über Phoscon erfolgreich ist. Ich habe das Danalock direkt über die deCONZ Gui auf meinem Raspberry aufgenommen. Du musst hierfür mit einer Büroklammer, Zahnstocher o.ä. ein mal kurz auf das Loch im Danalock drücken. Das Danalock beginnt dann grün zu leuchten / blinken. In diesem Zeitraum muss das Netzwerk für neue Geräte geöffnet werden.

tomac01 commented 6 years ago

Vielen Dank! Werde ich nachher sofort ausprobieren.

tomac01 commented 6 years ago

@pascal1337 : Ich hab mir das Repro nochmal mit „gibt clone“ neu runtergeladen und dann compiliert. Das war auch erfolgreich, denn es wurde das PlugIn erzeugt. Danach hab ich es in das bekannte PlugIn-Verzeichnis kopiert (das alte File wurde ersetzt).

Das Danalock hab ich (was es vorher zwar schon war) nochmal neu eingebunden. Über die deConz-Oberfläche (Netzwerk) kann ich das Schloss auch korrekt per ZigBee bedienen. Danach reboot des Raspi durchgeführt.

Leider zeigt mir das Phoscon das Schloss nicht als Lampe an. Auch nicht, wenn danach suchen lasse.

Hast Du noch eine Idee? Wie gesagt: Im Netzwerk über den Desktop des Raspi (per VNC) kann ich das Schloss steuern. Eingebunden ist es damit. Nur Phoscon zeigt nix an.

Vielen Dank im Voraus!

tomac01 commented 6 years ago

@pascal1337 Ich hab nochmal meine Anzeige in DeCONZ mit Deinen Bildern oben verglichen. Die general.xml von ebaauw zeigt anstatt „000a“ „Door Lock“ an. Aber das dürfte doch nur die Übersetzung für die 000a sein, oder?

2b703cea-87a4-4e22-a4f2-20eda9fc8d00

ebaauw commented 6 years ago

Indeed, afaik the device type is used only in the GUI display.

Battery-operated devices are a bitch to pair. If the lock already displays in the GUI, but the REST resources aren’t created:

If that doesn’t work, double-check your lock has the same:

tomac01 commented 6 years ago

I checked

I have followed the instructions of you exactly. But the lock is only recognized in the deCONZ GUI. Neither the old web-app nor phoscon will recognize the lock.

Here is a picture of the Node Info from the lock: unbenannt

Do you have another idea? Is it possible to search for errors somewhere?

Thx a lot!

tomac01 commented 6 years ago

@pascal1337 Könntest Du mir Deine compilierte libde_rest_plugin.so zum Test zur Verfügung stellen? Wenn die nicht geht, liegt es vielleicht an etwas anderem... danke im Voraus!

ebaauw commented 6 years ago

Some long shots:

tomac01 commented 6 years ago

@ebaauw:

This afternoon I will start deCONZ with the debug settings and have a look ....

pascal1337 commented 6 years ago

Hi,

my compiled plugin: http://dinge.xyz/libde_rest_plugin.so

pascal1337 commented 6 years ago

@ebaauw you have another tip for me regarding my api, which isn't doing anything?

tomac01 commented 6 years ago

@pascal1337 Great! After I copied your file into the directory and did a restart on Phoscon, the Danalock was immediately recognized as light. unbenannt

I do not know what I did wrong when compiling. But there must be the problem. There was no error compiling and the file was created. That was actually a good sign for me, but does not seem so ... ;-(

Many Thx!

ebaauw commented 6 years ago

you have another tip for me regarding my api, which isn't doing anything?

I wouldn’t necessarily trust the error message (that the resource cannot be found), but read it to mean that something failed while handling the PUT, like no OnOff cluster. Can you still update other light states? Looking at your repo, you didn’t yet change rest_lights.cpp?

pascal1337 commented 6 years ago

Hello, no other lights are still updatable via phoscon.

tomac01 commented 6 years ago

So you can not switch the lock on phoscon? the same for me

tomac01 commented 6 years ago

No, unfortunately not. Although Phoscon shows that the "lamp" is on, the lock does not react. In the deConz GUI, I also see no activities. As I said, I can open and close the lock via the GUI. Not with Phoscon.

tomac01 commented 6 years ago

@pascal1337 : Gibt es schon was Neues? Ich kann hier leider nicht helfen. Ich bekomme ja nicht mal das compilieren hin :-(. Hattest Du schon die Zuordnung des Clusters 101 kontrolliert? Es kann doch eigentlich nur noch etwas Kleines sein... Viele Grüße

pascal1337 commented 6 years ago

Hi, hab leider nicht so viel Zeit aktuell...

Hab leider keinen weiteren Lösungsansatz.

ebaauw commented 6 years ago

@pascal1337, in rest_lights.cpp you need to change setLightState(). Where handling the on key in the json body (if (hasOn)), you need to check whether the device is a lock and, if so, issue a Lock Door or Unlock Door command, instead of an On or Off command. You need to create the corresponding taks(s) in zcl_task,cpp, or create a new file, as was done for Window covering devices. See PR https://github.com/dresden-elektronik/deconz-rest-plugin/pull/746.

pascal1337 commented 6 years ago

I dont get the fucking logic out of rest_lights.cpp. It calls hasOn() and then addTaskSetOnOff(). But nowhere is said if it should turn the light on or off. I dont know, where to put my addTaskDoorLock respectively addTaskDoorUnlock. I also dont want to fuck with the API, why can we not integrate a correct lock-device into the API?

Best regards, Pascal

feelfree69 commented 6 years ago

addTaskSetOnOff takes the ON/OFF as a parameter: addTaskSetOnOff(task, isOn ? ONOFF_COMMAND_ON : ONOFF_COMMAND_OFF, 0)) So it depends on isOn, which is set earlier.

I'm totally new to this topic and can't help yet. I have a brand new Danalock V3 w/Zigbee in my house. What I have also here is a Raspberry 3B and a Raspberry Zero W and some programming experience. What would I need additionally to get as far as you did in controlling the Danalock? I assume a Zigbee stick, raspBee or conBee. Or can it be any Zigbee stick, like Qivicon/Telekom/whatever?