Receive commands from the app on the device
When you touch a control on the dashboard, the app writes a value to an address, and your sketch reacts with a block on that address. This page lists the three shapes a block can take — the widget blocks, the WHEN_ clauses, and the generic ISignal — and which one to use when.
When the user touches a control on the dashboard, the app writes to an address. Your sketch reacts with a block at file scope, closed with };. Three shapes.
1. The head carries the value
For controls that send a value — sliders, switches, joystick — the block’s parameters are the value:
IHorizontalSlider(I1, float v) { analogWrite(PWM, v); };
IVerticalSlider(I4, float v) { ... };
ISwitch(I3, bool on) { digitalWrite(RELAY, on); };
ISegmentedSwitch(I5, int index) { mode = index; };
IJoystick(I2, float x, float y) { drive(x, y); };
The parameter’s type does the conversion: declare float, int or bool and that is what you get, whatever the widget sent. A lamp with a dimmer, a relay and a three-position selector — the whole sketch:
#include <InstantIoT.h>
const char* TOKEN = "paste-the-token-the-app-gave-you";
#define PWM_PIN 5
#define RELAY_PIN 4
const int POWERS[3] = { 60, 150, 255 }; // eco, normal, boost
IHorizontalSlider(I1, float v) { // the slider's range is set in the app: 0 – 100 here
analogWrite(PWM_PIN, (int)(v * 255.0 / 100.0));
};
ISwitch(I3, bool on) {
digitalWrite(RELAY_PIN, on ? HIGH : LOW);
};
ISegmentedSwitch(I5, int index) {
if (index < 0 || index > 2) return; // an index outside the table does nothing
analogWrite(PWM_PIN, POWERS[index]);
};
IJoystick(I2, float x, float y) { // -1.0 … 1.0 on each axis; 0,0 on release if the widget springs back
drive(x, y);
};
void setup() {
pinMode(PWM_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
InstantIoT.begin(WiFiLink("MyWiFi", "secret"), Cloud(TOKEN));
}
void loop() { InstantIoT.loop(); }
2. WHEN_ carries the kind
For buttons and the pad, one address carries several kinds of event; WHEN_ sorts them:
| Block | WHEN_ clauses |
|---|---|
ISimpleButton(I0) |
WHEN_PRESSED, WHEN_RELEASED, WHEN_LONG_PRESSED |
IAdvancedButton(I0) |
same |
IEmergencyButton(I0) |
WHEN_TRIGGERED, WHEN_RESET |
IDirectionPad(I0) |
WHEN_UP … WHEN_CENTER, WHEN_*_LONG, WHEN_*_RELEASE, WHEN_RELEASED_ANY, WHEN_PAD_PRESSED(key), WHEN_PAD_RELEASED(key), WHEN_PAD_LONG_PRESSED(key) |
IDirectionPad(I7) {
WHEN_UP { forward(); }
WHEN_UP_LONG { faster(); }
WHEN_RELEASED_ANY { stop(); }
};
A rover — a pad to drive it, a button for the horn, an emergency stop — over the device’s own Wi-Fi, so the phone is next to it:
#include <InstantIoT.h>
#define LEFT_PWM 5
#define RIGHT_PWM 6
#define HORN 7
bool stopped = false;
void drive(int left, int right) {
if (stopped) { left = 0; right = 0; }
analogWrite(LEFT_PWM, left);
analogWrite(RIGHT_PWM, right);
}
IDirectionPad(I0) {
WHEN_UP { drive(200, 200); }
WHEN_DOWN { drive(100, 100); }
WHEN_LEFT { drive(0, 200); }
WHEN_RIGHT { drive(200, 0); }
WHEN_UP_LONG { drive(255, 255); }
WHEN_RELEASED_ANY { drive(0, 0); } // whichever key: let go, it stops
};
ISimpleButton(I1) {
WHEN_PRESSED { digitalWrite(HORN, HIGH); }
WHEN_RELEASED { digitalWrite(HORN, LOW); }
WHEN_LONG_PRESSED { InstantIoT.write(I3, "Honk!"); } // answer on a text signal
};
IEmergencyButton(I2) {
WHEN_TRIGGERED { stopped = true; drive(0, 0); InstantIoT.write(I3, "STOPPED"); }
WHEN_RESET { stopped = false; InstantIoT.write(I3, "Ready"); }
};
void setup() {
pinMode(HORN, OUTPUT);
InstantIoT.begin(AccessPoint("Rover", "12345678"));
}
void loop() { InstantIoT.loop(); }
WHEN_PAD_PRESSED(key) hands the key back in a variable when one clause for all five reads better than five clauses:
IDirectionPad(I0) {
WHEN_PAD_PRESSED(key) { motor(key); } // key: Up, Down, Left, Right, Center
WHEN_PAD_RELEASED(key) { stop(); }
};
3. ISignal — any address, any type
The generic block. You write the type of what you receive: float, bool, any integer type, or const char*. The device is the only place that knows what an address holds.
ISignal(I6, const char* text) { display.print(text); };
ISignal(I5, float setpoint) { target = setpoint; };
Write ISignal rather than a widget block when the value can come from more than one place — a slider today, an automation’s set a signal tonight, a metric someone taps to edit — or when it must come back after a restart (next section). A message board on a small OLED, and a setpoint:
#include <InstantIoT.h>
#include <Adafruit_SSD1306.h>
const char* TOKEN = "paste-the-token-the-app-gave-you";
Adafruit_SSD1306 display(128, 64, &Wire);
float target = 20.0;
ISignal(I6, const char* text) { // a Text signal: 48 characters at most
display.clearDisplay();
display.setCursor(0, 0);
display.print(text);
display.display();
};
ISignal(I5, float setpoint) { // a Decimal signal, from a slider or a rule
target = setpoint;
};
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
InstantIoT.begin(WiFiLink("MyWiFi", "secret"), Cloud(TOKEN));
}
void loop() { InstantIoT.loop(); }
Several blocks may watch one address. And a catch-all, for logging or a device that routes addresses itself — it runs for every address written, before the blocks:
void onSignalWritten(const SignalEvent& e) {
Serial.print("I"); Serial.print(e.address);
Serial.print(" = "); Serial.println((float)e.value); // (int), (bool), (const char*) as you need
}
A setpoint survives a reboot
A value is a state, not a gesture — so the Cloud keeps it and replays it the moment the device reconnects. A pump asked to run at 19 °C last Tuesday is asked again Wednesday morning, with nobody’s phone open. The ISignal(I5, float) block simply runs again on connect.
A button would not run: nobody pressed. The rule belongs to the block.
In the app, on the signal: Advanced → Restore after a restart. In the sketch, the block on that address is ISignal — a thermostat that finds its setpoint and its mode again by itself:
#include <InstantIoT.h>
const char* TOKEN = "paste-the-token-the-app-gave-you";
#define HEATER 4
InstantTimer timers;
float target = 20.0; // used until the Cloud sends the real one back
bool enabled = false;
ISignal(I5, float setpoint) { target = setpoint; }; // I5 · Decimal · Restore after a restart: on
ISignal(I6, bool on) { enabled = on; }; // I6 · Boolean · restored too — a switch in the app, but ISignal here
void regulate() {
float t = readTemperature();
digitalWrite(HEATER, enabled && t < target ? HIGH : LOW);
InstantIoT.write(I0, t);
}
void setup() {
pinMode(HEATER, OUTPUT);
InstantIoT.begin(WiFiLink("MyWiFi", "secret"), Cloud(TOKEN));
timers.every(5000, regulate);
}
void loop() { InstantIoT.loop(); timers.run(); }
Unplug it, plug it back: within seconds I5 and I6 run again with Tuesday’s values, and the heater is where it was. More on this in Receive any value with ISignal.
