maximkulkin / esp-homekit-demo

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

No response on a multi sensor example #204

Closed sakisdog closed 5 years ago

sakisdog commented 5 years ago

Hello maxim, I have built a multi sensor example on a NodeMCU but i'm getting no response after running for some hours. I use the identify function to blink the onboard LED when motion is detected. If i comment out the identify function in the motion sensor callback then it is running for days. If i enable it the i get no response. Would you mind to take a look in the code and tell my what i am doing wrong? Maybe i should use a bigger stack size for the task? Also is it necessary to use gpio_set_pullup command to init the sensors? I think it should be used only if you want to set the pullup resistor high using the true parameter. Otherwise it is unnecessary.

Lastly i would like to note that your work is amazing! You have done an excellent job maintaining this project. Thank you and keep up!

#define DEVICE_MANUFACTURER "Unknown"
#define DEVICE_NAME "MultiSensor"
#define DEVICE_MODEL "esp8266"
#define DEVICE_SERIAL "12345678"
#define FW_VERSION "1.0"
#define MOTION_SENSOR_GPIO 4
#define LED_GPIO 2
#define BUTTON_GPIO 0
#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 <queue.h>
#include <string.h>

#include <homekit/homekit.h>
#include <homekit/characteristics.h>
#include <wifi_config.h>
#include <dht/dht.h>
#include "button.h"

homekit_characteristic_t name             = HOMEKIT_CHARACTERISTIC_(NAME, DEVICE_NAME);
homekit_characteristic_t manufacturer     = HOMEKIT_CHARACTERISTIC_(MANUFACTURER,  DEVICE_MANUFACTURER);
homekit_characteristic_t serial           = HOMEKIT_CHARACTERISTIC_(SERIAL_NUMBER, DEVICE_SERIAL);
homekit_characteristic_t model            = HOMEKIT_CHARACTERISTIC_(MODEL,         DEVICE_MODEL);
homekit_characteristic_t revision         = HOMEKIT_CHARACTERISTIC_(FIRMWARE_REVISION,  FW_VERSION);
homekit_characteristic_t motion_detected  = HOMEKIT_CHARACTERISTIC_(MOTION_DETECTED, 0);
homekit_characteristic_t temperature = HOMEKIT_CHARACTERISTIC_(CURRENT_TEMPERATURE, 0);
homekit_characteristic_t humidity    = HOMEKIT_CHARACTERISTIC_(CURRENT_RELATIVE_HUMIDITY, 0);

#ifndef SENSOR_PIN
#error SENSOR_PIN is not specified
#endif
void button_callback(uint8_t gpio, button_event_t event);
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 multisensor configuration\n");
    xTaskCreate(reset_configuration_task, "Reset configuration", 256, NULL, 2, NULL);
}
void button_callback(uint8_t gpio, button_event_t event) {
    switch (event) {
        case button_event_long_press:
            reset_configuration();
            break;
        default:
            printf("Unknown button event: %d\n", event);
    }
}
void led_write(bool on) {
    gpio_write(LED_GPIO, on ? 0 : 1);
}

void identify_task(void *_args) {
    // We identify the board by Flashing it's LED.
    for (int i=0; i<1; i++) {
        for (int j=0; j<2; j++) {
            led_write(true);
            vTaskDelay(100 / portTICK_PERIOD_MS);
            led_write(false);
            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
        vTaskDelay(300 / portTICK_PERIOD_MS);
    }
    led_write(false);
    vTaskDelete(NULL);
}

void identify() {
    xTaskCreate(identify_task, "identify", 256, NULL, 2, NULL);
}
void temperature_sensor_identify(homekit_value_t _value) {
    printf("Temperature sensor identify\n");
}

void temperature_sensor_task(void *_args) {

    float humidity_value, temperature_value;
    while (1) {
        bool success = dht_read_float_data(
            DHT_TYPE_DHT22, SENSOR_PIN,
            &humidity_value, &temperature_value
        );
        if (success) {
            temperature.value.float_value = temperature_value;
            humidity.value.float_value = humidity_value;

            homekit_characteristic_notify(&temperature, HOMEKIT_FLOAT(temperature_value));
            homekit_characteristic_notify(&humidity, HOMEKIT_FLOAT(humidity_value));
        } else {
            printf("Couldnt read data from sensor\n");
        }

        vTaskDelay(6000 / portTICK_PERIOD_MS);
    }
}
void temperature_sensor_init() {
    xTaskCreate(temperature_sensor_task, "Temperature Sensor", 256, NULL, 2, NULL);
}

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,
            &manufacturer,
            &serial,
            &model,
            &revision,
            HOMEKIT_CHARACTERISTIC(IDENTIFY, identify),
            NULL
        }),
        HOMEKIT_SERVICE(MOTION_SENSOR, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Motion Sensor"),
            &motion_detected,
            NULL
        }),
        NULL
    }),
    HOMEKIT_ACCESSORY(.id=2, .category=homekit_accessory_category_thermostat, .services=(homekit_service_t*[]) {
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) {
            &name,
            &manufacturer,
            HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "0012345"),
            &model,
            &revision,
            HOMEKIT_CHARACTERISTIC(IDENTIFY, temperature_sensor_identify),
            NULL
        }),
        HOMEKIT_SERVICE(TEMPERATURE_SENSOR, .primary=true, .characteristics=(homekit_characteristic_t*[]) {
            HOMEKIT_CHARACTERISTIC(NAME, "Temperature Sensor"),
            &temperature,
            NULL
        }),
        HOMEKIT_SERVICE(HUMIDITY_SENSOR, .characteristics=(homekit_characteristic_t*[]) {
            HOMEKIT_CHARACTERISTIC(NAME, "Humidity Sensor"),
            &humidity,
            NULL
        }),
        NULL
    }),
    NULL
};

void motion_sensor_callback(uint8_t gpio) {
    if (gpio == MOTION_SENSOR_GPIO){
        int new = 0;
        new = gpio_read(MOTION_SENSOR_GPIO);
        if (new) {
            printf("Motion detected\n");
            identify();
        }
        motion_detected.value = HOMEKIT_BOOL(new);
        homekit_characteristic_notify(&motion_detected, HOMEKIT_BOOL(new));
    }
    else {
        printf("Interrupt on %d", gpio);
    }
}

void gpio_init() {
    gpio_enable(LED_GPIO, GPIO_OUTPUT);
    gpio_enable(MOTION_SENSOR_GPIO, GPIO_INPUT);
    //gpio_set_pullup(SENSOR_PIN, false, false);
    //gpio_set_pullup(MOTION_SENSOR_GPIO, false, false);
    gpio_set_interrupt(MOTION_SENSOR_GPIO, GPIO_INTTYPE_EDGE_ANY, motion_sensor_callback);
}

homekit_server_config_t config = {
    .accessories = accessories,
    .password = "111-11-111"
};
void on_wifi_ready() {
    homekit_server_init(&config);
    gpio_init();
    temperature_sensor_init();
}
void user_init(void) {
    uart_set_baud(0, 115200);
    wifi_config_init("motion-sensor", NULL, on_wifi_ready);
    if (button_create(BUTTON_GPIO, 0, 4000, button_callback)) {
        printf("Failed to initialize button\n");
    }
}
maximkulkin commented 5 years ago

Your identify() function has incorrect signature (no argument).

Also I that you reuse same characteristics in multiple places which is not allowed. Every characteristic should have it’s own unique ID within accessory. To simplify things, users of esp-homekit are not required to set those IDs manually and they are assigned automatically. However, if you reuse characteristics (or services) across different accessories, that might mess up IDs and lead to undesirable side effects.

My suggestion: rewrite code to use each characteristic only once.

sakisdog commented 5 years ago

Thank you for your reply. I moved the gpio_init() and temperature_sensor_init() at the end of user_init function and now it seems to work fine (2 days uptime). Another "extra" step i did was to erase_flash 3 times instead of 1 before flashing the new firmware. I don't know if this helped or not but either way thank you for your help and your time.

AR-Tawil commented 2 years ago

Hi Maximkulkin, sorry to open this again. But I'm testing the motion sensor code at my home and noticed that if there are several people moving around the motion sensor it becomes unresponsive. Is there a way to make the sensor delay for a couple of seconds before its next activation? Thank you for your help