
A Visionect 13-inch e-paper table display. The hardware is still useful even when the original server-side licensing model no longer fits a small local deployment.
I wanted a simple self-hosted setup for a Visionect e-paper table display: a local server, a folder of images, and a device that wakes up periodically to check whether there is something new to show. Visionect’s own software stack can do far more than that, but my goal was narrower: understand enough of the device/server relationship to run a small local workflow without a web UI, database, or fleet-management system.
This post describes the process, not a recipe for cloning a proprietary system. It intentionally leaves out raw packet captures, exact message layouts, credentials, identifiers, binary patching details, and anything that would turn the write-up into a drop-in replacement guide. The useful part is the debugging method: how to reason about a black-box TCP/IP device safely and systematically.
Why I Looked at Self-Hosting
Visionect has historically supported the Visionect Software Suite (VSS), also previously known as Visionect Server, for managing its e-paper displays. The public documentation still describes VSS as the core backend for Visionect devices and says it can be hosted on-premises or in the cloud.
The licensing situation changed, though. As of July 2026, Visionect’s public plans and billing documentation says the company has moved to a cloud-first software model and that a per-device software license fee is now required for Place & Play CMS and all versions of VSS. The VSS release notes also record the point where mandatory licenses were introduced: VSS release 7.7.0. If you are searching for this problem, you may also see it described as a Visionect VSS licence issue, depending on spelling and region.
That matters for older devices and personal/lab deployments. If you bought a used Visionect display, inherited one from an office fit-out, or simply want a private local photo/table-sign workflow, you may find yourself with working hardware but a server-side licensing model that no longer fits the scale of the project.
This is not an argument against paying for supported commercial software. For a fleet, support, updates, security fixes, monitoring, and vendor accountability are real value. My case was different: one local device, one local network, and a desire to understand whether the hardware could be made useful for a narrow personal workflow without depending on the full hosted management product.
Public references:
- Visionect Software page
- Visionect Plans & Billing documentation
- Visionect Software Suite documentation
- Visionect Software Suite release notes
The Self-Hosted Shape
The final local setup is conceptually small.

The device is not treated as a web browser. It does not need to fetch a public URL or render HTML. The server prepares a screen update in the form the panel can use, waits for the device to connect, sends work if there is work, then lets the device return to a low-power state.
For my Visionect table-display use case, the server only needs to:
- Load configuration from a local file.
- Choose an image from a prepared folder.
- Listen for the device’s check-in.
- Acknowledge status.
- Send a display update when appropriate.
- Ask the device to sleep after the session.
- Log when check-ins happen.
That is a deliberately small subset of a full device-management platform.
Start With Observation, Not Implementation
The first mistake in this kind of project is to write code too early. A TCP server that accepts a socket and sends plausible-looking bytes is easy to build. A server that behaves like the system the device expects is much harder.
The practical workflow was:

In practice, “known-good” can mean a few different things, depending on what you can still run:
- A current, properly licensed Visionect VSS installation.
- A current VSS installation even before licensing is fully sorted, if the device still connects far enough for the server to answer and produce useful session traces.
- An older VSS Docker image that you already have and are allowed to use, if it predates the mandatory-license behavior and is useful as a lab reference.
- A vendor/cloud-hosted Visionect environment, if you have access and can observe the local device/server side without exposing private data.
The point is not to bypass licensing. The point is to capture at least one normal conversation where the device connects, the server answers, and the session progresses far enough to identify message roles and timing.
The important distinction is message role, not byte-level decoding. Early on, I only needed to know that one packet was a status report, another was an acknowledgement, another carried a parameter read or write, and another carried a screen update. Exact fields can be mapped later, and many never need to be publicly documented at all.
Using Codex as the Reverse-Engineering Workbench
I did not approach this by manually writing a complete replacement server in one pass. I used Codex as an engineering workbench: ask it to inspect files, write small scripts, run them, read the output, and then adjust the next step.
The useful loop was:
- Use Docker to run the stock Visionect services when possible.
- Use Codex to inspect server logs, container output, config files, and local captures.
- Ask Codex to write small diagnostic tools: TCP listeners, capture proxies, image converters, status decoders, and one-off probes.
- Run those tools against the device.
- Compare the local server’s behavior with the stock server’s behavior.
- Keep only the smallest code path that moved the device further through the session.
Docker was useful because it made the original system observable. Even when the goal was to remove Docker from the final setup, the containerized VSS stack gave me logs, process boundaries, service names, and repeatable startup behavior. It was a reference environment rather than the final architecture.
Codex was useful because most of the work was tedious, not magical. The hard part was not guessing a secret. The hard part was keeping track of many small facts: which side sent first, which message caused the device to continue, which log line matched a network event, which image transform caused an upside-down display, and which connection-close behavior triggered fast retries.
That made the project feel less like a single act of reverse engineering and more like a long debugging session with a disciplined assistant writing the next probe.
Capture Both Directions
For TCP/IP debugging, one-sided logs are usually misleading. Server logs can tell you what the server thinks it sent. Device logs can tell you what firmware believes happened. Packet captures tell you what actually crossed the network.
The useful capture set was:
- A known-good session from the stock server.
- A failed session from the local server.
- A successful local session once the behavior matched closely enough.
- Timing logs showing when the device reconnected.
- Optional serial logs from the device, used only as a diagnostic aid.
I treated each session as a small state machine:

This is safer than publishing message formats. Readers can understand the model without receiving a protocol transcript.
Comparing Sessions Is More Useful Than Guessing
Reverse engineering a network protocol is mostly comparison work. The useful question is not “what does every byte mean?” It is “what changed between the session that worked and the session that failed?”
I used a simple loop:
- Capture a baseline session.
- Make the local server perform one additional behavior.
- Capture the result.
- Compare order, timing, payload size, and acknowledgements.
- Keep the change only if the device progresses further.
That approach avoids brute force. It also keeps the implementation small. For a single self-hosted display, there is no need to reproduce account management, admin screens, database schemas, renderer services, or fleet policy. The local server only needs to satisfy the part of the conversation the device uses.
Timing Was Part of the Protocol
One of the more interesting findings was that connection timing is not just transport noise. It affects battery behavior.
If the server keeps the socket open, the device may stop reconnecting, but that does not prove it is sleeping correctly. It may simply be connected. If the server closes the socket at the wrong point, the device may treat the session as failed and retry quickly. That can look like a heartbeat problem, but it is really an error-retry path.
The healthier pattern is:

That was the point where the project changed from “can I push an image?” to “can I push an image without accidentally draining the battery?”
Image Updates Are Physical, Not Cosmetic
E-paper image handling is stricter than normal web image handling. A photo that looks fine in a browser may be poor input for an e-paper panel. The server-side image pipeline had to account for:
- Fixed panel resolution.
- Landscape orientation.
- EXIF rotation from phone photos.
- Limited grayscale levels.
- Portrait photos on a landscape display.
- Black padding matching the physical frame.
- Avoiding distortion while still filling the screen appropriately.
The local setup prepares images before the device checks in. That keeps the runtime server simple and makes failures easier to debug: either the prepared image is wrong, or the transport/session behavior is wrong.
The Takeaway
The most useful mental model is that a low-power e-paper display is only half the product. The server is the other half. It prepares state, waits for a check-in, sends work, records telemetry, and helps the device get back to sleep.
Once I treated the connection as a state machine instead of a file upload, the self-hosted version became much easier to reason about. The project stopped being about copying a server and became about implementing the smallest well-behaved conversation the device needed for my local workflow.
