Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
claudiuskastner committed Apr 14, 2024
1 parent c56c436 commit 56400ad
Show file tree
Hide file tree
Showing 27 changed files with 321 additions and 67 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FROM python:3.11-slim
21 changes: 21 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
default: help
@>&2 echo "Choose an action."

help:
@echo "Please use 'make <target>' where <target> is one of:"
@echo ""
@echo " clean remove temporary files"
@echo " install tinstalls dependencies and pre-commit hooks"
@echo ""

clean:
@find . | grep -E "(__pycache__|\.pyc$$|\.pyo$$|dist|.egg-info$$|\build/*$$ )" | xargs rm -rf

install:
@python3.11 -m venv venv
@venv/bin/python3 -m pip install -U pre-commit
@venv/bin/python3 -m pip install -e .[dev]
@venv/bin/pre-commit install

dist: clean
@python3 -m build
13 changes: 11 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ readme = "README.md"
dependencies = [
"bleak~=0.20",
"construct~=2.10",
"fastapi~=0.101",
"influxdb~=5.3",
"influxdb-client[ciso]~=1.37",
"jsonpickle~=3.0",
"prometheus_client~=0.17",
"pydantic-settings~=2.0"
"pyfiglet~=0.8",
"python-interface~=1.6",
"requests~=2.31"
"requests~=2.31",
"sqlalchemy~=2.0",
"uvicorn[standard]~=0.23"
]

[project.scripts]
Expand All @@ -29,9 +33,14 @@ dev = [
"flake8~=6.1",
"isort~=5.12",
"mypy~=1.5",
"types-requests~=2.31.0"
"types-requests~=2.31.0",
"pylint~=2.17.5"
]

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[tool.mypy]
python_version = "3.11"
warn_return_any = true
Expand Down
19 changes: 1 addition & 18 deletions src/__main__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import argparse
from logging import INFO, getLogger

from .pitch import pitch_main
from .main import main
from .providers import CalibrationCloudProvider


Expand Down Expand Up @@ -41,22 +41,5 @@ def _get_args():
return parser.parse_args()


def main() -> None:
logger = getLogger(__name__)
logger.setLevel(INFO)
args = _get_args()
logger.info("Starting")
if args.calibrate:
# Run with only calibration provider, timeout and disable output of json logs to console
calibrator: CalibrationCloudProvider = CalibrationCloudProvider(
args.calibrate, args.actual_temp, args.actual_gravity
)
pitch_main(providers=[calibrator], timeout_seconds=5, console_log=False)
logger.info("Finished")
else:
# Run with default providers, forever, possibly simulating beacons
pitch_main(providers=None, timeout_seconds=0)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion src/abstractions/cloud_provider.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Protocol

from ..models import TiltStatus
from models import TiltStatus


class CloudProviderBase(Protocol):
Expand Down
Empty file added src/api/__init__.py
Empty file.
17 changes: 17 additions & 0 deletions src/api/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from functools import lru_cache

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
app_name: str = "Tilt Pitch API"
sqlalchemy_database_url: str
model_config = SettingsConfigDict(env_file=".env")


@lru_cache()
def get_settings():
return Settings()


settings = Settings()
36 changes: 36 additions & 0 deletions src/api/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from sqlalchemy.orm import Session

from . import database, schemas


def get_sensor(db: Session, sensor_id: int):
return db.query(database.Sensor).filter(database.Sensor.id == sensor_id).first()


def get_sensor_by_colour(db: Session, colour: str):
return db.query(database.Sensor).filter(database.Sensor.colour == colour).first()


def get_sensors(db: Session, skip: int = 0, limit: int = 100):
return db.query(database.Sensor).offset(skip).limit(limit).all()


def create_sensor(db: Session, sensor: schemas.SensorCreate):
db_sensor = database.Sensor(colour=sensor.colour, is_active=sensor.is_active)
db.add(db_sensor)
db.commit()
db.refresh(db_sensor)
return db_sensor



def get_brews(db: Session, skip: int = 0, limit: int = 100):
return db.query(database.Brew).offset(skip).limit(limit).all()


def create_brew(db: Session, brew: schemas.BrewCreate, sensor_id: int):
db_brew = database.Brew(**brew.model_dump(), sensor_id=sensor_id)
db.add(db_brew)
db.commit()
db.refresh(db_brew)
return db_brew
36 changes: 36 additions & 0 deletions src/api/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from sqlalchemy import (Boolean, Column, Engine, Float, ForeignKey, Integer,
String, create_engine)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker

from .config import get_settings

