Documentation
What every setting actually does - straight from PonControl's own in-app reference.
Initial setup ▾
If the configuration file (config/vars.php) doesn't exist yet, the site shows the
setup.php form instead, asking for:
- MySQL host / db / user / pass - access to the database PonControl uses for its
own tables (
olts,onus,fdb,settings, etc.). The database must already exist; its tables are created automatically when this form is saved. - telnet user / pass - credentials PonControl uses to log into an OLT over telnet for commands SNMP doesn't support (e.g. saving configuration).
- enable pass - the privileged (enable) mode password, if your OLTs require one.
- TFTP address - a TFTP server address, if OLT config-backup operations use TFTP.
After saving this form, the next steps are:
- Create staff accounts (Settings → Administrators) - the first account created becomes an admin.
- Add an OLT (OLT list → Add OLT): IP address, SNMP read/write community, number of SFP ports.
- Configure the sections below as needed - Zabbix, UserSide, Alerts, OpenObserve.
Main ▾
The only field here is PHP timezone - which timezone PHP uses when showing dates/times across the site (activity log, an ONU's last contact, etc.). Picked from a dropdown, so there's no way to enter an invalid value.
Zabbix ▾
Needed for ONU signal/traffic graphs and OLT battery/generator status (the "Power" sidebar section). Without Zabbix configured, those graphs simply don't show - everything else works independently of this section.
- Zabbix API user / password - credentials PonControl uses to log into the Zabbix
API (
user.login). A dedicated technical account with read-only history access is recommended. - Zabbix URL - the base URL of your Zabbix instance (without
/api_jsonrpc.phpat the end - PonControl appends that itself). - Default chart period - which period (in hours) a graph opens showing by default.
UserSide ▾
A direct connection to your UserSide billing database (separate from PonControl's own database). When enabled, it unlocks: subscriber search by address/code when binding an ONU, a subscriber card with balance when viewing an ONU, the map (using coordinates from UserSide), automatic PING3 power sensor detection for an OLT (when not set manually on the OLT card), and the customer portal (linking a subscriber's ONU to their own UserSide account).
- UserSide MySQL host / database / user / password - direct access to UserSide's
database (not its API) - needs read access to the relevant tables (
tbl_base,tbl_house,tbl_ip,tbl_switch,tbl_map, and others). - UserSide URL - the base address of your UserSide instance, for direct links to a subscriber's card.
- UserSide search path - a path (appended to the URL above) for linking straight to a MAC address in UserSide.
Turning this integration off doesn't delete anything entered - it just hides the section and whatever depends on it (Map, Alerts) until turned back on.
Alerts (Telegram) ▾
Only available once UserSide is enabled - every field here is the name of a custom field that must already exist on the subscriber card in UserSide itself, not arbitrary data:
- "User ID" field in UserSide - the field name where a subscriber's Telegram User ID is stored.
- "Send to user" / "Send to admin" field - the names of the checkbox fields that turn notifications on/off.
- Public Telegram bot token - the bot token used to send notifications to subscribers.
- Admin bot token / Admin chat ID - a separate bot and chat for notifications to admins/support staff.
Backup / Restore ▾
Create backup dumps every table in the database (as it currently stands) into one file and immediately starts downloading it in the browser - a gzip-compressed JSON file (not a raw SQL dump, and not a ZIP archive, since this server has no PHP ZipArchive extension available). The last 5 such files are kept - a list under the button lets you download or delete any of them later without regenerating; the 6th-oldest and beyond are removed automatically each time a new one is created.
vars.php is never included in the backup. It holds database
credentials, auth secrets, and other server-specific settings, and isn't stored in the database at
all - keep your own separate copy of that file.
Restore from backup accepts a file produced by the button above
(.json or .json.gz) and fully replaces the current contents of every table
mentioned in the file with the file's own data - there's no undo, so the form requires confirmation.
Tables or individual columns in the file that no longer exist in the current database are simply
skipped (not an error - the rest of the table still restores), so a backup from a slightly different
schema version can still be restored. Maximum file size on this server is 2 MB (the PHP
upload_max_filesize limit). Restore runs in the background with live progress (the same
console used for updating PonControl) - any rows/tables that had to be skipped show up right in that
log.
Before an actual PonControl update starts (the "Update"/"Force update" button), a warning screen with the same two buttons (create a backup, or continue) now shows first - an update no longer launches immediately on click.
OpenObserve integration (Logs) ▾
Connects the Logs sidebar page to an external
OpenObserve instance that's
already collecting your OLTs' syslog into one stream - PonControl only reads from it via the API, it
never receives or stores anything itself. Every log line must carry a source_ip field
matching the IP of the OLT it came from - that's the field filtering is based on.
- OpenObserve URL - the address of your OpenObserve instance.
- OpenObserve Organization - your OpenObserve organization identifier.
- OpenObserve Stream - the name of the stream your OLT logs land in.
- OpenObserve User / Password/token - API credentials (a dedicated Service Account is recommended over a personal login).
Finding these values in OpenObserve
1. Confirm OLT logs are already reaching OpenObserve. Every log line must include
a source_ip field with the OLT's IP address. If your log pipeline (e.g. Fluent
Bit/Vector/rsyslog → OpenObserve) calls that field something else, rename/map it to
source_ip at collection time, before it reaches OpenObserve.
2. Find your Organization. Log into the OpenObserve web UI - the organization
identifier is visible in the address bar after logging in
(/web/organizations/<org>/...), and in any ready-made curl example on the Data
Sources page.
3. Find the right Stream name. Under Streams (or Logs → Streams), pick the stream your OLT logs land in.
4. Create API credentials (a Service Account is recommended). A regular OpenObserve login/password will technically work, but a dedicated Service Account (IAM → Service Accounts → Add Service Account) is safer - it can't log into the OpenObserve UI, only authorize API requests. Use that Service Account's email as "OpenObserve User" and its issued token/password as "OpenObserve Password/token".
5. Fill in the "OpenObserve integration" card in PonControl's Settings with the values above and click Save.
OLT overview. The "Logs" menu item (with no specific OLT selected) shows a tile for every OLT with its message count for the selected period (last 24 hours by default). You can also pick a period and apply a saved filter or free-text search there - each tile's count then reflects that same filter. A tile is red if it has no messages (matching the current filter). If an OLT is online but has genuinely zero messages at all (regardless of filter or period - checked separately, over roughly the last 10 years), hovering the tile - and the OLT's own log page - shows a hint that logging likely just isn't set up for it yet; a filter/period that simply found nothing doesn't get that hint. Clicking a tile opens that OLT's logs with the same period and filter/search that were selected on the tile grid.
Period and filters. An OLT's own log page (and the overview above) lets you pick a time period (1 hour, 6 hours, 24 hours, 7 days, or 30 days) - an individual OLT defaults to just the last hour. You can apply a saved text filter (see "Log filters" below) or type free text into the search box - both do the same "message contains this text" match and are mutually exclusive. Typing your own text shows a "Save filter" button (admins only) next to it, adding that text to the list of saved filters.
OLT name. On an OLT's own log page, the name in the heading (along with its IP) is a link that opens that OLT's regular card (not its logs) in a new tab.
Message-volume chart. An OLT's own log page always shows a bar chart of message count over the selected period above the table - time on the X axis, count on the Y axis. It respects the same filter/search as the table below, and shows regardless of whether the table currently has any results (e.g. it can show a spike that's already over). Bar width adapts to the selected period to stay readable (no more than ~60 bars), and is never narrower than 5 minutes. Clicking a bar narrows the table to just that time slice - a chip with an "×" appears next to the period buttons (1h/6h/24h/7d/30d) to clear it; clicking any period button also clears the selection.
Log markup. Unlike filters, "Logs markup" rules (also under OpenObserve integration) never hide anything - each rule adds a name (for your own reference), an icon and/or a lightly tinted background to any line whose message contains a given piece of text - e.g. tagging lines containing "DYING_GASP" (an ONU lost due to power loss) with a power icon. At least one of icon/color is required (both are optional individually, but can be combined) - a "Reset" button next to each picker clears it. Colors come from a tile palette (like an emoji picker); icons come from a scrollable list (every icon in the theme that makes sense as a marker, i.e. no brand logos); both pickers open on their own button and close on an outside click. Color is always applied as a light, low-contrast tint, never a solid fill. Each rule also has three independent scope flags (not mutually exclusive): OLT logs (opened from an OLT's card or tile), ONU logs (opened from an ONU's card - determined by where the page was opened from, not by what's currently in the search box), and custom-device logs; all three are on by default, and at least one must stay on. An existing rule can be edited (an "Edit" link reopens this same form pre-filled) or deleted. Rules can only be managed from the web (adding/editing is admin-only) - the result (icons/coloring) shows identically on web and Android.
Custom devices. The "Custom devices" section (also under OpenObserve integration)
adds log sources that aren't a managed OLT - just a name and the IP address messages are matched on
(the same source_ip field used for OLTs). Stream override (optional) - if set, it's used
for that device's queries instead of the stream configured above (the field shows that value as a
placeholder until you set your own). Unlike an OLT (whose logs anyone signed in can see), a custom
device's logs are admin-only by default - a "Visible to non-admins" checkbox on the device's form opens
them up. Once at least one custom device exists, the Logs page always shows a "Custom devices" tile
first, leading to a tile grid of your devices - clicking one opens the same full log view (chart,
filters, markup) as a regular OLT. OLT tiles get a very slight blue background tint, custom-device
tiles a very slight yellow tint; a tile with no messages for the period stays red regardless of that
tint.
Technical details: PonControl calls OpenObserve's search API
(POST {URL}/api/{Organization}/_search) with a SQL query shaped like
SELECT * FROM "{Stream}" WHERE source_ip = '<OLT IP>' [AND match_all('*<filter
text>*')] ORDER BY _timestamp DESC (the *...* wrapping is OpenObserve's own
"contains" syntax - without it, match_all matches an exact token and wouldn't find, say,
"loop" inside "loopback"), authorizing via HTTP Basic Auth (User/Password), and paginates 20 records
per page. The message count (the "Showing X-Y of Z" counter and the OLT tiles) comes from a separate
SELECT COUNT(*) ... aggregate query, not the search query's own "total" field - that field
doesn't reflect the real match count on some OpenObserve deployments.