[HomeKit] Connect your Photon to HomeKit without homebridge

Hi, sry for late response. I have a lot of other work - this is just hobby, low priority. But still can you describe steps to reproduce the problem? How can i reproduce it? I will look at the problem.

Also TcpClient.status() might be buggy, but what firmware version are you running?

As far as i understand your fix - if new client is connected within the same IP address, you just close the old one? It seems legit, can you please “clean it” and prepare Merge request, i will accept it.

1 Like

This is such a fantastic project! I’ve only got a Particle Core at the moment, so need to get my hands on a few Photon’s or Argon’s soon.

I noticed on your GitHub project page that this supports blinds (I’m assuming rolling blinds?) and was wondering whether it could also support garage door (open/close and status?).

Hello Jeff,

yes, garage door is supported accessory in Homekit, but i did not provide any example for this. But you can easily implemented on your own. You just need to implement proper services and characteristics. You can look into to my examples and inspire yourself. Also look into homekit documentation, includeded in my repo.

1 Like

Hi Jeff,
have a look on following snippet. Thanks to Lucas’ examples it’s really easy:

std::string GarageDoorAccessoryBase::getDoorStatus (HKConnection *sender) 
{
    /*0 = fully open;
    1 = "Closed. The door is fully closed."
    2 = Opening
    3 = closing */
    if (lr->isOn())
        return format("%d", 1);
    else
        return format("%d", 0);
}
std::string GarageDoorAccessoryBase::getTargetDoorStatus (HKConnection *sender) 
{
    if (lr->isOn())
        return format("%d", 1);
    else
        return format("%d", 0);
}
void GarageDoorAccessoryBase::setTargetDoor (bool oldValue, bool newValue, HKConnection *sender) 
{
    if(newValue) 
       lr->switchOn();
    else lr->switchOff();
}
void GarageDoorAccessoryBase::sync()
{
    if (currentState != NULL)
        currentState->notify(NULL);
    if (targetDoorState != NULL)
        targetDoorState->notify(NULL);
}
void GarageDoorAccessoryBase::gdIdentify(bool oldValue, bool newValue, HKConnection *sender) {
    hkLog.info("Start Identify Garage Door Opener\n");
}
void GarageDoorAccessoryBase::initAccessorySet() {
    Accessory *gdAcc1 = new Accessory();
    AccessorySet *accSet = &AccessorySet::getInstance();
    addInfoServiceToAccessory(gdAcc1, " Garage Door Opener", "Vendor name", "Model name", "1","1.0.0", std::bind(&GarageDoorAccessoryBase::gdIdentify, this, std::placeholders::_1, std::placeholders::_2,std::placeholders::_3));
    accSet->addAccessory(gdAcc1);
    Service *gdService1 = new Service(serviceType_garageDoorOpener);
    gdAcc1->addService(gdService1);
    stringCharacteristics *gdServiceName1 = new stringCharacteristics(charType_serviceName, permission_read, 0);
    gdServiceName1->characteristics::setValue("Garage");
    gdAcc1->addCharacteristics(gdService1, gdServiceName1);
    currentState = new intCharacteristics(charType_currentDoorState, permission_read|permission_notify,0, 4, 1, unit_none);
     currentState->perUserQuery = std::bind(&GarageDoorAccessoryBase::getDoorStatus, this, std::placeholders::_1);
    gdAcc1->addCharacteristics(gdService1, currentState);
     targetDoorState = new intCharacteristics(charType_targetDoorState, permission_read|permission_write|permission_notify,0,1,1,unit_none);  
    targetDoorState->perUserQuery = std::bind(&GarageDoorAccessoryBase::getTargetDoorStatus, this, std::placeholders::_1);
    targetDoorState->valueChangeFunctionCall = std::bind(&GarageDoorAccessoryBase::setTargetDoor, this, std::placeholders::_1, std::placeholders::_2,std::placeholders::_3);
    gdAcc1->addCharacteristics(gdService1, targetDoorState);
    boolCharacteristics *obstruction = new boolCharacteristics(charType_obstruction, permission_read|permission_notify);
    obstruction->characteristics::setValue("false");
    gdAcc1->addCharacteristics(gdService1, obstruction);
};

works pretty fine in my case.

Best, Michael

3 Likes

Has anybody created a monochrome bulb accessory? Any suggestion how to go from RGB to monochrome?

