Added native support for WR (write-response)

HAPClient::putCharacteristics() now parses for "r":true in JSON, which is the HAP request for a write-response.  When found, HomeSpan will return with a full write-response for all Characteristics updated using "207 Multi-Status", where "value" will be included only if "r":true was specified for a Characteristic.

HomeSpan processes "r":true for any Characteristic regardless if permissions includes WR.

To change the value of the Characteristic from within an update() method, use setVal() WITH OPTIONAL SECOND ARGUMENT AS FALSE to supress an EV broadcast (in the unlikely event that there was a notification subscriber).

To do: Consider generally disallowing the changing of any Characteristic value from within update() using setVal() unless the Characteristic has WR permission.  And if so, automatically surpress EV notification.
This commit is contained in:
Gregg 2024-03-15 17:35:04 -05:00
parent 181c5e99b2
commit 8ce80157b3
3 changed files with 15 additions and 6 deletions

View File

@ -998,10 +998,10 @@ int HAPClient::putCharacteristicsURL(char *json){
if(!homeSpan.updateCharacteristics(json, pObj)) // perform update if(!homeSpan.updateCharacteristics(json, pObj)) // perform update
return(0); // return if failed to update (error message will have been printed in update) return(0); // return if failed to update (error message will have been printed in update)
int multiCast=0; // check if all status is OK, or if multicast response is request boolean multiCast=false;
for(int i=0;i<n;i++) for(int i=0;i<n && !multiCast;i++) // for each characterstic, check if any status is either NOT OKAY, or if WRITE-RESPONSE is requested
if(pObj[i].status!=StatusCode::OK) if(pObj[i].status!=StatusCode::OK || pObj[i].wr) // if so, to use multicast response
multiCast=1; multiCast=true;
LOG2("\n>>>>>>>>>> %s >>>>>>>>>>\n",client.remoteIP().toString().c_str()); LOG2("\n>>>>>>>>>> %s >>>>>>>>>>\n",client.remoteIP().toString().c_str());

View File

@ -1378,6 +1378,9 @@ int Span::updateCharacteristics(char *buf, SpanBuf *pObj){
pObj[nObj].ev=t3; pObj[nObj].ev=t3;
okay|=8; okay|=8;
} else } else
if(!strcmp(t2,"r") && (t3=strtok_r(t1,"}[]:, \"\t\n\r",&p2))){
pObj[nObj].wr=(t3 && (!strcmp(t3,"1") || !strcmp(t3,"true")));
} else
if(!strcmp(t2,"pid") && (t3=strtok_r(t1,"}[]:, \"\t\n\r",&p2))){ if(!strcmp(t2,"pid") && (t3=strtok_r(t1,"}[]:, \"\t\n\r",&p2))){
uint64_t pid=strtoull(t3,NULL,0); uint64_t pid=strtoull(t3,NULL,0);
if(!TimedWrites.count(pid)){ if(!TimedWrites.count(pid)){
@ -1396,6 +1399,8 @@ int Span::updateCharacteristics(char *buf, SpanBuf *pObj){
if(!t1){ // at least one token was found that was not initial "characteristics" if(!t1){ // at least one token was found that was not initial "characteristics"
if(okay==7 || okay==11 || okay==15){ // all required properties found if(okay==7 || okay==11 || okay==15){ // all required properties found
if(!pObj[nObj].val) // if value is NOT being updated
pObj[nObj].wr=false; // ignore any request for write-response
nObj++; // increment number of characteristic objects found nObj++; // increment number of characteristic objects found
} else { } else {
LOG0("\n*** ERROR: Problems parsing JSON characteristics object - missing required properties\n\n"); LOG0("\n*** ERROR: Problems parsing JSON characteristics object - missing required properties\n\n");
@ -1507,7 +1512,10 @@ void Span::printfAttributes(SpanBuf *pObj, int nObj){
hapOut << "{\"characteristics\":["; hapOut << "{\"characteristics\":[";
for(int i=0;i<nObj;i++){ for(int i=0;i<nObj;i++){
hapOut << "{\"aid\":" << pObj[i].aid << ",\"iid\":" << pObj[i].iid << ",\"status\":" << (int)pObj[i].status << "}"; hapOut << "{\"aid\":" << pObj[i].aid << ",\"iid\":" << pObj[i].iid << ",\"status\":" << (int)pObj[i].status;
if(pObj[i].status==StatusCode::OK && pObj[i].wr && pObj[i].characteristic)
hapOut << ",\"value\":" << pObj[i].characteristic->uvPrint(pObj[i].characteristic->value).c_str();
hapOut << "}";
if(i+1<nObj) if(i+1<nObj)
hapOut << ","; hapOut << ",";
} }

View File

@ -136,6 +136,7 @@ struct SpanConfig{
struct SpanBuf{ // temporary storage buffer for use with putCharacteristicsURL() and checkTimedResets() struct SpanBuf{ // temporary storage buffer for use with putCharacteristicsURL() and checkTimedResets()
uint32_t aid=0; // updated aid uint32_t aid=0; // updated aid
int iid=0; // updated iid int iid=0; // updated iid
boolean wr=false; // flag to indicate write-response has been requested
char *val=NULL; // updated value (optional, though either at least 'val' or 'ev' must be specified) char *val=NULL; // updated value (optional, though either at least 'val' or 'ev' must be specified)
char *ev=NULL; // updated event notification flag (optional, though either at least 'val' or 'ev' must be specified) char *ev=NULL; // updated event notification flag (optional, though either at least 'val' or 'ev' must be specified)
StatusCode status; // return status (HAP Table 6-11) StatusCode status; // return status (HAP Table 6-11)