Cameras¶
The machine has two cameras, one in the lid and one in the print head (The cameras). ForgeFIRM serves both over plain HTTP from the web control panel: MJPEG for anything that can read a stream of JPEGs, and an H.264 live stream for clients that decode video (the panel uses it when the browser can). There is no app, no cloud relay, and no proprietary protocol. This page tells you the one rule that governs the cameras, how to watch them, and what you get.
Read the Safety page first
ForgeFIRM is not the manufacturer's firmware. Read Safety before you run a job.
The sensors, what they can do, and the 8 MP status are in The cameras. The pipeline, the lighting, the camera-path sharing, and why the image looks the way it does are in The video pipeline.
Privacy: the cameras only work with the lid closed¶
Neither camera captures anything while the lid is open. Not the live view, not a snapshot, and not an image requested by the Glowforge service in cloud mode. Close the lid and everything works; open it and the sensors stop.
The reason is where the lid camera points. It is mounted in the lid, so raising the lid swings it up to face the room, and in cloud mode the shutter is not yours to press: the service asks for images on its own schedule, whenever it is connected. The rule removes the question. The enclosure being shut is the condition for an image to exist at all.
What the rule covers
- Both cameras. The head camera is gated too, so this is one rule to remember rather than a rule with an exception you have to trust.
- Every way in: the panel,
/cam/stream,/cam/snapshot, the mjpg-streamer aliases, LightBurn, and cloud mode's image actions. - Capture already running. Opening the lid stops a live stream within about a frame and shuts the sensor down; it does not merely block new requests.
- The lamps. A refused capture never raises them, so an attempt with the lid open leaves no trace.
How it behaves
| Situation | What happens |
|---|---|
| Snapshot requested with the lid open | 409 and a message naming the lid; no image data |
| Stream requested with the lid open | 409; the stream never opens |
| Lid opened while a stream is running | the stream ends cleanly and the pipeline is torn down |
| Lid state unreadable | treated as open: capture refused |
| Cloud service asks for an image with the lid open | refused, and reported back to the service as a failed action rather than left hanging |
| Lid closed again | everything works immediately; nothing to restart |
GET /cam/status reports it: capture_allowed is false whenever the lid is
open, and stopped_by_lid records that the last capture ended because the
lid opened rather than going idle. The panel's Status tab says lid open, the
cameras are off rather than showing a stream error.
Where the check comes from. The lid signal is the same one the hardware safety chain uses to gate the beam, the series combination of both lid switches, not a software flag, and the check fails closed: if the lid state cannot be read at all, the cameras stay dark. A unit test in CI covers that direction; an acceptance test on real hardware covers the end-to-end behavior.
One thing it costs. The factory firmware ran the cloud's focus hunt with the lid open, and part of a hunt is a head capture. Those captures are refused, so a hunt attempted with the lid open fails instead of completing. Close the lid before letting the app focus or print (Cloud mode).
What it is not. This is a rule enforced by the two programs that own the sensors, not a hardware cut-off: the sensor rails stay powered, and anyone with root on the machine could bypass it. It protects you from the Glowforge service, from other software on your network, and from a stream you forgot was running, not from someone who already controls the board. There is deliberately no setting to turn it off.
Watching it¶
In the panel. Open https://forgefirm.local/ or https://<machine-ip>/
and go to the Status tab.
The Lid camera card shows a still by default with Live and Refresh
buttons; Live switches the same frame to the running stream (H.264 when the
browser supports it, MJPEG otherwise), and Stop returns to the snapshot.
From another program. The endpoints are:
| URL | What it returns |
|---|---|
/cam/stream?cam=lid |
continuous MJPEG (multipart/x-mixed-replace) |
/cam/stream?cam=head |
the same, from the head camera |
/cam/h264?cam=lid |
continuous H.264 as fragmented MP4: the same picture in a fraction of the bytes, for clients that decode video |
/cam/snapshot?cam=lid |
one full-resolution JPEG |
/cam/snapshot?cam=lid&res=half |
one half-resolution JPEG (much faster) |
/cam/snapshot?cam=lid&q=1..100 |
a JPEG at the given quality |
/cam/status |
JSON: which sensor, which camera, frame rate, frame sizes, whether the lid currently permits capture |
/?action=stream |
the lid stream again, under the name mjpg-streamer clients expect |
/?action=snapshot |
one full-resolution lid JPEG, same aliasing |
The ?action= pair exists because a lot of software (print-server dashboards,
camera widgets, anything written against mjpg-streamer) assumes those exact
URLs. Point such a client at http://<machine-ip>/ and it works.
Every one of them answers 409 with the lid open, so a client that checks
status codes can tell "close the lid" apart from "the camera is broken".
Access. Reading the camera needs no login by default. The read-only
routes answer any client on your network, over plain HTTP on port 80 or
over HTTPS. A browser request must not be cross-site; that is what stops a
hostile page in another tab from reaching into your machine. The setting
panel_open_reads=0 closes the reads to logged-in sessions and the machine
itself (Settings). Anything that changes machine state
needs a login (The control panel).
The camera key. A program with no login, LightBurn or a stream viewer,
reads the cameras with the machine's camera key. Press Camera URL on
the Status tab's lid camera card: the panel shows the stream and snapshot
URLs with the key in them, ready to paste. The key is a key query
parameter, or the X-ForgeFIRM-Camera-Key header, on any read-only route,
over HTTP or HTTPS, with the reads open or closed. It authorizes reads and
nothing else. New key on the same card makes a fresh one; every URL that
carried the old key stops working. Treat the URL as a password for the
camera image.
LightBurn consumes the lid stream for its camera overlay while it drives motion over the Grbl connection; the two coexist.
What you get¶
| 5 MP machine (OV5648) | 8 MP machine (OV8856) | |
|---|---|---|
| Sensor frame captured | 2592 × 1944 | 3264 × 2448 |
| Live stream | 1296 × 972 | 1632 × 1224 |
| Full snapshot | 2592 × 1944 | 3264 × 2448 |
| Half snapshot | 1296 × 972 | 1632 × 1224 |
| Stream formats | MJPEG (quality 75 by default) and H.264 (about 1.5 Mbit/s by default) | same |
| Frame rate | 15 fps sustained | not measured; no 8 MP machine has been tested (The cameras) |
Measured on a 5 MP machine: 15.0 fps with a viewer attached, which is the rate the sensor itself produces in this mode; the machine is not the bottleneck. With the NEON demosaic feeding the hardware JPEG encoder, the daemon uses about 41 % of one CPU with one viewer, and LightBurn can watch the stream while jogging from the same session without disturbing motion. With the GPU demosaic feeding the H.264 stream, the stream's CPU cost drops to bookkeeping: about 14 % of the CPU for one viewer. A full-resolution still takes about 2.4 s to produce (2.7 s if the camera has to be started first), because 5 megapixels of demosaicing and JPEG encoding happen on the machine's CPU.
The live view is exactly half the capture in each axis because each 2 × 2 group of sensor pixels becomes one output pixel, rather than the frame being scaled down. That is what makes it cheap enough to run continuously (The video pipeline).
The image is the sensor's data, demosaiced and encoded, with fixed exposure and no tone curve; compared with a phone photo it looks flat, and that is expected. Nothing is recorded on the machine: if you want a recording, record the stream on the computer watching it (The video pipeline).
When something looks wrong¶
No picture at all, and a 409 mentioning the lid. Working as intended: the
lid is open. Close it. /cam/status shows capture_allowed: false while that
is the case. If the lid is shut and you still see this, one of the two lid
switches is not making, the same condition that would stop the laser firing,
so it is worth investigating rather than working around.
A black or nearly black picture. The scene is not lit: the exposure is
fixed, so the camera cannot compensate. Check the lid_lamp_idle setting
(Settings), and remember snapshots can carry their own
lamp=0..1023 level for one image.
The stream stops on its own. Either the lid opened (the panel says so), or someone else (another browser tab, LightBurn, the panel) asked for the other camera, or for a stream, and preempted yours. Reload; the panel does this automatically and says which it was.
"camera switch timed out". A viewer would not let go within the grace period. Close the other viewer and retry.
A snapshot returns 503. The camera could not start. The usual cause is another process holding the capture device; the daemon's log names the failing step (Logging).
/cam/status reports "sensor": "unknown". No camera was found on that
bus, or a sensor bound that this firmware has no profile for. On an 8 MP
machine see The cameras.