././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1617379706.7264533 meater-python-0.0.8/0000777000000000000000000000000000000000000012446 5ustar0000000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1617379706.7244542 meater-python-0.0.8/PKG-INFO0000666000000000000000000001312600000000000013546 0ustar0000000000000000Metadata-Version: 2.1 Name: meater-python Version: 0.0.8 Summary: A wrapper for the Apption Labs Meater probe API v1 Home-page: https://github.com/Sotolotl/meater-python Author: Billy Stevenson Author-email: meater-api@billystevenson.co.uk License: UNKNOWN Description: # meater-python Python wrapper for the Apption Labs Meater cooking probe using v1 of their public API. ## Installation `meater-python` can be installed from either PyPi or can be installed manually by cloning the GitHub repository. ### TL;DR installation ```pip install meater-python``` ### Manual installation First, clone the GitHub repository: ```git clone https://github.com/Sotolotl/meater-python.git``` Enter the newly created `meater-python` directory and run: ```pip install .``` This should install `meater-python` on your system. You can use it in your own Python scripts like so: ```python import meater ``` ## Usage All calls to this class are flagged with async, and are awaitable. To get started, first import the `MeaterApi` class from `meater`. ### Initializing ```python import aiohttp from meater import MeaterApi session = aiohttp.ClientSession() api = MeaterApi(session) ``` The code above initializes the cooker into the `api` variable. The api requires an aiohttp session be passed to it. One session should be created for the whole application to use, as per the aiohttp best practices. Before any information can be obtained, you need to authenticate with the api. In the current version of `meater-python`, only email/password authentication is supported. You can authenticate with the API like so: ```python await api.authenticate('','') ``` ### Getting Probe States Once you have authentiated with the API, you can get information about all available probes like so: ```python devices = await api.get_all_devices() ``` This will populate the `devices` variable with a list of all the available device objects. **NOTE**: Only devices that are actively connected to Meater Cloud are available through the API. Once a probe has been disconnected for a few minutes, it is no longer returned by the API. A specific device can be queried by the API like so: ```python device = await api.get_device('') ``` The device ID should be a 65 character long alphanumeric string. To obtain the device ID, make a call to `api.get_all_devices` while the device is connected. **NOTE**: This method will throw an exception if the device cannot be found. This includes if the device is currently offline. ### MeaterProbe Object Attributes The following arrtibutes are available on the MeaterProbe object | Attribute | Type | Description | | --- | --- | --- | | `id` | str | The ID of the device | | `internal_temperature` | float | The internal temperature reading of the probe in ℃ | | `ambient_temperature` | float | The ambient temperature reading of the probe in ℃ | | `time_updated` | datetime | The time that the probes values were last sent to the Meater cloud | | `cook` | MeaterCook (see below) | A MeaterCook class containing information about the current cook. If no cook is running, this will be `None` | The following attributes are available on the MeaterCook object | Attribute | Type | Description | | --- | --- | --- | | `id` | str | The ID of the cook | | `name` | str | The name of the cook | | `state` | str | The current state of the cook | | `target_temperature` | float | The target temperature for this cook in ℃ | | `peak_temperature` | float | The peak temperature so far for this cook in ℃ | | `time_remaining` | int | The time remaining for this cook in seconds | | `time_elapsed` | int | How long has elapsed since the start of the cook in seconds | ## Troubleshooting Devices will only be returned after the following criteria is met. There may be a delay between the MEATER Cloud seeing your device and it being returned in this endpoint. * Device must be seen by the MEATER Cloud. Ensure you've completed a cook while connected to MEATER Cloud. * The MEATER app or Block must have an active Bluetooth connection with the device. * The MEATER app or Block must have an active MEATER Cloud connection. If you make requests to the Meater API too quickly, you may be subject to rate-limiting. The reccomended rate is 2 requests per 60 seconds, and the maximum is 60 requests per 60 seconds. Requests are automatically slowed down once 10% of rate limit is reached, to 1.0 second per request. Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Requires-Python: >=3.6 Description-Content-Type: text/markdown ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617306329.0 meater-python-0.0.8/README.md0000666000000000000000000001035100000000000013725 0ustar0000000000000000# meater-python Python wrapper for the Apption Labs Meater cooking probe using v1 of their public API. ## Installation `meater-python` can be installed from either PyPi or can be installed manually by cloning the GitHub repository. ### TL;DR installation ```pip install meater-python``` ### Manual installation First, clone the GitHub repository: ```git clone https://github.com/Sotolotl/meater-python.git``` Enter the newly created `meater-python` directory and run: ```pip install .``` This should install `meater-python` on your system. You can use it in your own Python scripts like so: ```python import meater ``` ## Usage All calls to this class are flagged with async, and are awaitable. To get started, first import the `MeaterApi` class from `meater`. ### Initializing ```python import aiohttp from meater import MeaterApi session = aiohttp.ClientSession() api = MeaterApi(session) ``` The code above initializes the cooker into the `api` variable. The api requires an aiohttp session be passed to it. One session should be created for the whole application to use, as per the aiohttp best practices. Before any information can be obtained, you need to authenticate with the api. In the current version of `meater-python`, only email/password authentication is supported. You can authenticate with the API like so: ```python await api.authenticate('','') ``` ### Getting Probe States Once you have authentiated with the API, you can get information about all available probes like so: ```python devices = await api.get_all_devices() ``` This will populate the `devices` variable with a list of all the available device objects. **NOTE**: Only devices that are actively connected to Meater Cloud are available through the API. Once a probe has been disconnected for a few minutes, it is no longer returned by the API. A specific device can be queried by the API like so: ```python device = await api.get_device('') ``` The device ID should be a 65 character long alphanumeric string. To obtain the device ID, make a call to `api.get_all_devices` while the device is connected. **NOTE**: This method will throw an exception if the device cannot be found. This includes if the device is currently offline. ### MeaterProbe Object Attributes The following arrtibutes are available on the MeaterProbe object | Attribute | Type | Description | | --- | --- | --- | | `id` | str | The ID of the device | | `internal_temperature` | float | The internal temperature reading of the probe in ℃ | | `ambient_temperature` | float | The ambient temperature reading of the probe in ℃ | | `time_updated` | datetime | The time that the probes values were last sent to the Meater cloud | | `cook` | MeaterCook (see below) | A MeaterCook class containing information about the current cook. If no cook is running, this will be `None` | The following attributes are available on the MeaterCook object | Attribute | Type | Description | | --- | --- | --- | | `id` | str | The ID of the cook | | `name` | str | The name of the cook | | `state` | str | The current state of the cook | | `target_temperature` | float | The target temperature for this cook in ℃ | | `peak_temperature` | float | The peak temperature so far for this cook in ℃ | | `time_remaining` | int | The time remaining for this cook in seconds | | `time_elapsed` | int | How long has elapsed since the start of the cook in seconds | ## Troubleshooting Devices will only be returned after the following criteria is met. There may be a delay between the MEATER Cloud seeing your device and it being returned in this endpoint. * Device must be seen by the MEATER Cloud. Ensure you've completed a cook while connected to MEATER Cloud. * The MEATER app or Block must have an active Bluetooth connection with the device. * The MEATER app or Block must have an active MEATER Cloud connection. If you make requests to the Meater API too quickly, you may be subject to rate-limiting. The reccomended rate is 2 requests per 60 seconds, and the maximum is 60 requests per 60 seconds. Requests are automatically slowed down once 10% of rate limit is reached, to 1.0 second per request. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1617379706.6744525 meater-python-0.0.8/meater/0000777000000000000000000000000000000000000013723 5ustar0000000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617309709.0 meater-python-0.0.8/meater/MeaterApi.py0000666000000000000000000001336300000000000016152 0ustar0000000000000000import json from datetime import datetime class MeaterApi(object): """Meater api object""" def __init__(self, aiohttp_session): self._jwt = None self._session = aiohttp_session async def get_all_devices(self): """Get all the device states.""" device_states = await self.__get_raw_state_all() devices = [] for device in device_states: devices.append(self.__get_probe_object(device)) return devices async def get_device(self, device_id): device_state = await self.__get_raw_state(device_id) return self.__get_probe_object(device_state) async def __get_raw_state_all(self): """Get raw device state from the Meater API. We have to have authenticated before now.""" if not self._jwt: raise AuthenticationError('You need to authenticate before making requests to the API.') headers = {'Authorization': 'Bearer ' + self._jwt} async with self._session.get('https://public-api.cloud.meater.com/v1/devices', headers=headers) as device_state_request: if device_state_request.status == 401: raise AuthenticationError('Unable to authenticate with the Meater API') if device_state_request.status == 500: raise ServiceUnavailableError('The service is currently unavailable') if device_state_request.status == 429: raise TooManyRequestsError('Too many requests have been made to the API') if device_state_request.status != 200: raise Exception('Error connecting to Meater') device_state_body = await device_state_request.json() if len(device_state_body) == 0: raise Exception('The server did not return a valid response') return device_state_body.get('data').get('devices') async def __get_raw_state(self, device_id): """Get raw device state from the Meater API. We have to have authenticated before now.""" if not self._jwt: raise AuthenticationError('You need to authenticate before making requests to the API.') headers = {'Authorization': 'Bearer ' + self._jwt} async with self._session.get('https://public-api.cloud.meater.com/v1/devices/' + device_id, headers=headers) as device_state_request: if device_state_request.status == 404: raise UnknownDeviceError('The specified device could not be found, it might not be connected to Meater Cloud') if device_state_request.status == 401: raise AuthenticationError('Unable to authenticate with the Meater API') if device_state_request.status == 500: raise ServiceUnavailableError('The service is currently unavailable') if device_state_request.status == 429: raise TooManyRequestsError('Too many requests have been made to the API') if device_state_request.status != 200: raise Exception('Error connecting to Meater') device_state_body = await device_state_request.json() if len(device_state_body) == 0: raise Exception('The server did not return a valid response') return device_state_body.get('data') async def authenticate(self, email, password): """Authenticate with Meater.""" headers = {'Content-Type':'application/json'} body = {'email':email, 'password':password} async with self._session.post('https://public-api.cloud.meater.com/v1/login', data = json.dumps(body), headers=headers) as meater_auth_req: if meater_auth_req.status == 401: raise AuthenticationError('The specified credientals were incorrect') if meater_auth_req.status == 500: raise ServiceUnavailableError('The service is currently unavailable') if meater_auth_req.status == 429: raise TooManyRequestsError('Too many requests have been made to the API') if meater_auth_req.status != 200: raise Exception('Couldn\'t authenticate with the Meater API') auth_body = await meater_auth_req.json() jwt = auth_body.get('data').get('token') # The JWT is valid indefinitely... if not jwt: raise AuthenticationError('Unable to obtain an auth token from the Meater API') # Set JWT local variable self._jwt = jwt return True def __get_probe_object(self, device): cook = None if device.get('cook'): target_temp = 0 cook = MeaterCook(device.get('cook').get('id'), device.get('cook').get('name'), device.get('cook').get('state'), device.get('cook').get('temperature').get('target'), device.get('cook').get('temperature').get('peak'), device.get('cook').get('time').get('remaining'), device.get('cook').get('time').get('elapsed')) probe = MeaterProbe(device.get('id'), device.get('temperature').get('internal'), device.get('temperature').get('ambient'), cook, device.get('updated_at')) return probe class MeaterProbe(object): def __init__(self, id, internal_temp, ambient_temp, cook, time_updated): self.id = id self.internal_temperature = float(internal_temp) # Always in degrees celcius self.ambient_temperature = float(ambient_temp) # Always in degrees celcius self.cook = cook self.time_updated = datetime.fromtimestamp(time_updated) class MeaterCook(object): def __init__(self, id, name, state, target_temp, peak_temp, time_remaining, time_elapsed): self.id = id self.name = name self.state = state if target_temp: self.target_temperature = float(target_temp) # Always in degrees celcius if peak_temp: self.peak_temperature = float(peak_temp) # Always in degrees celcius if time_remaining: self.time_remaining = int(time_remaining) # Always in seconds if time_elapsed: self.time_elapsed = int(time_elapsed) # Always in seconds class UnknownDeviceError(Exception): pass class AuthenticationError(Exception): pass class ServiceUnavailableError(Exception): pass class TooManyRequestsError(Exception): pass ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617352354.0 meater-python-0.0.8/meater/__init__.py0000666000000000000000000000032400000000000016033 0ustar0000000000000000from .MeaterApi import MeaterApi from .MeaterApi import UnknownDeviceError from .MeaterApi import AuthenticationError from .MeaterApi import ServiceUnavailableError from .MeaterApi import TooManyRequestsError././@PaxHeader0000000000000000000000000000003300000000000011451 xustar000000000000000027 mtime=1617379706.722454 meater-python-0.0.8/meater_python.egg-info/0000777000000000000000000000000000000000000017016 5ustar0000000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617379705.0 meater-python-0.0.8/meater_python.egg-info/PKG-INFO0000666000000000000000000001312600000000000020116 0ustar0000000000000000Metadata-Version: 2.1 Name: meater-python Version: 0.0.8 Summary: A wrapper for the Apption Labs Meater probe API v1 Home-page: https://github.com/Sotolotl/meater-python Author: Billy Stevenson Author-email: meater-api@billystevenson.co.uk License: UNKNOWN Description: # meater-python Python wrapper for the Apption Labs Meater cooking probe using v1 of their public API. ## Installation `meater-python` can be installed from either PyPi or can be installed manually by cloning the GitHub repository. ### TL;DR installation ```pip install meater-python``` ### Manual installation First, clone the GitHub repository: ```git clone https://github.com/Sotolotl/meater-python.git``` Enter the newly created `meater-python` directory and run: ```pip install .``` This should install `meater-python` on your system. You can use it in your own Python scripts like so: ```python import meater ``` ## Usage All calls to this class are flagged with async, and are awaitable. To get started, first import the `MeaterApi` class from `meater`. ### Initializing ```python import aiohttp from meater import MeaterApi session = aiohttp.ClientSession() api = MeaterApi(session) ``` The code above initializes the cooker into the `api` variable. The api requires an aiohttp session be passed to it. One session should be created for the whole application to use, as per the aiohttp best practices. Before any information can be obtained, you need to authenticate with the api. In the current version of `meater-python`, only email/password authentication is supported. You can authenticate with the API like so: ```python await api.authenticate('','') ``` ### Getting Probe States Once you have authentiated with the API, you can get information about all available probes like so: ```python devices = await api.get_all_devices() ``` This will populate the `devices` variable with a list of all the available device objects. **NOTE**: Only devices that are actively connected to Meater Cloud are available through the API. Once a probe has been disconnected for a few minutes, it is no longer returned by the API. A specific device can be queried by the API like so: ```python device = await api.get_device('') ``` The device ID should be a 65 character long alphanumeric string. To obtain the device ID, make a call to `api.get_all_devices` while the device is connected. **NOTE**: This method will throw an exception if the device cannot be found. This includes if the device is currently offline. ### MeaterProbe Object Attributes The following arrtibutes are available on the MeaterProbe object | Attribute | Type | Description | | --- | --- | --- | | `id` | str | The ID of the device | | `internal_temperature` | float | The internal temperature reading of the probe in ℃ | | `ambient_temperature` | float | The ambient temperature reading of the probe in ℃ | | `time_updated` | datetime | The time that the probes values were last sent to the Meater cloud | | `cook` | MeaterCook (see below) | A MeaterCook class containing information about the current cook. If no cook is running, this will be `None` | The following attributes are available on the MeaterCook object | Attribute | Type | Description | | --- | --- | --- | | `id` | str | The ID of the cook | | `name` | str | The name of the cook | | `state` | str | The current state of the cook | | `target_temperature` | float | The target temperature for this cook in ℃ | | `peak_temperature` | float | The peak temperature so far for this cook in ℃ | | `time_remaining` | int | The time remaining for this cook in seconds | | `time_elapsed` | int | How long has elapsed since the start of the cook in seconds | ## Troubleshooting Devices will only be returned after the following criteria is met. There may be a delay between the MEATER Cloud seeing your device and it being returned in this endpoint. * Device must be seen by the MEATER Cloud. Ensure you've completed a cook while connected to MEATER Cloud. * The MEATER app or Block must have an active Bluetooth connection with the device. * The MEATER app or Block must have an active MEATER Cloud connection. If you make requests to the Meater API too quickly, you may be subject to rate-limiting. The reccomended rate is 2 requests per 60 seconds, and the maximum is 60 requests per 60 seconds. Requests are automatically slowed down once 10% of rate limit is reached, to 1.0 second per request. Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Requires-Python: >=3.6 Description-Content-Type: text/markdown ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617379705.0 meater-python-0.0.8/meater_python.egg-info/SOURCES.txt0000666000000000000000000000036100000000000020702 0ustar0000000000000000README.md setup.py meater/MeaterApi.py meater/__init__.py meater_python.egg-info/PKG-INFO meater_python.egg-info/SOURCES.txt meater_python.egg-info/dependency_links.txt meater_python.egg-info/requires.txt meater_python.egg-info/top_level.txt././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617379705.0 meater-python-0.0.8/meater_python.egg-info/dependency_links.txt0000666000000000000000000000000100000000000023064 0ustar0000000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617379705.0 meater-python-0.0.8/meater_python.egg-info/requires.txt0000666000000000000000000000001300000000000021410 0ustar0000000000000000aiohttp<=4 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617379705.0 meater-python-0.0.8/meater_python.egg-info/top_level.txt0000666000000000000000000000000700000000000021545 0ustar0000000000000000meater ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1617379706.7264533 meater-python-0.0.8/setup.cfg0000666000000000000000000000005200000000000014264 0ustar0000000000000000[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1617379509.0 meater-python-0.0.8/setup.py0000666000000000000000000000137000000000000014161 0ustar0000000000000000import setuptools with open("README.md", "r") as fh: long_description = fh.read() setuptools.setup( name="meater-python", version="0.0.8", author="Billy Stevenson", author_email="meater-api@billystevenson.co.uk", description="A wrapper for the Apption Labs Meater probe API v1", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/Sotolotl/meater-python", install_requires=["aiohttp<=4"], packages=setuptools.find_packages(), classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", ], python_requires='>=3.6', )