Compare commits

...

2 Commits

Author SHA1 Message Date
Moritz Graf 9af18e5879 feat: add memobird printing skill and integrated into AGENTS.md 2026-05-17 12:34:18 +02:00
Moritz Graf d445d22fda Adding recent changes 2026-04-01 17:27:09 +02:00
8 changed files with 216 additions and 28 deletions

View File

@ -20,6 +20,11 @@ A professional "Octobot Journalist" that generates daily, weekly, and monthly re
- **Topics:** IT News, GCP, AI (Anthropic/OpenAI), Hacker News, Regensburg Local News.
- **Special Features:** Monday catch-up, Drill-down ("Tell me more"), Gardening (Hochbeet), Supermarket Shopping Guide.
### [memobird](skills/memobird/SKILL.md)
Direct printing to the Memobird thermal printer. Allows sending text, images, and notes to the device on the local network.
- **Features:** Text styling (big, bold, underline), automated 1-bit image conversion, separator lines.
- **Target:** Default targets the static IP `192.168.10.165`.
### [rvv-regensburg](skills/rvv-regensburg/SKILL.md)
Real-time public transport information for Regensburg (RVV). Provides departures, stop finding, and journey planning via direct API access.
- **Features:** Real-time departures with delay info, connection search, Stop ID resolver.

BIN
memobird.skill Normal file

Binary file not shown.

44
skills/memobird/SKILL.md Normal file
View File

@ -0,0 +1,44 @@
---
name: memobird
description: Print text, images, and notes directly to the Memobird thermal printer. Use this when the user wants to print a physical note, a shopping list, or a small image to the Memobird at its local IP.
---
# 🐦 Memobird Printer
Direct printing to the Memobird thermal printer on the local network.
## 🚀 Usage
Use the `scripts/memobird_print.py` tool. By default, it targets the static IP `192.168.10.165`.
### 1. Print simple text
```bash
./scripts/memobird_print.py --text "Hello from Gemini!"
```
### 2. Print styled text
```bash
./scripts/memobird_print.py --text "IMPORTANT NOTE" --big --bold
```
### 3. Print an image
```bash
./scripts/memobird_print.py --image "path/to/image.png"
```
### 4. Print a separator line
```bash
./scripts/memobird_print.py --line THICK
```
## 🛠️ Options
- `--text`: The string to print.
- `--image`: Path to a local image file (converted to 1-bit monochrome automatically).
- `--ip`: Override the default IP (192.168.10.165).
- `--big`, `--bold`, `--underline`: Text styling.
- `--line`: Print a line (`THICK`, `THIN`, or `DASH`).
## 💡 Tips
- **Character Limit:** Thermal paper is narrow (384px wide). Long lines of text will wrap.
- **Image Size:** Large images might fail if they take too long to transfer. Keep them reasonably sized.
- **Connection:** Ensure the printer is powered on and connected to the same WiFi network.

View File

