pax_global_header00006660000000000000000000000064143325461570014524gustar00rootroot0000000000000052 comment=c611282b29e8863ebc168d9ec2af9a9b169a5170 home-assistant-ecosystem-python-luftdaten-fea3c31/000077500000000000000000000000001433254615700224665ustar00rootroot00000000000000home-assistant-ecosystem-python-luftdaten-fea3c31/.github/000077500000000000000000000000001433254615700240265ustar00rootroot00000000000000home-assistant-ecosystem-python-luftdaten-fea3c31/.github/workflows/000077500000000000000000000000001433254615700260635ustar00rootroot00000000000000home-assistant-ecosystem-python-luftdaten-fea3c31/.github/workflows/testing.yml000066400000000000000000000021471433254615700302670ustar00rootroot00000000000000name: Testing on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: [ "3.9", "3.10" ] steps: - name: Checkout uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install Poetry uses: snok/install-poetry@v1 with: virtualenvs-create: true virtualenvs-in-project: true installer-parallel: true - name: Load cached venv id: cached-poetry-dependencies uses: actions/cache@v2 with: path: .venv key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} - name: Install dependencies if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root - name: Install library run: poetry install --no-interaction - name: Run tests run: | source .venv/bin/activate pytest tests/ home-assistant-ecosystem-python-luftdaten-fea3c31/.gitignore000066400000000000000000000022051433254615700244550ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # dotenv .env # virtualenv .venv venv/ ENV/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ home-assistant-ecosystem-python-luftdaten-fea3c31/CHANGES.rst000066400000000000000000000032321433254615700242700ustar00rootroot00000000000000Changes ======= 0.7.4 - 2022-11-08 ------------------ - Fix API connection error handling (thanks @Cougar) 0.7.3 - 2022-09-25 ------------------ - Update dependencies (GHSA-h8pj-cxx2-jfg2) 0.7.2 - 2022-01-04 ------------------ - Support for later pytest-httpx releases 0.7.1 - 2021-11-25 ------------------ - Relax httpx constraint 0.7.0 - 2021-11-07 ------------------ - Add support for altitude - Add basic tests - Migrate to httpx - Migrate to pyproject 0.6.5 - 2021-03-17 ------------------ - Only allow aiohttp >= 3.7.4 to avoid CVE-2021-21330 0.6.4 - 2020-03-31 ------------------ - Use new API endpoint (thanks @mattsches) 0.6.3 - 2019-08-16 ------------------ - Increase timeout (thanks @darashenka) 0.6.2 - 2019-07-16 ------------------ - Only add value types if reported by the API (thanks @cgtobi) 0.6.1 - 2019-06-25 ------------------ - Remove debug print 0.6.0 - 2019-06-25 ------------------ - Better handling of empty API responses (thanks @jvanderneutstulen) 0.5.020190210 ---------------- - Limit data to P1 and P2 - Update docstrings 0.3.4 - 2018-10-21 ------------------ - Refactor sensor check - Update example 0.3.2 - 2018-10-21 ------------------ - Check if a given station is valid - Update example 0.3.1 - 2018-10-20 ------------------ - Check if a given station is available - Update example 0.3.0 - 2018-10-18 ------------------ - Update method name - Fix example 0.2.0 - 2018-05-25 ------------------ - Support for async syntax 0.1.3 - 2018-12-27 ------------------ - Add CHANGES.rst 0.1.2 - 2017-12-26 ------------------ - Add ordering fix by @ReneNulschDE (#1) 0.1.1 - 2017-12-01 ------------------ - Initial release home-assistant-ecosystem-python-luftdaten-fea3c31/LICENSE000066400000000000000000000021261433254615700234740ustar00rootroot00000000000000MIT License Copyright (c) 2017-2022 Fabian Affolter Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. home-assistant-ecosystem-python-luftdaten-fea3c31/README.rst000066400000000000000000000020351433254615700241550ustar00rootroot00000000000000python-luftdaten ================ Python client for interacting with `sensor.community `_ (previously known as `luftdaten.info `_. This module is not official, developed, supported or endorsed by sensor.community/luftdaten.info. Installation ------------ The module is available from the `Python Package Index `_. .. code:: bash $ pip3 install luftdaten On a Fedora-based system or on a CentOS/RHEL machine with has EPEL enabled. .. code:: bash $ sudo dnf -y install python3-luftdaten For Nix or NixOS is `pre-packed module `_ available. The lastest release is usually present in the ``unstable`` channel. .. code:: bash $ nix-env -iA nixos.python39Packages.luftdaten Usage ----- The file ``example.py`` contains an example about how to use this module. License ------- ``python-luftdaten`` is licensed under MIT, for more details check LICENSE. home-assistant-ecosystem-python-luftdaten-fea3c31/example.py000066400000000000000000000013341433254615700244740ustar00rootroot00000000000000"""Example for getting the data from a station.""" import asyncio from luftdaten import Luftdaten SENSOR_ID = 152 async def main(): """Sample code to retrieve the data.""" data = Luftdaten(SENSOR_ID) await data.get_data() if not await data.validate_sensor(): print("Station is not available:", data.sensor_id) return if data.values and data.meta: # Print the sensor values print("Sensor values:", data.values) # Print the coordinates fo the sensor print( "Location:", data.meta["latitude"], data.meta["longitude"], data.meta["altitude"], ) if __name__ == "__main__": asyncio.run(main()) home-assistant-ecosystem-python-luftdaten-fea3c31/luftdaten/000077500000000000000000000000001433254615700244545ustar00rootroot00000000000000home-assistant-ecosystem-python-luftdaten-fea3c31/luftdaten/__init__.py000066400000000000000000000052321433254615700265670ustar00rootroot00000000000000"""Wrapper to get the measurings from a Luftdaten station.""" import logging import httpx from . import exceptions _LOGGER = logging.getLogger(__name__) _RESOURCE = "https://data.sensor.community/airrohr/v1" class Luftdaten(object): """A class for handling the data retrieval.""" def __init__(self, sensor_id): """Initialize the connection.""" self.sensor_id = sensor_id self.data = None self.values = {} self.meta = {} self.url = "{}/{}".format(_RESOURCE, "sensor") async def get_data(self): """Retrieve the data.""" url = "{}/{}/".format(self.url, self.sensor_id) try: async with httpx.AsyncClient() as client: response = await client.get(str(url)) except httpx.ConnectError: raise exceptions.LuftdatenConnectionError(f"Connection to {url} failed") except httpx.ConnectTimeout: raise exceptions.LuftdatenConnectionError(f"Connection to {url} timed out") except httpx.ReadTimeout: raise exceptions.LuftdatenConnectionError(f"Read timeout from {url}") if response.status_code == httpx.codes.OK: try: _LOGGER.debug(response.json()) self.data = response.json() except TypeError: _LOGGER.error("Can not load data from Luftdaten API") raise exceptions.LuftdatenConnectionError( "Unable to get the data from Luftdaten API" ) if not self.data: for measurement in self.values.keys(): self.values[measurement] = None return try: sensor_data = sorted( self.data, key=lambda timestamp: timestamp["timestamp"], reverse=True )[0] for entry in sensor_data["sensordatavalues"]: if entry["value_type"] not in self.values.keys(): self.values[entry["value_type"]] = None for measurement in self.values.keys(): if measurement == entry["value_type"]: self.values[measurement] = float(entry["value"]) self.meta["sensor_id"] = self.sensor_id self.meta["longitude"] = float(sensor_data["location"]["longitude"]) self.meta["latitude"] = float(sensor_data["location"]["latitude"]) self.meta["altitude"] = float(sensor_data["location"]["altitude"]) except (TypeError, IndexError): raise exceptions.LuftdatenError() async def validate_sensor(self): """Return True if the sensor ID is valid.""" return True if self.data else False home-assistant-ecosystem-python-luftdaten-fea3c31/luftdaten/exceptions.py000066400000000000000000000005351433254615700272120ustar00rootroot00000000000000"""Exceptions for the Luftdaten Wrapper.""" class LuftdatenError(Exception): """General LuftdatenError exception occurred.""" pass class LuftdatenConnectionError(LuftdatenError): """When a connection error is encountered.""" pass class LuftdatenNoDataAvailable(LuftdatenError): """When no data is available.""" pass home-assistant-ecosystem-python-luftdaten-fea3c31/poetry.lock000066400000000000000000000304031433254615700246620ustar00rootroot00000000000000[[package]] name = "anyio" version = "3.6.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "main" optional = false python-versions = ">=3.6.2" [package.dependencies] idna = ">=2.8" sniffio = ">=1.1" [package.extras] trio = ["trio (>=0.16)"] test = ["uvloop (>=0.15)", "mock (>=4)", "uvloop (<0.15)", "contextlib2", "trustme", "pytest-mock (>=3.6.1)", "pytest (>=7.0)", "hypothesis (>=4.0)", "coverage[toml] (>=4.5)"] doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme", "packaging"] [[package]] name = "atomicwrites" version = "1.4.1" description = "Atomic file writes." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" version = "22.1.0" description = "Classes Without Boilerplate" category = "dev" optional = false python-versions = ">=3.5" [package.extras] tests_no_zope = ["cloudpickle", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] tests = ["cloudpickle", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] docs = ["sphinx-notfound-page", "zope.interface", "sphinx", "furo"] dev = ["cloudpickle", "pre-commit", "sphinx-notfound-page", "sphinx", "furo", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] [[package]] name = "black" version = "22.8.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.6.2" [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" version = "2022.9.24" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" [[package]] name = "click" version = "8.1.3" description = "Composable command line interface toolkit" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" version = "0.4.5" description = "Cross-platform colored terminal text." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "h11" version = "0.12.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" category = "main" optional = false python-versions = ">=3.6" [[package]] name = "httpcore" version = "0.15.0" description = "A minimal low-level HTTP client." category = "main" optional = false python-versions = ">=3.7" [package.dependencies] anyio = ">=3.0.0,<4.0.0" certifi = "*" h11 = ">=0.11,<0.13" sniffio = ">=1.0.0,<2.0.0" [package.extras] socks = ["socksio (>=1.0.0,<2.0.0)"] http2 = ["h2 (>=3,<5)"] [[package]] name = "httpx" version = "0.23.0" description = "The next generation HTTP client." category = "main" optional = false python-versions = ">=3.7" [package.dependencies] certifi = "*" httpcore = ">=0.15.0,<0.16.0" rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] socks = ["socksio (>=1.0.0,<2.0.0)"] http2 = ["h2 (>=3,<5)"] cli = ["pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)", "click (>=8.0.0,<9.0.0)"] brotli = ["brotli", "brotlicffi"] [[package]] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false python-versions = ">=3.5" [[package]] name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" category = "dev" optional = false python-versions = "*" [[package]] name = "isort" version = "5.10.1" description = "A Python utility / library to sort Python imports." category = "dev" optional = false python-versions = ">=3.6.1,<4.0" [package.extras] pipfile_deprecated_finder = ["pipreqs", "requirementslib"] requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] plugins = ["setuptools"] [[package]] name = "mypy-extensions" version = "0.4.3" description = "Experimental type system extensions for programs checked with the mypy typechecker." category = "dev" optional = false python-versions = "*" [[package]] name = "packaging" version = "21.3" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pathspec" version = "0.10.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false python-versions = ">=3.7" [[package]] name = "platformdirs" version = "2.5.2" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] [[package]] name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false python-versions = ">=3.6" [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pyparsing" version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "dev" optional = false python-versions = ">=3.6.8" [package.extras] diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pytest" version = "6.2.5" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" py = ">=1.8.2" toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] name = "pytest-asyncio" version = "0.16.0" description = "Pytest support for asyncio." category = "dev" optional = false python-versions = ">= 3.6" [package.dependencies] pytest = ">=5.4.0" [package.extras] testing = ["coverage", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-httpx" version = "0.21.0" description = "Send responses to httpx." category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] httpx = ">=0.23.0,<0.24.0" pytest = ">=6,<8" [package.extras] testing = ["pytest-cov (>=3.0.0,<4.0.0)", "pytest-asyncio (>=0.17.0,<0.18.0)"] [[package]] name = "rfc3986" version = "1.5.0" description = "Validating URI References per RFC 3986" category = "main" optional = false python-versions = "*" [package.dependencies] idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} [package.extras] idna2008 = ["idna"] [[package]] name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" category = "main" optional = false python-versions = ">=3.7" [[package]] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false python-versions = ">=3.7" [[package]] name = "typing-extensions" version = "4.3.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "dev" optional = false python-versions = ">=3.7" [metadata] lock-version = "1.1" python-versions = "^3.9" content-hash = "407700cf301489d0d74fd39ed1d12ad47bcc82bb0c0148ebf1fcab1279061916" [metadata.files] anyio = [] atomicwrites = [] attrs = [] black = [] certifi = [] click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] colorama = [] h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, ] httpcore = [] httpx = [] idna = [] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] pathspec = [] platformdirs = [ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] pyparsing = [] pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] pytest-asyncio = [ {file = "pytest-asyncio-0.16.0.tar.gz", hash = "sha256:7496c5977ce88c34379df64a66459fe395cd05543f0a2f837016e7144391fcfb"}, {file = "pytest_asyncio-0.16.0-py3-none-any.whl", hash = "sha256:5f2a21273c47b331ae6aa5b36087047b4899e40f03f18397c0e65fa5cca54e9b"}, ] pytest-httpx = [] rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, ] sniffio = [] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] typing-extensions = [] home-assistant-ecosystem-python-luftdaten-fea3c31/pyproject.toml000066400000000000000000000021051433254615700254000ustar00rootroot00000000000000[tool.poetry] name = "luftdaten" version = "0.7.4" description = "Python API for interacting with luftdaten.info" authors = ["Fabian Affolter "] license = "MIT" homepage = "https://github.com/home-assistant-ecosystem/python-luftdaten" repository = "https://github.com/home-assistant-ecosystem/python-luftdaten" readme = "README.rst" classifiers = [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Topic :: Utilities", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Topic :: Home Automation" ] [tool.poetry.dependencies] python = "^3.9" httpx = ">=0.23,<1" [tool.poetry.dev-dependencies] black = "^22.8" pytest = "^6.2.5" isort = "^5.10.0" pytest-httpx = ">0.15,<1" pytest-asyncio = "^0.16.0" [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" home-assistant-ecosystem-python-luftdaten-fea3c31/tests/000077500000000000000000000000001433254615700236305ustar00rootroot00000000000000home-assistant-ecosystem-python-luftdaten-fea3c31/tests/__init__.py000066400000000000000000000000521433254615700257360ustar00rootroot00000000000000"""Tests for the Luftdaten API client.""" home-assistant-ecosystem-python-luftdaten-fea3c31/tests/test_data.py000066400000000000000000000043711433254615700261570ustar00rootroot00000000000000"""Test the interaction with the Luftdaten API.""" import pytest from pytest_httpx import HTTPXMock from luftdaten import Luftdaten import httpx SENSOR_ID = 1 RESPONSE_VALID = [ { "sensor": { "sensor_type": {"manufacturer": "various", "name": "DHT22", "id": 9}, "pin": "7", "id": 152, }, "timestamp": "2021-11-07 11:16:45", "sampling_rate": None, "sensordatavalues": [ {"value": "10.50", "id": 16932663249, "value_type": "temperature"}, {"value": "79.30", "id": 16932663267, "value_type": "humidity"}, ], "id": 7706863277, "location": { "country": "DE", "latitude": "48.792", "exact_location": 0, "altitude": "326.9", "longitude": "9.164", "indoor": 0, "id": 68, }, }, { "sensor": { "sensor_type": {"manufacturer": "various", "name": "DHT22", "id": 9}, "pin": "7", "id": 152, }, "timestamp": "2021-11-07 11:14:13", "sampling_rate": None, "sensordatavalues": [ {"value": "10.50", "id": 16932614294, "value_type": "temperature"}, {"value": "80.60", "id": 16932614337, "value_type": "humidity"}, ], "id": 7706841422, "location": { "country": "DE", "latitude": "48.792", "exact_location": 0, "altitude": "326.9", "longitude": "9.164", "indoor": 0, "id": 68, }, }, ] @pytest.mark.asyncio async def test_sensor_values(httpx_mock: HTTPXMock): """Test the sensor values.""" httpx_mock.add_response(json=RESPONSE_VALID) client = Luftdaten(SENSOR_ID) await client.get_data() assert client.values == {"temperature": 10.5, "humidity": 79.3} @pytest.mark.asyncio async def test_meta(httpx_mock: HTTPXMock): """Test the meta information.""" httpx_mock.add_response(json=RESPONSE_VALID) client = Luftdaten(SENSOR_ID) await client.get_data() assert client.meta["sensor_id"] == 1 assert client.meta["latitude"] == 48.792 assert client.meta["longitude"] == 9.164 assert client.meta["altitude"] == 326.9 home-assistant-ecosystem-python-luftdaten-fea3c31/tests/test_timeout.py000066400000000000000000000023731433254615700267340ustar00rootroot00000000000000"""Test the interaction with the Luftdaten API.""" import httpx import pytest from pytest_httpx import HTTPXMock from luftdaten import Luftdaten from luftdaten.exceptions import LuftdatenConnectionError SENSOR_ID = 1 @pytest.mark.asyncio async def test_connect_timeout(httpx_mock: HTTPXMock): """Test if the connection is hitting the timeout during connect.""" def raise_timeout(request): """Set the timeout for the requests.""" raise httpx.ConnectTimeout( f"Unable to connect within {request.extensions['timeout']}", request=request ) httpx_mock.add_callback(raise_timeout) with pytest.raises(LuftdatenConnectionError): client = Luftdaten(SENSOR_ID) await client.get_data() @pytest.mark.asyncio async def test_read_timeout(httpx_mock: HTTPXMock): """Test if the connection is hitting the timeout during data reading.""" def raise_timeout(request): """Set the timeout for the requests.""" raise httpx.ReadTimeout( f"Unable to read within {request.extensions['timeout']}", request=request ) httpx_mock.add_callback(raise_timeout) with pytest.raises(LuftdatenConnectionError): client = Luftdaten(SENSOR_ID) await client.get_data()