async-httpd-data-collector 0.2__tar.gz → 0.2.1__tar.gz
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.
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/.github/workflows/publish.yml +7 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/PKG-INFO +1 -1
- async_httpd_data_collector-0.2.1/ahttpdc/__init__.py +1 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/fetch/async_fetch.py +0 -1
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/interface.py +1 -4
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/query/async_query.py +53 -26
- async_httpd_data_collector-0.2.1/examples/query.py +42 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/tests/reads/test_interface.py +3 -6
- async_httpd_data_collector-0.2/ahttpdc/__init__.py +0 -1
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/.gitignore +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/LICENSE +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/README.md +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/__init__.py +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/fetch/__init__.py +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/query/__init__.py +0 -0
- /async_httpd_data_collector-0.2/examples/minimal-example.py → /async_httpd_data_collector-0.2.1/examples/fetch.py +0 -0
- /async_httpd_data_collector-0.2/examples/dev_dashboard.py → /async_httpd_data_collector-0.2.1/examples/minimal_dashboard.py +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/influx +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/influxdb2-client-2.7.5-linux-amd64.tar.gz +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/pyproject.toml +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/requirements.txt +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/tests/dev_server.py +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/tests/reads/fetch/test_fetcher.py +0 -0
- {async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/tests/reads/query/test_query.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: async-httpd-data-collector
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Gateway facilitating asyncronous communication between sensory data-emitting devices, InfluxDB and the user.
|
|
5
5
|
Project-URL: Repository, https://github.com/straightchlorine/async-httpd-data-collector
|
|
6
6
|
Project-URL: Issues, https://github.com/straightchlorine/async-httpd-data-collector/issues
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.2.1'
|
|
@@ -135,7 +135,6 @@ class AsyncReadFetcher:
|
|
|
135
135
|
records (dict): The sensor readings as records for InfluxDB.
|
|
136
136
|
"""
|
|
137
137
|
|
|
138
|
-
print('<.> writing new read into database...')
|
|
139
138
|
write_api = client.write_api()
|
|
140
139
|
point = Point.from_dict(record, write_precision='ns')
|
|
141
140
|
await write_api.write(
|
{async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/interface.py
RENAMED
|
@@ -133,13 +133,12 @@ class DatabaseInterface:
|
|
|
133
133
|
pd.DataFrame: The latest measurement.
|
|
134
134
|
"""
|
|
135
135
|
|
|
136
|
-
print('<.> querying latest measurement...')
|
|
137
136
|
query_task = asyncio.create_task(self.query_interface.latest())
|
|
138
137
|
await query_task
|
|
139
138
|
result = query_task.result()
|
|
140
139
|
return result
|
|
141
140
|
|
|
142
|
-
async def query_historical(self, start: str, end: str) -> pd.DataFrame:
|
|
141
|
+
async def query_historical(self, start: str, end: str = '') -> pd.DataFrame:
|
|
143
142
|
"""
|
|
144
143
|
Query historical data from the database.
|
|
145
144
|
|
|
@@ -151,7 +150,6 @@ class DatabaseInterface:
|
|
|
151
150
|
pd.DataFrame: Historical data within the specified time range.
|
|
152
151
|
"""
|
|
153
152
|
|
|
154
|
-
print('<.> querying historical data...')
|
|
155
153
|
query_task = asyncio.create_task(
|
|
156
154
|
self.query_interface.historical_data(start, end)
|
|
157
155
|
)
|
|
@@ -170,7 +168,6 @@ class DatabaseInterface:
|
|
|
170
168
|
pd.DataFrame: The result of the custom query.
|
|
171
169
|
"""
|
|
172
170
|
|
|
173
|
-
print('<.> custom query...')
|
|
174
171
|
query_task = asyncio.create_task(self.query_interface.query(query))
|
|
175
172
|
await query_task
|
|
176
173
|
result = query_task.result()
|
|
@@ -8,6 +8,7 @@ from datetime import datetime, timedelta
|
|
|
8
8
|
|
|
9
9
|
from influxdb_client.client.exceptions import InfluxDBError
|
|
10
10
|
from influxdb_client.client.influxdb_client_async import InfluxDBClientAsync
|
|
11
|
+
from influxdb_client import InfluxDBClient
|
|
11
12
|
import pandas as pd
|
|
12
13
|
|
|
13
14
|
__all__ = ['AsyncQuery']
|
|
@@ -96,13 +97,14 @@ class AsyncQuery:
|
|
|
96
97
|
|
|
97
98
|
def _into_dataframe(self, tables) -> pd.DataFrame:
|
|
98
99
|
"""
|
|
99
|
-
Turns the tables into a pandas DataFrame
|
|
100
|
+
Turns the tables into a pandas DataFrame with time of measurement as
|
|
101
|
+
as index.
|
|
102
|
+
|
|
100
103
|
Args:
|
|
101
104
|
tables (list): The tables to turn into a DataFrame.
|
|
102
105
|
Returns:
|
|
103
|
-
pd.DataFrame: procured measurements as a DataFrame.
|
|
106
|
+
pd.DataFrame: procured measurements as a DataFrame sorted by time.
|
|
104
107
|
"""
|
|
105
|
-
print('into dataframe')
|
|
106
108
|
read: dict = {}
|
|
107
109
|
timestamps = set()
|
|
108
110
|
|
|
@@ -130,8 +132,11 @@ class AsyncQuery:
|
|
|
130
132
|
for timestamp in local_timestamps:
|
|
131
133
|
read['time'].append(pd.to_datetime(timestamp))
|
|
132
134
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
df = pd.DataFrame(read)
|
|
136
|
+
df.set_index('time', inplace=True)
|
|
137
|
+
df.sort_index(inplace=True)
|
|
138
|
+
|
|
139
|
+
return df
|
|
135
140
|
|
|
136
141
|
async def latest(self) -> pd.DataFrame:
|
|
137
142
|
"""
|
|
@@ -163,35 +168,57 @@ class AsyncQuery:
|
|
|
163
168
|
else:
|
|
164
169
|
return pd.DataFrame()
|
|
165
170
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
def historical_query(self, query: str) -> pd.DataFrame:
|
|
172
|
+
tables = None
|
|
173
|
+
try:
|
|
174
|
+
with InfluxDBClient(
|
|
175
|
+
url=self._db_url,
|
|
176
|
+
token=self._influxdb_token,
|
|
177
|
+
org=self._influxdb_organization,
|
|
178
|
+
) as client:
|
|
179
|
+
query_api = client.query_api()
|
|
180
|
+
tables = query_api.query(query)
|
|
181
|
+
except InfluxDBError as e:
|
|
182
|
+
print(f'Exception caught while querying the database:\n\n {e.message}')
|
|
169
183
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
184
|
+
if tables is not None:
|
|
185
|
+
return self._into_dataframe(tables)
|
|
186
|
+
else:
|
|
187
|
+
return pd.DataFrame()
|
|
173
188
|
|
|
174
|
-
|
|
175
|
-
pd.DataFrame: Historical data within the specified time range.
|
|
189
|
+
async def historical_data(self, start: str, end: str = '') -> pd.DataFrame:
|
|
176
190
|
"""
|
|
191
|
+
Query the database synchronously for historical data within the specified
|
|
192
|
+
range.
|
|
193
|
+
Query the database for historical data within the specified time range.
|
|
194
|
+
Use when dealing with large time intervals. Uses regular client, not the
|
|
195
|
+
async one.
|
|
177
196
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
197
|
+
Args:
|
|
198
|
+
start(str): start time (e.g., '2024-01-02T00:00:00Z') of the query
|
|
199
|
+
or relative time string (e.g., '-30d') for end unspecified
|
|
200
|
+
end (str): End time of the query (e.g., '2024-01-02T00:00:00Z')
|
|
181
201
|
|
|
182
|
-
|
|
183
|
-
|
|
202
|
+
Example:
|
|
203
|
+
interface.historical_data('-30d')
|
|
184
204
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
print(f'Exception caught while querying the database:\n\n {e.message}')
|
|
205
|
+
finish = datetime.now()
|
|
206
|
+
start = finish - timedelta(minuts=30)
|
|
207
|
+
start = start.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
208
|
+
finish = finish.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
190
209
|
|
|
191
|
-
|
|
210
|
+
interface.historical_data(start, finish)
|
|
192
211
|
|
|
193
|
-
|
|
194
|
-
|
|
212
|
+
Returns:
|
|
213
|
+
pd.DataFrame: Historical data within the specified time range.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
if start is not None and end == '':
|
|
217
|
+
query = f'from(bucket:"{self._influxdb_bucket}") |> range(start: {start})'
|
|
218
|
+
return self.historical_query(query)
|
|
219
|
+
elif start is not None and end != '':
|
|
220
|
+
query = f'from(bucket:"{self._influxdb_bucket}") |> range(start: {start}, stop: {end})'
|
|
221
|
+
return self.historical_query(query)
|
|
195
222
|
else:
|
|
196
223
|
return pd.DataFrame()
|
|
197
224
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
import json
|
|
3
|
+
import asyncio
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from ahttpdc.reads.interface import DatabaseInterface
|
|
6
|
+
|
|
7
|
+
# load the secrets
|
|
8
|
+
with open('secrets/rpi-secrets.json', 'r') as f:
|
|
9
|
+
secrets = json.load(f)
|
|
10
|
+
|
|
11
|
+
sensors = {
|
|
12
|
+
'bmp180': ['altitude', 'pressure', 'seaLevelPressure'],
|
|
13
|
+
'mq135': ['aceton', 'alcohol', 'co', 'co2', 'nh4', 'toulen'],
|
|
14
|
+
'ds18b20': ['temperature'],
|
|
15
|
+
'dht22': ['humidity'],
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
dev_ip = '192.168.10.101'
|
|
19
|
+
dev_port = '80'
|
|
20
|
+
|
|
21
|
+
# create the DatabaseInterface object
|
|
22
|
+
interface = DatabaseInterface(
|
|
23
|
+
secrets['host'],
|
|
24
|
+
secrets['port'],
|
|
25
|
+
secrets['token'],
|
|
26
|
+
secrets['organization'],
|
|
27
|
+
secrets['bucket'],
|
|
28
|
+
sensors,
|
|
29
|
+
dev_ip,
|
|
30
|
+
dev_port,
|
|
31
|
+
secrets['handle'],
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def query():
|
|
36
|
+
result = await interface.query_historical('-30d')
|
|
37
|
+
return result
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
if __name__ == '__main__':
|
|
41
|
+
dataframe: pd.DataFrame = asyncio.run(query())
|
|
42
|
+
dataframe.to_csv('sensor-data.csv')
|
{async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/tests/reads/test_interface.py
RENAMED
|
@@ -10,7 +10,7 @@ import os
|
|
|
10
10
|
import pytest
|
|
11
11
|
|
|
12
12
|
from ahttpdc.reads.interface import DatabaseInterface
|
|
13
|
-
from datetime import datetime, timedelta
|
|
13
|
+
# from datetime import datetime, timedelta
|
|
14
14
|
|
|
15
15
|
from tests.reads.query.test_query import TestQuery
|
|
16
16
|
|
|
@@ -104,11 +104,8 @@ class TestInterface:
|
|
|
104
104
|
self.set_up()
|
|
105
105
|
await asyncio.sleep(5)
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
result = await self.interface.query_historical(
|
|
110
|
-
start.strftime('%Y-%m-%dT%H:%M:%SZ'), finish.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
111
|
-
)
|
|
107
|
+
# the date variant tested in test_query.py
|
|
108
|
+
result = await self.interface.query_historical('-3s')
|
|
112
109
|
self.interface.disable_fetching()
|
|
113
110
|
|
|
114
111
|
assert not result.empty
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.2'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/__init__.py
RENAMED
|
File without changes
|
{async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/fetch/__init__.py
RENAMED
|
File without changes
|
{async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/ahttpdc/reads/query/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_httpd_data_collector-0.2 → async_httpd_data_collector-0.2.1}/tests/reads/query/test_query.py
RENAMED
|
File without changes
|