@ -0,0 +1,122 @@
#!/usr/bin/env python3
import sys
import os
import requests
import json
import base64
from io import BytesIO
from random import randint
from PIL import Image as PILImg, ImageOps
import argparse
# Default IP for Moritz's Memobird
DEFAULT_HOST = "192.168.10.165"
def to_byte_array(img):
imgByteArr = BytesIO()
img.save(imgByteArr, format='bmp')
return imgByteArr.getvalue()
class MemobirdSender:
def __init__(self, host=DEFAULT_HOST, port='80'):
self.host = host
self.port = port
self.uri = f"http://{self.host}:{self.port}/sys/printer"
def send(self, text_list, print_id=None):
print_id = print_id or randint(1, 10**6)
payload = {
'command': 3,
'content': {
'textList': text_list
},
'encryptFlag': 0,
'hasHead': 0,
'hasSignature': 0,
'hasTail': 0,
'isFromDirectPrint': False,
'msgType': 1,
'pkgCount': 1,
'pkgNo': 1,
'printID': print_id,
'priority': 0,
'result': 0,
'scripType': 3
}
try:
resp = requests.post(self.uri, json=payload, timeout=10)
resp.raise_for_status()
return resp.status_code
except Exception as e:
print(f"Error sending to Memobird: {e}")
sys.exit(1)
def create_text_element(text, big=False, bold=False, underline=False):
if not text.endswith('\n'):
text += '\n'
return {
'encodeType': 0,
'printType': 1,
'basetext': base64.b64encode(text.encode("GBK")).decode(),
'fontSize': 1 + big,
'bold': 1 * bold,
'underline': 1 * underline
}
def create_image_element(path):
img = PILImg.open(path)
img = img.convert(mode='L')
img = ImageOps.flip(img)
img = img.convert(mode='1')
return {
'encodeType': 0,
'printType': 5,
'basetext': base64.b64encode(to_byte_array(img)).decode()
}
def create_line_element(linetype='THICK'):
codes = {'THICK': 41, 'THIN': 42, 'DASH': 43}
return {
'encodeType': 0,
'printType': 4,
'iconID': codes.get(linetype, 41)
}
def main():
parser = argparse.ArgumentParser(description="Print to Memobird")
parser.add_argument("--text", help="Text to print")
parser.add_argument("--image", help="Path to image to print")
parser.add_argument("--ip", default=DEFAULT_HOST, help=f"Memobird IP (default: {DEFAULT_HOST})")
parser.add_argument("--big", action="store_true", help="Use big font")
parser.add_argument("--bold", action="store_true", help="Use bold font")
parser.add_argument("--underline", action="store_true", help="Use underline")
parser.add_argument("--line", choices=['THICK', 'THIN', 'DASH'], help="Print a separator line")
args = parser.parse_args()
if not args.text and not args.image and not args.line:
parser.print_help()
sys.exit(1)
sender = MemobirdSender(host=args.ip)
elements = []
if args.line:
elements.append(create_line_element(args.line))
if args.text:
elements.append(create_text_element(args.text, big=args.big, bold=args.bold, underline=args.underline))
if args.image:
if os.path.exists(args.image):
elements.append(create_image_element(args.image))
else:
print(f"Error: Image not found: {args.image}")
sys.exit(1)
status = sender.send(elements)
print(f"Success! Printer returned {status}")
if __name__ == "__main__":
main()

View File

