[ST Edge] How Temperature Scale for the location can be retrieved from within a driver?

Hi,

I’m looking for a way to retrieve a configured temperature scale from within an edge driver.
One use case would be emitting thermostatCoolingSetpoint.coolingSetpoint in a units, natural for location.
Thanks

This is an interesting area. I feel we are still rather influenced by the design of the legacy SmartThings environment where device handlers also defined the user interface, a nonsense that we have a glorious chance to kick firmly into touch. To me the question is not ‘how can we do this?’ but ‘should we even be thinking about doing this?’.

I don’t think drivers, or any other device integration, should ever have to concern themselves with conversion between units unless the device itself requires those units. We already have a vaguely defined and implemented ‘default unit’ for many attributes. That would do nicely if made mandatory.

For temperatureMeasurement and thermostat setpoints, as examples, I believe command arguments should already be in Celsius when they hit the driver, and events should be emitted in Celsius.

That places the responsibility firmly on the UI, apps or automations to handle conversion to and from other supported units.

I would be interested to know what thoughts ST have on this. I note that temperatures are already only being emitted in Celsius from the Zigbee library.

@orangebucket

That would be nice, provided the conversion for any event is never performed more than once.
Consider the user changes the desired temperature by 1 degree. The platform translates the units from user’s location scale to platform’s. The driver receives the request and emits event (in platform units), which is changed back to location units. The net result would be probably the slightly different value, presented to the user.
I’m not sure it is possible to guarantee that for each value v in F
to_f(to_c( v) ) would always be equal to v

I would prefer that event would always contain both the value and units. If user uses F scale, then that what driver should get. If the device is capable to receive commands in both F and C units, then the driver should either to configure it, according the selected scale for the location during device configure or to send commands with correct scale. Only if the device is unable to work with units, defined for the location, the transformation should be made by a driver

Further, for consistency, if platform always performs translation to C, then it should do the same for other units.
Speed, distance, voltage, current measurements, power, etc. The platform needs to be aware upfront about any possible unit.
What would happen if we want to present a value in milli Volts, instead of Volts? mW, mA? If we want to use sea miles for a distance? I don’t think it would be robust solution to have all translations made by the platform and I really doubt the ST team would be able to handle all such requests.

@ygerlovin,

In my virtual thermostat driver, with a temperature sensor, the user chooses F or C units for thermostat operation, setpoints, and automations, and works fine.

The sensor always send values in Celsius and app converts to local units automatically.
The user then chooses the thermostat units in preferences to match with their location.
It also has a vid to change the range from -50°C to 250°C, instead of the stock 0°C to 40°C, in case you use it for a freezer or an oven.

You can also choose the setpoint adjustment steps with profiles of 0.1°C or 0.5°C, instead 1°C stock steps

In my guthub is the code and vids, in case it helps you

1 Like

Hi @Mariano_Colmenarejo

Thanks for sharing.

So, the app converts to units, defined for location (which is very limiting, in my opinion). Why the user needs to set the same units in preferences?
It doesn’t seems reasonable to define the units both in location and in device preferences.
It feels merely as a workaround for missing functionality and it requires a custom code for trivial functionality that should be available at pre beta stage.
I think making automatic conversions, creates more issues than it solves and introduces unnecessary limitations.
What happens if users fails to properly set device preferences?
Besides, if platform is responsible for making conversion, why does it require a custom vid?
What happens if the device should report in both F and C? This could be very useful in hotels, where guests might be used to different units, than those, defined for location?

I think it would be better to have some simple temperature capability that does not petform any conversions. If automatic conversion is required, it should be implemented on top of simple temperature capability, not instead of it

Yes, of course, and generally it is where the unit is significant. More often than not they are enumerated in the stock capabilities and usage is policed in the app, in drivers and in Rules. It is not the free for all it was.

Custom capabilities would be a different matter entirely.

I have caused a digression though. It will be interesting to see if ST provide access to the Location settings in drivers, and if indeed the temperature remains as a Location setting. I am indifferent to the latter but would be disappointed if the former happens.

1 Like

In the App the capabilities of thermostatHeatingSetpoint and thermostatCoolingSetpoint also convert to local units automatically whenever the event is emitted in ºC, as in the defaults.

But for the thermostat programs defined in preferences, It would be necessary to know in which units ºC or ºF the values of the programmed temperatures are entered, in order to the code emit them in ºC and then the app convert to local units.

