Skip to content

Fixed method handleUpdatePlatformAccessories() #3765

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

justjam2013
Copy link
Contributor

@justjam2013 justjam2013 commented Jan 5, 2025

♻️ Current situation

The method handleUpdatePlatformAccessories() is not properly implemented. In this method, the array of PlatformAccessory objects is lost, as it is not used in the handleUpdatePlatformAccessories() method. The method just saves the currently cached platform accessories back to disc without updating anything.

See Updating Platform Accessories does nothing - method is not implemented.

💡 Proposed solution

  1. Find cached platform accessories that do not have matching UUIDs with the updated accessories.
  2. Overwrite the cached platform accessories array with the non-matching accessories plus the updated accessories.
  3. Save the cached platform accessories array with the new entries.

⚙️ Release Notes

➕ Additional Information

Testing

Reviewer Nudging

@github-actions github-actions bot added the latest label Jan 5, 2025
donavanbecker
donavanbecker previously approved these changes Jan 18, 2025
@donavanbecker donavanbecker enabled auto-merge (squash) January 18, 2025 15:03
@github-actions github-actions bot added the beta label Jan 18, 2025
@coveralls
Copy link

coveralls commented Jan 18, 2025

Pull Request Test Coverage Report for Build 12845094518

Details

  • 0 of 3 (0.0%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.05%) to 28.368%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/bridgeService.ts 0 3 0.0%
Totals Coverage Status
Change from base Build 12845052540: -0.05%
Covered Lines: 431
Relevant Lines: 1374

💛 - Coveralls

@donavanbecker donavanbecker merged commit b0ec950 into homebridge:beta-1.9.0 Jan 18, 2025
9 checks passed
donavanbecker pushed a commit that referenced this pull request Jan 19, 2025
* Fixed method handleUpdatePlatformAccessories()

* Fixed filter matching condition and removed lint annotation
donavanbecker pushed a commit that referenced this pull request Jan 19, 2025
* Fixed method handleUpdatePlatformAccessories()

* Fixed filter matching condition and removed lint annotation
@ebaauw
Copy link
Contributor

ebaauw commented Jan 19, 2025

I think this has caused #3773

@bwp91
Copy link
Contributor

bwp91 commented Jan 19, 2025

updatePlatformAccessories() technically expects an array:

updatePlatformAccessories(accessories: PlatformAccessory[]): void;

I wonder if part of the issue is that in homebridge-lib it is passing undefined rather than an empty array.

https://github.com/ebaauw/homebridge-lib/blob/06772ab5557aa07c3af753538852524162f19193/lib/Platform.js#L279

We could fix the homebridge code to check for the existence of a passed array. changing the type to optional.

I guess this new issue never presented itself before because the argument was never being used, whether any value was passed in or not.

@justjam2013
Copy link
Contributor Author

justjam2013 commented Jan 19, 2025

We could fix the homebridge code to check for the existence of a passed array. changing the type to optional.

The bug is in homebridge-lib, as it is calling updatePlatformAccessories() with the wrong parameters. Up until now it has been masked by the bug in Homebridge code. Homebridge should not be "coding to the bugs".

The reason that I recommend against modifying Homebridge code is, consider a scenario where someone removed from this decision decides to reimplement this method. This will end up breaking homebridge-lib anyway.

The fact that the code fix is in a beta, means that a Homebridge release could wait until a fixed version of homebridge-lib was released.

However adding some defensive code would not be a bad idea:

  handleUpdatePlatformAccessories(accessories: PlatformAccessory[]): void {
    if (accessories !== undefined) {
      const nonUpdatedPlugins = this.cachedPlatformAccessories.filter(
        cachedPlatformAccessory => (
          accessories.find(accessory => accessory.UUID === cachedPlatformAccessory._associatedHAPAccessory.UUID) === undefined
        ),
      );

      this.cachedPlatformAccessories = [ ...nonUpdatedPlugins, ...accessories];
    }

    // Update persisted accessories
    this.saveCachedPlatformAccessoriesOnDisk();
  }

ebaauw added a commit to ebaauw/homebridge-lib that referenced this pull request Jan 20, 2025
Fix bug that manifested in Homebridge 2.0 beta, see homebridge/homebridge#3765,  homebridge/homebridge#3773, and ebaauw/homebridge-ups#26.
@ebaauw
Copy link
Contributor

ebaauw commented Jan 20, 2025

Passing an empty array seems to work, thanks.

For truly defensive code, you would need to check that the accessories parameter is indeed of the correct type, not just that it is not undefined. It's probably easier to change the cal to accessories?.find(...) (assuming we'll no longer support old NodeJS versions that don't support ?..

