Статистика і енергія¶
Сторінка Stats — це BamDude'ів дашборд для "що ферма реально зробила?": кількість друків, спожитий пластик, енергія, час. Усе з print_archives (окремої stats-таблиці, що могла б дрейфувати, нема), тож числа завжди відповідають списку архівів під тим самим фільтром.
Top-level KPI¶
Хедер показує чотири lifetime-лічильники:
| Метрика | Джерело |
|---|---|
| Завершені друки | Рядки print_archives зі status='completed'. |
| Витрачено пластика | Сума filament_used_grams по всіх архівах діапазону (не лише завершених), групована за матеріалом/кольором. Невдалі / скасовані друки рахуються за фактично витраченим пластиком, а не повною оцінкою слайсера, тож сума збігається з тим, що було відняте з інвенторі. |
| Час друку | Виміряний, не оцінений: для кожного архіву, де є і початок, і кінець, береться час між ними, і лише архіви без однієї з міток падають на слайсерський print_time_seconds. Друку, який BamDude довелось відновлювати після розриву зв'язку, зараховується його очікувана тривалість, а не весь offline-розрив — інакше вихідні без зв'язку додали б днів фантомного часу друку. |
| Спожита енергія | Сума energy_kwh (per-print delta, обчислена диспатчером на завершенні) по завершених архівах, де на старті була прив'язана розумна розетка. Падає на ranged-sum з smart_plug_energy_snapshots, коли individual-print captures відсутні. |
Кожна KPI також показує відповідну ціну, коли default_filament_cost і energy_cost_per_kwh сконфігуровані під Settings → System.
Фільтр діапазону¶
Range-picker над KPI scope-ить усе нижче — last 7 days / last 30 / last quarter / custom range. KPI стають тими самими метриками за обраний період; per-printer breakdown перерендерюється.
Time-series графіки¶
Нижче KPI — два stacked line-графіки:
- Друки на день — bar chart завершених архівів, бакетовані за датою, colour-coded за принтером.
- Пластик на день — те саме бакетування, stacked за матеріалом, тож видно "ми перейшли з PLA-важкого на PETG-важкий у березні".
Hover на бар показує breakdown за той день.
Per-printer breakdown¶
Таблиця внизу складає внесок кожного принтера: друки, пластик, час, енергія, ціна. Клік на рядку дрилить у список архівів, попередньо відфільтрований на цей принтер.
Брак по принтерах — надруковано, брак і частка по кожній машині за обраний період, найгірша частка зверху; лише завершені друки.
Per-print облік енергії¶
Облік енергії — opt-in. Щоб захопити її на кожному друку:
- Додай розумну розетку під Settings → Smart Plugs (Tasmota, Home Assistant, REST/webhook або MQTT — див. Розумні розетки).
- Прив'яжи розетку до конкретного принтера.
- Розетка має репортити сумарні kWh — Tasmota field
Total, HAsensor.<plug>_energy_totalтощо.
На кожному друку:
- На
print_startBamDude читає поточні kWh розетки вprint_archives.energy_start_kwh. - На
print_completeBamDude читає розетку ще раз, обчислюєcurrent - energy_start_kwhі зберігає саму дельту вprint_archives.energy_kwh. Окремої колонкиenergy_end_kwhнемає — end-readout існує лише на час віднімання й одразу відкидається. - Зчитування restart-resilient — значення приходять з fresh DB-session щоразу, ніколи з in-memory dict, тож backend-restart між start і complete не ламає capture.
Якщо розетка не прив'язана або offline на одній з двох меж — energy_kwh лишається null, і той друк виключається з energy-KPI.
Hourly snapshot fallback¶
Per-print capture покладається, що розетка відгукнеться в саме ті два моменти. Щоб згладити її outage-и, BamDude також робить hourly snapshot сумарних kWh кожної розетки у smart_plug_energy_snapshots. Для запитів "total energy" за період stats-сторінка падає на цю таблицю, коли individual-print поля відсутні — _sum_snapshot_deltas() обчислює per-plug max(0, last_in_range - baseline) і сумує.
Snapshot-таблиця обмежена — старі рядки prune-ються після налаштовного retention-вікна, щоб не росла вічно.
Рекорди¶
Панель Records вибирає крайні значення обраного діапазону: Longest Print, Heaviest Print, Most Expensive, Busiest Day і поточний Success Streak.
Most Expensive рахує ще й електрику, а не лише пластик. Друки ранжуються за пластиком плюс енергією, яку друк реально спожив, і показується розбивка (filament / power) — щоб число можна було звірити зі сторінкою самого друку. Довгий друк, який тримав принтер десять годин, більше не програє п'єдестал короткому на дорожчому пластику, коштуючи при цьому дорожче.
Друк без розумної розетки ранжується за пластиком, як і раніше
Його енергію ніколи не міряли, а вигадане число на п'єдесталі було б гірше за його відсутність. Друки, зміряні в нуль, і друки, не зміряні взагалі, лишаються розрізненними.
Розрахунки ціни¶
| Ціна | Формула |
|---|---|
| Ціна пластика на друк | Сума частки кожної призначеної котушки (grams_from_spool × spool.cost / spool.weight). Грами, не покриті призначеною котушкою, добиваються за default_filament_cost / 1000 за грам — якщо дефолт заданий. Тож багатоколірний друк, де лише частина слотів AMS прив'язана до інвентаря, відображає весь друк, а не лише відстежувані слоти. |
| Ціна енергії на друк | energy_kwh × energy_cost_per_kwh. Нуль, коли capture не було (energy_kwh IS NULL). |
| Total | Пластик + енергія. |
Ставка, яку ти не задав, — це відсутність ставки
Якщо default_filament_cost не налаштований, невідстежуваний пластик не
оцінюється: друк без ставки має жодної ціни, а не ціну нуль, що читається
як «безкоштовно».
Раніше BamDude тихо припускав 25 за кг — у початковій оцінці архіву, у перерахунку вартості й у print-планах проєктів, оцінюючи друки числом, якого ніхто не вводив, і суперечачи сам собі між шляхами: один друк міг нести дві різні суми залежно від того, який шлях записав останнім.
Якщо ціна задана, не змінюється нічого: власна ціна котушки за кг і далі б'є дефолт, а дефолт і далі покриває пластик із котушок, яких немає в інвентарі.
Це живить per-archive-ціна в архівній картці і totals на проєктах / print-plan.
Експорт¶
Хедер має кнопку "Export CSV", що скидає поточну вибірку (відфільтрований період) як CSV з одним рядком на архів — корисно для виставлення рахунків print-as-a-service або годування іншого інструменту.
Сторінка Maintenance має схожий Excel-експорт для service-інтервалів — див. Maintenance.
Опції експорту¶
| Формат | Для чого | Зміст |
|---|---|---|
| CSV | Spreadsheet-и, ad-hoc-аналіз, скрипти | Один рядок на архів: принтер, файл, статус, start time, тривалість, грами філаменту, filament details, kWh, ціни |
| Excel | Звіти з форматуванням, шерення з нетехнічними стейкхолдерами | Ті самі колонки, що CSV, плюс форматування, заморожений header, типи на колонку |
Обидва експорти поважають поточно активні фільтри — діапазон, чіпи printer-selection, per-user-фільтр. Скинь фільтри спочатку, щоб експортувати повний dataset.
Widget-based дашборд¶
Сторінка Stats — це конфігурована сітка віджетів, не фіксований звіт. Можна:
- Перетягувати будь-який віджет за хедер, щоб переставити
- Ресайзити через corner handle — цикл Small → Medium → Large → Full Width
- Ховати непотрібні віджети іконкою ока — повертати з меню Hidden у хедері дашборда
- Reset to default — кнопка в хедері повертає дефолтний layout
Layout персистнутий per-user на бекенді, тож той самий логін на іншому пристрої бачить ту ж розкладку.
Доступні віджети¶
| Віджет | Що показує |
|---|---|
| Print Success Rate | Donut-gauge зі split-ом completed / failed / Cancelled. Per-printer filterable. Див. нотатку нижче про те, як рахуються скасовані друки. |
| Filament by Type | Pie-chart розподілу матеріалів (PLA / PETG / ABS / ...). Клік по сегментах — фільтрує. |
| Print Activity Calendar | GitHub-style heatmap, кількість друків на день, клік по дню — drill в архіви того дня. |
| Print Duration Distribution | Бакетна bar-діаграма: <30m, 30m–1h, 1–2h, 2–4h, 4–8h, 8–12h, 12–24h, 24h+. Показує твою типову довжину друку. |
| Time Accuracy | Predicted-vs-actual часи друку. Per-printer середні і trend — відповідь на "чи дрейфує калібровка?" Друки, які BamDude відновив після розриву зв'язку, сюди не входять: їхній час завершення реконструйований з оцінки, тож вони дали б ідеальні 100%, яких ніхто не міряв. |
| Printer Utilization | Години активного друку на принтер; % idle-часу. |
| Recent Activity | Стрічка останніх 10 завершених друків; клік відкриває архівну картку. |
| Quick Stats | KPI-плитки (друки, філамент, час, ціна, енергія) для активного діапазону. |
Printer Selection¶
Multi-select-чіпи над віджетами scope-ять увесь дашборд на підмножину принтерів:
- Клік по чіпу — toggle цього принтера on/off
- Усі віджети одразу перерендерюються проти відфільтрованого набору
- Кнопка експорту поважає той самий фільтр
Корисно для "покажи мені тільки ряд A1 у моєму MakerSpace" або "порівняй X1C-A vs X1C-B side-by-side".
Скасовані друки мають власний bucket¶
Друки, які ти (або черга) зупинив, не рахуються як failures. Архіви stopped, cancelled і skipped падають в окремий Cancelled bucket, окремо від справжніх quality-failures (failed / aborted), тож abort друку не псує твої числа:
- Success Rate ділить на completed + failed only — скасовані друки виключені і з чисельника, і зі знаменника, тож зупинка друку ніколи не тягне gauge вниз.
- failure-rate report (і його weekly trend) використовує те саме правило — cancelled / stopped / skipped друки виключені з обох сторін ratio.
- Вони все ще рахуються в Total Prints і лишаються видимими на власному рядку Cancelled у Success Rate breakdown, тож нічого не зникає тихо.
Per-User фільтрація¶
Коли в тебе є право stats:filter_by_user (за замовчуванням лише в Administrators), у хедері stats з'являється dropdown користувача поряд з timeframe-селектором. Вибір юзера фільтрує кожен віджет, failure-analysis і CSV/Excel-експорти на друки цього користувача — корисно для університетів, makerspace-ів чи будь-якого середовища, де треба per-person accountability чи cost-tracking.
| Значення фільтра | Ефект |
|---|---|
| All Users | Default — глобальна статистика |
<конкретний юзер> |
Тільки його друки |
| No User (System) | Друки без user-атрибуції (slicer-initiated, pre-auth, virtual-printer uploads) |
Видача права
Щоб дати dropdown не-адмінам, створи custom-групу в Settings → Users і додай stats:filter_by_user. Див. Authentication.
Energy "warming-up" indicator¶
У режимі Total Consumption date-range-енергія обчислюється з hourly-snapshot-ів lifetime-лічильника кожної розетки (див. Smart Plugs). На свіжому інсталі — або одразу після upgrade — першого snapshot-а до твого діапазону може ще не існувати. Плитки Energy Used / Energy Cost показують маленьку жовту warning-іконку з tooltip-ом, що пояснює ситуацію.
Через ~1 годину runtime-у іконка зникає для будь-якого діапазону, що починається після першого snapshot-а. KPI-значення в межах warming-up-вікна обчислюється проти 0 baseline-а, що завищує на стільки, скільки розетка показувала на момент інсталу — почекай ту годину, перш ніж читати число.
Налаштування ціни¶
Cost-плитки показують числа лише, коли вхідні дані сконфігуровані.
- Settings → System — постав Currency (
USD,EUR,UAHтощо) іenergy_cost_per_kwh - Settings → Filaments / Spoolman — постав per-spool
cost+weight(або глобальнийdefault_filament_costна кг) - Stats підхопить ставки одразу; нові друки зберігають їх на архіві в момент завершення
Recalculate Costs¶
Існуючі архіви тримають ціни, активні на момент їхнього завершення — історичні дані автоматично не переписуються, коли ставки змінилися. Щоб привести все до поточних цін:
- Натисни Recalculate Costs у хедері дашборда
- У кожному архіві перераховуються філамент + енергія проти поточних spool / config-ставок
- Дашборд перерендерюється проти нових totals
Поведінка ціни на reprint
Reprint-и — additive: ціна reprint-а додається до total оригінального архіву, а не перезаписує його, тож per-archive total відображає cumulative-витрати по всіх runs цього файла. Це значить, що числа stats трекають реально витрачені гроші, а не "скільки оригінал коштував би сьогодні".
Auto-refresh¶
Сторінка Stats полить кожні 60 с, тож дашборди, залишені відкритими під час print-сесії, лишаються свіжими без manual reload. Іконка refresh у хедері форсить негайний refetch — корисно одразу після того, як довгий друк завершився, якщо не хочеш чекати наступний tick.
Mutation-и з інших частин додатку (видалення архіву, recalculate costs, редагування ціни філаменту) автоматично інвалідують underlying queries — клікати refresh після них не треба.
API¶
Усе, що читає ця сторінка, живе під /api/v1/statistics/:
| Endpoint | Що віддає |
|---|---|
GET /statistics/overview |
KPI-блок: лічильники, години, грами, вартість, енергія, точність оцінки по принтерах і брак (date_from, date_to, created_by_id) |
GET /statistics/aggregate |
Часові серії, розбивки й рекорди, які згортають графіки й календар архівів |
GET /statistics/failures |
Аналіз збоїв — див. Failure analysis |
GET /statistics/export |
Підсумок аналізу збоїв у CSV, або ?format=xlsx — див. Export |
POST /statistics/recalculate-costs |
Перерахувати вартість філаменту всіх архівів за поточними цінами |
Раніші релізи відповідали під /api/v1/archives/… (/archives/stats, /archives/aggregate, /archives/analysis/failures, /archives/stats/export, /archives/recalculate-costs). Ці шляхи зникли, без редиректів. /api/v1/statistics/reports зарезервовано під звіти, які будуватимуться тут.