So I decided that the easiest thing would be that in preferences each user enters the programmed temperature values in the units they are used to handling and chooses the ºC or ºF units so that they are emitted with that ºC or ºF unit and the app does not convert them wrong, if the values are emmitted with ºF units, they are not converted in app.

    local temp_scale = "C"
    if device.preferences.thermTempUnits == "Fahrenheit" then temp_scale = "F" end
    device:emit_event_for_endpoint("main", capabilities.thermostatHeatingSetpoint.heatingSetpoint({value = heating_Setpoint, unit = temp_scale }))
    device:emit_event_for_endpoint("main", capabilities.thermostatCoolingSetpoint.coolingSetpoint({value = cooling_Setpoint, unit = temp_scale }))

Indeed, as it is now defined, it would be necessary to have a custom capability to emit in °C and not be converted automatically to the local unit.
And Use the custom capability to emit directly in °F or °K whatever the user chooses

@Mariano_Colmenarejo

Exactly, this is because the conversions are not consistent. If ST implicitly converts units to be displayed (that is from driver to GUI), than it should perform the reverse translation for user events (from GUI to driver) or at least provide displayed units in the event.

@nayelyz
The input from the team would be highly appreciated here.
Is there any general rules/guidelines that are common for all units?
Are there any plans for automatic translations for other units (pressure, volume, etc).
What are the expectations from the driver? Should it always expect automatic translation of events from user units to platform’s?
Specifically, when cooling point is changed, should we expect the value in user’s scale or platform’s?
Thanks

I’ve seen the following:

  • It’s best to use the corresponding unit in each capability event. Especially if you’ll use it in the dashboard view, if the unit value is not received, it will show “connected” instead of the value.
    • That’s why some stock capabilities define unit as “required” in their definition:
"required": [
    "value",
    "unit"
]
  • You cannot modify the units set in a stock capability but if you consider one should be added, we can open a feature request.

The temperature scale is a property of the location, so that’s why the conversion can be done. The issue with thermostatCoolingSetpoint and thermostatHeatingSetpoint is still pending.
For the other capabilities, I will ask the team.

This automatic conversion is currently only applied for temperatureMeasurement and it should show the value converted to the unit set for the location:

{
    "locationId": "0b018721-6bc0-xxxx-xxxx",
    "name": "Location name",
    "countryCode": "USA",
    "latitude": x,
    "longitude": x,
    "regionRadius": x,
    "temperatureScale": "F",  /*HERE*/
    "timeZoneId": "...",
    "locale": "en",
    "backgroundImage": null,
    "additionalProperties": {},
    "allowed": null,
    "parent": {
        "type": "ACCOUNT",
        "id": "365ebe93-8a04-xxxx-xxxx "
    }
}

Other capabilities show the unit sent in the capability event.

Once we get info about the issue with the thermostat setpoints we can know more.

1 Like

Hi @nayelyz

How can the location info be retrieved from within the driver, so I can use the correct units when emitting events?

It can’t be retrieved from there. You would need to make an HTTP request to the ST cloud and drivers don’t support the access to the public Internet.

The team provided this info:

  • Temperature events are automatically converted to the location units for Lua drivers.
  • There’s no option to disable this behavior.

@nayelyz

Thanks.
Let me explain the issue I see then.

  1. During initialization the driver emits
    device:emit_event(st_capabilities.thermostatCoolingSetpoint.coolingSetpoint({value = 30, unit = 'C' })) 
  1. This value is translated to location units (Fahrenheit) and is shown in the app (86 degrees F)
  2. The user presses “+” sign
  3. The driver receives the event with value 87 and no units
  4. At this point, since the driver is unable to retrieve the location units and it does not receive them in the capability handler it emits the event without units
  5. However, 87 without units is assumed to be in C and converted to F, so the user sees 188

@Mariano_Colmenarejo suggested to duplicate the temperature scale in the device preferences, however, I think this solution is error prone.
Thanks

1 Like

Ok, I made some tests and see what you mean, I’ll add this to the report.
The workaround from @Mariano_Colmenarejo could help you while the team revises the capabilities.

Hi @nayelyz

Any update regarding this? Thanks

@ygerlovin, sorry for the delay.

The team mentioned they are checking a permanent fix but there’s no ETA yet. Currently, all efforts are dedicated to the migration from Groovy and this change would require several actions.

However, they suggested you can use the same workaround applied to the stock drivers:

Use a custom capability handler where they validate the received value, if it’s greater than 40, it means the temperature’s unit is F, there’s a sample below: