Initial commit
This commit is contained in:
commit
b134f4c3b9
8 changed files with 299 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
*.pyd
|
||||
__pycache__
|
||||
11
auto_test.sh
Executable file
11
auto_test.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Start test if one of the files was modified
|
||||
|
||||
while true; do
|
||||
NOTIFY=$(inotifywait -rq -e modify . | grep '\.py')
|
||||
if [ _$? == _0 ]; then
|
||||
pytest --capture=no test
|
||||
echo ">>>>>>>> Test finished at: $(date)"
|
||||
fi
|
||||
done
|
||||
10
energyDB.conf
Normal file
10
energyDB.conf
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Configuration for the uvicorn server running the energyDB application
|
||||
|
||||
# Set HTTP port
|
||||
HTTP_PORT=8444
|
||||
|
||||
# Bind to address
|
||||
IP_ADDRESS=0.0.0.0
|
||||
|
||||
# More uvicorn command line arguments
|
||||
UVICORN_ARGS=--reload
|
||||
3
srv/__init__.py
Normal file
3
srv/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from .energyDB import app
|
||||
|
||||
energyDB = app
|
||||
117
srv/energyDB.py
Normal file
117
srv/energyDB.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
from typing import Optional, List
|
||||
from fastapi import FastAPI, Header, HTTPException
|
||||
from pydantic import BaseModel
|
||||
import datetime
|
||||
import databases
|
||||
import sqlalchemy
|
||||
from sqlite3 import OperationalError
|
||||
|
||||
DATABASE_URL = "sqlite:///./energyDB.sqlite"
|
||||
# DATABASE_URL = "sqlite://"
|
||||
db = databases.Database(DATABASE_URL)
|
||||
metadata = sqlalchemy.MetaData()
|
||||
energy = sqlalchemy.Table(
|
||||
"energy",
|
||||
metadata,
|
||||
sqlalchemy.Column("timestamp", sqlalchemy.DateTime, primary_key=True),
|
||||
sqlalchemy.Column("channel_id", sqlalchemy.Integer(), nullable=False),
|
||||
sqlalchemy.Column("value", sqlalchemy.Float),
|
||||
sqlalchemy.UniqueConstraint("timestamp"),
|
||||
)
|
||||
engine = sqlalchemy.create_engine(
|
||||
DATABASE_URL, connect_args={"check_same_thread": False}
|
||||
)
|
||||
metadata.create_all(engine)
|
||||
|
||||
class EnergyValue(BaseModel):
|
||||
timestamp: datetime.datetime
|
||||
value: float
|
||||
|
||||
class ChannelData(BaseModel):
|
||||
channel_id: int
|
||||
data: List[EnergyValue]
|
||||
msg: Optional[str]
|
||||
|
||||
class BulkData(BaseModel):
|
||||
bulk: List[ChannelData]
|
||||
msg: Optional[str]
|
||||
|
||||
class BulkDataRequest(BaseModel):
|
||||
channel_ids: List[int]
|
||||
fromTime: datetime.datetime
|
||||
tillTime: datetime.datetime = datetime.datetime.now()
|
||||
|
||||
app = FastAPI(debug=True)
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
"""On startup connect to the database"""
|
||||
await db.connect()
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown():
|
||||
"""On shutdow diconnect from the database"""
|
||||
await db.disconnect()
|
||||
|
||||
# def _raiseHttpExceptionOnWrongToken(token : str):
|
||||
# if token != fake_secret_token:
|
||||
# raise HTTPException(status_code=400, detail="Invalid X-Token header")
|
||||
|
||||
@app.put("/energy/bulkData")
|
||||
async def putBulkEnergyData(bulkData: BulkData):
|
||||
valuesToInsert = []
|
||||
for channelData in bulkData.bulk:
|
||||
for measurement in channelData.data:
|
||||
valuesToInsert.append({
|
||||
"channel_id": channelData.channel_id,
|
||||
"timestamp": measurement.timestamp,
|
||||
"value": measurement.value})
|
||||
query = energy.insert().values(valuesToInsert)
|
||||
result = await db.execute(query)
|
||||
return {
|
||||
"valuesToInsert": valuesToInsert
|
||||
}
|
||||
|
||||
@app.get("/energy/bulkData", response_model = BulkData)
|
||||
async def getBulkEnergyData(bulkDataRequest: BulkDataRequest):
|
||||
bulkData = []
|
||||
for ch in bulkDataRequest.channel_ids:
|
||||
query = sqlalchemy.select([energy.c.timestamp, energy.c.value]) \
|
||||
.where(energy.c.channel_id == ch) \
|
||||
.where(energy.c.timestamp >= bulkDataRequest.fromTime) \
|
||||
.where(energy.c.timestamp <= bulkDataRequest.tillTime)
|
||||
data = await db.fetch_all(query)
|
||||
bulkData.append({"channel_id": ch, "data": data})
|
||||
|
||||
return {
|
||||
"bulk": bulkData,
|
||||
"msg": __name__ + " - " +str(query.compile())
|
||||
}
|
||||
|
||||
|
||||
@app.get("/energy/{channel_id}", response_model = ChannelData)
|
||||
async def getChannelData(channel_id: int):
|
||||
try:
|
||||
query = sqlalchemy.select([energy.c.timestamp, energy.c.value]).where(energy.c.channel_id == channel_id)
|
||||
result = await db.fetch_all(query)
|
||||
return {
|
||||
"channel_id": channel_id,
|
||||
"data": result
|
||||
}
|
||||
except Exception as ex:
|
||||
raise HTTPException(status_code=500, detail=f"Internal error: {type(ex)} - \"{ex}\"")
|
||||
|
||||
@app.put("/energy/{channel_id}") #, response_model = EnergyValue)
|
||||
async def putChannelData(channel_id: int, data: EnergyValue):
|
||||
query = energy.insert().values(
|
||||
timestamp=data.timestamp,
|
||||
channel_id=channel_id,
|
||||
value=data.value)
|
||||
result = await db.execute(query)
|
||||
# # return await db.fetch_all(query)
|
||||
return {
|
||||
"timestamp": datetime.datetime.now(),
|
||||
# "channel" : data.channel,
|
||||
"value": data.value,
|
||||
"msg": str(result)
|
||||
}
|
||||
14
start_server.sh
Executable file
14
start_server.sh
Executable file
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Start uvicorn server with application srv:energyDB
|
||||
|
||||
ENERGY_DB_CONF=./energyDB.conf
|
||||
|
||||
if [ -f $ENERGY_DB_CONF ]; then
|
||||
. energyDB.conf
|
||||
fi
|
||||
|
||||
ARG_HTTP_PORT=${HTTP_PORT:-8000}
|
||||
ARG_IP_ADDRESS=${IP_ADDRESS:-127.0.0.1}
|
||||
|
||||
/usr/bin/env uvicorn --port $ARG_HTTP_PORT --host $ARG_IP_ADDRESS ${UVICORN_ARGS} srv:energyDB
|
||||
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
142
test/test_EnergyDB.py
Normal file
142
test/test_EnergyDB.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
from fastapi.testclient import TestClient
|
||||
import pytest
|
||||
|
||||
from datetime import datetime
|
||||
import json
|
||||
import urllib.parse
|
||||
|
||||
from srv import energyDB
|
||||
|
||||
class Test_energyDb:
|
||||
|
||||
bulkTestData = [
|
||||
{
|
||||
"channel_id": 1,
|
||||
"data": (
|
||||
{ "timestamp": "2020-12-11T12:00:22", "value": 1100.1 },
|
||||
{ "timestamp": "2020-12-11T12:10:15", "value": 1109.2 },
|
||||
{ "timestamp": "2020-12-11T12:20:13", "value": 1119.3 },
|
||||
{ "timestamp": "2020-12-11T12:30:21", "value": 1131.4 },
|
||||
{ "timestamp": "2020-12-11T12:40:08", "value": 1143.5 },
|
||||
{ "timestamp": "2020-12-11T12:50:13", "value": 1152.6 },
|
||||
{ "timestamp": "2020-12-11T13:00:11", "value": 1160.7 },
|
||||
{ "timestamp": "2020-12-11T13:10:09", "value": 1169.8 },
|
||||
{ "timestamp": "2020-12-11T13:20:10", "value": 1181.9 },
|
||||
{ "timestamp": "2020-12-11T13:30:17", "value": 1190.0 },
|
||||
)
|
||||
},
|
||||
{
|
||||
"channel_id": 2,
|
||||
"data": [
|
||||
{ "timestamp": "2020-12-11T12:01:15", "value": 1200.1 },
|
||||
{ "timestamp": "2020-12-11T12:21:28", "value": 1219.2 },
|
||||
{ "timestamp": "2020-12-11T12:41:21", "value": 1243.3 },
|
||||
{ "timestamp": "2020-12-11T13:01:16", "value": 1260.4 },
|
||||
{ "timestamp": "2020-12-11T13:21:18", "value": 1281.5 },
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
client = TestClient(energyDB)
|
||||
|
||||
# def setup(self):
|
||||
# self.client = TestClient(energyDB)
|
||||
|
||||
# def teardown(self):
|
||||
# self.client = None
|
||||
|
||||
def _test_bulkData_put(self):
|
||||
# response = self.client.put("/energy/bulkData", json=self.bulkTestData);
|
||||
response = self.client.put("/energy/bulkData", json={"bulk": self.bulkTestData})
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# requestJson = json.loads(response.request.body)
|
||||
# print(f"response.request.body: {json.dumps(requestJson, indent=2)}")
|
||||
print("---- response")
|
||||
print(f"response.reason: {response.reason}")
|
||||
responseJson = json.loads(response.text)
|
||||
print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# print(f"response.text: {json.dumps(response.text, indent=2)}")
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_bulkData_get(self):
|
||||
# response = self.client.put("/energy/bulkData", json=self.bulkTestData);
|
||||
fromTimestamp = datetime.fromisoformat("2020-12-11T12:30:00")
|
||||
tillTimestamp = datetime.fromisoformat("2020-12-11T12:30:59")
|
||||
response = self.client.get(
|
||||
"/energy/bulkData",
|
||||
json = {
|
||||
"channel_ids": [1, 2, 3],
|
||||
"fromTime": fromTimestamp.isoformat(),
|
||||
# "tillTime": tillTimestamp.isoformat()
|
||||
})
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
print("---- request")
|
||||
print(f"response.request.method: {response.request.method}")
|
||||
print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
print(f"response.request.headers: {response.request.headers}")
|
||||
print(f"dir(response.request): {dir(response.request)}")
|
||||
print(f"response.request.body: {response.request.body}")
|
||||
# requestJson = json.loads(response.request.body)
|
||||
# print(f"response.request.body: {json.dumps(requestJson, indent=2)}")
|
||||
print("---- response")
|
||||
print(f"response.reason: {response.reason}")
|
||||
responseJson = json.loads(response.text)
|
||||
print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# print(f"response.text: {json.dumps(response.text, indent=2)}")
|
||||
assert response.status_code == 200
|
||||
|
||||
@pytest.mark.skip(reason="Ignore me temporarily")
|
||||
def test_insert_energy(self):
|
||||
energyData = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"value": 234.5,
|
||||
}
|
||||
print(f"energyData: {energyData}")
|
||||
# response = self.client.put("/energies/1", json=energyData) #, headers={"X-Token": "coneofsilence"})
|
||||
response = self.client.put(
|
||||
"/energy/2",
|
||||
# params=energyData,
|
||||
json=energyData) #, headers={"X-Token": "coneofsilence"})
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# print(f"response.request.body: {json.loads(response.request.body)}")
|
||||
# print("---- response")
|
||||
# print(f"response.reason: {response.reason}")
|
||||
# print(f"response.text: {json.loads(response.text)}")
|
||||
# print(f"request.header: \"{response.request.header}\"")
|
||||
# print(f"request.body: \"{response.request.body}\"")
|
||||
assert response.status_code == 200
|
||||
# assert response.json()["msg"] == ""
|
||||
|
||||
@pytest.mark.skip(reason="Ignore me temporarily")
|
||||
def test_get_energy(self):
|
||||
response = self.client.get("/energy/1")
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# print("---- response")
|
||||
# print(f"response.reason: {response.reason}")
|
||||
responseJson = json.loads(response.text)
|
||||
print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
data = response.json()
|
||||
# print(f"data: {type(data)}")
|
||||
# for k,v in data.items():
|
||||
# print(f"key: {k} -> value: {v}")
|
||||
print(f"data of channel: {data['channel_id']}")
|
||||
for r in data["data"]:
|
||||
print(f"r: {r}")
|
||||
assert response.status_code == 200
|
||||
# assert response.json()["msg"] == ""
|
||||
Loading…
Add table
Reference in a new issue