R

Receipt Cockpit

Zentrale Kassenanalyse

© 2025 Monolith West GmbH
R
Receipt Cockpit
Übersicht Operations Waagen Verwaltung
Übersicht

Lade Daten...

Operations
Waagen-Updater

Wird geladen...

Konfigurations-Updates
Waagen-Konfigurationspakete verwalten und ausrollen

Wird geladen...

Wird geladen...

DIGI Waagen-Updater — Dokumentation

Stand: 2026-04-17 · Zugangsdaten & Passwörter siehe internen Passwort-Manager

1. Überblick

Der Waagen-Updater ermöglicht die zentrale Verwaltung und automatische Verteilung von Konfigurationsupdates für DIGI SM6000-Waagen. Die Waagen holen Updates selbstständig — kein manueller SSH-Zugriff nötig.

2. Architektur

Das System besteht aus drei Ebenen:

┌─────────────────────────────┐     ┌─────────────────────────────┐
│  Filiale (Markt 96 usw.)    │     │  FTP-Distribution           │
│  DIGI-Waage, Debian 10 ARM  │     │  ftp.mix-server.de          │
│  /root/tools/               │────▶│  /httpdocs/digi/            │
│  ├─ get_data.py     (Py2)   │     │  ├─ get_data.py             │
│  ├─ digi_updater.py (Py2)   │     │  ├─ digi_updater.py         │
│  └─ scale_updater.py (Py3)  │     │  └─ scale_updater.py        │
│                             │     └─────────────────────────────┘
│                             │     ┌─────────────────────────────┐
│                             │────▶│  pos.mixmarkt.info          │
│                             │     │  (diese Zentrale)           │
│                             │     │  /api/scale/heartbeat       │
│                             │     │  /api/scale/updates/…       │
└─────────────────────────────┘     └─────────────────────────────┘

3. Die drei Skript-Komponenten

SkriptPythonZweck
get_data.py2Artikel-/WGR-/Allergen-Transfer aus der Polyhedra-DB der Waage per FTP an den Filial-Server; startet anschließend Auto-Updater und scale_updater.
digi_updater.py2Zieht neue Versionen von mix-server.de, tauscht Dateien atomar mit Rollback-Backup aus.
scale_updater.py3Sendet Heartbeat an die Zentrale, zieht zentrale Konfigurations-Updates (ZIP) mit Rollback.

⚠️ Wichtig: get_data.py ist Python 2, scale_updater.py ist Python 3. Daher wird scale_updater.py als Subprocess aufgerufen — niemals importiert: subprocess.call(['python3', '/root/tools/scale_updater.py'])

4. Ablauf eines Waagen-Laufs

  1. Die Waage führt get_data.py aus (z.B. bei Artikelübertragung).
  2. digi_updater.py prüft, ob neue Versionen von get_data.py, digi_updater.py oder scale_updater.py auf dem FTP-Server liegen, und aktualisiert sie atomar (temp-file + rename, .bak-Backup).
  3. scale_updater.py sendet den Heartbeat an die Zentrale (pos.mixmarkt.info).
  4. Die Zentrale antwortet mit dem aktuell aktiven Update (oder leer, wenn keines vorhanden).
  5. Ist das Update neu (noch nicht installiert): ZIP herunterladen → SHA256 prüfen → Tabellen sichern → Update einspielen → Ergebnis melden. Bei Fehler: Rollback aus Backup.

5. Heartbeat-Payload

Die Waage sendet bei jedem Lauf folgende Felder. Diese landen in der DB-Tabelle scale_heartbeats und werden im Tab Waagen-Status angezeigt:

