
Examples
Ping-pong
A single application contains both of two clients which are registered via self-provisioning. The first client sends a message to another client.
Smart light switch example
Most of the MCU development boards contain a LED and a user button that allows to build a simple smart light switch. There are several levels of completeness of the device and we start from the simplest solution.
Stage 1
A user can click a button on the development board that just flips the LED state on/off
Just a single device can be controlled by multiple remote applications
The LED can be controlled remotely by desktop / mobile / web applications
mobile application on iOS or Android
displays the switch in the current state of the LED: on or off
The switch is grayed if the MCU is offline
the last online time is displayed
the state of the switch is undefined
A user can click on the left side to turn the light off or on the right side to turn the light on
it is important to use separated buttons for the state. If a single button would be used that just flips the state then it would be difficult to control LED by multiple users simultaneously clicking the “flip” button.
web-page
Similar to the mobile application
desktop console applications on Windows, Linux, Macos and FreeBSD
displays the current state of LED and is waiting for “1” or “2” to turn the LED on/off
There is no “pairing” required for the device and applications because the device is provisioned and flashed with all required information.
Follow these steps:
1. Creating a “room”
A room is an aethernet client under which all other clients (a smart led device and remote applications) will be created. The CLI tool is used for creating the room:
aether-cli self-create 0123456789abcdef room.bin
The output file room.bin contains a binary state of the client that can be used then. The client is created under a special application created and hosted by us as a special node for this particular example. The application server sets a quota for the room that allows this quota to be transferred to child clients: the switch and remote applications.
2. Creating the device’s client, set quota
> aether-cli create room.bin device.bin -num_servers 3 -pk_method hydrogen -sk_method hydrogen -kdf_method hydrogen -protocols TCP
> aether-cli set quota room.bin device.bin 0.001
The device’s client is created by the parent application created behind. A list of options overrides default values to be sure that the constrained device supports it.
3. Retrieving client’s data
The device’s client UID is retrieved from the binary state.
> aether-cli get uid device.bin
> abcdef1234567890
All other parameters like master key, a client’s cloud with servers should be retrieved.
4. Creating and configuring remote client
> aether-cli create room.bin client1.bin
> aether-cli set quota room.bin client.bin 0.001
A client for the remote application is created.
5. Allow remote and device to receive messages
> aether-cli allow room.bin client1.bin *
> aether-cli allow room.bin device.bin *
Any client from the room can receive messages from other clients of this room.
6. Flash the device
All device’s client parameters are retrieved and hardcoded within the firmware source code. Aethernet library is already pre-configured to support just as few features as possible to minimize system requirements.
The device is flashed with UID, all 3 servers keys, IPs and port numbers. Once the device runs it connects to aethernet and makes pull-requests every 10 seconds. The device is designed to be constantly powered on. Once a client is launching then the client sends a “hi” message to the device that indicates that the remote can turn the light or/off. The device starts to pull messages once a second to be more responsive.
Integration
C++ cmake
Create main.cpp
Create CMakeLists.txt
Create ae_user_config.h
clone github/aether-client-cpp into the folder
run aether-client-cpp/git_init.bat
Getting started (C++)
Linux prerequisites: git, cmake, g++
Aether is an instance of the API. An application can create multiple instances of Aether (for debug purposes, for example). A domain is a container of the API instance objects and must be unique for each instance of the API.
Domain domain;
Aether::ptr aether = FileSystemAdapter(domain);
Adapter is a runtime-specific class that implements network interaction, for example, with Berklay sockets. An adapter must be constructed from the adapter’s prefab:
Adapter::ptr adapter{
aether->domain_->LoadCopy(aether->adapter_prefabs_.front())
};
A client passes each request to Æthernet through all adapter groups assigned to the client’s cloud simultaneously. An Adapter group defines a policy of how the request is passed through the groups’ adapters.
AdapterGroup group1{adapter1, adapter2};
AdapterGroup group2{adapter1, adapter3};
aether->registration_cloud_->adapter_groups_ = {group1, group2};
An application may create a Client through the Aether API. Multiple simultaneous clients are supported. A client is represented by an unique (across the whole Æthernet) identifier.
Client client = aether->NewClient();
Any interaction with Æthernet is done with Actions. The action performs all necessary requests to Æthernet asynchronously. The action provides the progress of an operation, can be gracefully canceled or terminated. All actions are released on the API releasing process.
To obtain the uid, a client does auto-provisioning:
Registration::Descriptor desc{parent_uid};
Registration action = client->TakeAction(desc);
while (!action->Done()) { sleep(1); }
An action progress can be asked or a call-back can be used for the progress notification.
A registered client can send a message to another client with the action:
SendMessage::Descriptor desc{addressee_uid, data, data_size};
SendMessage action = client->TakeAction(desc);
A client can pull messages:
Pull::Descriptor desc{pull_interval, message_received_callback};
Pull action = client->TakeAction(desc);
Creating an application
Æthernet is a tree with nodes - clients. Application stays for a regular client that is designated to have child clients and to manage them. A client / application can be created only with the parent node UID specified. A special node “anonymous” is a parent for all self-created clients. A large amount of computations should be performed for the “Proof-of-work” mechanism of the registration process. The proof-of-work for the anonymous namespace is much larger than the one normally used for regular applications. In exchange, a client receives $10 equivalent for using Æthernet with auto replenishing by $1 every month (not exceeding $10). Replenishing can be performed at any given moment with the aethernet.io/replenish by any amount by specifying the UID and master-key of the client.
Managing clients
The application is represented by a client running somewhere: locally on the development desktop, on a cloud virtual machine or even on Arduino.
The application server can be created using Java/TS client library and performs just basic managing operations on child clients. An application can send a list of service clients UIDs that perform specific operations like authorization, database access etc. It is similar to a microservice architecture with the difference that a client accesses microservices directly. That improves reliability and scalability.