Mixiaoxiao / Arduino-HomeKit-ESP8266

Native Apple HomeKit accessory implementation for the ESP8266 Arduino core.
MIT License
1.52k stars 277 forks source link

Multiple Switches #92

Open DirkRussellG opened 3 years ago

DirkRussellG commented 3 years ago

I set up the Switch example on two ESP8266 and it works exactly right for me. Does anyone have any code examples of using one device to setup more than one switch/relay set ? I can see how to set up the my_accessory.c file but I haven't yet seen how to get the cha_name. (maybe just a hint - I've looked through the closed tickets)

#define PIN_SWITCH 2

//Called when the switch value is changed by iOS Home APP

void cha_switch_on_setter(const homekit_value_t value) {
    bool on = value.bool_value;
    cha_switch_on.value.bool_value = on;    //sync the value
    LOG_D("Switch: %s", on ? "ON" : "OFF");
    digitalWrite(PIN_SWITCH, on ? LOW : HIGH);
pratik019 commented 3 years ago

Even I would like help with this one

DirkRussellG commented 3 years ago

Oh I see, this is for "issues" (like it plainly states), not for novices getting help understanding the coding, my ignorance, my apologies

sircuri commented 3 years ago

Sure, you can ask for help as a novice. That is not a problem at all. There is a huge difference between a novice asking for help and someone that just dumps its questions on the web and expects others to solve it for them.

Please provide any relevant code so others can look at it and help you. The part of code that you added to this issue is not even related to the question. Or maybe it is, but than the question is unclear to me. I assume that you have to set it up as a BRIDGE accessory and add 2 characteristics for each individual switch with a corresponding value_t object attached to it. Each single value should be able to be read from and written to. So please, reword your question. People are willing to help.

DirkRussellG commented 3 years ago

My objective is to use one esp8266 for 2 individually controlled relays. I added a second id (.id=2) in the my_accessory.c file and it shows up ok in the Home app. I have not figured out how read the variable properly as to identify what switch was pressed. After that I assume its a simple IF statement to the code section I posted as to which pin to apply the changes to.

sircuri commented 3 years ago

You have to wire an additional homekit_characteristic_t to your configuration like so:

homekit_characteristic_t cha_switch_1 = HOMEKIT_CHARACTERISTIC_(ON, false);
homekit_characteristic_t cha_switch_2 = HOMEKIT_CHARACTERISTIC_(ON, false);

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*[]) {
             ---- left out for clarity -------
        }),
        HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){
                        HOMEKIT_CHARACTERISTIC(NAME, "Switch 1"),
            &cha_switch_1,
            NULL
        }),
        NULL
    }),
    HOMEKIT_ACCESSORY(.id=2, .category=homekit_accessory_category_switch, .services=(homekit_service_t*[]) {
        HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t*[]) {
             ---- left out for clarity -------
        }),
        HOMEKIT_SERVICE(SWITCH, .primary=true, .characteristics=(homekit_characteristic_t*[]){
                        HOMEKIT_CHARACTERISTIC(NAME, "Switch 2"),
            &cha_switch_2,
            NULL
        }),
        NULL
    }),
    NULL
};

In your 'my_homekit_setup' function you can attach the setter method to each of these 2 values:

cha_switch_1.setter = cha_switch_1_setter;
cha_switch_2.setter = cha_switch_2_setter;

woaw... markup is not that easy here...

DirkRussellG commented 3 years ago

Thank you. I think I can follow that. I wrongly thought the additional ID was instance of the main accessory, like an array or something. Can I post the finished code as an example? I know other novices like me would be interested.

DirkRussellG commented 3 years ago

Thanks sircuri, works. Thank you.

DirkRussellG commented 3 years ago

