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

Dynamic expose #9929

Closed
vk496 opened this issue Dec 1, 2021 · 11 comments
Closed

Dynamic expose #9929

vk496 opened this issue Dec 1, 2021 · 11 comments
Labels
feature request Feature request

Comments

@vk496
Copy link
Contributor

vk496 commented Dec 1, 2021

Is your feature request related to a problem? Please describe

Zlinky is a small zigbee device that can be connected to a electrical Linky box and expose different parameters. However, the same Linky device can have multiple configurations:

  • Mode. Depending of the mode of Linky (Historique or Standard) we receive differente kind of data
  • Monophase or Triphase
  • Could be in Production (throw energy back to the network, only with standard mode).

Those combinations makes useless expose all elements to the user, because most of them will be null or the max value of the data type.

Ex (using integration https://gist.github.com/ralmn/02de46e193bf111062f15be07d3e9bd2):
imagen

In this case, all data shown here is useless because my Linky is in mode Historique and monophase and the data shown above is for people with mode Standard and triphase

Describe the solution you'd like

exposes definition of the converter that could be adapted dynamically or during the init with options

Describe alternatives you've considered

Currently the only way right now is disabling in the code the elements you don't want.

Additional context

Zlinky Integration: https://gist.github.com/ralmn/02de46e193bf111062f15be07d3e9bd2
Zlinky doc: https://github.com/fairecasoimeme/Zlinky_TIC

@vk496 vk496 added the feature request Feature request label Dec 1, 2021
@nurikk
Copy link
Collaborator

nurikk commented Dec 1, 2021

You can you use different zigbee models based on selected mode. Then you can create different device definitions based on model name. They're few zigbee led controllers, which are doing in this way.

@vk496
Copy link
Contributor Author

vk496 commented Dec 1, 2021

Thank you @nurikk , I think that would be a acceptable way to handle it. Can you point me a reference of a led controller doing it like that? Thank you

Br,
Valentín

@nurikk
Copy link
Collaborator

nurikk commented Dec 1, 2021

I can't point to exact implementation, but your converter should look like this:
(read as pseudocode)

const baseDefinition = {

    vendor: 'LiXee', 
    description: 'Lixee ZLinky', 
    fromZigbee: [haMeterIdentificationFZ, seMeteringFZ, haElectricalMeasurementFZ],
    toZigbee: [],    
    configure: async (device, coordinatorEndpoint, logger) => {
        const SW1_ENDPOINT = 1;
        const endpoint = device.getEndpoint(SW1_ENDPOINT);

        // ZLinky don't emit divisor and multiplier
        endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', { acCurrentDivisor: 1, acCurrentMultiplier: 1 });
        endpoint.saveClusterAttributeKeyValue('seMetering', { divisor: 1, multiplier: 1 });

        for(let reportable of dataReportable){
                logger.debug(`ZLINKY_TIC: Start configure reporting for ${reportable.name} (${reportable.cluster}/${reportable.attribut}).`);
                //await endpoint.read(reportable.cluster, [reportable.attribut]);
                endpoint.configureReporting(reportable.cluster || reportable.clusterId,
                    [{
                        attribute: reportable.attribut || reportable.attributId,
                        minimumReportInterval: 1,
                        maximumReportInterval: repInterval.MINUTES_5,
                        reportableChange: 1,
                    }]).then(() => {
                        logger.debug(`ZLINKY_TIC: ${reportable.name} (${reportable.cluster}/${reportable.attribut}) report successfully configured.`);
                    }).catch(e => { // Bug on firmware v1.0.0 (2021 11 01) -> Some attributs reportable cannot be configured
                        logger.warning(`ZLINKY_TIC: Failed to configure reporting for ${reportable.name} (${reportable.cluster}/${reportable.attribut}). Adding in polling attributs list.`)
                        dataNonReportable.push(reportable);
                    });                       
        }

    },
    options: [exposes.options.measurement_poll_interval()],
    onEvent: async (type, data, device, options) => {
        const endpoint = device.getEndpoint(1);
        if (type === 'stop') {
            clearInterval(globalStore.getValue(device, 'interval'));
            globalStore.clearValue(device, 'interval');
        } else if (!globalStore.hasValue(device, 'interval')) {
            
            // periodic scan for non-reportable attributs
            
            const seconds = options && options.measurement_poll_interval ? options.measurement_poll_interval : 120;
            await poll(endpoint);
        
            const interval = setInterval(async () => {
                try {
                    await poll(endpoint);
                } catch (error) {/* Do nothing*/ }
            }, seconds * 1000);
            globalStore.putValue(device, 'interval', interval);
        }
    },
    endpoint: (dev) => {
        return {
            'haElectricalMeasurement': 1, 'seMetering': 1, 'haMeterIdentification': 1
        }
    }
}

// here you export array
module.exports = [
    {
        zigbeeModel: ['ZLinky_TIC_mode1'], 
        exposes: [indexEnergy(), ...exposesData],
        extends: baseDefinition,
       // you can create even custom configure method for every mode
    },
    {
        zigbeeModel: ['ZLinky_TIC_mode2'], 
        exposes: [indexEnergy(), ...anotherExposesData],
        extends: baseDefinition,
    },
    //continue
];

@vk496
Copy link
Contributor Author

vk496 commented Dec 1, 2021

ok, thanks. It is clear for me what sou say. But when the final user will pair the device, how it will be able to decide which to use?

The converters that I saw in the repo have some differences (like model, or last chars of manufacter, etc.) which makes possible to create fingerprints when paired.

Here we are talking about the exactly same device.

Sorry, I'm not familiar with the framework/APIs of Z2M

Br

@Danit2
Copy link

Danit2 commented Dec 2, 2021

I'm interested too.

Dynamic exposes would be interesting for one of my devices also.

@vk496
Copy link
Contributor Author

vk496 commented Dec 5, 2021

What I've tried to do is define exposes as variable and tried to edit/modify that variable from configure, but Z2M doesn't expose anything, so I assume evaluation of exposes comes before execution of configure.

Also I've tried the idea of @nurikk , but device is not recognized because there is no match based on zigbeeModel. It would work if could match by reading the cluster/attributes, but I'm not sure if it is possible or supported by Z2M

Br,
Valentín

@Danit2
Copy link

Danit2 commented Dec 5, 2021

I think i have found a solution to our problem.
You have to make several devices and then keep them apart with the fingerprint. like in this example:


    {
        fingerprint: [
            // https://github.com/Koenkk/zigbee2mqtt/issues/8027#issuecomment-904783277
            {modelID: 'ZLL-ColorTempera', manufacturerName: 'Trust International B.V.\u0000', applicationVersion: 1, endpoints: [
                {ID: 1, profileID: 49246, deviceID: 544,
                    inputClusters: [0, 4, 3, 6, 8, 5, 768, 65535, 65535, 25], outputClusters: [0, 4, 3, 6, 8, 5, 768, 25]},
                {ID: 2, profileID: 49246, deviceID: 4096, inputClusters: [4096], outputClusters: [4096]},
            ]},
        ],
        zigbeeModel: ['ZLL-ColorTempera', 'ZLL-ColorTemperature'],
        model: 'ZLED-TUNE9',
        vendor: 'Trust',
        description: 'Smart tunable LED bulb',
        extend: extend.light_onoff_brightness_colortemp(),
    },

Haven't tried yet. But I will tonight. I think this will work.

@Danit2
Copy link

Danit2 commented Dec 5, 2021

I have tried jet.

For my device it works like this:

    {
        zigbeeModel: ['Zigbee 3.0 DALI CONV LI'],
        model: '4062172044776',
        vendor: 'OSRAM',
        description: 'Zigbee 3.0 DALI CONV LI dimmer for DALI-based luminaires (only one Device)',
        extend: extend.ledvance.light_onoff_brightness(),
    },
    
    {
        fingerprint: [
            {modelID: 'Zigbee 3.0 DALI CONV LI', endpoints: [
                {ID: 10},
                {ID: 25},
                {ID: 242}
            ]},
        ],
        model: '4062172044776',
        vendor: 'OSRAM',
        description: 'Zigbee 3.0 DALI CONV LI dimmer for DALI-based luminaires (one Device and Pushbutton)',
        extend: extend.ledvance.light_onoff_brightness(),
    },
    
    {
        fingerprint: [
            {modelID: 'Zigbee 3.0 DALI CONV LI', endpoints: [
                {ID: 10},
                {ID: 11},
                {ID: 242}
            ]},
        ],
        model: '4062172044776',
        vendor: 'OSRAM',
        description: 'Zigbee 3.0 DALI CONV LI dimmer for DALI-based luminaires (with two Devices)',
        extend: extend.ledvance.light_onoff_brightness(),
        exposes: [e.light_brightness().withEndpoint('l1'), e.light_brightness().withEndpoint('l2')],
        endpoint: (device) => {
            return {'l1': 10, 'l2': 11};
        },
        meta: {multiEndpoint: true},
    },
    
    {
        fingerprint: [
            {modelID: 'Zigbee 3.0 DALI CONV LI', endpoints: [
                {ID: 10},
                {ID: 11},
                {ID: 25},
                {ID: 242}
            ]},
        ],
        model: '4062172044776',
        vendor: 'OSRAM',
        description: 'Zigbee 3.0 DALI CONV LI dimmer for DALI-based luminaires (with two Devices and Pushbutton)',
        extend: extend.ledvance.light_onoff_brightness(),
        exposes: [e.light_brightness().withEndpoint('l1'), e.light_brightness().withEndpoint('l2')],
        endpoint: (device) => {
            return {'l1': 10, 'l2': 11};
        },
        meta: {multiEndpoint: true},
    },

This is the same device but with different configurations.

Hope will help you to.

@vk496
Copy link
Contributor Author

vk496 commented Dec 6, 2021

Hi,

Thank you @Danit2 for sharing your code. In your example, you use fingerprint aproach by endpoints, right?

In that case, it means that your device expose different endpoints based on his mode/status?

@Danit2
Copy link

Danit2 commented Dec 6, 2021

Yes my device can have different modes.
But the name is everytime the same.
So i use the fingerprint on the endpoints to make the differents between the modes.

You can use them also.

@vk496
Copy link
Contributor Author

vk496 commented Dec 6, 2021

ok, thank you for clarifying it.

In my side the device doesn't have any mode. It just expose all attributes (some are reportable and some others you had to read them). So maybe if I can't control dynamically what is exposed to Z2M, maybe I could try to restrict what is sent to MQTT (Koenkk/zigbee-herdsman-converters#3468)

In any case, your aproach doesn't seems applicable to my case. Thank you in any case :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Feature request
Projects
None yet
Development

No branches or pull requests

3 participants