cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - Did you get an answer that solved your problem? Please mark it as an Accepted Solution so others with the same problem can find the answer easily. X

Inherit thing shapes to thing shapes

drieder
15-Moonstone

Inherit thing shapes to thing shapes

Hello everyone,

 

so I am wondering whether it is possible to "extend" a thing shape by another thing shape.

 

E.g I have a thing shape called "ThingWithLocation" which just contains a location property and another Thing Shape called "ThingWithState" which contains some sort of state property.

 

Now I would like to create a Third Thing Shape called "ThingWithStateAndLocation" without defining it from scratch (would be a lot of redundant code in case of more complex services contained in the thing shapes).

 

Note: I am aware that you can simply add both Shapes to a Thing or Template, but I would like to extend the "ThingWithStateAndLocation" Shape with mechanism that takes the properties of the different shapes into account. (e.g if the location changes the state changes to "moving") By adding each shape individually to a thing I would have to implement the mechanism over and over again for every thing/ thing template.

 

Any advices are appreciated very much.

 

Best Regards,

Dominik

1 ACCEPTED SOLUTION

Accepted Solutions

You can't do it out of the box.

 

We do it, but the solution it's a bit complex: third "Compound" Thing Shape can subscribe to ThingStart Event* and add the depending ThingShapes with Resources["EntityServices"].AddShapeToThing, something like:

var meName = me.name;

if (Things[meName].ImplementsShape({ thingShapeName: "DependingThingShape" })===false) {
    Resources["EntityServices"].AddShapeToThing({
        name: meName,
        thingShapeName: "DependingThingShape"
    });
}

You can see that I use Things[meName]. instead of me. That's very important as when you add a ThingShape to a Thing it automatically restarts and the reference to me. isn't valid anymore on the same service call.

 

* That's the easy part, the hard part here it's that you can't have more than one subscription to the same event on the same thing :( then you can only apply this approach to one compound ThingShape per Thing. Having multiple subscriptions to the same event on the same thing was a feature removed on TW 6.5 :( I had long discussions with R&D about this, and I think there's plans for new releases to get back this functionality. In the meantime here we have a solution too: We have a general ThingShape (let's name it GenericThingShape) which it's implemented by all the Things and it's the only one that subscribes to ThingStart event and with naming conventions it calls Init_"ThingShapeName" for each Implemented ThingShape (same can apply with ThingTemplates), the code looks something like:

 

var sName;
// -- Initialize Implemented Shapes
thing = Things[thingName];
var implementedShapes = thing.GetImplementedShapes();
var nImplementedShapes = implementedShapes.rows.length;
for (var i=0;i<nImplementedShapes;i++) {
  var shape = implementedShapes.rows[i];
  if (shape.name!=="wupGenericTS") {
      sName = "Init_"+shape.name;
      thing = Things[thingName];
      if (thing[sName]!=undefined) {
          times = 0;
          executed = false;
          lastError ="";
          while ((!executed)&&(times<MAX_REPEAT_TIMES)) {
              thing = Things[thingName];
              times++;
              try {
                  thing[sName]();
                  executed=true;
              } catch(err) {
                  lastError = (""+err);
                  // -- We are wainting to see it at the end it runs, for other errors we will stop.
                  if (lastError.indexOf("is not running")<0) {
                      break;
                  }
                  // -- Let's pause a bit to wait until it's running again.
                  pause(5);
              }
          }
          if (executed==false) {
              logger.error("[wupGenericTS("+thingName+")].Init Error calling ThingShape Initialization Service ["+sName+"], "+times+" retries. ERROR: "+lastError);
          }
      }
   }
}

View solution in original post

2 REPLIES 2

You can't do it out of the box.

 

We do it, but the solution it's a bit complex: third "Compound" Thing Shape can subscribe to ThingStart Event* and add the depending ThingShapes with Resources["EntityServices"].AddShapeToThing, something like:

var meName = me.name;

if (Things[meName].ImplementsShape({ thingShapeName: "DependingThingShape" })===false) {
    Resources["EntityServices"].AddShapeToThing({
        name: meName,
        thingShapeName: "DependingThingShape"
    });
}

You can see that I use Things[meName]. instead of me. That's very important as when you add a ThingShape to a Thing it automatically restarts and the reference to me. isn't valid anymore on the same service call.

 

* That's the easy part, the hard part here it's that you can't have more than one subscription to the same event on the same thing :( then you can only apply this approach to one compound ThingShape per Thing. Having multiple subscriptions to the same event on the same thing was a feature removed on TW 6.5 :( I had long discussions with R&D about this, and I think there's plans for new releases to get back this functionality. In the meantime here we have a solution too: We have a general ThingShape (let's name it GenericThingShape) which it's implemented by all the Things and it's the only one that subscribes to ThingStart event and with naming conventions it calls Init_"ThingShapeName" for each Implemented ThingShape (same can apply with ThingTemplates), the code looks something like:

 

var sName;
// -- Initialize Implemented Shapes
thing = Things[thingName];
var implementedShapes = thing.GetImplementedShapes();
var nImplementedShapes = implementedShapes.rows.length;
for (var i=0;i<nImplementedShapes;i++) {
  var shape = implementedShapes.rows[i];
  if (shape.name!=="wupGenericTS") {
      sName = "Init_"+shape.name;
      thing = Things[thingName];
      if (thing[sName]!=undefined) {
          times = 0;
          executed = false;
          lastError ="";
          while ((!executed)&&(times<MAX_REPEAT_TIMES)) {
              thing = Things[thingName];
              times++;
              try {
                  thing[sName]();
                  executed=true;
              } catch(err) {
                  lastError = (""+err);
                  // -- We are wainting to see it at the end it runs, for other errors we will stop.
                  if (lastError.indexOf("is not running")<0) {
                      break;
                  }
                  // -- Let's pause a bit to wait until it's running again.
                  pause(5);
              }
          }
          if (executed==false) {
              logger.error("[wupGenericTS("+thingName+")].Init Error calling ThingShape Initialization Service ["+sName+"], "+times+" retries. ERROR: "+lastError);
          }
      }
   }
}
drieder
15-Moonstone
(To:CarlesColl)

Hello @CarlesColl ,

 

thank you very much for your detailed answer. It does indeed look a bit complicated. 

 

But I will try this out.

 

Again, thank you very much.

 

Regards,

Dominik

Top Tags