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 ); };