{
  "store_number":      "96",
  "scale_ip":          "172.16.96.31",
  "hostname":          "SM6000",
  "mac_address":       "00:60:03:0a:a8:84",
  "model":             "TWS SM6000",
  "firmware":          "10",
  "arch":              "armv7l",
  "os_version":        "Debian GNU/Linux 10 (buster)",
  "disk_free_mb":      4149,
  "disk_total_mb":     13880,
  "uptime_seconds":    60677,
  "plu_count":         2358,
  "printfmt_count":    74,
  "txt_count":         230,
  "ingdt_count":       955,
  "allergen_count":    -1,
  "get_data_ver":      "2.2",
  "gefl_labelformat":  "38",
  "installed_version": "",
  "last_update_at":    "",
  "scale_token":       ""
}

6. API-Endpunkte (Zentrale)

EndpunktMethodeZweck
/api/scale/heartbeatPOSTWaage meldet sich; Response enthält optionales Update
/api/scale/updates/:id/zipGETWaage lädt Update-ZIP (authentifiziert via scale_token)
/api/scale/updates/:id/reportPOSTWaage meldet Install-Ergebnis
/api/admin/scale-heartbeatsGETDashboard: Liste aller bekannten Waagen (Admin)

7. TOFU-Token (Sicherheit)

Beim ersten Kontakt einer Waage wird automatisch ein sicheres Token generiert und zurückgegeben. Die Waage speichert es in /root/tools/marktinfo.ini unter dem Schlüssel scale_token. Alle weiteren Anfragen (ZIP-Download, Status-Meldung) werden mit diesem Token authentifiziert. Ohne gültiges Token wird der Zugriff verweigert.

Token zurücksetzen (Neuregistrierung erzwingen): UPDATE scale_heartbeats SET token_hash=NULL WHERE store_number='96' AND scale_ip='172.16.96.31';

8. Struktur des Update-ZIPs

update.zip
├── META.txt            # MinFirmware=24.50 (optional)
├── csv/
│   ├── printfmt.csv    # Etikettenformat-Tabelle
│   ├── printfmt2.csv
│   ├── text.csv        # Texte
│   ├── freetext.csv
│   ├── dept.csv
│   ├── tax.csv
│   ├── allergen.csv
│   ├── preset.csv
│   └── cabinet.csv
└── files/              # (optional) Dateien zum Kopieren
    └── opt/pcscale/...

Nur CSVs, die im ZIP vorhanden sind, werden importiert. Fehlende Tabellen bleiben unverändert. Spalten im CSV, die in der Waagen-Datenbank nicht existieren, werden automatisch ignoriert (Schema-Kompatibilität).

9. META.txt (optional im ZIP-Wurzelverzeichnis)

  • MinFirmware=24.50 — Update wird nur installiert, wenn die Firmware-Version der Waage ≥ diesem Wert ist.

10. Tabellen-Backup (vor jedem Update)

Gesicherte Tabellen: printfmt, printfmt2, printfmt3, printfmt4, text, freetext, dept, tax, allergen, preset, cabinet

Backups werden unter /root/tools/backups/backup_YYYYMMDD_HHMMSS/ gespeichert. Es werden maximal 5 Backups aufbewahrt — älteste werden automatisch gelöscht.

11. Kanäle

  • stable — Wird an alle Waagen ausgeliefert.
  • canary — Nur für Testwaagen (zukünftig über marktinfo.ini steuerbar).

12. Neues Update anlegen — Schritt für Schritt

  1. Tab Updates öffnen.
  2. + Neues Update klicken.
  3. Version eingeben (z.B. 2025-04).
  4. Beschreibung eingeben.
  5. Mindest-Firmware angeben (optional, z.B. 24.50).
  6. Kanal wählen (stable oder canary).
  7. ZIP-Datei auswählen und hochladen.
  8. Update auf aktiv setzen — erst dann wird es an Waagen ausgeliefert.

Ein bestehendes Update kann jederzeit mit ↑ ZIP ersetzt oder mit ✕ gelöscht werden.

13. Status-Codes im Install-Log

