bool ClimateControlBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(climatecontrol_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case activeCoolingMode_key+descriptions_key_offset: aPropValue->setBoolValue(climateDeviceKind==climatedevice_fancoilunit); // FCUs can cool actively return true; // Settings properties case heatingSystemCapability_key+settings_key_offset: aPropValue->setUint8Value(heatingSystemCapability); return true; case heatingSystemType_key+settings_key_offset: aPropValue->setUint8Value(heatingSystemType); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties case heatingSystemCapability_key+settings_key_offset: setPVar(heatingSystemCapability, (VdcHeatingSystemCapability)aPropValue->uint8Value()); return true; case heatingSystemType_key+settings_key_offset: setPVar(heatingSystemType, (VdcHeatingSystemType)aPropValue->uint8Value()); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }
// access to all fields bool ChannelBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(channel_Key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case name_key+descriptions_key_offset: aPropValue->setStringValue(getName()); return true; case channelIndex_key+descriptions_key_offset: aPropValue->setUint8Value(channelIndex); return true; case min_key+descriptions_key_offset: aPropValue->setDoubleValue(getMin()); return true; case max_key+descriptions_key_offset: aPropValue->setDoubleValue(getMax()); return true; case resolution_key+descriptions_key_offset: aPropValue->setDoubleValue(getResolution()); return true; // Settings properties // - none for now // States properties case value_key+states_key_offset: // get value of channel, possibly calculating it if needed (color conversions) aPropValue->setDoubleValue(getChannelValueCalculated()); return true; case age_key+states_key_offset: if (channelLastSync==Never) aPropValue->setNull(); // no value known else aPropValue->setDoubleValue((double)(MainLoop::now()-channelLastSync)/Second); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties // - none for now // States properties case value_key+states_key_offset: setChannelValue(aPropValue->doubleValue(), 0, true); // always apply, no transition time return true; } } } // single class level properties only, don't call inherited return false; }
// access to all fields bool EnoceanDevice::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(enoceanDevice_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { case profileVariants_key: aPropValue->setType(apivalue_object); // make object (incoming object is NULL) return getProfileVariants(aPropValue); case profile_key: aPropValue->setInt32Value(getEEProfile()); return true; case packetage_key: // Note lastPacketTime is set to now at startup, so additionally check lastRSSI if (lastPacketTime==Never || lastRSSI<=-999) aPropValue->setNull(); else aPropValue->setDoubleValue((double)(MainLoop::now()-lastPacketTime)/Second); return true; case rssi_key: if (lastRSSI<=-999) aPropValue->setNull(); else aPropValue->setInt32Value(lastRSSI); return true; case repeaterCount_key: if (lastRSSI<=-999) aPropValue->setNull(); else aPropValue->setUint8Value(lastRepeaterCount); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { case profile_key: setProfileVariant(aPropValue->int32Value()); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }
bool SensorBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(sensor_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case sensorType_key+descriptions_key_offset: aPropValue->setUint16Value(sensorType); return true; case sensorUsage_key+descriptions_key_offset: aPropValue->setUint16Value(sensorUsage); return true; case min_key+descriptions_key_offset: aPropValue->setDoubleValue(min); return true; case max_key+descriptions_key_offset: aPropValue->setDoubleValue(max); return true; case resolution_key+descriptions_key_offset: aPropValue->setDoubleValue(resolution); return true; case updateInterval_key+descriptions_key_offset: aPropValue->setDoubleValue((double)updateInterval/Second); return true; case aliveSignInterval_key+descriptions_key_offset: aPropValue->setDoubleValue((double)aliveSignInterval/Second); return true; // Settings properties case group_key+settings_key_offset: aPropValue->setUint16Value(sensorGroup); return true; case minPushInterval_key+settings_key_offset: aPropValue->setDoubleValue((double)minPushInterval/Second); return true; case changesOnlyInterval_key+settings_key_offset: aPropValue->setDoubleValue((double)changesOnlyInterval/Second); return true; // States properties case value_key+states_key_offset: // value if (lastUpdate==Never) aPropValue->setNull(); else aPropValue->setDoubleValue(currentValue); return true; case age_key+states_key_offset: // age if (lastUpdate==Never) aPropValue->setNull(); else aPropValue->setDoubleValue((double)(MainLoop::now()-lastUpdate)/Second); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties case group_key+settings_key_offset: setPVar(sensorGroup, (DsGroup)aPropValue->int32Value()); return true; case minPushInterval_key+settings_key_offset: setPVar(minPushInterval, (MLMicroSeconds)(aPropValue->doubleValue()*Second)); return true; case changesOnlyInterval_key+settings_key_offset: setPVar(changesOnlyInterval, (MLMicroSeconds)(aPropValue->doubleValue()*Second)); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }
ErrorPtr PropertyContainer::accessProperty(PropertyAccessMode aMode, ApiValuePtr aQueryObject, ApiValuePtr aResultObject, int aDomain, PropertyDescriptorPtr aParentDescriptor) { ErrorPtr err; #if DEBUGFOCUSLOGGING FOCUSLOG("\naccessProperty: entered with query = %s\n", aQueryObject->description().c_str()); if (aParentDescriptor) { FOCUSLOG("- parentDescriptor '%s' (%s), fieldKey=%u, objectKey=%u\n", aParentDescriptor->name(), aParentDescriptor->isStructured() ? "structured" : "scalar", aParentDescriptor->fieldKey(), aParentDescriptor->objectKey()); } #endif // for reading, NULL query is like query { "":NULL } if (aQueryObject->isNull() && aMode==access_read) { aQueryObject->setType(apivalue_object); aQueryObject->add("", aQueryObject->newValue(apivalue_null)); } // aApiObject must be of type apivalue_object if (!aQueryObject->isType(apivalue_object)) return ErrorPtr(new VdcApiError(415, "Query or Value written must be object")); if (aMode==access_read) { if (!aResultObject) return ErrorPtr(new VdcApiError(415, "accessing property for read must provide result object")); aResultObject->setType(apivalue_object); // must be object } // Iterate trough elements of query object aQueryObject->resetKeyIteration(); string queryName; ApiValuePtr queryValue; string errorMsg; while (aQueryObject->nextKeyValue(queryName, queryValue)) { FOCUSLOG("- starting to process query element named '%s' : %s\n", queryName.c_str(), queryValue->description().c_str()); if (aMode==access_read && queryName=="#") { // asking for number of elements at this level -> generate and return int value queryValue = queryValue->newValue(apivalue_int64); // integer queryValue->setInt32Value(numProps(aDomain, aParentDescriptor)); aResultObject->add(queryName, queryValue); } else { // accessing an element or series of elements at this level bool wildcard = isMatchAll(queryName); // - find all descriptor(s) for this queryName PropertyDescriptorPtr propDesc; int propIndex = 0; bool foundone = false; do { propDesc = getDescriptorByName(queryName, propIndex, aDomain, aParentDescriptor); if (propDesc) { foundone = true; // found at least one descriptor for this query element FOCUSLOG(" - processing descriptor '%s' (%s), fieldKey=%u, objectKey=%u\n", propDesc->name(), propDesc->isStructured() ? "structured" : "scalar", propDesc->fieldKey(), propDesc->objectKey()); // actually access by descriptor if (propDesc->isStructured()) { ApiValuePtr subQuery; // property is a container. Now check the value if (queryValue->isType(apivalue_object)) { subQuery = queryValue; // query specifies next level, just use it } else if (queryName!="*" && (!wildcard || propDesc->isWildcardAddressable())) { // don't recurse deeper when query name is "*" or property is not wildcard-adressable // special case is "*" as leaf in query - only recurse if it is not present // - autocreate subquery subQuery = queryValue->newValue(apivalue_object); subQuery->add("", queryValue->newValue(apivalue_null)); } if (subQuery) { // addressed property is a container by itself -> recurse // - get the PropertyContainer int containerDomain = aDomain; // default to same, but getContainer may modify it PropertyDescriptorPtr containerPropDesc = propDesc; PropertyContainerPtr container = getContainer(containerPropDesc, containerDomain); if (container) { FOCUSLOG(" - container for '%s' is 0x%p\n", propDesc->name(), container.get()); FOCUSLOG(" >>>> RECURSING into accessProperty()\n"); if (aMode==access_read) { // read needs a result object ApiValuePtr resultValue = queryValue->newValue(apivalue_object); err = container->accessProperty(aMode, subQuery, resultValue, containerDomain, containerPropDesc); if (Error::isOK(err)) { // add to result with actual name (from descriptor) FOCUSLOG("\n <<<< RETURNED from accessProperty() recursion\n"); FOCUSLOG(" - accessProperty of container for '%s' returns %s\n", propDesc->name(), resultValue->description().c_str()); aResultObject->add(propDesc->name(), resultValue); } } else { // for write, just pass the query value err = container->accessProperty(aMode, subQuery, ApiValuePtr(), containerDomain, containerPropDesc); FOCUSLOG(" <<<< RETURNED from accessProperty() recursion\n", propDesc->name(), container.get()); } if ((aMode!=access_read) && Error::isOK(err)) { // give this container a chance to post-process write access err = writtenProperty(aMode, propDesc, aDomain, container); } // 404 errors are collected, but dont abort the query if (Error::isError(err, VdcApiError::domain(), 404)) { if (!errorMsg.empty()) errorMsg += "; "; errorMsg += string_format("Error(s) accessing subproperties of '%s' : { %s }", queryName.c_str(), err->description().c_str()); err.reset(); // forget the error on this level } } } } else { // addressed (and known by descriptor!) property is a simple value field -> access it if (aMode==access_read) { // read access: create a new apiValue and have it filled ApiValuePtr fieldValue = queryValue->newValue(propDesc->type()); // create a value of correct type to get filled bool accessOk = accessField(aMode, fieldValue, propDesc); // read // for read, not getting an OK from accessField means: property does not exist (even if known per descriptor), // so it will not be added to the result if (accessOk) { // add to result with actual name (from descriptor) aResultObject->add(propDesc->name(), fieldValue); } FOCUSLOG(" - accessField for '%s' returns %s\n", propDesc->name(), fieldValue->description().c_str()); } else { // write access: just pass the value if (!accessField(aMode, queryValue, propDesc)) { // write err = ErrorPtr(new VdcApiError(403,string_format("Write access to '%s' denied", propDesc->name()))); } } } } else { // no descriptor found for this query element // Note: this means that property is not KNOWN, which IS not the same as getting false from accessField // (latter means that property IS known, but has no value in the context it was queried) // HOWEVER, for the vdc API it was decided that for reading, these cases should NOT be // distinguished for getProperty. If a property does not exist for either reason, the return tree just does // no contain that property. // Also note that not having a property is not the same as not having a property VALUE: // latter case will explicitly return a NULL value if (!wildcard && !foundone && aMode!=access_read) { // query did address a specific property but it is unknown -> report as error (for read AND write!) // - collect error message, but do not abort query processing if (!errorMsg.empty()) errorMsg += "; "; errorMsg += string_format("Unknown property '%s' -> ignored", queryName.c_str()); } } } while (Error::isOK(err) && propIndex!=PROPINDEX_NONE); } // now generate error if we have collected a non-empty error message if (!errorMsg.empty()) { err = ErrorPtr(new VdcApiError(404,errorMsg)); } #if DEBUGLOGGING if (aMode==access_read) { FOCUSLOG("- query element named '%s' now has result object: %s\n", queryName.c_str(), aResultObject->description().c_str()); } #endif } return err; }
// access to all fields bool ChannelBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(channel_Key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case name_key+descriptions_key_offset: aPropValue->setStringValue(getName()); return true; case channelIndex_key+descriptions_key_offset: if (aPropertyDescriptor->getApiVersion()>=3) return false; // property does not exist any more in v3 and later aPropValue->setUint8Value(channelIndex); return true; case dsIndex_key+descriptions_key_offset: aPropValue->setUint8Value(channelIndex); return true; case channelType_key+descriptions_key_offset: aPropValue->setUint8Value(getChannelType()); return true; case siunit_key+descriptions_key_offset: aPropValue->setStringValue(valueUnitName(getChannelUnit(), false)); return true; case unitsymbol_key+descriptions_key_offset: aPropValue->setStringValue(valueUnitName(getChannelUnit(), true)); return true; case min_key+descriptions_key_offset: aPropValue->setDoubleValue(getMin()); return true; case max_key+descriptions_key_offset: aPropValue->setDoubleValue(getMax()); return true; case resolution_key+descriptions_key_offset: aPropValue->setDoubleValue(getResolution()); return true; // Settings properties // - none for now // States properties case value_key+states_key_offset: // get value of channel, possibly calculating it if needed (color conversions) aPropValue->setDoubleValue(getChannelValueCalculated()); return true; case age_key+states_key_offset: if (channelLastSync==Never) aPropValue->setNull(); // no value known else aPropValue->setDoubleValue((double)(MainLoop::now()-channelLastSync)/Second); // time of last sync (does not necessarily relate to currently visible "value", as this might be a to-be-applied new value already) return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties // - none for now // States properties case value_key+states_key_offset: setChannelValue(aPropValue->doubleValue(), output.transitionTime, true); // always apply, default transition time (normally 0, unless set in outputState) return true; } } } // single class level properties only, don't call inherited return false; }
bool OutputBehaviour::accessField(PropertyAccessMode aMode, ApiValuePtr aPropValue, PropertyDescriptorPtr aPropertyDescriptor) { if (aPropertyDescriptor->hasObjectKey(output_groups_key)) { if (aMode==access_read) { // read group membership if (isMember((DsGroup)aPropertyDescriptor->fieldKey())) { aPropValue->setBoolValue(true); return true; } return false; } else { // write group setGroupMembership((DsGroup)aPropertyDescriptor->fieldKey(), aPropValue->boolValue()); return true; } } else if (aPropertyDescriptor->hasObjectKey(output_key)) { if (aMode==access_read) { // read properties switch (aPropertyDescriptor->fieldKey()) { // Description properties case outputFunction_key+descriptions_key_offset: aPropValue->setUint8Value(outputFunction); return true; case outputUsage_key+descriptions_key_offset: aPropValue->setUint16Value(outputUsage); return true; case variableRamp_key+descriptions_key_offset: aPropValue->setBoolValue(variableRamp); return true; case maxPower_key+descriptions_key_offset: aPropValue->setDoubleValue(maxPower); return true; // Settings properties case mode_key+settings_key_offset: aPropValue->setUint8Value(actualOutputMode()); // return actual mode, never outputmode_default return true; case pushChanges_key+settings_key_offset: aPropValue->setBoolValue(pushChanges); return true; // State properties case localPriority_key+states_key_offset: aPropValue->setBoolValue(localPriority); return true; } } else { // write properties switch (aPropertyDescriptor->fieldKey()) { // Settings properties case mode_key+settings_key_offset: setOutputMode((DsOutputMode)aPropValue->int32Value()); return true; case pushChanges_key+settings_key_offset: setPVar(pushChanges, aPropValue->boolValue()); return true; // State properties case localPriority_key+states_key_offset: setPVar(localPriority, aPropValue->boolValue()); return true; } } } // not my field, let base class handle it return inherited::accessField(aMode, aPropValue, aPropertyDescriptor); }