switchbotpy icon indicating copy to clipboard operation
switchbotpy copied to clipboard

usage

Open bachoo786 opened this issue 5 years ago • 41 comments

hi there Thanks for this wonderful application.

However being a novice and trying to get my head around on how to use this application I do not understand the usage section in the readme file.

After installing everything do I just navigate to my raspberry pi's address and go to /switch/...... E.g. 192.168.0.10/switch/.....

bachoo786 avatar Apr 17 '20 22:04 bachoo786

Generally I would recommend to run the application in a setup with Gunicorn and Nginx. However, if you only want to try it out, you don't need them.

After installing everything on the raspberry pi, you should be able to reach the login endpoint: {{ raspberry pi ip address }}/switchbot/api/v1/login (don't forget to pass a name and the password)

Afterwards you can contact the endpoint which lists all switchbots with the token in the header you received from the login: {{ raspberry pi ip address }}/switchbot/api/v1/bots

nicolas-kuechler avatar Apr 18 '20 13:04 nicolas-kuechler

hey @nicolas-kuechler so I managed to run it but its asking for a password now

pi@raspberrypi:~/switchbot $ sudo pipenv run python src/main.py
Login Password (required for receiving bearer token):

bachoo786 avatar Apr 18 '20 15:04 bachoo786

ok so I put in a random password and it says its running on 0.0.0.0:5000. I try to navigate to {{ raspberry pi ip address }}/switchbot/api/v1/login but the page doesnt work. I cannot reach the login endpoint.

Can you help please?

bachoo786 avatar Apr 18 '20 15:04 bachoo786

@bachoo786 it asks you to set a password (you choose one).

it is the password that you then later need in order to receive a bearer token on this endpoint: {{ raspberry pi ip address }}/switchbot/api/v1/login

if you already set a password but don't remember it (i.e. if you are not prompted again to enter one when you start), you can remove the switchbot entry in the keyring file which should be at this location: ~/.local/share/python_keyring/keyring_pass.cfg

nicolas-kuechler avatar Apr 18 '20 15:04 nicolas-kuechler

yes I have set the password and now what? I try to go to 192.168.0.19/switchbot/api/v1/login but it doesnt return anything? I thought you mentioned there is a login ? like a web interface?

See below please:

image

bachoo786 avatar Apr 18 '20 15:04 bachoo786

you cannot access it with your webbrowser, instead you have to login with a post request.

I recommend to use postman (because there is a collection in the repo which you can import)

If you want to use curl, this is what you need to send: (replace the PASSWORD in the request with the random password that you set)

curl --location --request POST 'http://192.168.0.19/switchbot/api/v1/login' \ --header 'Content-Type: application/json' \ --header 'Content-Type: text/plain' \ --data-raw '{ "name": "NAME", "password": "PASSWORD" }'

nicolas-kuechler avatar Apr 18 '20 15:04 nicolas-kuechler

oh right this is confusing for me sorry.

what I am trying to do is simply make my switchbot press on for 2 mins and then go back to off or its original state.

bachoo786 avatar Apr 18 '20 16:04 bachoo786

ok @nicolas-kuechler the curl command doesnt work either. I set the password and I used it in the curl command, but it says:

 curl --location --request POST 'http://192.168.0.19/switchbot/api/v1/login' \ --header 'Content-Type: application/json' \ --header 'Content-Type: text/plain' \ --data-raw '{ "name": "NAME", "password": "abcd123" }'
curl: (7) Failed to connect to 192.168.0.19 port 80: Connection refused
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL

[1/2]:  "name": "NAME" --> <stdout>
--_curl_-- "name": "NAME"
curl: (3) URL using bad/illegal format or missing URL

[2/2]:  "password": "abcd123"  --> <stdout>
--_curl_-- "password": "abcd123"
curl: (3) URL using bad/illegal format or missing URL

do I need to provide name as well?

bachoo786 avatar Apr 18 '20 16:04 bachoo786

I think there is a different problem because you get the connection refused error.

What you should see if you open the url with your browser is the following message: {"status":"405 Method Not Allowed: The method is not allowed for the requested URL."}

What you can try is to change http to https.

curl -k --location --request POST 'https://192.168.0.19/switchbot/api/v1/login' \ --header 'Content-Type: application/json' \ --header 'Content-Type: text/plain' \ --data-raw '{ "name": "NAME", "password": "PASSWORD" }'

I assume the switchbot program is still running, right? Does the cmd output show something?

nicolas-kuechler avatar Apr 18 '20 16:04 nicolas-kuechler

@nicolas-kuechler I get the same connection refused error if I change it to https.

Please tell me a few things:

1). do I have to continue running this command: pipenv run python src/main.py when I do my curl command?

