How to write an Edge Driver

I’ve been reading up about Edge Drivers and I have all the tools installed. I’ve worked through tutorials and examples of how to create, publish and install a driver. I’m not an expert but I get the gist of all that now.
What I’m now struggling with is what to code. For example, if I’ve got a Zigbee device, say a Motion Sensor, how would I know what to write? I know the sensor already has an Edge driver but what if it didn’t? Where would I start to work out what a driver should look like and do for a particular device?

Hi @ceekay

Don’t worry too much, or be in a hurry, with patience, perseverance, asking and reading and reading code and documentation, even I have managed to write edge drivers :smile:

The first thing of all is to read the documentation, you cannot expect someone to explain to you in 10 steps how to make an edge driver.

At most I going to try guide you on where to start.

The second thing is to have all the information about the device:

  • Know the manufacturer and model (fingerprints), to be able to pair the device.

  • What capabilities does it have, Movement, occupancy, temperature, humidity, illuminance, battery,…?

  • Know which clusters and attributes of each cluster it uses to send the capabilities information.

  • Know which endpoints each cluster is in, they can all be in the same endpoint or distributed across different endpoints.
    Device configuration commands must be sent to these endpoints.
    The default libraries today handle endpoints very well, as long as there are defaults that handle the capabilities of the device.

  • If you do not have a manual, you can use the zigbee thing Mc driver or another similar one to see this information

  • Know the documentation of how an edge driver is structured, folders and files that each folder must contain.
    If you don’t want to look for the documentation, use an existing driver as a base.

  • With this information you create or modify a profile file, device-x.yml, that contains the components, only main or main and others.

    • In each component you declare the capabilities device has. Include refresh capability.
    • Choose a device category.

For the profile, it is best to modify from one already made.

  • Create or modify the fingerprints.yml file, with the necessary fields.

  • Create or modify the config.yml file with the necessary data to create the new driver

  • I recomend you to modify an init.lua file from the existing src folder of a similar device:

    • In the template declare all capabilities of the device
    • If all the capabilities have defaults defined in the firmware libraries you don’t have to do anything else, it should work after packaged, assigned to a channel and installed in your hub.

When you pair the device, have the CLI ready with logcat to see the driver logs.

Here you will see the errors that occur and the error message will guide you on how to look for the error in the driver code.

An error in one driver does not affect the operation of other drivers and the hub, don’t worry about that. Correct the error in the code and try again

The default capabilities of the libraries are detailed in the documentation, but if you want to see the Lua code of the firmware libraries you can download them from here. It is very very useful.
For example, you can see in each capability default handler what cluster and attribute it handles and check if your device is compatible with the default handler of the firmware.

Practice, test and test many times.

12 Likes

Many thanks Mariano, that is all really helpful and sets my expectations.
Just out of interest, I’ve got some Scolmore Click Smart plugs with which I’m using your “Zigbee Multi Switch and Child Mc” driver which all works very well, but where did you start with that one? It’s got json code in that one too so looks even more complicated than other drivers. Perhaps I’m getting ahead of myself and trying to run before I can walk, but it would be interesting to know how you got there. Thanks

Hi @ceekay

I am happy that is was useful for you!

This driver and others are the result of an evolution of more than 2 years of work.

I created it at the beginning of edge, fall 2021, when the stock driver did not yet support multi-switch devices and I had triple power strips that I wanted to migrate to edge.
I based it on an example from the edge documentation for multi-component devices and adapted it to the init.lua of the stock zigbee switch.

At first I only had the fingerprints of my power strip and now it has more than 200 supported devices

The default libraries were still in their infancy, compared to the current ones. They didn’t handle endpoints as well as they do now.

@erickv, who was in developer support with @nayelyz, helped me resolve issues that were coming up daily.

As the lua libraries evolved and I discovered, thanks to @nayelyz, that the code of those libraries was public, everything began to improve and evolve. It is as if someone gives you the secret code to know how to decrypt and know how almost everything works within the hub with the drivers.

The json files are not part of the driver. They are the presentations of the custom capabilities and device presentations, VID, for multiple tiles for example, used in the driver.
I add them to each driver in the “capabilities” and “presentations” folders in the driver on my github, so that they can serve as help and examples to other users and not suffer as much as I did to find examples and templates.

In 2022, some multi-component Tuya devices began to appear that did not work independently of each switch.
After much searching for a solution, thanks to kkossev, @Trakker2 , in their hubitat dth there was TuyaBlackMagic solution. He explained to me how to implement it correctly by sending the reading of the attributes of the Basic cluster in a single message at the beginning of the installation.

The lua libraries did not contemplate reading several attributes in a single message and the code had to be modified and implemented within the driver, which is why there is the read_attribute_function function in init.lua.

