
    j                     `    d Z ddlZddlZddlmZmZmZmZmZ  G d de      Z	 G d de
      Zy)	a0  
 A community-contributed Python module to add support for Tuya WiFi smart thermostats

 This module attempts to provide everything needed so there is no need to import the base tinytuya module

 Module Author: uzlonewolf (https://github.com/uzlonewolf)

 Local Control Classes
    ThermostatDevice(..., version=3.3, persist=True)
        This class uses a default version of 3.3 and enables persistance so we can catch temperature updates
        See OutletDevice() for the other constructor arguments

 Additional Classes
    ThermostatSensorList(dps, parent_device)
        Mainly used internally, exposed in case it's useful elsewhere
        The 'dps' argument should be the DPS ID of the list so it knows what DPS to send when updating a sensor option
        The 'parent_device' argument should be the ThermostatDevice() this sensor list belongs to


    Sensor related functions:
        tstatdev = ThermostatDevice(...)
        tstatdev.sensors
            -> an iterable list of all the sensors that can also be acessed like a dict:

              for sensor in tstatdev.sensors:
                  if not sensor.online:
                      print( 'Sensor %r offline!' % sensor.name )

              if tstatdev.sensors['12345678'].battery < 10:
                  print( 'Sensor %r low battery!' % tstatdev.sensors['12345678'].name )
              else:
                  print( 'Sensor %r battery %d%%' % (tstatdev.sensors['12345678'].name, tstatdev.sensors['12345678'].battery ) )

            dict access matches against both name and id:
              tstatdev.sensors['name'] and tstatdev.sensors['id'] both work

        When sensor values change, the sensor object is also available in data['changed_sensors'].  i.e.
            data = tstatdev.receive()
            if data and 'changed_sensors' in data:
                for sensor in data['changed_sensors']:
                    if 'temperature' in sensor['changed'] and sensor.online:
                        ...do something with sensor.temperature or whatever...

        sensors have the following attributes:
          id -> ID # of the sensor as a hex string
          raw_id -> ID # of the sensor as a integer
          name -> decoded and trimmed name of the sensor
          raw_name -> NUL-padded name of the sensor as a byte array
          enabled -> sensor enabled flag True/False
          occupied -> sensor detected occupancy flag True/False
          temperature -> temperature in degrees C as a float
          raw_temperature -> temperature as reported by the sensor (degrees C * 100)
          temperature_used -> the rounded temperature used in averaging calculations
          raw_temperature_used -> the rounded temperature used in averaging calculations (degrees C * 100)
          online -> sensor online flag True/False
          participation -> schedule participation bitmask ['wake', 'away', 'home', 'sleep']
          battery -> battery percentage remaining
          unknown2 -> value of unknown field, integer 0-255
          firmware_version -> firmware version * 10 (01 = v0.1)
          averaging -> sensor currently participation in the temperature averaging (occupied is True and participation flag for the current schedule mode is set)
          unknown3 -> value of unknown field, 8 byte long byte array
          changed -> list of attributes which have changed since last update

        sensors also have the following methods:
          sensor.setName( new_name )
          sensor.setEnabled( enabled )
          sensor.setOccupied( occupied )
              -> not really useful for remote sensors as they get overwritten on the next update
          sensor.setParticipation( flag, val=True )
              -> flag can be either a string in ['wake', 'away', 'home', 'sleep'] or an integer bitmask
                 when it's a string, val sets (True) or clears (False) that particular flag
                 when it's a integer, the bitmask is set to flag and val is ignored
          sensor.getParticipation( flag )
              -> flag can be either a string in ['wake', 'away', 'home', 'sleep'] or an integer bitmask
                 returns True if (string) flag is set or (integer) bitmask matches exactly, otherwise returns False
              -> if the current value of all flags is wanted, the sensor.participation field can be read directly instead of using this function
          sensor.setUnknown2( val )
              -> sets the second unknown field to val.  'val' should be an integer in the range 0-255
          sensor.setUnknown3( val )
              -> sets the third unknown field to val.  'val' should be a 8 byte long byte array

        If multiple sensor options are going to be changed at the same time, it is much quicker to queue the updates and send them all at once:
            sensor.delayUpdates()
            ... call sensor.setName() or whatever here ...
            sensor.sendUpdates()


    Thermostat related functions:
        delayUpdates()
            -> when changing multiple settings, calling this first will cause them to be queued and sent all at once later
        sendUpdates()
            -> sends all queued updates at once and disables queueing (delayUpdates() will need to be called again if you want to queue things)

        setSetpoint( setpoint, cf=None )
            -> tried to auto-detect which setpoint you want to set (cooling or heating)) using the system mode and sets it
               if cf is None it assumes the given setpoint is the same temperature unit (degrees C or F) as the system temperature unit
        setCoolSetpoint( setpoint, cf=None )
            -> sets the cooling setpoint, for when the system mode is 'cool' or 'auto'
        setHeatSetpoint( setpoint, cf=None )
            -> sets the heating setpoint, for when the system mode is 'heat' or 'auto'
        setMiddleSetpoint( setpoint, cf=None )
            -> you should not need to call this, the thermostat handles it
               matches the cool or heat setpoint if the system is in those modes, or the midpoint between them if the mode is 'auto'

        setMode( mode )
            -> sets the system mode.  mode should be a string in ['cool', 'heat', 'auto', 'off']
        setFan( fan )
            -> sets the fan mode.  fan should be True (on), False (auto), or a string in ['on', 'auto', 'circ']
        setFanRuntime( runtime )
            -> when the fan mode is 'circ' this sets how many minutes per hour the fan is run to circulate the air
        setUnits( cf )
            -> sets the system temperature units.  cf should be a string in ['c', 'f']
        setSchedule( schedule )
            -> enables or disables the previously-created schedule.  creating a new schedule is not yet implemented
        setHold( hold )
            -> sets the temperature hold.  hold should be True (permhold), False (followschedule), or a string in ['permhold', 'temphold', 'followschedule']

        getCF(cf=None)
            -> parses the given cf value and returns either 'c' or 'f', or returns the system temperature units if cf is None
        isSingleSetpoint()
            -> returns True if the system is expecting a single temperature (mode is 'cool' or 'heat'), or False if it is expecting separate cool and heat setpoints

        sendPing()
            -> sends a async heartbeat packet
        sendStatusRequest()
            -> sends a async status request packet
        status()
            -> sends a synchronous status request packet and returns the result after parsing it
        receive()
            -> receives a single packet and returns the result after parsing it

        setValue( key, val )
            -> directly set a key in the dict.  you probably do not need to call this directly
        setValues( dict )
            -> directly set multiple keys in the dict.  you probably do not need to call this directly
        parseValue( key, val )
            -> converts a value to the format the DPS is expecting for that particular key.  you probably do not need to call this directly

    attributes:
        mode -> ['auto', 'cool', 'heat', 'emergencyheat', 'off']
        fan -> ['auto', 'cycle', 'on']
        system -> current system state, ['fanon', 'coolfanon', 'alloff', 'heatfanon', 'heaton']
        setpoint_c -> either the setpoint when system is not in 'auto' mode, or the midpoint between the heating and cooling setpoints
        temp_set -> alias for setpoint_c
        setpoint_f and temp_set_f -> same as setpoint_c but in degrees F
        cooling_setpoint_c and upper_temp
        cooling_setpoint_f and upper_temp_f
        heating_setpoint_c and lower_temp
        heating_setpoint_f and lower_temp_f
        units and temp_unit_convert -> system temperature units, either 'c' or 'f'
        temp_correction -> offset to adjust displayed sensor temperatures
        temperature_c and temp_current -> current temperature in degrees C
        temperature_f and temp_current_f -> current temperature in degrees F
        humidity -> RH%
        fault -> fault flags, [e1, e2, e3]
        system_type -> '4'=heatpump, '5'=2-stage heatpump?
        home -> ??
        schedule -> ThermostatSchedule() class
        schedule_enabled -> flag True/False
        hold -> ['permhold', 'temphold', 'followschedule']
        vacation -> binary blob
        fan_run_time -> when the fan mode is 'circ' this is how many minutes per hour the fan is run to circulate the air
        weather_forcast -> ??

    status() and receive() both return a dict containing both the raw DPS dict as well as a list of changed attributes in 'changed' and a list of changed sensors in 'changed_sensors'
     these can be used like:

            data = tstatdev.receive()
            if data and 'changed' in data:
                if 'system' in data['changed']:
                    print( 'System State changed, current temperature is:', tstatdev.temperature_c )
                for changed in data['changed']:
                    print( 'Changed:', changed, 'New Value:', getattr( tstatdev, changed ) )
            if data and 'changed_sensors' in data:
                for sensor in data['changed_sensors']:
                    print( 'Sensor Changed! Changed Attribs:%r DPS:%s ID:%s Name:"%s" Current Temperature: %r' % (sensor.changed, sensor.parent_sensorlist.dps, sensor.id, sensor.name, sensor.temperature) )
                    if 'sensor_added' in sensor.changed:
                        print( 'New sensor was added!' )
                    if 'name' in sensor.changed:
                        print( 'Sensor was renamed!' )
                    for changed in sensor.changed:
                        print( 'Changed:', changed, 'New Value:', getattr( sensor, changed ) )

    ThermostatSchedule class:

        !! WARNING !! The thermostat does NOT send the current schedule when you request the status, it only sends it when it has changed.  So, you
            must either a) set the entire schedule or b) change it in the app or on the thermostat itself while tinytuya is running.  Changes to a
            single day/period/value can only be made once this has been done.

        'day' is a case-insensitive string starting with su, m, tu, w, th, f, sa or an integer in the range 0-6
        'period' is a case-insensitive string starting with w[ake], a[way], h[ome], s[leep], e[xtra] or an integer in the range 0-4
            -> Only periods 0-3 (wake-sleep) show up in the app or on the thermostat! (4 (extra) is hidden)

        Schedule parameters can be accessed directly by dict via name or index:
            tstatdev.schedule[1][0].coolto = 25.0 or
            tstatdev.schedule['monday']['wake'].coolto = 25.0 or
            tstatdev.schedule['m']['w'].coolto = 25.0 or
            tstatdev.schedule['MoNdAySsUcK']['WakeMeUp'].coolto = 25.0
        all mean the same thing.  Parameters can also be set using the .setPeriod method:
            tstatdev.schedule.setPeriod( day_of_week, period, coolto=25.0, heatto=10.0, time=0, participation=(period & 3) )
        To disable a schedule period (set the time to 0xFFFF) you can:
            tstatdev.schedule.setPeriod( day, 4, delete=True)

        Once a day is set you can copy it to a different day with:
            # copy sunday (0) to monday-saturday (1-6)
            for i in range(6):
                tstatdev.schedule.copyDay( 0, i+1 )

        Individual periods can also be copied:
            tstatdev.schedule.copyPeriod( src_day, src_period, dst_day, dst_period )
    N   )Devicelog
HEART_BEATDP_QUERYCONTROLc                   2    e Zd ZdZdZi ddg ddddd	d
dddddddddddddddddddddddddgd d!d"d#d
dd$d%d&ddd'd(dd)d*d+d,dd-d.d/id0d.d1id2d3ed4d5ddd
d6d7d8d%d&d
d6d7d9ddd6dddd6dd:g d;dd.d<id=d6d>d?d.d@idAg dBddCd6dDd.dEidFg dGdd.dHidI
Z fdJZdK ZdedLZ	dedMZ
dedNZdedOZdP ZdQ ZdR ZdS ZdT ZdU ZdV ZdW ZdX ZdY ZdedZZd[ Zd\ Zd] Z fd^Zd_ Zd` Zda Z G db dc      Z G dd d>e       Z! xZ"S )fThermostatDevicez1
    Represents a Tuya based 24v Thermostat.
    )1221251261271282mode)autocoolheatemergencyheatoff)nameenum16temp_set
