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
339 stars 35 forks source link

Set brightness #135

Closed kolerak closed 7 months ago

kolerak commented 9 months ago

builtins.PlugEnergyMonitoringHandler' object has no attribute 'set_brightness'

I am getting this error in here, what could be the reason?


import asyncio
import os

from tapo import ApiClient

async def main():
    client = ApiClient("xd", "xd")
    device = await client.p110("192.168.1.8")

    while True:
        user_input = input("Enter 'o' to turn the device on or 'c' to turn it off (or 'q' to quit): ")

        if user_input == 'o':
            await device.on()
            device_usage = await device.get_device_usage()
            print("Işık Açıldı, bilgiler:")
            print(f"Device usage: {device_usage.to_dict()}")
        elif user_input == 'c':
            await device.set_brightness('30')
            print("Işık kapatıldı.")

        elif user_input == 'q':
            break
        else:
            print("Invalid input. Please enter 'o' or 'c'.")

if __name__ == "__main__":
    asyncio.run(main())
kolerak commented 9 months ago

i also wonder if there is a way to look for device state?

mihai-dinculescu commented 9 months ago

set_brightness is not found because you are configuring a P110 device.

Change

device = await client.p110("192.168.1.8")

to

device = await client.l510("192.168.1.8")

The lightbulb example contains information about how to get the device info.

mihai-dinculescu commented 9 months ago

get_device_info's result will tell you that. It has a device_on property.

kolerak commented 9 months ago

Thank you so much!

kolerak commented 9 months ago

Hi again, thank you so much, i think i kinda figured it out but i am getting this error now: Serde(Error("missing field type", line: 1, column: 742)) in here device_info = await device.get_device_info()

in this code:

import asyncio
import os
import PySimpleGUI as sg

from tapo import ApiClient

async def main():
  client = ApiClient("xd", "xd")
  device = await client.l510("192.168.1.8")

  device_info = await device.get_device_info()
  layout = [
    [sg.Text("Işık Kontrolcüsü")],
    [
      sg.Button("Aç", key="ON"),
      sg.Button("Kapat", key="OFF"),
      sg.Button("Çıkış"),
    ],
    [sg.Multiline("", size=(40, 10), key="CIHAZ_BILGILERI")],
    [sg.Text("Cihaz Durumu: "), sg.Text("OFF", key="STATUS")],
    [sg.Text("0-100: "), sg.InputText(key="BRIGHTNESS")],
    [sg.Button("Parlaklık Ayarla", key="SET_BRIGHTNESS")],
  ]

  window = sg.Window("Işık", layout)

  while True:
    event, values = window.read()

    # Handle button events
    if event == "ON":
      if device_info.device_on == False:
        await device.on()
        window["CIHAZ_BILGILERI"].update("Device is off. Turning it on...")
        device_info = await device.get_device_info()
      else:
        window["CIHAZ_BILGILERI"].update("Device is already on.")
    elif event == "OFF":
      if device_info.device_on == True:
        await device.off()
        window["CIHAZ_BILGILERI"].update("Device is on. Turning it off...")
        device_info = await device.get_device_info()
      else:
        window["CIHAZ_BILGILERI"].update("Device is already off.")
    elif event == "SET_BRIGHTNESS":
      brightness = int(values["BRIGHTNESS"])
      await device.set_brightness(brightness)
      device_usage = await device.get_device_usage()
      window["CIHAZ_BILGILERI"].update(
        f"Parlaklık ayarlandı, kullanım bilgileri:\n{device_usage.to_dict()}"
      )
    elif event == "Çıkış" or event == sg.WIN_CLOSED:
      break

  window.close()

if __name__ == "__main__":
  asyncio.run(main())
mihai-dinculescu commented 9 months ago

What's the device that you're using? Can you use get_device_info_json instead of get_device_info and paste here the output?

kolerak commented 9 months ago

get_device_info_json this here worked! thanks again the device is l510, I think I should read the source code more :D

mihai-dinculescu commented 9 months ago

Can you post the output of get_device_info_json please? I'd like to understand what went from with get_device_info for you.

kolerak commented 9 months ago

yes sure, this is my output for get device info json

{'avatar': 'bulb', 'brightness': 100, 'color_temp_range': [2700, 2700], 'default_states': {'brightness': {'type': 'last_states', 'value': 100}, 're_power_type': 'always_on'}, 'device_id': '', 'device_on': True, 'fw_id': '00000000000000000000000000000000', 'fw_ver': '1.1.0 Build 230721 Rel.224802', 'has_set_location_info': True, 'hw_id': 'FDE1C', 'hw_ver': '2.0', 'ip': '', 'lang': 'tr_TR', 'latitude': 0, 'longitude': 0, 'mac': '00', 'model': 'L510', 'nickname': '', 'oem_id': '', 'overheated': False, 'region': '', 'rssi': -56, 'signal_level': 2, 'specs': '', 'ssid': '', 'time_diff': 180, 'type': 'SMART.TAPOBULB'}

mihai-dinculescu commented 9 months ago

Oh wow, the value of default_states is totally different than what I was expecting. It must be a L510 thing because I couldn't replicate it with L530.

kolerak commented 9 months ago

Wow this is weird then, what are the usual values?

joergsch commented 8 months ago

same issue w/ a newer hardware version (some fields have been redacted)

Object` {"avatar": String("bulb"), "brightness": Number(20), "color_temp_range": Array [Number(2700), Number(2700)], "default_states": Object {"brightness": Object {"type": String("last_states"), "value": Number(20)}, "re_power_type": String("always_on")}, "device_id": String(".........."), "device_on": Bool(true), "fw_id": String("00000000000000000000000000000000"), "fw_ver": String("1.1.2 Build 231120 Rel.201048"), "has_set_location_info": Bool(false), "hw_id": String(".........."), "hw_ver": String("3.0"), "ip": String("10.11.12.13"), "lang": String(""), "latitude": Number(-1879048193), "longitude": Number(-1879048193), "mac": String(".........."), "model": String("L510"), "music_rhythm_enable": Bool(false), "music_rhythm_mode": String("single_lamp"), "nickname": String("QnVsYiBEZXY="), "oem_id": String(".........."), "overheated": Bool(false), "region": String("Europe/Berlin"), "rssi": Number(-50), "signal_level": Number(2), "specs": String(""), "ssid": String(".........."), "time_diff": Number(60), "type": String("SMART.TAPOBULB")}

L610 is behaving the same (json data works, but error "Serde: missing field type at line 1 column 742" if using get_device_info() )

mihai-dinculescu commented 8 months ago

Thank you for confirming a second instance. It must be a change in the L510/L610 API. I was not able to replicate it with L530.

Unfortunately, I do not own a L510 or L610 device. To apply a fix, I need to know more about all the possible values that default_states could contain.

joergsch commented 8 months ago

the json structure is as following (L510, L610):

"default_states": Object {
    "brightness": Object {
        "type": String(),
        "value": Number(),
    },
    "re_power_type": String(),
},

type: custom, last_states value: 1..100 (including 100) re_power_type: always_on, last_states

mihai-dinculescu commented 7 months ago

Thank you for the help. The fix has been released in Tapo Rust v0.7.7 and Tapo Python v0.1.4.