jasonacox / tinytuya

Python API for Tuya WiFi smart devices using a direct local area network (LAN) connection or the cloud (TuyaCloud API).
MIT License
923 stars 165 forks source link

Understanding scale and high_resolution #327

Closed elockman closed 1 year ago

elockman commented 1 year ago

I've seen an oddity with setting temp setpoints in a tuya thermostat, and I'm now trying to understand the difference between scale and high_resolution.

The thermostat dps table looks like this:

    dps_data = {
        '2' : { 'name': 'mode', 'enum': ['auto', 'cool', 'heat', 'emergencyheat', 'off'] },
        '16': { 'name': 'temp_set', 'alt': 'setpoint_c', 'scale': 100 },
        '17': { 'name': 'temp_set_f', 'alt': 'setpoint_f' },
        '18': { 'name': 'upper_temp_f', 'alt': 'cooling_setpoint_f', 'high_resolution': False },
        '19': { 'name': 'upper_temp', 'alt': 'cooling_setpoint_c', 'high_resolution': False },
        '20': { 'name': 'lower_temp_f', 'alt': 'heating_setpoint_f', 'high_resolution': False },
        '23': { 'name': 'temp_unit_convert', 'alt': 'units', 'enum': ['f','c'] },
        '24': { 'name': 'temp_current', 'alt': 'temperature_c', 'scale': 100 },
        '26': { 'name': 'lower_temp', 'alt': 'heating_setpoint_c', 'high_resolution': False },
        '27': { 'name': 'temp_correction', 'high_resolution': False },
        '29': { 'name': 'temp_current_f', 'alt': 'temperature_f' },
        '34': { 'name': 'humidity' },
        '45': { 'name': 'fault' },
        '107': { 'name': 'system_type', 'decode': int },
        '108': { 'name': 'upper_temp', 'alt': 'cooling_setpoint_c', 'scale': 100, 'high_resolution': True },
        '109': { 'name': 'lower_temp', 'alt': 'heating_setpoint_c', 'scale': 100, 'high_resolution': True },
        '110': { 'name': 'upper_temp_f', 'alt': 'cooling_setpoint_f', 'high_resolution': True },
        '111': { 'name': 'lower_temp_f', 'alt': 'heating_setpoint_f', 'high_resolution': True },
        '115': { 'name': 'fan', 'enum': ['auto', 'cycle', 'on'] },
        '116': { 'name': 'home' },
        '118': { 'name': 'schedule', 'base64': True, 'selfclass': 'ThermostatSchedule' },
        '119': { 'name': 'schedule_enabled' },
        '120': { 'name': 'hold', 'enum': ['permhold', 'temphold', 'followschedule'] },
        '121': { 'name': 'vacation', 'base64': True },
        '123': { 'name': 'fan_run_time' }, # presumably for when fan='circ'
        '129': { 'name': 'system', 'enum': ['fanon', 'coolfanon', 'alloff', 'heatfanon', 'heaton'] },
        '130': { 'name': 'weather_forcast' }
        }

scale makes sense to me with this code:

        if 'scale' in ddata:
            val = int( val * ddata['scale'] )

I also see that the dps table has multiple cooling_setpoint_f and heating_setpoint_f alternative naming keys.

Is high_resolution supposed to be a flag to distinguish between the common naming keys and assign the correct dps as well as the proper scale? It appears to be that way with this code:

        for k in self.dps_data:
            if( (key == self.dps_data[k]['name']) or (('alt' in self.dps_data[k]) and (key == self.dps_data[k]['alt'])) ):
                if( ('high_resolution' not in self.dps_data[k]) or (self.dps_data[k]['high_resolution'] == self.high_resolution) ):
                    dps = k
                    break

If that is indeed the case, I think dps 110 and dps 111 should have 'scale': 100 included. Otherwise dps 18 and 110 become virtually the same. Likewise, dps 19 and dps 108 become virtually the same.

Does that make sense to you @uzlonewolf?

uzlonewolf commented 1 year ago

They're not "virtually" the same , they are the same. Why they decided to do that I have no idea, I did not write the firmware for these things.

Depending on what firmware version you have, the thermostats use either DPs 18+19+20+26, or DPs 108+109+110+111. "high_resolution" is nothing but a flag which tells the program which DP set to use when sending 'set' commands. I named it that because degrees C changed from increments of 1 to increments of 0.01 (really 0.5 encoded as 0.01).

uzlonewolf commented 1 year ago

I also see that the dps table has multiple cooling_setpoint_f and heating_setpoint_f alternative naming keys.

Yes, I found the "official" name for those DPs ("upper_temp" and "lower_temp") really confusing, so I added those aliases.

elockman commented 1 year ago

Ok, I get it. My status does not come back with the 18,19,20,26 DPs. Would it be better to make the aliases different with different function calls to them?

uzlonewolf commented 1 year ago

I did it this way so the same code works no matter which firmware version you have. Giving them different names would mean your code would need to know about, detect, and use different calls for different firmware versions.

elockman commented 1 year ago

Ok, my code is working without changes to tinytuya. I had a variable that was a string instead of an int, and it looked like a scaling issue. Casting to int resolved my issue. Closing this issue.