maximkulkin / esp-homekit-demo

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

Using MQTT with esp-homekit #404

Closed sam632 closed 3 years ago

sam632 commented 3 years ago

Hi, I am trying to combine MQTT with HomeKit to make a pair of friendship lamps, each with 2 LEDs, one controlled by HomeKit (and a button) and the other controlled by the other persons lamp. The MQTT code works on its own but for some reason when I combine with HomeKit it won't work. The phone will not connect to the device and after it tries for a while, the MQTT connection drops. I tried adding a vTaskSuspend to the on_password function but this doesn't seem to get called. Any help would be much appreciated. (I used maqiatto's free MQTT Broker).

#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 <string.h>
#include <paho_mqtt_c/MQTTESP8266.h>
#include <paho_mqtt_c/MQTTClient.h>

#include <semphr.h>

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

#include "wifi.h"

#include "button.h"

#define MQTT_HOST ("maqiatto.com")
#define MQTT_PORT 1883

#define MQTT_USER ("myemail")
#define MQTT_PASS ("mypassword")

SemaphoreHandle_t wifi_alive;
QueueHandle_t publish_queue;
#define PUB_MSG_LEN 2

int led2_state = 0;

// The GPIO pin that is connected to the local LED
const int led1_gpio = 5; //D1
//The GPIO pin that is connected to the externally controlled LED
const int led2_gpio = 4; //D2
//The GPIO pin that is connected to the LED on the button
const int led3_gpio = 14; //D5
// The GPIO pin that is connected to the button on the WEMOS
const int button_gpio = 0; //D3 with internal pullup resistor

// Define callback functions
void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context);
void button_callback(button_event_t event, void* context);
TaskHandle_t MQTTTask;

// Define LED functions
void led1_write(bool on) {
    gpio_write(led1_gpio, on ? 1 : 0);
}
void led2_write(bool on) {
    gpio_write(led2_gpio, on ? 1 : 0);
}
void led3_write(bool on) {
    gpio_write(led3_gpio, on ? 1 : 0);
}

static void  wifi_task(void *pvParameters) {

    uint8_t status  = 0;
    uint8_t retries = 30;
    struct sdk_station_config config = {
        .ssid = WIFI_SSID,
        .password = WIFI_PASSWORD,
    };

    printf("WiFi: connecting to WiFi\n\r");
    sdk_wifi_set_opmode(STATION_MODE);
    sdk_wifi_station_set_config(&config);

    while(1)
    {
        while ((status != STATION_GOT_IP) && (retries)){
            status = sdk_wifi_station_get_connect_status();
            printf("%s: status = %d\n\r", __func__, status );
            if( status == STATION_WRONG_PASSWORD ){
                printf("WiFi: wrong password\n\r");
                break;
            } else if( status == STATION_NO_AP_FOUND ) {
                printf("WiFi: AP not found\n\r");
                break;
            } else if( status == STATION_CONNECT_FAIL ) {
                printf("WiFi: connection failed\r\n");
                break;
            }
            vTaskDelay( 1000 / portTICK_PERIOD_MS );
            --retries;
        }
        if (status == STATION_GOT_IP) {
            printf("WiFi: Connected\n\r");
            xSemaphoreGive( wifi_alive );
            taskYIELD();
        }

        while ((status = sdk_wifi_station_get_connect_status()) == STATION_GOT_IP) {
            xSemaphoreGive( wifi_alive );
            taskYIELD();
        }
        printf("WiFi: disconnected\n\r");
        sdk_wifi_station_disconnect();
        vTaskDelay( 1000 / portTICK_PERIOD_MS );
    }
}

void wifi_init() {
    printf("Starting WiFi task\n");
    xTaskCreate(&wifi_task, "wifi_task",  256, NULL, 2, NULL);
}

// For resetting the wifi
void reset_configuration_task() {
    //Flash the LED first before we start the reset
    for (int i=0; i<3; i++) {
        led3_write(true);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        led3_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 configuration\n");
    xTaskCreate(reset_configuration_task, "Reset configuration", 256, NULL, 2, NULL);
}

// Identifying the lamp with homekit by flashing the small LED
void lamp_identify_task(void *_args) {
    // We identify the lamp by flashing an LED.
    for (int i=0; i<3; i++) {
        for (int j=0; j<2; j++) {
            led3_write(true);
            vTaskDelay(200 / portTICK_PERIOD_MS);
            led3_write(false);
            vTaskDelay(200 / portTICK_PERIOD_MS);
        }
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
    led3_write(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
homekit_characteristic_t switch_on = HOMEKIT_CHARACTERISTIC_(
    ON, false, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(switch_on_callback)
);

// Initialise the GPIO pins for the LEDs
void gpio_init() {
    gpio_enable(led1_gpio, GPIO_OUTPUT);
    led1_write(switch_on.value.bool_value);

    gpio_enable(led2_gpio, GPIO_OUTPUT);
    led2_write(false);

    gpio_enable(led3_gpio, GPIO_OUTPUT);
    led3_write(true);

}

//Controls LED 2 using the MQTT message
static void led2_control(mqtt_message_data_t *md) {

    int i;
    mqtt_message_t *message = md->message;
    int length = message->payloadlen;
    char * payload = message->payload;
    payload[length] = '\0';

    printf("Received: ");
    for( i = 0; i < md->topic->lenstring.len; ++i)
        printf("%c", md->topic->lenstring.data[ i ]);

    printf("\r\n");

//  printf("The payload length is %i\n", length);
    printf("Payload: %s\n", (char *)payload);

    if(strcmp((char *)payload, "1") == 0) {
        // Turn the LED on
        led2_write(true);
        printf("Turn LED 2 on due to MQTT message being 1\n");

    }

      // Check if message is False
    if(strcmp((char *)payload, "0") == 0) {
    // Turn the LED off
        led2_write(false);
        printf("Turn LED 2 off due to MQTT message being 0\n");
    }

}

//To give the ESP a unique client id for MQTT
static const char *  get_my_id(void) {
    // Use MAC address for Station as unique ID
    static char my_id[13];
    static bool my_id_done = false;
    int8_t i;
    uint8_t x;
    if (my_id_done)
        return my_id;
    if (!sdk_wifi_get_macaddr(STATION_IF, (uint8_t *)my_id))
        return NULL;
    for (i = 5; i >= 0; --i)
    {
        x = my_id[i] & 0x0F;
        if (x > 9) x += 7;
        my_id[i * 2 + 1] = x + '0';
        x = my_id[i] >> 4;
        if (x > 9) x += 7;
        my_id[i * 2] = x + '0';
    }
    my_id[12] = '\0';
    my_id_done = true;
    return my_id;
}

//Connects to MQTT and publishes message
static void  mqtt_task(void *pvParameters) {

    int ret         = 0;
    struct mqtt_network network;
    mqtt_client_t client   = mqtt_client_default;
    char mqtt_client_id[20];
    uint8_t mqtt_buf[100];
    uint8_t mqtt_readbuf[100];
    mqtt_packet_connect_data_t data = mqtt_packet_connect_data_initializer;

    mqtt_network_new( &network );
    memset(mqtt_client_id, 0, sizeof(mqtt_client_id));
    strcpy(mqtt_client_id, "ESP-");
    strcat(mqtt_client_id, get_my_id());

    while(1) {
        xSemaphoreTake(wifi_alive, portMAX_DELAY);
        printf("%s: started\n\r", __func__);
        printf("%s: (Re)connecting to MQTT server %s ... ",__func__,
               MQTT_HOST);
        ret = mqtt_network_connect(&network, MQTT_HOST, MQTT_PORT);
        if( ret ){
            printf("error: %d\n\r", ret);
            taskYIELD();
            continue;
        }
        printf("done\n\r");
        mqtt_client_new(&client, &network, 5000, mqtt_buf, 100,
                      mqtt_readbuf, 100);

        data.willFlag       = 0;
        data.MQTTVersion    = 3;
        data.clientID.cstring   = mqtt_client_id;
        data.username.cstring   = MQTT_USER;
        data.password.cstring   = MQTT_PASS;
        data.keepAliveInterval  = 10;
        data.cleansession   = 0;
        printf("Send MQTT connect ... ");
        ret = mqtt_connect(&client, &data);
        if(ret){
            printf("error: %d\n\r", ret);
            mqtt_network_disconnect(&network);
            taskYIELD();
            continue;
        }
        printf("done\r\n");
        mqtt_subscribe(&client, "myemail/lamp21", MQTT_QOS1, led2_control);
        xQueueReset(publish_queue);

        while(1){

            char msg[PUB_MSG_LEN - 1] = "\0";

            while(xQueueReceive(publish_queue, (void *)msg, 0) ==
                  pdTRUE){
                printf("Published to topic lamp1: %s\r\n", msg);
                mqtt_message_t message;
                message.payload = msg;
                message.payloadlen = PUB_MSG_LEN;
                message.dup = 0;
                message.qos = MQTT_QOS1;
                message.retained = 0;
                ret = mqtt_publish(&client, "myemail/lamp1", &message);
                if (ret != MQTT_SUCCESS ){
                    printf("error while publishing message: %d\n", ret );
                    break;
                }
            }

            ret = mqtt_yield(&client, 1000);
            if (ret == MQTT_DISCONNECTED)
                break;
        }
        printf("Connection dropped, request restart\n\r");
        mqtt_network_disconnect(&network);
        taskYIELD();
    }
}

void mqtt_init() {
    printf("Starting MQTT task\n");
    xTaskCreate(&mqtt_task, "mqtt_task", 1024, NULL, 4, &MQTTTask);
}

// Homekits control over LED
void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context) {
    led1_write(switch_on.value.bool_value);
}

// Buttons control over LED and sending MQTT message
void button_callback(button_event_t event, void* context) {

    char msg[PUB_MSG_LEN];

    switch (event) {
        case button_event_single_press:
            printf("Toggling LED 1 due to button press\n");
            switch_on.value.bool_value = !switch_on.value.bool_value;
            led1_write(switch_on.value.bool_value);
            homekit_characteristic_notify(&switch_on, switch_on.value);

            printf("LED 1 state is %i\n", switch_on.value.bool_value); //led1_state is 1 or 0

            snprintf(msg, PUB_MSG_LEN, "%i", switch_on.value.bool_value);
            if (xQueueSend(publish_queue, (void *)msg, 0) == pdFALSE) {
                        printf("Publish queue overflow.\r\n");
                    }

            break;
        case button_event_double_press:
            // read state of led2
            printf("Toggling LED 2 due to button press\n");
            led2_state = gpio_read(led2_gpio);
            printf("LED 2 current state is %i.\n", led2_state); //LED 2 state is 1 or 0
            led2_state = !led2_state;
            printf("Changing LED 2 to state %i.\n", led2_state);
            led2_write(led2_state);

            break;
        case button_event_long_press:
            reset_configuration();
            break;
        default:
            printf("Unknown button event\n");
    }
}

void button_init() {
    button_config_t button_config = BUTTON_CONFIG(
        button_active_low, // This sets gpio_pullup on button pin
        .long_press_time = 5000,
        .max_repeat_presses = 2,
    );

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

}

// Homekit setup
homekit_characteristic_t name = HOMEKIT_CHARACTERISTIC_(NAME, "Friendship Lamp");

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, "SLMPSFL1"),
            HOMEKIT_CHARACTERISTIC(MODEL, "Friendship Lamp"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0.0"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, lamp_identify),
            NULL
        }),
        HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Friendship Lamp"),
            &switch_on,
            NULL
        }),
        NULL
    }),
    NULL
};

void on_password(const char *password) {
    printf("Suspending MQTT Task\n");
    vTaskSuspend(MQTTTask);
}

void on_homekit_event(homekit_event_t event) {
    printf("Resuming MQTT Task\n");
    vTaskResume(MQTTTask);
}

homekit_server_config_t config = {
    .accessories = accessories,
    .password = "137-22-976",
    .setupId="2SA8",
    .password_callback = on_password,
    .on_event = on_homekit_event,
};

// Create different accessory name each time so no clashes
void create_accessory_name() {
    uint8_t macaddr[6];
    sdk_wifi_get_macaddr(STATION_IF, macaddr);

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

    vSemaphoreCreateBinary(wifi_alive);
    publish_queue = xQueueCreate(3, PUB_MSG_LEN);
    wifi_init();

    mqtt_init();
    gpio_init();
    button_init();

    homekit_server_init(&config);

}
lrusnac commented 3 years ago

I did not read your code, but I do use mqtt with my devices, so you can find some examples of using mqtt here https://github.com/lrusnac/esp-homekit-devices hope it is useful

sam632 commented 3 years ago

Thank you very much, I will look at this now :)

peros550 commented 3 years ago

@lrusnac you are the first (to my knowledge) that you have brought together mqtt and esp-homekit. How is stability and performance? Are you getting any sort of "no response" status in your devices?

lrusnac commented 3 years ago

@peros550 I doubt I'm the first, but I have a couple of devices running for 10 months now (based on my examples commits) and it works well so far, haven't noticed any issues.

I even have one esp that is a bridge between mqtt and homekit without any sensors or actuators attached, instead of running homebridge. Pretty stable, and fast.

Although keep in mind I'm sample size of 1 so if you end up using mqtt with esp-homekit, let us know what your experience is!

sam632 commented 3 years ago

Worked a treat, here is my updated code for anyone interested.

#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 <string.h>
#include <paho_mqtt_c/MQTTESP8266.h>
#include <paho_mqtt_c/MQTTClient.h>

#include <semphr.h>

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

#include <wifi_config.h>

#include "button.h"

#define MQTT_HOST ("maqiatto.com")
#define MQTT_PORT 1883
#define MQTT_USER ("username")
#define MQTT_PASS ("password")
#define MQTT_CMND_TOPIC "username/topic" //Controls LED 2
#define MQTT_SEND_TOPIC "username/topic" //Sends MQTT to control other lamp

QueueHandle_t publish_queue;
#define PUB_MSG_LEN 2

int led2_state = 0;

// The GPIO pin that is connected to the local LED
const int led1_gpio = 5; //D1
//The GPIO pin that is connected to the externally controlled LED
const int led2_gpio = 4; //D2
//The GPIO pin that is connected to the LED on the button
const int led3_gpio = 14; //D5
// The GPIO pin that is connected to the button on the WEMOS
const int button_gpio = 0; //D3 with internal pullup resistor

// Define callback functions
void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context);
void button_callback(button_event_t event, void* context);

// Define LED functions
void led1_write(bool on) {
    gpio_write(led1_gpio, on ? 1 : 0);
}
void led2_write(bool on) {
    gpio_write(led2_gpio, on ? 1 : 0);
}
void led3_write(bool on) {
    gpio_write(led3_gpio, on ? 1 : 0);
}