the command output doesnt show anything:

pi@raspberrypi:~/switchbot $ sudo pipenv run python src/main.py
/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages/apispec/ext/marshmallow/common.py:145: UserWarning: Multiple schemas resolved to the name Timer. The name has been modified. Either manually add each of the schemas with a different name or provide a custom schema_name_resolver.
  UserWarning,
 * Serving Flask app "switchbot_api" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
INFO:werkzeug: * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

also there is no python_keyring folder in ~/.local/share. So I cannot locate this file ~/.local/share/python_keyring/keyring_pass.cfg

bachoo786 avatar Apr 18 '20 16:04 bachoo786

@bachoo786 yes, you have to keep this running. This is a flask server, that continuously runs.

You might need to google for keyring locations or you can search the raspberry pi file system for a keyring_pass.cfg file.

nicolas-kuechler avatar Apr 18 '20 16:04 nicolas-kuechler

ok I changed my password to "hello" and I ran the commands please see below:

pi@raspberrypi:~ $ curl --location --request POST 'https://192.168.0.19/switchbot/api/v1/login' \ --header 'Content-Type: application/json' \ --header 'Content-Type: text/plain' \ --data-raw '{ "name": "NAME", "password": "hello" }'
curl: (7) Failed to connect to 192.168.0.19 port 443: Connection refused
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL

[1/2]:  "name": "NAME" --> <stdout>
--_curl_-- "name": "NAME"
curl: (3) URL using bad/illegal format or missing URL

[2/2]:  "password": "hello"  --> <stdout>
--_curl_-- "password": "hello"
curl: (3) URL using bad/illegal format or missing URL
pi@raspberrypi:~ $ curl --location --request POST 'http://192.168.0.19/switchbot/api/v1/login' \ --header 'Content-Type: application/json' \ --header 'Content-Type: text/plain' \ --data-raw '{ "name": "NAME", "password": "hello" }'
curl: (7) Failed to connect to 192.168.0.19 port 80: Connection refused
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL
curl: (3) URL using bad/illegal format or missing URL

[1/2]:  "name": "NAME" --> <stdout>
--_curl_-- "name": "NAME"
curl: (3) URL using bad/illegal format or missing URL

[2/2]:  "password": "hello"  --> <stdout>
--_curl_-- "password": "hello"
curl: (3) URL using bad/illegal format or missing URL

same issue.

what port is this running on? 443?

bachoo786 avatar Apr 18 '20 16:04 bachoo786

can I ask you something? I am also following this person's switchbot command but he doesnt specify any timers for the press action of the switchbot. Here is his python code:

https://gist.githubusercontent.com/mugifly/a29f34df7de8960d72245fcb124513c7/raw/2a7c03821d008d23ada21661447a2e2c03397644/switchbot-cmd.py

Can you please tell me what can I add to the python code to make the press command hold for 2 minutes?

I am not familiar with python but learning.

bachoo786 avatar Apr 18 '20 16:04 bachoo786

ohh sorry, I think you need to use port 5000.

http://192.168.0.19:5000/switchbot/api/v1/login

nicolas-kuechler avatar Apr 18 '20 17:04 nicolas-kuechler

if you don't need the rest api and you just want a script which pushes the switchbot for 2 min.

The following script:

from switchbot import Bot
from switchbot import Scanner

scanner = Scanner()
mac_addresses = scanner.scan(known_dict={})

print(f"mac adresses: { mac_adresses}")

bot = Bot(id=1, mac=mac_adresses[0], name="your name")

# change the hold time to 2 minutes (you only need to do this once)
bot.set_hold_time(120)

# press the bot
bot.press() 

Place it in the folder switchbot/src on your raspberry pi with the name that you want and then execute from the root folder the following command. (you might require sudo because I think the scanner functionality relies on it)

pipenv run python src/yourname.py

nicolas-kuechler avatar Apr 18 '20 18:04 nicolas-kuechler

if you don't need the rest api and you just want a script which pushes the switchbot for 2 min.

The following script:

from switchbot import Bot
from switchbot import Scanner