setpoint_cd   )r   altscale17
temp_set_f
setpoint_f)r   r   18upper_temp_fcooling_setpoint_fF)r   r   high_resolution19
upper_tempcooling_setpoint_c20lower_temp_fheating_setpoint_f23temp_unit_convertunitsfc)r   r   r   24temp_currenttemperature_c26
lower_tempheating_setpoint_c27temp_correction)r   r%   29temp_current_ftemperature_f34r   humidity45fault107system_type)r   decode108T)r   r   r   r%   109110fan)r   cycleonhomescheduleThermostatSchedule)r   base64	selfclassschedule_enabledhold)permholdtempholdfollowschedulevacation)r   rL   fan_run_timesystem)fanon	coolfanonalloff	heatfanonheatonweather_forcast)
111115116118119120121123129130c                    d|vs|d   sd|d<   d|vrd|d<   t        t        | 
  |i | d | _        d | _        d| _        i | _        g | _        | j                  |       | _	        | j                  D ]'  }| j                  j                  t        ||              ) | j                  D ]2  }d }d| j                  |   v r# t        | | j                  |   d         | |      }t        | | j                  |   d   |       d| j                  |   v rt        | | j                  |   d   |       d	| j                  |   v sEd
| j                  |   v r| j                  |   d
   s"d| j                  |   v sd| j                  |   v rd| j                  |   d<   d| j                  |   v s| j                  |   d   st        | d| j                  |   d   z   d        5 y )Nversiongffffff
