Files
security-new/INSTRUCTION.md
2026-07-22 12:54:44 +03:00

9.1 KiB
Raw Blame History

Security Mesh Node — Architecture & Development Guide

Project Structure

security-new/
├── platformio.ini              # PlatformIO config (targets, libs, flags)
├── src/
│   ├── main.cpp                # Main firmware — SecurityMesh class + loop
│   ├── target.h                # Pin mappings, radio params, platform defs
│   └── variants/
│       └── promicro/           # ProMicro-specific files
├── boards/                     # Custom linker scripts
├── scripts/                    # Build helper scripts
├── .pio/                       # Build output (ignored)

All MeshCore library lives at ../MeshCore/.


How Radio Mesh Works

Low-level Layer (RadioLib)

  • radio_module (SX1262) — raw LoRa send/receive.
  • radio_driver (CustomSX1262Wrapper) — RadioLib wrapper. Provides getCurrentRSSI(), setParams(), setTxPower().

Mesh Layer (MeshCore)

  • mesh::Mesh — main class that manages flooding, routing, encryption, channel storage.
  • mesh::Dispatcher — base of Mesh (packet scheduling, radio control).
  • mesh::GroupChannel — channel with hash[1] and secret[32].
  • mesh::Packet — a mesh packet. Obtained from PacketManager (pool of 16 slots).

Lifecycle

1. radio_module.begin()          — init SX1262
2. radio_driver.setParams(...)   — freq, BW, SF, CR
3. Mesh.begin()                  — starts listening
4. Mesh.loop() loop()            — pumps radio ISR, processes incoming
5. onGroupDataRecv() callback    — called when encrypted group msg arrives

SecurityMesh Class

Channel Derivation (setup_channel())

SHA256("1234") → 32 bytes key
mesh_channel.secret = key[0..15]   (first 16 bytes)
mesh_channel.hash  = SHA256(secret)[0..0]  (first 1 byte, PATH_HASH_SIZE=1)

Critical Virtual Overrides

searchChannelsByHash()

WHY IT'S NEEDED: Mesh::loop() calls searchChannelsByHash() to match incoming packet hashes against stored channels. The base implementation returns 0 (no matches). Without this override, every incoming group message is silently dropped and onGroupDataRecv is never called.

int searchChannelsByHash(const uint8_t* hash, mesh::GroupChannel channels[], int max_matches) override {
    if (max_matches > 0 && channel_ready
        && memcmp(hash, mesh_channel.hash, sizeof(mesh_channel.hash)) == 0) {
        channels[0] = mesh_channel;
        return 1;  // found 1 match
    }
    return 0;
}

sizeof(mesh_channel.hash) = PATH_HASH_SIZE = 1 byte.

onGroupDataRecv()

Called for each decrypted group message that matched a channel. Format: [4 bytes ts][1 byte type][text]. Type byte must be 0 for text.

Sending (send_text())

void send_text(const char* text) {
    uint8_t buf[256];
    buf[0..3] = timestamp (4 bytes)
    buf[4]    = 0 (type: text)
    buf[5..]  = text
    Packet* pkt = createGroupDatagram(PAYLOAD_TYPE_GRP_TXT, mesh_channel, buf, 5 + text_len);
    sendFlood(pkt, 0, 1);  // 1 hop
}

sendFlood with path_hash_size=1 means 0-hop (immediate neighbors only). Increase to flood across the mesh.


Command Processing

All commands are processed in onGroupDataRecv():

Preprocessing

  1. Trim trailing spaces"status ""status"
  2. Lowercase"Status""status"
  3. Strip prefix"Security: status""status" (anything before ": ")
  4. Trim leading spaces

Command Table

Command Action Response
help list commands help:...
ohrana on arm, relay1 ON ohrana on ok
ohrana off disarm, relay1 OFF ohrana off ok
relay1 on relay1 ON (direct) relay1 on ok
relay1 off relay1 OFF (direct) relay1 off ok
relay2 on relay2 ON relay2 on ok
relay2 off relay2 OFF relay2 off ok
relay state of both relays relay:1on 2off
status report state status:armed/off temp:±X.XC hall:trig/ok motion:trig/ok bat:X.XXV/USB
ver build date build:Mon DD YYYY HH:MM:SS
scan noise floor noise:-XXXdBm
snr RSSI и SNR последнего пакета rssi:-78dBm snr:+6.5dB
uptime device uptime uptime:1d 3h 15m
kontrol <min> auto-status every N min kontrol 60 min ok
kontrol off disable auto-status kontrol off
reboot reboot device rebooting
time show RTC date/time time:22.07.2026 11:00
time s DD.MM.YYYY HH.MM set RTC date/time time set 22.07.2026 11.00

