plasticrake / tplink-smarthome-api

TP-Link Smarthome WiFi API
MIT License
1.02k stars 141 forks source link

Getting child emeter.realtime data without multiple queries to the strip #150

Closed raythree closed 9 months ago

raythree commented 1 year ago

We are attempting to use this library in an aquarium monitoring and control system. We discover all plugs, and let users choose which ones we should use. We perform the following:

  1. Turn a plug on or off based on aquarium parameters.
  2. Check if a plug being used was disconnected.
  3. Periodically monitor power usage, to detect failed equipment.

All of this works in our test setup where we have two individual plugs, one 3-outlet strip, and one 6-outlet. So there are 3 devices and 11 individual plugs.

When we periodically poll, What we need is the sysInfo (plug/relay state for each plug) as well as it's emeter.realtime. We are using the getInfo method, and just not using the cloud or schedule data.

It seems that without providing the childId, the sysInfo still gives us what we need (it has relay state for each child), but the emeter.realtime seems to give the power for the whole strip, and the only way to get the child data is to provide the childId.

If we poll each plug sequentially like this:

  const list = [];
  for (plug of Object.values(plugs)) {
    // NOTE getPlug awaits client.getDevice() and then device.getInfo(), and provides
    // the childId along with the host in getDevice if it is for a strip.
    const plugData = await getPlug(plug.id);
    list.push(plugData);
  }

Everything works fine, but the operation can be time consuming, sequentially calling each of the 11 plugs. When we tried doing this in parallel like this:

  const list = [];

  await Promise.all(
    Object.values(plugs).map(async plug => {
      const plugData = await getPlug(plug.id);
      list.push(plugData);
    })
  );

exceptions were thrown due to TCP resets from the plug strips. We are guessing this has to do with simultaneous connections to a strip trying to read the child data.

Ideally, we would like to make just one request each strip that has children, but when we tried that and omitted the childId we realized that we got the sysInfo data we needed, but that the emeter.realtime seemed like it provided usage for the entire strip, not per outlet.

Is there a better way to do this? Thanks in advance for any advice.

plasticrake commented 9 months ago

As far as I am aware this is a limitation with the device. If you can find a way to query the device to return it for all of the plugs in a strip I would add that feature to this library.