v.0.11.0 ap-server & pico-client
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -95,4 +95,8 @@ logs/
|
|||||||
|
|
||||||
# Temporary files
|
# Temporary files
|
||||||
*.tmp
|
*.tmp
|
||||||
*.temp
|
*.temp
|
||||||
|
|
||||||
|
# UV package manager
|
||||||
|
uv.lock
|
||||||
|
.uv/
|
||||||
|
|||||||
36
api-server/.devcontainer/Dockerfile
Normal file
36
api-server/.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
FROM python:3.13-alpine
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
git \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
bash \
|
||||||
|
build-base \
|
||||||
|
linux-headers \
|
||||||
|
fish
|
||||||
|
|
||||||
|
# Install uv from official image
|
||||||
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
|
||||||
|
RUN uv --version
|
||||||
|
|
||||||
|
# Create non-root user with fish shell
|
||||||
|
RUN adduser -D -s /usr/bin/fish vscode
|
||||||
|
|
||||||
|
# Create workspace and set permissions
|
||||||
|
RUN mkdir -p /workspace && chown vscode:vscode /workspace
|
||||||
|
|
||||||
|
USER vscode
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
# Set fish as default shell
|
||||||
|
SHELL ["/usr/bin/fish", "-c"]
|
||||||
|
|
||||||
|
# Install packages directly to system Python (container-isolated)
|
||||||
|
ENV UV_PROJECT_ENVIRONMENT=""
|
||||||
|
ENV UV_PYTHON=python
|
||||||
|
|
||||||
|
# Verify everything works
|
||||||
|
RUN echo "Python: $(python --version)" && \
|
||||||
|
echo "UV: $(uv --version)" && \
|
||||||
|
echo "Fish: $(fish --version)"
|
||||||
44
api-server/.devcontainer/devcontainer.json
Normal file
44
api-server/.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
|
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
||||||
|
{
|
||||||
|
"name": "API-Server",
|
||||||
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile"
|
||||||
|
},
|
||||||
|
// "image": "mcr.microsoft.com/devcontainers/python:1-3.12",
|
||||||
|
// "image": "python:latest",
|
||||||
|
//"image": "python:3.13-slim",
|
||||||
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
|
// "features": {},
|
||||||
|
// Configure tool-specific properties.
|
||||||
|
"customizations": {
|
||||||
|
// Configure properties specific to VS Code.
|
||||||
|
"vscode": {
|
||||||
|
"settings": {},
|
||||||
|
"extensions": [
|
||||||
|
"ms-python.python",
|
||||||
|
"frhtylcn.pythonsnippets",
|
||||||
|
"kevinrose.vsc-python-indent",
|
||||||
|
"wayou.vscode-todo-highlight",
|
||||||
|
"charliermarsh.ruff",
|
||||||
|
"tamasfe.even-better-toml"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
|
// "forwardPorts": [9000],
|
||||||
|
// Use 'portsAttributes' to set default properties for specific forwarded ports.
|
||||||
|
// More info: https://containers.dev/implementors/json_reference/#port-attributes
|
||||||
|
"portsAttributes": {
|
||||||
|
"9000": {
|
||||||
|
"label": "API-Server Application",
|
||||||
|
"onAutoForward": "notify"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
|
"postCreateCommand": "uv sync"
|
||||||
|
// "postCreateCommand": "apt-get update && apt-get install -y git && pip3 install -r requirements.txt"
|
||||||
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
|
// "remoteUser": "root"
|
||||||
|
}
|
||||||
75
api-server/app/main.py
Normal file
75
api-server/app/main.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
app = FastAPI(title="FastAPI Server", version="1.0.0")
|
||||||
|
|
||||||
|
# CORS middleware to allow client requests
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["http://localhost:3000", "http://client:3000"],
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
class Item(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: Optional[str] = None
|
||||||
|
price: float
|
||||||
|
|
||||||
|
# In-memory database
|
||||||
|
items_db = [
|
||||||
|
Item(id=1, name="Laptop", description="High-performance laptop", price=999.99),
|
||||||
|
Item(id=2, name="Mouse", description="Wireless mouse", price=29.99),
|
||||||
|
Item(id=3, name="Keyboard", description="Mechanical keyboard", price=79.99),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def root():
|
||||||
|
return {"message": "FastAPI Server is running!"}
|
||||||
|
|
||||||
|
@app.get("/items", response_model=List[Item])
|
||||||
|
async def get_items():
|
||||||
|
return items_db
|
||||||
|
|
||||||
|
@app.get("/items/{item_id}", response_model=Item)
|
||||||
|
async def get_item(item_id: int):
|
||||||
|
item = next((item for item in items_db if item.id == item_id), None)
|
||||||
|
if item is None:
|
||||||
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
|
return item
|
||||||
|
|
||||||
|
@app.post("/items", response_model=Item)
|
||||||
|
async def create_item(item: Item):
|
||||||
|
if any(existing_item.id == item.id for existing_item in items_db):
|
||||||
|
raise HTTPException(status_code=400, detail="Item ID already exists")
|
||||||
|
items_db.append(item)
|
||||||
|
return item
|
||||||
|
|
||||||
|
@app.put("/items/{item_id}", response_model=Item)
|
||||||
|
async def update_item(item_id: int, item: Item):
|
||||||
|
if item.id != item_id:
|
||||||
|
raise HTTPException(status_code=400, detail="Item ID mismatch")
|
||||||
|
|
||||||
|
for idx, existing_item in enumerate(items_db):
|
||||||
|
if existing_item.id == item_id:
|
||||||
|
items_db[idx] = item
|
||||||
|
return item
|
||||||
|
|
||||||
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
|
|
||||||
|
@app.delete("/items/{item_id}")
|
||||||
|
async def delete_item(item_id: int):
|
||||||
|
for idx, item in enumerate(items_db):
|
||||||
|
if item.id == item_id:
|
||||||
|
deleted_item = items_db.pop(idx)
|
||||||
|
return {"message": f"Item {deleted_item.name} deleted successfully"}
|
||||||
|
|
||||||
|
raise HTTPException(status_code=404, detail="Item not found")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||||
12
api-server/pyproject.toml
Normal file
12
api-server/pyproject.toml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[project]
|
||||||
|
name = "api-server"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
dependencies = [
|
||||||
|
"fastapi>=0.104.0",
|
||||||
|
"uvicorn[standard]>=0.24.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
# [build-system]
|
||||||
|
# requires = ["hatchling"]
|
||||||
|
# build-backend = "hatchling.build"
|
||||||
@@ -1,13 +1,3 @@
|
|||||||
#Moin from VSCode
|
|
||||||
|
|
||||||
# FROM python:3.13-slim
|
|
||||||
# RUN apt-get update && apt-get install -y \
|
|
||||||
# git \
|
|
||||||
# curl \
|
|
||||||
# wget \
|
|
||||||
# && rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
|
|
||||||
FROM python:3.13-alpine
|
FROM python:3.13-alpine
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
git \
|
git \
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
// README at: https://github.com/devcontainers/templates/tree/main/src/python
|
||||||
{
|
{
|
||||||
"name": "Python 3",
|
"name": "Pico-Client",
|
||||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile"
|
"dockerfile": "Dockerfile"
|
||||||
@@ -23,7 +23,8 @@
|
|||||||
"wayou.vscode-todo-highlight",
|
"wayou.vscode-todo-highlight",
|
||||||
"charliermarsh.ruff",
|
"charliermarsh.ruff",
|
||||||
"wokwi.wokwi-vscode",
|
"wokwi.wokwi-vscode",
|
||||||
"humao.rest-client"
|
"humao.rest-client",
|
||||||
|
"tamasfe.even-better-toml"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
// More info: https://containers.dev/implementors/json_reference/#port-attributes
|
// More info: https://containers.dev/implementors/json_reference/#port-attributes
|
||||||
"portsAttributes": {
|
"portsAttributes": {
|
||||||
"9000": {
|
"9000": {
|
||||||
"label": "Flask Application",
|
"label": "Pico-W Application",
|
||||||
"onAutoForward": "notify"
|
"onAutoForward": "notify"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from display import NeoPixel_64x64
|
from display import NeoPixel_64x64
|
||||||
from display.fonts import font_5x7
|
from display.fonts import font_5x7
|
||||||
from tryout import Font_Checker, Weather_Checker, Emoji_Checker
|
from tryout import Font_Checker, Weather_Checker, Emoji_Checker, API_Server_Checker
|
||||||
from utils import show_system_load
|
from utils import show_system_load
|
||||||
from utils import (
|
from utils import (
|
||||||
sync_ntp_time,
|
sync_ntp_time,
|
||||||
@@ -12,12 +12,12 @@ from utils.digital_clock import DigitalClock
|
|||||||
import uasyncio as asyncio # type: ignore
|
import uasyncio as asyncio # type: ignore
|
||||||
from web import Wlan
|
from web import Wlan
|
||||||
|
|
||||||
CITY_LIST: list[str] = sorted(
|
|
||||||
["Großhansdorf", "Columbus", "London", "Ebeltoft", "Tokio"]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def weather_check_task(weather_checker: Weather_Checker):
|
async def weather_check_task(weather_checker: Weather_Checker):
|
||||||
|
CITY_LIST: list[str] = sorted(
|
||||||
|
["Großhansdorf", "Columbus", "London", "Ebeltoft", "Tokio"]
|
||||||
|
)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
for city in CITY_LIST:
|
for city in CITY_LIST:
|
||||||
weather_checker.check(city=city, lang="de", test_mode=True)
|
weather_checker.check(city=city, lang="de", test_mode=True)
|
||||||
@@ -63,7 +63,9 @@ if __name__ == "__main__":
|
|||||||
# emoji_checker : Emoji_Checker = Emoji_Checker(display)
|
# emoji_checker : Emoji_Checker = Emoji_Checker(display)
|
||||||
# emoji_checker.check()
|
# emoji_checker.check()
|
||||||
|
|
||||||
# tryout.weather_check(display, test_mode=False)
|
api_server_check_task: API_Server_Checker = API_Server_Checker()
|
||||||
|
api_server_check_task.check()
|
||||||
|
|
||||||
display.set_font(font_5x7)
|
display.set_font(font_5x7)
|
||||||
weather_checker: Weather_Checker = Weather_Checker(display=display)
|
weather_checker: Weather_Checker = Weather_Checker(display=display)
|
||||||
|
|
||||||
|
|||||||
7
pico-client/restapi/server-api.http
Normal file
7
pico-client/restapi/server-api.http
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
### all Items
|
||||||
|
### FIXME: wie erreiche ich den Server aus dem Container
|
||||||
|
GET http://api-server-admin-:8000/items
|
||||||
|
Accept: application/json
|
||||||
|
|
||||||
|
###
|
||||||
|
GET http://0.0.0.0:8000/items
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
from .font_checker import Font_Checker
|
from .font_checker import Font_Checker
|
||||||
from .weather_checker import Weather_Checker
|
from .weather_checker import Weather_Checker
|
||||||
from .emoji_checker import Emoji_Checker
|
from .emoji_checker import Emoji_Checker
|
||||||
|
from .api_server_checker import API_Server_Checker
|
||||||
|
|
||||||
__all__ = [ 'Font_Checker', 'Weather_Checker', 'Emoji_Checker']
|
__all__ = ["Font_Checker", "Weather_Checker", "Emoji_Checker", "API_Server_Checker"]
|
||||||
|
|||||||
20
pico-client/tryout/api_server_checker.py
Normal file
20
pico-client/tryout/api_server_checker.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import urequests # type: ignore
|
||||||
|
import json
|
||||||
|
|
||||||
|
BASE_API_URL: str = "http://0.0.0.0:8000"
|
||||||
|
|
||||||
|
|
||||||
|
class API_Server_Checker:
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _get_items(self):
|
||||||
|
items_url: str = f"{BASE_API_URL}/items"
|
||||||
|
print(f"query: {items_url}")
|
||||||
|
r = urequests.get(items_url)
|
||||||
|
print("Status-Code:", r.status_code)
|
||||||
|
json_resp = r.json()
|
||||||
|
print("json_resp:", json_resp)
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
self._get_items()
|
||||||
Reference in New Issue
Block a user