`/*

include

include

include "wifi_info.h"

define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__);

void setup() { Serial.begin(115200); wifi_connect(); // in wifi_info.h //homekit_storage_reset(); // to remove the previous HomeKit pairing storage when you first run this new HomeKit example my_homekit_setup(); }

void loop() { my_homekit_loop(); delay(10); }

//============================== // HomeKit setup and loop //==============================

// access your HomeKit characteristics defined in my_accessory.c extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch_1; extern "C" homekit_characteristic_t cha_name_1; extern "C" homekit_characteristic_t cha_switch_2; extern "C" homekit_characteristic_t cha_name_2;

static uint32_t next_heap_millis = 0;

define PIN_SWITCH1 2 //D4

define PIN_SWITCH2 14 //D5

//Called when the switch value is changed by iOS Home APP

void cha_switch_1_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_1.value.bool_value = on; //sync the value LOG_D("Switch 1: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH1, on ? LOW : HIGH); } void cha_switch_2_setter(const homekit_value_t value) { bool on = value.bool_value; cha_switch_2.value.bool_value = on; //sync the value LOG_D("Switch 2: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH2, on ? LOW : HIGH); }

void my_homekit_setup() { pinMode(PIN_SWITCH1, OUTPUT); digitalWrite(PIN_SWITCH1, HIGH); pinMode(PIN_SWITCH2, OUTPUT); digitalWrite(PIN_SWITCH2, HIGH);

//Add the .setter function to get the switch-event sent from iOS Home APP.
//The .setter should be added before arduino_homekit_setup.
//HomeKit sever uses the .setter_ex internally, see homekit_accessories_init function.
//Maybe this is a legacy design issue in the original esp-homekit library,
//and I have no reason to modify this "feature".

cha_switch_1.setter = cha_switch_1_setter; cha_switch_2.setter = cha_switch_2_setter; arduino_homekit_setup(&config);

//report the switch value to HomeKit if it is changed (e.g. by a physical button)
//bool switch_is_on = true/false;
//cha_switch_on.value.bool_value = switch_is_on;
//homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value);

}

void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { // show heap info every 5 seconds next_heap_millis = t + 5 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count());

}

}`

DirkRussellG commented 3 years ago

