For those who follow my blog know that I have been working with ESP HomeKit for a while. To make new accessories I have to regularly re-flash my ESP modules. Especially when debugging the code, it often happens that I have to re-flash the firmware again. But here lies some troubles, When you didn’t removed the device when it was online you cant add it again and you have to Reset your HomeKit Device.
Reset Homekit Device
When device knows it was removed from HomeKit (that means that device was online and accessible from Home.app when it was removed), then there is no problem of reconnecting it back, since when Home.app removes accessory, it connects to it and sends command to remove pairing. When last admin pairing is removed, accessory switches back to discovery and pairing mode.
If you removed the accessory offline, then you need to factory reset your accessory. Various accessories have different ways to do that. E.g. with Sonoff Basic users usually implement reset on long button press. Some light bulbs (e.g. LIFX) require you to turn it on and off for 1 second 5 times in a row. So certified hardware also has this reset problem if you do it offline. My suggestion: just don’t unpair offline or be prepared to do factory reset/flash erase.
Button Library
At first you need to download two files so called libraries ( Button.c and Button.h ) We need to call the libraries in our main code later. Open the Terminal app. Click the Finder icon in your dock. Click Go. Click Utilities. Double-click Terminal.
Make a new folder called e.g reset. Where Your_Username is you Mac Username, Run this command:
mkdir /Users/Your_Username/reset
Change into the directory by typing:
cd reset
Now you can download the two files below within this directory
File name: Button.c
Version: 1.4.2
File name: Button.h
Version: 1.4.2
The Code
Now that we have downloaded the perquisite library’s we can make our new main.c file. You can use Apple Xcode or in my case Atom to code.
Atom
Atom is a free and open-source text and source code editor for macOS, Linux, and Microsoft Windows with support for plug-ins written in Node.js, and embedded Git Control, developed by GitHub. Atom is a desktop application built using web technologies. Most of the extending packages have free software licenses and are community-built and maintained. You can download your free copy here.
At firts we need to include the downloaded button library by adding this line:
#include "button.h"
Then we place after the last #define
line this part of code. On the second line you see the definition of the GPIO pin on your ESP. As you can see this is the same button that is used to put your ESP device in program mode. Why you may ask, because I already have a button connected to this GPIO and can give it more than one function with the button library.
// The GPIO pin that is connected to the button on the esp. const int button_gpio = 0; void button_callback(uint8_t gpio, button_event_t event);
Right here after you place this part of code. Here we create the task it self. We start with blinking the led so you know that the reset function is starting. Hereafter is will reset the WIFI Configuration followed by the HomeKit reset and at last it will restart your ESP module by executing sdk system restart procedure. In the last three line we make a xTask for executing the whole thing.
void reset_configuration_task() { //Flash the LED first before we start the reset for (int i = 0; i < 3; i++) { gpio_write(LED_INBUILT_GPIO, LED_ON); vTaskDelay(100 / portTICK_PERIOD_MS); gpio_write(LED_INBUILT_GPIO, 1 - LED_ON); 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 configuration\n"); xTaskCreate(reset_configuration_task, "Reset configuration", 256, NULL, 2, NULL); }
Right here after you place this part of code. Here we define the button press options. In this case I only will use a long press, as the single press is preserved to program your ESP module. under the line: case button_event_long_press
we call the previous made function reset_configuration();
.
void button_callback(uint8_t gpio, button_event_t event) { switch (event) { case button_event_single_press: //your_function_here(); //printf("your text here\n"); break; case button_event_long_press: // press for 4 Seconds reset_configuration(); break; default: printf("Unknown button event: %d\n", event); } }
Right before last {
on bottom of main script you place this part of code. Here you define that if button is pressed for 4 seconds (4000 milliseconds) it will callback the defined function eg. reset_configuration()
.
if (button_create(button_gpio, 0, 4000, button_callback)) { printf("Failed to initialize button\n"); }
Example Code
So now that we know what we have to do it’s time to implement it into a excising code. In this example I use the HomeKit LED example to demonstrate how to implement it.
Led.c Example
#include <stdio.h> #include <espressif/esp_wifi.h> #include <espressif/esp_sta.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" // The GPIO pin that is connected to the button on the esp. const int button_gpio = 0; 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++) { gpio_write(LED_INBUILT_GPIO, LED_ON); vTaskDelay(100 / portTICK_PERIOD_MS); gpio_write(LED_INBUILT_GPIO, 1 - LED_ON); 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 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_single_press: //your_function_here(); //printf("your text here\n"); break; case button_event_long_press: // press for 4 Seconds reset_configuration(); break; default: printf("Unknown button event: %d\n", event); } } 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(); } const int led_gpio = 2; bool led_on = false; void led_write(bool on) { gpio_write(led_gpio, on ? 0 : 1); } void led_init() { gpio_enable(led_gpio, GPIO_OUTPUT); led_write(led_on); } void led_identify_task(void *_args) { for (int i = 0; i < 3; 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(250 / portTICK_PERIOD_MS); } led_write(led_on); vTaskDelete(NULL); } void led_identify(homekit_value_t _value) { printf("LED identify\n"); xTaskCreate(led_identify_task, "LED identify", 128, NULL, 2, NULL); } homekit_value_t led_on_get() { return HOMEKIT_BOOL(led_on); } void led_on_set(homekit_value_t value) { if (value.format != homekit_format_bool) { printf("Invalid value format: %d\n", value.format); return; } led_on = value.bool_value; led_write(led_on); } 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*[]) { HOMEKIT_CHARACTERISTIC(NAME, "Sample LED"), HOMEKIT_CHARACTERISTIC(MANUFACTURER, "HaPK"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "037A2BABF19D"), HOMEKIT_CHARACTERISTIC(MODEL, "MyLED"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "0.1"), HOMEKIT_CHARACTERISTIC(IDENTIFY, led_identify), NULL }), HOMEKIT_SERVICE(LIGHTBULB, .primary = true, .characteristics = (homekit_characteristic_t*[]) { HOMEKIT_CHARACTERISTIC(NAME, "Sample LED"), HOMEKIT_CHARACTERISTIC( ON, false, .getter = led_on_get, .setter = led_on_set ), NULL }), NULL }), NULL }; homekit_server_config_t config = { .accessories = accessories, .password = "111-11-111" }; void user_init(void) { uart_set_baud(0, 115200); wifi_init(); led_init(); homekit_server_init(&config); if (button_create(button_gpio, 0, 4000, button_callback)) { printf("Failed to initialize button\n"); } }
When you have uploaded your .bin files to your esp hold the program button for 4 seconds and it will preform the reset! You can download all files here.
DO YOU HAVE ANY QUESTIONS? LEAVE A COMMENT DOWN HERE.
Note: To produce and sell HomeKit compatible accessories, your company need to be certified for that (https://developer.apple.com/homekit/, If you’re interested in developing or manufacturing a HomeKit accessory that will be distributed or sold, your company must enroll in the MFi Program.) Espressif have their implementation of HomeKit framework, but it will give you it only if you have MFi certification (notice this text at the bottom of page you mentioned: Please note that the Espressif HomeKit SDK is available to MFi licensees only, and you need to provide the Account Number for verification purposes when requesting the SDK.).This project is a non-commercial implementation of HAP protocol, not meant for commercial use.
REFERENCE
Maxim Kulkin, esp-wifi-config (2019), Library to bootstrap WiFi-enabled accessories WiFi config, https://github.com/maximkulkin/esp-wifi-config Paul Sokolovsky, esp-open-sdk (2019), Free and open (as much as possible) integrated SDK for ESP8266/ESP8285 chips, https://github.com/pfalcon/esp-open-sdk Espressif Systems, esptool (2019), ESP8266 and ESP32 serial bootloader utility, https://github.com/espressif/esptool