espressif / esp-homekit-sdk

541 stars 98 forks source link

How send the led status to the iPhone? #111

Closed leotordo closed 9 months ago

leotordo commented 9 months ago

Hello everybody. I've got esp-homekit-sdk from Espressif and I built the example "lightbulb". It works fine. I can change led status from may Home App.

Now, I want to switch on/off the led also by a mechanical switch. I modified the code for reading a GPIO input connected to this switch. I works, but the iPhone doesn't sense the status changed

How to send the changed status notification to the main task?

Thanks Andrea

shahpiyushv commented 9 months ago

You have to call hap_char_update_val() API to update the characteristic's value and also report it to the HomeKit controllers.

You can find sample usage in the smart_outlet example here.

leotordo commented 9 months ago

Thank you. I'll try ASAP and I'll turn here whit results regards

leotordo commented 9 months ago

Hello, I wrote this code

while(1)
{
        if(!gpio_get_level(GPIO_NUM_9)) 
        {
            lightbulb_set_brightness(50);

            hap_val_t appliance_value = { .i = 50, };
            hap_char_t *outlet_in_use = hap_serv_get_char_by_uuid(service, HAP_CHAR_UUID_BRIGHTNESS);
            hap_char_update_val(outlet_in_use, &appliance_value);
        }
}

The application starts with 10% of PWM

ret |= hap_serv_add_char(service, hap_char_brightness_create(10));

if I press GPIO9 switch the led brightness changes but the Home app remains at 10%

Where's the problem? Thanks Andrea

leotordo commented 9 months ago

Brief update. The position of my code is at the end of the thread _lightbulb_threadentry I added a single shot code for the button

/* Enable Hardware MFi authentication (applicable only for MFi variant of SDK) */
hap_enable_mfi_auth(HAP_MFI_AUTH_HW);

/* Initialize Wi-Fi */
app_wifi_init();

/* After all the initializations are done, start the HAP core */
hap_start();
/* Start Wi-Fi */
app_wifi_start(portMAX_DELAY);

hap_val_t appliance_value = { .i = 50, };
hap_char_t *outlet_in_use = hap_serv_get_char_by_uuid(service, HAP_CHAR_UUID_BRIGHTNESS);
int first=0;
while(1)
{
        if(!gpio_get_level(GPIO_NUM_9) && first==0) 
        {
            first=1;
            lightbulb_set_brightness(50);

            hap_char_update_val(outlet_in_use, &appliance_value);
        }
        if(gpio_get_level(GPIO_NUM_9) && first==1)
        {
            first=0;
            vTaskDelay(pdMS_TO_TICKS(300));
        }
}
/* The task ends here. The read/write callbacks will be invoked by the HAP Framework */
vTaskDelete(NULL);

light_err: hap_acc_delete(accessory); vTaskDelete(NULL); }

and...doesn't work :-( Thanks Andrea

shahpiyushv commented 9 months ago

@leotordo can you try adding prints to see if your code is reaching those lines? Additionally, it will be better to have a vTaskDelay(300/portTICK_PERIOD_MS); in your while(1) loop, outside the if conditions to prevent this task from consuming resources continuously.

leotordo commented 9 months ago

lightbulb_set_brightness has prints I added a print after hap_char_update_val (see below)

On the terminal I've these logs

Events Enabled for aid=1 iid=15 Events Enabled for aid=1 iid=17 Events Enabled for aid=1 iid=19 Events Enabled for aid=1 iid=20 Events Enabled for aid=1 iid=21

If I change from iPhone I've this output

image

if I press mechanical switch I get

image

"Value Changed" doesn't appear....and the iPhone is not updated

