dresden-elektronik / deconz-rest-plugin-v2

deCONZ REST-API version 2 development repository.
BSD 3-Clause "New" or "Revised" License
17 stars 0 forks source link

Classes / Subclasses in v2 #2

Open SwoopX opened 4 years ago

SwoopX commented 4 years ago

Gents,

following up our real good discussion, I'd like to keep the debate alive regarding the future classes. I guess it's safe to say we all anticipate a more granular and generic approach with this.

As a starting point, I'll just copy over Erik's suggestings around this:

  • Have a DeRestPluginPrivate::Node class, with an instance per deCONZ::Node instance;
  • Link all DeRestPluginPrivate::RestNodeBase instances (i.e. LightNode and SensorNode instances) to deRestPluginPrivate::Node;
  • deRestPluginPrivate::Node should hold the common attributes for all LightNode and SensorNode instances, like manufacturername, modelId, swversion, lastannounced, irrespective of from which endpoint these are sourced;
  • It should also hold the device capabilities, and the state of a final state engine to keep track of progress during pairing, reboot, whatever;
  • All incoming Zigbee traffic should be handled by deRestPluginPrivate::handleIndication() or something, so there's one method to keep the progress of device pairing
  • We could subclass deRestPluginPrivate::Node per set of devices with similar capabilities, requiring the same pairing steps, to keep the code clear (no whitelisting).

I don't think you can subclass deCONZ::Node, as these instances have already been created by the core programme. You'd need a DeRestPluginPrivate::Node with an attribute referring to the deCONZ::Node instance, cf. OtauNode::OtauNode in the OTAU plugin.

I would subclass DeRestPluginPrivate::Node to NodeOnWhenIdle, NodeLiteSleeper, and NodeDeepSleeper for handling the communication appropriately. Then, seperate base classes DeRestPluginPrivate::Endpoint and DeRestPluginPrivate::Cluster, with a reference to the DeRestPluginPrivate::Node instance. These classes would be subclassed for the various types of endpoints (if needed) and clusters.

SwoopX commented 4 years ago

So with regard to the mentioned NodeOnWhenIdle, NodeLiteSleeper and NodeDeepSleeper, I could immagine the differentiation criteria could be receiverOnWhenIdle. For the first mentioned class true, for 2nd false but what about the 3rd?

ebaauw commented 4 years ago

Probably need to whitelist that (i.e. set in the device capabilities file). For some device it will depend on how it's configured (Poll Control cluster or attribute reporting).

I meant for the penultimate bullet that the incoming traffic should be routed to the DeRestpluginPrivate::Node::handleIndication(), so there's one place to orchestrate the Zigbee traffic to/from this device. So instead of splitting the traffic per type of message in DeRestPluginPrivate::apsdeDataIndication() and DeRestPluginPrivate::apsdeDataConfirm(), to should split by device, calling the DeRestpluginPrivate::Node method. Obviously that will split out per message type, possible to the specific instances for handling the cluster and/or endpoint.

SwoopX commented 4 years ago

I make this quick and dirty due to the late hour...

As a starting point for DeRestpluginPrivate::Node, I'd like to have this data available:

I stripped most of DeRestPluginPrivate::RestNodeBase, as I'd move that down on cluster level.

One idea maybe to distinguish between light and deep sleepers, I never paid too close attention to that:

SwoopX commented 4 years ago