settings = get_settings()
SQLALCHEMY_DATABASE_URL = settings.sqlalchemy_database_url
engine: Engine

if SQLALCHEMY_DATABASE_URL.startswith("sqlite"):
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
else:
engine = create_engine(SQLALCHEMY_DATABASE_URL)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()


class Sensor(Base):
__tablename__ = "sensors"
id = Column(Integer, primary_key=True, index=True)
colour = Column(String)
is_active = Column(Boolean)
brews = relationship("Brew", back_populates="sensor")


class Brew(Base):
__tablename__ = "brews"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
starting_gravity = Column(Float, nullable=False)
sensor = relationship("Sensor", back_populates="brews")
sensor_id = Column(Integer, ForeignKey("sensors.id"))
66 changes: 66 additions & 0 deletions src/api/fast_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import threading
from typing import List

from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session

from api.sensors import sensor_router

from . import config, crud, database, schemas

fast_api_app = FastAPI()
# fast_api_app.include_router(sensor_router)

database.Base.metadata.create_all(bind=database.engine)


def get_db():
db = database.SessionLocal()
try:
yield db
finally:
db.close()


@fast_api_app.get("/")
def get_processes() -> list[str]:
threads: List[threading.Thread] = threading.enumerate()
thread_names: List[str] = []
for thread in threads:
thread_names.append(thread.name)
return thread_names


@fast_api_app.post("/sensors/", response_model=schemas.Sensor)
def create_sensor(sensor: schemas.SensorCreate, db: Session = Depends(get_db)):
db_sensor = crud.get_sensor_by_colour(db, colour=sensor.colour)
if db_sensor:
raise HTTPException(status_code=400, detail="Colour already registered")
return crud.create_sensor(db=db, sensor=sensor)


@fast_api_app.get("/sensors/", response_model=list[schemas.Sensor])
def read_sensors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
sensors = crud.get_sensors(db, skip=skip, limit=limit)
return sensors


@fast_api_app.get("/sensors/{sensor_id}", response_model=schemas.Sensor)
def read_sensor(sensor_id: int, db: Session = Depends(get_db)):
db_sensor = crud.get_sensor(db, sensor_id=sensor_id)
if db_sensor is None:
raise HTTPException(status_code=404, detail="Sensor not found")
return db_sensor


@fast_api_app.post("/sensors/{sensor_id}/brews/", response_model=schemas.Brew)
def create_brew_for_sensor(
sensor_id: int, brew: schemas.BrewCreate, db: Session = Depends(get_db)
):
return crud.create_brew(db=db, brew=brew, sensor_id=sensor_id)


@fast_api_app.get("/brews/", response_model=list[schemas.Brew])
def read_brews(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
brews = crud.get_brews(db, skip=skip, limit=limit)
return brews
33 changes: 33 additions & 0 deletions src/api/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from pydantic import BaseModel


class BrewBase(BaseModel):
name: str
starting_gravity: float
sensor_id: int


class BrewCreate(BrewBase):
pass


class Brew(BrewBase):
id: int

class Config:
from_attributes = True


class SensorBase(BaseModel):
is_active: bool
colour: str


class SensorCreate(SensorBase):
pass


class Sensor(SensorBase):

class Config:
from_attributes = True
29 changes: 29 additions & 0 deletions src/api/sensors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import List

from fastapi import APIRouter

sensor_router = APIRouter(
prefix="/sensors",
tags=["sensors"],
responses={404: {"description": "Not found"}},
)


@sensor_router.get("/")
async def get_sensors() -> List[str]:
return ["yellow", "purple"]


@sensor_router.get("/{sensor_id}")
async def get_sensor(sensor_id: str) -> dict:
return {"sensor_id": sensor_id}


@sensor_router.post("/")
async def add_sensor():
return {}


@sensor_router.put("/{sensor_id}")
async def update_sensor():
return {}
2 changes: 2 additions & 0 deletions src/configuration/pitch_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def __init__(self, data: dict):
# Grainfather
self.grainfather_custom_stream_urls: Optional[str] = None
self.grainfather_temp_unit = "F"

self.log_level = "INFO"
# Load user inputs from config file
self.update(data)

Expand Down
1 change: 1 addition & 0 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import argparse
from logging import INFO, getLogger

from api.fast_api import fast_api_app # noqa: F401s
from pitch import pitch_main
from providers import CalibrationCloudProvider

Expand Down
3 changes: 2 additions & 1 deletion src/models/tilt_status.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime

from ..configuration import PitchConfig
from configuration import PitchConfig

from .json_serialize import JsonSerialize


Expand Down
Loading

0 comments on commit 56400ad

Please sign in to comment.