{"id":10270,"date":"2026-08-15T01:00:11","date_gmt":"2026-08-14T23:00:11","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/narzedzia\/frigate-coral-tpu-capacity-planner\/"},"modified":"2026-08-15T01:00:11","modified_gmt":"2026-08-14T23:00:11","slug":"frigate-coral-tpu-capacity-planner","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/","title":{"rendered":"Planer wydajno\u015bci Frigate i Coral TPU"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">Coral TPU wykonuje sta\u0142\u0105 liczb\u0119 inferencji na sekund\u0119. Ka\u017cda kamera zabiera swoj\u0105 cz\u0119\u015b\u0107 przez liczb\u0119 klatek detekcji, a gdy suma przekroczy bud\u017cet, detekcja zaczyna si\u0119 sp\u00f3\u017ania\u0107 &#8211; nigdy g\u0142o\u015bno, po prostu za p\u00f3\u017ano. Ten planer liczy to wcze\u015bniej.<\/p>\n<div style=\"display: flex; gap: 12px; flex-wrap: wrap;\">\n<div style=\"flex: 1; min-width: 200px;\">\n            <label for=\"fg-detektor\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Detektor<\/label><br \/>\n            <select id=\"fg-detektor\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\"><option value=\"7\">Coral M.2 albo PCIe (oko\u0142o 7 ms)<\/option><option value=\"10\" selected>Coral USB (oko\u0142o 10 ms)<\/option><option value=\"100\">CPU bez akceleratora (oko\u0142o 100 ms)<\/option><\/select>\n        <\/div>\n<div style=\"flex: 1; min-width: 150px;\">\n            <label for=\"fg-anzahl\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Liczba detektor\u00f3w<\/label><br \/>\n            <input type=\"text\" id=\"fg-anzahl\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\" value=\"1\">\n        <\/div>\n<div style=\"flex: 1; min-width: 150px;\">\n            <label for=\"fg-inferenz\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Czas inferencji (ms)<\/label><br \/>\n            <input type=\"text\" id=\"fg-inferenz\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\" value=\"10\">\n        <\/div>\n<div style=\"flex: 1; min-width: 150px;\">\n            <label for=\"fg-bewegung\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Udzia\u0142 czasu z ruchem (%)<\/label><br \/>\n            <input type=\"text\" id=\"fg-bewegung\" class=\"form-control\" style=\"width: 100%; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; box-sizing: border-box;\" value=\"20\">\n        <\/div>\n<\/p><\/div>\n<div style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.85rem; margin: 18px 0 8px;\">Kamery i ich strumie\u0144 detekcji<\/div>\n<div id=\"fg-liste\" style=\"margin-bottom: 12px;\"><\/div>\n<div style=\"display: flex; gap: 10px; flex-wrap: wrap;\">\n        <button id=\"fg-add\" class=\"button\" type=\"button\" style=\"background: transparent; color: var(--text-primary, #e8e8ee); border: 1px solid var(--border, #2a2a35); padding: 10px 18px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Dodaj kamer\u0119<\/button><br \/>\n        <button id=\"fg-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: #0b1114; border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Zaplanuj wydajno\u015b\u0107<\/button>\n    <\/div>\n<div id=\"fg-ergebnis\" style=\"margin-top: 22px;\"><\/div>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Coral TPU wykonuje sta\u0142\u0105 liczb\u0119 inferencji na sekund\u0119. Ka\u017cda kamera zabiera swoj\u0105 cz\u0119\u015b\u0107 przez liczb\u0119 klatek detekcji, a gdy suma przekroczy bud\u017cet, detekcja zaczyna si\u0119 sp\u00f3\u017ania\u0107 - nigdy g\u0142o\u015bno, po prostu za p\u00f3\u017ano. Ten planer liczy to wcze\u015bniej.\",\"label_detektor\":\"Detektor\",\"detektor_m2\":\"Coral M.2 albo PCIe (oko\u0142o 7 ms)\",\"detektor_usb\":\"Coral USB (oko\u0142o 10 ms)\",\"detektor_cpu\":\"CPU bez akceleratora (oko\u0142o 100 ms)\",\"label_anzahl\":\"Liczba detektor\u00f3w\",\"label_inferenz\":\"Czas inferencji (ms)\",\"label_bewegung\":\"Udzia\u0142 czasu z ruchem (%)\",\"label_kameras\":\"Kamery i ich strumie\u0144 detekcji\",\"ph_name\":\"Nazwa kamery\",\"knopf\":\"Zaplanuj wydajno\u015b\u0107\",\"knopf_kamera\":\"Dodaj kamer\u0119\",\"knopf_weg\":\"Usu\u0144\",\"fehler_inferenz\":\"Czas inferencji musi by\u0107 liczb\u0105 wi\u0119ksz\u0105 od zera.\",\"fehler_anzahl\":\"Musi by\u0107 co najmniej jeden detektor.\",\"fehler_bewegung\":\"Udzia\u0142 musi mie\u015bci\u0107 si\u0119 mi\u0119dzy 0 a 100.\",\"fehler_fps\":\"Liczba klatek detekcji kamery %s nie jest liczb\u0105 wi\u0119ksz\u0105 od zera.\",\"fehler_aufloesung\":\"Nie uda\u0142o si\u0119 odczyta\u0107 rozdzielczo\u015bci kamery %s.\",\"fehler_keine_kamera\":\"Nie wpisano \u017cadnej kamery.\",\"h_auslastung\":\"Obci\u0105\u017cenie\",\"h_kameras\":\"Udzia\u0142 poszczeg\u00f3lnych kamer\",\"h_befunde\":\"Ustalenia\",\"h_yaml\":\"Szkielet pliku frigate.yml\",\"einheit_inferenzen\":\"inferencji na sekund\u0119\",\"z_kapazitaet\":\"Wydajno\u015b\u0107 detektor\u00f3w\",\"z_bedarf\":\"Zapotrzebowanie, gdy zg\u0142aszaj\u0105 wszystkie kamery naraz\",\"z_auslastung\":\"Obci\u0105\u017cenie w tym przypadku\",\"z_bedarf_echt\":\"Zapotrzebowanie przy podanym udziale ruchu\",\"z_auslastung_echt\":\"Obci\u0105\u017cenie w tym przypadku\",\"z_noetig\":\"Detektory potrzebne w najgorszym przypadku\",\"b_ueberlastet\":\"Przy %s procentach bud\u017cet jest przekroczony. Potrzeba %n detektor\u00f3w albo mniej klatek na sekund\u0119.\",\"b_knapp\":\"%s procent nie zostawia zapasu. Jedno zdarzenie na wszystkich kamerach wystarczy, aby detekcja zacz\u0119\u0142a si\u0119 sp\u00f3\u017ania\u0107.\",\"b_reicht\":\"%s procent obci\u0105\u017cenia: bud\u017cet ud\u017awignie nawet sytuacj\u0119, w kt\u00f3rej wszystkie kamery zg\u0142osz\u0105 ruch naraz.\",\"b_bewegung\":\"Przy podanym udziale ruchu codzienne obci\u0105\u017cenie wynosi oko\u0142o %s procent. To liczba, kt\u00f3r\u0105 pokazuje panel, a nie ta, wed\u0142ug kt\u00f3rej si\u0119 planuje.\",\"b_fps\":\"Wi\u0119cej ni\u017c pi\u0119\u0107 klatek detekcji na sekund\u0119 rzadko co\u015b daje: %s. Osoba przechodz\u0105ca przez kadr zostaje uchwycona przy pi\u0119ciu, a ka\u017cda kolejna klatka kosztuje bud\u017cet inferencji.\",\"b_aufloesung\":\"Strumie\u0144 detekcji powy\u017cej 1280x720 kosztuje CPU przy dekodowaniu, nie pomagaj\u0105c detekcji: %s. Model i tak skaluje ka\u017cd\u0105 klatk\u0119 do w\u0142asnego rozmiaru wej\u015bcia, czas inferencji pozostaje ten sam.\",\"b_modell\":\"Czas inferencji nie zale\u017cy od rozdzielczo\u015bci detekcji, tylko od modelu. Wi\u0119kszy obraz kosztuje dekodowanie, a nie TPU.\",\"b_cpu\":\"Bez akceleratora ka\u017cda inferencja trwa dziesi\u0119\u0107 razy d\u0142u\u017cej, a garstka kamer wystarczy, aby obci\u0105\u017cy\u0107 maszyn\u0119.\",\"b_mehrere\":\"Frigate sam rozdziela kamery na detektory, r\u0119czne przypisanie nie jest potrzebne.\",\"b_substrom\":\"Strumie\u0144 detekcji nale\u017cy do substrumienia kamery. Detekcja na strumieniu nagrywania marnuje moc dekodowania na ka\u017cd\u0105 pojedyncz\u0105 klatk\u0119.\"};<\/p>\n<p>    \/\/ --- reine Rechenlogik ---<\/p>\n<p>    function zahl(wert) {\n        const roh = String(wert === undefined || wert === null ? '' : wert).trim().replace(',', '.');\n        if (roh === '') { return NaN; }\n        if (!\/^[0-9]+(\\.[0-9]+)?$\/.test(roh)) { return NaN; }\n        return parseFloat(roh);\n    }<\/p>\n<p>    function runde(wert, stellen) {\n        const faktor = Math.pow(10, stellen === undefined ? 0 : stellen);\n        return Math.round(wert * faktor) \/ faktor;\n    }<\/p>\n<p>    function kennung(name) {\n        return String(name).toLowerCase()\n            .replace(\/[\u00e4\u00e0\u00e1\u00e2]\/g, 'a').replace(\/[\u00f6\u00f2\u00f3\u00f4]\/g, 'o').replace(\/[\u00fc\u00f9\u00fa\u00fb]\/g, 'u')\n            .replace(\/\u00df\/g, 'ss').replace(\/[^a-z0-9]+\/g, '_').replace(\/^_+|_+$\/g, '');\n    }<\/p>\n<p>    function planen(e) {\n        const ergebnis = { ok: false, fehler: '', kameras: [], befunde: [], yaml: '' };\n        const eingabe = e || {};<\/p>\n<p>        const inferenz = zahl(eingabe.inferenz);\n        const anzahl = zahl(eingabe.anzahl);\n        const bewegung = zahl(eingabe.bewegung);<\/p>\n<p>        if (!isFinite(inferenz) || inferenz <= 0) { ergebnis.fehler = T.fehler_inferenz; return ergebnis; }\n        if (!isFinite(anzahl) || anzahl < 1) { ergebnis.fehler = T.fehler_anzahl; return ergebnis; }\n        if (!isFinite(bewegung) || bewegung < 0 || bewegung > 100) { ergebnis.fehler = T.fehler_bewegung; return ergebnis; }<\/p>\n<p>        const roh = Array.isArray(eingabe.kameras) ? eingabe.kameras : [];\n        const kameras = [];\n        for (let i = 0; i < roh.length; i++) {\n            const name = String(roh[i].name === undefined ? '' : roh[i].name).trim();\n            if (name === '') { continue; }\n            const fps = zahl(roh[i].fps);\n            if (!isFinite(fps) || fps <= 0) {\n                ergebnis.fehler = T.fehler_fps.replace('%s', name);\n                return ergebnis;\n            }\n            const teile = String(roh[i].aufloesung || '1280x720').split('x');\n            const breite = parseInt(teile[0], 10);\n            const hoehe = parseInt(teile[1], 10);\n            if (!isFinite(breite) || !isFinite(hoehe)) {\n                ergebnis.fehler = T.fehler_aufloesung.replace('%s', name);\n                return ergebnis;\n            }\n            kameras.push({ name: name, kennung: kennung(name) || 'kamera_' + (i + 1), fps: fps, breite: breite, hoehe: hoehe });\n        }\n\n        if (!kameras.length) { ergebnis.fehler = T.fehler_keine_kamera; return ergebnis; }\n\n        const kapazitaet = (1000 \/ inferenz) * anzahl;\n        const bedarfVoll = kameras.reduce(function (summe, k) { return summe + k.fps; }, 0);\n        const bedarfEcht = bedarfVoll * (bewegung \/ 100);\n\n        ergebnis.kapazitaet = runde(kapazitaet, 1);\n        ergebnis.bedarfVoll = runde(bedarfVoll, 1);\n        ergebnis.bedarfEcht = runde(bedarfEcht, 1);\n        ergebnis.auslastungVoll = runde(bedarfVoll \/ kapazitaet * 100, 1);\n        ergebnis.auslastungEcht = runde(bedarfEcht \/ kapazitaet * 100, 1);\n        ergebnis.noetig = Math.ceil(bedarfVoll \/ (1000 \/ inferenz));\n        ergebnis.kameras = kameras.map(function (k) {\n            return {\n                name: k.name,\n                kennung: k.kennung,\n                fps: k.fps,\n                aufloesung: k.breite + 'x' + k.hoehe,\n                anteil: runde(k.fps \/ bedarfVoll * 100, 1),\n                pixel: k.breite * k.hoehe\n            };\n        });\n\n        \/\/ --- Befunde ---\n        if (ergebnis.auslastungVoll > 100) {\n            ergebnis.befunde.push({ schwer: true, text: T.b_ueberlastet.replace('%s', String(ergebnis.auslastungVoll)).replace('%n', String(ergebnis.noetig)) });\n        } else if (ergebnis.auslastungVoll > 80) {\n            ergebnis.befunde.push({ schwer: true, text: T.b_knapp.replace('%s', String(ergebnis.auslastungVoll)) });\n        } else {\n            ergebnis.befunde.push({ schwer: false, text: T.b_reicht.replace('%s', String(ergebnis.auslastungVoll)) });\n        }\n        ergebnis.befunde.push({ schwer: false, text: T.b_bewegung.replace('%s', String(ergebnis.auslastungEcht)) });<\/p>\n<p>        const schnelle = kameras.filter(function (k) { return k.fps > 5; });\n        if (schnelle.length) {\n            ergebnis.befunde.push({ schwer: true, text: T.b_fps.replace('%s', schnelle.map(function (k) { return k.name; }).join(', ')) });\n        }\n        const grosse = kameras.filter(function (k) { return k.breite > 1280; });\n        if (grosse.length) {\n            ergebnis.befunde.push({ schwer: true, text: T.b_aufloesung.replace('%s', grosse.map(function (k) { return k.name; }).join(', ')) });\n        }\n        ergebnis.befunde.push({ schwer: false, text: T.b_modell });\n        if (inferenz >= 50) {\n            ergebnis.befunde.push({ schwer: true, text: T.b_cpu });\n        }\n        if (anzahl > 1) {\n            ergebnis.befunde.push({ schwer: false, text: T.b_mehrere });\n        }\n        ergebnis.befunde.push({ schwer: false, text: T.b_substrom });<\/p>\n<p>        \/\/ --- Ger\u00fcst f\u00fcr die Konfiguration ---\n        const zeilen = [];\n        zeilen.push('detectors:');\n        for (let i = 0; i < anzahl; i++) {\n            zeilen.push('  coral' + i + ':');\n            zeilen.push('    type: edgetpu');\n            zeilen.push('    device: ' + (inferenz >= 50 ? 'cpu' : (i === 0 ? 'usb' : 'usb:' + i)));\n        }\n        zeilen.push('');\n        zeilen.push('cameras:');\n        kameras.forEach(function (k) {\n            zeilen.push('  ' + k.kennung + ':');\n            zeilen.push('    ffmpeg:');\n            zeilen.push('      inputs:');\n            zeilen.push('        - path: rtsp:\/\/benutzer:geheim@192.168.1.50:554\/stream2');\n            zeilen.push('          roles: [detect]');\n            zeilen.push('        - path: rtsp:\/\/benutzer:geheim@192.168.1.50:554\/stream1');\n            zeilen.push('          roles: [record]');\n            zeilen.push('    detect:');\n            zeilen.push('      width: ' + k.breite);\n            zeilen.push('      height: ' + k.hoehe);\n            zeilen.push('      fps: ' + k.fps);\n            zeilen.push('    objects:');\n            zeilen.push('      track: [person, car]');\n            zeilen.push('');\n        });\n        ergebnis.yaml = zeilen.join('\\n');<\/p>\n<p>        ergebnis.ok = true;\n        return ergebnis;\n    }<\/p>\n<p>    if (typeof window !== 'undefined') {\n        window.LW_TEST = window.LW_TEST || {};\n        window.LW_TEST.FG = { planen: planen, zahl: zahl, kennung: kennung };\n    }<\/p>\n<p>    \/\/ --- Anbindung an das Dokument ---<\/p>\n<p>    const btn = document.getElementById('fg-btn');\n    const out = document.getElementById('fg-ergebnis');\n    const liste = document.getElementById('fg-liste');\n    const addBtn = document.getElementById('fg-add');\n    if (!btn || !out || !liste || !addBtn) { return; }<\/p>\n<p>    const KASTEN = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 6px; padding: 14px; margin-bottom: 18px;';\n    const UEBERSCHRIFT = 'color: var(--text-primary, #e8e8ee); font-weight: 700; margin-bottom: 8px;';\n    const FELD = 'padding: 10px; background: var(--bg-panel, #1e1e24); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace;';<\/p>\n<p>    function el(tag, css, inhalt) {\n        const knoten = document.createElement(tag);\n        if (css) { knoten.setAttribute('style', css); }\n        if (inhalt !== undefined && inhalt !== null) { knoten.textContent = inhalt; }\n        return knoten;\n    }<\/p>\n<p>    function wert(id) {\n        const knoten = document.getElementById(id);\n        return knoten ? knoten.value : '';\n    }<\/p>\n<p>    let zaehler = 0;\n    function zeileErzeugen(vorgabe) {\n        const v = vorgabe || {};\n        zaehler++;\n        const zeile = el('div', 'display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-bottom: 8px;');\n        zeile.setAttribute('data-fg', 'zeile');<\/p>\n<p>        const name = document.createElement('input');\n        name.type = 'text';\n        name.id = 'fg-name-' + zaehler;\n        name.setAttribute('style', FELD + ' flex: 2; min-width: 150px;');\n        name.setAttribute('data-fg', 'name');\n        name.placeholder = T.ph_name;\n        name.value = v.name || '';\n        zeile.appendChild(name);<\/p>\n<p>        const aufloesung = document.createElement('select');\n        aufloesung.id = 'fg-res-' + zaehler;\n        aufloesung.setAttribute('style', FELD + ' min-width: 150px;');\n        aufloesung.setAttribute('data-fg', 'aufloesung');\n        ['640x360', '1280x720', '1920x1080', '2560x1440'].forEach(function (r) {\n            const option = document.createElement('option');\n            option.value = r;\n            option.textContent = r;\n            aufloesung.appendChild(option);\n        });\n        aufloesung.value = v.aufloesung || '1280x720';\n        zeile.appendChild(aufloesung);<\/p>\n<p>        const fps = document.createElement('input');\n        fps.type = 'text';\n        fps.id = 'fg-fps-' + zaehler;\n        fps.setAttribute('style', FELD + ' width: 90px;');\n        fps.setAttribute('data-fg', 'fps');\n        fps.placeholder = 'fps';\n        fps.value = v.fps || '5';\n        zeile.appendChild(fps);<\/p>\n<p>        const weg = el('button', 'background: transparent; color: var(--text-secondary, #a0a0b0); border: 1px solid var(--border, #2a2a35); padding: 10px 14px; border-radius: 6px; cursor: pointer;', T.knopf_weg);\n        weg.type = 'button';\n        weg.addEventListener('click', function () {\n            if (zeile.parentNode) { zeile.parentNode.removeChild(zeile); }\n            if (!liste.querySelector('[data-fg=\"zeile\"]')) { zeileErzeugen({}); }\n        });\n        zeile.appendChild(weg);<\/p>\n<p>        liste.appendChild(zeile);\n    }<\/p>\n<p>    function kamerasLesen() {\n        const knoten = liste.querySelectorAll('[data-fg=\"zeile\"]');\n        const daten = [];\n        for (let i = 0; i < knoten.length; i++) {\n            const name = knoten[i].querySelector('[data-fg=\"name\"]');\n            const aufloesung = knoten[i].querySelector('[data-fg=\"aufloesung\"]');\n            const fps = knoten[i].querySelector('[data-fg=\"fps\"]');\n            if (!name || !aufloesung || !fps) { continue; }\n            daten.push({ name: name.value, aufloesung: aufloesung.value, fps: fps.value });\n        }\n        return daten;\n    }\n\n    function zeile(kasten, name, inhalt, hervor) {\n        const z = el('div', 'display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap; padding: 5px 0;');\n        z.appendChild(el('span', 'color: var(--text-secondary, #a0a0b0);', name));\n        z.appendChild(el('span', 'color: ' + (hervor ? '#ffb86c' : 'var(--text-primary, #e8e8ee)') + '; font-family: monospace;', inhalt));\n        kasten.appendChild(z);\n    }\n\n    addBtn.addEventListener('click', function () { zeileErzeugen({}); });\n\n    btn.addEventListener('click', function () {\n        const erg = planen({\n            inferenz: wert('fg-inferenz'),\n            anzahl: wert('fg-anzahl'),\n            bewegung: wert('fg-bewegung'),\n            kameras: kamerasLesen()\n        });\n\n        out.textContent = '';\n        if (!erg.ok) {\n            out.appendChild(el('div', 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-left: 3px solid #ffb86c; color: var(--text-secondary, #a0a0b0); padding: 14px; border-radius: 6px;', erg.fehler));\n            return;\n        }\n\n        out.appendChild(el('div', UEBERSCHRIFT, T.h_auslastung));\n        const kasten = el('div', KASTEN);\n        zeile(kasten, T.z_kapazitaet, erg.kapazitaet + ' ' + T.einheit_inferenzen);\n        zeile(kasten, T.z_bedarf, erg.bedarfVoll + ' ' + T.einheit_inferenzen);\n        zeile(kasten, T.z_auslastung, erg.auslastungVoll + ' %', erg.auslastungVoll > 80);\n        zeile(kasten, T.z_bedarf_echt, erg.bedarfEcht + ' ' + T.einheit_inferenzen);\n        zeile(kasten, T.z_auslastung_echt, erg.auslastungEcht + ' %', erg.auslastungEcht > 80);\n        zeile(kasten, T.z_noetig, String(erg.noetig), erg.noetig > 1);\n        out.appendChild(kasten);<\/p>\n<p>        out.appendChild(el('div', UEBERSCHRIFT, T.h_kameras));\n        const tabelle = el('div', KASTEN);\n        erg.kameras.forEach(function (k) {\n            const z = el('div', 'display: flex; gap: 12px; align-items: center; padding: 6px 0; border-bottom: 1px solid var(--border, #2a2a35);');\n            z.appendChild(el('span', 'flex: 2; color: var(--text-primary, #e8e8ee);', k.name));\n            z.appendChild(el('span', 'width: 110px; color: var(--text-secondary, #a0a0b0); font-family: monospace; font-size: 0.85rem;', k.aufloesung));\n            z.appendChild(el('span', 'width: 70px; color: var(--text-secondary, #a0a0b0); font-family: monospace; font-size: 0.85rem;', k.fps + ' fps'));\n            z.appendChild(el('span', 'width: 70px; color: var(--text-primary, #e8e8ee); font-family: monospace; font-size: 0.85rem;', k.anteil + ' %'));\n            tabelle.appendChild(z);\n        });\n        out.appendChild(tabelle);<\/p>\n<p>        out.appendChild(el('div', UEBERSCHRIFT, T.h_befunde));\n        const befunde = el('div', KASTEN);\n        erg.befunde.forEach(function (b) {\n            const z = el('div', 'display: flex; gap: 10px; padding: 5px 0;');\n            z.appendChild(el('span', 'color: ' + (b.schwer ? '#ffb86c' : 'var(--text-secondary, #a0a0b0)') + '; font-family: monospace;', b.schwer ? '!' : '-'));\n            z.appendChild(el('span', 'color: var(--text-secondary, #a0a0b0); font-size: 0.9rem; line-height: 1.5;', b.text));\n            befunde.appendChild(z);\n        });\n        out.appendChild(befunde);<\/p>\n<p>        out.appendChild(el('div', UEBERSCHRIFT, T.h_yaml));\n        out.appendChild(el('pre', 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); padding: 16px; border-radius: 6px; overflow-x: auto; font-family: monospace; font-size: 0.8rem; line-height: 1.5; white-space: pre; margin-bottom: 18px;', erg.yaml));\n    });<\/p>\n<p>    zeileErzeugen({ name: 'Einfahrt', aufloesung: '1280x720', fps: '5' });\n    zeileErzeugen({ name: 'Haustuer', aufloesung: '1280x720', fps: '5' });\n    zeileErzeugen({ name: 'Garten', aufloesung: '640x360', fps: '5' });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sumuje obci\u0105\u017cenie detekcj\u0105 ze wszystkich kamer, zestawia je z wydajno\u015bci\u0105 Coral TPU i tworzy pasuj\u0105cy szkielet frigate.yml.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9284,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92460,92232,92223],"class_list":["post-10270","page","type-page","status-publish","hentry","tag-monitoring-cctv-pl-pl","tag-docker-pl","tag-raspberry-pi-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Planer wydajno\u015bci Frigate i Coral TPU - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Planer wydajno\u015bci Frigate i Coral TPU - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Sumuje obci\u0105\u017cenie detekcj\u0105 ze wszystkich kamer, zestawia je z wydajno\u015bci\u0105 Coral TPU i tworzy pasuj\u0105cy szkielet frigate.yml.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/frigate-coral-tpu-capacity-planner\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/frigate-coral-tpu-capacity-planner\\\/\",\"name\":\"Planer wydajno\u015bci Frigate i Coral TPU - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-08-14T23:00:11+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/frigate-coral-tpu-capacity-planner\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/frigate-coral-tpu-capacity-planner\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/frigate-coral-tpu-capacity-planner\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/toolbox-3\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Planer wydajno\u015bci Frigate i Coral TPU\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Planer wydajno\u015bci Frigate i Coral TPU - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/","og_locale":"en_US","og_type":"article","og_title":"Planer wydajno\u015bci Frigate i Coral TPU - Lukas Wojcik - Blog","og_description":"Sumuje obci\u0105\u017cenie detekcj\u0105 ze wszystkich kamer, zestawia je z wydajno\u015bci\u0105 Coral TPU i tworzy pasuj\u0105cy szkielet frigate.yml.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/","og_site_name":"Lukas Wojcik - Blog","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/","name":"Planer wydajno\u015bci Frigate i Coral TPU - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-08-14T23:00:11+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/frigate-coral-tpu-capacity-planner\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/toolbox-3\/"},{"@type":"ListItem","position":3,"name":"Planer wydajno\u015bci Frigate i Coral TPU"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/10270","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=10270"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/10270\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9284"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=10270"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=10270"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}