`/* my_accessory.c Define the accessory in C language using the Macro in characteristics.h

Created on: 2020-05-15
    Author: Mixiaoxiao (Wang Bin)

*/

include <homekit/homekit.h>

include <homekit/characteristics.h>

void my_accessory_identify(homekit_value_t _value) { printf("accessory identify\n"); }

// Switch (HAP section 8.38) // required: ON // optional: NAME

// format: bool; HAP section 9.70; write the .setter function to get the switch-event sent from iOS Home APP. homekit_characteristic_t cha_switch_1 = HOMEKITCHARACTERISTIC(ON, false); homekit_characteristic_t cha_switch_2 = HOMEKITCHARACTERISTIC(ON, false);

// format: string; HAP section 9.62; max length 64 homekit_characteristic_t cha_name_1 = HOMEKITCHARACTERISTIC(NAME, "Switch01"); homekit_characteristic_t cha_name_2 = HOMEKITCHARACTERISTIC(NAME, "Switch02");

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[]) { HOMEKIT_CHARACTERISTIC(NAME, "Switch01"), HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Arduino HomeKit"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "0123456"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266/ESP32"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), HOMEKIT_SERVICE(SWITCH, .primary = true, .characteristics = (homekit_characteristic_t[]) { &cha_switch_1, &cha_name_1, NULL }), NULL }), HOMEKIT_ACCESSORY(.id = 2, .category = homekit_accessory_category_switch, .services = (homekit_service_t[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics = (homekit_characteristic_t[]) { HOMEKIT_CHARACTERISTIC(NAME, "Switch02"), HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Arduino HomeKit"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "0123456"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266/ESP32"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), HOMEKIT_SERVICE(SWITCH, .primary = true, .characteristics = (homekit_characteristic_t*[]) { &cha_switch_2, &cha_name_2, NULL }), NULL }),

NULL };

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

yepkevin612 commented 3 years ago

@DirkRussellG my_accessory.c

include <homekit/homekit.h>

include <homekit/characteristics.h>

void my_accessory_identify(homekit_value_t _value) { printf("accessory identify\n"); }

// Switch (HAP section 8.38) // required: ON // optional: NAME

// format: bool; HAP section 9.70; write the .setter function to get the switch-event sent from iOS Home APP. homekit_characteristic_t cha_switch_on1 = HOMEKITCHARACTERISTIC(ON, false); homekit_characteristic_t cha_switch_on2 = HOMEKITCHARACTERISTIC(ON, false); // format: string; HAP section 9.62; max length 64 homekit_characteristic_t cha_name1 = HOMEKITCHARACTERISTIC(NAME, "LED"); homekit_characteristic_t cha_name2 = HOMEKITCHARACTERISTIC(NAME, "Fan");

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, "LED"), HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Arduino HomeKit"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "0123456"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266/ESP32"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), HOMEKIT_SERVICE(LIGHTBULB, .primary=true, .characteristics=(homekit_characteristic_t[]){ &cha_switch_on1, &cha_name1, NULL }), NULL }), HOMEKIT_ACCESSORY(.id=2, .category=homekit_accessory_category_fan, .services=(homekit_service_t[]) { HOMEKIT_SERVICE(ACCESSORY_INFORMATION, .characteristics=(homekit_characteristic_t[]) { HOMEKIT_CHARACTERISTIC(NAME, "Fan"), HOMEKIT_CHARACTERISTIC(MANUFACTURER, "Arduino HomeKit"), HOMEKIT_CHARACTERISTIC(SERIAL_NUMBER, "0123457"), HOMEKIT_CHARACTERISTIC(MODEL, "ESP8266/ESP32"), HOMEKIT_CHARACTERISTIC(FIRMWARE_REVISION, "1.0"), HOMEKIT_CHARACTERISTIC(IDENTIFY, my_accessory_identify), NULL }), HOMEKIT_SERVICE(FAN, .primary=true, .characteristics=(homekit_characteristic_t*[]){ &cha_switch_on2, &cha_name2, NULL }), NULL }), NULL };

homekit_server_config_t config = { .accessories = accessories, .password = "222-22-222" };

yepkevin612 commented 3 years ago

@DirkRussellG Switch

include

include

include "wifi_info.h"

define LOG_D(fmt, ...) printf_P(PSTR(fmt "\n") , ##__VA_ARGS__);

void setup() { Serial.begin(9600); wifi_connect(); // in wifi_info.h //homekit_storage_reset(); // to remove the previous HomeKit pairing storage when you first run this new HomeKit example my_homekit_setup(); }

void loop() { my_homekit_loop(); delay(10); }

//============================== // HomeKit setup and loop //==============================

// access your HomeKit characteristics defined in my_accessory.c extern "C" homekit_server_config_t config; extern "C" homekit_characteristic_t cha_switch_on1; extern "C" homekit_characteristic_t cha_switch_on2; static uint32_t next_heap_millis = 0;

define PIN_SWITCH1 2

define PIN_SWITCH2 16

//Called when the switch value is changed by iOS Home APP void cha_switch_on_setter1(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on1.value.bool_value = on; //sync the value LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH1, on ? HIGH : LOW); } void cha_switch_on_setter2(const homekit_value_t value) { bool on = value.bool_value; cha_switch_on2.value.bool_value = on; //sync the value LOG_D("Switch: %s", on ? "ON" : "OFF"); digitalWrite(PIN_SWITCH2, on ? LOW: HIGH); }

void my_homekit_setup() { pinMode(PIN_SWITCH1, OUTPUT); digitalWrite(PIN_SWITCH1, LOW); pinMode(PIN_SWITCH2, OUTPUT); digitalWrite(PIN_SWITCH2, HIGH); //Add the .setter function to get the switch-event sent from iOS Home APP. //The .setter should be added before arduino_homekit_setup. //HomeKit sever uses the .setter_ex internally, see homekit_accessories_init function. //Maybe this is a legacy design issue in the original esp-homekit library, //and I have no reason to modify this "feature". cha_switch_on1.setter = cha_switch_on_setter1; cha_switch_on2.setter = cha_switch_on_setter2; arduino_homekit_setup(&config);

//report the switch value to HomeKit if it is changed (e.g. by a physical button)
//bool switch_is_on = true/false;
//cha_switch_on.value.bool_value = switch_is_on;
//homekit_characteristic_notify(&cha_switch_on, cha_switch_on.value);

}

void my_homekit_loop() { arduino_homekit_loop(); const uint32_t t = millis(); if (t > next_heap_millis) { // show heap info every 5 seconds next_heap_millis = t + 5 * 1000; LOG_D("Free heap: %d, HomeKit clients: %d", ESP.getFreeHeap(), arduino_homekit_connected_clients_count());

}

}

DirkRussellG commented 3 years ago

@yepkevin612 Thank you so much. Are those changes mainly for proper naming convention? Doesn't change functionality or does it?

Here is my code for the connected physical push button, it works but it will probably give entertainment or a big sigh :-) I'm sure it could be done in just a few lines.

void check_pushbutton_state() {
  button1_state = digitalRead(PIN_BUTTON1);
  if (button1_state == HIGH) {
    if (button1_flag == 0) {
      button1_flag = 1; //
    }
  }
  if (button1_state == LOW && button1_flag == 1) { //button released
    button1_flag = 0;
    boolean readPinState = (digitalRead(PIN_SWITCH1)); //relay is active low
    digitalWrite(PIN_SWITCH1, !digitalRead(PIN_SWITCH1));
    cha_switch_1.value.bool_value = readPinState;
    homekit_characteristic_notify(&cha_switch_1, cha_switch_1.value);
  }
  button2_state = digitalRead(PIN_BUTTON2);
  if (button2_state == HIGH) {
    if (button2_flag == 0) {
      button2_flag = 1; //
    }
  }
  if (button2_state == LOW && button2_flag == 1) {
    button2_flag = 0;
    boolean readPinState = (digitalRead(PIN_SWITCH2));  
    digitalWrite(PIN_SWITCH2, !digitalRead(PIN_SWITCH2));
    cha_switch_2.value.bool_value = readPinState;
    homekit_characteristic_notify(&cha_switch_2, cha_switch_2.value);
  }
}
yepkevin612 commented 3 years ago

@DirkRussellG just two ON\OFF switch

yepkevin612 commented 3 years ago

@DirkRussellG Do you know the codes ,2 switch with push button ?

DirkRussellG commented 3 years ago

I guess I probably don't.

DirkRussellG commented 3 years ago

I was looking over the changes you made in the code. Is Serial.begin(9600); preferred over Serial.begin(115200); like in the examples?

yepkevin612 commented 3 years ago

@DirkRussellG in example is 115200.

yepkevin612 commented 3 years ago

can you share your code with push button?

DirkRussellG commented 3 years ago

in the original code I posted it had 115200, in the code you tweaked and reposted it has 9600

DirkRussellG commented 3 years ago

@yepkevin612 > can you share your code with push button?

Is this for me? I have my novice button code above.

paullj1 commented 3 years ago

Maybe a bit late, but I noticed your "password" was "222-22-222", which is explicitly called out in the HAP docs as not allowed. That could be your problem.

madmacks59 commented 2 years ago

Maybe a bit late, but I noticed your "password" was "222-22-222", which is explicitly called out in the HAP docs as not allowed. That could be your problem.

Where in the HAP doco is that specified? I have a "built device" using that password and it is a bit flaky, and I'm wondering... But I've scanned the HomeKit Accessory Protocol Specification (Non-Commercial Version Release R2) document and don't see any prohibitions...

or are you referring to the following line in section 4.2.1.2... The following are examples of setup codes that must not be used due to their trivial, insecure nature:

If so I think that's more of a guideline than a rule. If you build something for commercial distribution and submit it to Apple for validation I'd expect Apple to reject the device, because it's "trivial, insecure nature". But I don't think there is anything in the Spec (or Apples code) that "enforces" that guideline... we user 111-11-1111 in examples all over the place...

paullj1 commented 2 years ago

Yup, that’s the section I was talking about. You’re clearly correct in that it didn’t actually prevent your device from working, just offering it as a suggestion. When the spec says, “must not be used,” I typically take that to mean, “don’t do it.” I guess in this case you got lucky.