I have kind of a solution by pointing the three colours to the same pin, but in HomeKit it still shows up as a colour bulb. It would be nice if it would show up as a monochrome bulb.

Thanks!

1 Like

Hi, if you are using my lightbulb example - look into LightBulbAccessoryBase.cpp file and comment out adding of hue and saturation characteristics (lines 97,102). If you don’t want to use light intensity=brightness, then comment out also line 92.
Then you will have a lightbulb that just have only “Power state” characteristic - just ON/OFF.

1 Like

Super ljezny! I’ll try that now!

Thanks!

1 Like

I have made much progress, starting with the Relay Accessory. I have learned about C++ classes and was able to incorporate an additional functionality, an indicator light that is off when the relay is closed and is on when the relay is open. I have got one led bulb working with this.

I am currently using the WEB IDE as I have so far not been able to get Workbench working for this application.

Question 1:

Now I want to add an additional functionality to this setup, which is a (momentary) button. Press to switch the relay on, another press to switch the relay on. Any ideas or suggestion on how to do this and specifically where to add the code are very welcome!

Question 2:

I also want to add the same functionality to a dimmable led strip and I am using the lightbulb example as a starting point. However, I am not able to add the accessory to the Home app. It shows up in the app but when I want to connect, it fails to be registered by the app. I assume this is because I am using the HAP library (through the Web IDE) and this does not allow me to change the ACCESSORY_KEY in HKConsts.h. I have tried to bind to HKConsts.h directly in the Web IDE using a modified ACCESSORY_KEY, but this doesn’t work.

Is there a way to change the ACCESSORY_KEY when using the Web IDE?

If that’s not possible, I can only have one accessory in my home system and I will have to spend time trying to figure out how to do all this with Workbench.

Thanks for your help!

1 Like

@guussie and @ljezny,
Dear Lukas, I also started with the RelaySwitch example and have it running successfully. I have the same question as Guus (Question 1), I would also like to connect to the Photon a momentary push button to toggle the relay (= the output pin). I know how to implement buttons, but what I cannot figure out is to make the correct call to toggle the relay inside my photon code.
Another question from my side would be: how can I get in the code the actual status of the relay? is this stored in a variable that is associated with the accessory? how would I read it out?

1 Like

@guussie @hbierau
Q1:
I believe, that you want to implement “Stateless Programmable Switch” - look in HAP-Specification-Non-Commercial-Version.pdf chapter 9.21. You just need to implement service with one required characteristics. I strongly believe it will be some minor changes to RelaySwitch example. I don’t have time to provide complete example, sry, but i also think that it wont be fun when i provide full solution :slight_smile:

Q2:
You dont need to care about Accessory key. I know it’s constant, it weaknesses the crypto, but it’s not the issue. Please provide full log of failing pair.

TIP: Also, if you change the description of device (like changing, adding, removing services and characteristics), you don’t need to re-pair photon with homekit. It will work until you return valid responses for Accessory description call.

Make sure, that example is using latest version of particle-hap library.

Pairing mostly fails not because of crypto, but because you return invalid JSON response for Device description call. Mind that some services has mandatory characteristics, that you must preserve.

Also if you won’t be able to fix it let me know (send full sample).

I also thinks that this library is not for beginners, so WEB IDE is not a good way to start. Also particle-hap logs a lot over USB, so this logs are very valuable to investigate the issue.

@ljezny
Regarding Q1: Thanks for your feedback, but what you write about the “Stateless Programmable Switch” is not what I have in mind. What I would like to do, and I think it is the same for @guussie, is that I would like to add a momentary push button as a “hardware” method, which works in parallel to the “software” homekit button possibility. The intention is that the relay can be operated both from the “Home” panel on the iphone and by using a “real” pushbutton to toggle the relay. So on the code side, I would add to your code something like:

void setup() {
...
  pinMode(buttonPin, INPUT_PULLUP);   // momentary pushbutton connects buttonPin to GND
...
}

void loop() {
....
  if (digitalRead(buttonPin) == 0) toggleRelay();
....
....

}

void toggleRelay() {
....
  if (relay is off) ---> switch relay on;
  if (relay is on) --> switch relay off;
....
....

}

I cannot see from the RelaySwitchAccessory.h or RelaySwitchAccessory.cpp file how I can call a toggle of the relay or how I can retrieve the actual state.
For example, in RelaySwitchAccessory.cpp I can see in the following function:

void RelaySwitchAccessory::setPower (bool oldValue, bool newValue, HKConnection *sender){
    on = newValue;
}

Can I call this function, e.g. when there was a (hardware) button press to set the relay on or off?

I also see in RelaySwitchAccessory.cpp the following function:

std::string RelaySwitchAccessory::getPower (HKConnection *sender){
    return on ? "true" : "false";
}

Can this be called somehow in order to know in what state the relay is in?
Thanks,
Horst

@hbierau @ljezny
This is indeed the functionality I would like to add. A hardware on/off functionality, using a momentary button.

Ah. i see. It’s simle:

yourPowerCharacteristics->notify(NULL);

Call “notify” whenever you want to tell to Homekit that any characteristics value has changed. After “notify” call, the getPower will be call to get the current value. I think you should look into LightSensor example, where in i am refreshing characteristics value every 5s (in handle method).

Thanks @ljezny. Yes, I found the example and the call you mentioned.

I do not know very well how to use and programme well with pointers, therefore I still have some questions. I guess that some things that are obvious to you, they are not obvious for me, so bear with me because I might ask some really basic or even stupid things.
In the LightSensor example, you call

currentAmbilightChar->notify(NULL);

in the subroutine to update the light value every 5 seconds. I was looking to find the type definition of this variable, but I guess it is somewhere in other files that are included in the LightSensorAccessory.h or in the LightSensorAccessory.cpp file. However, I found in LightSensorAccessory.h this definition:

floatCharacteristics *currentAmbilightChar;

To come back to the relay example, you suggest to call

yourPowerCharacteristics->notify(NULL);

So I guess that yourPowerCharacteristics must be some kind of boolean variable. I simply tried defining yourPowerCharacteristics as a boolean variable, which however did not work (error during compiling.
The following was more guessing: I tried to “extrapolate” the floatCharacteristics from the LightSensor example and I included in my code:

boolCharacteristics *yourPowerCharacteristics;

With this included, the relayswitch example compiles successfully, but I don’t know how I can save the desired state (either on or off) in yourPowerCharacteristics before making the call. I tried a crude yourPowerCharacteristics = true; but that was not successful, I guess this is not the correct way to use these pointer variables. Could you please help me out here?
Thanks!

Does this work with older ‘Particle Core’ devices or just Photon?

Thanks @ljezny. I am sorry to bother you further, but I am still struggling to implement this, probably because I am not very familiar to use pointers and because the your code is quite advanced for my basic skills. So I was hoping you could give me some additional advice. I would very much appreciate your help. I guess it just takes very few additions to the code, but I have not been able yet to figure it out.
My questions are basically the following:

a) from where can I make the call that you suggested in your last reply?

yourPowerCharacteristics->notify(NULL);

Can I call this from my .ino file or do I need to implement this somewhere in the embedded library files (either the .cpp or the .h file)?

b) I guess the “yourPowerCharacteristics” is the argument I pass on with the call. What data type is that, e.g. bool, int, char, string? Where do I need to define that, in the setup routine?

Just to remind you what I have in mind. Parallel to the possibility of switching the relay through the Home app on the iPhone I would like to implement a hardware pushbutton which also toggles the relay on and off. The button press event needs to be communicated to the “Homekit code” so that the state change is registered and passed on and correctly displayed in the Home app.
Thanks again,
Horst

Hi,
please read the HAP documentation (the PDF document in repo). Basically, every Homekit accessory is described as set of Services and it’s characteristics. For example Lightbulb is described as “Light service” with at least one mandatory bool characteristic (power). Look into documentation and read about Lightbulbs, relays.

So “yourPowerCharacteristics” is just normal object, which only encapsulates bool value. You can get and set its value using get, set methods. Calling “notify” tells to HomeKit, that value has been changed.

So when you have a push button, and user toggles it, you need the set the new value (on/off) to yourPowerCharacteristics and then call notify.

To more understand, your Photon acts as HTTP server and your iPhone, iPads, apple tv acts as clients. so calling Notify actually sends a JSON object over secured sockets to all currently connected clients.

1 Like

@guussie, did you succeed in implementing the hardware button according to the instructions provided by @ljezny?

@hbierau not yet. Too busy for the moment…