A library to authenticate and interact with STIHL iMow mowers using their WebAPI
Project description
STIHL iMow unofficial Python API wrapper
This unofficial Python API was created to provide an interface to interact with the STIHL iMow mower WebAPI. This wrapper is able to receive the current state
from the mowers and to send actions.
I wrote this library to implement an integration for the Home Assistant Smart Home System, which you can find here.
iMOW compatibility
STIHL uses different webapps for their iMOW generations. Currently only the iMOW RMI series are supported by this library, because i'm not able to reverse engineer the newer generation. This is simply because I do not own them.
If you use this webapp, https://app.imow.sithl.com, this library should work for your mower.
Also see here: Issue #13
Getting Started
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
API Documentation is available on: https://chrishapunkt.github.io/stihl-imow-webapi/imow
Prerequisites
Python 3.8+ is required to run this application, other than that there are no prerequisites for the project, as the dependencies are included in the repository.
Installing
To install the library is as simple as cloning the repository and running
pip install -e .
It is recommended to create an virtual environment prior to installing this library. Alternatively, you can also install this library via Pip:
pip install imow-webapi
And have fun!
Usage
Python Import and Usage
Import the module and instantiate the IMowApi()
constructor with credentials. Afterwards, initiate the get_token()
method.
Or place credentials in the get_token()
method.
from imow.api import IMowApi
from imow.common.actions import IMowActions
import asyncio
import aiohttp
async def main():
async with aiohttp.ClientSession() as session:
api = IMowApi(aiohttp_session=session, lang="de")
# save token for later use if you want to recreate IMowApi(token=my_token) because the created token is valid for
# 30 days
token, expire_time = await api.get_token("email@account.stihl", "supersecret", return_expire_time=True)
print(await api.get_token())
mowers = await api.receive_mowers()
mower = mowers[0]
print(f"{mower.name} @ {mower.coordinateLatitude},{mower.coordinateLongitude}")
print(f"Currently: {mower.stateMessage['short']}")
await mower.update_setting("gpsProtectionEnabled", True)
print(mower.stateMessage)
print(mower.machineState)
await mower.intent(IMowActions.TO_DOCKING)
print(await mower.update_from_upstream())
print(await mower.get_startpoints())
if __name__ == "__main__":
asyncio.run(main())
Selection of outputs from above statements:
> Mährlin @ 54.123456,10.12345
> Currently: Hood blocked
> {'short': 'Hood blocked', 'long': 'The hood is blocked. Please check the hood and press the OK button on your machine (M1120).', 'legacyMessage': 'Abschaltung Automatikmode durch Bumper', 'errorId': '', 'error': False}
> HOOD_BLOCKED
> <imow.common.mowerstate.MowerState object at 0x000001B034C245F8>
Example: Receive startpoints and intent mowing
Save the following as myscript.sh
and execute chmod +x myscript.sh
. Make sure you install the api via pip3 install imow-webapi
Afterwards you can execute via ./myscript.sh
#!/usr/bin/env python3
from imow.api import IMowApi
from imow.common.actions import IMowActions
import asyncio
import aiohttp
import logging
logger = logging.getLogger("imow")
# Enable DEBUG output
logging.basicConfig(level=logging.DEBUG)
async def main():
async with aiohttp.ClientSession() as session:
api = IMowApi(aiohttp_session=session, lang="de")
# save token for later use if you want to recreate IMowApi(token=my_token) because the created token is valid for
# 30 days
token, expire_time = await api.get_token("email@account.stihl", "supersecret", return_expire_time=True)
print(await api.get_token())
mowers = await api.receive_mowers()
mower = mowers[0]
print(f"{mower.name} @ {mower.coordinateLatitude},{mower.coordinateLongitude}")
print(f"Currently: {mower.stateMessage['short']}")
startpoints = await mower.get_startpoints()
for i in range(len(startpoints)):
print("Startpoint {}: {}".format(i, startpoints[i]))
# if your mower supports the "startMowing" call, use this action (i.e iMow 600 series)
await mower.intent(IMowActions.START_MOWING, starttime="2023-08-12 20:50")
# await mower.intent(IMowActions.START_MOWING, endtime="2023-08-12 22:50")
# await mower.intent(IMowActions.START_MOWING, starttime="2023-08-12 20:50", endtime="2023-08-12 22:50")
# if your mower supports the "startMowingFromPoint" call, use this action (i.e iMow 400 series)
await mower.intent(IMowActions.START_MOWING_FROM_POINT, duration=50)
# await mower.intent(IMowActions.START_MOWING_FROM_POINT, startpoint=2)
# await mower.intent(IMowActions.START_MOWING_FROM_POINT, duration=50, startpoint=2)
if __name__ == "__main__":
asyncio.run(main())
Testing
For unit testing run pytest -s tests/test_unit*
. For upstream integration testing, provide a /secrets.py
with the following contents:
EMAIL = "email@account.stihl"
PASSWORD = "supersecret"
MOWER_NAME = "MyRobot"
and run pytest -s tests/test_integration*
or pytest -s
.
Built With
- aiohttp
- BeautifulSoup
- asyncio
Versioning
Navigate to tags on this repository to see all available versions.
Authors
Mail Address | GitHub Profile |
---|---|
chris@homeset.de | ChrisHaPunkt |
License
This project is licensed under the MIT License - see the LICENSE.md license file for more details.
Acknowledges
Thanks to
for repo structure inspiration
Changelog
Version 0.8.4 (2023-12-09)
Fix
- Loosen the version requirements for dependency libs
- update the tested python version placed inside setup and PyPi to python 3.12
Version 0.8.2 (2023-08-26)
Fix
- validation of values in keyword arguments
BREAKING CHANGE
The iMow action IMowActions.START_MOWING
now creates a startMowing
action and no longer a startMowingFromPoint
action.
To issue a startMowingFromPoint
, the new IMowAction.START_MOWING_FROM_POINT
needs to be used.
Added
- keywork arguments
starttime
andendtime
inIMow.intent()
call to be used with IMowActions.START_MOWING - Updated Readme with
IMow.intent
exampes - added debug log output in
intent()
call
Version 0.7.10 (2023-05-13)
- Bugfix http_session not present on logout
Version 0.7.9 (2023-05-13)
- remove unnecessary http_session closes
Version 0.7.8 (2022-03-06)
- Implement a logout function
ImowAPI.api_logout()
. Use within re-authentication
Version 0.7.7 (2022-03-06)
- Use more
async with
s
Version 0.7.6 (2022-03-05)
Dependency updates
- Update dependencies to latest
Version 0.7.4 (2021-09-06)
Bugfxes
- Allow handling of timestamps on mower intents (StartTime/Endtime)
Version 0.7.3 (2021-07-03)
Bugfxes
- Always return a MowerState on settings update
Version 0.7.2 (2021-07-03)
await mower.update_setting("gpsProtectionEnabled", True)
Features
- Possibility to update a specific settings for a mower like gpsProtection on/off
Version 0.7.0 (2021-06-30)
Breaking Changes
IMowApi.intent
Parametermower_action_id
is renamed tomower_external_id
to match the upstream api expectation.
Features
- If an
api_request
is intended, and the usedaccess_token
expires in less than one day, it's automatically renewed.
Version 0.6.0 (2021-06-28)
-
mower.machineError = 'M1120', mower.machineState = 'HOOD_BLOCKED', mower.stateMessage: dict = { 'short': 'Hood blocked', 'long': 'The hood is blocked. Please check the hood and press the OK button on your machine (M1120).', 'legacyMessage': 'Abschaltung Automatikmode durch Bumper', 'errorId': 'M1120', 'error': True }
Breaking Changes
- Migrated all own MowerState attributes to camelCase to match the upstream attributes style.
- MowerState.stateMessage = None - MowerState.machineError = None - MowerState.machineState = None
Version 0.5.2 (2021-06-15)
Bugfixes
- Also quote password string in auth request to support more special chars
Version 0.5.1 (2021-06-13)
Features
-
mower.machine_error = 'M1120', mower.machine_state = 'HOOD_BLOCKED', mower.state_message: dict = { 'short': 'Hood blocked', 'long': 'The hood is blocked. Please check the hood and press the OK button on your machine (M1120).', 'legacyMessage': 'Abschaltung Automatikmode durch Bumper', 'errorId': 'M1120', 'error': True }
Provide a machine usable string from the short message in english
Version 0.5.0 (2021-06-12)
Breaking Changes
- The
MowerTask
class is removed in favor of the newstate_message
property on thMowerState
object. - The
MowerState.get_current_task()
method now returns theshort
property of the state message instead of aMowerTask
property and is now longer anasync
method.
Features
-
mower.state_message -> dict { 'short': 'Hood blocked', 'long': 'The hood is blocked. Please check the hood and press the OK button on your machine (M1120).', 'errorId': 'M1120', 'error': True }
The MowerState Class now provides astate_message
property which gives ashort
andlong
text for description (Besides an error indication and errorId). All error and status codes are now dynamically matched and human readable available. This makes theMowerTask
obsolete and it is removed with this release. api = IMowApi(lang="en")
The imow api can now be instanced with a language code (fallback toen
). Thestate_message
property displays the messages in the corresponding language.
Version 0.4.5 (2021-06-01)
Features
- Add 2 new identified Tasks within
MowerTask
(Thanks to @lausser) - Add
check_api_maintenance()
method toIMowAPI
Class. Check if the api server is currently under maintenance. This method is automatically called if the api server returns a 500 error response for any request. - One should call the new
close()
method for theIMowAPI
Class when finishing the api interactions to correctly close the http session.
Bugfixes
- Issue #8 - Example not working
Version 0.4.4 (2021-05-28)
Features
- Add
validate_token()
method toIMowAPI
Class. Test if a token is valid and is able to call the webapi.
Version 0.4.3 (2021-05-27)
Features
- Allow
IMowAPI
Class to use predefinedaiohttp
session when instantiating
Version 0.4.1 (2021-05-24)
Changes
- Even more asynchronously with switch from
requests
toaiohttp
Version 0.4.0 (2021-05-17)
Breaking Changes
- Reworked everything to use asyncio where possible. See Readme.md for new usage example.
- Renamed MowerState method
update
toupdate_from_upstream
- Renamed MowerState method
get_status
toget_current_status
Version 0.3.0 (2021-05-17)
Breaking Changes
- Renamed Class/Enum
MowerState
toMowerTask
because it describes the current task not the state - Renamed Class
Mower
toMowerState
because it's just a snapshot of the last upstream state
Features
- Add methods to work on
MowerState
objects, like action intents or statistic receive - Add PDoc documents, available on https://chrishapunkt.github.io/stihl-imow-webapi/imow
Bugfixes
- Return a valid error message and raise if provided login credentials are wrong
Version 0.2.2 (2021-05-00)
- Initial release
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file imow-webapi-0.8.4.tar.gz
.
File metadata
- Download URL: imow-webapi-0.8.4.tar.gz
- Upload date:
- Size: 27.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.12.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | d92c68d3e4329268f673a40708b968d4a0453ec93925ab4e7e9d1e4c0dafa1d6 |
|
MD5 | bfbf3ddb54a016ffe5c81049e4217e9a |
|
BLAKE2b-256 | c7ee57190917ef291b965811821ef0149b49216b461878299e293ee1c51971fb |
File details
Details for the file imow_webapi-0.8.4-py3-none-any.whl
.
File metadata
- Download URL: imow_webapi-0.8.4-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.12.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 404c82730317aca9fc7ece7d316ab2ae36511b0af2538e27ed3cd9f191d93919 |
|
MD5 | fc8fb8e21c38db6409f860c3ea6e3bd8 |
|
BLAKE2b-256 | d74f2cc68c7bfa979a5ddfec9c00853058e51559c26094dd371e1b367f0b9afd |