Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider support for multiple profiles per item and channel link #35

Open
splatch opened this issue Aug 31, 2021 · 2 comments
Open

Consider support for multiple profiles per item and channel link #35

splatch opened this issue Aug 31, 2021 · 2 comments
Labels
question Further information is requested

Comments

@splatch
Copy link
Contributor

splatch commented Aug 31, 2021

Recently I come over an situation where I had to work with several devices which did have few configuration options related to "debounce" and "timeout" handling. These seem very fine mechanisms to minimize traffic on the bus.

Above case was relevant for CAN devices which can publish their updates to the bus. They for example publish data only if change was bigger than n or last successful publish is older than n seconds. Since I had to implement publishing semantics on OH/OSH end I currently miss support for that. While it is not a big issue now, I believe it shows some shortcomings of the framework.

Situation to consider:

when item X update
  if Math.abs($previous-$state) < 0.5W; skip
  if $lastPublish < 30s; skip
  callback.handleCommand($state)
  $previous = $state;
  $lastPublish = now();

There are few more situations which brought my attention. For example some bindings do not handle properly quantity types and can't really handle them well since end system is not aware of it and assumes certain unit on read and write. A prime example was modbus binding prior 3.0 release which simply ignored quantity values. With 3.1 release there is a support for dimensionless values which is a bit better, but still far from being perfect.
Given that we do not have quantify and de-quantify profiles we quickly run into situation where state description pattern is used t configure values coming out from an thing handler. Reason why quantify and de-quantify profiles aren't used is basic - there is only one profile per channel hence use of it would simply block hysteresis and other more valuable (higher level) profiles.

Looking now at how ie. modbus binding configuration looks a like it is clear to me that some of these shortcomings are pushed down to integrations. One of situations I faced recently was necessity to de-quantify a number and then scale it down. It was possible via read/write transformation supported by binding. Yet by looking at modbus and mqtt it is clear to me that transformations are suboptimal. They force multiple parsing of commands (incoming command -> text -> transformation -> text -> transformed command) and force use of TypeParser APIs which is deprecated on OSH end.
Other approach which is discussed within OH (see their issue 2172) is to introduce script profile. While it gives a lot of flexibility in how to handle certain things it again pushes the problem down to the user to write rules just like he did with transformations. This will also delay further standardization of profiles.

I did have a look on communication manage and how it handles profile interactions. From there it looks like we could possibly chain profiles. While profiles do not return new command as transformation services do, they do interact with ProfileCallback. This interface is quite compact and could be used to link multiple profiles (see ProfileCallbackImpl).
Profiles and their callbacks are created based on item channel links hence major part of rework would probably go there. Not to mention user interface which would require better handling of that.
Since profiles are stored within channel configuration under profile key at least that part is semi open for extension.

Situation when profile callbacks are chained

ProfileCallbac callback = handlerCallback; // the communication manager callback

// example 1
profile = new DebounceProfile(
  new DelegateProfileCallback(
    new PublishTimeoutProfile(callback, config)
  ), config
);
// example 2
profile = new ScaleProfile(
  new DelegateProfileCallback(
    new DebounceProfile(
      new DelegateProfileCallback(
        new PublishTimeoutProfile(callback, config)
    ), config)
  ), config);

Above syntax is currently missing, however I think it shows the point of using it at the channel level. With such approach we can give enough flexibility to the end user configurations without forcing him to write complex scripts.
Situation with above profile chains is not that far away from expire functionality, however here we can't unify its handling with expire manager as each and every channel might be different.
An alternative way is to use a "ComplexProfile" which could rely on different channel link configuration key. Then whole solution would be compatible with OH and would require minor changes to core. Obviously then it will require more work on ComplexProfileFactory to replicate CommunicationManager functionality/logic.

@splatch splatch added the question Further information is requested label Aug 31, 2021
@J-N-K
Copy link

J-N-K commented Sep 9, 2021

IMO having chained profiles would be very nice, for the reasons you explained above. Chained profiles are far superior to the mentioned ScriptProfile because they require less to no knowledge of a scripting language and can be configured entirely via UI.

I implemented the chained transformation in SmartHome/J because profiles do not differentiate between incoming and outgoing values and a single chain would not be useful if communication is bi-directional. I did have a look at your "reference implementation" of the ComplexProfile and you seem to try to solve that by iterating either up or down the list of profiles. This seems to be a good approach for most cases as the conversion steps are probably symmetrical.

@splatch
Copy link
Contributor Author

splatch commented Sep 9, 2021

Hey Jan, thank you for touching topic.

I do see a point in use of ScriptProfile when complex logic is needed, yet in many cases it is over complicated. Pulling a script engine just to multiply a number seems to be a large overkill both in complexity, dependency and abstraction level. Main point for employing scripts is to carry on situations which require multiple if/else branches. With such situation profiles can't be called in a sequential manner. Yet anyone who would wish to implement such thing will end up with implementation of an rule engine.
Anyways, I made a test attempt to implement a profile which consumed state of another item and it is doable. It is likely considered an illegal attempt from design point of view, however it opens again system to do more.

I saw you had useful transformations in SmartHome/J which tried to solve shortcomings of ones provided by core. Yet, functionality of profiles can be much richer by preserving state between thing handler/item calls. This makes it possible to ie. calculate volatile average/median etc without pulling persistence service in.

BTW. I haven't linked here other commit I made with complex profile: https://github.com/ConnectorIO/connectorio-addons/tree/5ee23bb8a5a2b3edfc8d18519be320e52f724ecf/bundles/org.connectorio.addons.profile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants