NOTICE: All information contained herein is, and remains
the property of TechnoCore Automate.
Updated : 2026-04-19
ObjServiceNetwork polls the MikroTik RB5009 RouterOS 7 REST API
(http://10.0.10.254) to capture router health, per-interface traffic
counters, DHCP leases, and internet connectivity. It also determines
household presence by matching DHCP leases and the ARP table against
known MACs and DHCP hostnames.
Config (device registry and household members) is sourced entirely from
the database — not from config.yaml. The only YAML entries needed are
the router connection credentials.
sync runs every minute via the gekkoridge cron scheduler.
ObjServiceNetwork
├── Router resources → data_network_router
├── Interface counters → data_network_interface
├── DHCP + ARP merge → data_network_presence
│ └── MAC/hostname match → data_household
└── ICMP ping → data_network_health
record_presence()
→ GET /rest/ip/dhcp-server/lease (DHCP leases)
→ read /proc/net/arp (static-IP devices)
→ merge by MAC
→ match against data_network_device registry
→ write data_network_presence
record_household()
→ for each member in data_network_member
→ check member MACs against current leases/ARP
→ hostname fallback for randomised Android MACs
→ upsert data_household (home/away, ArrivedAt, DepartedAt)
Android phones may rotate their MAC address. When no MAC match is found,
the hostname returned by DHCP is compared against the Hostnames JSON
list on the member record.
# config.yaml [network section]
network:
router_host: "http://10.0.10.254"
router_user: "api-user"
router_pass: "<encrypted>" # RSA-encrypted with package key
router_pass is decrypted at runtime via self.decrypt() (inherited
from ObjData).
Device registry and household members are not in YAML. They are
stored in data_network_device and data_network_member and loaded
on init via _load_config_from_db().
Router system snapshot written each sync cycle.
| Column | Type | Description |
|---|---|---|
| Guid | VARCHAR(64) | PK |
| CpuLoad | INT | CPU usage % |
| FreeMemory | BIGINT | Free RAM (bytes) |
| TotalMemory | BIGINT | Total RAM (bytes) |
| Uptime | VARCHAR(64) | RouterOS uptime string |
| FirmwareVersion | VARCHAR(64) | RouterOS version |
| BoardName | VARCHAR(64) | Hardware model |
| RecordedAt | DATETIME | Snapshot timestamp |
Per-interface Rx/Tx counters, one row per interface per cycle.
| Column | Type | Description |
|---|---|---|
| Guid | VARCHAR(64) | PK |
| InterfaceName | VARCHAR(64) | e.g. ether1, bridge |
| RxBytes | BIGINT | Total bytes received |
| TxBytes | BIGINT | Total bytes transmitted |
| RxErrors | INT | Rx error count |
| TxErrors | INT | Tx error count |
| Running | TINYINT | 1=up, 0=down |
| RecordedAt | DATETIME | Snapshot timestamp |
DHCP lease → known device last-seen record.
| Column | Type | Description |
|---|---|---|
| Guid | VARCHAR(64) | PK |
| MacAddress | VARCHAR(17) | Device MAC |
| IpAddress | VARCHAR(15) | Assigned IP |
| Hostname | VARCHAR(255) | DHCP hostname (may be null) |
| DeviceName | VARCHAR(255) | From data_network_device registry |
| Location | VARCHAR(255) | From data_network_device registry |
| Source | VARCHAR(16) | dhcp or arp |
| LastSeen | DATETIME | Time of detection |
Per-person home/away state. Upserted on each sync.
| Column | Type | Description |
|---|---|---|
| Person | VARCHAR(255) | PK — member name |
| Package | VARCHAR(255) | PK — Axion package |
| Status | VARCHAR(8) | home or away |
| ArrivedAt | DATETIME | Last arrival timestamp |
| DepartedAt | DATETIME | Last departure timestamp |
| LastSeen | DATETIME | Last time detected on network |
Internet health snapshot per ping target.
| Column | Type | Description |
|---|---|---|
| Guid | VARCHAR(64) | PK |
| Target | VARCHAR(255) | Ping target hostname or IP |
| LatencyMs | DECIMAL(10,2) | Round-trip time (ms); NULL = unreachable |
| PacketLoss | INT | Packet loss % |
| RecordedAt | DATETIME | Snapshot timestamp |
Device registry. Seeded via seed-config or add-device CLI.
| Column | Type | Description |
|---|---|---|
| MacAddress | VARCHAR(17) | PK — normalised MAC |
| DeviceName | VARCHAR(255) | Human-readable device name |
| Location | VARCHAR(255) | Physical location label |
| Package | VARCHAR(255) | Axion package |
Household members with MAC and hostname lists for presence matching.
| Column | Type | Description |
|---|---|---|
| Person | VARCHAR(255) | PK — member name |
| Package | VARCHAR(255) | PK — Axion package |
| Tier | VARCHAR(32) | Member tier (e.g. resident, guest) |
| MacAddresses | JSON | List of known MACs for this person |
| Hostnames | JSON | DHCP hostname fallbacks (Android) |
Runs all four record methods in sequence:
record_router() → record_interfaces() → record_presence() →
record_household() → record_health()
GET /rest/system/resource → writes one row to data_network_router.
GET /rest/interface → writes one row per interface to
data_network_interface.
Fetches DHCP leases (/rest/ip/dhcp-server/lease) and merges with
get_arp_devices(). Each discovered MAC is matched against
data_network_device. Writes to data_network_presence.
For each member in data_network_member, checks whether any known MAC
(or DHCP hostname) appears in the current lease/ARP set. Upserts
data_household with home/away and updates arrival/departure
timestamps when status changes.
Pings each configured target and writes latency and packet loss to
data_network_health.
Reads /proc/net/arp to enumerate devices with static IPs that may not
appear in DHCP (e.g. TendaNova at 10.0.10.200). Returns a list of
{mac, ip} dicts merged into the presence scan.
Called on __init__. Reads data_network_device and
data_network_member into instance variables. Config changes take
effect on the next sync cycle without restarting the service.
# Full snapshot
python ObjServiceNetwork.py sync
# Individual probes
python ObjServiceNetwork.py router
python ObjServiceNetwork.py interfaces
python ObjServiceNetwork.py presence
python ObjServiceNetwork.py health
python ObjServiceNetwork.py household
# Device registry
python ObjServiceNetwork.py list-devices
python ObjServiceNetwork.py add-device AA:BB:CC:DD:EE:FF "Living Room TV" lounge
python ObjServiceNetwork.py remove-device AA:BB:CC:DD:EE:FF
# Household members
python ObjServiceNetwork.py list-members
python ObjServiceNetwork.py add-member "Alice" resident '["AA:BB:CC:DD:EE:FF"]' '["alice-phone"]'
python ObjServiceNetwork.py remove-member "Alice"
# One-time seed after fresh deploy
python ObjServiceNetwork.py seed-config
data_network_device /data_network_member, not in YAML. Do not look for deviceconfig.yaml.add-device CLI or upsert directly todata_network_device.data_household (Status: home oraway, ArrivedAt, DepartedAt).Hostnames in data_network_membersync is invoked by the gekkoridge cron scheduler every minute. Dorequests — MikroTik REST API callssocket / subprocess — ICMP ping for health checksObjServiceEwelink.py — Sonoff device controlObjServiceSolarman.py — solar inverter APIObjServiceOpenWeather.py — weather APIUpdated : 2026-04-19