maximkulkin / esp-homekit-demo

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

Sonoff Toggle Switch #304

Closed sam632 closed 4 years ago

sam632 commented 4 years ago

Hi, I am quite new to this but have managed to flash a few Wemos D1 Minis with the LED code and the Sonoff Basic code. Now I want to add a toggle switch to my Wemos + Relay Shield but when I upload the code, the button doesn't appear to work. I changed the code slightly as I wanted it to connect to my wifi automatically, using the wifi.h but I'm not 100% sure I changed it right. It connects to the app and I can control the relay but the toggle button doesn't work. I have a momentary push button across GPIO 14 (D5) and GND but it does nothing. I have pasted my code below. Any help would be greatly appreciated.

include

include <espressif/esp_wifi.h>

include <espressif/esp_sta.h>

include <espressif/esp_common.h>

include <esp/uart.h>

include

include

include

include <homekit/homekit.h>

include <homekit/characteristics.h>

include "wifi.h"

include "button.h"

static void wifi_init() { struct sdk_station_config wifi_config = { .ssid = WIFI_SSID, .password = WIFI_PASSWORD, };

sdk_wifi_set_opmode(STATION_MODE);
sdk_wifi_station_set_config(&wifi_config);
sdk_wifi_station_connect();

}

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

include "toggle.h"

// The GPIO pin that is connected to the header on the Sonoff Basic (external switch). const int toggle_gpio = 14; void toggle_callback(uint8_t gpio);

void switch_on_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); }

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); }

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 = HOMEKITCHARACTERISTIC( ON, false, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(switch_on_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 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 = HOMEKITCHARACTERISTIC(NAME, "Sonoff Switch");

homekit_accessory_t accessories[] = { HOMEKIT_ACCESSORY(.id=1, .category=homekit_accessory_category_switch, .services=(homekit_service_t[]){ HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t[]){ &name, HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Sam"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "mps"), HOMEKIT_CHARACTERISTIC(MODEL, "Sonoff Basic"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1.6"), HOMEKIT_CHARACTERISTIC(IDENTIFY, switch_identify), NULL }), HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t[]){ HOMEKIT_CHARACTERISTIC(NAME, "Sonoff Basic"), &switch_on, NULL }), NULL }), NULL };

homekit_server_config_t config = { .accessories = accessories, .password = "111-11-111" //default easy };

void user_init(void) { uart_set_baud(0, 115200);

wifi_init();
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

That button code assumes "active high" configuration (where button is usually pulled to ground with a resistor and connects GPIO with VCC.

active-high-wiring

You need to either change button code or replace it with esp-button library which can handle both setups.

sam632 commented 4 years ago

Thank you for the reply. I am still slightly confused. I replaced the code in son off_basic_toggle>toggle.c and toggle.h with the code from eps-button library and then used the toggle example in the README file to change the code in main.c but this still does not work. I think I have misunderstood you when you said replace with eps-button library. I understand you don't want to have to write it out for me, and I find learning by trying the best way but any more help would be much appreciated. Thanks

maximkulkin commented 4 years ago

I meant "delete button. and toggle., add esp-button as dependency and rewrite code to use esp-button's APIs"

sam632 commented 4 years ago

I did this (I think) and the buttons now work. Grounding GPIO 4 (button) turns the relay on/off permanently, to use with a momentary button and GPIO 14 (toggle) can be used with a normal switch but ihome does not find the device anymore. I didn't change any of the wifi or HomeKit code so I'm not sure what has happened. Here is my code below. Thank you for your help.


#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.h"

#include "button.h"

static void wifi_init() {
    struct sdk_station_config wifi_config = {
        .ssid = WIFI_SSID,
        .password = WIFI_PASSWORD,
    };

    sdk_wifi_set_opmode(STATION_MODE);
    sdk_wifi_station_set_config(&wifi_config);
    sdk_wifi_station_connect();
}

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

#include "toggle.h"
// The GPIO pin that is connected to the header on the Sonoff Basic (external switch).
const int toggle_pin = 14;
void toggle_callback(bool high, void *context);

void switch_on_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);
}

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);
    }

    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)
);

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_pin, GPIO_INPUT);
    //
}

void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context) {
    relay_write(switch_on.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(bool high, void *context) {
    printf("toggle is %s\n", high ? "high" : "low");
    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_switch, .services=(homekit_service_t*[]){
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]){
            &name,
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Sam"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "mps"),
            HOMEKIT_CHARACTERISTIC(MODEL, "Sonoff Basic"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1.6"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, switch_identify),
            NULL
        }),
        HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Sonoff Basic"),
            &switch_on,
            NULL
        }),
        NULL
    }),
    NULL
};

homekit_server_config_t config = {
    .accessories = accessories,
    .password = "111-11-111"    //default easy
};

