diff --git a/examples/Tutorials/D-Expert/15-RealPushButtons/15-RealPushButtons.ino b/examples/Tutorials/D-Expert/15-RealPushButtons/15-RealPushButtons.ino new file mode 100644 index 0000000..e8d6235 --- /dev/null +++ b/examples/Tutorials/D-Expert/15-RealPushButtons/15-RealPushButtons.ino @@ -0,0 +1,41 @@ + +//////////////////////////////////////////////////////////// +// // +// HomeSpan: A HomeKit implementation for the ESP32 // +// ------------------------------------------------ // +// // +// Example 15: Real PushButtons // +// * manually controlling an LED // +// // +// // +//////////////////////////////////////////////////////////// + +#include "HomeSpan.h" +#include "DEV_LED.h" +#include "DEV_Identify.h" + +void setup() { + + Serial.begin(115200); + + homeSpan.begin(Category::Bridges,"HomeSpan Bridge"); + + new SpanAccessory(); + new DEV_Identify("Bridge #1","HomeSpan","123-ABC","HS Bridge","0.9",3); + new Service::HAPProtocolInformation(); + new Characteristic::Version("1.1.0"); + + new SpanAccessory(); + + new DEV_Identify("Switched LED","HomeSpan","123-ABC","20mA LED","0.9",0); + new DEV_DimmableLED(0,17); + +} // end of setup() + +////////////////////////////////////// + +void loop(){ + + homeSpan.poll(); + +} // end of loop() diff --git a/examples/Tutorials/D-Expert/15-RealPushButtons/DEV_Identify.h b/examples/Tutorials/D-Expert/15-RealPushButtons/DEV_Identify.h new file mode 100644 index 0000000..95ba92a --- /dev/null +++ b/examples/Tutorials/D-Expert/15-RealPushButtons/DEV_Identify.h @@ -0,0 +1,40 @@ + +////////////////////////////////// +// DEVICE-SPECIFIC SERVICES // +////////////////////////////////// + +struct DEV_Identify : Service::AccessoryInformation { + + int nBlinks; // number of times to blink built-in LED in identify routine + SpanCharacteristic *identify; // reference to the Identify Characteristic + + // NEW! modified constructor() method to include optional ServiceType argument + + DEV_Identify(char *name, char *manu, char *sn, char *model, char *version, int nBlinks, ServiceType sType=ServiceType::Regular) : Service::AccessoryInformation(sType){ + + new Characteristic::Name(name); // create all the required Characteristics with values set based on above arguments + new Characteristic::Manufacturer(manu); + new Characteristic::SerialNumber(sn); + new Characteristic::Model(model); + new Characteristic::FirmwareRevision(version); + identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below + + this->nBlinks=nBlinks; // store the number of times to blink the built-in LED + + pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output + } + + StatusCode update(){ + + for(int i=0;ichannel=channel; // save the channel number (from 0-15) + this->ledPin=ledPin; // save LED pin number + this->pwmPin=new PwmPin(channel, ledPin); // configure the PWM channel and attach the specified ledPin + + Serial.print("Configuring Dimmable LED: Pin="); // initialization message + Serial.print(ledPin); + Serial.print(" Channel="); + Serial.print(channel); + Serial.print("\n"); + + } // end constructor + + StatusCode update(){ // update() method + + LOG1("Updating Dimmable LED on pin="); + LOG1(ledPin); + LOG1(": Current Power="); + LOG1(power->getVal()?"true":"false"); + LOG1(" Current Brightness="); + LOG1(level->getVal()); + + if(power->updated()){ + LOG1(" New Power="); + LOG1(power->getNewVal()?"true":"false"); + } + + if(level->updated()){ + LOG1(" New Brightness="); + LOG1(level->getNewVal()); + } + + LOG1("\n"); + + pwmPin->set(channel,power->getNewVal()*level->getNewVal()); + + return(StatusCode::OK); // return OK status code + + } // update + + void button(int pin, boolean isLong){ + + Serial.print("Found button press on pin: "); + Serial.print(pin); + Serial.print(" type: "); + Serial.print(isLong?"LONG":"SHORT"); + Serial.print("\n"); + + } +}; + +////////////////////////////////// diff --git a/src/HAP.cpp b/src/HAP.cpp index c154981..252e3c9 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -102,7 +102,16 @@ void HAPClient::init(){ homeSpan.Loops.push_back(s); } } - + + + for(int i=0;ipin); + Serial.print(" iid: "); + Serial.print(homeSpan.PushButtons[i]->service->iid); + Serial.print("\n"); + } + } ////////////////////////////////////// @@ -1173,6 +1182,16 @@ void HAPClient::callServiceLoops(){ homeSpan.Loops[i]->loop(); // call the loop() method } + +////////////////////////////////////// + +void HAPClient::checkPushButtons(){ + + for(int i=0;icheck(); // check if long- or short-pressed, which calls button() method in attached Service if needed + +} + ////////////////////////////////////// void HAPClient::checkNotifications(){ diff --git a/src/HAP.h b/src/HAP.h index 87e793c..cb309cd 100644 --- a/src/HAP.h +++ b/src/HAP.h @@ -113,6 +113,7 @@ struct HAPClient { static void removeController(uint8_t *id); // removes specific Controller. If no remaining admin Controllers, remove all others (if any) as per HAP requirements. static void printControllers(); // prints IDs of all allocated (paired) Controller static void callServiceLoops(); // call the loop() method for any Service with that over-rode the default method + static void checkPushButtons(); // checks for PushButton presses and calls button() method of attached Services when found static void checkNotifications(); // checks for Event Notifications and reports to controllers as needed (HAP Section 6.8) static void checkTimedWrites(); // checks for expired Timed Write PIDs, and clears any found (HAP Section 6.7.2.4) static void eventNotify(SpanBuf *pObj, int nObj, int ignoreClient=-1); // transmits EVENT Notifications for nObj SpanBuf objects, pObj, with optional flag to ignore a specific client diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 77f6e52..87d7aff 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -148,6 +148,7 @@ void Span::poll() { } // for-loop over connection slots HAPClient::callServiceLoops(); + HAPClient::checkPushButtons(); HAPClient::checkNotifications(); HAPClient::checkTimedWrites(); @@ -1152,4 +1153,52 @@ SpanRange::SpanRange(int min, int max, int step){ homeSpan.Accessories.back()->Services.back()->Characteristics.back()->range=this; } +/////////////////////////////// +// SpanButton // +/////////////////////////////// + +SpanButton::SpanButton(int pin, unsigned long longTime, unsigned long shortTime){ + + if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ + Serial.print("*** FATAL ERROR: Can't create new PushButton without a defined Service. Program halted!\n\n"); + while(1); + } + + Serial.print("Configuring PushButton: Pin="); // initialization message + Serial.print(pin); + Serial.print("\n"); + + this->pin=pin; + this->shortTime=shortTime; + this->longTime=longTime; + service=homeSpan.Accessories.back()->Services.back(); + + homeSpan.PushButtons.push_back(this); + + pinMode(pin,INPUT_PULLUP); +} + +/////////////////////////////// + +void SpanButton::check(){ + + if(state==UNTRIGGERED && !digitalRead(pin)){ + state=TRIGGERED; + unsigned long cTime=millis(); + shortAlarm=cTime+shortTime; + longAlarm=cTime+longTime; + } else + + if(state==TRIGGERED && digitalRead(pin)){ + unsigned long cTime=millis(); + if(cTime>longAlarm) + service->button(pin, true); + else if(cTime>shortAlarm) + service->button(pin, false); + state=UNTRIGGERED; + } + +} + + /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 4118ac5..06ddeea 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -25,6 +25,7 @@ struct SpanService; struct SpanCharacteristic; struct SpanRange; struct SpanBuf; +struct SpanButton; /////////////////////////////// @@ -49,6 +50,7 @@ struct Span{ vector Accessories; // vector of pointers to all Accessories vector Loops; // vector of pointer to all Services that have over-ridden loop() methods vector Notifications; // vector of SpanBuf objects that store info for Characteristics that are updated with setVal() and require a Notification Event + vector PushButtons; // vector of pointer to all PushButtons unordered_map TimedWrites; // map of timed-write PIDs and Alarm Times (based on TTLs) void begin(Category catID, @@ -105,7 +107,8 @@ struct SpanService{ int sprintfAttributes(char *cBuf); // prints Service JSON records into buf; return number of characters printed, excluding null terminator virtual StatusCode update() {return(StatusCode::OK);} // update Service and return final statusCode based on updated Characteristics - should be overridden by DEVICE-SPECIFIC Services virtual void event(){} // event generation for Services that create their own events and need to notify HomeKit of a new Characteristic value(s) - virtual void loop(){} // loops for each service + virtual void loop(){} // loops for each Service + virtual void button(int pin, boolean isLong){} // method called for a Service when a button attached to "pin" has a Short-Press or Long-Press, according to "isLong" }; /////////////////////////////// @@ -231,6 +234,28 @@ struct SpanBuf{ // temporary storage buffer for us SpanCharacteristic *characteristic=NULL; // Characteristic to update (NULL if not found) }; +/////////////////////////////// + +struct SpanButton{ + + int pin; // pin number + unsigned long shortTime; // time (in millis) required to register a short press + unsigned long longTime; // time (in millis) required to register a long press + unsigned long shortAlarm; // alarm time to trigger a short press + unsigned long longAlarm; // alarm time to triger a long press + SpanService *service; // Service to which this PushButton is attached + + enum { + UNTRIGGERED, + TRIGGERED, + SHORT, + LONG + } state=UNTRIGGERED; + + SpanButton(int pin, unsigned long longTime=2000, unsigned long shortTime=5); + void check(); +}; + ///////////////////////////////////////////////// // Extern Variables