HEART Embedded Systems logoHEART

Do not wish to use heartcortex.ai/monitor? Run your own HEART Hub server#

https://heartcortex.ai/monitor is free, but you do not have to use it. HEART Hub is open code (Apache-2.0), and any site that follows the HEART Hub profile works with every HEART device. Run your own when you want your devices' health to stay on your own machine or network: for a company, a hospital, a farm, a home lab, or just because.

Code: github.com/syncaissa/heartcortex.ai/tree/main/ownMonitorServer, together with heart-monitor/, the site's own code.

FileWhat it is
server.mjsYour server: the HEART Hub site on Node, with its data in one file
test_e2e.pyProves it works: sign in, register a simulated device, see its alerts, restart, nothing lost
README.mdThis guide
../heart-monitor/worker/worker.jsThe site itself, the same file heartcortex.ai runs (built from heart-monitor/src/worker.src.js)

There are two ways to run your own:

A. Your own computer or server (this folder)B. Cloudflare Workers, like heartcortex.ai
You needA machine with Node 20+A Cloudflare account, an AWS account (DynamoDB) and an email sender (Resend)
Data livesIn one file, data/monitor.json, on your machineIn Amazon DynamoDB
Good forOne person, a team, a site on a private networkMany users, on the internet, with no server to look after
StepsBelowheart-monitor/README.md, "Deploying"

A. Run it on your own machine, step by step#

Step 1: Get the code#

You need the two folders ownMonitorServer/ and heart-monitor/ side by side, as they are in the repository:

git clone https://github.com/syncaissa/heartcortex.ai.git
cd heartcortex.ai

You need Node 20 or newer (node --version). Nothing else is installed: no packages, no database.

Step 2: Start it#

node ownMonitorServer/server.mjs
HEART Hub on http://127.0.0.1:8787  (listening on 127.0.0.1:8787, data in .../ownMonitorServer/data, email: console)
Point devices at it: HEART_MONITOR_URL=http://127.0.0.1:8787 (Python templates), CONFIG_HEART_MONITOR_URL (ESP32), --monitor-url (simulators)

Open http://127.0.0.1:8787/monitor in a browser. It is the same site as heartcortex.ai/monitor, on your machine.

At first start it makes ownMonitorServer/data/ with two files, both readable only by you:

FileWhat it holds
secrets.jsonThe session secret (signs sign-in cookies) and the approval signing key (signs owners' approval decisions; devices pin its public key). Keep it. Losing it signs everyone out, and devices that take approvals must be set up again.
monitor.jsonAccounts, devices, their latest health and 90 days of alerts. Expired codes and sessions are dropped as it goes.

Step 3: Sign in#

  1. Open /login and enter your email address.
  2. Where is the code? With the default --email console, the server prints the email it would have sent on its own console:

``` --- email to you@example.org: 481022 is your HEART Hub code ...


```

Type that code in. This is right for a server only you (or your team, at the console) use.

  1. To send real emails instead, get a Resend key for a domain you own, and start with:

``sh RESEND_API_KEY=re_... RESEND_FROM="HEART Hub <monitor@example.com>" node ownMonitorServer/server.mjs --email resend ``

Step 4: Connect a device and register it#

Every HEART device and simulator can report to any monitor site:

DevicePoint it at your server
Python template (heart-templates/templates/python)HEART_MONITOR_URL=http://127.0.0.1:8787 python3 heart.py
ESP32 Full starteridf.py menuconfig → HEART → monitor URL
A demo simulator (pacemakerSimulator/, ...)python3 pacemakerSimulator/pacemakerSimulator.py --monitor-url http://127.0.0.1:8787

The device prints a device ID and a claim code. On your server, open Register a device, enter them, and watch the device under My devices. Its page is private until you share it, and if it goes silent you get an email (on the console, or by Resend).

Try it in one minute:

node ownMonitorServer/server.mjs &
python3 pacemakerSimulator/pacemakerSimulator.py --monitor-url http://127.0.0.1:8787 --scenario all --speed 5

Step 5: Let devices on your network reach it (HTTPS)#

Devices refuse a monitor site without HTTPS, except on the same machine (127.0.0.1), because a report carries the device's key. So for devices on a network, put HTTPS in front of the server. The simplest is Caddy, which gets and renews a certificate by itself:

# /etc/caddy/Caddyfile
monitor.example.com {
    reverse_proxy 127.0.0.1:8787
}

Then start the server with your address, and tell it to trust Caddy for the visitor's address (used by the sign-in limits):

node ownMonitorServer/server.mjs --site-url https://monitor.example.com --trust-proxy

Keep the server itself on 127.0.0.1 (the default), so only Caddy can reach it. On a private network without a public name, use a certificate from your own certificate authority, and install that authority on your devices.

Step 6: Keep it running#

A systemd service, so it starts at boot and restarts if it stops:

# /etc/systemd/system/heart-monitor.service
[Unit]
Description=HEART Hub
After=network.target

[Service]
User=heart
WorkingDirectory=/opt/heartcortex.ai
ExecStart=/usr/bin/node ownMonitorServer/server.mjs --site-url https://monitor.example.com --trust-proxy
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now heart-monitor
journalctl -u heart-monitor -f        # with --email console, sign-in codes appear here

Step 7: Back it up and update it#

  • Back up the data/ folder (both files). To restore, stop the server, put the folder back, start it.
  • Update: git pull, then restart the service. The data file stays as it is.
  • The "gone quiet" check runs every 5 minutes inside the server; there is no cron to set up.

Options#

OptionDefaultMeaning
--port8787Port to listen on
--host127.0.0.1Address to listen on. Use 0.0.0.0 only behind your own HTTPS proxy
--site-urlhttp://127.0.0.1:PORTThe address people and devices use; must be https:// except for 127.0.0.1
--dataownMonitorServer/dataWhere the data file and secrets live
--emailconsoleconsole (print emails here) or resend (needs RESEND_API_KEY and RESEND_FROM)
--trust-proxyoffTake the visitor's address from X-Forwarded-For (only behind your own proxy)
--adminnoneAdministrator email addresses, comma-separated

Check that it works#

python3 ownMonitorServer/test_e2e.py

It starts a fresh server, signs in with the code printed on its console, registers the pacemaker simulator with its claim code, sees its alert on the device page, checks the page is private, then restarts the server and checks that the account, the session and the device were kept, and that the device keeps reporting.


What your server does, and does not, keep#

Exactly what heartcortex.ai keeps, because it is the same code:

  • Only public data from devices: the Pulse status and each alert's fault code, severity and times. Never a reading, a name or anything private: the site drops everything else, even if a device sends it.
  • Sign-in codes, claim codes, device keys and sessions only as hashes, so a stolen data file cannot be used to sign in or to report.
  • The latest Pulse and 90 days of alerts. An owner can delete a device and everything about it at once.
  • No commands to devices. A monitor site can never send a device a command; it can only pass on an owner's signed yes or no to a change the device itself asked about.

Limits of this server#

  • It is one process with its data in memory and one file. It suits up to a few hundred devices; for more, use option B.
  • It has no "are you a person" check (Cloudflare Turnstile). The per-address and per-network sign-in limits still apply.
  • The data file is written after every change; on a slow disk with many devices, prefer option B.

Licence: Apache-2.0. Part of HEART, the open standard at heartcortex.ai.