@ -1,20 +1,37 @@
---
name: nerd-report
description: Generiert personalisierte Morgen-Reports für Moritz Graf in Regensburg. Beinhaltet tägliche Updates (Wetter, News, Wikipedia), wöchentliche Tech-Ausblicke und monatliche Garten-Tipps. Nutzt eine journalistische "Octobot" Persona und beachtet strikte Telegram-HTML Formatierung.
description: Generiert personalisierte Morgen-Reports für Moritz Graf in Regensburg. Analysiert zuerst aktuelles Datum/Wochentag, um den passenden Berichtstyp (Daily, Weekly, Monthly) zu wählen. Nutzt eine journalistische "Octobot" Persona, baut viele relevante Links ein und verwendet Markdown (kein HTML!) zur optimalen Darstellung in Telegram.
---
# Nerd-Report Generator 🐙
Dieser Skill erstellt strukturierte, dichte Berichte für Moritz Graf. Er ist darauf optimiert, als "Isolated Agent" via Cron-Trigger ausgeführt zu werden oder auf Nachfragen ("Drill-down") zu reagieren.
## Kernfunktionen
1. **Täglicher Report (MO-SA):** Fokus auf Nerd-Wikipedia, Wetter, News-Dichte (idowa, BR24, HN, Youtube). Montags inkl. Sonntags-Catchup.
2. **Wöchentlicher Report (SO-Normal):** Hacker News Highlights, Nerd-Events (Binary Kitchen), Tech-Insider (GCP, AI).
3. **Monatlicher Report (1. SO):** Hochbeet-Gartenarbeit, Supermarkt-Guide (Saisonales kaufen/meiden), Tech-Kalender.
## Kern-Workflow & Routing
Wenn dieser Skill aufgerufen wird, führe als **ALLERERSTEN SCHRITT** folgende Logik aus:
1. **Datum und Wochentag ermitteln:** Finde heraus, welches Datum und welcher Wochentag heute ist.
2. **Report-Typ bestimmen:**
- **Montag bis Samstag:** Generiere den **Daily Report** (Normaler Tagesbericht, Montags inkl. Sonntags-Catchup).
- **Sonntag:** Prüfe, ob es der _erste Sonntag im Monat_ ist.
- Wenn JA: Generiere den **Monthly Report**.
- Wenn NEIN: Generiere den **Weekly Report**.
*(Hinweis: Ignoriere alle abweichenden Scheduling-Regeln in den Referenz-Dateien, diese dynamische Routing-Logik hat in jedem Fall Vorrang).*
## Report-Typen
1. **Daily Report (MO-SA):** Fokus auf Nerd-Wikipedia, Wetter, News-Dichte (idowa, BR24, HN, Youtube).
2. **Weekly Report (SO - normal):** Hacker News Highlights, Nerd-Events (Binary Kitchen), Tech-Insider (GCP, AI).
3. **Monthly Report (SO - 1. im Monat):** Hochbeet-Gartenarbeit, Supermarkt-Guide (Saisonales kaufen/meiden), Tech-Kalender.
4. **Drill-down:** Reagiert auf "Erzähle mir mehr über xxx" mit einem prägnanten, weiterleitbaren Steckbrief.
## Formatierung für Telegram (WICHTIG!)
- **KEIN HTML:** Verwende **NIEMALS** rohe HTML-Tags wie `<b>`, `<strong>`, `<i>` oder `<a>`. OpenClaw escapet diese Tags für Telegram, was dazu führt, dass sie als reiner Text (z.B. `<b>Text</b>`) in der Chat-Bubble angezeigt werden!
- **Nur Markdown:** Verwende für Hervorhebungen ausschließlich reines Markdown, z.B. `**fetter Text**` und `_kursiver Text_`.
- **Links im Markdown-Format:** Verwende `[Link-Text](URL)` anstelle von HTML-Links.
- **Mehr Links:** Baue in jedem Report **deutlich mehr Links** zu den Originalquellen, passenden Artikeln (z.B. Wikipedia) oder GitHub-Projekten ein! Je mehr nützliche Querverweise, desto besser.
- **Struktur:** Nutze sauberes Markdown, damit Telegram die Nachricht korrekt rendert.
## Richtlinien
- **Persona:** Handle als professioneller, ehrlicher Journalist mit Octobot-Charme. Siehe [persona.md](references/persona.md).
- **Persona:** Handle als professioneller, ehrlicher Journalist mit Octobot-Charme. Siehe `references/persona.md`.
- **Fokus:** Immer nerdy & techy. Priorisiere GCP, AI (OpenAI, Anthropic) und Hacker News.
- **Formatierung:** Strikte Telegram-HTML Regeln (Keine Header, keine Listen). Kompakte Links via `<a>`.
- **Workflow:** Siehe [daily.md](references/daily.md) und [weekly_monthly.md](references/weekly_monthly.md).
- **Details zu Inhalten:** Siehe `references/daily.md` und `references/weekly_monthly.md`.

View File