So I've implemented most of the above now and it seems to work as intended. You have almost half of the methods directly accessible from deCONZ::Node available via forward declaration. It does not interfere with the current code so far; I run it in my test environment. Created some debug output for most of the changes as PoC:

            sensor.setManufacturerv2("APIv2 manufacturer");
            QString mf = sensor.manufacturerv2();
            sensor.setModelIdv2("APIv2 modelID");
            QString md = sensor.modelIdv2();
            sensor.setDateCodev2("APIv2 datecode");
            QString dc = sensor.dateCodev2();
            sensor.setSwVersionv2("APIv2 SW version");
            QString sw = sensor.swVersionv2();

            QString endpoints;
            std::vector<uint8_t> eps = sensor.endpointsv2();
            QList<deCONZ::SimpleDescriptor> sdl = sensor.simpleDescriptorsv2();

            for (auto it = eps.begin(); it != eps.end(); ++it)
            {
                endpoints += QString("%1").arg(*it, 2, 16, QLatin1Char('0')).toUpper();
                endpoints += ", ";
            }

            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] NWK: 0x%04X\n", sensor.nwkv2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] Ext: 0x%016llX\n", sensor.extv2());

            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] Manufacturer: %s\n", mf.toUtf8().data());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] Model ID: %s\n", md.toUtf8().data());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] Datecode: %s\n", dc.toUtf8().data());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] SW Version: %s\n", sw.toUtf8().data());

            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] isCoordinatorv2: %d\n", sensor.isCoordinatorv2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] isRouterv2: %d\n", sensor.isRouterv2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] isEndDevicev2: %d\n", sensor.isEndDevicev2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] isZombiev2: %d\n", sensor.isZombiev2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] isReceiverOnWhenIdle: %d\n", sensor.isReceiverOnWhenIdlev2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] isFullFunctionDevice: %d\n", sensor.isFfdv2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] isMainsPowered: %d\n", sensor.isMainsPoweredv2());
            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] manufacturerCode: 0x%04X\n", sensor.manufacturerCodev2());

            DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] Endpoints: %s\n", endpoints.toUtf8().data());

            for (auto it = sdl.begin(); it != sdl.end(); ++it)
            {
                deCONZ::SimpleDescriptor sd = *it;
                QList<deCONZ::ZclCluster> icll = sd.inClusters();
                QList<deCONZ::ZclCluster> ocll = sd.outClusters();

                QString clusters = "Endpoint: ";
                clusters += QString("%1").arg(sd.endpoint(), 2, 16, QLatin1Char('0')).toUpper();
                clusters += ", Clusters: ";

                for (auto it = icll.begin(); it != icll.end(); ++it)
                {
                    deCONZ::ZclCluster cl = *it;
                    clusters += QString("%1").arg(cl.id(), 4, 16, QLatin1Char('0')).toUpper();
                    clusters += ", ";
                }
                for (auto it = ocll.begin(); it != ocll.end(); ++it)
                {
                    deCONZ::ZclCluster cl = *it;
                    clusters += QString("%1").arg(cl.id(), 4, 16, QLatin1Char('0')).toUpper();
                    clusters += ", ";
                }
                DBG_Printf(DBG_INFO_L2, "[APIv2 TEST] %s\n", clusters.toUtf8().data());
            }
02:13:56:963 [APIv2 TEST] NWK: 0x6FD3
02:13:56:963 [APIv2 TEST] Ext: 0x04CF8CDF3C764934
02:13:56:963 [APIv2 TEST] Manufacturer: APIv2 manufacturer
02:13:56:963 [APIv2 TEST] Model ID: APIv2 modelID
02:13:56:963 [APIv2 TEST] Datecode: APIv2 datecode
02:13:56:963 [APIv2 TEST] SW Version: APIv2 SW version
02:13:56:963 [APIv2 TEST] isCoordinatorv2: 0
02:13:56:963 [APIv2 TEST] isRouterv2: 1
02:13:56:963 [APIv2 TEST] isEndDevicev2: 0
02:13:56:963 [APIv2 TEST] isZombiev2: 0
02:13:56:963 [APIv2 TEST] isReceiverOnWhenIdle: 1
02:13:56:963 [APIv2 TEST] isFullFunctionDevice: 1
02:13:56:963 [APIv2 TEST] isMainsPowered: 1
02:13:56:963 [APIv2 TEST] manufacturerCode: 0x115F
02:13:56:963 [APIv2 TEST] Endpoints: 01, 15, 16, F2, 
02:13:56:963 [APIv2 TEST] Endpoint: 01, Clusters: 0000, 0002, 0003, 0004, 0005, 0006, FCC0, 000A, 0019, 
02:13:56:963 [APIv2 TEST] Endpoint: 15, Clusters: 000C, 
02:13:56:963 [APIv2 TEST] Endpoint: 16, Clusters: 000C, 
02:13:56:963 [APIv2 TEST] Endpoint: F2, Clusters: 0021,