void user_init(void) {
    uart_set_baud(0, 115200);

    wifi_init();
    gpio_init();

    button_config_t button_config = BUTTON_CONFIG(
        button_active_low,
        .long_press_time = 1000,
        .max_repeat_presses = 1,
    );

    int r = button_create(button_pin, button_config, button_callback, NULL);
    if (r) {
    printf("Failed to initialize a button\n");
    }

    int s = toggle_create(toggle_pin, toggle_callback, NULL);
    if (s) {
        printf("Failed to initialize a toggle\n");
    }

}
maximkulkin commented 4 years ago

First, you need to change gpio_init and instead of enabling INPUT mode for toggle_pin, you need to enable pull up for it:

gpio_set_pullup(toggle_pin, true, true);

Second, you need to fix your button callback signature, it's broken.

alangoveia commented 4 years ago

hi, @maximkulkin Do you use any RC Debounce circuit in your projects? When I am using a breadboard to test the circuit, it works fine. But when I solder the components in a perfboard, the push button doesn't do so good. I looked online and am trying a RC debounce circuit but no success :// Thanks in advance

maximkulkin commented 4 years ago

I have implemented a library that handles push buttons and toggle switches - button

alangoveia commented 4 years ago

oh. unfortunately that's beyond my current capabilities :/

in the current code of sonoff_basic, the button configuration is set to "active low", where the GPIO connects to GND. Can you please tell me how to change to "active high"? I think that might help me. Sorry for the trouble. And thanks again

sam632 commented 4 years ago

I got this working using what you said and implemented it in a light switch. I just noticed in toggle.c gpio_set_pullup is commented out with // but I already uploaded the code with it in and it worked. Why is this?

maximkulkin commented 4 years ago

Toggle does not know which configuration (active high/active low) you have, it just reacts to changes in level. Pulling pin high unconditionally would make active high configuration unusable. That's why it is your responsibility to set up proper pin configuration (either putting a pull down resistor on your schematic for active high configuration, or enabling internal pull-up resistor programmatically for active low configuration).

alangoveia commented 4 years ago

@sam632 can you, please, share your code? thanks in advance

sam632 commented 4 years ago

Hi sorry this took so long. I believe I used this code with the Wemos D1 Mini with relay shield.

/*
 * Example of using esp-homekit library to control
 * a simple $5 Sonoff Basic using HomeKit.
 * The esp-wifi-config library is also used in this
 * example. This means you don't have to specify
 * your network's SSID and password before building.
 *
 * In order to flash the sonoff basic you will have to
 * have a 3,3v (logic level) FTDI adapter.
 *
 * To flash this example connect 3,3v, TX, RX, GND
 * in this order, beginning in the (square) pin header
 * next to the button.
 * Next hold down the button and connect the FTDI adapter
 * to your computer. The sonoff is now in flash mode and
 * you can flash the custom firmware.
 *
 * WARNING: Do not connect the sonoff to AC while it's
 * connected to the FTDI adapter! This may fry your
 * computer and sonoff.
 *
 updated SSID to use full MAC address
 updated HomeKit name to end in last 3 bytes of MAC Address
 updated HomeKit passcode to valid value
 updated HomeKit identify pulses to be heartbeat timing
 added toggle switch via toggle.c based on button.c
 enabled GPIO14 as input and use as toggle
 */

#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.h"

#include "button.h"

static void wifi_init() {
    struct sdk_station_config wifi_config = {
        .ssid = WIFI_SSID,
        .password = WIFI_PASSWORD,
    };

    sdk_wifi_set_opmode(STATION_MODE);
    sdk_wifi_station_set_config(&wifi_config);
    sdk_wifi_station_connect();
}

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

#include "toggle.h"
// The GPIO pin that is connected to the header on the Sonoff Basic (external switch).
const int toggle_pin = 14;
void toggle_callback(bool high, void *context);

void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context);

void relay_write(bool on) {
    gpio_write(relay_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 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)
);

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_set_pullup(toggle_pin, true, true);
    //
}

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

// NEW
void toggle_callback(bool high, void *context) {
    printf("toggle is %s\n", high ? "high" : "low");
            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_switch, .services=(homekit_service_t*[]){
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]){
            &name,
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Sam"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "mps"),
            HOMEKIT_CHARACTERISTIC(MODEL, "Sonoff Basic"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1.6"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, switch_identify),
            NULL
        }),
        HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Sonoff Basic"),
            &switch_on,
            NULL
        }),
        NULL
    }),
    NULL
};

homekit_server_config_t config = {
    .accessories = accessories,
    .password = "111-11-111"    //default easy
};

void user_init(void) {
    uart_set_baud(0, 115200);

    wifi_init();
    gpio_init();
    homekit_server_init(&config);

    int r = toggle_create(toggle_pin, toggle_callback, NULL);
    if (r) {
        printf("Failed to initialize a toggle\n");
    }

}