@persistTFrM   r   r   r   rL   rB   	check_rawraw_)superr
   __init__r%   rJ   delay_updatesdelayed_updatessensorlists
SensorListsensors
sensor_dpsappendThermostatSensorListdps_datagetattrsetattr)selfargskwargskval	__class__s        N/DATA/.local/lib/python3.12/site-packages/tinytuya/Contrib/ThermostatDevice.pyrl   zThermostatDevice.__init__  s   F"&*; #F9F" $F9.??#"".A##$8D$AB ! ACdmmA..DgtT]]1%5k%BDdAOT4==+F3S:a((t}}Q/6=DMM!,,8t}}Q?O3OUYUbUbcdUefnUo  vA  EI  ER  ER  ST  EU  vU  [c  gk  gt  gt  uv  gw  [w04a -dmmA..4==3CK3Pva(8(@@$H     c                     d| _         y NTrm   rx   s    r~   delayUpdateszThermostatDevice.delayUpdates(  s
    !r   c                     | j                   dk(  r| j                  ||      S | j                   dk(  s| j                   dk(  r| j                  ||      S | j                  ||      S )Nr   r   r   )r   setCoolSetpointsetHeatSetpointsetMiddleSetpoint)rx   setpointcfs      r~   setSetpointzThermostatDevice.setSetpoint+  s`    99''277YY& DII$@''277 ))8R99r   c                 N    d| j                  |      z   }| j                  ||      S )Ncooling_setpoint_getCFsetValuerx   r   r   r{   s       r~   r   z ThermostatDevice.setCoolSetpoint4  &    $**b"22}}a++r   c                 N    d| j                  |      z   }| j                  ||      S )Nheating_setpoint_r   r   s       r~   r   z ThermostatDevice.setHeatSetpoint8  r   r   c                 N    d| j                  |      z   }| j                  ||      S )N	setpoint_r   r   s       r~   r   z"ThermostatDevice.setMiddleSetpoint<  s&    $**b**}}a++r   c                 &    | j                  d|      S )Nr   r   )rx   r   s     r~   setModezThermostatDevice.setMode@  s    }}fd,,r   c                 <    |sd}n|du rd}| j                  d|      S )Nr   TrH   rF   r   )rx   rF   s     r~   setFanzThermostatDevice.setFanC  s'    CD[C}}eS**r   c                 H    | j                  |      }| j                  d|      S )Nr-   r   rx   r   s     r~   setUnitszThermostatDevice.setUnitsJ  s"    ZZ}}1277r   c                 N    |r| j                  dd      S | j                  dd      S )NrN   TFr   )rx   schs     r~   setSchedulezThermostatDevice.setScheduleN  s)    =="4d<<}}0%99r   c                 ~    |du r| j                  dd      S |du r| j                  dd      S | j                  d|      S )NTrO   rP   FrR   r   )rx   rO   s     r~   setHoldzThermostatDevice.setHoldT  sD    4<==&*665===&*:<<}}fd,,r   c                 8    | j                  dt        |            S )NrT   )r   int)rx   rts     r~   setFanRuntimezThermostatDevice.setFanRuntime]  s    }}nc"g77r   c                     | j                  ||      \  }}| j                  s| j                  ||d      S || j                  |<   yNTnowait)
parseValuerm   	set_valuern   )rx   keyr|   dpss       r~   r   zThermostatDevice.setValue`  sG    ??C.S!!>>3D>::$'S!r   c                     |D ])  }| j                  |||         \  }}|| j                  |<   + | j                  s8| j                  t        | j                        }i | _        | j                  |      S yr   )r   rn   rm   generate_payloadr   send)rx   val_dictr   r   r|   payloads         r~   	setValueszThermostatDevice.setValuesi  sq    CXc]<HC(+D  %  !!++GT5I5IJG#&D 99W%%r   c                 ^   d }| j                   D ]s  }|| j                   |   d   k(  s(d| j                   |   v s*|| j                   |   d   k(  s@d| j                   |   vs | j                   |   d   | j                  k(  sq|} n |st        j                  d|z         y| j                   |   }d|v rt	        ||d   z        }d|v r |d   |      }d|v r,||d   vr%t        j                  d	|d
|d|d|d   d	       d|v r$t        j                  |      j                  d      }||fS )Nr   r   r%   zRequested key %r not found!Fr   encoder   zRequested value 	 for key / not in enum list z !  Setting anyway...rL   ascii)ru   r%   r   warnr   rL   	b64encoderB   )rx   r   r|   r   r{   ddatas         r~   r   zThermostatDevice.parseValueu  sU   Aa(00ua@P7PWZ^b^k^klm^not^uWu&dmmA.>>DMMRSDTUfDgkokkDC	  HH3c9;c"esU7^+-Cu!%/3(CU?%-'ilnqsvx}  E  yF  G  Iu""C)009Cc|r   c                     d| _         t        | j                        dkD  r8| j                  t        | j                        }i | _        | j                  |      S y)NFr   )rm   lenrn   r   r   r   rx   r   s     r~   sendUpdateszThermostatDevice.sendUpdates  sO    "t##$q(++GT5I5IJG#&D 99W%%r   c                 .    |t        | dd      }|dk(  ryy)Nr-   r0   r/   rv   r   s     r~   r   zThermostatDevice.getCF  s#    :2C8B9r   c                 $    | j                   dk(  ryy)Nr   FT)r   r   s    r~   isSingleSetpointz!ThermostatDevice.isSingleSetpoint  s    99r   c                 N    | j                  t              }| j                  |      S N)r   r   r   r   s     r~   sendPingzThermostatDevice.sendPing  s!    ''5yy!!r   c                 N    | j                  t              }| j                  |      S r   )r   r   r   r   s     r~   sendStatusRequestz"ThermostatDevice.sendStatusRequest  s!    ''3yy!!r   c                 (    t         t        |          S r   )rk   r
   status)rx   r}   s    r~   r   zThermostatDevice.status  s    %t355r   c                 $    | j                  d       S r   )_send_receiver   s    r~   receivezThermostatDevice.receive  s    !!$''r   c                    |s|S d|vr|S g |d<   g |d<   t        t        | j                              D ]H  }| j                  |   }||d   v s|dxx   | j                  |   j	                  |d   |         z  cc<   J | j
                  e| j                  D ]V  }||d   v sd| j                  |   v s| j                  |   d   | _        t        j                  d| j
                  z          n |d   D ]h  }|| j                  v s| j                  |   d   }d| j                  |   v r| j                  |   d   rd|z   n|}|d   |   }t        | |      |k(  rg|d   j                  |       ||k7  r|d   j                  |       t        | ||       d	| j                  |   v r$| j                  |   rt        j                  |      }d
