diff --git a/src/Characteristics.h b/src/Characteristics.h index e5d075f..5530d15 100644 --- a/src/Characteristics.h +++ b/src/Characteristics.h @@ -48,7 +48,8 @@ enum FORMAT { // HAP Table 6-5 UINT64=4, INT=5, FLOAT=6, - STRING=7 + STRING=7, + DATA=8 }; /////////////////////////////// @@ -195,6 +196,8 @@ struct HapCharacteristics { HAPCHAR( VolumeSelector, EA, PW, UINT8, true ); HAPCHAR( WaterLevel, B5, PR+EV, FLOAT, false ); + HAPCHAR( EveTest, 12345678-079E-48FF-8F27-9C2605A29F52, PW+PR+EV, DATA, false ); + }; extern HapCharacteristics hapChars; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 300c524..185dfda 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -934,7 +934,7 @@ void Span::processSerialCommand(const char *c){ Serial.printf("%s%s",(foundPerms++)?"+":"",pNames[i]); } - if((*chr)->format!=FORMAT::STRING && (*chr)->format!=FORMAT::BOOL){ + if((*chr)->format!=FORMAT::STRING && (*chr)->format!=FORMAT::BOOL && (*chr)->format!=FORMAT::DATA){ if((*chr)->validValues) Serial.printf(", Valid Values=%s",(*chr)->validValues); else if((*chr)->uvGet((*chr)->stepValue)>0) @@ -1378,7 +1378,7 @@ int Span::updateCharacteristics(char *buf, SpanBuf *pObj){ if(status==StatusCode::OK){ // if status is okay pObj[j].characteristic->uvSet(pObj[j].characteristic->value,pObj[j].characteristic->newValue); // update characteristic value with new value if(pObj[j].characteristic->nvsKey){ // if storage key found - if(pObj[j].characteristic->format != FORMAT::STRING) + if(pObj[j].characteristic->format!=FORMAT::STRING && pObj[j].characteristic->format!=FORMAT::DATA) nvs_set_blob(charNVS,pObj[j].characteristic->nvsKey,&(pObj[j].characteristic->value),sizeof(pObj[j].characteristic->value)); // store data else nvs_set_str(charNVS,pObj[j].characteristic->nvsKey,pObj[j].characteristic->value.STRING); // store data @@ -1771,7 +1771,7 @@ SpanCharacteristic::~SpanCharacteristic(){ free(validValues); free(nvsKey); - if(format==FORMAT::STRING){ + if(format==FORMAT::STRING || format==FORMAT::DATA){ free(value.STRING); free(newValue.STRING); } @@ -1786,7 +1786,7 @@ int SpanCharacteristic::sprintfAttributes(char *cBuf, int flags){ const char permCodes[][7]={"pr","pw","ev","aa","tw","hd","wr"}; - const char formatCodes[][8]={"bool","uint8","uint16","uint32","uint64","int","float","string"}; + const char formatCodes[][9]={"bool","uint8","uint16","uint32","uint64","int","float","string","data"}; nBytes+=snprintf(cBuf,cBuf?64:0,"{\"iid\":%d",iid); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index bb6efb1..7a34337 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -41,6 +41,7 @@ #include #include #include +#include #include "extras/Blinker.h" #include "extras/Pixel.h" @@ -476,6 +477,7 @@ class SpanCharacteristic{ sprintf(c,"%g",u.FLOAT); return(String(c)); case FORMAT::STRING: + case FORMAT::DATA: sprintf(c,"\"%s\"",u.STRING); return(String(c)); } // switch @@ -483,7 +485,7 @@ class SpanCharacteristic{ } void uvSet(UVal &dest, UVal &src){ - if(format==FORMAT::STRING) + if(format==FORMAT::STRING || format==FORMAT::DATA) uvSet(dest,(const char *)src.STRING); else dest=src; @@ -518,6 +520,7 @@ class SpanCharacteristic{ u.FLOAT=(double)val; break; case FORMAT::STRING: + case FORMAT::DATA: break; } // switch } @@ -540,6 +543,7 @@ class SpanCharacteristic{ case FORMAT::FLOAT: return((T) u.FLOAT); case FORMAT::STRING: + case FORMAT::DATA: break; } return(0); // included to prevent compiler warnings @@ -560,7 +564,7 @@ class SpanCharacteristic{ sprintf(nvsKey,"%04X%08X%03X",t,aid,iid&0xFFF); size_t len; - if(format != FORMAT::STRING){ + if(format!=FORMAT::STRING && format!=FORMAT::DATA){ if(!nvs_get_blob(homeSpan.charNVS,nvsKey,NULL,&len)){ nvs_get_blob(homeSpan.charNVS,nvsKey,&value,&len); } @@ -583,7 +587,7 @@ class SpanCharacteristic{ uvSet(newValue,value); - if(format != FORMAT::STRING) { + if(format!=FORMAT::STRING && format!=FORMAT::DATA) { uvSet(minValue,min); uvSet(maxValue,max); uvSet(stepValue,0); @@ -643,6 +647,61 @@ class SpanCharacteristic{ } // setString() + size_t getData(uint8_t *data, size_t len){ + if(format!=FORMAT::DATA) + return(0); + + size_t olen; + int ret=mbedtls_base64_decode(data,len,&olen,(uint8_t *)value.STRING,strlen(value.STRING)); + + if(data==NULL) + return(olen); + + if(ret==MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Destination buffer is too small (%d out of %d bytes needed)\n\n",hapName,len,olen); + else if(ret==MBEDTLS_ERR_BASE64_INVALID_CHARACTER) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Data is not in base-64 format\n\n",hapName); + + return(olen); + } + + size_t getNewData(uint8_t *data, size_t len){ + if(format!=FORMAT::DATA) + return(0); + + size_t olen; + int ret=mbedtls_base64_decode(data,len,&olen,(uint8_t *)newValue.STRING,strlen(newValue.STRING)); + + if(data==NULL) + return(olen); + + if(ret==MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Destination buffer is too small (%d out of %d bytes needed)\n\n",hapName,len,olen); + else if(ret==MBEDTLS_ERR_BASE64_INVALID_CHARACTER) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Data is not in base-64 format\n\n",hapName); + + return(olen); + } + + void setData(uint8_t *data, size_t len){ + + if((perms & EV) == 0){ + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. No NOTIFICATION permission on this characteristic\n\n",hapName); + return; + } + + if(len<1){ + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. Size of data buffer must be greater than zero\n\n",hapName); + return; + } + + size_t olen; + mbedtls_base64_encode(NULL,0,&olen,data,len); // get length of string buffer needed (mbedtls includes the trailing null in this size) + TempBuffer tBuf(olen); // create temporary string buffer, with room for trailing null + mbedtls_base64_encode((uint8_t*)tBuf.buf,olen,&olen,data,len ); // encode data into string buf + setString(tBuf.buf); // call setString to continue processing as if characteristic was a string + } + template void setVal(T val, boolean notify=true){ if((perms & EV) == 0){ diff --git a/src/Span.h b/src/Span.h index f751052..d7221be 100644 --- a/src/Span.h +++ b/src/Span.h @@ -526,6 +526,8 @@ namespace Characteristic { CREATE_CHAR(uint8_t,VolumeSelector,0,0,1); CREATE_CHAR(double,WaterLevel,0,0,100); + CREATE_CHAR(const char *,EveTest,"AAAA",0,1); + } //////////////////////////////////////////////////////// diff --git a/src/src.ino b/src/src.ino index 40d7395..b15dcb8 100644 --- a/src/src.ino +++ b/src/src.ino @@ -3,168 +3,42 @@ // as well as compile and test from this point. This file is ignored when the library is included in other sketches. #include "HomeSpan.h" -#include "FeatherPins.h" -#include "extras/Pixel.h" -#include "extras/RFControl.h" -#include "extras/Blinker.h" -#include "extras/PwmPin.h" - -#define STRING_t const char * // WORK-AROUND - -CUSTOM_CHAR(LightMode, AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA, PR, STRING, "ANY_VALUE", NULL, NULL, true); -CUSTOM_CHAR_STRING(DarkMode, AAAAAAAA-BBBB-AAAA-AAAA-AAAAAAAAAAAA, PR, "MY_VALUE"); - -SpanPoint *dev1; -SpanPoint *dev2; - -struct message_t { - char a[32]; - int b; - float c; - bool d; -} message; +Characteristic::EveTest *eveTest; void setup() { Serial.begin(115200); - -// homeSpan.setLogLevel(2); - homeSpan.setControlPin(F25); - homeSpan.setStatusPin(F26); -// homeSpan.setStatusPin(new LED(F26)); -// new Pixel(F27); + homeSpan.setLogLevel(2); + homeSpan.begin(Category::Lighting,"HomeSpan LightBulb"); - homeSpan.setHostNameSuffix("-lamp1"); - homeSpan.setPortNum(1201); -// homeSpan.setMaxConnections(6); -// homeSpan.setQRID("One1"); - homeSpan.enableOTA(); - homeSpan.setSketchVersion("OTA Test 8"); - homeSpan.setWifiCallback(wifiEstablished); - - homeSpan.setStatusCallback(statusUpdate); - - new SpanUserCommand('d',"- My Description",userCom1); - new SpanUserCommand('e',"- My second Description",userCom2); - -// homeSpan.enableAutoStartAP(); -// homeSpan.setApFunction(myWiFiAP); - - homeSpan.enableWebLog(10,"pool.ntp.org","UTC","myLog"); // creates a web log on the URL /HomeSpan-[DEVICE-ID].local:[TCP-PORT]/myLog - - SpanPoint::setChannelMask(1<<13); - - SpanPoint::setPassword("Hello Thert"); - - homeSpan.setLogLevel(1); - - dev2=new SpanPoint("7C:DF:A1:61:E4:A8",sizeof(int),sizeof(message_t)); - dev1=new SpanPoint("AC:67:B2:77:42:20",sizeof(int),0); - - homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); - - new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments - - new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, which has 6 required Characteristics - new Characteristic::Name("HomeSpan Test"); // Name of the Accessory, which shows up on the HomeKit "tiles", and should be unique across Accessories - new Characteristic::Manufacturer("HomeSpan"); // Manufacturer of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::SerialNumber("HSL-123"); // Serial Number of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::Model("HSL Test"); // Model of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::FirmwareRevision(HOMESPAN_VERSION); // Firmware of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::Identify(); // Create the required Identify - - new Service::HAPProtocolInformation(); // Create the HAP Protcol Information Service - new Characteristic::Version("1.1.0"); // Set the Version Characteristic to "1.1.0" as required by HAP + new SpanAccessory(); + new Service::AccessoryInformation(); + new Characteristic::Identify(); + new Service::LightBulb(); - new Characteristic::On(0); - new Characteristic::LightMode("HELLO"); - new Characteristic::DarkMode(); - new Characteristic::Brightness(50); - new Characteristic::Name("Light 1"); - new Characteristic::ColorTemperature(); - new Characteristic::Active(); + new Characteristic::On(); + new Characteristic::ConfiguredName(); + eveTest=new Characteristic::EveTest(); - - new Service::LightBulb(); - new Characteristic::On(0,true); - (new Characteristic::Brightness())->setRange(10,100,5); - new Characteristic::Name("Light 2"); + uint8_t x[]={0x01,0x26,0xFF,0x01,0x26,0xFF}; + eveTest->setData(x,6); + uint8_t y[6]={0}; + int n=eveTest->getData(y,10); + Serial.printf("%d:",n); + for(int i=0;isetRange(10,100,5); - new Characteristic::Name("Light 3"); - new Characteristic::TargetPosition(); - new Characteristic::OzoneDensity(); - (new Characteristic::OzoneDensity())->addPerms(PW|AA)->removePerms(EV|PR); - -} // end of setup() - -unsigned long alarmTime=0; +} ////////////////////////////////////// void loop(){ - homeSpan.poll(); -// if(dev1->get(&message)) -// Serial.printf("DEV1: '%s' %d %f %d\n",message.a,message.b,message.c,message.d); -// if(dev2->get(&message)) -// Serial.printf("DEV2: '%s' %d %f %d\n",message.a,message.b,message.c,message.d); -// -// if(millis()-alarmTime>5000){ -// alarmTime=millis(); -// boolean success = dev2->send(&alarmTime); -// Serial.printf("Success = %d\n",success); -// } - -} // end of loop() - -////////////////////////////////////// - -void myWiFiAP(){ - Serial.print("Calling My WIFI AP\n\n"); - homeSpan.setWifiCredentials("MY_NETWORK","MY_PASSWORD"); -} - -////////////////////////////////////// - -void wifiEstablished(){ - Serial.print("IN CALLBACK FUNCTION\n\n"); - Serial.printf("MODE = %d\n",WiFi.getMode()); - -} - -////////////////////////////////////// - -void userCom1(const char *v){ - Serial.printf("In User Command 1: '%s'\n\n",v); -} - -////////////////////////////////////// - -void userCom2(const char *v){ - Serial.printf("In User Command 2: '%s'\n\n",v); -} - -////////////////////////////////////// - -void statusUpdate(HS_STATUS status){ - Serial.printf("\n*** HOMESPAN STATUS CHANGE: %s\n",homeSpan.statusString(status)); + homeSpan.poll(); // run HomeSpan! + }