maximkulkin / esp-homekit-demo

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

WiFi config after Power Failure? #323

Closed kalindud closed 4 years ago

kalindud commented 4 years ago

Hi.. So i created a device with the Sonoff_basic_toggle. it has the WiFi config mode when WiFi is not available i guess? so if there is a power failure and the router turns off, would the homekit device try to reconnect to the same WiFi network or will it go into the WiFi config mode and create its own hotspot?

This happens to me, and every time i have to add the device as a new device in the home app.

hope any1 can help... thank you

shaurya0406 commented 4 years ago

Hi if you have not removed the mains switch then you can just turn off and then turn on your sonoff after some time or when you are able to access the internet. What happens with some routers is that they start broadcasting their SSID and esp connects to it but as there is no internet connection established yet, esp is unable to communicate with HomeKit and hence it shows device is not responding.you can even try pressing the toggle button on the Sonoff, as it will update the HomeKit characteristic and then it will start working. Else just switch of your son off and switch it on after you can access the internet on your mobile device. A permanent solution is to continuously reset the esp until you are able to communicate with HomeKit, but that will require changes in the wifi-config libraries. Hope it helps.

shaurya0406 commented 4 years ago

You can also create a watchdog timer like this..

#define NO_CONNECTION_WATCHDOG_TIMEOUT 600000  //change it according to your need.
 bool wifi_connected = false;
void wifi_connection_watchdog_task(void *_args) {
    vTaskDelay(NO_CONNECTION_WATCHDOG_TIMEOUT / portTICK_PERIOD_MS);

    if (! wifi_connected) {
       for (int i=0; i<3; i++) {
        led_write(true);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        led_write(false);
        vTaskDelay(100 / portTICK_PERIOD_MS);
       }
        printf("No Wifi Connection, Restarting\n");
        sdk_system_restart();
    } 
    vTaskDelete(NULL);
}
void create_wifi_connection_watchdog() {
    printf("Wifi connection watchdog\n");
    xTaskCreate(wifi_connection_watchdog_task, "Wifi Connection Watchdog", 128, NULL, 3, NULL);
}

And change your on_wifi_ready() function...

void on_wifi_ready() {
    wifi_connected= true;
    homekit_server_init(&config);
}

and change this function also...

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

    create_wifi_connection_watchdog();
}

I have not tested this because I use esp32 devices. Hope it solves the problem.

kalindud commented 4 years ago

Hi Shaurya, Thank you so much for the reply and solution. I will test it out.

I have another question.... When it creates the HotSpot for the WiFi Config when its unable to connect , doesn't it keep trying to reconnect to the saved WiFi SSID?

Thanks

maximkulkin commented 4 years ago

@kalindud Yes, when wifi-config can not connect to WiFi network you have configured, it goes into AP+Station mode: it creates it's own network so you can connect and reconfigure it while still trying to connect to configured WiFi network. If it connects, then it will automatically shut down it's own WiFi and proceed working as usual. Be advised that it makes sense to password protect your wifi-config network, so in case of power failure other people won't be able to access and reconfigure it. It's this NULL people always put

wifi_config_init("Sonoff Basic", NULL, on_wifi_ready);
                                 ^^^^ password goes here
kalindud commented 4 years ago

@maximkulkin Thank you for the reply!

I have 2 homekit devices that Resets after a couple of hours (or mins. its random) It then goes to the AP mode and create its own network. It doesn't happen when the power fails or router fails. It automatically Resets. AND it does not reconnect to the WiFi. It keeps its AP on. But when I turn off the device and Restart, it connects back to the WiFi network... Any Idea why its causing this?

This is my Code :

#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"
#include "toggle.h"
//#include "wifi.h"

// The GPIO pin that is connected to the relay on the Sonoff Dual R2
const int relay0_gpio = 16;
const int relay1_gpio = 5;
// The GPIO pin that is connected to the LED on the Sonoff Dual R2
const int led_gpio = 14;
// The GPIO pin that is connected to the button on the Sonoff Dual R2
const int button_gpio = 2;
const int button_gpio2 = 4;

void button_callback(uint8_t gpio, button_event_t event);

void relay_write(int relay, bool on) {
    gpio_write(relay, 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);
}

int lamp_state = 3;

void top_light_on_set(homekit_value_t value);
void bottom_light_on_set(homekit_value_t value);

homekit_characteristic_t top_light_on = HOMEKIT_CHARACTERISTIC_(
    ON, false,
    .setter=top_light_on_set,
);
homekit_characteristic_t bottom_light_on = HOMEKIT_CHARACTERISTIC_(
    ON, false,
    .setter=bottom_light_on_set,
);

void top_light_on_set(homekit_value_t value) {
    top_light_on.value = value;
    relay_write(relay0_gpio, top_light_on.value.bool_value);

}

void bottom_light_on_set(homekit_value_t value) {
    bottom_light_on.value = value;
    relay_write(relay1_gpio, bottom_light_on.value.bool_value);

}

void gpio_init() {
    gpio_enable(led_gpio, GPIO_OUTPUT);
    led_write(false);

    gpio_enable(relay0_gpio, GPIO_OUTPUT);
    gpio_enable(relay1_gpio, GPIO_OUTPUT);
    relay_write(relay0_gpio, true);
    relay_write(relay1_gpio, true);
}

void toggle_callback(uint8_t gpio) {
  //  lamp_state_set(lamp_state+1);            
    top_light_on.value.bool_value = !top_light_on.value.bool_value;
    relay_write(relay0_gpio, top_light_on.value.bool_value);
    homekit_characteristic_notify(&top_light_on, top_light_on.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);
             bottom_light_on.value.bool_value = !bottom_light_on.value.bool_value;
            relay_write(relay1_gpio, bottom_light_on.value.bool_value);
            homekit_characteristic_notify(&bottom_light_on, bottom_light_on.value);
            break;
        case button_event_long_press:
            reset_configuration();
            break;
        default:
            printf("Unknown button event: %d\n", event);
    }
}

void lamp_identify_task(void *_args) {
    // We identify the Sonoff by turning top light on
    // and flashing with bottom light
    relay_write(relay0_gpio, true);

    for (int i=0; i<3; i++) {
        for (int j=0; j<2; j++) {
            relay_write(relay1_gpio, true);
            vTaskDelay(100 / portTICK_PERIOD_MS);
            relay_write(relay1_gpio, false);
            vTaskDelay(100 / portTICK_PERIOD_MS);
        }

        vTaskDelay(250 / portTICK_PERIOD_MS);
    }

    relay_write(relay1_gpio, true);

    vTaskDelete(NULL);
}

void lamp_identify(homekit_value_t _value) {
    printf("Lamp identify\n");
    xTaskCreate(lamp_identify_task, "Lamp identify", 128, NULL, 2, NULL);
}

homekit_characteristic_t name = HOMEKIT_CHARACTERISTIC_(NAME, "Dual Lights");

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*[]){
            &name,
            HOMEKIT_CHARACTERISTIC(MANUFACTURER, "HaPK"),
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "0"),
            HOMEKIT_CHARACTERISTIC(MODEL, "Dual Lamps"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, lamp_identify),
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Left Light"),
            &top_light_on,
            NULL
        }),
        HOMEKIT_SERVICE(LIGHTBULB, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Right Light"),
            &bottom_light_on,
            NULL
        }),
        NULL
    }),
    NULL
};

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

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, "Dual Lights-%02X%02X%02X",
                            macaddr[3], macaddr[4], macaddr[5]);
    char *name_value = malloc(name_len+1);
    snprintf(name_value, name_len+1, "Dual Lights-%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();

    gpio_init();

    wifi_config_init("Dual Lights", NULL, on_wifi_ready);
    //wifi_init();
    //on_wifi_ready();

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

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

}
maximkulkin commented 4 years ago

@kalindud what's your wiring diagram?

kalindud commented 4 years ago

@maximkulkin cct

shaurya0406 commented 4 years ago

@kalindud

@maximkulkin would know better But initially I also had the same issues. So, do you face this issue when esp is powered through USB, without any load appliance connected. If yes, then what's the reset reason displayed on the Serial Monitor?

Give a try to the code changes. It resolved all my issues.

kalindud commented 4 years ago

Hi @shaurya0406 ...

No. it works fine on USB. It only happens when a load is connected... what changes did u make to fix it?

shaurya0406 commented 4 years ago

The ones I have mentioned above in the code.

maximkulkin commented 4 years ago

I think what's happening is button picking up AC interference and triggering long press, thus resetting all data. You should try using esp-button instead, it has different design that is resilient to interference.

shaurya0406 commented 4 years ago

If that's the case then.... Connect one pin of the push button to the ground and the other one directly to the GPIO pin.(No resistor) I know its a very primitive method and wrong also for interrupt to work. But we can try this.

kalindud commented 4 years ago

Hi.. been a while. Somehow this issue was fixed when I used a Pull-Up Resistor Instead of the Pull-down resistor i previously used... (And changed the code to accept the button as pull-up)

Thank you everyone for the support!!!