usage
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/.....
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
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):
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 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
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:

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" }'
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.
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?
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 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 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.
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?
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.
ohh sorry, I think you need to use port 5000.
http://192.168.0.19:5000/switchbot/api/v1/login
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
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?
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
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 ?
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
@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?
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.
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 sorry I had a typo. I updated the script above.
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?
the script I wrote for you does not need the flask part
@nicolas-kuechler i am having connection issues surprisingly but my raspberry pi and the switchbot is in the same room.
@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.
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
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 updatesudo apt-get upgradesudo apt-get install build-essential libssl-dev libffi-dev python-dev- delete the
Pipfile.lockin/home/pi/switchbot pipenv installin/home/pi/switchbotsudo 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 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.