StatusBedeutung
downloadedZIP heruntergeladen, noch nicht installiert
backup_createdTabellen-Backup erfolgreich erstellt
installedUpdate erfolgreich installiert
failedFehler beim Installieren (Details in Log)
rolled_backRollback aus Backup durchgeführt
skippedUpdate war bereits installiert

14. Skript-Verteilung per FTP (mix-server.de)

Die Python-Skripte werden über FTP verteilt. Öffentliche Download-URL: https://mix-server.de/digi/

FTP-Upload-Pfad: ftp.mix-server.de → /httpdocs/digi/ (Zugangsdaten im Passwort-Manager)

Beispiel-Upload:

curl -T get_data.py --ftp-ssl --insecure \
  --user "<user>:<pass>" \
  "ftp://ftp.mix-server.de/httpdocs/digi/get_data.py"

⚠️ Häufiger Fehler: Ohne /httpdocs/ liefert der Server 550 Access denied. Das Root des FTP-Users ist /, nicht /httpdocs/.

Beim nächsten Waagen-Lauf zieht sich digi_updater.py die neue Version automatisch.

15. Relevante Dateipfade auf der Waage

  • /root/tools/marktinfo.ini — Konfiguration (kunden_nr, scale_token, gefl_labelformat, …)
  • /root/tools/update_state.json — Zuletzt installierte Update-Version
  • /root/tools/backups/ — Tabellen-Backups
  • /root/tools/scale_updater.log — Log-Datei
  • /root/tools/scale_updater.py — Updater-Skript (Python 3)
  • /root/tools/get_data.py — Haupt-Skript (Python 2)
  • /root/tools/digi_updater.py — Auto-Updater (Python 2)

Python-Versionen auf DIGI-Waagen: 2.7.16 + 3.7.3 (beides installiert).

16. Troubleshooting

16.1 Dashboard zeigt leere Felder (Hostname, MAC, PLU-Count …)

Ursache: DB-Migration nicht gelaufen — Spalten fehlen in Postgres. Tritt auf, wenn eine alte server.js ohne die newCols-Einträge läuft.

Diagnose: Spaltenzahl prüfen (erwartet: 23; wenn nur 11 → Migration fehlt):

docker compose exec db psql -U cockpit -d cockpit -c \
  "SELECT column_name FROM information_schema.columns \
   WHERE table_name='scale_heartbeats' ORDER BY ordinal_position;"

Lösung: Neue server.js per scp hochladen, dann docker compose restart api. Der Restart triggert ensureScaleTables(), das per ALTER TABLE ADD COLUMN IF NOT EXISTS die fehlenden Spalten nachzieht.

16.2 scale_updater fehlgeschlagen: SyntaxError(…flush=True…)

Ursache: get_data.py (Python 2) versucht scale_updater.py (Python 3) zu importieren. Python 2 kann print(x, flush=True) nicht parsen.

Lösung: Niemals import scale_updater — immer als Subprocess: subprocess.call(['python3', '/root/tools/scale_updater.py']). Dieser Fix ist in get_data.py seit 2026-04-17 enthalten.

16.3 FTP-Upload: 550 Access denied

Ursache: Falscher Pfad. FTP-User landet in /, nicht in /httpdocs/. Ziel ist /httpdocs/digi/.

Lösung: Immer den vollen Pfad verwenden (ftp://…/httpdocs/digi/datei.py).

16.4 Waage nicht erreichbar (SSH-Timeout)

  1. ping 172.16.96.XX — Waage im Netzwerk?
  2. Filial-VPN prüfen
  3. Netzwerk-Status im Filial-Monitoring
  4. Im Zweifel: Filial-IT bitten, die Waage neu zu starten

16.5 Heartbeat kommt, aber available_update nicht gesetzt

Waage meldet installed_version = aktueller Ziel-Version, oder es gibt keinen aktiven scale_updates-Eintrag für den Kanal stable.

SELECT * FROM scale_updates
WHERE active = TRUE AND channel = 'stable'
ORDER BY released_at DESC LIMIT 5;

17. Siehe auch

Vollständige technische Dokumentation (inkl. Zugangsdaten):

  • E:\PROJEKTE\DRS-Updater\central-cockpit\docs\waagen-de.md (Deutsch)
  • E:\PROJEKTE\DRS-Updater\central-cockpit\docs\waagen-ru.md (Русский)
  • E:\GitHub\mono\tools\waage\README.md (Quick-Reference im Quellcode)

DIGI Весы-Апдейтер — Документация

Дата: 2026-04-17 · Учётные данные и пароли — во внутреннем менеджере паролей

1. Обзор

Апдейтер весов обеспечивает централизованное управление и автоматическое распространение обновлений конфигурации для весов DIGI SM6000. Весы загружают обновления самостоятельно — ручной доступ по SSH не требуется.

2. Архитектура

Система состоит из трёх уровней:

┌─────────────────────────────┐     ┌─────────────────────────────┐
│  Магазин (Markt 96 и т.д.)  │     │  FTP-распространение        │
│  Весы DIGI, Debian 10 ARM   │     │  ftp.mix-server.de          │
│  /root/tools/               │────▶│  /httpdocs/digi/            │
│  ├─ get_data.py     (Py2)   │     │  ├─ get_data.py             │
│  ├─ digi_updater.py (Py2)   │     │  ├─ digi_updater.py         │
│  └─ scale_updater.py (Py3)  │     │  └─ scale_updater.py        │
│                             │     └─────────────────────────────┘
│                             │     ┌─────────────────────────────┐
│                             │────▶│  pos.mixmarkt.info          │
│                             │     │  (эта центральная панель)   │
│                             │     │  /api/scale/heartbeat       │
│                             │     │  /api/scale/updates/…       │
└─────────────────────────────┘     └─────────────────────────────┘

3. Три компонента-скрипта

СкриптPythonНазначение
get_data.py2Передача артикулов/товарных групп/аллергенов из базы Polyhedra весов по FTP на сервер магазина; затем запускает авто-апдейтер и scale_updater.
digi_updater.py2Скачивает новые версии с mix-server.de, атомарно меняет файлы с бэкапом для отката.
scale_updater.py3Отправляет heartbeat в центр, получает центральные обновления конфигурации (ZIP) с возможностью отката.

⚠️ Важно: get_data.py работает на Python 2, scale_updater.py — на Python 3. Поэтому scale_updater.py вызывается как подпроцесс — никогда не импортируется: subprocess.call(['python3', '/root/tools/scale_updater.py'])

4. Процесс запуска на весах

  1. Весы запускают get_data.py (например, при передаче товаров).
  2. digi_updater.py проверяет, есть ли новые версии get_data.py, digi_updater.py или scale_updater.py на FTP-сервере, и обновляет их атомарно (временный файл + rename, бэкап .bak).
  3. scale_updater.py отправляет heartbeat в центр (pos.mixmarkt.info).
  4. Центр отвечает текущим активным обновлением (или пустым ответом).
  5. Если обновление новое (ещё не установлено): скачать ZIP → проверить SHA256 → создать бэкап таблиц → установить обновление → отправить отчёт. При сбое: откат из бэкапа.

5. Полезная нагрузка heartbeat

Весы при каждом запуске отправляют следующие поля. Они сохраняются в таблицу БД scale_heartbeats и отображаются во вкладке Waagen-Status:

{
  "store_number":      "96",
  "scale_ip":          "172.16.96.31",
  "hostname":          "SM6000",
  "mac_address":       "00:60:03:0a:a8:84",
  "model":             "TWS SM6000",
  "firmware":          "10",
  "arch":              "armv7l",
  "os_version":        "Debian GNU/Linux 10 (buster)",
  "disk_free_mb":      4149,
  "disk_total_mb":     13880,
  "uptime_seconds":    60677,
  "plu_count":         2358,
  "printfmt_count":    74,
  "txt_count":         230,
  "ingdt_count":       955,
  "allergen_count":    -1,
  "get_data_ver":      "2.2",
  "gefl_labelformat":  "38",
  "installed_version": "",
  "last_update_at":    "",
  "scale_token":       ""
}

6. API-endpoints (центр)

EndpointМетодНазначение
/api/scale/heartbeatPOSTВесы отчитываются; ответ содержит опциональное обновление
/api/scale/updates/:id/zipGETВесы скачивают ZIP (аутентификация через scale_token)
/api/scale/updates/:id/reportPOSTВесы отчитываются о результате установки
/api/admin/scale-heartbeatsGETДашборд: список всех известных весов (admin/support)

7. TOFU-токен (безопасность)

При первом обращении весов автоматически генерируется защищённый токен и возвращается в ответе. Весы сохраняют его в /root/tools/marktinfo.ini под ключом scale_token. Все последующие запросы (скачивание ZIP, отчёт о статусе) аутентифицируются этим токеном. Без действующего токена доступ запрещён.

Сброс токена (принудительная перерегистрация): UPDATE scale_heartbeats SET token_hash=NULL WHERE store_number='96' AND scale_ip='172.16.96.31';

8. Структура ZIP-обновления

update.zip
├── META.txt            # MinFirmware=24.50 (необязательно)
├── csv/
│   ├── printfmt.csv    # Таблица форматов этикеток
│   ├── printfmt2.csv
│   ├── text.csv        # Тексты
│   ├── freetext.csv
│   ├── dept.csv
│   ├── tax.csv
│   ├── allergen.csv
│   ├── preset.csv
│   └── cabinet.csv
└── files/              # (необязательно) Файлы для копирования
    └── opt/pcscale/...

Импортируются только те CSV, которые есть в ZIP. Отсутствующие таблицы не затрагиваются. Столбцы CSV, которых нет в базе данных весов, автоматически игнорируются (совместимость схемы).

9. META.txt (необязательно в корне ZIP)

  • MinFirmware=24.50 — обновление устанавливается только если версия прошивки весов ≥ этого значения.

10. Резервное копирование таблиц (перед каждым обновлением)

Таблицы, включаемые в бэкап: printfmt, printfmt2, printfmt3, printfmt4, text, freetext, dept, tax, allergen, preset, cabinet

Бэкапы хранятся в /root/tools/backups/backup_YYYYMMDD_HHMMSS/. Хранится не более 5 бэкапов — старые удаляются автоматически.

11. Каналы

  • stable — доставляется на все весы.
  • canary — только для тестовых весов (в будущем управляется через marktinfo.ini).

12. Создание обновления — пошагово

  1. Открыть вкладку Updates.
  2. Нажать + Neues Update.
  3. Ввести версию (например, 2025-04).
  4. Ввести описание.
  5. Указать минимальную прошивку (необязательно, например 24.50).
  6. Выбрать канал (stable или canary).
  7. Выбрать и загрузить ZIP-файл.
  8. Активировать обновление — только тогда оно начнёт доставляться на весы.

Существующее обновление можно заменить с помощью ↑ ZIP или удалить кнопкой ✕.

13. Коды статусов в журнале установки

СтатусЗначение
downloadedZIP скачан, ещё не установлен
backup_createdРезервная копия таблиц успешно создана
installedОбновление успешно установлено
failedОшибка при установке (подробности в журнале)
rolled_backВыполнен откат из резервной копии
skippedОбновление уже было установлено

14. Распространение скриптов через FTP (mix-server.de)

Python-скрипты распространяются через FTP. Публичный URL для скачивания: https://mix-server.de/digi/

FTP-путь для загрузки: ftp.mix-server.de → /httpdocs/digi/ (учётные данные — в менеджере паролей)

Пример загрузки:

curl -T get_data.py --ftp-ssl --insecure \
  --user "<user>:<pass>" \
  "ftp://ftp.mix-server.de/httpdocs/digi/get_data.py"

⚠️ Частая ошибка: без /httpdocs/ сервер возвращает 550 Access denied. Корень FTP-пользователя — это /, а не /httpdocs/.

При следующем запуске весов digi_updater.py автоматически загрузит новую версию.

15. Пути к файлам на весах

  • /root/tools/marktinfo.ini — конфигурация (kunden_nr, scale_token, gefl_labelformat, …)
  • /root/tools/update_state.json — последняя установленная версия обновления
  • /root/tools/backups/ — резервные копии таблиц
  • /root/tools/scale_updater.log — файл журнала
  • /root/tools/scale_updater.py — скрипт апдейтера (Python 3)
  • /root/tools/get_data.py — основной скрипт (Python 2)
  • /root/tools/digi_updater.py — авто-апдейтер (Python 2)

Версии Python на весах DIGI: 2.7.16 + 3.7.3 (оба установлены).

16. Устранение неполадок

16.1 Дашборд показывает пустые поля (hostname, MAC, PLU-count …)

Причина: миграция БД не отработала — колонок нет в Postgres. Это происходит при запущенной старой server.js, у которой в ensureScaleTables() ещё не было новых записей newCols.

Диагностика: проверить количество колонок (ожидается 23; если только 11 — миграция отсутствует):

docker compose exec db psql -U cockpit -d cockpit -c \
  "SELECT column_name FROM information_schema.columns \
   WHERE table_name='scale_heartbeats' ORDER BY ordinal_position;"

Решение: загрузить новый server.js через scp, затем docker compose restart api. Рестарт триггерит ensureScaleTables(), который добавляет недостающие колонки через ALTER TABLE ADD COLUMN IF NOT EXISTS.

16.2 scale_updater fehlgeschlagen: SyntaxError(…flush=True…)

Причина: get_data.py (Python 2) пытается импортировать scale_updater.py (Python 3). Python 2 не может распарсить print(x, flush=True).

Решение: никогда не делать import scale_updater — всегда как подпроцесс: subprocess.call(['python3', '/root/tools/scale_updater.py']). Это исправление включено в get_data.py с 2026-04-17.

16.3 FTP-загрузка: 550 Access denied

Причина: неверный путь. FTP-пользователь оказывается в /, а не в /httpdocs/. Цель — /httpdocs/digi/.

Решение: всегда использовать полный путь (ftp://…/httpdocs/digi/file.py).

16.4 Весы недоступны (таймаут SSH)

  1. ping 172.16.96.XX — весы в сети?
  2. Проверить VPN магазина
  3. Состояние сети в мониторинге магазина
  4. При сомнениях — попросить IT магазина перезагрузить весы

16.5 Heartbeat приходит, но available_update не установлено

Весы сообщают installed_version равную текущей целевой версии, или нет активной записи в scale_updates для канала stable.

SELECT * FROM scale_updates
WHERE active = TRUE AND channel = 'stable'
ORDER BY released_at DESC LIMIT 5;

17. См. также

Полная техническая документация (включая учётные данные):

  • E:\PROJEKTE\DRS-Updater\central-cockpit\docs\waagen-de.md (Deutsch)
  • E:\PROJEKTE\DRS-Updater\central-cockpit\docs\waagen-ru.md (Русский)
  • E:\GitHub\mono\tools\waage\README.md (краткий справочник в репозитории)
Verwaltung
Märkte Benutzer Gruppen Updates API-Keys Hilfe & API
R
Receipt Cockpit
Übersicht Dashboard Bons Artikel Tagesübersicht Storno / Retouren Kassierer Gutscheine & Rabatte Bonrückstellungen Security-Analyse
Verbinde...
© 2025 Monolith West GmbH
by Andreas Derr

Dashboard

Bon-Details