From 1fd493aa31d564b6b07aebd06a1e639968446614 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 4 Aug 2020 07:56:53 -0500 Subject: [PATCH] Completed Example 11 Transtioned to all getter methods: getVal(), getNewVal(), updated(), using templates for all floats. Finalized templates for getVal and getNewVal, including making default so it does not have to be set for most getVal() and getNewVal() calls. Works for booleans as well. TO DO: Re-work and check ALL prior examples to ensure they use getVal, etc., and DON'T access value, newValue, isUpdated, directly. --- examples/Advanced/11-RGB_LED/11-RGB_LED.ino | 14 +++- examples/Advanced/11-RGB_LED/DEV_Identify.h | 25 ------- examples/Advanced/11-RGB_LED/DEV_LED.h | 76 +++++++++++---------- src/HomeSpan.h | 8 ++- src/extras/PwmPin.cpp | 4 +- src/extras/PwmPin.h | 2 +- 6 files changed, 60 insertions(+), 69 deletions(-) diff --git a/examples/Advanced/11-RGB_LED/11-RGB_LED.ino b/examples/Advanced/11-RGB_LED/11-RGB_LED.ino index 5e88231..1bac00d 100644 --- a/examples/Advanced/11-RGB_LED/11-RGB_LED.ino +++ b/examples/Advanced/11-RGB_LED/11-RGB_LED.ino @@ -18,6 +18,8 @@ void setup() { // Example 11 illustrates how to control an RGB LED to set any color and brightness. // The config below should look familiar by now. We've created a new derived Service, // call RgbLED to house all the required logic. You'll find all the code in DEV_LED.h. + // For completeness, the config also contains an on/off LED and a dimmable LED as shown + // in prior examples. Serial.begin(115200); @@ -30,8 +32,16 @@ void setup() { new Characteristic::Version("1.1.0"); new SpanAccessory(); - new DEV_Identify("LED Blinker","HomeSpan","123-ABC","20mA LED","0.9",0); - new DEV_RgbLED(0,1,2,32,22,23); // An RGB LED requires three PWM channels and three pins to be specified + new DEV_Identify("On/Off LED","HomeSpan","123-ABC","20mA LED","0.9",0); + new DEV_LED(16); // Create an On/Off LED attached to pin 16 + + new SpanAccessory(); + new DEV_Identify("Dimmable LED","HomeSpan","123-ABC","20mA LED","0.9",0); + new DEV_DimmableLED(0,17); // Create a Dimmable LED using PWM channel 0, attached to pin 17 + + new SpanAccessory(); + new DEV_Identify("RGB LED","HomeSpan","123-ABC","20mA LED","0.9",0); + new DEV_RgbLED(1,2,3,32,22,23); // Create an RGB LED using PWM channels 1,2,3, attached to pins 32,22,23 (for R, G, and B LED anodes) } // end of setup() diff --git a/examples/Advanced/11-RGB_LED/DEV_Identify.h b/examples/Advanced/11-RGB_LED/DEV_Identify.h index 17cd16f..7e6826f 100644 --- a/examples/Advanced/11-RGB_LED/DEV_Identify.h +++ b/examples/Advanced/11-RGB_LED/DEV_Identify.h @@ -3,16 +3,10 @@ // DEVICE-SPECIFIC SERVICES // ////////////////////////////////// -// Here we define the DEV_Identify Service as derived class of AccessoryInformation - 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 - - // Next we define the constructor using all the arguments needed to implement the required Characteristics - // of AccessoryInformation, plus one extra argument at the end called "nBlinks" we will use to specify how many - // times HomeSpan should blink the built-in LED when HomeKit calls this device's Identify routine during pairing. DEV_Identify(char *name, char *manu, char *sn, char *model, char *version, int nBlinks) : Service::AccessoryInformation(){ @@ -28,25 +22,6 @@ struct DEV_Identify : Service::AccessoryInformation { pinMode(LED_BUILTIN,OUTPUT); // make sure built-in LED is set for output } - // How HomeKit Identifies Devices: - // - // When HomeKit first pairs with a new device it "calls" that device's identify routine for every defined Accessory. - // To do so, HomeKit requests the Identify Characteristic for each defined AccessoryInformation Service to be set to "true". - // The Identify Characteristic is write-only, so no value is ever stored, even though HomeKit is requesting its value - // be updated. We can therefore use the same update() method as if the Identify Characteristic was the same as any - // other boolean Characteristic. - - // There are many ways to implement some form of identification. For an LED, you could blink it one or more times. - // For a LightBulb, you can flash it on and off. For window shade, you could raise and lower it. - // Most commerical devices don't do anything. Because HomeSpan can be used to control many different types of - // device, below we implement a very generic routine that simply blinks the internal LED of the ESP32 the - // number of times specified above. In principle, this code could call a user-defined routine that is different - // for each physcially-attached device (light, shade, fan, etc), but in practice this is overkill. - - // Note that the blink routine below starts by turning off the built-in LED and then leaves it on once it has blinked - // the specified number of times. This is because when HomeSpan starts up if confirms to user that it has connected - // to the WiFi network by turning on the built-in LED. Thus we want to leave it on when blinking is completed. - StatusCode update(){ for(int i=0;igetVal()?"true":"false"); LOG1(" New Power="); - LOG1(power->newValue.BOOL?"true":"false"); + LOG1(power->getNewVal()?"true":"false"); LOG1("\n"); - digitalWrite(ledPin,power->newValue.BOOL); + digitalWrite(ledPin,power->getNewVal()); return(StatusCode::OK); // return OK status code @@ -73,24 +73,23 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED LOG1("Updating Dimmable LED on pin="); LOG1(ledPin); LOG1(": Current Power="); - LOG1(power->value.BOOL?"true":"false"); - LOG1(power->getVal()?"true":"false"); + LOG1(power->getVal()?"true":"false"); LOG1(" Current Brightness="); - LOG1(level->getVal()); + LOG1(level->getVal()); - if(power->isUpdated){ + if(power->updated()){ LOG1(" New Power="); - LOG1(power->getNewVal()?"true":"false"); + LOG1(power->getNewVal()?"true":"false"); } - if(level->isUpdated){ + if(level->updated()){ LOG1(" New Brightness="); - LOG1(level->getNewVal()); + LOG1(level->getNewVal()); } LOG1("\n"); - pwmPin->set(channel,power->getNewVal()*level->getNewVal()); + pwmPin->set(channel,power->getNewVal()*level->getNewVal()); return(StatusCode::OK); // return OK status code @@ -98,7 +97,8 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED }; ////////////////////////////////// -struct DEV_RgbLED : Service::LightBulb { // RGB LED (Command Cathode) + +struct DEV_RgbLED : Service::LightBulb { // RGB LED (Command Cathode) PwmPin *redPin; PwmPin *greenPin; @@ -133,64 +133,68 @@ struct DEV_RgbLED : Service::LightBulb { // RGB LED (Command Cathode) } // end constructor - StatusCode update(){ // update() method + StatusCode update(){ // update() method boolean p; - double v, h, s, r, g, b; + float v, h, s, r, g, b; - h=H->getVal(); // get all current values - s=S->getVal(); - v=V->getVal(); - p=power->getVal(); + h=H->getVal(); // get and store all current values + s=S->getVal(); + v=V->getVal(); + p=power->getVal(); char cBuf[128]; sprintf(cBuf,"Updating RGB LED on pins=(%d,%d,%d): ",redPin->getPin(),greenPin->getPin(),bluePin->getPin()); LOG1(cBuf); - if(power->isUpdated){ - p=power->getNewVal(); - sprintf(cBuf,"Power=%s->%s, ",power->getVal()?"true":"false",p?"true":"false"); + if(power->updated()){ + p=power->getNewVal(); + sprintf(cBuf,"Power=%s->%s, ",power->getVal()?"true":"false",p?"true":"false"); } else { sprintf(cBuf,"Power=%s, ",p?"true":"false"); } LOG1(cBuf); - if(H->isUpdated){ - h=H->getNewVal(); - sprintf(cBuf,"H=%d->%d, ",(int)H->getVal(),(int)h); + if(H->updated()){ + h=H->getNewVal(); + sprintf(cBuf,"H=%.0f->%.0f, ",H->getVal(),h); } else { - sprintf(cBuf,"H=%d, ",(int)h); + sprintf(cBuf,"H=%.0f, ",h); } LOG1(cBuf); - if(S->isUpdated){ - s=S->getNewVal(); - sprintf(cBuf,"S=%d->%d, ",(int)S->getVal(),(int)s); + if(S->updated()){ + s=S->getNewVal(); + sprintf(cBuf,"S=%.0f->%.0f, ",S->getVal(),s); } else { - sprintf(cBuf,"S=%d, ",(int)s); + sprintf(cBuf,"S=%.0f, ",s); } LOG1(cBuf); - if(V->isUpdated){ - v=V->getNewVal(); - sprintf(cBuf,"V=%d->%d ",(int)V->getVal(),(int)v); + if(V->updated()){ + v=V->getNewVal(); + sprintf(cBuf,"V=%.0f->%.0f ",V->getVal(),v); } else { - sprintf(cBuf,"V=%d ",(int)v); + sprintf(cBuf,"V=%.0f ",v); } LOG1(cBuf); - PwmPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b); + // Here we call a static function of PwmPin that converts HSV to RGB. + // Parameters must all be floats in range of H[0,360], S[0,1], and V[0,1] + // R, G, B, returned [0,1] range as well + + PwmPin::HSVtoRGB(h,s/100.0,v/100.0,&r,&g,&b); // since HomeKit provides S and V in percent, scale down by 100 int R, G, B; - R=p*r*100; + R=p*r*100; // since PwmPin uses percent, scale back up by 100, and multiple by status fo power (either 0 or 1) G=p*g*100; B=p*b*100; sprintf(cBuf,"RGB=(%d,%d,%d)\n",R,G,B); LOG1(cBuf); - redPin->set(redChannel,R); + redPin->set(redChannel,R); // update the PWM channels with new values greenPin->set(greenChannel,G); bluePin->set(blueChannel,B); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index a047745..680cdf6 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -165,9 +165,11 @@ struct SpanCharacteristic{ int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator StatusCode loadUpdate(char *val, char *ev); // load updated val/ev from PUT /characteristic JSON request. Return intiial HAP status code (checks to see if characteristic is found, is writable, etc.) - template T getVal(){return(getValue(value));} // returns UVal value - template T getNewVal(){return(getValue(newValue));} // returns UVal newValue - template T getValue(UVal v); // returns UVal v + template T getVal(){return(getValue(value));} // returns UVal value + template T getNewVal(){return(getValue(newValue));} // returns UVal newValue + template T getValue(UVal v); // returns UVal v + + boolean updated(){return(isUpdated);} // returns isUpdated }; diff --git a/src/extras/PwmPin.cpp b/src/extras/PwmPin.cpp index a1004b0..6fb67cf 100644 --- a/src/extras/PwmPin.cpp +++ b/src/extras/PwmPin.cpp @@ -33,7 +33,7 @@ void PwmPin::set(uint8_t channel, uint8_t level){ /////////////////// -void PwmPin::HSVtoRGB(double h, double s, double v, double *r, double *g, double *b ){ +void PwmPin::HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ){ // The algorithm below was provided on the web at https://www.cs.rit.edu/~ncs/color/t_convert.html // h = [0,360] @@ -41,7 +41,7 @@ void PwmPin::HSVtoRGB(double h, double s, double v, double *r, double *g, double // v = [0,1] int i; - double f, p, q, t; + float f, p, q, t; if( s == 0 ){ *r = *g = *b = v; diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index 82180a3..e292742 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -20,6 +20,6 @@ class PwmPin { void set(uint8_t channel, uint8_t level); // sets the PWM duty of channel to level (0-100) int getPin(){return pin;} // returns the pin number - static void HSVtoRGB(double h, double s, double v, double *r, double *g, double *b ); + static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); };