// For resetting the wifi
void reset_configuration_task() {
    //Flash the LED first before we start the reset
    for (int i=0; i<3; i++) {
        led3_write(true);
        vTaskDelay(100 / portTICK_PERIOD_MS);
        led3_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 configuration\n");
    xTaskCreate(reset_configuration_task, "Reset configuration", 256, NULL, 2, NULL);
}

// Identifying the lamp with homekit by flashing the small LED
void lamp_identify_task(void *_args) {
    // We identify the lamp by flashing an LED.
    for (int i=0; i<3; i++) {
        for (int j=0; j<2; j++) {
            led3_write(true);
            vTaskDelay(200 / portTICK_PERIOD_MS);
            led3_write(false);
            vTaskDelay(200 / portTICK_PERIOD_MS);
        }
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
    led3_write(false);
    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
homekit_characteristic_t switch_on = HOMEKIT_CHARACTERISTIC_(
    ON, false, .callback=HOMEKIT_CHARACTERISTIC_CALLBACK(switch_on_callback)
);

// Initialise the GPIO pins for the LEDs
void gpio_init() {
    gpio_enable(led1_gpio, GPIO_OUTPUT);
    led1_write(switch_on.value.bool_value);

    gpio_enable(led2_gpio, GPIO_OUTPUT);
    led2_write(false);

    gpio_enable(led3_gpio, GPIO_OUTPUT);
    led3_write(false);

}

//Controls LED 2 using the MQTT message
static void led2_control(mqtt_message_data_t *md) {

    int i;
    mqtt_message_t *message = md->message;
    int length = message->payloadlen;
    char * payload = message->payload;
    payload[length] = '\0';

    printf("Received: ");
    for( i = 0; i < md->topic->lenstring.len; ++i)
        printf("%c", md->topic->lenstring.data[ i ]);

    printf("\r\n");

//  printf("The payload length is %i\n", length);
    printf("Payload: %s\n", (char *)payload);

    if(strncmp((char *)payload, "1", 1) == 0) {
        // Turn the LED on
        led2_write(true);
        printf("Turn LED 2 on due to MQTT message being 1\n");

    }

      // Check if message is False
    if(strncmp((char *)payload, "0", 1) == 0) {
    // Turn the LED off
        led2_write(false);
        printf("Turn LED 2 off due to MQTT message being 0\n");
    }

}

//To give the ESP a unique client id for MQTT
static const char *  get_my_id(void) {
    // Use MAC address for Station as unique ID
    static char my_id[13];
    static bool my_id_done = false;
    int8_t i;
    uint8_t x;
    if (my_id_done)
        return my_id;
    if (!sdk_wifi_get_macaddr(STATION_IF, (uint8_t *)my_id))
        return NULL;
    for (i = 5; i >= 0; --i)
    {
        x = my_id[i] & 0x0F;
        if (x > 9) x += 7;
        my_id[i * 2 + 1] = x + '0';
        x = my_id[i] >> 4;
        if (x > 9) x += 7;
        my_id[i * 2] = x + '0';
    }
    my_id[12] = '\0';
    my_id_done = true;
    return my_id;
}

//Connects to MQTT and publishes message
static void  mqtt_task(void *pvParameters) {

    int ret         = 0;
    struct mqtt_network network;
    mqtt_client_t client   = mqtt_client_default;
    char mqtt_client_id[20];
    uint8_t mqtt_buf[100];
    uint8_t mqtt_readbuf[100];
    mqtt_packet_connect_data_t data = mqtt_packet_connect_data_initializer;

    mqtt_network_new( &network );
    memset(mqtt_client_id, 0, sizeof(mqtt_client_id));
    strcpy(mqtt_client_id, "ESP-");
    strcat(mqtt_client_id, get_my_id());

    printf("MQTT client ID: %s\r\n", mqtt_client_id);

    data.willFlag = 0;
    data.MQTTVersion = 4;
    data.clientID.cstring = mqtt_client_id;
    data.username.cstring = MQTT_USER;
    data.password.cstring = MQTT_PASS;
    data.keepAliveInterval = 10;
    data.cleansession = 0;

    while(1) {

        printf("%s: Started\n\r", __func__);
        printf("%s: Connecting to MQTT server %s ... ",__func__, MQTT_HOST);
        ret = mqtt_network_connect(&network, MQTT_HOST, MQTT_PORT);
        if( ret ){
            printf("Error: %d\n\r", ret);
            taskYIELD();
            vTaskDelay(100 / portTICK_PERIOD_MS);
            continue;
        }
        printf("Done\n\r");
        mqtt_client_new(&client, &network, 5000, mqtt_buf, 100, mqtt_readbuf, 100);

        printf("Send MQTT connect ... ");
        ret = mqtt_connect(&client, &data);
        if(ret){
            printf("Error: %d\n\r", ret);
            mqtt_network_disconnect(&network);
            taskYIELD();
            continue;
        }
        printf("Done\r\n");
        led3_write(true);

        mqtt_subscribe(&client, MQTT_CMND_TOPIC, MQTT_QOS1, led2_control);
        xQueueReset(publish_queue);

        while(1){

            char msg[PUB_MSG_LEN - 1] = "\0";
            while(xQueueReceive(publish_queue, (void *)msg, 0) == pdTRUE) {
                printf("Published to topic Blue: %s\r\n", msg);
                led3_write(true); \\to check if MQTT is still connected
                mqtt_message_t message;
                message.payload = msg;
                message.payloadlen = PUB_MSG_LEN;
                message.dup = 0;
                message.qos = MQTT_QOS1;
                message.retained = 0;

                ret = mqtt_publish(&client, MQTT_SEND_TOPIC, &message);
                if (ret != MQTT_SUCCESS ){
                    printf("Error while publishing message: %d\n", ret );
                    break;
                }
            }

            ret = mqtt_yield(&client, 1000);
            if (ret == MQTT_DISCONNECTED)
                break;
        }

        printf("Connection dropped, request restart\n\r");
        led3_write(false); //Tells you MQTT has disconnected 
        mqtt_network_disconnect(&network);
        taskYIELD();
    }
}

// Homekits control over LED
void switch_on_callback(homekit_characteristic_t *_ch, homekit_value_t on, void *context) {
    led1_write(switch_on.value.bool_value);

    printf("LED 1 state is %i\n", switch_on.value.bool_value);
    char msg[PUB_MSG_LEN];
    snprintf(msg, PUB_MSG_LEN, "%i", switch_on.value.bool_value);
    if (xQueueSend(publish_queue, (void *)msg, 0) == pdFALSE) {
                printf("Publish queue overflow.\r\n");

    }
}
// Buttons control over LED and sending MQTT message
void button_callback(button_event_t event, void* context) {

    switch (event) {
        case button_event_single_press:
            printf("Toggling LED 1 due to button press\n");
            switch_on.value.bool_value = !switch_on.value.bool_value;
            led1_write(switch_on.value.bool_value);

            homekit_characteristic_notify(&switch_on, switch_on.value); //This will update homekit and the MQTT topic

            break;
        case button_event_double_press:
            // read state of led2
            printf("Toggling LED 2 due to button press\n");
            led2_state = gpio_read(led2_gpio);
            printf("LED 2 current state is %i.\n", led2_state); //LED 2 state is 1 or 0
            led2_state = !led2_state;
            printf("Changing LED 2 to state %i.\n", led2_state);
            led2_write(led2_state);

            break;
        case button_event_long_press:
            reset_configuration();
            break;
        default:
            printf("Unknown button event\n");
    }
}

void button_init() {
    button_config_t button_config = BUTTON_CONFIG(
        button_active_low, // This sets gpio_pullup on button pin
        .long_press_time = 5000,
        .max_repeat_presses = 2,
    );

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

}

// Homekit setup
homekit_characteristic_t name = HOMEKIT_CHARACTERISTIC_(NAME, "Friendship Lamp");

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, "SLMPSFL1"),
            HOMEKIT_CHARACTERISTIC(MODEL, "Friendship Lamp"),
            HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0.0"),
            HOMEKIT_CHARACTERISTIC(IDENTIFY, lamp_identify),
            NULL
        }),
        HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){
            HOMEKIT_CHARACTERISTIC(NAME, "Friendship Lamp"),
            &switch_on,
            NULL
        }),
        NULL
    }),
    NULL
};

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

void on_wifi_ready() {
    homekit_server_init(&config);
    xTaskCreate(&mqtt_task, "mqtt_task", 1024, NULL, 4, NULL);
}

// Create different accessory name each time so no clashes
void create_accessory_name() {
    uint8_t macaddr[6];
    sdk_wifi_get_macaddr(STATION_IF, macaddr);

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

    publish_queue = xQueueCreate(3, PUB_MSG_LEN);
    wifi_config_init("Friendship Lamps -", NULL, on_wifi_ready);

    gpio_init();
    button_init();

}