while(1)
    {
           vTaskDelay(pdMS_TO_TICKS(300));
            if(!gpio_get_level(GPIO_NUM_9) && first==0) 
            {
                first=1;
                lightbulb_set_brightness(50);
                appliance_value.i=50;             
                hap_char_update_val(outlet_in_use, &appliance_value);
                ESP_LOGI(TAG, "hap_char_update_val SENT");
            }
            if(gpio_get_level(GPIO_NUM_9) && first==1)
            {
                first=0;
                vTaskDelay(pdMS_TO_TICKS(300));
            }
    }
leotordo commented 9 months ago

I added the print of the returned value of hap_char_update_val

image

the error is -1

shahpiyushv commented 9 months ago

A couple of points

    service = hap_serv_fw_upgrade_create(&ota_config);
    if (!service) {
        ESP_LOGE(TAG, "Failed to create Firmware Upgrade Service");
        goto light_err;
    }
    hap_acc_add_serv(accessory, service);

You can remove this snippet or use a different service pointer here.

leotordo commented 9 months ago

thank you. On monday I'll check your points. Have a nice w/end

leotordo commented 9 months ago

hello. Issue solved. You're right, the problem was on service = hap_serv_fw_upgrade_create(&ota_config);

I defined service2 instead of service and my routine works.

I'll keep in mind also your suggestion about using different values.

Thanks I close this issue Regards

defacedbeef commented 7 months ago

Hi,

Basically I hit the similar issue with not reflecting accessory status in Apple iPhone's HomeKit. And I checked that with out of the box smart_outlet from the examples.

Here is a diff of app_main.c - I've applied some stupid counter to bypass the double edge issue (state is changed twice every time we hit a push button there). This push button ISR is not a case here, so let's move on.

+static int counter = 0;
+static bool new_value = false;
+
 static QueueHandle_t s_esp_evt_queue = NULL;
 /**
  * @brief the recover outlet in use gpio interrupt function
@@ -162,6 +166,7 @@ static void smart_outlet_thread_entry(void *p)

     /* Create the Outlet Service. Include the "name" since this is a user visible service  */
     service = hap_serv_outlet_create(false, false);
+
     hap_serv_add_char(service, hap_char_name_create("My Smart Outlet"));

     /* Get pointer to the outlet in use characteristic which we need to monitor for state changes */
@@ -227,10 +232,16 @@ static void smart_outlet_thread_entry(void *p)
         if (xQueueReceive(s_esp_evt_queue, &io_num, portMAX_DELAY) == pdFALSE) {
             ESP_LOGI(TAG, "Outlet-In-Use trigger FAIL");
         } else {
-            appliance_value.b = gpio_get_level(io_num);
+            counter+=1;
+            if (counter % 3 == 0) {
+                new_value = !new_value;
+                appliance_value.b = new_value;
+                hap_char_update_val(outlet_in_use, &appliance_value);
+                ESP_LOGI(TAG, "Outlet-In-Use triggered [%d]", appliance_value.b);
+            }
+
             /* If any state change is detected, update the Outlet In Use characteristic value */
-            hap_char_update_val(outlet_in_use, &appliance_value);
-            ESP_LOGI(TAG, "Outlet-In-Use triggered [%d]", appliance_value.b);
+
         }
     }
 }

As you can see, it does not modify anything around services nor characteristics. And it is simply not working. When I toggle state via push button, the state change is not reflected in the HomeKit iPhone app.

With a DUPA approach (Debug Using Printable ASCII) I ended up printing HTTP messages sent out from the device and noticed I've got two characteristics assigned to one service. iid 12 and iid 13. So far so good.

outlet_in_use uses "13". So I changed it to 12 in the HTTP Message that is sent towards a controller (iPhone's HomeKit) and suddenly, as you can guess - status is reflected.

After all I modified the exemplary code in that endless loop with this:

hap_char_update_val(hap_serv_get_char_by_uuid(service, HAP_CHAR_UUID_ON), &appliance_value);

which eventually means that I am sending status update over "ON" characteristics and the status change is reflected in the iPhone's HomeKit web interface (without pushing app to background nor restarting)

Which is weird and I can't wait for comments. Regards