Skip to content
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

/api/accessories returns different results depending on mDNS Advertiser. #24

Open
teh-hippo opened this issue Sep 30, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@teh-hippo
Copy link

Analysis

I have a custom NodeJS program I've written that pulls data from the /api/accessories endpoint to make decisions about my home setup. E.g., the air con's current mode.

I noticed that the application broke when I reset the mDNS provider to the default Avahi, instead of Ciao. I don't recall why I selected Ciao, or if that's a legacy value, but I didn't see any need to use something other that the default. But after doing that, the size of the results I get from /api/accessories is roughly a 1/4 of that I got when using Ciao.

I believe only old accessory style plugins are exposed. Platform-provided plugins, of which my aircon is one, don't seem to be exposed.

Expected Behavior

All Homebridge accessories are available via /api/accessories, regardless of any Homebridge setting.

Steps To Reproduce

  1. Create an accessory using homebridge-dummy.
  2. Create a platform-accessory (your pick).
  3. Set Homebridge to use Ciao.
  4. Set Homebridge to use insecure mode (required for the accessories endpoint).
  5. GET /api/accessories. Confirm all accessories are visible.
  6. Change Homebridge to use Avahi.
  7. GET /api/accessories. Observe the platform accessories are no longer returned.

Logs

I don't think this is required here.  The missing accessories are just not present at all.

Configuration

As above; I don't believe this is beneficial here.

Environment

  • OS: Rasbian (Debian bullseye)
  • Software: Homebridge 1.8.4
  • Node: v20.17.0
  • npm: 10.8.2

Process Supervisor

hb-service

Additional Context

No response

@teh-hippo teh-hippo added the bug Something isn't working label Sep 30, 2024
@NorthernMan54
Copy link

Could you provide a small standalone test program that demonstrates the issue ?

Also when you look at the Accessories tab, is it fully populated or is it also incomplete ?

PS Personally I use node-red for this type of thing, so I can avoid the direct coding etc to the interface

@teh-hippo
Copy link
Author

Description

Once the requirements are fulfilled, and the config added, the node script below will use the no-auth endpoint to get a token, and call the list of accessories, emitting the count. When I run this locally, I have a discrepancy between what is returned when using Ciao to using Avahi.

I thought it was that all platforms are missing, but it doesn't seem to be as clear cut as that.

Requirements

Files

Homebridge Config:

{
    "bridge": {
        "advertiser": "ciao"
    },
    "platforms": [
        {
            "platform": "HomebridgeYAP",
            "accessories": [
                {
                    "name": "RPI",
                    "ip": "192.168.0.1"
                },
                {
                    "name": "Self",
                    "ip": "127.0.0.1"
                }
            ]
        }
    ],
    "accessories": [
        {
            "name": "Test-Switch",
            "accessory": "DummySwitch"
        }
    ]
}

The Script:

const http = require('http');

function makeRequest(options, postData = null) {
  return new Promise((resolve, reject) => {
    const req = http.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => data += chunk);
      res.on('end', () => resolve(JSON.parse(data)));
    });
    req.on('error', reject);
    if (postData) req.write(postData);
    req.end();
  });
}

async function main() {
  console.log('Step 1: Requesting authentication token...');
  const tokenResponse = await makeRequest({
    hostname: 'raspberrypi',
    port: 80,
    path: '/api/auth/noauth',
    method: 'POST',
    headers: { 'Content-Type': 'application/json' }
  }, JSON.stringify({}));
  
  const token = tokenResponse.access_token;
  console.log('Authentication token received:', token);

  console.log('Step 2: Fetching accessories using the token...');
  const accessories = await makeRequest({
    hostname: 'raspberrypi',
    port: 80,
    path: '/api/accessories',
    method: 'GET',
    headers: { 'Authorization': `Bearer ${token}` }
  });

  // Filter accessories by Model 'YAP' or 'Dummy Switch'
  const filteredAccessories = accessories.filter(item => {
    const model = item.accessoryInformation?.Model;
    return model === 'YAP' || model === 'Dummy Switch';
  });
  
  console.log('Filtered Accessories:', filteredAccessories);
  console.log('Returning ', filteredAccessories.length, 'items.')
}

main().catch(console.error);

Execution

node file.cjs

@NorthernMan54
Copy link

Slightly modified your program ( removed filtering as it did not apply to my setup, and made hostname/port constants.

#! /usr/bin/env node

const http = require('http');
const fs = require('fs');

const hostname = 'jessie.local';
const port = 8581;

function makeRequest(options, postData = null) {
  return new Promise((resolve, reject) => {
    const req = http.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => data += chunk);
      res.on('end', () => resolve(JSON.parse(data)));
    });
    req.on('error', reject);
    if (postData) req.write(postData);
    req.end();
  });
}

async function main() {
  console.log('Step 1: Requesting authentication token...');
  const tokenResponse = await makeRequest({
    hostname: hostname,
    port: port,
    path: '/api/auth/noauth',
    method: 'POST',
    headers: { 'Content-Type': 'application/json' }
  }, JSON.stringify({}));
  
  const token = tokenResponse.access_token;
  console.log('Authentication token received:', token);

  console.log('Step 2: Fetching accessories using the token...');
  const accessories = await makeRequest({
    hostname: hostname,
    port: port,
    path: '/api/accessories',
    method: 'GET',
    headers: { 'Authorization': `Bearer ${token}` }
  });

  const filename = 'accessories-'+process.argv[2]+'.json';
  fs.writeFileSync(filename, JSON.stringify(accessories, null, 2));
  console.log('Filtered Accessories:', accessories);
  console.log('Accessories saved to file:', filename);
  console.log('Returning ', accessories.length, 'items.')
}

main().catch(console.error);

With avahi I get 71 Accessories and with ciao I get 228

This is another instance of this - #12

PS I also found that with avahi, it was slow to populate the accessories tab and with ciao very quick

@NorthernMan54 NorthernMan54 transferred this issue from homebridge/homebridge Oct 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants