Online
6/6
CT #457 · Morton demo
Firmware
v1.0.4
All sensors current
ODN Gateway APs
—
Galgus API not connected
MQTT broker
—
broker.optified.io
Presence now
—
Waiting for MQTT
Sensor profiles & keyword tags
Enrich each sensor with structured tags. Tags work like web metadata backlinks —
brand:dyson on multiple sensors means querying that tag instantly gives you Dyson’s total exposure across every store and aisle.Sensor identity
MAC address
Status
Alias
Location
Department
Aisle / zone code
Range profile
Keyword tags
namespace:value — like web metadata
Available namespaces
brand:
zone:
dept:
campaign:
aisle:
sku-group:
category:
dooh:
traffic:
Tag query — find sensors by keyword
Query any tag across your entire fleet. One tag, instant results. Like a web search but for physical sensor locations.
Quick queries
Fleet tag directory
Brand exposure at scale
Aggregate presence analytics across all sensors sharing a brand tag. One brand tag = instant cross-fleet exposure report across all stores, zones, and campaigns.
Select a sensor from the sidebar to inspect and configure it.
Data insights
Zone tallies, dwell time, engagement, and trend analysis per sensor and store
–
73,807
Total customers
+12.4% vs prev period
41,440
Engaged customers
+8.1%
56.1%
Engagement rate
+2.3pp
66.4%
Quick exit rate
-1.2pp better
2.3m
Avg quick exit time
+0.2m
8.8m
Avg engaged time
+1.1m
Busiest hour
14:00–15:00
180 avg customers/hr
+6% vs last month
Busiest day
Saturday
2,100 avg customers
+9% vs last month
Busiest zone
CTC457-Media-CashFront-159
8,381 traffic · 60.5% eng
+4% engagement
Avg dwell (engaged)
14.2 min
across all sensors
+1.1m improvement
Customer time-in-store distribution — total vs engaged
Zone tally per hour of day — average customers detected
Zone tally by day of week
Monthly customer trend — 12 months
Engaged vs quick exit customers per sensor
Sources detailed view
Filter zone:
| Source | Traffic | Engaged | Eng. rate | Avg dwell | Quick exits | QE rate |
|---|
Sensor
Latest · 1.0.4
v 1.0.4 Retail New Target Dwell for MOR
https://github.com/josegardo/esp32-ota/raw/refs/heads/main/apollo_1_0_4.bin
Per-zone dwell filter (20/30/45/60s) · MQTT cloud control · NVS persistence · Meerby integration · broker.optified.io
Previous · 1.0.3
Retail Ready — Dwell 4× 5s ODN presence
https://github.com/josegardo/esp32-ota/raw/refs/heads/main/apollo_1_0_3.bin
Retail dwell / aisle analytics · Meerby trigger-ready · broker.optified.io
Stable · 1.0.2
ODN Presence Full — security use case
https://github.com/josegardo/esp32-ota/raw/refs/heads/main/apollo_1_0_2.bin
Per-unit firmware status
OPTiFied Architecture 5.0 — OpenWiFi + Multi-protocol gateway layer
OPTiFi Cloud layer
OW Controller Plumbing + sensor config mgmt
OW Gateway WebSocket · OpenWiFi conf/events
Event Engine MOR conf/events · sensor conf/events
MQTT Broker broker.optified.io:1883
Webhook endpoint MOR application · WebSocket
Public API api.optifi.io · Private API endpoint
Multi-protocol gateway
DHCP Server Auto IP on venue LAN
APNOS AP network OS · CHT cognitive wifi
WebSocket Real-time event stream
Webhook Inbound + outbound event triggers
FSK Decode Event creation from RF signals
Protocols BT · WiFi 5GHz · HaLow 900MHz · Thread · Zigbee
OPTiFied Edge Booster
Hardware Intel NUC · DHCP · DNS 8.8.8.8/8.8.4.4
WebSocket Green status real-time agent
MQTT Agent High-volume data processing
ODN SSID OPT1F13dD@t@ · WPA2-PSK
Connected devices Macro mmWave · Door · RFID · Motion · Call buttons
Roadmap Wi-Fi HaLow 802.11ah · Morse Micro · Edgecore
ODN sensor device types on multi-protocol gateway
MQTT Macro
Location Sensor
Location Sensor
Shelf Product
Sensor
Sensor
MQTT Door
Contact Sensor
Contact Sensor
UHF RFID
Tag Sensor
Tag Sensor
MQTT Micro
Motion Sensor
Motion Sensor
MQTT Customer
Call Button
Call Button
Join Digital access points — CT #457 Kanata site
Galgus GEN3 — legacy / migration
Being replaced by JoinGalgus manager
ODN session view — mmWave sensors on Join network
Sensors auto-provision to Join APs via ODN SSID. Station MAC matches sensor MAC — confirming link between WiFi session and MQTT data stream.
| Status | Station MAC (sensor) | AP MAC | Site | SSID | RSSI | Signal | Channel | fw version | Connected |
|---|
Campaigns
Create and manage sensor-linked campaigns with locations, days, activations, and audience results. Powered by
api.optifi.io/ws/:wsId/campaignsActive campaigns
3
CT #457 workspace
Campaign locations
8
across 3 campaigns
Total activations
14
this period
Avg engagement
58.4%
across locations
New campaign
Configure external API endpoints per account or sensor group. Toggle, edit endpoints and API keys — no firmware redeployment required.
Trigger log
Manage accounts, sensor groups, and cross-account sharing. Group admins approve share requests.
Active sensor shares
Global alert routing
OPTiFi operations (always CC)
uptime@OPTiFi.ca
Always active Account admin — 1st line
Per account Group alert email
Per group MSP escalation
MSP onlyAlert rules
Notification intervals
First offline alert
Repeat reminder
Low RSSI threshold
-80dBm
Recent alerts
AWS RDS PostgreSQL — OPTiFi data architecture
Multi-tenant schema · sensor telemetry · presence analytics · user IAM · MQTT bridge · Meerby event log
Region: ca-central-1 (Canada) · db.t3.medium → db.r6g.large for production · Multi-AZ recommended
Region: ca-central-1 (Canada) · db.t3.medium → db.r6g.large for production · Multi-AZ recommended
Data flow — MQTT → AWS → PostgreSQL
mmWave sensors
Apollo R-PRO-1
Join ODN WiFi
Join ODN WiFi
MQTT QoS 1
broker.optified.io
MQTT broker
AWS EC2 / ECS
Mosquitto / EMQX
Mosquitto / EMQX
pg-bridge Lambda
JSON → SQL INSERT
RDS PostgreSQL
ca-central-1
Multi-AZ + S3 backup
Multi-AZ + S3 backup
accountsmulti-tenant root
id UUID PK
name TEXT NOT NULL
type account_type ENUM
admin_email TEXT
alert_email TEXT
store_code TEXTMeerby
parent_id UUID FK → accounts
created_at TIMESTAMPTZ
active BOOLEAN DEFAULT true
ENUM account_type: retail | msp | brand | platform
sensor_groupsCT #457, zones
id UUID PK
account_id UUID FK → accounts
name TEXT NOT NULL
site_code TEXTCTC457
location TEXT
is_shared BOOLEAN DEFAULT false
created_at TIMESTAMPTZ
sensorsdevice registry
id UUID PK
mac_address MACADDR UNIQUE NOT NULL
group_id UUID FK → sensor_groups
account_id UUID FK → accounts
alias TEXTCTC457-Media-Furniture-1
firmware_version TEXT
capture_profile TEXTxsmall–xlarge
zone_config JSONBLD2450 zones
gate_config JSONBLD2412 thresholds
join_ap_mac MACADDRFK to AP
status sensor_status ENUM
last_seen TIMESTAMPTZ
provisioned_at TIMESTAMPTZ
ENUM sensor_status: online | warn | offline | staging
sensor_telemetryTimescaleDB / partitioned
id BIGSERIAL PK
sensor_id UUID FK → sensors
ts TIMESTAMPTZ NOT NULLpartition key
rssi SMALLINT
heap_free INTEGER
uptime_s INTEGER
mqtt_connected BOOLEAN
wifi_ssid TEXT
battery_mv SMALLINT
Partition: RANGE(ts) monthly · Retention: 90 days hot → S3 Glacier
presence_eventscore analytics table
id BIGSERIAL PK
sensor_id UUID FK → sensors
account_id UUID FK → accounts
event_ts TIMESTAMPTZ NOT NULL
event_type presence_event_type ENUM
targets_count SMALLINT
zone_id SMALLINT1–3
dwell_seconds INTEGER
is_engaged BOOLEANdwell ≥ threshold
quick_exit BOOLEAN
raw_payload JSONB
ENUM: presence_start | presence_end | zone_enter | zone_exit | target_move
zone_analytics_hourlymaterialized view
bucket TIMESTAMPTZtime_bucket 1h
sensor_id UUID FK → sensors
account_id UUID FK → accounts
zone_id SMALLINT
total_count INTEGER
engaged_count INTEGER
quick_exit_count INTEGER
avg_dwell_s NUMERIC
max_targets SMALLINT
Refreshed every 15 min via pg_cron · powers Insights dashboard
usersIAM
id UUID PK DEFAULT gen_random_uuid()
account_id UUID FK → accounts
email TEXT UNIQUE NOT NULL
name TEXT NOT NULL
role user_role ENUM
password_hash TEXTbcrypt
mfa_secret TEXTTOTP
permissions JSONBfeature overrides
active BOOLEAN DEFAULT true
last_login TIMESTAMPTZ
invited_by UUID FK → users
created_at TIMESTAMPTZ
ENUM user_role: superadmin | msp_admin | retail_admin | insights_only | brand_viewer
sensor_sharescross-account access
id UUID PK
group_id UUID FK → sensor_groups
from_account_id UUID FK → accounts
to_account_id UUID FK → accounts
access_level share_access ENUM
status share_status ENUM
approved_by UUID FK → users
created_at TIMESTAMPTZ
expires_at TIMESTAMPTZoptional
access_level: data_only | data_uptime | full_read | status: pending | approved | denied
alert_rulesnotification config
id UUID PK
account_id UUID FK → accounts
rule_type TEXToffline | low_rssi | ota_needed
scope TEXT
threshold_value TEXT
notify_emails TEXT[]always + uptime@OPTiFi.ca
first_alert_min SMALLINT DEFAULT 5
repeat_interval_min SMALLINT DEFAULT 60
active BOOLEAN DEFAULT true
api_endpointsMeerby / webhooks
id UUID PK
account_id UUID FK → accounts
name TEXT
base_url TEXT
endpoint_path TEXT
api_key_enc TEXTAES-256 encrypted
trigger_event TEXT
payload_template TEXT
enabled BOOLEAN DEFAULT true
last_triggered TIMESTAMPTZ
join_access_pointsJoin Digital APs
id UUID PK
account_id UUID FK → accounts
mac_address MACADDR UNIQUE
alias TEXT
model TEXTJoin Qi AP7
site TEXT
firmware_version TEXT
ip_address INET
status TEXT
health_pct SMALLINT
last_contact TIMESTAMPTZ
meerby_eventstrigger audit log
id BIGSERIAL PK
sensor_id UUID FK → sensors
account_id UUID FK → accounts
triggered_at TIMESTAMPTZ NOT NULL
beacon_id TEXT
store_code TEXT
http_status SMALLINT
response_ms INTEGER
lifecycle_status TEXTcreated→complete
AWS infrastructure setup
RDS PostgreSQL
Engine PostgreSQL 16 + TimescaleDB ext
Instance db.t3.medium (dev) → db.r6g.large
Storage 100GB gp3 · auto-scaling to 1TB
Multi-AZ Yes — standby in ca-central-1b
Backups 7-day automated → S3 Glacier 90d
Encryption AES-256 at rest · TLS in transit
Access VPC private subnet only
MQTT → DB bridge
Runtime Node.js 20 Lambda
Trigger MQTT broker → SQS → Lambda
Topics data/# · status/#
Batch 100 msgs/invocation
Pool RDS Proxy (pgBouncer)
Dead letter SQS DLQ → CloudWatch alarm
Deploy Terraform / AWS CDK
Security
Secrets AWS Secrets Manager
Roles Row-level security (RLS)
API keys AES-256 in api_endpoints table
Passwords bcrypt rounds=12
Sessions JWT · RS256 · 8h expiry
MFA TOTP (Authenticator app)
Audit CloudTrail + pg audit log
Key SQL — copy-ready for your RDS instance
-- OPTiFi PostgreSQL schema (AWS RDS ca-central-1)
-- Run as: psql -h your-rds-endpoint.ca-central-1.rds.amazonaws.com -U optifi_admin -d optifi
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS timescaledb;
-- ENUMS
CREATE TYPE account_type AS ENUM ('retail','msp','brand','platform');
CREATE TYPE user_role AS ENUM ('superadmin','msp_admin','retail_admin','insights_only','brand_viewer');
CREATE TYPE sensor_status AS ENUM ('online','warn','offline','staging');
CREATE TYPE presence_event_type AS ENUM ('presence_start','presence_end','zone_enter','zone_exit','target_move');
CREATE TYPE share_access AS ENUM ('data_only','data_uptime','full_read');
CREATE TYPE share_status AS ENUM ('pending','approved','denied');
-- accounts (multi-tenant root)
CREATE TABLE accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
type account_type NOT NULL,
admin_email TEXT,
alert_email TEXT,
store_code TEXT,
parent_id UUID REFERENCES accounts(id),
active BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT now()
);
-- sensor_groups
CREATE TABLE sensor_groups (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
name TEXT NOT NULL,
site_code TEXT,
location TEXT,
is_shared BOOLEAN DEFAULT false,
created_at TIMESTAMPTZ DEFAULT now()
);
-- sensors
CREATE TABLE sensors (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
mac_address MACADDR UNIQUE NOT NULL,
group_id UUID REFERENCES sensor_groups(id),
account_id UUID NOT NULL REFERENCES accounts(id),
alias TEXT,
firmware_version TEXT,
capture_profile TEXT DEFAULT 'medium',
zone_config JSONB,
gate_config JSONB,
join_ap_mac MACADDR,
status sensor_status DEFAULT 'staging',
last_seen TIMESTAMPTZ,
provisioned_at TIMESTAMPTZ DEFAULT now()
);
-- sensor_telemetry (time-series, partitioned)
CREATE TABLE sensor_telemetry (
id BIGSERIAL,
sensor_id UUID NOT NULL REFERENCES sensors(id),
ts TIMESTAMPTZ NOT NULL DEFAULT now(),
rssi SMALLINT,
heap_free INTEGER,
uptime_s INTEGER,
mqtt_connected BOOLEAN,
wifi_ssid TEXT,
battery_mv SMALLINT,
PRIMARY KEY (id, ts)
);
SELECT create_hypertable('sensor_telemetry','ts', chunk_time_interval => INTERVAL '1 day');
-- presence_events (core analytics)
CREATE TABLE presence_events (
id BIGSERIAL,
sensor_id UUID NOT NULL REFERENCES sensors(id),
account_id UUID NOT NULL REFERENCES accounts(id),
event_ts TIMESTAMPTZ NOT NULL DEFAULT now(),
event_type presence_event_type NOT NULL,
targets_count SMALLINT DEFAULT 0,
zone_id SMALLINT,
dwell_seconds INTEGER,
is_engaged BOOLEAN,
quick_exit BOOLEAN,
raw_payload JSONB,
PRIMARY KEY (id, event_ts)
);
SELECT create_hypertable('presence_events','event_ts', chunk_time_interval => INTERVAL '1 day');
CREATE INDEX ON presence_events (sensor_id, event_ts DESC);
CREATE INDEX ON presence_events (account_id, event_ts DESC);
-- zone_analytics_hourly (materialized, refreshed by pg_cron)
CREATE MATERIALIZED VIEW zone_analytics_hourly AS
SELECT
time_bucket('1 hour', event_ts) AS bucket,
sensor_id, account_id, zone_id,
COUNT(*) AS total_count,
COUNT(*) FILTER (WHERE is_engaged) AS engaged_count,
COUNT(*) FILTER (WHERE quick_exit) AS quick_exit_count,
AVG(dwell_seconds)::NUMERIC(8,1) AS avg_dwell_s,
MAX(targets_count) AS max_targets
FROM presence_events
GROUP BY 1,2,3,4;
CREATE UNIQUE INDEX ON zone_analytics_hourly (bucket, sensor_id, zone_id);
-- Refresh: SELECT cron.schedule('refresh-zone-analytics','*/15 * * * *',$$REFRESH MATERIALIZED VIEW CONCURRENTLY zone_analytics_hourly$$);
-- users
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_id UUID NOT NULL REFERENCES accounts(id),
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
role user_role NOT NULL DEFAULT 'insights_only',
password_hash TEXT,
mfa_secret TEXT,
permissions JSONB DEFAULT '{}',
active BOOLEAN DEFAULT true,
last_login TIMESTAMPTZ,
invited_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT now()
);
-- Row-level security: users only see their own account's data
ALTER TABLE sensors ENABLE ROW LEVEL SECURITY;
ALTER TABLE presence_events ENABLE ROW LEVEL SECURITY;
ALTER TABLE sensor_telemetry ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON sensors
USING (account_id = current_setting('app.current_account_id')::UUID);
CREATE POLICY tenant_isolation ON presence_events
USING (account_id = current_setting('app.current_account_id')::UUID);
-- sensor_shares (cross-account)
CREATE TABLE sensor_shares (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
group_id UUID NOT NULL REFERENCES sensor_groups(id),
from_account_id UUID NOT NULL REFERENCES accounts(id),
to_account_id UUID NOT NULL REFERENCES accounts(id),
access_level share_access NOT NULL DEFAULT 'data_only',
status share_status NOT NULL DEFAULT 'pending',
approved_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT now(),
expires_at TIMESTAMPTZ,
UNIQUE (group_id, to_account_id)
);
-- alert_rules
CREATE TABLE alert_rules (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_id UUID NOT NULL REFERENCES accounts(id),
rule_type TEXT NOT NULL,
scope TEXT,
threshold_value TEXT,
notify_emails TEXT[] DEFAULT ARRAY['uptime@OPTiFi.ca'],
first_alert_min SMALLINT DEFAULT 5,
repeat_interval_min SMALLINT DEFAULT 60,
active BOOLEAN DEFAULT true
);
-- api_endpoints (Meerby, webhooks)
CREATE TABLE api_endpoints (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_id UUID NOT NULL REFERENCES accounts(id),
name TEXT,
base_url TEXT,
endpoint_path TEXT,
api_key_enc TEXT,
trigger_event TEXT,
payload_template TEXT,
enabled BOOLEAN DEFAULT true,
last_triggered TIMESTAMPTZ
);
-- join_access_points
CREATE TABLE join_access_points (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
account_id UUID NOT NULL REFERENCES accounts(id),
mac_address MACADDR UNIQUE,
alias TEXT,
model TEXT,
site TEXT,
firmware_version TEXT,
ip_address INET,
status TEXT,
health_pct SMALLINT,
last_contact TIMESTAMPTZ
);
-- meerby_events (trigger audit)
CREATE TABLE meerby_events (
id BIGSERIAL PRIMARY KEY,
sensor_id UUID REFERENCES sensors(id),
account_id UUID REFERENCES accounts(id),
triggered_at TIMESTAMPTZ NOT NULL DEFAULT now(),
beacon_id TEXT,
store_code TEXT,
http_status SMALLINT,
response_ms INTEGER,
lifecycle_status TEXT
);
Connection string (Node.js):
Secrets Manager key:
postgresql://optifi_app:<secret>@your-rds-proxy.ca-central-1.rds.amazonaws.com:5432/optifi?sslmode=require
OPTiFi API (Next.js): https://api.optifi.ioSecrets Manager key:
optifi/prod/rds-credentials ·
IAM role: optifi-lambda-rds-role
All firmware, ESPHome configs, and platform code. Reference these URLs in OTA pushes and YAML generation.
Users & access control
Manage user roles, feature permissions, and cross-account access. Role changes take effect immediately.
Role permission matrix — what each role can access
| Feature | Super admin | MSP admin | Retail admin | Insights viewer | Brand viewer |
|---|---|---|---|---|---|
| Data insights & zone analytics | ◑ | ||||
| Sensor fleet view (own account) | |||||
| Sensor configuration & range profiles | |||||
| Firmware OTA push | ◑ | ||||
| Network / Join AP management | ◑ | ||||
| ESPHome YAML generator | |||||
| API router configuration | ◑ | ||||
| Account management & sensor sharing | ◑ | ◑ | |||
| Alert & notification settings | |||||
| User & access management | ◑ | ◑ | |||
| Campaigns — create & manage | ◑ | ◑ | |||
| GitHub & firmware repos | |||||
| Cross-account data (all orgs) |
Full access
◑Partial / scoped
No access
Users (6)
Select a user to edit permissions
Invite user