@ -5,7 +5,7 @@
- **Immer nerdy/techy!** (Wissenschaftler, Erfinder, IT-Durchbrüche). Keinen "Mainstream" ohne Tech-Bezug.
2. **Weather (BrightSky):**
- Location: Grabengasse 7, 93059 Regensburg.
- Erstelle eine Text-Tabelle im `<pre>` Block für die Intervalle: 6-9, 9-12, 12-15, 15-18 Uhr.
- Erstelle eine Text-Tabelle in einem formatfreien Bereich oder Markdown-Codeblock für die Intervalle: 6-9, 9-12, 12-15, 15-18 Uhr.
3. **News (Regensburg & Tech):**
- **Montags-Logik:** Hole die wichtigsten News vom Sonntag nach, da dort kein Report kam.
- Scanne `idowa.de`, `BR24`, `Hacker News` und `Youtube`.
@ -13,31 +13,31 @@
## Drill-down Feature ("Erzähle mir mehr")
Falls Moritz fragt: "Erzähle mir mehr über xxx", antworte SOFORT mit einem prägnanten Steckbrief:
- **Titel:** <b>[NAME/THEMA]</b>
- **Titel:** **[NAME/THEMA]**
- **Kerninfo:** 2-3 Sätze, was das ist und warum es relevant ist.
- **Deep Dive:** Weiterführende Links für mehr Details.
- **Format:** Direkt weiterleitbar (Telegram HTML).
- **Format:** Direkt weiterleitbar (nur Markdown `[Text](URL)` - kein HTML!).
## Format-Vorlage (Telegram HTML)
```html
<b>### Morgenreport (Wochentag, Datum) ###</b>
## Format-Vorlage (Telegram Markdown)
```markdown
**### Morgenreport (Wochentag, Datum) ###**
<b>📰 Person des Tages (Nerdy Edition):</b>
<a href="URL">Name</a>, Begründung (Fokus: Tech/Wissenschaft)
**📰 Person des Tages (Nerdy Edition):**
[Name](URL), Begründung (Fokus: Tech/Wissenschaft)
<b>🌡️ Wetterbericht für Regensburg:</b>
<pre>
**🌡️ Wetterbericht für Regensburg:**
```text
| Zeit | 6-9 | 9-12 | 12-15 | 15-18 |
|-------|-----|------|-------|-------|
| Temp | 12° | 16° | 18° | 10° |
| Wetter| 🌧️ | ☀️ | ☁️ | ☁️ |
</pre>
```
<b>💡 Besonderheit des Tages:</b>
<a href="URL">Artikel-Titel</a>: Prägnanter Tech-Fokus.
**💡 Besonderheit des Tages:**
[Artikel-Titel](URL): Prägnanter Tech-Fokus.
<b>📣 News Feed (Concise & Dense):</b>
1. <a href="URL">Titel</a>: Kurz-Teaser.
2. <a href="URL">Titel</a>: Kurz-Teaser.
**📣 News Feed (Concise & Dense):**
1. [Titel](URL): Kurz-Teaser.
2. [Titel](URL): Kurz-Teaser.
... (bis zu 5-7 News, wenn relevant)
```

View File

@ -12,6 +12,6 @@ Du bist ein hochspezialisierter KI-Journalist, der exklusiv für Moritz Graf arb
## Richtlinien für die Kommunikation
- Nutze Emojis passend zum Thema (🐙, 💻, 🌿, 🌤️, 🏛️).
- Nutze kompakte HTML-Links `<a>Klick</a>` um den Lesefluss nicht zu stören.
- Achte STRENG auf die Telegram-HTML-Beschränkungen (Keine Header, keine Listen).
- Nutze viele Links im Markdown-Format `[Text](URL)` um den Lesefluss zu fördern und Kontext zu bieten.
- Verwende **KEIN ROHES HTML** (kein `<b>`, kein `<a>`). Nutze stattdessen sauberes Markdown (`**fett**`), damit Telegram die Nachricht korrekt anzeigt.
- Bei Nachfragen ("Erzähle mir mehr...") wechselst du in den **Steckbrief-Modus** (siehe `daily.md`).

View File

@ -16,5 +16,5 @@
- **Tech-Kalender:** Wichtige Releases/Konferenzen.
## Formatierung
- Nutze `<b>` für Sektionen.
- Beachte die Telegram HTML-Beschränkungen.
- Nutze `**fett**` für Sektionen anstatt von HTML.
- Beachte die Telegram Markdown-Regeln (kein rohes HTML!). Baue viele aussagekräftige Links im Format `[Text](URL)` ein.