Completed Example 11
Transtioned to all getter methods: getVal(), getNewVal(), updated(), using templates for all floats. Finalized templates for getVal and getNewVal, including making <int> 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.
This commit is contained in:
parent
3e4ada5912
commit
1fd493aa31
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -3,17 +3,11 @@
|
|||
// 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(){
|
||||
|
||||
new Characteristic::Name(name); // create all the required Characteristics with values set based on above arguments
|
||||
|
|
@ -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;i<nBlinks;i++){
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ struct DEV_LED : Service::LightBulb { // ON/OFF LED
|
|||
LOG1("Updating On/Off LED on pin=");
|
||||
LOG1(ledPin);
|
||||
LOG1(": Current Power=");
|
||||
LOG1(power->value.BOOL?"true":"false");
|
||||
LOG1(power->getVal()?"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<boolean>()?"true":"false");
|
||||
LOG1(power->getVal()?"true":"false");
|
||||
LOG1(" Current Brightness=");
|
||||
LOG1(level->getVal<int>());
|
||||
LOG1(level->getVal());
|
||||
|
||||
if(power->isUpdated){
|
||||
if(power->updated()){
|
||||
LOG1(" New Power=");
|
||||
LOG1(power->getNewVal<boolean>()?"true":"false");
|
||||
LOG1(power->getNewVal()?"true":"false");
|
||||
}
|
||||
|
||||
if(level->isUpdated){
|
||||
if(level->updated()){
|
||||
LOG1(" New Brightness=");
|
||||
LOG1(level->getNewVal<boolean>());
|
||||
LOG1(level->getNewVal());
|
||||
}
|
||||
|
||||
LOG1("\n");
|
||||
|
||||
pwmPin->set(channel,power->getNewVal<boolean>()*level->getNewVal<boolean>());
|
||||
pwmPin->set(channel,power->getNewVal()*level->getNewVal());
|
||||
|
||||
return(StatusCode::OK); // return OK status code
|
||||
|
||||
|
|
@ -98,6 +97,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
|||
};
|
||||
|
||||
//////////////////////////////////
|
||||
|
||||
struct DEV_RgbLED : Service::LightBulb { // RGB LED (Command Cathode)
|
||||
|
||||
PwmPin *redPin;
|
||||
|
|
@ -136,61 +136,65 @@ struct DEV_RgbLED : Service::LightBulb { // RGB LED (Command Cathode)
|
|||
StatusCode update(){ // update() method
|
||||
|
||||
boolean p;
|
||||
double v, h, s, r, g, b;
|
||||
float v, h, s, r, g, b;
|
||||
|
||||
h=H->getVal<double>(); // get all current values
|
||||
s=S->getVal<double>();
|
||||
v=V->getVal<double>();
|
||||
p=power->getVal<boolean>();
|
||||
h=H->getVal<float>(); // get and store all current values
|
||||
s=S->getVal<float>();
|
||||
v=V->getVal<float>();
|
||||
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<boolean>();
|
||||
sprintf(cBuf,"Power=%s->%s, ",power->getVal<boolean>()?"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<double>();
|
||||
sprintf(cBuf,"H=%d->%d, ",(int)H->getVal<double>(),(int)h);
|
||||
if(H->updated()){
|
||||
h=H->getNewVal<float>();
|
||||
sprintf(cBuf,"H=%.0f->%.0f, ",H->getVal<float>(),h);
|
||||
} else {
|
||||
sprintf(cBuf,"H=%d, ",(int)h);
|
||||
sprintf(cBuf,"H=%.0f, ",h);
|
||||
}
|
||||
LOG1(cBuf);
|
||||
|
||||
if(S->isUpdated){
|
||||
s=S->getNewVal<double>();
|
||||
sprintf(cBuf,"S=%d->%d, ",(int)S->getVal<double>(),(int)s);
|
||||
if(S->updated()){
|
||||
s=S->getNewVal<float>();
|
||||
sprintf(cBuf,"S=%.0f->%.0f, ",S->getVal<float>(),s);
|
||||
} else {
|
||||
sprintf(cBuf,"S=%d, ",(int)s);
|
||||
sprintf(cBuf,"S=%.0f, ",s);
|
||||
}
|
||||
LOG1(cBuf);
|
||||
|
||||
if(V->isUpdated){
|
||||
v=V->getNewVal<double>();
|
||||
sprintf(cBuf,"V=%d->%d ",(int)V->getVal<double>(),(int)v);
|
||||
if(V->updated()){
|
||||
v=V->getNewVal<float>();
|
||||
sprintf(cBuf,"V=%.0f->%.0f ",V->getVal<float>(),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);
|
||||
|
||||
|
|
|
|||
|
|
@ -165,10 +165,12 @@ 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 <class T> T getVal(){return(getValue<T>(value));} // returns UVal value
|
||||
template <class T> T getNewVal(){return(getValue<T>(newValue));} // returns UVal newValue
|
||||
template <class T=int> T getVal(){return(getValue<T>(value));} // returns UVal value
|
||||
template <class T=int> T getNewVal(){return(getValue<T>(newValue));} // returns UVal newValue
|
||||
template <class T> T getValue(UVal v); // returns UVal v
|
||||
|
||||
boolean updated(){return(isUpdated);} // returns isUpdated
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue