Jump to content

Welcome to Smart Home Forum by FIBARO

Dear Guest,

 

as you can notice parts of Smart Home Forum by FIBARO is not available for you. You have to register in order to view all content and post in our community. Don't worry! Registration is a simple free process that requires minimal information for you to sign up. Become a part of of Smart Home Forum by FIBARO by creating an account.

 

As a member you can:

  •     Start new topics and reply to others
  •     Follow topics and users to get email updates
  •     Get your own profile page and make new friends
  •     Send personal messages
  •     ... and learn a lot about our system!

 

Regards,

Smart Home Forum by FIBARO Team


Recommended Posts

Posted (edited)

Hello everyone,

welcome to my series of almost completely unnecessary programs.

So far I have released here: PNG library (a total disaster), OCVC, YACL, Breakout, auto::cerr 1 and 2, Remote Config, and a few others that never made it to the forum at all.

Today I would like to present my new idea...

 

Story behind

We have many QuickApps whose purpose is to control devices in a Fibaro HC3 system. They read sensor values, toggle devices, manage automation logic.
This is, after all, what home automation is about. In most QuickApps we see lines like:

Please login or register to see this code.

 

So while writing a QA, we need to know the device IDs that we will be using. But what happens when the ID changes? For example, once in a long while we have to remove a device from the system (for “sanitary” reasons) and add it again. The device gets a new ID, and all references inside our QuickApps become invalid.

In my setup there are certainly more than 25,000 lines of code across multiple QAs. One of them – the SVG visualization of the house – has 75 device references for a single floor. Finding and updating changed IDs manually would be a nightmare...

 

Does it really have to be this way?
Do I actually need to know the numeric device IDs when writing a QA?

Turns out: no, I do not. There is, I belive, a better way.

 

And this is where the DNS  for Devices (DNSfD) comes in.

 

The idea is simple:

DNSfD (just a QuickApp) acts as a provider of always-up-to-date device IDs for any number of QuickApps, which act as clients. DNSfD keeps an internal table of devices with their current IDs and their synthetic serial numbers (CRC). These CRCs are computed from static fields in the device JSON – fields that never change regardless of device ID or device name. A client QA, on startup, sends a subscription request with a table of CRCs it is interested in. CRC for all devices can be obtained by a click.
Subscribe is a single command:

Please login or register to see this code.

 

 

The server asynchronously delivers the requested device IDs (in a form of {}) by remotely invoking a function inside the client QA, which then saves the IDs into its internal variables. There's no need to change user's variable names used in QA code. Translate table with DNSfD answer to user's variables takes a little effort (still comfortable, client code has a toolkit for this), but how big is the benefit!
 

From that moment on, the client is also notified about any future ID changes of those devices. 

Even in extreme situations – deleting all devices from the system and adding them back – every client QA will receive the correct new IDs for exactly the devices it cares about.

 

Reboot and synchronization

What if the HC3 is rebooted (planned or due to power outage)?
What if a client - after reboot - starts first and DNSfD is not yet running (it can happen - client send request while server is still down)?

No problem.

Both the server and the clients use a acknowledgements and retry mechanism. Recently I added a request queue, because with many concurrent clients occurs insidious read-write race...
A QA will not proceed to its operational logic until all needed IDs are supplied. 

DNSfD and the clients do not use event subscriptions or busy loops, so does not constantly charge CPU.

 

This may sound a bit like magic, but it's not. Actually the entire implementation fits in ~500 lines of code. On the side of client QA more ~60 lines have to be added.

Limitations: one device JSON field is required – the internal hardware serial number. It must participate in the CRC evaluation (however, alone - its not enough for usable, non-dup serial :)).
All Fibaro-made devices have it. For third party devices – I don’t know. Non-compatible devices as well as non-physical devices are recognized automatically, so user effort is minimal. 
 

Status

DNSfD is still under testing and development, but so far it works correctly in all scenarios: QA startup, device remove/add, HC3 reboot

I am really happy with this idea!

I will most likely release it here - not sure when exactly.

Edited by Łukasz997
  • Like 3
  • Łukasz997 changed the title to DNS for Real Devices
Posted

This sounds very similar to my system that I used during making UHAS for HC2 where each scene and Virtual Device has unique identifier set to their JSON tree. Thanks to that, each scene or VD could find other scenes or VD's they need to interact with, regardless of the ID given to them by the system. If any of the scene or VD is reinstalled it is sufficient to restart UHAS since search and initialization is done only when VD is restarted or scene run manually to preserve resources.

 

Something similar, but a bit more advanced I'm now using for Yubii UHAS. I guess your system will work with any user installed QuickApp while my system is limited only to those QA specifically made for Yubii UHAS. This is because changing QA ID is only part of the problem, I also need to know QA function e.g. sending notifications, or music player etc.

 

 

 

  • Topic Author
  • Posted (edited)

    Thank you for your comment. I enjoy reflecting on topics like this.
    I am relatively new to this forum and I keep telling myself that I will take the time to study the old, proven and long-standing solutions created by forum members. Unfortunately, so far I haven’t managed to do that...

     

    When designing the architecture of my DNSfD, I had in mind that the user will have no desire to rewrite their existing program just because they got a DNS server. They will not change the way they store device IDs in code, and they would be right! If they did, the benefits of having DNSfD would be overshadowed by the need to make scattered modifications and re-test everything. In my opinion, the only thing a user may agree to is adding a small piece of code, and even that should be minimal.
     

    My solution concerns only real, physical devices and even not all (also not other QA's) – that’s the first thing. And it has to remain until I find a method to generate synthetic serial numbers for all devices. For now, I’m not working on that.
    And second – on the user’s side, where the code already exists, I do not expect any changes. Of course, they must translate the data they receive into their own variables. But this must happen in a centralized and one-time manner, and they should receive tools that make this easy. Otherwise, I believe they simply won’t adopt the solution.

    Compared to yours, mine is probably very specialized: reinstalling devices results in client code working correctly again. And I tried to design it with "retrofitting" in mind. I must admit that this work is not yet finished…

    Edited by Łukasz997
    Posted

    I think the DNS in general a good idea.  Some way to decouple the deviceID from the actual device.

     

    “Native” devices tend to have relatively  stable ids, unless we have to re-include them.

    If it’s just one or two devices being re-included, it’s not that hard to manually update something like a “hometable”,

    If it’s every zwave device in the house an automatic method is of course a better choice.

     

    To have a stable “synthetic serial number” (SSN) instead of a deviceID id, I think, a worthy goal in itself.

    It becomes a stable base that more metainfo can be added to.

     

    A hometable, mapping names or section->room->name to SSNs, becomes more stable and only needs changes when we want to rename devices or move them between rooms.

     

    We could also add API contracts to the SSNs, in some way describing what QA calls it can handle.

    Note, that the fibaro type already gives a base for what function calls the device/QA should be able to handle - but QAs can of course have additional functions.

     

    Using the internal hardware serial number is a bit limiting though.

    I have zwave devices that don’t have serialNumber fields, and looking just at individual fields there is nothing that uniquely identifies them.

     

    One approach would be to manually set an identifier in the userDescription or quickAppUuid field. After re-inclusion, edit the userDescription and it’s usable…

    This would also work with QAs.

    A helper QA could scan zwave/zigbee devices and set their identifiers if they have unique fields, like serialNumber

     

    Another, more complex approach, would be to provide a device template “fingerprint” to match against, like

    {

        type = “com.fibaro.multilevelSwitch”,

        properties = { 

             vendorName = “Acme”

        }

    }

     

    Helper functions to deal with SSNs can be provided, fibaro.call could be patched to allow an SSN to be the first argument. Event mechanisms could return the SSN, etc.

     

    The problem is Scenes. The condition template don’t allow it and also block scenes does not support it…

  • Topic Author
  • Posted

    Since you mentioned finding a method for a synthetic serial number for every device, I can share what I managed to discover during my own work. Maybe with combined effort we can push this further. 

     

    Why did I stop working on SSNs? While building DNSfD I ran into so many issues – not really programming issues, but design and conceptual ones – that I was simply happy to discover any serial numbers at all.

     

    Finding the serialNumber field in the JSON was the game-changer. Unfortunately, the serial number alone is not enough. Every real device has multiple sub-devices, all sharing the same SN (the Smart Implant has around ten!). So I started looking for additional static fields that differ between sub-devices. When I thought I had found a promising set of fields, I downloaded the full JSON of all 358 devices in my system. After filtering out the items I wasn’t interested in (QuickApps, Z-Wave parents, logins, weather, no serial), I was left with 238 devices. I generated SSNs for them and – to my satisfaction – none of them were duplicated.

    The fields I used were:
    serialNumber | type | properties.endPointId | properties.deviceRole | properties.productInfo

     

    After that, I returned to the main topic.

     

    It has to be said clearly: the base of any SSN is the serialNumber field. My problem is that I practically don’t have any non-Fibaro devices. Except for one water valve – and that one happens to have no SN at all. Maybe devices from other manufacturers do have it? Perhaps someone can check?

     

    Given the generally low interest in solutions like DNSfD (hence my mild irony at the beginning :), I am not going to buy devices just to run experiments.
    It’s enough that I invest a lot of my time (reward: satisfaction).
     

    And now the core issue: even though the JSON contains a huge number of fields, is it really possible to find a set (without SN) that is both:

    - unique in value, and

    - identical in key key name and position,
    for all devices across all installations?

     

    Honestly – I doubt it. And that is the fundamental problem. Finding static fields for 5-10 device models doesn’t prove that other devices will have the same fields, nor that the fields will be equally stable in every installation.

    Jan has already pointed out a sensible path for QuickApps. Virtual devices (based on QAs) have real use in many more complex systems, and they tend to change IDs quite often after modifications. As for scenes – I do not intend to deal with them at all. There is not a single scene in my system, and I consider attempts to solve that problem in the context of SSNs to be hopeless.

     

     

    Something else came to my mind: in the Fibaro REST API there is (I believe) a method that modifies the device structure. If it can write something into the serialNumber field, then we’re home. Generating a pool of serial numbers and assigning them to devices that don’t have one (at start or change) would no longer be any problem at all.

    Posted

    Some fields are read-only in the device structure. It would be sensible if the serialNumber was read-only - I haven't checked.
    I have fibaro devices without serialNumber...

  • Topic Author
  • Posted

    Let’s assume for a while it is not read only. After thinking about it, I still believe we face the same problem: how do we figure out that this particular device should be assigned exactly the same serial number from the pool every single time? And we are at start again :)

    • Like 1
    Posted (edited)

    I think SSN has to be limited to Zwave devices only.

    2 fields can be changed using SWAGGER or API and they are very often equal to "":

    • Manufacturer
    • Description

    Then we can use "Manufaturer" to register the QAs or scenes Ids which use it and Description to set another unique value to prevent search error**

    Each field format similar to a table but as a string like:

    "{QA_Id_1=80,SC_Id1=107,QA_Id_2...}" or {QAs={QAid1,QAid2...},Scs={scId1,scId2,...}}

    This needs to create a helper QA with alphanumeric keypad that will change this 2 fields entering firts new device ID. I has to be able to create the tabkes or update it if a new QA or scene needs it but also suppress automatically any ID which does not exist anymore; this action will have to be done just after (re)including a new device.

     

    Then, like you proposed, some line of codes in each QA  to find which Ids are needed for that QA and replace old by new.

    Not sure that the above may work... but when back home I will start to develop that and let you know my finding.

     

    ** Need help to find the right type of value but a unique serial number created by the Helper QA may be OK.

    Edited by Christb
  • Topic Author
  • Posted

    Putting together voices of @jgab and @Christb I have more detailed solution of setting SN to any QA. It integrates well with DNSfD.

    Idea is that serial becomes part of the QA’s own code, so it survives all QA life troubles. 

    DNSfD is responsible for:

    - one-time generating and storing a pool of codes,

    - printing it on console (marking already used) to allow user choose first free one,

    - validate uniqueness,

    - api.put SN to the device's writable field.


    At startup, the QA sends always the same number to DNS and requests registration (like self:registerMe("ABCD1234")).

    DNS maintains a central registry of all serials.

    - If the serial is unused, DNS registers it, stores it in the device’s editable JSON field (optionally: returns an ACK).

    - If the serial is already taken, DNS returns “denied” (option) and the QA remains excluded from SSN processing.

    Later on, SSN is computed as before (only source of SN and maybe other fields is changed in QA case).

     

    This gives every QA a deterministic, permanent identity, independent of name, ID, room, function... Complication for QA is minimal (one little call in onInit).

    Posted

    Yes, but it requires the QA to be part of the scheme. Manually setting SSN in ex. userDescription allow us to also include. ex. @Sankotronic's QAs. 

  • Topic Author
  • Posted

    Thanks for opinions – I will continue developing my automated model, since that is the direction I’m aiming for.

    The manual method can exist as an optional fallback, but it’s not the focus of my design.

    I extend the SSN algorithm to use an alternative field when the primary serialNumber is missing.

     

    Posted

    For my QuickApps I use properties as follows:

    1. manufacturer - I use to identify all quick apps that belong to Yubii UHAS

    2. model - is set to the name of the Yubii UHAS module, e.g. "lights", "system", "appliances", "climate" etc.

    3. quickAppUuid - is set to unique string for particular quick app so can be easily found if installed by other quick apps and used. Since it is unique same as device ID for particular quick app it can be used to find if any of the quick apps was reinstalled and links can be restored during restart of either complete UHAS or just selected module (no need to restart gateway)

    I have added Fibaro motion sensor and managed to change property serialNumber using

    Please login or register to see this code.

    from the scene to unique string and therefore it seems it is possible to use it as unique string together with some other properties like created, manufacturer and deviceRole?

    I prefer not to use userDescription as it can be changed by users.

     

  • Topic Author
  • Posted

    Hmm… telepathy. I was checking similar (other field: userDescription) just a moment ago and the results were identical. 
    I also confirmed that the value is persistent; it survives a HC reboot and a power loss. Of course, it will not survive a re-include.
    I’m continuing my tests, but it’s already clear that the QA case can be solved.

  • Topic Author
  • Posted (edited)

    LOONG...

    Please login or register to see this attachment.

     

    I would like to share some progress on the DNS development.

    I’ve honestly never hit this many implementation problems while trying to make a system fully watertight. It seems to be a general problem for any solution where components cooperate asynchronously. In Fibaro this is even more visible, because there’s basically no built-in support for this kind of communication: fibaro.call(...) is like “fire and forget”. The entire handshaking and reliability layer has to be done manually.

     

    At the moment both the DNSfD server and the client-side toolbox are stable, although not entirely free of small gaps that come simply from the nature of the problem. Using DNSfD requires an understanding of how it works, even though the user is supported as much as possible and the usage is simple. If one doesn't know how the mechanics work, can cause themselves (reversible) trouble. For that reason it probably won’t have many users, even though it can be absolutely invaluable “once a year”.

     

    1. Fibaro devices without serial numbers

    The Fibaro devices without serial numbers mentioned by Jan do indeed exist. In my system it turned out they were members of a logical group representing a single physical device (smart implant, door sensor). Other “siblings” in that group did have a serialNumber. So I simply find a sibling with a non-empty serial and copy it over. When computing the final SSN, nothing changes. That part is done.

     

    2. QA as Virtual Devices (VD)

    I mean QuickApps acting as software sensors, switches, etc. I call them Virtual Devices. They’re basically identical to physical devices except that they additionally contain Lua code - a perfect place to store an immutable SN from which the SSN is computed. VDs don’t have a serialNumber field and you can’t add one to JSON. By using a different field (in my case 'manufacturer'), the VD assigns itself a sN that is always unique and immutable. The calculation path is different, but the end result is the same: a stable SSN.

     

    3. Child devices (chD)

    I use them very rarely (I have one), but I know they’re very popular in the community. They’re very similar to physical devices and also have no Lua code of their own. The code lives in its parent. The parent is an excellent source of SN for its children. After creating the children (once their IDs are known), it can register each one with a unique SN. This process is a bit trickier, because the registration happens per child, dynamically (not as for SSN - in single pack). The main difficulty is detecting when the parent has received all ACKs confirming the registrations.

    The logic for this is already worked out, but not implemented yet (it requires larger changes in both the server and the client). Finally the server will return the correct ID of every chD during initialization and also signal any ID changes while the client is running.

     

    In cases 2 and 3, responsibility for assigning SN is shared between the subscriber and DNSfD.

     

    4. Physical devices with an empty serialNumber

    Here I think I’ve hit the true boundary of the problem: such devices have no single “source of truth” regarding their identity. There’s no guarantee that any chosen “fingerprints” will be simultaneously unique among devices of the same type, and stable across inclusions into the system.

    I think this is the one case we simply have to accept and leave as is.

     

    What I’ve described is just the "tip of the iceberg" behind the whole DNSfD development. The system is now working, which I consider a major success. It has already handled about 1300 subscriptions to devices without errors (of course generated “artificially”).

    I’m continuing to test it in real usage, focusing mainly on edge-cases.

     

    Example usage:

    Please login or register to see this code.

     

    Edited by Łukasz997
    Posted (edited)

    Hi @Łukasz997,

     

    I can see that your DNSfD and my Yubii UHAS will clash since I'm also using "manufacturer", so will have to add note to my installation manual to check and not mix.

     

    Also, since assigning SN is shared between subscriber and DNSfD for "Virtual devices", why not do that also for physical devices that "serialNumber" is empty?

     

     

    Edited by Sankotronic
  • Topic Author
  • Posted (edited)

    Good morning @Sankotronic,

    regarding 'manufacturer' - please don't worry about collisions using this field, I will find other one. There are many of them and at this stage can be easily replaced in DNS.

     

    The second question deserves a broader answer, because it touches the foundations of how DNS works.

    What you describe can already be done today without any changes to DNSfD. A user can write a tiny QuickApp that performs an api.put(...) and writes any value into the sN field. Every physical device I have encountered has such a field (even if it is empty). From that moment, DNS will  include this device when calculating the synthetic SSN. No modifications on the DNS side are required.
     

    However, there is another side to this: at that moment the full responsibility for the correctness and persistence of that number falls on the user.

    What should be considered a “correct” serial number?
    One that is:

    - unique (DNS can ensure that part, just like it does for VDs),

    - and equally important, unchanged for the entire lifetime of the device, including across any future re-includes.

    And here is the problem: if the user makes a mistake even once, DNS will compute a different SSN, and the entire logic will break. The damage depends on how deeply that device is referenced in the system.

     

    Example: someone has 10 identical window open sensors without serial numbers. Each one must be assigned exactly the same number it had previously. Only on the initial assignment the choice doesn't matter. After that, it matters completely. The user would have to remember this or keep it “on a sticky note”. In practice, sooner or later a mistake will happen - and the later it happens, the worse.
     

    For VDs the situation is different: the serial is permanently written in the code. If someone changes it, it is no longer a “mistake” but a form of more or less intentional “sabotage”.
    For physical devices, the only unchangeable source of truth is the hardware serialNumber.
    For child devices – the parent’s code.

    In all three cases there is something persistent. Although - as noted - it can still be broken deliberately.

    Physical devices without a serialNumber do not have such a source of truth – and this is exactly why I exclude them from a deterministic system like DNS.
    Repeatability of the serial = repeatability of the SSN = reliability of DNS.

    This is why I mentioned earlier that understanding the mechanics of this system is essentially necessary to use it safely.


    It also needs to be said clearly that the damage caused by a misused DNS (misused!) in the event of a full system breakdown is still smaller than if DNS were not used at all. Only some IDs will be incorrect. Without DNS, all IDs used anywhere in references would have to be changed. With DNS used correctly, every ID change will be delivered to  QAs (not all QAs, but those which are the part of the project, all eligible phisical devices IDs are in the project automatically). 


    To me, this is a truly significant benefit.


    Long live serial numbers!

    Edited by Łukasz997
    Posted

    Hi @Łukasz997,

     

    25 minutes ago, Łukasz997 said:

    regarding 'manufacturer' - please don't worry about collisions using this field, I will find other one. There are many of them and at this stage can be easily replaced in DNS.

    Regarding this part please check my previous post in which I explained which Quick app properties I use and for what purpose. This is planned in advance and I already have table of all quick apps that I will make and offer as a part of the Yubii UHAS. Since everything is planned in advance Yubii UHAS users will not have to do anything about setting up devices ID and system itself. System will know what is installed and all interaction between quick apps will go naturally and automatically.

     

    Regarding physical devices it is really a different story as you already wrote, since there is actually no unique property to relay on like with quick apps. Replaced quick app will still have same properties like "manufacturer", "model" and "quickAppUuid" set by its own code so very easy to find and then update its ID in the table and then make other quick apps (maybe even scenes) to use replaced one and new installed ones too.

     

    For now I do not see any viable solution for physical devices that does not require users involvement. What I can think of is just type and location of the replaced device and compare installation date? Will have to study more if anything else can be used to identify if new physical device is replacement for the removed one or new installed one.

     

    Anyway, my goal is to reduce as much as possible users involvement in system setup, so can have more time to just adjust automation to their need and that all setup can be done on mobile app instead sitting in front of a computer :-) 

     

     

  • Topic Author
  • Posted (edited)

    Maybe previous example of usage is too complex. Simpler form of subscription for small QA, using only one ID reference.

    Please login or register to see this code.



    Above lines + ~300 lines universal toolbox aside is the complete cost of participance in DNS. If you use only SSN subscription, toolbox can be half smaller.

    Not much, I think...

    Edited by Łukasz997
  • Topic Author
  • Posted
    7 minut temu, Sankotronic napisał:

    Regarding this part please check my previous post in which I explained which Quick app properties I use and for what purpose

    I have read this and I remember. UHAS QA - as I understand it - have no reason to be a part of DNS, because they have its own supervising mechanism. In DNS the user must explicitly register a QA to participate.

     

    8 minut temu, Sankotronic napisał:

    What I can think of is just type and location of the replaced device and compare installation date?

    Thin ice...! :) 

    • 2 weeks later...
  • Topic Author
  • Posted

    DNSfD has been working beautifully. Just for fun, I was deleting a few devices to watch how new IDs propagate to the clients. Everything behaved perfectly… until it didn’t.
     

    Until I performed a firmware upgrade on 5 or 6 Smart Implants. The change was innocent: FW from 5.2 to 5.3.


    DNSfD politely informed me that the SSN had changed for... 60 devices (it breaks the connection: physical device ID <-> client QA). Then the server-side automation removed (with a proper log message) around 15 subscriptions that were no longer valid… (because I only had three clients connected). 

     

    After a moment of fear it turned out that reason is productInfo field, which I had originally included in the SSN calculation - to this day I’m not entirely sure why. It doesn’t add anything meaningful, and it’s identical across all endpoints of the device. The firmware upgrade replaces the last digit of the number sequence inside that field.

     

    And that one tiny bump changed everything.

    Fortunately, I eventually realized that all affected devices were Smart Implants, and faintly remembered doing “something” with them few days ago. Otherwise I would probably have assumed a logic bug in DNS… or who knows what else. After two hours of digging I found a better field to use, replaced the old one, and moved on.

     

    The moral of the story: having a so-called “single source of truth” is problematic if that source is anything other than the serial number (and SN alone isn’t enough). I treat api.get("/devices") as the sacred representation of the HC3 world. The manufacturer treats it as an interface that can change with firmware, templates, and the general mood of the R&D department.

    And this is why I try with DNSfD to build own stable(?) layer of truth on top of HC3 - a layer that isolates me from changes to productInfo, zwaveVersion, etc., and gives me SSNs based on something that actually represents “the same physical chunk of hardware.”
    One step ahead, I hope.

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest
    Reply to this topic...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

    ×
    ×
    • Create New...