Skip to main content

Architecture

GEM is built around one idea: a single server at each site owns everything. That server holds every device connection, runs all automation, and keeps the live state of the whole installation. Every screen an end user touches — the web app, a wall-mounted touchpanel, the mobile app — is a thin client of that one server. There is no per-client application server, and no dependency on the cloud for day-to-day operation: control happens on the local network, at local-network speed, and keeps working when the internet does not.

This page is the mental model an integrator needs before configuring devices, zones, and automation. For how the configuration entities relate, see Data Model.

The big picture

A GEM installation is normally one machine on the site's local network, alongside the equipment it controls. The server talks down to equipment over each device's native protocol, and across to clients over a web API. Remote access is reached the other way around — the server dials out to a cloud orchestrator, so no inbound ports or firewall holes are required.

One server owns the site

The server (a Node.js process, server.js) is the single source of truth. It is the only thing that opens a connection to a device — clients never talk to equipment directly. Because all control converges on one process, GEM can mix vendors and protocols freely in a single installation: Lutron lighting, a BACnet HVAC plant, Modbus relays, a cloud-API pool controller, and a generic-TCP receiver all coexist as ordinary devices. There is no vendor lock-in baked into the architecture.

One server corresponds to one site. (Multi-controller sites can link servers together, but the unit of an installation is still a single owning server.)

Drivers connect the equipment

Every piece of equipment is reached through a driver — a component that knows one equipment type's protocol. GEM ships with a large driver library, well over a hundred, spanning:

  • Generic transports — TCP, UDP, HTTP, serial (RS-232/485), and IR, configured with command/response templates for gear that has no dedicated driver.
  • Protocol families — Lutron, BACnet, Modbus, KNX, Z-Wave, Zigbee, Matter, MQTT, and DMX.
  • Cloud and IP devices — receivers, TVs, streamers, thermostats, pool/spa controllers, energy systems, and many vendor cloud APIs.

Conceptually a driver does two jobs: it translates GEM's generic verbs (on, off, open, set_level, …) into the device's native commands, and it parses device feedback back into attribute updates. That translation is what lets the rest of the system — UIs, macros, triggers — speak one vocabulary regardless of what brand of hardware is on the other end. See the Devices reference for how a driver is selected and configured.

Live state in memory

This is GEM's defining characteristic. The server keeps live, in-memory collections of every device, zone, subsystem, AV zone, and AV source, with each entity's current attribute values merged onto it. The current state of the system — what's the kitchen brightness right now? — is answered from memory, instantly, not from a database query.

The database and memory hold different things, and the split matters:

  • Memory holds now. Current brightness, temperature, online status. Device feedback updates memory the moment it arrives, and clients are pushed the change.
  • The database holds configuration and history. It is the durable record, loaded into memory at boot.

This is why the UI feels immediate, and it's why state survives a client disconnect but a configuration change survives a server restart. The two are kept in step automatically — you configure entities, and the server takes care of loading them into live state.

The database

Configuration and history live in PostgreSQL, running on the same machine as the server. It stores devices, zones, subsystems, users and roles, macros, schedules, UIs, the access-control rules, and the attributes that carry both configuration and recorded history. The same attribute mechanism underpins everything — see Attributes & the Registry.

Sensitive attributes (passwords, API keys) are encrypted at rest — see Secure Attributes. The database is captured by GEM's built-in backups (scheduled, optionally encrypted, with an automatic backup taken before a software update), so a site can be restored to a known-good configuration.

How clients connect

Clients reach the server three ways:

  • WebSocket (Socket.io) — the real-time channel for live state, subscriptions, and most interactive operations. A client subscribes to the zones or devices it cares about and is pushed updates as they happen. Every WebSocket event is automatically enumerated for role-based access control.
  • REST/api/data/[entity] for reading configuration and /api/control/[action] for issuing commands and running macros.
  • Web Services/web_service/[service] for inbound integrations and webhooks from external systems.

The web app, touchpanels, and the mobile app are all the same kind of client — the mobile app simply wraps the web client in a native shell. None of them is privileged; they all see the system through these surfaces. See the API Reference for details.

How control flows

A command is always handled the same way, no matter where the user is. The client sends an intent ("Kitchen Lights on"); the server resolves the target zone to its device and address, hands it to the right driver, and the driver speaks the device's protocol. When the device reports back, the server updates live state, persists what should be recorded, and pushes the new state to every subscribed client. A remote user's command takes exactly this path — it just arrives at the server through the cloud tunnel instead of directly over the LAN. (For the zone-resolution detail, see Devices.)

Remote access

For access from outside the site, the server opens an outbound reverse tunnel over TLS to the GEM Orchestrator in the cloud. Remote clients connect to the orchestrator, which relays their requests back down the established tunnel to the local server. Two consequences follow, and both matter to an integrator setting up a site's network:

  • No inbound holes. Because the tunnel is dialed outward, the site needs no port forwarding, no static IP, and no inbound firewall rules. The server is never directly reachable from the internet.
  • Local-first. The tunnel is for remote reach only. On-site clients talk to the server directly, so lighting, climate, security, and AV keep working at full speed even if the internet link or the cloud is down.

The same outbound path carries push notifications — alerts (a gate call, a security event) are delivered to mobile devices through APNs and FCM.

Automation and monitoring run in the server

The pieces that act on their own live inside the same server process, so they have direct access to live state and the drivers:

  • The automation engine runs macros on schedules and in response to triggers that watch attributes — see the Automation guides.
  • Monitoring watches device and network health and feeds status back as attributes.
  • Access control evaluates entry rules, and site modes track occupancy/security state.

None of these are separate services to deploy or keep in sync — they are part of the one server that already owns the devices and the state, which is what makes the whole system behave as a single coherent controller.