mStirner / oh-plg-shelly-gen1

Shelly gen 1 integration
0 stars 0 forks source link

Updates every added device with shelly specific labels. This breaks other plugins. #4

Closed mStirner closed 3 months ago

mStirner commented 3 months ago

Device is added as "shelly device" when the plugin oh-plg-shelly-gen1-integration is enabled:

{
  "_id": {
    "$oid": "66214260c28d1a66dcff3feb"
  },
  "name": "Phoscon Gateway",
  "icon": "fa-solid fa-wave-square",
  "interfaces": [
    {
      "type": "ETHERNET",
      "settings": {
        "socket": "tcp",
        "host": "192.168.2.4",
        "port": 80,
        "mac": null
      },
      "_id": "66214260c28d1a66dcff3fec",
      "adapter": [
        "raw"
      ],
      "description": null
    }
  ],
  "meta": {
    "manufacturer": "phoscon",
    "model": "raspbee",
    "serial": "00212EFFFF03FFC9",
    "revision": null
  },
  "labels": [
    "shelly=true",
    "gen=1",
    "auth=false",
    "type=null"
  ],
  "timestamps": {
    "created": 1713455712566,
    "updated": 1713455712698
  },
  "room": null,
  "enabled": true
}

Thats why the pairing vault event handler is not reached, because it is never registerd with the labels set above.

mStirner commented 3 months ago

The problem is the shell plugin, which does a http request when a new device is added & updates the device, with shelly labels:

    // listen for new added devices
    // fetch /shelly from device & update generation version
    C_DEVICES.events.on("add", (device) => {

        logger.info(`Shelly device ${device.name} added`);

        // NOTE: This does *not* throws error when typo interfaces[0] = interface[0]
        // See discover-endpoint.js
        let interface = device.interfaces[0];
        let { host, port } = interface.settings;
        let agent = interface.httpAgent();

        interface.once("attached", () => {

            // do request to unprotected /shelly endpoint
            // check if authenticiation is needed
            // any other request to a shelly device possible needs a password
            // TODO: add authentication stuffs
            request(`http://${host}:${port}/shelly`, {
                agent
            }, async (err, result) => {
                if (err) {

                    // NOTE: Autodelete device here?
                    logger.warn(`Could not fetch http://${host}:${port}/shelly. Please delete device and try again`, err);

                } else {
                    try {

                        logger.debug(`Fetched http://${host}:${port}/shelly (${device.name})`);

                        let {
                            gen = 1,
                            auth = false,
                            //mac = null,
                            type = null,
                            //name = null
                        } = result.body;

                        if (gen > 1) {
                            return logger.debug(`Device "${device.name}" is not a generation 1 device`);
                        }

                        // TODO format properly
                        //interface.mac = mac;

                        let labels = [
                            "shelly=true",
                            `gen=${gen}`,
                            `auth=${auth}`,
                            `type=${type}`,
                            //`name=${name}`
                        ];

                        logger.debug(`Update device labels with informations from http://${host}:${port}/shelly`, labels);

                        await C_DEVICES.update(device._id, {
                            interfaces: [
                                interface
                            ],
                            labels
                        });

                        // NOTE: why are here 3sec timeout needed?
                        // if this is removed or replaced with a process.nextTick(...) nothing works...
                        // Could it be that the update call above & the connector are to slow for the following http request?
                        setTimeout(() => {
                            events.emit("discover-endpoints", device, agent);
                        }, 3000);

                    } catch (err) {

                        logger.error("Could not update deivce", err);

                    }
                }
            });

        });

    });

This breaks the phoscon plugin (or other plugins in general)

mStirner commented 3 months ago

Change C_DEVICES.events.on("add", ...) to:

    C_DEVICES.found({
        labels: [
            "shelly=true",
            "gen=undefined",
            "needs-config=true"
        ]
    }, (device) => {

    });

...

            await C_DEVICES.add({
                name,
                interfaces: [{
                    settings: {
                        host: data,
                        port: 80
                    }
                }],
                labels: [
                    "shelly=true",
                    "gen=undefined",
                    "needs-config=true"
                ]
            });