scanner = Scanner()
mac_addresses = scanner.scan(known_dict={})

print(f"mac adresses: { mac_adresses}")

bot = Bot(id=1, mac=mac_adresses[0], name="your name")

# change the hold time to 2 minutes (you only need to do this once)
bot.set_hold_time(120)

# press the bot
bot.press() 

Place it in the folder switchbot/src on your raspberry pi with the name that you want and then execute from the root folder the following command. (you might require sudo because I think the scanner functionality relies on it)

pipenv run python src/yourname.py

So where do I put my mac address of my switchbot?

bachoo786 avatar Apr 18 '20 18:04 bachoo786

from switchbot import Bot

bot = Bot(id=1, mac="MAC_ADDRESS", name="your name")

# change the hold time to 2 minutes (you only need to do this once)
bot.set_hold_time(120)

# press the bot
bot.press() 

if you have the mac adress, you don't have to scan to find the bot, just replace MAC_ADDRESS in the code above

nicolas-kuechler avatar Apr 18 '20 18:04 nicolas-kuechler

so I used the script that you provided above however where shall i run it from? shall I run it in /home/pi/switchbot/src ?

bachoo786 avatar Apr 18 '20 20:04 bachoo786

ok @nicolas-kuechler I ran the script but it gives me an error that the hold time can only be between 0-60 seconds. I changed in the script to 240seconds. here is the error:

Traceback (most recent call last):
  File "src/air.py", line 6, in <module>
    bot.set_hold_time(240)
  File "/home/pi/switchbot/src/switchbot.py", line 125, in set_hold_time
    raise ValueError("hold time must be between [0, 60] seconds")
ValueError: hold time must be between [0, 60] seconds

bachoo786 avatar Apr 18 '20 20:04 bachoo786

@nicolas-kuechler I changed the time in switchbot.py to 250 seconds. and now I get a new error:

ERROR:switchbot:pygatt: failed to activate notifications
Traceback (most recent call last):
  File "/home/pi/switchbot/src/switchbot.py", line 371, in _activate_notifications
    self.device.subscribe(uuid, callback=handle_notification)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/device.py", line 202, in subscribe
    self._notification_handles(uuid)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/device.py", line 178, in _notification_handles
    value_handle = self.get_handle(uuid)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/device.py", line 263, in get_handle
    self._characteristics = self.discover_characteristics()
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/backends/gatttool/device.py", line 17, in wrapper
    return func(self, *args, **kwargs)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/backends/gatttool/device.py", line 58, in discover_characteristics
    self, *args, **kwargs)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/backends/gatttool/gatttool.py", line 50, in wrapper
    return func(self, *args, **kwargs)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/backends/gatttool/gatttool.py", line 531, in discover_characteristics
    raise NotConnectedError("Characteristic discovery failed")
pygatt.exceptions.NotConnectedError: Characteristic discovery failed
Traceback (most recent call last):
  File "/home/pi/switchbot/src/switchbot.py", line 371, in _activate_notifications
    self.device.subscribe(uuid, callback=handle_notification)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/device.py", line 202, in subscribe
    self._notification_handles(uuid)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/device.py", line 178, in _notification_handles
    value_handle = self.get_handle(uuid)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/device.py", line 263, in get_handle
    self._characteristics = self.discover_characteristics()
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages 
/pygatt/backends/gatttool/device.py", line 58, in discover_characteristics
    self, *args, **kwargs)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/backends/gatttool/gatttool.py", line 50, in wrapper
    return func(self, *args, **kwargs)
  File "/root/.local/share/virtualenvs/switchbot-rpEz6xuZ/lib/python3.7/site-packages                                 /pygatt/backends/gatttool/gatttool.py", line 531, in discover_characteristics
    raise NotConnectedError("Characteristic discovery failed")
pygatt.exceptions.NotConnectedError: Characteristic discovery failed

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "src/air.py", line 6, in <module>
    bot.set_hold_time(240)
  File "/home/pi/switchbot/src/switchbot.py", line 130, in set_hold_time
    self._activate_notifications()
  File "/home/pi/switchbot/src/switchbot.py", line 375, in _activate_notifications
    raise SwitchbotError(message="communication with ble device failed")
switchbot_util.SwitchbotError: communication with ble device failed

can you please help?

bachoo786 avatar Apr 18 '20 21:04 bachoo786

This check is there because the switchbot only accepts a hold time up to one minute. So you cannot do what you want directly.