in 2022 too, the functions were added to create child devices, which did not exist, first with virtual LAN devices and when smartthings published the child EDGE in its libraries I had to modify the entire driver to make it compatible with the new lua libraries.

One of the problems that arise in this type of multi-component Zigbee devices is how the endpoints are assigned to the components of the profile since in a component you cannot repeat the same capability.
Smartthings assumes that the endpoints are increased one by one in ascending order from the device.fingerprinted_endpoint_id and does so in its stock driver, but the reality is that there are manufacturers that do not follow this rule and will never work with the current zigbee switch stock. Maybe that’s why they do it to prevent them from working easily on other platforms.

You can see the device.fingerprinted_endpoint_id in the data with the zigbee thing Mc driver or if you ask it to print it for you with a function print("<<<< device.fingerprinted_endpoint_id >>>>", device.fingerprinted_endpoint_id) placed in the code of the driver and will show it in the CLI logs.

There are manufacturers that increase the endpoints in even or odd numbers or decrease them from the device.fingerprinted_endpoint_id, you can see it in the driver’s github code in the functions component_to_endpoint and endpoint_to_component, which the default libraries save in memory when installing the device to dynamically assign the endpoints to components and vice versa every time a command is sent or a message is received from the device.

In Zwave it is more standardized and respected by manufacturers, start in 1 and increment by 1, but there are some exceptions.

So as I said, don’t be in a hurry, read many examples and ask in the community when you have questions, someone will surely answer.

@AlejandroPadilla and @Ivan_Luis_Falleau are the team of developers support now.

Try without fear, nothing breaks, the errors are corrected and you move on

I have already extended enough for today, Greetings

11 Likes

Beginning the learning process to write an Edge Driver.
I’ve installed an lua environment and currently working my way through a lua tutorial which I intersperse with trying to use st libraries.
When I try to run lua commands such as

local PowerConfig = (require “st.zigbee.zcl.clusters”).PowerConfig

I get errors because my PC environment doesn’t know anything about st libraries. If I install such code on my hub then all is well because it knows all about st libraries.

Is it possible to install the st libraries on my PC so I can run the code locally without uploading to the hub?

I hope this is not a dumb question, I’m still very new to this stuff.

It’s not a dumb question, but as with many Lua implementations, the one that smartthings uses is designed to be embedded in a larger system, in this case, the smartthings hub firmware. And that firmware is not publicly released

So I’m pretty sure the only way to test your code is on the hub. :man_shrugging:t2:

Someone else can correct me if I’m wrong. :thinking:

2 Likes

Hi @Mariano_Colmenarejo, I’ve downloaded your beta drivers and am looking in particular at “zigbee-multi-switch-v4.5-childs-edge” in an effort to try to understand how it all hangs together. When I run “smartthings edge:drivers:package zigbee-multi-switch-v4.5-childs-edge” I get errors
“AxiosError: Request failed with status code 400:{“requestId”:“2381740260489367945”,“error”:“code”:“ConstraintViolationError”,“message”:“The request is malformed.”,“details”:{“code”:“NotValidValue”,“target”:“deviceProfiles.name”,“message”:“deviceProfiles.name cannot contain duplicates.”,“details”:}]}} Code: ERR_BAD_REQUEST”

This has completely thrown me because I’ve not yet made any changes. Can you help please?

This error is telling you that it has found some duplicate profile name in the driver. That is not allowed.

I’m surprised that there are any duplicate profile names in my github driver, but I updated the driver on GitHub to today’s version.

When you write the driver that needs to be packaged, you must write the full path of the folder that contains exclusively the driver folders and files. Is that route correct?

2 Likes

Thanks @Mariano_Colmenarejo for the latest update. I changed the name: value in “two-switch-power-energy-multi-1.yml” from “two-switch-power-energy-1-multi” to “two-switch-power-energy-multi-1” and we’re now all good. I assume that’s the correct thing to do?

That file has to be deleted, I don’t know what it’s doing there.

I already deleted it on github.

The profile name refers to the name within the profile in the .yml file, it does not refer to the file name

OK, thanks. I’m at the bottom of the edge driver mountain that I’m beginning to climb. I’ll re-check everything and try again.
Thanks again.

2 Likes

I think you have chosen one of the most complicated drivers to start with edge.
It has a lot of specific code for many devices with strange functioning, Tuya, Feibit, LUMI Vietnam and some others and also with management of child devices and dynamic profile changes.

but if it’s the one you need, that’s fine

I recommend you using the latest GitHub update, the previous one may be missing something that I didn’t update at the time, I don’t have time for that much

2 Likes