Okay, beyond my knowledge. I believed, apparently wrongly, that ON could arrive at a binding dimmer channel and the binding decided if that meant 100% or restore-last-brightness (because that’s device dependent).
Until I dug into ESH’s code, it wasn’t obvious, either. I’m assuming that’s why the Zwave binding, for example, exposes a OnOffType-bound channel and a PercentType-bound channel for dimmers. ON sent to the latter goes to 100%, ON to the former is device-dependent. (Another weird, and undocumented, inconsistency – which I assume is because of this framework limitation)
Not arbitrary - there is a published table of what Item types accept what commands.
That’s precisely why it is arbitrary. The binding has no say on it – the Item accepts one, and only one, type. The framework as an arbitrary set of conversions its doing, which only sense with whatever usecase they were originally added for. The fact that you need two channels to control a Z-wave dimmer properly is because ON is going to convert to PercentType(100), and would make it impossible to do a “ON to last value”. And the user, without knowing ESH is doing that, wouldn’t know why.
The architecture, as implemented, in ESH is just plain bad because the framework is defining a limited set of conversions and as a binding author you can’t do a thing about it. Even ignoring the appropriateness of logging a warning when you get it wrong, or the appropriateness of having as() on the enum-derived types universally support String as an output, the real problem is that the ESH binding framework can’t expose a channel as multiple types, so binding authors can’t overload the operations in a binding-appropriate way, and they’re stuck with the fallout of the conversions the framework is doing. (I haven’t looked, but presumably the bindings that do RGB lights need a separate channel to turn on to a preset or previous color, given that OnOffType converts to WHITE – another point of potential confusion to rule authors.)
While this is way out of scope for an OH discussion, IMO the system should deprecate the as() method, and extend the type metadata to support a “item-type-supports” property.
For example, this is the channel definition for the one above:
<channel-type id="fujitsu-power">
<item-type>String</item-type>
<label>Power Mode</label>
<state>
<options>
<option value="OFF">Off</option>
<option value="ON">On</option>
<option value="ECONOMY">Economy</option>
<option value="MINHEAT">Mininum Heat</option>
<option value="POWERFUL">Powerful</option>
</options>
</state>
</channel-type>
(Note, I probably could’ve done this as an enum as well, but the way to do that isn’t documented, and until I looked at how the built-in types were implemented, it wasn’t clear you could do that)
Now, ideally, I could do something like:
<channel-type id="fujitsu-power">
<item-type>String</item-type>
<item-type-supports>OnOffType,DecimalType</item-type-supports>
<label>Power Mode</label>
<state>
<options>
<option value="OFF">Off</option>
<option value="ON">On</option>
<option value="ECONOMY">Economy</option>
<option value="MINHEAT">Mininum Heat</option>
<option value="POWERFUL">Powerful</option>
</options>
</state>
</channel-type>
And then have the system send me any commands of those types – then I can do domain-specific conversions. The handleCommand() method takes a Command, anyway, so you can send any type you want into it. Its just a framework limitation that keeps channels 1:1 bound to a type.
Anyway, its an aside, but that’s how I think it should work. I don’t know if it ended up the way it is because of developmental inertia or an explicit decision, but its a weird and inconsistent spot its ended up.