diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 1dde9af..5a9f1a9 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -904,9 +904,22 @@ void Span::processSerialCommand(const char *c){ else LOG0(", %sRange=[%s,%s]",(*chr)->customRange?"Custom-":"",(*chr)->uvPrint((*chr)->minValue).c_str(),(*chr)->uvPrint((*chr)->maxValue).c_str()); } + + if(((*chr)->perms)&EV){ + LOG0(", EV=("); + boolean addComma=false; + for(int i=0;iev[i] && hap[i]->client){ + LOG0("%s%d",addComma?",":"",i); + addComma=true; + } + } + LOG0(")"); + } if((*chr)->nvsKey) LOG0(" (nvs)"); + LOG0("\n"); if(!(*chr)->isCustom && !(*svc)->isCustom && std::find((*svc)->req.begin(),(*svc)->req.end(),(*chr)->hapChar)==(*svc)->req.end() && std::find((*svc)->opt.begin(),(*svc)->opt.end(),(*chr)->hapChar)==(*svc)->opt.end()) @@ -1420,10 +1433,10 @@ int Span::updateCharacteristics(char *buf, SpanBuf *pObj){ } else { pObj[i].characteristic = find(pObj[i].aid,pObj[i].iid); // find characteristic with matching aid/iid and store pointer - if(pObj[i].characteristic) // if found, initialize characterstic update with new val/ev - pObj[i].status=pObj[i].characteristic->loadUpdate(pObj[i].val,pObj[i].ev); // save status code, which is either an error, or TBD (in which case isUpdated for the characteristic has been set to true) + if(pObj[i].characteristic) // if found, initialize characterstic update with new val/ev + pObj[i].status=pObj[i].characteristic->loadUpdate(pObj[i].val,pObj[i].ev,pObj[i].wr); // save status code, which is either an error, or TBD (in which case updateFlag for the characteristic has been set to either 1 or 2) else - pObj[i].status=StatusCode::UnknownResource; // if not found, set HAP error + pObj[i].status=StatusCode::UnknownResource; // if not found, set HAP error } } // first pass @@ -1455,7 +1468,7 @@ int Span::updateCharacteristics(char *buf, SpanBuf *pObj){ pObj[j].characteristic->uvSet(pObj[j].characteristic->newValue,pObj[j].characteristic->value); // replace characteristic new value with original value LOG1(" (failed)\n"); } - pObj[j].characteristic->isUpdated=false; // reset isUpdated flag for characteristic + pObj[j].characteristic->updateFlag=0; // reset updateFlag for characteristic } } @@ -1899,7 +1912,7 @@ void SpanCharacteristic::printfAttributes(int flags){ /////////////////////////////// -StatusCode SpanCharacteristic::loadUpdate(char *val, char *ev){ +StatusCode SpanCharacteristic::loadUpdate(char *val, char *ev, boolean wr){ if(ev){ // request for notification boolean evFlag; @@ -2000,7 +2013,7 @@ StatusCode SpanCharacteristic::loadUpdate(char *val, char *ev){ } // switch - isUpdated=true; + updateFlag=1+wr; // set flag to 1 if successful update or 2 if successful AND write-response flag is set updateTime=homeSpan.snapTime; return(StatusCode::TBD); } diff --git a/src/HomeSpan.h b/src/HomeSpan.h index deeb737..f3ce254 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -500,13 +500,13 @@ class SpanCharacteristic{ boolean setValidValuesError=false; // flag to indicate attempt to set Valid Values on Characteristic that does not support changes to Valid Values uint32_t aid=0; // Accessory ID - passed through from Service containing this Characteristic - boolean isUpdated=false; // set to true when new value has been requested by PUT /characteristic + uint8_t updateFlag=0; // set to either 1 (for normal write) or 2 (for write-response) inside update() when Characteristic is successfully updated via Home App unsigned long updateTime=0; // last time value was updated (in millis) either by PUT /characteristic OR by setVal() UVal newValue; // the updated value requested by PUT /characteristic SpanService *service=NULL; // pointer to Service containing this Characteristic - void printfAttributes(int flags); // writes Characteristic JSON to hapOut stream - StatusCode loadUpdate(char *val, char *ev); // load updated val/ev from PUT /characteristic JSON request. Return intitial HAP status code (checks to see if characteristic is found, is writable, etc.) + void printfAttributes(int flags); // writes Characteristic JSON to hapOut stream + StatusCode loadUpdate(char *val, char *ev, boolean wr); // load updated val/ev from PUT /characteristic JSON request. Return intitial HAP status code (checks to see if characteristic is found, is writable, etc.) String uvPrint(UVal &u){ char c[67]; // space for 64 characters + surrounding quotes + terminating null @@ -669,28 +669,35 @@ class SpanCharacteristic{ return NULL; } - void setString(const char *val){ + void setString(const char *val, boolean notify=true){ - if((perms & EV) == 0){ - LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setString() ignored. No NOTIFICATION permission on this characteristic\n\n",hapName); + if(!((perms&EV) || (updateFlag==2))){ + LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. No EVENT NOTIFICATION (EV) permission on this characteristic\n\n",hapName); return; - } + } + + if(updateFlag==1) + LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setVal() within update() while it is being updated by Home App. This may cause device to become non-responsive!\n\n",hapName); uvSet(value,val); uvSet(newValue,value); updateTime=homeSpan.snapTime; - - SpanBuf sb; // create SpanBuf object - sb.characteristic=this; // set characteristic - sb.status=StatusCode::OK; // set status - char dummy[]=""; - sb.val=dummy; // set dummy "val" so that printfNotify knows to consider this "update" - homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector - if(nvsKey){ - nvs_set_str(homeSpan.charNVS,nvsKey,value.STRING); // store data - nvs_commit(homeSpan.charNVS); + if(notify){ + if(updateFlag!=2){ // do not broadcast EV if update is being done in context of write-response + SpanBuf sb; // create SpanBuf object + sb.characteristic=this; // set characteristic + sb.status=StatusCode::OK; // set status + char dummy[]=""; + sb.val=dummy; // set dummy "val" so that printfNotify knows to consider this "update" + homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector + } + + if(nvsKey){ + nvs_set_str(homeSpan.charNVS,nvsKey,value.STRING); // store data + nvs_commit(homeSpan.charNVS); + } } } // setString() @@ -731,12 +738,12 @@ class SpanCharacteristic{ return(olen); } - void setData(uint8_t *data, size_t len){ + void setData(uint8_t *data, size_t len, boolean notify=true){ - if((perms & EV) == 0){ - LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. No NOTIFICATION permission on this characteristic\n\n",hapName); + if(!((perms&EV) || (updateFlag==2))){ + LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. No EVENT NOTIFICATION (EV) permission on this characteristic\n\n",hapName); return; - } + } if(len<1){ LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. Size of data buffer must be greater than zero\n\n",hapName); @@ -744,18 +751,21 @@ class SpanCharacteristic{ } 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(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.get(),olen,&olen,data,len ); // encode data into string buf - setString(tBuf); // call setString to continue processing as if characteristic was a string + setString(tBuf,notify); // call setString to continue processing as if characteristic was a string } template void setVal(T val, boolean notify=true){ - if((perms & EV) == 0){ - LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setVal() ignored. No NOTIFICATION permission on this characteristic\n\n",hapName); + if(!((perms&EV) || (updateFlag==2))){ + LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. No EVENT NOTIFICATION (EV) permission on this characteristic\n\n",hapName); return; - } + } + + if(updateFlag==1) + LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setVal() within update() while it is being updated by Home App. This may cause device to become non-responsive!\n\n",hapName); if(!((val >= uvGet(minValue)) && (val <= uvGet(maxValue)))){ LOG0("\n*** WARNING: Attempt to update Characteristic::%s with setVal(%g) is out of range [%g,%g]. This may cause device to become non-responsive!\n\n", @@ -768,13 +778,15 @@ class SpanCharacteristic{ updateTime=homeSpan.snapTime; if(notify){ - SpanBuf sb; // create SpanBuf object - sb.characteristic=this; // set characteristic - sb.status=StatusCode::OK; // set status - char dummy[]=""; - sb.val=dummy; // set dummy "val" so that printfNotify knows to consider this "update" - homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector - + if(updateFlag!=2){ // do not broadcast EV if update is being done in context of write-response + SpanBuf sb; // create SpanBuf object + sb.characteristic=this; // set characteristic + sb.status=StatusCode::OK; // set status + char dummy[]=""; + sb.val=dummy; // set dummy "val" so that printfNotify knows to consider this "update" + homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector + } + if(nvsKey){ nvs_set_u64(homeSpan.charNVS,nvsKey,value.UINT64); // store data as uint64_t regardless of actual type (it will be read correctly when access through uvGet()) nvs_commit(homeSpan.charNVS); @@ -783,8 +795,8 @@ class SpanCharacteristic{ } // setVal() - boolean updated(){return(isUpdated);} // returns isUpdated - unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated + boolean updated(){return(updateFlag>0);} // returns true within update() if Characteristic was updated by Home App + unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated, either by Home App or by using setVal() SpanCharacteristic *setValidValues(int n, ...); // sets a list of 'n' valid values allowed for a Characteristic and returns pointer to self. Only applicable if format=INT, UINT8, UINT16, or UINT32