Skip to content

Commit

Permalink
use async requests
Browse files Browse the repository at this point in the history
  • Loading branch information
Aohzan committed Apr 11, 2021
1 parent 98dfc92 commit 3bdced0
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 60 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ build/
pyecodevices.egg-info
__pycache__
publish
.vscode/
.vscode/
test.py
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.2.0

- Make async requests

## 1.1.0

- Use XML API of the Eco-Devices to get more information
Expand Down
34 changes: 20 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Get information from GCE Eco-Devices
- `port`: (default: 80)
- `username`: if authentication enabled on Eco-Devices
- `password`: if authentication enabled on Eco-Devices
- `timeout`: (default: 3)
- `request_timeout`: (default: 3)

## Properties

Expand All @@ -30,17 +30,23 @@ Get information from GCE Eco-Devices
```python
from pyecodevices import EcoDevices

ecodevices = EcoDevices('192.168.1.239','80',"username","password")

print("# ping")
print(ecodevices.ping())
print("# firmware version")
print(ecodevices.firmware)
print("# all values")
print(ecodevices.global_get())
print("# inputs values")
print(ecodevices.get_t1())
print(ecodevices.get_t2())
print(ecodevices.get_c1())
print(ecodevices.get_c2())
import asyncio


async def main():
async with EcoDevices('192.168.1.239', '80', "username", "password") as ecodevices:
ping = await ecodevices.ping()
print("ping:", ping)
version = await ecodevices.firmware
print("firmware version: ", version)
data = await ecodevices.global_get()
print("all values: ", data)
data = await ecodevices.get_t1()
print("teleinfo 1: ", data["current"])


if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

```
145 changes: 101 additions & 44 deletions pyecodevices/__init__.py
Original file line number Diff line number Diff line change
@@ -1,104 +1,161 @@
"""Get information from GCE Eco-Devices."""
import requests
import asyncio
import socket

import aiohttp
import async_timeout
import xmltodict


class EcoDevices:
"""Class representing the Eco-Devices and its XML API."""

def __init__(self, host, port=80, username=None, password=None, timeout=3):
def __init__(
self,
host: str,
port: int = 80,
username: str = None,
password: str = None,
request_timeout: int = 10,
session: aiohttp.client.ClientSession = None
) -> None:
"""Init a EcoDevice API."""
self._host = host
self._port = port
self._username = username
self._password = password
self._timeout = timeout
self._request_timeout = request_timeout
self._api_url = f"http://{host}:{port}/status.xml"

def _request(self):
if self._username is not None and self._password is not None:
r = requests.get(
self._api_url,
params={},
auth=(self._username, self._password),
timeout=self._timeout,
)
else:
r = requests.get(self._api_url, params={}, timeout=self._timeout)
r.raise_for_status()
xml_content = xmltodict.parse(r.text)
response = xml_content.get("response", None)
if response:
return response
else:
raise Exception(
"Eco-Devices XML request error, url: %s`r%s",
r.request.url,
response,
self._session = session
self._close_session = False

async def _request(self) -> dict:
"""Make a request to get Eco-Devices data."""
auth = None
if self._username and self._password:
auth = aiohttp.BasicAuth(self._username, self._password)

if self._session is None:
self._session = aiohttp.ClientSession()
self._close_session = True

try:
with async_timeout.timeout(self._request_timeout):
response = await self._session.request(
"GET",
self._api_url,
auth=auth,
data=None,
json=None,
params=None,
headers={},
ssl=False,
)
except asyncio.TimeoutError as exception:
raise CannotConnectError(
"Timeout occurred while connecting to Eco-Devices."
) from exception
except (aiohttp.ClientError, socket.gaierror) as exception:
raise CannotConnectError(
"Error occurred while communicating with Eco-Devices."
) from exception
if response.status == 401:
raise InvalidAuthError(
"Authentication failed with Eco-Devices."
)

if response.status:
contents = await response.text()
response.close()
xml_content = xmltodict.parse(contents)
data = xml_content.get("response", None)
if data:
return data
raise CannotConnectError("Eco-Devices XML request error:", data)

@property
def host(self):
def host(self) -> str:
"""Return the hostname."""
return self._host

@property
def mac_address(self):
async def mac_address(self) -> str:
"""Return the mac address."""
return self._request().get("config_mac")
data = await self._request()
return data["config_mac"]

@property
def firmware(self):
"""Return the firmware."""
return self._request().get("version")
async def firmware(self) -> str:
"""Return the mac address."""
data = await self._request()
return data["version"]

def ping(self) -> bool:
async def ping(self) -> bool:
"""Return true if Eco-Devices answer to API request."""
try:
self._request()
if await self._request():
return True
except Exception:
pass
return False

def global_get(self):
async def global_get(self) -> dict:
"""Return all values from API."""
return self._request()
return await self._request()

def get_t1(self):
async def get_t1(self) -> dict:
"""Get values from teleinformation 1 input."""
data = self._request()
data = await self._request()
return {
"current": data.get("T1_PAPP"),
"type_heures": data.get("T1_PTEC"),
"souscription": data.get("T1_ISOUSC"),
"intensite_max": data.get("T1_IMAX"),
}

def get_t2(self):
async def get_t2(self) -> dict:
"""Get values from teleinformation 1 input."""
data = self._request()
data = await self._request()
return {
"current": data.get("T2_PAPP"),
"type_heures": data.get("T2_PTEC"),
"souscription": data.get("T2_ISOUSC"),
"intensite_max": data.get("T2_IMAX"),
}

def get_c1(self):
async def get_c1(self) -> dict:
"""Get values from meter 1 input."""
data = self._request()
data = await self._request()
return {
"daily": data.get("c0day"),
"total": data.get("count0"),
"fuel": data.get("c0_fuel"),
}

def get_c2(self):
async def get_c2(self) -> dict:
"""Get values from meter 2 input."""
data = self._request()
data = await self._request()
return {
"daily": data.get("c1day"),
"total": data.get("count1"),
"fuel": data.get("c1_fuel"),
}

async def close(self) -> None:
"""Close open client session."""
if self._session and self._close_session:
await self._session.close()

async def __aenter__(self):
"""Async enter."""
return self

async def __aexit__(self, *_exc_info) -> None:
"""Async exit."""
await self.close()


class CannotConnectError(Exception):
"""Exception to indicate an error in connection."""


class InvalidAuthError(Exception):
"""Exception to indicate an error in authentication."""
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="pyecodevices",
version="1.1.0",
version="1.2.0",
author="Aohzan",
author_email="aohzan@gmail.com",
description="Get information from GCE Eco-Devices.",
Expand Down

0 comments on commit 3bdced0

Please sign in to comment.