-
Notifications
You must be signed in to change notification settings - Fork 3
WritingYourFirstSysMod
A walkthrough that takes you from
raft newto a custom SysMod with its own JSON config, REST endpoint and publish data, with logs visible in the serial monitor.Time required: about 30 minutes.
This tutorial assumes you have followed Quick Start and have the Raft CLI installed.
A BlinkSysMod that:
- Reads a blink rate (Hz) and pin number from the SysType JSON.
- Toggles a GPIO pin in
loop()at the configured rate. - Exposes a
blink/rate/<hz>REST endpoint that updates the rate at runtime. - Publishes the current rate so a subscriber can be notified when it changes.
raft new MyBlinker
cd MyBlinkerThis creates a project with RaftCoreApp already wired up, a default SysType, and a CMakeLists. Build and flash to confirm:
raft build
raft flash
raft monitorYou should see the standard SysManager startup logs.
Under main/ add BlinkSysMod.h:
#pragma once
#include "RaftSysMod.h"
class APISourceInfo;
class RestAPIEndpointManager;
class BlinkSysMod : public RaftSysMod
{
public:
BlinkSysMod(const char* pModuleName, RaftJsonIF& sysConfig)
: RaftSysMod(pModuleName, sysConfig)
{
}
static RaftSysMod* create(const char* pModuleName, RaftJsonIF& sysConfig)
{
return new BlinkSysMod(pModuleName, sysConfig);
}
protected:
virtual void setup() override final;
virtual void loop() override final;
virtual void addRestAPIEndpoints(RestAPIEndpointManager& endpointManager) override final;
private:
int _pin = -1;
float _rateHz = 1.0f;
uint32_t _lastToggleMs = 0;
bool _level = false;
RaftRetCode apiBlink(const String& reqStr, String& respStr, const APISourceInfo& sourceInfo);
static constexpr const char* MODULE_PREFIX = "Blink";
};…and BlinkSysMod.cpp:
#include "BlinkSysMod.h"
#include "Logger.h"
#include "RaftArduino.h"
#include "RaftUtils.h"
#include "RestAPIEndpointManager.h"
void BlinkSysMod::setup()
{
_pin = configGetLong("pin", -1);
_rateHz = configGetDouble("rateHz", 1.0);
if (_pin >= 0)
pinMode(_pin, OUTPUT);
LOG_I(MODULE_PREFIX, "setup pin %d rateHz %.2f", _pin, _rateHz);
}
void BlinkSysMod::loop()
{
if (_pin < 0 || _rateHz <= 0.0f)
return;
uint32_t periodMs = (uint32_t)(1000.0f / (_rateHz * 2.0f));
if (Raft::isTimeout(millis(), _lastToggleMs, periodMs))
{
_level = !_level;
digitalWrite(_pin, _level ? HIGH : LOW);
_lastToggleMs = millis();
}
}
void BlinkSysMod::addRestAPIEndpoints(RestAPIEndpointManager& endpointManager)
{
endpointManager.addEndpoint("blink",
RestAPIEndpoint::ENDPOINT_CALLBACK, RestAPIEndpoint::ENDPOINT_GET,
std::bind(&BlinkSysMod::apiBlink, this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
"blink/rate/<hz> - set blink rate in Hz");
}
RaftRetCode BlinkSysMod::apiBlink(const String& reqStr, String& respStr, const APISourceInfo&)
{
String cmd = RestAPIEndpointManager::getNthArgStr(reqStr.c_str(), 1);
if (cmd.equalsIgnoreCase("rate"))
{
String hzStr = RestAPIEndpointManager::getNthArgStr(reqStr.c_str(), 2);
_rateHz = hzStr.toFloat();
LOG_I(MODULE_PREFIX, "rate set to %.2f Hz", _rateHz);
}
Raft::setJsonResult(reqStr.c_str(), respStr, true, nullptr,
("\"rateHz\":" + String(_rateHz)).c_str());
return RaftRetCode::RAFT_OK;
}Add the file to main/CMakeLists.txt:
idf_component_register(
SRCS "main.cpp" "BlinkSysMod.cpp"
INCLUDE_DIRS "."
...)Open main/main.cpp and register the SysMod with SysManager after RaftCoreApp is constructed:
#include "RaftCoreApp.h"
#include "RegisterSysMods.h"
#include "BlinkSysMod.h"
extern "C" void app_main(void)
{
RaftCoreApp raftApp;
// Register built-in SysMods (NetworkManager, BLEManager, etc.)
RegisterSysMods::registerSysMods(raftApp.getSysManager());
// Register your SysMod
raftApp.getSysManager().registerSysMod("Blink", BlinkSysMod::create);
raftApp.setup();
while (true)
raftApp.loop();
}Open the active SysType JSON (e.g. systypes/Common/SysType.json) and add a Blink entry to the SysMods array:
The name value must match what you registered ("Blink"). Any other keys are read by your SysMod via configGet*.
raft build
raft flash
raft monitorIn the serial monitor you should see:
Blink: setup pin 2 rateHz 2.00
…and the LED on GPIO 2 will toggle at 2 Hz. From a host on the same network, change the rate:
curl http://<device-ip>/api/blink/rate/5Response:
{"req":"blink/rate/5","rslt":"ok","rateHz":5.00}Add a getDebugJSON() override or, better, register the SysMod as a data source so subscribers can be notified on rate changes. See Registering as a Data Source.
- Adding a Comms Channel — write a SysMod that exposes a transport (the other half of the system).
- Adding REST API Endpoints — full API for endpoint registration including POST bodies and chunked uploads.
- SysMods and SysManager — life-cycle reference.
-
Configuration — how
configGet*resolves values across SysType / NV / runtime overrides.
Getting Started
- Quick Start
- Architecture at a Glance
- Writing Your First SysMod
- Adding a Comms Channel
- Adding an I2C Device Type
- PlatformIO / Arduino
Scaffolding & Building
- Raft CLI
- SysTypes
- Top-Level SysType
- Build Process
- WebUI Build Pipeline
- File System
- Partitions & Flash
- Local Dev Libraries
- Library Developer Guide
Architecture
Built-in SysMods
- NetworkManager
- BLEManager
- WebServer
- MQTTManager
- SerialConsole
- CommandSerial
- CommandSocket
- CommandFile
- FileManager
- LogManager
- ESPOTAUpdate
- StatePublisher
- Remote Logging
- Data Source Registration
Comms & Protocols
- Stack Overview
- Comms Channels
- ProtocolExchange
- RICREST Protocol
- Real-Time Streams
- Adding REST Endpoints
- Built-in REST Endpoints
- File Download (OKTO)
- OTA Update Flow
Devices & Buses
- DeviceManager
- Device Manager REST API
- Device Factory & Classes
- Device Type Records
- Adding an I2C Device Type
- Device Data Publishing
- Data Logger
- I2C Bus
- I2C Device Scanning
- I2C ID & Polling
- MotorControl Overview
- MotorControl Config
- MotorControl Commands
Helpers
Reference
{ "SysMods": [ // ... existing built-ins ... { "name": "Blink", "pin": 2, "rateHz": 2.0 } ] }