| j                  |   v r{t        | |      j	                  |       d| j                  |   v s|d   j                  | j                  |   d          t        | | j                  |   d   t        | |             bd| j                  |   v r | j                  |   d   |      }d| j                  |   v r|| j                  |   d   z  }t        | ||       d| j                  |   v rF|| j                  |   d   vr2t        j                  d|d|d|d| j                  |   d   d	       d| j                  |   v s(|d   j                  | j                  |   d          t        | | j                  |   d   |       k |S )Nr   changedchanged_sensorsr%   z+ThermostatDevice: high-resolution is now %rr   ri   rj   rL   rM   r   rB   r   r   zReceived value r   r   r   z* !  Perhaps enum list needs to be updated?)ranger   rr   ro   updater%   ru   r   inforv   rs   rw   rL   	b64decoder   )rx   datair{   r   	checknamer|   s          r~   _process_responsez"ThermostatDevice._process_response  s   KKY"%DOO,.A"ADK&'4+;+;A+>+E+EtE{ST~+WW' /
 ']]U#(9T]]1=M(M+/==+;<M+ND(HHJTMaMaab	 # eADMM!}}Q'//:dmmA>N/NSWS`S`abScdoSpVd]vz	5k!nD)-4Y&&.9$d9o&<&<i&Iy#/a 00dmmA6F **C1C$--"22T4)00#7a 00Y..a0@0GIt}}Q'7'>t@UW4==#338dmmA.x8#?$--"22t}}Q/88D$,q!11dmmA&6v&>>HH  JM  OP  RV  X\  Xe  Xe  fg  Xh  io  Xp  'q  sa 00Y..a0@0GIt}}Q'7'>EK N r   c              #     K   | j                   D ]s  }d| j                   |   v r0| j                   |   d   t        | | j                   |   d         f | j                   |   d   t        | | j                   |   d         f u y w)Nr   r   )ru   rv   )rx   r{   s     r~   __iter__zThermostatDevice.__iter__  s     Aa((}}Q'.dmmA>Nu>U0VWW==#F+WT4==;KF;S-TUU s   BBc                   0    e Zd Zd Zd Zd Zd Zd Zd Zy)ThermostatDevice.SensorListc                     || _         y r   )parent)rx   r   s     r~   rl   z$ThermostatDevice.SensorList.__init__  s	     DKr   c                     | j                   j                  D ]-  }|D ]&  }|j                  |k(  s|j                  |k(  s"|c c S  / y r   )r   ro   idr   )rx   r   lss       r~   find_sensorz'ThermostatDevice.SensorList.find_sensor   s?    [[,,Attt|qvv~   -
 r   c                     t        |t              r| j                  |      S t        |t              st	        | |      S d}| j
                  j                  D ]  }|D ]  }||k(  r|c c S |dz  }  y Nr      )
isinstancestrr   r   rv   r   ro   )rx   r   r   r   r   s        r~   __getitem__z'ThermostatDevice.SensorList.__getitem__  sq    3%''..c+c++A[[,,ACx FA  - r   c                 X    d}| j                   j                  D ]  }|D ]  }|dz  }	  |S r   r   ro   )rx   r   r   r   s       r~   __len__z#ThermostatDevice.SensorList.__len__  s5    A[[,,AFA  - Hr   c              #   X   K   | j                   j                  D ]  }|D ]  }|   y wr   r   rx   r   r   s      r~   r   z$ThermostatDevice.SensorList.__iter__  )     [[,,AG  -   (*c              #   X   K   | j                   j                  D ]  }|D ]  }|   y wr   r   r   s      r~   __call__z$ThermostatDevice.SensorList.__call__#  r   r   N)	__name__
__module____qualname__rl   r   r   r   r   r    r   r~   rp   r     s     	!				
	r   rp   c                   t    e Zd Z G d d      Zd Zd Zd Zd Zd Zd Z	d	 Z
d
 Zd Zd Zd Zd Zd Zd Zy)#ThermostatDevice.ThermostatSchedulec                   P    e Zd Z G d d      Zd Zd Zd Zd Zd Zd Z	d	 Z