@justjam2013
Copy link
Contributor Author

For truly defensive code, you would need to check that the accessories parameter is indeed of the correct type, not just that it is not undefined.

I can't speak about Javascript, as I have limited experience, but in Typescript you cannot call myfunc(param: Foo[]) and pass param: Bar[]. You would get a compile time error. null is its own fun kind of hell that even some strongly typed languages struggle to deal with. I'm not massively experienced with Typescript either, but I think you would have to write myfunc(param: Foo[] | undefined) to allow passing undefined and not get a compile time error ... ?
The problems arise from Typescript getting transpiled to Javascript and losing some of the guardrails in the process.
All of which is why I am not a fan of weakly typed languages in general. I like strict type checks. My personal quote is "with strongly typed languages you catch type errors at compile time, with weakly typed languages you catch type errors at run time". It's kind of like walking through the forest: you can clear cobwebs with a stick or with your face. Either works rather well, but one is a bit unpleasant.

@bwp91
Copy link
Contributor

bwp91 commented Jan 20, 2025

@ebaauw after another thought on this situation it made me wonder what your intentions were with these lines

this._homebridge.updatePlatformAccessories()

this._homebridge.updatePlatformAccessories([])

because even before or after the changes in this PR, it seems to me that it isn't doing anything?

    const nonUpdatedPlugins = this.cachedPlatformAccessories.filter(
      cachedPlatformAccessory => (
        accessories.find(accessory => accessory.UUID === cachedPlatformAccessory._associatedHAPAccessory.UUID) === undefined
      ),
    );

    this.cachedPlatformAccessories = [ ...nonUpdatedPlugins, ...accessories];

If an empty array is passed in:

  • this.cachedPlatformAccessories.filter is just going to return all the elements
  • so nonUpdatedPlugins will be equal to this.cachedPlatformAccessories
  • so the final this.cachedPlatformAccessories will be ` = [ ...this.cachedPlatformAccessories, ...[]) - i.e. - nothing is changing

perhaps I am missing something? or what you are aiming to do isn't actually happening?

@ebaauw
Copy link
Contributor

ebaauw commented Jan 20, 2025

what you are aiming to do

I want to force-write cachedAccessories so the accessory context as set by my plugins is persisted. Normally, Homebridge would do this on a clean exit, but not when Homebridge crashes. I do this after startup/initialisation (when the plugin has re-connected to all devices) and once every hour.

All of which is why I am not a fan of weakly typed languages in general.

Couldn't agree more. I started with Homebridge way before TypeScript, so all my plugins (still) are plain JavaScript. I might want to change that to TypeScript, someday, but I rather spend my time on functional enhancements than a technical refactor. Homebridge might very well be obsoleted by Matter, before I'll find the time.

@justjam2013
Copy link
Contributor Author

I do this after startup/initialisation (when the plugin has re-connected to all devices) and once every hour.

Do you store the accessory's state in the context? I have accessories with persistent state (on/off, open/close) and I store that in a json file, and handle writing, reading, and deletion. And after reading your statement, a lightbulb just went off and I'm feeling like a complete donkey 🤣

@ebaauw
Copy link
Contributor

ebaauw commented Jan 20, 2025

That's what the context is for. I even store the Eve history in there. I was a bit worried about the size when I first tried that, but it works out just fine. No need to delete stale files when the device is no longer exposed as an accessory.

donavanbecker pushed a commit that referenced this pull request Feb 11, 2025
- Added method updateDisplayName() (#3764) (@justjam2013)
- Fixed method handleUpdatePlatformAccessories() (#3765) (@justjam2013)
- Make it possible to set Characteristic.SerialNumber via config.json (#3761) (@Vvorcun)
- minor dependency updates
- fix: check for valid array in `handleUpdatePlatformAccessories`
- minor dependency updates

- `hap-nodejs` @ `v0.12.3`
bwp91 pushed a commit that referenced this pull request Feb 11, 2025
* Fixed method handleUpdatePlatformAccessories()

* Fixed filter matching condition and removed lint annotation
bwp91 added a commit that referenced this pull request Feb 11, 2025
- Added method updateDisplayName() (#3764) (@justjam2013)
- Fixed method handleUpdatePlatformAccessories() (#3765) (@justjam2013)
- Make it possible to set Characteristic.SerialNumber via config.json (#3761) (@Vvorcun)
- minor dependency updates
- fix: check for valid array in `handleUpdatePlatformAccessories`
- minor dependency updates

- `hap-nodejs` @ `v0.12.3`
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.

5 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy