mihai-dinculescu / tapo

Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L610, L630), light strips (L900, L920, L930), plugs (P100, P105, P110, P115, P300), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315).
MIT License
373 stars 37 forks source link

Behaviour of start_date and end_date parameters of device.get_energy_data() #250

Closed goofy2k closed 2 months ago

goofy2k commented 2 months ago

In an earlier issue (#221) we discussed on the meaning of the returned timestamps in the device.get_energy_data() response.

Now I have an issue with the input parameters of this API call. Want to make sure that the returned daily energies belong to fully completed days. So, I set the end_date (which is default None) to yesterday. I notice that the reponse still contains zeroes for the energies of tomorrow and more days ahead. That means that the data for today, which is also returned is not for a complete day.

I could live with that if I could relate the returned timestamps with the data items. However, I notice that the response nicely returns the start_date that I used as input, but that is not the timestamp belonging to the first data item in the response.

E.g. if I use a start_date of 5 days before now, the data still contains 35 items befor that of today. I did not yet investigate if the difference is alway 30 days (or a month).

It would be nice if the actual day belonging to a data item could be derived from the returned timestamps. Now I have to "remember" the time of the call and relate that to the last non-zero value in the data.

(the description is maybe pretty complicated, but I don't know how to make this more clear now)

goofy2k commented 2 months ago

I can state my issue in a different way: when I try to set the start_date for the sequence, the device properly returns a timestamp (as start_timestamp) correponding with the input start_date. But I can not rely on the fact that the first item in energy_data_daily.data corresponds with the energy recorded for that day.

goofy2k commented 2 months ago

The only reference between returned energy values and the date is that the last non-zero item in the list coresponds with the (unfinsihed) day of the request.

A work-around that I pack the date of the request in an object together with the received response and create a routine to find the date corresponding with each data item.

goofy2k commented 2 months ago

My code: (using python module V0.3.0)

        # create datetimes just before midnight
        # with an end_date late yesterday evening 
        start_date = (today + timedelta(days=-30)).replace(hour=23, minute=59, second=0,microsecond =0) #about a month ago
        end_date = (today +  timedelta(days=-1)).replace(hour=23, minute=59, second=0, microsecond = 0)  # yesterday

        energy_data_daily = await device.get_energy_data(
            EnergyDataInterval.Daily,
            start_date,
            end_date=end_date #default
        )        

        print(f"Energy data (daily): {energy_data_daily.to_dict()}")        
        print("start date_time:",datetime.fromtimestamp(energy_data_daily.to_dict()['start_timestamp']), "start_ts:",energy_data_daily.to_dict()['start_timestamp'] )
        print("  end date_time:",datetime.fromtimestamp(energy_data_daily.to_dict()['end_timestamp']), "  end_ts:",energy_data_daily.to_dict()['end_timestamp'] )
goofy2k commented 2 months ago

Console output:

Energy data (daily): {'data': [287, 288, 287, 287, 288, 286, 286, 476, 292, 292, 290, 288, 287, 555, 292, 291, 291, 292, 294, 294, 294, 292, 290, 290, 292, 291, 291, 291, 291, 294, 294, 290, 292, 292, 290, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'end_timestamp': 1720224000, 'interval': 1440, 'local_time': '2024-08-05T19:15:32', 'start_timestamp': 1720224000}
start date_time: 2024-07-06 02:00:00 start_ts: 1720224000
  end date_time: 2024-07-06 02:00:00   end_ts: 1720224000 (which is non-valid)

Visual Studio Locals: (it is now: 2024/08/05 19:17)

+       start_date  datetime.datetime(2024, 7, 6, 23, 59)   datetime
+       end_date    datetime.datetime(2024, 8, 4, 23, 59)   datetime

+       energy_data_daily['data']

        00  287 int    expect this to be the value for 2024-07-06 (as requested with start_date), but according to the app and 
        01  288 int    counting back from last non-zero value it is 
        02  287 int
        03  287 int
        04  288 int
        05  286 int
        06  286 int    
        07  476 int    expect this to be 07/08 (based on counting back from last non-zero item) which is OK according app screenshot.
        08  292 int    
        09  292 int
        10  290 int
        11  288 int
        12  287 int
        13  555 int
        14  292 int
        15  291 int
        16  291 int
        17  292 int
        18  294 int
        19  294 int
        20  294 int
        21  292 int
        22  290 int
        23  290 int
        24  292 int
        25  291 int
        26  291 int
        27  291 int
        28  291 int
        29  294 int  07/29 
        30  294 int  07/30
        31  290 int  08/01
        32  292 int  08/02 
        33  292 int  08/03 
        34  290 int  08/04
        35  233 int  this is the value of the unfinished day of today (2024/08/05) 
        36  0   int
        37  0   int
goofy2k commented 2 months ago

And the screenshot of the Android app: Screenshot_20240805_192603_Tapo

mihai-dinculescu commented 2 months ago

Daily intervals are quarterly based. Therefore, start_date must be the first day of a quarter. end_date is not required. The interval will run until the end of the quarter, and there's no flexibility on that, unfortunately.

goofy2k commented 2 months ago

OK. Thanks.

Does this mean that I only can select any specific quarter? Or can I only select the current quarter?

If the latter is true it means that it is "hard "to get full day data for the last day of a running quarter. The request MUST then be done just before midnight of that last day.

EDIT: I checked this. Actually a three month period can also start at the first day of the current month. So, the full last day of any month can be captured in this way.

mihai-dinculescu commented 2 months ago

You can select a specific quarter.