From 64efd542751566a71811e2b9a01521c420cfd669 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 May 2024 06:39:13 +0000 Subject: [PATCH] Deployed aa87db6 with MkDocs version: 1.5.3 --- .nojekyll | 0 404.html | 850 +++ assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.5cf534bf.min.js | 29 + assets/javascripts/bundle.5cf534bf.min.js.map | 8 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.12658920.min.js | 42 + .../workers/search.12658920.min.js.map | 8 + assets/stylesheets/main.f56500e0.min.css | 1 + assets/stylesheets/main.f56500e0.min.css.map | 1 + assets/stylesheets/palette.2505c338.min.css | 1 + .../stylesheets/palette.2505c338.min.css.map | 1 + config.for.camera.csi.legacy/index.html | 1006 +++ config.for.camera.csi.libcamera/index.html | 1009 +++ config.for.camera.esphome.snapshot/index.html | 1053 +++ config.for.camera.esphome.stream/index.html | 1056 +++ config.for.camera.mjpg/index.html | 1024 +++ config.for.camera.rtsp/index.html | 1052 +++ config.for.camera.snapshot/index.html | 1088 +++ config.for.camera.usb/index.html | 1061 +++ config.for.camera/index.html | 1139 +++ configuration.env.full/index.html | 1026 +++ configuration.env/index.html | 994 +++ configuration.overview/index.html | 948 +++ configuration.tuning/index.html | 1254 +++ css/extra.css | 3 + index.html | 507 ++ installation/index.html | 953 +++ performance/index.html | 953 +++ prusa.connect/index.html | 945 +++ requirements/index.html | 1067 +++ search/search_index.json | 1 + service.docker/index.html | 1137 +++ service.systemd/index.html | 1075 +++ service/index.html | 943 +++ sitemap.xml | 123 + sitemap.xml.gz | Bin 0 -> 419 bytes static/esp32-camera.jpg | Bin 0 -> 80717 bytes static/pi-camera.jpg | Bin 0 -> 16523 bytes static/prusa-connect-cam-small.png | Bin 0 -> 7327 bytes static/prusa-connect-cam.png | Bin 0 -> 11494 bytes static/usb_cam.png | Bin 0 -> 63884 bytes stream.mediamtx/index.html | 1021 +++ test.config/index.html | 962 +++ troubleshooting/index.html | 1182 +++ 72 files changed, 32718 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.5cf534bf.min.js create mode 100644 assets/javascripts/bundle.5cf534bf.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.12658920.min.js create mode 100644 assets/javascripts/workers/search.12658920.min.js.map create mode 100644 assets/stylesheets/main.f56500e0.min.css create mode 100644 assets/stylesheets/main.f56500e0.min.css.map create mode 100644 assets/stylesheets/palette.2505c338.min.css create mode 100644 assets/stylesheets/palette.2505c338.min.css.map create mode 100644 config.for.camera.csi.legacy/index.html create mode 100644 config.for.camera.csi.libcamera/index.html create mode 100644 config.for.camera.esphome.snapshot/index.html create mode 100644 config.for.camera.esphome.stream/index.html create mode 100644 config.for.camera.mjpg/index.html create mode 100644 config.for.camera.rtsp/index.html create mode 100644 config.for.camera.snapshot/index.html create mode 100644 config.for.camera.usb/index.html create mode 100644 config.for.camera/index.html create mode 100644 configuration.env.full/index.html create mode 100644 configuration.env/index.html create mode 100644 configuration.overview/index.html create mode 100644 configuration.tuning/index.html create mode 100644 css/extra.css create mode 100644 index.html create mode 100644 installation/index.html create mode 100644 performance/index.html create mode 100644 prusa.connect/index.html create mode 100644 requirements/index.html create mode 100644 search/search_index.json create mode 100644 service.docker/index.html create mode 100644 service.systemd/index.html create mode 100644 service/index.html create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz create mode 100644 static/esp32-camera.jpg create mode 100644 static/pi-camera.jpg create mode 100644 static/prusa-connect-cam-small.png create mode 100644 static/prusa-connect-cam.png create mode 100644 static/usb_cam.png create mode 100644 stream.mediamtx/index.html create mode 100644 test.config/index.html create mode 100644 troubleshooting/index.html diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..95a2f33 --- /dev/null +++ b/404.html @@ -0,0 +1,850 @@ + + + + + + + + + + + + + + + + + + Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c GIT binary patch literal 1870 zcmV-U2eJ5xP)Gc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.5cf534bf.min.js b/assets/javascripts/bundle.5cf534bf.min.js new file mode 100644 index 0000000..eb0280e --- /dev/null +++ b/assets/javascripts/bundle.5cf534bf.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Hi=Object.create;var xr=Object.defineProperty;var Pi=Object.getOwnPropertyDescriptor;var $i=Object.getOwnPropertyNames,kt=Object.getOwnPropertySymbols,Ii=Object.getPrototypeOf,Er=Object.prototype.hasOwnProperty,an=Object.prototype.propertyIsEnumerable;var on=(e,t,r)=>t in e?xr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))Er.call(t,r)&&on(e,r,t[r]);if(kt)for(var r of kt(t))an.call(t,r)&&on(e,r,t[r]);return e};var sn=(e,t)=>{var r={};for(var n in e)Er.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&kt)for(var n of kt(e))t.indexOf(n)<0&&an.call(e,n)&&(r[n]=e[n]);return r};var Ht=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ji=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $i(t))!Er.call(e,o)&&o!==r&&xr(e,o,{get:()=>t[o],enumerable:!(n=Pi(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Hi(Ii(e)):{},ji(t||!e||!e.__esModule?xr(r,"default",{value:e,enumerable:!0}):r,e));var fn=Ht((wr,cn)=>{(function(e,t){typeof wr=="object"&&typeof cn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(wr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Ne=O.type,Ue=O.tagName;return!!(Ue==="INPUT"&&a[Ne]&&!O.readOnly||Ue==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(s(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){s(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){s(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),B())}function B(){document.addEventListener("mousemove",V),document.addEventListener("mousedown",V),document.addEventListener("mouseup",V),document.addEventListener("pointermove",V),document.addEventListener("pointerdown",V),document.addEventListener("pointerup",V),document.addEventListener("touchmove",V),document.addEventListener("touchstart",V),document.addEventListener("touchend",V)}function re(){document.removeEventListener("mousemove",V),document.removeEventListener("mousedown",V),document.removeEventListener("mouseup",V),document.removeEventListener("pointermove",V),document.removeEventListener("pointerdown",V),document.removeEventListener("pointerup",V),document.removeEventListener("touchmove",V),document.removeEventListener("touchstart",V),document.removeEventListener("touchend",V)}function V(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,re())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),B(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var un=Ht(Sr=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},a=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(re,V){d.append(V,re)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,B=!0,re=this;["append","delete","set"].forEach(function(O){var Ne=h[O];h[O]=function(){Ne.apply(h,arguments),v&&(B=!1,re.search=h.toString(),B=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var V=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==V&&(V=this.search,B&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},a=i.prototype,s=function(f){Object.defineProperty(a,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){s(f)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr)});var Qr=Ht((Lt,Kr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Lt=="object"&&typeof Kr=="object"?Kr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Lt=="object"?Lt.ClipboardJS=r():t.ClipboardJS=r()})(Lt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return ki}});var a=i(279),s=i.n(a),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(F){try{return document.execCommand(F)}catch(T){return!1}}var d=function(T){var w=p()(T);return m("cut"),w},h=d;function v(F){var T=document.documentElement.getAttribute("dir")==="rtl",w=document.createElement("textarea");w.style.fontSize="12pt",w.style.border="0",w.style.padding="0",w.style.margin="0",w.style.position="absolute",w.style[T?"right":"left"]="-9999px";var k=window.pageYOffset||document.documentElement.scrollTop;return w.style.top="".concat(k,"px"),w.setAttribute("readonly",""),w.value=F,w}var B=function(T,w){var k=v(T);w.container.appendChild(k);var j=p()(k);return m("copy"),k.remove(),j},re=function(T){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},k="";return typeof T=="string"?k=B(T,w):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?k=B(T.value,w):(k=p()(T),m("copy")),k},V=re;function O(F){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(w){return typeof w}:O=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},O(F)}var Ne=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},w=T.action,k=w===void 0?"copy":w,j=T.container,N=T.target,Me=T.text;if(k!=="copy"&&k!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(N!==void 0)if(N&&O(N)==="object"&&N.nodeType===1){if(k==="copy"&&N.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(k==="cut"&&(N.hasAttribute("readonly")||N.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return V(Me,{container:j});if(N)return k==="cut"?h(N):V(N,{container:j})},Ue=Ne;function $e(F){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(w){return typeof w}:$e=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},$e(F)}function Oi(F,T){if(!(F instanceof T))throw new TypeError("Cannot call a class as a function")}function nn(F,T){for(var w=0;w0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof j.action=="function"?j.action:this.defaultAction,this.target=typeof j.target=="function"?j.target:this.defaultTarget,this.text=typeof j.text=="function"?j.text:this.defaultText,this.container=$e(j.container)==="object"?j.container:document.body}},{key:"listenClick",value:function(j){var N=this;this.listener=c()(j,"click",function(Me){return N.onClick(Me)})}},{key:"onClick",value:function(j){var N=j.delegateTarget||j.currentTarget,Me=this.action(N)||"copy",Rt=Ue({action:Me,container:this.container,target:this.target(N),text:this.text(N)});this.emit(Rt?"success":"error",{action:Me,text:Rt,trigger:N,clearSelection:function(){N&&N.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(j){return yr("action",j)}},{key:"defaultTarget",value:function(j){var N=yr("target",j);if(N)return document.querySelector(N)}},{key:"defaultText",value:function(j){return yr("text",j)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(j){var N=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return V(j,N)}},{key:"cut",value:function(j){return h(j)}},{key:"isSupported",value:function(){var j=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],N=typeof j=="string"?[j]:j,Me=!!document.queryCommandSupported;return N.forEach(function(Rt){Me=Me&&!!document.queryCommandSupported(Rt)}),Me}}]),w}(s()),ki=Ri},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,f){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(f))return s;s=s.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function s(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?s.apply(null,arguments):typeof m=="function"?s.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return s(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),s=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(m))return c(m,d,h);if(a.nodeList(m))return u(m,d,h);if(a.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return s(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),a=f.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,s){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var f=this;function c(){f.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=s.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var is=/["'&<>]/;Jo.exports=as;function as(e){var t=""+e,r=is.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],a;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(s){a={error:s}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(a)throw a.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||s(m,d)})})}function s(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof Xe?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){s("next",m)}function u(m){s("throw",m)}function p(m,d){m(d),i.shift(),i.length&&s(i[0][0],i[0][1])}}function mn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof xe=="function"?xe(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(a){return new Promise(function(s,f){a=e[i](a),o(s,f,a.done,a.value)})}}function o(i,a,s,f){Promise.resolve(f).then(function(c){i({value:c,done:s})},a)}}function A(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var $t=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function We(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=xe(a),f=s.next();!f.done;f=s.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var u=this.initialTeardown;if(A(u))try{u()}catch(v){i=v instanceof $t?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=xe(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{dn(h)}catch(v){i=i!=null?i:[],v instanceof $t?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new $t(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)dn(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&We(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&We(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=Ie.EMPTY;function It(e){return e instanceof Ie||e&&"closed"in e&&A(e.remove)&&A(e.add)&&A(e.unsubscribe)}function dn(e){A(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new Ie(function(){n.currentObservers=null,We(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new wn(r,n)},t}(U);var wn=function(e){ne(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Tr},t}(E);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ne(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,f=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Ut);var Tn=function(e){ne(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var we=new Tn(On);var R=new U(function(e){return e.complete()});function Dt(e){return e&&A(e.schedule)}function kr(e){return e[e.length-1]}function qe(e){return A(kr(e))?e.pop():void 0}function Se(e){return Dt(kr(e))?e.pop():void 0}function Vt(e,t){return typeof kr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function zt(e){return A(e==null?void 0:e.then)}function Nt(e){return A(e[ft])}function qt(e){return Symbol.asyncIterator&&A(e==null?void 0:e[Symbol.asyncIterator])}function Kt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ki(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=Ki();function Yt(e){return A(e==null?void 0:e[Qt])}function Gt(e){return ln(this,arguments,function(){var r,n,o,i;return Pt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,Xe(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,Xe(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,Xe(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Bt(e){return A(e==null?void 0:e.getReader)}function $(e){if(e instanceof U)return e;if(e!=null){if(Nt(e))return Qi(e);if(pt(e))return Yi(e);if(zt(e))return Gi(e);if(qt(e))return _n(e);if(Yt(e))return Bi(e);if(Bt(e))return Ji(e)}throw Kt(e)}function Qi(e){return new U(function(t){var r=e[ft]();if(A(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Yi(e){return new U(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?M(function(o,i){return e(o,i,n)}):me,Te(1),r?ke(t):zn(function(){return new Xt}))}}function Nn(){for(var e=[],t=0;t=2,!0))}function fe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new E}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,f=s===void 0?!0:s;return function(c){var u,p,m,d=0,h=!1,v=!1,B=function(){p==null||p.unsubscribe(),p=void 0},re=function(){B(),u=m=void 0,h=v=!1},V=function(){var O=u;re(),O==null||O.unsubscribe()};return g(function(O,Ne){d++,!v&&!h&&B();var Ue=m=m!=null?m:r();Ne.add(function(){d--,d===0&&!v&&!h&&(p=Fr(V,f))}),Ue.subscribe(Ne),!u&&d>0&&(u=new et({next:function($e){return Ue.next($e)},error:function($e){v=!0,B(),p=Fr(re,o,$e),Ue.error($e)},complete:function(){h=!0,B(),p=Fr(re,a),Ue.complete()}}),$(O).subscribe(u))})(c)}}function Fr(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function q(e,t=document){let r=se(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function se(e,t=document){return t.querySelector(e)||void 0}function je(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(Re(1),l(()=>{let t=je();return typeof t!="undefined"?e.contains(t):!1}),z(e===je()),Y())}function Ye(e){return{x:e.offsetLeft,y:e.offsetTop}}function Yn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ae(0,we),l(()=>Ye(e)),z(Ye(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ae(0,we),l(()=>rr(e)),z(rr(e)))}var Bn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),xa?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ya.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Jn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Zn=typeof WeakMap!="undefined"?new WeakMap:new Bn,eo=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Ea.getInstance(),n=new Ra(t,r,this);Zn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){eo.prototype[e]=function(){var t;return(t=Zn.get(this))[e].apply(t,arguments)}});var ka=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:eo}(),to=ka;var ro=new E,Ha=I(()=>H(new to(e=>{for(let t of e)ro.next(t)}))).pipe(x(e=>L(Oe,H(e)).pipe(C(()=>e.disconnect()))),J(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){return Ha.pipe(S(t=>t.observe(e)),x(t=>ro.pipe(M(({target:r})=>r===e),C(()=>t.unobserve(e)),l(()=>de(e)))),z(de(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var no=new E,Pa=I(()=>H(new IntersectionObserver(e=>{for(let t of e)no.next(t)},{threshold:0}))).pipe(x(e=>L(Oe,H(e)).pipe(C(()=>e.disconnect()))),J(1));function sr(e){return Pa.pipe(S(t=>t.observe(e)),x(t=>no.pipe(M(({target:r})=>r===e),C(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function oo(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=de(e),o=bt(e);return r>=o.height-n.height-t}),Y())}var cr={drawer:q("[data-md-toggle=drawer]"),search:q("[data-md-toggle=search]")};function io(e){return cr[e].checked}function Ge(e,t){cr[e].checked!==t&&cr[e].click()}function Be(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),z(t.checked))}function $a(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ia(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(z(!1))}function ao(){let e=b(window,"keydown").pipe(M(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:io("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),M(({mode:t,type:r})=>{if(t==="global"){let n=je();if(typeof n!="undefined")return!$a(n,r)}return!0}),fe());return Ia().pipe(x(t=>t?R:e))}function _e(){return new URL(location.href)}function ot(e){location.href=e.href}function so(){return new E}function co(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)co(e,r)}function _(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)co(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function fo(){return location.hash.substring(1)}function uo(e){let t=_("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function ja(){return b(window,"hashchange").pipe(l(fo),z(fo()),M(e=>e.length>0),J(1))}function po(){return ja().pipe(l(e=>se(`[id="${e}"]`)),M(e=>typeof e!="undefined"))}function Nr(e){let t=matchMedia(e);return Zt(r=>t.addListener(()=>r(t.matches))).pipe(z(t.matches))}function lo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(z(e.matches))}function qr(e,t){return e.pipe(x(r=>r?t():R))}function ur(e,t={credentials:"same-origin"}){return ve(fetch(`${e}`,t)).pipe(ce(()=>R),x(r=>r.status!==200?Ot(()=>new Error(r.statusText)):H(r)))}function Fe(e,t){return ur(e,t).pipe(x(r=>r.json()),J(1))}function mo(e,t){let r=new DOMParser;return ur(e,t).pipe(x(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),J(1))}function pr(e){let t=_("script",{src:e});return I(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(x(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),C(()=>document.head.removeChild(t)),Te(1))))}function ho(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function bo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(ho),z(ho()))}function vo(){return{width:innerWidth,height:innerHeight}}function go(){return b(window,"resize",{passive:!0}).pipe(l(vo),z(vo()))}function yo(){return Q([bo(),go()]).pipe(l(([e,t])=>({offset:e,size:t})),J(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(X("size")),o=Q([n,r]).pipe(l(()=>Ye(e)));return Q([r,t,o]).pipe(l(([{height:i},{offset:a,size:s},{x:f,y:c}])=>({offset:{x:a.x-f,y:a.y-c+i},size:s})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(a=>{let s=document.createElement("script");s.src=i,s.onload=a,document.body.appendChild(s)})),Promise.resolve())}var r=class{constructor(n){this.url=n,this.onerror=null,this.onmessage=null,this.onmessageerror=null,this.m=a=>{a.source===this.w&&(a.stopImmediatePropagation(),this.dispatchEvent(new MessageEvent("message",{data:a.data})),this.onmessage&&this.onmessage(a))},this.e=(a,s,f,c,u)=>{if(s===this.url.toString()){let p=new ErrorEvent("error",{message:a,filename:s,lineno:f,colno:c,error:u});this.dispatchEvent(p),this.onerror&&this.onerror(p)}};let o=new EventTarget;this.addEventListener=o.addEventListener.bind(o),this.removeEventListener=o.removeEventListener.bind(o),this.dispatchEvent=o.dispatchEvent.bind(o);let i=document.createElement("iframe");i.width=i.height=i.frameBorder="0",document.body.appendChild(this.iframe=i),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

CSI camera on Raspberry Pi (legacy)

+

CSI Camera V2

+

CSI Camera V2 +as of Sat 23 Mar 08:47:12 UTC 2024.

+

Example for older operating systems (those with command raspistill):

+
    +
  • copy csi-legacy.dist as .env if you want to use Raspberry Pi camera
  • +
  • in copied file .env replace token-change-me with the value of the token + you copied
  • +
  • in copied file .env replace fingerprint-change-me with some random value, + which is alphanumeric and has at least 16 chars (and max of 40 chars), + for example set it to fingerprint-myprinter-camera-1
  • +
  • save edited file .env
  • +
+

Next, test config.

+

Real world scenario

+

Some older Rpi 3 with older Debian with basic cam:

+
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=token-change-me
+PRUSA_CONNECT_CAMERA_FINGERPRINT=trash-cam-night-video-wide-1
+CAMERA_DEVICE=/dev/video0
+CAMERA_COMMAND=raspistill
+CAMERA_COMMAND_EXTRA_PARAMS="--nopreview --mode 640:480 -o"
+
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera.csi.libcamera/index.html b/config.for.camera.csi.libcamera/index.html new file mode 100644 index 0000000..bee1f4b --- /dev/null +++ b/config.for.camera.csi.libcamera/index.html @@ -0,0 +1,1009 @@ + + + + + + + + + + + + + + + + + + + + + + + + CSI - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

CSI camera on Raspberry Pi

+

CSI Camera V2

+

CSI Camera V2 +as of Sat 23 Mar 08:47:12 UTC 2024.

+

Example for newer operating systems (commands libcamera or rpicam-still):

+
    +
  • copy csi.dist as .env if you want to use Raspberry Pi camera
  • +
  • in copied file .env replace token-change-me with the value of the token + you copied
  • +
  • in copied file .env replace fingerprint-change-me with some random value, + which is alphanumeric and has at least 16 chars (and max of 40 chars), + for example set it to fingerprint-myprinter-camera-1
  • +
  • save edited file .env
  • +
+

Next, test config.

+

Real example

+

My Rpi Zero W with Raspberry Pi Camera v2 with +maximum resolution available:

+ +
PRINTER_ADDRESS=192.168.1.25
+PRUSA_CONNECT_CAMERA_TOKEN=redacted
+PRUSA_CONNECT_CAMERA_FINGERPRINT=c10eb887-f107-41a4-900e-2c38ea12a11c
+CAMERA_DEVICE=/dev/video0
+CAMERA_COMMAND=rpicam-still
+CAMERA_COMMAND_EXTRA_PARAMS="--immediate --nopreview --mode 2592:1944:12:P --lores-width 0 --lores-height 0 --thumb none -o"
+
+ + +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera.esphome.snapshot/index.html b/config.for.camera.esphome.snapshot/index.html new file mode 100644 index 0000000..8e77b8a --- /dev/null +++ b/config.for.camera.esphome.snapshot/index.html @@ -0,0 +1,1053 @@ + + + + + + + + + + + + + + + + + + + + + + + + ESPHome Snapshot - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

ESPHome camera snapshot

+

esp32-wrover-dev

+

With esphome camera with snapshot we can use the ultimate power of curl +command to fetch the image from the camera.

+

Prepare esphome device

+

Configure esphome device:

+
    +
  • install esphome camera + on the device and add esp32_camera and esp32_camera_web_server with + snapshot modules:
  • +
+
esp32_camera:
+... (skipped due to the fact there are different modules)
+
+esp32_camera_web_server:
+  - port: 8081
+    mode: snapshot
+
+

Flash the device and wait until it boots and is available.

+

Create config for script

+
    +
  • copy esphome-snapshot.dist as .env
  • +
  • in copied file .env replace token-change-me with the value + of the token you copied
  • +
  • in copied file .env replace fingerprint-change-me with some + random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), + for example set it to fingerprint-myprinter3-camera-3
  • +
  • in copied file .env replace your esphome device address and port + in CAMERA_COMMAND_EXTRA_PARAMS
  • +
  • save edited file .env
  • +
+

Next, test config.

+

Real world example

+

I have esp32-wrover-dev board with camera + esphome + web ui for camera exposing +snapshot frame on port 8081.

+

We can use curl to fetch it.

+
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=redacted
+PRUSA_CONNECT_CAMERA_FINGERPRINT=06f47777-f179-4025-bd80-9e4cb8db2aed
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=curl
+CAMERA_COMMAND_EXTRA_PARAMS=http://esp32-wrover-0461c8.local:8081/ -o
+
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera.esphome.stream/index.html b/config.for.camera.esphome.stream/index.html new file mode 100644 index 0000000..5185302 --- /dev/null +++ b/config.for.camera.esphome.stream/index.html @@ -0,0 +1,1056 @@ + + + + + + + + + + + + + + + + + + + + + + + + ESPHome Stream - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

ESPHome camera stream

+

esp32-wrover-dev

+

With esphome camera stream we can use the ffmpeg to fetch the image from the +camera stream. It requires a bit more computing power from esp device and the +host that runs the image processing.

+

Notice that this is not recommended way due to the amount of consumed resources.

+

Prepare esphome device

+

Configure esphome device:

+
    +
  • install esphome camera + on the device and add esp32_camera and esp32_camera_web_server with + stream modules:
  • +
+
esp32_camera:
+... (skipped due to the fact there are different modules)
+
+esp32_camera_web_server:
+  - port: 8080
+    mode: stream
+
+

Flash the device and wait until it boots and is available.

+

Create config for script

+
    +
  • copy esphome-stream.dist as .env
  • +
  • in copied file .env replace token-change-me with the value + of the token you copied
  • +
  • in copied file .env replace fingerprint-change-me with some + random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), + for example set it to fingerprint-myprinter3-camera-3
  • +
  • in copied file .env replace your esphome device address and port + in CAMERA_COMMAND_EXTRA_PARAMS
  • +
  • notice that -update 1 may not be needed in certain ffmpeg versions
  • +
  • save edited file .env
  • +
+

Next, test config.

+

Real world example

+

The same ESP device with stream, notice different port (8080).

+ +
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=token-change-me
+PRUSA_CONNECT_CAMERA_FINGERPRINT=f68336b-8dab-42cd-8729-6abd8855ff63
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=ffmpeg
+CAMERA_COMMAND_EXTRA_PARAMS="-y -i 'http://esp32-wrover-0461c8.local:8080/' -vframes 1 -q:v 1 -f image2 -update 1 "
+
+ + +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera.mjpg/index.html b/config.for.camera.mjpg/index.html new file mode 100644 index 0000000..f9ea217 --- /dev/null +++ b/config.for.camera.mjpg/index.html @@ -0,0 +1,1024 @@ + + + + + + + + + + + + + + + + + + + + + + + + Web Cams - MJPG streams - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Web Cam - MJPG stream

+

This processing requires ffmpeg package.

+

Most standalone webcams are actually mjpg cams, they send infinite motion jpeg stream +over specific URL.

+

The best option to check what is the URL is in the camera manual, or if you +open web UI of the camera and see the stream image then right click on the image +and select Inspect to see the URL for the image - copy that URL.

+

You should be able to test the stream locally with ffplay command.

+

For example, if your camera is reachable over address 192.168.0.20 and port 8000 +under endpoint /ipcam/mjpeg.cgi then below command should show the stream:

+
ffplay http://192.168.0.20:8000/ipcam/mjpeg.cgi
+
+

There may be some user and password in the URL.

+

If that works, then configuration should be pretty straightforward:

+
    +
  • copy ffmpeg-mjpg-stream.dist as .env
  • +
  • in copied file .env replace token-change-me with the value + of the token you copied
  • +
  • in copied file .env replace fingerprint-change-me + with some random value, which is alphanumeric and has at least 16 chars + (and max of 40 chars), for example set it to fingerprint-myprinter4-camera-4
  • +
  • in copied file .env replace your RTSP device address raspberry-pi, + port and stream id in CAMERA_COMMAND_EXTRA_PARAMS if needed
  • +
  • save edited file .env
  • +
+

Next, test config.

+

Unverified example

+

Beagle Camera stream - if I remember correctly, then camera url to the stream +is something like http://192.168.2.92/ipcam/mjpeg.cgi

+

Replace 192.168.2.92 with your address in the example below.

+ +
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=token-change-me
+PRUSA_CONNECT_CAMERA_FINGERPRINT=fingerprint-change-me
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=ffmpeg
+CAMERA_COMMAND_EXTRA_PARAMS="-y -i 'http://192.168.2.92/ipcam/mjpeg.cgi' -vframes 1 -q:v 1 -f image2 -update 1 "
+
+ + +

But it is better to use a snapshot instead of stream if available, +see here.

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera.rtsp/index.html b/config.for.camera.rtsp/index.html new file mode 100644 index 0000000..0219f80 --- /dev/null +++ b/config.for.camera.rtsp/index.html @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + Web Cams - RTSP streams - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Web Cam - RTSP stream

+

Caution

+

DO NOT use VLC to test streams, there are unfortunately problems with it. +Please use ffplay from ffmpeg package.

+

You have some options such as TCP or UDP stream (whatever..). +This should work with any other camera (usually there is a different port per stream)

+

You should be able to test the stream locally with ffplay command.

+

For example, if your camera is reachable over address 192.168.0.20 and port 8000 +under endpoint /stream then below command should show the stream:

+
ffplay rtsp://192.168.0.20:8000/stream
+
+

If that works, then configuration should be pretty straightforward:

+
    +
  • copy ffmpeg-mediamtx-rtsp-tcp.dist as .env
  • +
  • in copied file .env replace token-change-me with the value + of the token you copied
  • +
  • in copied file .env replace fingerprint-change-me + with some random value, which is alphanumeric and has at least 16 chars + (and max of 40 chars), for example set it to fingerprint-myprinter4-camera-4
  • +
  • in copied file .env replace your RTSP device address raspberry-pi, + port and stream id in CAMERA_COMMAND_EXTRA_PARAMS if needed
  • +
  • save edited file .env
  • +
+

You can try with UDP, but you may not get it ;-)

+

Next, test config.

+

Real world example

+

My another Rpi Zero W named hormex has two cameras:

+
    +
  • CSI
  • +
  • endoscope on /dev/video
  • +
+

and I'm running mediamtx server to conver those to RTSP streams. +More about mediamtx is here.

+

So I can have two configs:

+

.stream-csi over UDP:

+ + +
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=redacted
+PRUSA_CONNECT_CAMERA_FINGERPRINT=62e8ab72-9766-4ad5-b8b1-174d389fc0d3
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=ffmpeg
+CAMERA_COMMAND_EXTRA_PARAMS="-loglevel error -y -rtsp_transport udp -i "rtsp://hormex:8554/cam" -f image2 -vframes 1 -pix_fmt yuvj420p "
+
+ + +

.stream-endo over TCP:

+ +
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=redacted
+PRUSA_CONNECT_CAMERA_FINGERPRINT=01a67af8-86a3-45c7-b6e2-39e9d086b367
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=ffmpeg
+CAMERA_COMMAND_EXTRA_PARAMS="-loglevel error -y -rtsp_transport tcp -i "rtsp://hormex:8554/endoscope" -f image2 -vframes 1 -pix_fmt yuvj420p "
+
+ + +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera.snapshot/index.html b/config.for.camera.snapshot/index.html new file mode 100644 index 0000000..9b13e01 --- /dev/null +++ b/config.for.camera.snapshot/index.html @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + Web Cams - Snapshot - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Web Cam - snapshot

+

Some cameras expose single image snapshot under specific URL. +we can use the ultimate power of curl command to fetch the image from the camera.

+

This is the preferred way to use web cams because right now Prusa Connect do not +support streams, and thus there is no point in wasting CPU on that.

+

The best option to check what is the URL is in the camera manual, or if you +open web UI of the camera and see the still image then right click on the image +and select Inspect to see the URL for the image - copy that URL.

+

You should be able to test the stream locally with ffplay command.

+

For example, if your camera is reachable over address 192.168.0.20 and port 8001 +under endpoint /snap.jpg then below command should show the image:

+
curl -vvv http://another-cam.local:8081/snap.jpg -o snap.jpg
+
+

then you should see in the output something like Content-Type: image/jpeg, +then you are good - see snap.jpg in the folder you executed the command.

+

Create config for script

+
    +
  • copy snapshot.dist as .env
  • +
  • in copied file .env replace token-change-me with the value + of the token you copied
  • +
  • in copied file .env replace fingerprint-change-me with some + random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), + for example set it to fingerprint-myprinter3-camera-3
  • +
  • in copied file .env replace your esphome device address and port + in CAMERA_COMMAND_EXTRA_PARAMS
  • +
  • save edited file .env
  • +
+

Next, test config.

+

Real world example

+

esp32 with esphome

+

For more in-depth details see esphome snapshot.

+

I have esp32-wrover-dev board with camera + esphome + web ui for camera exposing +snapshot frame on port 8081.

+

We can use curl to fetch it.

+
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=redacted
+PRUSA_CONNECT_CAMERA_FINGERPRINT=06f47777-f179-4025-bd80-9e4cb8db2aed
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=curl
+CAMERA_COMMAND_EXTRA_PARAMS=http://esp32-wrover-0461c8.local:8081/ -o
+
+

Beagle Camera

+

This is not tested, I do not own such camera so hard to tell if this is right.

+

Camera URL for snapshot http://192.168.2.92/images/snapshot0.jpg so the config +should be like below:

+
PRINTER_ADDRESS=127.0.0.1
+PRUSA_CONNECT_CAMERA_TOKEN=redacted
+PRUSA_CONNECT_CAMERA_FINGERPRINT=06f47777-f179-4025-bd80-9e4cb8db2aed
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=curl
+CAMERA_COMMAND_EXTRA_PARAMS=http://192.168.2.92/images/snapshot0.jpg -o
+
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera.usb/index.html b/config.for.camera.usb/index.html new file mode 100644 index 0000000..408326c --- /dev/null +++ b/config.for.camera.usb/index.html @@ -0,0 +1,1061 @@ + + + + + + + + + + + + + + + + + + + + + + + + USB - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + + + + + +

USB camera

+

USB camera

+

This should work on any linux distro with any sane camera that you have.

+

How to get info which cameras are available?

+

Run v4l2-ctl --list-devices.

+

This should show list of devices to use, where /dev/video0 is a device +name.

+

Notice that not every device is an actual camera.

+

How to get what modes are available for the camera?

+

The quick all-in one output for camera /dev/video0 is

+
v4l2-ctl -d /dev/video0 --all
+
+

For more details about formats it is better to use +v4l2-ctl --list-formats-ext -d /dev/video0

+

Prepare config

+
    +
  • copy usb.dist as .env
  • +
  • in copied file .env replace token-change-me with the value of the token + you copied
  • +
  • in copied file .env replace fingerprint-change-me with some random value, + which is alphanumeric and has at least 16 chars (and max of 40 chars), + for example set it to fingerprint-myprinter2-camera-2
  • +
  • in copied file .env replace /dev/video0 with desired device in CAMERA_DEVICE
  • +
  • save edited file .env
  • +
+

Next, test config.

+

Real world example

+

Raspberry Pi Zero W with endoscope camera over USB, registered as /dev/video1:

+ +
PRINTER_ADDRESS=192.168.1.25
+PRUSA_CONNECT_CAMERA_TOKEN=redacted
+PRUSA_CONNECT_CAMERA_FINGERPRINT=7054ba85-bc19-4eb9-badc-6129575d9651
+CAMERA_DEVICE=/dev/video1
+CAMERA_COMMAND=fswebcam
+CAMERA_COMMAND_EXTRA_PARAMS="--resolution 1280x960 --no-banner"
+
+ + +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/config.for.camera/index.html b/config.for.camera/index.html new file mode 100644 index 0000000..58acef5 --- /dev/null +++ b/config.for.camera/index.html @@ -0,0 +1,1139 @@ + + + + + + + + + + + + + + + + + + + + + + + + General overview - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Create config for prusa-connect-camera-script env vars

+

Prusa Camera Token

+

PRUSA_CONNECT_CAMERA_TOKEN should be taken from earlier step.

+

Fingerprint

+

PRUSA_CONNECT_CAMERA_FINGERPRINT should be uniqe and set only once for each camera.

+

Fingerprint can be easily generated using command:

+
uuidgen
+
+

or via online website, +just copy/paste the output as fingerprint value into the config.

+

Do not change fingerprint after launching the script - thus camera is registered +and you may need to revert the change or delete and readd camera again and start +from scratch.

+

Example devices

+

Other env vars are set depending on the camera device we want to use.

+

Locally connected

+ +

Web cams

+

Generic

+ +

Specific example

+ +

Next

+

Next, test config.

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/configuration.env.full/index.html b/configuration.env.full/index.html new file mode 100644 index 0000000..22fff8e --- /dev/null +++ b/configuration.env.full/index.html @@ -0,0 +1,1026 @@ + + + + + + + + + + + + + + + + + + + + + + + + Configuration all env vars - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Configuration Env Vars

+

Config for camera is to the script as environment variables (env vars).

+
    +
  • +

    SLEEP - sleep time in seconds between image captures, + notice that PrusaConnect accepts images at most every 10s or slower. + Default value 10.

    +
  • +
  • +

    PRINTER_ADDRESS - Printer address to ping, if address is unreachable there + is no point in sending an image. Set to 127.0.0.1 to always send images. + Set to empty value to disable ping check and always send images. + Default value 127.0.0.1

    +
  • +
  • +

    PRUSA_CONNECT_CAMERA_TOKEN - required, PrusaConnect API key

    +
  • +
  • +

    PRUSA_CONNECT_CAMERA_FINGERPRINT - required, PrusaConnect camera fingerprint, + use for example cli uuidgen or web + to generate it, it must be at least 16 alphanumeric chars, 40 max. + Remember not to change this if it was already set, otherwise you need to + remove and add the camera again.

    +
  • +
  • +

    CAMERA_DEVICE - camera device to use, if you use Raspberry Pi camera + attached to the CSI via camera ribbon then leave as is + Default /dev/video0 which points to first detected camera.

    +
  • +
  • +

    CAMERA_SETUP_COMMAND - camera setup command and params executed before + taking image, default value is empty, because some cameras do not support it, + in general you want to use something like v4l2-ctl parameters, so + so for example + setup_command=v4l2-ctl --set-ctrl brightness=10,gamma=120 -d $CAMERA_DEVICE + will translate to: + v4l2-ctl --set-ctrl brightness=10,gamma=120 -d /dev/video0

    +
  • +
  • +

    CAMERA_COMMAND - command used to invoke image capture, + default is rpicam-still + available options:

    +
  • +
  • rpicam-still - using CSI camera + modern Raspberry Pi operating systems since + Debian 11 Bullseye
  • +
  • raspistill - using CSI camera + older Raspberry Pi operating systems
  • +
  • fswebcam - using USB camera + custom package 'fswebcam'
  • +
  • +

    anything else will be processed directly, so for example you could use + 'ffmpeg' in here

    +
  • +
  • +

    CAMERA_COMMAND_EXTRA_PARAMS -extra params passed to the camera program, + passed directly as <command> <extra-params> <output_file> + example values per specific camera: + +

    +
  • +
  • +

    libcamera (rpicam-still) + --immediate --nopreview --mode 2592:1944:12:P --lores-width 0 --lores-height 0 --thumb none -o

    +
  • +
  • raspistill + --nopreview --mode 2592:1944:12:P -o
  • +
  • fswebcam + --resolution 1280x960 --no-banner
  • +
  • ffmpeg, in this case CAMERA_DEVICE is ignored, use it directly in the extra params + -f v4l2 -y -i /dev/video0 -f image2 -vframes 1 -pix_fmt yuvj420p
  • +
+ + +
    +
  • +

    TARGET_DIR - directory where to save camera images, image per camera will + be overwritten per image capture, + default value /dev/shm so that we do not write to microSD cards or read only + filesystems/containers. /dev/shm is a shared memory space. if you have more + printers you may need to increase this value on system level.

    +
  • +
  • +

    CURL_EXTRA_PARAMS - extra params to curl when pushing an image, + default empty value, but you could for example add additional params if needed + such as -k if using tls proxy with self-signed certificate

    +
  • +
  • +

    PRUSA_CONNECT_URL - Prusa Connect endpoint where to post images, + default value https://webcam.connect.prusa3d.com/c/snapshot + You could put here Prusa Connect Proxy if you use one.

    +
  • +
+

For more in-depth details (no need to repeat them here) please see the top of +the prusa-connect-camera.sh.

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/configuration.env/index.html b/configuration.env/index.html new file mode 100644 index 0000000..b2baf24 --- /dev/null +++ b/configuration.env/index.html @@ -0,0 +1,994 @@ + + + + + + + + + + + + + + + + + + + + + + + + Env vars - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Configuration Env Vars

+

Minimum required env vars

+

Config for camera is to the script as environment variables (env vars).

+

The most important env vars are:

+
    +
  • PRUSA_CONNECT_CAMERA_TOKEN
  • +
  • PRUSA_CONNECT_CAMERA_FINGERPRINT
  • +
  • CAMERA_COMMAND
  • +
  • CAMERA_COMMAND_EXTRA_PARAMS
  • +
+

Those env vars will be filled in in the next steps.

+

Full list of env vars can be seen here

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/configuration.overview/index.html b/configuration.overview/index.html new file mode 100644 index 0000000..b92ecd3 --- /dev/null +++ b/configuration.overview/index.html @@ -0,0 +1,948 @@ + + + + + + + + + + + + + + + + + + + + + + + + Overview - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Configuration Overview

+

Short overview of actions:

+
    +
  • ensure printer is up and running and sending status to Prusa Connect + (otherwise images will be discarded)
  • +
  • add new camera to the existing printer in Prusa Connect, + obtain token and generate fingerprint
  • +
  • create config for prusa-connect-camera-script env vars
  • +
  • test the config
  • +
  • install script as systemd service
  • +
  • tuning config
  • +
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/configuration.tuning/index.html b/configuration.tuning/index.html new file mode 100644 index 0000000..6cdd632 --- /dev/null +++ b/configuration.tuning/index.html @@ -0,0 +1,1254 @@ + + + + + + + + + + + + + + + + + + + + + + + + Configuration Tuning - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Configuration tuning

+

Assuming you already have a working camera with basic setup, we can tune it further.

+

Below steps depend on the camera capabilities, thus your mileage may vary.

+

Notice that Prusa Connect has file size limit something about 8MB of the image uploaded, +so there may be no point in getting images with super high resolutions.

+

Getting higher quality camera images

+

Use v4l2-ctl to get the list of available resolutions that camera provides +and then update it in the env var configs.

+

Run v4l2-ctl --list-formats-ext -d /dev/video0 where /dev/video0 is a device +listed from command above.

+

Example output:

+
v4l2-ctl --list-formats-ext -d /dev/video1
+ioctl: VIDIOC_ENUM_FMT
+  Type: Video Capture
+
+  [0]: 'MJPG' (Motion-JPEG, compressed)
+    Size: Discrete 640x480
+      Interval: Discrete 0.033s (30.000 fps)
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 640x360
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 352x288
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 320x240
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 176x144
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 160x120
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 800x600
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 1280x720
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 1280x960
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 640x480
+      Interval: Discrete 0.033s (30.000 fps)
+      Interval: Discrete 0.033s (30.000 fps)
+  [1]: 'YUYV' (YUYV 4:2:2)
+    Size: Discrete 640x480
+      Interval: Discrete 0.033s (30.000 fps)
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 640x360
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 352x288
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 320x240
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 176x144
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 160x120
+      Interval: Discrete 0.033s (30.000 fps)
+    Size: Discrete 800x600
+      Interval: Discrete 0.200s (5.000 fps)
+    Size: Discrete 1280x720
+      Interval: Discrete 0.200s (5.000 fps)
+    Size: Discrete 1280x960
+      Interval: Discrete 0.200s (5.000 fps)
+    Size: Discrete 640x480
+      Interval: Discrete 0.033s (30.000 fps)
+      Interval: Discrete 0.033s (30.000 fps)
+
+

As you can see if I set video to YUYV and with resolution higher than 800x600 +I would get only 5 frames per second. +For still images this is not a problem, but for video streaming that could be +too low and I would have to switch to MJPG (or actually mjpeg in ffmpeg)

+

For Raspberry Cam v2 you could use csi.dist as source and add +--mode 2592:1944:12:P to the CAMERA_COMMAND_EXTRA_PARAMS.

+

For certain USB cameras (such as Tracer Endoscope) you should use usb.dist and +you should be able to add --resolution 1280x960 to the CAMERA_COMMAND_EXTRA_PARAMS.

+

Setting up video camera controls

+

Video controls are things like brightness, auto white balance (awb), +exposure and so on.

+

Get device capabilities, especially User controls:

+
v4l2-ctl -d /dev/video0 -l
+
+

and set accordingly parameters you want in CAMERA_SETUP_COMMAND env var, for example:

+
CAMERA_SETUP_COMMAND="v4l2-ctl --set-ctrl brightness=64,gamma=300 -d $CAMERA_DEVICE"
+
+

remember to restart given camera service.

+

You can try to use guvcview desktop application to check prams in realtime.

+

Image flip and rotation

+

You can pass on params to rpicam-still or fswebcam as you want.

+

rpicam-still

+

See rpicam-still --help

+
  --hflip      Read out with horizontal mirror
+  --vflip      Read out with vertical flip
+  --rotation   Use hflip and vflip to create the given rotation <angle>
+
+

so for example:

+
CAMERA_COMMAND=rpicam-still
+CAMERA_COMMAND_EXTRA_PARAMS="--rotation 90 --immediate --nopreview --thumb none -o"
+
+

fswebcam

+

See fswebcam --help

+
  --flip <direction>       Flips the image. (h, v)
+  --crop <size>[,<offset>] Crop a part of the image.
+  --scale <size>           Scales the image.
+  --rotate <angle>         Rotates the image in right angles.
+
+

so for example:

+
CAMERA_COMMAND=fswebcam
+CAMERA_COMMAND_EXTRA_PARAMS="--flip v --resolution 640x480 --no-banner"
+
+

ffmpeg

+

When curl is not enough and you don't really want to physically rotate your camera, +then use ffmpeg for post processing. +You can process static images with it, load v4l2 devices... whatever.

+

With ffmpeg you can do interesting things with filters, it will just require +more computing power.

+

Adding v4l2 options

+

v4l2 can be used as alias for video4linux2.

+

You can pass video4linux options to ffmpeg on device initialization, for example:

+ +
ffmpeg -f v4l2 -pix_fmt mjpeg -video_size 1280x960 -framerate 30 -i /dev/video1 \
+  -c:v libx264 -preset ultrafast -b:v 6000k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
+
+ + +

would instruct ffmpeg to use video4linux and force it to talk to the camera under +/dev/video1 and forcing mjpeg encoder, resolution and framerate.

+

This command above is directly taken from mediamtx.

+

For more params, see official ffmpeg docs. +Just remember to pass them before defining input (-i /dev/video1).

+

Rotation

+

See here +for basic ones.

+

You probably want to use -vf "transpose=1" to rotate image 90 degrees clockwise:

+ +
CAMERA_COMMAND=ffmpeg
+CAMERA_COMMAND_EXTRA_PARAMS="-y -i 'http://esp32-wrover-0461c8.local:8080/' -vf 'transpose=1' -vframes 1 -q:v 1 -f image2 -update 1 "
+
+ + +

Other processing

+

Frankly speaking you can do anything you want with ffmpeg, for example

+

-vf transpose=1,shufflepixels=m=block:height=16:width=16

+

Why? why not :D

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/css/extra.css b/css/extra.css new file mode 100644 index 0000000..7f4bc84 --- /dev/null +++ b/css/extra.css @@ -0,0 +1,3 @@ +.wy-nav-content { + max-width: 100%; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..1342414 --- /dev/null +++ b/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + +Prusa Connect Camera Script + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+

Welcome to Prusa-Connect-Camera-Script

+

logo

+

This project aims to make it easier to use any camera to be used as +Prusa Connect camera.

+

Features

+
    +
  • allows to read images from CSI cameras, USB cameras, RTSP streams, still images...
  • +
  • do not send pictures if the printer is offline
  • +
  • store data in memory to prevent MicroSD wear out
  • +
  • verbose error messages to see if the image capture works
  • +
  • ability to run multiple cameras in separate instances
  • +
  • ability to run in docker containers (multi-platform multi-arch)
  • +
+

Architecture

+
sequenceDiagram + script->>script: initial checks + script->>script: start loop + script->>camera_command: Call camera command + camera_command->>image_on_disk: camera command writes image to disk + image_on_disk->>script: script checks image from disk if exits etc + script->>script: show errors if image_on_disk is missing + script->>curl: run curl to post image to Prusa Connect API (pass image_on_disk) + curl->>image_on_disk: curl reads image from disk + curl->>PrusaConnect: send image to Prusa Connect + PrusaConnect->>curl: return response code / messages + script->>script: sleep + end loop +
+

Known limitations

+
    +
  • this script performs processing of the single camera, if you need more cameras + then just create multiple copies with different settings (see below)
  • +
  • +

    Rpi Zero W or older devices may have CPU limitations to process remote streams + or multiple cameras at once

    +
  • +
  • +

    I was not able to test EVERY setting so this may still have some bugs

    +
  • +
  • Prusa Connect will not show camera image if the printer is not alive, this is + Prusa Connect limitation.
  • +
  • default settings are quire generic and thus low camera quality, you need to adjust + them, see advanced configuration at the end
  • +
+
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + +
+
+
+
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/installation/index.html b/installation/index.html new file mode 100644 index 0000000..360d2dd --- /dev/null +++ b/installation/index.html @@ -0,0 +1,953 @@ + + + + + + + + + + + + + + + + + + + + + + + + Installation - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Installation

+

Install system packages - assuming Debian based distros on Raspberry Pi OS, which +also come in with some pre-installed packages.

+

Below commands should be executed in shell/terminal (on the Raspberry Pi).

+

For most Raspberry Pi Cameras (CSI/USB):

+
sudo apt-get update
+sudo apt-get install -y curl libcamera0 fswebcam git iputils-ping v4l-utils uuid-runtime
+
+

Additional packages for remote cameras - especially the one that are used for streaming:

+
sudo apt-get install -y ffmpeg
+
+

Download this script:

+
mkdir -p /home/pi/src
+cd /home/pi/src
+git clone https://github.com/nvtkaszpir/prusa-connect-camera-script.git
+cd prusa-connect-camera-script
+
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/performance/index.html b/performance/index.html new file mode 100644 index 0000000..d187297 --- /dev/null +++ b/performance/index.html @@ -0,0 +1,953 @@ + + + + + + + + + + + + + + + + + + + + + + + + Performance - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Performance

+
    +
  • +

    Raspberry Pi Zero W is able to process CSI camera + (Rpi Cam v2) and USB 2k camera + but it has load average about 1.4, and CPU is quite well utilized, so you may + need to decrease resolution per camera to see how + it goes.

    +
  • +
  • +

    for webcams it is always better to choose snapshot + because it requires less computing both on camera and on the host, + otherwise we need to use ffmpeg

    +
  • +
  • +

    ffmpeg is usually noticeably slow and cpu intensive, especially if you do more + complex operations

    +
  • +
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/prusa.connect/index.html b/prusa.connect/index.html new file mode 100644 index 0000000..070acdf --- /dev/null +++ b/prusa.connect/index.html @@ -0,0 +1,945 @@ + + + + + + + + + + + + + + + + + + + + + + + + Add camera to Prusa Connect - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Create new camera in the Prusa Connect

+
    +
  • go to Prusa Connect and log in
  • +
  • select Printer
  • +
  • select Camera
  • +
  • on the bottom click Add new other camera
  • +
  • new camera is created, copy Token, this is needed later as + PRUSA_CONNECT_CAMERA_TOKEN env var
  • +
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/requirements/index.html b/requirements/index.html new file mode 100644 index 0000000..5c01c30 --- /dev/null +++ b/requirements/index.html @@ -0,0 +1,1067 @@ + + + + + + + + + + + + + + + + + + + + + + + + Requirements - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Requirements

+

Hardware

+

Physical host or virtual machine or container:

+
    +
  • probably something like Raspberry Pi Zero W at least, can be without camera
  • +
  • more cameras usually requires more compute power
  • +
+

Camera such as:

+ + + +
    +
  • most of USB cameras if they work under Linux
  • +
  • esphome cameras using esp32_camera_web_server with snapshot module
  • +
  • esphome cameras using esp32_camera_web_server with stream module using ffmpeg
  • +
  • probably any camera if using ffmpeg
  • +
+

Software

+

Linux operating system. +Debian based preferred, for example Raspberry Pi OS Lite if you run Raspberry Pi. +I use also laptop with Ubuntu 22.04, but I believe with minor tweaks it should +work on most distributions (mainly package names are different).

+

Below list uses Debian package names.

+

Generic system packages

+
    +
  • bash 5.x (what year is it?)
  • +
  • git (just to install scripts from this repo)
  • +
  • curl
  • +
  • iputils-ping
  • +
  • uuid-runtime to make generation of camera fingerprint easier
  • +
+

Optional packages

+
    +
  • v4l-utils - to detect camera capabilities
  • +
  • libcamera0 - for Rpi CSI cameras
  • +
  • libraspberrypi-bin or rpicam-apps-lite for Rpi CSI cameras + (should be already installed on Rpi OS)
  • +
  • fswebcam - for generic USB cameras
  • +
  • ffmpeg - for custom commands for capturing remote streams
  • +
  • you-name-it - for custom commands beyond my imagination
  • +
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 0000000..575abd2 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to Prusa-Connect-Camera-Script","text":"

This project aims to make it easier to use any camera to be used as Prusa Connect camera.

"},{"location":"#features","title":"Features","text":"
  • allows to read images from CSI cameras, USB cameras, RTSP streams, still images...
  • do not send pictures if the printer is offline
  • store data in memory to prevent MicroSD wear out
  • verbose error messages to see if the image capture works
  • ability to run multiple cameras in separate instances
  • ability to run in docker containers (multi-platform multi-arch)
"},{"location":"#architecture","title":"Architecture","text":"sequenceDiagram script->>script: initial checks script->>script: start loop script->>camera_command: Call camera command camera_command->>image_on_disk: camera command writes image to disk image_on_disk->>script: script checks image from disk if exits etc script->>script: show errors if image_on_disk is missing script->>curl: run curl to post image to Prusa Connect API (pass image_on_disk) curl->>image_on_disk: curl reads image from disk curl->>PrusaConnect: send image to Prusa Connect PrusaConnect->>curl: return response code / messages script->>script: sleep + end loop"},{"location":"#known-limitations","title":"Known limitations","text":"
  • this script performs processing of the single camera, if you need more cameras then just create multiple copies with different settings (see below)
  • Rpi Zero W or older devices may have CPU limitations to process remote streams or multiple cameras at once

  • I was not able to test EVERY setting so this may still have some bugs

  • Prusa Connect will not show camera image if the printer is not alive, this is Prusa Connect limitation.
  • default settings are quire generic and thus low camera quality, you need to adjust them, see advanced configuration at the end
"},{"location":"config.for.camera.csi.legacy/","title":"CSI camera on Raspberry Pi (legacy)","text":"

CSI Camera V2 as of Sat 23 Mar 08:47:12 UTC 2024.

Example for older operating systems (those with command raspistill):

  • copy csi-legacy.dist as .env if you want to use Raspberry Pi camera
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter-camera-1
  • save edited file .env

Next, test config.

"},{"location":"config.for.camera.csi.legacy/#real-world-scenario","title":"Real world scenario","text":"

Some older Rpi 3 with older Debian with basic cam:

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=token-change-me\nPRUSA_CONNECT_CAMERA_FINGERPRINT=trash-cam-night-video-wide-1\nCAMERA_DEVICE=/dev/video0\nCAMERA_COMMAND=raspistill\nCAMERA_COMMAND_EXTRA_PARAMS=\"--nopreview --mode 640:480 -o\"\n
"},{"location":"config.for.camera.csi.libcamera/","title":"CSI camera on Raspberry Pi","text":"

CSI Camera V2 as of Sat 23 Mar 08:47:12 UTC 2024.

Example for newer operating systems (commands libcamera or rpicam-still):

  • copy csi.dist as .env if you want to use Raspberry Pi camera
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter-camera-1
  • save edited file .env

Next, test config.

"},{"location":"config.for.camera.csi.libcamera/#real-example","title":"Real example","text":"

My Rpi Zero W with Raspberry Pi Camera v2 with maximum resolution available:

PRINTER_ADDRESS=192.168.1.25\nPRUSA_CONNECT_CAMERA_TOKEN=redacted\nPRUSA_CONNECT_CAMERA_FINGERPRINT=c10eb887-f107-41a4-900e-2c38ea12a11c\nCAMERA_DEVICE=/dev/video0\nCAMERA_COMMAND=rpicam-still\nCAMERA_COMMAND_EXTRA_PARAMS=\"--immediate --nopreview --mode 2592:1944:12:P --lores-width 0 --lores-height 0 --thumb none -o\"\n
"},{"location":"config.for.camera.esphome.snapshot/","title":"ESPHome camera snapshot","text":"

With esphome camera with snapshot we can use the ultimate power of curl command to fetch the image from the camera.

"},{"location":"config.for.camera.esphome.snapshot/#prepare-esphome-device","title":"Prepare esphome device","text":"

Configure esphome device:

  • install esphome camera on the device and add esp32_camera and esp32_camera_web_server with snapshot modules:
esp32_camera:\n... (skipped due to the fact there are different modules)\n\nesp32_camera_web_server:\n  - port: 8081\n    mode: snapshot\n

Flash the device and wait until it boots and is available.

"},{"location":"config.for.camera.esphome.snapshot/#create-config-for-script","title":"Create config for script","text":"
  • copy esphome-snapshot.dist as .env
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter3-camera-3
  • in copied file .env replace your esphome device address and port in CAMERA_COMMAND_EXTRA_PARAMS
  • save edited file .env

Next, test config.

"},{"location":"config.for.camera.esphome.snapshot/#real-world-example","title":"Real world example","text":"

I have esp32-wrover-dev board with camera + esphome + web ui for camera exposing snapshot frame on port 8081.

We can use curl to fetch it.

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=redacted\nPRUSA_CONNECT_CAMERA_FINGERPRINT=06f47777-f179-4025-bd80-9e4cb8db2aed\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=curl\nCAMERA_COMMAND_EXTRA_PARAMS=http://esp32-wrover-0461c8.local:8081/ -o\n
"},{"location":"config.for.camera.esphome.stream/","title":"ESPHome camera stream","text":"

With esphome camera stream we can use the ffmpeg to fetch the image from the camera stream. It requires a bit more computing power from esp device and the host that runs the image processing.

Notice that this is not recommended way due to the amount of consumed resources.

"},{"location":"config.for.camera.esphome.stream/#prepare-esphome-device","title":"Prepare esphome device","text":"

Configure esphome device:

  • install esphome camera on the device and add esp32_camera and esp32_camera_web_server with stream modules:
esp32_camera:\n... (skipped due to the fact there are different modules)\n\nesp32_camera_web_server:\n  - port: 8080\n    mode: stream\n

Flash the device and wait until it boots and is available.

"},{"location":"config.for.camera.esphome.stream/#create-config-for-script","title":"Create config for script","text":"
  • copy esphome-stream.dist as .env
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter3-camera-3
  • in copied file .env replace your esphome device address and port in CAMERA_COMMAND_EXTRA_PARAMS
  • notice that -update 1 may not be needed in certain ffmpeg versions
  • save edited file .env

Next, test config.

"},{"location":"config.for.camera.esphome.stream/#real-world-example","title":"Real world example","text":"

The same ESP device with stream, notice different port (8080).

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=token-change-me\nPRUSA_CONNECT_CAMERA_FINGERPRINT=f68336b-8dab-42cd-8729-6abd8855ff63\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=ffmpeg\nCAMERA_COMMAND_EXTRA_PARAMS=\"-y -i 'http://esp32-wrover-0461c8.local:8080/' -vframes 1 -q:v 1 -f image2 -update 1 \"\n
"},{"location":"config.for.camera/","title":"Create config for prusa-connect-camera-script env vars","text":""},{"location":"config.for.camera/#prusa-camera-token","title":"Prusa Camera Token","text":"

PRUSA_CONNECT_CAMERA_TOKEN should be taken from earlier step.

"},{"location":"config.for.camera/#fingerprint","title":"Fingerprint","text":"

PRUSA_CONNECT_CAMERA_FINGERPRINT should be uniqe and set only once for each camera.

Fingerprint can be easily generated using command:

uuidgen\n

or via online website, just copy/paste the output as fingerprint value into the config.

Do not change fingerprint after launching the script - thus camera is registered and you may need to revert the change or delete and readd camera again and start from scratch.

"},{"location":"config.for.camera/#example-devices","title":"Example devices","text":"

Other env vars are set depending on the camera device we want to use.

"},{"location":"config.for.camera/#locally-connected","title":"Locally connected","text":"
  • Raspberry Pi CSI camera - libcamera (recommended)
  • Raspberry Pi CSI camera - legacy
  • USB camera
"},{"location":"config.for.camera/#web-cams","title":"Web cams","text":""},{"location":"config.for.camera/#generic","title":"Generic","text":"
  • Snapshot cams (recommended)
  • MJPG streaming cams
  • RTSP streaming cams
"},{"location":"config.for.camera/#specific-example","title":"Specific example","text":"
  • ESPHome via camera snapshot (recommended)
  • ESPHome via camera stream
"},{"location":"config.for.camera/#next","title":"Next","text":"

Next, test config.

"},{"location":"config.for.camera.mjpg/","title":"Web Cam - MJPG stream","text":"

This processing requires ffmpeg package.

Most standalone webcams are actually mjpg cams, they send infinite motion jpeg stream over specific URL.

The best option to check what is the URL is in the camera manual, or if you open web UI of the camera and see the stream image then right click on the image and select Inspect to see the URL for the image - copy that URL.

You should be able to test the stream locally with ffplay command.

For example, if your camera is reachable over address 192.168.0.20 and port 8000 under endpoint /ipcam/mjpeg.cgi then below command should show the stream:

ffplay http://192.168.0.20:8000/ipcam/mjpeg.cgi\n

There may be some user and password in the URL.

If that works, then configuration should be pretty straightforward:

  • copy ffmpeg-mjpg-stream.dist as .env
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter4-camera-4
  • in copied file .env replace your RTSP device address raspberry-pi, port and stream id in CAMERA_COMMAND_EXTRA_PARAMS if needed
  • save edited file .env

Next, test config.

"},{"location":"config.for.camera.mjpg/#unverified-example","title":"Unverified example","text":"

Beagle Camera stream - if I remember correctly, then camera url to the stream is something like http://192.168.2.92/ipcam/mjpeg.cgi

Replace 192.168.2.92 with your address in the example below.

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=token-change-me\nPRUSA_CONNECT_CAMERA_FINGERPRINT=fingerprint-change-me\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=ffmpeg\nCAMERA_COMMAND_EXTRA_PARAMS=\"-y -i 'http://192.168.2.92/ipcam/mjpeg.cgi' -vframes 1 -q:v 1 -f image2 -update 1 \"\n

But it is better to use a snapshot instead of stream if available, see here.

"},{"location":"config.for.camera.rtsp/","title":"Web Cam - RTSP stream","text":""},{"location":"config.for.camera.rtsp/#caution","title":"Caution","text":"

DO NOT use VLC to test streams, there are unfortunately problems with it. Please use ffplay from ffmpeg package.

You have some options such as TCP or UDP stream (whatever..). This should work with any other camera (usually there is a different port per stream)

You should be able to test the stream locally with ffplay command.

For example, if your camera is reachable over address 192.168.0.20 and port 8000 under endpoint /stream then below command should show the stream:

ffplay rtsp://192.168.0.20:8000/stream\n

If that works, then configuration should be pretty straightforward:

  • copy ffmpeg-mediamtx-rtsp-tcp.dist as .env
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter4-camera-4
  • in copied file .env replace your RTSP device address raspberry-pi, port and stream id in CAMERA_COMMAND_EXTRA_PARAMS if needed
  • save edited file .env

You can try with UDP, but you may not get it ;-)

Next, test config.

"},{"location":"config.for.camera.rtsp/#real-world-example","title":"Real world example","text":"

My another Rpi Zero W named hormex has two cameras:

  • CSI
  • endoscope on /dev/video

and I'm running mediamtx server to conver those to RTSP streams. More about mediamtx is here.

So I can have two configs:

.stream-csi over UDP:

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=redacted\nPRUSA_CONNECT_CAMERA_FINGERPRINT=62e8ab72-9766-4ad5-b8b1-174d389fc0d3\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=ffmpeg\nCAMERA_COMMAND_EXTRA_PARAMS=\"-loglevel error -y -rtsp_transport udp -i \"rtsp://hormex:8554/cam\" -f image2 -vframes 1 -pix_fmt yuvj420p \"\n

.stream-endo over TCP:

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=redacted\nPRUSA_CONNECT_CAMERA_FINGERPRINT=01a67af8-86a3-45c7-b6e2-39e9d086b367\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=ffmpeg\nCAMERA_COMMAND_EXTRA_PARAMS=\"-loglevel error -y -rtsp_transport tcp -i \"rtsp://hormex:8554/endoscope\" -f image2 -vframes 1 -pix_fmt yuvj420p \"\n
"},{"location":"config.for.camera.snapshot/","title":"Web Cam - snapshot","text":"

Some cameras expose single image snapshot under specific URL. we can use the ultimate power of curl command to fetch the image from the camera.

This is the preferred way to use web cams because right now Prusa Connect do not support streams, and thus there is no point in wasting CPU on that.

The best option to check what is the URL is in the camera manual, or if you open web UI of the camera and see the still image then right click on the image and select Inspect to see the URL for the image - copy that URL.

You should be able to test the stream locally with ffplay command.

For example, if your camera is reachable over address 192.168.0.20 and port 8001 under endpoint /snap.jpg then below command should show the image:

curl -vvv http://another-cam.local:8081/snap.jpg -o snap.jpg\n

then you should see in the output something like Content-Type: image/jpeg, then you are good - see snap.jpg in the folder you executed the command.

"},{"location":"config.for.camera.snapshot/#create-config-for-script","title":"Create config for script","text":"
  • copy snapshot.dist as .env
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter3-camera-3
  • in copied file .env replace your esphome device address and port in CAMERA_COMMAND_EXTRA_PARAMS
  • save edited file .env

Next, test config.

"},{"location":"config.for.camera.snapshot/#real-world-example","title":"Real world example","text":""},{"location":"config.for.camera.snapshot/#esp32-with-esphome","title":"esp32 with esphome","text":"

For more in-depth details see esphome snapshot.

I have esp32-wrover-dev board with camera + esphome + web ui for camera exposing snapshot frame on port 8081.

We can use curl to fetch it.

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=redacted\nPRUSA_CONNECT_CAMERA_FINGERPRINT=06f47777-f179-4025-bd80-9e4cb8db2aed\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=curl\nCAMERA_COMMAND_EXTRA_PARAMS=http://esp32-wrover-0461c8.local:8081/ -o\n
"},{"location":"config.for.camera.snapshot/#beagle-camera","title":"Beagle Camera","text":"

This is not tested, I do not own such camera so hard to tell if this is right.

Camera URL for snapshot http://192.168.2.92/images/snapshot0.jpg so the config should be like below:

PRINTER_ADDRESS=127.0.0.1\nPRUSA_CONNECT_CAMERA_TOKEN=redacted\nPRUSA_CONNECT_CAMERA_FINGERPRINT=06f47777-f179-4025-bd80-9e4cb8db2aed\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=curl\nCAMERA_COMMAND_EXTRA_PARAMS=http://192.168.2.92/images/snapshot0.jpg -o\n
"},{"location":"config.for.camera.usb/","title":"USB camera","text":"

This should work on any linux distro with any sane camera that you have.

"},{"location":"config.for.camera.usb/#how-to-get-info-which-cameras-are-available","title":"How to get info which cameras are available?","text":"

Run v4l2-ctl --list-devices.

This should show list of devices to use, where /dev/video0 is a device name.

Notice that not every device is an actual camera.

"},{"location":"config.for.camera.usb/#how-to-get-what-modes-are-available-for-the-camera","title":"How to get what modes are available for the camera?","text":"

The quick all-in one output for camera /dev/video0 is

v4l2-ctl -d /dev/video0 --all\n

For more details about formats it is better to use v4l2-ctl --list-formats-ext -d /dev/video0

"},{"location":"config.for.camera.usb/#prepare-config","title":"Prepare config","text":"
  • copy usb.dist as .env
  • in copied file .env replace token-change-me with the value of the token you copied
  • in copied file .env replace fingerprint-change-me with some random value, which is alphanumeric and has at least 16 chars (and max of 40 chars), for example set it to fingerprint-myprinter2-camera-2
  • in copied file .env replace /dev/video0 with desired device in CAMERA_DEVICE
  • save edited file .env

Next, test config.

"},{"location":"config.for.camera.usb/#real-world-example","title":"Real world example","text":"

Raspberry Pi Zero W with endoscope camera over USB, registered as /dev/video1:

PRINTER_ADDRESS=192.168.1.25\nPRUSA_CONNECT_CAMERA_TOKEN=redacted\nPRUSA_CONNECT_CAMERA_FINGERPRINT=7054ba85-bc19-4eb9-badc-6129575d9651\nCAMERA_DEVICE=/dev/video1\nCAMERA_COMMAND=fswebcam\nCAMERA_COMMAND_EXTRA_PARAMS=\"--resolution 1280x960 --no-banner\"\n
"},{"location":"configuration.env.full/","title":"Configuration Env Vars","text":"

Config for camera is to the script as environment variables (env vars).

  • SLEEP - sleep time in seconds between image captures, notice that PrusaConnect accepts images at most every 10s or slower. Default value 10.

  • PRINTER_ADDRESS - Printer address to ping, if address is unreachable there is no point in sending an image. Set to 127.0.0.1 to always send images. Set to empty value to disable ping check and always send images. Default value 127.0.0.1

  • PRUSA_CONNECT_CAMERA_TOKEN - required, PrusaConnect API key

  • PRUSA_CONNECT_CAMERA_FINGERPRINT - required, PrusaConnect camera fingerprint, use for example cli uuidgen or web to generate it, it must be at least 16 alphanumeric chars, 40 max. Remember not to change this if it was already set, otherwise you need to remove and add the camera again.

  • CAMERA_DEVICE - camera device to use, if you use Raspberry Pi camera attached to the CSI via camera ribbon then leave as is Default /dev/video0 which points to first detected camera.

  • CAMERA_SETUP_COMMAND - camera setup command and params executed before taking image, default value is empty, because some cameras do not support it, in general you want to use something like v4l2-ctl parameters, so so for example setup_command=v4l2-ctl --set-ctrl brightness=10,gamma=120 -d $CAMERA_DEVICE will translate to: v4l2-ctl --set-ctrl brightness=10,gamma=120 -d /dev/video0

  • CAMERA_COMMAND - command used to invoke image capture, default is rpicam-still available options:

  • rpicam-still - using CSI camera + modern Raspberry Pi operating systems since Debian 11 Bullseye
  • raspistill - using CSI camera + older Raspberry Pi operating systems
  • fswebcam - using USB camera + custom package 'fswebcam'
  • anything else will be processed directly, so for example you could use 'ffmpeg' in here

  • CAMERA_COMMAND_EXTRA_PARAMS -extra params passed to the camera program, passed directly as <command> <extra-params> <output_file> example values per specific camera:

  • libcamera (rpicam-still) --immediate --nopreview --mode 2592:1944:12:P --lores-width 0 --lores-height 0 --thumb none -o

  • raspistill --nopreview --mode 2592:1944:12:P -o
  • fswebcam --resolution 1280x960 --no-banner
  • ffmpeg, in this case CAMERA_DEVICE is ignored, use it directly in the extra params -f v4l2 -y -i /dev/video0 -f image2 -vframes 1 -pix_fmt yuvj420p
  • TARGET_DIR - directory where to save camera images, image per camera will be overwritten per image capture, default value /dev/shm so that we do not write to microSD cards or read only filesystems/containers. /dev/shm is a shared memory space. if you have more printers you may need to increase this value on system level.

  • CURL_EXTRA_PARAMS - extra params to curl when pushing an image, default empty value, but you could for example add additional params if needed such as -k if using tls proxy with self-signed certificate

  • PRUSA_CONNECT_URL - Prusa Connect endpoint where to post images, default value https://webcam.connect.prusa3d.com/c/snapshot You could put here Prusa Connect Proxy if you use one.

For more in-depth details (no need to repeat them here) please see the top of the prusa-connect-camera.sh.

"},{"location":"configuration.env/","title":"Configuration Env Vars","text":""},{"location":"configuration.env/#minimum-required-env-vars","title":"Minimum required env vars","text":"

Config for camera is to the script as environment variables (env vars).

The most important env vars are:

  • PRUSA_CONNECT_CAMERA_TOKEN
  • PRUSA_CONNECT_CAMERA_FINGERPRINT
  • CAMERA_COMMAND
  • CAMERA_COMMAND_EXTRA_PARAMS

Those env vars will be filled in in the next steps.

Full list of env vars can be seen here

"},{"location":"configuration.overview/","title":"Configuration Overview","text":"

Short overview of actions:

  • ensure printer is up and running and sending status to Prusa Connect (otherwise images will be discarded)
  • add new camera to the existing printer in Prusa Connect, obtain token and generate fingerprint
  • create config for prusa-connect-camera-script env vars
  • test the config
  • install script as systemd service
  • tuning config
"},{"location":"configuration.tuning/","title":"Configuration tuning","text":"

Assuming you already have a working camera with basic setup, we can tune it further.

Below steps depend on the camera capabilities, thus your mileage may vary.

Notice that Prusa Connect has file size limit something about 8MB of the image uploaded, so there may be no point in getting images with super high resolutions.

"},{"location":"configuration.tuning/#getting-higher-quality-camera-images","title":"Getting higher quality camera images","text":"

Use v4l2-ctl to get the list of available resolutions that camera provides and then update it in the env var configs.

Run v4l2-ctl --list-formats-ext -d /dev/video0 where /dev/video0 is a device listed from command above.

Example output:

v4l2-ctl --list-formats-ext -d /dev/video1\nioctl: VIDIOC_ENUM_FMT\n  Type: Video Capture\n\n  [0]: 'MJPG' (Motion-JPEG, compressed)\n    Size: Discrete 640x480\n      Interval: Discrete 0.033s (30.000 fps)\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 640x360\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 352x288\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 320x240\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 176x144\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 160x120\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 800x600\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 1280x720\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 1280x960\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 640x480\n      Interval: Discrete 0.033s (30.000 fps)\n      Interval: Discrete 0.033s (30.000 fps)\n  [1]: 'YUYV' (YUYV 4:2:2)\n    Size: Discrete 640x480\n      Interval: Discrete 0.033s (30.000 fps)\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 640x360\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 352x288\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 320x240\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 176x144\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 160x120\n      Interval: Discrete 0.033s (30.000 fps)\n    Size: Discrete 800x600\n      Interval: Discrete 0.200s (5.000 fps)\n    Size: Discrete 1280x720\n      Interval: Discrete 0.200s (5.000 fps)\n    Size: Discrete 1280x960\n      Interval: Discrete 0.200s (5.000 fps)\n    Size: Discrete 640x480\n      Interval: Discrete 0.033s (30.000 fps)\n      Interval: Discrete 0.033s (30.000 fps)\n

As you can see if I set video to YUYV and with resolution higher than 800x600 I would get only 5 frames per second. For still images this is not a problem, but for video streaming that could be too low and I would have to switch to MJPG (or actually mjpeg in ffmpeg)

For Raspberry Cam v2 you could use csi.dist as source and add --mode 2592:1944:12:P to the CAMERA_COMMAND_EXTRA_PARAMS.

For certain USB cameras (such as Tracer Endoscope) you should use usb.dist and you should be able to add --resolution 1280x960 to the CAMERA_COMMAND_EXTRA_PARAMS.

"},{"location":"configuration.tuning/#setting-up-video-camera-controls","title":"Setting up video camera controls","text":"

Video controls are things like brightness, auto white balance (awb), exposure and so on.

Get device capabilities, especially User controls:

v4l2-ctl -d /dev/video0 -l\n

and set accordingly parameters you want in CAMERA_SETUP_COMMAND env var, for example:

CAMERA_SETUP_COMMAND=\"v4l2-ctl --set-ctrl brightness=64,gamma=300 -d $CAMERA_DEVICE\"\n

remember to restart given camera service.

You can try to use guvcview desktop application to check prams in realtime.

"},{"location":"configuration.tuning/#image-flip-and-rotation","title":"Image flip and rotation","text":"

You can pass on params to rpicam-still or fswebcam as you want.

"},{"location":"configuration.tuning/#rpicam-still","title":"rpicam-still","text":"

See rpicam-still --help

  --hflip      Read out with horizontal mirror\n  --vflip      Read out with vertical flip\n  --rotation   Use hflip and vflip to create the given rotation <angle>\n

so for example:

CAMERA_COMMAND=rpicam-still\nCAMERA_COMMAND_EXTRA_PARAMS=\"--rotation 90 --immediate --nopreview --thumb none -o\"\n
"},{"location":"configuration.tuning/#fswebcam","title":"fswebcam","text":"

See fswebcam --help

  --flip <direction>       Flips the image. (h, v)\n  --crop <size>[,<offset>] Crop a part of the image.\n  --scale <size>           Scales the image.\n  --rotate <angle>         Rotates the image in right angles.\n

so for example:

CAMERA_COMMAND=fswebcam\nCAMERA_COMMAND_EXTRA_PARAMS=\"--flip v --resolution 640x480 --no-banner\"\n
"},{"location":"configuration.tuning/#ffmpeg","title":"ffmpeg","text":"

When curl is not enough and you don't really want to physically rotate your camera, then use ffmpeg for post processing. You can process static images with it, load v4l2 devices... whatever.

With ffmpeg you can do interesting things with filters, it will just require more computing power.

"},{"location":"configuration.tuning/#adding-v4l2-options","title":"Adding v4l2 options","text":"

v4l2 can be used as alias for video4linux2.

You can pass video4linux options to ffmpeg on device initialization, for example:

ffmpeg -f v4l2 -pix_fmt mjpeg -video_size 1280x960 -framerate 30 -i /dev/video1 \\\n  -c:v libx264 -preset ultrafast -b:v 6000k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH\n

would instruct ffmpeg to use video4linux and force it to talk to the camera under /dev/video1 and forcing mjpeg encoder, resolution and framerate.

This command above is directly taken from mediamtx.

For more params, see official ffmpeg docs. Just remember to pass them before defining input (-i /dev/video1).

"},{"location":"configuration.tuning/#rotation","title":"Rotation","text":"

See here for basic ones.

You probably want to use -vf \"transpose=1\" to rotate image 90 degrees clockwise:

CAMERA_COMMAND=ffmpeg\nCAMERA_COMMAND_EXTRA_PARAMS=\"-y -i 'http://esp32-wrover-0461c8.local:8080/' -vf 'transpose=1' -vframes 1 -q:v 1 -f image2 -update 1 \"\n
"},{"location":"configuration.tuning/#other-processing","title":"Other processing","text":"

Frankly speaking you can do anything you want with ffmpeg, for example

-vf transpose=1,shufflepixels=m=block:height=16:width=16

Why? why not :D

"},{"location":"installation/","title":"Installation","text":"

Install system packages - assuming Debian based distros on Raspberry Pi OS, which also come in with some pre-installed packages.

Below commands should be executed in shell/terminal (on the Raspberry Pi).

For most Raspberry Pi Cameras (CSI/USB):

sudo apt-get update\nsudo apt-get install -y curl libcamera0 fswebcam git iputils-ping v4l-utils uuid-runtime\n

Additional packages for remote cameras - especially the one that are used for streaming:

sudo apt-get install -y ffmpeg\n

Download this script:

mkdir -p /home/pi/src\ncd /home/pi/src\ngit clone https://github.com/nvtkaszpir/prusa-connect-camera-script.git\ncd prusa-connect-camera-script\n
"},{"location":"performance/","title":"Performance","text":"
  • Raspberry Pi Zero W is able to process CSI camera (Rpi Cam v2) and USB 2k camera but it has load average about 1.4, and CPU is quite well utilized, so you may need to decrease resolution per camera to see how it goes.

  • for webcams it is always better to choose snapshot because it requires less computing both on camera and on the host, otherwise we need to use ffmpeg

  • ffmpeg is usually noticeably slow and cpu intensive, especially if you do more complex operations

"},{"location":"prusa.connect/","title":"Create new camera in the Prusa Connect","text":"
  • go to Prusa Connect and log in
  • select Printer
  • select Camera
  • on the bottom click Add new other camera
  • new camera is created, copy Token, this is needed later as PRUSA_CONNECT_CAMERA_TOKEN env var
"},{"location":"requirements/","title":"Requirements","text":""},{"location":"requirements/#hardware","title":"Hardware","text":"

Physical host or virtual machine or container:

  • probably something like Raspberry Pi Zero W at least, can be without camera
  • more cameras usually requires more compute power

Camera such as:

  • Raspberry Pi CSI cameras such as Raspberry Pi Cam
  • most of USB cameras if they work under Linux
  • esphome cameras using esp32_camera_web_server with snapshot module
  • esphome cameras using esp32_camera_web_server with stream module using ffmpeg
  • probably any camera if using ffmpeg
"},{"location":"requirements/#software","title":"Software","text":"

Linux operating system. Debian based preferred, for example Raspberry Pi OS Lite if you run Raspberry Pi. I use also laptop with Ubuntu 22.04, but I believe with minor tweaks it should work on most distributions (mainly package names are different).

Below list uses Debian package names.

"},{"location":"requirements/#generic-system-packages","title":"Generic system packages","text":"
  • bash 5.x (what year is it?)
  • git (just to install scripts from this repo)
  • curl
  • iputils-ping
  • uuid-runtime to make generation of camera fingerprint easier
"},{"location":"requirements/#optional-packages","title":"Optional packages","text":"
  • v4l-utils - to detect camera capabilities
  • libcamera0 - for Rpi CSI cameras
  • libraspberrypi-bin or rpicam-apps-lite for Rpi CSI cameras (should be already installed on Rpi OS)
  • fswebcam - for generic USB cameras
  • ffmpeg - for custom commands for capturing remote streams
  • you-name-it - for custom commands beyond my imagination
"},{"location":"service.docker/","title":"Install script as docker container","text":"

You can run the app as container.

Multi-platform images are available at quay.io/kaszpir/prusa-connect-script.

Currently available platforms:

  • linux/amd64 (64bit)
  • linux/arm64 (64bit)
  • linux/arm/v7 (32bit)
"},{"location":"service.docker/#preparation-of-the-host","title":"Preparation of the host","text":"

Install docker on Debian.

Optional - you may want to make sure current user is in docker group so it is possible to run containers without using sudo:

sudo usermod -a -G docker $(whoami)\n

logout and login again, or reboot Raspberry Pi.

"},{"location":"service.docker/#preparation-of-env-files-for-docker-command","title":"Preparation of env files for docker command","text":"

Notice - you may not have to do it if you use docker-compose (I think...).

If you use docker command directly you need to edit env files and remove quotation marks from the files (this is a limitation of the Docker)

For example:

CAMERA_COMMAND_EXTRA_PARAMS=\"--immediate --nopreview --thumb none -o\"\n

becomes

CAMERA_COMMAND_EXTRA_PARAMS=--immediate --nopreview --thumb none -o\n
"},{"location":"service.docker/#raspberry-pi-csi-or-usb-camera","title":"Raspberry Pi CSI or USB camera","text":"

We assume that .csi is a env file with example variables after edit, it is possible to run below command and have screenshots sent to the Prusa Connect.

docker run --env-file .csi -v /run/udev:/run/udev:ro -v /dev/:/dev/ --device /dev:/dev --read-only quay.io/kaszpir/prusa-connect-script:03c4886\n
"},{"location":"service.docker/#raspberry-pi-and-remote-cams","title":"Raspberry Pi and remote cams","text":"

If you use remote camera you can make command even shorter:

docker run --env-file .esp32 --read-only quay.io/kaszpir/prusa-connect-script:03c4886\n
"},{"location":"service.docker/#other-examples","title":"Other examples","text":"
docker run --env-file .docker-csi --device /dev:/dev -v /dev/:/dev/ -v /run/udev:/run/udev:ro -it quay.io/kaszpir/prusa-connect-script:03c4886-arm64\n\ndocker run --env-file .docker-esphome-snapshot --read-only quay.io/kaszpir/prusa-connect-script:03c4886-amd64\ndocker run --env-file .docker-video0 --device /dev:/dev -v /dev/:/dev/ -v /run/udev:/run/udev:ro -it quay.io/kaszpir/prusa-connect-script:03c4886\n
"},{"location":"service.docker/#running-multiple-cameras-at-once","title":"Running multiple cameras at once","text":"

Create env file per camera and run each container separately.

"},{"location":"service.docker/#docker-compose","title":"docker-compose","text":"

Instead of running single command per container, you can manage them using docker-compose. Example docker-compose.yaml contains some examples. Some sections are commented out, though.

Notice they still require proper env files to work, for example copy usb.dist as .usb, edit its parameters and run docker-compose up

Notice that you may need to change remote cameras addresses from hostnames to IP addresses.

Another notice that sharing /dev/ or /dev/shm across different containers with different architectures may be problematic.

"},{"location":"service/","title":"Install script as service","text":"

Depending on the distro there are various options to configure scripts as service.

  • systemd - most common service on Linux systems
  • docker - run as Docker container

Other - not implemented, do it on your own.

"},{"location":"service.systemd/","title":"Install script as systemd service","text":"

Depending on the distro there are various options to configure scripts as service. On newer distros Raspberry Pi runs systemd, we will use that.

cd /home/pi/src/prusa-connect-camera-script\nsudo cp -f prusa-connect-camera@.service /etc/systemd/system/prusa-connect-camera@.service\nsudo systemctl daemon-reload\n
"},{"location":"service.systemd/#configuring-single-camera","title":"Configuring single camera","text":"

Assuming that /home/pi/src/prusa-connect-camera-script/.env file was created in previous steps, we use that .env file as example camera config.

Notice there is no dot before env in the commands below!

sudo systemctl enable prusa-connect-camera@env.service\nsudo systemctl start prusa-connect-camera@env.service\nsudo systemctl status prusa-connect-camera@env.service\n

Above commands will enable given service on device restart (reboot), start the service and show current status.

"},{"location":"service.systemd/#configure-multiple-cameras","title":"Configure multiple cameras","text":"

This project allows spawning multiple systemd units. The suffix after @ defines what env file to load from given path. For example if you set unit file name to prusa-connect-camera@csi.service then systemd will load env vars from the file under path /home/pi/src/prusa-connect-camera-script/.csi

So in short:

  • copy csi.dist as .csi and edit it
  • copy prusa-connect-camera@.service as prusa-connect-camera@csi.service
  • you may additionally edit unit file if you use different config paths
  • run systemctl daemon-reload
  • enable systemd service
  • start systemd service
cd /home/pi/src/prusa-connect-camera-script/\ncp csi.dist .csi\n# edit .csi and set custom command params, token and fingerprint etc...\nsudo systemctl enable prusa-connect-camera@csi.service\nsudo systemctl start prusa-connect-camera@csi.service\nsudo systemctl status prusa-connect-camera@csi.service\n

For another camera, let say for another camera attached over USB

cd /home/pi/src/prusa-connect-camera-script/\ncp usb.dist .usb1\n# edit .usb1 and set device, token and fingerprint etc...\nsudo systemctl enable prusa-connect-camera@usb1.service\nsudo systemctl start prusa-connect-camera@usb1.service\nsudo systemctl status prusa-connect-camera@usb1.service\n

For esphome camera, for static images:

cd /home/pi/src/prusa-connect-camera-script/\ncp esphome-snapshot.dist .esphome1\n# edit .esphome1 and set device, token and fingerprint etc...\nsudo systemctl enable prusa-connect-camera@esphome1.service\nsudo systemctl start prusa-connect-camera@esphome1.service\nsudo systemctl status prusa-connect-camera@esphome1.service\n

I hope you get the idea...

"},{"location":"service.systemd/#uninstall-systemd-service","title":"Uninstall systemd service","text":"

Just run two commands per camera (where csi is a camera config):

sudo systemctl stop prusa-connect-camera@csi.service\nsudo systemctl disable prusa-connect-camera@csi.service\n

After removing all cameras remove systemd service definition and reload daemon:

sudo rm -f /etc/systemd/system/prusa-connect-camera@.service\nsudo systemctl daemon-reload\n
"},{"location":"stream.mediamtx/","title":"mediamtx","text":"

Use mediamtx on another Raspberry Pi to create RTSP camera stream for test.

Assuming you run mediamtx with Raspberry Pi CSI camera and that raspberry-pi is the hostname of your device and that you expose two cams:

  • CSI Rasberry Pi camera under /dev/video0
  • USB camera under /dev/video1

so your mediamtx.yml has config fragment such as:

paths:\n  cam:\n    source: rpiCamera\n\n  endoscope:\n    runOnInit: ffmpeg -f v4l2 -pix_fmt mjpeg -video_size 1280x960 -framerate 30 -i /dev/video1 -c:v libx264 -preset ultrafast -b:v 6000k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH\n    runOnInitRestart: yes\n

Start mediamtx server:

./mediamtx\n

This should allow us to reach two streams, replace rpi-address with the name of your Raspberry Pi hostname or IP address. The ports are default for mediamtx.

ffplay rtsp://rpi-address:8554/cam\nffplay rtsp://rpi-address:8554/endoscope\n

Or you could watch it via web browser under endpoints such as

http://rpi-address:8889/cam\nhttp://rpi-address:8889/endoscope\n
"},{"location":"stream.mediamtx/#example-with-single-camera-over-usb","title":"Example with single camera over USB","text":"

Raspberry Pi Zero 2 + Logitech C920, thanks to user [&] undso.io for working example.

Allows to have a camera live stream and prusa camera script to use that stream as source of the images to send to PrusaConnect.

mediamtx config fragment

paths:\n  cam:\n    runOnInit: ffmpeg -f v4l2 -i /dev/video0 -pix_fmt yuv420p -video_size 1920x1080 -framerate 30 -preset ultrafast -c:v libx264 -b:v 6000k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH\n    runOnInitRestart: yes\n

env file for prusa connect script, remember to replace [rpizero-ip] with device address (or try 127.0.0.1 or 0.0.0.0 if script runs on the same host where mediamtx runs)

PRINTER_ADDRESS=...\nPRUSA_CONNECT_CAMERA_TOKEN=...\nPRUSA_CONNECT_CAMERA_FINGERPRINT=...\nCAMERA_DEVICE=/dev/null\nCAMERA_COMMAND=ffmpeg\nCAMERA_COMMAND_EXTRA_PARAMS=\"-loglevel error -y -rtsp_transport udp -i 'rtsp://[rpizero-ip]:8554/cam' -f image2 -vframes 1 -pix_fmt yuv420p \"\n
"},{"location":"test.config/","title":"Test the config","text":"
  • ensure to turn on the 3D Printer so that it sends telemetry, otherwise images will sent and you will get successful image uploads but on PrusaConnect page they will not be available
  • run below commands, we assume .env is the camera config we defined earlier
set -o allexport; source .env; set +o allexport\n./prusa-connect-camera.sh\n

Above commands will load env vars and will start the script. In the beginning script shows some commands that will be executed, for example command to fetch the image from camera, example log line:

Camera capture command: fswebcam -d /dev/video0 --resolution 640x480 --no-banner /dev/shm/camera_87299de9-ea57-45be-b6ea-4d388a52c954.jpg\n

so you should run:

fswebcam -d /dev/video0 --resolution 640x480 --no-banner /dev/shm/camera_87299de9-ea57-45be-b6ea-4d388a52c954.jpg\n

and get the outputs from the command, and also it should write an image.

Check for errors, if any, if everything is ok you should see a lot of 204 every 10s.

If not, see troubleshooting, copy logs and raise an issue on GitHub.

"},{"location":"troubleshooting/","title":"Troubleshooting","text":"

Things to check if it does not work.

"},{"location":"troubleshooting/#general","title":"General","text":"
  • check /dev/shm/camera_*.stdout and /dev/shm/camera_*.stderr files for more details - if they still that 'everything is okay' then probably you have issues with permissions when running script for the second time (see below)

  • if you use feature to ping the printer then ensure printer is up and running and responds to ping, or just disable the feature (set PRINTER_ADDRESS=\"\" or to PRINTER_ADDRESS=127.0.0.1)

  • check if the camera actually works - check cables if they are not damaged, if the cables are properly plugged, if the camera connects to the network...

  • check if the camera supports passed parameters such as resolution and codec, especially after replacing the camera - see tuning how to use v4l2-ctl to see available camera options.

  • check if any other app is not accessing the camera - especially local cameras are locked by another processes.

If another application is accessing camera then unfortunately only one app can access the camera and you must decide which app to run.

This means if you have something like Klipper/Obico/PrusaLink/motioneye/frigate (and so on) accessing the directly attached device to the Raspberry Pi then it will not work.

In such case you can try to find the process using fuser package, assuming /dev/video0 is your camera:

sudo apt install -y psmisc\nfuser /dev/video0\n

See StackOverflow for more details.

In general you could create a loopback camera device but this is quite a lot of work to do.

  • check IP/domain names for remote camera - try that you can access camera over IP address, otherwise you have a DNS issues.

  • file permissions - check files under /dev/shm/camera* and /dev/video0

ls -la /dev/shm/camera* /dev/video*\n

and compare them with the current user executing the script or the user that is running docker (see below) or systemd service (see section below).

The quickest fix is just to delete files in /dev/shm/camera_* to fix only specific permission issues:

sudo systemctl stop prusa-connect-camera@env.service\nsudo rm -f /dev/shm/camera_*\nsudo systemctl start prusa-connect-camera@env.service\n

and see if the issue is resolved.

If you still have issues due to accessing /dev/video* then ensure the user is added to video group.

"},{"location":"troubleshooting/#docker-troubleshooting","title":"Docker troubleshooting","text":"
  • dockerized script - ensure you restart the pi after adding docker, check user permissions to the mounted files and devices (unfortunately this can get very messy with direct access to the devices and files on the host)

  • check IP/domain names for remote camera - ensure that you can access camera over IP address (or fully qualified domain name), because .local or .lan domains are not resolved. Another option is to reconfigure docker to use proper local DNS servers and not generic 8.8.8.8.

You can also try to run container with --add-host or extra_hosts in docker-compose.

Another option is to run container with --network=\"host\" or network_mode: \"host\" in docker-compose.

"},{"location":"troubleshooting/#systemd-troubleshooting","title":"Systemd troubleshooting","text":""},{"location":"troubleshooting/#get-systemd-logs","title":"Get systemd logs","text":"

If the script runs locally but service is not running then you can get the logs like below, ensure to replace env with the name your camera is using:

  • stop service
sudo systemctl stop prusa-connect-camera@env.service\n
  • open new terminal and type:
sudo journalctl -f -u prusa-connect-camera\n

and keep it open

  • get back to the first terminal and write commands:
sudo systemctl start prusa-connect-camera@env.service\nsleep 10\nsudo systemctl stop prusa-connect-camera@env.service\n
  • get back to the terminal with running journalctl and see the logs and look carefully at the errors described there

  • copy the output from starting to the another starting command and paste on GitHub

"},{"location":"troubleshooting/#permissions-issues","title":"Permissions issues","text":"
  • check if the user used in systemd file is the same as the one which executed test command - and you can edit systemd unit file via nano editor
sudo nano /etc/systemd/system/prusa-connect-camera@.service\n

and replace User=pi and Group=pi with the current user and group, then reload systemd and start service again

sudo systemctl daemon-reload\nsudo systemctl start prusa-connect-camera@env.service\n

This way it will use your user account to access camera device and write files.

"}]} \ No newline at end of file diff --git a/service.docker/index.html b/service.docker/index.html new file mode 100644 index 0000000..585adc5 --- /dev/null +++ b/service.docker/index.html @@ -0,0 +1,1137 @@ + + + + + + + + + + + + + + + + + + + + + + + + Docker - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + +

Install script as docker container

+

You can run the app as container.

+

Multi-platform images are available at quay.io/kaszpir/prusa-connect-script.

+

Currently available platforms:

+
    +
  • linux/amd64 (64bit)
  • +
  • linux/arm64 (64bit)
  • +
  • linux/arm/v7 (32bit)
  • +
+

Preparation of the host

+

Install docker on Debian.

+

Optional - you may want to make sure current user is in docker group so it is possible +to run containers without using sudo:

+
sudo usermod -a -G docker $(whoami)
+
+

logout and login again, or reboot Raspberry Pi.

+

Preparation of env files for docker command

+

Notice - you may not have to do it if you use docker-compose (I think...).

+

If you use docker command directly you need to edit env files +and remove quotation marks from the files (this is a limitation of the Docker)

+

For example:

+
CAMERA_COMMAND_EXTRA_PARAMS="--immediate --nopreview --thumb none -o"
+
+

becomes

+
CAMERA_COMMAND_EXTRA_PARAMS=--immediate --nopreview --thumb none -o
+
+

Raspberry Pi CSI or USB camera

+

We assume that .csi is a env file with example variables after edit, it is +possible to run below command and have screenshots sent to the Prusa Connect.

+ +
docker run --env-file .csi -v /run/udev:/run/udev:ro -v /dev/:/dev/ --device /dev:/dev --read-only quay.io/kaszpir/prusa-connect-script:03c4886
+
+ + +

Raspberry Pi and remote cams

+

If you use remote camera you can make command even shorter:

+
docker run --env-file .esp32 --read-only quay.io/kaszpir/prusa-connect-script:03c4886
+
+

Other examples

+ +
docker run --env-file .docker-csi --device /dev:/dev -v /dev/:/dev/ -v /run/udev:/run/udev:ro -it quay.io/kaszpir/prusa-connect-script:03c4886-arm64
+
+docker run --env-file .docker-esphome-snapshot --read-only quay.io/kaszpir/prusa-connect-script:03c4886-amd64
+docker run --env-file .docker-video0 --device /dev:/dev -v /dev/:/dev/ -v /run/udev:/run/udev:ro -it quay.io/kaszpir/prusa-connect-script:03c4886
+
+ + +

Running multiple cameras at once

+

Create env file per camera and run each container separately.

+

docker-compose

+

Instead of running single command per container, you can manage them using +docker-compose. Example docker-compose.yaml contains some examples. +Some sections are commented out, though.

+

Notice they still require proper env files to work, for example +copy usb.dist as .usb, edit its parameters and run docker-compose up

+

Notice that you may need to change remote cameras addresses from hostnames +to IP addresses.

+

Another notice that sharing /dev/ or /dev/shm across different containers +with different architectures may be problematic.

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/service.systemd/index.html b/service.systemd/index.html new file mode 100644 index 0000000..372305b --- /dev/null +++ b/service.systemd/index.html @@ -0,0 +1,1075 @@ + + + + + + + + + + + + + + + + + + + + + + + + Systemd - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Install script as systemd service

+

Depending on the distro there are various options to configure scripts as service. +On newer distros Raspberry Pi runs systemd, we will use that.

+
cd /home/pi/src/prusa-connect-camera-script
+sudo cp -f prusa-connect-camera@.service /etc/systemd/system/prusa-connect-camera@.service
+sudo systemctl daemon-reload
+
+

Configuring single camera

+

Assuming that /home/pi/src/prusa-connect-camera-script/.env file was created in +previous steps, we use that .env file as example camera config.

+

Notice there is no dot before env in the commands below!

+
sudo systemctl enable prusa-connect-camera@env.service
+sudo systemctl start prusa-connect-camera@env.service
+sudo systemctl status prusa-connect-camera@env.service
+
+

Above commands will enable given service on device restart (reboot), +start the service and show current status.

+

Configure multiple cameras

+

This project allows spawning multiple systemd units. +The suffix after @ defines what env file to load from given path. +For example if you set unit file name to prusa-connect-camera@csi.service +then systemd will load env vars from the file under path +/home/pi/src/prusa-connect-camera-script/.csi

+

So in short:

+
    +
  • copy csi.dist as .csi and edit it
  • +
  • copy prusa-connect-camera@.service as prusa-connect-camera@csi.service
  • +
  • you may additionally edit unit file if you use different config paths
  • +
  • run systemctl daemon-reload
  • +
  • enable systemd service
  • +
  • start systemd service
  • +
+
cd /home/pi/src/prusa-connect-camera-script/
+cp csi.dist .csi
+# edit .csi and set custom command params, token and fingerprint etc...
+sudo systemctl enable prusa-connect-camera@csi.service
+sudo systemctl start prusa-connect-camera@csi.service
+sudo systemctl status prusa-connect-camera@csi.service
+
+

For another camera, let say for another camera attached over USB

+
cd /home/pi/src/prusa-connect-camera-script/
+cp usb.dist .usb1
+# edit .usb1 and set device, token and fingerprint etc...
+sudo systemctl enable prusa-connect-camera@usb1.service
+sudo systemctl start prusa-connect-camera@usb1.service
+sudo systemctl status prusa-connect-camera@usb1.service
+
+

For esphome camera, for static images:

+
cd /home/pi/src/prusa-connect-camera-script/
+cp esphome-snapshot.dist .esphome1
+# edit .esphome1 and set device, token and fingerprint etc...
+sudo systemctl enable prusa-connect-camera@esphome1.service
+sudo systemctl start prusa-connect-camera@esphome1.service
+sudo systemctl status prusa-connect-camera@esphome1.service
+
+

I hope you get the idea...

+

Uninstall systemd service

+

Just run two commands per camera (where csi is a camera config):

+
sudo systemctl stop prusa-connect-camera@csi.service
+sudo systemctl disable prusa-connect-camera@csi.service
+
+

After removing all cameras remove systemd service definition and reload daemon:

+
sudo rm -f /etc/systemd/system/prusa-connect-camera@.service
+sudo systemctl daemon-reload
+
+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/service/index.html b/service/index.html new file mode 100644 index 0000000..978a7e8 --- /dev/null +++ b/service/index.html @@ -0,0 +1,943 @@ + + + + + + + + + + + + + + + + + + + + + + + + Overview - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Install script as service

+

Depending on the distro there are various options to configure scripts as service.

+
    +
  • systemd - most common service on Linux systems
  • +
  • docker - run as Docker container
  • +
+

Other - not implemented, do it on your own.

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..d041680 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,123 @@ + + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.csi.legacy/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.csi.libcamera/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.esphome.snapshot/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.esphome.stream/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.mjpg/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.rtsp/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.snapshot/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/config.for.camera.usb/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/configuration.env.full/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/configuration.env/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/configuration.overview/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/configuration.tuning/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/installation/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/performance/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/prusa.connect/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/requirements/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/service.docker/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/service/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/service.systemd/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/stream.mediamtx/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/test.config/ + 2024-05-08 + daily + + + https://nvtkaszpir.github.io/prusa-connect-camera-script/troubleshooting/ + 2024-05-08 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..89f99a8bc9555446fe985647931e2467d320bcd4 GIT binary patch literal 419 zcmV;U0bKqciwFo19y?|N|8r?{Wo=<_E_iKh0Ns~MZsRZvhW9;1;Jqog=m2fuxVxTU z<^YP!*lP5uNF_~AKXM!tIY3cB(nc0ZQ~&3OMD?$q)@+U#Nqe_#?xAZo=#(F|o3_or zzi;hR^E%x1DH=lFMxRPCL+EgqTRS$~%XOTO}<<*^-Jnu;|5d`)xK!Z2dSqbPtbh z_owZia>&(o6Q*YACfrB-7)GhhxfeH$+bwP1NX=^~L;-oP5CIsHNr40tpz2Vco_`R3ClX8O*h{=U>@+FC8Hd N{{aE5)mQ5h002D5$(;ZI literal 0 HcmV?d00001 diff --git a/static/esp32-camera.jpg b/static/esp32-camera.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f7e3d082ecac618954995fbae7639880cb0a3f5 GIT binary patch literal 80717 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�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 uA9(t6RzK25`qfr`Q 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 literal 0 HcmV?d00001 diff --git a/static/prusa-connect-cam.png b/static/prusa-connect-cam.png new file mode 100644 index 0000000000000000000000000000000000000000..e789c0b05d2fe008a55dc1d6b16c70676645bef1 GIT binary patch literal 11494 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 + + + + + + + + + + + + + + + + + + + + Streaming cameras with mediamtx - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

mediamtx

+

Use mediamtx on another Raspberry Pi +to create RTSP camera stream for test.

+

Assuming you run mediamtx with Raspberry Pi CSI camera +and that raspberry-pi is the hostname of your device and that you expose two cams:

+
    +
  • CSI Rasberry Pi camera under /dev/video0
  • +
  • USB camera under /dev/video1
  • +
+

so your mediamtx.yml has config fragment such as:

+ + +
paths:
+  cam:
+    source: rpiCamera
+
+  endoscope:
+    runOnInit: ffmpeg -f v4l2 -pix_fmt mjpeg -video_size 1280x960 -framerate 30 -i /dev/video1 -c:v libx264 -preset ultrafast -b:v 6000k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
+    runOnInitRestart: yes
+
+ + +

Start mediamtx server:

+
./mediamtx
+
+

This should allow us to reach two streams, replace rpi-address with the name +of your Raspberry Pi hostname or IP address. The ports are default for mediamtx.

+
ffplay rtsp://rpi-address:8554/cam
+ffplay rtsp://rpi-address:8554/endoscope
+
+

Or you could watch it via web browser under endpoints such as

+
http://rpi-address:8889/cam
+http://rpi-address:8889/endoscope
+
+

Example with single camera over USB

+

Raspberry Pi Zero 2 + Logitech C920, thanks to user [&] undso.io +for working example.

+

Allows to have a camera live stream and prusa camera script to use that stream +as source of the images to send to PrusaConnect.

+ +

mediamtx config fragment

+
paths:
+  cam:
+    runOnInit: ffmpeg -f v4l2 -i /dev/video0 -pix_fmt yuv420p -video_size 1920x1080 -framerate 30 -preset ultrafast -c:v libx264 -b:v 6000k -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH
+    runOnInitRestart: yes
+
+

env file for prusa connect script, remember to replace [rpizero-ip] with +device address (or try 127.0.0.1 or 0.0.0.0 if script runs on the same host where mediamtx runs)

+
PRINTER_ADDRESS=...
+PRUSA_CONNECT_CAMERA_TOKEN=...
+PRUSA_CONNECT_CAMERA_FINGERPRINT=...
+CAMERA_DEVICE=/dev/null
+CAMERA_COMMAND=ffmpeg
+CAMERA_COMMAND_EXTRA_PARAMS="-loglevel error -y -rtsp_transport udp -i 'rtsp://[rpizero-ip]:8554/cam' -f image2 -vframes 1 -pix_fmt yuv420p "
+
+ + +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/test.config/index.html b/test.config/index.html new file mode 100644 index 0000000..bbe7ba8 --- /dev/null +++ b/test.config/index.html @@ -0,0 +1,962 @@ + + + + + + + + + + + + + + + + + + + + + + + + Test Config - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Test the config

+
    +
  • ensure to turn on the 3D Printer so that it sends telemetry, otherwise images + will sent and you will get successful image uploads but on PrusaConnect page + they will not be available
  • +
  • run below commands, we assume .env is the camera config we defined earlier
  • +
+
set -o allexport; source .env; set +o allexport
+./prusa-connect-camera.sh
+
+

Above commands will load env vars and will start the script. +In the beginning script shows some commands that will be executed, for example +command to fetch the image from camera, example log line:

+ +
Camera capture command: fswebcam -d /dev/video0 --resolution 640x480 --no-banner /dev/shm/camera_87299de9-ea57-45be-b6ea-4d388a52c954.jpg
+
+

so you should run:

+
fswebcam -d /dev/video0 --resolution 640x480 --no-banner /dev/shm/camera_87299de9-ea57-45be-b6ea-4d388a52c954.jpg
+
+ + +

and get the outputs from the command, and also it should write an image.

+

Check for errors, if any, if everything is ok you should see a lot of 204 +every 10s.

+

If not, see troubleshooting, copy logs +and raise an issue on GitHub.

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/troubleshooting/index.html b/troubleshooting/index.html new file mode 100644 index 0000000..2cccbeb --- /dev/null +++ b/troubleshooting/index.html @@ -0,0 +1,1182 @@ + + + + + + + + + + + + + + + + + + + + + + + + Troubleshooting - Prusa Connect Camera Script + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + +

Troubleshooting

+

Things to check if it does not work.

+

General

+
    +
  • +

    check /dev/shm/camera_*.stdout and /dev/shm/camera_*.stderr + files for more details - if they still that 'everything is okay' + then probably you have issues with permissions when running script + for the second time (see below)

    +
  • +
  • +

    if you use feature to ping the printer then ensure printer is up and running + and responds to ping, or just disable the feature (set PRINTER_ADDRESS="" or + to PRINTER_ADDRESS=127.0.0.1)

    +
  • +
  • +

    check if the camera actually works - check cables if they are not damaged, + if the cables are properly plugged, if the camera connects to the network...

    +
  • +
  • +

    check if the camera supports passed parameters such as resolution and codec, + especially after replacing the camera - see tuning + how to use v4l2-ctl to see available camera options.

    +
  • +
  • +

    check if any other app is not accessing the camera - especially local cameras + are locked by another processes.

    +
  • +
+

If another application is accessing camera then unfortunately only one app can + access the camera and you must decide which app to run.

+

This means if you have something like Klipper/Obico/PrusaLink/motioneye/frigate + (and so on) accessing the directly attached device to the Raspberry Pi + then it will not work.

+

In such case you can try to find the process + using fuser package, assuming /dev/video0 is your camera:

+
sudo apt install -y psmisc
+fuser /dev/video0
+
+

See StackOverflow + for more details.

+

In general you could create a loopback camera device + but this is quite a lot of work to do.

+
    +
  • +

    check IP/domain names for remote camera - try that you can access camera over + IP address, otherwise you have a DNS issues.

    +
  • +
  • +

    file permissions - check files under /dev/shm/camera* and /dev/video0

    +
  • +
+
ls -la /dev/shm/camera* /dev/video*
+
+

and compare them with the current user executing the script or the user that + is running docker (see below) or systemd service (see section below).

+

The quickest fix is just to delete files in /dev/shm/camera_* + to fix only specific permission issues:

+
sudo systemctl stop prusa-connect-camera@env.service
+sudo rm -f /dev/shm/camera_*
+sudo systemctl start prusa-connect-camera@env.service
+
+

and see if the issue is resolved.

+

If you still have issues due to accessing /dev/video* then ensure the user + is added to video group.

+

Docker troubleshooting

+
    +
  • +

    dockerized script - ensure you restart the pi after adding docker, + check user permissions to the mounted files and devices (unfortunately this can + get very messy with direct access to the devices and files on the host)

    +
  • +
  • +

    check IP/domain names for remote camera - ensure that you can access camera + over IP address (or fully qualified domain name), because .local or .lan + domains are not resolved. Another option is to reconfigure docker to use proper + local DNS servers and not generic 8.8.8.8.

    +
  • +
+

You can also try to run container with --add-host + or + extra_hosts + in docker-compose.

+

Another option is to run container with --network="host" + or + network_mode: "host" + in docker-compose.

+

Systemd troubleshooting

+

Get systemd logs

+

If the script runs locally but service is not running then you can get the logs +like below, ensure to replace env with the name your camera is using:

+
    +
  • stop service
  • +
+
sudo systemctl stop prusa-connect-camera@env.service
+
+
    +
  • open new terminal and type:
  • +
+
sudo journalctl -f -u prusa-connect-camera
+
+

and keep it open

+
    +
  • get back to the first terminal and write commands:
  • +
+
sudo systemctl start prusa-connect-camera@env.service
+sleep 10
+sudo systemctl stop prusa-connect-camera@env.service
+
+
    +
  • +

    get back to the terminal with running journalctl and see the logs + and look carefully at the errors described there

    +
  • +
  • +

    copy the output from starting to the another starting command and paste + on GitHub

    +
  • +
+

Permissions issues

+
    +
  • check if the user used in systemd file is the same as the one which executed + test command - and you can edit systemd unit file via nano editor
  • +
+
sudo nano /etc/systemd/system/prusa-connect-camera@.service
+
+

and replace User=pi and Group=pi with the current user and group, + then reload systemd and start service again

+
sudo systemctl daemon-reload
+sudo systemctl start prusa-connect-camera@env.service
+
+

This way it will use your user account to access camera device and write files.

+ +
+
+ + + Last update: + 2024-05-08 08:38:11 +0200 (UTC) + + + +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file