rudders / homebridge-http

HTTP Plugin for Homebridge
Apache License 2.0
178 stars 110 forks source link

Getting on/off status #3

Closed MPV closed 8 years ago

MPV commented 8 years ago

Hi, Great plugin, worked like a charm!

I noticed that when I tried this together with the "Insteon" app, the app doesn't know which state my button is in (so if I press it elsewhere, the app's state is wrong).

What do you think about the feasibility of adding support for checking the state of the button? I don't know much about HomeKit yet, so I'm not sure how to help out right away, but curious what you think.

I am asking, since the switch that I have added (on/off to my surround receiver), also has an HTTP request I can send to check whether it's on or off.

rudders commented 8 years ago

Hi Victor, I considered this with the home security system I use the module to enable/disable but the challenge with adding this to homebridge-http is that there is no simple way to interpret the likely proprietary json or xml that will come back from that kind of status check API call.

i.e. My bet is that there is no simple - getbinarystate function from your surround receiver which would return some generic state object to be interpreted and you'll get back some xml which you'll need to look into to determine the state.

This is a great opportunity for you to clone or fork this module, roll your own and release it as homebridge- module of your own I reckon.

Let me know if you need help with packaging and releasing - I've done it twice now so I reckon I'm just the kind of expert you'll need ;)

Cheers

dr-ito commented 8 years ago

Hi Rudders,

I had a similar request. I use HomeBridge-HTTP to contol OpenHab which controls the lights in my house. I would love to know if these are on or off.

I had a suggestion for a possible solution. There would be some extra options to the configuration:

        "on_state_url": "https://192.168.1.22:3030/devices/23222/",
        "on_state_regex": "^(.*?(\bdevice is activated\b)[^$]*)$",
        "refresh_interval": "60",

If the regular expression matches the content on the "on_state_url" the device is on, if not the device is off. The "on_state_url" will be loaded every "refresh_interval" number of seconds.

a bit more complex and not entirely neccesary for me: Something similar would be possible for the brightness state, only the regex substitution operation would create a number which is the brightness. "brightness_state_url": "https://192.168.1.22:3030/devices/23222/brightness/%b", "brightness_state_regex": "something",

What do you think of it?

cheers,

Simon

NovaGL commented 8 years ago

This repo does on\off status

https://github.com/mattharris5/homebridge-readablehttp

I am having trouble using it though, I get "This callback function has already been called by someone else; it can only be called one time."

Whenever I try and run it.

rudders commented 8 years ago

Great to see some innovation based on the original code - I'll see if it can be pulled back into this module. Seems to depend on the called URL returning a simple value which would not always be the case. I'm working on another module at the moment and will come back and look at this over the christmas break.

Callback already being called suggests there may be multiple callbacks for some reason. Do you have logs you can share?

NovaGL commented 8 years ago

Here is the error that occurs, tried registering it as a separate accessory to no avail

/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/util/once.js:11
      throw new Error("This callback function has already been called by someo
            ^
Error: This callback function has already been called by someone else; it can only be called one time.
    at /root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/util/once.js:11:13
    at Object.<anonymous> (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/index.js:85:9)
    at Request._callback (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/index.js:45:7)
    at self.callback (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/node_modules/request/request.js:198:22)
    at Request.emit (events.js:107:17)
    at Request.init (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/node_modules/request/request.js:244:17)
    at new Request (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/node_modules/request/request.js:140:8)
    at request (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/node_modules/request/index.js:55:10)
    at Object.HttpreadAccessory.httpRequest (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/index.js:34:5)
    at Object.HttpreadAccessory.getPowerState (/root/.nvm/versions/node/v0.12.7/lib/node_modules/homebridge-readablehttp/index.js:82:10)
rudders commented 8 years ago

Try upgrading node. I do my dev and testing on node 5+

NovaGL commented 8 years ago

Still failed with v4 don't have v5 atm.


 HTTP get power function failed: options.uri is a required argument
/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/util/once.js:11
      throw new Error("This callback function has already been called by someone else; it can only be called one time.");
      ^

Error: This callback function has already been called by someone else; it can only be called one time.
    at /root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge/node_modules/hap-nodejs/lib/util/once.js:11:13
    at Object.<anonymous> (/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge-readablehttp/index.js:85:9)
    at Request._callback (/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge-readablehttp/index.js:45:7)
    at self.callback (/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge-readablehttp/node_modules/request/request.js:198:22)
    at emitOne (events.js:77:13)
    at Request.emit (events.js:169:7)
    at Request.init (/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge-readablehttp/node_modules/request/request.js:244:17)
    at new Request (/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge-readablehttp/node_modules/request/request.js:140:8)
    at request (/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge-readablehttp/node_modules/request/index.js:55:10)
    at Object.HttpReadAccessory.httpRequest (/root/.nvm/versions/node/v4.2.3/lib/node_modules/homebridge-readablehttp/index.js:34:5)
rudders commented 8 years ago

Maybe this issue is best addressed by the author of ...readabble not me. The first error is a function in that module not this one.

NovaGL commented 8 years ago

Just wanted to let you know I figured it out :)

The problem is two fold, the syntax in the authors readme is wrong and the app has poor error handling, instead of just ignoring the command it crashes the app.

Since I was on a roll I decided what they hey, lets do this for brightness too!

And that also works! So you can set the brightness or in my case volume in another app, come to homebridge and it will reflect the correct on\off state and the correct brightness level.

Since I don't know java at all it has no error handling in it.

I forked the repo and the changes can be found here: https://github.com/NovaGL/homebridge-httpstatus

rudders commented 8 years ago

Thanks @NovaGL - updated and released.

Leonoerlemans commented 6 years ago

I Am a newbe. I want an arduino to return a status on or of. Can anyone help me how to do this? I have an relaisboard which is controlled by the Arduino bij sending a http command. Because now HomeKit gives an exclamation sign and does not work properly. It does work though.

Thanks in advance, Leon

This is how the Arduino is set up:

include

include

include "PCF8574.h"

include

/* URL format: http://0.0.0.0/?XpYnnnn

//Manual network settings byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192, 168, 2, 30 };
byte gateway[] = { 192, 168, 2, 254 }; byte subnet[] = { 255, 255, 255, 0 };

// Initialize the Ethernet server on port no EthernetServer server(80);

// Define expanders int startAddress = 0x20; //write addres of A1=0 A2=0 A3=0 PCF8574 pA(startAddress); PCF8574 pB(++startAddress); PCF8574 pC(++startAddress); PCF8574 pD(++startAddress); PCF8574 pE(++startAddress); PCF8574 pF(++startAddress); PCF8574 pG(++startAddress); PCF8574 pH(++startAddress);

void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // for debugging }

// start the Ethernet connection and the server: Ethernet.begin(mac, ip, gateway, subnet); server.begin(); Serial.print("server is at "); Serial.println(Ethernet.localIP());

// Init expanders pA.begin(); pA.write8(255); pB.begin(); pB.write8(255); pC.begin(); pC.write8(255); pD.begin(); pD.write8(255); pE.begin(); pE.write8(255); pF.begin(); pF.write8(255); pG.begin(); pG.write8(255); pH.begin(); pH.write8(255); }

void loop(){ // listen for incoming clients, and process request. checkForClient(); }

void checkForClient() { EthernetClient client = server.available(); if (client) { boolean currentLineIsBlank = true; boolean sentHeader = false; boolean reading = false; String myStr = ""; while (client.connected()) { if (client.available()) { char c = client.read(); if(reading && c == ' ') reading = false; if(c == '?') reading = true; //found the ?, begin reading the info if(reading){ if (c!='?') { myStr += c; } } if (c == '\n' && currentLineIsBlank) break; if (c == '\n') { currentLineIsBlank = true; }else if (c != '\r') { currentLineIsBlank = false; } } } parseThings(myStr); // client.println("URL format: http://0.0.0.0/?XpYnnnn"); // client.println("X = Board (A-B-C-D-E-F-G-H)"); // client.println("p = Pin number (0-7)"); // client.println("Y = Action to perform"); // client.println(" - H = Relay OFF"); // client.println(" - L = Relay ON"); // client.println(" - T = Toggle (ON > OFF & OFF > ON)"); // client.println(" - P = Pulse nnnnn milliseconds uses toggle!!"); client.println("On"); delay(100); // give the web browser time to receive the data client.stop(); // close the connection:
} }

void parseThings(String str) { str = str + "xxxxxx";

String boardString = str.substring(0, 1); char boardChar[2]; boardString.toCharArray(boardChar, 2);

String pinString = str.substring(1,2); char pinChar[2]; pinString.toCharArray(pinChar, 2); int pin = atoi(pinChar);

String actionString = str.substring(2, 3); char actionChar[2]; actionString.toCharArray(actionChar, 2); //char action = actionChar[1];

String milliSecondsString = str.substring(3, 7); char milliSecondsChar[5]; milliSecondsString.toCharArray(milliSecondsChar, sizeof(milliSecondsChar)); int milliSeconds = atoi(milliSecondsChar);

// Serial.print("Board:"); // Serial.println(boardChar); // Serial.print("Pin:"); // Serial.println(pin); // Serial.print("Action:"); // Serial.println(actionChar); // Serial.print("Milli seconds:"); // Serial.println(milliSeconds);

action(boardChar[0], pin, actionChar[0], milliSeconds);

}

void action(char board, int pin, char action, int milliSeconds) { switch (action) { case 'L': low(board, pin); // Serial.println("LOW"); break; case 'H': high(board, pin); // Serial.println("HIGH"); break; case 'T': toggle(board, pin); // Serial.println("TOGGLE"); break; case 'P': pulse(board, pin, milliSeconds); // Serial.println("PULSE"); break; } }

void pulse(char board, int pin, int milliSeconds) { toggle(board, pin); delay(milliSeconds); toggle(board, pin); }

void high(char board, int pin) { switch (board) { case 'A': pA.write(pin, HIGH); break; case 'B': pB.write(pin, HIGH); break; case 'C': pC.write(pin, HIGH); break; case 'D': pD.write(pin, HIGH); break; case 'E': pE.write(pin, HIGH); break; case 'F': pF.write(pin, HIGH); break; case 'G': pG.write(pin, HIGH); break; case 'H': pH.write(pin, HIGH); break; } }

void low(char board, int pin) { switch (board) { case 'A': pA.write(pin, LOW); break; case 'B': pB.write(pin, LOW); break; case 'C': pC.write(pin, LOW); break; case 'D': pD.write(pin, LOW); break; case 'E': pE.write(pin, LOW); break; case 'F': pF.write(pin, LOW); break; case 'G': pG.write(pin, LOW); break; case 'H': pH.write(pin, LOW); break; } }

void toggle(char board, int pin) { switch (board) { case 'A': pA.toggle(pin); break; case 'B': pB.toggle(pin); break; case 'C': pC.toggle(pin); break; case 'D': pD.toggle(pin); break; case 'E': pE.toggle(pin); break; case 'F': pF.toggle(pin); break; case 'G': pG.toggle(pin); break; case 'H': pH.toggle(pin); break; } }