Files
shopdb-flask/docs/EVENTSAVER.md
cproudlock 2083029ff2
Some checks failed
CI / backend (push) Failing after 8s
CI / naming (push) Successful in 3s
CI / frontend (push) Successful in 10s
CI / migrations-mysql (push) Failing after 7s
Generate the collector script per site, and bring EventSaver into the repo
A site adopting ShopDB had to be handed two files and told what to edit in them.
Both are now the product's, and one of them the server writes for you.

GET /api/computers/client-script (admin) returns Report-AssetToShopDB.ps1 with
this site's values already in it: site_base_url becomes the -ApiUrl default and
the new computers_routableranges setting becomes -AllowedRanges. Only the
PARAMETER DEFAULTS are substituted - the copy in plugins/computers/client/ stays
runnable, so there is no second version to drift from the first - and everything
stamped stays overridable by argument or registry, because a bay may need to
differ from its site. Settings > Computers > Asset reporter edits the ranges,
downloads the script and shows its SHA-256.

The collector key is deliberately not stamped in, and a test fails if it ever
is. That file lands on every shop-floor PC, and a token spread across hundreds
of bays cannot be rotated quietly; it stays in the registry, provisioned per
ADOPTING-AT-ANOTHER-SITE.md.

The routable ranges are the last thing that was hardcoded in that script. They
are now a setting, so West Jefferson's two CIDRs move out of source code and
into that site's own configuration - which is what ADR-015 asks for - and a site
that sets nothing still works, because the script falls back to the NIC carrying
the default route.

EventSaver joins it in plugins/slides/client/, source only: EventSaver.cs and
EventSaver.ini, no compiled .scr - a binary is a release asset, like the
installer exe. The share path that was compiled into Config.Folder is gone. It
used to be the fallback when the ini was missing, which silently pointed a new
site at the reference site's file server; it is now empty, and failing visibly
beats displaying another site's slides. Verified by compiling the edited source
in the Windows VM with the in-box csc.exe: 15,872 bytes, exit 0.

Also: the DSC example in the adoption guide gains a CollectorRanges resource and
stops passing -ApiUrl to a script that already reads BaseUrl from the registry
the same example writes, and the guide points at the generated download instead
of hand-editing a URL.

The contract test caught the endpoint importing shopdb directly for the version
string, which ADR-002 forbids a plugin from doing. The product and contract
versions are in app.config now, which a plugin reads through current_app.

Adds docs/proposals/printer-assignment.md: assign printers to a PC in ShopDB and
let the bay install them, with what the fleet data says about drivers - HP and
Xerox cover 41 of 44 printers with universal drivers, there are no Brother
printers at all despite 208 files of Brother inkjet drivers in the installer,
and printerdrivers holds one row pointing at a per-model folder instead of a
universal driver.
2026-08-18 15:51:14 -04:00

5.6 KiB

EventSaver

A rotating-image screensaver for shop-floor PCs. Idle bays show the slides managed in ShopDB, so a safety notice or a shift message reaches the floor without anyone walking to each machine.

It is a small C# WinForms screensaver (.scr), not part of the ShopDB server. It is documented here because ShopDB serves its content and because a site adopting the fleet tools needs to know how it is configured.

For how to deploy it at a new site, see ADOPTING-AT-ANOTHER-SITE.md. This page is what it is, how it decides what to show, and how to diagnose it.

Two sources, one of them preferred

EventSaver reads EventSaver.ini from the directory it lives in, on every launch. Retargeting it never needs a recompile.

# HTTP mode: pull the playlist from ShopDB and cache it locally.
url=https://shopdb.example.net/api/slides/feed?surface=shopfloor

# Folder mode: used only when url is blank. SMB or local path.
# folder=\\fileserver\shopfloor\tv

interval=10     # seconds per image, unless a slide carries its own time
shuffle=0       # 1 = random order, 0 = ordered
fadems=600      # crossfade length in ms, reserved (v1 hard-cuts)

