maximkulkin / esp-homekit-demo

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

Multiple Accessories with Separate Controls #320

Closed kalindud closed 4 years ago

kalindud commented 4 years ago

Hi, Is it possible to use the same ESP to control multiple Accessories? for example, There are Two Buttons that can control Two separate Lights, and Siri Would be able to Control them separately.

Help? Thanks

maximkulkin commented 4 years ago

Yes, you can do it. E.g. check out sonoff_dual_lights - two lights controlled by two relays. You can use Siri to control them individually. This example uses a single switch to alter modes (none, first light, second light, both - modeled after my lamp's 4 position switch, but you can add another toggle/button handling and change existing logic to make each toggle/button control it's own light.

kalindud commented 4 years ago

Ok..... so I modified the original sonoff basic toggle code. Am i doing it right?

#include <stdio.h>
#include <espressif/esp_wifi.h>
#include <espressif/esp_sta.h>
#include <espressif/esp_common.h>
#include <esp/uart.h>
#include <esp8266.h>
#include <FreeRTOS.h>
#include <task.h>

#include <homekit/homekit.h>
#include <homekit/characteristics.h>
#include <wifi_config.h>

#include "button.h"

// The GPIO pin that is connected to the relay on the Sonoff Basic.
const int relay_gpio = 4;
// The GPIO pin that is connected to the LED on the Sonoff Basic.
const int led_gpio = 14;
// The GPIO pin that is connected to the button on the Sonoff Basic.
const int button_gpio = 5;

// NEW
#include "toggle.h"
// The GPIO pin that is connected to the header on the Sonoff Basic (external switch).
const int toggle_gpio = 2;
void toggle_callback(uint8_t gpio);
//

void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context);
void switch_2on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context);
void button_callback(uint8_t gpio, button_event_t event);

void relay_write(bool on) {
    gpio_write(relay_gpio, on ? 1 : 0);
    gpio_write(led_gpio, on ? 1 : 0);
}

void relay_2write(bool on) {
    gpio_write(relay_gpio, on ? 1 : 0);
    gpio_write(led_gpio, on ? 1 : 0);
}

void led_write(bool on) {
    gpio_write(led_gpio, on ? 0 : 1);
}

void reset_configuration_task() {
    //Flash the LED first before we start the reset
    for (int i=0; i<3; i++) {
        led_write(true);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        led_write(false);
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
    printf("Resetting Wifi Config\n");
    wifi_config_reset();
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    printf("Resetting HomeKit Config\n");
    homekit_server_reset();
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    printf("Restarting\n");
    sdk_system_restart();
    vTaskDelete(NULL);
}

void reset_configuration() {
    printf("Resetting Sonoff configuration\n");
    xTaskCreate(reset_configuration_task, "Reset configuration", 256, NULL, 2, NULL);
}

homekit_characteristic_t switch_on = HOMEKIT_CHARACTERISTIC_(
    ON, false, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(switch_on_callback)
);

homekit_characteristic_t switch_2on = HOMEKIT_CHARACTERISTIC_(
    ON, false, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(switch_2on_callback)
);

void gpio_init() {
    gpio_enable(led_gpio, GPIO_OUTPUT);
    led_write(false);
    gpio_enable(relay_gpio, GPIO_OUTPUT);
    relay_write(switch_on.value.bool_value);
    // NEW
    gpio_enable(toggle_gpio, GPIO_INPUT);
    //
}

void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context) {
    relay_write(switch_on.value.bool_value);
}

void switch_2on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context) {
    relay_write(switch_2on.value.bool_value);
}

void button_callback(uint8_t gpio, button_event_t event) {
    switch (event) {
        case button_event_single_press:
            printf("Toggling relay due to button at GPIO %2d\n", gpio);
            switch_on.value.bool_value = !switch_on.value.bool_value;
            relay_write(switch_on.value.bool_value);
            homekit_characteristic_notify(&switch_on, switch_on.value);
            break;
        case button_event_long_press:
            reset_configuration();
            break;
        default:
            printf("Unknown button event: %d\n", event);
    }
}

// NEW
void toggle_callback(uint8_t gpio) {
            printf("Toggling relay due to switch at GPIO %2d\n", gpio);
            switch_on.value.bool_value = !switch_on.value.bool_value;
            relay_write(switch_on.value.bool_value);
            homekit_characteristic_notify(&switch_on, switch_on.value);
}
//

void switch_identify_task(void *_args) {
    // We identify the Sonoff by Flashing it's LED.
    for (int i=0; i<3; i++) {
        for (int j=0; j<2; j++) {
            led_write(true);
            vTaskDelay(200 / portTICK_PERIOD_MS);
            led_write(false);
            vTaskDelay(200 / portTICK_PERIOD_MS);
        }
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
    led_write(false);
    vTaskDelete(NULL);
}

void switch_identify(homekit_value_t _value) {
    printf("Switch identify\n");
    xTaskCreate(switch_identify_task, "Switch identify", 128, NULL, 2, NULL);
}

homekit_characteristic_t name = HOMEKIT_CHARACTERISTIC_(NAME, "Sonoff Switch");

homekit_accessory_t *accessories[] = {
    HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_shower_head, .services=(homekit_service_t*[]){
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]){
            &name,
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "HaPK"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "1"),
            HOMEKIT_CHARACTERISTIC(MODEL, "Basic"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, switch_identify),
            NULL
        }),
        HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, Switch one"),
            &switch_on,
            NULL
        }),

        HOMEKIT_SERVICE(SWITCH, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, Switch two
            &switch_2on,
            NULL
    }),
    NULL

    }),
    NULL
};

homekit_server_config_t config = {
    .accessories = accessories,
    .password = "190-11-978"    //changed tobe valid
//    .password = "111-11-111"    //default easy
};

void on_wifi_ready() {
    homekit_server_init(&config);
}

void create_accessory_name() {
    uint8_t macaddr[6];
    sdk_wifi_get_macaddr(STATION_IF, macaddr);

    int name_len = snprintf(NULL, 0, "Switches %02X:%02X:%02X",
            macaddr[3], macaddr[4], macaddr[5]);
    char *name_value = malloc(name_len+1);
    snprintf(name_value, name_len+1, "Switches %02X:%02X:%02X",
            macaddr[3], macaddr[4], macaddr[5]);

    name.value = HOMEKIT_STRING(name_value);
}

void user_init(void) {
    uart_set_baud(0, 115200);
    create_accessory_name();
    wifi_config_init("Sonoff Basic", NULL, on_wifi_ready);
    gpio_init();

    if (button_create(button_gpio, 0, 4000, button_callback)) {
        printf("Failed to initialize button\n");
    }

    if (toggle_create(toggle_gpio, toggle_callback)) {
        printf("Failed to initialize toggle\n");
    }

}
maximkulkin commented 4 years ago

@kalindud yes, you can do it like that. Although since you're dealing with toggle, you might want to match relay state with toggle state. So in your toggle_callback instead of flipping state of your switch, read actual state of a toggle by doing gpio_read(toggle_gpio) to get it's current state.