However, there is a workaround. You can try the following:

import time
from switchbot import Bot

bot = Bot(id=1, mac="MAC_ADDRESS", name="your name")

# switch to the dual state mode (allows you to extend the arm with bot.switch(on=True))
bot.set_mode(dual_state=True, inverse=False)

# extend the switchbot arm
bot.switch(on=True)

# wait for 120 seconds
time.sleep(120)

# retract the switchbot arm
bot.switch(on=False)

# switch back to the normal operation mode
bot.set_mode(dual_state=False, inverse=False)

The failed connection can happen sometimes, you can wait a bit and then retry. If the problem persists you can reset your switchbot. Check the official site to see how to do this.

nicolas-kuechler avatar Apr 19 '20 07:04 nicolas-kuechler

ok I tried the above script and now I get this error:

pi@raspberrypi:~/switchbot $ sudo pipenv run python src/air.py
  File "src/air.py", line 7
    bot.set_mode(dual_state=True, inverse=False):
                                                ^
SyntaxError: invalid syntax

bachoo786 avatar Apr 19 '20 10:04 bachoo786

@bachoo786 sorry I had a typo. I updated the script above.

nicolas-kuechler avatar Apr 19 '20 11:04 nicolas-kuechler

Thanks I will try it.

Is it possible to have a script without the flask? Because I would have to run the flask all the time using cronjob and then execute the script above.

Is there a way where a script can just do the press and hold for 2 minutes?

bachoo786 avatar Apr 19 '20 11:04 bachoo786

the script I wrote for you does not need the flask part

nicolas-kuechler avatar Apr 19 '20 11:04 nicolas-kuechler

@nicolas-kuechler i am having connection issues surprisingly but my raspberry pi and the switchbot is in the same room.

bachoo786 avatar Apr 19 '20 13:04 bachoo786

@bachoo786

does it sometimes work and sometimes not? or did it never work?

If it never worked, you might have used the wrong mac address. (you can find the mac address via the mobile app)

Does it always fail at the same step? (e.g. it does extend the arm but not retract it)

What firmware does your switchbot have? (you can check in the mobile app)

In my setup it works very reliable with this code over quite some distance. So I don't think it's an issue related to this codebase.

nicolas-kuechler avatar Apr 19 '20 13:04 nicolas-kuechler

Well the script that I posted yesterday which you can find above it works perfectly with it I suppose that script is of the official api by switchbot.

With your script it doesn't move at all.

I have the correct mac address as I got it from the app.

The firmware version is V4.5

bachoo786 avatar Apr 19 '20 14:04 bachoo786

@bachoo786

I took the time and tested the script in my own setup and it worked. You might need to update some packages. If performing the following steps does not resolve your issues I dont know what the problem is in your setting:

  • sudo apt-get update
  • sudo apt-get upgrade
  • sudo apt-get install build-essential libssl-dev libffi-dev python-dev
  • delete the Pipfile.lock in /home/pi/switchbot
  • pipenv install in /home/pi/switchbot
  • sudo reboot

Additionally, I also tested if it works to set a hold time above 60 seconds. Unfortunately the switchbot hardware does not support this. The maximum it will hold is 60 seconds.

What my script does is the following, it changes the mode to dual state. Here the switchbot has a separate on and off state. What the script does is: first it activates this mode, then it extends the arm, waits 120 seconds, then retracts the arm and finally it switches the mode back. (switching the mode also executes a certain movement of the arm) If you don't need your switchbot for anything else, you can comment out the last line, then run it and then comment out bot.set_mode(dual_state=True, inverse=False) this line too.

I don't know if this is sufficient for your needs.

Another option would be to push the switchbot for one minute, then push it for another minute afterwards.

nicolas-kuechler avatar Apr 19 '20 16:04 nicolas-kuechler

@nicolas-kuechler Hello mate sorry for the delayed response.

1). Can I run your script in my home folder using the following command: sudo python air.py? 2). Did you experience any connection issues or drop outs when you ran your script? Do you experience occasional connection drop outs? 3). The other option you gave for push the switchbot for a minute and then for another minute, does it require a new script? how can I achieve that?

All I need is to turn push the switch for 120 seconds and then return back to its original state. So basically it acts like a push switch but with hold. I want to be able to control the hold duration and also when to turn the switchbot on.

Many thanks.

bachoo786 avatar May 16 '20 18:05 bachoo786