d
 Zy)/ThermostatDevice.ThermostatSchedule.ScheduleDayc                   6    e Zd Zd Zd Zd Zd Zd Zd Zd Z	y)	>ThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriodc                 J    || _         d| _        d| _        d| _        d| _        y )N   i  i )schedparticipationtimeheattocoolto)rx   r  s     r~   rl   zGThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriod.__init__,  s&    !&DJ)-D& &DI"(DK"(DKr   c                     t        |t              st        | ||       |dk(  r|| _        y |dk(  r|| _        y |dk(  r|| _        y |dk(  r|| _        y t        d      Nr   r   r      z$Numeric index must be an integer 0-3)r   r   rw   r  r  r  r  
IndexErrorrx   r   r   s      r~   __setitem__zJThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriod.__setitem__3  sY    %sC1sD2axd!3t494;4; *+Q RRr   c                     t        |t              st        | |      S |dk(  r| j                  S |dk(  r| j                  S |dk(  r| j
                  S |dk(  r| j                  S t        d      r  )r   r   rv   r  r  r  r  r
  rx   r   s     r~   r   zJThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriod.__getitem__=  sg    %sC1&tS11ax(:(:!:$))#3$++#5$++#5 *+Q RRr   c                      y)N   r   r   s    r~   r   zFThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriod.__len__G  s    r   c              #   |   K   | j                    | j                   | j                   | j                   y wr   )r  r  r  r  r   s    r~   r   zGThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriod.__iter__J  s/     ,,,))O++%++%s   :<c           	      R   | j                   j                  j                  | j                   j                        }| j                  dk  s| j                  dkD  rt        | j                        }n;| j                  }|dk(  r|dz
  dz  }t        |dz        }|dz  }||z  }|dk\  r|dz  }| j                  dk  s| j                  dkD  rt        | j                        }n;| j                  }|dk(  r|dz
  dz  }t        |dz        }|dz  }||z  }|dk\  r|dz  }t        j                  d|| j                  |dz  | j                  |dz  | j                         t        | j                  t              rY| j                  j                  d	      }t        |      d
k\  r!t        |d         dz  t        |d         z   }nKt        |d         }n<t        | j                  t              r| j                  }nt        | j                        }t        j                   d| j"                  |||      S )Nir   r/       ?2      zCF is: %r %r %r cool: %r %r %r:r   r   <   r   >BHhh)r  r   r   r   r  roundr  r   r   r  r   r   splitr   r   structpackr  )rx   r   r  heatmodr  coolmodtpartsptimes           r~   	__bytes__zHThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriod.__bytes__P  s   **00$**--AB{{T)T[[3->!&t{{!3!%9&,rkS%8F!&v|!4"(2+')"b=&B,&{{T)T[[3->!&t{{!3!%9&,rkS%8F!&v|!4"(2+')"b=&B,&HH>DKKQWZ]Q]_c_j_jlruxlxz~  {D  {D  F "499c3!%#!7v;!+%(^b%8Cq	N$JE$'q	NE#TYY5 $		 #DII!;;1C1CUFTZ\\r   c                 P    t        |       j                         j                         S r   byteshexupperr   s    r~   __repr__zGThermostatDevice.ThermostatSchedule.ScheduleDay.SchedulePeriod.__repr__{  s     ;??,2244r   N)
r   r   r   rl   r  r   r   r   r"  r(  r   r   r~   SchedulePeriodr   +  s)    )SS&)]V5r   r)  c                     || _         g | _        t        d      D ].  }| j                  |      }| j                  j	                  |       0 y N   )r  periodsr   r)  rs   )rx   r  r   sps       r~   rl   z8ThermostatDevice.ThermostatSchedule.ScheduleDay.__init__~  s@    "
"A,,e5BLL''- $r   c                     t        |t              r|dk\  r|dk  r|S t        d      t        |t              st        d      |d   j	                         }|dk(  ry|dk(  ry|dk(  ry|d	k(  ry
|dk(  ryt        d      )Nr   r,  zS"period" must be an integer in the range 0-4 or a string containing the period namewar   hr   r   r	  er  r   r   
ValueErrorr   lower)rx   periods     r~   period_to_idxz=ThermostatDevice.ThermostatSchedule.ScheduleDay.period_to_idx  s    vs,{vz%$%z{{!630$%z{{*S=S=S=S=S= !vwwr   c                     t        |t              r| j                  |      }nt        |t              st	        | ||       |dk  s|dkD  rt        d      || j                  |<   y Nr   r  z$Numeric index must be an integer 0-4)r   r   r8  r   rw   r
  r-  r  s      r~   r  z;ThermostatDevice.ThermostatSchedule.ScheduleDay.__setitem__  sY    sC),,c3C#S#/T3.7cAg$%KLL$(S!r   c                     t        |t              r| j                  |      }nt        |t              st	        | |      S |dk  s|dkD  rt        d      | j                  |   S r:  )r   r   r8  r   rv   r
  r-  r  s     r~   r   z;ThermostatDevice.ThermostatSchedule.ScheduleDay.__getitem__  s[    sC),,c3C#S#/"D#//7cAg$%KLL||C((r   c                      yr+  r   r   s    r~   r   z7ThermostatDevice.ThermostatSchedule.ScheduleDay.__len__  s    r   c              #   6   K   | j                   D ]  }|  y wr   )r-  )rx   ps     r~   r   z8ThermostatDevice.ThermostatSchedule.ScheduleDay.__iter__  s     AG &   c                 |    t               }| j                  D ]  }|t        t        |            z  } t        |      S r   )	bytearrayr-  r%  )rx   retr7  s      r~   r"  z9ThermostatDevice.ThermostatSchedule.ScheduleDay.__bytes__  s4    k"llF9eVo77C +Sz!r   c                 P    t        |       j                         j                         S r   r$  r   s    r~   r(  z8ThermostatDevice.ThermostatSchedule.ScheduleDay.__repr__  s    T{(..00r   N)r   r   r   r)  rl   r8  r  r   r   r   r"  r(  r   r   r~   ScheduleDayr   *  s8    Q5 Q5f.x$	)	)"1r   rD  c                     || _         || _        d| _        d | _        g | _        t        d      D ].  }| j                  |       }| j                  j                  |       0 y )NF   )r   r   	have_datar   day_datar   rD  rs   )rx   r   r   r   sds        r~   rl   z,ThermostatDevice.ThermostatSchedule.__init__  sU     DKDH"DNDGDMAZ%%t-$$b*  r   c                 (   t        |t              r|dk\  r|dk  r|S t        d      t        |t              st        d      |d d j	                         }|dk(  ry|d   dk(  ry|dk(  ry|d   d	k(  ry
|dk(  ry|d   dk(  ry|dk(  ryt        d      )Nr   rF  zM"day" must be an integer in the range 0-6 or a string containing the day namer   sumr   tur0  r	  thr  r/   r,  sa   r4  )rx   days     r~   
day_to_idxz.ThermostatDevice.ThermostatSchedule.day_to_idx  s    3%!8aJ !pqqsC) !pqqbq'--/Cd{Q1v}Qd{Q1v}Qd{Q1v}Qd{Qlmmr   c                 L   | j                  |      }| j                  |      }t        t        | j                  |               D ]S  }t        t        | j                  |   |               D ]*  }| j                  |   |   |   | j                  |   |   |<   , U | j                  S r   rR  r   r   rH  rG  )rx   srcdstr7  itms        r~   copyDayz+ThermostatDevice.ThermostatSchedule.copyDay  s    //3(C//3(CT]]3%7!8: #dmmC&8&@"ACC6:mmC6H6PQT6UDMM#&v.s3 D ; >>!r   c                     | j                  |      }| j                  |      }t        t        | j                  |   |               D ]*  }| j                  |   |   |   | j                  |   |   |<   , | j                  S r   rT  )rx   src_day
src_perioddst_day
dst_periodrW  s         r~   
copyPeriodz.ThermostatDevice.ThermostatSchedule.copyPeriod  s|    oow0Goow0G c$--"8"DEG:>--:PQ[:\]`:ag&z237 H >>!r   c                 d   | j                  |      }d|v r+| j                  j                  |       | j                  |   |<   d|v r|d   | j                  |   |   _        d|v r|d   | j                  |   |   _        d|v r|d   | j                  |   |   _        d|v r|d   | j                  |   |   _        | j                  |   |   d   dkD  r`| j                  |   |   d   d	k  rG| j                  |   |   d   d
k7  rt        j                  d|       |dz  | j                  |   |   d<   y y y )Ndeleter  r  r  r  r   r	  r     r  z:Selected participation flag is out of range, setting to %d)
rR  rD  r)  rH  r  r  r  r  r   r   )rx   rQ  r7  rz   s       r~   	setPeriodz-ThermostatDevice.ThermostatSchedule.setPeriod  sP   //3(C 6!-1-=-=-L-Ld-Tc"6*&(;A/;Rc"6*828.c"6*/6!4:84Dc"6*16!4:84Dc"6*1}}S!&)!,q0T]]35G5OPQ5RUY5Y==%f-a0D8HHY[ab06
c"6*1- 6Z0r   c                     || _         y r   )r   r   s     r~   setCFz)ThermostatDevice.ThermostatSchedule.setCF  s	    DGr   c                    d| _         t        |      dz  dk7  rt        j                  d       y| j                  j                  | j                        }t        t        |      dz        }t        d      D ]  }||z  }||||z    }t        |      dz  dk7  rt        j                  d|z          yt        |      dz  }d}t        dt        |      d      D ]Z  }	|dz  }||	|	dz    }
t        |
      dk7  rt        j                  d||fz           yt        j                  d	|
      }t        t        |            D ]  }||   | j                  |   |   |<    | j                  |   |   j                  d
k  rct        | j                  |   |   j                  dz        }| j                  |   |   j                  dz  }d||fz  | j                  |   |   _        | j                  |   |   j                  dkD  r| j                  |   |   j                  dk  rj| j                  |   |   xj                  dz  c_        |dk(  r@t        | j                  |   |   j                  dz  dz         | j                  |   |   _        | j                  |   |   j                  dkD  s| j                  |   |   j                  dk  s| j                  |   |   xj                  dz  c_        |dk(  st        | j                  |   |   j                  dz  dz         | j                  |   |   _        ]  d| _         y )NFrF  r   z8Schedule data is in an unknown format, ignoring schedulezGSchedule day data for day %d is in an unknown format, ignoring scheduler   zWSchedule period data for period %d on day %d is in an unknown format, ignoring scheduler  ra  r  z%d:%02dii'  r   r/   r  r  T)rG  r   r   r   r   r   r   r   r   r  unpackrH  r  r  r  r  )rx   r   r   daylendowoffsetrQ  r-  r7  	dayoffset
perioddatanewdatar   hrsminss                  r~   r   z*ThermostatDevice.ThermostatSchedule.update  s   "DN4y1}!TV""DGG-BTQ'Fazv6&-0s8a<1$HHgjmmo c(Q,!&3s8Q!8IaKF!$Yy{!;J:!+"{  @F  HK  L  #L  N$$mmWjBG"CL28?
c*6215 3 }}S)&166=!$--"4V"<"A"AB"FG#}}S1&9>>C:Cs4j:Pc*627}}S)&1886AdmmTWFXY_F`FgFgjoFoc*6299S@99@Et}}UXGYZ`GaGhGhknGnrtFt@uDMM#.v6=}}S)&1886AdmmTWFXY_F`FgFgjoFoc*6299S@99@Et}}UXGYZ`GaGhGhknGnrtFt@uDMM#.v6=7 "9 "P "DNr   c                 n    | j                   j                  | j                  | j                         d      S r   )r   r   r   b64r   s    r~   savez(ThermostatDevice.ThermostatSchedule.saveA  s(    ;;(($((DHHJt(MMr   c                 |    t               }| j                  D ]  }|t        t        |            z  } t        |      S r   )rA  rH  r%  )rx   rB  daydatas      r~   r"  z-ThermostatDevice.ThermostatSchedule.__bytes__D  s7    +C==y%"244 ) :r   c                 P    t        |       j                         j                         S r   r$  r   s    r~   r(  z,ThermostatDevice.ThermostatSchedule.__repr__K  s     ;??$**,,r   c                 \    t        j                  t        |             j                  d      S Nr   )rL   r   r%  rB   r   s    r~   rq  z'ThermostatDevice.ThermostatSchedule.b64P  s"    ##U4[299'BBr   c              #   6   K   | j                   D ]  }|  y wr   )rH  )rx   ds     r~   r   z,ThermostatDevice.ThermostatSchedule.__iter__S  s     ]] #r?  c                     t        |t              r|dk(  r|| _        y | j                  |      }nt        |t              st        | ||       |dk  s|dkD  rt        d      || j                  |<   y )Nr   r   rP  $Numeric index must be an integer 0-6)r   r   r   rR  r   rw   r
  rH  r  s      r~   r  z/ThermostatDevice.ThermostatSchedule.__setitem__W  sh    3%$;"DGoos,c+sD*Qw#' !GHH!%DMM#r   c                     t        |t              r| j                  |      }nt        |t              st	        | |      S |dk  s|dkD  rt        d      | j                  |   S )Nr   rP  r{  )r   r   rR  r   rv   r
  rH  r  s     r~   r   z/ThermostatDevice.ThermostatSchedule.__getitem__e  sY    3%oos,c+c++Qw#' !GHH==%%r   N)r   r   r   rD  rl   rR  rX  r^  rb  rd  r   rr  r"  r(  rq  r   r  r   r   r   r~   rK   r   )  sY    Q	1 Q	1h
	+	n(	"		"	;0	1	"f	N		-
	C		&		&r   r   )#r   r   r   __doc__rr   r   ru   rl   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rp   objectrK   __classcell__)r}   s   @r~   r
   r
      sc    5J!
