commit 402395c8566562101a8de70df2d5173262daf3e5 Author: Christoph K. Date: Wed Mar 11 16:26:11 2026 +0100 init diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..25c304f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,28 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when testing the PoC via REST API and curl. + +The API is mapped via a tunnel on port `10000` and exposes endpoints under `/smarthome-ext/diag/EMMANATIVE/`: +- `GET /smarthome-ext/diag` — base diagnostics +- `PublishPvData` — publish photovoltaic data +- `GetWeather` — weather data +- `GetVersion` — version info + +## API Curl Requests + +```bash +# Base diagnostics +curl http://localhost:10000/smarthome-ext/diag + +# All EMMANATIVE diagnostics +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE + +# Get version +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE/GetVersion + +# Get weather +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE/GetWeather + +# Publish PV data +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE/PublishPvData +``` diff --git a/README.md b/README.md new file mode 100644 index 0000000..4942399 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# EMMA Go PoC + +The API is mapped via a tunnel on port `10000`. + +Tunnel creation command: +ssh -N -L 10000:127.0.0.1:8080 root@192.168.1.200 + +## API Curl Requests + +```bash +# Base diagnostics +curl http://localhost:10000/smarthome-ext/diag + +# All EMMANATIVE diagnostics +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE + +# Get version +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE/GetVersion + +# Get weather +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE/GetWeather + +# Publish PV data +curl http://localhost:10000/smarthome-ext/diag/EMMANATIVE/PublishPvData +``` diff --git a/dummyhttpserver/Dockerfile b/dummyhttpserver/Dockerfile new file mode 100644 index 0000000..e0561c2 --- /dev/null +++ b/dummyhttpserver/Dockerfile @@ -0,0 +1,5 @@ + +FROM python:3.13-alpine +WORKDIR /app +COPY server.py . +CMD ["python", "server.py"] diff --git a/dummyhttpserver/docker-compose.yml b/dummyhttpserver/docker-compose.yml new file mode 100644 index 0000000..3e24ae8 --- /dev/null +++ b/dummyhttpserver/docker-compose.yml @@ -0,0 +1,15 @@ +services: + dummyhttpserver: + image: python:3.13-alpine + container_name: dummyhttpserver + restart: unless-stopped + ports: + - "10001:8080" + volumes: + - ./server.py:/app/server.py:ro + - ./example.json:/data/example.json:ro + working_dir: /app + command: python server.py + environment: + - DATA_FILE=/data/example.json + - PORT=8080 diff --git a/dummyhttpserver/example.json b/dummyhttpserver/example.json new file mode 100644 index 0000000..4e357d0 --- /dev/null +++ b/dummyhttpserver/example.json @@ -0,0 +1 @@ +{"currentTemperatureC":22.5,"humidity":50} \ No newline at end of file diff --git a/dummyhttpserver/server.py b/dummyhttpserver/server.py new file mode 100644 index 0000000..3754f1d --- /dev/null +++ b/dummyhttpserver/server.py @@ -0,0 +1,27 @@ +from http.server import BaseHTTPRequestHandler, HTTPServer +import os + +DATA_FILE = os.environ.get("DATA_FILE", "/data/example.json") + + +class Handler(BaseHTTPRequestHandler): + def do_GET(self): + try: + with open(DATA_FILE, "rb") as f: + body = f.read() + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + except FileNotFoundError: + self.send_error(404, "Data file not found") + + def log_message(self, format, *args): + print(f"{self.address_string()} - {format % args}", flush=True) + + +if __name__ == "__main__": + port = int(os.environ.get("PORT", 8080)) + print(f"Serving {DATA_FILE} on port {port}", flush=True) + HTTPServer(("", port), Handler).serve_forever() diff --git a/mosquitto/README.md b/mosquitto/README.md new file mode 100644 index 0000000..6362425 --- /dev/null +++ b/mosquitto/README.md @@ -0,0 +1,93 @@ +# mqtt-emma + +Eclipse Mosquitto MQTT broker als Docker Compose Stack für Synology NAS. + +## Voraussetzungen + +- Synology NAS mit Docker/Container Manager +- SSH-Zugriff auf die NAS +- `docker` und `docker compose` verfügbar (ab DSM 7.2 inklusive) + +## Deployment + +### 1. Dateien auf die NAS kopieren + +```bash +scp -r mqtt-emma/ admin@192.168.1.4:/volume1/docker/mqtt-emma +``` + +Oder per File Station / SMB-Share auf die NAS kopieren. + +### 2. Per SSH einloggen und ins Projektverzeichnis wechseln + +```bash +ssh admin@192.168.1.4 +cd /volume1/docker/mqtt-emma +``` + +### 3. Stack starten + +```bash +docker compose up -d +``` + +### 4. Verbindung testen + +Von einem Rechner im gleichen Netzwerk (mosquitto-clients erforderlich): + +```bash +# Subscriber starten +mosquitto_sub -h 192.168.1.4 -p 1883 -t 'test/#' -v + +# In einem zweiten Terminal: Nachricht senden +mosquitto_pub -h 192.168.1.4 -p 1883 -t 'test/hello' -m 'welt' +``` + +> **Hinweis:** Aktuell ist anonymer Zugriff aktiviert (kein Passwort nötig). Für Produktion `allow_anonymous false` und `password_file` in `mosquitto/config/mosquitto.conf` einkommentieren. + +## Ports + +| Port | Protokoll | Beschreibung | +|------|------------|-----------------------------------| +| 1883 | MQTT | Standard MQTT | +| 9001 | WebSockets | Für Browser-Clients (z. B. MQTT.js) | + +## Nützliche Befehle + +```bash +# Logs anzeigen +docker compose logs -f mosquitto + +# Stack stoppen +docker compose down + +# Config neu laden (ohne Neustart) +docker compose kill -s HUP mosquitto + +# Broker-Status prüfen +docker compose ps +``` + +## Konfiguration + +Die Broker-Konfiguration liegt in `mosquitto/config/mosquitto.conf`. +Nach Änderungen genügt ein Config-Reload: + +```bash +docker compose kill -s HUP mosquitto +``` + +Für Änderungen an Ports oder Volumes ist ein Neustart nötig: + +```bash +docker compose down && docker compose up -d +``` + +## Zeitzone anpassen + +In `docker-compose.yml` die Umgebungsvariable `TZ` anpassen, z. B.: + +```yaml +environment: + - TZ=Europe/Vienna +``` diff --git a/mosquitto/config/mosquitto.conf b/mosquitto/config/mosquitto.conf new file mode 100644 index 0000000..cac49a1 --- /dev/null +++ b/mosquitto/config/mosquitto.conf @@ -0,0 +1,28 @@ +# Mosquitto MQTT Broker Configuration + +# Persistence +persistence true +persistence_location /mosquitto/data/ + +# Logging +log_dest file /mosquitto/log/mosquitto.log +log_dest stdout +log_type error +log_type warning +log_type notice +log_type information + +# MQTT Listener (plain) +listener 1883 +protocol mqtt + +# WebSocket Listener +listener 9001 +protocol websockets + +# Authentication +# Für lokale Tests: anonym erlaubt, kein Passwort nötig +allow_anonymous true +# Für Produktion: anonym deaktivieren und passwd-Datei einbinden +# allow_anonymous false +# password_file /mosquitto/config/passwd diff --git a/mosquitto/docker-compose.yml b/mosquitto/docker-compose.yml new file mode 100644 index 0000000..17e7878 --- /dev/null +++ b/mosquitto/docker-compose.yml @@ -0,0 +1,14 @@ +services: + mosquitto: + image: eclipse-mosquitto:latest + container_name: mqtt-emma + restart: unless-stopped + ports: + - "1883:1883" # MQTT + - "9001:9001" # WebSocket + volumes: + - ./mosquitto/config:/mosquitto/config + - ./mosquitto/data:/mosquitto/data + - ./mosquitto/log:/mosquitto/log + environment: + - TZ=Europe/Berlin