maximkulkin / esp-homekit-demo

Demo of Apple HomeKit accessory server library
MIT License
807 stars 233 forks source link

getter + setter with variable #410

Open MGPhil opened 3 years ago

MGPhil commented 3 years ago

Hi

first of all thanks for that git and the option to programm an esp with homekit support and I appriciate any help as I am stuck here right now.

I try to have multiple relays controller by PCF8574 via I2C from ESP-01

Now I want to have that for multiple relays which would need to have a variable passed to the getter and setter function. => Copying the setter and getter code multiple times seems with different function names is not really "professional" and very frustation if I need to update something ;-)

How do I have to modify the code that it can pass an variable to getter and setter?

Initial Setter/Getter Example Code:

homekit_accessory_t *accessories[] = {
    HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_lightbulb, .services=(homekit_service_t*[]){
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Sample LED"),
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "HaPK"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "037A2BABF19D"),
            HOMEKIT_CHARACTERISTIC(MODEL, "MyLED"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, led_identify),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Sample LED"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter=led_on_get,
                .setter=led_on_set
            ),
            NULL
        }),
        NULL
    }),
    NULL
};

I tried to merge the dynamic and led sample code but the get seems not to work as homekit showes only the latest set status and does not get the update:

homekit_accessory_t *accessories[] = {
    HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_lightbulb, .services=(homekit_service_t*[]){
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Sample LED"),
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "HaPK"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "037A2BABF19D"),
            HOMEKIT_CHARACTERISTIC(MODEL, "MyLED"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, led_identify),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Status LED"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter=led_on_get,
                .setter=led_on_set
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 1"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[0]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[0]),
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 2"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[1]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[1]),
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 3"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[2]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[2]),
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 4"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[3]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[3]),
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 5"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[4]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[4]),
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 6"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[5]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[5]),
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 7"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[6]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[6]),
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 8"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_get, .context=(void*)&relay_gpios[7]),
                .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(relay_callback_set, .context=(void*)&relay_gpios[7]),
            ),
            NULL
        }),
        NULL
    }),
    NULL
};

Thanks

Philipp

maximkulkin commented 3 years ago

What you need to do is: 1) use .getter_ex and .setter_ex instead of .getter and .setter. The .*_ex variants are the same getters and setters, except for they take a pointer to characteristic as first argument. 2) use .context field in homekit_characteristic_t to store your extra data. Then you can access it through characteristic pointer in getter and setter (and callback, although callbacks were designed prior to realizing that getters and setters will need context too, so they had a separate means to attach context which is now superseeded by characteristic context).

homekit_value_t light_on_get(homekit_charactersitic_t *ch) {
    uint8_t gpio = *((uint8_t*) ch->conext);
    return HOMEKIT_BOOL(gpio_read(gpio));
}

void light_on_set(homekit_characteristic_t *ch, homekit_value_t value) {
    uint8_t gpio = *((uint8_t*) ch->conext);
    gpio_write(gpio, value.bool_value);
}

HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
    HOMEKIT_CHARACTERISTIC(NAME, "Relay 7"),
    HOMEKIT_CHARACTERISTIC(
        ON, false,
        .getter_ex=light_on_get,
        .setter_ex=light_on_set,
        .context=(void*)&relay_gpios[6],
    ),
    NULL
}),
MGPhil commented 3 years ago

I will try that, right now I added 8 times led_on_set0, led_on_set1... were in the function it passes the relay_gpios[ ] to the „working“ functions. => Works ;-) Removing that led_on_set/get* will cut the code and makes it more readable i hope, thanks

Right now I have the „.primary=true“ on all 8 relays/lightbulbs, is that ok or whats the function of „.primary=true“?

Just one additional question, when should I make a new task and when it is ok to have it direct in the „homekit“ function calls?

maximkulkin commented 3 years ago

is that ok or whats the function of „.primary=true“?

No, this is not OK. Accessory should have only one primary service.

when should I make a new task and when it is ok to have it direct in the „homekit“ function calls?

Well, the rule of thumb is to have all getters/setters/callbacks being fast: no waiting, sleeping, expensive computations.

MGPhil commented 3 years ago

And whats the difference between primary and non primary?

maximkulkin commented 3 years ago

I think primary attribute determines which accessory tile will be displayed in Home app. E.g. if you have a thermostat and an outlet services together in one accessory, whichever is marked primary will be displayed on accessory tile in Home app.

MGPhil commented 3 years ago

Thanks for support and the great git!

MGPhil commented 3 years ago

Tried it out and get a warning which I dont understand, any ideas whats the problem? Thanks

make -C schaltkasten all
make: Verzeichnis „/home/pi/projects/schaltkasten“ wird betreten
CC /home/pi/projects/schaltkasten/schaltkasten.c
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
     HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_lightbulb, .services=(homekit_service_t*[]){
     ^
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: initialization from incompatible pointer type [enabled by default]
/home/pi/projects/schaltkasten/schaltkasten.c:118:5: warning: (near initialization for '(anonymous).getter_ex') [enabled by default]

Code:

homekit_accessory_t *accessories[] = {
    HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_lightbulb, .services=(homekit_service_t*[]){
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Sample LED"),
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "HaPK"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "037A2BABF19D"),
            HOMEKIT_CHARACTERISTIC(MODEL, "MyLED"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, led_identify),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Status LED"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter=led_on_get,
                .setter=led_on_set
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 1"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[0]
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 2"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[1]
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 3"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[2]
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 4"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[3],
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 5"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[4]
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 6"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[5]
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 7"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[6]
            ),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=false, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Relay 8"),
            HOMEKIT_CHARACTERISTIC(
                ON, false,
                .getter_ex=get_relay,
                .setter_ex=set_relay,
                .context=(void*)&relay[7]
            ),
            NULL
        }),
        NULL
    }),
    NULL
};
rottenhowler commented 3 years ago
warning: initialization from incompatible pointer type

I guess you're using wrong function signature for getters and setters.