(XZ!

<#G!
 	\;!
 	/CX]_	!

 	-AV[]!
 	/CX]_!
 	+Gc#YP!
 	N!
 	-AV[]!
 	)eE!
 	(B!
 	
$!
 	!!
 	#7!
 	.BSeik!
  	.BSeik!!
" 	0DY]_#!
$ (0DY]_(?A!#tBVX+-)SU#t5)
 "+bd*,A!
HF!IF":,,,-+8:-8
:""6(=~V* *ZE&V E& E&r   r
   c                   D    e Zd ZdZd Zd Zd Zd Zd Z G d de	      Z
y	)
rt   a!  
    Represents a list of sensors such as what gets returned in DPS 122

    Args:
        dps: the DPS of this sensor list
        parent_device: the ThermostatDevice which this sensor list is attached to


    The .update(sensordata_list) method parses an update
      Args:
        sensordata_list: either a base64-encoded string such as what DPS 122 contains, or an already-decoded byte string

    The .b64() method returns a base64-encoded string ready for sending
    The str() method returns a hexidecimal string to make it easier to visualize the data

    This class is iterable so you can easily loop through the individual sensors

    I.e.
        ## create a new list
        sensor_list_object = ThermostatSensorList( '122', self ) # for DPS 122

        ## populate the sensor data
        sensor_list_object.update( 'base64 string here' )

        ## send an update after changing a sensor value
        send_dps = { '122': sensor_list_object.b64() }
        payload = d.generate_payload(tinytuya.CONTROL, data)
        d.send(payload)
    c                     d| _         d| _        g | _        || _        t	        |t
              rt        |      }|| _        y )Nr   )stated_countactual_countrq   parent_devicer   r   r   r   )rx   r   r  s      r~   rl   zThermostatSensorList.__init__  s;    *c3c(Cr   c                    g }t        |t              rt        j                  |      }nt        |t              st        d      t        |      dk  rdx| _        | _        g | _	        y t        |      dz  }|dk(  r|d   | _        n|dk(  rd | _        nt        d      t        t        |      |z
  dz        | _        t        | j                        D ]  }|t        | j                        k  rP| j                  |   j                  ||dz  |z   |dz   dz  |z          sM|j                  | j                  |          l| j                  j                  | j                  |              | j                  |   j                  ||dz  |z   |dz   dz  |z           dg| j                  |   _        d| j                  |   _        |j                  | j                  |           |S )Nz*Unhandled Thermostat Sensor List data typer   r   4   z,Unhandled Thermostat Sensor List data lengthsensor_addedT)r   r   rL   r   r%  	TypeErrorr   r  r  rq   r   r   parsers   ThermostatSensorDatar   r  )rx   sensordata_listr   lenmodr   s        r~   r   zThermostatSensorList.update  s   os+$..AOOU3IKK 1$455D 1DL_%*Q; / 2Dq[ $DKMM_!5!>" DE))+A3t||$$<<?((!B$1bRXGX)YZNN4<<?3##T%>%>%FHQ%%oqtVmac2XvDU&VW,:*<Q'/3Q,t||A/ , r   c                     | j                   d| j                   z  }nd}| j                  D ]  }|t        |      z  } |S )Nz%02X )r  rq   r   )rx   outr   s      r~   r(  zThermostatSensorList.__repr__  sE    (4,,,CCA3q6MC  
r   c                     | j                   t        | j                   g      }n
t               }| j                  D ]  }|t        t        |            z  } t	        j
                  |      j                  d      S rw  )r  rA  rq   r%  rL   r   rB   )rx   br   s      r~   rq  zThermostatSensorList.b64  se    (D--.0AAAE1J((A $++G44r   c              #   6   K   | j                   D ]  }|  y wr   )rq   )rx   r   s     r~   r   zThermostatSensorList.__iter__  s     AG r?  c                       e Zd ZdZdZej                  d      Zej                  d      Zd Zd Z	d Z
d Zd	 Zd
 ZddZd Zd Zd ZddZd Zd Zy))ThermostatSensorList.ThermostatSensorDataz>I30s??h?BBBB?h6s)raw_idraw_nameenabledoccupiedraw_temperature_usedonliner  batteryfirmware_versionunknown2	averagingraw_temperatureunknown3r  r  c                 *   || _         d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _	        d| _
        d| _        d| _        d| _        d| _        d| _        d| _        g | _        g | _        d| _        d| _        y )Nr   s                                 r  Tg        s           F)parent_sensorlistr  r  r   r  r  r  temperaturer  temperature_usedr  r  r  r  r  r  r  r   want_updater  rm   )rx   r  s     r~   rl   z2ThermostatSensorList.ThermostatSensorData.__init__  s    %6D"DK(DMDIDL DM#$D "D()D%$'D!DK!"DDLDM$%D!!DN'DMDL"D $D!&Dr   c                 d   t        j                  | j                  |      }g | _        d| _        d| _        || j                     dk(  rRt        |      }|| j                     || j                  <   t        || j                     dz        dz  || j                  <   t        t        | j                              D ]]  }| j                  |   }|| j                  v st        | |      ||   k7  s3| j                  j                  |       t!        | |||          _ d| j                  v rJ| j                  j#                  d       | j                  j                  d       d| j$                  z  | _        d| j                  v re| j                  j#                  d       | j                  j                  d       | j(                  j+                  d	      j-                  d
      | _        d| j                  v rJ| j                  j#                  d       | j                  j                  d       | j0                  dz  | _        d| j                  v rJ| j                  j#                  d       | j                  j                  d       | j4                  dz  | _        g | _        t        | j                        dk7  S )NFr   r  r  r   z%08xr  r       utf8r  r  g      Y@r  r  )r  rg  struct_formatr   r  rm   raw_temperature_idxlistraw_temperature_used_idxr   r   r   keysr  rv   rs   rw   remover  r   r  striprB   r   r  r  r  r  )rx   
sensordatanewr   r{   s        r~   r  z/ThermostatSensorList.ThermostatSensorData.parse  s0   --!3!3ZACDL %D!&D4++,13i03D4Q4Q0RD,,-58T=Z=Z9[^`9`5adf5fD1123tyy>*IIaL)))wtQ/?3q6/ILL'',D!SV, + 4<<'##H-##D) 4;;.T\\)##J/##F+ MM//8??G	 DLL0##$56##M2#'#7#7%#? %5##$:;##$67(,(A(AE(I%"D%*+r   c                     d| _         y r   r   r   s    r~   r   z6ThermostatSensorList.ThermostatSensorData.delayUpdates%  s
    !%Dr   c                     || _         |d d j                  d      j                  dd      | _        | j                  j                  d       | j                  d       y )N   r     r  r  F)r   r   rjustr  r  rs   r   )rx   r   s     r~   setNamez1ThermostatSensorList.ThermostatSensorData.setName(  sP    DI "I,,V4::BGDM##Z1U#r   c                 j    || _         | j                  j                  d       | j                  d       y )Nr  F)r  r  rs   r   )rx   enas     r~   
setEnabledz4ThermostatSensorList.ThermostatSensorData.setEnabled/  s+    DL##Y0U#r   c                 j    || _         | j                  j                  d       | j                  d       y )Nr  F)r  r  rs   r   )rx   occs     r~   setOccupiedz5ThermostatSensorList.ThermostatSensorData.setOccupied4  s+    DM##Z1U#r   c                 0   | j                   j                  d       t        |t              rCddj	                  |      z  }|r| xj
                  |z  c_        n.| xj
                  | z  c_        nt        |t              r|| _        | j                  d       y )Nr  r   wakeawayrI   sleepF)r  rs   r   r   indexr  r   r   )rx   flagr|   masks       r~   setParticipationz:ThermostatSensorList.ThermostatSensorData.setParticipation9  s}    ##_64&?EEtMM&&$.&&&4%/&T3(%)"U#r   c                     t        |t              r(ddj                  |      z  }| j                  |z  |k(  ryyt        |t              r| j                  |z  |k(  ryyy)Nr   r  TF)r   r   r  r  r   )rx   r  r  s      r~   getParticipationz:ThermostatSensorList.ThermostatSensorData.getParticipationJ  sa    4&?EEtMM&&-$6T3(&&-$6r   c                 j    || _         | j                  j                  d       | j                  d       y )Nr  F)r  r  rs   r   )rx   u2s     r~   setUnknown2z5ThermostatSensorList.ThermostatSensorData.setUnknown2[  s+    DM##Z1U#r   c                     t        |t              st        |      }t        |      dk  r|ddt        |      z
  z  z   }|d d | _        | j                  j                  d       | j                  d       y )N   r  r  F)r   r%  r   r  r  rs   r   )rx   u3s     r~   setUnknown3z5ThermostatSensorList.ThermostatSensorData.setUnknown3`  sf    r5*B[By1}7a#r)m45rFDM##Z1U#r   c                 ^   |s| j                   ry d| _         | j                  j                  j                  j	                  | j                  j
                        }| j                  j                  j                  | j                  j
                  | j                  j                         d       y )NFTr   )rm   r  r  rr   r  r   r   rq  )rx   forceidxs      r~   r   z5ThermostatSensorList.ThermostatSensorData.sendUpdatesk  s    t11!&D((66AAGGI_I_IcIceC""00::D<R<R<V<VX\XnXnXrXrXt  ~B:  Dr   c                 P    t        |       j                         j                         S r   r$  r   s    r~   r(  z2ThermostatSensorList.ThermostatSensorData.__repr__s  s    ;??$**,,r   c                      	 t        j                   j                  g fd j                  D         S #  t	        j
                  d j                  g fd j                  D           xY w)Nc              3   6   K   | ]  }t        |        y wr   r   .0r{   rx   s     r~   	<genexpr>zFThermostatSensorList.ThermostatSensorData.__bytes__.<locals>.<genexpr>x  s     9^T]q'$:JT]   zJError while attempting to pack %s with %r/%r/%r/%r/%r/%r/%r/%r/%r/%r/%r/%rc              3   6   K   | ]  }t        |        y wr   r   r  s     r~   r  zFThermostatSensorList.ThermostatSensorData.__bytes__.<locals>.<genexpr>z  s?       Ch  ^g  YZ  DK  LP  RS  DT  ^gr  )r  r  r  r  r   	exceptionr   s   `r~   r"  z3ThermostatSensorList.ThermostatSensorData.__bytes__v  s{    {{D$6$6`9^TXT]T]9^``kmqmm  j  Ch  ^b  ^g  ^g  Ch  js	   26 7A-N)T)r   r   r   r  r  r  r  r  rl   r  r   r  r  r  r  r  r  r  r   r(  r"  r   r   r~   r  r    sr    + G#'::/E#G "jj*;=	'0)	,V	&	$	$
	$
	$"	"	$
		$	D	-	r   r  N)r   r   r   r}  rl   r   r(  rq  r   r~  r  r   r   r~   rt   rt   q  s/    <	%N	5`v `r   rt   )r}  r  rL   corer   r   r   r   r   r
   r~  rt   r   r   r~   <module>r     s7   Rh   = =R
&v R
&jJ6 Jr   