3

First thing first, this is the first time ever i work and use python, so please be patient :)

I'm trying to hack a dash button from amazon to toggle my philips hue light, and i manage to find all the required elements and code and edit it to suit my needs.

The problem i've got now, is that if i run the script, the function in python that i'd like to run execute instantly and doesn't wait to the button to be pressed...

here's some code:

from pydhcplib.dhcp_network
import *
import requests, json

bridgeIP = "{{mybridgeIP}}"
user = "{{philipsUserID}}"
dashMac = "{{dashMacAddress}}"
lightID = "4"

def do_something():
    print("button has been pressed")

def toggleLight(lightID):
    url = "http://" + bridgeIP + "/api/" + user + "/lights/" + lightID
    r = requests.get(url)
    data = json.loads(r.text)
    if data["state"]["on"] == False:
      r = requests.put(url + "/state", json.dumps({
        'on': True
      }))
    elif data["state"]["on"] == True:
      r = requests.put(url + "/state", json.dumps({
        'on': False
        }))


netopt = {'client_listen_port':"68", 'server_listen_port':"67", 'listen_address':"0.0.0.0"}

class Server(DhcpServer):
    def __init__(self, options, dashbuttons):
        DhcpServer.__init__(self, options["listen_address"],
                                options["client_listen_port"],
                                options["server_listen_port"])
        self.dashbuttons = dashbuttons

    def HandleDhcpRequest(self, packet):
        mac = self.hwaddr_to_str(packet.GetHardwareAddress())
        self.dashbuttons.press(mac)


    def hwaddr_to_str(self, hwaddr):
        result = []
        hexsym = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f']
        for iterator in range(6) :
            result += [str(hexsym[hwaddr[iterator]/16]+hexsym[hwaddr[iterator]%16])]
        return ':'.join(result)

class DashButtons():
    def __init__(self):
        self.buttons = {}

    def register(self, mac, function):
        self.buttons[mac] = function

    def press(self, mac):
        if mac in self.buttons:
            self.buttons[mac]()
            return True
        return False


dashbuttons = DashButtons()
dashbuttons.register(dashMac, do_something)
dashbuttons.register(dashMac, toggleLight(lightID))
server = Server(netopt, dashbuttons)

while True :
    server.GetNextDhcpPacket()

My problem is that do_something() is called properly (when i press the button) but toggleLight(lightID) is called as soon as i run the script..

i don't understand why, they look identical to me..

can you help me understand? thanks

3
  • Try only toggleLight not toggleLight(lightID) this is already calling the method when create the button Commented Mar 8, 2017 at 23:00
  • if i do that, it run on click but then i get this error: TypeError: toggleLight() takes exactly 1 argument (0 given) Commented Mar 8, 2017 at 23:02
  • Yes you need to change the method definition to take only 0 parameters - you can still get your id by saving it in global context and then get it in the method itself - you need to assign a reference to the method - not a call of a method Commented Mar 8, 2017 at 23:04

2 Answers 2

6

With this line

dashbuttons.register(dashMac, toggleLight(lightID))

you execute toggleLight(lightID) and bind the result of that call to the function parameter. Since the function takes a parameter, you can not just pass toggleLight, either. Instead, use a lambda function:

dashbuttons.register(dashMac, lambda: toggleLight(lightID))

This creates a new anonymous function that takes no parameters and that will call toggleLight(lightID) when invoked by the button.

Sign up to request clarification or add additional context in comments.

2 Comments

another option is to wrap toggleLight itself, in a function factory
You can also use functools.partial, e.g. dashbuttons.register(dashMac, partial(toggleLight, lightID))
0

I may be wrong, as I review your code quickly, but when registering, you shall not put () after the function, otherwise it's executed as the interpreter comes across it.

dashbuttons.register(dashMac, do_something)
dashbuttons.register(dashMac, toggleLight)

2 Comments

But toggleLight will expect a parameter when it is eventually called.
yep, this is true. I was more trying to help understand the issue than giving a solution... I didn't thought about lambda (from @tobias_k's answer) when I saw the code; once again, lambdas can be damn impressive!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.