HTTP mode is the one to use. Slides are managed in ShopDB (Slides), the feed is public so the screensaver needs no credentials, and each PC caches what it fetched under its own LocalApplicationData. A bay that cannot reach the server keeps showing the last set it saw instead of going black - which matters, because the failure would otherwise be visible to the whole floor.

Folder mode predates the server and stays as a fallback for a site with no ShopDB instance yet, or for content nobody wants in the database.

If EventSaver.ini is missing, or both url and folder are blank, there is no source to read and the screensaver shows nothing. That is deliberate: the compiled-in fallback used to be the path of the site it was first built for, so a missing ini silently pointed a new site at someone else's file server. It is now empty, and failing visibly beats displaying the wrong site's slides. Ship the ini.

What decides the running order

Situation Behaviour
No order.txt Every image shows, sorted by filename. Number them 001_, 002_ to sequence.
shuffle=1 Random order, ignored when a playlist is present.
order.txt present ONLY the listed files show, in the listed order, looped.

order.txt is the strict-sequence option and is the whole playlist - a file not listed does not appear. Per-slide duration is appended with a pipe:

# Lines starting with # or ; are ignored.
001_welcome.jpg
002_safety_week.jpg|15
003_quality_board.jpg

In HTTP mode you do not write order.txt by hand: ShopDB's feed carries the order and each slide's own seconds, and EventSaver writes the equivalent order.txt into its cache so the same playlist logic runs either way.

A running screensaver rescans about every 30 seconds, so a slide change reaches the floor without touching any PC.

Command-line switches

Windows calls a screensaver with these, and EventSaver answers all three:

Switch Meaning
/s Show fullscreen. What Windows uses on idle.
/c Configuration. Reports the resolved source and cache directory, and points at the ini.
/p <hwnd> Preview pane. Deliberately a no-op - it keeps the Settings dialog happy without drawing a thumbnail nobody looks at.

EventSaver.scr /c is the first diagnostic: it says which source it resolved and where it is caching, which answers most "why is it showing the wrong thing" questions immediately.

Where it should and should not run

A screensaver over a live display is a defect, not a feature. The reference fleet excludes:

  • Kiosks and lobby displays, which show a live dashboard.
  • Metrology bays - CMM, Genspect, Keyence, wax-trace - where an operator watches a measurement run.
  • Bays that sleep, where the screensaver never wins anyway.

Targeting is per PC type in the GE-Enforce manifest, or by group assignment in Intune. Decide it deliberately: the cost of getting it wrong is a screensaver covering something someone needed to see.

Building it

The source is plugins/slides/client/EventSaver.cs. No SDK required - it compiles with the in-box .NET Framework compiler on any Windows 10 or 11 machine:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe ^
  /target:winexe /out:EventSaver.scr ^
  /reference:System.dll,System.Drawing.dll,System.Windows.Forms.dll ^
  EventSaver.cs

Ship EventSaver.scr and EventSaver.ini together. A .scr is an executable with a different extension, so it goes to C:\Windows\System32\.

Diagnosing it

Symptom Cause to check first
Blank screen, no images Source unreachable and cache empty. Run /c and open the url in a browser on that PC.
Old slides only Feed reachable at first run, not since. The cache is doing its job; fix the network path.
Wrong content Pointing at another surface, or another site's server. /c reports which.
Local ini edits revert Correct behaviour if the config is enforced by hash. Edit the copy on the share and update its DetectionValue.
Screensaver never starts Per-user setting missing. Check HKCU:\Control Panel\Desktop for SCRNSAVE.EXE, ScreenSaveActive and ScreenSaveTimeOut.

The feed is a plain public endpoint, so it can always be checked from the PC itself:

https://shopdb.example.net/api/slides/feed?surface=shopfloor

An empty slides array means no slides have been uploaded for that surface - the PC is configured correctly and there is nothing to show.