Direct command exchange without an Analyzer
AirNgin supports a direct command model for products whose firmware already understands the AirNgin logical operation/command structure. In this mode, no Analyzer is required to translate between the mobile application and the device.
The shared logical identity is the operationName that you define for the device in the producer panel. Each operation has one or more commands such as on, off, or another product-specific value.
Server-to-device topic
projectCode/ServerToDevice/{serial}
Device-to-server topic
projectCode/DeviceToServer
If AES security is enabled for an encrypted Direct Device topic, append /AES according to the security contract.
Send state from the device to the server
For DeviceToServer, send a JSON list of key/value pairs. key is the operationName; value is the command/current value. The list form lets one device report one or many changed operations in the same message.
One operation
[
{ "key": "operationName", "value": "command" }
]
Two operations
[
{ "key": "operationName", "value": "command" },
{ "key": "operationName", "value": "command" }
]
Relay and temperature example
[
{ "key": "ch1", "value": "on" },
{ "key": "temp", "value": "28" }
]
Receive a command from the server
A ServerToDevice/{serial} message contains the target deviceSerial and a data field. data contains the logical key and value for the requested operation.
{"deviceSerial":"AIRN0000000000","data":"{\"key\":\"OPERATION_NAME\",\"value\":\"COMMAND\"}"}
Example for channel 1:
{"deviceSerial":"AIRN0000000000","data":"{\"key\":\"ch1\",\"value\":\"on\"}"}
A typical firmware handler should:
- Verify that the received
deviceSerialmatches the local device identity. - Parse
dataand resolve thekeyto the intended operation. - Apply the requested
valueonly if it is valid for that operation.
void callback(char* topic, byte* payload, unsigned int length) {
String message;
for (unsigned int i = 0; i < length; i++) {
message += (char)payload[i];
}
StaticJsonDocument<256> doc;
if (deserializeJson(doc, message)) {
Serial.println("JSON parse error");
return;
}
const char* deviceSerial = doc["deviceSerial"];
if (strcmp(deviceSerial, myDeviceSerial) != 0) {
Serial.println("Message belongs to another device");
return;
}
message = doc["data"].as<String>();
if (deserializeJson(doc, message)) {
Serial.println("Inner JSON parse error");
return;
}
const char* key = doc["key"];
const char* value = doc["value"];
if (strcmp(key, "ch1") == 0) {
if (strcmp(value, "on") == 0) {
digitalWrite(relayPin, HIGH);
} else if (strcmp(value, "off") == 0) {
digitalWrite(relayPin, LOW);
}
}
}
