pyJPI 0.1.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyJPI might be problematic. Click here for more details.

pyjpi/__init__.py ADDED
@@ -0,0 +1,28 @@
1
+ """JPI Library."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from importlib.metadata import PackageNotFoundError, version
7
+
8
+ import aiohttp
9
+
10
+ from .library import JPILibrary
11
+
12
+
13
+ async def _get_version() -> str:
14
+ """Returns the version of the package (hopefully)."""
15
+ try:
16
+ return await asyncio.to_thread(version, "pyJPI")
17
+ except PackageNotFoundError:
18
+ return "0+local"
19
+
20
+
21
+ async def jpiInit(session: aiohttp.ClientSession) -> JPILibrary:
22
+ """
23
+ Initialize the library.
24
+ Returns an object with an initialized HTTP session.
25
+ This same object will have to be provided later on each called method.
26
+ """
27
+ package_version = await _get_version()
28
+ return JPILibrary(session, package_version)
pyjpi/library.py ADDED
@@ -0,0 +1,96 @@
1
+ """
2
+ A library to interact with JPI devices.
3
+ Rationale: according to HomeAssistant documentation, the integration MUST not interact directly with the physical devices.
4
+ Instead, it MUST use a library published on pyPI repository.
5
+ This file is so the first version of such the interaction library.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from datetime import datetime
11
+ import logging
12
+
13
+ from aiohttp.web import HTTPError
14
+
15
+
16
+ class JPILibrary:
17
+ """Class for the pyJPI library."""
18
+
19
+ def __init__(self, session, version):
20
+ """Initialize a HTTP session."""
21
+ self._session = session
22
+ self._initialized = datetime.now()
23
+ self._log = logging.getLogger(__name__)
24
+ self._log.debug("JPILibrary v%s successfully instantiated", version)
25
+
26
+ def _batt_parse_text(self, text: str) -> dict:
27
+ """
28
+ Parse battery info text into a structured dictionary.
29
+ Input:
30
+ Niveau: 52%
31
+ En charge: NON
32
+ Alim. connectée: NON
33
+ Output:
34
+ {'level': 52, 'charging': False, 'power': False}
35
+ """
36
+ result = {}
37
+ for line in text.splitlines():
38
+ if not line.strip():
39
+ continue # skip empty lines
40
+ key, value = line.split(":", 1)
41
+ key = key.strip()
42
+ value = value.strip()
43
+
44
+ if key == "Niveau":
45
+ result["level"] = int(value.strip("%"))
46
+ elif key == "En charge":
47
+ result["charging"] = value.upper() == "OUI"
48
+ elif key == "Alim. connectée":
49
+ result["power"] = value.upper() == "OUI"
50
+ return result
51
+
52
+ async def battInfo(self, url: str):
53
+ """
54
+ Returns the battery informations as a hash:
55
+ level: <int>
56
+ charging: <bool>
57
+ power: <bool>
58
+ """
59
+ target = f"{url}?action=battInfo"
60
+ resp = await self.get(target)
61
+ result = None
62
+ self._log.debug("battInfo resp=%s", resp)
63
+ if resp:
64
+ result = self._batt_parse_text(resp["text"])
65
+ return result
66
+
67
+ async def getDeviceName(self, url: str):
68
+ """
69
+ Returns the device name as provided by the manufacturer.
70
+ E.g. Samsung sets that as 'Samsung SM-J320FN' for a Galaxy J3.
71
+ """
72
+ target = f"{url}?action=getDeviceName"
73
+ resp = await self.get(target)
74
+ self._log.debug("getDeviceName resp=%s", resp)
75
+ device_name = None
76
+ if resp:
77
+ device_name = resp["text"]
78
+ return device_name
79
+
80
+ async def get(self, url: str):
81
+ """
82
+ Returns an object containing the raw HTTP response from GETting the provided url plus the got text content.
83
+ Uses async I/O to avoid blocking the main event loop.
84
+ Throw an exception in case of an error.
85
+ """
86
+ resp = None
87
+ result = None
88
+ try:
89
+ resp = await self._session.get(url)
90
+ except HTTPError as e:
91
+ self._log.error("HTTPError exception: %s", e)
92
+ return False
93
+ if resp:
94
+ text = await resp.text()
95
+ result = {"text": text, "resp": resp}
96
+ return result
@@ -0,0 +1,145 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyJPI
3
+ Version: 0.1.13
4
+ Summary: A library to access Android devices which run JPI
5
+ Author-email: Pierre Wieser <p.wieser@trychlos.org>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/trychlos/pyjpi
8
+ Project-URL: Issues, https://github.com/trychlos/pyjpi/issues
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Dynamic: license-file
15
+
16
+ # pyJPI - An asynchronous Python module to interact with Android devices running JPI
17
+
18
+ [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/trychlos/pyjpi)
19
+ [![Latest release](https://github.com/trychlos/pyjpi/workflows/Latest%20release/badge.svg)](https://github.com/trychlos/pyjpi/actions)
20
+ [![Newest commit](https://github.com/trychlos/pyjpi/workflows/Latest%20commit/badge.svg)](https://github.com/trychlos/pyjpi/actions)
21
+
22
+ [![PyPI version fury.io](https://badge.fury.io/py/pyjpi.svg)](https://pypi.python.org/pypi/pyjpi/)
23
+
24
+ <!--
25
+ [![CodeRabbit.ai is Awesome](https://img.shields.io/badge/AI-orange?label=CodeRabbit&color=orange&link=https%3A%2F%2Fcoderabbit.ai)](https://coderabbit.ai)
26
+ [![renovate maintained](https://img.shields.io/badge/maintained%20with-renovate-blue?logo=renovatebot)](https://github.com/compatech/python-airos/issues/8)
27
+
28
+ [![CodeFactor](https://www.codefactor.io/repository/github/compatech/python-airos/badge)](https://www.codefactor.io/repository/github/plugwise/python-airos)
29
+ [![codecov](https://codecov.io/gh/compatech/python-airos/graph/badge.svg?token=WI5K2IZWNS)](https://codecov.io/gh/compatech/python-airos)
30
+
31
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
32
+ [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
33
+ [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=CoMPaTech_python-airos&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=CoMPaTech_python-airos)
34
+ -->
35
+
36
+ ## Overview
37
+
38
+ `pyJPI` is an asynchronous Python library designed to programmatically interact with Android devices running JPI.
39
+
40
+ This library is a key component for a core integration with [Home Assistant](https://www.home-assistant.io).
41
+
42
+ More details on the integration can be found on the [JPI](https://www.home-assistant.io/integrations/jpi/) page.
43
+
44
+ ## Features
45
+
46
+ - Asynchronous operations are built with ``aiohttp` for non-blocking I/O, which is perfect for integrations and background tasks.
47
+ - API: `battInfo`
48
+ - API: `get`
49
+ - API: `getDeviceName`
50
+
51
+ ## Installation
52
+
53
+ You can install `pyJPI` from PyPI using pip:
54
+
55
+ ```Bash
56
+ pip install pyjpi
57
+ ```
58
+
59
+ ## Usage
60
+
61
+ Here is a more detailed example of how to use the library to connect, fetch status, and perform an action on an Android device running JPI.
62
+
63
+ ```Python
64
+ import aiohttp
65
+ from pyjpi import jpiInit
66
+
67
+ async def main():
68
+ """Main function to demonstrate library usage."""
69
+ # Create an aiohttp session with SSL verification disabled.
70
+ # Be cautious with this setting; it's useful for self-signed certificates
71
+ # but not recommended for production environments without proper validation.
72
+ session = aiohttp.ClientSession( connector=aiohttp.TCPConnector( verify_ssl=False ))
73
+
74
+ # Get a handle on the pyJPI library.
75
+ handle = await jpiInit( session )
76
+
77
+ # Have an URL somewhere.
78
+ url = "http://myhost.example.com:8080"
79
+
80
+ # Then just has to call the library functions.
81
+ try:
82
+ res = await handle.get( url )
83
+ # returns a dict { resp: ClientResponse, text: str } or False
84
+ res = await handle.getDeviceName( url )
85
+ # returns the device name as set by the manufacturer (a single string) or False
86
+ res = await handle.battInfo( url )
87
+ # returns a dict { level: integer, charging: bool, power: bool }
88
+
89
+
90
+ if __name__ == "__main__":
91
+ main()
92
+ ```
93
+
94
+ ## Available functions
95
+
96
+ - `async jpiInit( session: aiohttp.ClientSession ) -> JPILibrary`:
97
+
98
+ Initializes the library.
99
+
100
+ Returns a handle on it.
101
+
102
+ ## Available classes
103
+
104
+ - `JPILibrary`:
105
+
106
+ The class which manages the devices accesses.
107
+
108
+ ## Available `JPILibrary` methods
109
+
110
+ - `async get( url: str) -> dict`:
111
+
112
+ Runs a HTTP GET method on the specified URL.
113
+
114
+ Returns a dict with:
115
+
116
+ ```Python
117
+ resp: the `aiohttp.ClientResponse`
118
+ text: the resp.text() content
119
+ ```
120
+
121
+ - `async getDeviceName( url: str) -> str`:
122
+
123
+ Runs a HTTP GET method on f"{url}?action=getDeviceName" url.
124
+
125
+ Returns a string which contains the device name as set by the manufacturer.
126
+
127
+ - `async battInfo( url: str) -> dict`:
128
+
129
+ Runs a HTTP GET method on on f"{url}?action=battInfo" url.
130
+
131
+ Returns a dict with:
132
+
133
+ ```Python
134
+ level: an integer with the current battery level in %
135
+ charging: a boolean which says if the battery is currently charging
136
+ power: a boolean which says if the power is on on the device.
137
+ ```
138
+
139
+ ## Contributing
140
+
141
+ We welcome contributions as well as additional codeowners to `pyjpi`.
142
+
143
+ ## Issues & help
144
+
145
+ In case of support or error, please report your issue request to our [Issues tracker](https://github.com/trychlos/pyjpi/issues).
@@ -0,0 +1,7 @@
1
+ pyjpi/__init__.py,sha256=psIA86RpUkgDEkN83iYyBg39kSyZ4ncKtHirmacfM3s,731
2
+ pyjpi/library.py,sha256=w67KC7ky4oEfhxGvWLnsvDo2BM8bsa4gZZS1pHLDoLM,3158
3
+ pyjpi-0.1.13.dist-info/licenses/LICENSE,sha256=R3qRa5L_mIKSS6sn0ZihAoffUJFYEHplpGizodZmYSU,1070
4
+ pyjpi-0.1.13.dist-info/METADATA,sha256=RoXshzlJDCFjsBVXpj6reARZyi1UXJKis_QqZgDuG-I,5309
5
+ pyjpi-0.1.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
+ pyjpi-0.1.13.dist-info/top_level.txt,sha256=jid62Fv2u4Pis12DgKx2kEUQc7OhHZbtbxcoFbG4NNU,6
7
+ pyjpi-0.1.13.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 by @CoMPaTech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ pyjpi