Response Delay

All command responses are sent with a 5-second delay (non-blocking, via defer_response).
The action (relay toggle, armed state change) happens immediately — only the reply text is deferred.
Alerts (alert:hall, alert:motion) and startup (poweron) are sent immediately without delay.

Special Commands

  • snr — returns rssi:-78dBm snr:+6.5dB based on the last received packet. Uses radio_driver.getLastRSSI() and pkt->getSNR(). Stored in last_rssi / last_snr fields, updated on every onGroupDataRecv.

  • reboot — sends rebooting immediately (not deferred), blinks LED 5 times, then NVIC_SystemReset().

  • uptime — calculates uptime from g_boot_time (set at boot). Format: uptime:1d 3h 15m (days/hours/minutes).

  • kontrol <min> — sets g_auto_status_interval = min * 60000. In loop(), when millis() - g_last_auto_status >= interval, sends status. Range: 11440 minutes.

Auto-Sent Messages

  • Startup: poweron Mon DD YYYY HH:MM:SS — sent 10s after boot.
  • Hall alert: alert:hall — when armed and reed opens.
  • Motion alert: alert:motion — when armed and PIR triggers.

Cooldown: 10 minutes between alerts (ALERT_COOLDOWN_MS).


Hardware

Pin (nRF52) Pin (ProMicro) Function
30 13 NSS (LoRa SPI CS)
29 12 SCK
31 14 MOSI
2 15 MISO
7 11 DIO1 (LoRa IRQ)
6 10 RST
10 16 BUSY
21 POWER_EN (ProMicro only)
12 0 REED (hall sensor)
11 1 PIR (motion)
3 2 DS18B20 (temp)
4 3 RELAY_1
5 4 RELAY_2
13 22 LED_STATUS

Reference: target.h lines 25114.


Radio Config

Param Value
Frequency 868.731018 MHz
Bandwidth 62.5 kHz
Spreading Factor 7
Coding Rate 7 (4/7)
TX Power 22 dBm
TCXO voltage 1.8V
Current limit 140 mA
RX Boosted Gain on
DIO2 as RF switch on

PATH_HASH_MODE=0PATH_HASH_SIZE=1 (minimal hash, maximum throughput).


Build & Upload

# Build
pio run -e promicro_security

# Upload (via nrfutil)
pio run -e promicro_security -t upload

# Monitor
pio device monitor -b 115200

Current resource usage: RAM 8.1%, Flash 36.8%.


Common Pitfalls & Debugging

The LED blink (3 fast flashes) is the first thing in onGroupDataRecv. If LED doesn't blink:

  • Check searchChannelsByHash() override — it's required.
  • Check hash match: both sides must derive the same secret and hash from passphrase.
  • Check radio config matches (freq, BW, SF, CR).

No response despite LED blinking

  • Command was received (LED blinked) but processing or send failed.
  • Test with simple response — if send_text("ok") fails but send_text("relay2 on ok") works, check response length/SNPRINTF.
  • sendFlood with path_hash_size=1 sends only to neighbors. If response doesn't arrive at the remote app, check app's mesh routing or increase path_hash_size.

send_text() doesn't actually send

  • createGroupDatagram may return NULL if packet pool is full (16 slots).
  • rtc_clock.getCurrentTime() returning bogus data (VolatileRTCClock starts from 0, fine).

Adding a new command

  1. Add else if block in onGroupDataRecv() after line 168.
  2. Use strcmp(cmd, "command") == 0 for exact match.
  3. Call send_text("response") to reply.
  4. Update the help string.

Config persistent storage

  • InternalFS (LittleFS) on nRF52 internal flash.
  • SecurityConfig: armed + relay2 state saved as binary struct.
  • File: /security.cfg, magic 0x53454355.

Key Files in MeshCore Library

File What it provides
MeshCore/src/Mesh.h Mesh, GroupChannel, virtual methods
MeshCore/src/MeshCore.h Constants (PUB_KEY_SIZE, PATH_HASH_SIZE, etc.)
MeshCore/src/Dispatcher.h Dispatcher, packet scheduling
MeshCore/src/helpers/SimpleMeshTables.h Duplicate packet detection
MeshCore/src/helpers/StaticPoolPacketManager.h Packet memory pool
MeshCore/src/helpers/ChannelDetails.h Channel helper structs
MeshCore/src/helpers/NRF52Board.h nRF52 board abstraction

Things That Won't Work

  • BLE — not included. No BLESerialInterface, no BaseChatMesh.
  • BaseChatMesh — not used. SecurityMesh inherits directly from mesh::Mesh.
  • Serial commands — not processed. Serial is for debug output only.
  • onPeerDataRecv — not used. Group messaging only, no direct peer messages.