From ce6d44e69f8c5c734fef415b7dcac5166638438b Mon Sep 17 00:00:00 2001 From: cproudlock Date: Fri, 14 Aug 2026 14:19:16 -0400 Subject: [PATCH] docs: EventSaver, and how GE-Enforce reaches a bay in the first place EventSaver was undocumented anywhere a reader could find it. What it is, the two source modes and why HTTP is the one to use, how order.txt and the ShopDB feed each decide the running order, the three command-line switches Windows calls it with, where it must NOT run (a screensaver over a live dashboard or a metrology run is a defect), how to build it with the in-box compiler, and a table of symptoms with the first thing to check. The adoption guide also stopped short of the question it invites: the fleet tools assume GE-Enforce is already on the PC, so how does GE-Enforce get there. Both real paths are now written down - imaging time, which is how the shop-floor pipeline does it, and Intune, which is how the display cohort is deployed today because those PCs are Entra-joined with no share. Machine Configuration is possible and unshipped, with the caveat that matters: DSC and GE-Enforce are both convergence loops, so give each a layer to own rather than pointing them at the same configuration. --- docs/ADOPTING-AT-ANOTHER-SITE.md | 63 +++++++++++++++ docs/EVENTSAVER.md | 132 +++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+) create mode 100644 docs/EVENTSAVER.md diff --git a/docs/ADOPTING-AT-ANOTHER-SITE.md b/docs/ADOPTING-AT-ANOTHER-SITE.md index e4e98e3..2ec363a 100644 --- a/docs/ADOPTING-AT-ANOTHER-SITE.md +++ b/docs/ADOPTING-AT-ANOTHER-SITE.md @@ -351,6 +351,69 @@ been uploaded for that surface, not that the PC is misconfigured. --- +--- + +## Part 3: bootstrapping GE-Enforce itself + +The two parts above assume the tools are already on the PC. GE-Enforce is what +puts them there and keeps them there - so the question is how GE-Enforce gets +onto a bay in the first place. Two paths are supported, and they are the two +that actually occur: imaging time, and a management plane such as Intune. + +Whichever you use, the end state is the same three things: + +1. The client files in `C:\Program Files\GE\Shopfloor`. +2. `HKLM:\SOFTWARE\GE\ShopDB` carrying `BaseUrl`, and `ApiToken` where the scope + is served over HTTPS. +3. A scheduled task running the enforce cycle as SYSTEM. + +### At imaging time (the usual path) + +The shop-floor imaging pipeline registers the enforce task as its last step, +once the PC type is known - the type is what decides which manifest scope the +bay enforces. Self-contained types are skipped deliberately: a display kiosk +gets its configuration at imaging time and no share, so registering an enforce +task on one would give it a cycle with nothing to do. + +If you are building your own imaging pipeline, the equivalent step is: copy the +engine into a runtime directory, write the PC type where the client can read it, +and register the task. That is what `Install-GEEnforce.ps1` does in one call. + +### Through Intune + +`Install-GEEnforce.ps1` is parameterised for exactly this, and this is how the +display cohort is deployed today - those PCs are Entra-joined, have no file +share, and fetch their manifest over HTTPS: + +```powershell +.\Install-GEEnforce.ps1 ` + -PCType 'gea-shopfloor-common' ` + -ShopdbUrl 'https://shopdb.example.net' ` + -ShopdbToken 'shopdb_pat_REPLACE_WITH_YOUR_TOKEN' +``` + +Package it as a Win32 app with the client files. Detection rule: the scheduled +task exists **and** `HKLM:\SOFTWARE\GE\ShopDB\BaseUrl` matches your server, so a +PC that was imaged for another site is repaired rather than skipped. + +The token is a managed service token scoped to the GE-Enforce fetch scope, not +an admin credential. Scope it that way and a token read off a bay buys the +reader a manifest they could have read anyway. + +### With DSC (Machine Configuration) + +There is no shipped DSC configuration, but nothing about the end state resists +one - it is two registry values, a set of files and a scheduled task, which is +ordinary DSC territory. Express it the same way as the reporter example above: +`Registry` resources for `BaseUrl` and `ApiToken`, `File` resources for the +client, and a `Script` resource that registers the task. + +One caution. DSC converges state on a schedule and GE-Enforce is itself a +convergence loop, so running both against the same PC means two things fighting +to own the same configuration. Use DSC to install and configure the client, and +let GE-Enforce own everything downstream of that. Deciding which tool owns what +is the whole job; splitting it by layer is what keeps it answerable. + ## Which path to choose | You have | Use | diff --git a/docs/EVENTSAVER.md b/docs/EVENTSAVER.md new file mode 100644 index 0000000..6ced26b --- /dev/null +++ b/docs/EVENTSAVER.md @@ -0,0 +1,132 @@ +# 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](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. + +```ini +# 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, the +> binary falls back to a path compiled into `EventSaver.cs` - and that path +> belongs to the site it was first built for. Ship the ini. A missing ini is not +> a neutral default. + +## 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 ` | 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 + +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.